summaryrefslogtreecommitdiff
path: root/internal
diff options
context:
space:
mode:
Diffstat (limited to 'internal')
-rw-r--r--internal/handlers/handlers.go4
-rw-r--r--internal/handlers/tabs.go31
-rw-r--r--internal/models/atom.go21
3 files changed, 48 insertions, 8 deletions
diff --git a/internal/handlers/handlers.go b/internal/handlers/handlers.go
index 8d809ae..e4d6457 100644
--- a/internal/handlers/handlers.go
+++ b/internal/handlers/handlers.go
@@ -762,10 +762,10 @@ func (h *Handler) HandleUnifiedAdd(w http.ResponseWriter, r *http.Request) {
return
}
- // Parse due date if provided
+ // Parse due date if provided (use local timezone)
var dueDate *time.Time
if dueDateStr != "" {
- parsed, err := time.Parse("2006-01-02", dueDateStr)
+ parsed, err := time.ParseInLocation("2006-01-02", dueDateStr, time.Local)
if err == nil {
dueDate = &parsed
}
diff --git a/internal/handlers/tabs.go b/internal/handlers/tabs.go
index 7e0b352..bd15710 100644
--- a/internal/handlers/tabs.go
+++ b/internal/handlers/tabs.go
@@ -88,7 +88,12 @@ func (h *TabsHandler) HandleTasks(w http.ResponseWriter, r *http.Request) {
}
}
- // Sort atoms: by DueDate (earliest first), then by Priority (descending)
+ // Compute UI fields (IsOverdue, HasSetTime)
+ for i := range atoms {
+ atoms[i].ComputeUIFields()
+ }
+
+ // Sort atoms: by DueDate (earliest first), then by HasSetTime, then by Priority
sort.SliceStable(atoms, func(i, j int) bool {
// Handle nil due dates (push to end)
if atoms[i].DueDate == nil && atoms[j].DueDate != nil {
@@ -98,14 +103,30 @@ func (h *TabsHandler) HandleTasks(w http.ResponseWriter, r *http.Request) {
return true
}
- // Both have due dates, sort by date
+ // Both have due dates
if atoms[i].DueDate != nil && atoms[j].DueDate != nil {
- if !atoms[i].DueDate.Equal(*atoms[j].DueDate) {
- return atoms[i].DueDate.Before(*atoms[j].DueDate)
+ // Compare by date only (ignore time)
+ dateI := atoms[i].DueDate.Truncate(24 * time.Hour)
+ dateJ := atoms[j].DueDate.Truncate(24 * time.Hour)
+
+ if !dateI.Equal(dateJ) {
+ return dateI.Before(dateJ)
+ }
+
+ // Same day: tasks with set times come before midnight tasks
+ if atoms[i].HasSetTime != atoms[j].HasSetTime {
+ return atoms[i].HasSetTime
+ }
+
+ // Both have set times or both are midnight, sort by actual time
+ if atoms[i].HasSetTime && atoms[j].HasSetTime {
+ if !atoms[i].DueDate.Equal(*atoms[j].DueDate) {
+ return atoms[i].DueDate.Before(*atoms[j].DueDate)
+ }
}
}
- // Same due date (or both nil), sort by priority (descending)
+ // Same due date/time (or both nil), sort by priority (descending)
return atoms[i].Priority > atoms[j].Priority
})
diff --git a/internal/models/atom.go b/internal/models/atom.go
index fe40962..b3a384a 100644
--- a/internal/models/atom.go
+++ b/internal/models/atom.go
@@ -36,11 +36,30 @@ type Atom struct {
// UI Helpers (to be populated by mappers)
SourceIcon string // e.g., "trello-icon.svg" or emoji
ColorClass string // e.g., "border-blue-500"
+ IsOverdue bool // True if due date is before today
+ HasSetTime bool // True if due time is not midnight (has specific time)
// Original Data (for write operations)
Raw interface{}
}
+// ComputeUIFields calculates IsOverdue and HasSetTime based on DueDate
+func (a *Atom) ComputeUIFields() {
+ if a.DueDate == nil {
+ return
+ }
+
+ now := time.Now()
+ today := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location())
+
+ // Check if overdue (due date is before today)
+ dueDay := time.Date(a.DueDate.Year(), a.DueDate.Month(), a.DueDate.Day(), 0, 0, 0, 0, a.DueDate.Location())
+ a.IsOverdue = dueDay.Before(today)
+
+ // Check if has set time (not midnight)
+ a.HasSetTime = a.DueDate.Hour() != 0 || a.DueDate.Minute() != 0
+}
+
// TaskToAtom converts a Todoist Task to an Atom
func TaskToAtom(t Task) Atom {
// Todoist priority: 1 (normal) to 4 (urgent)
@@ -63,7 +82,7 @@ func TaskToAtom(t Task) Atom {
DueDate: t.DueDate,
CreatedAt: t.CreatedAt,
Priority: priority,
- SourceIcon: "✓", // Checkmark emoji for tasks
+ SourceIcon: "🔴", // Red circle for Todoist
ColorClass: "border-red-500",
Raw: t,
}