Quality of life improvements with client login

This commit is contained in:
Bryce Covert
2020-07-30 08:44:44 -07:00
parent 6df080cc3f
commit 98f0d40313
13 changed files with 210 additions and 115 deletions

View File

@@ -478,3 +478,12 @@ table.balance-sheet th.total {
}
}
.loader.big {
height: 150px !important;
width: 150px !important;
border: 4px solid #00d1b2;
border-right-color: transparent;
border-top-color: transparent;
}

View File

@@ -17,37 +17,7 @@
</head>
<body>
<div id="app">
<nav class="navbar has-shadow">
<div class="container">
<div class="navbar-brand">
<a class="navbar-item" href="../">
<img src="/img/logo.png" />
</a>
</div>
</div>
</nav>
<div class="has-text-centered hero is-fullheight is-vertically-centered" id="mail-app">
<div class="is-vertically-centered">
<h1 class="title"><i class="fa fa-spin fa-spinner"></i></h1>
</div>
</div>
<footer class="footer">
<div class="container">
<div class="content has-text-centered">
<p>
<strong>Integreat</strong>
by <a href="https://github.com/">Integreat</a>.
</p>
<p>
<a class="icon" href="https://github.com/dansup/bulma-templates">
<i class="fa fa-github"></i>
</a>
</p>
</div>
</div>
</footer>
</div>
<div id="app"><div><nav class="navbar has-shadow is-fixed-top"><div class="container"><div class="navbar-brand"><a class="navbar-item" href="../"><img src="/img/logo.png"></a></div><div class="navbar-menu"><div class="navbar-burger burger" data-target="navMenu"><span></span><span></span><span></span></div></div></div></nav><div class="columns has-shadow" id="mail-app" style="margin-bottom: 0px; height: calc(100vh - 46px);"><aside class="column aside menu is-2 "><div class="main left-nav"><div></div></div></aside><div class="column messages hero " id="message-feed" style="overflow: auto;"><div class="inbox-messages"><div class="has-text-centered hero is-fullheight is-vertically-centered is-centered"><div class="hero-body"><div class="container"><div class="column is-4 is-offset-4 has-text-centered"><div class="loader is-loading is-active big is-centered"></div></div></div></div></div></div></div></div><div></div><div id="dz-hidden"></div></div></div>
<script src="/js/compiled/app.js"></script>
<script>auto_ap.core.init();</script>
</body>

View File

