// src/account.jsx — Account + Address-picker screens. Both real, both interactive. // AccountScreen: identity + standing + saved addresses + payment + preferences + recent orders + neighborhood credits. // AddressPicker: full-screen overlay; saved addresses, recent searches, "current location" tile, map preview, etc. // ─── AccountScreen ───────────────────────────────────────────────────────── function AccountScreen({ onNav }) { const isMobile = useMedia("(max-width: 720px)"); // Local state for toggles & defaults — feels real on click. const [defaultAddrId, setDefaultAddrId] = React.useState("home"); const [defaultPay, setDefaultPay] = React.useState("amex"); const [prefs, setPrefs] = React.useState({ plasticReturn: true, sundayDigest: true, notifyOpenLate: false, roundUp: true, leaveAtDoor: true, }); const togglePref = (k) => setPrefs(p => ({ ...p, [k]: !p[k] })); const orders = [ { id: "4821", status: "Out for delivery", store: "Kalymnos Deli", items: 3, total: 28.40, eta: "9 min", when: "Today, 6:42 PM" }, { id: "4799", status: "Pickup ready", store: "Fig & Thistle", items: 2, total: 41.00, eta: "Held til 8:30 PM", when: "Today, 5:10 PM" }, { id: "4754", status: "Delivered", store: "Verde Produce", items: 7, total: 32.18, eta: "", when: "Tue, 7:18 PM" }, { id: "4691", status: "Delivered", store: "Liu's 24hr", items: 4, total: 18.62, eta: "", when: "Sun, 11:24 PM" }, ]; const addresses = [ { id: "home", label: "Home", line1: "98 Orchard St, Apt 4B", line2: "New York, NY 10002", note: "Buzz 4B — door is unmarked", icon: "Pin" }, { id: "work", label: "Studio", line1: "315 W 36th St, Floor 9", line2: "New York, NY 10018", note: "Reception accepts after 6pm", icon: "Store" }, { id: "moms", label: "Mom's", line1: "1142 Carroll St", line2: "Brooklyn, NY 11225", note: "Stairs on the left", icon: "Heart" }, ]; const payments = [ { id: "amex", brand: "Amex", last4: "1004", exp: "06/27" }, { id: "visa", brand: "Visa", last4: "8821", exp: "11/26" }, { id: "ebt", brand: "EBT", last4: "—", exp: "" }, ]; return (
{/* Header band */}
{/* Decorative arcs */}
NG
Nikhil Gupta
Member since Mar 2024 · 84 orders · 6 stores supported
}>Edit profile Sign out
{/* Standing card — neighborhood credits */}
Block standing
$14.20 in store credits
{[ { k: "212", l: "bags saved" }, { k: "$32", l: "given pantry" }, { k: "9", l: "shared trips" }, ].map(s => (
{s.k}
{s.l}
))}
{/* Two-column layout: orders left, settings right (stack on mobile) */}
{/* LEFT — orders + addresses */}
{/* Recent orders */}
}>All orders} />
{orders.map(o => { const live = o.status === "Out for delivery" || o.status === "Pickup ready"; return (
{o.store} · {o.items} items · {money(o.total)}
{live && ● {o.status}{o.eta && ` · ${o.eta}`}} {!live && {o.status}} · {o.when} · #{o.id}
{live ? ( Track ) : ( }>Reorder )}
); })}
{/* Saved addresses */}
}>Add} />
{addresses.map(a => { const isDefault = defaultAddrId === a.id; const Icon = Icons[a.icon] || Icons.Pin; return ( ); })}
{/* RIGHT — payment, preferences, support */}
{/* Payment methods */}
}>Add} />
{payments.map(p => { const isDefault = defaultPay === p.id; return ( ); })}
{/* Preferences */}
{[ { k: "leaveAtDoor", label: "Leave at door", hint: "Default for all deliveries" }, { k: "plasticReturn", label: "Return bags & containers", hint: "Driver picks up empty totes" }, { k: "roundUp", label: "Round up for the LES pantry", hint: "$0.18 average per order" }, { k: "sundayDigest", label: "Sunday digest from your block", hint: "What's new at your shops" }, { k: "notifyOpenLate", label: "Tell me when shops stay open late", hint: "Push only, no email" }, ].map((row, i, arr) => ( ))}
{/* Support / legal */}
{[ { label: "Help center", icon: "Sparkle" }, { label: "Contact your last driver", icon: "Mic" }, { label: "Privacy & data", icon: "User" }, { label: "Terms", icon: "Receipt" }, ].map((row, i, arr) => { const Icon = Icons[row.icon] || Icons.Chevron; return ( ); })}
Opa v2.0 · build 4821 · made on Orchard St
); } // ─── Switch ──────────────────────────────────────────────────────────────── function Switch({ on }) { return ( ); } // ─── AddressPicker ───────────────────────────────────────────────────────── // Full-screen overlay. Triggered from the topbar address pill. function AddressPicker({ open, current, onClose, onPick }) { const isMobile = useMedia("(max-width: 720px)"); const [q, setQ] = React.useState(""); const inputRef = React.useRef(null); React.useEffect(() => { if (open) setTimeout(() => inputRef.current?.focus(), 100); if (!open) setQ(""); }, [open]); // Lock body scroll React.useEffect(() => { if (!open) return; const prev = document.body.style.overflow; document.body.style.overflow = "hidden"; return () => { document.body.style.overflow = prev; }; }, [open]); // ESC closes React.useEffect(() => { if (!open) return; const fn = (e) => { if (e.key === "Escape") onClose(); }; window.addEventListener("keydown", fn); return () => window.removeEventListener("keydown", fn); }, [open, onClose]); if (!open) return null; const saved = [ { id: "home", label: "Home", line: "98 Orchard St, Apt 4B · NY 10002", eta: "Default · 28 stores within 0.5 mi", icon: "Pin", tone: "navy" }, { id: "work", label: "Studio", line: "315 W 36th St, Floor 9 · NY 10018", eta: "12 stores within 0.5 mi", icon: "Store", tone: "navy" }, { id: "moms", label: "Mom's", line: "1142 Carroll St · Brooklyn, NY 11225", eta: "9 stores within 0.5 mi", icon: "Heart", tone: "navy" }, ]; const recent = [ { line: "55 Hudson Yards · NY 10001", last: "Tue" }, { line: "Brooklyn Bridge Park, Pier 2", last: "Sat — picnic order" }, { line: "230 5th Ave Rooftop · NY 10001", last: "Last month" }, ]; // crude filter const matches = q.trim() ? [...saved, ...recent.map(r => ({ id: r.line, label: r.line.split(" · ")[0], line: r.line }))] .filter(s => (s.label + " " + s.line).toLowerCase().includes(q.toLowerCase())) : null; return (
{ if (e.currentTarget === e.target) onClose(); }}>
{/* Header / search */}
Where are we delivering?
setQ(e.target.value)} placeholder="Address, intersection, or landmark" style={{ flex: 1, height: 28, border: 0, background: "transparent", outline: 0, color: "var(--ink)", fontSize: 14.5, fontFamily: "inherit" }} /> {q && ( )}
{/* Body — scrolls */}
{/* Use current location */} {!matches && ( <> {/* Saved */}
Saved
{saved.map(s => { const Icon = Icons[s.icon] || Icons.Pin; const isCurrent = current === s.id; return ( ); })}
{/* Recent */}
Recent
{recent.map((r) => ( ))}
{/* Schedule for later */}
Need it later? Tonight · Tomorrow · Pick a time
)} {matches && (
{matches.length} matches
{matches.map(m => ( ))} {matches.length === 0 && (
No saved or recent address matches "{q}". .
)}
)}
); } Object.assign(window, { AccountScreen, AddressPicker, Switch });