xtablo-source/backend/templates/planning_forms.go
Arthur Belleville 5624ca59ca
feat(17): add day-separator headers to planning event list
- PlanningShowDaySeparator in planning_forms.go — returns true when date
  changes between consecutive events
- PlanningDaySeparator templ: slate-50 header row with date label and
  data-day-separator attribute
- PlanningEventListItem: remove redundant DateLabel column (now in separator)
- Loop uses index to call PlanningShowDaySeparator before each event row

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
2026-05-17 13:03:30 +02:00

114 lines
2.9 KiB
Go

package templates
import (
"time"
"backend/internal/db/sqlc"
)
type PlanningAgenda struct {
Start time.Time
End time.Time
Today time.Time
RangeLabel string
PrevURL string
TodayURL string
NextURL string
ShowingToday bool
Events []PlanningEventRow
}
type PlanningEventRow struct {
Title string
DateLabel string
TimeRange string
TabloTitle string
TabloColor string
HasColor bool
Location string
HasLocation bool
URL string
}
func NewPlanningAgenda(start time.Time, end time.Time, today time.Time, rows []sqlc.ListUserEventsRangeRow) PlanningAgenda {
events := make([]PlanningEventRow, 0, len(rows))
for _, row := range rows {
location := ""
if row.Location.Valid {
location = row.Location.String
}
color := ""
if row.TabloColor.Valid {
color = row.TabloColor.String
}
events = append(events, PlanningEventRow{
Title: row.Title,
DateLabel: PlanningEventDateLabel(row),
TimeRange: PlanningEventTimeRange(row),
TabloTitle: row.TabloTitle,
TabloColor: color,
HasColor: color != "",
Location: location,
HasLocation: location != "",
URL: PlanningEventURL(row),
})
}
return PlanningAgenda{
Start: start,
End: end,
Today: today,
RangeLabel: PlanningRangeLabel(start, end),
PrevURL: PlanningURL(start.AddDate(0, 0, -14)),
TodayURL: "/planning",
NextURL: PlanningURL(start.AddDate(0, 0, 14)),
ShowingToday: samePlanningDay(start, today),
Events: events,
}
}
func PlanningURL(start time.Time) string {
return "/planning?start=" + start.Format("2006-01-02")
}
func PlanningEventURL(row sqlc.ListUserEventsRangeRow) string {
return "/tablos/" + row.TabloID.String() + "/events?month=" + row.EventDate.Time.Format("2006-01")
}
func PlanningEventDateLabel(row sqlc.ListUserEventsRangeRow) string {
if !row.EventDate.Valid {
return ""
}
return row.EventDate.Time.Format("Jan 2, 2006")
}
func PlanningEventTimeRange(row sqlc.ListUserEventsRangeRow) string {
start := FormatEventTime(row.StartTime)
if start == "" {
return ""
}
if !row.EndTime.Valid {
return start
}
return start + "-" + FormatEventTime(row.EndTime)
}
func PlanningRangeLabel(start time.Time, end time.Time) string {
if start.Year() == end.Year() {
return start.Format("January 2") + " - " + end.Format("January 2, 2006")
}
return start.Format("January 2, 2006") + " - " + end.Format("January 2, 2006")
}
func samePlanningDay(a time.Time, b time.Time) bool {
return a.Year() == b.Year() && a.Month() == b.Month() && a.Day() == b.Day()
}
// PlanningShowDaySeparator returns true when the event at index i belongs to a
// different day than the previous event — i.e. a date-group header should be
// rendered before it.
func PlanningShowDaySeparator(events []PlanningEventRow, index int) bool {
if index == 0 {
return true
}
return events[index].DateLabel != events[index-1].DateLabel
}