Frontend-Komponenten & Benutzeroberfläche

Das SMARTKRIS-Dashboard ist als Single-Page-Application (SPA) innerhalb des Next.js App Routers konzipiert. Es bietet den städtischen Mitarbeitern eine interaktive, kartenbasierte und echtzeitfähige Benutzeroberfläche.

Dieses Kapitel erklärt die zentralen UI-Komponenten aus zwei Perspektiven: der Bedienersicht (Wie nutze ich die Funktion richtig?) und der Entwicklersicht (Wie ist es gebaut und wie kann ich es erweitern?).

1. Zentrales State-Management (DataContext.tsx)

Das gesamte Dashboard wird von einem globalen React Context (DataContext) umschlossen.

  • Wenn eine neue Komponente gebaut wird, sollte sie Stammdaten (Kategorien, Eskalationsstufen, Gebiete) immer über den Hook const { categories } = useData() beziehen und nicht selbst von der API laden. Auch Mutationen (Erstellen, Bearbeiten, Löschen) sollten bevorzugt über die im Context bereitgestellten Funktionen (z.B. createMessageInState) ausgeführt werden. Diese Funktionen rufen die API (client-api.ts) auf, aktualisieren bei Erfolg sofort den lokalen React-State (verhindert Flimmern/Neuladen der Seite), aktualisieren die Zähler-Statistiken im Hintergrund und feuern eine Toast-Benachrichtigung.

2. Listen-Ansichten (Dashboard, Archiv, Pending)

Die Hauptnavigation teilt sich in verschiedene Ansichten auf (Dashboard.tsx, SituationsComponent.tsx, MessageComponent.tsx, Archive.tsx, Pending.tsx). Alle diese Ansichten nutzen unter der Haube dieselben UI-Konzepte, filtern die Daten aber unterschiedlich.

  • Die Listen sind hierarchisch aufgebaut. Eine Haupt-Lage (Parent) enthält ihre direkten Meldungen und aufklappbar ihre Einsatzschwerpunkte (Children), welche wiederum eigene Meldungen haben. Über die dynamischen Filterleisten (Header.tsx) kann die Ansicht nach Status, Typ oder Gebiet eingegrenzt werden. * Die Komponenten laden ihre spezifischen Daten über loadData() und berechnen den Hierarchie-Baum im Frontend (groupedItems mit useMemo). Die Hilfsfunktion hydrateTree() sorgt dafür, dass, wenn das Backend z. B. nur eine gefilterte Meldung zurückgibt, das Frontend automatisch die fehlenden Parent-Situationen nachlädt, damit der visuelle Baum im UI nicht zerbricht.

3. Interaktive Karten (react-leaflet)

Karten sind ein zentrales Element von SMARTKRIS und in zwei Hauptbereichen zu finden: als Übersicht (Map.tsx) und als Auswahl-Werkzeug in Formularen (MapSelector.tsx).

  • Auf der großen Karte können Lagen und Feedbacks visuell erfasst werden. Durch Klick auf einen Marker öffnet sich in der rechten Bildschirmhälfte ein Detail-Panel (MapDetails.tsx) mit allen Informationen und direktem Bearbeitungszugriff. Lagen-Marker zeigen farblich die Eskalationsstufe und das Kategorie-Icon. * Die Basiskarte (BaseMap.tsx) nutzt entweder einen konfigurierten WMS-Tile-Server (NEXT_PUBLIC_TILE_SERVER_URL) oder fällt auf Standard-OpenStreetMap zurück. Marker werden in mapUtils.ts dynamisch als HTML (DivIcon) gerendert. Das erlaubt aufwendige CSS-Animationen (Pulsieren bei Selektion) und die Einbettung externer SVGs über die Proxy-Routen. Die Geometrien der Gebiete (Areas) werden als GeoJSON aus der Datenbank gelesen und direkt als Polygon-Layer auf die Karte gelegt.

4. Formulardialoge & Vorschau-Modus

Das Erstellen von Lagen (SituationFormModal.tsx) und Meldungen (MessageFormModal.tsx) ist der wichtigste Prozess im System.

Adressen & Koordinaten (Nominatim)

  • Sobald man in das Adressfeld tippt, schlägt das System Adressen in der konfigurierten Stadt vor. Alternativ kann man einen Punkt auf der Karte anklicken.

  • Dies wird über den AddressInput und den MapSelector gesteuert. Beide kommunizieren mit der Nominatim-API. Setzt man einen Pin auf der Karte, wird per Reverse-Geocoding automatisch das Adressformular ausgefüllt. Tippt man eine Adresse, verschiebt Forward-Geocoding den Pin.

