Auto-reload app every 24h when inactive

This commit is contained in:
Tom Moor
2023-03-29 22:01:45 -04:00
parent f8a6a4b840
commit 381d640719
4 changed files with 70 additions and 1 deletions

View File

@@ -8,6 +8,7 @@ import { LoadingIndicatorBar } from "~/components/LoadingIndicator";
import SkipNavContent from "~/components/SkipNavContent";
import SkipNavLink from "~/components/SkipNavLink";
import env from "~/env";
import useAutoRefresh from "~/hooks/useAutoRefresh";
import useKeyDown from "~/hooks/useKeyDown";
import { MenuProvider } from "~/hooks/useMenuContext";
import useStores from "~/hooks/useStores";
@@ -28,6 +29,8 @@ const Layout: React.FC<Props> = ({
const { ui } = useStores();
const sidebarCollapsed = !sidebar || ui.sidebarIsClosed;
useAutoRefresh();
useKeyDown(".", (event) => {
if (isModKey(event)) {
ui.toggleCollapsedSidebar();

View File

@@ -0,0 +1,33 @@
import * as React from "react";
import { Minute } from "@shared/utils/time";
import Logger from "~/utils/Logger";
import useIdle from "./useIdle";
import useInterval from "./useInterval";
import usePageVisibility from "./usePageVisibility";
/**
* Hook to reload the app around once a day to stop old code from running.
*/
export default function useAutoRefresh() {
const [minutes, setMinutes] = React.useState(0);
const isVisible = usePageVisibility();
const isIdle = useIdle(15 * Minute);
useInterval(() => {
setMinutes((prev) => prev + 1);
if (minutes >= 60 * 24) {
if (isVisible) {
Logger.debug("lifecycle", "Skipping reload due to app visible");
return;
}
if (!isIdle) {
Logger.debug("lifecycle", "Skipping reload due to user activity");
return;
}
Logger.debug("lifecycle", "Auto-reloading app…");
window.location.reload();
}
}, Minute);
}

View File

@@ -1,4 +1,5 @@
import * as React from "react";
import { Minute } from "@shared/utils/time";
const activityEvents = [
"click",
@@ -18,7 +19,7 @@ const activityEvents = [
* @param {number} timeToIdle
* @returns boolean if the user is idle
*/
export default function useIdle(timeToIdle: number = 3 * 60 * 1000) {
export default function useIdle(timeToIdle: number = 3 * Minute) {
const [isIdle, setIsIdle] = React.useState(false);
const timeout = React.useRef<ReturnType<typeof setTimeout>>();

32
app/hooks/useInterval.ts Normal file
View File

@@ -0,0 +1,32 @@
import * as React from "react";
type Callback = () => void;
/**
* Hook to set up an interval that calls a callback.
*
* @param callback The callback to call.
* @param delay The delay in milliseconds.
*/
export default function useInterval(callback: Callback, delay: number) {
const savedCallback = React.useRef<Callback>();
// Remember the latest callback.
React.useEffect(() => {
savedCallback.current = callback;
}, [callback]);
// Set up the interval.
React.useEffect(() => {
function tick() {
savedCallback.current?.();
}
if (delay !== null) {
const id = setInterval(tick, delay);
return () => clearInterval(id);
}
return undefined;
}, [delay]);
}