// RIFTR storefront — checkout: details + fulfillment, then TNG payment + receipt upload. (() => { const { Button, Input, Label, Card } = window.RIFTRDesignSystem_b64b32; const FULFILLMENT = [ { type: 'pickup', location: 'Boards & Brew, Sunway', fee: 0, sub: 'Self-collect' }, { type: 'meetup', location: 'Subang Jaya', fee: 0, sub: 'Meetup point' }, { type: 'meetup', location: 'Kota Kemuning', fee: 0, sub: 'Meetup point' }, { type: 'delivery', location: 'Peninsular Malaysia', fee: 10, sub: 'Courier · +RM10', needsAddress: true }, ]; const TYPE_LABEL = { pickup: 'Pickup', meetup: 'COD meetup', delivery: 'Delivery' }; function Field({ children }) { return
{children}
; } function Checkout({ cart, onBack, onClearCart }) { const RM = window.RIFTR_RM; const Ic = window.Ic; const [name, setName] = React.useState(''); const [email, setEmail] = React.useState(''); const [phone, setPhone] = React.useState(''); const [sel, setSel] = React.useState(null); const [address, setAddress] = React.useState(''); const [stage, setStage] = React.useState('form'); // form → pay → done const [order, setOrder] = React.useState(null); const [busy, setBusy] = React.useState(false); const [err, setErr] = React.useState(''); const [file, setFile] = React.useState(null); const [upBusy, setUpBusy] = React.useState(false); const [upErr, setUpErr] = React.useState(''); React.useEffect(() => { window.lucide && window.lucide.createIcons(); }); const subtotal = cart.reduce((a, b) => a + b.price * b.qty, 0); const fee = sel != null ? FULFILLMENT[sel].fee : 0; const total = subtotal + fee; async function placeOrder() { setErr(''); if (!name.trim()) return setErr('Please enter your name.'); if (!/^\S+@\S+\.\S+$/.test(email)) return setErr('Please enter a valid email.'); if (!phone.trim()) return setErr('Please enter your phone number.'); if (sel == null) return setErr('Please choose a fulfillment option.'); const opt = FULFILLMENT[sel]; if (opt.needsAddress && !address.trim()) return setErr('Please enter your delivery address.'); setBusy(true); try { const res = await fetch('/api/create_order.php', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ name, email, phone, fulfillment_type: opt.type, fulfillment_location: opt.location, delivery_address: opt.needsAddress ? address : '', items: cart.map((c) => ({ id: c.id, qty: c.qty })), }), }); const data = await res.json(); if (!data.ok) throw new Error(data.error || 'Could not place order.'); setOrder(data); onClearCart(); setStage('pay'); window.scrollTo({ top: 0 }); } catch (e) { setErr(e.message || 'Network error. Please try again.'); } finally { setBusy(false); } } async function uploadReceipt() { setUpErr(''); if (!file) return setUpErr('Please choose your receipt image first.'); setUpBusy(true); try { const fd = new FormData(); fd.append('order_id', order.order_id); fd.append('receipt', file); const res = await fetch('/api/upload_receipt.php', { method: 'POST', body: fd }); const data = await res.json(); if (!data.ok) throw new Error(data.error || 'Upload failed.'); setStage('done'); window.scrollTo({ top: 0 }); } catch (e) { setUpErr(e.message || 'Network error. Please try again.'); } finally { setUpBusy(false); } } // ---------- DONE ---------- if (stage === 'done') { return (

Receipt received

We're verifying your payment now. You'll get an email once it's confirmed — usually within a few hours.

{order.order_id}

Save this ID to track your order anytime.

); } // ---------- PAY ---------- if (stage === 'pay') { return (

Pay with TNG

Scan the QR with Touch ’n Go eWallet and pay the exact total. Then upload your receipt below.

{RM(order.total)}
TNG QR

ORDER {order.order_id}

{upErr &&

{upErr}

}

Save your order ID — {order.order_id}

); } // ---------- FORM ---------- return (

Checkout

{cart.length === 0 ? (

Your cart is empty.

) : (
{/* LEFT — details */}

Your details

setName(e.target.value)} placeholder="Your name" /> setEmail(e.target.value)} placeholder="you@email.com" /> setPhone(e.target.value)} placeholder="01X-XXXXXXX" />

Fulfillment

{FULFILLMENT.map((o, i) => { const on = sel === i; return ( ); })}
{sel != null && FULFILLMENT[sel].needsAddress && (
setAddress(e.target.value)} placeholder="Full address, postcode, state" />
)}
{/* RIGHT — summary */}

Order summary

{cart.map((it) => (
{it.qty}× {it.name} {RM(it.price * it.qty)}
))}
{RM(subtotal)}
{sel == null ? '—' : (fee ? RM(fee) : 'FREE')}
Total {RM(total)}
{err &&

{err}

}

Pay via TNG QR on the next step

)}
); } Object.assign(window, { Checkout }); })();