Files
quietthanks/src/components/AuthProvider.tsx
Gemini Agent 504f07a106 Add multiple entries per day, user management, reminders, and AI reflections
- Multiple entries per day: Home page now starts fresh, Save & New button
- Admin user management: Add/delete users, reset passwords, toggle admin
- Daily reminders: Browser notifications at configurable time
- AI reflections: Generate insights from entries using Claude API
- Remove cloud sync placeholder (already have user accounts)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-24 12:05:39 +00:00

90 lines
2.0 KiB
TypeScript

"use client";
import { createContext, useContext, useState, useEffect, useCallback } from "react";
import { useRouter, usePathname } from "next/navigation";
interface User {
id: string;
email: string;
name: string | null;
isAdmin: boolean;
}
interface AuthContextType {
user: User | null;
isLoading: boolean;
logout: () => Promise<void>;
refresh: () => Promise<void>;
}
const AuthContext = createContext<AuthContextType>({
user: null,
isLoading: true,
logout: async () => {},
refresh: async () => {},
});
export function useAuth() {
return useContext(AuthContext);
}
const PUBLIC_PATHS = ["/login", "/register"];
export function AuthProvider({ children }: { children: React.ReactNode }) {
const [user, setUser] = useState<User | null>(null);
const [isLoading, setIsLoading] = useState(true);
const router = useRouter();
const pathname = usePathname();
const fetchUser = useCallback(async () => {
try {
const res = await fetch("/api/auth/me");
const data = await res.json();
setUser(data.user);
return data.user;
} catch {
setUser(null);
return null;
} finally {
setIsLoading(false);
}
}, []);
useEffect(() => {
fetchUser().then((user) => {
if (!user && !PUBLIC_PATHS.includes(pathname)) {
router.push("/login");
}
});
}, [fetchUser, pathname, router]);
const logout = async () => {
try {
await fetch("/api/auth/logout", { method: "POST" });
setUser(null);
router.push("/login");
} catch {
// Ignore errors
}
};
const refresh = async () => {
await fetchUser();
};
// Show nothing while checking auth on protected pages
if (isLoading && !PUBLIC_PATHS.includes(pathname)) {
return (
<div className="min-h-screen flex items-center justify-center">
<div className="animate-pulse text-muted">Loading...</div>
</div>
);
}
return (
<AuthContext.Provider value={{ user, isLoading, logout, refresh }}>
{children}
</AuthContext.Provider>
);
}