feat(demo): make return, data-quality and knowledge flows demo-legible
Fixes a real honesty bug in Knowledge.tsx (body copy named "RAGcore" while the active provider is the demo one) and a second real bug discovered while fixing it: the brief's suggested Dutch questions would silently return "insufficient evidence" against the English-only demo knowledge base -- verified empirically and fixed by keeping suggested questions in English. The return flow now pre-fills the odometer-regression scenario's suspicious reading instead of asking a visitor to invent one, and links to automation/audit after committing. Data-quality issues get a shared plain-language "what's wrong / why it matters" explainer per rule type, a post-resolution confirmation with audit/vehicle links, and a "demo scenario's only" list filter. Also fixes a real async race where the odometer pre-fill could clobber text a visitor had already started typing.
This commit is contained in:
@@ -1,7 +1,8 @@
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
import { Link, useParams } from "react-router-dom";
|
||||
import { api } from "../api/client";
|
||||
import type { Booking, RegisterReturnResult } from "../api/types";
|
||||
import type { Booking, RegisterReturnResult, VehicleDetail } from "../api/types";
|
||||
import { useDemoManifest } from "../context/DemoManifestContext";
|
||||
import { StatusBadge } from "../components/Badge";
|
||||
import { ReturnForm, ReturnResultPanel } from "../components/ReturnForm";
|
||||
import { Icon } from "../components/Icons";
|
||||
@@ -9,9 +10,11 @@ import { ErrorState, LoadingState, PageHeader } from "../components/PageChrome";
|
||||
|
||||
export function BookingDetail() {
|
||||
const { publicRef } = useParams<{ publicRef: string }>();
|
||||
const { manifest } = useDemoManifest();
|
||||
const [booking, setBooking] = useState<Booking | null>(null);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const [returnResult, setReturnResult] = useState<RegisterReturnResult | null>(null);
|
||||
const [canonicalOdometerKm, setCanonicalOdometerKm] = useState<number | null>(null);
|
||||
|
||||
const load = useCallback(() => {
|
||||
if (!publicRef) return;
|
||||
@@ -28,6 +31,21 @@ export function BookingDetail() {
|
||||
load();
|
||||
}, [load]);
|
||||
|
||||
// The odometer-regression demo scenario supplies its own suspicious reading (per the
|
||||
// brief: never ask a demo visitor to invent one) -- only fetched for that one known
|
||||
// scenario booking, not for every return.
|
||||
const isReturnAnomalyScenario =
|
||||
manifest?.scenarios.find((s) => s.id === "return-anomaly")?.start_path === `/bookings/${publicRef}`;
|
||||
|
||||
useEffect(() => {
|
||||
setCanonicalOdometerKm(null);
|
||||
if (!isReturnAnomalyScenario || !booking) return;
|
||||
api
|
||||
.get<VehicleDetail>(`/api/v1/vehicles/${booking.vehicle_ref}`)
|
||||
.then((vehicle) => setCanonicalOdometerKm(vehicle.odometer_km))
|
||||
.catch(() => setCanonicalOdometerKm(null));
|
||||
}, [isReturnAnomalyScenario, booking]);
|
||||
|
||||
function handleRegistered(result: RegisterReturnResult) {
|
||||
setReturnResult(result);
|
||||
load();
|
||||
@@ -50,9 +68,28 @@ export function BookingDetail() {
|
||||
<div><dt>Requirements complete</dt><dd>{booking.requirements_complete ? "Yes" : "No"}</dd></div>
|
||||
</dl></section>
|
||||
|
||||
{isReturnAnomalyScenario && !returnResult && canonicalOdometerKm !== null && (
|
||||
<section className="record-surface scenario-callout" aria-label="Demo scenario">
|
||||
<Icon name="spark" />
|
||||
<div>
|
||||
<strong>Demonstratiescenario: afwijkende kilometerstand</strong>
|
||||
<p>
|
||||
Dit voertuig staat momenteel op <strong>{canonicalOdometerKm.toLocaleString("en-GB")} km</strong>.
|
||||
Het onderstaande formulier is vooraf ingevuld met een retourstand die daaronder
|
||||
ligt — een teken van een foutieve invoer of een verwisseld voertuig. Bevestig de
|
||||
retour om te zien hoe MobilityOps dit detecteert en afhandelt.
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
)}
|
||||
|
||||
{returnResult && <ReturnResultPanel result={returnResult} />}
|
||||
{!returnResult && booking.status === "active" && (
|
||||
<ReturnForm bookingRef={booking.public_ref} onRegistered={handleRegistered} />
|
||||
<ReturnForm
|
||||
bookingRef={booking.public_ref}
|
||||
onRegistered={handleRegistered}
|
||||
suggestedOdometerKm={isReturnAnomalyScenario && canonicalOdometerKm !== null ? Math.max(0, canonicalOdometerKm - 50) : undefined}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user