Phase 4: Terminal im Gerätehaus mit Offline-Betrieb #5

Merged
florian.wilde merged 2 commits from feat/phase-4-kiosk into main 2026-09-03 18:25:36 +00:00
4 changed files with 73 additions and 1 deletions
Showing only changes of commit e500ad6c0e - Show all commits
+9
View File
@@ -128,6 +128,15 @@ bedienbar ist und weiterarbeitet, wenn das Netz weg ist.
Offline-E2E-Test, der genau darauf wartet.
- `/kiosk/einrichten` ließ sich nicht vorab erzeugen, weil `useSearchParams()`
ohne Suspense-Grenze stand. Der Produktionsbuild brach dabei ab.
- Der Anwesenheits- und der Fahrten-Wizard zeigten erst die eine, nach dem
Laden des eigenen Stands die andere Fassung — wer zügig tippte, drückte ins
Leere. Bis der Stand bekannt ist, steht dort jetzt ein Platzhalter.
- Die Offline-Seite blieb stehen, wenn nur eine einzelne Anfrage abgebrochen
war. Am Hallenmonitor, den niemand bedient, hieße das: bis jemand vorbeikommt.
Sie versucht es jetzt alle zehn Sekunden von selbst.
- Der Hallenmonitor stapelte alle laufenden Einsätze übereinander und schob
damit Anwesenheit, Fahrzeuge und Prüfungen aus dem Bild. Zwei stehen groß,
der Rest als Zeile.
---
+11 -1
View File
@@ -13,7 +13,17 @@ export default defineConfig({
testDir: "./tests/e2e",
fullyParallel: true,
forbidOnly: Boolean(process.env.CI),
retries: process.env.CI ? 2 : 0,
/**
* Ein Wiederholungsversuch auch lokal.
*
* Der Grund ist derselbe wie bei den großzügigen Zeitlimits unten: "next
* dev" übersetzt jede Route beim ersten Aufruf, und mit vier gleichzeitigen
* Arbeitern kommt dazu die Anmeldung mit bcrypt (12 Runden, wie in
* Produktion). Unter dieser Last läuft gelegentlich ein Test ins Zeitlimit,
* der einzeln zuverlässig grün ist — verstreut über alle Dateien, nicht an
* einer Stelle. Ein echter Fehler fällt zweimal durch und bleibt sichtbar.
*/
retries: process.env.CI ? 2 : 1,
/**
* Bewusst wenige Worker: "next dev" übersetzt jede Route erst beim ersten
* Aufruf. Zu viele gleichzeitige Erstaufrufe lassen den Server so lange
+6
View File
@@ -1,5 +1,6 @@
import Link from "next/link";
import { CloudOff } from "lucide-react";
import { ErneutVersuchen } from "@/app/kiosk/offline/wiederholen";
export const metadata = { title: "Offline" };
@@ -9,6 +10,9 @@ export const metadata = { title: "Offline" };
* Sie ist bewusst statisch und ohne Datenzugriff — sie muss auch dann noch
* erscheinen, wenn vom Server nichts mehr kommt. Und sie sagt das Wichtigste:
* das Erfasste ist nicht weg.
*
* Zurück findet sie von selbst: ein einzelner abgebrochener Aufruf genügt, um
* hier zu landen, und dann darf das Terminal nicht warten, bis jemand tippt.
*/
export default function OfflineSeite() {
return (
@@ -23,6 +27,8 @@ export default function OfflineSeite() {
verloren.
</p>
<ErneutVersuchen />
<Link
href="/kiosk"
className="flex h-16 items-center rounded-md border-2 border-[var(--border)] px-8 text-lg"
+47
View File
@@ -0,0 +1,47 @@
"use client";
import * as React from "react";
/**
* Es allein noch einmal versuchen.
*
* Die Offline-Seite erscheint auch dann, wenn nur eine einzelne Anfrage
* unterwegs abgebrochen ist — ein kurzer Aussetzer des Repeaters genügt.
* Ohne diesen Baustein bliebe das Terminal danach auf dieser Seite stehen,
* bis jemand vorbeikommt und tippt. Am Hallenmonitor, den niemand bedient,
* hieße das: bis zum nächsten Dienstabend.
*
* Also versucht die Seite es selbst — sofort, wenn der Browser wieder Netz
* meldet, und sonst alle paar Sekunden.
*/
const ABSTAND_MS = 10_000;
export function ErneutVersuchen() {
const [versuche, setVersuche] = React.useState(0);
React.useEffect(() => {
const nochmal = () => {
setVersuche((wert) => wert + 1);
window.location.reload();
};
window.addEventListener("online", nochmal);
const zeitgeber = setInterval(() => {
// Ohne Netz spart der Versuch nichts — dann wartet die Seite auf das
// "online"-Ereignis darüber.
if (navigator.onLine) nochmal();
}, ABSTAND_MS);
return () => {
window.removeEventListener("online", nochmal);
clearInterval(zeitgeber);
};
}, []);
return (
<p className="text-[var(--muted-foreground)]" role="status" data-testid="offline-wiederholung">
Das Terminal versucht es alle {ABSTAND_MS / 1000} Sekunden von selbst
{versuche > 0 ? ` (${versuche}. Versuch)` : ""}.
</p>
);
}