import { useState, useEffect } from 'react'; import { useTranslation } from 'react-i18next'; import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter, } from '@/components/ui/dialog'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { Label } from '@/components/ui/label'; import { Alert, AlertDescription } from '@/components/ui/alert'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from '@/components/ui/select'; import { Skeleton } from '@/components/ui/skeleton'; import { Loader2, Copy, CheckCircle2, AlertTriangle, ExternalLink, QrCode, Wallet } from 'lucide-react'; import { usePezkuwi } from '@/contexts/PezkuwiContext'; import { useWallet } from '@/contexts/WalletContext'; import { toast } from 'sonner'; import { supabase } from '@/lib/supabase'; import { getPlatformWalletAddress, type CryptoToken } from '@shared/lib/p2p-fiat'; interface DepositModalProps { isOpen: boolean; onClose: () => void; onSuccess?: () => void; } type DepositStep = 'select' | 'send' | 'verify' | 'success'; export function DepositModal({ isOpen, onClose, onSuccess }: DepositModalProps) { const { t } = useTranslation(); const { api, selectedAccount } = usePezkuwi(); const { balances, signTransaction } = useWallet(); const [step, setStep] = useState('select'); const [token, setToken] = useState('HEZ'); const [amount, setAmount] = useState(''); const [platformWallet, setPlatformWallet] = useState(''); const [txHash, setTxHash] = useState(''); const [loading, setLoading] = useState(false); const [copied, setCopied] = useState(false); const [verifying, setVerifying] = useState(false); // Fetch platform wallet address on mount useEffect(() => { if (isOpen) { fetchPlatformWallet(); } }, [isOpen]); const fetchPlatformWallet = async () => { const address = await getPlatformWalletAddress(); setPlatformWallet(address); }; const resetModal = () => { setStep('select'); setToken('HEZ'); setAmount(''); setTxHash(''); setLoading(false); setCopied(false); setVerifying(false); }; const handleClose = () => { resetModal(); onClose(); }; const handleCopyAddress = async () => { try { await navigator.clipboard.writeText(platformWallet); setCopied(true); toast.success(t('p2pDeposit.addressCopied')); setTimeout(() => setCopied(false), 2000); } catch { toast.error(t('p2pDeposit.failedToCopy')); } }; const getAvailableBalance = () => { if (token === 'HEZ') return balances.HEZ; if (token === 'PEZ') return balances.PEZ; return '0'; }; const handleSendDeposit = async () => { if (!api || !selectedAccount) { toast.error(t('p2pDeposit.connectWallet')); return; } const depositAmount = parseFloat(amount); if (isNaN(depositAmount) || depositAmount <= 0) { toast.error(t('p2pDeposit.enterValidAmount')); return; } setLoading(true); try { // Build the transfer transaction const DECIMALS = 12; const amountBN = BigInt(Math.floor(depositAmount * 10 ** DECIMALS)); let tx; if (token === 'HEZ') { // Native transfer tx = api.tx.balances.transferKeepAlive(platformWallet, amountBN); } else { // Asset transfer (PEZ = asset ID 1) const assetId = token === 'PEZ' ? 1 : 0; tx = api.tx.assets.transfer(assetId, platformWallet, amountBN); } toast.info(t('p2pDeposit.signTransaction')); // Sign and send const hash = await signTransaction(tx); if (hash) { setTxHash(hash); setStep('verify'); toast.success(t('p2pDeposit.txSent')); } } catch (error: unknown) { console.error('Deposit transaction error:', error); const message = error instanceof Error ? error.message : t('p2pDeposit.txFailed'); toast.error(message); } finally { setLoading(false); } }; const handleVerifyDeposit = async () => { if (!txHash) { toast.error(t('p2pDeposit.enterTxHash')); return; } const depositAmount = parseFloat(amount); if (isNaN(depositAmount) || depositAmount <= 0) { toast.error(t('p2pDeposit.invalidAmount')); return; } setVerifying(true); try { // Call the Edge Function for secure deposit verification // This verifies the transaction on-chain before crediting balance const { data, error } = await supabase.functions.invoke('verify-deposit', { body: { txHash, token, expectedAmount: depositAmount } }); if (error) { throw new Error(error.message || t('p2pDeposit.verificationFailed')); } if (data?.success) { toast.success(t('p2pDeposit.depositVerified', { amount: data.amount, token })); setStep('success'); onSuccess?.(); } else { throw new Error(data?.error || t('p2pDeposit.verificationFailed')); } } catch (error) { console.error('Verify deposit error:', error); const message = error instanceof Error ? error.message : t('p2pDeposit.verificationFailed'); toast.error(message); } finally { setVerifying(false); } }; const renderStepContent = () => { switch (step) { case 'select': return (
setAmount(e.target.value)} min="0" step="0.0001" />
{token}

{t('p2pDeposit.walletBalance', { amount: parseFloat(getAvailableBalance()).toFixed(4), token })}

{t('p2pDeposit.depositInfo', { token })}
); case 'send': return (

{t('p2pDeposit.sendAmountTo', { amount, token })}

{platformWallet ? (
{platformWallet}
) : ( )}
{t('p2pDeposit.networkWarning', { token })}
); case 'verify': return (
{t('p2pDeposit.txSentVerify')}
setTxHash(e.target.value)} placeholder="0x..." className="font-mono text-xs" />

{t('p2pDeposit.tokenLabel')}

{token}

{t('p2pDeposit.amountLabel')}

{amount}

); case 'success': return (

{t('p2pDeposit.depositSuccess')}

{t('p2pDeposit.addedToBalance', { amount, token })}

{t('p2pDeposit.successInfo')}

); } }; return ( !open && handleClose()}> {t('p2pDeposit.title')} {step !== 'success' && ( {step === 'select' && t('p2pDeposit.selectStep')} {step === 'send' && t('p2pDeposit.sendStep')} {step === 'verify' && t('p2pDeposit.verifyStep')} )} {renderStepContent()} ); }