diff --git a/NEXT_STEPS.md b/NEXT_STEPS.md index d4830a5..3e82073 100644 --- a/NEXT_STEPS.md +++ b/NEXT_STEPS.md @@ -3,10 +3,10 @@ ## 🎯 Für die nächsten Sessions ### Package 1: Fehlerbehandlung & Sessions (1-2h) -- [ ] Session-Handling in `bootstrap.php` implementieren -- [ ] Error-Messages in Session speichern ($SESSION['error'], $SESSION['success']) -- [ ] Header mit Fehlermeldungen in Layout -- [ ] Validierungsfehler anzeigen +- [x] Session-Handling in `bootstrap.php` implementieren +- [x] Error-Messages in Session speichern (`$_SESSION['error']`, `$_SESSION['success']`) +- [x] Header mit Fehlermeldungen in Layout +- [x] Validierungsfehler anzeigen ### Package 2: Delete-Funktionen (1h) - [ ] DELETE-Endpoints für alle Module diff --git a/app/assets/css/app.css b/app/assets/css/app.css index fa37a8f..b37b5b6 100644 --- a/app/assets/css/app.css +++ b/app/assets/css/app.css @@ -77,6 +77,42 @@ main { min-height: calc(100vh - 200px); } +.flash-stack { + display: grid; + gap: 10px; + margin: 0 auto 18px; + max-width: 1200px; +} + +.flash-message { + border-radius: 8px; + border: 1px solid transparent; + padding: 12px 14px; + background: #f8fafc; +} + +.flash-message--success { + border-color: #99dfba; + background: #ebf9f1; + color: #165938; +} + +.flash-message--error { + border-color: #efb4b4; + background: #fff1f1; + color: #8a1f1f; +} + +.flash-message__text { + margin: 0; + font-weight: 600; +} + +.flash-message__list { + margin: 8px 0 0 18px; + padding: 0; +} + /* Shared components -------------------------------------------------- */ .filter-form { margin: 20px 0; @@ -192,4 +228,4 @@ main { footer>p { margin-bottom: 0; -} \ No newline at end of file +} diff --git a/app/bootstrap.php b/app/bootstrap.php index fbb71df..e19966c 100644 --- a/app/bootstrap.php +++ b/app/bootstrap.php @@ -12,6 +12,10 @@ if (session_status() !== PHP_SESSION_ACTIVE) { session_start(); } +if (!isset($_SESSION['validation_errors']) || !is_array($_SESSION['validation_errors'])) { + $_SESSION['validation_errors'] = []; +} + require_once __DIR__ . '/lib/_sql.php'; $sql = new SQL(); diff --git a/app/modules/buildings/save.php b/app/modules/buildings/save.php index 2aa4b50..61809f6 100644 --- a/app/modules/buildings/save.php +++ b/app/modules/buildings/save.php @@ -25,6 +25,7 @@ if ($locationId <= 0) { if (!empty($errors)) { $_SESSION['error'] = implode(', ', $errors); + $_SESSION['validation_errors'] = $errors; $redirectUrl = $buildingId ? "?module=buildings&action=edit&id=$buildingId" : "?module=buildings&action=edit"; header("Location: $redirectUrl"); exit; diff --git a/app/modules/connections/save.php b/app/modules/connections/save.php index d56efd2..8f0a51d 100644 --- a/app/modules/connections/save.php +++ b/app/modules/connections/save.php @@ -88,6 +88,7 @@ if ($isEndpointUsed($portBType, $portBId)) { if (!empty($errors)) { $_SESSION['error'] = implode(', ', $errors); + $_SESSION['validation_errors'] = $errors; $redirectUrl = $connId ? "?module=connections&action=edit&id=$connId" : "?module=connections&action=edit"; header("Location: $redirectUrl"); exit; @@ -123,6 +124,7 @@ if ($connId > 0) { if ($connectionTypeId <= 0) { $_SESSION['error'] = "Kein Verbindungstyp verfuegbar"; + $_SESSION['validation_errors'] = ["Kein Verbindungstyp verfuegbar"]; header("Location: ?module=connections&action=edit"); exit; } diff --git a/app/modules/device_types/save.php b/app/modules/device_types/save.php index ec6bfc5..c7c1432 100644 --- a/app/modules/device_types/save.php +++ b/app/modules/device_types/save.php @@ -49,6 +49,7 @@ if (!in_array($category, ['switch', 'server', 'patchpanel', 'other'])) { // Falls Fehler: zurück zum Edit-Formular if (!empty($errors)) { $_SESSION['error'] = implode(', ', $errors); + $_SESSION['validation_errors'] = $errors; header('Location: ?module=device_types&action=edit' . ($deviceTypeId ? "&id=$deviceTypeId" : "")); exit; } @@ -67,6 +68,7 @@ if (!empty($_FILES['image']['name'])) { // Nur SVG, JPG, PNG erlaubt if (!in_array($fileExt, ['svg', 'jpg', 'jpeg', 'png'])) { $_SESSION['error'] = "Nur SVG, JPG und PNG sind erlaubt"; + $_SESSION['validation_errors'] = ["Nur SVG, JPG und PNG sind erlaubt"]; header('Location: ?module=device_types&action=edit' . ($deviceTypeId ? "&id=$deviceTypeId" : "")); exit; } @@ -86,6 +88,7 @@ if (!empty($_FILES['image']['name'])) { $imageType = $fileExt === 'svg' ? 'svg' : 'bitmap'; } else { $_SESSION['error'] = "Datei-Upload fehlgeschlagen"; + $_SESSION['validation_errors'] = ["Datei-Upload fehlgeschlagen"]; header('Location: ?module=device_types&action=edit' . ($deviceTypeId ? "&id=$deviceTypeId" : "")); exit; } diff --git a/app/modules/devices/save.php b/app/modules/devices/save.php index c10e2d5..18ccd6f 100644 --- a/app/modules/devices/save.php +++ b/app/modules/devices/save.php @@ -57,6 +57,7 @@ if ($rackHeightHe < 1) { // Falls Fehler: zurück zum Edit-Formular if (!empty($errors)) { $_SESSION['error'] = implode(', ', $errors); + $_SESSION['validation_errors'] = $errors; $redirectUrl = $deviceId ? "?module=devices&action=edit&id=$deviceId" : "?module=devices&action=edit"; header("Location: $redirectUrl"); exit; diff --git a/app/modules/floor_infrastructure/save.php b/app/modules/floor_infrastructure/save.php index c416bee..0126dd8 100644 --- a/app/modules/floor_infrastructure/save.php +++ b/app/modules/floor_infrastructure/save.php @@ -20,6 +20,24 @@ if ($type === 'patchpanel') { $height = $fixedPanelHeight; $portCount = (int)($_POST['port_count'] ?? 0); $comment = trim($_POST['comment'] ?? ''); + $errors = []; + + if ($name === '') { + $errors[] = 'Name ist erforderlich'; + } + if ($floorId <= 0) { + $errors[] = 'Stockwerk ist erforderlich'; + } + if ($portCount < 0) { + $errors[] = 'Port-Anzahl darf nicht negativ sein'; + } + if (!empty($errors)) { + $_SESSION['error'] = implode(', ', $errors); + $_SESSION['validation_errors'] = $errors; + $redirectUrl = $id > 0 ? "?module=floor_infrastructure&action=edit&type=patchpanel&id=$id" : "?module=floor_infrastructure&action=edit&type=patchpanel"; + header("Location: $redirectUrl"); + exit; + } $panelId = $id; @@ -55,6 +73,7 @@ if ($type === 'patchpanel') { } } } + $_SESSION['success'] = $id > 0 ? 'Patchpanel gespeichert' : 'Patchpanel erstellt'; } elseif ($type === 'outlet') { $name = trim($_POST['name'] ?? ''); $roomId = (int)($_POST['room_id'] ?? 0); @@ -62,6 +81,21 @@ if ($type === 'patchpanel') { $y = (int)($_POST['y'] ?? 0); $comment = trim($_POST['comment'] ?? ''); $outletId = $id; + $errors = []; + + if ($name === '') { + $errors[] = 'Name ist erforderlich'; + } + if ($roomId <= 0) { + $errors[] = 'Raum ist erforderlich'; + } + if (!empty($errors)) { + $_SESSION['error'] = implode(', ', $errors); + $_SESSION['validation_errors'] = $errors; + $redirectUrl = $id > 0 ? "?module=floor_infrastructure&action=edit&type=outlet&id=$id" : "?module=floor_infrastructure&action=edit&type=outlet"; + header("Location: $redirectUrl"); + exit; + } if ($id > 0) { $sql->set( @@ -93,6 +127,10 @@ if ($type === 'patchpanel') { ); } } + $_SESSION['success'] = $id > 0 ? 'Wandbuchse gespeichert' : 'Wandbuchse erstellt'; +} else { + $_SESSION['error'] = 'Ungueltiger Infrastrukturobjekt-Typ'; + $_SESSION['validation_errors'] = ['Ungueltiger Infrastrukturobjekt-Typ']; } header('Location: ?module=floor_infrastructure&action=list'); diff --git a/app/modules/floors/save.php b/app/modules/floors/save.php index 0bd3012..55ed0da 100644 --- a/app/modules/floors/save.php +++ b/app/modules/floors/save.php @@ -37,6 +37,7 @@ if ($buildingId <= 0) { // Falls Fehler: zurück zum Edit-Formular if (!empty($errors)) { $_SESSION['error'] = implode(', ', $errors); + $_SESSION['validation_errors'] = $errors; $redirectUrl = $floorId ? "?module=floors&action=edit&id=$floorId" : "?module=floors&action=edit"; header("Location: $redirectUrl"); exit; @@ -50,6 +51,7 @@ if ($floorSvgContent !== '') { $storedSvgPath = storeSvgEditorContent($sql, $floorId, $floorSvgContent); if ($storedSvgPath === false) { $_SESSION['error'] = "SVG aus dem Editor konnte nicht gespeichert werden"; + $_SESSION['validation_errors'] = ["SVG aus dem Editor konnte nicht gespeichert werden"]; $redirectUrl = $floorId ? "?module=floors&action=edit&id=$floorId" : "?module=floors&action=edit"; header("Location: $redirectUrl"); exit; diff --git a/app/modules/locations/save.php b/app/modules/locations/save.php index 6245513..1ae21ee 100644 --- a/app/modules/locations/save.php +++ b/app/modules/locations/save.php @@ -20,6 +20,7 @@ if (empty($name)) { if (!empty($errors)) { $_SESSION['error'] = implode(', ', $errors); + $_SESSION['validation_errors'] = $errors; $redirectUrl = $locationId ? "?module=locations&action=edit&id=$locationId" : "?module=locations&action=edit"; header("Location: $redirectUrl"); exit; diff --git a/app/modules/port_types/edit.php b/app/modules/port_types/edit.php index 9334b4d..68ca3ce 100644 --- a/app/modules/port_types/edit.php +++ b/app/modules/port_types/edit.php @@ -23,20 +23,11 @@ $isEdit = !empty($portType); $pageTitle = $isEdit ? "Porttyp bearbeiten: " . htmlspecialchars($portType['name']) : "Neuen Porttyp anlegen"; $mediaOptions = ['copper' => 'Kupfer', 'fiber' => 'Lichtwelle', 'coax' => 'Koax', 'other' => 'Sonstiges']; -$error = $_SESSION['error'] ?? ''; -unset($_SESSION['error']); - ?>