Live-Vorschau (Preview.tsx)

  • Klickt man oben rechts im Formular auf das Auge-Symbol, teilt sich der Dialog. Man sieht nun exakt, wie der getippte Text später auf der Webseite (Ticker-Ansicht) oder auf dem Smartphone (Push-Benachrichtigung mit Sperrbildschirm-Simulation) aussehen wird.

  • Die Vorschau-Komponente reagiert live auf State-Änderungen des Formulars. Die Mobile-Preview berechnet dynamisch CSS-Gradienten und Schatten basierend auf dem Hex-Code der gewählten Eskalationsstufe, um kritische Warnungen visuell bedrohlicher wirken zu lassen (rotes Glühen).

Autorisierungs-Flow

  • Normalerweise werden erstellte Elemente im Status "Wartend" gespeichert und müssen von einem Vorgesetzten freigegeben werden. Setzt man im Formular den Haken bei "Sofort autorisieren", erscheint ein PIN-Feld. Stimmt der PIN, geht die Meldung sofort live.

  • Der State authorizeImmediately fügt den authorizationPin zum Payload hinzu und ändert das Ziel-Status-Flag des API-Calls von PENDING_AUTHORIZATION auf ACTIVE.

5. Card Actions & PIN-Modal (CardActionsMenu.tsx)

Jede Karte (Lage/Meldung) besitzt ein Kontextmenü (Drei-Punkte-Icon) oder direkte Aktions-Buttons (Bearbeiten, Freigeben, Löschen).

  • Bestimmte kritische Aktionen (Freigeben, Archivieren, Löschen) erfordern eine Bestätigung. Es öffnet sich das PIN-Modal (PinModal.tsx). Erst nach Eingabe der korrekten 4 Ziffern wird die Aktion ausgeführt.

  • Das CardActionsMenu kapselt diese Logik vollständig. Es entscheidet anhand des aktuellen view-Prop (pending, active, archive), welche Buttons gerendert werden. Wird eine kritische Aktion geklickt, wird der actionState gesetzt, das PinModal öffnet sich, und beim Callback handlePinConfirm wird der API-Aufruf mit dem PIN abgesetzt.

6. Feedback-Kanban-Board (FeedbackComponent.tsx)

  • Bürger-Rückmeldungen landen in einem Kanban-Board. Spalten repräsentieren den Bearbeitungsstatus (z. B. "Neu", "In Bearbeitung"). Feedbacks können per Drag & Drop von einer Spalte in die andere gezogen werden. Mit Klick auf "Antworten" kann ein Dialog mit dem Bürger gestartet werden.

  • Die Komponente nutzt die native HTML5 Drag & Drop API (draggable, onDragStart, onDrop). Beim Loslassen (handleDrop) wird die Ziel-Spalten-ID ausgelesen und sofort der API-Call handleStatusChange ausgelöst, um das Backend zu aktualisieren.

7. Audit-Log Viewer (AuditLogComponent.tsx)

  • In dieser Ansicht lässt sich forensisch nachvollziehen, wer wann was geändert hat. Ein Klick auf einen Eintrag öffnet die Details.

  • Die Komponente AuditLogCard.tsx berechnet visuelle Diffs. Sie vergleicht oldState und newState des Backends. Geänderte Felder werden farblich hervorgehoben (rot für alt, grün für neu). Besonders wichtig: Das Frontend prüft das Flag isCompromised. Ist dies true (Signatur in der Datenbank fehlerhaft), rendert das UI eine prominente rote Sicherheitswarnung, dass dieser Datensatz potenziell manipuliert wurde.

8. Entwickler-Hinweis: Neue Komponenten hinzufügen

Um das System um neue Stammdaten zu erweitern, sind folgende Schritte im Frontend nötig: 1. Types: Die Interfaces in types/index.ts ergänzen. 2. Client-API: Die CRUD-Funktionen in lib/client-api.ts hinzufügen. 3. BFF-Routen: Entsprechende Route-Handler in app/api/…​ anlegen. 4. Context: Den State und die Mutationsfunktionen im DataContext.tsx registrieren. 5. Settings: In der SettingsComponent.tsx das Mapping im entityConfig-Objekt hinzufügen – das UI generiert die dazugehörige Verwaltungstabelle und das Edit-Modal danach weitgehend generisch.