import React from "react"; import {idleStateAction, type State, type IdleState} from "../reducer"; import {useDispatch, useSelector} from "react-redux"; export const DEFAULT_IDLE_TIMEOUT = 300; interface Props { children: React.ReactNode; } export const IdleDetectorContext = React.createContext({ timeout: DEFAULT_IDLE_TIMEOUT, state: "active", }); function createTimer(time: number, callback: (idleState: IdleState["state"]) => void) { let timer: number; function start() { timer = window.setTimeout(() => callback("idle"), time * 1000); } function reset() { clearTimeout(timer); callback("active"); start(); } function clear() { clearTimeout(timer); } return {start, reset, clear}; } export function IdleDetector(props: Props) { const {children} = props; const {timeout, state} = useSelector((state: State) => state.idle); const stateRef = React.useRef(state); stateRef.current = state; const dispatch = useDispatch(); React.useEffect(() => { if (timeout > 0) { const idleTimer = createTimer(timeout, newIdleState => { if (newIdleState !== stateRef.current) { dispatch(idleStateAction(newIdleState)); } }); idleTimer.start(); window.addEventListener("click", idleTimer.reset); window.addEventListener("touchmove", idleTimer.reset); window.addEventListener("keydown", idleTimer.reset); window.addEventListener("mousemove", idleTimer.reset); return () => { window.removeEventListener("click", idleTimer.reset); window.removeEventListener("touchmove", idleTimer.reset); window.removeEventListener("keydown", idleTimer.reset); window.removeEventListener("mousemove", idleTimer.reset); idleTimer.clear(); }; } }, [timeout]); return {children}; }