supports validation on complete

This commit is contained in:
2022-07-20 06:02:47 -07:00
parent 0baab4eaf0
commit 9b5b7bef53
6 changed files with 115 additions and 127 deletions

View File

@@ -108,7 +108,7 @@
(add-shutdown-hook! shutdown-mount) (add-shutdown-hook! shutdown-mount)
(start-server :port 9000 :bind "0.0.0.0" #_#_:handler (cider-nrepl-handler)) (start-server :port 9000 :bind "0.0.0.0" #_#_:handler (cider-nrepl-handler))
(alter-var-root #'nrepl.middleware.print/*print-fn* (constantly clojure.pprint/pprint)) #_(alter-var-root #'nrepl.middleware.print/*print-fn* (constantly clojure.pprint/pprint))
(apply mount/start-without without))) (apply mount/start-without without)))
(comment (comment

View File

@@ -83,6 +83,10 @@
(fn [db [_ form & paths]] (fn [db [_ form & paths]]
(update-in db [::forms form :visited] (fn [v] (update-in db [::forms form :visited] (fn [v]
(set (into v paths)))))) (set (into v paths))))))
(re-frame/reg-event-db
::attempted-submit
(fn [db [_ form & paths]]
(assoc-in db [::forms form :attempted-submit?] true)))
(defn change-handler [form customize-fn] (defn change-handler [form customize-fn]
(fn [db [_ & path-pairs]] (fn [db [_ & path-pairs]]

View File

@@ -34,45 +34,49 @@
(get-in field-path) (get-in field-path)
first)) first))
(defn builder [{:keys [value on-change can-submit data-sub error-messages change-event submit-event id fullwidth? schema] :as z}] (defn builder [{:keys [value on-change can-submit data-sub error-messages change-event submit-event id fullwidth? schema validation-error-string]}]
(when (and change-event on-change) (when (and change-event on-change)
(throw "Either the form is to be managed by ::forms, or it should have value and on-change passed in")) (throw "Either the form is to be managed by ::forms, or it should have value and on-change passed in"))
(let [data-sub (or data-sub [::forms/form id]) (let [data-sub (or data-sub [::forms/form id])
change-event (when-not on-change change-event (when-not on-change
(or change-event [::forms/change id])) (or change-event [::forms/change id]))
{:keys [data error visited] form-key :id} @(re-frame/subscribe data-sub) {:keys [data error visited attempted-submit?] form-key :id} @(re-frame/subscribe data-sub)
data (or value data) data (or value data)
status @(re-frame/subscribe [::status/single id]) status @(re-frame/subscribe [::status/single id])
can-submit (if can-submit @(re-frame/subscribe can-submit) can-submit (if can-submit @(re-frame/subscribe can-submit)
true) true)
problems (when schema problems (when schema
(m/explain schema data))] (m/explain schema data))]
(r/create-element Provider #js {:value #js {:can-submit can-submit
:error-messages (or error-messages
(r/create-element Provider #js {:value #js {:can-submit can-submit
:error-messages (or error-messages
nil) nil)
:on-change on-change :on-change on-change
:change-event change-event :change-event change-event
:blur-event [::forms/visited id] :blur-event [::forms/visited id]
:visited visited :visited visited
:submit-event submit-event :submit-event submit-event
:problems problems :problems problems
:error error :attempted-submit? attempted-submit?
:status status :error error
:id id :status status
:data data :id id
:fullwidth? fullwidth?}} :data data
:fullwidth? fullwidth?}}
(r/as-element (r/as-element
^{:key form-key} ^{:key form-key}
[:form {:on-submit (fn [e] [:form {:on-submit (fn [e]
(when (.-stopPropagation e) (when (.-stopPropagation e)
(.stopPropagation e) (.stopPropagation e)
(.preventDefault e)) (.preventDefault e))
(when can-submit (if (and schema (not (m/validate schema data)))
(re-frame/dispatch-sync (vec (conj submit-event {})))))} (do
(re-frame/dispatch-sync [::status/dispose-single id])
(re-frame/dispatch [::status/error id [{:message (or validation-error-string "Please fix the errors and try again.")}]])
(re-frame/dispatch [::forms/attempted-submit id]))
(when can-submit
(re-frame/dispatch-sync (vec (conj submit-event {}))))))}
(into [:fieldset {:disabled (boolean (= :loading (:state status)))}] (into [:fieldset {:disabled (boolean (= :loading (:state status)))}]
(r/children (r/current-component)))] (r/children (r/current-component)))]
)))) ))))
(defn virtual-builder [] (defn virtual-builder []
@@ -155,9 +159,10 @@
:else :else
nil) nil)
visited? (get (aget consume-form "visited") full-field-path)] visited? (get (aget consume-form "visited") full-field-path)
attempted-submit? (aget consume-form "attempted-submit?")]
(when-let [error-message (and (when-let [error-message (and
visited? (or visited? attempted-submit?)
(spec-error-message (aget consume-form "problems") full-field-path (aget consume-form "error-messages")))] (spec-error-message (aget consume-form "problems") full-field-path (aget consume-form "error-messages")))]
[:div [:div
[:p.help.has-text-danger error-message]]))))]))]) [:p.help.has-text-danger error-message]]))))]))])
@@ -184,6 +189,7 @@
:else :else
nil) nil)
visited? (get (aget consume-form "visited") full-field-path) visited? (get (aget consume-form "visited") full-field-path)
attempted-submit? (aget consume-form "attempted-submit?")
value (get-in (aget consume-form "data") full-field-path) value (get-in (aget consume-form "data") full-field-path)
on-change (aget consume-form "on-change")] on-change (aget consume-form "on-change")]
(-> child-props (-> child-props
@@ -196,7 +202,7 @@
(update :class (fn [class] (update :class (fn [class]
(str class (str class
(cond (cond
(not visited?) (and (not visited?) (not attempted-submit?))
"" ""
(not (valid-field? (aget consume-form "problems") full-field-path)) (not (valid-field? (aget consume-form "problems") full-field-path))
" is-danger" " is-danger"
@@ -317,5 +323,3 @@
(when-let [error (aget consume "error")] (when-let [error (aget consume "error")]
^{:key error} ^{:key error}
[:div.has-text-danger.animated.fadeInUp {} error])))])) [:div.has-text-danger.animated.fadeInUp {} error])))]))

