updates on the login

This commit is contained in:
2026-07-01 16:19:49 +05:30
parent f50d5a0c56
commit 39e97c3041
6 changed files with 147 additions and 49 deletions

View File

@@ -0,0 +1,96 @@
import { useEffect, useRef } from 'react';
import { useQueryClient } from '@tanstack/react-query';
import { useDispatch } from 'react-redux';
import { clearFcmToken } from 'store/reducers/fcmSlice';
import { logoutUser } from 'store/reducers/loginUserSlice';
import {
ABSOLUTE_SESSION_TIMEOUT_MS,
ACTIVITY_STORAGE_KEY,
AUTH_PRESENCE_KEY,
INACTIVITY_TIMEOUT_MS,
SESSION_START_STORAGE_KEY,
isSessionActive,
markActivity,
markSessionStart,
performSessionLogout
} from 'utils/session';
const ACTIVITY_EVENTS = ['mousemove', 'mousedown', 'keydown', 'scroll', 'touchstart', 'wheel'];
const ACTIVITY_WRITE_THROTTLE_MS = 5000;
const IDLE_CHECK_INTERVAL_MS = 15000;
// Two independent timers, both enforced from localStorage so every tab on the
// origin agrees:
// - INACTIVITY_TIMEOUT_MS: logs out after 15 minutes with no interaction, so
// a laptop left unlocked doesn't leave the console open indefinitely.
// - ABSOLUTE_SESSION_TIMEOUT_MS: a hard 30-minute cap since login, even if
// the user has been continuously active, so localStorage (auth keys, FCM
// token, cached zone list) never lingers on disk longer than that.
// A logout in one tab (auth key cleared) is picked up by the others via the
// 'storage' event.
const useInactivityLogout = () => {
const queryClient = useQueryClient();
const dispatch = useDispatch();
const lastWriteRef = useRef(0);
useEffect(() => {
const doLogout = () => performSessionLogout({ queryClient, dispatch, clearFcmToken, logoutUser });
const handleActivity = () => {
const now = Date.now();
if (now - lastWriteRef.current < ACTIVITY_WRITE_THROTTLE_MS) return;
lastWriteRef.current = now;
markActivity();
};
const handleStorage = (event) => {
if (event.key === AUTH_PRESENCE_KEY && !event.newValue) {
doLogout();
}
};
// Guards against the browser restoring a cached (bfcache) copy of a
// protected page via the back/forward button after logout happened.
const handlePageShow = (event) => {
if (event.persisted && !isSessionActive()) {
window.location.replace('/login');
}
};
if (isSessionActive()) {
if (!localStorage.getItem(ACTIVITY_STORAGE_KEY)) markActivity();
// Sessions that were already open before this feature shipped won't have
// a start time yet — give them a fresh 30-minute window instead of
// treating them as already expired.
if (!localStorage.getItem(SESSION_START_STORAGE_KEY)) markSessionStart();
}
ACTIVITY_EVENTS.forEach((eventName) => window.addEventListener(eventName, handleActivity, { passive: true }));
window.addEventListener('storage', handleStorage);
window.addEventListener('pageshow', handlePageShow);
const intervalId = setInterval(() => {
if (!isSessionActive()) return;
const lastActivity = Number(localStorage.getItem(ACTIVITY_STORAGE_KEY)) || Date.now();
if (Date.now() - lastActivity >= INACTIVITY_TIMEOUT_MS) {
doLogout();
return;
}
const sessionStart = Number(localStorage.getItem(SESSION_START_STORAGE_KEY)) || Date.now();
if (Date.now() - sessionStart >= ABSOLUTE_SESSION_TIMEOUT_MS) {
doLogout();
}
}, IDLE_CHECK_INTERVAL_MS);
return () => {
ACTIVITY_EVENTS.forEach((eventName) => window.removeEventListener(eventName, handleActivity));
window.removeEventListener('storage', handleStorage);
window.removeEventListener('pageshow', handlePageShow);
clearInterval(intervalId);
};
}, [queryClient, dispatch]);
};
export default useInactivityLogout;