Put new invoice and edit invoice forms into a dialog
In this case i have to use the same id for the dialog content in all pages because, for now, there are a couple of forms that need to replace it on submit—the new/edit form and the product selection form. Unfortunately, HTMx does not have support for `formaction` attribute at this point, so i had to use the workaround described in [0]. [0] https://github.com/bigskysoftware/htmx/issues/623
This commit is contained in:
parent
d1852a9703
commit
5717a5b9ed
|
@ -393,7 +393,7 @@ func mustRenderNewInvoiceForm(w http.ResponseWriter, r *http.Request, form *invo
|
|||
locale := getLocale(r)
|
||||
form.Customer.EmptyLabel = gettext("Select a customer to bill.", locale)
|
||||
page := newNewInvoicePage(form, r)
|
||||
mustRenderAppTemplate(w, r, "invoices/new.gohtml", page)
|
||||
mustRenderModalTemplate(w, r, "invoices/new.gohtml", page)
|
||||
}
|
||||
|
||||
func mustRenderNewInvoiceProductsForm(w http.ResponseWriter, r *http.Request, action string, form *invoiceForm) {
|
||||
|
@ -404,7 +404,7 @@ func mustRenderNewInvoiceProductsForm(w http.ResponseWriter, r *http.Request, ac
|
|||
Form: form,
|
||||
Products: mustGetProductChoices(r.Context(), conn, company),
|
||||
}
|
||||
mustRenderAppTemplate(w, r, "invoices/products.gohtml", page)
|
||||
mustRenderModalTemplate(w, r, "invoices/products.gohtml", page)
|
||||
}
|
||||
|
||||
func mustGetProductChoices(ctx context.Context, conn *Conn, company *Company) []*productChoice {
|
||||
|
@ -457,8 +457,14 @@ func HandleAddInvoice(w http.ResponseWriter, r *http.Request, _ httprouter.Param
|
|||
return
|
||||
}
|
||||
slug := conn.MustGetText(r.Context(), "", "select add_invoice($1, $2, $3, $4, $5, $6, $7, $8)", company.Id, form.Number, form.Date, form.Customer, form.Notes, form.PaymentMethod, form.Tags, NewInvoiceProductArray(form.Products))
|
||||
if IsHTMxRequest(r) {
|
||||
w.Header().Set("HX-Trigger", "closeModal")
|
||||
w.Header().Set("HX-Refresh", "true")
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
} else {
|
||||
http.Redirect(w, r, companyURI(company, "/invoices/"+slug), http.StatusSeeOther)
|
||||
}
|
||||
}
|
||||
|
||||
func HandleNewInvoiceAction(w http.ResponseWriter, r *http.Request, params httprouter.Params) {
|
||||
switch params[0].Value {
|
||||
|
@ -832,7 +838,12 @@ func HandleUpdateInvoice(w http.ResponseWriter, r *http.Request, params httprout
|
|||
if slug == "" {
|
||||
http.NotFound(w, r)
|
||||
}
|
||||
if IsHTMxRequest(r) {
|
||||
w.Header().Set("HX-Refresh", "true")
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
} else {
|
||||
http.Redirect(w, r, companyURI(mustGetCompany(r), "/invoices"), http.StatusSeeOther)
|
||||
}
|
||||
} else {
|
||||
slug := params[0].Value
|
||||
if !form.Validate() {
|
||||
|
@ -845,9 +856,15 @@ func HandleUpdateInvoice(w http.ResponseWriter, r *http.Request, params httprout
|
|||
http.NotFound(w, r)
|
||||
return
|
||||
}
|
||||
if IsHTMxRequest(r) {
|
||||
w.Header().Set("HX-Trigger", "closeModal")
|
||||
w.Header().Set("HX-Refresh", "true")
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
} else {
|
||||
http.Redirect(w, r, companyURI(company, "/invoices/"+slug), http.StatusSeeOther)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func ServeEditInvoice(w http.ResponseWriter, r *http.Request, params httprouter.Params) {
|
||||
conn := getConn(r)
|
||||
|
@ -879,7 +896,7 @@ func newEditInvoicePage(slug string, form *invoiceForm, r *http.Request) *editIn
|
|||
|
||||
func mustRenderEditInvoiceForm(w http.ResponseWriter, r *http.Request, slug string, form *invoiceForm) {
|
||||
page := newEditInvoicePage(slug, form, r)
|
||||
mustRenderAppTemplate(w, r, "invoices/edit.gohtml", page)
|
||||
mustRenderModalTemplate(w, r, "invoices/edit.gohtml", page)
|
||||
}
|
||||
|
||||
func HandleEditInvoiceAction(w http.ResponseWriter, r *http.Request, params httprouter.Params) {
|
||||
|
|
|
@ -421,6 +421,19 @@ htmx.onLoad((target) => {
|
|||
}
|
||||
})
|
||||
|
||||
htmx.on('htmx:configRequest', function(e) {
|
||||
const element = e.detail.elt;
|
||||
if (element && element.nodeName === 'FORM') {
|
||||
let submitter = e.detail.triggeringEvent.submitter;
|
||||
if (submitter) {
|
||||
const action = submitter.attributes['formaction'];
|
||||
if (action && action.value) {
|
||||
e.detail.path = action.value;
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
htmx.on('closeModal', () => {
|
||||
const openDialog = document.querySelector('dialog[open]');
|
||||
if (!openDialog) {
|
||||
|
|
|
@ -15,9 +15,9 @@
|
|||
|
||||
{{ define "content" }}
|
||||
{{- /*gotype: dev.tandem.ws/tandem/numerus/pkg.editInvoicePage*/ -}}
|
||||
<section class="dialog-content">
|
||||
<section class="dialog-content" id="invoice-dialog-content" data-hx-target="this">
|
||||
<h2>{{ printf (pgettext "Edit Invoice “%s”" "title") .Number }}</h2>
|
||||
<form method="POST" action="{{ companyURI "/invoices/" }}{{ .Slug }}">
|
||||
<form method="POST" action="{{ companyURI "/invoices/" }}{{ .Slug }}" data-hx-boost="true" data-hx-select="#invoice-dialog-content">
|
||||
{{ csrfToken }}
|
||||
|
||||
{{ with .Form -}}
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
name="action" value="download"
|
||||
>{{( pgettext "Download invoices" "action" )}}</button>
|
||||
<a class="primary button"
|
||||
data-hx-push-url="false" data-hx-swap="beforeend" data-hx-boost="true"
|
||||
href="{{ companyURI "/invoices/new" }}">{{( pgettext "New invoice" "action" )}}</a>
|
||||
</p>
|
||||
</form>
|
||||
|
@ -68,7 +69,7 @@
|
|||
<td>
|
||||
<details class="invoice-status menu">
|
||||
<summary class="invoice-status-{{ .Status }}">{{ .StatusLabel }}</summary>
|
||||
<form action="{{companyURI "/invoices/"}}{{ .Slug }}" method="POST">
|
||||
<form action="{{companyURI "/invoices/"}}{{ .Slug }}" method="POST" data-hx-boost="true">
|
||||
{{ csrfToken }}
|
||||
{{ putMethod }}
|
||||
<input type="hidden" name="quick" value="status">
|
||||
|
@ -104,7 +105,9 @@
|
|||
<summary><i class="ri-more-line"></i></summary>
|
||||
<ul role="menu" class="action-menu">
|
||||
<li role="presentation">
|
||||
<a role="menuitem" href="{{ companyURI "/invoices"}}/{{ .Slug }}/edit">
|
||||
<a role="menuitem" href="{{ companyURI "/invoices"}}/{{ .Slug }}/edit"
|
||||
data-hx-push-url="false" data-hx-swap="beforeend" data-hx-boost="true"
|
||||
>
|
||||
<i class="ri-edit-line"></i>
|
||||
{{( pgettext "Edit" "action" )}}
|
||||
</a>
|
||||
|
|
|
@ -15,9 +15,9 @@
|
|||
|
||||
{{ define "content" }}
|
||||
{{- /*gotype: dev.tandem.ws/tandem/numerus/pkg.newInvoicePage*/ -}}
|
||||
<section class="dialog-content">
|
||||
<section class="dialog-content" id="invoice-dialog-content" data-hx-target="this">
|
||||
<h2>{{(pgettext "New Invoice" "title")}}</h2>
|
||||
<form method="POST" action="{{ companyURI "/invoices" }}">
|
||||
<form method="POST" action="{{ companyURI "/invoices" }}" data-hx-boost="true" data-hx-select="#invoice-dialog-content">
|
||||
{{ csrfToken }}
|
||||
|
||||
{{ with .Form -}}
|
||||
|
|
|
@ -19,9 +19,9 @@
|
|||
|
||||
{{ define "content" }}
|
||||
{{- /*gotype: dev.tandem.ws/tandem/numerus/pkg.newInvoiceProductsPage*/ -}}
|
||||
<section class="dialog-content">
|
||||
<section class="dialog-content" id="invoice-dialog-content" data-hx-target="this">
|
||||
<h2>{{(pgettext "Add Products to Invoice" "title")}}</h2>
|
||||
<form method="POST" action="{{ .Action }}">
|
||||
<form method="POST" action="{{ .Action }}" data-hx-boost="true" data-hx-select="#invoice-dialog-content">
|
||||
{{ csrfToken }}
|
||||
|
||||
{{- with .Form }}
|
||||
|
|
Loading…
Reference in New Issue