diff --git a/src/components/InsufficientBalancePrompt.tsx b/src/components/InsufficientBalancePrompt.tsx new file mode 100644 index 0000000..243f508 --- /dev/null +++ b/src/components/InsufficientBalancePrompt.tsx @@ -0,0 +1,200 @@ +import { useState } from 'react' +import { useTranslation } from 'react-i18next' +import { useQuery } from '@tanstack/react-query' +import { balanceApi } from '../api/balance' +import { useCurrency } from '../hooks/useCurrency' +import TopUpModal from './TopUpModal' +import type { PaymentMethod } from '../types' + +interface InsufficientBalancePromptProps { + /** Amount missing in kopeks */ + missingAmountKopeks: number + /** Optional custom message */ + message?: string + /** Compact mode for inline use */ + compact?: boolean + /** Additional className */ + className?: string +} + +export default function InsufficientBalancePrompt({ + missingAmountKopeks, + message, + compact = false, + className = '', +}: InsufficientBalancePromptProps) { + const { t } = useTranslation() + const { formatAmount, currencySymbol } = useCurrency() + const [showMethodSelect, setShowMethodSelect] = useState(false) + const [selectedMethod, setSelectedMethod] = useState(null) + + const { data: paymentMethods } = useQuery({ + queryKey: ['payment-methods'], + queryFn: balanceApi.getPaymentMethods, + enabled: showMethodSelect, + }) + + const missingRubles = missingAmountKopeks / 100 + const displayAmount = formatAmount(missingRubles) + + const handleMethodSelect = (method: PaymentMethod) => { + setSelectedMethod(method) + setShowMethodSelect(false) + } + + if (compact) { + return ( + <> +
+
+ + + + + {message || t('balance.insufficientFunds')}: {displayAmount} {currencySymbol} + +
+ +
+ + {showMethodSelect && ( + setShowMethodSelect(false)} + /> + )} + + {selectedMethod && ( + setSelectedMethod(null)} + /> + )} + + ) + } + + return ( + <> +
+
+
+ + + +
+
+
+ {t('balance.insufficientFunds')} +
+
+ {message || t('balance.topUpToComplete')} +
+
+
+ {t('balance.missing')}: {displayAmount} {currencySymbol} +
+
+
+
+ +
+ + {showMethodSelect && ( + setShowMethodSelect(false)} + /> + )} + + {selectedMethod && ( + setSelectedMethod(null)} + /> + )} + + ) +} + +interface PaymentMethodModalProps { + paymentMethods: PaymentMethod[] | undefined + onSelect: (method: PaymentMethod) => void + onClose: () => void +} + +function PaymentMethodModal({ paymentMethods, onSelect, onClose }: PaymentMethodModalProps) { + const { t } = useTranslation() + const { formatAmount, currencySymbol } = useCurrency() + + return ( +
+
+
+

{t('balance.selectPaymentMethod')}

+ +
+ + {!paymentMethods ? ( +
+
+
+ ) : paymentMethods.length === 0 ? ( +
+ {t('balance.noPaymentMethods')} +
+ ) : ( +
+ {paymentMethods.map((method) => { + const methodKey = method.id.toLowerCase().replace(/-/g, '_') + const translatedName = t(`balance.paymentMethods.${methodKey}.name`, { defaultValue: '' }) + const translatedDesc = t(`balance.paymentMethods.${methodKey}.description`, { defaultValue: '' }) + + return ( + + ) + })} +
+ )} +
+
+ ) +} diff --git a/src/components/TopUpModal.tsx b/src/components/TopUpModal.tsx index c6d0107..772c949 100644 --- a/src/components/TopUpModal.tsx +++ b/src/components/TopUpModal.tsx @@ -35,12 +35,28 @@ const openPaymentLink = (url: string, reservedWindow?: Window | null) => { window.location.href = url } -interface TopUpModalProps { method: PaymentMethod; onClose: () => void } +interface TopUpModalProps { + method: PaymentMethod + onClose: () => void + /** Pre-filled amount in rubles (will be converted to user's currency) */ + initialAmountRubles?: number +} -export default function TopUpModal({ method, onClose }: TopUpModalProps) { +export default function TopUpModal({ method, onClose, initialAmountRubles }: TopUpModalProps) { const { t } = useTranslation() const { formatAmount, currencySymbol, convertAmount, convertToRub, targetCurrency } = useCurrency() - const [amount, setAmount] = useState('') + + // Calculate initial amount in user's currency + const getInitialAmount = (): string => { + if (!initialAmountRubles || initialAmountRubles <= 0) return '' + const converted = convertAmount(initialAmountRubles) + if (targetCurrency === 'IRR' || targetCurrency === 'RUB') { + return Math.ceil(converted).toString() + } + return converted.toFixed(2) + } + + const [amount, setAmount] = useState(getInitialAmount) const [error, setError] = useState(null) const [selectedOption, setSelectedOption] = useState( method.options && method.options.length > 0 ? method.options[0].id : null