summaryrefslogtreecommitdiff
path: root/internal/handlers/tabs.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/handlers/tabs.go')
-rw-r--r--internal/handlers/tabs.go178
1 files changed, 162 insertions, 16 deletions
diff --git a/internal/handlers/tabs.go b/internal/handlers/tabs.go
index 986222a..87be344 100644
--- a/internal/handlers/tabs.go
+++ b/internal/handlers/tabs.go
@@ -171,39 +171,185 @@ func (h *TabsHandler) HandleTasks(w http.ResponseWriter, r *http.Request) {
}
}
-// HandlePlanning renders the Planning tab (Trello boards)
+// ScheduledItem represents a scheduled event or task for the planning view
+type ScheduledItem struct {
+ Type string // "event" or "task"
+ ID string
+ Title string
+ Description string
+ Start time.Time
+ End time.Time
+ URL string
+ Source string // "todoist", "trello", "calendar"
+ SourceIcon string
+ Priority int
+}
+
+// HandlePlanning renders the Planning tab with structured sections
func (h *TabsHandler) HandlePlanning(w http.ResponseWriter, r *http.Request) {
+ now := time.Now()
+ today := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location())
+ tomorrow := today.AddDate(0, 0, 1)
+ in3Days := today.AddDate(0, 0, 4) // End of 3rd day
+
// Fetch Trello boards
boards, err := h.store.GetBoards()
if err != nil {
- http.Error(w, "Failed to fetch boards", http.StatusInternalServerError)
log.Printf("Error fetching boards: %v", err)
- return
+ boards = []models.Board{}
+ }
+
+ // Fetch Todoist tasks
+ tasks, err := h.store.GetTasks()
+ if err != nil {
+ log.Printf("Error fetching tasks: %v", err)
+ tasks = []models.Task{}
}
// Fetch Google Calendar events
var events []models.CalendarEvent
if h.googleCalendarClient != nil {
- var err error
- events, err = h.googleCalendarClient.GetUpcomingEvents(r.Context(), 10)
+ events, err = h.googleCalendarClient.GetUpcomingEvents(r.Context(), 20)
if err != nil {
log.Printf("Error fetching calendar events: %v", err)
- // Don't fail the whole request, just show empty events
- } else {
- log.Printf("Fetched %d calendar events", len(events))
}
- } else {
- log.Printf("Google Calendar client not configured")
}
+ // Categorize into sections
+ var scheduled []ScheduledItem // Events and timed tasks for today
+ var unscheduled []models.Atom // Tasks due today without specific time
+ var upcoming []ScheduledItem // Events and tasks for next 3 days
+
+ // Process calendar events
+ for _, event := range events {
+ item := ScheduledItem{
+ Type: "event",
+ ID: event.ID,
+ Title: event.Summary,
+ Description: event.Description,
+ Start: event.Start,
+ End: event.End,
+ URL: event.HTMLLink,
+ Source: "calendar",
+ SourceIcon: "📅",
+ }
+
+ if event.Start.Before(tomorrow) {
+ scheduled = append(scheduled, item)
+ } else if event.Start.Before(in3Days) {
+ upcoming = append(upcoming, item)
+ }
+ }
+
+ // Process Todoist tasks
+ for _, task := range tasks {
+ if task.Completed || task.DueDate == nil {
+ continue
+ }
+ dueDate := *task.DueDate
+
+ // Check if task has a specific time (not midnight)
+ hasTime := dueDate.Hour() != 0 || dueDate.Minute() != 0
+
+ if dueDate.Before(tomorrow) {
+ if hasTime {
+ // Timed task for today -> scheduled
+ scheduled = append(scheduled, ScheduledItem{
+ Type: "task",
+ ID: task.ID,
+ Title: task.Content,
+ Start: dueDate,
+ URL: task.URL,
+ Source: "todoist",
+ SourceIcon: "✓",
+ Priority: task.Priority,
+ })
+ } else {
+ // All-day task for today -> unscheduled
+ atom := models.TaskToAtom(task)
+ atom.ComputeUIFields()
+ unscheduled = append(unscheduled, atom)
+ }
+ } else if dueDate.Before(in3Days) {
+ upcoming = append(upcoming, ScheduledItem{
+ Type: "task",
+ ID: task.ID,
+ Title: task.Content,
+ Start: dueDate,
+ URL: task.URL,
+ Source: "todoist",
+ SourceIcon: "✓",
+ Priority: task.Priority,
+ })
+ }
+ }
+
+ // Process Trello cards with due dates
+ for _, board := range boards {
+ for _, card := range board.Cards {
+ if card.DueDate == nil {
+ continue
+ }
+ dueDate := *card.DueDate
+ hasTime := dueDate.Hour() != 0 || dueDate.Minute() != 0
+
+ if dueDate.Before(tomorrow) {
+ if hasTime {
+ scheduled = append(scheduled, ScheduledItem{
+ Type: "task",
+ ID: card.ID,
+ Title: card.Name,
+ Start: dueDate,
+ URL: card.URL,
+ Source: "trello",
+ SourceIcon: "📋",
+ })
+ } else {
+ atom := models.CardToAtom(card)
+ atom.ComputeUIFields()
+ unscheduled = append(unscheduled, atom)
+ }
+ } else if dueDate.Before(in3Days) {
+ upcoming = append(upcoming, ScheduledItem{
+ Type: "task",
+ ID: card.ID,
+ Title: card.Name,
+ Start: dueDate,
+ URL: card.URL,
+ Source: "trello",
+ SourceIcon: "📋",
+ })
+ }
+ }
+ }
+
+ // Sort scheduled by start time
+ sort.Slice(scheduled, func(i, j int) bool {
+ return scheduled[i].Start.Before(scheduled[j].Start)
+ })
+
+ // Sort unscheduled by priority (higher first)
+ sort.Slice(unscheduled, func(i, j int) bool {
+ return unscheduled[i].Priority > unscheduled[j].Priority
+ })
+
+ // Sort upcoming by date
+ sort.Slice(upcoming, func(i, j int) bool {
+ return upcoming[i].Start.Before(upcoming[j].Start)
+ })
+
data := struct {
- Boards []models.Board
- Projects []models.Project
- Events []models.CalendarEvent
+ Scheduled []ScheduledItem
+ Unscheduled []models.Atom
+ Upcoming []ScheduledItem
+ Boards []models.Board
+ Today string
}{
- Boards: boards,
- Projects: []models.Project{}, // Empty for now
- Events: events,
+ Scheduled: scheduled,
+ Unscheduled: unscheduled,
+ Upcoming: upcoming,
+ Boards: boards,
+ Today: today.Format("2006-01-02"),
}
if err := h.templates.ExecuteTemplate(w, "planning-tab", data); err != nil {