From 7828e19501b3ca8b2e86ca7297f580c659e5c9b8 Mon Sep 17 00:00:00 2001 From: Peter Stone Date: Fri, 23 Jan 2026 16:10:52 -1000 Subject: Fix bugs #24-27: calendar dedup, uncomplete tasks, planning view Bug fixes: - #24: Deduplicate calendar events across multiple calendars using summary + start time as key - #25: Change event icon from calendar to clock to avoid confusion with date display - #26: Add task uncomplete functionality via ReopenTask API for Todoist and closed=false for Trello - #27: Restructure planning view with sections for Scheduled (timed events/tasks), Today (unscheduled), Quick Add, and Upcoming (3 days) Co-Authored-By: Claude Opus 4.5 --- internal/handlers/handlers.go | 69 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 63 insertions(+), 6 deletions(-) (limited to 'internal/handlers/handlers.go') diff --git a/internal/handlers/handlers.go b/internal/handlers/handlers.go index b8fc574..c364188 100644 --- a/internal/handlers/handlers.go +++ b/internal/handlers/handlers.go @@ -827,21 +827,78 @@ func (h *Handler) HandleCompleteAtom(w http.ResponseWriter, r *http.Request) { } } - // Return completed task HTML (stays visible with strikethrough until refresh) + // Return completed task HTML with uncomplete option w.Header().Set("Content-Type", "text/html") - completedHTML := fmt.Sprintf(`
+ completedHTML := fmt.Sprintf(`
- +
-

%s

-
Completed
+

%s

+
Completed - click to undo
-
`, template.HTMLEscapeString(title)) +
`, template.HTMLEscapeString(id), template.HTMLEscapeString(source), template.HTMLEscapeString(title)) w.Write([]byte(completedHTML)) } +// HandleUncompleteAtom handles reopening a completed task +func (h *Handler) HandleUncompleteAtom(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + + if err := r.ParseForm(); err != nil { + http.Error(w, "Failed to parse form", http.StatusBadRequest) + log.Printf("Error parsing form: %v", err) + return + } + + id := r.FormValue("id") + source := r.FormValue("source") + + if id == "" || source == "" { + http.Error(w, "Missing id or source", http.StatusBadRequest) + return + } + + var err error + switch source { + case "todoist": + err = h.todoistClient.ReopenTask(ctx, id) + case "trello": + // Reopen the card (closed = false) + updates := map[string]interface{}{ + "closed": false, + } + err = h.trelloClient.UpdateCard(ctx, id, updates) + default: + http.Error(w, "Unknown source: "+source, http.StatusBadRequest) + return + } + + if err != nil { + http.Error(w, "Failed to reopen task", http.StatusInternalServerError) + log.Printf("Error reopening atom (source=%s, id=%s): %v", source, id, err) + return + } + + // Invalidate cache to force refresh + switch source { + case "todoist": + h.store.InvalidateCache(store.CacheKeyTodoistTasks) + case "trello": + h.store.InvalidateCache(store.CacheKeyTrelloBoards) + } + + // Trigger refresh + w.Header().Set("HX-Trigger", "refresh-tasks") + w.WriteHeader(http.StatusOK) +} + // HandleUnifiedAdd creates a task in Todoist or a card in Trello from the Quick Add form func (h *Handler) HandleUnifiedAdd(w http.ResponseWriter, r *http.Request) { ctx := r.Context() -- cgit v1.2.3