Makes loading page asynchronous

This commit is contained in:
2024-04-29 11:08:59 -07:00
parent 0b2ec31160
commit cb5028948e
4 changed files with 224 additions and 186 deletions

File diff suppressed because one or more lines are too long

View File

@@ -1,5 +1,6 @@
(ns auto-ap.ssr.dashboard (ns auto-ap.ssr.dashboard
(:require [auto-ap.datomic :refer [conn]] (:require [auto-ap.client-routes :as client-routes]
[auto-ap.datomic :refer [conn]]
[auto-ap.graphql.ledger :refer [get-profit-and-loss-raw]] [auto-ap.graphql.ledger :refer [get-profit-and-loss-raw]]
[auto-ap.graphql.utils :refer [<-graphql]] [auto-ap.graphql.utils :refer [<-graphql]]
[auto-ap.ledger.reports :as r] [auto-ap.ledger.reports :as r]
@@ -9,23 +10,27 @@
wrap-client-redirect-unauthenticated]] wrap-client-redirect-unauthenticated]]
[auto-ap.ssr-routes :as ssr-routes] [auto-ap.ssr-routes :as ssr-routes]
[auto-ap.ssr.components :as com] [auto-ap.ssr.components :as com]
[auto-ap.ssr.hiccup-helper :as hh]
[auto-ap.ssr.hx :as hx] [auto-ap.ssr.hx :as hx]
[auto-ap.ssr.svg :as svg]
[auto-ap.ssr.ui :refer [base-page]] [auto-ap.ssr.ui :refer [base-page]]
[auto-ap.ssr.utils :refer [apply-middleware-to-all-handlers]] [auto-ap.ssr.utils :refer [apply-middleware-to-all-handlers
html-response]]
[auto-ap.time :as atime] [auto-ap.time :as atime]
[bidi.bidi :as bidi] [bidi.bidi :as bidi]
[cemerick.url :as url]
[clj-time.coerce :as coerce] [clj-time.coerce :as coerce]
[clj-time.core :as time] [clj-time.core :as time]
[datomic.api :as dc] [datomic.api :as dc]
[hiccup.util :as hu] [hiccup.util :as hu]))
[auto-ap.client-routes :as client-routes]
[cemerick.url :as url]))
(defn bank-accounts-card [request] (defn bank-accounts-card [request]
(html-response
(com/card {:class "inline-block " } (com/card {:class "inline-block " }
[:div.p-4 [:div.p-4
[:h1.text-2xl.font-bold "Bank Accounts"] [:h1.text-2xl.font-bold "Bank Accounts"]
[:div {:class "max-h-[900px] overflow-scroll"} [:div (hx/alpine-mount-then-appear {:class "max-h-[900px] overflow-scroll"
:data-key "show"})
(for [c (:valid-trimmed-client-ids request) (for [c (:valid-trimmed-client-ids request)
b (:client/bank-accounts (dc/pull (dc/db conn) '[{:client/bank-accounts b (:client/bank-accounts (dc/pull (dc/db conn) '[{:client/bank-accounts
@@ -79,9 +84,10 @@
(atime/unparse-local atime/standard-time) (atime/unparse-local atime/standard-time)
(#(str "Synced " %))))] (#(str "Synced " %))))]
[:div.inline-flex.justify-end.text-xs.text-gray-400.it])) [:div.inline-flex.justify-end.text-xs.text-gray-400.it]))
#_[:div.inline-flex.justify-between.items-baseline]]])]])) #_[:div.inline-flex.justify-between.items-baseline]]])]])))
(defn sales-chart-card [request] (defn sales-chart-card [request]
(html-response
(let [ totals (let [ totals
(->> (dc/q '[:find ?sd (sum ?total) (->> (dc/q '[:find ?sd (sum ?total)
:with ?e :with ?e
@@ -121,9 +127,10 @@
} }
} }
} }
});"}]]))) });"}]]))))
(defn expense-pie-card [request] (defn expense-pie-card [request]
(html-response
(let [ totals (let [ totals
(->> (dc/q '[:find ?an (sum ?amt) (->> (dc/q '[:find ?an (sum ?amt)
:with ?iea :with ?iea
@@ -163,15 +170,15 @@
maintainAspectRatio: false, maintainAspectRatio: false,
} }
});"}]]))) });"}]]))))
(defn pnl-card [request] (defn pnl-card [request]
(html-response
(com/card {:class "w-full h-full p-4"} (com/card {:class "w-full h-full p-4"}
[:h1.text-2xl.font-bold.text-gray-700 [:h1.text-2xl.font-bold.text-gray-700
"Profit and Loss" "Profit and Loss, last month" ]
]
(let [ data (<-graphql (get-profit-and-loss-raw (:valid-trimmed-client-ids request) (let [ data (<-graphql (get-profit-and-loss-raw (:valid-trimmed-client-ids request)
[{:start (time/plus (time/now) (time/days -90)) [{:start (time/plus (time/now) (time/months -1))
:end (time/now)}])) :end (time/now)}]))
data (r/->PNLData {} (:accounts (first (:periods data))) {}) data (r/->PNLData {} (:accounts (first (:periods data))) {})
sales (r/aggregate-accounts (r/filter-categories data [ :sales])) sales (r/aggregate-accounts (r/filter-categories data [ :sales]))
@@ -179,7 +186,7 @@
(list (list
#_(when (not= (count all-clients) (count clients)) #_(when (not= (count all-clients) (count clients))
) )
[:canvas.w-full.h-full.p-8 {:x-data (hx/json {:chart nil [:canvas.w-full.h-full.p-8 {:x-data (hx/json {:chart nil
:labels [(format "Income $%,.2f" sales) (format "Expenses $%,.2f" expenses)] :labels [(format "Income $%,.2f" sales) (format "Expenses $%,.2f" expenses)]
:data [sales expenses]}) :data [sales expenses]})
:x-init :x-init
@@ -207,12 +214,14 @@
[:div [:div
"Income: " (format "$%,.2f" sales)] "Income: " (format "$%,.2f" sales)]
[:div [:div
"Expenses: " (format "$%,.2f" expenses)])))) "Expenses: " (format "$%,.2f" expenses)])))))
(defn tasks-card [request] (defn tasks-card [request]
(html-response
(com/card {:class "w-full h-full p-4 space-y-2"} (com/card {:class "w-full h-full p-4 space-y-2"}
[:h1.text-2xl.font-bold.text-gray-700 [:h1.text-2xl.font-bold.text-gray-700
"Tasks"] "Tasks"]
[:div (hx/alpine-mount-then-appear {:data-key "show"})
(let [[unpaid-invoice-count unpaid-invoice-amount] (let [[unpaid-invoice-count unpaid-invoice-amount]
(first (dc/q '[:find (count ?e) (sum ?ab) (first (dc/q '[:find (count ?e) (sum ?ab)
:in $ [?clients ?start-date ?end-date] :in $ [?clients ?start-date ?end-date]
@@ -254,24 +263,43 @@
(url/url-encode (pr-str {:start (atime/unparse-local (time/plus (time/now) (time/years -1)) atime/iso-date) :end (atime/unparse-local (time/now) atime/iso-date)}))) } (url/url-encode (pr-str {:start (atime/unparse-local (time/plus (time/now) (time/years -1)) atime/iso-date) :end (atime/unparse-local (time/now) atime/iso-date)}))) }
"Review now") "Review now")
]))))) ])))])))
(defn stub-card [params & children]
(com/card (-> params
(dissoc :title)
(update :class #(hh/add-class (or % "") "w-full h-full p-4 space-y-2"))
(assoc :hx-swap "outerHTML"))
[:h1.text-2xl.font-bold.text-gray-700
(:title params)]
[:div.w-full.h-full.flex.justify-center.items-center
[:div.htmx-indicator (svg/spinner {:class "inline w-32 h-32 text-green-500"})]]))
(defn- page-contents [request] (defn- page-contents [request]
[:div [:div
[:div {:class "grid grid-cols-1 lg:grid-cols-2 2xl:grid-cols-3 gap-4 auto-rows-fr max-h-[970px]"} [:div {:class "grid grid-cols-1 lg:grid-cols-2 2xl:grid-cols-3 gap-4 auto-rows-fr max-h-[970px]"}
[:div (expense-pie-card request)] [:div (stub-card {:title "Expenses"
:hx-get (bidi.bidi/path-for ssr-routes/only-routes ::d-routes/expense-card)
:hx-trigger "load"} )]
[:div [:div
(tasks-card request)] (stub-card {:title "Tasks"
:hx-get (bidi.bidi/path-for ssr-routes/only-routes ::d-routes/tasks-card)
:hx-trigger "load"} )]
[:div.row-span-2 [:div.row-span-2
(bank-accounts-card request)] (stub-card {:title "Bank Accounts"
:hx-get (bidi.bidi/path-for ssr-routes/only-routes ::d-routes/bank-accounts-card)
[:div :hx-trigger "load"} )
(sales-chart-card request)]
[:div
(pnl-card request)
] ]
] ])
[:div
(stub-card {:title "Gross Sales, last 14 days"
:hx-get (bidi.bidi/path-for ssr-routes/only-routes ::d-routes/sales-card)
:hx-trigger "load"})
]
[:div
(stub-card {:title "Profit and Loss, last month"
:hx-get (bidi.bidi/path-for ssr-routes/only-routes ::d-routes/pnl-card)
:hx-trigger "load"}) ] ] ])
(defn page [request] (defn page [request]
(base-page (base-page
@@ -298,6 +326,11 @@
(def key->handler (def key->handler
( apply-middleware-to-all-handlers ( apply-middleware-to-all-handlers
{::d-routes/page page} {::d-routes/page page
::d-routes/expense-card expense-pie-card
::d-routes/pnl-card pnl-card
::d-routes/sales-card sales-chart-card
::d-routes/bank-accounts-card bank-accounts-card
::d-routes/tasks-card tasks-card}
(fn [h] (fn [h]
(wrap-client-redirect-unauthenticated (wrap-admin h))))) (wrap-client-redirect-unauthenticated (wrap-admin h)))))

View File

@@ -1,3 +1,8 @@
(ns auto-ap.routes.dashboard) (ns auto-ap.routes.dashboard)
(def routes {"" (def routes {""
{:get ::page }}) {:get ::page }
"/expense-card" ::expense-card
"/pnl-card" ::pnl-card
"/sales-card" ::sales-card
"/bank-accounts-card" ::bank-accounts-card
"/tasks-card" ::tasks-card})

View File

@@ -17,7 +17,7 @@
"search" :search "search" :search
"indicators" indicator-routes/routes "indicators" indicator-routes/routes
"dashboard" {:get ::d-routes/page} "dashboard" d-routes/routes
"account" {"/search" {:get :account-search}} "account" {"/search" {:get :account-search}}
"admin" {"" :auto-ap.routes.admin/page "admin" {"" :auto-ap.routes.admin/page
"/client" ac-routes/routes "/client" ac-routes/routes