/* @component-map * App — Main container, handles view switching and layout * Confetti — Animated confetti overlay on chore completion * Leaderboard — Family member scores and progress bars * AddChoreModal — Modal for adding new chores * ChoreBoard — Board view of chores list * ChoreWeek — Weekly grouped view of chores * StatsFooter — Fixed bottom stats bar * @end-component-map */ import { useCollection } from '@deplixo/sdk'; import { FAMILY, CHORE_TEMPLATES, DAYS, SEED_CHORES } from './components/constants.jsx'; import { Confetti } from './components/Confetti.jsx'; import { Leaderboard } from './components/Leaderboard.jsx'; import { AddChoreModal } from './components/AddChoreModal.jsx'; import { ChoreBoard } from './components/ChoreBoard.jsx'; import { ChoreWeek } from './components/ChoreWeek.jsx'; import { useEffect, useState } from 'react'; import { StatsFooter } from './components/StatsFooter.jsx'; function App() { const { items: chores, loading, add, update, remove, collection } = useCollection("brennan_chores", { personal: true }); const [view, setView] = useState("board"); const [filterPerson, setFilterPerson] = useState(null); const [showConfetti, setShowConfetti] = useState(false); const [showModal, setShowModal] = useState(false); const [justCompleted, setJustCompleted] = useState(null); const [seeded, setSeeded] = useState(false); useEffect(() => { if (!collection || seeded) return; async function seed() { for (const chore of SEED_CHORES) { await collection.addIfEmpty(chore); } setSeeded(true); } seed(); }, [collection, seeded]); const toggleDone = async (choreId) => { const entry = chores.find(c => c.id === choreId); if (!entry) return; if (!entry.value.done) { setShowConfetti(true); setJustCompleted(choreId); setTimeout(() => { setShowConfetti(false); setJustCompleted(null); }, 2000); } await update(choreId, { ...entry.value, done: !entry.value.done }); }; const addChore = async ({ name, icon, assignee, day, points }) => { await add({ name, icon, assignee, day, points, done: false }); }; const deleteChore = async (choreId) => { await remove(choreId); }; const scores = {}; FAMILY.forEach(f => { scores[f.id] = 0; }); chores.filter(c => c.value.done).forEach(c => { scores[c.value.assignee] = (scores[c.value.assignee] || 0) + c.value.points; }); const filtered = filterPerson ? chores.filter(c => c.value.assignee === filterPerson) : chores; return (
setShowModal(false)} onAdd={addChore} />

🏠 Brennan Family Chores

This week's mission board

{[{ key: "board", label: "📋 Board" }, { key: "week", label: "📅 Week" }].map(v => ( ))}
{filterPerson && (
)} {view === "board" && } {view === "week" && }
); } ReactDOM.createRoot(document.getElementById("root")).render();