- -
- -
- -
@@ -157,12 +148,4 @@ unset($_SESSION['error']); opacity: 0.8; } -.error-message { - background: #ffe3e3; - color: #a73737; - border: 1px solid #f5c2c2; - padding: 10px; - border-radius: 4px; - margin-bottom: 15px; -} diff --git a/app/modules/port_types/list.php b/app/modules/port_types/list.php index d0a7725..e462d00 100644 --- a/app/modules/port_types/list.php +++ b/app/modules/port_types/list.php @@ -34,20 +34,11 @@ $portTypes = $sql->get( $params ); -$success = $_SESSION['success'] ?? ''; -unset($_SESSION['success']); - ?>

Porttypen

- -
- -
- -
@@ -164,8 +155,7 @@ unset($_SESSION['success']); font-weight: bold; } -.empty-state, -.success-message { +.empty-state { margin: 20px 0; padding: 15px; border-radius: 6px; @@ -177,12 +167,6 @@ unset($_SESSION['success']); text-align: center; } -.success-message { - background: #e9f8f1; - border: 1px solid #c7eedc; - color: #2c7d59; -} - .actions { white-space: nowrap; } diff --git a/app/modules/port_types/save.php b/app/modules/port_types/save.php index 9461db3..124233e 100644 --- a/app/modules/port_types/save.php +++ b/app/modules/port_types/save.php @@ -29,6 +29,7 @@ if (!in_array($medium, $allowedMediums, true)) { if (!empty($errors)) { $_SESSION['error'] = implode(', ', $errors); + $_SESSION['validation_errors'] = $errors; $redirect = $portTypeId ? "?module=port_types&action=edit&id=$portTypeId" : "?module=port_types&action=edit"; header("Location: $redirect"); exit; diff --git a/app/modules/racks/save.php b/app/modules/racks/save.php index 6dc0d59..edc0fe3 100644 --- a/app/modules/racks/save.php +++ b/app/modules/racks/save.php @@ -40,6 +40,7 @@ if ($heightHe < 1) { // Falls Fehler: zurück zum Edit-Formular if (!empty($errors)) { $_SESSION['error'] = implode(', ', $errors); + $_SESSION['validation_errors'] = $errors; $redirectUrl = $rackId ? "?module=racks&action=edit&id=$rackId" : "?module=racks&action=edit"; header("Location: $redirectUrl"); exit; diff --git a/app/modules/rooms/save.php b/app/modules/rooms/save.php index c4cf750..bf01a73 100644 --- a/app/modules/rooms/save.php +++ b/app/modules/rooms/save.php @@ -18,6 +18,15 @@ $comment = trim((string)($_POST['comment'] ?? '')); $rawPolygon = trim((string)($_POST['polygon_points'] ?? '')); if ($name === '' || $floorId <= 0) { + $errors = []; + if ($name === '') { + $errors[] = 'Name ist erforderlich'; + } + if ($floorId <= 0) { + $errors[] = 'Stockwerk ist erforderlich'; + } + $_SESSION['error'] = implode(', ', $errors); + $_SESSION['validation_errors'] = $errors; $redirect = $roomId > 0 ? "?module=rooms&action=edit&id=$roomId" : "?module=rooms&action=edit&floor_id=$floorId"; header("Location: $redirect"); exit; @@ -100,6 +109,7 @@ if (roomsHasPolygonColumn($sql)) { } } +$_SESSION['success'] = $roomId > 0 ? 'Raum gespeichert' : 'Raum erstellt'; header('Location: ?module=locations&action=list'); exit; diff --git a/app/templates/footer.php b/app/templates/footer.php index 6e333c5..172e10d 100644 --- a/app/templates/footer.php +++ b/app/templates/footer.php @@ -12,21 +12,5 @@ | Session:

- - - - - diff --git a/app/templates/header.php b/app/templates/header.php index 766327f..6478ff4 100644 --- a/app/templates/header.php +++ b/app/templates/header.php @@ -64,4 +64,60 @@ + 'success', + 'text' => $successMessage, + ]; +} + +$errorMessage = trim((string)($_SESSION['error'] ?? '')); +if ($errorMessage !== '') { + $flashMessages[] = [ + 'type' => 'error', + 'text' => $errorMessage, + ]; +} + +$validationErrors = $_SESSION['validation_errors'] ?? []; +if (!is_array($validationErrors)) { + $validationErrors = []; +} +$validationErrors = array_values(array_filter(array_map(static function ($entry) { + return trim((string)$entry); +}, $validationErrors), static function ($entry) { + return $entry !== ''; +})); + +if (!empty($validationErrors)) { + $flashMessages[] = [ + 'type' => 'error', + 'text' => 'Bitte pruefe die Eingaben:', + 'details' => $validationErrors, + ]; +} + +unset($_SESSION['success'], $_SESSION['error'], $_SESSION['validation_errors']); +?> +
+ +
+ +
+

+ +
    + +
  • + +
+ +
+ +
+