payments ssr
voiding supports bulk void. exact match id linking voidnig payments works. minor tweak.
This commit is contained in:
@@ -1,25 +1,32 @@
|
||||
(ns auto-ap.ssr.grid-page-helper
|
||||
(:require
|
||||
[auto-ap.graphql.utils :refer [extract-client-ids]]
|
||||
[auto-ap.query-params :as query-params]
|
||||
[auto-ap.routes.utils
|
||||
:refer [wrap-client-redirect-unauthenticated wrap-secure]]
|
||||
[auto-ap.ssr-routes :as ssr-routes]
|
||||
[auto-ap.ssr.components :as com]
|
||||
[auto-ap.ssr.svg :as svg]
|
||||
[auto-ap.ssr.ui :refer [base-page]]
|
||||
[auto-ap.ssr.utils :refer [html-response]]
|
||||
[auto-ap.time :as atime]
|
||||
[malli.core :as m]
|
||||
[bidi.bidi :as bidi]
|
||||
[cemerick.url :as url]
|
||||
[clojure.string :as str]
|
||||
[hiccup2.core :as hiccup]
|
||||
[malli.transform :as mt2]
|
||||
[auto-ap.ssr.hiccup-helper :as hh]))
|
||||
(:require [auto-ap.graphql.utils :refer [extract-client-ids]]
|
||||
[auto-ap.logging :as alog]
|
||||
[auto-ap.query-params :as query-params]
|
||||
[auto-ap.routes.utils
|
||||
:refer [wrap-client-redirect-unauthenticated wrap-secure]]
|
||||
[auto-ap.ssr-routes :as ssr-routes]
|
||||
[auto-ap.ssr.components :as com]
|
||||
[auto-ap.ssr.hiccup-helper :as hh]
|
||||
[auto-ap.ssr.hx :as hx]
|
||||
[auto-ap.ssr.svg :as svg]
|
||||
[auto-ap.ssr.ui :refer [base-page]]
|
||||
[auto-ap.ssr.utils :refer [html-response main-transformer]]
|
||||
[auto-ap.time :as atime]
|
||||
[bidi.bidi :as bidi]
|
||||
[cemerick.url :as url]
|
||||
[clojure.string :as str]
|
||||
[hiccup2.core :as hiccup]
|
||||
[malli.core :as m]
|
||||
[malli.transform :as mt2]
|
||||
[malli.transform :as mt]
|
||||
[taoensso.encore :refer [filter-vals]]))
|
||||
|
||||
(defn row* [gridspec user entity {:keys [flash? delete-after-settle? request class] :as options}]
|
||||
(let [cells (->> gridspec
|
||||
(let [cells (if (:check-boxes? gridspec)
|
||||
[(com/data-grid-cell {} (com/checkbox {:name "id" :value ((:id-fn gridspec) entity)
|
||||
:x-model "selected"}))]
|
||||
[])
|
||||
cells (->> gridspec
|
||||
:headers
|
||||
(filter (fn [h]
|
||||
(if (and (:hide? h)
|
||||
@@ -30,14 +37,15 @@
|
||||
(com/data-grid-cell {:class (if-let [show-starting (:show-starting header)]
|
||||
(format "hidden %s:table-cell" show-starting)
|
||||
(:class header))}
|
||||
((:render header) entity)))))
|
||||
((:render header) entity))))
|
||||
(into cells))
|
||||
cells (conj cells (com/data-grid-right-stack-cell {}
|
||||
(into [:form.flex.space-x-2
|
||||
[:input {:type :hidden :name "id" :value ((:id-fn gridspec) entity)}]]
|
||||
((:row-buttons gridspec) request entity))))] ;; TODO double check usage of row buttons user and identity in callers
|
||||
(apply com/data-grid-row
|
||||
(apply com/data-grid-row
|
||||
{:class (cond-> (or class "")
|
||||
flash? (hh/add-class "live-added"))
|
||||
flash? (hh/add-class "live-added"))
|
||||
"_" (hiccup/raw (when delete-after-settle?
|
||||
" on htmx:afterSettle wait 400ms then remove me"))
|
||||
|
||||
@@ -52,24 +60,18 @@
|
||||
|
||||
(defn sort-by-list [grid-spec sort]
|
||||
(if (seq sort)
|
||||
(into
|
||||
[:div.flex.gap-2.items-center
|
||||
|
||||
"sorted by"
|
||||
(into
|
||||
[:div.flex.gap-2.items-center
|
||||
|
||||
]
|
||||
(for [{:keys [name sort-icon sort-key ]} sort]
|
||||
[:div.py-1.px-3.text-sm.rounded.bg-gray-100.dark:bg-gray-600.flex.items-center.gap-2.relative name [:div.h-4.w-4.mr-3 sort-icon]
|
||||
[:div {:class "absolute inline-flex items-center justify-center w-6 h-6 text-xs font-bold text-white hover:scale-110 transition-all duration-300 bg-gray-400 border-2 border-white rounded-full -top-2 -right-2 dark:border-gray-900"}
|
||||
[:a {:href (str (bidi/path-for ssr-routes/only-routes
|
||||
(:route grid-spec)) "?remove-sort=" sort-key)
|
||||
:hx-boost "true"
|
||||
:hx-target (str "#" (:id grid-spec))
|
||||
|
||||
}
|
||||
[:div.h-4.w-4 svg/x]]
|
||||
]]
|
||||
))
|
||||
"sorted by"]
|
||||
(for [{:keys [name sort-icon sort-key]} sort]
|
||||
[:div.py-1.px-3.text-sm.rounded.bg-gray-100.dark:bg-gray-600.flex.items-center.gap-2.relative name [:div.h-4.w-4.mr-3 sort-icon]
|
||||
[:div {:class "absolute inline-flex items-center justify-center w-6 h-6 text-xs font-bold text-white hover:scale-110 transition-all duration-300 bg-gray-400 border-2 border-white rounded-full -top-2 -right-2 dark:border-gray-900"}
|
||||
[:a {:href (str (bidi/path-for ssr-routes/only-routes
|
||||
(:route grid-spec)) "?remove-sort=" sort-key)
|
||||
:hx-boost "true"
|
||||
:hx-target (str "#" (:id grid-spec))}
|
||||
[:div.h-4.w-4 svg/x]]]]))
|
||||
"default sort"))
|
||||
|
||||
(defn table* [grid-spec user {{:keys [start per-page flash-id sort]} :parsed-query-params :as request}]
|
||||
@@ -79,7 +81,9 @@
|
||||
request)]
|
||||
|
||||
(com/data-grid-card {:id (:id grid-spec)
|
||||
:title (:title grid-spec)
|
||||
:title (if (string? (:title grid-spec))
|
||||
(:title grid-spec)
|
||||
((:title grid-spec) request))
|
||||
:route (:route grid-spec)
|
||||
:start start
|
||||
:per-page per-page
|
||||
@@ -87,7 +91,18 @@
|
||||
:subtitle [:div.flex.items-center.gap-2
|
||||
[:span (format "Total %s: %d, " (:entity-name grid-spec) total)]
|
||||
(sort-by-list grid-spec sort)]
|
||||
:action-buttons ((:action-buttons grid-spec) request)
|
||||
:action-buttons (cond->> ((:action-buttons grid-spec) request)
|
||||
(:check-boxes? grid-spec) (into [(com/pill {:color :primary
|
||||
:x-show "selected.length > 0"}
|
||||
[:div.flex.space-x-2.items-center
|
||||
[:div
|
||||
|
||||
[:span {:x-text "selected.length" :x-show "!all_selected"}]
|
||||
[:span {:x-show "all_selected"} "All"]
|
||||
" selected"]
|
||||
[:div.w-3.h-3
|
||||
(com/link {"@click" "selected=[]; all_selected=false"}
|
||||
svg/x)]])]))
|
||||
:rows (for [entity entities]
|
||||
(row* grid-spec user entity {:flash? (= flash-id ((:id-fn grid-spec) entity)) :request request}))
|
||||
:thead-params {:hx-get (bidi/path-for ssr-routes/only-routes
|
||||
@@ -97,37 +112,37 @@
|
||||
:hx-trigger "sorted once"
|
||||
:hx-vals "js:{\"toggle-sort\": event.detail.key || \"\"}"}
|
||||
:headers
|
||||
(conj
|
||||
(->> grid-spec
|
||||
:headers
|
||||
(map
|
||||
(fn [h]
|
||||
(cond
|
||||
(and (:hide? h)
|
||||
((:hide? h) request))
|
||||
nil
|
||||
(conj
|
||||
(->> grid-spec
|
||||
:headers
|
||||
(map
|
||||
(fn [h]
|
||||
(cond
|
||||
(and (:hide? h)
|
||||
((:hide? h) request))
|
||||
nil
|
||||
|
||||
(:sort-key h)
|
||||
(com/data-grid-sort-header {:class (if-let [show-starting (:show-starting h)]
|
||||
(format "hidden %s:table-cell" show-starting)
|
||||
(:class h))
|
||||
:sort-key (:sort-key h)}
|
||||
(:sort-key h)
|
||||
(com/data-grid-sort-header {:class (if-let [show-starting (:show-starting h)]
|
||||
(format "hidden %s:table-cell" show-starting)
|
||||
(:class h))
|
||||
:sort-key (:sort-key h)}
|
||||
|
||||
[:div.flex.gap-4.items-center
|
||||
(:name h)
|
||||
[:div.h-6.w-6.text-gray-400.dark:text-gray-500 (sort-icon sort (:sort-key h))]])
|
||||
[:div.flex.gap-4.items-center
|
||||
(:name h)
|
||||
[:div.h-6.w-6.text-gray-400.dark:text-gray-500 (sort-icon sort (:sort-key h))]])
|
||||
|
||||
:else
|
||||
(com/data-grid-header {:class (if-let [show-starting (:show-starting h)]
|
||||
(format "hidden %s:table-cell" show-starting)
|
||||
(:class h))
|
||||
:sort-key (:sort-key h)}
|
||||
(:name h))
|
||||
|
||||
)))
|
||||
(filter identity)
|
||||
(into []))
|
||||
(com/data-grid-header {}))})))
|
||||
:else
|
||||
(com/data-grid-header {:class (if-let [show-starting (:show-starting h)]
|
||||
(format "hidden %s:table-cell" show-starting)
|
||||
(:class h))
|
||||
:sort-key (:sort-key h)}
|
||||
(:name h)))))
|
||||
(filter identity)
|
||||
(into (if (:check-boxes? grid-spec)
|
||||
[(com/data-grid-checkbox-header {:name "all" :value "all" :x-model "all_selected"})]
|
||||
[])))
|
||||
(com/data-grid-header {}))})))
|
||||
|
||||
|
||||
(defn sort->query [s]
|
||||
@@ -137,47 +152,47 @@
|
||||
s)))
|
||||
|
||||
(defn default-unparse-query-params [query-params]
|
||||
(reduce
|
||||
(fn [query-params [k value]]
|
||||
(assoc query-params k
|
||||
(cond (= k :sort)
|
||||
(sort->query value)
|
||||
(reduce
|
||||
(fn [query-params [k value]]
|
||||
(assoc query-params k
|
||||
(cond (= k :sort)
|
||||
(sort->query value)
|
||||
|
||||
(instance? org.joda.time.base.AbstractInstant value)
|
||||
(atime/unparse-local value atime/normal-date)
|
||||
(instance? org.joda.time.base.AbstractInstant value)
|
||||
(atime/unparse-local value atime/normal-date)
|
||||
|
||||
(instance? Long value)
|
||||
(str value)
|
||||
(instance? Long value)
|
||||
(str value)
|
||||
|
||||
(instance? Double value)
|
||||
(format "%.2f" value)
|
||||
(instance? Double value)
|
||||
(format "%.2f" value)
|
||||
|
||||
(instance? Float value)
|
||||
(format "%.2f" value)
|
||||
(instance? Float value)
|
||||
(format "%.2f" value)
|
||||
|
||||
(keyword? value)
|
||||
(name value)
|
||||
(keyword? value)
|
||||
(name value)
|
||||
|
||||
(and (map? value)
|
||||
(:db/id value))
|
||||
(:db/id value)
|
||||
(and (map? value)
|
||||
(:db/id value))
|
||||
(:db/id value)
|
||||
|
||||
:else
|
||||
value)))
|
||||
query-params
|
||||
query-params))
|
||||
:else
|
||||
value)))
|
||||
query-params
|
||||
query-params))
|
||||
|
||||
(defn default-parse-query-params [grid-spec]
|
||||
(comp
|
||||
(query-params/apply-remove-sort)
|
||||
(query-params/apply-toggle-sort grid-spec)
|
||||
(query-params/apply-date-range :date-range :start-date :end-date)
|
||||
(query-params/parse-key :exact-match-id query-params/parse-long)
|
||||
(query-params/parse-key :sort #(query-params/parse-sort grid-spec %))
|
||||
(query-params/parse-key :per-page query-params/parse-long)
|
||||
(query-params/parse-key :start query-params/parse-long)
|
||||
(query-params/parse-key :start-date query-params/parse-date)
|
||||
(query-params/parse-key :end-date query-params/parse-date)))
|
||||
(query-params/apply-remove-sort)
|
||||
(query-params/apply-toggle-sort grid-spec)
|
||||
(query-params/apply-date-range :date-range :start-date :end-date)
|
||||
(query-params/parse-key :exact-match-id query-params/parse-long)
|
||||
(query-params/parse-key :sort #(query-params/parse-sort grid-spec %))
|
||||
(query-params/parse-key :per-page query-params/parse-long)
|
||||
(query-params/parse-key :start query-params/parse-long)
|
||||
(query-params/parse-key :start-date query-params/parse-date)
|
||||
(query-params/parse-key :end-date query-params/parse-date)))
|
||||
|
||||
(defn wrap-trim-client-ids [handler]
|
||||
(fn trim-client-ids [request]
|
||||
@@ -196,10 +211,17 @@
|
||||
(let [unparse-query-params (or (:unparse-query grid-spec)
|
||||
default-unparse-query-params)]
|
||||
(html-response (table*
|
||||
grid-spec
|
||||
identity
|
||||
request)
|
||||
:headers {"hx-push-url" (str "?" (url/map->query (unparse-query-params (:parsed-query-params request))))}
|
||||
grid-spec
|
||||
identity
|
||||
request)
|
||||
:headers {"hx-push-url" (str "?" (url/map->query
|
||||
(if (:query-schema grid-spec)
|
||||
(update (filter-vals #(not (nil? %))
|
||||
(m/encode (:query-schema grid-spec)
|
||||
(:query-params request)
|
||||
main-transformer))
|
||||
"sort" sort->query)
|
||||
(unparse-query-params (:parsed-query-params request)))))}
|
||||
:oob (when-let [oob-render (:oob-render grid-spec)]
|
||||
(oob-render request)))))
|
||||
(wrap-trim-client-ids)
|
||||
@@ -208,22 +230,23 @@
|
||||
(wrap-secure)
|
||||
(wrap-client-redirect-unauthenticated)))
|
||||
|
||||
(defn page-route [grid-spec ]
|
||||
(defn page-route [grid-spec]
|
||||
(-> (fn page [{:keys [identity] :as request}]
|
||||
(base-page
|
||||
request
|
||||
(com/page {:nav (:nav grid-spec)
|
||||
:page-specific (when-let [page-specific-nav (:page-specific-nav grid-spec)]
|
||||
[:div#page-specific-nav (page-specific-nav request)])
|
||||
:client-selection (:client-selection (:session request))
|
||||
:clients (:clients request)
|
||||
:client (:client request)
|
||||
:identity (:identity request)}
|
||||
(apply com/breadcrumbs {} (:breadcrumbs grid-spec))
|
||||
request
|
||||
(com/page {:nav (:nav grid-spec)
|
||||
:page-specific (when-let [page-specific-nav (:page-specific-nav grid-spec)]
|
||||
[:div#page-specific-nav (page-specific-nav request)])
|
||||
:client-selection (:client-selection (:session request))
|
||||
:clients (:clients request)
|
||||
:client (:client request)
|
||||
:identity (:identity request)}
|
||||
(apply com/breadcrumbs {} (:breadcrumbs grid-spec))
|
||||
[:div {:x-data (hx/json {:selected [] :all_selected false})}
|
||||
(table* grid-spec
|
||||
identity
|
||||
request))
|
||||
(:title grid-spec)))
|
||||
request)])
|
||||
(:title grid-spec)))
|
||||
(wrap-trim-client-ids)
|
||||
(query-params/wrap-parse-query-params (or (:parse-query-params grid-spec)
|
||||
(default-parse-query-params grid-spec)))
|
||||
@@ -235,6 +258,7 @@
|
||||
(def header-spec (m/schema [:map
|
||||
[:key :string]
|
||||
[:name :string]
|
||||
[:header-class {:optional true} [:maybe :string]]
|
||||
[:sort-key {:optional true} :string]
|
||||
[:render [:=> [:cat entity-spec] :any]]
|
||||
[:hide? {:optional true} [:=> [:cat entity-spec] :boolean]]]))
|
||||
@@ -264,10 +288,12 @@
|
||||
{:optional true
|
||||
:default (fn [request])}
|
||||
[:=>
|
||||
[:cat request-spec]
|
||||
vector?]]
|
||||
[:cat request-spec]
|
||||
vector?]]
|
||||
[:breadcrumbs [:vector vector?]]
|
||||
[:title :string]
|
||||
[:title [:or :string
|
||||
[:=> [:cat [:map-of :keyword :any]]
|
||||
:string]]]
|
||||
[:entity-name :string]
|
||||
[:route :keyword]
|
||||
[:action-buttons
|
||||
@@ -290,4 +316,13 @@
|
||||
(m/explain grid-spec grid-page))))
|
||||
(m/decode grid-spec grid-page (mt2/default-value-transformer {::mt2/add-optional-keys true})))
|
||||
|
||||
(defn wrap-apply-sort [handler grid-spec]
|
||||
(fn apply-sort [request]
|
||||
(handler (update request :query-params
|
||||
(fn [qp]
|
||||
((comp
|
||||
(query-params/apply-remove-sort)
|
||||
(query-params/apply-toggle-sort grid-spec)
|
||||
(query-params/parse-key :sort #(query-params/parse-sort grid-spec %)))
|
||||
qp))))))
|
||||
|
||||
|
||||
Reference in New Issue
Block a user