import Link from "next/link"; import { db, initDatabase } from "@/lib/db"; export const runtime = "nodejs"; export const dynamic = "force-dynamic"; type MotorcycleMaintenanceRow = { id: number; nickname: string; brand: string; model: string; year: number | null; plate: string | null; owner_name: string; tire_pressure_front_bar: number | null; tire_pressure_rear_bar: number | null; chain_tension_min_mm: number | null; chain_tension_max_mm: number | null; oil_type: string | null; oil_capacity_liters: number | null; oil_check_temp: "warm" | "cold" | null; oil_check_run_minutes: number | null; oil_check_wait_min_minutes: number | null; oil_check_wait_max_minutes: number | null; oil_check_method: "dipstick" | "sight_glass" | null; }; function formatBar(value: number | null) { if (value == null) return "—"; return `${new Intl.NumberFormat("de-DE", { minimumFractionDigits: 1, maximumFractionDigits: 1, }).format(value)} bar`; } function oilTempLabel(value: MotorcycleMaintenanceRow["oil_check_temp"]) { if (value === "warm") return "Warm"; if (value === "cold") return "Kalt"; return "—"; } function oilMethodLabel(value: MotorcycleMaintenanceRow["oil_check_method"]) { if (value === "dipstick") return "Peilstab"; if (value === "sight_glass") return "Schauglas"; return "—"; } function oilInstruction(bike: MotorcycleMaintenanceRow) { const tempText = bike.oil_check_temp === "warm" ? "bei warmem Motor" : bike.oil_check_temp === "cold" ? "bei kaltem Motor" : null; const methodText = bike.oil_check_method === "dipstick" ? "mit Peilstab" : bike.oil_check_method === "sight_glass" ? "über Schauglas" : null; if (!tempText && !methodText) return "Keine Anleitung hinterlegt."; const runText = bike.oil_check_temp === "warm" && bike.oil_check_run_minutes != null ? `Motor mindestens ${bike.oil_check_run_minutes} Min. laufen lassen, ` : ""; const waitText = bike.oil_check_temp === "warm" && bike.oil_check_wait_min_minutes != null && bike.oil_check_wait_max_minutes != null ? `danach ${bike.oil_check_wait_min_minutes}-${bike.oil_check_wait_max_minutes} Min. warten, ` : ""; return `${runText}${waitText}Ölstand ${tempText ?? "im passenden Motorzustand"} messen ${methodText ?? "Methode offen"}.`.trim(); } function plateFromParams(value: string | string[] | undefined) { if (Array.isArray(value)) return String(value[0] ?? "").trim(); return String(value ?? "").trim(); } function validatedPlate(value: string) { const trimmed = value.slice(0, 20).trim(); if (!trimmed) return ""; if (!/^[A-Za-z0-9ÄÖÜäöü \-]+$/.test(trimmed)) { throw new Error("Kennzeichen enthält ungültige Zeichen."); } return trimmed; } export default async function KioskPage({ searchParams, }: { searchParams: Promise>; }) { initDatabase(); const params = await searchParams; let plate = ""; let plateError: string | null = null; try { plate = validatedPlate(plateFromParams(params.plate)); } catch (error) { plateError = error instanceof Error ? error.message : "Ungültige Eingabe."; } const matches = plate && !plateError ? (db .prepare( `SELECT m.id, m.nickname, m.brand, m.model, m.year, m.plate, owner.name AS owner_name, m.tire_pressure_front_bar, m.tire_pressure_rear_bar, m.chain_tension_min_mm, m.chain_tension_max_mm, m.oil_type, m.oil_capacity_liters, m.oil_check_temp, m.oil_check_run_minutes, m.oil_check_wait_min_minutes, m.oil_check_wait_max_minutes, m.oil_check_method FROM motorcycles m JOIN users owner ON owner.id = m.created_by WHERE m.plate IS NOT NULL AND TRIM(m.plate) <> '' AND REPLACE(REPLACE(UPPER(m.plate), ' ', ''), '-', '') = REPLACE(REPLACE(UPPER(?), ' ', ''), '-', '') ORDER BY m.id ASC LIMIT 2`, ) .all(plate) as MotorcycleMaintenanceRow[]) : []; const bike = matches.length === 1 ? matches[0] : null; const notFound = plate.length > 0 && matches.length === 0; const ambiguous = matches.length > 1; return (

Öffentlicher Zugriff

Kiosk-Modus

Kennzeichen eingeben und Wartungsdaten direkt anzeigen.

Zur Anmeldung
{plateError && (
{plateError}
)} {notFound && (
Kein Motorrad mit diesem Kennzeichen gefunden.
)} {ambiguous && (
Dieses Kennzeichen ist nicht eindeutig. Bitte in der App ein eindeutiges Kennzeichen pflegen.
)} {bike && ( <>

{bike.brand} · {bike.model}{bike.year ? ` · ${bike.year}` : ""}

{bike.nickname}

Kennzeichen: {bike.plate ?? "—"} · Besitzer: {bike.owner_name}

Reifen & Kette

Reifendruck vorne
{formatBar(bike.tire_pressure_front_bar)}
Reifendruck hinten
{formatBar(bike.tire_pressure_rear_bar)}
Kettenspannung
{bike.chain_tension_min_mm != null && bike.chain_tension_max_mm != null ? `${bike.chain_tension_min_mm}-${bike.chain_tension_max_mm} mm` : "—"}

Ölstand-Kontrolle

Benötigtes Öl
{bike.oil_type ?? "—"}
Ölmenge gesamt
{bike.oil_capacity_liters != null ? `${new Intl.NumberFormat("de-DE", { minimumFractionDigits: 1, maximumFractionDigits: 1 }).format(bike.oil_capacity_liters)} l` : "—"}
Motorzustand
{oilTempLabel(bike.oil_check_temp)}
Laufzeit vor Messung
{bike.oil_check_temp === "warm" && bike.oil_check_run_minutes != null ? `${bike.oil_check_run_minutes} Min.` : "—"}
Wartezeitfenster
{bike.oil_check_temp === "warm" && bike.oil_check_wait_min_minutes != null && bike.oil_check_wait_max_minutes != null ? `${bike.oil_check_wait_min_minutes}-${bike.oil_check_wait_max_minutes} Min.` : "—"}
Methode
{oilMethodLabel(bike.oil_check_method)}

{oilInstruction(bike)}

)}
); }