/* @component-map * App — Main container, loads fonts and renders layout * RSVPForm — RSVP form with name, count, dish selection, note, submit/edit * GuestList — Displays list of RSVPed guests with edit/remove actions * ConfettiOverlay — Confetti animation overlay * @end-component-map */ import { useCollection } from '@deplixo/sdk'; import { RSVPForm } from './components/RSVPForm.jsx'; import { GuestList } from './components/GuestList.jsx'; import { useEffect, useState } from 'react'; import { ConfettiOverlay } from './components/ConfettiOverlay.jsx'; const FONTS_URL = "https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;500;600;700;800;900&family=Fraunces:opsz,wght@9..144,300;9..144,500;9..144,700;9..144,900&display=swap"; function App() { const { items: guests, loading, add, update, remove } = useCollection("block-party-rsvps", { personal: true }); const [editingGuest, setEditingGuest] = useState(null); const [showConfetti, setShowConfetti] = useState(false); const [submitted, setSubmitted] = useState(false); useEffect(() => { const link = document.createElement("link"); link.rel = "stylesheet"; link.href = FONTS_URL; document.head.appendChild(link); }, []); const totalHeads = guests.reduce((s, g) => s + (g.value?.count || 0), 0); const handleSubmitted = () => { setSubmitted(true); setShowConfetti(true); setEditingGuest(null); setTimeout(() => setShowConfetti(false), 2400); setTimeout(() => setSubmitted(false), 3000); }; const handleEdit = (guest) => { setEditingGuest(guest); setSubmitted(false); window.scrollTo({ top: 0, behavior: "smooth" }); }; if (loading) { return
You're invited to the neighborhood cookout!
📍 Meet at the cul-de-sac · Bring lawn chairs!