Files
beer-inventory/app/root.tsx
T
kennyboy55 36881293ed
Build dev docker image / build (push) Successful in 23s
Build dev docker image / build (push) Successful in 36s
Build dev docker image / release (push) Successful in 1s
AI Changes: scan page fix, filters improvements
2026-08-07 11:53:20 +02:00

170 lines
4.8 KiB
TypeScript

import type { LinksFunction } from "@remix-run/node";
import {
Links,
Meta,
Outlet,
Scripts,
ScrollRestoration,
isRouteErrorResponse,
useRouteError
} from "@remix-run/react";
import React, { useEffect, useState, type PropsWithChildren } from "react";
import stylesheet from "bootstrap/dist/css/bootstrap.min.css?url";
export const links: LinksFunction = () => [
{ rel: "stylesheet", href: stylesheet },
];
import { Col, Container, Row } from "react-bootstrap";
function Document({
children,
title = "K-FRIDGE",
}: PropsWithChildren<{ title?: string}>) {
return (
<html lang="en" data-bs-theme="light">
<head>
<meta charSet="utf-8" />
<meta
name="viewport"
content="width=device-width, initial-scale=1"
/>
<Meta />
<Links />
</head>
<body>
{children}
<ScrollRestoration />
<Scripts />
</body>
</html>
);
}
export default function App() {
return (
<Document>
<Outlet></Outlet>
</Document>
);
}
export function ErrorBoundary() {
const error = useRouteError();
const [isOnline, setIsOnline] = useState<boolean>(
typeof navigator !== "undefined" ? navigator.onLine : true
);
const tryRefresh = async () => {
if (typeof window === "undefined") return;
try {
const res = await fetch(window.location.href, { method: "GET", cache: "no-store" });
if (res && res.ok) {
window.location.reload();
}
} catch (e) {
// network still down; ignore, we'll retry on the next interval or when online
}
};
useEffect(() => {
if (typeof window === "undefined") return;
const handleOnline = () => {
setIsOnline(true);
tryRefresh();
};
const handleOffline = () => setIsOnline(false);
window.addEventListener("online", handleOnline);
window.addEventListener("offline", handleOffline);
const hourly = window.setInterval(() => {
tryRefresh();
}, 15 * 60 * 1000); // Every 15 minutes
return () => {
window.removeEventListener("online", handleOnline);
window.removeEventListener("offline", handleOffline);
window.clearInterval(hourly);
};
}, []);
if (isRouteErrorResponse(error)) {
return (
<Document
title={`${error.status} ${error.statusText}`}
>
<Container>
<Row className="align-items-md-stretch">
<Col md={12}>
<div className="h-100 p-5 text-bg-dark rounded-3">
<h1>{error.status}</h1>
{error.statusText}
<div className="mt-3">
<button
className="btn btn-primary me-2"
onClick={() => {
if (typeof window !== "undefined") window.location.reload();
}}
>
Reload page
</button>
<button
className="btn btn-outline-secondary"
onClick={() => {
tryRefresh();
}}
>
Try refresh now
</button>
<div className="mt-2">Status: {isOnline ? "Online" : "Offline"}. Will retry automatically every 15 minutes.</div>
</div>
</div>
</Col>
</Row>
</Container>
</Document>
);
}
const errorMessage =
error instanceof Error
? error.message
: "Unknown error";
return (
<Document title="Uh-oh!">
<Container>
<Row className="align-items-md-stretch">
<Col md={12}>
<div className="h-100 p-5 text-bg-dark rounded-3">
<h1>App Error</h1>
{errorMessage}
<div className="mt-3">
<button
className="btn btn-primary me-2"
onClick={() => {
if (typeof window !== "undefined") window.location.reload();
}}
>
Reload page
</button>
<button
className="btn btn-outline-secondary"
onClick={() => {
tryRefresh();
}}
>
Try refresh now
</button>
<div className="mt-2">Status: {isOnline ? "Online" : "Offline"}. Will retry automatically every 15 minutes.</div>
</div>
</div>
</Col>
</Row>
</Container>
</Document>
);
}