/* Willow Creek Portal — Resident experience: dashboard, payments, forms & signing. */ const { PIcon: RIcon, SignaturePad: RSignaturePad, PSection: RSection, KindBadge: RKindBadge, makeReceiptNo: rMakeReceiptNo, ReceiptModal: RReceiptModal } = window.WCPortal; const { useState: rUseState } = React; function ResidentPortal({ store, setStore, user, onLogout }) { const { Card, Button, Badge, Alert, Input, Textarea, ProgressBar, Tabs } = window.WillowCreekDesignSystem_90378c; const [tab, setTab] = rUseState("home"); const [activeForm, setActiveForm] = rUseState(null); const [payOpen, setPayOpen] = rUseState(false); const [receipt, setReceipt] = rUseState(null); const resident = store.residents.find((r) => r.name === user) || store.residents[0]; const signed = store.signedForms[resident.name] || []; const published = store.forms.filter((f) => f.status === "published"); const pendingForms = published.filter((f) => !signed.includes(f.id)); const myPayments = store.payments.filter((p) => p.resident === resident.name); const rate = store.cms.weeklyRate; const markSigned = (formId) => { setStore((s) => { const next = { ...s, signedForms: { ...s.signedForms, [resident.name]: [ ...(s.signedForms[resident.name] || []), formId ] } }; return next; }); setActiveForm(null); }; const recordPayment = (amount) => { const paid = { id: "p" + Date.now(), resident: resident.name, amount, method: "Visa ··4242", status: "Paid", receiptNo: rMakeReceiptNo(), date: new Date().toLocaleDateString("en-US", { month: "short", day: "numeric", year: "numeric" }) }; setStore((s) => ({ ...s, payments: [paid, ...s.payments], residents: s.residents.map((r) => r.name === resident.name ? { ...r, balance: Math.max(0, r.balance - amount) } : r), })); setPayOpen(false); setReceipt(paid); }; const navItems = [["home", "layout-dashboard", "Overview"], ["payments", "credit-card", "Payments"], ["forms", "file-signature", "Forms & waivers"]]; return (
{/* Sidebar */} {/* Main */}
{tab === "home" && ( <>

Welcome back, {resident.name.split(" ")[0]}.

One honest day at a time. Here's where things stand.

{resident.balance > 0 && ( } style={{ marginBottom: 20 }}> Your weekly rate is ${rate}. { e.preventDefault(); setTab("payments"); setPayOpen(true); }}>Pay now to stay current. )} {pendingForms.length > 0 && ( 1 ? "s" : ""} need your signature`} icon={} style={{ marginBottom: 20 }}> { e.preventDefault(); setTab("forms"); }}>Review and sign — they only take a few minutes. )}
My bed
{(store.houses.flatMap((h) => h.beds.map((b) => ({ ...b, house: h.name }))).find((b) => b.resident === resident.name) || {}).label || "—"}
{resident.house}
Program phase
Paperwork
)} {tab === "payments" && ( <>

Payments

One transparent weekly rate: ${rate}/week. No surprises.

{myPayments.length === 0 &&

No payments yet.

} {myPayments.map((p) => (
Weekly program fee
{p.date} · {p.method} · {p.receiptNo}
${p.amount} {p.status}
))}
Balance due
0 ? "var(--clay-600)" : "var(--brand-primary)", lineHeight: 1 }}> ${resident.balance}

{resident.balance > 0 ? "Covers this week's program fee." : "You're all caught up. Nice."}

{!payOpen ? ( ) : ( setPayOpen(false)} onPay={recordPayment} /> )}

Secured by Stripe — demo mode, no real charge.

)} {tab === "forms" && !activeForm && ( <>

Forms & waivers

Read carefully, fill in your details, and sign. Ask a house manager anything, any time.

{published.map((f) => { const done = signed.includes(f.id); return (
{f.title} {f.required && !done && Required}
{f.body}
{done ? Signed : }
); })}
)} {tab === "forms" && activeForm && ( setActiveForm(null)} onSigned={() => markSigned(activeForm.id)} /> )}
{receipt && setReceipt(null)} />}
); } /* Stripe-style embedded checkout (demo). */ function StripeCheckout({ amount, name, onCancel, onPay }) { const { Button } = window.WillowCreekDesignSystem_90378c; const [busy, setBusy] = rUseState(false); const [card, setCard] = rUseState(""); const [exp, setExp] = rUseState(""); const [cvc, setCvc] = rUseState(""); const fmtCard = (v) => v.replace(/\D/g, "").slice(0, 16).replace(/(.{4})/g, "$1 ").trim(); const fmtExp = (v) => { const d = v.replace(/\D/g, "").slice(0, 4); return d.length > 2 ? d.slice(0, 2) + " / " + d.slice(2) : d; }; const submit = () => { setBusy(true); setTimeout(() => { setBusy(false); onPay(amount); }, 1100); }; const fieldStyle = { width: "100%", border: "none", outline: "none", fontFamily: "var(--font-sans)", fontSize: 15, color: "var(--text-heading)", background: "transparent", padding: "12px 14px" }; return (
Card payment stripe
setCard(fmtCard(e.target.value))} placeholder="1234 1234 1234 1234" inputMode="numeric" autoComplete="cc-number" style={fieldStyle} />
setExp(fmtExp(e.target.value))} placeholder="MM / YY" inputMode="numeric" autoComplete="cc-exp" style={{ ...fieldStyle, borderRight: "1px solid var(--border-subtle)" }} /> setCvc(e.target.value.replace(/\D/g, "").slice(0, 4))} placeholder="CVC" inputMode="numeric" autoComplete="cc-csc" style={fieldStyle} />
); } function FormSigner({ form, residentName, onBack, onSigned }) { const { Card, Button, Input, Textarea, Checkbox, Alert } = window.WillowCreekDesignSystem_90378c; const [agreed, setAgreed] = rUseState(false); const [hasSig, setHasSig] = rUseState(false); const [values, setValues] = rUseState({}); const canSign = agreed && hasSig; return (
{form.required && REQUIRED}

{form.title}

{form.body}
{form.fields.map((fl, i) => fl.type === "textarea" ?