- 将类型定义从各个模块统一到 type 文件中进行管理 - 移除 auth-session 中不再使用的 AuthSessionInput 和 AuthUser 类型导入 - 移除 game store 中多余的类型导入如 BetSelection、StartAutoHostingInput 等 - 将 i18n 模块中的 AppLanguage 类型改为从 type 文件导入 - 移除 mobile-header 中未使用的 MessageBroadcast 组件导入 - 统一各组件中的类型引用路径,全部指向 type 文件 - 修复 withdraw 组件中 currencies 映射的类型注解问题 - 更新 modal-store 中移除未使用的 ModalKey 类型导入
642 lines
23 KiB
TypeScript
642 lines
23 KiB
TypeScript
import { Minus, Plus } from 'lucide-react'
|
|
import { type ReactNode, useState } from 'react'
|
|
import { useTranslation } from 'react-i18next'
|
|
import lengthBlueBtn from '@/assets/system/length-blue-btn.webp'
|
|
import lengthGreenBtn from '@/assets/system/length-green-btn.webp'
|
|
import { SmartBackground } from '@/components/smart-background.tsx'
|
|
import { Input } from '@/components/ui/input.tsx'
|
|
import {
|
|
Select,
|
|
SelectContent,
|
|
SelectItem,
|
|
SelectTrigger,
|
|
SelectValue,
|
|
} from '@/components/ui/select.tsx'
|
|
import { useWithdrawSubmit } from '@/hooks/use-withdraw-submit'
|
|
import { useWithdrawVm } from '@/hooks/use-withdraw-vm'
|
|
import { cn } from '@/lib/utils'
|
|
import { useModalStore } from '@/store'
|
|
import type { FinanceCurrencyConfig } from '@/type'
|
|
|
|
const PANEL_CLASS =
|
|
'rounded-md border border-[rgba(110,229,243,0.24)] bg-[linear-gradient(180deg,rgba(7,30,43,0.9),rgba(3,15,26,0.94))] shadow-[inset_0_0_calc(var(--design-unit)*10)_rgba(88,225,238,0.08)]'
|
|
|
|
function formatNumber(value: number) {
|
|
return new Intl.NumberFormat('en-US').format(value)
|
|
}
|
|
|
|
function getPaymentGlyph(code: string, name: string) {
|
|
if (code.toLowerCase().includes('alipay')) {
|
|
return '支'
|
|
}
|
|
|
|
return name.trim().slice(0, 1).toUpperCase() || code.slice(0, 1).toUpperCase()
|
|
}
|
|
|
|
function WithdrawField({
|
|
label,
|
|
children,
|
|
}: {
|
|
label: string
|
|
children: ReactNode
|
|
}) {
|
|
return (
|
|
<div className="flex flex-col gap-design-3">
|
|
<div className="text-design-10 font-medium uppercase leading-none text-[#6FD4DA]">
|
|
{label}
|
|
</div>
|
|
<div className="min-w-0">{children}</div>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
function AmountShell({
|
|
amount,
|
|
availableBalanceText,
|
|
onAmountChange,
|
|
onMinus,
|
|
onPlus,
|
|
}: {
|
|
amount: number
|
|
availableBalanceText: string
|
|
onAmountChange: (value: number) => void
|
|
onMinus: () => void
|
|
onPlus: () => void
|
|
}) {
|
|
function handleInputChange(value: string) {
|
|
const nextValue = Number(value.replace(/[^\d]/g, ''))
|
|
|
|
onAmountChange(Number.isFinite(nextValue) ? nextValue : 0)
|
|
}
|
|
|
|
return (
|
|
<div className="flex flex-col gap-design-2">
|
|
<div className="flex h-design-34 items-center gap-design-6 rounded-[calc(var(--design-unit)*5)] border border-[rgba(103,227,239,0.32)] bg-[linear-gradient(180deg,rgba(14,64,74,0.82),rgba(8,36,47,0.78))] px-design-6 shadow-[inset_0_0_calc(var(--design-unit)*10)_rgba(93,239,255,0.08)]">
|
|
<button
|
|
type="button"
|
|
onClick={onMinus}
|
|
className="flex h-design-24 w-design-24 shrink-0 items-center justify-center rounded-[calc(var(--design-unit)*4)] border border-[rgba(109,232,244,0.44)] bg-[rgba(37,115,123,0.32)] text-[#E1FEFF] transition hover:border-[rgba(170,247,255,0.82)] hover:bg-[rgba(66,146,151,0.35)]"
|
|
>
|
|
<Minus className="h-design-12 w-design-12" />
|
|
</button>
|
|
|
|
<input
|
|
value={amount === 0 ? '' : String(amount)}
|
|
onChange={(event) => handleInputChange(event.target.value)}
|
|
inputMode="numeric"
|
|
pattern="[0-9]*"
|
|
className="h-full min-w-0 flex-1 bg-transparent text-center text-design-16 font-medium text-[#A1EBF3] outline-none placeholder:text-[rgba(109,170,176,0.55)]"
|
|
placeholder="0"
|
|
/>
|
|
|
|
<button
|
|
type="button"
|
|
onClick={onPlus}
|
|
className="flex h-design-24 w-design-24 shrink-0 items-center justify-center rounded-[calc(var(--design-unit)*4)] border border-[rgba(109,232,244,0.44)] bg-[rgba(37,115,123,0.32)] text-[#E1FEFF] transition hover:border-[rgba(170,247,255,0.82)] hover:bg-[rgba(66,146,151,0.35)]"
|
|
>
|
|
<Plus className="h-design-12 w-design-12" />
|
|
</button>
|
|
</div>
|
|
|
|
<div className="pl-design-2 text-design-10 text-[#6DAAB0]">
|
|
{availableBalanceText}
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
function QuickAmountCard({
|
|
amount,
|
|
preview,
|
|
active,
|
|
onClick,
|
|
}: {
|
|
amount: number
|
|
preview: string
|
|
active: boolean
|
|
onClick: () => void
|
|
}) {
|
|
return (
|
|
<button
|
|
type="button"
|
|
onClick={onClick}
|
|
className={cn(
|
|
'group relative flex h-design-42 min-w-0 w-full cursor-pointer flex-col items-start justify-center overflow-hidden rounded-[calc(var(--design-unit)*6)] border px-design-6 text-left transition-[border-color,background-color,box-shadow,filter] duration-150',
|
|
active
|
|
? 'border-[#D18A43] bg-[linear-gradient(180deg,rgba(88,54,28,0.96),rgba(56,33,18,0.92))] shadow-[0_0_calc(var(--design-unit)*10)_rgba(209,138,67,0.2),inset_0_0_calc(var(--design-unit)*10)_rgba(255,217,120,0.08)]'
|
|
: 'border-[rgba(103,227,239,0.26)] bg-[linear-gradient(180deg,rgba(11,48,63,0.9),rgba(5,24,35,0.94))] hover:border-[rgba(170,247,255,0.62)] hover:brightness-110',
|
|
)}
|
|
>
|
|
<span
|
|
className={cn(
|
|
'absolute right-design-6 top-design-6 h-design-5 w-design-5 rounded-full transition',
|
|
active
|
|
? 'bg-[#FFD15E] shadow-[0_0_8px_rgba(255,209,94,0.8)]'
|
|
: 'bg-[rgba(122,220,230,0.26)]',
|
|
)}
|
|
/>
|
|
<div className="max-w-full truncate text-design-13 font-semibold leading-none text-[#FFE229]">
|
|
{amount}
|
|
</div>
|
|
<div
|
|
className={cn(
|
|
'max-w-full truncate pt-design-3 text-design-10 leading-none',
|
|
active ? 'text-[#FFDFA4]' : 'text-[#63AEB6]',
|
|
)}
|
|
>
|
|
{preview}
|
|
</div>
|
|
</button>
|
|
)
|
|
}
|
|
|
|
function PaymentCard({
|
|
active,
|
|
label,
|
|
glyph,
|
|
onClick,
|
|
}: {
|
|
active: boolean
|
|
label: string
|
|
glyph: string
|
|
onClick: () => void
|
|
}) {
|
|
return (
|
|
<button
|
|
type="button"
|
|
onClick={onClick}
|
|
className={cn(
|
|
'group relative flex h-design-42 min-w-0 cursor-pointer items-center gap-design-6 rounded-[calc(var(--design-unit)*6)] border px-design-6 text-left transition-[border-color,background-color,box-shadow,filter] duration-150',
|
|
active
|
|
? 'border-[#D18A43] bg-[linear-gradient(180deg,rgba(88,54,28,0.96),rgba(56,33,18,0.92))] shadow-[0_0_calc(var(--design-unit)*10)_rgba(209,138,67,0.18),inset_0_0_calc(var(--design-unit)*10)_rgba(255,217,120,0.08)]'
|
|
: 'border-[rgba(103,227,239,0.24)] bg-[linear-gradient(180deg,rgba(11,48,63,0.9),rgba(5,24,35,0.94))] hover:border-[rgba(170,247,255,0.62)] hover:brightness-110',
|
|
)}
|
|
>
|
|
<span
|
|
className={cn(
|
|
'absolute right-design-6 top-design-6 h-design-5 w-design-5 rounded-full transition',
|
|
active
|
|
? 'bg-[#FFD15E] shadow-[0_0_8px_rgba(255,209,94,0.8)]'
|
|
: 'bg-[rgba(122,220,230,0.26)]',
|
|
)}
|
|
/>
|
|
<div
|
|
className={cn(
|
|
'flex h-design-26 w-design-26 shrink-0 items-center justify-center rounded-[calc(var(--design-unit)*5)] border text-design-12 font-semibold leading-none transition-colors',
|
|
active
|
|
? 'border-[rgba(255,218,132,0.45)] bg-[rgba(255,211,113,0.16)] text-[#FFD97A]'
|
|
: 'border-[rgba(121,219,229,0.28)] bg-[rgba(10,39,52,0.7)] text-[#8DE4EA]',
|
|
)}
|
|
>
|
|
{glyph}
|
|
</div>
|
|
<div className="min-w-0 flex-1 pr-design-7">
|
|
<div
|
|
className={cn(
|
|
'truncate !text-design-12 font-medium leading-none',
|
|
active ? 'text-[#FFF1C9]' : 'text-[#D7FBFF]',
|
|
)}
|
|
>
|
|
{label}
|
|
</div>
|
|
<div
|
|
className={cn(
|
|
'pt-design-2 !text-design-10 uppercase leading-none tracking-[0.03em]',
|
|
active ? 'text-[#FFDFA4]' : 'text-[#63AEB6]',
|
|
)}
|
|
>
|
|
Channel
|
|
</div>
|
|
</div>
|
|
</button>
|
|
)
|
|
}
|
|
|
|
function InputShell({
|
|
value,
|
|
onChange,
|
|
placeholder,
|
|
error,
|
|
errorMessage,
|
|
uppercase = false,
|
|
type = 'text',
|
|
}: {
|
|
value: string
|
|
onChange: (value: string) => void
|
|
placeholder: string
|
|
error?: boolean
|
|
errorMessage?: string
|
|
uppercase?: boolean
|
|
type?: 'text' | 'email' | 'tel'
|
|
}) {
|
|
return (
|
|
<div className="flex w-full flex-col gap-design-3">
|
|
<Input
|
|
type={type}
|
|
value={value}
|
|
onChange={(event) => onChange(event.target.value)}
|
|
placeholder={placeholder}
|
|
className={cn(
|
|
'h-design-30 rounded-[calc(var(--design-unit)*5)] border px-design-8 text-design-12',
|
|
uppercase && 'uppercase',
|
|
error
|
|
? 'border-[#B93F44] bg-[rgba(34,13,16,0.78)] text-[#FCEEEE]'
|
|
: 'border-[rgba(103,227,239,0.24)] bg-[linear-gradient(180deg,rgba(10,47,57,0.84),rgba(5,23,32,0.92))] text-[#ACF1F6]',
|
|
)}
|
|
/>
|
|
{error && errorMessage ? (
|
|
<div className="pl-design-2 text-design-10 text-[#F44F4F]">
|
|
{errorMessage}
|
|
</div>
|
|
) : null}
|
|
</div>
|
|
)
|
|
}
|
|
|
|
function PreviewRow({
|
|
label,
|
|
value,
|
|
highlight = false,
|
|
}: {
|
|
label: string
|
|
value: ReactNode
|
|
highlight?: boolean
|
|
}) {
|
|
return (
|
|
<div className="flex border-b border-[rgba(89,209,223,0.2)] last:border-b-0">
|
|
<div className="flex w-[46%] shrink-0 items-center border-r border-[rgba(89,209,223,0.2)] px-design-6 py-design-7 text-design-10 font-medium uppercase leading-[1.15] text-[#7CE3E8]">
|
|
{label}
|
|
</div>
|
|
<div
|
|
className={cn(
|
|
'flex min-w-0 flex-1 items-center justify-end px-design-6 py-design-7 text-right text-design-10 text-[#E6FFFF]',
|
|
highlight && 'text-design-11 font-semibold text-[#6DFF83]',
|
|
)}
|
|
>
|
|
{value}
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
function MobileWithdraw() {
|
|
const { t } = useTranslation()
|
|
const vm = useWithdrawVm()
|
|
const withdrawSubmitMutation = useWithdrawSubmit()
|
|
const setModalOpen = useModalStore((state) => state.setModalOpen)
|
|
const [hasSubmitted, setHasSubmitted] = useState(false)
|
|
const [activeQuickAmountId, setActiveQuickAmountId] = useState<string | null>(
|
|
null,
|
|
)
|
|
|
|
function handleAmountChange(nextAmount: number) {
|
|
vm.setAmount(Math.max(0, nextAmount))
|
|
setActiveQuickAmountId(null)
|
|
}
|
|
|
|
function handleQuickAmountSelect(optionId: string, amount: number) {
|
|
vm.setAmount(Math.max(0, amount))
|
|
setActiveQuickAmountId(optionId)
|
|
}
|
|
|
|
function resetWithdrawFormState() {
|
|
setHasSubmitted(false)
|
|
setActiveQuickAmountId(null)
|
|
vm.resetForm()
|
|
}
|
|
|
|
function handleCloseWithdraw() {
|
|
resetWithdrawFormState()
|
|
setModalOpen('desktopWithdrawTopup', false)
|
|
}
|
|
|
|
function handleConfirmWithdraw() {
|
|
if (withdrawSubmitMutation.isPending) {
|
|
return
|
|
}
|
|
|
|
setHasSubmitted(true)
|
|
|
|
if (
|
|
vm.amountRequiredError ||
|
|
vm.amountExceedsBalance ||
|
|
vm.holderNameError ||
|
|
vm.bankAccountError ||
|
|
vm.paymentChannelCodeError ||
|
|
vm.bankCodeError ||
|
|
vm.receiverEmailError ||
|
|
vm.receiverPhoneError
|
|
) {
|
|
return
|
|
}
|
|
|
|
withdrawSubmitMutation.mutate(
|
|
{
|
|
bank_code: vm.bankCode,
|
|
channel_code: vm.paymentChannelCode,
|
|
idempotency_key: String(Date.now()),
|
|
receive_account: vm.bankAccount.trim(),
|
|
receiver_email: vm.receiverEmail.trim(),
|
|
receiver_mobile: vm.receiverPhone.trim(),
|
|
receiver_name: vm.holderName.trim(),
|
|
receive_type: 'bank',
|
|
withdraw_coin: vm.amount,
|
|
},
|
|
{
|
|
onSuccess: () => {
|
|
handleCloseWithdraw()
|
|
},
|
|
},
|
|
)
|
|
}
|
|
|
|
return (
|
|
<div className="flex h-full min-h-0 w-full px-design-6 pb-design-6 text-[#D9FFFF]">
|
|
<div
|
|
className={cn(
|
|
PANEL_CLASS,
|
|
'flex h-full min-h-0 w-full min-w-0 flex-col overflow-hidden',
|
|
)}
|
|
>
|
|
<div className="min-h-0 flex-1 overflow-y-auto px-design-8 py-design-7">
|
|
<div className="flex flex-col !gap-design-10">
|
|
<WithdrawField
|
|
label={t('gameDesktop.withdraw.fields.diamondAmount')}
|
|
>
|
|
<AmountShell
|
|
amount={vm.amount}
|
|
availableBalanceText={t(
|
|
'gameDesktop.withdraw.availableBalance',
|
|
{ amount: formatNumber(vm.availableBalance) },
|
|
)}
|
|
onAmountChange={handleAmountChange}
|
|
onMinus={() => handleAmountChange(vm.amount - 1)}
|
|
onPlus={() => handleAmountChange(vm.amount + 1)}
|
|
/>
|
|
{hasSubmitted && vm.amountRequiredError ? (
|
|
<div className="pl-design-2 text-design-10 text-[#F44F4F]">
|
|
{t('gameDesktop.withdraw.errors.amountRequired')}
|
|
</div>
|
|
) : null}
|
|
{hasSubmitted && vm.amountExceedsBalance ? (
|
|
<div className="pl-design-2 text-design-10 text-[#F44F4F]">
|
|
{t('gameDesktop.withdraw.errors.amountExceedsBalance')}
|
|
</div>
|
|
) : null}
|
|
</WithdrawField>
|
|
|
|
<div className="grid min-w-0 grid-cols-3 gap-design-5">
|
|
{vm.quickAmounts.map((option) => (
|
|
<QuickAmountCard
|
|
key={option.id}
|
|
amount={option.diamonds}
|
|
preview={option.preview}
|
|
active={option.id === activeQuickAmountId}
|
|
onClick={() =>
|
|
handleQuickAmountSelect(option.id, option.diamonds)
|
|
}
|
|
/>
|
|
))}
|
|
</div>
|
|
|
|
<WithdrawField
|
|
label={t('gameDesktop.withdraw.fields.currencyType')}
|
|
>
|
|
<Select
|
|
value={vm.currencyCode}
|
|
onValueChange={vm.setCurrencyCode}
|
|
>
|
|
<SelectTrigger
|
|
className="h-design-30 w-full rounded-[calc(var(--design-unit)*5)] border-[rgba(103,227,239,0.3)] bg-[linear-gradient(180deg,rgba(12,61,72,0.82),rgba(6,28,39,0.9))] px-design-8 text-left !text-design-12 text-[#A5EDF4] shadow-[inset_0_0_calc(var(--design-unit)*10)_rgba(94,237,255,0.08)] data-[size=default]:h-design-30 data-[placeholder]:text-[rgba(109,170,176,0.55)] [&_svg]:h-design-14 [&_svg]:w-design-14 [&_svg]:text-[#79DFEA]"
|
|
aria-label={t('gameDesktop.withdraw.currencySelection')}
|
|
>
|
|
<SelectValue
|
|
placeholder={t('gameDesktop.withdraw.selectCurrency')}
|
|
/>
|
|
</SelectTrigger>
|
|
<SelectContent>
|
|
{vm.config.currencies.map((option: FinanceCurrencyConfig) => (
|
|
<SelectItem key={option.code} value={option.code}>
|
|
{option.label}
|
|
</SelectItem>
|
|
))}
|
|
</SelectContent>
|
|
</Select>
|
|
</WithdrawField>
|
|
|
|
<WithdrawField
|
|
label={t('gameDesktop.withdraw.fields.paymentChannel')}
|
|
>
|
|
<div className="flex w-full flex-col gap-design-3">
|
|
{vm.sortedPayChannels.length > 0 ? (
|
|
<div className="grid grid-cols-2 gap-design-5">
|
|
{vm.sortedPayChannels.map((channel) => (
|
|
<PaymentCard
|
|
key={channel.code}
|
|
active={channel.code === vm.paymentChannelCode}
|
|
label={channel.name}
|
|
glyph={getPaymentGlyph(channel.code, channel.name)}
|
|
onClick={() => vm.setPaymentChannelCode(channel.code)}
|
|
/>
|
|
))}
|
|
</div>
|
|
) : (
|
|
<div className="flex min-h-design-38 items-center rounded-[calc(var(--design-unit)*6)] border border-[rgba(185,63,68,0.45)] bg-[rgba(34,13,16,0.6)] px-design-8 text-design-10 text-[#F4B1B1]">
|
|
{t('gameDesktop.withdraw.errors.paymentChannelUnavailable')}
|
|
</div>
|
|
)}
|
|
{hasSubmitted && vm.paymentChannelCodeError ? (
|
|
<div className="pl-design-2 text-design-10 text-[#F44F4F]">
|
|
{t('gameDesktop.withdraw.errors.paymentChannelRequired')}
|
|
</div>
|
|
) : null}
|
|
</div>
|
|
</WithdrawField>
|
|
|
|
<WithdrawField label={t('gameDesktop.withdraw.fields.bankCode')}>
|
|
<div className="flex w-full flex-col gap-design-3">
|
|
<Select
|
|
value={vm.bankCode}
|
|
onValueChange={vm.setBankCode}
|
|
disabled={vm.sortedBanks.length === 0}
|
|
>
|
|
<SelectTrigger
|
|
className={cn(
|
|
'h-design-30 w-full rounded-[calc(var(--design-unit)*5)] bg-[linear-gradient(180deg,rgba(12,61,72,0.82),rgba(6,28,39,0.9))] px-design-8 text-left !text-design-12 text-[#A5EDF4] shadow-[inset_0_0_calc(var(--design-unit)*10)_rgba(94,237,255,0.08)] data-[size=default]:h-design-30 data-[placeholder]:text-[rgba(109,170,176,0.55)] [&_svg]:h-design-14 [&_svg]:w-design-14 [&_svg]:text-[#79DFEA]',
|
|
hasSubmitted && vm.bankCodeError
|
|
? 'border-[#B93F44]'
|
|
: 'border-[rgba(103,227,239,0.3)]',
|
|
)}
|
|
aria-label={t('gameDesktop.withdraw.fields.bankCode')}
|
|
>
|
|
<SelectValue
|
|
placeholder={t(
|
|
'gameDesktop.withdraw.placeholders.bankCode',
|
|
)}
|
|
/>
|
|
</SelectTrigger>
|
|
<SelectContent>
|
|
{vm.sortedBanks.map((bank) => (
|
|
<SelectItem key={bank.code} value={bank.code}>
|
|
{bank.label}
|
|
</SelectItem>
|
|
))}
|
|
</SelectContent>
|
|
</Select>
|
|
{vm.sortedBanks.length === 0 ? (
|
|
<div className="pl-design-2 text-design-10 text-[#F4B1B1]">
|
|
{t('gameDesktop.withdraw.errors.bankCodeUnavailable')}
|
|
</div>
|
|
) : null}
|
|
{hasSubmitted && vm.bankCodeError ? (
|
|
<div className="pl-design-2 text-design-10 text-[#F44F4F]">
|
|
{t('gameDesktop.withdraw.errors.bankCodeRequired')}
|
|
</div>
|
|
) : null}
|
|
</div>
|
|
</WithdrawField>
|
|
|
|
<WithdrawField
|
|
label={t('gameDesktop.withdraw.fields.cardHolderName')}
|
|
>
|
|
<InputShell
|
|
value={vm.holderName}
|
|
onChange={vm.setHolderName}
|
|
placeholder={t(
|
|
'gameDesktop.withdraw.placeholders.cardHolderName',
|
|
)}
|
|
error={hasSubmitted && vm.holderNameError}
|
|
errorMessage={t(
|
|
'gameDesktop.withdraw.errors.cardHolderNameRequired',
|
|
)}
|
|
/>
|
|
</WithdrawField>
|
|
|
|
<WithdrawField
|
|
label={t('gameDesktop.withdraw.fields.bankAccountNumber')}
|
|
>
|
|
<InputShell
|
|
value={vm.bankAccount}
|
|
onChange={vm.setBankAccount}
|
|
placeholder={t(
|
|
'gameDesktop.withdraw.placeholders.bankAccountNumber',
|
|
)}
|
|
error={hasSubmitted && vm.bankAccountError}
|
|
errorMessage={t(
|
|
'gameDesktop.withdraw.errors.bankAccountRequired',
|
|
)}
|
|
/>
|
|
</WithdrawField>
|
|
|
|
<WithdrawField
|
|
label={t('gameDesktop.withdraw.fields.receiverEmail')}
|
|
>
|
|
<InputShell
|
|
value={vm.receiverEmail}
|
|
onChange={vm.setReceiverEmail}
|
|
placeholder={t(
|
|
'gameDesktop.withdraw.placeholders.receiverEmail',
|
|
)}
|
|
type="email"
|
|
error={hasSubmitted && vm.receiverEmailError}
|
|
errorMessage={t(
|
|
'gameDesktop.withdraw.errors.receiverEmailInvalid',
|
|
)}
|
|
/>
|
|
</WithdrawField>
|
|
|
|
<WithdrawField
|
|
label={t('gameDesktop.withdraw.fields.receiverPhone')}
|
|
>
|
|
<InputShell
|
|
value={vm.receiverPhone}
|
|
onChange={vm.setReceiverPhone}
|
|
placeholder={t(
|
|
'gameDesktop.withdraw.placeholders.receiverPhone',
|
|
)}
|
|
type="tel"
|
|
error={hasSubmitted && vm.receiverPhoneError}
|
|
errorMessage={t(
|
|
'gameDesktop.withdraw.errors.receiverPhoneInvalid',
|
|
)}
|
|
/>
|
|
</WithdrawField>
|
|
|
|
<div className="overflow-hidden rounded-[calc(var(--design-unit)*4)] border border-[rgba(89,209,223,0.22)] bg-[rgba(4,19,28,0.58)]">
|
|
<PreviewRow
|
|
label={t('gameDesktop.withdraw.preview.diamondAmount')}
|
|
value={formatNumber(vm.amount)}
|
|
/>
|
|
<PreviewRow
|
|
label={vm.selectedCurrencyPreview.exchangeRateLabel}
|
|
value={vm.selectedCurrencyPreview.exchangeRateValue}
|
|
/>
|
|
<PreviewRow
|
|
label={vm.selectedCurrencyPreview.convertibleLabel}
|
|
value={vm.selectedCurrencyPreview.convertibleValue}
|
|
highlight={true}
|
|
/>
|
|
<PreviewRow
|
|
label={t(
|
|
'gameDesktop.withdraw.preview.fixedExchangeDiamondAmount',
|
|
)}
|
|
value="0-0-0 0:0:0"
|
|
/>
|
|
</div>
|
|
|
|
<div className="rounded-[calc(var(--design-unit)*4)] border border-[rgba(240,175,66,0.2)] bg-[rgba(110,77,26,0.24)] px-design-8 py-design-6 text-design-10 leading-[1.3] text-[#F0B44A]">
|
|
{vm.withdrawCopy.rateHint}
|
|
</div>
|
|
|
|
<div className="flex flex-col gap-design-3 px-design-1 text-design-10 uppercase leading-[1.3] text-[#7AD8E0]">
|
|
<div>
|
|
{vm.withdrawCopy.processingLabel}:{' '}
|
|
<span className="text-[#77FF76]">
|
|
{vm.withdrawCopy.processingValue}
|
|
</span>
|
|
</div>
|
|
<div>
|
|
{vm.withdrawCopy.noticeLabel}:{' '}
|
|
<span className="text-red-700">{vm.withdrawCopy.feeNote}</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="flex shrink-0 items-center justify-between gap-design-6 border-t border-[rgba(89,209,223,0.22)] bg-[rgba(3,15,24,0.86)] px-design-8 py-design-5">
|
|
<SmartBackground
|
|
as="button"
|
|
type="button"
|
|
src={lengthGreenBtn}
|
|
size="100% 100%"
|
|
onClick={handleCloseWithdraw}
|
|
className="flex h-design-38 flex-1 cursor-pointer items-center justify-center pb-design-2 text-center !text-design-12 font-bold uppercase text-[#F0FFFF] transition hover:brightness-110 active:scale-[0.98]"
|
|
>
|
|
{t('gameDesktop.withdraw.cancel')}
|
|
</SmartBackground>
|
|
<SmartBackground
|
|
as="button"
|
|
type="button"
|
|
src={lengthBlueBtn}
|
|
size="100% 100%"
|
|
onClick={handleConfirmWithdraw}
|
|
disabled={withdrawSubmitMutation.isPending}
|
|
className={cn(
|
|
'flex h-design-38 flex-1 items-center justify-center whitespace-nowrap pb-design-2 text-center !text-design-12 font-bold uppercase leading-[1.05] text-[#F0FFFF] transition',
|
|
withdrawSubmitMutation.isPending
|
|
? 'cursor-not-allowed opacity-70'
|
|
: 'cursor-pointer hover:brightness-110 active:scale-[0.98]',
|
|
)}
|
|
>
|
|
{withdrawSubmitMutation.isPending
|
|
? t('commonUi.action.submitting')
|
|
: `${t('gameDesktop.withdraw.confirm')}`}
|
|
</SmartBackground>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
export default MobileWithdraw
|