progress on pay button.

This commit is contained in:
2024-03-11 08:20:33 -07:00
parent fb2eefc9ac
commit 9e9eda343a
5 changed files with 109 additions and 35 deletions

View File

@@ -98,7 +98,8 @@
(str " bg-white dark:bg-gray-600 border-gray-300 dark:border-gray-700 text-gray-500 hover:text-gray-800 dark:text-gray-400 dark:hover:text-gray-100 font-medium border border-gray-300 dark:border-gray-700"))) (str " bg-white dark:bg-gray-600 border-gray-300 dark:border-gray-700 text-gray-500 hover:text-gray-800 dark:text-gray-400 dark:hover:text-gray-100 font-medium border border-gray-300 dark:border-gray-700")))
[:div.htmx-indicator.flex.items-center [:div.htmx-indicator.flex.items-center
(svg/spinner {:class "inline w-4 h-4 text-white"}) (svg/spinner {:class "inline w-4 h-4 text-white"})
[:div.ml-3 "Loading..."]] (when (not (:minimal-loading? params))
[:div.ml-3 "Loading..."])]
(into [:div.htmx-indicator-hidden.inline-flex.gap-2.items-center.justify-center] children)]) (into [:div.htmx-indicator-hidden.inline-flex.gap-2.items-center.justify-center] children)])
(defn a-button- [params & children] (defn a-button- [params & children]

View File

@@ -215,13 +215,14 @@
identity identity
request) request)
:headers {"hx-push-url" (str "?" (url/map->query :headers {"hx-push-url" (str "?" (url/map->query
(if (:query-schema grid-spec) (dissoc (if (:query-schema grid-spec)
(update (filter-vals #(not (nil? %)) (update (filter-vals #(not (nil? %))
(m/encode (:query-schema grid-spec) (m/encode (:query-schema grid-spec)
(:query-params request) (:query-params request)
main-transformer)) main-transformer))
"sort" sort->query) "sort" sort->query)
(unparse-query-params (:parsed-query-params request)))))} (unparse-query-params (:parsed-query-params request)))
"selected" "all-selected")))} ;; TODO seems hacky to special case selected and all-selected here
:oob (when-let [oob-render (:oob-render grid-spec)] :oob (when-let [oob-render (:oob-render grid-spec)]
(oob-render request))))) (oob-render request)))))
(wrap-trim-client-ids) (wrap-trim-client-ids)
@@ -242,7 +243,11 @@
:client (:client request) :client (:client request)
:identity (:identity request)} :identity (:identity request)}
(apply com/breadcrumbs {} (:breadcrumbs grid-spec)) (apply com/breadcrumbs {} (:breadcrumbs grid-spec))
[:div {:x-data (hx/json {:selected [] :all_selected false})} [:div {:x-data (hx/json {:selected [] :all_selected false})
"x-bind:hx-vals" "JSON.stringify({selected: $data.selected, 'all-selected': $data.all_selected})"
:x-init "$watch('selected', s=> $dispatch('selectedChanged', {selected: s, all_selected: all_selected}) );
$watch('all_selected', a=>$dispatch('selectedChanged', {selected: selected, all_selected: a}))"}
(table* grid-spec (table* grid-spec
identity identity
request)]) request)])

View File

