enlighten-qalb / src /hooks /useAuth.js
eli02's picture
feat: Add user type selection to Login component and update useAuth hook to manage user type
0056542
raw
history blame contribute delete
3.59 kB
// src/hooks/useAuth.js
import { useState, useContext, createContext, useCallback, useEffect } from 'react';
import { useNavigate } from 'react-router-dom';
import { login as apiLogin, logout as apiLogout, refreshToken as apiRefreshToken } from '../services/auth';
import { useLocalStorage } from './useLocalStorage';
const AuthContext = createContext();
export const AuthProvider = ({ children }) => {
const [user, setUser] = useState(null);
const [authTokens, setAuthTokens] = useLocalStorage('authTokens', null);
const [userType, setUserType] = useLocalStorage('userType', 'Enthusiast');
const [isRefreshing, setIsRefreshing] = useState(false);
const navigate = useNavigate();
const parseJwt = (token) => {
try {
return JSON.parse(atob(token.split('.')[1]));
} catch (e) {
return null;
}
};
const login = useCallback(async (username, password) => {
try {
const { access_token, refresh_token } = await apiLogin(username, password);
setAuthTokens({
access: access_token,
refresh: refresh_token
});
setUser(username);
return { success: true };
} catch (error) {
return { success: false, error: error.message };
}
}, [setAuthTokens]);
const logout = useCallback(async () => {
try {
if (authTokens?.access) {
await apiLogout(authTokens.access);
}
setAuthTokens(null);
setUser(null);
navigate('/login');
} catch (error) {
console.error('Logout error:', error);
// Even if logout API fails, clear local tokens
setAuthTokens(null);
setUser(null);
}
}, [authTokens, setAuthTokens, navigate]);
const refreshToken = useCallback(async () => {
if (!authTokens?.refresh || isRefreshing) return;
setIsRefreshing(true);
try {
const { access_token, refresh_token } = await apiRefreshToken({
refresh_token: authTokens.refresh
});
setAuthTokens({
access: access_token,
refresh: refresh_token
});
return access_token;
} catch (error) {
console.error('Token refresh failed:', error);
logout(); // Full logout if refresh fails
throw error;
} finally {
setIsRefreshing(false);
}
}, [authTokens, isRefreshing, setAuthTokens, logout]);
// Auto-refresh token when it's about to expire
useEffect(() => {
const refreshInterval = setInterval(() => {
if (authTokens?.access) {
const { exp } = parseJwt(authTokens.access);
// Refresh token if it expires in less than 5 minutes
if (exp * 1000 - Date.now() < 300000) {
refreshToken();
}
}
}, 60000); // Check every minute
return () => clearInterval(refreshInterval);
}, [authTokens, refreshToken]);
const getAccessToken = useCallback(async () => {
if (!authTokens?.access) return null;
const { exp } = parseJwt(authTokens.access);
if (exp * 1000 - Date.now() < 30000) { // If expires in <30 seconds
return await refreshToken();
}
return authTokens.access;
}, [authTokens, refreshToken]);
const value = {
user,
authTokens,
userType,
setUserType,
isAuthenticated: !!authTokens?.access,
isRefreshing,
login,
logout,
refreshToken,
getAccessToken
};
return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;
};
export const useAuth = () => {
const context = useContext(AuthContext);
if (!context) {
throw new Error('useAuth must be used within an AuthProvider');
}
return context;
};