"use client"; import { useState, useEffect } from "react"; import Link from "next/link"; const OFFLINE_QUEUE_KEY = "tia_offline_queue"; export interface OfflineEntry { id: string; type: "feed" | "diaper" | "sleep"; data: { type: "feed" | "diaper" | "sleep"; childId: string; subType: string; amountMl?: number; notes?: string; startedAt?: string; endedAt?: string; }; timestamp: number; } // Get queue from localStorage export function getOfflineQueue(): OfflineEntry[] { if (typeof window === "undefined") return []; try { const data = localStorage.getItem(OFFLINE_QUEUE_KEY); return data ? JSON.parse(data) : []; } catch { return []; } } // Add to queue export function addToOfflineQueue(entry: Omit) { const queue = getOfflineQueue(); queue.push({ ...entry, id: crypto.randomUUID(), timestamp: Date.now(), }); localStorage.setItem(OFFLINE_QUEUE_KEY, JSON.stringify(queue)); } // Process queue when online export async function processOfflineQueue() { const queue = getOfflineQueue(); if (queue.length === 0) return; const failed: OfflineEntry[] = []; for (const entry of queue) { try { await fetch("/api/logs", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(entry.data), }); } catch { failed.push(entry); } } localStorage.setItem(OFFLINE_QUEUE_KEY, JSON.stringify(failed)); } interface LogModalProps { type: "feed" | "diaper" | "sleep" | null; childId: string; onClose: () => void; } function LogModal({ type, childId, onClose }: LogModalProps) { const [loading, setLoading] = useState(false); const [subType, setSubType] = useState("breast_milk"); const [amountMl, setAmountMl] = useState(""); const [notes, setNotes] = useState(""); if (!type) return null; const handleSubmit = async () => { setLoading(true); const data = { type, childId, subType, amountMl: amountMl ? Number(amountMl) : undefined, notes: notes || undefined, }; try { // Try online first const res = await fetch("/api/logs", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(data), }); if (!res.ok && !navigator.onLine) { // Offline - add to queue addToOfflineQueue({ type: type as any, data }); } onClose(); } catch { // Network error - add to queue addToOfflineQueue({ type: type as any, data }); onClose(); } setLoading(false); }; return (

{type === "feed" && "Log Feed"} {type === "diaper" && "Log Diaper"} {type === "sleep" && "Log Sleep"}

{type === "feed" && ( <> setAmountMl(e.target.value)} className="w-full p-3 border rounded-xl mb-3" /> )} {type === "diaper" && ( )} {type === "sleep" && ( )} setNotes(e.target.value)} className="w-full p-3 border rounded-xl mb-4" />
); } export default function HomePage() { const [modalType, setModalType] = useState<"feed" | "diaper" | "sleep" | null>(null); const [childId] = useState("5ad3b16a-1e0d-45ab-bc91-038397d75d0a"); const [pendingCount, setPendingCount] = useState(0); // Check queue on mount useEffect(() => { const queue = getOfflineQueue(); setPendingCount(queue.length); // Process queue when coming online const handleOnline = () => processOfflineQueue(); window.addEventListener("online", handleOnline); // Register service worker if ("serviceWorker" in navigator) { navigator.serviceWorker.register("/sw.js").catch(console.error); } return () => window.removeEventListener("online", handleOnline); }, []); return (

Tia 👶

Your baby tracking companion

{pendingCount > 0 && (
{pendingCount} pending log{pendingCount > 1 ? "s" : ""} (offline)
)}

Baby: Baby Tia

setModalType(null)} />
); }