'use client' import { useEffect } from 'react' import { usePathname } from 'next/navigation' /** * Misst die Ladewerte und schickt sie an `/api/vitals`. * * Gesendet wird mit `sendBeacon`: das überlebt den Seitenwechsel, blockiert * nichts und braucht keine offene Verbindung. Die Bibliothek wird erst * geladen, wenn der Browser Zeit hat — die Messung darf nicht selbst zur * Ladezeit beitragen. * * Übertragen wird das **Routenmuster**, nicht der konkrete Pfad: eine * Messreihe soll sagen, ob Fallakten langsam sind, nicht welche. */ export function Vitals() { const pathname = usePathname() useEffect(() => { let abgebrochen = false const starten = () => { void import('web-vitals').then(({ onLCP, onINP, onCLS, onTTFB, onFCP }) => { if (abgebrochen) return const senden = (metric: { name: string; value: number; rating: string }) => { const nutzlast = JSON.stringify({ metric: metric.name, value: metric.value, rating: metric.rating, route: routenMuster(pathname), }) try { navigator.sendBeacon?.('/api/vitals', new Blob([nutzlast], { type: 'application/json' })) } catch { // Messwerte sind kein Grund, irgendetwas scheitern zu lassen. } } onLCP(senden) onINP(senden) onCLS(senden) onTTFB(senden) onFCP(senden) }) } if ('requestIdleCallback' in window) { const id = requestIdleCallback(starten) return () => { abgebrochen = true cancelIdleCallback(id) } } const timer = setTimeout(starten, 2000) return () => { abgebrochen = true clearTimeout(timer) } }, [pathname]) return null } /** * Aus `/faelle/AfiS-2026-0042/dokumente` wird `/faelle/[caseNumber]/dokumente`. * * Die Kennungen dürfen nicht mit: sonst entstünde aus einer Messreihe eine * Spur, wer wann welche Akte geöffnet hat. */ function routenMuster(pfad: string): string { return pfad .replace(/\/faelle\/[^/]+/, '/faelle/[caseNumber]') .replace(/\/dokumente\/[^/]+/, '/dokumente/[documentNumber]') .replace(/\/personalakten\/[^/]+/, '/personalakten/[id]') .slice(0, 120) }