summaryrefslogtreecommitdiff
path: root/internal/handlers
diff options
context:
space:
mode:
authorPeter Stone <thepeterstone@gmail.com>2026-01-13 14:20:41 -1000
committerPeter Stone <thepeterstone@gmail.com>2026-01-13 14:20:41 -1000
commita7a9aa3dcfe4b90d9b32791c8313a0019ad11289 (patch)
treee04c67d6896275a773ad759d27820a1d445695a0 /internal/handlers
parente107192be5efb65807c7da3b6aa99ce3555944d0 (diff)
Implement Todoist write operations - Handlers & UI (Part 2)
Complete Todoist task creation and completion functionality: Handlers: - Update aggregateData to fetch and populate Projects - Add HandleCreateTask: creates task, refreshes list, re-renders - Add HandleCompleteTask: marks task complete, returns empty - Both handlers pass Projects to template for dropdown Routes: - Register POST /tasks for task creation - Register POST /tasks/complete for task completion UI (todoist-tasks.html): - Add Quick Add form with collapsible details element - Project selector dropdown (iterates over .Projects) - Content input field with validation - HTMX integration: hx-post, hx-target, hx-swap - Functional completion checkboxes on each task - Remove disabled attribute from checkboxes - Add todoist-task-item wrapper class for HTMX targeting - Glassmorphism styling for form Features: - Create Todoist tasks with optional project assignment - Mark tasks complete with single click (disappears) - Real-time task list updates without page reload - Seamless HTMX partial updates All tests pass. Full Todoist write operations now live in UI! Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Diffstat (limited to 'internal/handlers')
-rw-r--r--internal/handlers/handlers.go101
1 files changed, 101 insertions, 0 deletions
diff --git a/internal/handlers/handlers.go b/internal/handlers/handlers.go
index 8762035..c3e49ed 100644
--- a/internal/handlers/handlers.go
+++ b/internal/handlers/handlers.go
@@ -254,6 +254,20 @@ func (h *Handler) aggregateData(ctx context.Context, forceRefresh bool) (*models
}
}()
+ // Fetch Todoist projects
+ wg.Add(1)
+ go func() {
+ defer wg.Done()
+ projects, err := h.todoistClient.GetProjects(ctx)
+ mu.Lock()
+ defer mu.Unlock()
+ if err != nil {
+ log.Printf("Failed to fetch projects: %v", err)
+ } else {
+ data.Projects = projects
+ }
+ }()
+
// Fetch Obsidian notes (if configured)
if h.obsidianClient != nil {
wg.Add(1)
@@ -528,3 +542,90 @@ func (h *Handler) HandleCompleteCard(w http.ResponseWriter, r *http.Request) {
// Return empty response (card will be removed from DOM)
w.WriteHeader(http.StatusOK)
}
+
+// HandleCreateTask creates a new Todoist task
+func (h *Handler) HandleCreateTask(w http.ResponseWriter, r *http.Request) {
+ ctx := r.Context()
+
+ // Parse form data
+ if err := r.ParseForm(); err != nil {
+ http.Error(w, "Failed to parse form", http.StatusBadRequest)
+ log.Printf("Error parsing form: %v", err)
+ return
+ }
+
+ content := r.FormValue("content")
+ projectID := r.FormValue("project_id")
+
+ if content == "" {
+ http.Error(w, "Missing content", http.StatusBadRequest)
+ return
+ }
+
+ // Create the task
+ _, err := h.todoistClient.CreateTask(ctx, content, projectID, nil, 0)
+ if err != nil {
+ http.Error(w, "Failed to create task", http.StatusInternalServerError)
+ log.Printf("Error creating task: %v", err)
+ return
+ }
+
+ // Force refresh to get updated tasks
+ tasks, err := h.fetchTasks(ctx, true)
+ if err != nil {
+ http.Error(w, "Failed to refresh tasks", http.StatusInternalServerError)
+ log.Printf("Error refreshing tasks: %v", err)
+ return
+ }
+
+ // Fetch projects for the dropdown
+ projects, err := h.todoistClient.GetProjects(ctx)
+ if err != nil {
+ log.Printf("Failed to fetch projects: %v", err)
+ projects = []models.Project{}
+ }
+
+ // Prepare data for template rendering
+ data := struct {
+ Tasks []models.Task
+ Projects []models.Project
+ }{
+ Tasks: tasks,
+ Projects: projects,
+ }
+
+ // Render the updated task list
+ if err := h.templates.ExecuteTemplate(w, "todoist-tasks", data); err != nil {
+ http.Error(w, "Failed to render template", http.StatusInternalServerError)
+ log.Printf("Error rendering todoist tasks template: %v", err)
+ }
+}
+
+// HandleCompleteTask marks a Todoist task as complete
+func (h *Handler) HandleCompleteTask(w http.ResponseWriter, r *http.Request) {
+ ctx := r.Context()
+
+ // Parse form data
+ if err := r.ParseForm(); err != nil {
+ http.Error(w, "Failed to parse form", http.StatusBadRequest)
+ log.Printf("Error parsing form: %v", err)
+ return
+ }
+
+ taskID := r.FormValue("task_id")
+
+ if taskID == "" {
+ http.Error(w, "Missing task_id", http.StatusBadRequest)
+ return
+ }
+
+ // Mark task as complete
+ if err := h.todoistClient.CompleteTask(ctx, taskID); err != nil {
+ http.Error(w, "Failed to complete task", http.StatusInternalServerError)
+ log.Printf("Error completing task: %v", err)
+ return
+ }
+
+ // Return empty response (task will be removed from DOM)
+ w.WriteHeader(http.StatusOK)
+}