"use client"; import Link from "next/link"; import { useCallback, useEffect, useMemo, useState } from "react"; import { useCart } from "@/contexts/CartContext"; import { useWallet } from "@/contexts/WalletContext"; import { getMerchantBtcAddress, isMerchantBtcConfigured } from "@/lib/merchantBtc"; import { estimateUsdForCryptoAmount } from "@/lib/shopFx"; const ENCRYPTION_BTC_FEE: Record<"standard" | "enhanced" | "quantum", number> = { standard: 0, enhanced: 0.001, quantum: 0.005, }; const CheckoutFlow = () => { const { lines, setLineQty, removeLine, clearCart, hydrated: cartHydrated } = useCart(); const [step, setStep] = useState(1); const [paymentMethod, setPaymentMethod] = useState<"crypto" | "guest" | "card">("crypto"); const [cryptoType, setCryptoType] = useState<"BTC" | "ETH" | "XMR">("BTC"); const [guestEmail, setGuestEmail] = useState(""); const [encryptionLevel, setEncryptionLevel] = useState<"standard" | "enhanced" | "quantum">("enhanced"); const [btcUsd, setBtcUsd] = useState(null); const [txidInput, setTxidInput] = useState(""); const [verifyMsg, setVerifyMsg] = useState<{ kind: "ok" | "err"; text: string } | null>(null); const [verifyBusy, setVerifyBusy] = useState(false); const [payError, setPayError] = useState(null); const [orderComplete, setOrderComplete] = useState(false); const { usdStoreCredit, spendUsdStoreCredit, verifyBtcDeposit } = useWallet(); useEffect(() => { let cancelled = false; (async () => { try { const res = await fetch( "https://api.coingecko.com/api/v3/simple/price?ids=bitcoin&vs_currencies=usd", ); const j = (await res.json()) as { bitcoin?: { usd?: number } }; const p = j.bitcoin?.usd; if (!cancelled && p && Number.isFinite(p)) setBtcUsd(p); } catch { if (!cancelled) setBtcUsd(96000); } })(); return () => { cancelled = true; }; }, []); const spotBtc = btcUsd ?? 96000; const subtotalUsd = useMemo( () => Math.round( lines.reduce( (sum, l) => sum + estimateUsdForCryptoAmount(l.price, l.currency, spotBtc) * l.qty, 0, ) * 100, ) / 100, [lines, spotBtc], ); const encryptionFeeUsd = useMemo(() => { const rate = btcUsd ?? 96000; return Math.round(ENCRYPTION_BTC_FEE[encryptionLevel] * rate * 100) / 100; }, [encryptionLevel, btcUsd]); const orderTotalUsd = useMemo( () => Math.round((subtotalUsd + encryptionFeeUsd) * 100) / 100, [subtotalUsd, encryptionFeeUsd], ); const orderTotalBtc = useMemo(() => { const r = btcUsd && btcUsd > 0 ? btcUsd : spotBtc; if (!r || r <= 0) return null; return Math.round((orderTotalUsd / r) * 1e8) / 1e8; }, [orderTotalUsd, btcUsd, spotBtc]); const merchantAddr = getMerchantBtcAddress(); const merchantReady = isMerchantBtcConfigured(); const btcPayUri = useMemo(() => { if (!merchantReady || orderTotalBtc == null) return ""; return `bitcoin:${merchantAddr}?amount=${orderTotalBtc}`; }, [merchantReady, merchantAddr, orderTotalBtc]); const handleVerify = useCallback(async () => { setVerifyMsg(null); setVerifyBusy(true); try { const result = await verifyBtcDeposit(txidInput.trim()); if (result.ok) { setVerifyMsg({ kind: "ok", text: `Confirmed. Added $${result.creditedUsd?.toFixed(2) ?? "0.00"} USD to your spendable balance.`, }); setTxidInput(""); } else { setVerifyMsg({ kind: "err", text: result.error || "Verification failed" }); } } finally { setVerifyBusy(false); } }, [txidInput, verifyBtcDeposit]); const tryCompleteOrder = () => { setPayError(null); if (paymentMethod === "crypto") { if (!spendUsdStoreCredit(orderTotalUsd)) { setPayError( `Insufficient USD balance. You need $${orderTotalUsd.toFixed(2)}. Send Bitcoin to the address below, wait for at least one confirmation, then paste the transaction ID and click Verify.`, ); return; } } setOrderComplete(true); clearCart(); }; const steps = [ { number: 1, title: "Cart", description: "Review items" }, { number: 2, title: "Payment", description: "Choose method" }, { number: 3, title: "Encryption", description: "Select privacy level" }, { number: 4, title: "Confirmation", description: "Complete ritual" }, ]; const handleNext = () => { if (step === 1 && lines.length === 0) return; if (step < 4) setStep(step + 1); }; const handlePrev = () => { if (step > 1) setStep(step - 1); }; return (
{steps.map((s) => (
= s.number ? "border-neon-cyan bg-neon-cyan/20 text-neon-cyan" : "border-white/20 text-foreground/40" }`} > {s.number}
{s.title}
{s.description}
))}
{step === 1 && (

YOUR CART

{!cartHydrated ? (

Loading cart…

) : lines.length === 0 ? (

Your cart is empty.

Add SKUs from the hub or candy market.

Browse catalog
) : (
{lines.map((item) => { const unitUsd = estimateUsdForCryptoAmount(item.price, item.currency, spotBtc); const lineUsd = Math.round(unitUsd * item.qty * 100) / 100; return (
{item.name}
{item.price} {item.currency} each · ≈ ${unitUsd.toFixed(2)} USD @ spot
Qty {item.qty}
${lineUsd.toLocaleString()}
USD est.
); })}
)} {lines.length > 0 ? (
Subtotal (USD est.) ${subtotalUsd.toLocaleString()}
) : null}
)} {step === 2 && (

SELECT PAYMENT METHOD

USD balance: ${usdStoreCredit.toFixed(2)} {" "} — use after Bitcoin deposit is verified (on-chain).
{paymentMethod === "crypto" && (
{(["BTC", "ETH", "XMR"] as const).map((coin) => ( ))}
{cryptoType !== "BTC" && (

Deposits that add USD balance use Bitcoin only. Switch to BTC to see the deposit address. (ETH/XMR shown for display.)

)} {cryptoType === "BTC" && (
Estimated order total after encryption step
${orderTotalUsd.toLocaleString()} USD {orderTotalBtc != null && btcUsd != null && ( (≈ {orderTotalBtc} BTC @ ${btcUsd.toLocaleString()}/BTC) )}

Final total includes the encryption add-on you pick in the next step. Fund your balance with any amount of BTC; verified value is credited in USD at spot rate. You can pay this order once your balance covers the total.

)}
)} {paymentMethod === "guest" && (
setGuestEmail(e.target.value)} />

Guest checkout is a demo and does not charge your USD balance.

)}

Bitcoin deposit (all checkouts)

{!merchantReady ? (

Set NEXT_PUBLIC_MERCHANT_BTC_ADDRESS and{" "} MERCHANT_BTC_ADDRESS in{" "} .env.local, then restart the app.

) : ( <>

Send Bitcoin to this address. After the network confirms your payment (at least one block), paste the transaction ID to add the equivalent USD to your balance.

{merchantAddr}
{btcPayUri && (
Bitcoin payment QR
QR encodes a suggested payment URI for the current cart estimate (you may send any amount; all verified BTC to this address becomes USD credit).
)}
setTxidInput(e.target.value.replace(/\s+/g, ""))} /> {verifyMsg && (

{verifyMsg.text}

)}
)}
)} {step === 3 && (

ENCRYPTION LEVEL

Choose how securely your data is protected. Higher levels add to your order total in USD.

{[ { level: "standard" as const, name: "Stealth Encryption", desc: "Military‑grade encryption, basic anonymity", icon: "🕵️" }, { level: "enhanced" as const, name: "Ghost Protocol", desc: "Post‑quantum cryptography, zero‑trace", icon: "👻" }, { level: "quantum" as const, name: "Zero‑Trace", desc: "Experimental, quantum‑entangled proofs", icon: "⚛️" }, ].map((opt) => ( ))}
Order total so far
${orderTotalUsd.toLocaleString()} USD
)} {step === 4 && !orderComplete && (

COMPLETE PAYMENT

Total due ${orderTotalUsd.toLocaleString()}
Your USD balance ${usdStoreCredit.toFixed(2)}
Payment path {paymentMethod === "crypto" ? "Crypto (USD balance)" : "Demo (guest/card)"}
{payError &&

{payError}

} {paymentMethod === "crypto" && (

Crypto checkout pulls from your verified USD balance only. Send BTC on the payment step and verify the txid so your balance matches the total above.

)}
)} {step === 4 && orderComplete && (

RITUAL COMPLETE

Your order is now encrypted with {encryptionLevel} protection. A unique digital artwork receipt has been generated and stored in your vault.

ORDER #CYBR‑9A2F‑B8E1
Amount
${orderTotalUsd.toLocaleString()} USD
Privacy
{encryptionLevel.toUpperCase()}
Payment
{paymentMethod === "crypto" ? "USD balance (BTC-funded)" : "Demo guest/card"}

Your digital receipt is available in your vault. Thank you for choosing CyberLux.

)}
{step < 4 ? ( ) : orderComplete ? ( ) : null}
); }; export default CheckoutFlow;