// ===== Shared page wrapper ===== // Hosts announcement, header, mega-nav, footer, cart drawer, product modal, toast. // Pages render their content inside .... const { useState: useWS, useEffect: useWE } = React; const useCart = () => { const [cart, setCart] = useWS(() => { try { return JSON.parse(localStorage.getItem("store_cart")) || []; } catch { return []; } }); useWE(() => { localStorage.setItem("store_cart", JSON.stringify(cart)); }, [cart]); return [cart, setCart]; }; const useFaves = () => { const [faves, setFaves] = useWS(() => { try { return new Set(JSON.parse(localStorage.getItem("store_faves")) || []); } catch { return new Set(); } }); useWE(() => { localStorage.setItem("store_faves", JSON.stringify([...faves])); }, [faves]); return [faves, setFaves]; }; // ---------- Cart Drawer ---------- const CartDrawer = ({ open, onClose, items, onQty, onRemove, onCheckout }) => { const subtotal = items.reduce((s, it) => s + it.p.price * it.qty, 0); const shipping = subtotal > 50000 || items.length === 0 ? 0 : 1200; const total = subtotal + shipping; return ( <>
); }; // ---------- Product Modal ---------- const ProductModal = ({ p, onClose, onAdd }) => { const [qty, setQty] = useWS(1); const [thumb, setThumb] = useWS(0); useWE(() => { setQty(1); setThumb(0); }, [p?.id]); if (!p) return null; const discount = p.was ? Math.round((1 - p.price / p.was) * 100) : 0; return (
e.stopPropagation()}>
{p.badges.map((b, i) => { const cls = b.includes("%") ? "sale" : b === "NEW" ? "new" : "hot"; return {b}; })}
{p.img ? ( {p.name} ) : ( {p.cat.toLowerCase()}.hero.render )}
{[0,1,2,3].map(i => (
setThumb(i)}>
))}
{p.brand} · SKU APT-{1000 + p.id}

{p.name}

{p.rating.toFixed(1)} ({p.reviews} reviews) In stock — {p.stock} left
{money(p.price)} DZD {p.was && {money(p.was)} DZD} {p.was && -{discount}%}
VAT included · Ships in 24h from Algiers warehouse
{p.specs.map((s, i) => { const labels = ["Chipset", "Memory", "Speed", "Form factor"]; return (
{labels[i] || "Spec"}
{s}
); })}
Warranty
2 years
Ships from
Algiers, DZ
{qty}
Full details
Free delivery on 50K+
2-year warranty
14-day returns
Compatibility-verified
); }; const Toast = ({ msg, show }) => (
{msg}
); // ---------- Algerian Checkout Modal ---------- const WILAYAS = [ ["16","Alger",400], ["31","Oran",600], ["25","Constantine",600], ["19","Sétif",500], ["09","Blida",450], ["35","Boumerdès",450], ["06","Béjaïa",550], ["23","Annaba",650], ["15","Tizi Ouzou",500], ["05","Batna",650], ["02","Chlef",550], ["27","Mostaganem",650], ["13","Tlemcen",700], ["22","Sidi Bel Abbès",700], ["44","Aïn Defla",500], ["42","Tipaza",450], ["10","Bouira",500], ["26","Médéa",500], ["38","Tissemsilt",600], ["48","Relizane",600], ["29","Mascara",650], ["46","Aïn Témouchent",700], ["20","Saïda",700], ["14","Tiaret",650], ["17","Djelfa",750], ["28","M'Sila",700], ["34","Bordj Bou Arréridj",550], ["18","Jijel",600], ["21","Skikda",650], ["43","Mila",600], ["24","Guelma",700], ["36","El Tarf",750], ["41","Souk Ahras",700], ["04","Oum El Bouaghi",700], ["12","Tébessa",800], ["40","Khenchela",750], ["07","Biskra",800], ["39","El Oued",900], ["30","Ouargla",1000], ["32","El Bayadh",900], ["45","Naâma",900], ["08","Béchar",1100], ["37","Tindouf",1300], ["11","Tamanrasset",1500], ["33","Illizi",1500], ["47","Ghardaïa",1000], ["01","Adrar",1200], ["03","Laghouat",800], ]; const CheckoutModal = ({ open, items, onClose, onConfirm }) => { const [step, setStep] = useWS(1); const [form, setForm] = useWS({ name: "", phone: "", wilaya: "16", commune: "", address: "", delivery: "home", notes: "", payment: "cod", }); const [submitting, setSubmitting] = useWS(false); const [orderId, setOrderId] = useWS(null); useWE(() => { if (open) { setStep(1); setOrderId(null); } }, [open]); const wilayaInfo = WILAYAS.find(w => w[0] === form.wilaya) || WILAYAS[0]; const homeFee = wilayaInfo[2]; const stopdeskFee = Math.round(homeFee * 0.6); const deliveryFee = form.delivery === "home" ? homeFee : stopdeskFee; const subtotal = items.reduce((s, it) => s + it.p.price * it.qty, 0); const total = subtotal + deliveryFee; const set = (k, v) => setForm(p => ({ ...p, [k]: v })); const phoneOk = /^0(5|6|7)\d{8}$/.test(form.phone.replace(/\s/g, "")); const canContinue = (step === 1) || (step === 2 && form.name.trim().length >= 3 && phoneOk && form.address.trim().length >= 5); const submit = () => { setSubmitting(true); setTimeout(() => { setSubmitting(false); const id = "APT-" + Math.floor(100000 + Math.random() * 900000); setOrderId(id); setStep(3); onConfirm && onConfirm(); }, 1100); }; if (!open) return null; return (
e.stopPropagation()}>
Secure checkout · Paiement à la livraison