@@ -50,7 +50,7 @@
[:div {:id "exact-match-id-tag"}])) [:div {:id "exact-match-id-tag"}]))
(defn filters [request] (defn filters [request]
[:form#payment-filters {"hx-trigger" "change delay:500ms, keyup changed from:.hot-filter delay:1000ms" [:form#invoice-filters {"hx-trigger" "change delay:500ms, keyup changed from:.hot-filter delay:1000ms"
"hx-get" (bidi/path-for ssr-routes/only-routes "hx-get" (bidi/path-for ssr-routes/only-routes
::route/table) ::route/table)
"hx-target" "#entity-table" "hx-target" "#entity-table"
@@ -264,11 +264,10 @@
[:start {:optional true :default 0} [:maybe :int]] [:start {:optional true :default 0} [:maybe :int]]
[:amount-gte {:optional true} [:maybe :double]] [:amount-gte {:optional true} [:maybe :double]]
[:amount-lte {:optional true} [:maybe :double]] [:amount-lte {:optional true} [:maybe :double]]
[:payment-type {:optional true} [:maybe (ref->enum-schema "payment-type")]]
[:vendor {:optional true :default nil} [:maybe [:entity-map {:pull [:db/id :vendor/name]}]]] [:vendor {:optional true :default nil} [:maybe [:entity-map {:pull [:db/id :vendor/name]}]]]
[:check-number {:optional true} [:maybe [:string {:decode/string strip}]]] [:check-number {:optional true} [:maybe [:string {:decode/string strip}]]]
[:invoice-number {:optional true} [:maybe [:string {:decode/string strip}]]] [:invoice-number {:optional true} [:maybe [:string {:decode/string strip}]]]
[:status {:optional true} [:maybe (ref->enum-schema "payment-status")]] [:status {:optional true} [:maybe (ref->enum-schema "invoice-status")]]
[:exact-match-id {:optional true} [:maybe entity-id]] [:exact-match-id {:optional true} [:maybe entity-id]]
[:all-selected {:optional true :default nil} [:maybe :boolean]] [:all-selected {:optional true :default nil} [:maybe :boolean]]
[:selected {:optional true :default nil} [:maybe [:vector {:coerce? true} [:selected {:optional true :default nil} [:maybe [:vector {:coerce? true}
@@ -283,6 +282,75 @@
{:start " "} {:start " "}
main-transformer)) main-transformer))
(defn selected->ids [request params]
(let [all-selected (:all-selected params)
selected (:selected params)
ids (cond
all-selected
(:ids (fetch-ids (dc/db conn) (-> request
(assoc :query-params params)
(assoc-in [:query-params :start] 0)
(assoc-in [:query-params :per-page] 250))))
:else
selected)]
ids))
(defn pay-button* [params]
(let [ids (:ids params)
selected-client-count (if (seq ids)
(ffirst
(dc/q '[:find (count ?c)
:in $ [?i ...]
:where [?i :invoice/client ?c]]
(dc/db conn)
ids))
0)]
[:div {:hx-target "this"
:x-data (hx/json {:popper nil
:hovering false})
"x-init" "popper = Popper.createPopper($refs.button, $refs.tooltip, {placement: 'bottom', strategy: 'fixed', modifiers: [{name: 'preventOverflow'}, {name: 'offset', options: {offset: [0, 10]}}]});"}
(com/button {:color :primary
:disabled (or (= (count (:ids params)) 0)
(not= 1 selected-client-count))
"x-bind:hx-vals" "JSON.stringify({selected: $data.selected, 'all-selected': $data.all_selected})"
"hx-include" "#invoice-filters"
:hx-get (bidi/path-for ssr-routes/only-routes ::route/pay-button)
:hx-swap "outerHTML"
:hx-trigger "selectedChanged from:body, htmx:afterSwap from:#entity-table"
"@mouseover" "hovering=true; $nextTick(() => popper.update())"
"@mouseout" "hovering=false;"
:x-ref "button"
:minimal-loading? true
:class "relative"}
(if (> (count (:ids params)) 0)
(str "Pay " (count (:ids params)) " invoices")
"Pay")
(when (or (= 0 (count ids))
(> selected-client-count 1))
(com/badge {} "!")))
[:div (hx/alpine-appear {:x-ref "tooltip"
:x-show "hovering"
:class "bg-gray-100 dark:bg-gray-600 rounded-lg shadow-2xl w-max z-50 p-4"})
(cond
(= 0 (count ids))
[:div "Please select some invoices to pay"]
(> selected-client-count 1)
[:div "Can only pay for one client at a time"]
:else
[:div "Click to choose a bank account"])]]))
(defn pay-button [request]
(html-response
(pay-button* {:ids (selected->ids request
(:query-params request))})))
;; TODO fix parsing of query params ;; TODO fix parsing of query params
(def grid-page (def grid-page
(helper/build {:id "entity-table" (helper/build {:id "entity-table"
@@ -298,12 +366,15 @@
:parse-query-params (fn [p] :parse-query-params (fn [p]
(mc/decode query-schema p main-transformer)) (mc/decode query-schema p main-transformer))
:action-buttons (fn [request] :action-buttons (fn [request]
[(when (can? (:identity request) {:subject :payment :activity :bulk-delete}) [(when (can? (:identity request) {:subject :invoice :activity :bulk-delete})
(com/button {:hx-get (str (bidi/path-for ssr-routes/only-routes ::route/bulk-delete)) (com/button {:hx-get (str (bidi/path-for ssr-routes/only-routes ::route/bulk-delete))
"x-bind:hx-vals" "JSON.stringify({selected: $data.selected, 'all-selected': $data.all_selected})" "x-bind:hx-vals" "JSON.stringify({selected: $data.selected, 'all-selected': $data.all_selected})"
"hx-include" "#payment-filters" "hx-include" "#invoice-filters"
:color :red} :color :red}
"Void selected"))]) "Void selected"))
(when (can? (:identity request) {:subject :invoice :activity :pay})
(pay-button* {:ids (selected->ids request
(:query-params request))}))])
:row-buttons (fn [_ entity] :row-buttons (fn [_ entity]
[(when (= :invoice-status/unpaid (:invoice/status entity)) [(when (= :invoice-status/unpaid (:invoice/status entity))
(com/icon-button {:hx-delete (bidi/path-for ssr-routes/only-routes (com/icon-button {:hx-delete (bidi/path-for ssr-routes/only-routes
@@ -470,7 +541,7 @@
(assoc "hx-retarget" ".modal-stack") (assoc "hx-retarget" ".modal-stack")
(assoc "hx-reswap" "beforeend"))))) (assoc "hx-reswap" "beforeend")))))
(defn void-payments-internal [all-ids id] (defn void-invoices-internal [all-ids id]
(let [all-ids (->> all-ids (let [all-ids (->> all-ids
(dc/q '[:find (pull ?i [:db/id :invoice/date {:invoice/expense-accounts [:db/id]}]) (dc/q '[:find (pull ?i [:db/id :invoice/date {:invoice/expense-accounts [:db/id]}])
:in $ [?i ...] :in $ [?i ...]
@@ -512,21 +583,12 @@
id) id)
(count all-ids))) (count all-ids)))
(defn bulk-delete-dialog-confirm [request] (defn bulk-delete-dialog-confirm [request]
(alog/peek (:form-params request)) (alog/peek (:form-params request))
(let [all-selected (:all-selected (:form-params request)) (let [ids (selected->ids request (:form-params request))
selected (:selected (:form-params request)) updated-count (void-invoices-internal ids (:identity request))]
ids (cond
all-selected
(:ids (fetch-ids (dc/db conn) (-> request
(assoc :query-params (:form-params request))
(assoc-in [:query-params :start] 0)
(assoc-in [:query-params :per-page] 250))))
:else
selected)
updated-count (void-payments-internal ids (:identity request))]
(html-response [:div] (html-response [:div]
:headers {"hx-trigger" (hx/json {:modalclose "" :headers {"hx-trigger" (hx/json {:modalclose ""
@@ -539,6 +601,8 @@
(def key->handler (def key->handler
(apply-middleware-to-all-handlers (apply-middleware-to-all-handlers
{::route/page (helper/page-route grid-page) {::route/page (helper/page-route grid-page)
::route/pay-button (-> pay-button
(wrap-schema-enforce :query-schema query-schema))
::route/delete (-> delete ::route/delete (-> delete
(wrap-entity [:route-params :db/id] default-read) (wrap-entity [:route-params :db/id] default-read)
(wrap-schema-enforce :route-params [:map [:db/id entity-id]])) (wrap-schema-enforce :route-params [:map [:db/id entity-id]]))

View File

@@ -259,12 +259,15 @@
(mt2/transformer {:decoders {:vector {:compile (fn [schema _] (mt2/transformer {:decoders {:vector {:compile (fn [schema _]
(when (:coerce? (m/properties schema)) (when (:coerce? (m/properties schema))
(fn [data] (fn [data]
(cond (sequential? data) (cond
data (vector? data)
(nil? data) data
nil (sequential? data)
:else data
[data]))))}}})) (nil? data)
nil
:else
[data]))))}}}))
(defn wrap-merge-prior-hx [handler] (defn wrap-merge-prior-hx [handler]
;; TODO this should just be automatic ;; TODO this should just be automatic

View File

@@ -1,5 +1,6 @@
(ns auto-ap.routes.invoice) (ns auto-ap.routes.invoice)
(def routes {"" {:get ::page} (def routes {"" {:get ::page}
"/pay-button" ::pay-button
"/bulk-delete" {:get ::bulk-delete "/bulk-delete" {:get ::bulk-delete
:delete ::bulk-delete-confirm} :delete ::bulk-delete-confirm}
["/" [#"\d+" :db/id]] {:delete ::delete} ["/" [#"\d+" :db/id]] {:delete ::delete}