Files
beer-inventory/app/routes/inventory/layout.tsx
T
kennyboy55 e4c93eb024
Build dev docker image / build (push) Successful in 34s
Build dev docker image / release (push) Successful in 1s
AI Changes: add user management and hashed passwords, admin dashboard, report fixes
2026-08-01 11:47:21 +02:00

108 lines
2.9 KiB
TypeScript

import { LoaderFunctionArgs, MetaFunction } from "@remix-run/node";
import { Outlet, json, useLoaderData, useRevalidator } from "@remix-run/react";
import { useEffect, useRef, useState } from "react";
import Header, { HeaderData } from "~/components/header";
import { enhance } from "~/utils/db.server";
export async function loader({
request,
}: LoaderFunctionArgs) {
const {dbe, session} = await enhance(request);
let sessiondata : HeaderData = {loggedin: false};
if(session.has("user_id")){
sessiondata.user = session.get("user");
sessiondata.loggedin = true;
}
const numCheckouts = await dbe.history.count({});
return json({sessiondata, checkouts: numCheckouts});
}
export const meta: MetaFunction = ({}) => {
return [{ title: "Inventory | K-FRIDGE" }];
};
export default function InventoryLayout() {
let data = useLoaderData<typeof loader>();
let revalidator = useRevalidator();
const [checkouts, setCheckouts] = useState(data.checkouts);
const shouldFetchRef = useRef(true);
// User has switched back to the tab
const onFocus = () => {
shouldFetchRef.current = true;
};
// User has switched away from the tab (AKA tab is hidden)
const onBlur = () => {
shouldFetchRef.current = false;
};
useEffect(() => {
window.addEventListener("focus", onFocus);
window.addEventListener("blur", onBlur);
// Calls onFocus when the window first loads
onFocus();
// Specify how to clean up after this effect:
return () => {
window.removeEventListener("focus", onFocus);
window.removeEventListener("blur", onBlur);
};
}, []);
useEffect(() => {
const pollCheckouts = async () => {
if (!shouldFetchRef.current) {
return;
}
try {
const response = await fetch("/resource/checkouts", { credentials: "same-origin" });
if (!response.ok) {
return;
}
const payload = await response.json() as { checkouts?: number | string | null };
const newCheckouts = Number(payload.checkouts);
if (!Number.isFinite(newCheckouts)) {
return;
}
if (newCheckouts !== checkouts) {
setCheckouts(newCheckouts);
if (revalidator.state === "idle") {
revalidator.revalidate();
}
}
} catch {
// Ignore transient network errors while the connection is down.
}
};
const timer = window.setInterval(() => {
void pollCheckouts();
}, 5000);
void pollCheckouts();
return () => window.clearInterval(timer);
}, [checkouts, revalidator]);
return (
<>
<header>
<Header data={data.sessiondata}></Header>
</header>
<main>
<Outlet />
</main>
</>
);
}