Files
coastal_timesheet/frontend/src/contexts/AuthContext.jsx
T
BizzleBot 70ed672381 Fix: ManageUsers component missing useAuth() - caused blank admin page
The ManageUsers sub-component referenced user?.role for conditional
role dropdown options but didn't call useAuth() to get the user object.
This caused 'user is not defined' JS errors and blank admin pages.

Browser E2E: 20/20 tests pass.
2026-02-16 20:24:34 +00:00

99 lines
2.5 KiB
React

import { createContext, useContext, useState, useEffect, useCallback } from 'react';
import { useLocation } from 'react-router-dom';
import api, { setTokens, clearTokens, getAccessToken } from '../api/client';
const AuthContext = createContext(null);
export function AuthProvider({ children }) {
const [user, setUser] = useState(() => {
try {
const stored = localStorage.getItem('user');
return stored ? JSON.parse(stored) : null;
} catch {
return null;
}
});
const [loading, setLoading] = useState(true);
const location = useLocation();
const refreshUser = useCallback(async () => {
try {
const { data } = await api.get('/auth/me');
setUser(data.user);
localStorage.setItem('user', JSON.stringify(data.user));
} catch {
/* If /me fails, we might be logged out or server is down */
}
}, []);
/* On mount, verify the stored token is still valid */
useEffect(() => {
async function verify() {
const token = getAccessToken();
if (!token) {
setLoading(false);
return;
}
try {
const { data } = await api.get('/auth/me');
setUser(data.user);
localStorage.setItem('user', JSON.stringify(data.user));
} catch {
clearTokens();
setUser(null);
} finally {
setLoading(false);
}
}
verify();
}, []);
/* Refresh user profile on navigation to ensure role is up to date */
useEffect(() => {
if (user) {
refreshUser();
}
}, [location.pathname, user?.id]);
const login = useCallback(async (email, password) => {
const { data } = await api.post('/auth/login', { email, password });
setTokens(data.accessToken, data.refreshToken);
setUser(data.user);
localStorage.setItem('user', JSON.stringify(data.user));
return data.user;
}, []);
const logout = useCallback(async () => {
try {
await api.post('/auth/logout');
} catch {
/* ignore — we clear locally regardless */
}
clearTokens();
setUser(null);
}, []);
const isAdmin = ['office', 'admin', 'super_admin'].includes(user?.role);
const value = {
user,
loading,
login,
logout,
isAdmin,
isAuthenticated: !!user,
};
return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;
}
export function useAuth() {
const ctx = useContext(AuthContext);
if (!ctx) {
throw new Error('useAuth must be used within an AuthProvider');
}
return ctx;
}
export default AuthContext;