summaryrefslogtreecommitdiff
path: root/internal/handlers/widget_test.go
diff options
context:
space:
mode:
authorPeter Stone <thepeterstone@gmail.com>2026-07-12 06:21:40 +0000
committerPeter Stone <thepeterstone@gmail.com>2026-07-12 06:21:40 +0000
commit84252756c687044d73a0ea5cebf8088c7c9ed3e8 (patch)
tree0f76a627ee9fb4037d83a57270a3426694b69c2f /internal/handlers/widget_test.go
parenta43cc7b8f007a86742756bd4b67f9ba1c204bbd0 (diff)
fix(widget): pin all-day calendar events to the top instead of losing them
WidgetItem.isAllDay was carried by the client's data model but nothing ever read it. All-day events had no Start at all, so they fell into the same floating-task queue as ordinary untimed tasks; if enough tasks were ahead of one in the queue, SlotPacker could assign it an hour slot past the visible grid range entirely -- not merely unpinned, actually invisible. Server: TimelineItemToWidgetItem now populates Start for all-day CALENDAR EVENTS specifically (their real event date), while leaving undated doot/gtask tasks -- also flagged IsAllDay as a "no specific time" fallback, a different concept -- on the existing nil-Start floating behavior. Client: all-day events are filtered out of the hourly grid/floating-task pipeline entirely, bucketed by day using the new Start date, and rendered in a new pinned AllDayRow section right after the TODAY/TOMORROW headers.
Diffstat (limited to 'internal/handlers/widget_test.go')
-rw-r--r--internal/handlers/widget_test.go61
1 files changed, 61 insertions, 0 deletions
diff --git a/internal/handlers/widget_test.go b/internal/handlers/widget_test.go
index 850dc07..6d741d2 100644
--- a/internal/handlers/widget_test.go
+++ b/internal/handlers/widget_test.go
@@ -109,6 +109,67 @@ func TestTimelineItemToWidgetItem_Event(t *testing.T) {
}
}
+// TestTimelineItemToWidgetItem_AllDayEvent proves the 2026-07-12 fix: an
+// all-day CALENDAR EVENT (Type == event, IsAllDay == true) must get Start
+// populated with its real date -- previously Start was nil for every
+// 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.
+func TestTimelineItemToWidgetItem_AllDayEvent(t *testing.T) {
+ day := time.Date(2026, 7, 12, 0, 0, 0, 0, time.Local)
+ item := models.TimelineItem{
+ ID: "cal-holiday",
+ Title: "Company Holiday",
+ Source: "calendar",
+ Type: models.TimelineItemTypeEvent,
+ Time: day,
+ IsAllDay: true,
+ }
+
+ wi := TimelineItemToWidgetItem(item)
+
+ if wi.Type != "event" {
+ t.Errorf("Type: got %q, want %q", wi.Type, "event")
+ }
+ if !wi.IsAllDay {
+ t.Error("expected IsAllDay to be true")
+ }
+ if wi.Start == nil {
+ t.Fatal("all-day event should have non-nil Start (needed to pin it to the correct day)")
+ }
+ if !wi.Start.Equal(day) {
+ t.Errorf("Start = %v, want %v", *wi.Start, day)
+ }
+ if wi.End != nil {
+ t.Error("all-day event should have nil 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
+// TimelineItem.ComputeDaySection) but are a different concept from a real
+// all-day calendar event -- they must keep the existing nil-Start
+// "floating" treatment so the hourly-slot packer still places them.
+func TestTimelineItemToWidgetItem_AllDayTask_KeepsFloatingBehavior(t *testing.T) {
+ item := models.TimelineItem{
+ ID: "undated-task",
+ Title: "Someday task",
+ Source: "doot",
+ Type: models.TimelineItemTypeTask,
+ Time: time.Now(),
+ IsAllDay: true,
+ }
+
+ wi := TimelineItemToWidgetItem(item)
+
+ if wi.Start != nil {
+ t.Error("an undated task (IsAllDay as a fallback, not a real all-day event) should still have nil Start")
+ }
+}
+
func TestHandleWidgetComplete_NonCompletable(t *testing.T) {
h := &Handler{}
body := `{"id":"x","source":"calendar"}`