import { useState, useEffect, useId } from 'react' import { Info } from 'lucide-react' import { getStatusColor } from '../utils/interpret' /** * Zerlegt eine KPI-Kachel für Bottom-Sheet / Tooltip. * @param {{ hoverTop?: string, category?: string, hoverBody?: string, keys?: string[] }} t */ export function kpiTileDetailParts(t) { const registryLine = t.keys?.length ? `Registry: ${t.keys.join(', ')}` : '' const body = [t.hoverBody, registryLine].filter(Boolean).join('\n\n') return { title: t.hoverTop || t.category || 'Kennzahl', body } } /** Ein Zeilentext wie natives `title` (Desktop-Hover). */ export function buildKpiTileTitleString(t) { return [t.hoverTop, t.hoverBody, t.keys?.length ? `Registry: ${t.keys.join(', ')}` : ''] .filter(Boolean) .join('\n\n') } /** * Standard-KPI-Kacheln: Desktop `title`-Tooltip, Touch ℹ → Bottom-Sheet (gleicher Inhalt). * * Erwartete Kachel-Felder: * - `key` (string, eindeutig) * - `category` (string) — Zeilenkopf * - `value` (ReactNode) — Hauptwert * - `status` — für Farbstreifen: `good` | `warn` | `bad` * - optional: `icon`, `sublabel`, `verdict`, `valueColor`, `hoverTop`, `hoverBody`, `keys` * - optional: `hint` — Kurz-Hinweis/Warnung direkt auf der Kachel (z. B. Ernährung bei warn/bad) */ export default function KpiTilesOverview({ tiles, heading = 'Kennzahlen', showTouchHint = true, gridClassName = 'kpi-tiles-grid', marginBottom = 12, }) { const [touchUi, setTouchUi] = useState(false) const [openKey, setOpenKey] = useState(null) const sheetTitleId = useId() useEffect(() => { const mq = window.matchMedia('(hover: none)') const apply = () => setTouchUi(mq.matches) apply() mq.addEventListener('change', apply) return () => mq.removeEventListener('change', apply) }, []) useEffect(() => { if (!openKey) return const onKey = e => { if (e.key === 'Escape') setOpenKey(null) } const prev = document.body.style.overflow document.body.style.overflow = 'hidden' window.addEventListener('keydown', onKey) return () => { document.body.style.overflow = prev window.removeEventListener('keydown', onKey) } }, [openKey]) if (!tiles?.length) return null const openTile = openKey ? tiles.find(x => x.key === openKey) : null const openParts = openTile ? kpiTileDetailParts(openTile) : null const showVerdict = (v) => v != null && String(v).trim() !== '' && String(v).trim() !== '—' return (