diff --git a/components/dashboard/withdraw/withdrawal-confirmation-modal.tsx b/components/dashboard/withdraw/withdrawal-confirmation-modal.tsx new file mode 100644 index 00000000..fc7a1171 --- /dev/null +++ b/components/dashboard/withdraw/withdrawal-confirmation-modal.tsx @@ -0,0 +1,104 @@ +"use client"; + +import { AlertTriangle, Loader2 } from "lucide-react"; +import { cn } from "@/lib/utils"; + +interface WithdrawalConfirmationModalProps { + amount: string | number; + currency: string; + destinationAddress: string; + onConfirm: () => void | Promise; + onCancel: () => void; + isLoading?: boolean; +} + +export function WithdrawalConfirmationModal({ + amount, + currency, + destinationAddress, + onConfirm, + onCancel, + isLoading = false, +}: WithdrawalConfirmationModalProps) { + const formattedAmount = + typeof amount === "number" + ? amount.toLocaleString() + : amount; + + return ( +
+
+

Confirm withdrawal

+

+ Review the destination address carefully before you submit. +

+
+ +
+
+

You are withdrawing

+

+ {formattedAmount} {currency} +

+
+ +
+

To

+
+

+ {destinationAddress.trim() || "No address provided"} +

+
+
+
+ +
+
+ +
+

+ This action cannot be undone. +

+

+ Funds sent to an incorrect address cannot be recovered. +

+
+
+
+ +
+ + +
+
+ ); +} diff --git a/components/dashboard/withdraw/withdrawal-success.tsx b/components/dashboard/withdraw/withdrawal-success.tsx new file mode 100644 index 00000000..362ba607 --- /dev/null +++ b/components/dashboard/withdraw/withdrawal-success.tsx @@ -0,0 +1,91 @@ +"use client"; + +import Link from "next/link"; +import { CheckCircle2, Copy, ExternalLink, ArrowRight } from "lucide-react"; +import { useState } from "react"; +import { cn } from "@/lib/utils"; +import { useWithdrawalStore } from "@/hooks/useWithdrawalStore"; +import type { Transaction } from "@/lib/api/transactions"; + +interface WithdrawalSuccessProps { + transaction: Transaction; +} + +export function WithdrawalSuccess({ transaction }: WithdrawalSuccessProps) { + const [copied, setCopied] = useState(false); + const resetForm = useWithdrawalStore((state) => state.resetForm); + + const handleCopy = () => { + navigator.clipboard.writeText(transaction.id); + setCopied(true); + window.setTimeout(() => setCopied(false), 2000); + }; + + return ( +
+
+
+ +
+

Withdrawal submitted

+

+ Your withdrawal request has been received and is now being processed. +

+
+ +
+
+
+

Transaction ID

+

{transaction.id}

+
+ +
+ +
+
+

Amount

+

{transaction.amountString}

+
+
+

Currency

+

{transaction.currency}

+
+
+

Destination address

+

+ {transaction.destinationAddress || transaction.reference || "Pending verification"} +

+
+
+

Estimated processing time

+

1-3 business days

+
+
+
+ +
+ + View in transactions + + + +
+
+ ); +} diff --git a/components/dashboard/withdrawal/WithdrawalReview.tsx b/components/dashboard/withdrawal/WithdrawalReview.tsx index 88db0d57..2fcabb92 100644 --- a/components/dashboard/withdrawal/WithdrawalReview.tsx +++ b/components/dashboard/withdrawal/WithdrawalReview.tsx @@ -1,26 +1,13 @@ "use client"; import { useWithdrawalStore } from "@/hooks/useWithdrawalStore"; -import { ChevronLeft, Loader2, Coins, CircleDollarSign, BadgeDollarSign } from "lucide-react"; -import { cn } from "@/lib/utils"; -import { createWithdrawal } from "@/lib/api/transactions"; - -const currencies = [ - { id: 'USDC', name: 'USD Coin', icon: }, - { id: 'ETH', name: 'Ethereum', icon: }, - { id: 'BNB', name: 'BNB', icon: }, -]; +import { createWithdrawal, type Transaction } from "@/lib/api/transactions"; +import { WithdrawalConfirmationModal } from "@/components/dashboard/withdraw/withdrawal-confirmation-modal"; export function WithdrawalReview() { - const { currency, amount, walletAddress, step, setStep, setTransactionResult, close, reset } = useWithdrawalStore(); + const { currency, amount, walletAddress, step, setStep, setTransactionResult, setTransactionData } = useWithdrawalStore(); const isProcessing = step === 'processing'; - const selectedCurrency = currencies.find(c => c.id === currency) || currencies[0]; - - const truncateAddress = (addr: string) => { - if (addr.length <= 16) return addr; - return `${addr.slice(0, 8)}...${addr.slice(-6)}`; - }; const handleConfirm = async () => { setStep('processing'); @@ -32,7 +19,21 @@ export function WithdrawalReview() { destinationAddress: walletAddress, }); - setTransactionResult(response.transactionId, 'success'); + const transaction: Transaction = { + id: response.transactionId, + type: 'Withdraw', + currency, + amount: parseFloat(amount), + amountString: `${parseFloat(amount).toLocaleString()} ${currency}`, + date: new Date().toISOString(), + status: response.status === 'success' ? 'Success' : response.status === 'failed' ? 'Failed' : 'Pending', + reference: walletAddress, + description: 'Withdrawal request submitted', + destinationAddress: walletAddress, + }; + + setTransactionData(transaction); + setTransactionResult(response.transactionId, response.status === 'success' ? 'success' : response.status === 'failed' ? 'failed' : 'pending'); setStep('success'); } catch (error) { const errorMessage = error instanceof Error @@ -43,120 +44,17 @@ export function WithdrawalReview() { } }; - const handleCancel = () => { - if (isProcessing) return; - close(); - setTimeout(() => reset(), 300); - }; - return ( -
- {/* Header */} -
- -
-

Review Withdrawal

-

Confirm your withdrawal details

-
-
- - {/* Summary Card */} -
- {/* Amount */} -
-

You are withdrawing

-
- {selectedCurrency.icon} - - {parseFloat(amount).toLocaleString()} {currency} - -
-
- - {/* Details */} -
-
- Destination - - {truncateAddress(walletAddress)} - -
-
- Network - - {currency === 'ETH' ? 'Ethereum' : currency === 'BNB' ? 'BSC' : 'Stellar'} - -
-
- Fee - - Free - -
-
-
- - {/* Warning */} -
-

- Important: Please verify the wallet address is correct. Transactions cannot be reversed once confirmed. -

-
- - {/* Actions */} -
- - - -
-
+ { + if (isProcessing) return; + setStep('form'); + }} + isLoading={isProcessing} + /> ); } diff --git a/components/dashboard/withdrawal/WithdrawalSuccess.tsx b/components/dashboard/withdrawal/WithdrawalSuccess.tsx index 2109d7ff..3ce9f548 100644 --- a/components/dashboard/withdrawal/WithdrawalSuccess.tsx +++ b/components/dashboard/withdrawal/WithdrawalSuccess.tsx @@ -1,143 +1,34 @@ "use client"; import { useWithdrawalStore } from "@/hooks/useWithdrawalStore"; -import { CheckCircle2, XCircle, Copy, ExternalLink, Coins, CircleDollarSign, BadgeDollarSign } from "lucide-react"; -import { cn } from "@/lib/utils"; -import { useState } from "react"; - -const currencies = [ - { id: 'USDC', name: 'USD Coin', icon: }, - { id: 'ETH', name: 'Ethereum', icon: }, - { id: 'BNB', name: 'BNB', icon: }, -]; +import { WithdrawalSuccess as WithdrawalStatusScreen } from "@/components/dashboard/withdraw/withdrawal-success"; +import { XCircle } from "lucide-react"; export function WithdrawalSuccess() { - const { currency, amount, transactionId, transactionStatus, errorMessage, close, reset, setStep } = useWithdrawalStore(); - const [copied, setCopied] = useState(false); - - const selectedCurrency = currencies.find(c => c.id === currency) || currencies[0]; - const isSuccess = transactionStatus === 'success'; + const { transaction, transactionStatus, errorMessage, setStep } = useWithdrawalStore(); - const handleCopyTxId = () => { - if (transactionId) { - navigator.clipboard.writeText(transactionId); - setCopied(true); - setTimeout(() => setCopied(false), 2000); - } - }; - - const handleDone = () => { - close(); - setTimeout(() => reset(), 300); - }; + if (transaction && transactionStatus === 'success') { + return ; + } return (
- {/* Status Icon */}
-
- {isSuccess ? ( - - ) : ( - - )} +
+
- -

- {isSuccess ? "Withdrawal Successful!" : "Withdrawal Failed"} -

- -

- {isSuccess - ? "Your withdrawal has been submitted successfully" - : (errorMessage || "Something went wrong. Please try again.") - } +

Withdrawal failed

+

+ {errorMessage || "Something went wrong. Please try again."}

- {/* Amount Display */} - {isSuccess && ( -
-

Amount Withdrawn

-
- {selectedCurrency.icon} - - {parseFloat(amount).toLocaleString()} {currency} - -
-
- )} - - {/* Transaction Details */} - {isSuccess && transactionId && ( -
-
-
-

Transaction ID

-

{transactionId}

-
- -
- -
-
-

Status

-
- -

Pending Confirmation

-
-
-
-
- )} - - {/* Info Note */} - {isSuccess && ( -
-

- Your transaction is being processed. It may take a few minutes to reflect in your wallet. -

-
- )} - - {/* Actions */} -
- - - {isSuccess && ( - - )} -
+
); } diff --git a/hooks/useWithdrawalStore.ts b/hooks/useWithdrawalStore.ts index ba0300b3..37532368 100644 --- a/hooks/useWithdrawalStore.ts +++ b/hooks/useWithdrawalStore.ts @@ -1,4 +1,5 @@ import { create } from "zustand"; +import type { Transaction } from "@/lib/api/transactions"; export type WithdrawalStep = 'select' | 'form' | 'review' | 'processing' | 'success' | 'error'; export type TransactionStatus = 'pending' | 'success' | 'failed' | null; @@ -23,6 +24,7 @@ interface WithdrawalState { transactionId: string | null; transactionStatus: TransactionStatus; errorMessage: string | null; + transaction: Transaction | null; // Actions open: () => void; @@ -30,6 +32,8 @@ interface WithdrawalState { setStep: (step: WithdrawalStep) => void; setFormData: (data: Partial) => void; setTransactionResult: (id: string | null, status: TransactionStatus, error?: string) => void; + setTransactionData: (transaction: Transaction | null) => void; + resetForm: () => void; reset: () => void; } @@ -42,6 +46,7 @@ const initialState = { transactionId: null, transactionStatus: null as TransactionStatus, errorMessage: null as string | null, + transaction: null as Transaction | null, }; export const useWithdrawalStore = create((set) => ({ @@ -64,5 +69,19 @@ export const useWithdrawalStore = create((set) => ({ errorMessage: error ?? null, }), + setTransactionData: (transaction) => set({ transaction }), + + resetForm: () => set((state) => ({ + ...state, + currency: 'USDC', + amount: '', + walletAddress: '', + transactionId: null, + transactionStatus: null, + errorMessage: null, + transaction: null, + step: 'form' as WithdrawalStep, + })), + reset: () => set(initialState), })); diff --git a/lib/api/transactions.ts b/lib/api/transactions.ts index 596249ce..c14b6318 100644 --- a/lib/api/transactions.ts +++ b/lib/api/transactions.ts @@ -14,6 +14,7 @@ export interface Transaction { status: TransactionStatus; reference: string; description?: string; + destinationAddress?: string; fee?: number; exchangeRate?: number; toAmount?: number;