Files
headquarter/apps/web/src/state/auth.tsx
T

64 lines
1.6 KiB
TypeScript

import { createContext, useCallback, useContext, useEffect, useMemo, useState } from "react";
import { apiClient } from "../api/client";
import type { SessionPayload, SessionUser } from "../types";
type AuthState = "loading" | "authenticated" | "unauthenticated";
type AuthContextValue = {
state: AuthState;
user: SessionUser | null;
refreshSession: () => Promise<void>;
logout: () => Promise<void>;
};
const AuthContext = createContext<AuthContextValue | undefined>(undefined);
export const AuthProvider = ({ children }: { children: React.ReactNode }) => {
const [state, setState] = useState<AuthState>("loading");
const [user, setUser] = useState<SessionUser | null>(null);
const refreshSession = useCallback(async () => {
setState("loading");
try {
const response = await apiClient.get<SessionPayload>("/auth/me");
setUser(response.data.user);
setState("authenticated");
} catch {
setUser(null);
setState("unauthenticated");
}
}, []);
const logout = useCallback(async () => {
await apiClient.post("/auth/logout");
setUser(null);
setState("unauthenticated");
}, []);
useEffect(() => {
void refreshSession();
}, [refreshSession]);
const value = useMemo(
() => ({
state,
user,
refreshSession,
logout
}),
[refreshSession, state, user, logout]
);
return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;
};
export const useAuth = (): AuthContextValue => {
const context = useContext(AuthContext);
if (!context) {
throw new Error("useAuth must be used within AuthProvider");
}
return context;
};