feat(demo): add demo manifest, Dutch demo entry, permanent badge and About page
Adds GET /api/v1/demo/manifest as a single source of truth for the demo's fictional org identity (Northstar Mobility -- surfacing the project's already-locked tenant name), synthetic-data/reset state, and live scenario readiness. Rewrites the login screen in Dutch with an honest, no-password demo entry and a guided-demo entry point, replaces the loud full-width demo banner with a subtle badge + popover, and adds a compact About page explaining what's real vs. synthetic vs. not yet connected.
This commit is contained in:
@@ -0,0 +1,124 @@
|
||||
import { useAuth } from "../context/AuthContext";
|
||||
import { useDemoManifest } from "../context/DemoManifestContext";
|
||||
import { Icon } from "../components/Icons";
|
||||
import { IntegrationMark, LoadingState, PageHeader, SectionHeading } from "../components/PageChrome";
|
||||
|
||||
function formatDateTime(value: string | null): string {
|
||||
if (!value) return "onbekend";
|
||||
return new Date(value).toLocaleString("nl-BE", {
|
||||
dateStyle: "medium",
|
||||
timeStyle: "short",
|
||||
timeZone: "Europe/Brussels",
|
||||
});
|
||||
}
|
||||
|
||||
const INTEGRATION_ICON: Record<string, "n8n" | "rag" | "mcp"> = {
|
||||
n8n: "n8n",
|
||||
ragcore: "rag",
|
||||
mcp_hub: "mcp",
|
||||
};
|
||||
|
||||
export function AboutDemo() {
|
||||
const { manifest, loading } = useDemoManifest();
|
||||
const { user } = useAuth();
|
||||
|
||||
return (
|
||||
<div className="page">
|
||||
<PageHeader
|
||||
eyebrow="Over deze demo"
|
||||
title="Wat MobilityOps wel en niet is"
|
||||
description={
|
||||
manifest
|
||||
? `${manifest.organization_name} is een fictieve verhuurorganisatie die dient om deze demo tastbaar te maken — geen bestaand bedrijf.`
|
||||
: undefined
|
||||
}
|
||||
/>
|
||||
|
||||
{loading && <LoadingState label="Demo-informatie laden…" />}
|
||||
|
||||
{manifest && (
|
||||
<>
|
||||
<section className="record-surface about-card">
|
||||
<h2>Het fictieve probleem</h2>
|
||||
<p>
|
||||
{manifest.organization_name} verhuurt zo'n 50 campers en bestelwagens vanuit één
|
||||
hoofdlocatie. Boekingen, retours, klantgegevens en onderhoud kwamen tot nu toe uit
|
||||
losse spreadsheets en mondelinge afspraken, waardoor fouten (dubbele klanten,
|
||||
foutieve kilometerstanden, dubbel geboekte voertuigen) laat aan het licht kwamen.
|
||||
MobilityOps toont hoe één samenhangend systeem die problemen vroeg signaleert en
|
||||
gecontroleerd laat oplossen.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section className="record-surface about-card">
|
||||
<h2>Wat écht werkt</h2>
|
||||
<p>
|
||||
Alles hieronder is functionele code, niet alleen een mockup: rol-gebaseerde
|
||||
toegang en sessies, voertuig- en boekingsbeheer, retourverwerking met
|
||||
serverzijdige validatie, vijf datakwaliteitsregels met elk een eigen
|
||||
oplossingsstap, een volledige audit trail, geautomatiseerde aflevering naar n8n
|
||||
met begrensde herpogingen, Docker-gebaseerde deployment en een geautomatiseerde
|
||||
testsuite (backend en Playwright end-to-end).
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section className="record-surface about-card">
|
||||
<h2>Wat synthetisch is</h2>
|
||||
<p>
|
||||
De organisatie, alle klanten, voertuigen, boekingen, onderhoudsgeschiedenis,
|
||||
procedures in de kennisbank en de vooraf ingerichte scenario's zijn volledig
|
||||
verzonnen. Geen enkel gegeven verwijst naar een bestaand persoon, voertuig of
|
||||
bedrijf; e-mailadressen gebruiken uitsluitend het testdomein <code>.test</code>.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section aria-label="Koppelingsstatus" className="record-surface">
|
||||
<SectionHeading
|
||||
title="Koppelingen — eerlijk gelabeld"
|
||||
description="Wat operationeel is, wat demomodus is, en wat nog niet gekoppeld is."
|
||||
/>
|
||||
<div className="integration-cards">
|
||||
{manifest.integrations.map((integration) => (
|
||||
<article key={integration.key}>
|
||||
<IntegrationMark kind={INTEGRATION_ICON[integration.key]} />
|
||||
<div>
|
||||
<span className="integration-kicker">{integration.status_label}</span>
|
||||
<h2>{integration.label}</h2>
|
||||
<p>{integration.detail}</p>
|
||||
</div>
|
||||
</article>
|
||||
))}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section className="record-surface about-card">
|
||||
<h2>Demo-omgeving herstellen</h2>
|
||||
<p>
|
||||
De omgeving is op elk moment terug te zetten naar de startsituatie. Laatste reset:{" "}
|
||||
<strong>{formatDateTime(manifest.last_reset_at)}</strong>.{" "}
|
||||
{user?.role === "operations_manager" ? (
|
||||
<>
|
||||
Gebruik <strong>Reset demo data</strong> in de zijbalk om opnieuw te beginnen.
|
||||
</>
|
||||
) : (
|
||||
<>Een Operations Manager kan de demo-omgeving herstellen via de zijbalk.</>
|
||||
)}
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section className="access-note record-surface" aria-label="Beperkingen">
|
||||
<Icon name="shield" />
|
||||
<p>
|
||||
<strong>Beperkingen</strong>
|
||||
<span>
|
||||
Dit is een gerichte proof of concept, geen volledig ERP. RAGcore en de ITWorx
|
||||
MCP Hub zijn nog niet live gekoppeld; de kennisassistent gebruikt een lokale,
|
||||
afgebakende demokennisbank in plaats van een live RAGcore-omgeving.
|
||||
</span>
|
||||
</p>
|
||||
</section>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user