more progress for client fdorm.

This commit is contained in:
2022-07-20 08:10:30 -07:00
parent 86aaa4a933
commit 899efe0efa
5 changed files with 130 additions and 100 deletions

View File

@@ -44,19 +44,21 @@
(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)
(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])
change-event (when-not on-change
(or change-event [::forms/change id]))
(let [data-sub (or data-sub [::forms/form id])
change-event (when-not on-change
(or change-event [::forms/change id]))
{:keys [data visited attempted-submit?] form-key :id} @(re-frame/subscribe data-sub)
data (or value data)
status @(re-frame/subscribe [::status/single id])
can-submit (if can-submit @(re-frame/subscribe can-submit)
true)
problems (when schema
(m/explain schema data))]
data (or value data)
status @(re-frame/subscribe [::status/single id])
can-submit (if can-submit @(re-frame/subscribe can-submit)
true)
;; TODO ONLY validate on blur
problems (when schema
(m/explain schema data))]
(r/create-element Provider #js {:value #js {:can-submit can-submit
:error-messages (or error-messages
nil)
nil)
:on-change on-change
:change-event change-event
:blur-event [::forms/visited id]
@@ -155,14 +157,14 @@
["visited" "attempted-submit?" "problems" "error-messages"]
(fn [visited attempted-submit? problems error-messages]
(consume FormScopeConsumer
["form-scope"]
(fn [form-scope]
["scope"]
(fn [scope]
(let [full-field-path (cond
(sequential? field)
(into form-scope field)
(into scope field)
field
(conj form-scope field)
(conj scope field)
:else
nil)
@@ -181,43 +183,43 @@
["visited" "attempted-submit?" "data" "on-change" "change-event" "blur-event" "problems"]
(fn [visited attempted-submit? data on-change change-event blur-event problems]
(consume FormScopeConsumer
["form-scope"]
(fn [form-scope]
["scope"]
(fn [scope]
(update child 1 (fn [child-props]
(let [
full-field-path (cond
(sequential? field)
(into form-scope field)
(let [
full-field-path (cond
(sequential? field)
(into scope field)
field
(conj form-scope field)
:else
nil)
visited? (get visited full-field-path)
value (get-in data full-field-path)]
(-> child-props
(assoc :on-change
(if on-change
(partial form-change-handler data full-field-path on-change)
(partial change-handler full-field-path change-event))
:on-blur (partial blur-handler full-field-path blur-event)
:value value)
(update :class (fn [class]
(str class
(cond
(and (not visited?) (not attempted-submit?))
""
(not (valid-field? problems full-field-path))
" is-danger"
value
"is-success"
field
(conj scope field)
:else
""))))))))))))))
nil)
visited? (get visited full-field-path)
value (get-in data full-field-path)]
(-> child-props
(assoc :on-change
(if on-change
(partial form-change-handler data full-field-path on-change)
(partial change-handler full-field-path change-event))
:on-blur (partial blur-handler full-field-path blur-event)
:value value)
(update :class (fn [class]
(str class
(cond
(and (not visited?) (not attempted-submit?))
""
(not (valid-field? problems full-field-path))
" is-danger"
value
"is-success"
:else
""))))))))))))))
(defn with-scope [{:keys [scope]}]
(r/create-element FormScopeProvider #js {:value scope}
(r/create-element FormScopeProvider #js {:value #js {:scope scope}}
(r/as-element (into [:<>]
(r/children (r/current-component))))))

View File

@@ -11,6 +11,7 @@
(def money (m/schema [float? {:error/message "Invalid money"}]))
(def not-empty-string (m/schema [:re {:error/message "Required"} #"\S+"]))
(def code-string (m/schema [:re #"[A-Z0-9\-]+"]))
(def keyword (m/schema [:fn (fn [d]
(keyword? d))]))

View File

@@ -1,6 +1,7 @@
(ns auto-ap.views.components
(:require [reagent.core :as r]
[clojure.string :as str]))
[clojure.string :as str]
[auto-ap.views.components.multi :as multi]))
(defn checkbox [{:keys [on-change
@@ -32,3 +33,5 @@
[:option {:value nil}])
(for [[k v] options]
^{:key k} [:option {:value k} v])]]])
(def multi-field-v2 multi/multi-field-v2)

View File

@@ -20,9 +20,9 @@
[:div {:style {:margin-bottom "0.25em"}}
(into [appearing-group]
(for [[i override] (map vector (range) prop-value)
:let [is-disabled? (if (= false allow-change?)
(not (boolean (::new? override)))
nil)]]
:let [extant? (boolean (key-fn override))
is-disabled? (boolean (and (= false allow-change?)
extant?))]]
^{:key (or (key-fn override)
(::key override))}
@@ -31,25 +31,31 @@
(::key override))}
[:div.level {:style {:margin-bottom "0.25em"}}
[:div.level-left {:style {:padding "0.5em 1em"}
:class (when-not (key-fn override)
:class (when-not extant?
"has-background-info-light")}
(let [template (if (fn? template)
(template override)
template)]
(for [[idx template] (map vector (range ) template)]
^{:key idx}
[:div.level-item
template]))
(when-not disable-remove?
[:div.level-item
[:a.button.level-item
{:disabled is-disabled?
:on-click (fn []
(on-change (into []
(for [[idx item] (map vector (range) prop-value)
:when (not= idx i)]
item))))}
[:span.icon [:span.icon-remove]]]])]]]))
[:fieldset.level-left {:disabled is-disabled?
:style {:padding "0.5em 1em"}
:class (when-not extant?
"has-background-info-light")}
(for [[idx template] (map vector (range ) template)]
^{:key idx}
[:div.level-item
template])
(when-not (and disable-remove?
extant?)
[:div.level-item
[:a.button.level-item
{:disabled is-disabled?
:on-click (fn []
(on-change (into []
(for [[idx item] (map vector (range) prop-value)
:when (not= idx i)]
item))))}
[:span.icon [:span.icon-remove]]]])])
]]]))
(when-not disable-new?
[:button.button.is-outline
{:type "button"

View File

@@ -10,6 +10,7 @@
[react-signature-canvas]
[auto-ap.views.components.typeahead :refer [typeahead-v3]]
[auto-ap.views.components.level :refer [left-stack]]
[auto-ap.views.components :as com]
[auto-ap.views.components.typeahead.vendor
:refer [search-backed-typeahead]]
[auto-ap.views.utils
@@ -24,10 +25,25 @@
[re-frame.core :as re-frame]
[reagent.core :as r]
[react-signature-canvas]
[vimsical.re-frame.cofx.inject :as inject]))
[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 email-schema [:map
[:email schema/not-empty-string]
[:description schema/not-empty-string]])
(def client-schema [:map
[:name schema/not-empty-string]
[:code schema/code-string]
[:locations [:sequential location-schema]]
[:emails [:sequential email-schema]]])
(defn upload-replacement-button [{:keys [on-change]} text]
(let [button (atom nil)]
(r/create-class {:display-name "Upload button"
@@ -109,7 +125,8 @@
{:id (:id new-client-data),
:name (:name new-client-data)
:code (:code new-client-data) ;; TODO add validation can't change
:emails (:emails new-client-data)
:emails (map #(select-keys % [:id :email :description])
(:emails new-client-data))
:square-auth-token (:square-auth-token new-client-data)
:square-locations (map
(fn [x]
@@ -193,13 +210,15 @@
{:id (:id sl)
:square-location sl
:client-location (:client-location sl)}))))
(update :locations #(mapv (fn [l] {:location l}) %))
(update :locations #(mapv (fn [l] {:location l
:id (random-uuid)}) %))
(update :matches #(mapv (fn [l] {:match l}) %))
(update :bank-accounts
(fn [bas]
(mapv (fn [ba]
(update ba :locations (fn [ls]
(map (fn [l] {:location l})
(map (fn [l] {:location l
:id (random-uuid)})
ls))))
bas))))))}))
@@ -535,57 +554,54 @@
(defn general-section []
(let [{new-client :data} @(re-frame/subscribe [::forms/form ::form])]
[form-builder/section {:title "General"}
[form-builder/field
[form-builder/field-v2 {:field :name}
"Name"
[:input.input {:type "text"
:style {:width "20em"}
:field [:name]
:spec ::entity/name}]]
[form-builder/field
:style {:width "20em"}}]]
[form-builder/field-v2 {:field :code}
"Client code"
[:input.input {:type "code"
:style {:width "5em"}
:field :code
:disabled (boolean (:id new-client))
:spec ::entity/code}]]
[form-builder/field
[form-builder/field-v2 {:field :locations}
"Locations"
[multi-field {:type "multi-field"
:field :locations
:allow-change? false
:template [[:input.input {:field [:location]
:max-length 2
:style { :width "4em"}}]]}]]
[com/multi-field-v2 {:allow-change? false
:template [[form-builder/raw-field-v2 {:field :location}
[:input.input {:max-length 2
:style { :width "4em"}}]]]
:disable-remove? true
:key-fn :id
:schema [:sequential location-schema]
:next-key (random-uuid)}]]
[:div.field
[:label.label "Signature"]
[form-builder/vertical-control
"Signature"
[signature {:signature-file (:signature-file new-client)
:signature-data (:signature-data new-client)
:on-change (fn [uri]
(re-frame/dispatch [::forms/change ::form [:signature-data] uri]))}]]
[form-builder/field
[form-builder/field-v2 {:field :locked-until}
"Locked Until"
[date-picker {:type "date"
:output :cljs-date
:field [:locked-until]
:style {:width "15em"}}]]]))
[date-picker {:output :cljs-date
:style {:width "15em"}}]]]))
(defn contacts-section []
[form-builder/section {:title "Contacts"}
[form-builder/field
[form-builder/field-v2 {:field :emails}
"Emails (address/description)"
[multi-field {:type "multi-field"
:field :emails
:template [[:input.input {:type "email"
:field [:email]
:placeholder "tom@myspace.com"
:spec ::entity/email}]
[:input.input {:type "text"
:placeholder "Manager"
:field [:description]}]]}]]
[com/multi-field-v2 {:template [[form-builder/raw-field-v2 {:field :email}
[:input.input {:type "email"
:placeholder "tom@myspace.com"}]]
[form-builder/raw-field-v2 {:field :description}
[:input.input {:type "text"
:placeholder "Manager"}]]]
:key-fn :id
:schema [:sequential email-schema]
:next-key (random-uuid)}]]
[form-builder/vertical-control
"Address"
@@ -735,6 +751,7 @@
:step "0.01"}]]
:disable-remove? true}]]])
(defn form-content []
(let [_ @(re-frame/subscribe [::client])
{new-client :data} @(re-frame/subscribe [::forms/form ::form])]
@@ -743,7 +760,8 @@
"new")}
[form-builder/builder {:submit-event [::save-new-client ]
:id ::form
:fullwidth? false}
:fullwidth? false
:schema client-schema}
[general-section]
[contacts-section]