diff options
Diffstat (limited to 'internal')
| -rw-r--r-- | internal/handlers/widget.go | 10 | ||||
| -rw-r--r-- | internal/handlers/widget_test.go | 33 |
2 files changed, 40 insertions, 3 deletions
diff --git a/internal/handlers/widget.go b/internal/handlers/widget.go index 0092b6b..f0fd101 100644 --- a/internal/handlers/widget.go +++ b/internal/handlers/widget.go @@ -70,7 +70,15 @@ func TimelineItemToWidgetItem(item models.TimelineItem) models.WidgetItem { if !item.Time.IsZero() && (!item.IsAllDay || item.Type == models.TimelineItemTypeEvent) { t := item.Time wi.Start = &t - if !item.IsAllDay { + if item.Type == models.TimelineItemTypeEvent { + // Events always forward End when known, even when IsAllDay -- + // a multi-day all-day event (e.g. a 3-day conference) needs its + // End date reaching the client so it can detect the span and + // render "starts"/"ends"/spans-through labels per rendered day. + if item.EndTime != nil { + wi.End = item.EndTime + } + } else if !item.IsAllDay { if item.EndTime != nil { wi.End = item.EndTime } else { diff --git a/internal/handlers/widget_test.go b/internal/handlers/widget_test.go index 4e08d2a..2a6967e 100644 --- a/internal/handlers/widget_test.go +++ b/internal/handlers/widget_test.go @@ -174,8 +174,9 @@ func TestTimelineItemToWidgetItem_Event(t *testing.T) { // IsAllDay item regardless of type, which meant the widget client's // hourly-slot packer had no date information to pin all-day events to the // top of the correct day and they could silently fall outside the visible -// grid range instead. End stays nil since there's no meaningful end time to -// show for an all-day item. +// grid range instead. This fixture's End stays nil only because it has no +// EndTime set -- see TestTimelineItemToWidgetItem_MultiDayAllDayEvent_ForwardsEnd +// for the case where a multi-day all-day event has a real EndTime. func TestTimelineItemToWidgetItem_AllDayEvent(t *testing.T) { day := time.Date(2026, 7, 12, 0, 0, 0, 0, time.Local) item := models.TimelineItem{ @@ -206,6 +207,34 @@ func TestTimelineItemToWidgetItem_AllDayEvent(t *testing.T) { } } +// TestTimelineItemToWidgetItem_MultiDayAllDayEvent_ForwardsEnd proves that a +// genuine all-day CALENDAR EVENT with a real EndTime (e.g. a 3-day +// conference with no specific time) still gets End forwarded to the widget +// client, even though IsAllDay is true -- needed so the client can detect +// the multi-day span and render "starts"/"ends" labels per day. +func TestTimelineItemToWidgetItem_MultiDayAllDayEvent_ForwardsEnd(t *testing.T) { + start := time.Date(2026, 7, 12, 0, 0, 0, 0, time.Local) + end := time.Date(2026, 7, 15, 0, 0, 0, 0, time.Local) + item := models.TimelineItem{ + ID: "cal-conference", + Title: "Offsite", + Source: "calendar", + Type: models.TimelineItemTypeEvent, + Time: start, + EndTime: &end, + IsAllDay: true, + } + + wi := TimelineItemToWidgetItem(item) + + if wi.End == nil { + t.Fatal("expected End to be forwarded for a multi-day all-day event") + } + if !wi.End.Equal(end) { + t.Errorf("End = %v, want %v", *wi.End, end) + } +} + // TestTimelineItemToWidgetItem_AllDayTask_KeepsFloatingBehavior proves the // same fix does NOT change behavior for undated doot/gtask tasks, which are // also flagged IsAllDay as a "no specific time" fallback (see |
