/* @component-map * App — Main container, layout and header with progress bar * CategorySection — Individual bake sale category with signup list and add form * SignupCard — Single signup entry display with remove button * @end-component-map */ import { useCollection } from '@deplixo/sdk'; import { useCallback, useState } from 'react'; import { CategorySection } from './components/CategorySection.jsx'; const CATEGORIES_DATA = [ { id: "cookies", label: "Cookies", emoji: "🍪", slots: 4 }, { id: "cakes", label: "Cakes & Cupcakes", emoji: "🧁", slots: 3 }, { id: "pies", label: "Pies & Tarts", emoji: "🥧", slots: 3 }, { id: "breads", label: "Breads & Muffins", emoji: "🍞", slots: 3 }, { id: "brownies", label: "Brownies & Bars", emoji: "🍫", slots: 3 }, { id: "other", label: "Other Treats", emoji: "🍬", slots: 4 }, ]; function App() { const { items: signupEntries, loading: signupsLoading, add: addSignup, remove: removeSignup } = useCollection("bake-sale-signups", { personal: true }); const { items: categories, loading: catsLoading } = useCollection("bake-sale-categories", { personal: true, seedIfEmpty: CATEGORIES_DATA }); const loading = signupsLoading || catsLoading; const resolvedCategories = CATEGORIES_DATA.map(cat => { const catEntry = categories.find(c => c.value.id === cat.id); return catEntry ? catEntry.value : cat; }); const handleAdd = useCallback(async (categoryId, entry) => { const cat = resolvedCategories.find(c => c.id === categoryId); const maxSlots = cat ? cat.slots : 4; const existing = signupEntries.filter(e => e.value.categoryId === categoryId); if (existing.length >= maxSlots) return; await addSignup({ ...entry, categoryId }); }, [resolvedCategories, signupEntries, addSignup]); const handleRemove = useCallback(async (entryId) => { await removeSignup(entryId); }, [removeSignup]); const handleReset = useCallback(async () => { if (!window.confirm("Clear all signups? This can't be undone.")) return; for (const entry of signupEntries) { await removeSignup(entry.id); } }, [signupEntries, removeSignup]); if (loading) { return
Loading signups…
; } const totalSignups = signupEntries.length; const totalSlots = CATEGORIES_DATA.reduce((s, c) => s + c.slots, 0); const progressPct = totalSlots > 0 ? (totalSignups / totalSlots) * 100 : 0; return (
🧁🍪🥧

Bake Sale Signup

Sign up below to bring your favorite baked goods!

{totalSignups} signed up {totalSlots - totalSignups} spots remaining
{resolvedCategories.map((cat, i) => { const catSignups = signupEntries.filter(e => e.value.categoryId === cat.id); return (
); })}
{totalSignups > 0 && (
)}
); } ReactDOM.createRoot(document.getElementById("root")).render();