diff --git a/apps/web/src/components/offramp/OfframpSuccessModal.tsx b/apps/web/src/components/offramp/OfframpSuccessModal.tsx index d9e1fdc..9d50669 100644 --- a/apps/web/src/components/offramp/OfframpSuccessModal.tsx +++ b/apps/web/src/components/offramp/OfframpSuccessModal.tsx @@ -1,7 +1,7 @@ "use client"; import React, { useState, useRef, useEffect } from "react"; -import { CheckCircle2, Copy, ExternalLink, X, Loader2, XCircle, Clock } from "lucide-react"; +import { CheckCircle2, Copy, ExternalLink, X, Loader2, XCircle, Clock, Info } from "lucide-react"; import { Button } from "@/components/ui/button"; import toast from "react-hot-toast"; import type { QuoteStatusData, BridgeFeeBreakdown } from "@/types/offramp"; @@ -45,8 +45,10 @@ export default function OfframpSuccessModal({ if (!isOpen) return null; - const isCompleted = payoutStatus?.status === "completed" || payoutStatus?.status === "confirmed"; - const isFailed = payoutStatus?.status === "failed"; + const status = payoutStatus?.status; + const isCompleted = status === "completed" || status === "confirmed"; + const isFailed = status === "failed" || status === "expired"; + const isProcessing = status === "pending" || status === "processing" || !status; return (
@@ -57,7 +59,7 @@ export default function OfframpSuccessModal({ /> {/* Modal */} -
+
{/* Close Button */} - {/* Success Icon */} + {/* Status Icon */}
-
+
{isCompleted ? ( ) : isFailed ? ( ) : ( - + )}
- {/* Title */} + {/* Title & Processing Time Banner */}

- {isCompleted ? "Offramp Complete! 🎉" : isFailed ? "Offramp Failed" : "Offramp Processing"} + {isCompleted ? "Offramp Complete! 🎉" : isFailed ? "Offramp Failed" : "Processing Transfer"}

-

+ + {/* Added: Processing Time Banner for Task #62 */} + {isProcessing && ( +

+ + + Estimated: 2-5 Minutes + +
+ )} + +

{isCompleted ? "Your funds have been successfully sent to your bank account." : isFailed - ? payoutStatus?.providerMessage || "There was an issue with your transfer. Please contact support." - : "Your transaction is being processed. You can close this window and check back later."} + ? payoutStatus?.providerMessage || "There was an issue with your transfer." + : "Your transaction is on the way. You can safely close this window."}

- {/* Summary Card */} + {/* Summary Card with Exchange Rate */} {feeBreakdown && (
@@ -102,33 +115,46 @@ export default function OfframpSuccessModal({ {parseFloat(feeBreakdown.sendAmount).toFixed(4)} USDC
+ + {/* Added: Exchange Rate for Transparency */} +
+ + Exchange Rate + + + 1 USDC = ₦{(parseFloat(feeBreakdown.fiatPayout) / (parseFloat(feeBreakdown.sendAmount) - parseFloat(feeBreakdown.bridgeFee))).toLocaleString()} + +
+
Bridge Fee - + -{parseFloat(feeBreakdown.bridgeFee).toFixed(4)} USDC
+
+
- Total Received - + Total Payout + ₦{parseFloat(feeBreakdown.fiatPayout).toLocaleString()}
)} - {/* Transaction Info */} -
+ {/* Transaction Reference & Explorer */} +
{payoutStatus?.transactionReference && ( -
-

Reference ID

-
- {payoutStatus.transactionReference} - +
+
+

Ref ID

+ {payoutStatus.transactionReference}
+
)} @@ -137,7 +163,7 @@ export default function OfframpSuccessModal({ href={`https://stellar.expert/explorer/public/tx/${bridgeTxHash}`} target="_blank" rel="noopener noreferrer" - className="flex items-center justify-center gap-2 w-full py-3 text-xs text-fundable-purple hover:text-fundable-violet transition-colors font-medium" + className="flex items-center justify-center gap-2 w-full py-2 text-xs text-fundable-purple hover:underline font-medium" > View Stellar Explorer @@ -147,7 +173,7 @@ export default function OfframpSuccessModal({ {/* Action Button */} diff --git a/apps/web/src/components/offramp/OfframpSummary.tsx b/apps/web/src/components/offramp/OfframpSummary.tsx index c400d7f..b976ff0 100644 --- a/apps/web/src/components/offramp/OfframpSummary.tsx +++ b/apps/web/src/components/offramp/OfframpSummary.tsx @@ -1,7 +1,8 @@ "use client"; import { Button } from "@/components/ui/button"; -import { Loader2 } from "lucide-react"; +// Added Clock and ShieldCheck icons +import { Loader2, Clock, ShieldCheck, Info } from "lucide-react"; import type { OfframpFormState, ProviderRate } from "@/types/offramp"; import { SUPPORTED_COUNTRIES } from "@/types/offramp"; @@ -33,114 +34,119 @@ export default function OfframpSummary({ const canProceed = isFormValid && quote && !isLoading; + // Helper to render currency symbols + const getCurrencySymbol = () => { + if (!selectedCountry) return ""; + switch (selectedCountry.currency) { + case "NGN": return "₦"; + case "GHS": return "₵"; + case "KES": return "KSh "; + default: return selectedCountry.currency + " "; + } + }; + return ( -
-

- Quote Summary +
+

+ + Transaction Summary

- {/* Real-time Quote Info */} {isLoading ? ( -
- - Fetching quote... +
+ + Calculating best rates...
) : quote ? ( -
-
- You Send - - {quote.cryptoAmount} {formState.token} - -
-
- Exchange Rate - - 1 {formState.token} = {quote.currency} {quote.rate?.toLocaleString() ?? "N/A"} - -
-
- Provider - {quote.displayName} -
- {quote.expiresAt && ( +
+ {/* THE BREAKDOWN CARD */} +
- Expires At - - {new Date(quote.expiresAt).toLocaleTimeString()} + Exchange Rate + + 1 {formState.token} = {quote.currency} {quote.rate?.toLocaleString()}
- )} + +
+ + Service Fee + + + -{quote.fee} {quote.currency} + +
+ + {/* ESTIMATED TIME COMPONENT */} +
+ + + Est. Arrival: 2-5 Minutes + +
+
+ + {/* PROVIDER INFO */} +
+ Provider: {quote.displayName} + {quote.expiresAt && ( + + Quote expires: {new Date(quote.expiresAt).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })} + + )} +
) : quoteError ? ( -
-

{quoteError}

+
+

{quoteError}

) : ( -
-
- You Send - - {formState.amount || "0"} {formState.token} - -
-
- Exchange Rate - Enter amount for quote -
+
+

Enter an amount to see the fee breakdown

)} -
-
- You Receive + {/* FINAL PAYOUT SECTION */} +
+
+
+ Total Payout +

Includes all network and provider fees

+
{quote ? ( - <> -

- {selectedCountry?.currency === "NGN" ? "₦" : - selectedCountry?.currency === "GHS" ? "₵" : - selectedCountry?.currency === "KES" ? "KSh " : ""} - {quote.fiatAmount?.toLocaleString()} -

-

- Fee: {quote.fee} {quote.currency} -

- +

+ {getCurrencySymbol()} + {quote.fiatAmount?.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })} +

) : ( - <> -

- {selectedCountry?.currency || "---"} -

-

- --- -

- +

+ {selectedCountry?.currency || "---"} +

)}
-
- {/* Proceed Button */} - + +
);