Auto-reload app every 24h when inactive
This commit is contained in:
@@ -8,6 +8,7 @@ import { LoadingIndicatorBar } from "~/components/LoadingIndicator";
|
|||||||
import SkipNavContent from "~/components/SkipNavContent";
|
import SkipNavContent from "~/components/SkipNavContent";
|
||||||
import SkipNavLink from "~/components/SkipNavLink";
|
import SkipNavLink from "~/components/SkipNavLink";
|
||||||
import env from "~/env";
|
import env from "~/env";
|
||||||
|
import useAutoRefresh from "~/hooks/useAutoRefresh";
|
||||||
import useKeyDown from "~/hooks/useKeyDown";
|
import useKeyDown from "~/hooks/useKeyDown";
|
||||||
import { MenuProvider } from "~/hooks/useMenuContext";
|
import { MenuProvider } from "~/hooks/useMenuContext";
|
||||||
import useStores from "~/hooks/useStores";
|
import useStores from "~/hooks/useStores";
|
||||||
@@ -28,6 +29,8 @@ const Layout: React.FC<Props> = ({
|
|||||||
const { ui } = useStores();
|
const { ui } = useStores();
|
||||||
const sidebarCollapsed = !sidebar || ui.sidebarIsClosed;
|
const sidebarCollapsed = !sidebar || ui.sidebarIsClosed;
|
||||||
|
|
||||||
|
useAutoRefresh();
|
||||||
|
|
||||||
useKeyDown(".", (event) => {
|
useKeyDown(".", (event) => {
|
||||||
if (isModKey(event)) {
|
if (isModKey(event)) {
|
||||||
ui.toggleCollapsedSidebar();
|
ui.toggleCollapsedSidebar();
|
||||||
|
|||||||
33
app/hooks/useAutoRefresh.ts
Normal file
33
app/hooks/useAutoRefresh.ts
Normal 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);
|
||||||
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
|
import { Minute } from "@shared/utils/time";
|
||||||
|
|
||||||
const activityEvents = [
|
const activityEvents = [
|
||||||
"click",
|
"click",
|
||||||
@@ -18,7 +19,7 @@ const activityEvents = [
|
|||||||
* @param {number} timeToIdle
|
* @param {number} timeToIdle
|
||||||
* @returns boolean if the user is idle
|
* @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 [isIdle, setIsIdle] = React.useState(false);
|
||||||
const timeout = React.useRef<ReturnType<typeof setTimeout>>();
|
const timeout = React.useRef<ReturnType<typeof setTimeout>>();
|
||||||
|
|
||||||
|
|||||||
32
app/hooks/useInterval.ts
Normal file
32
app/hooks/useInterval.ts
Normal 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]);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user