/* eslint-disable no-undef */ const { useState, useEffect, useRef, useMemo, useCallback } = React; /* ========================================================= Small visual atoms ========================================================= */ function Star({ filled, onClick, size = 30 }) { // Chunky 5-point star. Use a path that feels hand-cut, not generic 5-point math. return ( ); } function StarsInput({ value, onChange }) { return (
{[1,2,3,4,5].map(n => ( onChange(value === n ? 0 : n)} /> ))}
); } function MiniStars({ value }) { if (!value) return null; return {"★".repeat(value)}{"☆".repeat(5 - value)}; } function Badges({ gf, v, compact }) { if (!gf && !v) return null; return ( {gf && GF} {v && VG} ); } function Avatar({ friend, size = 26 }) { if (!friend) return null; const initials = (friend.name || "?").trim().split(/\s+/).map(s => s[0]).slice(0,2).join("").toUpperCase() || "?"; return ( {initials} ); } function Drip({ className }) { // hand-drawn pink drip ribbon similar to the poster corners return ( ); } /* ========================================================= Flavor row inside the NOW card ========================================================= */ function FlavorRow({ flavor, log, onLogChange, toppingName, toppingTags, sprinklesAlways }) { // For the "now" card we let each friend pick which flavor(s) they got — so the // log isn't per-row. We just render the flavor info + badges here. return (
{flavor.name}
); } /* ========================================================= Entry card — the per-friend logging form ========================================================= */ function EntryCard({ week, friend, entry, onChange, onDelete, onClose }) { const [draftComment, setDraftComment] = useState(entry?.comment || ""); useEffect(() => { setDraftComment(entry?.comment || ""); }, [friend?.id, week.id]); const flavorIds = week.flavors.map(f => f.name); const got = entry?.flavors || []; const toggleFlavor = (name) => { const next = got.includes(name) ? got.filter(f => f !== name) : [...got, name]; onChange({ ...entry, flavors: next }); }; return (

{friend.name}'s pick

Got which?
{week.flavors.map(f => { const on = got.includes(f.name); return ( ); })}
Topping?
How was it? onChange({ ...entry, stars })} />
Note