Made admin clients easier to work with.

This commit is contained in:
2022-07-14 12:58:06 -07:00
parent 24da451c50
commit 99fe24ddae
12 changed files with 2849 additions and 260 deletions

2414
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -18,7 +18,7 @@
"react-prop-types": "^0.4.0",
"react-signature-canvas": "^1.0.3",
"react-signature-pad": "0.0.6",
"react-transition-group": "^2.4.0",
"react-transition-group": "^4.4.2",
"recharts": "^1.4.2"
},
"devDependencies": {

View File

@@ -7,7 +7,9 @@
"needs-activation" :needs-activation
"payments/" :payments
"admin/" {"" :admin
"clients" :admin-clients
"clients/" {"" :admin-clients
[:id] {"" :admin-specific-client
"/bank-accounts/" {[:bank-account] :admin-specific-bank-account}}}
"users" :admin-users
"rules" :admin-rules
"accounts" :admin-accounts
@@ -29,7 +31,6 @@
"unapproved" :unapproved-transactions
"approved" :approved-transactions
"requires-feedback" :requires-feedback-transactions
"excluded" :excluded-transactions}
"reports/" {"" :reports}
"ledger/" {"" :ledger

View File

@@ -40,27 +40,27 @@
(cond
(= :login handler)
{:db (assoc db/default-db
:active-page :login
:active-route :login
:last-client-id (.getItem js/localStorage "last-client-id")
:user nil)}
(and (not= :login handler) (not token))
{:redirect "/login"
:db (assoc db/default-db
:active-page :login
:active-route :login
:last-client-id (.getItem js/localStorage "last-client-id")
:user token)}
(and token (= "none" (or (get (jwt->data token) "role") (get (jwt->data token) "user/role")) ))
{:redirect "/needs-activation"
:db (assoc db/default-db
:active-page :needs-activation
:active-route :needs-activation
:last-client-id (.getItem js/localStorage "last-client-id")
:user token)}
:else
{:db (assoc db/default-db
:active-page handler
:active-route handler
:is-initial-loading? true
:last-client-id (.getItem js/localStorage "last-client-id")
:query-params (auto-ap.views.utils/query-params)
@@ -123,7 +123,7 @@
(assoc db :initial-error e
:is-initial-loading? false
:active-page :initial-error)))
:active-route :initial-error)))
(re-frame/reg-event-db
::swap-client
@@ -140,20 +140,19 @@
(re-frame/reg-event-fx
::set-active-page
(fn [{:keys [db]} [_ handler params]]
::set-active-route
(fn [{:keys [db]} [_ handler params route-params]]
(if (and (not= :login handler) (not (:user db)))
{:redirect "/login"
:db (assoc db :active-page :login
:page-failure nil
:auto-ap.forms/forms nil)}
:db (assoc db :active-route :login
:page-failure nil)}
{:db (-> db
(assoc :active-page handler
(assoc :active-route handler
:page-failure nil
:query-params params
:auto-ap.forms/forms nil)
:route-params route-params)
(auto-ap.views.pages.data-page/dispose-all))})))

View File

@@ -105,8 +105,6 @@
(re-frame/reg-event-db
::save-error
(fn [db [_ form result]]
(println result)
(-> db
(assoc-in [::forms form :status] :error)
(assoc-in [::forms form :error] (or (:message (first result))
@@ -153,7 +151,7 @@
(assoc-in [::forms id :error] nil)))
(defn vertical-form [{:keys [can-submit id change-event submit-event ]}]
(defn vertical-form [{:keys [can-submit id change-event submit-event fullwidth?] :or {fullwidth? true}}]
{:form
(fn [{:keys [title] :as params} & children]
(let [{:keys [data active? error]} @(re-frame/subscribe [::form id])
@@ -190,13 +188,15 @@
(assoc-in [1 :event] change-event))]))
:field-holder (fn [label control]
[:div.field
(when label [:p.help label])
(when label (if fullwidth? [:p.help label]
[:label.label label]))
[:div.control control]])
:field ^{:key "field"}
(fn [label control]
(let [{:keys [data]} @(re-frame/subscribe [::form id])]
[:div.field
(when label [:p.help label])
(when label (if fullwidth? [:p.help label]
[:label.label label]))
[:div.control [bind-field (-> control
(assoc-in [1 :subscription] data)
(assoc-in [1 :event] change-event))]]]))
@@ -210,8 +210,9 @@
(let [error (:error @(re-frame/subscribe [::form id]))
status @(re-frame/subscribe [::status/single id])
can-submit @(re-frame/subscribe can-submit)]
[:button.button.is-medium.is-primary.is-fullwidth {:disabled (or (status/disabled-for status)
[:button.button.is-medium.is-primary {:disabled (or (status/disabled-for status)
(not can-submit))
:class (status/class-for status) }
:class (cond-> (status/class-for status)
fullwidth? (conj "is-fullwidth")) }
child]))})

View File

@@ -12,7 +12,7 @@
(defn- dispatch-route [matched-route]
(println "Matched route" matched-route)
(re-frame/dispatch [:auto-ap.events/set-active-page (:handler matched-route) (u/query-params)]))
(re-frame/dispatch [:auto-ap.events/set-active-route (:handler matched-route) (u/query-params) (:route-params matched-route)]))
(def history (pushy/pushy dispatch-route parse-url))

View File

@@ -138,16 +138,30 @@
(when (:user db)
(js->clj (.parse js/JSON (base64/decodeString (second (str/split (:user db) #"\.")))) :keywordize-keys true))))
(re-frame/reg-sub
::active-route
(fn [db]
(:active-route db)))
(re-frame/reg-sub
::active-page
(fn [db]
(:active-page db)))
:<- [::active-route]
(fn [route]
(or ({:admin-specific-client :admin-clients
:admin-specific-bank-account :admin-clients}
route)
route)))
(re-frame/reg-sub
::query-params
(fn [db]
(:query-params db)))
(re-frame/reg-sub
::route-params
(fn [db]
(:route-params db)))
(re-frame/reg-sub
::page-failure
(fn [db]

View File

@@ -93,6 +93,9 @@
(defmethod page :admin-clients [_]
(admin-clients-page))
(defmethod page :admin-specific-client [_]
(admin-clients-page))
(defmethod page :admin-rules [_]
(admin-rules-page))

View File

@@ -1,27 +1,21 @@
(ns auto-ap.views.pages.admin.clients
(:require [re-frame.core :as re-frame]
[reagent.core :as reagent]
[clojure.spec.alpha :as s]
[clojure.string :as str]
[cljs-time.core :as t]
[cljs-time.coerce :as coerce]
[auto-ap.subs :as subs]
[auto-ap.forms :as forms]
[auto-ap.events :as events]
[auto-ap.entities.clients :as entity]
[auto-ap.views.components.address :refer [address-field]]
[auto-ap.views.components.layouts :refer [side-bar-layout appearing-side-bar side-bar] ]
[auto-ap.views.components.admin.side-bar :refer [admin-side-bar]]
[auto-ap.views.utils :refer [login-url dispatch-event dispatch-value-change bind-field horizontal-field nf with-user]]
[auto-ap.views.pages.admin.clients.table :as table]
[auto-ap.views.pages.admin.clients.form :as form]
[cljs.reader :as edn]
[auto-ap.routes :as routes]
[bidi.bidi :as bidi]
[auto-ap.status :as status]
[auto-ap.views.components.grid :as grid]
[auto-ap.views.pages.admin.clients.side-bar :as side-bar]
[vimsical.re-frame.fx.track :as track]))
(:require
[auto-ap.forms :as forms]
[auto-ap.subs :as subs]
[auto-ap.status :as status]
[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]]
[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]))
(re-frame/reg-event-db
::received-intuit-bank-accounts
@@ -82,24 +76,130 @@
: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
[:div
[:h1.title "Clients"]
[:div.is-pulled-right
[:a.button.is-primary.is-outlined {:on-click (dispatch-event [::new])} "New client"]]
[table/clients-table {:page @(re-frame/subscribe [::page])
:status @(re-frame/subscribe [::status/single ::page])}]]])
{:component-did-mount #(re-frame/dispatch [::mounted])
[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]
])
{:component-did-mount #(re-frame/dispatch [::mounted])
:component-will-unmount #(re-frame/dispatch-sync [::unmounted])}))
(defn admin-clients-page []
(let [{:keys [active?]} @(re-frame/subscribe [::forms/form ::form/form])]
[side-bar-layout {:side-bar [admin-side-bar {}
[side-bar/client-side-bar]]
:main [admin-clients-content]
:right-side-bar [appearing-side-bar {:visible? active?} [form/new-client-form]] }]))
[side-bar-layout {:side-bar [admin-side-bar {}
[side-bar/client-side-bar]]
:main [admin-clients-content]}])

View File

@@ -19,9 +19,12 @@
[cljs-time.coerce :as coerce]
[cljs-time.core :as t]
[clojure.string :as str]
[vimsical.re-frame.cofx.inject :as inject]
[re-frame.core :as re-frame]
[reagent.core :as r]
[react-signature-canvas]))
[react-signature-canvas]
[bidi.bidi :as bidi]
[auto-ap.routes :as routes]))
(def signature-canvas (r/adapt-react-class (.-default react-signature-canvas)))
@@ -54,8 +57,8 @@
[:div
[signature-canvas {"canvasProps" {"width" w
"height" h
"style" #js {"border" "1px solid rgb(219,219,219)"
"border-radius" "4px"}}
"style" #js {"border" "1px solid #CCC"
"border-radius" "10px"}}
"backgroundColor" "#FFF"
:ref (fn [el]
(reset! canvas el))}]
@@ -72,7 +75,9 @@
[:div
[:img {:src (or signature-data signature-file)
:style {:width w
:height h}}]
:height h
:border "1px solid #CCC"
:border-radius "10px"}}]
[:div.buttons
[:a.button {:on-click (fn []
(reset! edit-mode? true))}
@@ -83,7 +88,10 @@
[:div.has-text-centered.is-vcentered {:style {:width w
:height h
:margin-bottom "8px"
:background "#EEE"}}
:border "1px solid #CCC"
:border-radius "10px"
:background "#EEE"
}}
"No signature"]
[:div.buttons
[:a.button.is-primary.is-outlined {:on-click (fn []
@@ -113,9 +121,9 @@
:square-auth-token (:square-auth-token new-client-data)
:square-locations (map
(fn [x]
{:id (:id x)
{:id (:id (:square-location x))
:client-location (:client-location x)})
(:square-locations new-client-data))
(:selected-square-locations new-client-data))
:ezcater-locations (map
(fn [x]
@@ -189,20 +197,30 @@
(:bank-accounts new-client-data))})))
(re-frame/reg-event-fx
::editing
(fn [{:keys [db]} [_ client-id]]
{:db (-> db
(forms/stop-form ::form)
(forms/start-form ::form (-> (get (:clients db) client-id)
(update :locations #(mapv (fn [l] {:location l}) %))
(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})
ls))))
bas))))))}))
::mounted
[(re-frame/inject-cofx ::inject/sub [::subs/route-params])
(re-frame/inject-cofx ::inject/sub [::subs/clients-by-id])]
(fn [{:keys [db]
::subs/keys [clients-by-id route-params]} [_ client-id]]
(let [client (get clients-by-id (:id route-params))]
{:db (-> db
(forms/stop-form ::form)
(forms/start-form ::form (-> client
(assoc :selected-square-locations (->> (:square-locations client)
(filter :client-location )
(mapv (fn [sl]
{:id (:id sl)
:square-location sl
:client-location (:client-location sl)}))))
(update :locations #(mapv (fn [l] {:location l}) %))
(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})
ls))))
bas))))))})))
(re-frame/reg-event-fx
::save-new-client
@@ -222,13 +240,16 @@
(events/client-query user)]}]}
:on-success [::save-complete]
:on-error [::forms/save-error ::form]}})))
(re-frame/reg-event-db
(re-frame/reg-event-fx
::save-complete
(fn [db [_ client]]
(-> db
(forms/stop-form ::form)
(assoc-in [:clients (:id (:edit-client client))] (update (:edit-client client) :bank-accounts (fn [bas] (->> bas (sort-by :sort-order) vec)))))))
(fn [{:keys [db]} [_ client]]
{:db
(-> db
#_(forms/stop-form ::form)
(assoc-in [:clients (:id (:edit-client client))] (update (:edit-client client) :bank-accounts (fn [bas] (->> bas (sort-by :sort-order) vec)))))
:redirect (bidi/path-for routes/routes :admin-clients)}))
@@ -285,7 +306,8 @@
(forms/vertical-form {:can-submit [::can-submit]
:change-event [::forms/change ::form]
:submit-event [::save-new-client ]
:id ::form}))
:id ::form
:fullwidth? false}))
(def first-week-a (coerce/to-date-time #inst "1999-12-27T00:00:00.000-07:00"))
@@ -314,8 +336,9 @@
(defn bank-account-card [new-client {:keys [active? new? type visible code name sort-order]} first? last?]
(let [{:keys [field raw-field]} client-form]
[:div.card {:style {:margin-bottom "1em"}}
[:header.card-header
[:div.card {:style {:margin-bottom "1em"
:width "600px"}}
[:header.card-header.has-background-primary-light
[:div.card-header-title {:style {:text-overflow "ellipsis"}}
[:div.level {:style {:width "100%"}}
[:div.level-left
@@ -327,6 +350,8 @@
(#{:credit ":credit"} type) [:span.icon-credit-card-1]
:else [:span.icon-accounting-bill])]]
#_[:div.level-item
]
[:div.level-item code ": " name]]
[:div.level-right
[:div.level-item
@@ -373,7 +398,7 @@
:field [:bank-accounts sort-order :name]}]]
[horizontal-field
nil
[field "Numeric Code (for finiancials)"
[field "Numeric Code"
[:input.input {:placeholder "20101"
:type "text"
:field [:bank-accounts sort-order :numeric-code]}]]]
@@ -399,6 +424,7 @@
:field [:bank-accounts sort-order :bank-name]}]]
[field "Routing #"
[:input.input {:placeholder "104819123"
:style {:width "9em"}
:type "text"
:field [:bank-accounts sort-order :routing]}]]
[field "Bank code"
@@ -406,16 +432,17 @@
:type "text"
:field [:bank-accounts sort-order :bank-code]}]]]
[:label.label "Checking account"]
[horizontal-field
nil
[field "Account #"
[:input.input {:placeholder "123456789"
:type "text"
:style {:width "20em"}
:field [:bank-accounts sort-order :number]}]]
[field "Check Number"
[:input.input {:placeholder "10000"
:style {:width "6em"}
:type "text"
:field [:bank-accounts sort-order :check-number]}]]]
[field "Yodlee Account"
@@ -520,8 +547,15 @@
(when new?
[:a.card-footer-item.is-warning {:href "#" :on-click (dispatch-event [::bank-account-removed sort-order])} "Remove"])])]))
(defn new-client-form []
(let [{new-client :data } @(re-frame/subscribe [::forms/form ::form])
(defn form-section [{:keys [title]}]
[:<>
[:h4.is-4.title title]
[:hr]
(into [:div {:style {:margin-bottom "5em"}}]
(r/children (r/current-component)))])
(defn form-content []
(let [{new-client :data :as f} @(re-frame/subscribe [::forms/form ::form])
{:keys [form-inline field raw-field error-notification submit-button ]} client-form
next-week-a (if (is-week-a? (t/now))
"This week"
@@ -529,177 +563,214 @@
next-week-b (if (is-week-a? (t/now))
"Next week"
"This week")]
[side-bar {:on-close (dispatch-event [::forms/form-closing ::form ])}
^{:key (:id new-client)}
[:div ;; div is important for actually unmounting for now
(form-inline {:title "Add client"}
[:<>
(field "Name"
[:input.input {:type "text"
:field [:name]
:spec ::entity/name
}])
^{:key (or (:id new-client)
"new")}
[:div ;; div is important for actually unmounting for now
(form-inline {:title ""}
[:<>
[form-section {:title "General"}
(field "Name"
[:input.input {:type "text"
:style {:width "20em"}
:field [:name]
:spec ::entity/name
}])
[:div.field
[:p.help "Client code"
]
[:label.label "Client code"]
(if (:id new-client)
[:div.control
(:code new-client)]
(raw-field
[:input.input {:type "code"
:style {:width "5em"}
:field :code
:spec ::entity/code
:disabled true}])
]
[:div.control
(raw-field
[:input.input {:type "code"
:field :code
:spec ::entity/code}])])]
(field "Locked Until"
[date-picker {:class-name "input"
:class "input"
:format-week-number (fn [] "")
:previous-month-button-label ""
:placeholder "mm/dd/yyyy"
:next-month-button-label ""
:next-month-label ""
:type "date"
:field [:locked-until]}])
[:input.input {:type "code"
:style {:width "5em"}
:field :code
:spec ::entity/code}])])]
[:h2.subtitle.is-5 "Emails (address/description)"]
[:div.control
(raw-field
[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]}]]}])]
[:div.field
[:label.label "Locations"]
[:div.control
(raw-field
[multi-field {:type "multi-field"
:field :locations
:allow-change? false
:template [[:input.input {:field [:location]
:maxlength 2
:style { :width "4em"}}]]}])]]
[:div.field
[:p.help "Signature"]
[:label.label "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]))}]]
:on-change (fn [uri]
(re-frame/dispatch [::forms/change ::form [:signature-data] uri]))}]]
[:h2.subtitle.is-5 "Name matches"]
[:div.control
(raw-field
[multi-field {:type "multi-field"
:field :matches
:template [[:input.input {:field [:match]
:placeholder "Harry's burger joint"
:style { :width "15em"}}]]}])]
[:h2.subtitle "Locations"]
[:div.control
(raw-field
[multi-field {:type "multi-field"
:field :locations
:allow-change? false
:template [[:input.input {:field [:location]
:maxlength 2
:style { :width "4em"}}]]}])]
[:h2.subtitle "Location Matches"]
[:div.control
(raw-field
[multi-field {:type "multi-field"
:field :location-matches
:template [[:input.input {:field [:match]
:placeholder "Downtown"
:style { :width "15em"}}]
[:input.input {:field [:location]
:placeholder "DT"
:maxlength 2
:style { :width "4em"}}]]}])]
(field "Locked Until"
[date-picker {:class-name "input"
:class "input"
:format-week-number (fn [] "")
:previous-month-button-label ""
:placeholder "mm/dd/yyyy"
:next-month-button-label ""
:next-month-label ""
:type "date"
:field [:locked-until]
:style {:width "15em"}}])]
[form-section {:title "Contacts"}
[:h2.subtitle "Address"]
[address-field {:field [:address]
:event [::forms/change ::form]
:subscription new-client}]
[:div.field
[:label.label "Emails (address/description)"]
[:div.control
(raw-field
[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]}]]}])]]
[:label.label "Address"]
[:div {:style {:width "30em"}}
[address-field {:field [:address]
:event [::forms/change ::form]
:subscription new-client}]]]
[:h2.subtitle "Bank accounts"]
[form-section {:title "Matching"}
[:div.field
[:label.label "Name matches"]
[:div.control
(raw-field
[multi-field {:type "multi-field"
:field :matches
:template [[:input.input {:field [:match]
:placeholder "Harry's burger joint"
:style { :width "15em"}}]]}])]]
[:div.field
[:label.label "Location Matches"]
[:div.control
(raw-field
[multi-field {:type "multi-field"
:field :location-matches
:template [[:input.input {:field [:match]
:placeholder "Downtown"
:style { :width "15em"}}]
[:input.input {:field [:location]
:placeholder "DT"
:maxlength 2
:style { :width "4em"}}]]}])]]]
[form-section {:title "Bank Accounts"}
(for [bank-account (sort-by :sort-order (:bank-accounts new-client))]
^{:key (:sort-order bank-account)}
[bank-account-card new-client bank-account (= 0 (:sort-order bank-account)) (= (:sort-order bank-account) (dec (count (:bank-accounts new-client))))])
[:div.columns
[:div.column.is-third
[:a.button.is-primary.is-outlined.is-fullwidth {:on-click (dispatch-event [::add-new-bank-account :credit])} "Add Credit Account"]]
[:div.column.is-third
[:a.button.is-primary.is-outlined.is-fullwidth {:on-click (dispatch-event [::add-new-bank-account :check])} "Add Checking Account"]]
[:div.column.is-third
[:a.button.is-primary.is-outlined.is-fullwidth {:on-click (dispatch-event [::add-new-bank-account :cash])} "Add Cash Account"]]]
[:div.buttons
[:a.button.is-primary.is-outlined {:on-click (dispatch-event [::add-new-bank-account :credit])} "Add Credit Account"]
[:a.button.is-primary.is-outlined {:on-click (dispatch-event [::add-new-bank-account :check])} "Add Checking Account"]
[:a.button.is-primary.is-outlined {:on-click (dispatch-event [::add-new-bank-account :cash])} "Add Cash Account"]]]
[:h2.subtitle "Cash flow"]
[form-section {:title "Cash flow"}
[:label.label (str "Week A (" next-week-a ")")]
[field "Regular Credits"
[:input.input {:type "number"
:placeholder "500.00"
:field [:week-a-credits]
:step "0.01"}]]
[field "Regular Debits"
[:input.input {:type "number"
:placeholder "150.00"
:field [:week-a-debits]
:step "0.01"}]]
[:div.level
[:div.level-left
[:div.level-item
[field "Regular Credits"
[:input.input {:type "number"
:style {:width "10em"}
:placeholder "500.00"
:field [:week-a-credits]
:step "0.01"}]]]
[:div.level-item
[field "Regular Debits"
[:input.input {:type "number"
:style {:width "10em"}
:placeholder "150.00"
:field [:week-a-debits]
:step "0.01"}]]]]]
[:label.label (str "Week B (" next-week-b ")")]
[field "Regular Credits"
[:input.input {:type "number"
:placeholder "1000.00"
:field [:week-b-credits]
:step "0.01"}]]
[field "Regular Debits"
[:input.input {:type "number"
:placeholder "250.00"
:field [:week-b-debits]
:step "0.01"}]]
[:div.level
[:div.level-left
[:div.level-item
[field "Regular Credits"
[:input.input {:type "number"
:style {:width "10em"}
:placeholder "1000.00"
:field [:week-b-credits]
:step "0.01"}]]]
[:div.level-item
[field "Regular Debits"
[:input.input {:type "number"
:style {:width "10em"}
:placeholder "250.00"
:field [:week-b-debits]
:step "0.01"}]]]]]
[:div.field
[:label.label "Forecasted transactions"]
[:div.control
(raw-field
[multi-field {:type "multi-field"
:field :forecasted-transactions
:template [[:input.input {:type "text"
:placeholder "Identifier"
:style {:width "10em"}
:field [ :identifier]}]
[:input.input {:type "number"
:style {:width "4em"}
:placeholder "Day of month"
:step "1"
:field [:day-of-month]}]
[:input.input {:type "number"
:placeholder "250.00"
:class "has-text-right"
:style {:width "7em"}
:field [:amount]
:step "0.01"}]]}])]]
[multi-field {:type "multi-field"
:field :forecasted-transactions
:template [[:input.input {:type "text"
:placeholder "Identifier"
:style {:width "10em"}
:field [ :identifier]}]
[:input.input {:type "number"
:style {:width "8em"}
:placeholder "DOM"
:step "1"
:field [:day-of-month]}]
[:input.input {:type "number"
:placeholder "250.00"
:class "has-text-right"
:style {:width "7em"}
:field [:amount]
:step "0.01"}]]}])]]]
[form-section {:title "Square Integration"}
(field "Square Authentication Token"
[:input.input {:type "text"
:style {:width "40em"}
:field [:square-auth-token]}])
[:div.field
[:label.label "Square Locations"]
[:div.control
(raw-field
[multi-field {:type "multi-field"
:field :square-locations
:template [[:input.input {:type "text"
:style {:width "15em"}
:disabled true
:field [:name]}]
[:input.input {:type "text"
:style {:width "4em"}
:field [:client-location]
:step "0.01"}]]
:disable-remove? true
:disable-new? true}])]]
[multi-field {:type "multi-field"
:field :selected-square-locations
:template [[typeahead-v3 {:entities (:square-locations new-client)
:entity->text :name
:type "typeahead-v3"
:style {:width "15em"}
:field [:square-location]}]
[:input.input {:type "text"
:style {:width "4em"}
:field [:client-location]
:step "0.01"}]]
:disable-remove? true}])]]]
[form-section {:title "EZCater integration"}
[:div.field
[:label.label "EZCater Locations"]
@@ -710,17 +781,23 @@
:template [
[search-backed-typeahead {:search-query (fn [i]
[:search_ezcater_caterer
{:query i}
{:query i}
[:name :id]])
:entity->text :name
:type "typeahead-v3"
:field [:caterer]
:style {:width "20em"}}]
:field [:caterer]
:style {:width "20em"}}]
[:input.input {:type "text"
:style {:width "4em"}
:field [:location]
:step "0.01"}]]
:disable-remove? true}])]]
:disable-remove? true}])]]]
(error-notification)
(submit-button "Save")])]]))
(error-notification)
(submit-button "Save")])]))
(def new-client-form
(with-meta
(fn []
[form-content])
{:component-did-mount #(re-frame/dispatch [::mounted])}))

View File

@@ -2,12 +2,13 @@
(:require [auto-ap.subs :as subs]
[clojure.string :as str]
[re-frame.core :as re-frame]
[auto-ap.views.pages.admin.clients.form :as form]
[auto-ap.views.utils :refer [action-cell-width date->str with-user]]
[auto-ap.views.components.grid :as grid]
[auto-ap.views.components.modal :as modal]
[auto-ap.views.components.buttons :as buttons]
[auto-ap.status :as status]))
[auto-ap.status :as status]
[bidi.bidi :as bidi]
[auto-ap.routes :as routes]))
(re-frame/reg-sub
::specific-params
@@ -115,5 +116,5 @@
[grid/cell {} [:div.buttons [buttons/fa-icon {:event [::setup-sales-queries id]
:class (status/class-for (get states id))
:icon :fa-dollar}]
[buttons/fa-icon {:event [::form/editing id]
:icon :fa-pencil}]]]])]]]))
[buttons/fa-icon {:href (bidi/path-for routes/routes :admin-specific-client :id id)
:icon :fa-pencil}]]]])]]]))

