Show the duplicate invoice form in a dialog

Had to add a new hidden field to the form to know whether, when the
request is HTMx-triggered, to refresh the page, as i do when duplicating
from the index, or redirect the client to the new invoice’s view page,
but only if i was duplicating from that same page, not the index.

Since i now have to target main when redirecting to the view page, so
i had to add a location structure with the required json fields and all
that, when “refreshing” i actually tell HTMx to open the index page
again, which seems faster, now that i am used to boosted links.
This commit is contained in:
jordi fita mas 2023-04-04 14:39:55 +02:00
parent b6668e72ef
commit dbfa58699c
8 changed files with 49 additions and 8 deletions

23
pkg/htmx.go Normal file
View File

@ -0,0 +1,23 @@
package pkg
import (
"encoding/json"
"net/http"
)
type HTMxLocation struct {
Path string `json:"path"`
Target string `json:"target"`
}
func IsHTMxRequest(r *http.Request) bool {
return r.Header.Get("HX-Request") == "true"
}
func MustMarshalHTMxLocation(location *HTMxLocation) string {
data, err := json.Marshal(location)
if err != nil {
panic(err)
}
return string(data)
}

View File

@ -217,6 +217,7 @@ func ServeInvoice(w http.ResponseWriter, r *http.Request, params httprouter.Para
if invoiceToDuplicate := r.URL.Query().Get("duplicate"); invoiceToDuplicate != "" { if invoiceToDuplicate := r.URL.Query().Get("duplicate"); invoiceToDuplicate != "" {
form.MustFillFromDatabase(r.Context(), conn, invoiceToDuplicate) form.MustFillFromDatabase(r.Context(), conn, invoiceToDuplicate)
form.InvoiceStatus.Selected = []string{"created"} form.InvoiceStatus.Selected = []string{"created"}
form.Location.Val = r.URL.Query().Get("location")
} }
form.Date.Val = time.Now().Format("2006-01-02") form.Date.Val = time.Now().Format("2006-01-02")
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
@ -456,12 +457,21 @@ func HandleAddInvoice(w http.ResponseWriter, r *http.Request, _ httprouter.Param
return return
} }
slug := conn.MustGetText(r.Context(), "", "select add_invoice($1, $2, $3, $4, $5, $6, $7)", company.Id, form.Date, form.Customer, form.Notes, form.PaymentMethod, form.Tags, NewInvoiceProductArray(form.Products)) slug := conn.MustGetText(r.Context(), "", "select add_invoice($1, $2, $3, $4, $5, $6, $7)", company.Id, form.Date, form.Customer, form.Notes, form.PaymentMethod, form.Tags, NewInvoiceProductArray(form.Products))
viewUrl := companyURI(company, "/invoices/"+slug)
if IsHTMxRequest(r) { if IsHTMxRequest(r) {
w.Header().Set("HX-Trigger", "closeModal") w.Header().Set("HX-Trigger", "closeModal")
w.Header().Set("HX-Refresh", "true") location := &HTMxLocation{
Target: "main",
}
if form.Location.Val == "view" {
location.Path = viewUrl
} else {
location.Path = companyURI(company, "/invoices")
}
w.Header().Set("HX-Location", MustMarshalHTMxLocation(location))
w.WriteHeader(http.StatusNoContent) w.WriteHeader(http.StatusNoContent)
} else { } else {
http.Redirect(w, r, companyURI(company, "/invoices/"+slug), http.StatusSeeOther) http.Redirect(w, r, viewUrl, http.StatusSeeOther)
} }
} }
@ -529,6 +539,7 @@ type invoiceForm struct {
locale *Locale locale *Locale
company *Company company *Company
Number string Number string
Location *InputField
InvoiceStatus *SelectField InvoiceStatus *SelectField
Customer *SelectField Customer *SelectField
Date *InputField Date *InputField
@ -542,6 +553,10 @@ func newInvoiceForm(ctx context.Context, conn *Conn, locale *Locale, company *Co
return &invoiceForm{ return &invoiceForm{
locale: locale, locale: locale,
company: company, company: company,
Location: &InputField{
Name: "redirect",
Type: "hidden",
},
InvoiceStatus: &SelectField{ InvoiceStatus: &SelectField{
Name: "invoice_status", Name: "invoice_status",
Required: true, Required: true,
@ -584,6 +599,7 @@ func (form *invoiceForm) Parse(r *http.Request) error {
if err := r.ParseForm(); err != nil { if err := r.ParseForm(); err != nil {
return err return err
} }
form.Location.FillValue(r)
form.InvoiceStatus.FillValue(r) form.InvoiceStatus.FillValue(r)
form.Customer.FillValue(r) form.Customer.FillValue(r)
form.Date.FillValue(r) form.Date.FillValue(r)

View File

@ -87,7 +87,3 @@ func MethodOverrider(next http.Handler) http.Handler {
next.ServeHTTP(w, r) next.ServeHTTP(w, r)
}) })
} }
func IsHTMxRequest(r *http.Request) bool {
return r.Header.Get("HX-Request") == "true"
}

View File

@ -21,6 +21,7 @@
{{ csrfToken }} {{ csrfToken }}
{{ with .Form -}} {{ with .Form -}}
{{ template "hidden-field" .Location }}
{{ template "select-field" .Customer }} {{ template "select-field" .Customer }}
{{ template "hidden-field" .Date }} {{ template "hidden-field" .Date }}
{{ template "tags-field" .Tags }} {{ template "tags-field" .Tags }}

View File

@ -113,7 +113,9 @@
</a> </a>
</li> </li>
<li role="presentation"> <li role="presentation">
<a role="menuitem" href="{{ companyURI "/invoices/new"}}?duplicate={{ .Slug }}"> <a role="menuitem" href="{{ companyURI "/invoices/new"}}?duplicate={{ .Slug }}"
data-hx-push-url="false" data-hx-swap="beforeend" data-hx-boost="true"
>
<i class="ri-file-copy-line"></i> <i class="ri-file-copy-line"></i>
{{( pgettext "Duplicate" "action" )}} {{( pgettext "Duplicate" "action" )}}
</a> </a>

View File

@ -21,6 +21,7 @@
{{ csrfToken }} {{ csrfToken }}
{{ with .Form -}} {{ with .Form -}}
{{ template "hidden-field" .Location }}
{{ template "hidden-select-field" .InvoiceStatus }} {{ template "hidden-select-field" .InvoiceStatus }}
{{ template "select-field" .Customer }} {{ template "select-field" .Customer }}
{{ template "input-field" .Date }} {{ template "input-field" .Date }}

View File

@ -25,6 +25,7 @@
{{ csrfToken }} {{ csrfToken }}
{{- with .Form }} {{- with .Form }}
{{ template "hidden-field" .Location }}
{{ template "hidden-select-field" .Customer }} {{ template "hidden-select-field" .Customer }}
{{ template "hidden-field" .Date }} {{ template "hidden-field" .Date }}
{{ template "hidden-field" .Notes }} {{ template "hidden-field" .Notes }}

View File

@ -12,7 +12,8 @@
</p> </p>
<p> <p>
<a class="button primary" <a class="button primary"
href="{{ companyURI "/invoices/new"}}?duplicate={{ .Slug }}">{{( pgettext "Duplicate" "action" )}}</a> data-hx-push-url="false" data-hx-swap="beforeend" data-hx-boost="true"
href="{{ companyURI "/invoices/new"}}?duplicate={{ .Slug }}&amp;location=view">{{( pgettext "Duplicate" "action" )}}</a>
<a class="button primary" <a class="button primary"
data-hx-push-url="false" data-hx-swap="beforeend" data-hx-boost="true" data-hx-push-url="false" data-hx-swap="beforeend" data-hx-boost="true"
href="{{ companyURI "/invoices/"}}{{ .Slug }}/edit">{{( pgettext "Edit" "action" )}}</a> href="{{ companyURI "/invoices/"}}{{ .Slug }}/edit">{{( pgettext "Edit" "action" )}}</a>