const CheckoutPage = ({ cart, setCart, setPage, lang, user }) => { const t = (en, id) => lang === "id" ? id : en; const [step, setStep] = React.useState(1); const [orderNumber, setOrderNumber] = React.useState(""); const [form, setForm] = React.useState({ name: user?.name || "", email: user?.email || "", phone: "", address: "", province: "", city: "", district: "", postal: "", notes: "" }); const [courier, setCourier] = React.useState(null); const [couriers, setCouriers] = React.useState([]); const [shippingLoad, setShippingLoad] = React.useState(false); const [shippingErr, setShippingErr] = React.useState(""); const [payment, setPayment] = React.useState("duitku"); const [postalQueried, setPostalQueried] = React.useState(""); const set = (k, v) => setForm(f => ({ ...f, [k]: v })); // InitiateCheckout — sekali saat halaman checkout dibuka React.useEffect(() => { if (typeof fbq === 'function') { fbq('track', 'InitiateCheckout', { content_ids: cart.map(i => String(i.id)), content_type: 'product', num_items: cart.reduce((s, i) => s + i.qty, 0), value: cart.reduce((s, i) => s + i.price * i.qty, 0), currency: 'IDR' }); } }, []); // Load alamat tersimpan saat pertama buka React.useEffect(() => { if (!user) return; fetch("api/account.php", { credentials:"include" }) .then(r => r.json()) .then(d => { if (d.user?.saved_address) { const a = d.user.saved_address; setForm(f => ({ ...f, address: a.address || f.address, district: a.district || f.district, city: a.city || f.city, province: a.province || f.province, postal: a.postal || f.postal, })); } if (d.user?.phone) setForm(f => ({ ...f, phone: f.phone || d.user.phone })); }).catch(() => {}); }, [user]); const subtotal = cart.reduce((s, i) => s + i.price * i.qty, 0); // Voucher state const [voucherCode, setVoucherCode] = React.useState(""); const [voucherInput, setVoucherInput] = React.useState(""); const [voucher, setVoucher] = React.useState(null); // { code, type, value, discount } const [voucherErr, setVoucherErr] = React.useState(""); const [voucherChecking, setVoucherChecking] = React.useState(false); // Free shipping state const [freeShip, setFreeShip] = React.useState(null); // { eligible, rule } | null // Re-validate voucher kalau subtotal berubah (qty change) React.useEffect(() => { if (!voucher) return; fetch("api/promo.php?action=validate_voucher", { method:"POST", headers:{"Content-Type":"application/json"}, body: JSON.stringify({ code: voucher.code, subtotal }) }).then(r => r.json()).then(d => { if (d.success) setVoucher({ ...voucher, discount: d.discount }); else { setVoucher(null); setVoucherErr(d.error || ""); } }); // eslint-disable-next-line }, [subtotal]); // Check free shipping eligibility kalau cart/postal berubah React.useEffect(() => { if (!form.postal || cart.length === 0) { setFreeShip(null); return; } fetch("api/promo.php?action=check_free_shipping", { method:"POST", headers:{"Content-Type":"application/json"}, body: JSON.stringify({ items: cart.map(i => ({ id:i.id, qty:i.qty, price:i.price })), subtotal, postal: form.postal }) }).then(r => r.json()).then(d => setFreeShip(d)).catch(() => {}); }, [form.postal, cart.length, subtotal]); const applyVoucher = async () => { const code = voucherInput.trim().toUpperCase(); if (!code) { setVoucherErr("Masukkan kode voucher"); return; } setVoucherChecking(true); setVoucherErr(""); try { const r = await fetch("api/promo.php?action=validate_voucher", { method:"POST", headers:{"Content-Type":"application/json"}, body: JSON.stringify({ code, subtotal }) }); const d = await r.json(); if (d.success) { setVoucher({ ...d.voucher, discount: d.discount }); setVoucherCode(code); setVoucherErr(""); } else { setVoucherErr(d.error || "Voucher tidak valid"); setVoucher(null); } } catch (e) { setVoucherErr("Gagal cek voucher"); } finally { setVoucherChecking(false); } }; const removeVoucher = () => { setVoucher(null); setVoucherCode(""); setVoucherInput(""); setVoucherErr(""); try { localStorage.removeItem("lopobya_pending_voucher"); } catch {} }; // Auto-apply voucher dari Welcome Popup (Meta ads) — sekali saja const autoVoucherTried = React.useRef(false); React.useEffect(() => { if (autoVoucherTried.current || voucher || subtotal <= 0) return; let code = ""; try { code = (localStorage.getItem("lopobya_pending_voucher") || "").trim().toUpperCase(); } catch {} if (!code) return; autoVoucherTried.current = true; fetch("api/promo.php?action=validate_voucher", { method:"POST", headers:{"Content-Type":"application/json"}, body: JSON.stringify({ code, subtotal }) }).then(r => r.json()).then(d => { if (d.success) { setVoucher({ ...d.voucher, discount: d.discount }); setVoucherCode(code); } }).catch(() => {}); }, [subtotal, voucher]); // Hitung ongkir & total dengan voucher + free shipping const courierPrice = courier ? courier.price : 0; const isFreeShip = freeShip?.eligible === true; const ongkir = isFreeShip ? 0 : courierPrice; const discount = voucher?.discount || 0; const total = Math.max(0, subtotal - discount + ongkir); const inputStyle = { width:"100%", padding:"12px 14px", background:"#fff", border:"1px solid #e8e6e2", fontFamily:"'DM Sans',sans-serif", fontSize:13, color:"#111", outline:"none", boxSizing:"border-box", transition:"border-color 0.2s", borderRadius:2 }; const labelStyle = { fontFamily:"'DM Sans',sans-serif", fontSize:10, letterSpacing:"0.14em", textTransform:"uppercase", color:"#888", display:"block", marginBottom:8, fontWeight:600 }; const btnPrimary = { padding:"14px 32px", background:"#111", border:"none", cursor:"pointer", fontFamily:"'DM Sans',sans-serif", fontSize:11, letterSpacing:"0.16em", textTransform:"uppercase", color:"#f9f8f6", fontWeight:600, borderRadius:2 }; const btnSecondary = { padding:"14px 24px", background:"none", border:"1px solid #e8e6e2", cursor:"pointer", fontFamily:"'DM Sans',sans-serif", fontSize:11, letterSpacing:"0.12em", textTransform:"uppercase", color:"#888", borderRadius:2 }; // Fetch ongkir dari Biteship const fetchRates = async () => { if (!form.postal || form.postal.length !== 5) { setShippingErr("Kode pos harus 5 digit"); return; } if (form.postal === postalQueried) return; // sudah pernah dicek setShippingLoad(true); setShippingErr(""); setCouriers([]); setCourier(null); try { const res = await fetch("api/shipping.php", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ destination_postal: form.postal, items: cart.map(i => ({ name: i.name, price: i.price, qty: i.qty })) }) }); const data = await res.json(); if (!res.ok || data.error) { setShippingErr(data.error || "Gagal mengambil tarif pengiriman"); return; } const pricing = data.pricing || []; if (!pricing.length) { setShippingErr("Tidak ada kurir tersedia untuk kode pos ini"); return; } // Deduplikasi: ambil harga termurah per kurir+service const seen = new Set(); const clean = pricing .filter(p => { const key = p.courier_code + "-" + p.courier_service_code; if (seen.has(key)) return false; seen.add(key); return true; }) .sort((a, b) => a.price - b.price); setCouriers(clean); setCourier(clean[0]); // default pilih yang termurah setPostalQueried(form.postal); } catch(e) { setShippingErr("Gagal terhubung ke server pengiriman"); } finally { setShippingLoad(false); } }; // Step 4 — Success if (step === 4) return (

{t("Order Placed!","Pesanan Diterima!")}

{t(`Thank you, ${form.name}! We'll confirm your order shortly.`, `Terima kasih, ${form.name}! Kami akan segera konfirmasi pesananmu.`)}

{t("Confirmation will be sent to","Konfirmasi dikirim ke")} {form.email}

{t("Order Summary","Ringkasan Pesanan")}

{cart.map(item => (
{item.name}{item.selectedVariant ? " — " + item.selectedVariant : ""} ×{item.qty} {formatPrice(item.price * item.qty)}
))}
Subtotal {formatPrice(subtotal)}
{courier && (
{courier.courier_name} {courier.courier_service_name} {formatPrice(courier.price)}
)}
Total {formatPrice(total)}
{orderNumber && (

Nomor Pesananmu:

{orderNumber}

🚚 Lacak Pesanan
)}
); const steps = [t("Information","Informasi"), t("Shipping","Pengiriman"), t("Payment","Pembayaran")]; return (
{/* Header */}
LOPOBYA
{steps.map((s, i) => (
i+1 ? "#111" : step === i+1 ? "#111" : "#e8e6e2", display:"flex", alignItems:"center", justifyContent:"center" }}> {step > i+1 ? : {i+1} }
{s}
{i < steps.length-1 &&
i+1?"#111":"#e8e6e2", margin:"0 8px", marginBottom:24, flexShrink:0 }} />} ))}
{/* Form */}
{/* ── Step 1: Informasi Kontak ── */} {step === 1 && (

{t("Contact Information","Informasi Kontak")}

set("name",e.target.value)} placeholder={t("Your full name","Nama lengkap kamu")} />
set("email",e.target.value)} placeholder="email@example.com" />
set("phone",e.target.value)} placeholder="08xx xxxx xxxx" />
)} {/* ── Step 2: Alamat + Kurir ── */} {step === 2 && (

{t("Shipping Address","Alamat Pengiriman")}

set("address",e.target.value)} placeholder={t("Street, No., RT/RW","Jalan, No., RT/RW")} />
{ set("city", city); set("district", district); set("province", province); if (postal) { set("postal", postal); setPostalQueried(""); setCouriers([]); setCourier(null); } }} />
{ set("postal",e.target.value.replace(/\D/g,"")); setPostalQueried(""); setCouriers([]); setCourier(null); }} maxLength={5} placeholder="16680" onKeyDown={e => e.key==="Enter" && fetchRates()} />