+
{t('gameDesktop.withdraw.preview.title')}
@@ -684,6 +690,10 @@ function DesktopWithdraw() {
value={vm.selectedCurrencyPreview.convertibleValue}
highlight={true}
/>
+
{withdrawSubmitMutation.isPending
- ? t('commonUi.action.submitting')
+ ? t('commonUi.actions.submitting')
: `${t('gameDesktop.withdraw.confirm')}${t('gameDesktop.withdraw.withdrawal')}`}
diff --git a/src/features/game/components/mobile/mobile-withdraw.tsx b/src/features/game/components/mobile/mobile-withdraw.tsx
index 60e4646..a60ebca 100644
--- a/src/features/game/components/mobile/mobile-withdraw.tsx
+++ b/src/features/game/components/mobile/mobile-withdraw.tsx
@@ -122,13 +122,15 @@ function AmountShell({
}
function QuickAmountCard({
- amount,
- preview,
+ amountLabel,
+ diamondLabel,
+ feeLabel,
active,
onClick,
}: {
- amount: number
- preview: string
+ amountLabel: string
+ diamondLabel: string
+ feeLabel: string
active: boolean
onClick: () => void
}) {
@@ -137,7 +139,7 @@ function QuickAmountCard({
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',
+ 'group relative flex h-design-58 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',
@@ -151,16 +153,19 @@ function QuickAmountCard({
: 'bg-[rgba(122,220,230,0.26)]',
)}
/>
-
- {amount}
+
+ {amountLabel}
- {preview}
+ {diamondLabel}
+
+
+ {feeLabel}
)
@@ -490,8 +495,9 @@ function MobileWithdraw() {
{vm.quickAmounts.map((option) => (
handleQuickAmountSelect(option.id, option.diamonds)
@@ -654,6 +660,10 @@ function MobileWithdraw() {
value={vm.selectedCurrencyPreview.convertibleValue}
highlight={true}
/>
+
{withdrawSubmitMutation.isPending
- ? t('commonUi.action.submitting')
+ ? t('commonUi.actions.submitting')
: `${t('gameDesktop.withdraw.confirm')}`}
diff --git a/src/hooks/use-withdraw-vm.ts b/src/hooks/use-withdraw-vm.ts
index 5a5e862..f39dfe7 100644
--- a/src/hooks/use-withdraw-vm.ts
+++ b/src/hooks/use-withdraw-vm.ts
@@ -20,6 +20,42 @@ function formatNumber(locale: string, value: number) {
return new Intl.NumberFormat(locale).format(value)
}
+function formatConfiguredAmount(locale: string, value: string) {
+ const normalizedValue = value.trim()
+ const numericValue = Number(normalizedValue)
+
+ if (!Number.isFinite(numericValue)) {
+ return normalizedValue || '0'
+ }
+
+ const fractionDigits = Math.min(
+ 6,
+ normalizedValue.includes('.')
+ ? (normalizedValue.split('.')[1]?.length ?? 0)
+ : 0,
+ )
+
+ return new Intl.NumberFormat(locale, {
+ maximumFractionDigits: fractionDigits,
+ minimumFractionDigits: fractionDigits,
+ }).format(numericValue)
+}
+
+function calculateNetWithdrawalAmount(
+ grossAmount: number,
+ handlingFee: string,
+) {
+ const parsedHandlingFee = Number(handlingFee)
+
+ if (!Number.isFinite(parsedHandlingFee)) {
+ return grossAmount
+ }
+
+ const handlingFeeRate = Math.min(100, Math.max(0, parsedHandlingFee)) / 100
+
+ return grossAmount * (1 - handlingFeeRate)
+}
+
function getInitialWithdrawAmount(bounds: WithdrawDiamondBounds | null) {
return bounds?.minimumDiamonds ?? 0
}
@@ -209,6 +245,7 @@ export function useWithdrawVm() {
const selectedPaymentChannel =
sortedPayChannels.find((channel) => channel.code === paymentChannelCode) ??
null
+ const selectedHandlingFee = selectedPaymentChannel?.handlingFee ?? '0.00'
const availablePaymentMethods = useMemo(
() => selectedPaymentChannel?.methods ?? [],
[selectedPaymentChannel],
@@ -223,6 +260,9 @@ export function useWithdrawVm() {
const selectedCurrency =
availableCurrencies.find((item) => item.code === currencyCode) ?? null
const selectedCurrencyCode = selectedCurrency?.code ?? ''
+ const selectedHandlingFeeValue = selectedPaymentChannel
+ ? `${formatConfiguredAmount(locale, selectedHandlingFee)}%`
+ : '--'
const selectedRate = selectedCurrency?.withdrawCoinsPerFiatValue ?? 0
const selectedExchangeRate = selectedCurrency
? getCurrencyExchangeRate(config, selectedCurrency.code, selectedRate || 1)
@@ -372,12 +412,21 @@ export function useWithdrawVm() {
}
return getQuickWithdrawAmounts(withdrawDiamondBounds).map((diamonds) => ({
- diamonds,
- id: `quick-${paymentChannelCode}-${paymentType}-${selectedCurrency.code}-${diamonds}`,
- preview: `${selectedCurrency.code} ${formatNumber(
+ amountLabel: `${selectedCurrency.code} ${formatNumber(
locale,
- diamonds * selectedExchangeRate,
+ calculateNetWithdrawalAmount(
+ diamonds * selectedExchangeRate,
+ selectedHandlingFee,
+ ),
)}`,
+ diamondLabel: t('gameDesktop.withdraw.preview.quickDiamondAmount', {
+ amount: formatNumber(locale, diamonds),
+ }),
+ diamonds,
+ feeLabel: t('gameDesktop.withdraw.preview.quickHandlingFee', {
+ fee: selectedHandlingFeeValue,
+ }),
+ id: `quick-${paymentChannelCode}-${paymentType}-${selectedCurrency.code}-${diamonds}`,
}))
}, [
locale,
@@ -385,6 +434,9 @@ export function useWithdrawVm() {
paymentType,
selectedCurrency,
selectedExchangeRate,
+ selectedHandlingFee,
+ selectedHandlingFeeValue,
+ t,
withdrawDiamondBounds,
])
@@ -448,11 +500,24 @@ export function useWithdrawVm() {
selectedCurrency && selectedExchangeRate > 0
? `${formatNumber(
locale,
- amount * selectedExchangeRate,
+ calculateNetWithdrawalAmount(
+ amount * selectedExchangeRate,
+ selectedHandlingFee,
+ ),
)} ${selectedCurrency.code}`
: '--',
+ handlingFeeLabel: t('gameDesktop.withdraw.preview.handlingFee'),
+ handlingFeeValue: selectedHandlingFeeValue,
}
- }, [amount, locale, selectedCurrency, selectedExchangeRate, t])
+ }, [
+ amount,
+ locale,
+ selectedCurrency,
+ selectedExchangeRate,
+ selectedHandlingFee,
+ selectedHandlingFeeValue,
+ t,
+ ])
return {
amount,
diff --git a/src/locales/en-US.ts b/src/locales/en-US.ts
index 75968df..70910b8 100644
--- a/src/locales/en-US.ts
+++ b/src/locales/en-US.ts
@@ -470,6 +470,9 @@ export default {
},
},
commonUi: {
+ actions: {
+ submitting: TEXT_SUBMITTING,
+ },
dialog: {
close: 'Close alert',
confirm: 'OK',
@@ -839,6 +842,9 @@ export default {
exchangeRate: 'Exchange Rate ({{currency}})',
exchangeRateValue: '{{coins}} {{platformCoinLabel}} = 1 {{currency}}',
convertible: 'Convertible {{currency}}',
+ handlingFee: 'Handling Fee',
+ quickDiamondAmount: '{{amount}} diamonds',
+ quickHandlingFee: 'Fee deducted: {{fee}}',
fixedExchangeDiamondAmount: 'Fixed Exchange Diamond Amount',
},
},
diff --git a/src/locales/id-ID.ts b/src/locales/id-ID.ts
index 1ee4fa9..f099eda 100644
--- a/src/locales/id-ID.ts
+++ b/src/locales/id-ID.ts
@@ -469,6 +469,9 @@ export default {
},
},
commonUi: {
+ actions: {
+ submitting: TEXT_SUBMITTING,
+ },
dialog: {
close: 'Tutup notifikasi',
confirm: 'OK',
@@ -841,6 +844,9 @@ export default {
exchangeRate: 'Rasio Penukaran ({{currency}})',
exchangeRateValue: '{{coins}} {{platformCoinLabel}} = 1 {{currency}}',
convertible: 'Bisa Ditukar {{currency}}',
+ handlingFee: 'Biaya Penanganan',
+ quickDiamondAmount: '{{amount}} diamond',
+ quickHandlingFee: 'Biaya dipotong: {{fee}}',
fixedExchangeDiamondAmount: 'Jumlah Berlian Tukar Tetap',
},
},
diff --git a/src/locales/ms-MY.ts b/src/locales/ms-MY.ts
index 8c61ca0..fd7799a 100644
--- a/src/locales/ms-MY.ts
+++ b/src/locales/ms-MY.ts
@@ -472,6 +472,9 @@ export default {
},
},
commonUi: {
+ actions: {
+ submitting: TEXT_SUBMITTING,
+ },
dialog: {
close: 'Tutup notifikasi',
confirm: 'OK',
@@ -845,6 +848,9 @@ export default {
exchangeRate: 'Kadar Pertukaran ({{currency}})',
exchangeRateValue: '{{coins}} {{platformCoinLabel}} = 1 {{currency}}',
convertible: 'Boleh Tukar {{currency}}',
+ handlingFee: 'Yuran Pengendalian',
+ quickDiamondAmount: '{{amount}} berlian',
+ quickHandlingFee: 'Yuran ditolak: {{fee}}',
fixedExchangeDiamondAmount: 'Jumlah Berlian Tukaran Tetap',
},
},
diff --git a/src/locales/zh-CN.ts b/src/locales/zh-CN.ts
index 548f45a..4b6cb63 100644
--- a/src/locales/zh-CN.ts
+++ b/src/locales/zh-CN.ts
@@ -453,6 +453,9 @@ export default {
},
},
commonUi: {
+ actions: {
+ submitting: TEXT_SUBMITTING,
+ },
dialog: {
close: '关闭提示',
confirm: '知道了',
@@ -809,6 +812,9 @@ export default {
exchangeRate: '兑换比例 ({{currency}})',
exchangeRateValue: '{{coins}} {{platformCoinLabel}} = 1 {{currency}}',
convertible: '可兑换{{currency}}',
+ handlingFee: '手续费',
+ quickDiamondAmount: '{{amount}} 钻石',
+ quickHandlingFee: '扣除手续费 {{fee}}',
fixedExchangeDiamondAmount: '固定兑换钻石金额',
},
},
diff --git a/src/modal/desktop/desktop-withdraw-topup-modal.tsx b/src/modal/desktop/desktop-withdraw-topup-modal.tsx
index 9dcc161..bc01f22 100644
--- a/src/modal/desktop/desktop-withdraw-topup-modal.tsx
+++ b/src/modal/desktop/desktop-withdraw-topup-modal.tsx
@@ -27,7 +27,7 @@ function DesktopWithdrawTopupModal() {
}
isNormalBg={true}
titleAlign="left"
- className={'w-design-1200 h-design-700'}
+ className={'h-design-700 w-design-1320'}
>
{type === 'withdraw' ? : }
diff --git a/src/type/api.type.ts b/src/type/api.type.ts
index fae6207..df42a6e 100644
--- a/src/type/api.type.ts
+++ b/src/type/api.type.ts
@@ -30,6 +30,7 @@ export interface FinancePayChannelDto {
currency_codes?: string[]
deposit_banks?: FinanceWithdrawBankDto[]
fee_note?: string
+ handling_fee?: string
methods?: FinanceDepositMethodDto[]
min_bank?: string
min_ewallet?: string
@@ -171,6 +172,7 @@ export interface FinancePayChannel {
currencyCodes: string[]
depositBanks: FinanceWithdrawBank[]
feeNote: string
+ handlingFee: string
methods: FinanceDepositMethod[]
minBank: string
minEwallet: string