more progress for client fdorm.
This commit is contained in:
@@ -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]}]
|
(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 visited attempted-submit?] form-key :id} @(re-frame/subscribe data-sub)
|
{:keys [data 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
|
;; TODO ONLY validate on blur
|
||||||
(m/explain schema data))]
|
problems (when schema
|
||||||
|
|
||||||
|
(m/explain schema data))]
|
||||||
(r/create-element Provider #js {:value #js {:can-submit can-submit
|
(r/create-element Provider #js {:value #js {:can-submit can-submit
|
||||||
:error-messages (or error-messages
|
: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]
|
||||||
@@ -155,14 +157,14 @@
|
|||||||
["visited" "attempted-submit?" "problems" "error-messages"]
|
["visited" "attempted-submit?" "problems" "error-messages"]
|
||||||
(fn [visited attempted-submit? problems error-messages]
|
(fn [visited attempted-submit? problems error-messages]
|
||||||
(consume FormScopeConsumer
|
(consume FormScopeConsumer
|
||||||
["form-scope"]
|
["scope"]
|
||||||
(fn [form-scope]
|
(fn [scope]
|
||||||
(let [full-field-path (cond
|
(let [full-field-path (cond
|
||||||
(sequential? field)
|
(sequential? field)
|
||||||
(into form-scope field)
|
(into scope field)
|
||||||
|
|
||||||
field
|
field
|
||||||
(conj form-scope field)
|
(conj scope field)
|
||||||
|
|
||||||
:else
|
:else
|
||||||
nil)
|
nil)
|
||||||
@@ -181,43 +183,43 @@
|
|||||||
["visited" "attempted-submit?" "data" "on-change" "change-event" "blur-event" "problems"]
|
["visited" "attempted-submit?" "data" "on-change" "change-event" "blur-event" "problems"]
|
||||||
(fn [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
|
(consume FormScopeConsumer
|
||||||
["form-scope"]
|
["scope"]
|
||||||
(fn [form-scope]
|
(fn [scope]
|
||||||
(update child 1 (fn [child-props]
|
(update child 1 (fn [child-props]
|
||||||
(let [
|
(let [
|
||||||
full-field-path (cond
|
full-field-path (cond
|
||||||
(sequential? field)
|
(sequential? field)
|
||||||
(into form-scope field)
|
(into scope field)
|
||||||
|
|
||||||
field
|
field
|
||||||
(conj form-scope 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
|
: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]}]
|
(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/as-element (into [:<>]
|
||||||
(r/children (r/current-component))))))
|
(r/children (r/current-component))))))
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
|
|
||||||
(def money (m/schema [float? {:error/message "Invalid money"}]))
|
(def money (m/schema [float? {:error/message "Invalid money"}]))
|
||||||
(def not-empty-string (m/schema [:re {:error/message "Required"} #"\S+"]))
|
(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]
|
(def keyword (m/schema [:fn (fn [d]
|
||||||
(keyword? d))]))
|
(keyword? d))]))
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
(ns auto-ap.views.components
|
(ns auto-ap.views.components
|
||||||
(:require [reagent.core :as r]
|
(: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
|
(defn checkbox [{:keys [on-change
|
||||||
@@ -32,3 +33,5 @@
|
|||||||
[:option {:value nil}])
|
[:option {:value nil}])
|
||||||
(for [[k v] options]
|
(for [[k v] options]
|
||||||
^{:key k} [:option {:value k} v])]]])
|
^{:key k} [:option {:value k} v])]]])
|
||||||
|
|
||||||
|
(def multi-field-v2 multi/multi-field-v2)
|
||||||
|
|||||||
@@ -20,9 +20,9 @@
|
|||||||
[:div {:style {:margin-bottom "0.25em"}}
|
[:div {:style {:margin-bottom "0.25em"}}
|
||||||
(into [appearing-group]
|
(into [appearing-group]
|
||||||
(for [[i override] (map vector (range) prop-value)
|
(for [[i override] (map vector (range) prop-value)
|
||||||
:let [is-disabled? (if (= false allow-change?)
|
:let [extant? (boolean (key-fn override))
|
||||||
(not (boolean (::new? override)))
|
is-disabled? (boolean (and (= false allow-change?)
|
||||||
nil)]]
|
extant?))]]
|
||||||
|
|
||||||
^{:key (or (key-fn override)
|
^{:key (or (key-fn override)
|
||||||
(::key override))}
|
(::key override))}
|
||||||
@@ -31,25 +31,31 @@
|
|||||||
(::key override))}
|
(::key override))}
|
||||||
[:div.level {:style {:margin-bottom "0.25em"}}
|
[:div.level {:style {:margin-bottom "0.25em"}}
|
||||||
[:div.level-left {:style {:padding "0.5em 1em"}
|
[:div.level-left {:style {:padding "0.5em 1em"}
|
||||||
:class (when-not (key-fn override)
|
:class (when-not extant?
|
||||||
"has-background-info-light")}
|
"has-background-info-light")}
|
||||||
(let [template (if (fn? template)
|
(let [template (if (fn? template)
|
||||||
(template override)
|
(template override)
|
||||||
template)]
|
template)]
|
||||||
(for [[idx template] (map vector (range ) template)]
|
[:fieldset.level-left {:disabled is-disabled?
|
||||||
^{:key idx}
|
:style {:padding "0.5em 1em"}
|
||||||
[:div.level-item
|
:class (when-not extant?
|
||||||
template]))
|
"has-background-info-light")}
|
||||||
(when-not disable-remove?
|
(for [[idx template] (map vector (range ) template)]
|
||||||
[:div.level-item
|
^{:key idx}
|
||||||
[:a.button.level-item
|
[:div.level-item
|
||||||
{:disabled is-disabled?
|
template])
|
||||||
:on-click (fn []
|
(when-not (and disable-remove?
|
||||||
(on-change (into []
|
extant?)
|
||||||
(for [[idx item] (map vector (range) prop-value)
|
[:div.level-item
|
||||||
:when (not= idx i)]
|
[:a.button.level-item
|
||||||
item))))}
|
{:disabled is-disabled?
|
||||||
[:span.icon [:span.icon-remove]]]])]]]))
|
: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?
|
(when-not disable-new?
|
||||||
[:button.button.is-outline
|
[:button.button.is-outline
|
||||||
{:type "button"
|
{:type "button"
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
[react-signature-canvas]
|
[react-signature-canvas]
|
||||||
[auto-ap.views.components.typeahead :refer [typeahead-v3]]
|
[auto-ap.views.components.typeahead :refer [typeahead-v3]]
|
||||||
[auto-ap.views.components.level :refer [left-stack]]
|
[auto-ap.views.components.level :refer [left-stack]]
|
||||||
|
[auto-ap.views.components :as com]
|
||||||
[auto-ap.views.components.typeahead.vendor
|
[auto-ap.views.components.typeahead.vendor
|
||||||
:refer [search-backed-typeahead]]
|
:refer [search-backed-typeahead]]
|
||||||
[auto-ap.views.utils
|
[auto-ap.views.utils
|
||||||
@@ -24,10 +25,25 @@
|
|||||||
[re-frame.core :as re-frame]
|
[re-frame.core :as re-frame]
|
||||||
[reagent.core :as r]
|
[reagent.core :as r]
|
||||||
[react-signature-canvas]
|
[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 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]
|
(defn upload-replacement-button [{:keys [on-change]} text]
|
||||||
(let [button (atom nil)]
|
(let [button (atom nil)]
|
||||||
(r/create-class {:display-name "Upload button"
|
(r/create-class {:display-name "Upload button"
|
||||||
@@ -109,7 +125,8 @@
|
|||||||
{:id (:id new-client-data),
|
{:id (:id new-client-data),
|
||||||
:name (:name new-client-data)
|
:name (:name new-client-data)
|
||||||
:code (:code new-client-data) ;; TODO add validation can't change
|
: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-auth-token (:square-auth-token new-client-data)
|
||||||
:square-locations (map
|
:square-locations (map
|
||||||
(fn [x]
|
(fn [x]
|
||||||
@@ -193,13 +210,15 @@
|
|||||||
{:id (:id sl)
|
{:id (:id sl)
|
||||||
:square-location sl
|
:square-location sl
|
||||||
:client-location (:client-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 :matches #(mapv (fn [l] {:match l}) %))
|
||||||
(update :bank-accounts
|
(update :bank-accounts
|
||||||
(fn [bas]
|
(fn [bas]
|
||||||
(mapv (fn [ba]
|
(mapv (fn [ba]
|
||||||
(update ba :locations (fn [ls]
|
(update ba :locations (fn [ls]
|
||||||
(map (fn [l] {:location l})
|
(map (fn [l] {:location l
|
||||||
|
:id (random-uuid)})
|
||||||
ls))))
|
ls))))
|
||||||
bas))))))}))
|
bas))))))}))
|
||||||
|
|
||||||
@@ -535,57 +554,54 @@
|
|||||||
(defn general-section []
|
(defn general-section []
|
||||||
(let [{new-client :data} @(re-frame/subscribe [::forms/form ::form])]
|
(let [{new-client :data} @(re-frame/subscribe [::forms/form ::form])]
|
||||||
[form-builder/section {:title "General"}
|
[form-builder/section {:title "General"}
|
||||||
[form-builder/field
|
[form-builder/field-v2 {:field :name}
|
||||||
"Name"
|
"Name"
|
||||||
[:input.input {:type "text"
|
[:input.input {:type "text"
|
||||||
:style {:width "20em"}
|
:style {:width "20em"}}]]
|
||||||
:field [:name]
|
[form-builder/field-v2 {:field :code}
|
||||||
:spec ::entity/name}]]
|
|
||||||
[form-builder/field
|
|
||||||
"Client code"
|
"Client code"
|
||||||
[:input.input {:type "code"
|
[:input.input {:type "code"
|
||||||
:style {:width "5em"}
|
:style {:width "5em"}
|
||||||
:field :code
|
|
||||||
:disabled (boolean (:id new-client))
|
:disabled (boolean (:id new-client))
|
||||||
:spec ::entity/code}]]
|
:spec ::entity/code}]]
|
||||||
|
|
||||||
[form-builder/field
|
[form-builder/field-v2 {:field :locations}
|
||||||
"Locations"
|
"Locations"
|
||||||
[multi-field {:type "multi-field"
|
[com/multi-field-v2 {:allow-change? false
|
||||||
:field :locations
|
:template [[form-builder/raw-field-v2 {:field :location}
|
||||||
:allow-change? false
|
[:input.input {:max-length 2
|
||||||
:template [[:input.input {:field [:location]
|
:style { :width "4em"}}]]]
|
||||||
:max-length 2
|
:disable-remove? true
|
||||||
:style { :width "4em"}}]]}]]
|
:key-fn :id
|
||||||
|
:schema [:sequential location-schema]
|
||||||
|
:next-key (random-uuid)}]]
|
||||||
|
|
||||||
[:div.field
|
[form-builder/vertical-control
|
||||||
[:label.label "Signature"]
|
"Signature"
|
||||||
[signature {:signature-file (:signature-file new-client)
|
[signature {:signature-file (:signature-file new-client)
|
||||||
:signature-data (:signature-data new-client)
|
:signature-data (:signature-data new-client)
|
||||||
:on-change (fn [uri]
|
:on-change (fn [uri]
|
||||||
(re-frame/dispatch [::forms/change ::form [:signature-data] uri]))}]]
|
(re-frame/dispatch [::forms/change ::form [:signature-data] uri]))}]]
|
||||||
|
|
||||||
[form-builder/field
|
[form-builder/field-v2 {:field :locked-until}
|
||||||
"Locked Until"
|
"Locked Until"
|
||||||
[date-picker {:type "date"
|
[date-picker {:output :cljs-date
|
||||||
:output :cljs-date
|
:style {:width "15em"}}]]]))
|
||||||
:field [:locked-until]
|
|
||||||
:style {:width "15em"}}]]]))
|
|
||||||
|
|
||||||
(defn contacts-section []
|
(defn contacts-section []
|
||||||
[form-builder/section {:title "Contacts"}
|
[form-builder/section {:title "Contacts"}
|
||||||
|
|
||||||
[form-builder/field
|
[form-builder/field-v2 {:field :emails}
|
||||||
"Emails (address/description)"
|
"Emails (address/description)"
|
||||||
[multi-field {:type "multi-field"
|
[com/multi-field-v2 {:template [[form-builder/raw-field-v2 {:field :email}
|
||||||
:field :emails
|
[:input.input {:type "email"
|
||||||
:template [[:input.input {:type "email"
|
:placeholder "tom@myspace.com"}]]
|
||||||
:field [:email]
|
[form-builder/raw-field-v2 {:field :description}
|
||||||
:placeholder "tom@myspace.com"
|
[:input.input {:type "text"
|
||||||
:spec ::entity/email}]
|
:placeholder "Manager"}]]]
|
||||||
[:input.input {:type "text"
|
:key-fn :id
|
||||||
:placeholder "Manager"
|
:schema [:sequential email-schema]
|
||||||
:field [:description]}]]}]]
|
:next-key (random-uuid)}]]
|
||||||
|
|
||||||
[form-builder/vertical-control
|
[form-builder/vertical-control
|
||||||
"Address"
|
"Address"
|
||||||
@@ -735,6 +751,7 @@
|
|||||||
:step "0.01"}]]
|
:step "0.01"}]]
|
||||||
:disable-remove? true}]]])
|
:disable-remove? true}]]])
|
||||||
|
|
||||||
|
|
||||||
(defn form-content []
|
(defn form-content []
|
||||||
(let [_ @(re-frame/subscribe [::client])
|
(let [_ @(re-frame/subscribe [::client])
|
||||||
{new-client :data} @(re-frame/subscribe [::forms/form ::form])]
|
{new-client :data} @(re-frame/subscribe [::forms/form ::form])]
|
||||||
@@ -743,7 +760,8 @@
|
|||||||
"new")}
|
"new")}
|
||||||
[form-builder/builder {:submit-event [::save-new-client ]
|
[form-builder/builder {:submit-event [::save-new-client ]
|
||||||
:id ::form
|
:id ::form
|
||||||
:fullwidth? false}
|
:fullwidth? false
|
||||||
|
:schema client-schema}
|
||||||
|
|
||||||
[general-section]
|
[general-section]
|
||||||
[contacts-section]
|
[contacts-section]
|
||||||
|
|||||||
Reference in New Issue
Block a user