Demoklart: demoärende, dashboard-filter, publik delningssida, utskrift

- Demoärende med ett klick: komplett vibrationsärende (Volvo XC60)
  med 1 tim 35 min historik — besvarade symptomfrågor, fyra hjulfoton,
  mätvärden, provkörning, inaktivitetsförklaring, överlämning mellan
  två tekniker och en hypotes. Testat: tidsordning, arbetstid, kvar-
  varande kontroller så guiden kan fortsätta live i demon.
- Dashboard enligt direktivet: räknare och filter Alla/Pågående/Klara.
- Publik delningssida /felsokning/delad/:kod som läser via
  hamta_delat_arende utan inloggning och pollar för liveuppdatering;
  delad vykomponent med interna förhandsvisningen; Kopiera
  delningslänk i rapportfliken.
- Utskriftsvänlig kundrapport: svart på vitt vid utskrift, knappar
  och fält döljs automatiskt.
- Demomanus i docs/DEMO.md med steg-för-steg-flöde och tabell över
  demoläge kontra produktion.

Verifierat: 21 vitest-tester gröna, produktionsbygge ok, Playwright-
röktest inkl. demoflödet i färsk profil.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012EQg3rJsrQ1ZNTvkzmQAtt
This commit is contained in:
Claude
2026-08-03 00:49:21 +00:00
parent 8908224a01
commit a33e2bfcbf
13 changed files with 540 additions and 128 deletions
+39
View File
@@ -0,0 +1,39 @@
import { describe, expect, it } from "vitest";
import { byggDemoArende } from "../demo";
import { VIBRATION_METODIK, valjMetodik } from "../metodik";
import { brief, felbeskrivning } from "../projektioner";
describe("demoärendet", () => {
const arende = byggDemoArende(7);
it("väljer vibrationsmetodiken och har ett rikt underlag", () => {
expect(valjMetodik(felbeskrivning(arende)!).id).toBe("vibration");
const b = brief(arende, VIBRATION_METODIK);
expect(b.objekt?.identifierare).toBe("ABC123");
expect(b.utfordaKontroller.length).toBeGreaterThanOrEqual(10);
expect(b.observationer.length).toBeGreaterThanOrEqual(4);
expect(b.hypoteser).toHaveLength(1);
expect(b.avslutat).toBe(false);
});
it("lämnar kontroller kvar så att guiden kan fortsätta i demon", () => {
const b = brief(arende, VIBRATION_METODIK);
expect(b.ejKontrollerat).toContain("Kontrollera radial- och sidokast");
expect(b.ejKontrollerat).toContain("Förändring vid kurvtagning");
expect(b.rekommenderatNastaSteg.length).toBeGreaterThan(0);
});
it("har cirka 1,5 timmars loggad arbetstid och en överlämning", () => {
const b = brief(arende, VIBRATION_METODIK);
expect(b.totalArbetstid).toBe("1 tim 35 min");
expect(arende.handelser.some((p) => p.handelse.typ === "overlamning")).toBe(true);
expect(new Set(arende.handelser.map((p) => p.anvandare)).size).toBeGreaterThanOrEqual(2);
});
it("händelserna ligger i tidsordning med demoärendets id-format", () => {
const tider = arende.handelser.map((p) => p.tidpunkt);
expect([...tider].sort()).toEqual(tider);
expect(arende.id).toMatch(/^arende-demo-/);
expect(arende.delningskod).toBeTruthy();
});
});