import React from 'react'; import { IcClose, IcBuilding } from '../res/icons'; import { MinusCircle } from 'lucide-react'; import { AmountKeyboard } from './AmountKeyboard'; import type { AlipayBankCard } from '../types'; import { useAlipayStrings } from '../hooks/useAlipayStrings'; import { useLocale } from '@/apps/Alipay/locale'; import { localizeBankName } from '../utils/localizeBankName'; function clampMoney2(v: number): number { if (!Number.isFinite(v)) return 0; return Math.max(0, Math.round(v * 100) / 100); } function splitEven(total: number, n: number): number[] { const t = clampMoney2(total); const k = Math.max(0, Math.floor(n)); if (k <= 0) return []; const base = clampMoney2(t / k); const arr = Array.from({ length: k }, () => base); const sum = clampMoney2(arr.reduce((s, x) => s + x, 0)); const drift = clampMoney2(t - sum); if (arr.length > 0) arr[0] = clampMoney2(arr[0] + drift); return arr; } export type MultiRechargeRow = { cardId: string; amount: string }; export const MultiCardRechargeModal: React.FC<{ visible: boolean; totalAmount: string; boundCards: AlipayBankCard[]; onClose: () => void; onAddMoreCards: () => void; onSubmit: (rows: MultiRechargeRow[]) => void; }> = ({ visible, totalAmount, boundCards, onClose, onAddMoreCards, onSubmit }) => { const s = useAlipayStrings(); const locale = useLocale(); const isEnglish = locale === 'en'; const [rows, setRows] = React.useState([]); const [activeCardId, setActiveCardId] = React.useState(null); const scrollRef = React.useRef(null); const inputRefs = React.useRef>(new Map()); React.useEffect(() => { if (!visible) { setActiveCardId(null); return; } const cards = (boundCards || []).filter(c => c && c.bound); const total = Number(totalAmount); const parts = splitEven(Number.isFinite(total) ? total : 0, cards.length); setRows(cards.map((c, idx) => { const v = parts[idx] ?? 0; return { cardId: c.id, amount: v > 0 ? v.toFixed(2) : '' }; })); }, [visible, boundCards, totalAmount]); React.useEffect(() => { if (!activeCardId) return; const el = inputRefs.current.get(activeCardId); if (el) el.focus({ preventScroll: true }); const timer = setTimeout(() => { const container = scrollRef.current; const input = el; if (!container || !input) return; const cRect = container.getBoundingClientRect(); const iRect = input.getBoundingClientRect(); const offsetInContainer = iRect.top - cRect.top + container.scrollTop; const targetScroll = offsetInContainer - 12; container.scrollTo({ top: Math.max(0, targetScroll), behavior: 'smooth' }); }, 80); return () => clearTimeout(timer); }, [activeCardId]); const cardsById = React.useMemo(() => { const m = new Map(); for (const c of boundCards || []) m.set(c.id, c); return m; }, [boundCards]); const parsed = rows.map(r => clampMoney2(Number(r.amount))); const total = clampMoney2(parsed.reduce((s, x) => s + x, 0)); const canSubmit = rows.length >= 1 && total > 0; const handleKeyInput = (key: string) => { if (!activeCardId) return; setRows(prev => prev.map(r => { if (r.cardId !== activeCardId) return r; const cur = r.amount; if (key === '.') { if (cur.includes('.')) return r; return { ...r, amount: cur === '' ? '0.' : cur + '.' }; } if (cur === '0') return { ...r, amount: key }; const next = cur + key; if (/^\d+\.\d{3,}$/.test(next)) return r; return { ...r, amount: next }; })); }; const handleKeyDelete = () => { if (!activeCardId) return; setRows(prev => prev.map(r => r.cardId === activeCardId ? { ...r, amount: r.amount.slice(0, -1) } : r )); }; if (!visible) return null; const kbOpen = activeCardId !== null; return (
e.stopPropagation()} >
{s.multi_card_recharge_title}
{rows.length === 0 ? (
{s.multi_card_recharge_no_cards}
) : null} {rows.map((r) => { const card = cardsById.get(r.cardId) || null; const isActive = activeCardId === r.cardId; return (
{card ? `${localizeBankName(card.bankName, isEnglish)}${isEnglish ? ` (${card.last4})` : `(${card.last4})`}` : r.cardId}
{ if (el) inputRefs.current.set(r.cardId, el); else inputRefs.current.delete(r.cardId); }} className={`w-full bg-[#F6F7FB] rounded-lg px-4 py-3 outline-none text-sm text-gray-900 placeholder:text-gray-400 caret-[#1677FF] border-2 transition-colors ${isActive ? 'border-app-primary' : 'border-transparent'}`} value={r.amount} inputMode="none" type="text" onClick={() => setActiveCardId(r.cardId)} onChange={e => { const v = e.target.value; if (v === '' || /^\d*\.?\d{0,2}$/.test(v)) { setActiveCardId(r.cardId); setRows(prev => prev.map(x => x.cardId === r.cardId ? { ...x, amount: v } : x)); } }} placeholder={s.multi_card_recharge_input_placeholder} />
); })}
{s.multi_card_recharge_total}
¥{total.toFixed(2)}
setActiveCardId(null)} actionPrefix="multiRecharge" open={kbOpen} onToggle={(open) => { if (!open) setActiveCardId(null); }} />
); };