diff --git a/src/app/activity/page.tsx b/src/app/activity/page.tsx index c77799b..86d4a13 100644 --- a/src/app/activity/page.tsx +++ b/src/app/activity/page.tsx @@ -2,6 +2,7 @@ import { useState, useEffect } from "react"; import Link from "next/link"; +import { useFamily } from "../FamilyProvider"; type ViewMode = "timeline" | "calendar"; type LogType = "feed" | "sleep" | "diaper"; @@ -29,33 +30,23 @@ interface DayLogs { } export default function ActivityPage() { + const { child, childId: providerChildId, familyId } = useFamily(); const [view, setView] = useState("timeline"); const [logs, setLogs] = useState([]); const [loading, setLoading] = useState(true); const [filter, setFilter] = useState("all"); - const [child, setChild] = useState(null); const [showSuggested, setShowSuggested] = useState(true); const [generating, setGenerating] = useState(false); - const childId = "default"; + const childId = providerChildId || "default"; useEffect(() => { - fetchLogs(); - fetchChild(); - }, []); - - const fetchChild = async () => { - try { - const res = await fetch("/api/children?familyId=default"); - const data = await res.json(); - if (data.children?.length > 0) { - setChild(data.children[0]); - } - } catch (err) { - console.error("Failed to fetch:", err); + if (providerChildId) { + fetchLogs(); } - }; + }, [providerChildId]); const fetchLogs = async () => { + if (!childId) return; try { const res = await fetch(`/api/logs?childId=${childId}&limit=100`); const data = await res.json(); diff --git a/src/app/ai/page.tsx b/src/app/ai/page.tsx index e6b7fbd..da38ce9 100644 --- a/src/app/ai/page.tsx +++ b/src/app/ai/page.tsx @@ -1,6 +1,7 @@ "use client"; import { useState, useEffect } from "react"; +import { useFamily } from "../FamilyProvider"; interface AIChat { id: string; @@ -18,7 +19,7 @@ interface ChatSession { } export default function AIChatPage() { - const childId = "default"; + const { childId } = useFamily(); const [sessions, setSessions] = useState([]); const [currentSessionId, setCurrentSessionId] = useState(""); const [input, setInput] = useState(""); @@ -26,10 +27,13 @@ export default function AIChatPage() { const [sidebarOpen, setSidebarOpen] = useState(true); useEffect(() => { - fetchSessions(); - }, []); + if (childId) { + fetchSessions(); + } + }, [childId]); const fetchSessions = async () => { + if (!childId) return; try { const res = await fetch(`/api/chat?childId=${childId}`); const data = await res.json(); diff --git a/src/app/api/auth/profile/route.ts b/src/app/api/auth/profile/route.ts index b57a975..e987a41 100644 --- a/src/app/api/auth/profile/route.ts +++ b/src/app/api/auth/profile/route.ts @@ -1,29 +1,96 @@ import { NextResponse } from "next/server"; +import { sql } from "@/db"; +import { cookies } from "next/headers"; -// Mock user for now - in production, fetch from database +// GET current user profile from session export async function GET() { try { - // TODO: In production, get user from session - const user = { - id: "1", - name: "Parent", - email: "parent@example.com", - }; + const cookieStore = await cookies(); + const sessionToken = cookieStore.get("tia_session")?.value; - return NextResponse.json({ user }); + if (!sessionToken) { + return NextResponse.json({ error: "Not authenticated" }, { status: 401 }); + } + + // Get session and user + const sessions = await sql` + SELECT s.user_id, s.expires, u.id, u.email, u.name, u.created_at + FROM sessions s + JOIN users u ON u.id = s.user_id + WHERE s.session_token = ${sessionToken} + AND s.expires > NOW() + `; + + const session = sessions?.[0]; + + if (!session) { + return NextResponse.json({ error: "Invalid session" }, { status: 401 }); + } + + // Get family info + const members = await sql` + SELECT fm.family_id, f.name as family_name + FROM family_members fm + JOIN families f ON f.id = fm.family_id + WHERE fm.user_id = ${session.user_id} + `; + + return NextResponse.json({ + user: { + id: session.id, + email: session.email, + name: session.name || "Parent", + familyId: members?.[0]?.family_id, + familyName: members?.[0]?.family_name, + memberSince: session.created_at, + }, + }); } catch (error) { + console.error("Profile fetch error:", error); return NextResponse.json({ error: String(error) }, { status: 500 }); } } +// UPDATE user profile (name only) export async function POST(request: Request) { try { const body = await request.json(); const { name } = body; - // TODO: Save to database in production + if (!name) { + return NextResponse.json({ error: "Name required" }, { status: 400 }); + } + + const cookieStore = await cookies(); + const sessionToken = cookieStore.get("tia_session")?.value; + + if (!sessionToken) { + return NextResponse.json({ error: "Not authenticated" }, { status: 401 }); + } + + // Get user from session + const sessions = await sql` + SELECT s.user_id + FROM sessions s + WHERE s.session_token = ${sessionToken} + AND s.expires > NOW() + `; + + const session = sessions?.[0]; + + if (!session) { + return NextResponse.json({ error: "Invalid session" }, { status: 401 }); + } + + // Update user name + await sql` + UPDATE users SET name = ${name}, updated_at = NOW() + WHERE id = ${session.user_id} + `; + return NextResponse.json({ success: true, name }); } catch (error) { + console.error("Profile update error:", error); return NextResponse.json({ error: String(error) }, { status: 500 }); } } \ No newline at end of file diff --git a/src/app/family/page.tsx b/src/app/family/page.tsx index 0033c8f..317715c 100644 --- a/src/app/family/page.tsx +++ b/src/app/family/page.tsx @@ -2,6 +2,7 @@ import { useState, useEffect } from "react"; import { useRouter } from "next/navigation"; +import { useFamily } from "../FamilyProvider"; interface Child { id: string; @@ -13,6 +14,7 @@ interface Child { export default function FamilyPage() { const router = useRouter(); + const { familyId, children: childrenFromProvider } = useFamily(); const [children, setChildren] = useState([]); const [loading, setLoading] = useState(true); const [editing, setEditing] = useState(null); @@ -23,13 +25,20 @@ export default function FamilyPage() { const [newDob, setNewDob] = useState(""); const [newSex, setNewSex] = useState("male"); + // Load children from FamilyProvider or fetch useEffect(() => { - fetchChildren(); - }, []); + if (childrenFromProvider && childrenFromProvider.length > 0) { + setChildren(childrenFromProvider); + setLoading(false); + } else if (familyId) { + fetchOwnChildren(); + } + }, [childrenFromProvider, familyId]); - const fetchChildren = async () => { + const fetchOwnChildren = async () => { + if (!familyId) return; try { - const res = await fetch("/api/children?familyId=default"); + const res = await fetch(`/api/children?familyId=${familyId}`); const data = await res.json(); setChildren(data.children || []); } catch (err) { @@ -45,6 +54,7 @@ export default function FamilyPage() { }; const saveEdit = async (childId: string) => { + if (!familyId) return; try { const res = await fetch("/api/children", { method: "PATCH", @@ -62,12 +72,12 @@ export default function FamilyPage() { }; const addChild = async () => { - if (!newName || !newDob) return; + if (!newName || !newDob || !familyId) return; try { const res = await fetch("/api/children", { method: "POST", headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ name: newName, birthDate: newDob, sex: newSex, familyId: "default" }), + body: JSON.stringify({ name: newName, birthDate: newDob, sex: newSex, familyId }), }); const data = await res.json(); if (data.success) { @@ -180,11 +190,9 @@ export default function FamilyPage() { -
- -
+ )} diff --git a/src/app/medical/page.tsx b/src/app/medical/page.tsx index 2cf488d..09fd015 100644 --- a/src/app/medical/page.tsx +++ b/src/app/medical/page.tsx @@ -358,7 +358,7 @@ export default function MedicalPage() { setShowAddIllness(false); }; - const childId = sessionChildId || "default"; + const childId = sessionChildId; const birthDate = child?.birthDate || "2024-01-15"; // Common supplements for babies diff --git a/src/app/memories/page.tsx b/src/app/memories/page.tsx index a50097b..d721ec9 100644 --- a/src/app/memories/page.tsx +++ b/src/app/memories/page.tsx @@ -2,6 +2,7 @@ import { useState, useEffect, useRef } from "react"; import Link from "next/link"; +import { useFamily } from "../FamilyProvider"; interface Memory { key: string; @@ -11,18 +12,21 @@ interface Memory { } export default function MemoriesPage() { + const { childId } = useFamily(); const [memories, setMemories] = useState([]); const [selected, setSelected] = useState(null); const [uploading, setUploading] = useState(false); const [uploadProgress, setUploadProgress] = useState(0); const fileRef = useRef(null); - const childId = "default"; useEffect(() => { - fetchMemories(); - }, []); + if (childId) { + fetchMemories(); + } + }, [childId]); const fetchMemories = async () => { + if (!childId) return; try { const res = await fetch(`/api/upload?childId=${childId}`); const data = await res.json(); diff --git a/src/app/menu/page.tsx b/src/app/menu/page.tsx index 99b7799..4202a5a 100644 --- a/src/app/menu/page.tsx +++ b/src/app/menu/page.tsx @@ -2,9 +2,11 @@ import Link from "next/link"; import { useRouter } from "next/navigation"; +import { useState } from "react"; export default function MenuPage() { const router = useRouter(); + const [signingOut, setSigningOut] = useState(false); const menuItems = [ { icon: "🏠", label: "Home", href: "/" }, @@ -15,6 +17,18 @@ export default function MenuPage() { { icon: "🤖", label: "AI Chat", href: "/ai" }, ]; + const handleSignOut = async () => { + if (!confirm("Are you sure you want to sign out?")) return; + setSigningOut(true); + try { + await fetch("/api/auth/signout", { method: "POST" }); + router.push("/login"); + } catch (err) { + console.error("Sign out failed:", err); + } + setSigningOut(false); + }; + return (
{/* Header */} @@ -37,8 +51,8 @@ export default function MenuPage() { ))}
- {/* Bottom Section - Settings only */} -
+ {/* Bottom Section - Settings and Sign Out */} +
⚙️ Settings +
); diff --git a/src/app/profile/page.tsx b/src/app/profile/page.tsx index 6cfe7fb..736c2cf 100644 --- a/src/app/profile/page.tsx +++ b/src/app/profile/page.tsx @@ -28,8 +28,27 @@ export default function ProfilePage() { }, []); const saveProfile = async () => { - // TODO: Call API to save profile - alert("Profile saved!"); + if (!name.trim()) { + alert("Please enter your name"); + return; + } + setLoading(true); + try { + const res = await fetch("/api/auth/profile", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ name }), + }); + const data = await res.json(); + if (data.success) { + alert("Profile saved!"); + } else { + alert(data.error || "Failed to save profile"); + } + } catch (err) { + alert("Failed to save profile"); + } + setLoading(false); }; return ( diff --git a/src/app/settings/page.tsx b/src/app/settings/page.tsx index 1fbf9f8..aa72ca0 100644 --- a/src/app/settings/page.tsx +++ b/src/app/settings/page.tsx @@ -68,8 +68,9 @@ export default function SettingsPage() { }, [familyId]); const fetchMembers = async () => { + if (!familyId) return; try { - const res = await fetch(`/api/family/members?familyId=${familyId || "default"}`); + const res = await fetch(`/api/family/members?familyId=${familyId}`); const data = await res.json(); setMembers(data.members || []); } catch (err) { @@ -78,8 +79,9 @@ export default function SettingsPage() { }; const fetchInvites = async () => { + if (!familyId) return; try { - const res = await fetch("/api/invites?familyId=default"); + const res = await fetch(`/api/invites?familyId=${familyId}`); const data = await res.json(); setInvites(data.invites || []); } catch (err) { @@ -88,14 +90,14 @@ export default function SettingsPage() { }; const sendInvite = async () => { - if (!inviteEmail) return; + if (!inviteEmail || !familyId) return; setInviteLoading(true); try { const res = await fetch("/api/invites", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ - familyId: "default", + familyId: familyId, email: inviteEmail, role: inviteRole, displayName: inviteEmail.split("@")[0],