View File

@@ -117,6 +117,7 @@
::error ::error
[(re-frame/path [::status]) ] [(re-frame/path [::status]) ]
(fn [db [_ single error]] (fn [db [_ single error]]
(println "STATUS" single error)
(assoc db single {:state :error (assoc db single {:state :error
:info nil :info nil
:error error}))) :error error})))

View File

@@ -3,6 +3,7 @@
[auto-ap.forms.builder :as form-builder] [auto-ap.forms.builder :as form-builder]
[auto-ap.schema :as schema] [auto-ap.schema :as schema]
[auto-ap.utils :refer [dollars-0?]] [auto-ap.utils :refer [dollars-0?]]
[auto-ap.views.components :as com]
[auto-ap.views.components.button-radio :as button-radio] [auto-ap.views.components.button-radio :as button-radio]
[auto-ap.views.components.level :refer [left-stack]] [auto-ap.views.components.level :refer [left-stack]]
[auto-ap.views.components.money-field :refer [money-field]] [auto-ap.views.components.money-field :refer [money-field]]
@@ -232,18 +233,7 @@
[:location schema/not-empty-string] [:location schema/not-empty-string]
[:amount schema/money]]])) [:amount schema/money]]]))
(defn select-field [{:keys [options allow-nil? class] :as props}]
[:div.select {:class class}
[:select (-> props
(dissoc :allow-nil? :class :options)
(update :value (fn [v] (if (str/blank? v)
""
v))))
[:<>
(when allow-nil?
[:option {:value nil}])
(for [[k v] options]
^{:key k} [:option {:value k} v])]]])
(defn expense-accounts-field-v2 [{value :value on-change :on-change expense-accounts :value client :client max-value :max locations :locations disabled :disabled percentage-only? :percentage-only? :or {percentage-only? false}}] (defn expense-accounts-field-v2 [{value :value on-change :on-change expense-accounts :value client :client max-value :max locations :locations disabled :disabled percentage-only? :percentage-only? :or {percentage-only? false}}]
[form-builder/virtual-builder {:value value [form-builder/virtual-builder {:value value
@@ -306,7 +296,7 @@
[form-builder/field-v2 {:required? true [form-builder/field-v2 {:required? true
:field [index :location]} :field [index :location]}
"Location" "Location"
[select-field {:options (if (:location account) [com/select-field {:options (if (:location account)
[[(:location account) (:location account)]] [[(:location account) (:location account)]]
(map (fn [l] [l l]) (map (fn [l] [l l])
locations)) locations))

View File

@@ -72,13 +72,6 @@
[:or [:maybe :string] [:or [:maybe :string]
[:maybe keyword?]]]])) [:maybe keyword?]]]]))
(re-frame/reg-sub
::can-submit
:<- [::forms/form ::vendor-form]
(fn [form]
(m/validate schema (:data form))))
(re-frame/reg-event-fx (re-frame/reg-event-fx
::save-complete ::save-complete
[(forms/triggers-stop ::vendor-form)] [(forms/triggers-stop ::vendor-form)]
@@ -89,55 +82,58 @@
::save ::save
[with-user with-is-admin? (forms/triggers-loading ::vendor-form) (forms/in-form ::vendor-form)] [with-user with-is-admin? (forms/triggers-loading ::vendor-form) (forms/in-form ::vendor-form)]
(fn [{:keys [user is-admin?] {{:keys [name hidden print-as terms invoice-reminder-schedule primary-contact automatically-paid-when-due schedule-payment-dom secondary-contact address default-account terms-overrides account-overrides id legal-entity-tin legal-entity-tin-type legal-entity-first-name legal-entity-last-name legal-entity-middle-name legal-entity-1099-type] :as data} :data} :db} _] (fn [{:keys [user is-admin?] {{:keys [name hidden print-as terms invoice-reminder-schedule primary-contact automatically-paid-when-due schedule-payment-dom secondary-contact address default-account terms-overrides account-overrides id legal-entity-tin legal-entity-tin-type legal-entity-first-name legal-entity-last-name legal-entity-middle-name legal-entity-1099-type] :as data} :data} :db} _]
(let [query [:upsert-vendor (if (m/validate schema data)
{:vendor (cond-> {:id id (let [query [:upsert-vendor
:name name {:vendor (cond-> {:id id
:print-as print-as :name name
:terms (or terms :print-as print-as
nil) :terms (or terms
:default-account-id (:id default-account) nil)
:address address :default-account-id (:id default-account)
:primary-contact primary-contact :address address
:secondary-contact secondary-contact :primary-contact primary-contact
:invoice-reminder-schedule invoice-reminder-schedule} :secondary-contact secondary-contact
is-admin? (assoc :hidden hidden :invoice-reminder-schedule invoice-reminder-schedule}
:terms-overrides (mapv is-admin? (assoc :hidden hidden
(fn [{:keys [client terms id]}] :terms-overrides (mapv
{:id id (fn [{:keys [client terms id]}]
:client-id (:id client) {:id id
:terms (or (str->int terms) 0)}) :client-id (:id client)
terms-overrides) :terms (or (str->int terms) 0)})
:account-overrides (mapv terms-overrides)
(fn [{:keys [client account id]}] :account-overrides (mapv
{:id id (fn [{:keys [client account id]}]
:client-id (:id client) {:id id
:account-id (:id account)}) :client-id (:id client)
account-overrides) :account-id (:id account)})
:schedule-payment-dom (mapv account-overrides)
(fn [{:keys [client dom id]}] :schedule-payment-dom (mapv
{:id id (fn [{:keys [client dom id]}]
:client-id (:id client) {:id id
:dom (or (str->int dom) :client-id (:id client)
0)}) :dom (or (str->int dom)
schedule-payment-dom) 0)})
:automatically-paid-when-due (mapv schedule-payment-dom)
(comp :id :client) :automatically-paid-when-due (mapv
automatically-paid-when-due) (comp :id :client)
:legal-entity-first-name legal-entity-first-name automatically-paid-when-due)
:legal-entity-middle-name legal-entity-middle-name :legal-entity-first-name legal-entity-first-name
:legal-entity-last-name legal-entity-last-name :legal-entity-middle-name legal-entity-middle-name
:legal-entity-tin legal-entity-tin :legal-entity-last-name legal-entity-last-name
:legal-entity-tin-type (some-> legal-entity-tin-type clojure.core/name not-empty keyword) :legal-entity-tin legal-entity-tin
:legal-entity-1099-type (some-> legal-entity-1099-type clojure.core/name not-empty keyword) :legal-entity-tin-type (some-> legal-entity-tin-type clojure.core/name not-empty keyword)
))} :legal-entity-1099-type (some-> legal-entity-1099-type clojure.core/name not-empty keyword)))}
common/default-read]] common/default-read]]
{ :graphql { :graphql
{:token user {:token user
:owns-state {:single ::vendor-form} :owns-state {:single ::vendor-form}
:query-obj {:venia/operation :query-obj {:venia/operation
{:operation/type :mutation {:operation/type :mutation
:operation/name "UpsertVendor"} :venia/queries [{:query/data query}]} :operation/name "UpsertVendor"} :venia/queries [{:query/data query}]}
:on-success [::save-complete]}}))) :on-success [::save-complete]}})
{:dispatch-n [[::forms/attempted-submit ::vendor-form]
[::status/error ::vendor-form [{:message "Please fix the errors and try again."}]]]})))
(defn pull-left [] (defn pull-left []
(into [:div {:style {:position "relative" (into [:div {:style {:position "relative"
@@ -178,7 +174,6 @@
(let [is-admin? @(re-frame/subscribe [::subs/is-admin?]) (let [is-admin? @(re-frame/subscribe [::subs/is-admin?])
clients @(re-frame/subscribe [::subs/client-refs])] clients @(re-frame/subscribe [::subs/client-refs])]
[form-builder/builder {:submit-event [::save] [form-builder/builder {:submit-event [::save]
:can-submit [::can-submit]
:id ::vendor-form :id ::vendor-form
:schema schema} :schema schema}
[form-builder/field-v2 {:field :name [form-builder/field-v2 {:field :name
@@ -282,7 +277,6 @@
[contact-field {:name "Secondary" [contact-field {:name "Secondary"
:field [:secondary-contact]}]] :field [:secondary-contact]}]]
(when is-admin? (when is-admin?
[form-builder/section {:title "Legal Entity"} [form-builder/section {:title "Legal Entity"}
[form-builder/vertical-control [form-builder/vertical-control
@@ -334,27 +328,23 @@
::vendor-selected ::vendor-selected
[with-user (forms/in-form ::select-vendor-form)] [with-user (forms/in-form ::select-vendor-form)]
(fn [{{:keys [data]} :db :keys [user]} _] (fn [{{:keys [data]} :db :keys [user]} _]
{:graphql {:token user (if (:vendor data)
:query-obj {:venia/queries [[:vendor-by-id {:graphql {:token user
{:id (:id (:vendor data))} :query-obj {:venia/queries [[:vendor-by-id
common/default-read]]} {:id (:id (:vendor data))}
:owns-state {:single ::select-vendor-form} common/default-read]]}
:on-success (fn [r] :owns-state {:single ::select-vendor-form}
[::started (:vendor-by-id r)])}})) :on-success (fn [r]
[::started (:vendor-by-id r)])}}
(re-frame/reg-sub {:dispatch-n [[::forms/attempted-submit ::select-vendor-form]
::can-submit-select-vendor-form [::status/error ::select-vendor-form [{:message "Please select a vendor."}]]]})))
:<- [::forms/field ::select-vendor-form [:vendor]]
(fn [vendor]
(if vendor
true
false)))
(defn select-vendor-form-content [] (defn select-vendor-form-content []
[form-builder/builder {:submit-event [::vendor-selected] [form-builder/builder {:submit-event [::vendor-selected]
:can-submit [::can-submit-select-vendor-form] :id ::select-vendor-form
:id ::select-vendor-form} :validation-error-string "Please select a vendor."
:schema [:map
[:vendor schema/reference]]}
[form-builder/field-v2 {:field :vendor [form-builder/field-v2 {:field :vendor
:required? true} :required? true}
"Vendor to edit" "Vendor to edit"
@@ -384,11 +374,11 @@
{:title "Vendor" {:title "Vendor"
:body [vendor-dialog] :body [vendor-dialog]
:class "semi-wide" :class "semi-wide"
:status-from [::status/single ::vendor-form]
:confirm {:value "Save Vendor" :confirm {:value "Save Vendor"
:status-from [::status/single ::vendor-form] :status-from [::status/single ::vendor-form]
:class "is-primary" :class "is-primary"
:on-click (dispatch-event [::save]) :on-click (dispatch-event [::save])
:can-submit [::can-submit]
:close-event [::status/completed ::vendor-form]}}]})) :close-event [::status/completed ::vendor-form]}}]}))
(re-frame/reg-event-fx (re-frame/reg-event-fx
@@ -402,5 +392,4 @@
:status-from [::status/single ::select-vendor-form] :status-from [::status/single ::select-vendor-form]
:class "is-primary" :class "is-primary"
:on-click (dispatch-event [::vendor-selected]) :on-click (dispatch-event [::vendor-selected])
:can-submit [::can-submit-select-vendor-form]
:close-event [::status/completed ::select-vendor-form]}}]})) :close-event [::status/completed ::select-vendor-form]}}]}))