From f24c5e768057b2ff7dd8d9f847843e24f1ba2ec0 Mon Sep 17 00:00:00 2001 From: Mannu Date: Sun, 10 May 2026 10:45:29 +0530 Subject: [PATCH] Add better home UI with greeting, age card, quick log, recent activity --- src/app/page.tsx | 221 ++++++++++++++++++++++++++++------------------- 1 file changed, 132 insertions(+), 89 deletions(-) diff --git a/src/app/page.tsx b/src/app/page.tsx index aafc4b2..b1ac86b 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -2,6 +2,7 @@ import { useState, useEffect } from "react"; import Link from "next/link"; +import { useRouter } from "next/navigation"; const OFFLINE_QUEUE_KEY = "tia_offline_queue"; @@ -20,7 +21,6 @@ export interface OfflineEntry { timestamp: number; } -// Get queue from localStorage export function getOfflineQueue(): OfflineEntry[] { if (typeof window === "undefined") return []; try { @@ -31,7 +31,6 @@ export function getOfflineQueue(): OfflineEntry[] { } } -// Add to queue export function addToOfflineQueue(entry: Omit) { const queue = getOfflineQueue(); queue.push({ @@ -42,7 +41,6 @@ export function addToOfflineQueue(entry: Omit) localStorage.setItem(OFFLINE_QUEUE_KEY, JSON.stringify(queue)); } -// Process queue when online export async function processOfflineQueue() { const queue = getOfflineQueue(); if (queue.length === 0) return; @@ -89,7 +87,6 @@ function LogModal({ type, childId, onClose }: LogModalProps) { }; try { - // Try online first const res = await fetch("/api/logs", { method: "POST", headers: { "Content-Type": "application/json" }, @@ -97,12 +94,10 @@ function LogModal({ type, childId, onClose }: LogModalProps) { }); 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(); } @@ -120,32 +115,18 @@ function LogModal({ type, childId, onClose }: LogModalProps) { {type === "feed" && ( <> - setSubType(e.target.value)} className="w-full p-3 border rounded-xl mb-3"> - setAmountMl(e.target.value)} - className="w-full p-3 border rounded-xl mb-3" - /> + setAmountMl(e.target.value)} className="w-full p-3 border rounded-xl mb-3" /> )} {type === "diaper" && ( - setSubType(e.target.value)} className="w-full p-3 border rounded-xl mb-3"> @@ -153,33 +134,17 @@ function LogModal({ type, childId, onClose }: LogModalProps) { )} {type === "sleep" && ( - setSubType(e.target.value)} className="w-full p-3 border rounded-xl mb-3"> )} - setNotes(e.target.value)} - className="w-full p-3 border rounded-xl mb-4" - /> + setNotes(e.target.value)} className="w-full p-3 border rounded-xl mb-4" />
- - +
@@ -188,74 +153,152 @@ function LogModal({ type, childId, onClose }: LogModalProps) { ); } +// Helper to calculate age +function calculateAge(birthDate: string) { + const birth = new Date(birthDate); + const now = new Date(); + const years = now.getFullYear() - birth.getFullYear(); + const months = now.getMonth() - birth.getMonth(); + const days = Math.floor((now.getTime() - birth.getTime()) / (1000 * 60 * 60 * 24)); + + if (years > 0) return `${years} year${years > 1 ? "s" : ""} old`; + if (months > 0) return `${months} month${months > 1 ? "s" : ""} old`; + return `${days} days old`; +} + +function getGreeting() { + const hour = new Date().getHours(); + if (hour < 12) return "Good morning"; + if (hour < 18) return "Good afternoon"; + return "Good evening"; +} + export default function HomePage() { + const router = useRouter(); const [modalType, setModalType] = useState<"feed" | "diaper" | "sleep" | null>(null); const [childId] = useState("5ad3b16a-1e0d-45ab-bc91-038397d75d0a"); const [pendingCount, setPendingCount] = useState(0); + const [lastLogs, setLastLogs] = useState([]); + + const child = { name: "Baby Tia", birthDate: "2024-01-15" }; - // 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); }, []); + useEffect(() => { + // Fetch recent logs + Promise.all([ + fetch(`/api/logs?type=feed&childId=${childId}&limit=1`).then(r => r.json()), + fetch(`/api/logs?type=sleep&childId=${childId}&limit=1`).then(r => r.json()), + fetch(`/api/logs?type=diaper&childId=${childId}&limit=1`).then(r => r.json()), + ]).then(([feed, sleep, diaper]) => { + setLastLogs([ + feed.entries?.[0], + sleep.entries?.[0], + diaper.entries?.[0], + ].filter(Boolean)); + }).catch(() => {}); + }, [childId]); + return (
-
-
-

Tia 👶

-

Your baby tracking companion

-
+ {/* Header */} +
+ + +
- {pendingCount > 0 && ( -
- {pendingCount} pending log{pendingCount > 1 ? "s" : ""} (offline) + {/* Welcome */} +
+

{getGreeting()} 👋

+

How is {child.name} doing today?

+
+ + {/* Age Card */} +
+
+
+ 👶 +
+
+
{child.name}
+
{calculateAge(child.birthDate)}
- )} - -
- - - -
+
-
-

Baby: Baby Tia

+ {/* Pending Offline */} + {pendingCount > 0 && ( +
+ {pendingCount} pending log{pendingCount > 1 ? "s" : ""} (will sync when online) +
+ )} + + {/* Quick Actions */} +
+

Quick Log

+
+ + + + + 💊 + Medical + +
+
+ + {/* 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} +
+ )) + )}