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:
parent
b6668e72ef
commit
dbfa58699c
|
@ -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)
|
||||||
|
}
|
|
@ -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)
|
||||||
|
|
|
@ -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"
|
|
||||||
}
|
|
||||||
|
|
|
@ -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 }}
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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 }}
|
||||||
|
|
|
@ -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 }}
|
||||||
|
|
|
@ -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 }}&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>
|
||||||
|
|
Loading…
Reference in New Issue