Skip to content

Instantly share code, notes, and snippets.

@slinkardbrandon
Created June 10, 2021 19:40
Show Gist options
  • Save slinkardbrandon/189fe9af8cad9f91ebd4c93485c6b9ab to your computer and use it in GitHub Desktop.
Save slinkardbrandon/189fe9af8cad9f91ebd4c93485c6b9ab to your computer and use it in GitHub Desktop.
useIdleTimer
export const Screen: React.FC = () => {
useIdleTimer({
idleMs: 30 * 60000,
warningBeforeIdleMs: 25 * 60000,
onWarning: () => console.log('pop warning dialog'),
onIdle: async () => {
console.log('close warning dialog, sign the user out, etc');
},
});
return <div>Screen Content</div>
}
import { throttle } from 'lodash';
import { useEffect, useRef } from 'react';
export interface IEventHandler {
addEventListener(eventName: string, cb: () => void): void;
setTimeout(cb: () => void, time: number): number;
setInterval(cb: () => void, time: number): number;
clearTimeout(id: number): void;
clearInterval(id: number): void;
}
export interface IIdleTimerProps {
idleMs?: number | false;
warningBeforeIdleMs?: number | false;
onWarning?: () => void;
onIdle?: () => void;
eventNames?: string[];
throttleMs?: number;
}
export function provideEventContainer(): IEventHandler {
return window;
}
export function useIdleTimer({
idleMs,
warningBeforeIdleMs,
onWarning = () => undefined,
onIdle = () => undefined,
throttleMs = 500,
eventNames = [
'mousedown',
'mouseup',
'mousemove',
'touchstart',
'touchend',
'touchmove',
'scroll',
'resize',
'focus',
'keydown',
'keyup',
],
}: IIdleTimerProps): { resetTimer: () => void } {
const { addEventListener, setTimeout, clearTimeout } = provideEventContainer();
const timeoutIds = useRef<{ idle: any; warning: any }>({
idle: null,
warning: null,
});
const stopTimer = () => {
clearTimeout(timeoutIds.current.idle);
clearTimeout(timeoutIds.current.warning);
};
const startTimer = () => {
if (idleMs) {
timeoutIds.current.idle = setTimeout(onIdle, idleMs);
}
if (idleMs && warningBeforeIdleMs) {
timeoutIds.current.warning = setTimeout(onWarning, idleMs - warningBeforeIdleMs);
}
};
const resetTimer = throttle(() => {
stopTimer();
startTimer();
}, throttleMs);
useEffect(() => {
startTimer();
eventNames.forEach(eventName => addEventListener(eventName, resetTimer));
return () => stopTimer();
}, [idleMs, warningBeforeIdleMs]);
return {
resetTimer,
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment