From 746787df795a56c7ec9e45611703a37cdb552222 Mon Sep 17 00:00:00 2001 From: Bryce Covert Date: Thu, 21 Jul 2022 06:04:09 -0700 Subject: [PATCH] made client form great --- src/cljs/auto_ap/forms/builder.cljs | 2 +- src/cljs/auto_ap/views/components.cljs | 5 +- src/cljs/auto_ap/views/components/multi.cljs | 3 +- src/cljs/auto_ap/views/components/number.cljs | 3 +- .../views/pages/admin/clients/form.cljs | 259 ++++++++---------- 5 files changed, 119 insertions(+), 153 deletions(-) diff --git a/src/cljs/auto_ap/forms/builder.cljs b/src/cljs/auto_ap/forms/builder.cljs index ecb66368..e76286de 100644 --- a/src/cljs/auto_ap/forms/builder.cljs +++ b/src/cljs/auto_ap/forms/builder.cljs @@ -55,7 +55,7 @@ ;; TODO ONLY validate on blur 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 nil) diff --git a/src/cljs/auto_ap/views/components.cljs b/src/cljs/auto_ap/views/components.cljs index f358e28b..c61bcd5c 100644 --- a/src/cljs/auto_ap/views/components.cljs +++ b/src/cljs/auto_ap/views/components.cljs @@ -1,7 +1,8 @@ (ns auto-ap.views.components (:require [reagent.core :as r] [clojure.string :as str] - [auto-ap.views.components.multi :as multi])) + [auto-ap.views.components.multi :as multi] + [auto-ap.views.components.number :as number])) (defn checkbox [{:keys [on-change @@ -35,3 +36,5 @@ ^{:key k} [:option {:value k} v])]]]) (def multi-field-v2 multi/multi-field-v2) + +(def number-input number/number-input) diff --git a/src/cljs/auto_ap/views/components/multi.cljs b/src/cljs/auto_ap/views/components/multi.cljs index c7afdf01..1d1760eb 100644 --- a/src/cljs/auto_ap/views/components/multi.cljs +++ b/src/cljs/auto_ap/views/components/multi.cljs @@ -13,6 +13,7 @@ (let [prop-value (if (seq prop-value) prop-value [])] + (println "PROP VALUE IS") [form-builder/virtual-builder {:value prop-value :schema schema :on-change on-change} @@ -60,7 +61,7 @@ [:button.button.is-outline {:type "button" :on-click (fn [e] - (on-change (conj prop-value {::key next-key})) + (on-change (conj prop-value {::key (random-uuid)})) (.stopPropagation e) (.preventDefault e))} [:span.icon [:i.fa.fa-plus]] diff --git a/src/cljs/auto_ap/views/components/number.cljs b/src/cljs/auto_ap/views/components/number.cljs index 2aeadf6a..bb31e30c 100644 --- a/src/cljs/auto_ap/views/components/number.cljs +++ b/src/cljs/auto_ap/views/components/number.cljs @@ -34,7 +34,8 @@ :value text :type "number" :step "1" - :style {:width "5em"} + :style (or (:style props) + {:width "5em"}) :size 3)]]])) (defn number-input [] diff --git a/src/cljs/auto_ap/views/pages/admin/clients/form.cljs b/src/cljs/auto_ap/views/pages/admin/clients/form.cljs index b6915a11..0411c398 100644 --- a/src/cljs/auto_ap/views/pages/admin/clients/form.cljs +++ b/src/cljs/auto_ap/views/pages/admin/clients/form.cljs @@ -27,13 +27,18 @@ [react-signature-canvas] [vimsical.re-frame.cofx.inject :as inject] [auto-ap.schema :as schema] - [auto-ap.views.components :as com] [malli.core :as m])) (def signature-canvas (r/adapt-react-class (.-default react-signature-canvas))) (def location-schema (m/schema [:map [:location schema/not-empty-string]])) + +(def name-match-schema (m/schema [:map + [:match schema/not-empty-string]])) +(def location-match-schema (m/schema [:map + [:match schema/not-empty-string] + [:location schema/not-empty-string]])) (def email-schema [:map [:email schema/not-empty-string] [:description schema/not-empty-string]]) @@ -42,7 +47,12 @@ [:name schema/not-empty-string] [:code schema/code-string] [:locations [:sequential location-schema]] - [:emails [:sequential email-schema]]]) + [:emails {:optional true} + [:maybe [:sequential email-schema]]] + [:matches {:optional true} + [:maybe [:sequential name-match-schema]]] + [:location-matches {:optional true} + [:maybe [:sequential location-match-schema]]]]) (defn upload-replacement-button [{:keys [on-change]} text] (let [button (atom nil)] @@ -164,10 +174,8 @@ :bank-accounts (map-indexed (fn [i {:keys [number name check-number plaid-account intuit-bank-account include-in-reports type id code numeric-code start-date bank-name routing bank-code new? sort-order visible yodlee-account-id locations yodlee-account use-date-instead-of-post-date]}] {:number number :name name - :check-number (when-not (str/blank? check-number) - (js/parseInt check-number)) - :numeric-code (when-not (str/blank? numeric-code) - (js/parseInt numeric-code)) + :check-number check-number + :numeric-code numeric-code :include-in-reports include-in-reports :start-date start-date :type type @@ -176,8 +184,6 @@ :visible visible :locations (mapv :location locations) :use-date-instead-of-post-date use-date-instead-of-post-date - :yodlee-account-id (when-not (str/blank? yodlee-account-id) - (js/parseInt yodlee-account-id)) :yodlee-account (:id yodlee-account) :plaid-account (:id plaid-account) :intuit-bank-account (:id intuit-bank-account) @@ -212,7 +218,8 @@ :client-location (:client-location sl)})))) (update :locations #(mapv (fn [l] {:location l :id (random-uuid)}) %)) - (update :matches #(mapv (fn [l] {:match l}) %)) + (update :matches #(mapv (fn [l] {:match l + :id (random-uuid)}) %)) (update :bank-accounts (fn [bas] (mapv (fn [ba] @@ -367,182 +374,132 @@ (when active? [:div.card-content [:label.label "General"] - [horizontal-field - nil + [level/left-stack [:div.control [:p.help "Account Code"] (if new? - [:div.field.has-addons.is-extended + [:div.field.has-addons [:p.control [:a.button.is-static (:code new-client) "-" ]] [:p.control - [form-builder/raw-field - [:input.input {:type "code" - :field [:code] - :spec ::entity/code}]]]] + [form-builder/raw-field-v2 {:field :code} + [:input.input {:type "text"}]]]] [:div.field [:p.control code]])] - - - [form-builder/field + [form-builder/field-v2 {:field :name} "Nickname" [:input.input {:placeholder "BOA Checking #1" - :type "text" - :field [:name]}]] - [horizontal-field - nil - [form-builder/field - "Numeric Code" - [:input.input {:placeholder "20101" - :type "text" - :field [:numeric-code]}]]] - [form-builder/field + :type "text"}]] + [form-builder/field-v2 {:field :numeric-code} + "Numeric Code" + [com/number-input {:placeholder "20101" + :style {:width "8em"}}]] + [form-builder/field-v2 {:field :start-date} "Start date" - [date-picker {:type "date" - :output :cljs-date - :field [:start-date]}]]] + [date-picker {:output :cljs-date}]]] + (when (#{:check ":check"} type ) [:div [:label.label "Bank"] - [horizontal-field - nil - [form-builder/field + [level/left-stack + [form-builder/field-v2 {:field :bank-name} "Bank Name" [:input.input {:placeholder "Bank of America" - :type "text" - :field [:bank-name]}]] - [form-builder/field + :type "text"}]] + [form-builder/field-v2 {:field [:routing]} "Routing #" [:input.input {:placeholder "104819123" :style {:width "9em"} - :type "text" - :field [:routing]}]] - [form-builder/field + :type "text"}]] + [form-builder/field-v2 {:field :bank-code} "Bank code" [:input.input {:placeholder "12/10123" - :type "text" - :field [:bank-code]}]]] + :type "text"}]]] - [horizontal-field - nil - [form-builder/field + [level/left-stack + [form-builder/field-v2 {:field :number} "Account #" [:input.input {:placeholder "123456789" :type "text" - :style {:width "20em"} - :field [:number]}]] + :style {:width "20em"}}]] - [form-builder/field + [form-builder/field-v2 {:field :check-number} "Check Number" - [:input.input {:placeholder "10000" - :style {:width "6em"} - :type "text" - :field [:check-number]}]]] - [form-builder/field - "Yodlee Account" - [:input.input {:placeholder "Yodlee Account #" - :type "text" - :field [:yodlee-account-id]}]] - [form-builder/field + [com/number-input {:style {:width "8em"} + :placeholder "10000"}]]] + + [form-builder/field-v2 {:field :yodlee-account} "Yodlee Account (new)" [typeahead-v3 {:entities @(re-frame/subscribe [::yodlee-accounts (:id new-client)]) - :entity->text (fn [m] (str (:name m) " - " (:number m))) - :type "typeahead-v3" - :field [:yodlee-account]}]] - [:div.field - [:label.checkbox - [form-builder/raw-field - [:input {:type "checkbox" - :field [:use-date-instead-of-post-date]}]] - " (Yodlee only) Use 'date' instead of 'postDate'"]] + :entity->text (fn [m] (str (:name m) " - " (:number m)))}]] - [form-builder/field + + [form-builder/raw-field-v2 {:field :use-date-instead-of-post-date} + [com/checkbox {:label " (Yodlee only) Use 'date' instead of 'postDate'"}]] + + [form-builder/field-v2 {:field :intuit-bank-account} "Intuit Bank Account" [typeahead-v3 {:entities @(re-frame/subscribe [::subs/intuit-bank-accounts]) - :entity->text (fn [m] (str (:name m))) - :type "typeahead-v3" - :field [:intuit-bank-account]}]] - [form-builder/field + :entity->text (fn [m] (str (:name m)))}]] + [form-builder/field-v2 {:field :plaid-accounti} "Plaid Account" [typeahead-v3 {:entities @(re-frame/subscribe [::plaid-accounts (:id new-client)]) - :entity->text (fn [m] (str (:name m))) - :type "typeahead-v3" - :field [:plaid-account]}]]]) + :entity->text (fn [m] (str (:name m)))}]]]) (when (#{:credit ":credit"} type ) [:div [:label.label "Account"] - [horizontal-field - nil - [form-builder/field - "Bank Name" - [:input.input {:placeholder "Bank of America" - :type "text" - :field [:bank-name]}]]] - + [form-builder/field-v2 {:field :bank-name} + "Bank Name" + [:input.input {:placeholder "Bank of America" + :type "text"}]] - [horizontal-field - nil - [form-builder/field - "Account #" - [:input.input {:placeholder "123456789" - :type "text" - :field [:number]}]]] - - [form-builder/field - "Yodlee Account" - [:input.input {:placeholder "Yodlee Account #" + [form-builder/field-v2 {:field :number} + "Account #" + [:input.input {:placeholder "123456789" :type "text" - :field [:yodlee-account-id]}]] - [form-builder/field + :style {:width "20em"}}]] + + [form-builder/field-v2 {:field :yodlee-account} "Yodlee Account (new)" [typeahead-v3 {:entities @(re-frame/subscribe [::yodlee-accounts (:id new-client)]) - :entity->text (fn [m] (str (:name m) " - " (:number m))) - :type "typeahead-v3" - :field [:yodlee-account]}]] - [:div.field - [:label.checkbox - [form-builder/raw-field - [:input {:type "checkbox" - :field [:use-date-instead-of-post-date]}]] - " (Yodlee only) Use 'date' instead of 'postDate'"]] - [form-builder/field + :entity->text (fn [m] (str (:name m) " - " (:number m)))}]] + + [form-builder/raw-field-v2 {:field :use-date-instead-of-post-date} + [com/checkbox {:label "(Yodlee only) Use 'date' instead of 'postDate'"}] + [:input {:type "checkbox" + :field [:use-date-instead-of-post-date]}]] + + [form-builder/field-v2 {:field :intuit-bank-account} "Intuit Bank Account" [typeahead-v3 {:entities @(re-frame/subscribe [::subs/intuit-bank-accounts]) - :entity->text (fn [m] (str (:name m))) - :type "typeahead-v3" - :field [:intuit-bank-account]}]] - [form-builder/field + :entity->text (fn [m] (str (:name m)))}]] + + [form-builder/field-v2 {:field :plaid-account} "Plaid Account" [typeahead-v3 {:entities @(re-frame/subscribe [::plaid-accounts (:id new-client)]) - :entity->text (fn [m] (str (:name m))) - :type "typeahead-v3" - :field [:plaid-account]}]]]) + :entity->text (fn [m] (str (:name m)))}]]]) [:div.field [:label.label "Locations"] [:div.control [:p.help "If this account is location-specific, add the valid locations"] - [form-builder/raw-field - [multi-field {:type "multi-field" - :field [:locations] - :template [[:select.select {:type "select" - :style {:width "7em"} - :allow-nil? true - :field [:location] - :spec (set (map :location (get-in new-client [:locations])))} - [:<> - [:option ""] - [:<> (map (fn [l] ^{:key (:location l)} - [:option {:value (:location l)} (:location l)]) - (get-in new-client [:locations]))]]]]}]]]] - [:div.field - [:label.checkbox - [form-builder/raw-field - [:input {:type "checkbox" - :field [:include-in-reports]}]] - " Include in reports"]]]) + [form-builder/raw-field-v2 {:field :locations} + [com/multi-field-v2 {:template [[form-builder/raw-field {:key :location} + [com/select-field {:options (map (fn [l] + [(:location l) (:location l)]) + (get-in new-client [:locations])) + :allow-nil? true + :style {:width "7em"} + }]]] + :schema [:sequential location-schema] + :key-fn :id}]]]] + + [form-builder/raw-field-v2 {:field :include-in-reports} + [com/checkbox {:label "Include in reports"}] + ] + ]) (when active? [:footer.card-footer @@ -609,28 +566,32 @@ [form-builder/raw-field-v2 {:field :address} [address2-field]]]]]) +;; TODO Name matches, locations, bank account locations are all "single field multis", and require weird mounting and +;; unmounting. A new field could sort that out easily (defn matching-section [] [form-builder/section {:title "Matching"} - [form-builder/field + [form-builder/field-v2 {:field :matches} "Name matches" - [multi-field {:type "multi-field" - :field :matches - :template [[:input.input {:field [:match] - :placeholder "Harry's burger joint" - :style { :width "15em"}}]]}]] + [com/multi-field-v2 {:template [[form-builder/raw-field-v2 {:field [:match]} + [:input.input {:placeholder "Harry's burger joint" + :style { :width "15em"}}]]] + :key-fn :id + :next-key (random-uuid) + :schema [:sequential name-match-schema]}]] - [form-builder/field + [form-builder/field-v2 {:field :location-matches} "Location Matches" - [multi-field {:type "multi-field" - :field :location-matches - :template [[:input.input {:field [:match] - :placeholder "Downtown" - :style { :width "15em"}}] - [:input.input {:field [:location] - :placeholder "DT" - :max-length 2 - :style { :width "4em"}}]]}]]]) + [com/multi-field-v2 {:template [[form-builder/raw-field-v2 {:field :match} + [:input.input {:placeholder "Downtown" + :style { :width "15em"}}]] + [form-builder/raw-field-v2 {:field :location} + [:input.input {:placeholder "DT" + :max-length 2 + :style { :width "4em"}}]]] + :schema [:sequential location-match-schema] + :next-key (random-uuid) + :key-fn :id}]]]) (defn bank-accounts-section [] (let [{new-client :data} @(re-frame/subscribe [::forms/form ::form])]