Form builder as a way to simplify some things
This commit is contained in:
@@ -17,15 +17,7 @@
|
||||
:data
|
||||
(get-in f))))
|
||||
|
||||
|
||||
(re-frame/reg-sub
|
||||
::is-loading?
|
||||
(fn [db [_ x]]
|
||||
(if (#{"loading" :loading} (get-in db [::forms x :status]) )
|
||||
true
|
||||
false)))
|
||||
|
||||
(re-frame/reg-sub
|
||||
(re-frame/reg-sub
|
||||
::loading-class
|
||||
(fn [db [_ x]]
|
||||
(if (#{"loading" :loading} (get-in db [::forms x :status]) )
|
||||
@@ -43,10 +35,6 @@
|
||||
:data data
|
||||
:complete-listener complete-listener})))
|
||||
|
||||
(defn ^:depracated saved-form [db form data]
|
||||
(update-in db [::forms form]
|
||||
assoc :error nil :status nil :data data))
|
||||
|
||||
(defn triggers-saved [form data-key]
|
||||
(i/->interceptor
|
||||
:id :triggers-saved
|
||||
@@ -55,7 +43,6 @@
|
||||
:after (fn [context]
|
||||
(let [db (i/get-coeffect context :db)
|
||||
result (get-in (i/get-coeffect context :event) [1 data-key])]
|
||||
|
||||
(cond-> context
|
||||
true
|
||||
(i/assoc-effect :db (update-in db
|
||||
|
||||
106
src/cljs/auto_ap/forms/builder.cljs
Normal file
106
src/cljs/auto_ap/forms/builder.cljs
Normal file
@@ -0,0 +1,106 @@
|
||||
(ns auto-ap.forms.builder
|
||||
(:require
|
||||
[auto-ap.views.utils :refer [bind-field]]
|
||||
[re-frame.core :as re-frame]
|
||||
[react :as react]
|
||||
[reagent.core :as r]
|
||||
[auto-ap.forms :as forms]
|
||||
[auto-ap.status :as status]))
|
||||
|
||||
(defonce ^js/React.Context form-context (react/createContext "default"))
|
||||
(def ^js/React.Provider Provider (. form-context -Provider))
|
||||
(def ^js/React.Consumer Consumer (. form-context -Consumer))
|
||||
|
||||
(defonce ^js/React.Context form-scope-context (react/createContext []))
|
||||
(def ^js/React.Provider FormScopeProvider (. form-scope-context -Provider))
|
||||
(def ^js/React.Consumer FormScopeConsumer (. form-scope-context -Consumer))
|
||||
|
||||
(defn builder [{:keys [can-submit data-sub change-event submit-event id fullwidth?] :as z}]
|
||||
(let [data-sub (or data-sub [::forms/form id])
|
||||
change-event (or change-event [::forms/change id])
|
||||
{:keys [data error]} @(re-frame/subscribe data-sub)]
|
||||
(r/create-element Provider #js {:value #js {:can-submit @(re-frame/subscribe can-submit)
|
||||
:change-event change-event
|
||||
:submit-event submit-event
|
||||
:error error
|
||||
:status @(re-frame/subscribe [::status/single id])
|
||||
:id id
|
||||
:data data
|
||||
:fullwidth? fullwidth?}}
|
||||
(r/as-element
|
||||
(into [:form {:on-submit (fn [e]
|
||||
(when (.-stopPropagation e)
|
||||
(.stopPropagation e)
|
||||
(.preventDefault e))
|
||||
(when can-submit
|
||||
(re-frame/dispatch-sync (vec (conj submit-event {})))))}]
|
||||
(r/children (r/current-component)))))))
|
||||
|
||||
(defn raw-field []
|
||||
(let [[child] (r/children (r/current-component))]
|
||||
[:> Consumer {}
|
||||
(fn [consume-form]
|
||||
(r/as-element
|
||||
[:> FormScopeConsumer {}
|
||||
(fn [form-scope]
|
||||
(r/as-element
|
||||
[bind-field (-> child
|
||||
(update-in [1 :field] (fn [f]
|
||||
(cond
|
||||
(sequential? f)
|
||||
(into form-scope f)
|
||||
|
||||
f
|
||||
(conj form-scope f)
|
||||
|
||||
:else
|
||||
nil)))
|
||||
(assoc-in [1 :subscription] (aget consume-form "data"))
|
||||
(assoc-in [1 :event] (aget consume-form "change-event")))]))]))]))
|
||||
|
||||
(defn with-scope [{:keys [scope]}]
|
||||
(r/create-element FormScopeProvider #js {:value scope}
|
||||
(r/as-element (into [:<>]
|
||||
(r/children (r/current-component))))))
|
||||
|
||||
(defn field []
|
||||
(let [[label child] (r/children (r/current-component))]
|
||||
[:> Consumer {}
|
||||
(fn [consume]
|
||||
(r/as-element
|
||||
[:div.field
|
||||
(when label (if (aget consume "fullwidth?") [:p.help label]
|
||||
[:label.label label]))
|
||||
[:div.control [raw-field {} child]]]))]))
|
||||
|
||||
(defn section [{:keys [title]}]
|
||||
[:<>
|
||||
[:h4.is-4.title title]
|
||||
[:hr]
|
||||
(into [:div {:style {:margin-bottom "5em"}}]
|
||||
(r/children (r/current-component)))])
|
||||
|
||||
(defn submit-button []
|
||||
(let [[child] (r/children (r/current-component))]
|
||||
[:> Consumer {}
|
||||
(fn [consume]
|
||||
(let [status (aget consume "status")
|
||||
can-submit (aget consume "can-submit")
|
||||
fullwidth? (aget consume "fullwidth?")]
|
||||
(r/as-element
|
||||
[:button.button.is-medium.is-primary {:disabled (or (status/disabled-for status)
|
||||
(not can-submit))
|
||||
:class (cond-> (status/class-for status)
|
||||
fullwidth? (conj "is-fullwidth")) }
|
||||
child])))]))
|
||||
|
||||
(defn error-notification []
|
||||
(let [[child] (r/children (r/current-component))]
|
||||
[:> Consumer {}
|
||||
(fn [consume]
|
||||
(r/as-element
|
||||
(when-let [error (aget consume "error")]
|
||||
^{:key error}
|
||||
[:div.has-text-danger.animated.fadeInUp {} error])))]))
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
(ns auto-ap.views.components.address
|
||||
(:require [auto-ap.entities.address :as address]
|
||||
[auto-ap.views.utils :refer [dispatch-value-change dispatch-event bind-field horizontal-field]]))
|
||||
[auto-ap.views.utils :refer [dispatch-value-change dispatch-event bind-field horizontal-field]]
|
||||
[auto-ap.forms.builder :as form-builder]))
|
||||
|
||||
(defn address-field [{:keys [event field subscription]}]
|
||||
[:span
|
||||
@@ -58,3 +59,50 @@
|
||||
:event event
|
||||
:subscription subscription
|
||||
:placeholder "95014"}]]]]])
|
||||
|
||||
(defn address2-field []
|
||||
[:span
|
||||
[horizontal-field
|
||||
nil
|
||||
[:div.control
|
||||
[:p.help "Address"]
|
||||
[form-builder/raw-field
|
||||
[:input.input.is-expanded {:type "text"
|
||||
:placeholder "1700 Pennsylvania Ave"
|
||||
:field [:street1]
|
||||
:spec ::address/street1}]]]]
|
||||
|
||||
[horizontal-field
|
||||
nil
|
||||
[:div.control
|
||||
[form-builder/raw-field
|
||||
[:input.input.is-expanded {:type "text"
|
||||
:placeholder "Suite 400"
|
||||
:field [:street2]
|
||||
:spec ::address/street2}]]]]
|
||||
|
||||
[horizontal-field
|
||||
nil
|
||||
[:div.control
|
||||
[:p.help "City"]
|
||||
[form-builder/raw-field
|
||||
[:input.input.is-expanded {:type "text"
|
||||
:placeholder "Cupertino"
|
||||
:field [:city]
|
||||
:spec ::address/city}]]]
|
||||
[:div.control
|
||||
[:p.help "State"]
|
||||
[form-builder/raw-field
|
||||
[:input.input {:type "text"
|
||||
:placeholder "CA"
|
||||
:field [:state]
|
||||
:spec ::address/state
|
||||
:size 2
|
||||
:max-length "2"}]]]
|
||||
[:div.control
|
||||
[:p.help "Zip"]
|
||||
[form-builder/raw-field
|
||||
[:input.input {:type "text"
|
||||
:field [:zip]
|
||||
:spec ::address/zip
|
||||
:placeholder "95014"}]]]]])
|
||||
|
||||
@@ -1,21 +1,20 @@
|
||||
(ns auto-ap.views.pages.admin.clients
|
||||
(:require
|
||||
[auto-ap.forms :as forms]
|
||||
[auto-ap.subs :as subs]
|
||||
[auto-ap.routes :as routes]
|
||||
[auto-ap.status :as status]
|
||||
[auto-ap.subs :as subs]
|
||||
[auto-ap.views.components.admin.side-bar :refer [admin-side-bar]]
|
||||
[auto-ap.views.components.grid :as grid]
|
||||
[auto-ap.views.components.layouts :refer [side-bar-layout]]
|
||||
[auto-ap.views.pages.admin.clients.form :as form]
|
||||
[auto-ap.views.pages.admin.clients.side-bar :as side-bar]
|
||||
[auto-ap.views.pages.admin.clients.table :as table]
|
||||
[auto-ap.views.utils :refer [dispatch-event transition switch-transition with-user transition-group]]
|
||||
[auto-ap.views.pages.page-stack :as page-stack]
|
||||
[auto-ap.views.utils :refer [with-user]]
|
||||
[bidi.bidi :as bidi]
|
||||
[clojure.string :as str]
|
||||
[re-frame.core :as re-frame]
|
||||
[reagent.core :as r]
|
||||
[vimsical.re-frame.fx.track :as track]
|
||||
[bidi.bidi :as bidi]
|
||||
[auto-ap.routes :as routes]))
|
||||
[vimsical.re-frame.fx.track :as track]))
|
||||
|
||||
(re-frame/reg-event-db
|
||||
::received-intuit-bank-accounts
|
||||
@@ -25,7 +24,7 @@
|
||||
(re-frame/reg-event-fx
|
||||
::mounted
|
||||
[with-user]
|
||||
(fn [{:keys [db user]} _]
|
||||
(fn [{:keys [user]} _]
|
||||
{::track/register {:id ::params
|
||||
:subscription [::params]
|
||||
:event-fn (fn [params] [::params-change params])}
|
||||
@@ -49,14 +48,6 @@
|
||||
(seq filter-params) (merge filter-params)
|
||||
(seq table-params) (merge table-params))))
|
||||
|
||||
|
||||
|
||||
(re-frame/reg-event-db
|
||||
::new
|
||||
(fn [db [_ client-id]]
|
||||
(-> db
|
||||
(forms/start-form ::form/form {:bank-accounts []}))))
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::params-change
|
||||
(fn [_ [_ params]]
|
||||
@@ -75,125 +66,28 @@
|
||||
(assoc (grid/virtual-paginate-controls (:start params ) (:per-page params) matching-clients)
|
||||
:data (grid/virtual-paginate (:start params) (:per-page params) matching-clients)))))
|
||||
|
||||
|
||||
(defn stacked-page [& children]
|
||||
[:div
|
||||
(->> children
|
||||
(reverse)
|
||||
(filter identity)
|
||||
first)])
|
||||
|
||||
(defn hierachy []
|
||||
(let [last-stack-size (r/atom (->> (r/current-component)
|
||||
r/children
|
||||
(filter identity) count))
|
||||
forward? (r/atom false)]
|
||||
(fn []
|
||||
(let [stack (filter identity (r/children (r/current-component)))
|
||||
current-stack-size (count stack)
|
||||
current-child (last stack)]
|
||||
(when (not= current-stack-size @last-stack-size)
|
||||
(reset! forward? (> current-stack-size @last-stack-size))
|
||||
(reset! last-stack-size current-stack-size))
|
||||
[:div
|
||||
[switch-transition {:mode "in-out"}
|
||||
|
||||
^{:key current-stack-size}
|
||||
[transition
|
||||
{:timeout 100
|
||||
:exit true
|
||||
:in true #_(= current-stack- (:key (meta child)))
|
||||
:appear (> current-stack-size 1)}
|
||||
(clj->js (fn [state]
|
||||
(r/as-element
|
||||
[:div {:style {
|
||||
:position (cond
|
||||
(= "entered" state)
|
||||
""
|
||||
|
||||
(= "entering" state)
|
||||
"absolute"
|
||||
|
||||
(= "exiting" state)
|
||||
"absolute"
|
||||
|
||||
(= "exited" state)
|
||||
"")
|
||||
|
||||
:transition "opacity 300ms ease-in-out, transform 300ms ease-in-out"
|
||||
|
||||
:opacity (cond
|
||||
(= "entered" state)
|
||||
""
|
||||
|
||||
(= "entering" state)
|
||||
0.0
|
||||
|
||||
(= "exiting" state)
|
||||
1.0
|
||||
|
||||
(= "exited" state)
|
||||
0.0)
|
||||
:transform (if @forward?
|
||||
(cond
|
||||
(= "entered" state)
|
||||
""
|
||||
|
||||
(= "entering" state)
|
||||
"translateX(100%)"
|
||||
|
||||
(= "exiting" state)
|
||||
"translateX(-100%)"
|
||||
|
||||
(= "exited" state)
|
||||
"translateX(0%)")
|
||||
(cond
|
||||
(= "entered" state)
|
||||
""
|
||||
|
||||
(= "entering" state)
|
||||
"translateX(-100%)"
|
||||
|
||||
(= "exiting" state)
|
||||
"translateX(100%)"
|
||||
|
||||
(= "exited" state)
|
||||
"translateX(0%)"))}}
|
||||
current-child])))]]
|
||||
]))))
|
||||
|
||||
(defn test-appear []
|
||||
[:div
|
||||
[hierachy
|
||||
[table/clients-table {:page @(re-frame/subscribe [::page])
|
||||
:status @(re-frame/subscribe [::status/single ::page])}]
|
||||
(when (#{:admin-specific-bank-account :admin-specific-client} @(re-frame/subscribe [::subs/active-route]))
|
||||
[form/new-client-form])
|
||||
(when (= :admin-specific-bank-account @(re-frame/subscribe [::subs/active-route]))
|
||||
[:div "This is a bank account!"])]])
|
||||
|
||||
(defn breadcrumbs []
|
||||
[:h1.title.is-1
|
||||
(cond (= :admin-clients @(re-frame/subscribe [::subs/active-route]))
|
||||
"Clients"
|
||||
|
||||
:else
|
||||
[:span [:a {:href (bidi/path-for routes/routes :admin-clients)}
|
||||
"Clients"]
|
||||
" / "
|
||||
(or (:name (:data @(re-frame/subscribe [::forms/form ::form/form])))
|
||||
[:i "New client"])])
|
||||
])
|
||||
(def admin-clients-content
|
||||
(with-meta
|
||||
(fn []
|
||||
[:div
|
||||
[breadcrumbs]
|
||||
[:div.is-pulled-right
|
||||
(when (= :admin-clients @(re-frame/subscribe [::subs/active-route]))
|
||||
[:a.button.is-primary.is-outlined {:href (bidi/path-for routes/routes :admin-specific-client :id "new")} "New client"])]
|
||||
[test-appear]
|
||||
])
|
||||
[page-stack/page-stack
|
||||
{:active @(re-frame/subscribe [::subs/active-route])
|
||||
:pages [{:key :admin-clients
|
||||
:breadcrumb "Clients"
|
||||
:content [:<>
|
||||
[:div.is-pulled-right
|
||||
[:a.button.is-primary.is-outlined {:href (bidi/path-for routes/routes :admin-specific-client :id "new")} "New client"]]
|
||||
[table/clients-table {:page @(re-frame/subscribe [::page])
|
||||
:status @(re-frame/subscribe [::status/single ::page])}]]}
|
||||
|
||||
{:key :admin-specific-client
|
||||
:breadcrumb [:span [:a {:href (bidi/path-for routes/routes :admin-clients)}
|
||||
"Clients"]
|
||||
" / "
|
||||
(or (:name @(re-frame/subscribe [::form/client]))
|
||||
[:i "New client"])]
|
||||
:content [form/new-client-form]}
|
||||
]}]])
|
||||
{:component-did-mount #(re-frame/dispatch [::mounted])
|
||||
:component-will-unmount #(re-frame/dispatch-sync [::unmounted])}))
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
85
src/cljs/auto_ap/views/pages/page_stack.cljs
Normal file
85
src/cljs/auto_ap/views/pages/page_stack.cljs
Normal file
@@ -0,0 +1,85 @@
|
||||
(ns auto-ap.views.pages.page-stack
|
||||
(:require
|
||||
[auto-ap.views.utils :refer [switch-transition transition]]
|
||||
[reagent.core :as r]))
|
||||
|
||||
(defn page-stack []
|
||||
(let [last-stack-size (r/atom (->> (r/current-component)
|
||||
r/children
|
||||
(filter identity) count))
|
||||
forward? (r/atom false)]
|
||||
(fn [{:keys [pages active]}]
|
||||
(let [current-stack-size (->> pages
|
||||
(take-while #(not= (:key %)
|
||||
active))
|
||||
count)
|
||||
current-child (->> pages
|
||||
(filter #(= (:key %)
|
||||
active))
|
||||
first)]
|
||||
(when (not= current-stack-size @last-stack-size)
|
||||
(reset! forward? (> current-stack-size @last-stack-size))
|
||||
(reset! last-stack-size current-stack-size))
|
||||
[:div
|
||||
[:h1.title (:breadcrumb current-child)]
|
||||
[switch-transition {:mode "in-out"}
|
||||
^{:key current-stack-size}
|
||||
[transition
|
||||
{:timeout 100
|
||||
:exit true
|
||||
:in true #_(= current-stack- (:key (meta child)))
|
||||
:appear (> current-stack-size 1)}
|
||||
(clj->js (fn [state]
|
||||
(r/as-element
|
||||
[:div {:style {
|
||||
:position (cond
|
||||
(= "entered" state)
|
||||
""
|
||||
|
||||
(= "entering" state)
|
||||
"absolute"
|
||||
|
||||
(= "exiting" state)
|
||||
"absolute"
|
||||
|
||||
(= "exited" state)
|
||||
"")
|
||||
:transition "opacity 300ms ease-in-out, transform 300ms ease-in-out"
|
||||
:opacity (cond
|
||||
(= "entered" state)
|
||||
""
|
||||
|
||||
(= "entering" state)
|
||||
0.0
|
||||
|
||||
(= "exiting" state)
|
||||
1.0
|
||||
|
||||
(= "exited" state)
|
||||
0.0)
|
||||
:transform (if @forward?
|
||||
(cond
|
||||
(= "entered" state)
|
||||
""
|
||||
|
||||
(= "entering" state)
|
||||
"translateX(100%)"
|
||||
|
||||
(= "exiting" state)
|
||||
"translateX(-100%)"
|
||||
|
||||
(= "exited" state)
|
||||
"translateX(0%)")
|
||||
(cond
|
||||
(= "entered" state)
|
||||
""
|
||||
|
||||
(= "entering" state)
|
||||
"translateX(-100%)"
|
||||
|
||||
(= "exiting" state)
|
||||
"translateX(100%)"
|
||||
|
||||
(= "exited" state)
|
||||
"translateX(0%)"))}}
|
||||
(:content current-child)])))]]]))))
|
||||
Reference in New Issue
Block a user