Builds client SSR approach, sunsets old cljs.
This commit is contained in:
@@ -47,7 +47,7 @@
|
||||
|
||||
(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"))
|
||||
(throw (js/Error. "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]))
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
[auto-ap.views.components.typeahead :refer [typeahead-v3]]
|
||||
[auto-ap.views.components.typeahead.vendor
|
||||
:refer [search-backed-typeahead]]
|
||||
[auto-ap.views.pages.admin.vendors.common :as common]
|
||||
[auto-ap.views.utils
|
||||
:refer [dispatch-event str->int with-is-admin? with-user]]
|
||||
[malli.core :as m]
|
||||
@@ -23,9 +22,25 @@
|
||||
;; Remaining cleanup todos:
|
||||
;; test minification
|
||||
|
||||
(def default-read [:id :name :hidden :terms [:default-account [:name :id :location]]
|
||||
[:account-overrides [[:client [:id :name]] :id [:account [:id :numeric-code :name]]]]
|
||||
[:automatically-paid-when-due [:id :name]]
|
||||
[:terms-overrides [[:client [:id :name]] :id :terms]]
|
||||
[:schedule-payment-dom [[:client [:id :name]] :id :dom]]
|
||||
[:usage [:client-id :count]]
|
||||
[:primary-contact [:name :phone :email :id]]
|
||||
[:plaid-merchant [:name :id]]
|
||||
[:secondary-contact [:id :name :phone :email]]
|
||||
:print-as :invoice-reminder-schedule :code
|
||||
:legal-entity-name
|
||||
:legal-entity-first-name :legal-entity-middle-name :legal-entity-last-name
|
||||
:legal-entity-tin :legal-entity-tin-type
|
||||
:legal-entity-1099-type
|
||||
[:address [:id :street1 :street2 :city :state :zip]]])
|
||||
|
||||
(def terms-override-schema (m/schema [:map
|
||||
[:client schema/reference]
|
||||
[:terms :int]]))
|
||||
[:client schema/reference]
|
||||
[:terms :int]]))
|
||||
|
||||
(def automatically-paid-schema (m/schema [:map
|
||||
[:client schema/reference]]))
|
||||
@@ -35,8 +50,8 @@
|
||||
[:dom [:int {:max 30}]]]))
|
||||
|
||||
(def account-override-schema (m/schema [:map
|
||||
[:client schema/reference]
|
||||
[:account schema/reference]]))
|
||||
[:client schema/reference]
|
||||
[:account schema/reference]]))
|
||||
|
||||
(def schema (m/schema [:map [:name schema/not-empty-string]
|
||||
[:print-as {:optional true}
|
||||
@@ -72,73 +87,73 @@
|
||||
(re-frame/reg-event-fx
|
||||
::save-complete
|
||||
[(forms/triggers-stop ::vendor-form)]
|
||||
(fn [_ [_ _ ]]
|
||||
{:dispatch [::modal/modal-closed ]}))
|
||||
(fn [_ [_ _]]
|
||||
{:dispatch [::modal/modal-closed]}))
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::save
|
||||
[with-user with-is-admin? (forms/triggers-loading ::vendor-form) (forms/in-form ::vendor-form)]
|
||||
(fn [{:keys [user is-admin?] {{:keys [name hidden print-as terms invoice-reminder-schedule plaid-merchant primary-contact automatically-paid-when-due schedule-payment-dom secondary-contact address default-account terms-overrides account-overrides id legal-entity-name legal-entity-tin legal-entity-tin-type legal-entity-first-name legal-entity-last-name legal-entity-middle-name legal-entity-1099-type] :as data} :data} :db} _]
|
||||
(if (m/validate schema data)
|
||||
(let [query [:upsert-vendor
|
||||
{:vendor (cond-> {:id id
|
||||
:name name
|
||||
:print-as print-as
|
||||
:terms (or terms
|
||||
nil)
|
||||
:default-account-id (:id default-account)
|
||||
:address address
|
||||
:primary-contact primary-contact
|
||||
:secondary-contact secondary-contact
|
||||
:invoice-reminder-schedule invoice-reminder-schedule}
|
||||
is-admin? (assoc :hidden hidden
|
||||
:terms-overrides (mapv
|
||||
(fn [{:keys [client terms id]}]
|
||||
{:id id
|
||||
:client-id (:id client)
|
||||
:terms (or (str->int terms) 0)})
|
||||
terms-overrides)
|
||||
:account-overrides (mapv
|
||||
(fn [{:keys [client account id]}]
|
||||
{:id id
|
||||
:client-id (:id client)
|
||||
:account-id (:id account)})
|
||||
account-overrides)
|
||||
:schedule-payment-dom (mapv
|
||||
(fn [{:keys [client dom id]}]
|
||||
{:id id
|
||||
:client-id (:id client)
|
||||
:dom (or (str->int dom)
|
||||
0)})
|
||||
schedule-payment-dom)
|
||||
:automatically-paid-when-due (mapv
|
||||
(comp :id :client)
|
||||
automatically-paid-when-due)
|
||||
:plaid-merchant (:id plaid-merchant)
|
||||
:legal-entity-name legal-entity-name
|
||||
:legal-entity-first-name legal-entity-first-name
|
||||
:legal-entity-middle-name legal-entity-middle-name
|
||||
:legal-entity-last-name legal-entity-last-name
|
||||
:legal-entity-tin legal-entity-tin
|
||||
:legal-entity-tin-type (some-> legal-entity-tin-type clojure.core/name not-empty keyword)
|
||||
:legal-entity-1099-type (some-> legal-entity-1099-type clojure.core/name not-empty keyword)))}
|
||||
common/default-read]]
|
||||
{ :graphql
|
||||
{:token user
|
||||
:owns-state {:single ::vendor-form}
|
||||
:query-obj {:venia/operation
|
||||
{:operation/type :mutation
|
||||
:operation/name "UpsertVendor"} :venia/queries [{:query/data query}]}
|
||||
:on-success [::save-complete]}})
|
||||
::save
|
||||
[with-user with-is-admin? (forms/triggers-loading ::vendor-form) (forms/in-form ::vendor-form)]
|
||||
(fn [{:keys [user is-admin?] {{:keys [name hidden print-as terms invoice-reminder-schedule plaid-merchant primary-contact automatically-paid-when-due schedule-payment-dom secondary-contact address default-account terms-overrides account-overrides id legal-entity-name legal-entity-tin legal-entity-tin-type legal-entity-first-name legal-entity-last-name legal-entity-middle-name legal-entity-1099-type] :as data} :data} :db} _]
|
||||
(if (m/validate schema data)
|
||||
(let [query [:upsert-vendor
|
||||
{:vendor (cond-> {:id id
|
||||
:name name
|
||||
:print-as print-as
|
||||
:terms (or terms
|
||||
nil)
|
||||
:default-account-id (:id default-account)
|
||||
:address address
|
||||
:primary-contact primary-contact
|
||||
:secondary-contact secondary-contact
|
||||
:invoice-reminder-schedule invoice-reminder-schedule}
|
||||
is-admin? (assoc :hidden hidden
|
||||
:terms-overrides (mapv
|
||||
(fn [{:keys [client terms id]}]
|
||||
{:id id
|
||||
:client-id (:id client)
|
||||
:terms (or (str->int terms) 0)})
|
||||
terms-overrides)
|
||||
:account-overrides (mapv
|
||||
(fn [{:keys [client account id]}]
|
||||
{:id id
|
||||
:client-id (:id client)
|
||||
:account-id (:id account)})
|
||||
account-overrides)
|
||||
:schedule-payment-dom (mapv
|
||||
(fn [{:keys [client dom id]}]
|
||||
{:id id
|
||||
:client-id (:id client)
|
||||
:dom (or (str->int dom)
|
||||
0)})
|
||||
schedule-payment-dom)
|
||||
:automatically-paid-when-due (mapv
|
||||
(comp :id :client)
|
||||
automatically-paid-when-due)
|
||||
:plaid-merchant (:id plaid-merchant)
|
||||
:legal-entity-name legal-entity-name
|
||||
:legal-entity-first-name legal-entity-first-name
|
||||
:legal-entity-middle-name legal-entity-middle-name
|
||||
:legal-entity-last-name legal-entity-last-name
|
||||
:legal-entity-tin legal-entity-tin
|
||||
:legal-entity-tin-type (some-> legal-entity-tin-type clojure.core/name not-empty keyword)
|
||||
:legal-entity-1099-type (some-> legal-entity-1099-type clojure.core/name not-empty keyword)))}
|
||||
default-read]]
|
||||
{:graphql
|
||||
{:token user
|
||||
:owns-state {:single ::vendor-form}
|
||||
:query-obj {:venia/operation
|
||||
{:operation/type :mutation
|
||||
:operation/name "UpsertVendor"} :venia/queries [{:query/data query}]}
|
||||
:on-success [::save-complete]}})
|
||||
|
||||
{:dispatch-n [[::forms/attempted-submit ::vendor-form]
|
||||
[::status/error ::vendor-form [{:message "Please fix the errors and try again."}]]]})))
|
||||
{:dispatch-n [[::forms/attempted-submit ::vendor-form]
|
||||
[::status/error ::vendor-form [{:message "Please fix the errors and try again."}]]]})))
|
||||
|
||||
(defn contact-field [{:keys [name field]}]
|
||||
[form-builder/with-scope {:scope field}
|
||||
[form-builder/vertical-control
|
||||
name
|
||||
[left-stack
|
||||
[left-stack
|
||||
[form-builder/vertical-control {:is-small? true}
|
||||
"Name"
|
||||
[:div.control.has-icons-left
|
||||
@@ -196,23 +211,22 @@
|
||||
[form-builder/section {:title "Terms"}
|
||||
[form-builder/field-v2 {:field :terms}
|
||||
"Terms"
|
||||
[number-input ]]
|
||||
[number-input]]
|
||||
(when is-admin?
|
||||
[form-builder/field-v2 {:field [:terms-overrides]}
|
||||
"Overrides"
|
||||
[multi-field-v2 {:template [[form-builder/raw-field-v2 {:field [:client]}
|
||||
[multi-field-v2 {:template [[form-builder/raw-field-v2 {:field [:client]}
|
||||
[typeahead-v3 {:entities clients
|
||||
:entity->text :name
|
||||
:style {:width "13em"}
|
||||
:type "typeahead-v3"
|
||||
}]]
|
||||
:type "typeahead-v3"}]]
|
||||
[form-builder/raw-field-v2 {:field :terms}
|
||||
[number-input]]]
|
||||
:schema [:sequential terms-override-schema]
|
||||
:key-fn :id
|
||||
:next-key (random-uuid)
|
||||
:new-text "New Terms Override"}]])]
|
||||
|
||||
|
||||
(when is-admin?
|
||||
[form-builder/section {:title "Schedule payment when due"}
|
||||
[form-builder/field-v2 {:field [:automatically-paid-when-due]}
|
||||
@@ -228,7 +242,7 @@
|
||||
|
||||
(when is-admin?
|
||||
[form-builder/section {:title "Schedule payment on day of month"}
|
||||
[form-builder/field-v2 {:field [:schedule-payment-dom]}
|
||||
[form-builder/field-v2 {:field [:schedule-payment-dom]}
|
||||
"Overrides"
|
||||
[multi-field-v2 {:template [[form-builder/raw-field-v2 {:field :client}
|
||||
[typeahead-v3 {:entities clients
|
||||
@@ -249,8 +263,7 @@
|
||||
{:query i
|
||||
:allowance :vendor}
|
||||
[:name :id :warning]])
|
||||
:style {:width "19em"}}]
|
||||
]
|
||||
:style {:width "19em"}}]]
|
||||
(when (:warning (:default-account vendor))
|
||||
[:div.notification.is-warning.is-light
|
||||
(:warning (:default-account vendor))])
|
||||
@@ -258,23 +271,22 @@
|
||||
[form-builder/field-v2 {:field [:account-overrides]}
|
||||
"Overrides"
|
||||
[multi-field-v2 {:template (fn [entity]
|
||||
[[form-builder/raw-field-v2 {:field :client}
|
||||
[typeahead-v3 {:entities clients
|
||||
:entity->text :name
|
||||
:style {:width "19em"}
|
||||
}]]
|
||||
[form-builder/raw-field-v2 {:field :account}
|
||||
[search-backed-typeahead {:search-query (fn [i]
|
||||
[:search_account
|
||||
{:query i
|
||||
:client_id (:id (:client entity))
|
||||
:allowance :vendor}
|
||||
[:name :id :warning]])
|
||||
:style {:width "15em"}}]]])
|
||||
:schema [:sequential account-override-schema]
|
||||
:key-fn :id
|
||||
:next-key (random-uuid)
|
||||
:new-text "Add override"}]])]
|
||||
[[form-builder/raw-field-v2 {:field :client}
|
||||
[typeahead-v3 {:entities clients
|
||||
:entity->text :name
|
||||
:style {:width "19em"}}]]
|
||||
[form-builder/raw-field-v2 {:field :account}
|
||||
[search-backed-typeahead {:search-query (fn [i]
|
||||
[:search_account
|
||||
{:query i
|
||||
:client_id (:id (:client entity))
|
||||
:allowance :vendor}
|
||||
[:name :id :warning]])
|
||||
:style {:width "15em"}}]]])
|
||||
:schema [:sequential account-override-schema]
|
||||
:key-fn :id
|
||||
:next-key (random-uuid)
|
||||
:new-text "Add override"}]])]
|
||||
|
||||
[form-builder/section {:title "Address"}
|
||||
[:div {:style {:width "30em"}}
|
||||
@@ -319,8 +331,7 @@
|
||||
[form-builder/raw-field-v2 {:field :legal-entity-tin}
|
||||
[:input.input {:type "text"
|
||||
:placeholder "SSN or EIN"
|
||||
:size "12"
|
||||
}]]
|
||||
:size "12"}]]
|
||||
|
||||
[:div.control
|
||||
[form-builder/raw-field-v2 {:field :legal-entity-tin-type}
|
||||
@@ -336,25 +347,25 @@
|
||||
:allow-nil? true}]]])
|
||||
[form-builder/hidden-submit-button]]))
|
||||
|
||||
(defn vendor-dialog [ ]
|
||||
(defn vendor-dialog []
|
||||
(let [{:keys [data]} @(re-frame/subscribe [::forms/form ::vendor-form])]
|
||||
[:div
|
||||
[form-content {:data data}]]))
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::vendor-selected
|
||||
[with-user (forms/in-form ::select-vendor-form)]
|
||||
(fn [{{:keys [data]} :db :keys [user]} _]
|
||||
(if (:vendor data)
|
||||
{:graphql {:token user
|
||||
:query-obj {:venia/queries [[:vendor-by-id
|
||||
{:id (:id (:vendor data))}
|
||||
common/default-read]]}
|
||||
:owns-state {:single ::select-vendor-form}
|
||||
:on-success (fn [r]
|
||||
[::started (:vendor-by-id r)])}}
|
||||
{:dispatch-n [[::forms/attempted-submit ::select-vendor-form]
|
||||
[::status/error ::select-vendor-form [{:message "Please select a vendor."}]]]})))
|
||||
::vendor-selected
|
||||
[with-user (forms/in-form ::select-vendor-form)]
|
||||
(fn [{{:keys [data]} :db :keys [user]} _]
|
||||
(if (:vendor data)
|
||||
{:graphql {:token user
|
||||
:query-obj {:venia/queries [[:vendor-by-id
|
||||
{:id (:id (:vendor data))}
|
||||
default-read]]}
|
||||
:owns-state {:single ::select-vendor-form}
|
||||
:on-success (fn [r]
|
||||
[::started (:vendor-by-id r)])}}
|
||||
{:dispatch-n [[::forms/attempted-submit ::select-vendor-form]
|
||||
[::status/error ::select-vendor-form [{:message "Please select a vendor."}]]]})))
|
||||
|
||||
(defn select-vendor-form-content []
|
||||
[form-builder/builder {:submit-event [::vendor-selected]
|
||||
|
||||
@@ -18,9 +18,7 @@
|
||||
[auto-ap.views.pages.ledger.profit-and-loss-detail :refer [profit-and-loss-detail-page]]
|
||||
[auto-ap.views.pages.login :refer [login-page]]
|
||||
[auto-ap.views.pages.payments :refer [payments-page]]
|
||||
[auto-ap.views.pages.home :refer [home-page]]
|
||||
[auto-ap.views.pages.admin.clients :refer [admin-clients-page]]
|
||||
[auto-ap.views.pages.admin.vendors :refer [admin-vendors-page]]))
|
||||
[auto-ap.views.pages.home :refer [home-page]]))
|
||||
|
||||
(defmulti page (fn [active-page] active-page))
|
||||
(defmethod page :unpaid-invoices [_]
|
||||
@@ -93,14 +91,6 @@
|
||||
(when (p/can? @(re-frame/subscribe [::subs/user]) {:subject :ledger-page})
|
||||
(balance-sheet-page)))
|
||||
|
||||
(defmethod page :admin-clients [_]
|
||||
(when (p/can? @(re-frame/subscribe [::subs/user]) {:subject :admin-page})
|
||||
(admin-clients-page)))
|
||||
|
||||
(defmethod page :admin-specific-client [_]
|
||||
(when (p/can? @(re-frame/subscribe [::subs/user]) {:subject :admin-page})
|
||||
(admin-clients-page)))
|
||||
|
||||
(defmethod page :admin-vendors [_]
|
||||
(when (p/can? @(re-frame/subscribe [::subs/user]) {:subject :admin-page})
|
||||
(admin-vendors-page)))
|
||||
|
||||
@@ -1,106 +0,0 @@
|
||||
(ns auto-ap.views.pages.admin.clients
|
||||
(:require
|
||||
[auto-ap.routes :as routes]
|
||||
[auto-ap.status :as status]
|
||||
[auto-ap.subs :as subs]
|
||||
[auto-ap.shared-views.admin.side-bar :refer [admin-side-bar]]
|
||||
[auto-ap.views.pages.data-page :as data-page]
|
||||
[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.pages.page-stack :as page-stack]
|
||||
[auto-ap.views.utils :refer [with-user]]
|
||||
[bidi.bidi :as bidi]
|
||||
[clojure.string :as str]
|
||||
[clojure.set :as set]
|
||||
[re-frame.core :as re-frame]
|
||||
[vimsical.re-frame.fx.track :as track]
|
||||
[auto-ap.events :as events]
|
||||
[auto-ap.forms :as forms]
|
||||
[auto-ap.db :as db]))
|
||||
|
||||
(re-frame/reg-event-db
|
||||
::received-intuit-bank-accounts
|
||||
(fn [db [_ result]]
|
||||
(assoc db ::subs/intuit-bank-accounts (:intuit-bank-accounts result))))
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::mounted
|
||||
[with-user]
|
||||
(fn [{:keys [user db]} _]
|
||||
{::track/register [{:id ::params
|
||||
:subscription [::data-page/params ::page]
|
||||
:event-fn (fn [params] [::params-change params])}
|
||||
{:id ::active-route
|
||||
:subscription [::subs/active-route]
|
||||
:event-fn (fn [params] [::params-change params])}]
|
||||
:db (-> db
|
||||
(forms/stop-form [::form/form]))
|
||||
:graphql {:token user
|
||||
:query-obj {:venia/queries [[:intuit_bank_accounts [:external_id :id :name]]]}
|
||||
:owns-state {:single [::load-intuit-bank-accounts]}
|
||||
:on-success [::received-intuit-bank-accounts]} }))
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::unmounted
|
||||
(fn [{:keys [db]} _]
|
||||
{:db (dissoc db ::table/params ::side-bar/filter-params)
|
||||
::track/dispose [{:id ::params}
|
||||
{:id ::active-route}]}))
|
||||
|
||||
(defn data-params->query-params [params]
|
||||
{:start (:start params 0)
|
||||
:per-page (:per-page params)
|
||||
:sort (:sort params)
|
||||
:name-like (:name-like params)
|
||||
:code (:code params)})
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::params-change
|
||||
[with-user]
|
||||
(fn [{:keys [user]} [_ params]]
|
||||
{:graphql {:token user
|
||||
:owns-state {:single [::data-page/page ::page]}
|
||||
:query-obj {:venia/queries [[:client-page
|
||||
{:filters (data-params->query-params params)}
|
||||
[[:clients (events/client-detail-query user)]
|
||||
:total
|
||||
:start
|
||||
:end]]]}
|
||||
:on-success (fn [result]
|
||||
[::data-page/received ::page (set/rename-keys (:client-page result)
|
||||
{:clients :data})])}}))
|
||||
|
||||
(def admin-clients-content
|
||||
(with-meta
|
||||
(fn []
|
||||
[:div
|
||||
[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 {:data-page ::page
|
||||
:id :clients}]]}
|
||||
|
||||
{:key :admin-specific-client
|
||||
:breadcrumb [:span [:a {:href (bidi/path-for routes/routes :admin-clients)}
|
||||
"Clients"]
|
||||
" / "
|
||||
(or (:name (:data @(re-frame/subscribe [::forms/form ::form/form])))
|
||||
[:i "New client"])]
|
||||
:content [form/new-client-form]}
|
||||
]}]])
|
||||
{:component-did-mount #(re-frame/dispatch [::mounted])
|
||||
:component-will-unmount #(re-frame/dispatch-sync [::unmounted])}))
|
||||
|
||||
|
||||
(defn admin-clients-page []
|
||||
[side-bar-layout {:side-bar [admin-side-bar {}
|
||||
[side-bar/client-side-bar {:data-page ::page}]]
|
||||
:main [admin-clients-content]}])
|
||||
|
||||
@@ -1,761 +0,0 @@
|
||||
(ns auto-ap.views.pages.admin.clients.form
|
||||
(:require
|
||||
[auto-ap.events :as events]
|
||||
[auto-ap.forms :as forms]
|
||||
[auto-ap.forms.builder :as form-builder]
|
||||
[auto-ap.routes :as routes]
|
||||
[auto-ap.subs :as subs]
|
||||
[auto-ap.views.components.address :refer [address2-field]]
|
||||
[react-signature-canvas]
|
||||
[auto-ap.views.components.typeahead :refer [typeahead-v3]]
|
||||
[auto-ap.views.components.level :refer [left-stack] :as level]
|
||||
[auto-ap.views.components :as com]
|
||||
[auto-ap.views.components.typeahead.vendor
|
||||
:refer [search-backed-typeahead]]
|
||||
[auto-ap.views.utils
|
||||
:refer [date-picker
|
||||
with-user
|
||||
dispatch-event]]
|
||||
[bidi.bidi :as bidi]
|
||||
[cljs-time.coerce :as coerce]
|
||||
[cljs-time.core :as t]
|
||||
[re-frame.core :as re-frame]
|
||||
[reagent.core :as r]
|
||||
[vimsical.re-frame.cofx.inject :as inject]
|
||||
[auto-ap.schema :as schema]
|
||||
[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 feature-flag-schema (m/schema [:map
|
||||
[:feature-flag schema/not-empty-string]]))
|
||||
|
||||
(def square-location-schema (m/schema [:map
|
||||
[:square-location schema/reference]
|
||||
[:client-location schema/not-empty-string]]))
|
||||
|
||||
(def ezcater-schema (m/schema [:map
|
||||
[:caterer schema/reference]
|
||||
[:client-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]])
|
||||
|
||||
(def client-schema [:map
|
||||
[:name schema/not-empty-string]
|
||||
[:code schema/code-string]
|
||||
[:locations [:sequential location-schema]]
|
||||
[:feature-flags {:optional true} [:maybe [:sequential feature-flag-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]]]
|
||||
[:selected-square-locations {:optional true}
|
||||
[:maybe [:sequential square-location-schema]]]])
|
||||
|
||||
(defn upload-replacement-button [{:keys [on-change]} text]
|
||||
(let [button (atom nil)]
|
||||
(r/create-class {:display-name "Upload button"
|
||||
:reagent-render
|
||||
(fn []
|
||||
[:<>
|
||||
[:label.button {:for "upload_replacement_signature"} text]
|
||||
[:input.button {:type "file" :id "upload_replacement_signature"
|
||||
:style {:display "none"}
|
||||
:on-change (fn []
|
||||
(let [fr (js/FileReader.)]
|
||||
(.addEventListener fr "load" (fn []
|
||||
(on-change (.-result fr))))
|
||||
|
||||
(.readAsDataURL fr (aget (.-files @button) 0)))
|
||||
)
|
||||
:ref (fn [i] (reset! button i))} ]])})))
|
||||
|
||||
(defn signature [_]
|
||||
(let [canvas (atom nil)
|
||||
edit-mode? (r/atom false)
|
||||
w (* 1.5 464)
|
||||
h (* 1.5 174)]
|
||||
(fn [{:keys [signature-file signature-data on-change]}]
|
||||
[:div
|
||||
(if @edit-mode?
|
||||
[:div
|
||||
[signature-canvas {"canvasProps" {"width" w
|
||||
"height" h
|
||||
"style" #js {"border" "1px solid #CCC"
|
||||
"border-radius" "10px"}}
|
||||
"backgroundColor" "#FFF"
|
||||
:ref (fn [el]
|
||||
(reset! canvas el))}]
|
||||
[:div.buttons
|
||||
[:a.button.is-primary.is-outlined {:on-click (fn []
|
||||
(on-change (.toDataURL @canvas "image/jpeg"))
|
||||
(reset! edit-mode? false))}
|
||||
"Accept"]
|
||||
[:a.button.is-warning.is-outlined {:on-click (fn []
|
||||
(.clear @canvas)
|
||||
(reset! edit-mode? false))}
|
||||
"Cancel"]]]
|
||||
(if (or signature-data signature-file)
|
||||
[:div
|
||||
[:img {:src (or signature-data signature-file)
|
||||
:style {:width w
|
||||
:height h
|
||||
:border "1px solid #CCC"
|
||||
:border-radius "10px"}}]
|
||||
[:div.buttons
|
||||
[:a.button {:on-click (fn []
|
||||
(reset! edit-mode? true))}
|
||||
"Replace Signature"]
|
||||
|
||||
[upload-replacement-button {:on-change on-change} "Upload replacement"]]]
|
||||
[:div
|
||||
[:div.has-text-centered.is-vcentered {:style {:width w
|
||||
:height h
|
||||
:margin-bottom "8px"
|
||||
:border "1px solid #CCC"
|
||||
:border-radius "10px"
|
||||
:background "#EEE"
|
||||
}}
|
||||
"No signature"]
|
||||
[:div.buttons
|
||||
[:a.button.is-primary.is-outlined {:on-click (fn []
|
||||
(reset! edit-mode? true))}
|
||||
"New Signature"]
|
||||
|
||||
[upload-replacement-button {:on-change on-change} "Upload signature"]]]))
|
||||
])))
|
||||
|
||||
(re-frame/reg-sub
|
||||
::new-client-request
|
||||
:<- [::forms/form ::form]
|
||||
(fn [{new-client-data :data} _]
|
||||
(cond->
|
||||
{:id (:id new-client-data),
|
||||
:name (:name new-client-data)
|
||||
:code (:code new-client-data) ;; TODO add validation can't change
|
||||
: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]
|
||||
{:id (:id (:square-location x))
|
||||
:client-location (:client-location x)})
|
||||
(:selected-square-locations new-client-data))
|
||||
|
||||
:ezcater-locations (map
|
||||
(fn [x]
|
||||
{:id (:id x)
|
||||
:caterer (:id (:caterer x))
|
||||
:location (:location x)})
|
||||
(:ezcater-locations new-client-data))
|
||||
|
||||
:locked-until (:locked-until new-client-data)
|
||||
:locations (mapv :location (:locations new-client-data))
|
||||
:feature-flags (mapv :feature-flag (:feature-flags new-client-data))
|
||||
:matches (mapv :match (:matches new-client-data))
|
||||
:location-matches (:location-matches new-client-data)
|
||||
:week-a-credits (:week-a-credits new-client-data)
|
||||
:week-a-debits (:week-a-debits new-client-data)
|
||||
:week-b-credits (:week-b-credits new-client-data)
|
||||
:week-b-debits (:week-b-debits new-client-data)
|
||||
:address {:id (:id (:address new-client-data))
|
||||
:street1 (:street1 (:address new-client-data))
|
||||
:street2 (:street2 (:address new-client-data)),
|
||||
:city (:city (:address new-client-data))
|
||||
:state (:state (:address new-client-data))
|
||||
:zip (:zip (:address new-client-data))}
|
||||
:signature-data (:signature-data new-client-data)
|
||||
:forecasted-transactions (map (fn [{:keys [id day-of-month identifier amount]}]
|
||||
{:id id
|
||||
:day-of-month (js/parseInt day-of-month)
|
||||
:identifier identifier
|
||||
:amount amount})
|
||||
(:forecasted-transactions new-client-data))
|
||||
: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? visible locations yodlee-account use-date-instead-of-post-date]}]
|
||||
{:number number
|
||||
:name name
|
||||
:check-number check-number
|
||||
:numeric-code numeric-code
|
||||
:include-in-reports include-in-reports
|
||||
:start-date start-date
|
||||
:type type
|
||||
:id id
|
||||
:sort-order i
|
||||
:visible visible
|
||||
:locations (mapv :location locations)
|
||||
:use-date-instead-of-post-date use-date-instead-of-post-date
|
||||
:yodlee-account (:id yodlee-account)
|
||||
:plaid-account (:id plaid-account)
|
||||
:intuit-bank-account (:id intuit-bank-account)
|
||||
:code (if new?
|
||||
(str (:code new-client-data) "-" code)
|
||||
code)
|
||||
:bank-name bank-name
|
||||
:routing routing
|
||||
:bank-code bank-code})
|
||||
(:bank-accounts new-client-data))})))
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::mounted
|
||||
[with-user (re-frame/inject-cofx ::inject/sub [::subs/route-params])]
|
||||
(fn [{:keys [user db] ::subs/keys [route-params]} _]
|
||||
(when-let [id (some-> (:id route-params) (js/parseInt ) (#(if (js/Number.isNaN %) nil %)))]
|
||||
{:graphql {:token user
|
||||
:query-obj {:venia/queries [[:admin-client
|
||||
{:id id}
|
||||
(events/client-detail-query user)]]}
|
||||
:on-success (fn [result]
|
||||
[::received (:admin-client result)])}
|
||||
:db (-> db
|
||||
(forms/stop-form ::form))})))
|
||||
|
||||
(re-frame/reg-event-db
|
||||
::received
|
||||
(fn [db [_ client]]
|
||||
(-> 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
|
||||
:id (random-uuid)}) %))
|
||||
|
||||
(update :feature-flags #(mapv (fn [l] {:feature-flag l
|
||||
:id (random-uuid)}) %))
|
||||
(update :matches #(mapv (fn [l] {:match l
|
||||
:id (random-uuid)}) %))
|
||||
(update :bank-accounts
|
||||
(fn [bas]
|
||||
(mapv (fn [ba]
|
||||
(update ba :locations (fn [ls]
|
||||
(map (fn [l] {:location l
|
||||
:id (random-uuid)})
|
||||
ls))))
|
||||
bas))))))))
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::save-new-client
|
||||
[(forms/in-form ::form)]
|
||||
(fn [_ _]
|
||||
|
||||
(let [new-client-req @(re-frame/subscribe [::new-client-request])
|
||||
user @(re-frame/subscribe [::subs/token])]
|
||||
|
||||
{:graphql
|
||||
{:token user
|
||||
:owns-state {:single ::form}
|
||||
:query-obj {:venia/operation {:operation/type :mutation
|
||||
:operation/name "EditClient"}
|
||||
:venia/queries [{:query/data [:edit-client
|
||||
{:edit-client new-client-req}
|
||||
(events/client-detail-query user)]}]}
|
||||
:on-success [::save-complete]
|
||||
:on-error [::forms/save-error ::form]}})))
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::save-complete
|
||||
(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)}))
|
||||
|
||||
|
||||
|
||||
(re-frame/reg-event-db
|
||||
::add-new-bank-account
|
||||
[(forms/in-form ::form) (re-frame/path [:data])]
|
||||
(fn [client [_ type]]
|
||||
(update client :bank-accounts conj {:type type :active? true :new? true :visible true :sort-order (count (:bank-accounts client))})))
|
||||
|
||||
(re-frame/reg-event-db
|
||||
::bank-account-activated
|
||||
[(forms/in-form ::form) (re-frame/path [:data :bank-accounts])]
|
||||
(fn [bank-accounts [_ index]]
|
||||
(update (vec (sort-by :sort-order bank-accounts)) index assoc :active? true)))
|
||||
|
||||
(re-frame/reg-event-db
|
||||
::bank-account-deactivated
|
||||
[(forms/in-form ::form) (re-frame/path [:data :bank-accounts])]
|
||||
(fn [bank-accounts [_ index]]
|
||||
(update (vec (sort-by :sort-order bank-accounts)) index assoc :active? false)))
|
||||
|
||||
(re-frame/reg-event-db
|
||||
::bank-account-removed
|
||||
[(forms/in-form ::form) (re-frame/path [:data :bank-accounts])]
|
||||
(fn [bank-accounts [_ index]]
|
||||
(vec (concat (take index bank-accounts)
|
||||
(drop (inc index) bank-accounts)))))
|
||||
|
||||
(re-frame/reg-event-db
|
||||
::sort-swapped
|
||||
[(forms/in-form ::form) (re-frame/path [:data :bank-accounts])]
|
||||
(fn [bank-accounts [_ source dest]]
|
||||
(->> (-> bank-accounts
|
||||
(assoc-in [source :sort-order] (get-in bank-accounts [dest :sort-order]))
|
||||
(assoc-in [dest :sort-order] (get-in bank-accounts [source :sort-order]))
|
||||
|
||||
)
|
||||
(sort-by :sort-order)
|
||||
vec)))
|
||||
|
||||
(re-frame/reg-event-db
|
||||
::toggle-visible
|
||||
[(forms/in-form ::form) (re-frame/path [:data :bank-accounts])]
|
||||
(fn [bank-accounts [_ account]]
|
||||
(-> (->> bank-accounts
|
||||
(sort-by :sort-order)
|
||||
vec)
|
||||
(update-in [account :visible] #(not %)))))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
(def first-week-a (coerce/to-date-time #inst "1999-12-27T00:00:00.000-07:00"))
|
||||
|
||||
(defn is-week-a? [d]
|
||||
(= 0 (mod (t/in-weeks (t/interval first-week-a d)) 2)))
|
||||
|
||||
|
||||
(re-frame/reg-sub
|
||||
::yodlee-accounts
|
||||
:<- [::subs/clients-by-id]
|
||||
(fn [clients [_ id]]
|
||||
|
||||
(if id
|
||||
(mapcat :accounts (:yodlee-provider-accounts (get clients id) ))
|
||||
[])))
|
||||
|
||||
(re-frame/reg-sub
|
||||
::plaid-accounts
|
||||
:<- [::subs/clients-by-id]
|
||||
(fn [clients [_ id]]
|
||||
|
||||
(if id
|
||||
(mapcat :accounts (:plaid-items (get clients id) ))
|
||||
[])))
|
||||
|
||||
|
||||
(defn bank-account-card [new-client {:keys [active? new? type visible code name sort-order]} first? last?]
|
||||
[: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
|
||||
[:div.level-item
|
||||
[:span.icon.inline
|
||||
(cond
|
||||
(#{:check ":check"} type) [:span.icon-check-payment-sign]
|
||||
|
||||
(#{:credit ":credit"} type) [:span.icon-credit-card-1]
|
||||
|
||||
:else [:span.icon-accounting-bill])]]
|
||||
[:div.level-item code ": " name]]
|
||||
[:div.level-right
|
||||
[:div.level-item
|
||||
[:div.buttons
|
||||
[:a.button {:on-click (dispatch-event [::toggle-visible sort-order])} [:span.icon (if visible
|
||||
[:span.fa.fa-eye]
|
||||
[:span.fa.fa-eye-slash]
|
||||
)]]
|
||||
(when-not last?
|
||||
[:a.button {:on-click (dispatch-event [::sort-swapped sort-order (inc sort-order)])} [:span.icon [:span.fa.fa-sort-down]]])
|
||||
(when-not first?
|
||||
[:a.button {:on-click (dispatch-event [::sort-swapped sort-order (dec sort-order)])} [:span.icon [:span.fa.fa-sort-up]]])]]]]]
|
||||
(if active?
|
||||
[:a.card-header-icon
|
||||
{:on-click (dispatch-event [::bank-account-deactivated sort-order])}
|
||||
[:span.icon
|
||||
[:span.fa.fa-angle-up]]]
|
||||
[:a.card-header-icon
|
||||
{:on-click (dispatch-event [::bank-account-activated sort-order])}
|
||||
[:span.icon
|
||||
[:span.fa.fa-angle-down]]])]
|
||||
(when active?
|
||||
[:div.card-content
|
||||
[:label.label "General"]
|
||||
[level/left-stack
|
||||
[:div.control
|
||||
[:p.help "Account Code"]
|
||||
(if new?
|
||||
[:div.field.has-addons
|
||||
[:p.control [:a.button.is-static (:code new-client) "-" ]]
|
||||
[:p.control
|
||||
[form-builder/raw-field-v2 {:field :code}
|
||||
[:input.input {:type "text"}]]]]
|
||||
[:div.field [:p.control code]])]
|
||||
|
||||
[form-builder/field-v2 {:field :name}
|
||||
"Nickname"
|
||||
[:input.input {:placeholder "BOA Checking #1"
|
||||
: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 {:output :cljs-date}]]]
|
||||
|
||||
(when (#{:check ":check"} type )
|
||||
[:div
|
||||
|
||||
[:label.label "Bank"]
|
||||
[level/left-stack
|
||||
[form-builder/field-v2 {:field :bank-name}
|
||||
"Bank Name"
|
||||
[:input.input {:placeholder "Bank of America"
|
||||
:type "text"}]]
|
||||
[form-builder/field-v2 {:field [:routing]}
|
||||
"Routing #"
|
||||
[:input.input {:placeholder "104819123"
|
||||
:style {:width "9em"}
|
||||
:type "text"}]]
|
||||
[form-builder/field-v2 {:field :bank-code}
|
||||
"Bank code"
|
||||
[:input.input {:placeholder "12/10123"
|
||||
:type "text"}]]]
|
||||
|
||||
[level/left-stack
|
||||
[form-builder/field-v2 {:field :number}
|
||||
"Account #"
|
||||
[:input.input {:placeholder "123456789"
|
||||
:type "text"
|
||||
:style {:width "20em"}}]]
|
||||
|
||||
[form-builder/field-v2 {:field :check-number}
|
||||
"Check Number"
|
||||
[com/number-input {:style {:width "8em"}
|
||||
:placeholder "10000"}]]]
|
||||
|
||||
[form-builder/field-v2 {:field :yodlee-account}
|
||||
"Yodlee Account (new)"
|
||||
[typeahead-v3 {:entities (mapcat :accounts (:yodlee-provider-accounts new-client ))
|
||||
: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'"}]]
|
||||
|
||||
[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)))}]]
|
||||
[form-builder/field-v2 {:field :plaid-account}
|
||||
"Plaid Account"
|
||||
[typeahead-v3 {:entities (mapcat :accounts (:plaid-items new-client ))
|
||||
:entity->text (fn [m] (str (:name m)))}]]])
|
||||
|
||||
(when (#{:credit ":credit"} type )
|
||||
[:div
|
||||
|
||||
|
||||
[:label.label "Account"]
|
||||
[form-builder/field-v2 {:field :bank-name}
|
||||
"Bank Name"
|
||||
[:input.input {:placeholder "Bank of America"
|
||||
:type "text"}]]
|
||||
|
||||
[form-builder/field-v2 {:field :number}
|
||||
"Account #"
|
||||
[:input.input {:placeholder "123456789"
|
||||
:type "text"
|
||||
:style {:width "20em"}}]]
|
||||
|
||||
[form-builder/field-v2 {:field :yodlee-account}
|
||||
"Yodlee Account (new)"
|
||||
[typeahead-v3 {:entities (mapcat :accounts (:yodlee-provider-accounts new-client ))
|
||||
: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)))}]]
|
||||
|
||||
[form-builder/field-v2 {:field :plaid-account}
|
||||
"Plaid Account"
|
||||
[typeahead-v3 {:entities (mapcat :accounts (:plaid-items new-client ))
|
||||
: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-v2 {:field :locations}
|
||||
[com/multi-field-v2 {:template [[form-builder/raw-field-v2 {:field :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
|
||||
[:a.card-footer-item {:href "#" :on-click (dispatch-event [::bank-account-deactivated sort-order])} "Done"]
|
||||
(when new?
|
||||
[:a.card-footer-item.is-warning {:href "#" :on-click (dispatch-event [::bank-account-removed sort-order])} "Remove"])])])
|
||||
|
||||
|
||||
(defn general-section []
|
||||
(let [{new-client :data} @(re-frame/subscribe [::forms/form ::form])]
|
||||
[form-builder/section {:title "General"}
|
||||
[form-builder/field-v2 {:field :name}
|
||||
"Name"
|
||||
[:input.input {:type "text"
|
||||
:style {:width "20em"}}]]
|
||||
[form-builder/field-v2 {:field :code}
|
||||
"Client code"
|
||||
[:input.input {:type "code"
|
||||
:style {:width "5em"}
|
||||
:disabled (boolean (:id new-client))}]]
|
||||
[:div.field
|
||||
[:label.label "Feature Flags"]
|
||||
[:div.control
|
||||
[:p.help "These are specific new features that can be enabled or disabled on a per-client basis"]
|
||||
[form-builder/raw-field-v2 {:field :feature-flags}
|
||||
[com/multi-field-v2 {:allow-change? true
|
||||
:template [[form-builder/raw-field-v2 {:field :feature-flag}
|
||||
[com/select-field {:options [[nil nil]
|
||||
["new-square" "New Square+Ezcater (no effect)"]
|
||||
["manually-pay-cintas" "Manually Pay Cintas"]
|
||||
["include-in-ntg-corp-reports" "Include in NTG Corporate reports"]]
|
||||
:allow-nil? false
|
||||
:style {:width "18em"}}]]]
|
||||
:key-fn :id
|
||||
:schema [:sequential feature-flag-schema]
|
||||
:next-key (random-uuid)}]]]]
|
||||
|
||||
[form-builder/field-v2 {:field :locations}
|
||||
"Locations"
|
||||
[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)}]]
|
||||
|
||||
[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-v2 {:field :locked-until}
|
||||
"Locked Until"
|
||||
[date-picker {:output :cljs-date
|
||||
:style {:width "15em"}}]]]))
|
||||
|
||||
(defn contacts-section []
|
||||
[form-builder/section {:title "Contacts"}
|
||||
|
||||
[form-builder/field-v2 {:field :emails}
|
||||
"Emails (address/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"
|
||||
[:div {:style {:width "30em"}}
|
||||
[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-v2 {:field :matches}
|
||||
"Name matches"
|
||||
[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-v2 {:field :location-matches}
|
||||
"Location Matches"
|
||||
[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])]
|
||||
[form-builder/section {:title "Bank Accounts"}
|
||||
(for [bank-account (sort-by :sort-order (:bank-accounts new-client))]
|
||||
^{:key (:sort-order bank-account)}
|
||||
[form-builder/with-scope {:scope [:bank-accounts (: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.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"]]]))
|
||||
|
||||
(defn cash-flow-section []
|
||||
(let [next-week-a (if (is-week-a? (t/now))
|
||||
"This week"
|
||||
"Next week")
|
||||
next-week-b (if (is-week-a? (t/now))
|
||||
"Next week"
|
||||
"This week")]
|
||||
|
||||
|
||||
[form-builder/section {:title "Cash Flow"}
|
||||
[:label.label (str "Week A (" next-week-a ")")]
|
||||
[left-stack
|
||||
[form-builder/field-v2 {:field :week-a-credits}
|
||||
"Regular Credits"
|
||||
[com/money-input]]
|
||||
[form-builder/field-v2 {:field :week-a-debits}
|
||||
"Regular Debits"
|
||||
[com/money-input]]]
|
||||
[:label.label (str "Week B (" next-week-b ")")]
|
||||
[left-stack
|
||||
[form-builder/field-v2 {:field :week-b-credits}
|
||||
"Regular Credits"
|
||||
[com/money-input]]
|
||||
[form-builder/field-v2 {:field :week-b-debits}
|
||||
"Regular Debits"
|
||||
[com/money-input]]]
|
||||
|
||||
[form-builder/field-v2 {:field :forecasted-transactions}
|
||||
"Forecasted transactions"
|
||||
|
||||
[com/multi-field-v2 {:template [[form-builder/raw-field-v2 {:field :identifier}
|
||||
[:input.input {:type "text"
|
||||
:placeholder "Identifier"
|
||||
:style {:width "10em"}}]]
|
||||
[form-builder/raw-field-v2 {:field :day-of-month}
|
||||
[com/number-input {:placeholder "DOM"}]]
|
||||
[form-builder/raw-field-v2 {:field :amount
|
||||
:placeholder "AMT"}
|
||||
[com/money-input]]]
|
||||
:key-fn :id}]]]))
|
||||
|
||||
(defn square-section []
|
||||
(let [{new-client :data} @(re-frame/subscribe [::forms/form ::form])]
|
||||
[form-builder/section {:title "Square Integration"}
|
||||
[form-builder/field-v2 {:field :square-auth-token}
|
||||
"Square Authentication Token"
|
||||
[:input.input {:type "text"
|
||||
:style {:width "40em"}}]]
|
||||
[form-builder/field-v2 {:field :selected-square-locations}
|
||||
"Square Locations"
|
||||
[com/multi-field-v2 {:template [[form-builder/raw-field-v2 {:field :square-location}
|
||||
[typeahead-v3 {:entities (:square-locations new-client)
|
||||
:entity->text :name
|
||||
:style {:width "15em"}}]]
|
||||
[form-builder/raw-field-v2 {:field :client-location}
|
||||
[com/select-field {:options (map (fn [l]
|
||||
[(:location l) (:location l)])
|
||||
(get-in new-client [:locations]))
|
||||
:allow-nil? true
|
||||
:style {:width "7em"}
|
||||
}]]]
|
||||
:disable-remove? true
|
||||
:key-fn :id
|
||||
:schema [:sequential square-location-schema]}]]]))
|
||||
|
||||
(defn ezcater-section []
|
||||
(let [{new-client :data} @(re-frame/subscribe [::forms/form ::form])]
|
||||
[form-builder/section {:title "EZCater integration"}
|
||||
|
||||
[form-builder/field-v2 {:field :ezcater-locations}
|
||||
"EZCater Locations"
|
||||
[com/multi-field-v2 {:template [[form-builder/raw-field-v2 {:field :caterer}
|
||||
[search-backed-typeahead {:search-query (fn [i]
|
||||
[:search_ezcater_caterer
|
||||
{:query i}
|
||||
[:name :id]])
|
||||
:entity->text :name
|
||||
:style {:width "20em"}}]]
|
||||
[form-builder/raw-field-v2 {:field [:location]}
|
||||
[com/select-field {:options (map (fn [l]
|
||||
[(:location l) (:location l)])
|
||||
(get-in new-client [:locations]))
|
||||
:allow-nil? true
|
||||
:style {:width "7em"}}]]]
|
||||
:key-fn :id
|
||||
:schema [:sequential ezcater-schema]
|
||||
:disable-remove? true}]]]))
|
||||
|
||||
|
||||
(defn form-content []
|
||||
(let [{new-client :data} @(re-frame/subscribe [::forms/form ::form])]
|
||||
|
||||
^{:key (or (:id new-client)
|
||||
"new")}
|
||||
[form-builder/builder {:submit-event [::save-new-client ]
|
||||
:id ::form
|
||||
:fullwidth? false
|
||||
:schema client-schema}
|
||||
|
||||
[general-section]
|
||||
[contacts-section]
|
||||
[matching-section]
|
||||
[bank-accounts-section]
|
||||
[cash-flow-section]
|
||||
[square-section]
|
||||
[ezcater-section]
|
||||
[form-builder/error-notification]
|
||||
[form-builder/submit-button "Save"]]))
|
||||
|
||||
(def new-client-form
|
||||
(with-meta
|
||||
(fn []
|
||||
(let [_ @(re-frame/subscribe [::subs/route-params])]
|
||||
[form-content]))
|
||||
{:component-did-mount #(re-frame/dispatch [::mounted])}))
|
||||
@@ -1,23 +0,0 @@
|
||||
(ns auto-ap.views.pages.admin.clients.side-bar
|
||||
(:require
|
||||
[re-frame.core :as re-frame]
|
||||
[auto-ap.views.utils :refer [dispatch-value-change]]
|
||||
[auto-ap.views.pages.data-page :as data-page]))
|
||||
|
||||
(defn client-side-bar [{:keys [data-page]}]
|
||||
[:div
|
||||
[:p.menu-label "Name"]
|
||||
|
||||
[:div.field
|
||||
[:div.control [:input.input {:placeholder "Harry's Food Products"
|
||||
:value @(re-frame/subscribe [::data-page/filter data-page :name-like])
|
||||
:on-change (dispatch-value-change [::data-page/filter-changed data-page :name-like])} ]]]
|
||||
|
||||
[:p.menu-label "Code"]
|
||||
|
||||
[:div.field
|
||||
[:div.control [:input.input {:placeholder "CBC"
|
||||
:value @(re-frame/subscribe [::data-page/filter data-page :code])
|
||||
:on-change (dispatch-value-change [::data-page/filter-changed data-page :code])} ]]]])
|
||||
|
||||
|
||||
@@ -1,123 +0,0 @@
|
||||
(ns auto-ap.views.pages.admin.clients.table
|
||||
(:require [auto-ap.subs :as subs]
|
||||
[clojure.string :as str]
|
||||
[re-frame.core :as re-frame]
|
||||
[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]
|
||||
[bidi.bidi :as bidi]
|
||||
[auto-ap.routes :as routes]
|
||||
[auto-ap.views.pages.data-page :as data-page]))
|
||||
|
||||
(re-frame/reg-sub
|
||||
::specific-params
|
||||
(fn [db]
|
||||
(::params db)))
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::params-changed
|
||||
(fn [{:keys [db]} [_ p]]
|
||||
{:db (assoc db ::params p)}))
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::sales-queries-setup
|
||||
(fn [_ [_ results]]
|
||||
{:dispatch [::modal/modal-requested {:title "Sales Queries"
|
||||
:body [:div [:pre (:message (:setup-sales-queries results))]]}]}))
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::setup-sales-queries
|
||||
[with-user]
|
||||
(fn [{:keys [user]} [_ client-id]]
|
||||
{:graphql
|
||||
{:token user
|
||||
:owns-state {:multi ::setup-sales-queries
|
||||
:which client-id}
|
||||
:query-obj {:venia/operation {:operation/type :mutation
|
||||
:operation/name "SetupSalesQueries"}
|
||||
:venia/queries [{:query/data [:setup-sales-queries
|
||||
{:client-id client-id}
|
||||
[:message]]}]}
|
||||
:on-success [::sales-queries-setup]}}
|
||||
))
|
||||
|
||||
(re-frame/reg-sub
|
||||
::params
|
||||
:<- [::specific-params]
|
||||
:<- [::subs/query-params]
|
||||
(fn [[specific-params query-params]]
|
||||
(merge (select-keys query-params #{:start :sort}) specific-params )))
|
||||
|
||||
|
||||
(defn integration-status-badge [name status]
|
||||
(condp = (:state status)
|
||||
:success
|
||||
[:div.tag.has-tooltip-right.has-tooltip-arrow {:data-tooltip (str "Last updated:" (date->str (:last-updated status))
|
||||
"\n"
|
||||
"Last Attempted:" (date->str (:last-attempt status)))} [:span.icon [:i.has-text-success.fa.fa-check]] [:span name]]
|
||||
|
||||
:failed
|
||||
[:div.tag.is-danger.is-light.has-tooltip-right.has-tooltip-arrow {:data-tooltip (str "Last updated:" (date->str (:last-updated status))
|
||||
"\n"
|
||||
"Last Attempted:" (date->str (:last-attempt status))
|
||||
"\n"
|
||||
(:message status))
|
||||
} [:span.icon [:i.has-text-danger.fa.fa-warning]] [:span name]]
|
||||
|
||||
:unauthorized
|
||||
[:div.tag.is-danger.is-light.has-tooltip-right.has-tooltip-arrow {:data-tooltip (str "Last updated:" (date->str (:last-updated status))
|
||||
"\n"
|
||||
"Last Attempted:" (date->str (:last-attempt status))
|
||||
"\n"
|
||||
"Your user is unauthorized. Detail:\n"
|
||||
(:message status))
|
||||
} [:span.icon [:i.has-text-danger.fa.fa-warning]] [:span name]]
|
||||
nil
|
||||
))
|
||||
|
||||
(defn clients-table [{:keys [data-page status]}]
|
||||
(let [states @(re-frame/subscribe [::status/multi ::setup-sales-queries])
|
||||
{:keys [data]} @(re-frame/subscribe [::data-page/page data-page])]
|
||||
[grid/grid {:on-params-change (fn [p]
|
||||
(re-frame/dispatch [::params-changed p]))
|
||||
:data-page data-page
|
||||
:status status
|
||||
:params @(re-frame/subscribe [::params])
|
||||
:column-count 5}
|
||||
[grid/controls data]
|
||||
[grid/table {:fullwidth true}
|
||||
[grid/header
|
||||
[grid/row {}
|
||||
[grid/header-cell {} "Name"]
|
||||
[grid/header-cell {:style {:width "20em"}} "Code"]
|
||||
[grid/header-cell {} "Locations"]
|
||||
[grid/header-cell {} "Status"]
|
||||
[grid/header-cell {} "Email"]
|
||||
[grid/header-cell {:style {:width (action-cell-width 2)}}]]]
|
||||
[grid/body
|
||||
(for [{:keys [id name email square-integration-status locked-until code locations bank-accounts]} (:data data)]
|
||||
^{:key (str name "-" id)}
|
||||
[grid/row {:id id}
|
||||
[grid/cell {} name]
|
||||
[grid/cell {} code]
|
||||
[grid/cell {} (str/join ", " locations)]
|
||||
[grid/cell {:class "expandable"} [:div.tags
|
||||
|
||||
[:div.tag (or (some-> locked-until date->str (#(str "Locked " %))) "Not locked")]
|
||||
[integration-status-badge "Square" square-integration-status]
|
||||
[:<>
|
||||
(for [bank-account bank-accounts
|
||||
:let [code (:code bank-account)
|
||||
integration-status (:integration-status bank-account)]
|
||||
:when (:id integration-status)]
|
||||
^{:key (:id integration-status)}
|
||||
[integration-status-badge code integration-status])]]]
|
||||
[grid/cell {} email]
|
||||
[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 {:href (bidi/path-for routes/routes :admin-specific-client :id id)
|
||||
:icon :fa-pencil}]]]])]]
|
||||
[grid/bottom-paginator data]]))
|
||||
@@ -1,94 +0,0 @@
|
||||
(ns auto-ap.views.pages.admin.vendors
|
||||
(:require
|
||||
[auto-ap.effects.forward :as forward]
|
||||
[auto-ap.subs :as subs]
|
||||
[auto-ap.shared-views.admin.side-bar :refer [admin-side-bar]]
|
||||
[auto-ap.views.components.layouts :refer [side-bar-layout]]
|
||||
[auto-ap.views.pages.admin.vendors.merge-dialog :as merge-dialog]
|
||||
[auto-ap.views.pages.admin.vendors.side-bar :as side-bar]
|
||||
[auto-ap.views.pages.admin.vendors.table :as table]
|
||||
[auto-ap.views.pages.data-page :as data-page]
|
||||
[auto-ap.views.utils :refer [dispatch-event with-user]]
|
||||
[clojure.set :as set]
|
||||
[re-frame.core :as re-frame]
|
||||
[vimsical.re-frame.fx.track :as track]
|
||||
[auto-ap.views.components.vendor-dialog :as vendor-dialog]))
|
||||
|
||||
(def default-read [:id :name :hidden :terms [:default-account [:name :id :location]]
|
||||
[:account-overrides [[:client [:id :name]] :id [:account [:id :numeric-code :name]]]]
|
||||
[:automatically-paid-when-due [:id :name]]
|
||||
[:terms-overrides [[:client [:id :name]] :id :terms]]
|
||||
[:schedule-payment-dom [[:client [:id :name]] :id :dom]]
|
||||
[:usage [:client-id :count]]
|
||||
[:primary-contact [:name :phone :email :id]]
|
||||
[:secondary-contact [:id :name :phone :email]]
|
||||
[:plaid-merchant [:id :name]]
|
||||
:print-as :invoice-reminder-schedule :code
|
||||
:legal-entity-name
|
||||
:legal-entity-first-name :legal-entity-middle-name :legal-entity-last-name
|
||||
:legal-entity-tin :legal-entity-tin-type
|
||||
:legal-entity-1099-type
|
||||
[:address [:id :street1 :street2 :city :state :zip]]])
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::params-change
|
||||
[with-user]
|
||||
(fn [{:keys [user]} [_ params]]
|
||||
{:graphql {:token user
|
||||
:owns-state {:single [::data-page/page ::page]}
|
||||
:query-obj {:venia/queries [{:query/data [:vendor
|
||||
{:sort (:sort params)
|
||||
:start (:start params 0)
|
||||
:per-page (:per-page params)
|
||||
:name-like (:name-like params)}
|
||||
[[:vendors default-read]
|
||||
:total
|
||||
:start
|
||||
:end]]
|
||||
:query/alias :result}]}
|
||||
:on-success (fn [result]
|
||||
[::data-page/received ::page
|
||||
(set/rename-keys (:result result)
|
||||
{:vendors :data})])}}))
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::mounted
|
||||
(fn [_ _]
|
||||
{::forward/register [{:id ::merge-complete
|
||||
:events #{::merge-dialog/complete}
|
||||
:event-fn (fn [_]
|
||||
[::params-change {}])}
|
||||
{:id ::save-complete
|
||||
:events #{::vendor-dialog/save-complete}
|
||||
:event-fn (fn [_]
|
||||
[::params-change {}])}]
|
||||
::track/register {:id ::params
|
||||
:subscription [::data-page/params ::page]
|
||||
:event-fn (fn [params]
|
||||
[::params-change params])}}))
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::unmounted
|
||||
(fn [_ _]
|
||||
{:dispatch [::data-page/dispose ::page]
|
||||
::forward/dispose [{:id ::merge-complete} {:id ::save-complete}]
|
||||
::track/dispose {:id ::params}}))
|
||||
|
||||
(defn admin-vendors-content []
|
||||
[(with-meta
|
||||
(fn []
|
||||
[:div.inbox-messages
|
||||
(when-let [banner (:banner @(re-frame/subscribe [::subs/admin]))]
|
||||
[:div.notification banner])
|
||||
[:div
|
||||
[:h1.title "Vendors"]
|
||||
[:div.is-pulled-right [:a.button.is-primary.is-outlined {:on-click (dispatch-event [::merge-dialog/show])} "Merge vendors"]]
|
||||
[table/vendors-table {:id :vendors
|
||||
:data-page ::page}]]])
|
||||
{:component-did-mount #(re-frame/dispatch [::mounted])
|
||||
:component-will-unmount #(re-frame/dispatch-sync [::unmounted])})])
|
||||
|
||||
(defn admin-vendors-page []
|
||||
[side-bar-layout {:side-bar [admin-side-bar {}
|
||||
[side-bar/vendor-side-bar {:data-page ::page}]]
|
||||
:main [admin-vendors-content]}])
|
||||
@@ -1,17 +0,0 @@
|
||||
(ns auto-ap.views.pages.admin.vendors.common)
|
||||
|
||||
(def default-read [:id :name :hidden :terms [:default-account [:name :id :location]]
|
||||
[:account-overrides [[:client [:id :name]] :id [:account [:id :numeric-code :name]]]]
|
||||
[:automatically-paid-when-due [:id :name]]
|
||||
[:terms-overrides [[:client [:id :name]] :id :terms]]
|
||||
[:schedule-payment-dom [[:client [:id :name]] :id :dom]]
|
||||
[:usage [:client-id :count]]
|
||||
[:primary-contact [:name :phone :email :id]]
|
||||
[:plaid-merchant [:name :id]]
|
||||
[:secondary-contact [:id :name :phone :email]]
|
||||
:print-as :invoice-reminder-schedule :code
|
||||
:legal-entity-name
|
||||
:legal-entity-first-name :legal-entity-middle-name :legal-entity-last-name
|
||||
:legal-entity-tin :legal-entity-tin-type
|
||||
:legal-entity-1099-type
|
||||
[:address [:id :street1 :street2 :city :state :zip]]])
|
||||
@@ -1,80 +0,0 @@
|
||||
(ns auto-ap.views.pages.admin.vendors.merge-dialog
|
||||
(:require
|
||||
[auto-ap.forms :as forms]
|
||||
[auto-ap.forms.builder :as form-builder]
|
||||
[auto-ap.schema :as schema]
|
||||
[auto-ap.status :as status]
|
||||
[auto-ap.subs :as subs]
|
||||
[auto-ap.views.components :as com]
|
||||
[auto-ap.views.components.modal :as modal]
|
||||
[auto-ap.views.utils :refer [dispatch-event]]
|
||||
[malli.core :as m]
|
||||
[re-frame.core :as re-frame]))
|
||||
|
||||
(def merge-schema
|
||||
(m/schema [:map
|
||||
[:from schema/reference]
|
||||
[:to schema/reference]]))
|
||||
|
||||
(defn form []
|
||||
[form-builder/builder {:submit-event [::try-save]
|
||||
:id ::form
|
||||
:schema merge-schema}
|
||||
[form-builder/field-v2 {:field :from}
|
||||
"Form Vendor (will be deleted)"
|
||||
[com/search-backed-typeahead {:search-query (fn [i]
|
||||
[:search_vendor
|
||||
{:query i}
|
||||
[:name :id]])
|
||||
:auto-focus true}]]
|
||||
|
||||
|
||||
[form-builder/field-v2 {:field :to}
|
||||
"To Vendor"
|
||||
[com/search-backed-typeahead {:search-query (fn [i]
|
||||
[:search_vendor
|
||||
{:query i}
|
||||
[:name :id]])}]]
|
||||
[form-builder/hidden-submit-button]])
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::show
|
||||
(fn [{:keys [db]} _]
|
||||
{:dispatch [::modal/modal-requested {:title "Merge Vendors"
|
||||
:body [form]
|
||||
:confirm {:value "Merge"
|
||||
:status-from [::status/single ::form]
|
||||
:class "is-primary"
|
||||
:on-click (dispatch-event [::try-save])
|
||||
:close-event [::status/completed ::form]}}]
|
||||
:db (forms/start-form db ::form {})}))
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::complete
|
||||
(fn [{:keys [db]} _]
|
||||
{:db (forms/stop-form db ::form)
|
||||
:dispatch [::modal/modal-closed ]}))
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::save
|
||||
[(forms/in-form ::form)]
|
||||
(fn [{{{:keys [from to]} :data} :db} _]
|
||||
(let [user @(re-frame/subscribe [::subs/token])]
|
||||
{:graphql
|
||||
{:token user
|
||||
:owns-state {:single ::form}
|
||||
:query-obj {:venia/operation {:operation/type :mutation
|
||||
:operation/name "MergeVendors"}
|
||||
:venia/queries [{:query/data [:merge-vendors
|
||||
{:from (:id from) :to (:id to)} []]}]}
|
||||
:on-success [::complete]}})))
|
||||
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::try-save
|
||||
[(forms/in-form ::form)]
|
||||
(fn [{:keys [db]}]
|
||||
(if (not (m/validate merge-schema (:data db)))
|
||||
{:dispatch-n [[::status/error ::form [{:message "Please correct any errors and try again"}]]
|
||||
[::forms/attempted-submit ::form]]}
|
||||
{:dispatch [::save]})))
|
||||
@@ -1,16 +0,0 @@
|
||||
(ns auto-ap.views.pages.admin.vendors.side-bar
|
||||
(:require
|
||||
[auto-ap.views.pages.data-page :as data-page]
|
||||
[auto-ap.views.utils :refer [dispatch-value-change]]
|
||||
[re-frame.core :as re-frame]))
|
||||
|
||||
(defn vendor-side-bar [{:keys [data-page]}]
|
||||
[:div
|
||||
[:p.menu-label "Name"]
|
||||
[:div
|
||||
[:div.field
|
||||
[:div.control [:input.input {:placeholder "HOME DEPOT"
|
||||
:value @(re-frame/subscribe [::data-page/filter data-page :name-like])
|
||||
:on-change (dispatch-value-change [::data-page/filter-changed data-page :name-like])} ]]]]])
|
||||
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
(ns auto-ap.views.pages.admin.vendors.table
|
||||
(:require
|
||||
[auto-ap.views.components.buttons :as buttons]
|
||||
[auto-ap.views.components.grid :as grid]
|
||||
[auto-ap.views.components.vendor-dialog :as vendor-dialog]
|
||||
[auto-ap.views.pages.data-page :as data-page]
|
||||
[auto-ap.views.utils :refer [action-cell-width]]
|
||||
[re-frame.core :as re-frame]))
|
||||
|
||||
(defn vendors-table [{:keys [data-page]}]
|
||||
(let [{:keys [data]} @(re-frame/subscribe [::data-page/page data-page])]
|
||||
[grid/grid {:data-page data-page
|
||||
:column-count 4}
|
||||
[grid/controls data]
|
||||
[grid/table {:fullwidth true}
|
||||
[grid/header
|
||||
[grid/row {}
|
||||
[grid/header-cell {} "Name"]
|
||||
[grid/header-cell {} "Email"]
|
||||
[grid/header-cell {} "Default Account"]
|
||||
[grid/header-cell {:style {:width (action-cell-width 1)}}]]]
|
||||
[grid/body
|
||||
(for [v (:data data)]
|
||||
^{:key (str (:id v))}
|
||||
[grid/row {:class (:class v) :id (:id v)}
|
||||
[grid/cell {} (:name v)
|
||||
(let [total-usage (reduce + 0 (map :count (:usage v)))]
|
||||
(if (> total-usage 0)
|
||||
[:div.mx-2.tag.is-info.is-light total-usage " usages, " (count (:usage v)) " clients"]
|
||||
[:div.mx-2.tag.is-warning.is-light "Unused"]))]
|
||||
[grid/cell {} (:email (:primary-contact v))]
|
||||
[grid/cell {} (-> v :default-account :name)]
|
||||
[grid/cell {}
|
||||
[buttons/fa-icon {:event [::vendor-dialog/started v]
|
||||
:icon "fa-pencil"}]]])]]
|
||||
[grid/bottom-paginator data]]))
|
||||
Reference in New Issue
Block a user