ccount modal
This commit is contained in:
@@ -29,8 +29,10 @@
|
||||
html-response
|
||||
main-transformer
|
||||
many-entity
|
||||
modal-response
|
||||
ref->enum-schema
|
||||
ref->select-options
|
||||
strip
|
||||
temp-id
|
||||
wrap-entity
|
||||
wrap-form-4xx-2
|
||||
@@ -44,8 +46,8 @@
|
||||
[:form {"hx-trigger" "change delay:500ms, keyup changed from:.hot-filter delay:1000ms"
|
||||
"hx-get" (bidi/path-for ssr-routes/only-routes
|
||||
:admin-account-table)
|
||||
"hx-target" "#account-table"
|
||||
"hx-indicator" "#account-table"}
|
||||
"hx-target" "#entity-table"
|
||||
"hx-indicator" "#entity-table"}
|
||||
|
||||
[:fieldset.space-y-6
|
||||
(com/field {:label "Name"}
|
||||
@@ -129,7 +131,7 @@
|
||||
matching-count]))
|
||||
|
||||
(def grid-page
|
||||
(helper/build {:id "account-table"
|
||||
(helper/build {:id "entity-table"
|
||||
:nav (com/admin-aside-nav)
|
||||
:page-specific-nav filters
|
||||
:fetch-page fetch-page
|
||||
@@ -139,16 +141,12 @@
|
||||
:action-buttons (fn [_]
|
||||
[(com/button {:hx-get (str (bidi/path-for ssr-routes/only-routes
|
||||
:admin-account-new-dialog))
|
||||
:hx-target "#modal-content"
|
||||
:hx-swap "innerHTML"
|
||||
:color :primary}
|
||||
"New Account")])
|
||||
:row-buttons (fn [_ entity]
|
||||
[(com/icon-button {:hx-get (str (bidi/path-for ssr-routes/only-routes
|
||||
:admin-account-edit-dialog
|
||||
:db/id (:db/id entity)))
|
||||
:hx-target "#modal-content"
|
||||
:hx-swap "innerHTML"}
|
||||
:db/id (:db/id entity)))}
|
||||
svg/pencil)])
|
||||
:breadcrumbs [[:a {:href (bidi/path-for ssr-routes/only-routes
|
||||
:admin)}
|
||||
@@ -181,31 +179,29 @@
|
||||
(def table* (partial helper/table* grid-page))
|
||||
|
||||
(defn account-save [{:keys [form-params request-method] :as request}]
|
||||
(let [entity (cond-> form-params
|
||||
(= :post request-method) (assoc :db/id "new"))
|
||||
_ (cond (= :post request-method)
|
||||
(when (seq (dc/q '[:find ?x :in $ ?nc :where [?x :account/numeric-code ?nc]] (dc/db conn) (:account/numeric-code entity)))
|
||||
(field-validation-error (format "The code %d is already in use." (:account/numeric-code entity))
|
||||
[:account/numeric-code]
|
||||
:form form-params))
|
||||
)
|
||||
_ (some->> form-params
|
||||
:account/client-overrides
|
||||
(group-by :account-client-override/client)
|
||||
(filter (fn [[_ overrides]]
|
||||
(> (count overrides) 1)))
|
||||
(map first)
|
||||
seq
|
||||
(#(form-validation-error (format "Client(s) %s have more than one override."
|
||||
(str/join ", "
|
||||
(map (fn [client]
|
||||
(format "'%s'" (pull-attr (dc/db conn)
|
||||
:client/name
|
||||
(-> client)))
|
||||
) %)))
|
||||
:form form-params))
|
||||
|
||||
)
|
||||
(let [entity (cond-> form-params
|
||||
(= :post request-method) (assoc :db/id "new"))
|
||||
_ (cond (= :post request-method)
|
||||
(when (seq (dc/q '[:find ?x :in $ ?nc :where [?x :account/numeric-code ?nc]] (dc/db conn) (:account/numeric-code entity)))
|
||||
(field-validation-error (format "The code %d is already in use." (:account/numeric-code entity))
|
||||
[:account/numeric-code]
|
||||
:form form-params)))
|
||||
_ (some->> form-params
|
||||
:account/client-overrides
|
||||
(group-by :account-client-override/client)
|
||||
(filter (fn [[_ overrides]]
|
||||
(> (count overrides) 1)))
|
||||
(map first)
|
||||
seq
|
||||
(#(form-validation-error (format "Client(s) %s have more than one override."
|
||||
(str/join ", "
|
||||
(map (fn [client]
|
||||
(format "'%s'" (pull-attr (dc/db conn)
|
||||
:client/name
|
||||
(-> client)))
|
||||
) %)))
|
||||
:form form-params)) ;; TODO shouldnt need to bubble this through. See if we can eliminate the passing of form and last-form.
|
||||
)
|
||||
{:keys [tempids]} (audit-transact [[:upsert-entity (cond-> entity
|
||||
(:account/numeric-code entity) (assoc :account/code (str (:account/numeric-code entity))))]]
|
||||
(:identity request))
|
||||
@@ -231,8 +227,10 @@
|
||||
"account_client_override_id" (:db/id o)})))
|
||||
(html-response
|
||||
(row* identity updated-account {:flash? true})
|
||||
:headers {"hx-trigger" "modalclose"
|
||||
"hx-retarget" (format "#account-table tr[data-id=\"%d\"]" (:db/id updated-account))})))
|
||||
:headers (cond-> {"hx-trigger" "modalclose"}
|
||||
(= :post request-method) (assoc "hx-retarget" "#entity-table tbody"
|
||||
"hx-reswap" "afterbegin")
|
||||
(= :put request-method) (assoc "hx-retarget" (format "#entity-table tr[data-id=\"%d\"]" (:db/id updated-account)))))))
|
||||
|
||||
;; TODO decide when cursors are used. other cases it's not, some are
|
||||
(defn client-override* [override]
|
||||
@@ -377,14 +375,14 @@
|
||||
:index (count (fc/field-value))
|
||||
:hx-get (bidi/path-for ssr-routes/only-routes
|
||||
:admin-account-client-override-new)}
|
||||
"New override"))))
|
||||
|
||||
]
|
||||
"New override"))))]
|
||||
[:div
|
||||
(com/form-errors {:errors (:errors fc/*form-errors*)})
|
||||
(com/validated-save-button {:errors (seq form-errors)}
|
||||
"Save account")])]])]))
|
||||
|
||||
;; TODO saving new row should att it to the tbody
|
||||
|
||||
(defn new-client-override [{ {:keys [index]} :query-params}]
|
||||
(html-response
|
||||
(fc/start-form-with-prefix
|
||||
@@ -398,8 +396,8 @@
|
||||
[:map
|
||||
[:db/id {:optional true} [:maybe entity-id]]
|
||||
[:account/numeric-code {:optional true} [:maybe :int]]
|
||||
[:account/name [:string {:min 1}]]
|
||||
[:account/location [:maybe :string]]
|
||||
[:account/name [:string {:min 1 :decode/string strip}]]
|
||||
[:account/location {:optional true} [:maybe [:string {:decode/string strip}]]]
|
||||
[:account/type (ref->enum-schema "account-type")]
|
||||
[:account/applicability (ref->enum-schema "account-applicability")] ;
|
||||
[:account/invoice-allowance (ref->enum-schema "allowance")]
|
||||
@@ -409,17 +407,16 @@
|
||||
(many-entity {}
|
||||
[:db/id [:or entity-id temp-id]]
|
||||
[:account-client-override/client entity-id]
|
||||
[:account-client-override/name [:string {:min 2}]])]]]))
|
||||
[:account-client-override/name [:string {:min 2 :decode/string strip}]])]]]))
|
||||
|
||||
(defn account-dialog [{:keys [entity form-params form-errors]}]
|
||||
(html-response (dialog* {:entity entity
|
||||
(modal-response (dialog* {:entity entity
|
||||
:form-params (or (when (seq form-params)
|
||||
form-params)
|
||||
(when entity
|
||||
(mc/decode form-schema entity main-transformer))
|
||||
{})
|
||||
:form-errors form-errors})
|
||||
:headers {"hx-trigger" "modalopen"}))
|
||||
:form-errors form-errors})))
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
html-response
|
||||
main-transformer
|
||||
many-entity
|
||||
modal-response
|
||||
money
|
||||
percentage
|
||||
ref->enum-schema
|
||||
@@ -44,21 +45,14 @@
|
||||
[bidi.bidi :as bidi]
|
||||
[clojure.string :as str]
|
||||
[datomic.api :as dc]
|
||||
[iol-ion.query :refer [ident]]
|
||||
[malli.core :as mc]))
|
||||
|
||||
;; TODO with dependencies, I really don't like that you have to be ultra specific in what
|
||||
;; you want to include, and generating the routes and interconnection is weird too.
|
||||
;; I'm tempted to say to include a full snapshot of the form, and the indicator
|
||||
;; as to which one to generate.
|
||||
|
||||
|
||||
(defn filters [request]
|
||||
[:form {"hx-trigger" "change delay:500ms, keyup changed from:.hot-filter delay:1000ms"
|
||||
"hx-get" (bidi/path-for ssr-routes/only-routes
|
||||
:admin-transaction-rule-table)
|
||||
"hx-target" "#transaction-rule-table"
|
||||
"hx-indicator" "#transaction-rule-table"}
|
||||
"hx-target" "#entity-table"
|
||||
"hx-indicator" "#entity-table"}
|
||||
|
||||
[:fieldset.space-y-6
|
||||
(com/field {:label "Vendor"}
|
||||
@@ -180,7 +174,7 @@
|
||||
matching-count]))
|
||||
|
||||
(def grid-page
|
||||
(helper/build {:id "transaction-rule-table"
|
||||
(helper/build {:id "entity-table"
|
||||
:nav (com/admin-aside-nav)
|
||||
:page-specific-nav filters
|
||||
:fetch-page fetch-page
|
||||
@@ -190,16 +184,12 @@
|
||||
:action-buttons (fn [request]
|
||||
[(com/button {:hx-get (str (bidi/path-for ssr-routes/only-routes
|
||||
:admin-transaction-rule-new-dialog))
|
||||
:hx-target "#modal-content"
|
||||
:hx-swap "innerHTML"
|
||||
:color :primary}
|
||||
"New Transaction Rule")])
|
||||
:row-buttons (fn [request entity]
|
||||
[(com/icon-button {:hx-get (str (bidi/path-for ssr-routes/only-routes
|
||||
:admin-transaction-rule-edit-dialog
|
||||
:db/id (:db/id entity)))
|
||||
:hx-target "#modal-content"
|
||||
:hx-swap "innerHTML"}
|
||||
:db/id (:db/id entity)))}
|
||||
svg/pencil)])
|
||||
:breadcrumbs [[:a {:href (bidi/path-for ssr-routes/only-routes
|
||||
:admin)}
|
||||
@@ -269,6 +259,7 @@
|
||||
bank-account-id))
|
||||
|
||||
(defn transaction-rule-save [{:keys [form-params request-method identity] :as request}]
|
||||
(clojure.pprint/pprint form-params)
|
||||
(let [entity (cond-> form-params
|
||||
(= :post request-method) (assoc :db/id "new")
|
||||
true (assoc :transaction-rule/note (entity->note form-params)))
|
||||
@@ -297,13 +288,15 @@
|
||||
|
||||
{:keys [tempids]} (audit-transact [[:upsert-entity entity]]
|
||||
(:identity request))
|
||||
updated-account (dc/pull (dc/db conn)
|
||||
updated-rule (dc/pull (dc/db conn)
|
||||
default-read
|
||||
(or (get tempids (:db/id entity)) (:db/id entity)))]
|
||||
(html-response
|
||||
(row* identity updated-account {:flash? true})
|
||||
:headers {"hx-trigger" "modalclose"
|
||||
"hx-retarget" (format "#transaction-rule-table tr[data-id=\"%d\"]" (:db/id updated-account))})))
|
||||
(row* identity updated-rule {:flash? true})
|
||||
:headers (cond-> {"hx-trigger" "modalclose"}
|
||||
(= :post request-method) (assoc "hx-retarget" "#entity-table tbody"
|
||||
"hx-reswap" "afterbegin")
|
||||
(= :put request-method) (assoc "hx-retarget" (format "#entity-table tr[data-id=\"%d\"]" (:db/id updated-rule)))))))
|
||||
|
||||
|
||||
|
||||
@@ -327,81 +320,84 @@
|
||||
[{:keys [name value client-id x-model]}]
|
||||
[:div.flex.flex-col
|
||||
(com/typeahead-2 {:name name
|
||||
:placeholder "Search..."
|
||||
:url (str (bidi/path-for ssr-routes/only-routes :account-search) "?client-id=" client-id)
|
||||
:id name
|
||||
:x-model x-model
|
||||
:value value
|
||||
:content-fn (fn [value]
|
||||
(:account/name (d-accounts/clientize (dc/pull (dc/db conn) d-accounts/default-read value)
|
||||
client-id)))})])
|
||||
:placeholder "Search..."
|
||||
:url (str (bidi/path-for ssr-routes/only-routes :account-search) "?client-id=" client-id)
|
||||
:id name
|
||||
:x-model x-model
|
||||
:value value
|
||||
:content-fn (fn [value]
|
||||
(:account/name (d-accounts/clientize (dc/pull (dc/db conn) d-accounts/default-read value)
|
||||
client-id)))})])
|
||||
|
||||
;; TODO something is making the accountId not change the location for only existing ones?
|
||||
(defn- transaction-rule-account-row*
|
||||
[transaction-rule account]
|
||||
(com/data-grid-row (-> {:x-data (hx/json {:accountId (or (:db/id (fc/field-value (:transaction-rule-account/account account)))
|
||||
(fc/field-value (:transaction-rule-account/account account)))
|
||||
:show (boolean (not (fc/field-value (:new? account))))})
|
||||
:data-key "show"
|
||||
:x-ref "p"}
|
||||
hx/alpine-mount-then-appear)
|
||||
(let [account-name (fc/field-name (:transaction-rule-account/account account))]
|
||||
(list
|
||||
|
||||
(fc/with-field :db/id
|
||||
(com/hidden {:name (fc/field-name)
|
||||
:value (fc/field-value)}))
|
||||
(fc/with-field :transaction-rule-account/account
|
||||
(com/data-grid-cell
|
||||
{}
|
||||
(com/validated-field
|
||||
{:errors (fc/field-errors)}
|
||||
[:div {:hx-trigger "changed"
|
||||
:hx-target "next div"
|
||||
:hx-vals (format "js:{name: '%s', 'client-id': event.detail.clientId}" account-name)
|
||||
:hx-get (str (bidi/path-for ssr-routes/only-routes :admin-transaction-rule-account-typeahead))
|
||||
:x-init "$watch('clientId', cid => $dispatch('changed', $data))"}]
|
||||
(account-typeahead* {:value (fc/field-value)
|
||||
:client-id (:db/id (:transaction-rule/client transaction-rule))
|
||||
:name (fc/field-name)
|
||||
:x-model "accountId"}))))
|
||||
(fc/with-field :transaction-rule-account/location
|
||||
(com/data-grid-cell
|
||||
{}
|
||||
(com/validated-field
|
||||
{:errors (fc/field-errors)
|
||||
:x-data (hx/json {:location (fc/field-value)})}
|
||||
[:div {:hx-trigger "changed"
|
||||
:hx-target "next *"
|
||||
:hx-vals (format "js:{name: '%s', 'client-id': event.detail.clientId || '', 'account-id': event.detail.accountId || ''}" (fc/field-name) )
|
||||
:hx-get (bidi/path-for ssr-routes/only-routes :admin-transaction-rule-location-select)
|
||||
:x-init "$watch('clientId', cid => $dispatch('changed', $data)); $watch('accountId', cid => $dispatch('changed', $data))"}]
|
||||
(location-select* {:name (fc/field-name)
|
||||
:account-location (:account/location (cond->> (:transaction-rule-account/account @account)
|
||||
(nat-int? (:transaction-rule-account/account @account)) (dc/pull (dc/db conn)
|
||||
'[:account/location])))
|
||||
:client-locations (:client/locations (:transaction-rule/client transaction-rule))
|
||||
:hx-model "location"
|
||||
:value (fc/field-value)}))))
|
||||
(fc/with-field :transaction-rule-account/percentage
|
||||
(com/data-grid-cell
|
||||
{}
|
||||
(com/validated-field
|
||||
{:errors (fc/field-errors)}
|
||||
(com/money-input {:name (fc/field-name)
|
||||
:class "w-16"
|
||||
:value (some-> (fc/field-value)
|
||||
(* 100 )
|
||||
(long ))}))))))
|
||||
(com/data-grid-cell {:class "align-top"}
|
||||
(com/a-icon-button {"@click.prevent.stop" "show=false; setTimeout(() => $refs.p.remove(), 500)"} svg/x))))
|
||||
(com/data-grid-row
|
||||
(-> {:x-data (hx/json {:accountId (or (:db/id (fc/field-value (:transaction-rule-account/account account)))
|
||||
(fc/field-value (:transaction-rule-account/account account)))
|
||||
:show (boolean (not (fc/field-value (:new? account))))})
|
||||
:data-key "show"
|
||||
:x-ref "p"}
|
||||
hx/alpine-mount-then-appear)
|
||||
(let [account-name (fc/field-name (:transaction-rule-account/account account))]
|
||||
(list
|
||||
|
||||
(fc/with-field :db/id
|
||||
(com/hidden {:name (fc/field-name)
|
||||
:value (fc/field-value)}))
|
||||
(fc/with-field :transaction-rule-account/account
|
||||
(com/data-grid-cell
|
||||
{}
|
||||
(com/validated-field
|
||||
{:errors (fc/field-errors)}
|
||||
[:div {:hx-trigger "changed"
|
||||
:hx-target "next div"
|
||||
:hx-vals (format "js:{name: '%s', 'client-id': event.detail.clientId}" account-name)
|
||||
:hx-get (str (bidi/path-for ssr-routes/only-routes :admin-transaction-rule-account-typeahead))
|
||||
:x-init "$watch('clientId', cid => $dispatch('changed', $data))"}]
|
||||
(account-typeahead* {:value (fc/field-value)
|
||||
:client-id (:db/id (:transaction-rule/client transaction-rule))
|
||||
:name (fc/field-name)
|
||||
:x-model "accountId"}))))
|
||||
(fc/with-field :transaction-rule-account/location
|
||||
(com/data-grid-cell
|
||||
{}
|
||||
(com/validated-field
|
||||
{:errors (fc/field-errors)
|
||||
:x-data (hx/json {:location (fc/field-value)})}
|
||||
[:div {:hx-trigger "changed"
|
||||
:hx-target "next *"
|
||||
:hx-vals (format "js:{name: '%s', 'client-id': event.detail.clientId || '', 'account-id': event.detail.accountId || ''}" (fc/field-name) )
|
||||
:hx-get (bidi/path-for ssr-routes/only-routes :admin-transaction-rule-location-select)
|
||||
:x-init "$watch('clientId', cid => $dispatch('changed', $data)); $watch('accountId', cid => $dispatch('changed', $data) )"}]
|
||||
(location-select* {:name (fc/field-name)
|
||||
:account-location (:account/location (cond->> (:transaction-rule-account/account @account)
|
||||
(nat-int? (:transaction-rule-account/account @account)) (dc/pull (dc/db conn)
|
||||
'[:account/location])))
|
||||
:client-locations (:client/locations (:transaction-rule/client transaction-rule))
|
||||
:hx-model "location"
|
||||
:value (fc/field-value)}))))
|
||||
(fc/with-field :transaction-rule-account/percentage
|
||||
(com/data-grid-cell
|
||||
{}
|
||||
(com/validated-field
|
||||
{:errors (fc/field-errors)}
|
||||
(println "FIELD VALUE IS" (fc/field-value) (some-> (fc/field-value)
|
||||
(* 100 )
|
||||
(long )))
|
||||
(com/money-input {:name (fc/field-name)
|
||||
:class "w-16"
|
||||
:value (some-> (fc/field-value)
|
||||
(* 100 )
|
||||
(long ))}))))))
|
||||
(com/data-grid-cell {:class "align-top"}
|
||||
(com/a-icon-button {"@click.prevent.stop" "show=false; setTimeout(() => $refs.p.remove(), 500)"} svg/x))))
|
||||
|
||||
;; TODO background jobs and company 1099
|
||||
(defn dialog* [{:keys [entity form-params form-errors]}]
|
||||
(fc/start-form form-params form-errors
|
||||
(com/modal
|
||||
{:modal-class "max-w-2xl"
|
||||
:hx-target "this"}
|
||||
:hx-target "this"}
|
||||
|
||||
[:form {:hx-ext "response-targets"
|
||||
:hx-swap "outerHTML swap:300ms"
|
||||
@@ -415,7 +411,6 @@
|
||||
{}
|
||||
[:div.flex [:div.p-2 "Transaction Rule"]]
|
||||
[:fieldset {:class "hx-disable"
|
||||
:hx-disinherit "hx-target" ;; TODO why disinherit
|
||||
:x-data (hx/json {:clientId (or (:db/id (:transaction-rule/client form-params))
|
||||
(:transaction-rule/client form-params)
|
||||
(:db/id (:transaction-rule/client entity)))})}
|
||||
@@ -542,8 +537,7 @@
|
||||
(com/data-grid {:headers [(com/data-grid-header {} "Account")
|
||||
(com/data-grid-header {:class "w-32"} "Location")
|
||||
(com/data-grid-header {:class "w-16"} "%")
|
||||
(com/data-grid-header {:class "w-16"})]
|
||||
:id "transaction-rule-account-table"}
|
||||
(com/data-grid-header {:class "w-16"})]}
|
||||
(fc/cursor-map #(transaction-rule-account-row* form-params %))
|
||||
(com/data-grid-new-row {:colspan 4
|
||||
:hx-get (bidi/path-for ssr-routes/only-routes
|
||||
@@ -604,7 +598,8 @@
|
||||
client-id client-id]
|
||||
(html-response (account-typeahead* {:name name
|
||||
:value account
|
||||
:client-id client-id}))))
|
||||
:client-id client-id
|
||||
:x-model "accountId"}))))
|
||||
|
||||
(def form-schema (mc/schema
|
||||
[:map
|
||||
@@ -627,14 +622,13 @@
|
||||
[:transaction-rule-account/percentage percentage])]]))
|
||||
|
||||
(defn transaction-dialog [{:keys [entity form-params form-errors]}]
|
||||
(html-response (dialog* {:entity entity
|
||||
(modal-response (dialog* {:entity entity
|
||||
:form-params (or (when (seq form-params)
|
||||
form-params)
|
||||
(when entity
|
||||
(mc/decode form-schema entity main-transformer)) ;; TODO coerce into form params
|
||||
(mc/decode form-schema entity main-transformer))
|
||||
{})
|
||||
:form-errors form-errors})
|
||||
:headers {"hx-trigger" "modalopen"}))
|
||||
:form-errors form-errors})))
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
(ns auto-ap.ssr.ui
|
||||
(:require
|
||||
[hiccup2.core :as hiccup]
|
||||
[auto-ap.ssr.hx :as hx]))
|
||||
[auto-ap.ssr.hx :as hx]
|
||||
[config.core :refer [env]]
|
||||
[hiccup2.core :as hiccup]))
|
||||
|
||||
(defn html-page [hiccup]
|
||||
{:status 200
|
||||
@@ -27,8 +28,12 @@
|
||||
[:script {:src "https://unpkg.com/hyperscript.org@0.9.7/dist/_hyperscript.min.js"}]
|
||||
[:script {:src "https://unpkg.com/@popperjs/core@2.11.8/dist/umd/popper.min.js"}]
|
||||
[:script {:src "https://cdn.plaid.com/link/v2/stable/link-initialize.js"}]
|
||||
[:script {:src "https://unpkg.com/htmx.org@1.9.6/dist/htmx.min.js"
|
||||
:crossorigin= "anonymous"}]
|
||||
(if (= "dev" (:dd-env env))
|
||||
[:script {:src "https://unpkg.com/htmx.org@1.9.6/dist/htmx.js"
|
||||
:crossorigin= "anonymous"}]
|
||||
[:script {:src "https://unpkg.com/htmx.org@1.9.6/dist/htmx.min.js"
|
||||
:crossorigin= "anonymous"}])
|
||||
|
||||
[:script {:src "https://unpkg.com/htmx.org/dist/ext/debug.js"}]
|
||||
[:script {:src "/js/htmx-disable.js"}]
|
||||
[:script {:type "text/javascript", :src "https://cdn.yodlee.com/fastlink/v4/initialize.js", :async "async"}]]
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
html-response
|
||||
main-transformer
|
||||
many-entity
|
||||
modal-response
|
||||
ref->enum-schema
|
||||
ref->select-options
|
||||
wrap-entity
|
||||
@@ -213,9 +214,7 @@
|
||||
:hx-vals (format "{\"db/id\": \"%s\"}" (:db/id entity))} "Impersonate")
|
||||
(com/icon-button {:hx-get (str (bidi/path-for ssr-routes/only-routes
|
||||
:user-edit-dialog
|
||||
:db/id (:db/id entity)))
|
||||
:hx-target "#modal-content"
|
||||
:hx-swap "innerHTML"}
|
||||
:db/id (:db/id entity)))}
|
||||
svg/pencil)])
|
||||
:breadcrumbs [[:a {:href (bidi/path-for ssr-routes/only-routes
|
||||
:admin)}
|
||||
@@ -352,16 +351,14 @@
|
||||
[:user/role (ref->enum-schema "user-role")]]))
|
||||
|
||||
(defn user-dialog [{:keys [form-params entity form-errors]}]
|
||||
(html-response
|
||||
(modal-response
|
||||
(dialog* {:form-params (or (when (seq form-params)
|
||||
form-params)
|
||||
(when entity
|
||||
(mc/decode form-schema entity main-transformer))
|
||||
{})
|
||||
:entity entity
|
||||
:form-errors form-errors})
|
||||
|
||||
:headers {"hx-trigger" "modalopen"}))
|
||||
:form-errors form-errors})))
|
||||
|
||||
(defn new-client [{ {:keys [index]} :query-params}]
|
||||
(html-response
|
||||
|
||||
@@ -27,6 +27,16 @@
|
||||
o))
|
||||
oob)))})
|
||||
|
||||
(defn modal-response [hiccup & {:as opts}]
|
||||
(apply html-response
|
||||
(into
|
||||
[hiccup]
|
||||
(mapcat identity
|
||||
(-> opts
|
||||
(assoc-in [:headers "hx-trigger"] "modalopen")
|
||||
(assoc-in [:headers "hx-retarget"] "#modal-content")
|
||||
(assoc-in [:headers "hx-reswap"] "innerHTML"))))))
|
||||
|
||||
(defn wrap-error-response [handler]
|
||||
(fn [request]
|
||||
(try
|
||||
@@ -105,8 +115,11 @@
|
||||
|
||||
(def temp-id (mc/schema [:string {:min 1}]))
|
||||
(def money (mc/schema [:double]))
|
||||
(def percentage (mc/schema [:double {:decode/arbitrary (fn [x] (some-> x (* 0.01)))
|
||||
:max 1.0
|
||||
(def percentage (mc/schema [:double {:decode/string {:enter (fn [x]
|
||||
(if (and (string? x) (re-find #"^\d+(\.\d+)?$" x))
|
||||
(-> x (Double/parseDouble) (* 0.01))
|
||||
x))}
|
||||
:max 1.0
|
||||
:error/message "1-100"}]))
|
||||
|
||||
(def regex (mc/schema [:fn {:error/message "not a regex"}
|
||||
@@ -124,13 +137,7 @@
|
||||
x
|
||||
(into []
|
||||
(for [[k v] (sort-by (comp #(Long/parseLong %) name first) x)]
|
||||
v
|
||||
#_(assoc v :db/id (cond (and (string? k) (re-find #"^\d+$" k))
|
||||
(Long/parseLong k)
|
||||
(keyword? k)
|
||||
(name k)
|
||||
:else
|
||||
k))))))})
|
||||
v))))})
|
||||
|
||||
(defn many-entity [params & keys]
|
||||
(mc/schema
|
||||
@@ -174,6 +181,16 @@
|
||||
(mt2/transformer {:name :arbitrary})
|
||||
mt2/default-value-transformer))
|
||||
|
||||
(defn strip [s]
|
||||
(cond (and (string? s) (str/blank? s))
|
||||
nil
|
||||
|
||||
(string? s)
|
||||
(str/trim s)
|
||||
|
||||
:else
|
||||
s))
|
||||
|
||||
(defn wrap-schema-decode [handler & {:keys [form-schema query-schema route-schema params-schema]}]
|
||||
(fn [{:keys [form-params query-params params] :as request}]
|
||||
(let [request (try
|
||||
@@ -207,7 +224,6 @@
|
||||
main-transformer)))
|
||||
(catch Exception e
|
||||
(alog/warn ::validation-error :error e)
|
||||
|
||||
(throw (ex-info (->> (-> e
|
||||
(ex-data )
|
||||
:data
|
||||
@@ -251,17 +267,6 @@
|
||||
|
||||
|
||||
|
||||
#_(defn namespaceize-decoder [n]
|
||||
{:exit (fn [m]
|
||||
(when m
|
||||
(reduce
|
||||
(fn [m [k v]]
|
||||
(if (= k "id")
|
||||
(assoc m :db/id v)
|
||||
(assoc m (keyword n (name k)) v)))
|
||||
m
|
||||
m)))})
|
||||
|
||||
|
||||
(defn wrap-form-4xx [handler]
|
||||
(fn [request]
|
||||
@@ -274,17 +279,6 @@
|
||||
(html-response [:span.error-content.text-red-500 (:message &throw-context)]
|
||||
:status 400)))))
|
||||
|
||||
(defn assoc-errors-into-meta [entity errors]
|
||||
(reduce
|
||||
(fn add-error [entity {:keys [path message] :as se}]
|
||||
(if (= (count path) 1)
|
||||
(with-meta entity (assoc (meta entity) (last path) {:errors message}))
|
||||
|
||||
(update-in entity (butlast path)
|
||||
(fn [terminal]
|
||||
(with-meta terminal (assoc (meta terminal) (last path) {:errors message}))))))
|
||||
entity
|
||||
errors))
|
||||
|
||||
(defn wrap-form-4xx-2 [handler form-handler]
|
||||
(fn [request]
|
||||
|
||||
Reference in New Issue
Block a user