From 4df8a5fa285c6ae06bd07960bfbdc19b80b711bd Mon Sep 17 00:00:00 2001 From: Kalle <38327916+Sendouc@users.noreply.github.com> Date: Sun, 4 Oct 2026 19:28:05 +0300 Subject: [PATCH] Reload page if 503 so they see the updating page --- app/components/Catcher.tsx | 70 +++++++++++++++++++++++++++++--------- 1 file changed, 54 insertions(+), 16 deletions(-) diff --git a/app/components/Catcher.tsx b/app/components/Catcher.tsx index 55b7148ef..303db4a16 100644 --- a/app/components/Catcher.tsx +++ b/app/components/Catcher.tsx @@ -1,13 +1,16 @@ import { RefreshCcw } from "lucide-react"; import * as React from "react"; import { + type ErrorResponse, isRouteErrorResponse, useLocation, useNavigate, useRevalidator, useRouteError, } from "react-router"; +import * as v from "valibot"; import { useUser } from "~/features/auth/core/user"; +import * as PersistedState from "~/modules/persisted-state/persisted-state"; import * as Redirect from "~/modules/redirects/core/Redirect"; import { getSessionId } from "~/utils/session-id"; import { @@ -19,6 +22,15 @@ import { SendouButton } from "./elements/Button"; import { Image } from "./Image"; import { Main } from "./Main"; +const MAINTENANCE_RELOAD_COOLDOWN_MS = 60_000; + +const maintenanceReloadedAtPersisted = PersistedState.define({ + key: "maintenanceReloadedAt", + storage: "session", + schema: v.number(), + default: 0, +}); + export function Catcher() { const error = useRouteError(); const user = useUser(); @@ -91,6 +103,8 @@ export function Catcher() { } switch (error.status) { + case 503: + return ; case 401: if (!user) { return ( @@ -125,22 +139,7 @@ export function Catcher() { case 404: return ; default: - return ( - -

Error {error.status}

- -
- Please include the session ID and message below if any and an - explanation on what you were doing: -
-
-						Session ID: {getSessionId()}
-						{error.data
-							? `\n${typeof error.data === "string" ? error.data : JSON.stringify(error.data, null, 2)}`
-							: null}
-					
-
- ); + return ; } } @@ -166,6 +165,45 @@ function PageNotFound() { ); } +/** Render answers with 503 during maintenance, a full reload lets it serve its static "updating" page instead. */ +function ServiceUnavailable({ error }: { error: ErrorResponse }) { + const [shouldReload] = React.useState( + () => + Date.now() - PersistedState.read(maintenanceReloadedAtPersisted) > + MAINTENANCE_RELOAD_COOLDOWN_MS, + ); + + React.useEffect(() => { + if (!shouldReload) return; + + PersistedState.write(maintenanceReloadedAtPersisted, Date.now()); + window.location.reload(); + }, [shouldReload]); + + if (shouldReload) return null; + + return ; +} + +function ErrorStatus({ error }: { error: ErrorResponse }) { + return ( + +

Error {error.status}

+ +
+ Please include the session ID and message below if any and an + explanation on what you were doing: +
+
+				Session ID: {getSessionId()}
+				{error.data
+					? `\n${typeof error.data === "string" ? error.data : JSON.stringify(error.data, null, 2)}`
+					: null}
+			
+
+ ); +} + /** Every branch of the error page, marked so tests can assert one is not shown. */ function ErrorMain({ children }: { children: React.ReactNode }) { return
{children}
;