import React, { useState, useEffect, useCallback } from 'react'; import { Link } from 'react-router-dom'; import { useTranslation } from 'react-i18next'; import { useAuth } from '../context/AuthContext'; import { getUserUsage, redeemCode, getAffCode, transferAffQuota, getAffEarnings, 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); // Invitation / Aff const [affLink, setAffLink] = useState(''); const [affEarnings, setAffEarnings] = useState([]); const [showAffEarnings, setShowAffEarnings] = useState(false); const [affEarningsLoading, setAffEarningsLoading] = useState(false); const [transferAmount, setTransferAmount] = useState(''); const [transferring, setTransferring] = useState(false); const loadData = useCallback(async () => { try { const [usageRes, affRes] = await Promise.all([ getUserUsage(), getAffCode().catch(() => null), ]); if (usageRes.data.success) setUsage(usageRes.data.data); if (affRes?.data?.success && affRes.data.data) { setAffLink(`${window.location.origin}/register?aff=${affRes.data.data}`); } } catch (e) { /* interceptor */ } }, []); useEffect(() => { loadData(); }, [loadData]); const handleRedeem = async (e) => { e.preventDefault(); if (!redeemInput.trim()) return; setRedeeming(true); try { const res = await redeemCode(redeemInput.trim()); if (res.data.success) { toast.success(t('dashboard.redeemSuccess')); setRedeemInput(''); await Promise.all([loadData(), refreshUser()]); } } catch (err) { /* interceptor */ } setRedeeming(false); }; const loadAffEarnings = async () => { setAffEarningsLoading(true); try { const res = await getAffEarnings({ page: 1, page_size: 20 }); if (res.data.success && res.data.data) { setAffEarnings(res.data.data); } } catch (e) { /* interceptor */ } setAffEarningsLoading(false); }; const handleCopyAffLink = () => { if (!affLink) return; navigator.clipboard.writeText(affLink).then(() => { toast.success(t('topup.copied')); }).catch(() => { toast.error('Copy failed'); }); }; const handleTransfer = async () => { const val = parseInt(transferAmount); if (!val || val <= 0) { toast.error(t('topup.enterAmount')); return; } setTransferring(true); try { const res = await transferAffQuota({ quota: val }); if (res.data.success) { toast.success(res.data.message || t('topup.transferSuccess')); setTransferAmount(''); await Promise.all([loadData(), refreshUser()]); } } catch (e) { /* interceptor */ } setTransferring(false); }; 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 * rate; return (
{/* Welcome */}

{t('dashboard.welcome')} {user?.display_name || user?.username || 'User'}

{t('dashboard.manageDesc')}

{/* Stats Cards */}

{t('dashboard.balance')}

{symbol}

{t('dashboard.quotaUnits', { count: quota.toLocaleString() })}

{t('dashboard.used')}

{symbol}

{t('dashboard.quotaUnits', { count: usedQuota.toLocaleString() })}

{t('dashboard.totalRequests')}

{/* Quick Actions */}
{/* Redeem Code */}

{t('dashboard.redeemCode')}

setRedeemInput(e.target.value)} className="input flex-1" placeholder={t('dashboard.enterCode')} />
{/* Quick Links */}

{t('dashboard.quickLinks')}

{t('dashboard.apiKeys')}

{t('dashboard.manageKeys')}

{t('nav.topup')}

{t('dashboard.topupDesc')}

{t('dashboard.packages')}

{t('dashboard.viewPlans')}

{t('dashboard.pricing')}

{t('dashboard.modelPrices')}

{t('dashboard.logs')}

{t('dashboard.viewLogs')}

{/* Invitation / Affiliate */} {affLink && (

{t('topup.inviteTitle')}

{t('topup.inviteSubtitle')}

{/* Stats */}

{t('topup.affAvailable')}

{symbol}{((user?.aff_quota || 0) / Q * rate).toFixed(2)}

{t('topup.affTotal')}

{symbol}{((user?.aff_history_quota || 0) / Q * rate).toFixed(2)}

{t('topup.affCount')}

{user?.aff_count || 0}

{/* Invitation Link */}
{/* Transfer to balance */} {(user?.aff_quota || 0) > 0 && (
setTransferAmount(e.target.value)} placeholder={t('topup.transferPlaceholder')} className="input flex-1 text-sm" min={1} />
)} {/* Earnings Details */}
{showAffEarnings && (
{affEarningsLoading ? (
) : affEarnings.length === 0 ? (

{t('topup.noEarnings')}

) : (
{affEarnings.map((item, i) => (

{item.model_name}

{new Date(item.created_time * 1000).toLocaleString()} ยท {(item.commission_rate * 100).toFixed(1)}%

+{symbol}{(item.commission_quota / Q * rate).toFixed(4)}
))}
)}
)}
)}
); }