View File

@@ -118,6 +118,14 @@
(def css-transition-group
(reagent/adapt-react-class react-transition-group/CSSTransition))
(def transition
(reagent/adapt-react-class react-transition-group/Transition))
(def transition-group
(reagent/adapt-react-class react-transition-group/TransitionGroup))
(def switch-transition
(reagent/adapt-react-class react-transition-group/SwitchTransition))
(defn appearing [{:keys [visible? enter-class exit-class timeout]}]
(let [final-state (reagent/atom visible?)]
@@ -140,15 +148,18 @@
value
(conj value {:key (random-uuid)
:new? true}))]
[:div
[:div {:style {:margin-bottom "1em"}}
(for [[i override] (map vector (range) value)
:let [is-disabled? (if (= false allow-change?)
(not (boolean (:new? override)))
nil)]
]
^{:key (:key override)}
[:div.level
[:div.level-left
[:div.level
[:div.level-left {:style (when (and (= i (dec (count value)))
(:new? override))
{:background "#EEE"
:padding "0.25em 1em 0.25em 0em"})}
[:div.level-item
(if (:new? override)
@@ -187,7 +198,7 @@
@value-repr))))])
]
(when-not disable-remove?
[:div.level-item
[:div.level-item
[:a.button.level-item
{:disabled is-disabled?
:on-click (fn []