diff --git a/go-backend/internal/web/ui/app.css b/go-backend/internal/web/ui/app.css index dc93167..1f0173e 100644 --- a/go-backend/internal/web/ui/app.css +++ b/go-backend/internal/web/ui/app.css @@ -883,6 +883,7 @@ margin-bottom: 1.5rem; } +.overview-section-heading h1, .overview-section-heading h3, .tasks-section-header h3 { color: var(--color-surface-muted-inverse); diff --git a/go-backend/internal/web/views/planning_view.go b/go-backend/internal/web/views/planning_view.go new file mode 100644 index 0000000..34a912d --- /dev/null +++ b/go-backend/internal/web/views/planning_view.go @@ -0,0 +1,40 @@ +package views + +// PlanningEventRow holds data for a single event row in the planning agenda. +type PlanningEventRow struct { + DateLabel string + TimeRange string + Title string + TabloTitle string + Location string +} + +// PlanningTabData is the view model for the planning page. +type PlanningTabData struct { + Events []PlanningEventRow + DateRange string +} + +// NewPlanningTabData returns a PlanningTabData with static demo events spanning 2 dates. +func NewPlanningTabData() PlanningTabData { + return PlanningTabData{ + DateRange: "May 17 – May 30, 2026", + Events: []PlanningEventRow{ + {DateLabel: "May 17, 2026", TimeRange: "09:00-10:00", Title: "Sprint Planning", TabloTitle: "Product", Location: "Room A"}, + {DateLabel: "May 17, 2026", TimeRange: "11:00-12:00", Title: "Design Review", TabloTitle: "Design", Location: ""}, + {DateLabel: "May 17, 2026", TimeRange: "14:00-15:00", Title: "Stakeholder Sync", TabloTitle: "Product", Location: "HQ"}, + {DateLabel: "May 18, 2026", TimeRange: "10:00-11:00", Title: "Engineering Stand-up", TabloTitle: "Engineering", Location: ""}, + {DateLabel: "May 18, 2026", TimeRange: "15:00-16:00", Title: "Retrospective", TabloTitle: "Product", Location: "Room B"}, + }, + } +} + +// PlanningShowDaySeparator returns true when a day separator header should be +// rendered before the event at index. The separator is shown for the first +// event (index 0) or whenever the date label changes from the previous event. +func PlanningShowDaySeparator(events []PlanningEventRow, index int) bool { + if index == 0 { + return true + } + return events[index].DateLabel != events[index-1].DateLabel +} diff --git a/go-backend/internal/web/views/planning_view_test.go b/go-backend/internal/web/views/planning_view_test.go new file mode 100644 index 0000000..4978436 --- /dev/null +++ b/go-backend/internal/web/views/planning_view_test.go @@ -0,0 +1,54 @@ +package views + +import ( + "context" + "strings" + "testing" +) + +func TestPlanningShowDaySeparator(t *testing.T) { + events := []PlanningEventRow{ + {DateLabel: "May 17, 2026", TimeRange: "09:00", Title: "A"}, + {DateLabel: "May 17, 2026", TimeRange: "11:00", Title: "B"}, + {DateLabel: "May 18, 2026", TimeRange: "10:00", Title: "C"}, + } + + tests := []struct { + name string + index int + want bool + }{ + {"first event always shows separator", 0, true}, + {"same date as previous — no separator", 1, false}, + {"different date from previous — show separator", 2, true}, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + got := PlanningShowDaySeparator(events, tc.index) + if got != tc.want { + t.Fatalf("PlanningShowDaySeparator(events, %d) = %v; want %v", tc.index, got, tc.want) + } + }) + } +} + +func TestPlanningMainContentRendersOverviewSection(t *testing.T) { + data := PlanningTabData{ + DateRange: "May 17 – May 18, 2026", + Events: []PlanningEventRow{ + {DateLabel: "May 17, 2026", TimeRange: "09:00", Title: "Alpha"}, + {DateLabel: "May 17, 2026", TimeRange: "11:00", Title: "Beta"}, + {DateLabel: "May 18, 2026", TimeRange: "10:00", Title: "Gamma"}, + }, + } + + _ = context.Background() // ensure import is used + html := renderViewToString(t, PlanningMainContent(data)) + + for _, want := range []string{"overview-section", "overview-section-heading", "data-day-separator"} { + if !strings.Contains(html, want) { + t.Fatalf("PlanningMainContent rendered HTML missing %q; html: %.1500s", want, html) + } + } +}