@@ -193,3 +193,16 @@
(map <-datomic)))
(defn get-existing-set []
(d/query
(cond-> {:query {:find ['?vendor '?client '?invoice-number]
:in ['$]
:where '[[?e :invoice/invoice-number ?invoice-number]
[?e :invoice/vendor ?vendor]
[?e :invoice/client ?client]
(not [?e :invoice/status :invoice-status/voided])
]}
:args [(d/db (d/connect uri))]})))

View File

@@ -174,7 +174,7 @@
@(d/transact
(d/connect uri)
(mapv
#(auto-ap.ledger/entity-change->ledger (d/db (d/connect uri)) [:transaction %])
#(entity-change->ledger (d/db (d/connect uri)) [:transaction %])
(concat
(->>
(d/query {:query {:find ['?t ]

View File

@@ -39,8 +39,6 @@
(if-let [id (:db/id (or (clients client-code)
(clients client)))]
(do
(println "FOUND CLIENT" (or (clients client-code)
(clients client)))
(when (not ((set (:client/locations (or (clients client-code)
(clients client))))
default-location))
@@ -78,8 +76,8 @@
(defn parse-account-numeric-code [i]
(try
(when-let [account-numeric-code (:account-numeric-code i)]
(d-accounts/get-account-by-numeric-code-and-sets (Integer/parseInt account-numeric-code)
["default"]))
(:db/id (d-accounts/get-account-by-numeric-code-and-sets (Integer/parseInt account-numeric-code)
["default"])))
(catch Exception e
(throw (Exception. (str "Could not parse expense account from value '" (:account-numeric-code i) "'") e)))))
@@ -481,12 +479,7 @@
{{:keys [excel-rows]} :edn-params user :identity}
(assert-admin user)
(let [parsed-invoice-rows (parse-invoice-rows excel-rows)
existing-rows (->> (d-invoices/get-graphql {:count Integer/MAX_VALUE})
first
(filter (fn [i] (not= :invoice-status/voided (:invoice/status i))))
(map (fn [{:keys [:invoice/vendor :invoice/client :invoice/invoice-number]}]
[(:db/id vendor) (:db/id client) invoice-number]))
set)
existing-rows (set (d-invoices/get-existing-set ))
grouped-rows (group-by
(fn [i]
(cond (seq (:errors i))

View File

@@ -2,6 +2,7 @@
(:require [auto-ap.datomic :refer [uri]]
[auto-ap.utils :refer [by]]
#_[auto-ap.ledger :as l]
[datomic.api :as d]
[clojure.data.csv :as csv]
[clj-time.coerce :as c]
@@ -300,11 +301,12 @@
)
vec))
(defn patch-missing-ledger-entries []
;; TODO uncommenting the two below this makes lein build not work, probably related to the ledger
#_(defn patch-missing-ledger-entries []
@(d/transact
(d/connect uri)
(mapv
#(auto-ap.ledger/entity-change->ledger (d/db (d/connect uri)) [:transaction %])
#(l/entity-change->ledger (d/db (d/connect uri)) [:transaction %])
(concat
(->>
(d/query {:query {:find ['?t ]
@@ -317,7 +319,7 @@
(defn check-for-out-of-date-ledger [?code]
#_(defn check-for-out-of-date-ledger [code]
[(d/query {:query {:find ['(count ?e)]
:in ['$ '?code]
:where ['[?e :transaction/accounts ?ta]
@@ -327,11 +329,13 @@
'[?e :transaction/client ?c]
'[?c :client/code ?code]
]}
:args [(d/db (d/connect uri)) ?code]})
:args [(d/db (d/connect uri)) code]})
(d/query {:query {:find ['?t ]
:in ['$]
:where ['[?t :transaction/date]
'[?t :transaction/client ?c]
'[?c :client/code ?code]
'(not [?t :transaction/approval-status :transaction-approval-status/excluded])
'(not-join [?t] [?e :journal-entry/original-entity ?t])]}
:args [(d/db (d/connect uri))]})
@@ -339,9 +343,20 @@
(d/query {:query {:find ['?t ]
:in ['$]
:where ['[?t :transaction/date]
'[?t :transaction/client ?c]
'[?c :client/code ?code]
'(not [?t :transaction/approval-status :transaction-approval-status/excluded])
'[?t :transaction/vendor ?v]
'[?j :journal-entry/original-entity ?t]
'(not [?j :journal-entry/vendor ?v])
#_'(not-join [?t] [?e :journal-entry/original-entity ?t])]}
:args [(d/db (d/connect uri))]})
(d/query {:query {:find ['(count ?i) ]
:in ['$]
:where ['[?i :invoice/client ?c]
'(not [?i :invoice/status :invoice-status/voided])
'[?c :client/code ?code]
'(not-join [?i] [?e :journal-entry/original-entity ?i])]}
:args [(d/db (d/connect uri))]})])

View File

@@ -19,7 +19,6 @@
::initialize-db
(fn [{:keys [db]} [_ token]]
(let [handler (:handler (bidi/match-route routes/routes (.. js/window -location -pathname)))]
(prn (and token (get (jwt->data token) "user/role")))
(cond
(and (not= :login handler) (not token))
{:redirect "/login"
@@ -38,6 +37,7 @@
:else
{:db (assoc db/default-db
:active-page handler
:is-initial-loading? true
:last-client-id (.getItem js/localStorage "last-client-id")
:query-params (auto-ap.views.utils/query-params)
:user token)
@@ -84,7 +84,9 @@
[:accounts [:numeric-code :name :location :type :account_set :applicability :id [:client-overrides [:name [:client [:name :id]]]]]]]}
:on-success [::received-initial]}
:db (assoc db :user (assoc user :token token))}))
:db (assoc db
:user (assoc user :token token)
:is-initial-loading? true)}))
(re-frame/reg-event-db
::received-initial
@@ -93,6 +95,7 @@
(-> db
(assoc :clients (by :id clients) )
(assoc :vendors (by :id vendors) )
(assoc :is-initial-loading? false)
(assoc :accounts accounts )
(assoc :client (or (when (= 1 (count clients)) (->> clients first :id ))
(->> clients

View File

@@ -150,6 +150,11 @@
(fn [db]
(:menu db)))
(re-frame/reg-sub
::is-initial-loading?
(fn [db]
(:is-initial-loading? db)))
(re-frame/reg-sub
::modal-state
(fn [db [_ id status-from]]

View File

@@ -37,7 +37,8 @@
url-filters {:vendor (when-let [vendor-id (:vendor-id url-filters)]
{:id (str vendor-id)
:name (get-in vendors-by-id [(str vendor-id) :name] "Loading...")})
:date-range (:date-range url-filters)
:date-range {:raw (:date-range url-filters)
:settled (:date-range url-filters)}
:due-range (:due-range url-filters)
:amount-range {:raw {:amount-gte (:amount-gte url-filters)
:amount-lte (:amount-lte url-filters)}
@@ -60,7 +61,7 @@
(fn [[filters ap ]]
{:vendor-id (:id (:vendor filters))
:date-range (:date-range filters)
:date-range (:settled (:date-range filters))
:due-range (:due-range filters)
:amount-gte (:amount-gte (:settled (:amount-range filters)))
:amount-lte (:amount-lte (:settled (:amount-range filters)))
@@ -114,6 +115,25 @@
:key ::amount-range}
:db (assoc-in db [:raw which] value)}))
(re-frame/reg-event-fx
::date-range-settled
[(re-frame/path [::filters :date-range])]
(fn [{:keys [db]} [_ which value]]
{:db (assoc-in db [:settled which] value)
:dispatch [::filter-changed :date-range [:settled] (assoc (:settled db) which value)]}))
;; TODO for some reason reloading is borken, and typing will unset stuff, has nothing to do with it being debounced
(re-frame/reg-event-fx
::date-range-changed
[(re-frame/path [::filters :date-range])]
(fn [{:keys [db]} [_ [which] value]]
(println which value)
{:dispatch-debounce
{:event [::date-range-settled which value]
:time 1000
:key ::date-range}
:db (assoc-in db [:raw which] value)}))
(defn invoice-number-filter []
[:div.field
[:div.control [:input.input {:placeholder "AP-123"
@@ -171,8 +191,8 @@
[:p.menu-label "Date Range"]
[:div
[date-range-filter
{:on-change-event [::filter-changed :date-range]
:value @(re-frame/subscribe [::filter :date-range])}]]
{:on-change-event [::date-range-changed]
:value (:raw @(re-frame/subscribe [::filter :date-range]))}]]
[:p.menu-label "Due Range"]
[:div

View File

@@ -90,71 +90,75 @@
clients (re-frame/subscribe [::subs/clients])
matching-clients @(re-frame/subscribe [::matching-clients])
menu (re-frame/subscribe [::subs/menu])
client-search @(re-frame/subscribe [::client-search])]
client-search @(re-frame/subscribe [::client-search])
is-initial-loading @(re-frame/subscribe [::subs/is-initial-loading?])]
[:nav {:class "navbar has-shadow is-fixed-top"}
[:div {:class "container"}
[:div {:class "navbar-brand"}
[:a {:class "navbar-item", :href "../"}
[:img {:src "/img/logo.png"}]]]
[:div.navbar-menu
[:div.navbar-start
[:a.navbar-item {:class [(active-when ap = :index)]
:href (bidi/path-for routes/routes :index)}
"Home" ]
[:a.navbar-item {:class [(active-when ap #{:unpaid-invoices :paid-invoices})]
:href (bidi/path-for routes/routes :unpaid-invoices)}
"Invoices" ]
[:a.navbar-item {:class [(active-when ap = :payments)]
:href (bidi/path-for routes/routes :payments)}
"Payments" ]
[:a.navbar-item {:class [(active-when ap = :transactions)]
:href (bidi/path-for routes/routes :transactions)}
"Transactions" ]
(when (not= "manager" (:user/role @user))
[:a.navbar-item {:class [(active-when ap = :ledger)]
:href (bidi/path-for routes/routes :ledger)}
"Ledger" ])]
(when-not is-initial-loading
[:div.navbar-start
[:a.navbar-item {:class [(active-when ap = :index)]
:href (bidi/path-for routes/routes :index)}
"Home" ]
[:a.navbar-item {:class [(active-when ap #{:unpaid-invoices :paid-invoices})]
:href (bidi/path-for routes/routes :unpaid-invoices)}
"Invoices" ]
[:a.navbar-item {:class [(active-when ap = :payments)]
:href (bidi/path-for routes/routes :payments)}
"Payments" ]
[:a.navbar-item {:class [(active-when ap = :transactions)]
:href (bidi/path-for routes/routes :transactions)}
"Transactions" ]
(when (not= "manager" (:user/role @user))
[:a.navbar-item {:class [(active-when ap = :ledger)]
:href (bidi/path-for routes/routes :ledger)}
"Ledger" ])])
[:div {:class "navbar-burger burger", :data-target "navMenu"}
[:span]
[:span]
[:span]]
[:div.navbar-end
[:div.navbar-item
[:a.button.is-primary.is-outlined
{:on-click (dispatch-event [::vendor-dialog/started {}])}
[:span.icon [:i.fa.fa-plus] ] [:span "Vendor"]]]
(when-not is-initial-loading
[:div.navbar-end
[:div.navbar-item
[:a.button.is-primary.is-outlined
{:on-click (dispatch-event [::vendor-dialog/started {}])}
[:span.icon [:i.fa.fa-plus] ] [:span "Vendor"]]]
(when (> (count @clients) 1)
[navbar-drop-down {:header (str "Client: " (if @client (:name @client)
"All"))
:id ::select-client}
[:div
[:a {:class "navbar-item"
:on-click (fn []
(re-frame/dispatch [::events/swap-client nil]))} "All" ]
[:hr {:class "navbar-divider"}]
[bind-field
[:input.input.navbar-item {:placeholder "Client name"
:auto-focus true
:field [:value]
:on-key-up (fn [k]
(when (= 13 (.-which k))
(do
(re-frame/dispatch [::events/swap-client (first matching-clients)])
(re-frame/dispatch [::events/toggle-menu ::select-client])
(re-frame/dispatch [::client-search-changed [:value] nil])))
)
:event [::client-search-changed]
:subscription client-search}]]
(for [{:keys [name id] :as client} matching-clients]
^{:key id }
(when (> (count @clients) 1)
[navbar-drop-down {:header (str "Client: " (if @client (:name @client)
"All"))
:id ::select-client}
[:div
[:a {:class "navbar-item"
:on-click (fn []
(re-frame/dispatch [::events/swap-client client]))
} name])]])]]
[login-dropdown]]]))
(re-frame/dispatch [::events/swap-client nil]))} "All" ]
[:hr {:class "navbar-divider"}]
[bind-field
[:input.input.navbar-item {:placeholder "Client name"
:auto-focus true
:field [:value]
:on-key-up (fn [k]
(when (= 13 (.-which k))
(do
(re-frame/dispatch [::events/swap-client (first matching-clients)])
(re-frame/dispatch [::events/toggle-menu ::select-client])
(re-frame/dispatch [::client-search-changed [:value] nil])))
)
:event [::client-search-changed]
:subscription client-search}]]
(for [{:keys [name id] :as client} matching-clients]
^{:key id }
[:a {:class "navbar-item"
:on-click (fn []
(re-frame/dispatch [::events/swap-client client]))
} name])]])])]
(when-not is-initial-loading
[login-dropdown])]]))
(defn footer []
@@ -170,7 +174,8 @@
(defn side-bar-layout [{:keys [side-bar main ap bottom right-side-bar]}]
(let [ap @(re-frame/subscribe [::subs/active-page])
client @(re-frame/subscribe [::subs/client])]
client @(re-frame/subscribe [::subs/client])
is-initial-loading @(re-frame/subscribe [::subs/is-initial-loading?])]
[:div
[navbar ap]
[:div {:class "columns has-shadow", :style {:margin-bottom "0px" :height "calc(100vh - 46px)" } :id "mail-app" }
@@ -190,7 +195,8 @@
]
#_[footer]
[:div
[vendor-dialog {}]
(when-not is-initial-loading
[vendor-dialog {}])
bottom]
[:div#dz-hidden]]))
@@ -198,3 +204,11 @@
(defn side-bar [{:keys [on-close]} children]
[:div [:a.delete.is-pulled-right {:on-click on-close}] [:div children]])
(defn loading-layout []
[side-bar-layout
{:main [:div.has-text-centered.hero.is-fullheight.is-vertically-centered.is-centered
[:div.hero-body
[:div.container
[:div.column.is-4.is-offset-4.has-text-centered
[:div.loader.is-loading.is-active.big.is-centered]]]]]}])

View File

@@ -6,7 +6,7 @@
[auto-ap.subs :as subs]
[auto-ap.events :as events]
[auto-ap.views.utils :refer [active-when active-when= login-url dispatch-event]]
[auto-ap.views.components.layouts :refer [side-bar-layout]]
[auto-ap.views.components.layouts :refer [side-bar-layout loading-layout]]
[auto-ap.views.pages.unpaid-invoices :refer [unpaid-invoices-page]]
[auto-ap.views.pages.import-invoices :refer [import-invoices-page]]
[auto-ap.views.pages.needs-activation :refer [needs-activation-page]]
@@ -111,8 +111,44 @@
(defmethod page :admin-excel-import [_]
[admin-excel-import-page])
;;
;; ;; <div id="app">
;; <nav class="navbar has-shadow">
;; <div class="container">
;; <div class="navbar-brand">
;; <a class="navbar-item" href="../">
;; <img src="/img/logo.png" />
;; </a>
;; </div>
;; </div>
;; </nav>
;; <div class="has-text-centered hero is-fullheight is-vertically-centered" id="mail-app">
;; <div class="is-vertically-centered">
;; <h1 class="title"><i class="fa fa-spin fa-spinner"></i></h1>
;; </div>
;; </div>
;; <footer class="footer">
;; <div class="container">
;; <div class="content has-text-centered">
;; <p>
;; <strong>Integreat</strong>
;; by <a href="https://github.com/">Integreat</a>.
;; </p>
;; <p>
;; <a class="icon" href="https://github.com/dansup/bulma-templates">
;; <i class="fa fa-github"></i>
;; </a>
;; </p>
;; </div>
;; </div>
;; </footer>
;; </div>
(defn active-page []
(let [ap (re-frame/subscribe [::subs/active-page])]
[:div
^{:key @ap} [page @ap]]))
(let [ap (re-frame/subscribe [::subs/active-page])
is-loading? @(re-frame/subscribe [::subs/is-initial-loading?])]
(if is-loading?
[loading-layout]
[:div
^{:key @ap} [page @ap]])))

View File

@@ -27,8 +27,8 @@
{:vendor-id (:id (:vendor filters))
:date-range (:date-range filters)
:bank-account-id (:id (:bank-account filters))
:amount-gte (:amount-gte (:amount-range filters))
:amount-lte (:amount-lte (:amount-range filters))
:amount-gte (:amount-gte (:settled (:amount-range filters)))
:amount-lte (:amount-lte (:settled (:amount-range filters)))
:description (:settled (:description filters))
:approval-status (condp = ap
:transactions nil
@@ -65,6 +65,23 @@
:key ::description}
:db (assoc db :raw description)}))
(re-frame/reg-event-fx
::amount-range-settled
[(re-frame/path [::filters :amount-range])]
(fn [{:keys [db]} [_ which value]]
{:db (assoc-in db [:settled which] value)
:dispatch [::filter-changed :amount-range [:settled] (assoc (:settled db) which value)]}))
(re-frame/reg-event-fx
::amount-range-changed
[(re-frame/path [::filters :amount-range])]
(fn [{:keys [db]} [_ [which] value]]
{:dispatch-debounce
{:event [::amount-range-settled which value]
:time 500
:key ::amount-range}
:db (assoc-in db [:raw which] value)}))
(defn side-bar []
(let [ap @(re-frame/subscribe [::subs/active-page])
user @(re-frame/subscribe [::subs/user])]
@@ -119,8 +136,8 @@
[:p.menu-label "Amount"]
[:div
[number-filter
{:on-change-event [::filter-changed :amount-range]
:value @(re-frame/subscribe [::filter :amount-range])}]]
{:on-change-event [::amount-range-changed]
:value (:raw @(re-frame/subscribe [::filter :amount-range]))}]]
[:p.menu-label "Vendor"]
[:div

View File

@@ -82,7 +82,6 @@
(seq filter-params) (merge filter-params)
(seq table-params) (merge table-params))]
(when (not= params last-params)
(println "DISPATCHING" params last-params)
(re-frame/dispatch [::params-change]))
params)))
@@ -113,6 +112,7 @@
(re-frame/reg-event-fx
::unmounted
(fn [{:keys [db]} _]
(println "UNMOUNTING?")
{:db (dissoc db ::invoice-page ::table/table-params ::side-bar/filters ::last-params)}))
(re-frame/reg-event-db