diff --git a/src/app/checkout/page.tsx b/src/app/checkout/page.tsx new file mode 100644 index 0000000..b5d30e9 --- /dev/null +++ b/src/app/checkout/page.tsx @@ -0,0 +1,143 @@ +'use client' +import { useState, useEffect } from 'react' +import { useRouter } from 'next/navigation' +import Link from 'next/link' +import { useVulaCart } from '@/hooks/useVulaCart' +import { useCustomerAuth } from '@/hooks/useCustomerAuth' +import { CircleCheck, Loader2 } from 'lucide-react' + +function fmt(amount: number) { return `R${(amount / 100).toFixed(2)}` } + +export default function CheckoutPage() { + const { items, subtotal, itemCount, checkout, loading, error } = useVulaCart() + const { customer, isAuthenticated } = useCustomerAuth() + const router = useRouter() + const [done, setDone] = useState<{ orderNumber: string } | null>(null) + const [form, setForm] = useState({ + customerName: '', customerEmail: '', customerPhone: '', + fulfillmentType: 'delivery', notes: '', + address_line1: '', city: '', province: '', postal_code: '' + }) + + useEffect(() => { + if (!customer) return + setForm(f => ({ + ...f, + customerName: f.customerName || [customer.first_name, customer.last_name].filter(Boolean).join(' '), + customerEmail: f.customerEmail || customer.email, + customerPhone: f.customerPhone || (customer.phone ?? ''), + address_line1: f.address_line1 || (customer.address_line1 ?? ''), + city: f.city || (customer.city ?? ''), + province: f.province || (customer.province ?? ''), + postal_code: f.postal_code || (customer.postal_code ?? ''), + })) + }, [customer]) + + const set = (k: string) => (e: React.ChangeEvent) => + setForm(f => ({ ...f, [k]: e.target.value })) + + if (done) return ( +
+ +

Order Placed!

+

Order {done.orderNumber} has been received. We'll be in touch shortly.

+ + Continue Shopping + +
+ ) + + if (!itemCount) return ( +
+

Your cart is empty.

+ Browse Products +
+ ) + + async function handleSubmit(e: React.FormEvent) { + e.preventDefault() + try { + const order = await checkout({ + customerName: form.customerName, + customerEmail: form.customerEmail, + customerPhone: form.customerPhone || undefined, + fulfillmentType: form.fulfillmentType, + notes: form.notes || undefined, + shippingAddress: form.fulfillmentType !== 'pickup' ? { + address_line1: form.address_line1, city: form.city, + province: form.province || undefined, postal_code: form.postal_code || undefined + } : undefined + }) + setDone({ orderNumber: order.order_number }) + } catch {} + } + + const inputCls = "w-full border border-border rounded-lg px-3 py-2.5 bg-background text-sm focus:outline-none focus:ring-2 focus:ring-primary/40" + const labelCls = "block text-sm font-medium mb-1" + + return ( +
+
+

Checkout

+
+
+
+
+

Your Details

+ {isAuthenticated && ( + + Signed in · My orders + + )} +
+
+
+
+
+
+
+ +
+

Delivery

+
+ + +
+ {form.fulfillmentType === 'delivery' && ( +
+
+
+
+
+
+
+
+ )} +