feat: 分站前端默认使用人民币显示价格和余额
- 后端 GetDistSiteInfo 返回 currency 配置(符号/汇率/代码) - SiteContext 新增 useCurrency() hook 提供 symbol/rate/fmt - Pricing/Dashboard/Topup/Packages 所有价格从 $ 改为 ¥ 并乘以汇率 - 7 个主题的 Home.jsx 套餐价格同步更新 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
1 parent
31e4bd22e4
commit
c9c711e4f6
12 files changed
+72
-36
No files matched your search
@@ -41,3 +41,24 @@ export function useSite() {
|
||||
if (!ctx) throw new Error('useSite must be used within SiteProvider');
|
||||
return ctx;
|
||||
}
|
||||
|
||||
/**
|
||||
* useCurrency - 获取分站货币配置
|
||||
* 返回 { symbol, rate, code, fmt(usdValue) }
|
||||
* fmt() 将 USD 值转换为显示货币并格式化
|
||||
*/
|
||||
export function useCurrency() {
|
||||
const { site } = useSite();
|
||||
const currency = site?.currency;
|
||||
const symbol = currency?.symbol || '¥';
|
||||
const rate = currency?.exchange_rate || 7;
|
||||
const code = currency?.code || 'CNY';
|
||||
|
||||
const fmt = (usdValue, decimals = 4) => {
|
||||
if (usdValue == null || isNaN(usdValue)) return '-';
|
||||
const converted = Number(usdValue) * rate;
|
||||
return symbol + converted.toFixed(decimals);
|
||||
};
|
||||
|
||||
return { symbol, rate, code, fmt };
|
||||
}
|
||||
@@ -3,12 +3,14 @@ import { Link } from 'react-router-dom';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useAuth } from '../context/AuthContext';
|
||||
import { getUserUsage, redeemCode, Q, quotaToDollar } from '../api';
|
||||
import { useCurrency } from '../context/SiteContext';
|
||||
import CountUp from '../components/bits/CountUp';
|
||||
import toast from 'react-hot-toast';
|
||||
|
||||
export default function Dashboard() {
|
||||
const { t } = useTranslation();
|
||||
const { user, refreshUser } = useAuth();
|
||||
const { symbol, rate } = useCurrency();
|
||||
const [usage, setUsage] = useState(null);
|
||||
const [redeemInput, setRedeemInput] = useState('');
|
||||
const [redeeming, setRedeeming] = useState(false);
|
||||
@@ -40,7 +42,7 @@ export default function Dashboard() {
|
||||
const quota = usage?.quota ?? user?.quota ?? 0;
|
||||
const usedQuota = usage?.used_quota ?? user?.used_quota ?? 0;
|
||||
const requestCount = usage?.request_count ?? user?.request_count ?? 0;
|
||||
const balanceDollars = quota / Q;
|
||||
const balanceDollars = quota / Q * rate;
|
||||
|
||||
return (
|
||||
<div className="max-w-7xl mx-auto px-6 py-10">
|
||||
@@ -57,7 +59,7 @@ export default function Dashboard() {
|
||||
<div className="glass rounded-2xl p-6">
|
||||
<p className="text-sm text-page-secondary mb-2">{t('dashboard.balance')}</p>
|
||||
<div className="text-3xl font-bold text-page">
|
||||
$<CountUp from={0} to={balanceDollars} duration={1.5} />
|
||||
{symbol}<CountUp from={0} to={balanceDollars} duration={1.5} />
|
||||
</div>
|
||||
<p className="text-xs text-page-muted mt-1">{t('dashboard.quotaUnits', { count: quota.toLocaleString() })}</p>
|
||||
</div>
|
||||
@@ -65,7 +67,7 @@ export default function Dashboard() {
|
||||
<div className="glass rounded-2xl p-6">
|
||||
<p className="text-sm text-page-secondary mb-2">{t('dashboard.used')}</p>
|
||||
<div className="text-3xl font-bold text-page">
|
||||
$<CountUp from={0} to={usedQuota / Q} duration={1.5} />
|
||||
{symbol}<CountUp from={0} to={usedQuota / Q * rate} duration={1.5} />
|
||||
</div>
|
||||
<p className="text-xs text-page-muted mt-1">{t('dashboard.quotaUnits', { count: usedQuota.toLocaleString() })}</p>
|
||||
</div>
|
||||
|
||||
@@ -3,6 +3,7 @@ import { Link, useNavigate } from 'react-router-dom';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useAuth } from '../context/AuthContext';
|
||||
import { getSitePackages, getSiteModels, subscribePackage, getActiveSubscriptions, Q } from '../api';
|
||||
import { useCurrency } from '../context/SiteContext';
|
||||
import SpotlightCard from '../components/bits/SpotlightCard';
|
||||
import { calcOfficialEquivList } from '../utils/officialEquiv';
|
||||
import RotatingEquiv from '../components/bits/RotatingEquiv';
|
||||
@@ -24,6 +25,7 @@ export default function Packages() {
|
||||
const { t } = useTranslation();
|
||||
const { user, refreshUser } = useAuth();
|
||||
const navigate = useNavigate();
|
||||
const { symbol, rate } = useCurrency();
|
||||
const [packages, setPackages] = useState([]);
|
||||
const [models, setModels] = useState([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
@@ -144,7 +146,7 @@ export default function Packages() {
|
||||
style={{ width: `${pct}%` }} />
|
||||
</div>
|
||||
<span className="text-xs text-page-secondary whitespace-nowrap">
|
||||
${(remain / Q).toFixed(2)} / ${(total / Q).toFixed(2)}
|
||||
{symbol}{(remain / Q * rate).toFixed(2)} / {symbol}{(total / Q * rate).toFixed(2)}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -204,9 +206,9 @@ export default function Packages() {
|
||||
{/* Price */}
|
||||
<div className="mb-6">
|
||||
<div className="flex items-baseline gap-2">
|
||||
<span className="text-4xl font-bold text-page">${Number(pkg.price).toFixed(2)}</span>
|
||||
<span className="text-4xl font-bold text-page">{symbol}{(Number(pkg.price) * rate).toFixed(2)}</span>
|
||||
{pkg.original_price > 0 && pkg.original_price > pkg.price && (
|
||||
<span className="text-lg text-page-muted line-through">${Number(pkg.original_price).toFixed(2)}</span>
|
||||
<span className="text-lg text-page-muted line-through">{symbol}{(Number(pkg.original_price) * rate).toFixed(2)}</span>
|
||||
)}
|
||||
</div>
|
||||
{pkg.duration > 0 && (
|
||||
@@ -277,7 +279,7 @@ export default function Packages() {
|
||||
|
||||
{/* Confirmation Modal */}
|
||||
{confirmPkg && (() => {
|
||||
const userBalance = (user?.quota || 0) / Q;
|
||||
const userBalance = (user?.quota || 0) / Q * rate;
|
||||
const pkgPrice = Number(confirmPkg.price);
|
||||
const insufficient = userBalance < pkgPrice;
|
||||
const resetPeriod = confirmPkg.quota_reset_period || 'never';
|
||||
@@ -301,7 +303,7 @@ export default function Packages() {
|
||||
</div>
|
||||
)}
|
||||
<p className="text-sm text-page-secondary mb-4">
|
||||
{t('packages.yourBalance')} <span className={`font-medium ${insufficient ? 'text-page-danger' : 'text-page-success'}`}>${userBalance.toFixed(2)}</span>
|
||||
{t('packages.yourBalance')} <span className={`font-medium ${insufficient ? 'text-page-danger' : 'text-page-success'}`}>{symbol}{userBalance.toFixed(2)}</span>
|
||||
</p>
|
||||
{insufficient && (
|
||||
<div className="bg-red-500/10 border border-red-500/20 rounded-xl p-3 mb-4">
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import React, { useState, useEffect, useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { getSiteModels } from '../api';
|
||||
import { useCurrency } from '../context/SiteContext';
|
||||
|
||||
export default function Pricing() {
|
||||
const { t } = useTranslation();
|
||||
const { symbol, rate } = useCurrency();
|
||||
const [models, setModels] = useState([]);
|
||||
const [vendors, setVendors] = useState([]);
|
||||
const [search, setSearch] = useState('');
|
||||
@@ -132,10 +134,10 @@ export default function Pricing() {
|
||||
<span className="font-mono text-page">{m.display_name || m.model_name}</span>
|
||||
</td>
|
||||
<td className="px-5 py-3.5 text-right font-mono text-page-label">
|
||||
{m.input_price != null ? `$${(Number(m.input_price) * 1000).toFixed(4)}` : '-'}
|
||||
{m.input_price != null ? `${symbol}${(Number(m.input_price) * 1000 * rate).toFixed(4)}` : '-'}
|
||||
</td>
|
||||
<td className="px-5 py-3.5 text-right font-mono text-page-label">
|
||||
{m.output_price != null ? `$${(Number(m.output_price) * 1000).toFixed(4)}` : '-'}
|
||||
{m.output_price != null ? `${symbol}${(Number(m.output_price) * 1000 * rate).toFixed(4)}` : '-'}
|
||||
</td>
|
||||
<td className="px-5 py-3.5 text-center">
|
||||
<span className={`inline-flex items-center gap-1.5 px-2 py-0.5 rounded-full text-xs border ${
|
||||
|
||||
+7
-5
@@ -8,6 +8,7 @@ import {
|
||||
createCryptoOrder, getCryptoOrderStatus, getTopupHistory,
|
||||
Q, quotaToDollar,
|
||||
} from '../api';
|
||||
import { useCurrency } from '../context/SiteContext';
|
||||
import CountUp from '../components/bits/CountUp';
|
||||
import toast from 'react-hot-toast';
|
||||
|
||||
@@ -15,6 +16,7 @@ export default function Topup() {
|
||||
const { t } = useTranslation();
|
||||
const { user, refreshUser } = useAuth();
|
||||
const { site } = useSite();
|
||||
const { symbol, rate } = useCurrency();
|
||||
|
||||
const [usage, setUsage] = useState(null);
|
||||
const [topupInfo, setTopupInfo] = useState(null);
|
||||
@@ -67,7 +69,7 @@ export default function Topup() {
|
||||
const quota = usage?.quota ?? user?.quota ?? 0;
|
||||
const usedQuota = usage?.used_quota ?? user?.used_quota ?? 0;
|
||||
const requestCount = usage?.request_count ?? user?.request_count ?? 0;
|
||||
const balanceDollars = quota / Q;
|
||||
const balanceDollars = quota / Q * rate;
|
||||
|
||||
// Redeem
|
||||
const handleRedeem = async (e) => {
|
||||
@@ -324,7 +326,7 @@ export default function Topup() {
|
||||
<div className="glass rounded-2xl p-6">
|
||||
<p className="text-sm text-page-secondary mb-2">{t('dashboard.balance')}</p>
|
||||
<div className="text-3xl font-bold text-page">
|
||||
$<CountUp from={0} to={balanceDollars} duration={1.5} />
|
||||
{symbol}<CountUp from={0} to={balanceDollars} duration={1.5} />
|
||||
</div>
|
||||
<p className="text-xs text-page-muted mt-1">{t('dashboard.quotaUnits', { count: quota.toLocaleString() })}</p>
|
||||
</div>
|
||||
@@ -332,7 +334,7 @@ export default function Topup() {
|
||||
<div className="glass rounded-2xl p-6">
|
||||
<p className="text-sm text-page-secondary mb-2">{t('dashboard.used')}</p>
|
||||
<div className="text-3xl font-bold text-page">
|
||||
$<CountUp from={0} to={usedQuota / Q} duration={1.5} />
|
||||
{symbol}<CountUp from={0} to={usedQuota / Q * rate} duration={1.5} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -371,7 +373,7 @@ export default function Topup() {
|
||||
: 'glass-sm text-page-label hover:text-page hover:bg-page-surface-hover'
|
||||
}`}
|
||||
>
|
||||
${val}
|
||||
{symbol}{val}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
@@ -591,7 +593,7 @@ export default function Topup() {
|
||||
{history.map((item, i) => (
|
||||
<div key={i} className="flex items-center justify-between glass-sm rounded-xl px-4 py-3">
|
||||
<div>
|
||||
<p className="text-sm text-page">${item.amount}</p>
|
||||
<p className="text-sm text-page">{symbol}{(Number(item.amount) * rate).toFixed(2)}</p>
|
||||
<p className="text-xs text-page-muted">
|
||||
{new Date(item.create_time * 1000).toLocaleString()} · {item.payment_method || t('topup.redeemCode')}
|
||||
</p>
|
||||
|
||||
@@ -2,7 +2,7 @@ import React, { useState, useEffect } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useAuth } from '../../context/AuthContext';
|
||||
import { useSite } from '../../context/SiteContext';
|
||||
import { useSite, useCurrency } from '../../context/SiteContext';
|
||||
import { getSiteModels, getSitePackages, Q } from '../../api';
|
||||
import { calcOfficialEquivList } from '../../utils/officialEquiv';
|
||||
import RotatingEquiv from '../../components/bits/RotatingEquiv';
|
||||
@@ -13,6 +13,7 @@ export default function ClaudeHome() {
|
||||
const { t } = useTranslation();
|
||||
const { user } = useAuth();
|
||||
const { site } = useSite();
|
||||
const { symbol, rate } = useCurrency();
|
||||
const [models, setModels] = useState([]);
|
||||
const [packages, setPackages] = useState([]);
|
||||
|
||||
@@ -159,9 +160,9 @@ export default function ClaudeHome() {
|
||||
<h3 className="text-base font-semibold text-[#3D3024]">{pkg.name}</h3>
|
||||
{pkg.description && <p className="text-sm text-[#8B7D6E] mt-1">{pkg.description}</p>}
|
||||
<div className="mt-auto pt-6">
|
||||
<span className="text-3xl font-bold text-[#3D3024]">${pkg.price}</span>
|
||||
<span className="text-3xl font-bold text-[#3D3024]">{symbol}{(Number(pkg.price) * rate).toFixed(2)}</span>
|
||||
{pkg.original_price > pkg.price && (
|
||||
<span className="text-sm text-[#8B7D6E] line-through ml-2">${pkg.original_price}</span>
|
||||
<span className="text-sm text-[#8B7D6E] line-through ml-2">{symbol}{(Number(pkg.original_price) * rate).toFixed(2)}</span>
|
||||
)}
|
||||
{pkg.duration > 0 && <p className="text-xs text-[#8B7D6E] mt-1">{t('home.days', { count: pkg.duration })}</p>}
|
||||
</div>
|
||||
|
||||
@@ -2,7 +2,7 @@ import React, { useState, useEffect } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useAuth } from '../../context/AuthContext';
|
||||
import { useSite } from '../../context/SiteContext';
|
||||
import { useSite, useCurrency } from '../../context/SiteContext';
|
||||
import { getSiteModels, getSitePackages, Q } from '../../api';
|
||||
import { calcOfficialEquivList } from '../../utils/officialEquiv';
|
||||
import RotatingEquiv from '../../components/bits/RotatingEquiv';
|
||||
@@ -13,6 +13,7 @@ export default function CleanHome() {
|
||||
const { t } = useTranslation();
|
||||
const { user } = useAuth();
|
||||
const { site } = useSite();
|
||||
const { symbol, rate } = useCurrency();
|
||||
const [models, setModels] = useState([]);
|
||||
const [packages, setPackages] = useState([]);
|
||||
|
||||
@@ -172,9 +173,9 @@ export default function CleanHome() {
|
||||
<h3 className="text-base font-semibold text-gray-900">{pkg.name}</h3>
|
||||
{pkg.description && <p className="text-sm text-gray-500 mt-1">{pkg.description}</p>}
|
||||
<div className="mt-auto pt-6">
|
||||
<span className="text-3xl font-bold text-gray-900">${pkg.price}</span>
|
||||
<span className="text-3xl font-bold text-gray-900">{symbol}{(Number(pkg.price) * rate).toFixed(2)}</span>
|
||||
{pkg.original_price > pkg.price && (
|
||||
<span className="text-sm text-gray-500 line-through ml-2">${pkg.original_price}</span>
|
||||
<span className="text-sm text-gray-500 line-through ml-2">{symbol}{(Number(pkg.original_price) * rate).toFixed(2)}</span>
|
||||
)}
|
||||
{pkg.duration > 0 && <p className="text-xs text-gray-500 mt-1">{t('home.days', { count: pkg.duration })}</p>}
|
||||
</div>
|
||||
|
||||
@@ -2,7 +2,7 @@ import React, { useState, useEffect } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useAuth } from '../../context/AuthContext';
|
||||
import { useSite } from '../../context/SiteContext';
|
||||
import { useSite, useCurrency } from '../../context/SiteContext';
|
||||
import { getSiteModels, getSitePackages, Q } from '../../api';
|
||||
import { calcOfficialEquivList } from '../../utils/officialEquiv';
|
||||
import RotatingEquiv from '../../components/bits/RotatingEquiv';
|
||||
@@ -13,6 +13,7 @@ export default function CorporateHome() {
|
||||
const { t } = useTranslation();
|
||||
const { user } = useAuth();
|
||||
const { site } = useSite();
|
||||
const { symbol, rate } = useCurrency();
|
||||
const [models, setModels] = useState([]);
|
||||
const [packages, setPackages] = useState([]);
|
||||
|
||||
@@ -171,9 +172,9 @@ export default function CorporateHome() {
|
||||
<h3 className="text-base font-semibold text-slate-900">{pkg.name}</h3>
|
||||
{pkg.description && <p className="text-sm text-slate-500 mt-1">{pkg.description}</p>}
|
||||
<div className="mt-auto pt-6">
|
||||
<span className="text-3xl font-bold text-slate-900">${pkg.price}</span>
|
||||
<span className="text-3xl font-bold text-slate-900">{symbol}{(Number(pkg.price) * rate).toFixed(2)}</span>
|
||||
{pkg.original_price > pkg.price && (
|
||||
<span className="text-sm text-slate-500 line-through ml-2">${pkg.original_price}</span>
|
||||
<span className="text-sm text-slate-500 line-through ml-2">{symbol}{(Number(pkg.original_price) * rate).toFixed(2)}</span>
|
||||
)}
|
||||
{pkg.duration > 0 && <p className="text-xs text-slate-500 mt-1">{t('home.days', { count: pkg.duration })}</p>}
|
||||
</div>
|
||||
|
||||
@@ -2,7 +2,7 @@ import React, { useState, useEffect } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useAuth } from '../../context/AuthContext';
|
||||
import { useSite } from '../../context/SiteContext';
|
||||
import { useSite, useCurrency } from '../../context/SiteContext';
|
||||
import { getSiteModels, getSitePackages, Q } from '../../api';
|
||||
import { calcOfficialEquivList } from '../../utils/officialEquiv';
|
||||
import RotatingEquiv from '../../components/bits/RotatingEquiv';
|
||||
@@ -13,6 +13,7 @@ export default function DarkHome() {
|
||||
const { t } = useTranslation();
|
||||
const { user } = useAuth();
|
||||
const { site } = useSite();
|
||||
const { symbol, rate } = useCurrency();
|
||||
const [models, setModels] = useState([]);
|
||||
const [packages, setPackages] = useState([]);
|
||||
|
||||
@@ -162,9 +163,9 @@ export default function DarkHome() {
|
||||
<h3 className="text-base font-semibold text-white">{pkg.name}</h3>
|
||||
{pkg.description && <p className="text-sm text-neutral-500 mt-1">{pkg.description}</p>}
|
||||
<div className="mt-auto pt-6">
|
||||
<span className="text-3xl font-bold text-white">${pkg.price}</span>
|
||||
<span className="text-3xl font-bold text-white">{symbol}{(Number(pkg.price) * rate).toFixed(2)}</span>
|
||||
{pkg.original_price > pkg.price && (
|
||||
<span className="text-sm text-neutral-600 line-through ml-2">${pkg.original_price}</span>
|
||||
<span className="text-sm text-neutral-600 line-through ml-2">{symbol}{(Number(pkg.original_price) * rate).toFixed(2)}</span>
|
||||
)}
|
||||
{pkg.duration > 0 && <p className="text-xs text-neutral-600 mt-1">{t('home.days', { count: pkg.duration })}</p>}
|
||||
</div>
|
||||
|
||||
@@ -2,7 +2,7 @@ import React, { useState, useEffect } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useAuth } from '../../context/AuthContext';
|
||||
import { useSite } from '../../context/SiteContext';
|
||||
import { useSite, useCurrency } from '../../context/SiteContext';
|
||||
import { getSiteModels, getSitePackages, Q } from '../../api';
|
||||
import { calcOfficialEquivList } from '../../utils/officialEquiv';
|
||||
import RotatingEquiv from '../../components/bits/RotatingEquiv';
|
||||
@@ -13,6 +13,7 @@ export default function DefaultHome() {
|
||||
const { t } = useTranslation();
|
||||
const { user } = useAuth();
|
||||
const { site } = useSite();
|
||||
const { symbol, rate } = useCurrency();
|
||||
const [models, setModels] = useState([]);
|
||||
const [packages, setPackages] = useState([]);
|
||||
|
||||
@@ -171,9 +172,9 @@ export default function DefaultHome() {
|
||||
<h3 className="text-base font-semibold text-white">{pkg.name}</h3>
|
||||
{pkg.description && <p className="text-sm text-neutral-500 mt-1">{pkg.description}</p>}
|
||||
<div className="mt-auto pt-6">
|
||||
<span className="text-3xl font-bold text-white">${pkg.price}</span>
|
||||
<span className="text-3xl font-bold text-white">{symbol}{(Number(pkg.price) * rate).toFixed(2)}</span>
|
||||
{pkg.original_price > pkg.price && (
|
||||
<span className="text-sm text-neutral-600 line-through ml-2">${pkg.original_price}</span>
|
||||
<span className="text-sm text-neutral-600 line-through ml-2">{symbol}{(Number(pkg.original_price) * rate).toFixed(2)}</span>
|
||||
)}
|
||||
{pkg.duration > 0 && <p className="text-xs text-neutral-600 mt-1">{t('home.days', { count: pkg.duration })}</p>}
|
||||
</div>
|
||||
|
||||
@@ -2,7 +2,7 @@ import React, { useState, useEffect } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useAuth } from '../../context/AuthContext';
|
||||
import { useSite } from '../../context/SiteContext';
|
||||
import { useSite, useCurrency } from '../../context/SiteContext';
|
||||
import { getSiteModels, getSitePackages, Q } from '../../api';
|
||||
import { calcOfficialEquivList } from '../../utils/officialEquiv';
|
||||
import RotatingEquiv from '../../components/bits/RotatingEquiv';
|
||||
@@ -13,6 +13,7 @@ export default function MinimalHome() {
|
||||
const { t } = useTranslation();
|
||||
const { user } = useAuth();
|
||||
const { site } = useSite();
|
||||
const { symbol, rate } = useCurrency();
|
||||
const [models, setModels] = useState([]);
|
||||
const [packages, setPackages] = useState([]);
|
||||
|
||||
@@ -154,9 +155,9 @@ export default function MinimalHome() {
|
||||
<h3 className="text-base font-semibold text-white">{pkg.name}</h3>
|
||||
{pkg.description && <p className="text-sm text-neutral-500 mt-1">{pkg.description}</p>}
|
||||
<div className="mt-auto pt-6">
|
||||
<span className="text-3xl font-bold text-white">${pkg.price}</span>
|
||||
<span className="text-3xl font-bold text-white">{symbol}{(Number(pkg.price) * rate).toFixed(2)}</span>
|
||||
{pkg.original_price > pkg.price && (
|
||||
<span className="text-sm text-neutral-600 line-through ml-2">${pkg.original_price}</span>
|
||||
<span className="text-sm text-neutral-600 line-through ml-2">{symbol}{(Number(pkg.original_price) * rate).toFixed(2)}</span>
|
||||
)}
|
||||
{pkg.duration > 0 && <p className="text-xs text-neutral-600 mt-1">{t('home.days', { count: pkg.duration })}</p>}
|
||||
</div>
|
||||
|
||||
@@ -2,7 +2,7 @@ import React, { useState, useEffect } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useAuth } from '../../context/AuthContext';
|
||||
import { useSite } from '../../context/SiteContext';
|
||||
import { useSite, useCurrency } from '../../context/SiteContext';
|
||||
import { getSiteModels, getSitePackages, Q } from '../../api';
|
||||
import { calcOfficialEquivList } from '../../utils/officialEquiv';
|
||||
import RotatingEquiv from '../../components/bits/RotatingEquiv';
|
||||
@@ -13,6 +13,7 @@ export default function StarterHome() {
|
||||
const { t } = useTranslation();
|
||||
const { user } = useAuth();
|
||||
const { site } = useSite();
|
||||
const { symbol, rate } = useCurrency();
|
||||
const [models, setModels] = useState([]);
|
||||
const [packages, setPackages] = useState([]);
|
||||
|
||||
@@ -177,9 +178,9 @@ export default function StarterHome() {
|
||||
<h3 className="text-base font-semibold text-white">{pkg.name}</h3>
|
||||
{pkg.description && <p className="text-sm text-neutral-500 mt-1">{pkg.description}</p>}
|
||||
<div className="mt-auto pt-6">
|
||||
<span className="text-3xl font-bold text-white">${pkg.price}</span>
|
||||
<span className="text-3xl font-bold text-white">{symbol}{(Number(pkg.price) * rate).toFixed(2)}</span>
|
||||
{pkg.original_price > pkg.price && (
|
||||
<span className="text-sm text-neutral-600 line-through ml-2">${pkg.original_price}</span>
|
||||
<span className="text-sm text-neutral-600 line-through ml-2">{symbol}{(Number(pkg.original_price) * rate).toFixed(2)}</span>
|
||||
)}
|
||||
{pkg.duration > 0 && <p className="text-xs text-neutral-600 mt-1">{t('home.days', { count: pkg.duration })}</p>}
|
||||
</div>
|
||||
|
||||
Reference in new issue
Block a user