"use client"; import { ChangeEvent, CSSProperties } from "react"; import { SatsDisplay } from "../../components/SatsDisplay"; import { formatEur } from "../../utils/exchange"; import { buttonStyles } from "../../styles/shared"; import constants from "../../../../shared/constants.json"; import { useTranslation } from "../../hooks/useTranslation"; const { lightningMaxEur: LIGHTNING_MAX_EUR } = constants.exchange; type Direction = "buy" | "sell"; type BitcoinTransferMethod = "onchain" | "lightning"; interface ExchangeDetailsStepProps { direction: Direction; onDirectionChange: (direction: Direction) => void; bitcoinTransferMethod: BitcoinTransferMethod; onBitcoinTransferMethodChange: (method: BitcoinTransferMethod) => void; eurAmount: number; onEurAmountChange: (amount: number) => void; satsAmount: number; eurMin: number; eurMax: number; eurIncrement: number; isPriceStale: boolean; hasPrice: boolean; onContinue: () => void; } const styles: Record = { tradeCard: { background: "rgba(255, 255, 255, 0.03)", border: "1px solid rgba(255, 255, 255, 0.08)", borderRadius: "12px", padding: "1.5rem", marginBottom: "2rem", }, directionRow: { display: "flex", gap: "0.5rem", marginBottom: "1.5rem", }, directionBtn: { flex: 1, fontFamily: "'DM Sans', system-ui, sans-serif", fontSize: "1rem", fontWeight: 600, padding: "0.875rem", background: "rgba(255, 255, 255, 0.05)", border: "1px solid rgba(255, 255, 255, 0.1)", borderRadius: "8px", color: "rgba(255, 255, 255, 0.6)", cursor: "pointer", transition: "all 0.2s", }, directionBtnBuyActive: { background: "rgba(74, 222, 128, 0.15)", border: "1px solid #4ade80", color: "#4ade80", }, directionBtnSellActive: { background: "rgba(248, 113, 113, 0.15)", border: "1px solid #f87171", color: "#f87171", }, paymentMethodSection: { marginBottom: "1.5rem", }, paymentMethodLabel: { fontFamily: "'DM Sans', system-ui, sans-serif", color: "rgba(255, 255, 255, 0.7)", fontSize: "0.9rem", marginBottom: "0.75rem", }, required: { color: "#f87171", }, paymentMethodRow: { display: "flex", gap: "0.5rem", }, paymentMethodBtn: { flex: 1, fontFamily: "'DM Sans', system-ui, sans-serif", fontSize: "0.95rem", fontWeight: 600, padding: "0.875rem", background: "rgba(255, 255, 255, 0.05)", border: "1px solid rgba(255, 255, 255, 0.1)", borderRadius: "8px", color: "rgba(255, 255, 255, 0.6)", cursor: "pointer", transition: "all 0.2s", display: "flex", alignItems: "center", justifyContent: "center", gap: "0.5rem", }, paymentMethodBtnActive: { background: "rgba(167, 139, 250, 0.15)", border: "1px solid #a78bfa", color: "#a78bfa", }, paymentMethodBtnDisabled: { opacity: 0.4, cursor: "not-allowed", }, paymentMethodIcon: { fontSize: "1.2rem", }, thresholdMessage: { fontFamily: "'DM Sans', system-ui, sans-serif", fontSize: "0.75rem", color: "rgba(251, 146, 60, 0.9)", marginTop: "0.5rem", padding: "0.5rem", background: "rgba(251, 146, 60, 0.1)", borderRadius: "6px", border: "1px solid rgba(251, 146, 60, 0.2)", }, amountSection: { marginBottom: "1.5rem", }, amountHeader: { display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: "0.75rem", }, amountLabel: { fontFamily: "'DM Sans', system-ui, sans-serif", color: "rgba(255, 255, 255, 0.7)", fontSize: "0.9rem", }, amountInputWrapper: { display: "flex", alignItems: "center", background: "rgba(255, 255, 255, 0.05)", border: "1px solid rgba(255, 255, 255, 0.1)", borderRadius: "8px", padding: "0.5rem 0.75rem", }, amountCurrency: { fontFamily: "'DM Mono', monospace", color: "rgba(255, 255, 255, 0.5)", fontSize: "1rem", marginRight: "0.25rem", }, amountInput: { fontFamily: "'DM Mono', monospace", fontSize: "1.25rem", fontWeight: 600, color: "#fff", background: "transparent", border: "none", outline: "none", width: "80px", textAlign: "right" as const, }, slider: { width: "100%", height: "8px", appearance: "none" as const, background: "rgba(255, 255, 255, 0.1)", borderRadius: "4px", outline: "none", cursor: "pointer", }, amountRange: { display: "flex", justifyContent: "space-between", marginTop: "0.5rem", fontFamily: "'DM Sans', system-ui, sans-serif", fontSize: "0.75rem", color: "rgba(255, 255, 255, 0.4)", }, tradeSummary: { background: "rgba(255, 255, 255, 0.02)", borderRadius: "8px", padding: "1rem", textAlign: "center" as const, marginBottom: "1.5rem", }, summaryText: { fontFamily: "'DM Sans', system-ui, sans-serif", color: "rgba(255, 255, 255, 0.8)", fontSize: "0.95rem", margin: 0, }, satsValue: { fontFamily: "'DM Mono', monospace", color: "#f7931a", // Bitcoin orange }, continueButton: { width: "100%", fontFamily: "'DM Sans', system-ui, sans-serif", fontSize: "1rem", fontWeight: 600, padding: "0.875rem", background: "linear-gradient(135deg, #a78bfa 0%, #8b5cf6 100%)", border: "none", borderRadius: "8px", color: "#fff", cursor: "pointer", transition: "all 0.2s", }, }; /** * Step 1 of the exchange wizard: Exchange Details * Allows user to select direction (buy/sell), payment method, and amount. */ export function ExchangeDetailsStep({ direction, onDirectionChange, bitcoinTransferMethod, onBitcoinTransferMethodChange, eurAmount, onEurAmountChange, satsAmount, eurMin, eurMax, eurIncrement, isPriceStale, hasPrice, onContinue, }: ExchangeDetailsStepProps) { const t = useTranslation("exchange"); const isLightningDisabled = eurAmount > LIGHTNING_MAX_EUR * 100; const handleAmountChange = (value: number) => { // Clamp to valid range and snap to increment const minCents = eurMin * 100; const maxCents = eurMax * 100; const incrementCents = eurIncrement * 100; // Clamp value let clamped = Math.max(minCents, Math.min(maxCents, value)); // Snap to nearest increment clamped = Math.round(clamped / incrementCents) * incrementCents; onEurAmountChange(clamped); }; const handleAmountInputChange = (e: ChangeEvent) => { const inputValue = e.target.value.replace(/[^0-9]/g, ""); if (inputValue === "") { onEurAmountChange(eurMin * 100); return; } const eurValue = parseInt(inputValue, 10); handleAmountChange(eurValue * 100); }; return (
{/* Direction Selector */}
{/* Payment Method Selector */}
{t("detailsStep.paymentMethod")}{" "} {t("detailsStep.required")}
{isLightningDisabled && (
{t("detailsStep.lightningThreshold", { max: LIGHTNING_MAX_EUR })}
)}
{/* Amount Section */}
{t("detailsStep.amount")}
€
onEurAmountChange(Number(e.target.value))} style={styles.slider} />
{formatEur(eurMin * 100)} {formatEur(eurMax * 100)}
{/* Trade Summary */}
{direction === "buy" ? (

{t("detailsStep.summaryBuy", { sats: "", eur: "" }).split("{sats}")[0].trim()}{" "} {", "} {t("detailsStep.summaryBuy", { sats: "", eur: "" }) .split("{sats}")[1] ?.split("{eur}")[0] ?.trim()}{" "} {formatEur(eurAmount)}

) : (

{t("detailsStep.summarySell", { sats: "", eur: "" }) .split("{sats}")[0] ?.split("{eur}")[0] ?.trim()}{" "} {formatEur(eurAmount)} {", "} {t("detailsStep.summarySell", { sats: "", eur: "" }) .split("{sats}")[0] ?.split("{eur}")[1] ?.trim()}{" "} {t("detailsStep.summarySell", { sats: "", eur: "" }).split("{sats}")[1]?.trim()}

)}
{/* Continue Button */}
); }