feat(demo): plain-language integration status, richer audit, reset integrity
Integration status badges across Dashboard/Automation now show honest plain-language labels instead of raw backend state strings (and fix a few states that had no matching CSS colour class at all). Audit trail gets a "view related events" action reusing the existing correlation_id filter. About page gains scope/architecture/security/testing sections and a guided-demo entry point. POST /api/v1/demo/reset now runs and records a server-side scenario-integrity check. Also fixes a second real race condition (caught by the return-review e2e test): the odometer scenario pre-fill now resolves before ReturnForm mounts instead of patching its value in after the fact.
This commit is contained in:
@@ -3,6 +3,6 @@ export function SeverityBadge({ severity }: { severity: "low" | "medium" | "high
|
||||
return <span className={`badge severity-${severity}`}>{label} severity</span>;
|
||||
}
|
||||
|
||||
export function StatusBadge({ status }: { status: string }) {
|
||||
return <span className={`badge status-${status}`}>{status.replace(/_/g, " ")}</span>;
|
||||
export function StatusBadge({ status, label }: { status: string; label?: string }) {
|
||||
return <span className={`badge status-${status}`}>{label ?? status.replace(/_/g, " ")}</span>;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useEffect, useRef, useState, type FormEvent } from "react";
|
||||
import { useState, type FormEvent } from "react";
|
||||
import { Link, useNavigate } from "react-router-dom";
|
||||
import { api, ApiError } from "../api/client";
|
||||
import type { RegisterReturnRequest, RegisterReturnResult, ReturnPreviewResult } from "../api/types";
|
||||
@@ -95,7 +95,6 @@ export function ReturnForm({
|
||||
suggestedOdometerKm?: number;
|
||||
}) {
|
||||
const [odometer, setOdometer] = useState(suggestedOdometerKm !== undefined ? String(suggestedOdometerKm) : "");
|
||||
const odometerEditedByUser = useRef(false);
|
||||
const [fuel, setFuel] = useState("50");
|
||||
const [cleanlinessOk, setCleanlinessOk] = useState(true);
|
||||
const [damageReported, setDamageReported] = useState(false);
|
||||
@@ -108,16 +107,6 @@ export function ReturnForm({
|
||||
const [step, setStep] = useState<"capture" | "review">("capture");
|
||||
const [preview, setPreview] = useState<ReturnPreviewResult | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
// suggestedOdometerKm arrives asynchronously (BookingDetail fetches the vehicle's
|
||||
// canonical odometer after this form has already mounted), so the initial useState
|
||||
// value alone won't catch it -- sync it once it resolves. Never overwrite a value the
|
||||
// visitor has already started typing.
|
||||
if (suggestedOdometerKm !== undefined && !odometerEditedByUser.current) {
|
||||
setOdometer(String(suggestedOdometerKm));
|
||||
}
|
||||
}, [suggestedOdometerKm]);
|
||||
|
||||
function currentBody(): RegisterReturnRequest {
|
||||
return {
|
||||
end_odometer_km: Number(odometer),
|
||||
@@ -184,10 +173,7 @@ export function ReturnForm({
|
||||
required
|
||||
min={0}
|
||||
value={odometer}
|
||||
onChange={(e) => {
|
||||
odometerEditedByUser.current = true;
|
||||
setOdometer(e.target.value);
|
||||
}}
|
||||
onChange={(e) => setOdometer(e.target.value)}
|
||||
/>
|
||||
</label>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user