From bbf12fc441ca36c423e865107d34df178e3d26de Mon Sep 17 00:00:00 2001 From: Peter Stone Date: Mon, 26 Jan 2026 17:00:30 -1000 Subject: Fix multiple UI issues and shopping completion bug - #54: Fix shopping item completion - now works for all sources (trello, plantoeat, user) with state stored in local DB - #48: Hide 12:00am times in timeline (all-day items) - #49: Remove "Task" type label from timeline items for cleaner UI - #51: Combine multiple PlanToEat meals for same date+mealType - #52: Change Conditions tab to standard link to standalone page Co-Authored-By: Claude Opus 4.5 --- internal/handlers/handlers.go | 58 ++++++++++++++++++++++--------------------- 1 file changed, 30 insertions(+), 28 deletions(-) (limited to 'internal/handlers/handlers.go') diff --git a/internal/handlers/handlers.go b/internal/handlers/handlers.go index 1e376b5..a1a12e7 100644 --- a/internal/handlers/handlers.go +++ b/internal/handlers/handlers.go @@ -1179,7 +1179,8 @@ func (h *Handler) HandleShoppingToggle(w http.ResponseWriter, r *http.Request) { source := r.FormValue("source") checked := r.FormValue("checked") == "true" - if source == "user" { + switch source { + case "user": var userID int64 if _, err := fmt.Sscanf(id, "user-%d", &userID); err != nil { JSONError(w, http.StatusBadRequest, "Invalid user item ID", err) @@ -1189,35 +1190,30 @@ func (h *Handler) HandleShoppingToggle(w http.ResponseWriter, r *http.Request) { JSONError(w, http.StatusInternalServerError, "Failed to toggle item", err) return } + case "trello", "plantoeat": + // Store checked state locally for external sources + if err := h.store.SetShoppingItemChecked(source, id, checked); err != nil { + JSONError(w, http.StatusInternalServerError, "Failed to toggle item", err) + return + } + default: + JSONError(w, http.StatusBadRequest, "Unknown source", nil) + return } - // Note: Trello and PlanToEat toggle would need their own API calls - - // Return updated item HTML - checkedClass := "" - checkedAttr := "" - textClass := "text-white" - if checked { - checkedClass = "opacity-50" - checkedAttr = "checked" - textClass = "line-through text-white/40" - } - html := fmt.Sprintf(`
  • - - %s - user -
  • `, checkedClass, checkedAttr, template.HTMLEscapeString(id), template.HTMLEscapeString(source), !checked, textClass, template.HTMLEscapeString(r.FormValue("name"))) - HTMLString(w, html) + + // Return refreshed shopping tab + stores := h.aggregateShoppingLists(r.Context()) + HTMLResponse(w, h.templates, "shopping-tab", struct{ Stores []models.ShoppingStore }{stores}) } // aggregateShoppingLists combines Trello, PlanToEat, and user shopping items by store func (h *Handler) aggregateShoppingLists(ctx context.Context) []models.ShoppingStore { storeMap := make(map[string]map[string][]models.UnifiedShoppingItem) + // Fetch locally stored checked states for external sources + trelloChecks, _ := h.store.GetShoppingItemChecks("trello") + plantoeatChecks, _ := h.store.GetShoppingItemChecks("plantoeat") + // 1. Fetch Trello "Shopping" board cards boards, err := h.store.GetBoards() if err != nil { @@ -1237,10 +1233,11 @@ func (h *Handler) aggregateShoppingLists(ctx context.Context) []models.ShoppingS } item := models.UnifiedShoppingItem{ - ID: card.ID, - Name: card.Name, - Store: storeName, - Source: "trello", + ID: card.ID, + Name: card.Name, + Store: storeName, + Source: "trello", + Checked: trelloChecks[card.ID], } storeMap[storeName][""] = append(storeMap[storeName][""], item) } @@ -1265,6 +1262,11 @@ func (h *Handler) aggregateShoppingLists(ctx context.Context) []models.ShoppingS storeMap[storeName] = make(map[string][]models.UnifiedShoppingItem) } + // Use locally stored check state if available, otherwise use scraped state + checked := item.Checked + if localChecked, ok := plantoeatChecks[item.ID]; ok { + checked = localChecked + } unified := models.UnifiedShoppingItem{ ID: item.ID, Name: item.Name, @@ -1272,7 +1274,7 @@ func (h *Handler) aggregateShoppingLists(ctx context.Context) []models.ShoppingS Category: item.Category, Store: storeName, Source: "plantoeat", - Checked: item.Checked, + Checked: checked, } storeMap[storeName][item.Category] = append(storeMap[storeName][item.Category], unified) } -- cgit v1.2.3