From 6900291685d5c73e335b52db77ac09b22d058b56 Mon Sep 17 00:00:00 2001 From: nic Date: Wed, 23 Apr 2025 16:43:52 -0400 Subject: [PATCH] fix: logic before multi invoice just re-ran invoice query after changing invoice status; with multi invoices this is bad; created individual invoice card to update just single invoices when changing statuses --- internal/handlers/web/invoices.go | 81 ++++++++++++++++++- templates/partials/invoice_card.html | 54 +++++++++++++ .../partials/invoice_search_results.html | 81 +------------------ 3 files changed, 136 insertions(+), 80 deletions(-) create mode 100644 templates/partials/invoice_card.html diff --git a/internal/handlers/web/invoices.go b/internal/handlers/web/invoices.go index 749f20c..ff1d4cc 100644 --- a/internal/handlers/web/invoices.go +++ b/internal/handlers/web/invoices.go @@ -160,6 +160,9 @@ func handleSingleInvoice(w http.ResponseWriter, invoiceID string, session *api.S // Add the buttons to display invoice["buttons"] = getInvoiceStatusButtons(invoice["id"].(string), invoice["status"].(string)) + // Add the search term to the template data + invoice["SearchTerm"] = invoiceID + err = tmpl.ExecuteTemplate(w, "invoice_search_results", invoice) if err != nil { log.Printf("Error executing template: %v", err) @@ -192,6 +195,10 @@ func handleMultipleInvoices(w http.ResponseWriter, invoiceIDs []string, session // Add status buttons invoice["buttons"] = getInvoiceStatusButtons(invoice["id"].(string), invoice["status"].(string)) + // Mark this as part of a multiple invoice view + invoice["MultipleInvoices"] = true + invoice["SearchTerm"] = originalSearchTerm + invoices = append(invoices, invoice) } @@ -338,7 +345,79 @@ func UpdateInvoiceStatusHandler(w http.ResponseWriter, r *http.Request) { return } - mockReq, _ := http.NewRequest("GET", fmt.Sprintf("?search=%s", invoiceID), nil) + // Check if it's a request for a single invoice update within a multi-invoice view + isPartialUpdate := r.URL.Query().Get("partial") == "true" + if isPartialUpdate { + renderSingleInvoiceUpdate(w, invoiceID, session, r) + return + } + + // Get the original search term from request headers or query parameters + originalSearch := r.Header.Get("X-Original-Search") + if originalSearch == "" { + // If not in the header, check query parameters + originalSearch = r.URL.Query().Get("original_search") + } + + // If we have the original search term with multiple IDs, use it to preserve the multi-invoice view + // Otherwise, fall back to just showing the updated invoice + searchQuery := invoiceID + if originalSearch != "" { + invoiceIDs := parseInvoiceIDs(originalSearch) + if len(invoiceIDs) > 1 { + searchQuery = originalSearch + } + } + + // Re-run the search with either the original search term or just the updated invoice ID + mockReq, _ := http.NewRequest("GET", fmt.Sprintf("?search=%s", searchQuery), nil) mockReq = mockReq.WithContext(r.Context()) handleInvoiceSearch(w, mockReq, session) } + +// renderSingleInvoiceUpdate fetches a single invoice and renders just its card with hx-swap-oob +// for efficient in-place updates within a multi-invoice view +func renderSingleInvoiceUpdate(w http.ResponseWriter, invoiceID string, session *api.Session, r *http.Request) { + log.Printf("Rendering single invoice update for: %s", invoiceID) + + // Get the original search term for maintaining context in buttons + originalSearch := r.Header.Get("X-Original-Search") + if originalSearch == "" { + originalSearch = r.URL.Query().Get("original_search") + } + + // Fetch just the updated invoice + invoice, err := session.GetInvoice(invoiceID) + if err != nil { + log.Printf("Error fetching updated invoice: %v", err) + http.Error(w, fmt.Sprintf("Error fetching invoice: %v", err), http.StatusInternalServerError) + return + } + + if invoice == nil { + log.Printf("No invoice found for update: %s", invoiceID) + http.Error(w, "Invoice not found", http.StatusNotFound) + return + } + + // Format the invoice ID if needed + if id, ok := invoice["id"].(float64); ok { + invoice["id"] = fmt.Sprintf("%.0f", id) + } + + // Add status buttons + invoice["buttons"] = getInvoiceStatusButtons(invoice["id"].(string), invoice["status"].(string)) + + // Add search term and set flag for partial update + invoice["SearchTerm"] = originalSearch + invoice["PartialUpdate"] = true + invoice["InvoiceID"] = invoiceID + + // Render only the specific invoice card with hx-swap-oob + tmpl := root.WebTemplates + err = tmpl.ExecuteTemplate(w, "invoice_card", invoice) + if err != nil { + log.Printf("Error executing template for partial update: %v", err) + http.Error(w, "Internal Server Error", http.StatusInternalServerError) + } +} diff --git a/templates/partials/invoice_card.html b/templates/partials/invoice_card.html new file mode 100644 index 0000000..0001ac4 --- /dev/null +++ b/templates/partials/invoice_card.html @@ -0,0 +1,54 @@ +{{define "invoice_card"}} +
+
+

Invoice #{{.invoiceNumber}}

+
{{.status}}
+
+ +
+
+ {{with .customer}}

Customer: {{.name}}

{{end}} + {{with .job}}

Job: {{.name}}

{{end}} + {{/* Show location only in single invoice view */}} + {{if not .MultipleInvoices}} + {{with .location}}

Location: {{.name}}

{{end}} + {{end}} +

Total: ${{.totalPrice}}

+ + {{/* Show items only in single invoice view */}} + {{if not .MultipleInvoices}} + {{if .items}} +
+
Items
+
    + {{range .items}} +
  • {{.description}} - ${{.totalPrice}}
  • + {{end}} +
+
+ {{end}} + {{end}} +
+ +
+
+ {{range .buttons}} + + {{end}} +
+
+
+
+{{end}} \ No newline at end of file diff --git a/templates/partials/invoice_search_results.html b/templates/partials/invoice_search_results.html index b91e8b9..d3fe2c0 100644 --- a/templates/partials/invoice_search_results.html +++ b/templates/partials/invoice_search_results.html @@ -23,91 +23,14 @@ {{range .Invoices}} -
-
-

Invoice #{{.invoiceNumber}}

-
{{.status}}
-
- -
-
- {{with .customer}}

Customer: {{.name}}

{{end}} - {{with .job}}

Job: {{.name}}

{{end}} -

Total: ${{.totalPrice}}

-
- -
-
- {{range .buttons}} - - {{end}} -
-
-
-
+ {{template "invoice_card" .}} {{end}} {{else if .invoiceNumber}}

Invoice Details

- -
-
-

Invoice #{{.invoiceNumber}}

-
{{.status}}
-
- -
-
- {{with .customer}}

Customer: {{.name}}

{{end}} - {{with .job}}

Job: {{.name}}

{{end}} - {{with .location}}

Location: {{.name}}

{{end}} -

Total Price: ${{.totalPrice}}

- - {{if .items}} -
-
Items
-
    - {{range .items}} -
  • {{.description}} - ${{.totalPrice}}
  • - {{end}} -
-
- {{end}} -
- -
-
- {{range .buttons}} - - {{end}} -
-
-
-
+ {{template "invoice_card" .}}
{{else}}