import { useMutation } from '@tanstack/react-query' import { CircleDollarSign, CreditCard, Landmark } from 'lucide-react' import { useRef } from 'react' import { useTranslation } from 'react-i18next' import { createDeposit } from '@/api' import { DataLoadingIndicator } from '@/components/ui/data-loading-indicator' import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from '@/components/ui/select' import { useTopupVm } from '@/hooks/use-topup-vm' import { notify } from '@/lib/notify' import { cn } from '@/lib/utils' import type { DepositCreateRequestDto, DepositTierItem } from '@/type' const PANEL_CLASS = 'rounded-md border border-[rgba(126,234,244,0.22)] bg-[linear-gradient(180deg,rgba(4,18,29,0.98),rgba(1,8,16,0.99))] shadow-[inset_0_1px_0_rgba(255,255,255,0.06),0_0_calc(var(--design-unit)*12)_rgba(44,210,230,0.08)]' const FILTER_BAR_CLASS = 'rounded-[calc(var(--design-unit)*7)] border border-[rgba(126,234,244,0.16)] bg-[linear-gradient(180deg,rgba(9,35,48,0.82),rgba(5,20,32,0.9))] p-design-7 shadow-[inset_0_1px_0_rgba(255,255,255,0.05)]' const FIELD_LABEL_CLASS = 'mb-design-3 flex items-center gap-design-4 text-design-9 font-semibold uppercase tracking-[0.07em] text-[#8FE7EF]' const SELECT_TRIGGER_CLASS = 'h-design-34 w-full rounded-[calc(var(--design-unit)*5)] border-[rgba(126,234,244,0.18)] bg-[rgba(2,15,26,0.78)] px-design-8 text-design-10 font-semibold text-[#E9FEFF] shadow-none focus-visible:border-[#7CE3E8] focus-visible:ring-[#7CE3E8]/25 data-placeholder:text-[#6FAAB2]' function formatNumber(value: number) { return new Intl.NumberFormat('en-US').format(value) } function getMethodIcon(gatewayCode: string) { if (gatewayCode === 'ONLINE_DEBIT') { return Landmark } if (gatewayCode === 'E_WALLET') { return CreditCard } return CircleDollarSign } function MobileTopup() { const { t } = useTranslation() const vm = useTopupVm() const createDepositInFlightRef = useRef(false) const pendingPayWindowRef = useRef(null) const createDepositMutation = useMutation({ mutationFn: (payload: DepositCreateRequestDto) => createDeposit(payload), }) const getPaymentMethodLabel = (method: (typeof vm.methods)[number]) => method.name.trim() || t(`gameDesktop.topup.flow.paymentMethods.${method.gatewayCode}`, { defaultValue: t('gameDesktop.topup.flow.methodTitle'), }) const handleCreateDeposit = async (tier: DepositTierItem) => { if (createDepositInFlightRef.current || createDepositMutation.isPending) { return } const payload = vm.getCreateDepositPayload(tier) if (!payload) { notify.error(t('commonUi.toast.configError')) return } createDepositInFlightRef.current = true const payWindow = window.open('', '_blank') if (!payWindow) { createDepositInFlightRef.current = false notify.error(t('gameDesktop.topup.tier.openPayUrlFailed')) return } payWindow.opener = null pendingPayWindowRef.current = payWindow try { const result = await createDepositMutation.mutateAsync(payload) const payUrl = result.pay_url.trim() if (!payUrl) { payWindow.close() notify.error(t('gameDesktop.topup.tier.missingPayUrl')) return } payWindow.location.replace(payUrl) notify.success(t('gameDesktop.topup.tier.createSuccess')) } catch (error) { payWindow.close() notify.error( error instanceof Error ? error.message : t('commonUi.toast.requestFailed'), ) } finally { createDepositInFlightRef.current = false if (pendingPayWindowRef.current === payWindow) { pendingPayWindowRef.current = null } } } return (
{vm.isLoading ? ( ) : vm.isError ? (
{t('gameDesktop.topup.tier.failed')}
) : (
{t('gameDesktop.topup.tier.title')}
{vm.selectedPayChannel?.name} {vm.selectedCurrencyCode ? ` / ${vm.selectedCurrencyCode}` : ''}
{vm.filteredTiers.length}
{vm.filteredTiers.length === 0 ? (
{t('gameDesktop.topup.tier.empty')}
) : (
{vm.filteredTiers.map((tier) => ( ))}
)}
)}
) } export default MobileTopup