diff --git a/src/app/globals.css b/src/app/globals.css index c04ece7..9529058 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -19,6 +19,15 @@ --font-mono: var(--font-geist-mono); } +@keyframes marquee { + 0% { transform: translateX(0); } + 100% { transform: translateX(-50%); } +} + +.animate-marquee { + animation: marquee 20s linear infinite; +} + body { background: var(--background); color: var(--foreground); diff --git a/src/app/page.tsx b/src/app/page.tsx index 09fa01e..6a4c8c5 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -55,7 +55,6 @@ export async function processOfflineQueue() { localStorage.setItem(OFFLINE_QUEUE_KEY, JSON.stringify(failed)); } -// --- AI Session Functions (using database) --- async function getSessions(cid: string): Promise { try { const res = await fetch(`/api/chat?childId=${cid}`); @@ -134,6 +133,48 @@ function getGreeting() { return "Good evening"; } +function formatTimeAgo(dateStr: string | null | undefined) { + if (!dateStr) return null; + const date = new Date(dateStr); + const now = new Date(); + const diffMs = now.getTime() - date.getTime(); + const diffMins = Math.floor(diffMs / 60000); + const diffHours = Math.floor(diffMins / 60); + const diffDays = Math.floor(diffHours / 24); + if (diffMins < 1) return "just now"; + if (diffMins < 60) return `${diffMins}m ago`; + if (diffHours < 24) return `${diffHours}h ago`; + return `${diffDays}d ago`; +} + +function ActivityScroller({ lastLogs }: { lastLogs: any[] }) { + const feedLog = lastLogs.find(l => l?.type === "feed"); + const sleepLog = lastLogs.find(l => l?.type === "sleep"); + const diaperLog = lastLogs.find(l => l?.type === "diaper"); + + const items = [ + { icon: "๐Ÿผ", label: "Fed", time: feedLog?.logged_at }, + { icon: "๐Ÿ˜ด", label: "Sleep", time: sleepLog?.logged_at }, + { icon: "๐Ÿงท", label: "Diaper", time: diaperLog?.logged_at }, + ].filter(item => item.time); + + if (items.length === 0) return null; + + return ( +
+
+ {[...items, ...items].map((item, i) => ( +
+ {item.icon} + {item.label}: + {formatTimeAgo(item.time)} +
+ ))} +
+
+ ); +} + 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() { @@ -145,6 +186,7 @@ export default function HomePage() { const [homeSessionId, setHomeSessionId] = useState(null); const [pendingCount, setPendingCount] = useState(0); const [lastLogs, setLastLogs] = useState([]); + const [logsLoading, setLogsLoading] = useState(true); const [vaccineReminders, setVaccineReminders] = useState([]); const { theme, toggle: toggleTheme } = useTheme(); const { childId, child, familyId, loading } = useFamily(); @@ -173,18 +215,21 @@ export default function HomePage() { useEffect(() => { if (!childId) return; + setLogsLoading(true); 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))); + ]).then(([feed, sleep, diaper]) => { + setLastLogs([feed.entries?.[0], sleep.entries?.[0], diaper.entries?.[0]].filter(Boolean)); + setLogsLoading(false); + }).catch(() => setLogsLoading(false)); }, [childId]); if (loading) { return
Loading...
; } - // Not logged in - redirect to login if (!familyId) { if (typeof window !== "undefined") { window.location.href = "/login"; @@ -200,7 +245,6 @@ export default function HomePage() { toggleTheme(); }; - // Unified AI chat โ€” creates a fresh session per modal open, reuses it for follow-ups const handleAiChat = async (question?: string) => { const q = question || aiInput; if (!q.trim() || aiLoading) return; @@ -210,7 +254,6 @@ export default function HomePage() { const inputVal = q.trim(); if (!question) setAiInput(""); - // Reuse session within same modal open, or create fresh one let sessionId = homeSessionId; if (!sessionId) { const newSession = await createSession(childId); @@ -220,7 +263,6 @@ export default function HomePage() { setAiChats([]); } - // Optimistically show user message const userMsg: AIChat = { id: "tmp-" + Date.now(), role: "user", content: inputVal, createdAt: new Date().toISOString() }; setAiChats(prev => [...prev, userMsg]); @@ -264,12 +306,13 @@ export default function HomePage() {

How is {child?.name || "your baby"} doing today?

-
+
๐Ÿ‘ถ
-
{child?.name || "Baby"}
{calculateAge(child?.birthDate || "")}
+
{child?.name || "Baby"}
{calculateAge(child?.birthDate || "")}
+
โ†’
-
+ {pendingCount > 0 &&
{pendingCount} pending log{pendingCount > 1 ? "s" : ""}
} @@ -289,12 +332,14 @@ export default function HomePage() { )} + +

Quick Log

- + ๐Ÿ’ŠMedical
@@ -318,7 +363,7 @@ export default function HomePage() {

Recent Activity

- {lastLogs.length === 0 ?

No logs yet today

: lastLogs.filter(Boolean).map((log: any, i: number) => ( + {logsLoading ?

Loading...

: lastLogs.length === 0 ?

No logs yet today

: lastLogs.filter(Boolean).map((log: any, i: number) => (
{log.type === "feed" && "๐Ÿผ"}{log.type === "sleep" && "๐Ÿ˜ด"}{log.type === "diaper" && "๐Ÿ‘ถ"}