import { useEffect, useMemo, useState } from "react"; import { useNavigate } from "react-router-dom"; import { apiRequest } from "../api/client"; import { useAuth } from "../auth/AuthContext"; import type { Objekt } from "../api/types"; interface Eintrag { id: string; label: string; hinweis?: string; gehe: () => void; } /** * globale Suche/Quick Actions per Ctrl+K bzw. ⌘+K. * Öffnet sich über der ganzen App (AppShell), navigiert nur - keine eigene * Fachlogik, nur Zusammenfassung bereits vorhandener Routen/Aktionen. */ export function CommandPalette() { const navigate = useNavigate(); const { istVerantwortlich, istAdmin } = useAuth(); const [offen, setOffen] = useState(false); const [suche, setSuche] = useState(""); const [objekte, setObjekte] = useState([]); useEffect(() => { function onKeyDown(e: KeyboardEvent) { if ((e.ctrlKey || e.metaKey) && e.key.toLowerCase() === "k") { e.preventDefault(); setOffen((v) => !v); } if (e.key === "Escape") setOffen(false); } function onOeffnenAnfrage() { setOffen(true); } window.addEventListener("keydown", onKeyDown); window.addEventListener("mabea:open-command-palette", onOeffnenAnfrage); return () => { window.removeEventListener("keydown", onKeyDown); window.removeEventListener("mabea:open-command-palette", onOeffnenAnfrage); }; }, []); useEffect(() => { if (offen && objekte.length === 0) { apiRequest("/objekte") .then(setObjekte) .catch(() => undefined); } if (!offen) setSuche(""); }, [offen, objekte.length]); const aktionen = useMemo(() => { const liste: Eintrag[] = [ { id: "nav-objekte", label: "Objekte", gehe: () => navigate("/objekte") }, { id: "nav-maengel", label: "Mängel", gehe: () => navigate("/maengel") }, { id: "action-scan", label: "QR scannen", hinweis: "Quick Action", gehe: () => navigate("/objekte?scan=1") }, ]; if (istVerantwortlich) { liste.push( { id: "nav-dashboard", label: "Dashboard", gehe: () => navigate("/dashboard") }, { id: "nav-fehlbestaende", label: "Fehlbestände", gehe: () => navigate("/fehlbestaende") }, { id: "action-material", label: "Material buchen (Lager)", hinweis: "Quick Action", gehe: () => navigate("/admin?tab=lager"), }, { id: "nav-lager", label: "Lager", gehe: () => navigate("/admin?tab=lager") }, { id: "nav-ausgabe", label: "Ausgabe/Rückgabe", gehe: () => navigate("/admin?tab=ausgabe") }, { id: "nav-personal", label: "Personal", gehe: () => navigate("/admin?tab=personal") }, { id: "nav-material", label: "Material (Stammdaten)", gehe: () => navigate(`/admin?tab=${istAdmin ? "material" : "objekte"}`), }, { id: "nav-admin", label: istAdmin ? "Administration" : "Verwaltung", gehe: () => navigate("/admin") } ); } return liste; }, [navigate, istVerantwortlich, istAdmin]); const objektTreffer = useMemo(() => { if (suche.trim().length === 0) return []; const s = suche.toLowerCase(); return objekte .filter((o) => o.name.toLowerCase().includes(s) || o.code.toLowerCase().includes(s)) .slice(0, 8) .map((o) => ({ id: `objekt-${o.id}`, label: o.name, hinweis: o.code, gehe: () => navigate(`/akte/objekt/${o.id}`), })); }, [suche, objekte, navigate]); const gefilterteAktionen = useMemo(() => { if (suche.trim().length === 0) return aktionen; const s = suche.toLowerCase(); return aktionen.filter((a) => a.label.toLowerCase().includes(s)); }, [suche, aktionen]); if (!offen) return null; const treffer = [...objektTreffer, ...gefilterteAktionen]; function auswaehlen(eintrag: Eintrag) { eintrag.gehe(); setOffen(false); } return (
setOffen(false)} role="dialog" aria-modal="true" aria-label="Globale Suche" >
e.stopPropagation()}> setSuche(e.target.value)} />
    {treffer.length === 0 &&
  • Keine Treffer.
  • } {treffer.map((eintrag) => (
  • ))}
); }