summaryrefslogtreecommitdiff
path: root/internal/models
diff options
context:
space:
mode:
Diffstat (limited to 'internal/models')
-rw-r--r--internal/models/recurrence.go40
-rw-r--r--internal/models/recurrence_test.go40
2 files changed, 0 insertions, 80 deletions
diff --git a/internal/models/recurrence.go b/internal/models/recurrence.go
index f407688..f42183c 100644
--- a/internal/models/recurrence.go
+++ b/internal/models/recurrence.go
@@ -55,43 +55,3 @@ func nextWeeklyOccurrence(due time.Time, interval int, weekdays []int) time.Time
daysToNextWeekStart := 7 - dueWeekday
return due.AddDate(0, 0, daysToNextWeekStart+sorted[0]+7*(interval-1))
}
-
-// CollapseRecurringSeries reduces each recurrence series to its single
-// earliest-due instance, preserving input order otherwise.
-//
-// The scheduler deliberately materializes a series' next instance once the
-// current one comes due, whether or not it was completed, so that ignoring one
-// occurrence doesn't stall the series (see
-// GetSeriesNeedingNextIteration). The side effect is that an unfinished
-// recurring chore and its already-generated successor both sit in the flat task
-// list at once -- "Bills" appearing twice, once overdue from Sep 1 and once for
-// Oct 1. Only the earliest open one is a thing you actually owe right now.
-//
-// This is for flat "what's open" views only. Date-anchored views (timeline,
-// widget) should keep every instance, since there each one legitimately belongs
-// to its own day.
-func CollapseRecurringSeries(tasks []Task) []Task {
- earliest := make(map[string]*Task)
- for i := range tasks {
- t := &tasks[i]
- if t.RecurrenceSeriesID == "" || t.DueDate == nil {
- continue
- }
- cur, ok := earliest[t.RecurrenceSeriesID]
- if !ok || t.DueDate.Before(*cur.DueDate) {
- earliest[t.RecurrenceSeriesID] = t
- }
- }
-
- out := make([]Task, 0, len(tasks))
- for i := range tasks {
- t := tasks[i]
- // An undated recurring row has no position in the series ordering, so it
- // is never collapsed away -- only dated instances compete.
- if keep, ok := earliest[t.RecurrenceSeriesID]; ok && t.DueDate != nil && keep.ID != t.ID {
- continue
- }
- out = append(out, t)
- }
- return out
-}
diff --git a/internal/models/recurrence_test.go b/internal/models/recurrence_test.go
index affba56..8d18996 100644
--- a/internal/models/recurrence_test.go
+++ b/internal/models/recurrence_test.go
@@ -49,43 +49,3 @@ func TestComputeNextOccurrence(t *testing.T) {
})
}
}
-
-func TestCollapseRecurringSeries_KeepsOnlyEarliestOpenInstance(t *testing.T) {
- sep1 := time.Date(2026, 9, 1, 0, 0, 0, 0, time.UTC)
- oct1 := time.Date(2026, 10, 1, 0, 0, 0, 0, time.UTC)
-
- tasks := []Task{
- {ID: "bills-sep", Content: "Bills", DueDate: &sep1, RecurrenceSeriesID: "bills"},
- {ID: "bills-oct", Content: "Bills", DueDate: &oct1, RecurrenceSeriesID: "bills"},
- {ID: "one-off", Content: "Fix curtain holder"},
- }
-
- got := CollapseRecurringSeries(tasks)
-
- var ids []string
- for _, task := range got {
- ids = append(ids, task.ID)
- }
- if len(got) != 2 {
- t.Fatalf("got %d tasks (%v), want 2: one row per recurring series plus the one-off", len(got), ids)
- }
- if got[0].ID != "bills-sep" {
- t.Errorf("kept %q for the Bills series, want bills-sep (the earliest open instance is the one you actually owe)", got[0].ID)
- }
- if got[1].ID != "one-off" {
- t.Errorf("non-recurring task was dropped or reordered: got %q", got[1].ID)
- }
-}
-
-func TestCollapseRecurringSeries_UndatedAndDistinctSeriesUntouched(t *testing.T) {
- due := time.Date(2026, 9, 1, 0, 0, 0, 0, time.UTC)
- tasks := []Task{
- {ID: "a", RecurrenceSeriesID: "series-a", DueDate: &due},
- {ID: "b", RecurrenceSeriesID: "series-b", DueDate: &due},
- {ID: "c", RecurrenceSeriesID: "series-c"}, // recurring but undated
- }
-
- if got := CollapseRecurringSeries(tasks); len(got) != 3 {
- t.Errorf("len = %d, want 3 -- distinct series must not collapse into each other", len(got))
- }
-}