{step === 3 ? "Order confirmed" : "Finalize your order"}

{step !== 3 && (
= 1 ? "active" : ""}`}> 1 Review
= 2 ? "active" : ""}`}> 2 Delivery & contact
= 3 ? "active" : ""}`}> 3 Confirmation
)}
{step === 1 && (

Order items ({items.reduce((s, i) => s + i.qty, 0)})

{items.map(it => (
{it.p.brand}
{it.p.name}
Qty: {it.qty} × {money(it.p.price)} DZD
{money(it.p.price * it.qty)} DZD
))}
)} {step === 2 && (

Contact

Delivery

Payment

)} {step === 3 && (

Thank you, {form.name.split(" ")[0]}!

Your order {orderId} has been placed. We'll call +213 {form.phone} within 2 hours to confirm, then dispatch to {wilayaInfo[1]} for delivery in 2–4 working days.

Order total {money(total)} DZD
Payment {form.payment === "cod" ? "Cash on delivery" : "Online (CIB / Edahabia)"}
Delivery {form.delivery === "home" ? "Home delivery" : "Stop-desk pickup"}
Back to shop
)}
{step !== 3 && ( )}
); }; window.CheckoutModal = CheckoutModal; const PageWrapper = ({ children, query, setQuery }) => { const [cart, setCart] = useCart(); const [faves, setFaves] = useFaves(); const [drawer, setDrawer] = useWS(false); const [modal, setModal] = useWS(null); const [toast, setToast] = useWS({ msg: "", show: false }); const [internalQ, setInternalQ] = useWS(""); const [checkout, setCheckout] = useWS(null); // null or { items, source } const q = query ?? internalQ; const setQ = setQuery ?? setInternalQ; const showToast = (msg) => { setToast({ msg, show: true }); setTimeout(() => setToast({ msg: "", show: false }), 2200); }; const addToCart = (p, qty = 1) => { setCart(prev => { const found = prev.find(it => it.p.id === p.id); if (found) return prev.map(it => it.p.id === p.id ? { ...it, qty: it.qty + qty } : it); return [...prev, { p, qty }]; }); showToast(`${p.name.split(" ").slice(0, 4).join(" ")} added to cart`); }; const setQty = (id, qty) => { if (qty < 1) return removeFromCart(id); setCart(prev => prev.map(it => it.p.id === id ? { ...it, qty } : it)); }; const removeFromCart = (id) => setCart(prev => prev.filter(it => it.p.id !== id)); const toggleFav = (id) => setFaves(prev => { const next = new Set(prev); next.has(id) ? next.delete(id) : next.add(id); return next; }); const openCheckout = (items, source = "buynow") => { if (!items || items.length === 0) return; setCheckout({ items, source }); setDrawer(false); setModal(null); }; const onCheckoutConfirm = () => { if (checkout?.source === "cart") setCart([]); }; useWE(() => { const onKey = (e) => { if (e.key === "Escape") { setDrawer(false); setModal(null); setCheckout(null); } }; window.addEventListener("keydown", onKey); return () => window.removeEventListener("keydown", onKey); }, []); const cartCount = cart.reduce((s, it) => s + it.qty, 0); const ctx = { addToCart, openModal: setModal, faves, toggleFav, openCheckout, cart }; return (
setDrawer(true)} query={q} setQuery={setQ} /> {typeof children === "function" ? children(ctx) : children} setDrawer(false)} items={cart} onQty={setQty} onRemove={removeFromCart} onCheckout={() => openCheckout(cart, "cart")} /> {modal && ( setModal(null)} onAdd={addToCart} /> )} setCheckout(null)} onConfirm={onCheckoutConfirm} />
); }; window.PageWrapper = PageWrapper; window.CartDrawer = CartDrawer; window.ProductModal = ProductModal; window.Toast = Toast;