From 5561861d3d4d636b28e59663251b261b51ea6258 Mon Sep 17 00:00:00 2001 From: Bryce Covert Date: Thu, 6 Apr 2023 14:38:22 -0700 Subject: [PATCH] (cloud) big performance improvements for page load. --- src/clj/auto_ap/datomic/clients.clj | 142 +++++++++++++----- src/clj/auto_ap/datomic/sales_orders.clj | 3 +- src/clj/auto_ap/graphql.clj | 19 ++- src/clj/auto_ap/graphql/clients.clj | 88 ++++++++--- src/cljs/auto_ap/events.cljs | 12 +- .../auto_ap/views/pages/admin/clients.cljs | 73 +++++---- .../views/pages/admin/clients/form.cljs | 81 +++++----- .../views/pages/admin/clients/side_bar.cljs | 68 +-------- .../views/pages/admin/clients/table.cljs | 13 +- src/cljs/auto_ap/views/pages/home.cljs | 122 ++++++++------- 10 files changed, 349 insertions(+), 272 deletions(-) diff --git a/src/clj/auto_ap/datomic/clients.clj b/src/clj/auto_ap/datomic/clients.clj index eea2ea40..22371d15 100644 --- a/src/clj/auto_ap/datomic/clients.clj +++ b/src/clj/auto_ap/datomic/clients.clj @@ -1,10 +1,46 @@ (ns auto-ap.datomic.clients (:require - [auto-ap.datomic :refer [conn]] + [auto-ap.datomic :refer [add-sorter-fields + apply-pagination + apply-sort-3 + conn + merge-query + pull-many]] + [auto-ap.graphql.utils :refer [can-see-client? limited-clients]] [auto-ap.search :as search] [clj-time.coerce :as coerce] [clojure.string :as str] - [datomic.client.api :as dc])) + [datomic.client.api :as dc] + [com.brunobonacci.mulog :as mu])) + +(def full-read '[* + {:client/square-integration-status [:integration-status/message + :integration-status/last-attempt + :integration-status/last-updated + :db/id + {:integration-status/state [:db/ident]}]} + {:client/address [*]} + {:client/square-locations [:square-location/square-id + :square-location/name + :square-location/client-location + :db/id]} + + {:client/ezcater-locations [{:ezcater-location/caterer [:ezcater-caterer/name :db/id]} + :ezcater-location/location + :db/id]} + {:client/bank-accounts [* {:bank-account/type [*] + :bank-account/yodlee-account [:yodlee-account/name :yodlee-account/id :yodlee-account/number] + :bank-account/plaid-account [:plaid-account/name :db/id :plaid-account/number :plaid-account/balance] + :bank-account/intuit-bank-account [:intuit-bank-account/name :intuit-bank-account/external-id :db/id] + :bank-account/integration-status [:integration-status/message + :db/id + :integration-status/last-attempt + :integration-status/last-updated + {:integration-status/state [:db/ident]}]} + ]} + {:yodlee-provider-account/_client [*]} + {:plaid-item/_client [*]} + {:client/emails [:db/id :email-contact/email :email-contact/description]}]) (defn cleanse [e] (-> e @@ -29,52 +65,25 @@ (update :bank-account/sort-order (fn [so] (or so i))))) (range) bas))))) (defn get-all [] - (->> (dc/q '[:find (pull ?e [* - {:client/square-integration-status [:integration-status/message - :integration-status/last-attempt - :integration-status/last-updated - :db/id - {:integration-status/state [:db/ident]}]} - {:client/address [*]} - {:client/square-locations [:square-location/square-id - :square-location/name - :square-location/client-location - :db/id]} - - {:client/ezcater-locations [{:ezcater-location/caterer [:ezcater-caterer/name :db/id]} - :ezcater-location/location - :db/id]} - {:client/bank-accounts [* {:bank-account/type [*] - :bank-account/yodlee-account [:yodlee-account/name :yodlee-account/id :yodlee-account/number] - :bank-account/plaid-account [:plaid-account/name :db/id :plaid-account/number :plaid-account/balance] - :bank-account/intuit-bank-account [:intuit-bank-account/name :intuit-bank-account/external-id :db/id] - :bank-account/integration-status [:integration-status/message - :db/id - :integration-status/last-attempt - :integration-status/last-updated - {:integration-status/state [:db/ident]}]} - ]} - {:yodlee-provider-account/_client [*]} - {:plaid-item/_client [*]} - {:client/emails [:db/id :email-contact/email :email-contact/description]}]) + (->> (dc/q '[:find (pull ?e ?r) + :in $ ?r :where [?e :client/name]] - (dc/db conn)) + (dc/db conn) + full-read) + (map first) + (map cleanse))) + +(defn get-minimal [] + (->> (dc/q '[:find (pull ?e [:client/name :client/code :client/locations :db/id {:client/bank-accounts [{:bank-account/type [:db/ident]} :bank-account/name :bank-account/code :db/id]}]) + :where [?e :client/name]] + (dc/db conn)) (map first) (map cleanse))) (defn get-by-id [id] (->> (dc/pull (dc/db conn ) - '[* {:client/bank-accounts [* {:bank-account/type [*] - :bank-account/yodlee-account [:yodlee-account/name :yodlee-account/id :yodlee-account/number] - :bank-account/intuit-bank-account [:intuit-bank-account/name :intuit-bank-account/external-id :db/id] - :bank-account/plaid-account [:plaid-account/name :db/id :plaid-account/number :plaid-account/balance]}] - :client/emails [:db/id :email-contact/email :email-contact/description]} - {:client/ezcater-locations [{:ezcater-location/caterer [:ezcater-caterer/name :db/id]} - :ezcater-location/location - :db/id]} - {:yodlee-provider-account/_client [*]} - {:plaid-item/_client [*]}] + full-read id) (cleanse))) @@ -105,3 +114,54 @@ :text match :exact-match (str/upper-case match)}) "client")) + + +(defn raw-graphql-ids [db args] + (let [query (cond-> {:query {:find [] + :in ['$ ] + :where []} + :args [db]} + + + (not (str/blank? (:code args))) + (merge-query {:query {:in ['?client-code] + :where ['[?e :client/code ?client-code]]} + :args [(:code args)]}) + + (not (str/blank? (:name-like args))) + (merge-query {:query {:in ['?name-like] + :where ['[?e :client/name ?name] + '[(clojure.string/includes? ?name ?name-like)]]} + :args [(:name-like args)]}) + + (limited-clients (:id args)) + (merge-query {:query {:in ['[?e ...]] + :where []} + :args [(set (map :db/id (limited-clients (:id args))))]}) + + + (:sort args) (add-sorter-fields {"name" ['[?e :client/name ?sort-name]]} + args) + + true + (merge-query {:query {:find ['?sort-default '?e] :where ['[?e :client/name ?sort-default]]}}))] + (mu/log ::q + :query query) + (->> query + (dc/q) + (apply-sort-3 (update args :sort conj {:sort-key "default-2" :asc true})) + (apply-pagination args)))) + +(defn graphql-results [ids db args] + (let [results (->> (pull-many db full-read + ids) + (map cleanse))] + results)) + + +(defn get-graphql-page [args] + (let [db (dc/db conn) + {ids-to-retrieve :ids matching-count :count} (raw-graphql-ids db args)] + + [(->> (graphql-results ids-to-retrieve db args)) + matching-count])) diff --git a/src/clj/auto_ap/datomic/sales_orders.clj b/src/clj/auto_ap/datomic/sales_orders.clj index e9d20b03..27d3d103 100644 --- a/src/clj/auto_ap/datomic/sales_orders.clj +++ b/src/clj/auto_ap/datomic/sales_orders.clj @@ -9,11 +9,10 @@ pull-many visible-clients conn]] - [auto-ap.graphql.utils :refer [limited-clients]] + [iol-ion.query] [clj-time.coerce :as c] [clj-time.core :as time] [clojure.set :as set] - [clojure.tools.logging :as log] [datomic.client.api :as dc] [com.brunobonacci.mulog :as mu] )) diff --git a/src/clj/auto_ap/graphql.clj b/src/clj/auto_ap/graphql.clj index c5bd3b13..818d548a 100644 --- a/src/clj/auto_ap/graphql.clj +++ b/src/clj/auto_ap/graphql.clj @@ -699,15 +699,14 @@ (- (+ total credit) debit)) 0.0 - (dc/q {:query {:find '[?debit ?credit] - :in '[$ ?client] - :where ['[?j :journal-entry/client ?client] - '[?j :journal-entry/line-items ?je] - '[?je :journal-entry-line/account ?ba] - '[?ba :bank-account/type :bank-account-type/check] - '[(get-else $ ?je :journal-entry-line/debit 0.0) ?debit] - '[(get-else $ ?je :journal-entry-line/credit 0.0) ?credit]]} - :args [(dc/db conn) client_id]})) + (dc/q {:query {:find '[?debit ?credit] + :in '[$ ?client] + :where ['[?client :client/bank-accounts ?ba] + '[?ba :bank-account/type :bank-account-type/check] + '[?je :journal-entry-line/account ?ba] + '[(get-else $ ?je :journal-entry-line/debit 0.0) ?debit] + '[(get-else $ ?je :journal-entry-line/credit 0.0) ?credit]]} + :args [(dc/db conn) client_id]})) bills-due-soon (dc/q {:query {:find '[?due ?outstanding ?invoice-number ?vendor-id ?vendor-name] :in '[$ ?client ?due-before] :where ['[?i :invoice/client ?client] @@ -734,8 +733,8 @@ recent-fulfillments (dc/q {:query {:find '[?f ?d] :in '[$ ?client ?min-date] :where ['[?t :transaction/forecast-match ?f] - '[?t :transaction/date ?d] '[?t :transaction/client ?client] + '[?t :transaction/date ?d] '[(>= ?d ?min-date)]]} :args [(dc/db conn) client_id (coerce/to-date (t/plus (time/local-now) (t/months -2)))]}) forecasted-transactions (for [{:forecasted-transaction/keys [amount identifier day-of-month] diff --git a/src/clj/auto_ap/graphql/clients.clj b/src/clj/auto_ap/graphql/clients.clj index 485a0c4e..60eb9b95 100644 --- a/src/clj/auto_ap/graphql/clients.clj +++ b/src/clj/auto_ap/graphql/clients.clj @@ -3,12 +3,13 @@ [amazonica.aws.s3 :as s3] [auto-ap.datomic :refer [audit-transact conn]] [auto-ap.datomic.clients :as d-clients] - [iol-ion.tx :refer [upsert-entity]] [auto-ap.graphql.utils :refer [->graphql assert-admin attach-tracing-resolvers can-see-client? + <-graphql + result->page is-admin?]] [auto-ap.routes.queries :as q] [auto-ap.square.core :as square] @@ -18,12 +19,12 @@ [clojure.set :as set] [clojure.string :as str] [clojure.tools.logging :as log] + [com.brunobonacci.mulog :as mu] [datomic.client.api :as dc] - [unilog.context :as lc] + [iol-ion.tx :refer [random-tempid upsert-entity]] [mount.core :as mount] - [yang.scheduler :as scheduler] - [iol-ion.tx :refer [random-tempid]] - [com.brunobonacci.mulog :as mu]) + [unilog.context :as lc] + [yang.scheduler :as scheduler]) (:import (java.util UUID) (org.apache.commons.codec.binary Base64))) @@ -200,23 +201,39 @@ (defn get-client [context _ _] (->graphql - (->> (d-clients/get-all) - (filter #(can-see-client? (:id context) %)) - (map (fn [c] - (update c :client/bank-accounts (fn [bas] - (map #(set/rename-keys % {:bank-account/use-date-instead-of-post-date? :use-date-instead-of-post-date}) bas))))) - (map (fn [c] - (if (is-admin? (:id context)) - c - (-> c - (dissoc :client/yodlee-provider-accounts) - (dissoc :client/plaid-items))))) - (map (fn [c] - (update c :client/bank-accounts - (fn [bank-accounts] - (mapv (fn [ba] - (assoc ba :bank-account/yodlee-balance-old nil)) - bank-accounts)))))))) + (->> (d-clients/get-minimal) + (filter #(can-see-client? (:id context) %))))) + +(defn get-admin-client [context {:keys [id]} _] + (assert-admin (:id context)) + (->graphql + (-> (d-clients/get-by-id id) + (update :client/bank-accounts (fn [bas] + (map #(set/rename-keys % {:bank-account/use-date-instead-of-post-date? :use-date-instead-of-post-date}) bas)))))) + +(defn get-client-page [context args _] + (assert-admin (:id context)) + (let [args (assoc args :id (:id context)) + [clients clients-count] (d-clients/get-graphql-page (assoc (<-graphql (:filters args)) + :id (:id context))) + clients (->> clients + + (map (fn [c] + (update c :client/bank-accounts (fn [bas] + (map #(set/rename-keys % {:bank-account/use-date-instead-of-post-date? :use-date-instead-of-post-date}) bas))))) + (map (fn [c] + (if (is-admin? (:id context)) + c + (-> c + (dissoc :client/yodlee-provider-accounts) + (dissoc :client/plaid-items))))) + (map (fn [c] + (update c :client/bank-accounts + (fn [bank-accounts] + (mapv (fn [ba] + (assoc ba :bank-account/yodlee-balance-old nil)) + bank-accounts))))))] + (result->page clients clients-count :clients (:filters args)))) (def sales-summary-query "[:find ?d4 (sum ?total) (sum ?tax) (sum ?tip) (sum ?service-charge) (sum ?discount) (sum ?returns) @@ -437,6 +454,15 @@ :yodlee_provider_accounts {:type '(list :yodlee_provider_account)} :plaid_items {:type '(list :plaid_item)}}} + :client_page + {:fields {:clients {:type '(list :client)} + :count {:type 'Int} + :total {:type 'Int} + :start {:type 'Int} + :end {:type 'Int}}} + + + :bank_account {:fields {:id {:type :id} :integration_status {:type :integration_status} @@ -471,7 +497,14 @@ (def queries {:client {:type '(list :client) - :resolve :get-client}}) + :resolve :get-client} + + :admin_client {:type :client + :args {:id {:type :id}} + :resolve :get-admin-client} + :client_page {:type :client_page + :args {:filters {:type :client_filters}} + :resolve :get-client-page}}) (def mutations {:edit_client {:type :client @@ -486,6 +519,13 @@ :match {:type 'String} :id {:type :id}}} + :client_filters + {:fields {:code {:type 'String} + :name_like {:type 'String} + :start {:type 'Int} + :per_page {:type 'Int} + :sort {:type '(list :sort_item)}}} + :edit_square_location {:fields {:client_location {:type 'String} :id {:type :id}}} @@ -551,6 +591,8 @@ (def resolvers {:get-client get-client + :get-admin-client get-admin-client + :get-client-page get-client-page :mutation/edit-client edit-client :mutation/setup-sales-queries setup-sales-queries}) diff --git a/src/cljs/auto_ap/events.cljs b/src/cljs/auto_ap/events.cljs index 094147bf..e0fbdf9f 100644 --- a/src/cljs/auto_ap/events.cljs +++ b/src/cljs/auto_ap/events.cljs @@ -16,7 +16,13 @@ (js->clj (.parse js/JSON (b64/decodeString (second (str/split token #"\." )))))) -(defn client-query [token] +(defn client-query [] + (cond-> [:id :name :code :email :locations :feature-flags + [:emails [:id :email :description]] + [:bank-accounts [:id :code :bank-name :name :type :visible + :locations :include-in-reports :current-balance]]])) + +(defn client-detail-query [token] (cond-> [:id :name :signature-file :code :email :matches :week-a-debits :week-a-credits :week-b-debits :week-b-credits :locations :locked-until :square-auth-token :feature-flags [:square-integration-status [:last-updated :last-attempt :message :state :id]] [:square-locations [:square-id :id :name :client-location]] @@ -68,7 +74,7 @@ :query-params (auto-ap.views.utils/query-params) :user token) :graphql {:token token - :query-obj {:venia/queries [[:client (client-query token)]]} + :query-obj {:venia/queries [[:client (client-query)]]} :on-success [::received-initial] :on-error [::failed-initial]}})))) @@ -100,7 +106,7 @@ (fn [{:keys [db]}] (let [token (-> db :user)] {:graphql {:token token - :query-obj {:venia/queries [[:client (client-query token)]]} + :query-obj {:venia/queries [[:client (client-query)]]} :on-success [::received-refreshed-clients]}}))) (re-frame/reg-event-fx diff --git a/src/cljs/auto_ap/views/pages/admin/clients.cljs b/src/cljs/auto_ap/views/pages/admin/clients.cljs index cadc5db0..3dfd0deb 100644 --- a/src/cljs/auto_ap/views/pages/admin/clients.cljs +++ b/src/cljs/auto_ap/views/pages/admin/clients.cljs @@ -4,6 +4,7 @@ [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] @@ -13,8 +14,12 @@ [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])) + [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 @@ -24,10 +29,15 @@ (re-frame/reg-event-fx ::mounted [with-user] - (fn [{:keys [user]} _] - {::track/register {:id ::params - :subscription [::params] - :event-fn (fn [params] [::params-change params])} + (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]} @@ -37,34 +47,31 @@ ::unmounted (fn [{:keys [db]} _] {:db (dissoc db ::table/params ::side-bar/filter-params) - ::track/dispose {:id ::params}})) + ::track/dispose [{:id ::params} + {:id ::active-route}]})) -(re-frame/reg-sub - ::params - :<- [::table/params] - :<- [::side-bar/filter-params] - (fn [[table-params filter-params]] - (cond-> {} - (seq filter-params) (merge filter-params) - (seq table-params) (merge table-params)))) +(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 - (fn [_ [_ params]] - {:set-uri-params params})) - -(re-frame/reg-sub - ::page - :<- [::params] - :<- [::subs/clients] - (fn [[params all-clients]] - (let [matching-clients (cond->> all-clients - (not-empty (:name params)) (filter #(str/includes? (str/lower-case (or (:name %) "")) - (str/lower-case (:name params)))) - (not-empty (:code params)) (filter #(= (str/lower-case (or (:code %) "")) - (str/lower-case (:code params)))))] - (assoc (grid/virtual-paginate-controls (:start params ) (:per-page params) matching-clients) - :data (grid/virtual-paginate (:start params) (:per-page params) matching-clients))))) + [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 @@ -77,14 +84,14 @@ :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])}]]} + [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 @(re-frame/subscribe [::form/client])) + (or (:name (:data @(re-frame/subscribe [::forms/form ::form/form]))) [:i "New client"])] :content [form/new-client-form]} ]}]]) @@ -94,6 +101,6 @@ (defn admin-clients-page [] [side-bar-layout {:side-bar [admin-side-bar {} - [side-bar/client-side-bar]] + [side-bar/client-side-bar {:data-page ::page}]] :main [admin-clients-content]}]) diff --git a/src/cljs/auto_ap/views/pages/admin/clients/form.cljs b/src/cljs/auto_ap/views/pages/admin/clients/form.cljs index 15e324d5..4eed305f 100644 --- a/src/cljs/auto_ap/views/pages/admin/clients/form.cljs +++ b/src/cljs/auto_ap/views/pages/admin/clients/form.cljs @@ -14,6 +14,7 @@ :refer [search-backed-typeahead]] [auto-ap.views.utils :refer [date-picker + with-user dispatch-event]] [bidi.bidi :as bidi] [cljs-time.coerce :as coerce] @@ -206,42 +207,46 @@ :bank-code bank-code}) (:bank-accounts new-client-data))}))) -(re-frame/reg-sub - ::client - :<- [::subs/route-params] - :<- [::subs/clients-by-id] - (fn [[rp clients-by-id]] - (or (get clients-by-id (:id rp)) - {}))) - (re-frame/reg-event-fx ::mounted - [(re-frame/inject-cofx ::inject/sub [::client])] - (fn [{:keys [db] ::keys [client]} _] - {: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 - :id (random-uuid)}) %)) + [with-user (re-frame/inject-cofx ::inject/sub [::subs/route-params])] + (fn [{:keys [user db] ::subs/keys [route-params]} _] + {:graphql {:token user + :query-obj {:venia/queries [[:admin-client + {:id (js/parseInt (:id route-params))} + (events/client-detail-query user)]]} + :on-success (fn [result] + [::received (:admin-client result)])} + :db (-> db + (forms/stop-form ::form))})) - (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-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 @@ -249,7 +254,7 @@ (fn [_ _] (let [new-client-req @(re-frame/subscribe [::new-client-request]) - user @(re-frame/subscribe [::subs/token])] + user @(re-frame/subscribe [::subs/token])] {:graphql {:token user @@ -258,7 +263,7 @@ :operation/name "EditClient"} :venia/queries [{:query/data [:edit-client {:edit-client new-client-req} - (events/client-query user)]}]} + (events/client-detail-query user)]}]} :on-success [::save-complete] :on-error [::forms/save-error ::form]}}))) @@ -727,8 +732,7 @@ (defn form-content [] - (let [_ @(re-frame/subscribe [::client]) - {new-client :data} @(re-frame/subscribe [::forms/form ::form])] + (let [{new-client :data} @(re-frame/subscribe [::forms/form ::form])] ^{:key (or (:id new-client) "new")} @@ -750,5 +754,6 @@ (def new-client-form (with-meta (fn [] - [form-content]) + (let [_ @(re-frame/subscribe [::subs/route-params])] + [form-content])) {:component-did-mount #(re-frame/dispatch [::mounted])})) diff --git a/src/cljs/auto_ap/views/pages/admin/clients/side_bar.cljs b/src/cljs/auto_ap/views/pages/admin/clients/side_bar.cljs index 467e313f..fe4578e3 100644 --- a/src/cljs/auto_ap/views/pages/admin/clients/side_bar.cljs +++ b/src/cljs/auto_ap/views/pages/admin/clients/side_bar.cljs @@ -2,78 +2,22 @@ (:require [re-frame.core :as re-frame] [auto-ap.views.utils :refer [dispatch-value-change]] - [auto-ap.subs :as subs])) + [auto-ap.views.pages.data-page :as data-page])) -(re-frame/reg-sub - ::specific-filters - (fn [db ] - (::filters db nil))) - -(re-frame/reg-sub - ::filters - :<- [::specific-filters] - :<- [::subs/query-params] - (fn [[specific-filters _ query-params] ] - (let [url-filters (-> query-params - (select-keys #{:name - :code})) - url-filters {:name (str (:name url-filters)) - :code (str (:code url-filters))}] - (merge url-filters specific-filters )))) - -(re-frame/reg-sub - ::filter - :<- [::filters] - (fn [filters [_ which]] - (get filters which))) - -(re-frame/reg-sub - ::filter-params - :<- [::settled-filters] - :<- [::filters] - :<- [::subs/active-page] - (fn [[settled-filters filters _ ]] - (let [filters (or settled-filters filters)] - {:name (:name filters) - :code (:code filters)}))) - -(re-frame/reg-sub - ::settled-filters - (fn [db ] - (::settled-filters db))) - -(re-frame/reg-event-fx - ::filters-settled - (fn [{:keys [db]} _] - {:db (assoc db ::settled-filters @(re-frame/subscribe [::filters]))})) - -(re-frame/reg-event-fx - ::filter-changed - (fn [{:keys [db]} [_ & params]] - (let [[a b c] params - [which val] (if (= 3 (count params)) - [(into [a] b) c] - [[a] b])] - {:db (assoc-in db (into [::filters] which) val) - :dispatch-debounce {:event [::filters-settled] - :time 800 - :key ::filters}}))) - - -(defn client-side-bar [] +(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 [::filter :name]) - :on-change (dispatch-value-change [::filter-changed :name])} ]]] + :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 [::filter :code]) - :on-change (dispatch-value-change [::filter-changed :code])} ]]]]) + :value @(re-frame/subscribe [::data-page/filter data-page :code]) + :on-change (dispatch-value-change [::data-page/filter-changed data-page :code])} ]]]]) diff --git a/src/cljs/auto_ap/views/pages/admin/clients/table.cljs b/src/cljs/auto_ap/views/pages/admin/clients/table.cljs index 60f9d44a..3f60040d 100644 --- a/src/cljs/auto_ap/views/pages/admin/clients/table.cljs +++ b/src/cljs/auto_ap/views/pages/admin/clients/table.cljs @@ -8,7 +8,8 @@ [auto-ap.views.components.buttons :as buttons] [auto-ap.status :as status] [bidi.bidi :as bidi] - [auto-ap.routes :as routes])) + [auto-ap.routes :as routes] + [auto-ap.views.pages.data-page :as data-page])) (re-frame/reg-sub ::specific-params @@ -76,14 +77,16 @@ nil )) -(defn clients-table [{:keys [page status]}] - (let [states @(re-frame/subscribe [::status/multi ::setup-sales-queries])] +(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 page] + [grid/controls data] [grid/table {:fullwidth true} [grid/header [grid/row {} @@ -95,7 +98,7 @@ [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 page)] + (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] diff --git a/src/cljs/auto_ap/views/pages/home.cljs b/src/cljs/auto_ap/views/pages/home.cljs index d8cfa285..131cd81f 100644 --- a/src/cljs/auto_ap/views/pages/home.cljs +++ b/src/cljs/auto_ap/views/pages/home.cljs @@ -15,7 +15,9 @@ [re-frame.core :as re-frame] [recharts] [reagent.core :as r] - [react])) + [react] + [vimsical.re-frame.cofx.inject :as inject] + [auto-ap.status :as status])) (def pie-chart (r/adapt-react-class recharts/PieChart)) (def pie (r/adapt-react-class recharts/Pie)) @@ -238,23 +240,28 @@ (re-frame/reg-event-fx ::mounted - (fn [{:keys [db]} _] - {:db (assoc db ::top-expense-categories nil) - :graphql {:token (-> db :user) - :query-obj {:venia/queries [[:expense_account_stats - {:client-id (:id @(re-frame/subscribe [::subs/client]))} - [[:account [:id :name]] :total]] - [:invoice_stats - {:client-id (:id @(re-frame/subscribe [::subs/client]))} - [:name :paid :unpaid]] - [:cash-flow - {:client-id (:id @(re-frame/subscribe [::subs/client]))} - [:beginning-balance - :outstanding-payments - [:invoices-due-soon [:due :outstanding-balance [:vendor [:id :name]] :invoice-number]] - [:upcoming-credits [:date :amount :identifier]] - [:upcoming-debits [:date :amount :identifier]]]]]} - :on-success [::received]}})) + [(re-frame/inject-cofx ::inject/sub [::subs/client])] + (fn [{:keys [db] ::subs/keys [client]} _] + (cond-> + {:db (assoc db ::top-expense-categories nil + ::cash-flow nil + ::invoice-stats nil)} + client (assoc :graphql {:token (-> db :user) + :owns-state {:single ::page} + :query-obj {:venia/queries [[:expense_account_stats + {:client-id (:id client)} + [[:account [:id :name]] :total]] + [:invoice_stats + {:client-id (:id client)} + [:name :paid :unpaid]] + [:cash-flow + {:client-id (:id client)} + [:beginning-balance + :outstanding-payments + [:invoices-due-soon [:due :outstanding-balance [:vendor [:id :name]] :invoice-number]] + [:upcoming-credits [:date :amount :identifier]] + [:upcoming-debits [:date :amount :identifier]]]]]} + :on-success [::received]})))) (defn cash-flow-range-button [{:keys [name value chart-options]}] [:a.button {:class (when (= value (:cash-flow-range chart-options)) @@ -298,51 +305,56 @@ (defn home-content [] (let [client-id (-> @(re-frame/subscribe [::subs/client]) :id) - chart-options @(re-frame/subscribe [::chart-options])] + chart-options @(re-frame/subscribe [::chart-options]) + state @(re-frame/subscribe [::status/single ::page])] ^{:key client-id} [side-bar-layout {:side-bar [:div - ] :main [:div [:h1.title "Home"] - [:h1.title.is-4 "Top expense categories"] - (let [expense-categories @(re-frame/subscribe [::top-expense-categories])] - (make-pie-chart {:width 800 :height 500 :data (clj->js - (map (fn [x] {:name (:name (:account x)) :value (:total x)}) expense-categories))})) - [:h1.title.is-4 "Upcoming Bills"] - (make-bar-chart {:width 800 :height 500 :data (clj->js - @(re-frame/subscribe [::invoice-stats]))}) + (if client-id + (if (= :loading (:state state)) + [:div.loader.is-loading.big.is-centered] - [:h1.title.is-4 "Cash Flow"] - [:div.buttons.has-addons - [cash-flow-range-button {:name "7 days" - :value :seven-days - :chart-options chart-options}] - [cash-flow-range-button {:name "30 days" - :value :thirty-days - :chart-options chart-options}] + [:<> + [:h1.title.is-4 "Top expense categories"] + (let [expense-categories @(re-frame/subscribe [::top-expense-categories])] + (make-pie-chart {:width 800 :height 500 :data (clj->js + (map (fn [x] {:name (:name (:account x)) :value (:total x)}) expense-categories))})) + [:h1.title.is-4 "Upcoming Bills"] + (make-bar-chart {:width 800 :height 500 :data (clj->js + @(re-frame/subscribe [::invoice-stats]))}) - [cash-flow-range-button {:name "60 days" - :value :sixty-days - :chart-options chart-options}] + [:h1.title.is-4 "Cash Flow"] + [:div.buttons.has-addons + [cash-flow-range-button {:name "7 days" + :value :seven-days + :chart-options chart-options}] + [cash-flow-range-button {:name "30 days" + :value :thirty-days + :chart-options chart-options}] - [cash-flow-range-button {:name "90 days" - :value :ninety-days - :chart-options chart-options}] - [cash-flow-range-button {:name "120 days" - :value :one-hundred-twenty-days - :chart-options chart-options}] - [cash-flow-range-button {:name "150 days" - :value :one-hundred-fifty-days - :chart-options chart-options}] - [cash-flow-range-button {:name "180 days" - :value :one-hundred-eighty-days - :chart-options chart-options}]] - - - (make-cash-flow-chart {:width 800 :height 500 - :data (clj->js @(re-frame/subscribe [::cash-flow]))}) + [cash-flow-range-button {:name "60 days" + :value :sixty-days + :chart-options chart-options}] - [cash-flow-grid]]}])) + [cash-flow-range-button {:name "90 days" + :value :ninety-days + :chart-options chart-options}] + [cash-flow-range-button {:name "120 days" + :value :one-hundred-twenty-days + :chart-options chart-options}] + [cash-flow-range-button {:name "150 days" + :value :one-hundred-fifty-days + :chart-options chart-options}] + [cash-flow-range-button {:name "180 days" + :value :one-hundred-eighty-days + :chart-options chart-options}]] + + (make-cash-flow-chart {:width 800 :height 500 + :data (clj->js @(re-frame/subscribe [::cash-flow]))}) + + [cash-flow-grid]]) + [:h2.title.is-6 "Please select a customer to see reports."])]}])) (defn home-page []