diff options
Diffstat (limited to 'internal/handlers/handlers.go')
| -rw-r--r-- | internal/handlers/handlers.go | 150 |
1 files changed, 145 insertions, 5 deletions
diff --git a/internal/handlers/handlers.go b/internal/handlers/handlers.go index e4d6457..73a05f0 100644 --- a/internal/handlers/handlers.go +++ b/internal/handlers/handlers.go @@ -78,15 +78,21 @@ func (h *Handler) HandleDashboard(w http.ResponseWriter, r *http.Request) { return } + // Generate random background URL (Unsplash Source API) + // Add timestamp to prevent caching + backgroundURL := fmt.Sprintf("https://source.unsplash.com/1920x1080/?landscape,nature&t=%d", time.Now().UnixNano()) + // Wrap dashboard data with active tab for template data := struct { *models.DashboardData - ActiveTab string - CSRFToken string + ActiveTab string + CSRFToken string + BackgroundURL string }{ DashboardData: dashboardData, ActiveTab: tab, CSRFToken: auth.GetCSRFTokenFromContext(ctx), + BackgroundURL: backgroundURL, } if err := h.templates.ExecuteTemplate(w, "index.html", data); err != nil { @@ -411,7 +417,7 @@ func (h *Handler) convertSyncItemToTask(item api.SyncItemResponse, projectMap ma 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), } if item.AddedAt != "" { @@ -728,6 +734,34 @@ func (h *Handler) HandleCompleteAtom(w http.ResponseWriter, r *http.Request) { return } + // Get task title before removing from cache + var title string + switch source { + case "todoist": + if tasks, err := h.store.GetTasks(); err == nil { + for _, t := range tasks { + if t.ID == id { + title = t.Content + break + } + } + } + case "trello": + if boards, err := h.store.GetBoards(); err == nil { + for _, b := range boards { + for _, c := range b.Cards { + if c.ID == id { + title = c.Name + break + } + } + } + } + } + if title == "" { + title = "Task" + } + // Remove from local cache switch source { case "todoist": @@ -740,8 +774,19 @@ func (h *Handler) HandleCompleteAtom(w http.ResponseWriter, r *http.Request) { } } - // Return 200 OK with empty body to remove the element from DOM - w.WriteHeader(http.StatusOK) + // Return completed task HTML (stays visible with strikethrough until refresh) + w.Header().Set("Content-Type", "text/html") + completedHTML := fmt.Sprintf(`<div class="task-item bg-gray-100 rounded-lg shadow-sm border-l-4 border-gray-300 opacity-60"> + <div class="flex items-start gap-2 sm:gap-3 p-3 sm:p-4"> + <input type="checkbox" checked disabled class="mt-1 h-5 w-5 rounded border-gray-300 text-green-600 cursor-not-allowed flex-shrink-0"> + <span class="text-lg flex-shrink-0">✓</span> + <div class="flex-1 min-w-0"> + <h3 class="text-sm font-medium text-gray-400 line-through break-words">%s</h3> + <div class="text-xs text-green-600 mt-1">Completed</div> + </div> + </div> + </div>`, template.HTMLEscapeString(title)) + w.Write([]byte(completedHTML)) } // HandleUnifiedAdd creates a task in Todoist or a card in Trello from the Quick Add form @@ -875,3 +920,98 @@ func (h *Handler) HandleReportBug(w http.ResponseWriter, r *http.Request) { // Return updated bug list h.HandleGetBugs(w, r) } + +// HandleGetTaskDetail returns task details as HTML for modal +func (h *Handler) HandleGetTaskDetail(w http.ResponseWriter, r *http.Request) { + id := r.URL.Query().Get("id") + source := r.URL.Query().Get("source") + + if id == "" || source == "" { + http.Error(w, "Missing id or source", http.StatusBadRequest) + return + } + + var title, description string + switch source { + case "todoist": + tasks, err := h.store.GetTasks() + if err == nil { + for _, t := range tasks { + if t.ID == id { + title = t.Content + description = t.Description + break + } + } + } + case "trello": + boards, err := h.store.GetBoards() + if err == nil { + for _, b := range boards { + for _, c := range b.Cards { + if c.ID == id { + title = c.Name + // Card model doesn't store description, leave empty + description = "" + break + } + } + } + } + } + + w.Header().Set("Content-Type", "text/html") + html := fmt.Sprintf(` + <div class="p-4"> + <h3 class="font-semibold text-gray-900 mb-3">%s</h3> + <form hx-post="/tasks/update" hx-swap="none" hx-on::after-request="if(event.detail.successful) { closeTaskModal(); htmx.trigger(document.body, 'refresh-tasks'); }"> + <input type="hidden" name="id" value="%s"> + <input type="hidden" name="source" value="%s"> + <label class="block text-sm font-medium text-gray-700 mb-1">Description</label> + <textarea name="description" class="w-full border border-gray-300 rounded-lg px-3 py-2 text-sm mb-3 h-32">%s</textarea> + <button type="submit" class="w-full bg-primary-600 hover:bg-primary-700 text-white px-4 py-2 rounded-lg text-sm font-medium">Save</button> + </form> + </div> + `, template.HTMLEscapeString(title), template.HTMLEscapeString(id), template.HTMLEscapeString(source), template.HTMLEscapeString(description)) + w.Write([]byte(html)) +} + +// HandleUpdateTask updates a task description +func (h *Handler) HandleUpdateTask(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + + if err := r.ParseForm(); err != nil { + http.Error(w, "Failed to parse form", http.StatusBadRequest) + return + } + + id := r.FormValue("id") + source := r.FormValue("source") + description := r.FormValue("description") + + if id == "" || source == "" { + http.Error(w, "Missing id or source", http.StatusBadRequest) + return + } + + var err error + switch source { + case "todoist": + updates := map[string]interface{}{"description": description} + err = h.todoistClient.UpdateTask(ctx, id, updates) + case "trello": + updates := map[string]interface{}{"desc": description} + err = h.trelloClient.UpdateCard(ctx, id, updates) + default: + http.Error(w, "Unknown source", http.StatusBadRequest) + return + } + + if err != nil { + http.Error(w, "Failed to update task", http.StatusInternalServerError) + log.Printf("Error updating task: %v", err) + return + } + + w.WriteHeader(http.StatusOK) +} |
