A way better approach for form validation. Feels good now.
This commit is contained in:
@@ -1,6 +1,5 @@
|
||||
(ns auto-ap.views.pages.invoices.form
|
||||
(:require
|
||||
[auto-ap.entities.invoice :as invoice]
|
||||
[auto-ap.events :as events]
|
||||
[auto-ap.forms :as forms]
|
||||
[auto-ap.forms.builder :as form-builder]
|
||||
@@ -8,10 +7,11 @@
|
||||
[auto-ap.subs :as subs]
|
||||
[auto-ap.time-utils :refer [next-dom]]
|
||||
[auto-ap.utils :refer [dollars=]]
|
||||
[auto-ap.schema :as schema]
|
||||
[auto-ap.views.components.expense-accounts-field
|
||||
:as eaf
|
||||
:refer [recalculate-amounts
|
||||
expense-accounts-field]]
|
||||
expense-accounts-field-v2]]
|
||||
[auto-ap.views.components.layouts :as layouts]
|
||||
[auto-ap.views.components.level :refer [left-stack]]
|
||||
[auto-ap.views.components.modal :as modal]
|
||||
@@ -20,6 +20,7 @@
|
||||
[auto-ap.views.components.switch-field :refer [switch-field]]
|
||||
[auto-ap.views.components.typeahead :refer [typeahead-v3]]
|
||||
[auto-ap.views.components.typeahead.vendor
|
||||
|
||||
:refer [search-backed-typeahead]]
|
||||
[auto-ap.views.pages.invoices.common :refer [invoice-read]]
|
||||
[auto-ap.views.utils
|
||||
@@ -27,13 +28,25 @@
|
||||
dispatch-event
|
||||
with-user]]
|
||||
[cljs-time.core :as c]
|
||||
[clojure.spec.alpha :as s]
|
||||
[clojure.string :as str]
|
||||
[re-frame.core :as re-frame]
|
||||
[reagent.core :as r]
|
||||
[malli.core :as m]
|
||||
[vimsical.re-frame.cofx.inject :as inject]
|
||||
[vimsical.re-frame.fx.track :as track]))
|
||||
|
||||
|
||||
(def schema (m/schema
|
||||
[:map
|
||||
[:client schema/reference]
|
||||
[:vendor schema/reference]
|
||||
[:date schema/date]
|
||||
[:due {:optional true} [:maybe schema/date]]
|
||||
[:scheduled-payment {:optional true} [:maybe schema/date]]
|
||||
[:invoice-number schema/not-empty-string]
|
||||
[:total schema/money]
|
||||
[:expense-accounts eaf/schema]]))
|
||||
|
||||
;; SUBS
|
||||
(re-frame/reg-sub
|
||||
::can-submit
|
||||
@@ -42,11 +55,12 @@
|
||||
(let [min-total (if (= (:total (:original data)) (:outstanding-balance (:original data)))
|
||||
nil
|
||||
(- (:total (:original data)) (:outstanding-balance (:original data))))
|
||||
account-total (reduce + 0 (map (fn [ea] (js/parseFloat (:amount ea))) (:expense-accounts data)))]
|
||||
(and (s/valid? ::invoice/invoice data)
|
||||
(or (not min-total) (>= (:total data) min-total))
|
||||
(or (not (:id data))
|
||||
(dollars= (Math/abs (js/parseFloat (:total data))) (Math/abs account-total)))))))
|
||||
account-total (reduce + 0 (map :amount (:expense-accounts data)))]
|
||||
(and
|
||||
(m/validate schema data)
|
||||
(or (not min-total) (>= (:total data) min-total))
|
||||
(or (not (:id data))
|
||||
(dollars= (Math/abs (:total data)) (Math/abs account-total)))))))
|
||||
|
||||
(re-frame/reg-sub
|
||||
::create-query
|
||||
@@ -143,8 +157,8 @@
|
||||
:vendor (:vendor edit-invoice)
|
||||
:client (:client edit-invoice)
|
||||
:expense-accounts (eaf/from-graphql (:expense-accounts which)
|
||||
(:total which)
|
||||
locations-for-client)}))})))
|
||||
(:total which)
|
||||
locations-for-client)}))})))
|
||||
|
||||
|
||||
|
||||
@@ -321,7 +335,8 @@
|
||||
[form-builder/builder {:can-submit [::can-submit]
|
||||
:change-event [::changed]
|
||||
:submit-event [::save-requested [::saving ]]
|
||||
:id ::form}
|
||||
:id ::form
|
||||
:schema schema}
|
||||
|
||||
[form-builder/section {:title [:div "New Invoice "
|
||||
(cond
|
||||
@@ -344,48 +359,39 @@
|
||||
nil)]}
|
||||
|
||||
(when-not active-client
|
||||
[form-builder/field {:required? true}
|
||||
[form-builder/field-v2 {:required? true
|
||||
:field [:client]}
|
||||
"Client"
|
||||
[typeahead-v3 {:entities @(re-frame/subscribe [::subs/clients])
|
||||
:entity->text :name
|
||||
:type "typeahead-v3"
|
||||
:style {:width "8em"}
|
||||
:style {:width "18em"}
|
||||
:auto-focus (if active-client false true)
|
||||
:field [:client]
|
||||
:disabled exists?}]])
|
||||
[form-builder/field {:required? true}
|
||||
[form-builder/field-v2 {:required? true
|
||||
:field [:vendor]}
|
||||
"Vendor"
|
||||
[search-backed-typeahead {:disabled exists?
|
||||
:search-query (fn [i]
|
||||
[:search_vendor
|
||||
{:query i}
|
||||
[:name :id]])
|
||||
:type "typeahead-v3"
|
||||
|
||||
:style {:width "18em"}
|
||||
:auto-focus (if active-client true false)
|
||||
:field [:vendor]}]]
|
||||
[form-builder/vertical-control {:required? true}
|
||||
:auto-focus (if active-client true false)}]]
|
||||
[form-builder/field-v2 {:required? true
|
||||
:field :date}
|
||||
"Date"
|
||||
[:label
|
||||
[form-builder/raw-field
|
||||
[date-picker {:type "date"
|
||||
:field [:date]
|
||||
:output :cljs-date}]]]]
|
||||
[date-picker {:output :cljs-date}]]
|
||||
|
||||
[form-builder/field
|
||||
[form-builder/field-v2 {:field [:due]}
|
||||
"Due (optional)"
|
||||
[date-picker {:type "date"
|
||||
:field [:due]
|
||||
:output :cljs-date}]]
|
||||
[date-picker {:output :cljs-date}]]
|
||||
[form-builder/vertical-control
|
||||
"Scheduled payment (optional)"
|
||||
[left-stack
|
||||
[:div.control
|
||||
[form-builder/raw-field
|
||||
[date-picker {:type "date"
|
||||
:field [:scheduled-payment]
|
||||
:output :cljs-date}]]]
|
||||
[form-builder/raw-field-v2 {:field :scheduled-payment}
|
||||
[date-picker {:output :cljs-date}]]
|
||||
[form-builder/raw-error-v2 {:field :scheduled-payment}]]
|
||||
[:div.control
|
||||
[form-builder/raw-field
|
||||
|
||||
@@ -393,26 +399,23 @@
|
||||
:field [:schedule-when-due]
|
||||
:label "Same as due date"
|
||||
:type "checkbox"}]]]]]
|
||||
[form-builder/field {:required? true}
|
||||
[form-builder/field-v2 {:required? true
|
||||
:field :invoice-number}
|
||||
"Invoice #"
|
||||
[:input.input {:type "text"
|
||||
:field [:invoice-number]
|
||||
:style {:width "12em"}}]]
|
||||
[form-builder/field {:required? true}
|
||||
[:input.input {:style {:width "12em"}}]]
|
||||
|
||||
[form-builder/field-v2 {:required? true
|
||||
:field :total}
|
||||
"Total"
|
||||
[money-field {:type "money"
|
||||
:field [:total]
|
||||
:disabled (if can-change-amount? "" "disabled")
|
||||
[money-field {:disabled (if can-change-amount? "" "disabled")
|
||||
:style {:max-width "8em"}
|
||||
:min min-total
|
||||
:step "0.01"}]]]
|
||||
[form-builder/raw-field
|
||||
[expense-accounts-field {:type "expense-accounts"
|
||||
:descriptor "expense account"
|
||||
:locations (:locations (:client data))
|
||||
:max (:total data)
|
||||
:client (or (:client data) active-client)
|
||||
:field [:expense-accounts]}]]
|
||||
:min min-total}]]]
|
||||
[form-builder/field-v2 {:field :expense-accounts}
|
||||
"Expense Accounts"
|
||||
[expense-accounts-field-v2 {:descriptor "expense account"
|
||||
:locations (:locations (:client data))
|
||||
:max (:total data)
|
||||
:client (or (:client data) active-client)}]]
|
||||
[form-builder/error-notification]
|
||||
[:div {:style {:margin-bottom "1em"}}]
|
||||
[:div.columns
|
||||
|
||||
Reference in New Issue
Block a user