import React, { useState } from 'react';
import { X, Lock, CheckCircle2, CreditCard, Shield, Truck, Sparkles, ArrowLeft, ChevronRight, Check, Download } from 'lucide-react';
import { CartItem, Address, Order } from '../types';
import { downloadOrderInvoice } from '../utils/invoiceGenerator';
interface CheckoutModalProps {
isOpen: boolean;
onClose: () => void;
items: CartItem[];
savedAddresses: Address[];
onOrderPlaced: (order: Order) => void;
onOpenOrderInAccount: (orderId: string) => void;
initialPaymentMethod?: 'Apple Pay' | 'Credit Card';
}
export const CheckoutModal: React.FC
= ({
isOpen,
onClose,
items,
savedAddresses,
onOrderPlaced,
onOpenOrderInAccount,
initialPaymentMethod = 'Credit Card',
}) => {
if (!isOpen) return null;
// Selected saved address or custom input
const defaultAddr = savedAddresses.find((a) => a.isDefault) || savedAddresses[0];
const [selectedSavedAddrId, setSelectedSavedAddrId] = useState(defaultAddr ? defaultAddr.id : 'custom');
const [addressForm, setAddressForm] = useState(
defaultAddr || {
id: 'custom-addr',
label: 'New Address',
fullName: 'Eleanor Vance',
street: '740 Park Avenue',
apartment: 'Apt 14B',
city: 'New York',
state: 'NY',
postalCode: '10021',
country: 'United States',
phone: '+1 (212) 555-0198',
isDefault: false,
}
);
const [email, setEmail] = useState('eleanor.vance@vancemedia.com');
const [phone, setPhone] = useState('+1 (212) 555-0198');
const [shippingMethod, setShippingMethod] = useState<'standard' | 'express'>('standard');
const [paymentMethod, setPaymentMethod] = useState<'Apple Pay' | 'Credit Card'>(initialPaymentMethod);
// Credit card state
const [cardNumber, setCardNumber] = useState('4242 •••• •••• 4092');
const [cardExpiry, setCardExpiry] = useState('08/28');
const [cardCvc, setCardCvc] = useState('883');
const [cardName, setCardName] = useState('Eleanor Vance');
const [saveCard, setSaveCard] = useState(true);
// Promo code state
const [promoCode, setPromoCode] = useState('');
const [appliedPromo, setAppliedPromo] = useState<{ code: string; discountPercent?: number; fixedDiscount?: number } | null>({
code: 'WARDROBE15',
discountPercent: 15,
});
const [promoError, setPromoError] = useState('');
// Processing & Confirmation
const [isSubmitting, setIsSubmitting] = useState(false);
const [applePaySheetActive, setApplePaySheetActive] = useState(false);
const [applePayBiometricState, setApplePayBiometricState] = useState<'scanning' | 'success' | 'idle'>('idle');
const [completedOrder, setCompletedOrder] = useState(null);
// Price calculations
const subtotal = items.reduce((acc, item) => acc + item.price * item.quantity, 0);
const shippingCost = shippingMethod === 'express' ? 25 : 0;
let discount = 0;
if (appliedPromo) {
if (appliedPromo.discountPercent) {
discount = Math.round((subtotal * appliedPromo.discountPercent) / 100);
} else if (appliedPromo.fixedDiscount) {
discount = appliedPromo.fixedDiscount;
}
}
const taxableAmount = Math.max(0, subtotal - discount);
const tax = Math.round(taxableAmount * 0.08875); // NY Tax ~8.875%
const finalTotal = taxableAmount + shippingCost + tax;
const handleApplyPromo = () => {
setPromoError('');
const code = promoCode.trim().toUpperCase();
if (code === 'WARDROBE15' || code === 'VIP15') {
setAppliedPromo({ code, discountPercent: 15 });
setPromoCode('');
} else if (code === 'ATELIER') {
setAppliedPromo({ code, fixedDiscount: 100 });
setPromoCode('');
} else {
setPromoError('Voucher code invalid or expired. Try "WARDROBE15"');
}
};
const handleSelectSavedAddress = (addr: Address) => {
setSelectedSavedAddrId(addr.id);
setAddressForm(addr);
};
const executeOrderPlacement = (method: 'Apple Pay' | 'Credit Card') => {
setIsSubmitting(true);
setTimeout(() => {
const newOrder: Order = {
id: `TW-${Math.floor(10000 + Math.random() * 90000)}`,
date: new Date().toISOString().split('T')[0],
status: 'Preparing at Atelier',
items: items.map((it) => ({
productId: it.productId,
productName: it.product.name,
image: it.selectedColor.image || it.product.images[0],
colorName: it.selectedColor.name,
size: it.selectedSize,
quantity: it.quantity,
price: it.price,
})),
subtotal,
shippingMethod:
shippingMethod === 'express'
? 'Priority Evening White-Glove Courier'
: 'Complimentary White-Glove Delivery',
shippingCost,
discount,
tax,
total: finalTotal,
shippingAddress: addressForm,
paymentMethod: method,
cardLastFour: method === 'Credit Card' ? cardNumber.slice(-4).replace(/\D/g, '') || '4092' : undefined,
trackingNumber: `TW-COURIER-${Math.floor(1000000 + Math.random() * 9000000)}`,
estimatedDelivery: '3 business days',
};
setIsSubmitting(false);
setCompletedOrder(newOrder);
onOrderPlaced(newOrder);
}, 1400);
};
const triggerApplePayFlow = () => {
setApplePaySheetActive(true);
setApplePayBiometricState('scanning');
setTimeout(() => {
setApplePayBiometricState('success');
setTimeout(() => {
setApplePaySheetActive(false);
executeOrderPlacement('Apple Pay');
}, 900);
}, 1600);
};
// Card formatting
const handleCardNumberChange = (e: React.ChangeEvent) => {
let val = e.target.value.replace(/\D/g, '').substring(0, 16);
let formatted = val.match(/.{1,4}/g)?.join(' ') || val;
setCardNumber(formatted);
};
return (
{/* Top Luxury Checkout Navigation Bar */}
Return to Boutique
•
256-Bit SSL Encrypted Checkout
The Wardrobe
{/* ORDER CONFIRMATION VIEW */}
{completedOrder ? (
Order Confirmed • Atelier Notified
Thank You, {addressForm.fullName}
Your garments are being prepared at our master atelier in Biella and Paris. An executive dispatch confirmation has been dispatched to {email}.
{/* Receipt Summary Card */}
Order Reference
{completedOrder.id}
Payment Method
{completedOrder.paymentMethod}
Delivery Address
{addressForm.fullName} • {addressForm.street}, {addressForm.apartment && `${addressForm.apartment}, `}{addressForm.city}, {addressForm.state} {addressForm.postalCode}
Purchased Ensemble
{completedOrder.items.map((it, idx) => (
{it.quantity}x {it.productName} ({it.size}, {it.colorName})
${(it.price * it.quantity).toLocaleString()}
))}
Total Charged
${completedOrder.total.toLocaleString()}
downloadOrderInvoice(completedOrder)}
className="w-full sm:w-auto px-6 py-3.5 bg-[#B88E4B] hover:bg-[#C7A66C] text-[#111111] text-xs uppercase tracking-[0.2em] font-bold transition-colors flex items-center justify-center gap-2 shadow-sm"
id="download-order-invoice-btn"
>
Download Invoice Receipt
onOpenOrderInAccount(completedOrder.id)}
className="w-full sm:w-auto px-6 py-3.5 bg-[#111111] hover:bg-neutral-800 text-white text-xs uppercase tracking-[0.2em] font-semibold transition-colors"
id="view-in-order-history-btn"
>
View in Order History
Continue Shopping
) : (
/* ONE-PAGE CHECKOUT FORM */
{/* Left Column: Form Details (7 cols) */}
{/* Express Apple Pay Banner */}
Express Luxury Checkout
Pay with
Pay
{/* Step 1: Contact Information */}
1
Contact Information
Logged in as Gold VIP Client
{/* Step 2: Shipping Destination & Saved Addresses */}
2
Shipping Destination
Saved Addresses Available
{/* Saved Address Quick Select */}
{savedAddresses.length > 0 && (
{savedAddresses.map((addr) => (
handleSelectSavedAddress(addr)}
className={`p-3.5 border cursor-pointer transition-all ${
selectedSavedAddrId === addr.id
? 'bg-[#FAF7EF] border-[#B88E4B] ring-1 ring-[#B88E4B]'
: 'bg-white border-neutral-200 hover:border-neutral-400'
}`}
>
{addr.label}
{addr.isDefault && (
Default
)}
{addr.fullName}, {addr.street}, {addr.city}, {addr.state} {addr.postalCode}
))}
)}
{/* Form fields */}
{/* Step 3: Courier Selection */}
3
Delivery Method
setShippingMethod('standard')}
className={`p-4 border flex items-start justify-between cursor-pointer transition-all ${
shippingMethod === 'standard'
? 'bg-[#FAF7EF] border-[#B88E4B] ring-1 ring-[#B88E4B]'
: 'bg-white border-neutral-200 hover:border-neutral-400'
}`}
>
Complimentary White-Glove
2-3 Business Days • Embossed Box
FREE
setShippingMethod('express')}
className={`p-4 border flex items-start justify-between cursor-pointer transition-all ${
shippingMethod === 'express'
? 'bg-[#FAF7EF] border-[#B88E4B] ring-1 ring-[#B88E4B]'
: 'bg-white border-neutral-200 hover:border-neutral-400'
}`}
>
Priority Atelier Evening
Next-Day Guaranteed by 7PM
$25.00
{/* Step 4: Payment Method */}
4
Payment Method
{/* Method selector tabs */}
setPaymentMethod('Apple Pay')}
className={`py-3 px-4 border text-xs uppercase tracking-wider font-medium flex items-center justify-center gap-2 transition-all ${
paymentMethod === 'Apple Pay'
? 'bg-black text-white border-black shadow-xs'
: 'bg-white text-neutral-700 border-neutral-300 hover:border-neutral-400'
}`}
>
Apple Pay
Pay
setPaymentMethod('Credit Card')}
className={`py-3 px-4 border text-xs uppercase tracking-wider font-medium flex items-center justify-center gap-2 transition-all ${
paymentMethod === 'Credit Card'
? 'bg-[#111111] text-white border-[#111111] shadow-xs'
: 'bg-white text-neutral-700 border-neutral-300 hover:border-neutral-400'
}`}
>
Credit Card
{/* Credit card fields */}
{paymentMethod === 'Credit Card' && (
)}
{/* Apple pay info */}
{paymentMethod === 'Apple Pay' && (
One-Touch Biometric Authentication
Clicking 'Complete Purchase' will initiate the native Apple Pay authorization prompt with Face ID / Touch ID verification.
)}
{/* Right Column: Sticky Order Review & Confirmation Action (5 cols) */}
Order Summary ({items.length} {items.length === 1 ? 'Piece' : 'Pieces'})
{/* Items List */}
{items.map((it) => (
{it.product.name}
{it.selectedColor.name} • Size {it.selectedSize} • Qty: {it.quantity}
${(it.price * it.quantity).toLocaleString()}
))}
{/* Promo Code Input */}
setPromoCode(e.target.value)}
placeholder="VIP Voucher (e.g. WARDROBE15)"
className="flex-1 border border-neutral-300 px-3 py-2 text-xs uppercase focus:outline-none focus:border-[#B88E4B]"
/>
Apply
{appliedPromo && (
Voucher '{appliedPromo.code}' Active
setAppliedPromo(null)}
className="text-neutral-400 hover:text-red-600 underline"
>
Remove
)}
{promoError &&
{promoError}
}
{/* Cost Breakdown */}
Subtotal
${subtotal.toLocaleString()}
{discount > 0 && (
VIP Privilege Discount
-${discount.toLocaleString()}
)}
White-Glove Courier
{shippingCost === 0 ? 'Complimentary' : `$${shippingCost}`}
Sales Tax (NY 8.875%)
${tax.toLocaleString()}
Total Due
${finalTotal.toLocaleString()}
{/* Action Button */}
{paymentMethod === 'Apple Pay' ? (
Authorize with
Pay
• ${finalTotal.toLocaleString()}
) : (
executeOrderPlacement('Credit Card')}
disabled={isSubmitting}
className="w-full py-4 bg-[#111111] hover:bg-[#B88E4B] text-white text-xs uppercase tracking-[0.22em] font-semibold transition-all duration-300 flex items-center justify-center gap-2 shadow-lg hover:shadow-xl"
id="confirm-card-order-btn"
>
{isSubmitting ? (
Authorizing Atelier Order...
) : (
<>
Place Atelier Order • ${finalTotal.toLocaleString()}
>
)}
)}
30-Day Home Trial
•
Free Returns
•
Bespoke Hemming
)}
{/* Realistic Apple Pay Biometric Sheet Modal Simulation */}
{applePaySheetActive && (
Pay
The Wardrobe Boutique
{/* Biometric Scanning Visual */}
{applePayBiometricState === 'scanning' ? (
) : (
)}
{applePayBiometricState === 'scanning' ? 'Verifying with Face ID...' : 'Payment Authorized'}
Apple Card •••• 4092
${finalTotal.toLocaleString()}
Shipped to {addressForm.street}, {addressForm.city}
)}
);
};
Comments
Post a Comment