import { useEffect, useRef } from 'react'; import { useAuth } from '../context/AuthContext'; import { getAutoLockMinutes, subscribeAutoLockSetting, type AutoLockMinutes, } from '../lib/autoLockSettings'; const ACTIVITY_EVENTS: Array = [ 'keydown', 'mousedown', 'pointermove', 'touchstart', 'wheel', ]; // Throttle activity-event resets to once per second to avoid thrashing the // timer on rapid mouse movement. const RESET_THROTTLE_MS = 1000; export function useIdleAutoLock(): void { const { session, signOut } = useAuth(); const minutesRef = useRef(getAutoLockMinutes()); const timerRef = useRef(null); const lastResetAtRef = useRef(0); // Keep minutesRef live to the setting. useEffect(() => { const unsub = subscribeAutoLockSetting((v) => { minutesRef.current = v; scheduleNext(); }); return unsub; // eslint-disable-next-line react-hooks/exhaustive-deps }, []); // Helper: schedule the lock based on the current setting. function scheduleNext(): void { if (timerRef.current !== null) { window.clearTimeout(timerRef.current); timerRef.current = null; } const min = minutesRef.current; if (min === 0) return; // disabled timerRef.current = window.setTimeout(() => { timerRef.current = null; // Fire the lock. signOut wipes local state and navigates to /device // (PIN re-entry screen). void signOut().catch((err) => console.warn('auto-lock signOut failed', err)); }, min * 60 * 1000); } useEffect(() => { if (!session) return; scheduleNext(); const onActivity = () => { const now = Date.now(); if (now - lastResetAtRef.current < RESET_THROTTLE_MS) return; lastResetAtRef.current = now; scheduleNext(); }; for (const ev of ACTIVITY_EVENTS) { window.addEventListener(ev, onActivity, { passive: true }); } return () => { for (const ev of ACTIVITY_EVENTS) { window.removeEventListener(ev, onActivity); } if (timerRef.current !== null) { window.clearTimeout(timerRef.current); timerRef.current = null; } }; // eslint-disable-next-line react-hooks/exhaustive-deps }, [session]); }