M12: complete daily operations cycle

This commit is contained in:
NuklearRabbit
2026-08-10 03:15:46 +02:00
parent 4a3c3bd0a9
commit 15bdbe40ac
32 changed files with 802 additions and 18 deletions
+11 -1
View File
@@ -2,7 +2,7 @@ import { FormEvent, useCallback, useEffect, useState } from "react";
import { Link, useParams } from "react-router-dom";
import { useTranslation } from "react-i18next";
import { api } from "../api/client";
import type { Booking, RegisterReturnResult, VehicleDetail } from "../api/types";
import type { Booking, CheckoutBookingResult, RegisterReturnResult, VehicleDetail } from "../api/types";
import { useDemoManifest } from "../context/DemoManifestContext";
import { useLocaleFormat } from "../i18n/format";
import { StatusBadge } from "../components/Badge";
@@ -12,6 +12,7 @@ import { ErrorState, LoadingState, PageHeader } from "../components/PageChrome";
import { PRODUCT_NAME } from "../product";
import { describeApiError, type ApiErrorInfo } from "../api/errorMessages";
import { ApiErrorNotice } from "../components/PageChrome";
import { CheckoutForm } from "../components/CheckoutForm";
export function BookingDetail() {
const { t } = useTranslation(["bookings", "returns", "errors"]);
@@ -25,6 +26,7 @@ export function BookingDetail() {
const [cancelReason, setCancelReason] = useState("");
const [cancelling, setCancelling] = useState(false);
const [actionError, setActionError] = useState<ApiErrorInfo | null>(null);
const [checkoutResult, setCheckoutResult] = useState<CheckoutBookingResult | null>(null);
const load = useCallback(() => {
if (!publicRef) return;
@@ -77,6 +79,11 @@ export function BookingDetail() {
}
}
function handleCheckout(result: CheckoutBookingResult) {
setCheckoutResult(result);
load();
}
if (error) return <ErrorState message={error} />;
if (!booking) return <LoadingState label={t("detail.loading")} />;
@@ -101,6 +108,9 @@ export function BookingDetail() {
<div className="form-actions"><button className="button button-danger" type="submit" disabled={cancelling || cancelReason.trim().length < 3}>{cancelling ? t("detail.cancelling") : t("detail.confirmCancel")}</button></div>
</form>}
{checkoutResult && <section className={`record-surface checkout-result ${checkoutResult.activated ? "success" : "warning"}`} role="status"><h2>{t(checkoutResult.activated ? "checkout.activatedTitle" : "checkout.blockedTitle")}</h2><p>{t(checkoutResult.activated ? "checkout.activatedDetail" : "checkout.blockedDetail", { inspection: checkoutResult.inspection_ref })}</p></section>}
{!checkoutResult && booking.status === "reserved" && <CheckoutForm bookingRef={booking.public_ref} vehicleRef={booking.vehicle_ref} onRecorded={handleCheckout} />}
{isReturnAnomalyScenario && !returnResult && canonicalOdometerKm !== null && (
<section className="record-surface scenario-callout" aria-label={t("returns:scenario.ariaLabel")}>
<Icon name="spark" />