import { useState, useEffect, useCallback, useMemo } from 'react' import { useTranslation } from 'react-i18next' import { getSelf } from '@/lib/api' import { useStatus } from '@/hooks/use-status' import { useSystemConfig } from '@/hooks/use-system-config' import { SectionPageLayout } from '@/components/layout' import { AffiliateRewardsCard } from './components/affiliate-rewards-card' import { BillingHistoryDialog } from './components/dialogs/billing-history-dialog' import { CreemConfirmDialog } from './components/dialogs/creem-confirm-dialog' import { PaymentConfirmDialog } from './components/dialogs/payment-confirm-dialog' import { TransferDialog } from './components/dialogs/transfer-dialog' import { RechargeFormCard } from './components/recharge-form-card' import { SubscriptionPlansCard } from './components/subscription-plans-card' import { WalletStatsCard } from './components/wallet-stats-card' import { DEFAULT_DISCOUNT_RATE } from './constants' import { useTopupInfo, usePayment, useAffiliate, useRedemption, useCreemPayment, useWaffoPayment, useWaffoPancakePayment, } from './hooks' import { getDefaultPaymentType, getMinTopupAmount, isWaffoPancakePayment, } from './lib' import type { UserWalletData, PaymentMethod, PresetAmount, CreemProduct, } from './types' interface WalletProps { initialShowHistory?: boolean } export function Wallet(props: WalletProps) { const { t } = useTranslation() const [user, setUser] = useState(null) const [userLoading, setUserLoading] = useState(true) const [topupAmount, setTopupAmount] = useState(0) const [selectedPreset, setSelectedPreset] = useState(null) const [selectedPaymentMethod, setSelectedPaymentMethod] = useState() const [paymentLoading, setPaymentLoading] = useState(null) const [confirmDialogOpen, setConfirmDialogOpen] = useState(false) const [transferDialogOpen, setTransferDialogOpen] = useState(false) const [billingDialogOpen, setBillingDialogOpen] = useState(false) const [redemptionCode, setRedemptionCode] = useState('') const [creemDialogOpen, setCreemDialogOpen] = useState(false) const [selectedCreemProduct, setSelectedCreemProduct] = useState(null) const { status } = useStatus() const { currency } = useSystemConfig() const { topupInfo, presetAmounts, loading: topupLoading } = useTopupInfo() // Calculate effective exchange rate - when display type is USD, use rate of 1 const effectiveUsdExchangeRate = useMemo(() => { return currency?.quotaDisplayType === 'USD' ? 1 : currency?.usdExchangeRate || 1 }, [currency?.quotaDisplayType, currency?.usdExchangeRate]) const { amount: paymentAmount, calculating, processing, calculatePaymentAmount, processPayment, } = usePayment() const { affiliateLink, loading: affiliateLoading, transferQuota, transferring, } = useAffiliate() const { redeeming, redeemCode } = useRedemption() const { processing: creemProcessing, processCreemPayment } = useCreemPayment() const { processWaffoPayment } = useWaffoPayment() const { processing: pancakeProcessing, processWaffoPancakePayment } = useWaffoPancakePayment() // Fetch and refresh user data const fetchUser = useCallback(async () => { try { setUserLoading(true) const response = await getSelf() if (response.success && response.data) { setUser(response.data as UserWalletData) } } catch (error) { // eslint-disable-next-line no-console console.error('Failed to fetch user data:', error) } finally { setUserLoading(false) } }, []) useEffect(() => { fetchUser() }, [fetchUser]) useEffect(() => { if (props.initialShowHistory) { setBillingDialogOpen(true) window.history.replaceState({}, '', window.location.pathname) } }, [props.initialShowHistory]) // Initialize topup amount when topup info is loaded useEffect(() => { if (topupInfo && topupAmount === 0) { const minTopup = getMinTopupAmount(topupInfo) setTopupAmount(minTopup) // Calculate initial payment amount with default payment type const defaultPaymentType = getDefaultPaymentType(topupInfo) calculatePaymentAmount(minTopup, defaultPaymentType) } }, [topupInfo, topupAmount, calculatePaymentAmount]) // Get current payment type (selected or default) const getCurrentPaymentType = useCallback(() => { return selectedPaymentMethod?.type || getDefaultPaymentType(topupInfo) }, [selectedPaymentMethod, topupInfo]) // Handle preset selection const handleSelectPreset = (preset: PresetAmount) => { setTopupAmount(preset.value) setSelectedPreset(preset.value) calculatePaymentAmount(preset.value, getCurrentPaymentType()) } // Handle topup amount change const handleTopupAmountChange = (amount: number) => { setTopupAmount(amount) setSelectedPreset(null) calculatePaymentAmount(amount, getCurrentPaymentType()) } // Handle payment method selection const handlePaymentMethodSelect = async (method: PaymentMethod) => { setSelectedPaymentMethod(method) setPaymentLoading(method.type) try { // Validate minimum topup const minTopup = getMinTopupAmount(topupInfo) if (topupAmount < minTopup) { return } // Calculate payment amount and show confirmation dialog await calculatePaymentAmount(topupAmount, method.type) setConfirmDialogOpen(true) } finally { setPaymentLoading(null) } } // Handle payment confirmation const handlePaymentConfirm = async () => { if (!selectedPaymentMethod) return const isPancake = isWaffoPancakePayment(selectedPaymentMethod.type) const success = isPancake ? await processWaffoPancakePayment(topupAmount) : await processPayment(topupAmount, selectedPaymentMethod.type) if (success) { setConfirmDialogOpen(false) await fetchUser() } } // Handle redemption const handleRedeem = async () => { if (!redemptionCode) return const success = await redeemCode(redemptionCode) if (success) { setRedemptionCode('') await fetchUser() } } // Handle transfer const handleTransfer = async (amount: number) => { const success = await transferQuota(amount) if (success) { await fetchUser() } return success } // Handle Creem product selection const handleCreemProductSelect = (product: CreemProduct) => { setSelectedCreemProduct(product) setCreemDialogOpen(true) } // Handle Creem payment confirmation const handleCreemConfirm = async () => { if (!selectedCreemProduct) return const success = await processCreemPayment(selectedCreemProduct.productId) if (success) { setCreemDialogOpen(false) setSelectedCreemProduct(null) await fetchUser() } } const handleWaffoMethodSelect = async (_method: unknown, index: number) => { const loadingKey = `waffo-${index}` setPaymentLoading(loadingKey) try { await processWaffoPayment(topupAmount, index) } finally { setPaymentLoading(null) } } // Get discount rate for current topup amount const getDiscountRate = useCallback(() => { return topupInfo?.discount?.[topupAmount] || DEFAULT_DISCOUNT_RATE }, [topupInfo, topupAmount]) return ( <> {t('Wallet')} {t('Manage your balance and payment methods')}
{/* Left Column - Stats & Recharge */}
setBillingDialogOpen(true)} creemProducts={topupInfo?.creem_products} enableCreemTopup={topupInfo?.enable_creem_topup} onCreemProductSelect={handleCreemProductSelect} enableWaffoTopup={topupInfo?.enable_waffo_topup} waffoPayMethods={topupInfo?.waffo_pay_methods} waffoMinTopup={topupInfo?.waffo_min_topup} onWaffoMethodSelect={handleWaffoMethodSelect} enableWaffoPancakeTopup={topupInfo?.enable_waffo_pancake_topup} />
{/* Right Column - Affiliate & Subscriptions */}
setTransferDialogOpen(true)} loading={affiliateLoading} />
{/* Subscription Plans */}
) }