import { useState, useCallback, useRef } from "preact/hooks"; import { slugify } from "../../lib/categories"; export function PackTab({ items, initialState, tripId }: { items: string[]; initialState: Record; tripId: string; }) { const [checked, setChecked] = useState>(() => { const state: Record = {}; items.forEach(item => { const key = slugify(item); state[key] = initialState[key] ?? false; }); return state; }); const saveTimeout = useRef | null>(null); const persist = useCallback((newState: Record) => { if (saveTimeout.current) clearTimeout(saveTimeout.current); saveTimeout.current = setTimeout(() => { fetch(`/travel/api/pack-state?tripId=${tripId}`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(newState), }).catch(() => { /* silent fail */ }); }, 500); }, [tripId]); const toggle = useCallback((item: string) => { const key = slugify(item); setChecked(prev => { const next = { ...prev, [key]: !prev[key] }; persist(next); return next; }); }, [persist]); const total = items.length; const done = Object.values(checked).filter(Boolean).length; const pct = total > 0 ? Math.round((done / total) * 100) : 0; return (

Packing List

{done}/{total}
Tap to check off. Saved automatically.
{items.map(item => { const key = slugify(item); const isChecked = checked[key] ?? false; return (
toggle(item)} >
{isChecked ? "\u2713" : ""}
{item}
); })}
{items.length === 0 && (
No items in packing list.
)}
); }