From 255a73dc307067f9aa9b4aaf709d7fea6a78b130 Mon Sep 17 00:00:00 2001 From: Bryce Covert Date: Wed, 12 Aug 2020 09:18:59 -0700 Subject: [PATCH] so many small tweaks due to the fact that the grid was slow. --- project.clj | 9 +- src/clj/auto_ap/yodlee/import.clj | 42 ++-- src/cljs/auto_ap/effects.cljs | 4 +- src/cljs/auto_ap/views/components/grid.cljs | 50 ++--- .../views/components/invoice_table.cljs | 15 +- .../auto_ap/views/pages/import_invoices.cljs | 15 +- .../auto_ap/views/pages/invoices/form.cljs | 194 +++++++++--------- .../auto_ap/views/pages/payments/table.cljs | 2 +- .../views/pages/transactions/table.cljs | 2 +- .../auto_ap/views/pages/unpaid_invoices.cljs | 20 +- 10 files changed, 192 insertions(+), 161 deletions(-) diff --git a/project.clj b/project.clj index 561fa334..3c14ee92 100644 --- a/project.clj +++ b/project.clj @@ -28,7 +28,7 @@ [dk.ative/docjure "1.12.0"] [org.clojure/java.jdbc "0.7.3"] [cljsjs/dropzone "4.3.0-0"] - [cljsjs/recharts "1.4.2-0"] + [cljsjs/recharts "1.4.2-0" :exclusions [cljsjs/react cljsjs/react-dom]] [clj-fuzzy "0.4.1"] [honeysql "0.9.2"] [com.walmartlabs/lacinia "0.25.0"] @@ -71,6 +71,7 @@ [org.clojure/data.csv "0.1.4"] [io.rkn/conformity "0.5.1"] [cider/piggieback "0.4.0"] + [hiccup "1.0.5"]] :plugins [[lein-ring "0.9.7"] [lein-cljsbuild "1.1.5"]] @@ -119,9 +120,9 @@ org.eclipse.jetty.websocket/websocket-servlet args4j]]]} :provided {:dependencies [[org.clojure/clojurescript "1.10.339"] - [reagent "1.0.0-alpha1" ] - [cljsjs/react-datepicker "2.1.0-0"] - [cljsjs/react-transition-group "2.4.0-0"] + [reagent "1.0.0-alpha2" ] + [cljsjs/react-datepicker "2.1.0-0" :exclusions [cljsjs/react cljsjs/react-dom]] + [cljsjs/react-transition-group "2.4.0-0" :exclusions [cljsjs/react cljsjs/react-dom]] [re-frame "0.10.2"] [re-frame-utils "0.1.0"] [com.andrewmcveigh/cljs-time "0.5.2"]]}} diff --git a/src/clj/auto_ap/yodlee/import.clj b/src/clj/auto_ap/yodlee/import.clj index 3b9d1706..8a07c9a9 100644 --- a/src/clj/auto_ap/yodlee/import.clj +++ b/src/clj/auto_ap/yodlee/import.clj @@ -17,8 +17,24 @@ [clojure.tools.logging :as log])) +(defn rough-match [client-id bank-account-id amount] + (if (and client-id bank-account-id amount) + (let [[matching-checks] (d-checks/get-graphql {:client-id client-id + :bank-account-id bank-account-id + :amount (- amount) + :status :payment-status/pending})] + (if (= 1 (count matching-checks)) + (first matching-checks) + nil)) + nil)) + (defn transaction->payment [_ check-number client-id bank-account-id amount id] + (log/info "Searching for a matching check for " + {:client-id client-id + :check-number check-number + :bank-account-id bank-account-id + :amount amount}) (cond (not (and client-id bank-account-id)) nil @@ -26,25 +42,17 @@ nil check-number - (-> (d-checks/get-graphql {:client-id client-id - :bank-account-id bank-account-id - :check-number check-number - :amount (- amount) - :status :payment-status/pending}) - first - first) - - (and client-id bank-account-id amount) - (let [[matching-checks] (d-checks/get-graphql {:client-id client-id - :bank-account-id bank-account-id - :amount (- amount) - :status :payment-status/pending})] - (if (= 1 (count matching-checks)) - (first matching-checks) - nil)) + (or (-> (d-checks/get-graphql {:client-id client-id + :bank-account-id bank-account-id + :check-number check-number + :amount (- amount) + :status :payment-status/pending}) + first + first) + (rough-match client-id bank-account-id amount)) :else - nil)) + (rough-match client-id bank-account-id amount))) (defn extract-check-number [{{description-original :original} :description}] diff --git a/src/cljs/auto_ap/effects.cljs b/src/cljs/auto_ap/effects.cljs index dc788bf3..da79df69 100644 --- a/src/cljs/auto_ap/effects.cljs +++ b/src/cljs/auto_ap/effects.cljs @@ -161,10 +161,10 @@ (fn [{:keys [query on-success on-error token variables query-obj owns-state]}] (go (when (:multi owns-state) - (re-frame/dispatch [::status/loading-multi (:multi owns-state) (:which owns-state)])) + (re-frame/dispatch-sync [::status/loading-multi (:multi owns-state) (:which owns-state)])) (when (:single owns-state) - (re-frame/dispatch [::status/loading (:single owns-state)])) + (re-frame/dispatch-sync [::status/loading (:single owns-state)])) (let [headers (if token {"Authorization" (str "Token " token)} {}) diff --git a/src/cljs/auto_ap/views/components/grid.cljs b/src/cljs/auto_ap/views/components/grid.cljs index a8c13e97..2513a6cd 100644 --- a/src/cljs/auto_ap/views/components/grid.cljs +++ b/src/cljs/auto_ap/views/components/grid.cljs @@ -119,13 +119,12 @@ (mapv (fn [c] [:div.level-item c]) children))]]))))])) -(defn table [] - (r/create-class {:reagent-render - (fn [{:keys [fullwidth]}] - (into - [:table.table.compact.grid {:class (if fullwidth - ["is-fullwidth"])}] - (r/children (r/current-component))))})) +(defn table [{:keys [fullwidth]}] + + (into + [:table.table.compact.grid {:class (if fullwidth + ["is-fullwidth"])}] + (r/children (r/current-component)))) (defn header [] (into @@ -138,13 +137,17 @@ (r/children (r/current-component)))) (defn row [{:keys [class]}] - (into [:tr {:class class}] - (r/children (r/current-component)))) + (apply r/create-element "tr" #js {:className class} + (map r/as-element (r/children (r/current-component))))) + +(defn button-cell [params] + (apply r/create-element "td" #js {"style" #js {"overflow" "visible"}} + (map r/as-element (r/children (r/current-component))))) (defn cell [params] - [:td params - (into [:span.test ] - (r/children (r/current-component)))]) + (apply r/create-element "td" #js {} + (map r/as-element (r/children (r/current-component)))) + ) (defn body [] (let [children (r/children (r/current-component))] @@ -153,29 +156,28 @@ (let [{:strs [column-count status]} (js->clj consume)] (r/as-element (cond (= :loading (:state status)) - [:tbody - (for [i (range 40)] + ^{:key "loading-body"} + [:tbody.test + (for [i (range 20)] ^{:key i} [:tr (for [x (range column-count)] ^{:key x} [:td #_{:col-span column-count} - [appearing {:visible? true - :timeout 1000 - :enter-class "appear" - :exit-class "disappear"} - [:div.test - [:div.ph-item - [:div.ph-row - [:div.ph-col-12.big]]]]]]) - ])] + [:div + [:div.ph-item + [:div.ph-row + [:div.ph-col-12.big]]]]])])] + (= :error (:state status)) + ^{:key "error-body"} [:tbody [:tr [:td.has-text-centered {:col-span column-count} "An unexpected error has occured. " (-> status :error first :message) " Please try refreshing the page."]]] :else - (into [:tbody] + (into ^{:key "main-body"} + [:tbody] children)))))])) diff --git a/src/cljs/auto_ap/views/components/invoice_table.cljs b/src/cljs/auto_ap/views/components/invoice_table.cljs index 6b4e9737..a525bb35 100644 --- a/src/cljs/auto_ap/views/components/invoice_table.cljs +++ b/src/cljs/auto_ap/views/components/invoice_table.cljs @@ -44,7 +44,8 @@ :<- [::specific-table-params] :<- [::subs/query-params] (fn [[specific-table-params query-params]] - (merge (select-keys query-params #{:start :sort}) specific-table-params ))) + (update (merge (select-keys query-params #{:start :sort}) specific-table-params ) + :sort seq))) (re-frame/reg-event-fx ::params-changed @@ -128,7 +129,7 @@ [grid/cell {:class "has-text-right"} (nf total )] [grid/cell {:class "has-text-right"} (nf outstanding-balance )] - [grid/cell {:style {:overflow "visible"}} + [grid/button-cell {} [:div.buttons (when (seq expense-accounts) [drop-down {:id [::expense-accounts id ] @@ -188,9 +189,12 @@ {:keys [sort]} @(re-frame/subscribe [::table-params]) {:keys [invoices outstanding]} invoice-page selected-client @(re-frame/subscribe [::subs/client]) - is-loading? (= :loading status) + is-loading? (= :loading (:state status)) is-sorted-by-vendor? (and (= "vendor" (:sort-key (first sort))) - (not is-loading?)) + (not is-loading?) + (or (apply <= (map (comp :name :vendor) (:invoices invoice-page))) + (apply >= (map (comp :name :vendor) (:invoices invoice-page))))) + [invoice-groups] (if is-sorted-by-vendor? (reduce (fn [[acc last-vendor] invoice] @@ -203,7 +207,9 @@ [[] nil] (:invoices invoice-page)) [[(:invoices invoice-page)]])] + ^{:key (str @(re-frame/subscribe [::table-params]))} [grid/grid {:on-params-change (fn [p] + (re-frame/dispatch [::params-changed p])) :params @(re-frame/subscribe [::table-params]) :status status @@ -242,7 +248,6 @@ [row {:invoice i :check-boxes check-boxes :checked checked - :on-check-changed on-check-changed :selected-client selected-client :overrides overrides :expense-event expense-event}])]])])) diff --git a/src/cljs/auto_ap/views/pages/import_invoices.cljs b/src/cljs/auto_ap/views/pages/import_invoices.cljs index f00860d8..4e79b2ea 100644 --- a/src/cljs/auto_ap/views/pages/import_invoices.cljs +++ b/src/cljs/auto_ap/views/pages/import_invoices.cljs @@ -49,13 +49,14 @@ [:div.field.has-addons [:p.control [:a.button.is-static "Force vendor"]] - [typeahead-entity {:matches @(re-frame/subscribe [::subs/vendors]) - :match->text :name - :name "vendor" - :type "typeahead" - :on-change (fn [v] - (reset! vendor v)) - :value @vendor}] + [:div.control {:style {:width "400px"}} + [typeahead-entity {:matches @(re-frame/subscribe [::subs/vendors]) + :match->text :name + :name "vendor" + :type "typeahead" + :on-change (fn [v] + (reset! vendor v)) + :value @vendor}]] ] [:div.tile.notification diff --git a/src/cljs/auto_ap/views/pages/invoices/form.cljs b/src/cljs/auto_ap/views/pages/invoices/form.cljs index a620d556..a21dc36e 100644 --- a/src/cljs/auto_ap/views/pages/invoices/form.cljs +++ b/src/cljs/auto_ap/views/pages/invoices/form.cljs @@ -203,9 +203,10 @@ {:db (cond-> db - (#{:create :add-and-print} command) (forms/start-form ::form {:client @(re-frame/subscribe [::subs/client]) - :status :unpaid - :date (date->str (c/now) standard)}) + (#{:create :add-and-print} command) (-> (forms/stop-form ::form ) + (forms/start-form ::form {:client @(re-frame/subscribe [::subs/client]) + :status :unpaid + :date (date->str (c/now) standard)})) (= :edit command) (forms/stop-form ::form)) :dispatch-n (cond-> [(conj invoice-created invoice)] (= :add-and-print command) (conj (conj invoice-printed (:pdf-url (:add-and-print-invoice result)))))}))) @@ -228,111 +229,112 @@ min-total (if (= (:total (:original data)) (:outstanding-balance (:original data))) nil (- (:total (:original data)) (:outstanding-balance (:original data))))] - ^{:key id} - (form-inline (assoc params :title "New Invoice") - [:<> - (when-not @(re-frame/subscribe [::subs/client]) - (field "Client" - [typeahead-entity {:matches @(re-frame/subscribe [::subs/clients]) + (with-meta + (form-inline (assoc params :title "New Invoice") + [:<> + (when-not @(re-frame/subscribe [::subs/client]) + (field "Client" + [typeahead-entity {:matches @(re-frame/subscribe [::subs/clients]) + :match->text :name + :type "typeahead" + :auto-focus (if @(re-frame/subscribe [::subs/client]) false true) + :field [:client] + :disabled exists? + :spec ::invoice/client}])) + + (field "Vendor" + [typeahead-entity {:matches @(re-frame/subscribe [::subs/vendors]) :match->text :name :type "typeahead" - :auto-focus (if @(re-frame/subscribe [::subs/client]) false true) - :field [:client] :disabled exists? - :spec ::invoice/client}])) + :auto-focus (if @(re-frame/subscribe [::subs/client]) true false) + :field [:vendor]}]) - (field "Vendor" - [typeahead-entity {:matches @(re-frame/subscribe [::subs/vendors]) - :match->text :name - :type "typeahead" - :disabled exists? - :auto-focus (if @(re-frame/subscribe [::subs/client]) true false) - :field [:vendor]}]) + (field "Date" + [date-picker {:class-name "input" + :class "input" + :format-week-number (fn [] "") + :previous-month-button-label "" + :placeholder "mm/dd/yyyy" + :next-month-button-label "" + :next-month-label "" + :type "date" + :field [:date] + :spec ::invoice/date}]) - (field "Date" - [date-picker {:class-name "input" - :class "input" - :format-week-number (fn [] "") - :previous-month-button-label "" - :placeholder "mm/dd/yyyy" - :next-month-button-label "" - :next-month-label "" - :type "date" - :field [:date] - :spec ::invoice/date}]) + (field "Due (optional)" + [date-picker {:class-name "input" + :class "input" + :format-week-number (fn [] "") + :previous-month-button-label "" + :placeholder "mm/dd/yyyy" + :next-month-button-label "" + :next-month-label "" + :type "date" + :field [:due] + :spec ::invoice/due}]) - (field "Due (optional)" - [date-picker {:class-name "input" - :class "input" - :format-week-number (fn [] "") - :previous-month-button-label "" - :placeholder "mm/dd/yyyy" - :next-month-button-label "" - :next-month-label "" - :type "date" - :field [:due] - :spec ::invoice/due}]) + [:div.field + [:label.checkbox + (raw-field + [:input {:type "checkbox" + :field [:automatically-paid-when-due] + :spec ::invoice/automatically-paid-when-due}]) + " Mark as paid on due date"]] - [:div.field - [:label.checkbox - (raw-field - [:input {:type "checkbox" - :field [:automatically-paid-when-due] - :spec ::invoice/automatically-paid-when-due}]) - " Mark as paid on due date"]] - - (field "Invoice #" - [:input.input {:type "text" - :field [:invoice-number] - :spec ::invoice/invoice-number}]) + (field "Invoice #" + [:input.input {:type "text" + :field [:invoice-number] + :spec ::invoice/invoice-number}]) - (field "Total" - [money-field {:type "money" - :field [:total] - :disabled (if can-change-amount? "" "disabled") - :min min-total - :spec ::invoice/total - :step "0.01"}]) + (field "Total" + [money-field {:type "money" + :field [:total] + :disabled (if can-change-amount? "" "disabled") + :min min-total + :spec ::invoice/total + :step "0.01"}]) - (field nil - [expense-accounts-field {:type "expense-accounts" - :descriptor "expense account" - :locations (:locations (:client data)) - :max (:total data) - :client (or (:client data) @(re-frame/subscribe [::subs/client])) - :field [:expense-accounts]}]) + (field nil + [expense-accounts-field {:type "expense-accounts" + :descriptor "expense account" + :locations (:locations (:client data)) + :max (:total data) + :client (or (:client data) @(re-frame/subscribe [::subs/client])) + :field [:expense-accounts]}]) - + - (error-notification) + (error-notification) - [:div.columns - (when-not exists? + [:div.columns + (when-not exists? + [:div.column + [drop-down {:header [:button.button.is-info.is-outlined.is-medium.is-fullwidth {:aria-haspopup true + :type "button" + :on-click (dispatch-event [::events/toggle-menu ::add-and-print-invoice ]) + :disabled (if @(re-frame/subscribe [::can-submit]) + "" + "disabled") + + :class (if false + "is-loading" + "")} + "Save & Pay " + [:span " "] + [:span.icon.is-small [:i.fa.fa-angle-down {:aria-hidden "true"}]]] + :class "is-fullwidth" + :id ::add-and-print-invoice} + [:div + (list + (for [{:keys [id number name type]} (->> (:bank-accounts (:client data)) (filter :visible) (sort-by :sort-order))] + (if (= :cash type) + ^{:key id} [:a.dropdown-item {:on-click (dispatch-event [::add-and-print params id :cash])} "With cash"] + (list + ^{:key (str id "-check")} [:a.dropdown-item {:on-click (dispatch-event [::add-and-print params id :check])} "Print checks from " name] + ^{:key (str id "-debit")} [:a.dropdown-item {:on-click (dispatch-event [::add-and-print params id :debit])} "Debit from " name]))))]]]) [:div.column - [drop-down {:header [:button.button.is-info.is-outlined.is-medium.is-fullwidth {:aria-haspopup true - :type "button" - :on-click (dispatch-event [::events/toggle-menu ::add-and-print-invoice ]) - :disabled (if @(re-frame/subscribe [::can-submit]) - "" - "disabled") - :class (if false - "is-loading" - "")} - "Save & Pay " - [:span " "] - [:span.icon.is-small [:i.fa.fa-angle-down {:aria-hidden "true"}]]] - :class "is-fullwidth" - :id ::add-and-print-invoice} - [:div - (list - (for [{:keys [id number name type]} (->> (:bank-accounts (:client data)) (filter :visible) (sort-by :sort-order))] - (if (= :cash type) - ^{:key id} [:a.dropdown-item {:on-click (dispatch-event [::add-and-print params id :cash])} "With cash"] - (list - ^{:key (str id "-check")} [:a.dropdown-item {:on-click (dispatch-event [::add-and-print params id :check])} "Print checks from " name] - ^{:key (str id "-debit")} [:a.dropdown-item {:on-click (dispatch-event [::add-and-print params id :debit])} "Debit from " name]))))]]]) - [:div.column - - (submit-button "Save")]]]))]) + (submit-button "Save")]]]) + {:key id}))]) diff --git a/src/cljs/auto_ap/views/pages/payments/table.cljs b/src/cljs/auto_ap/views/pages/payments/table.cljs index 939c1661..70312be6 100644 --- a/src/cljs/auto_ap/views/pages/payments/table.cljs +++ b/src/cljs/auto_ap/views/pages/payments/table.cljs @@ -74,7 +74,7 @@ [grid/cell {} (date->str date) ] [grid/cell {:class "has-text-right"} (nf amount )] [grid/cell {} status] - [grid/cell {:style {:overflow "visible"}} + [grid/button-cell {} [:div.buttons (when (seq invoices) [drop-down {:id [::invoices id] diff --git a/src/cljs/auto_ap/views/pages/transactions/table.cljs b/src/cljs/auto_ap/views/pages/transactions/table.cljs index 273bece0..fa3a6f75 100644 --- a/src/cljs/auto_ap/views/pages/transactions/table.cljs +++ b/src/cljs/auto_ap/views/pages/transactions/table.cljs @@ -93,7 +93,7 @@ [grid/cell {} (date->str date) ] [grid/cell {:class "has-text-right"} (nf amount )] [grid/cell {} status] - [grid/cell {:style {:overflow "visible"}} + [grid/button-cell {} [:div.buttons [drop-down {:id [::expense-accounts id ] :header [buttons/sl-icon {:aria-haspopup true diff --git a/src/cljs/auto_ap/views/pages/unpaid_invoices.cljs b/src/cljs/auto_ap/views/pages/unpaid_invoices.cljs index 4f402092..5cbec39d 100644 --- a/src/cljs/auto_ap/views/pages/unpaid_invoices.cljs +++ b/src/cljs/auto_ap/views/pages/unpaid_invoices.cljs @@ -97,6 +97,7 @@ ::params-change [with-user] (fn [{:keys [user]} [_ params]] + (println "REQUERY") {:graphql {:token user :owns-state {:single ::page} :query-obj (table/query params ) @@ -363,10 +364,21 @@ (re-frame/reg-event-fx ::invoice-updated [(re-frame/path [::invoice-page :invoices])] - (fn [{:keys [db]} [_ [_ invoice]]] - {:db (merge-by db :id invoice)})) - + (fn [{:keys [db]} [_ [_ invoice]]] + (let [by-id (by :id db )] + {:db (if (by-id (:id invoice)) + (merge-by db :id invoice) + (into [invoice] db))}))) +(re-frame/reg-event-fx + ::invoice-edited + [(re-frame/path [::invoice-page :invoices])] + (fn [{:keys [db]} [_ invoice]] + (let [invoice (assoc invoice :class "live-added")] + (let [by-id (by :id db )] + {:db (if (by-id (:id invoice)) + (merge-by db :id invoice) + (into [invoice] db))})))) (re-frame/reg-event-fx ::expense-accounts-updated @@ -630,5 +642,5 @@ [print-checks-modal] [handwrite-checks-modal] [change-expense-accounts-modal {:updated-event [::expense-accounts-updated]}]] - :right-side-bar [appearing-side-bar {:visible? invoice-bar-active?} [form/form {:invoice-created [::invoice-updated] + :right-side-bar [appearing-side-bar {:visible? invoice-bar-active?} [form/form {:invoice-created [::invoice-edited] :invoice-printed [::checks-printed]}]]}]))}))