From 9d2cb794244271ca806e8f4eea76eb6514ff5306 Mon Sep 17 00:00:00 2001 From: noroot Date: Sat, 29 Aug 2026 23:10:42 +0200 Subject: [PATCH] =?UTF-8?q?fix:=20Startseite=20zeigt=20echte=20=C3=9Cbersi?= =?UTF-8?q?cht=20statt=20Phase-1-Platzhalter?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit handleIndex war seit dem Produktwechsel unverändert ein Platzhalter aus Schritt 1 ("Antrag stellen"/"Meine Anträge" — beides bereits in der Seitenleiste vorhanden, die Startseite selbst zeigte nichts Eigenes). Zeigt jetzt die Zahl eigener offener Anträge, und für die Fachebene zusätzlich die Zahl offener Fälle im Posteingang; Betreiber sehen einen Link zur Plattform statt leerer Antrags-Kacheln, die für sie ohnehin nicht gelten. Bewusst ohne Wiedervorlage-Zahl — deren Berechnung vergleicht jeden Genehmigungs-Snapshot gegen den aktuellen Katalogstand und wäre für eine bei jedem Login geladene Startseite zu teuer. Co-Authored-By: Claude Sonnet 5 --- internal/web/handlers.go | 46 +++++++++++++++++++--- internal/web/handlers_test.go | 63 +++++++++++++++++++++++++++++++ internal/web/templates/index.html | 11 +++++- 3 files changed, 113 insertions(+), 7 deletions(-) create mode 100644 internal/web/handlers_test.go diff --git a/internal/web/handlers.go b/internal/web/handlers.go index afbeca9..3dbce2e 100644 --- a/internal/web/handlers.go +++ b/internal/web/handlers.go @@ -11,15 +11,49 @@ func (s *Server) handleHealth(w http.ResponseWriter, r *http.Request) { } type indexData struct { - Title string - Nav navData + Title string + Nav navData + OffeneAntraege int + ZeigePosteingang bool + OffenerPosteingang int } -// handleIndex ist die Startseite nach der Anmeldung. Platzhalter für -// Phase 1 (Datenmodell/Regelwerk/Katalogstruktur) — der geführte -// Fragebogen (Ebene 2, "Antrag stellen") ist Phase 2 der Baureihenfolge. +// handleIndex ist die Startseite nach der Anmeldung — ein kurzer +// Überblick statt reiner Navigations-Duplikate (die Links stehen +// eh schon in der Seitenleiste): eigene offene Anträge, und für die +// Fachebene zusätzlich die Zahl offener Fälle im Posteingang. Bewusst +// ohne die Wiedervorlage-Zahl hier — deren Berechnung vergleicht jeden +// aktiven Genehmigungs-Snapshot gegen den aktuellen Katalogstand +// (siehe handleWiedervorlageListe) und wäre für eine Startseite, die +// bei jedem Login geladen wird, zu teuer. func (s *Server) handleIndex(w http.ResponseWriter, r *http.Request) { - data := indexData{Title: "Start", Nav: navFor(r)} + user := currentUser(r) + nav := navFor(r) + data := indexData{Title: "Start", Nav: nav} + + if !nav.IsBetreiber { + eigene, err := s.store.ListAntraegeForUser(r.Context(), user.ID) + if err == nil { + for _, a := range eigene { + if a.Status == "eingereicht" { + data.OffeneAntraege++ + } + } + } + } + + if nav.IsFachebene { + data.ZeigePosteingang = true + alle, err := s.store.ListAntraegeForAccount(r.Context(), user.AccountID) + if err == nil { + for _, a := range alle { + if a.Status == "eingereicht" { + data.OffenerPosteingang++ + } + } + } + } + if err := s.templates.ExecuteTemplate(w, "index", data); err != nil { http.Error(w, "Seite konnte nicht gerendert werden", http.StatusInternalServerError) } diff --git a/internal/web/handlers_test.go b/internal/web/handlers_test.go new file mode 100644 index 0000000..c329aba --- /dev/null +++ b/internal/web/handlers_test.go @@ -0,0 +1,63 @@ +package web_test + +import ( + "net/http" + "strings" + "testing" +) + +func TestIndexZeigtEigeneOffeneAntraege(t *testing.T) { + s, _, cookie := newAuthedTestServer(t) + postForm(t, s, cookie, "/antraege", fullAntragForm()) + + resp := getWithCookie(t, s, cookie, "/") + if resp.Code != http.StatusOK { + t.Fatalf("status = %d, body: %s", resp.Code, resp.Body.String()) + } + if !strings.Contains(resp.Body.String(), `href="/antraege">Meine offenen Anträge 1`) { + t.Errorf("expected 1 offenen Antrag auf der Startseite, got: %s", resp.Body.String()) + } +} + +func TestIndexZeigtPosteingangNurFuerFachebene(t *testing.T) { + fs := newFakeStore() + s := newServer(t, fs) + _, verantwortlicherCookie := seedFallImAccount(t, fs, s, "verantwortlicher") + + resp := getWithCookie(t, s, verantwortlicherCookie, "/") + if resp.Code != http.StatusOK { + t.Fatalf("status = %d, body: %s", resp.Code, resp.Body.String()) + } + if !strings.Contains(resp.Body.String(), `href="/faelle">Posteingang 1`) { + t.Errorf("expected 1 offenen Fall im Posteingang auf der Startseite, got: %s", resp.Body.String()) + } +} + +func TestIndexZeigtKeinenPosteingangFuerMitarbeiter(t *testing.T) { + s, _, cookie := newAuthedTestServer(t) + + resp := getWithCookie(t, s, cookie, "/") + if resp.Code != http.StatusOK { + t.Fatalf("status = %d, body: %s", resp.Code, resp.Body.String()) + } + if strings.Contains(resp.Body.String(), "Posteingang") { + t.Errorf("expected no Posteingang tile for mitarbeiter, got: %s", resp.Body.String()) + } +} + +func TestIndexZeigtPlattformLinkFuerBetreiber(t *testing.T) { + fs := newFakeStore() + s := newServer(t, fs) + betreiberCookie := seedAccountWithRole(t, fs, "Deklarix Betreiber", "betreiber@example.com", "betreiber") + + resp := getWithCookie(t, s, betreiberCookie, "/") + if resp.Code != http.StatusOK { + t.Fatalf("status = %d, body: %s", resp.Code, resp.Body.String()) + } + if !strings.Contains(resp.Body.String(), `href="/betreiber">Zur Plattform`) { + t.Errorf("expected a Plattform link for betreiber, got: %s", resp.Body.String()) + } + if strings.Contains(resp.Body.String(), "Antrag stellen") { + t.Errorf("expected no antrag tiles for betreiber, got: %s", resp.Body.String()) + } +} diff --git a/internal/web/templates/index.html b/internal/web/templates/index.html index aa50fc2..be31a39 100644 --- a/internal/web/templates/index.html +++ b/internal/web/templates/index.html @@ -5,10 +5,19 @@ {{template "nav" .Nav}}

Willkommen bei Deklarix

+{{if .Nav.IsBetreiber}} + +{{else}} +{{end}}