diff --git a/src/app/page.tsx b/src/app/page.tsx index 59c3a42..995164e 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -32,32 +32,19 @@ export function getOfflineQueue(): OfflineEntry[] { export function addToOfflineQueue(entry: Omit) { const queue = getOfflineQueue(); - queue.push({ - ...entry, - id: crypto.randomUUID(), - timestamp: Date.now(), - }); + queue.push({ ...entry, id: crypto.randomUUID(), timestamp: Date.now() }); localStorage.setItem(OFFLINE_QUEUE_KEY, JSON.stringify(queue)); } 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); - } + 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)); } @@ -77,29 +64,12 @@ function LogModal({ type, childId, onClose }: LogModalProps) { const handleSubmit = async () => { setLoading(true); - const data = { - type, - childId, - subType, - amountMl: amountMl ? Number(amountMl) : undefined, - notes: notes || undefined, - }; - + const data = { type, childId, subType, amountMl: amountMl ? Number(amountMl) : undefined, notes: notes || undefined }; try { - const res = await fetch("/api/logs", { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify(data), - }); - - if (!res.ok && !navigator.onLine) { - addToOfflineQueue({ type: type as any, data }); - } + const res = await fetch("/api/logs", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(data) }); + if (!res.ok && !navigator.onLine) { addToOfflineQueue({ type: type as any, data }); } onClose(); - } catch { - addToOfflineQueue({ type: type as any, data }); - onClose(); - } + } catch { addToOfflineQueue({ type: type as any, data }); onClose(); } setLoading(false); }; @@ -111,41 +81,29 @@ function LogModal({ type, childId, onClose }: LogModalProps) { {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" /> -
- +
@@ -158,7 +116,6 @@ function calculateAge(birthDate: string) { const days = Math.floor((now.getTime() - birth.getTime()) / (1000 * 60 * 60 * 24)); const months = Math.floor(days / 30); const years = Math.floor(months / 12); - if (years > 0) return `${years} year${years > 1 ? "s" : ""} old`; if (months > 0) return `${months} month${months > 1 ? "s" : ""} old`; return `${days} day${days > 1 ? "s" : ""} old`; @@ -171,6 +128,16 @@ function getGreeting() { return "Good evening"; } +// Quick questions for mama +const QUICK_QUESTIONS = [ + "How much should my baby eat?", + "When should baby sleep?", + "Is fever normal?", + "How to increase milk supply?", + "Baby won't sleep 😴", + "Starting solids?", +]; + export default function HomePage() { const [modalType, setModalType] = useState<"feed" | "diaper" | "sleep" | null>(null); const [aiOpen, setAiOpen] = useState(false); @@ -186,21 +153,15 @@ export default function HomePage() { useEffect(() => { const saved = localStorage.getItem("tia_theme"); - if (saved === "dark") { - setDarkMode(true); - document.documentElement.classList.add("dark"); - } + if (saved === "dark") { setDarkMode(true); document.documentElement.classList.add("dark"); } }, []); const toggleDarkMode = () => { const next = !darkMode; setDarkMode(next); localStorage.setItem("tia_theme", next ? "dark" : "light"); - if (next) { - document.documentElement.classList.add("dark"); - } else { - document.documentElement.classList.remove("dark"); - } + if (next) { document.documentElement.classList.add("dark"); } + else { document.documentElement.classList.remove("dark"); } }; useEffect(() => { @@ -208,9 +169,7 @@ export default function HomePage() { setPendingCount(queue.length); const handleOnline = () => processOfflineQueue(); window.addEventListener("online", handleOnline); - if ("serviceWorker" in navigator) { - navigator.serviceWorker.register("/sw.js").catch(console.error); - } + if ("serviceWorker" in navigator) { navigator.serviceWorker.register("/sw.js").catch(console.error); } return () => window.removeEventListener("online", handleOnline); }, []); @@ -224,37 +183,24 @@ export default function HomePage() { }).catch(() => {}); }, [childId]); - const handleAiChat = async () => { - if (!aiInput.trim() || aiLoading) return; + const handleAiChat = async (question?: string) => { + const q = question || aiInput; + if (!q.trim() || aiLoading) return; setAiLoading(true); try { - const res = await fetch("/api/ai", { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ messages: [{ role: "user", content: aiInput }] }), - }); + const res = await fetch("/api/ai", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ messages: [{ role: "user", content: q }] }) }); const data = await res.json(); setAiReply(data.reply || "Sorry, I couldn't help with that."); - } catch { - setAiReply("Something went wrong. Try again."); - } + } catch { setAiReply("Something went wrong. Try again."); } setAiLoading(false); - setAiInput(""); + if (!question) setAiInput(""); }; return (
- - + +
@@ -265,105 +211,70 @@ export default function HomePage() {
👶
-
-
{child.name}
-
{calculateAge(child.birthDate)}
+
{child.name}
{calculateAge(child.birthDate)}
+
+
+ + {pendingCount > 0 &&
{pendingCount} pending log{pendingCount > 1 ? "s" : ""}
} + + {/* Quick Log - Keep as is */} +
+

Quick Log

+
+ + + +
+
+ + {/* AI Chat Card */} +
+

🤖 Ask Tia AI

+
+

Quick questions:

+
+ {QUICK_QUESTIONS.map((q, i) => ( + + ))} +
+
+ setAiInput(e.target.value)} onKeyDown={(e) => e.key === "Enter" && handleAiChat()} placeholder="Ask anything..." className="flex-1 p-2 border rounded-xl text-sm" disabled={aiLoading} /> +
- {pendingCount > 0 && ( -
- {pendingCount} pending log{pendingCount > 1 ? "s" : ""} (will sync when online) -
- )} - -
-

Quick Log

-
- - - - -
-
- -
+ {/* Recent Activity */} +

Recent Activity

- {lastLogs.length === 0 ? ( -

No logs yet today

- ) : ( - lastLogs.filter(Boolean).map((log: any, i: number) => ( -
-
- - {log.type === "feed" && "🍼"} - {log.type === "sleep" && "😴"} - {log.type === "diaper" && "👶"} - -
-
{log.type}
-
- {new Date(log.logged_at).toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" })} -
-
-
- {log.amount_ml && {log.amount_ml}ml} + {lastLogs.length === 0 ?

No logs yet today

: lastLogs.filter(Boolean).map((log: any, i: number) => ( +
+
+ {log.type === "feed" && "🍼"}{log.type === "sleep" && "😴"}{log.type === "diaper" && "👶"} +
{log.type}
{new Date(log.logged_at).toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" })}
- )) - )} + {log.amount_ml && {log.amount_ml}ml} +
+ ))}
setModalType(null)} /> - {aiOpen && ( + {aiOpen && aiReply && (
setAiOpen(false)}> -
e.stopPropagation()}> -
-

🤖 Ask Tia AI

- -
- -
- {aiReply && ( -
- {aiReply} -
- )} -
- -
- setAiInput(e.target.value)} - onKeyDown={(e) => e.key === "Enter" && handleAiChat()} - placeholder="Ask a quick question..." - className="flex-1 p-2 border rounded-xl text-sm" - disabled={aiLoading} - /> - -
+
e.stopPropagation()}> +

🤖 Tia says:

+
{aiReply}
)}