From 583f90c5dedf0235fa45557359b0e6e7dd62b0f0 Mon Sep 17 00:00:00 2001 From: Peter Stone Date: Wed, 21 Jan 2026 22:53:37 -1000 Subject: Implement 10 UI/UX improvements and bug fixes - Fix outdated Todoist task URL format (showTask -> app/task) - Fix quick-add date defaulting to tomorrow in evening (client-side JS) - Add tap-to-expand for task descriptions with checkbox completion - Add visual differentiation: overdue (red), future (gray), today (normal) - Sort tasks by urgency: overdue > today-timed > today-allday > future - Keep completed tasks visible with strikethrough until refresh - Add random Unsplash landscape background with content overlay - Hide future tasks behind collapsible fold with count badge - Unified modal menu for Quick Add + Bug Report (Ctrl+K shortcut) - Click task title to edit description in modal Co-Authored-By: Claude Opus 4.5 --- internal/api/interfaces.go | 1 + internal/api/todoist.go | 31 ++++++++++++++++++++++++++++++- 2 files changed, 31 insertions(+), 1 deletion(-) (limited to 'internal/api') diff --git a/internal/api/interfaces.go b/internal/api/interfaces.go index 33bef59..32d0120 100644 --- a/internal/api/interfaces.go +++ b/internal/api/interfaces.go @@ -12,6 +12,7 @@ type TodoistAPI interface { GetTasks(ctx context.Context) ([]models.Task, error) GetProjects(ctx context.Context) ([]models.Project, error) CreateTask(ctx context.Context, content, projectID string, dueDate *time.Time, priority int) (*models.Task, error) + UpdateTask(ctx context.Context, taskID string, updates map[string]interface{}) error CompleteTask(ctx context.Context, taskID string) error Sync(ctx context.Context, syncToken string) (*TodoistSyncResponse, error) } diff --git a/internal/api/todoist.go b/internal/api/todoist.go index b51fffd..14c6c0b 100644 --- a/internal/api/todoist.go +++ b/internal/api/todoist.go @@ -266,7 +266,7 @@ func ConvertSyncItemsToTasks(items []SyncItemResponse, projectMap map[string]str Priority: item.Priority, Completed: false, Labels: item.Labels, - URL: fmt.Sprintf("https://todoist.com/showTask?id=%s", item.ID), + URL: fmt.Sprintf("https://todoist.com/app/task/%s", item.ID), } // Parse added_at @@ -389,6 +389,35 @@ func (c *TodoistClient) CreateTask(ctx context.Context, content, projectID strin return task, nil } +// UpdateTask updates a task with the specified changes +func (c *TodoistClient) UpdateTask(ctx context.Context, taskID string, updates map[string]interface{}) error { + jsonData, err := json.Marshal(updates) + if err != nil { + return fmt.Errorf("failed to marshal updates: %w", err) + } + + url := fmt.Sprintf("%s/tasks/%s", c.baseURL, taskID) + req, err := http.NewRequestWithContext(ctx, "POST", url, bytes.NewBuffer(jsonData)) + if err != nil { + return fmt.Errorf("failed to create request: %w", err) + } + req.Header.Set("Authorization", "Bearer "+c.apiKey) + req.Header.Set("Content-Type", "application/json") + + resp, err := c.httpClient.Do(req) + if err != nil { + return fmt.Errorf("failed to update task: %w", err) + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusNoContent { + body, _ := io.ReadAll(resp.Body) + return fmt.Errorf("todoist API error (status %d): %s", resp.StatusCode, string(body)) + } + + return nil +} + // CompleteTask marks a task as complete in Todoist func (c *TodoistClient) CompleteTask(ctx context.Context, taskID string) error { // Create POST request to close endpoint -- cgit v1.2.3