Skip to content

Commit b3ba3fe

Browse files
committed
Fix auth de-auth on navigation, merge dashboards, smart logo navigation
- Add AuthProvider context for shared app-wide auth state (no per-page session re-fetch) - Create NavLogo component: links to /kid-dashboard when logged in, / when not - Merge parent/kid dashboards: /dashboard redirects to /kid-dashboard - OAuth callback redirects to /kid-dashboard - Remove Parent button, add Screening + Community quick links - Add back navigation to game pages and subpages - Update all /dashboard links across 34 files
1 parent 7c037f0 commit b3ba3fe

34 files changed

Lines changed: 254 additions & 682 deletions

File tree

app/api/auth/callback/google/route.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ export async function GET(request: NextRequest) {
9797
const sessionToken = await createSessionForUser(user.id);
9898

9999
// ─── Set cookie & redirect ────────────────────────────────────
100-
const response = NextResponse.redirect(`${appUrl}/dashboard`);
100+
const response = NextResponse.redirect(`${appUrl}/kid-dashboard`);
101101

102102
response.cookies.set(sessionCookieName, sessionToken, {
103103
httpOnly: true,

app/components/NavLogo.tsx

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
"use client";
2+
3+
import Link from "next/link";
4+
import { useAuth } from "../hooks/useAuth";
5+
6+
export default function NavLogo() {
7+
const { isAuthenticated } = useAuth();
8+
9+
return (
10+
<Link href={isAuthenticated ? "/kid-dashboard" : "/"} className="logo">
11+
Auti<em>Sense</em>
12+
</Link>
13+
);
14+
}

app/components/Providers.tsx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
"use client";
2+
3+
import { AuthProvider } from "../contexts/AuthContext";
4+
5+
export default function Providers({ children }: { children: React.ReactNode }) {
6+
return <AuthProvider>{children}</AuthProvider>;
7+
}

app/contexts/AuthContext.tsx

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
"use client";
2+
3+
import { createContext, useState, useEffect, useCallback, type ReactNode } from "react";
4+
5+
export interface AuthUser {
6+
id: string;
7+
email: string;
8+
name: string;
9+
picture: string;
10+
}
11+
12+
export interface AuthContextValue {
13+
user: AuthUser | null;
14+
loading: boolean;
15+
isAuthenticated: boolean;
16+
refresh: () => Promise<void>;
17+
logout: () => Promise<void>;
18+
}
19+
20+
export const AuthContext = createContext<AuthContextValue>({
21+
user: null,
22+
loading: true,
23+
isAuthenticated: false,
24+
refresh: async () => {},
25+
logout: async () => {},
26+
});
27+
28+
export function AuthProvider({ children }: { children: ReactNode }) {
29+
const [user, setUser] = useState<AuthUser | null>(null);
30+
const [loading, setLoading] = useState(true);
31+
32+
const fetchSession = useCallback(async () => {
33+
try {
34+
setLoading(true);
35+
const res = await fetch("/api/auth/session", {
36+
credentials: "include",
37+
});
38+
if (res.ok) {
39+
const data = await res.json();
40+
setUser(data.user ?? null);
41+
} else {
42+
setUser(null);
43+
}
44+
} catch {
45+
setUser(null);
46+
} finally {
47+
setLoading(false);
48+
}
49+
}, []);
50+
51+
useEffect(() => {
52+
fetchSession();
53+
}, [fetchSession]);
54+
55+
const logout = useCallback(async () => {
56+
try {
57+
await fetch("/api/auth/logout", {
58+
method: "POST",
59+
credentials: "include",
60+
});
61+
} catch {
62+
// Ignore network errors — still clear local state
63+
}
64+
setUser(null);
65+
window.location.href = "/";
66+
}, []);
67+
68+
return (
69+
<AuthContext.Provider
70+
value={{
71+
user,
72+
loading,
73+
isAuthenticated: !!user,
74+
refresh: fetchSession,
75+
logout,
76+
}}
77+
>
78+
{children}
79+
</AuthContext.Provider>
80+
);
81+
}

app/dashboard/child/[id]/page.tsx

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import Link from "next/link";
44
import { useState, useEffect, useCallback, use } from "react";
5+
import NavLogo from "../../../components/NavLogo";
56
import { getProfile } from "../../../lib/db/childProfile.repository";
67
import { listSessions } from "../../../lib/db/session.repository";
78
import { aggregateBiomarkers } from "../../../lib/db/biomarker.repository";
@@ -123,9 +124,7 @@ export default function ChildDetailPage({
123124
<div className="page">
124125
{/* Nav */}
125126
<nav className="nav">
126-
<Link href="/" className="logo">
127-
Auti<em>Sense</em>
128-
</Link>
127+
<NavLogo />
129128
<div style={{ display: "flex", alignItems: "center", gap: 12 }}>
130129
<button
131130
onClick={() => setTheme((t) => (t === "light" ? "dark" : "light"))}
@@ -145,7 +144,7 @@ export default function ChildDetailPage({
145144
>
146145
{/* Back */}
147146
<Link
148-
href="/dashboard"
147+
href="/kid-dashboard"
149148
className="btn btn-outline"
150149
style={{
151150
minHeight: 40,

0 commit comments

Comments
 (0)