Files

74 lines
2.1 KiB
TypeScript

"use client";
import React, {
createContext,
useContext,
useState,
useEffect,
useCallback,
} from "react";
import type { AuthUser, AuthState } from "@/lib/auth-types";
interface AuthContextValue extends AuthState {
login: (token: string, user: AuthUser) => void;
logout: () => void;
}
const AuthContext = createContext<AuthContextValue | null>(null);
const TOKEN_KEY = "auth_token";
const USER_KEY = "auth_user";
export function AuthProvider({ children }: { children: React.ReactNode }) {
const [state, setState] = useState<AuthState>({
user: null,
token: null,
isLoading: true,
});
useEffect(() => {
const token = localStorage.getItem(TOKEN_KEY);
const userRaw = localStorage.getItem(USER_KEY);
if (token && userRaw) {
try {
const user = JSON.parse(userRaw) as AuthUser;
setState({ user, token, isLoading: false });
} catch {
localStorage.removeItem(TOKEN_KEY);
localStorage.removeItem(USER_KEY);
setState({ user: null, token: null, isLoading: false });
}
} else {
setState((s) => ({ ...s, isLoading: false }));
}
}, []);
const login = useCallback((token: string, user: AuthUser) => {
localStorage.setItem(TOKEN_KEY, token);
localStorage.setItem(USER_KEY, JSON.stringify(user));
// Also set a cookie so proxy.ts (Next.js 16) can read it for route gating
document.cookie = `auth_token=${token}; path=/; SameSite=Strict; max-age=28800`;
setState({ user, token, isLoading: false });
}, []);
const logout = useCallback(() => {
localStorage.removeItem(TOKEN_KEY);
localStorage.removeItem(USER_KEY);
document.cookie = "auth_token=; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT";
setState({ user: null, token: null, isLoading: false });
window.location.href = "/auth/login";
}, []);
return (
<AuthContext.Provider value={{ ...state, login, logout }}>
{children}
</AuthContext.Provider>
);
}
export function useAuth(): AuthContextValue {
const ctx = useContext(AuthContext);
if (!ctx) throw new Error("useAuth must be used inside AuthProvider");
return ctx;
}