@@ -1,4 +1,4 @@
|
||||
import { useReducer, createContext, useEffect } from 'react';
|
||||
import { useReducer, createContext, useEffect, useCallback } from 'react';
|
||||
import axios from 'axios';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { apiUrl } from "../apiConfig";
|
||||
@@ -14,12 +14,16 @@ interface ActionType {
|
||||
|
||||
type InitialStateType = {
|
||||
user: any;
|
||||
lastActivityTime?: number;
|
||||
};
|
||||
|
||||
const initialState = {
|
||||
user: null,
|
||||
lastActivityTime: Date.now(),
|
||||
};
|
||||
|
||||
const AUTO_LOGOUT_TIME = 4 * 60 * 60 * 1000; // 4 hours in milliseconds
|
||||
|
||||
const AuthContext = createContext<{
|
||||
state: InitialStateType;
|
||||
dispatch: React.Dispatch<ActionType>;
|
||||
@@ -34,11 +38,13 @@ const reducer = (state: InitialStateType, action: ActionType) => {
|
||||
return {
|
||||
...state,
|
||||
user: action.payload,
|
||||
lastActivityTime: Date.now(),
|
||||
};
|
||||
case 'LOGOUT':
|
||||
return {
|
||||
...state,
|
||||
user: null,
|
||||
lastActivityTime: undefined,
|
||||
};
|
||||
default:
|
||||
return state;
|
||||
@@ -50,6 +56,39 @@ const AuthProvider = ({ children }: AuthProviderProps) => {
|
||||
const navigate = useNavigate();
|
||||
axios.defaults.withCredentials = true;
|
||||
|
||||
const handleLogout = useCallback(async () => {
|
||||
try {
|
||||
await axios.get(`${apiUrl}/auth/logout`);
|
||||
dispatch({ type: 'LOGOUT' });
|
||||
window.localStorage.removeItem('user');
|
||||
navigate('/login');
|
||||
} catch (err) {
|
||||
console.error('Logout error:', err);
|
||||
}
|
||||
}, [navigate]);
|
||||
|
||||
const checkAutoLogout = useCallback(() => {
|
||||
if (state.user && state.lastActivityTime) {
|
||||
const currentTime = Date.now();
|
||||
const timeSinceLastActivity = currentTime - state.lastActivityTime;
|
||||
|
||||
if (timeSinceLastActivity >= AUTO_LOGOUT_TIME) {
|
||||
handleLogout();
|
||||
}
|
||||
}
|
||||
}, [state.user, state.lastActivityTime, handleLogout]);
|
||||
|
||||
// Update last activity time on user interactions
|
||||
const updateActivityTime = useCallback(() => {
|
||||
if (state.user) {
|
||||
dispatch({
|
||||
type: 'LOGIN',
|
||||
payload: state.user // Reuse existing user data
|
||||
});
|
||||
}
|
||||
}, [state.user]);
|
||||
|
||||
// Initialize user from localStorage
|
||||
useEffect(() => {
|
||||
const storedUser = window.localStorage.getItem('user');
|
||||
if (storedUser) {
|
||||
@@ -57,21 +96,54 @@ const AuthProvider = ({ children }: AuthProviderProps) => {
|
||||
}
|
||||
}, []);
|
||||
|
||||
// Set up activity listeners
|
||||
useEffect(() => {
|
||||
if (state.user) {
|
||||
// List of events to track for user activity
|
||||
const events = ['mousedown', 'keydown', 'scroll', 'touchstart'];
|
||||
|
||||
// Throttled event handler
|
||||
let timeoutId: NodeJS.Timeout;
|
||||
const handleActivity = () => {
|
||||
if (timeoutId) {
|
||||
clearTimeout(timeoutId);
|
||||
}
|
||||
timeoutId = setTimeout(updateActivityTime, 1000);
|
||||
};
|
||||
|
||||
// Add event listeners
|
||||
events.forEach(event => {
|
||||
window.addEventListener(event, handleActivity);
|
||||
});
|
||||
|
||||
// Set up periodic check for auto logout
|
||||
const checkInterval = setInterval(checkAutoLogout, 60000); // Check every minute
|
||||
|
||||
// Cleanup
|
||||
return () => {
|
||||
events.forEach(event => {
|
||||
window.removeEventListener(event, handleActivity);
|
||||
});
|
||||
clearInterval(checkInterval);
|
||||
if (timeoutId) {
|
||||
clearTimeout(timeoutId);
|
||||
}
|
||||
};
|
||||
}
|
||||
}, [state.user, updateActivityTime, checkAutoLogout]);
|
||||
|
||||
axios.interceptors.response.use(
|
||||
function (response) {
|
||||
return response;
|
||||
},
|
||||
function (error) {
|
||||
const res = error.response;
|
||||
if (res.status === 401 && res.config && !res.config.__isRetryRequest) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
.get(`${apiUrl}/auth/logout`)
|
||||
if (res?.status === 401 && res.config && !res.config.__isRetryRequest) {
|
||||
return new Promise((_, reject) => {
|
||||
handleLogout()
|
||||
.then(() => {
|
||||
console.log('/401 error > logout');
|
||||
dispatch({ type: 'LOGOUT' });
|
||||
window.localStorage.removeItem('user');
|
||||
navigate('/login');
|
||||
reject(error);
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error('AXIOS INTERCEPTORS ERROR:', err);
|
||||
|
||||
Reference in New Issue
Block a user