Makes reports page work with new tailwind

This commit is contained in:
2023-05-12 15:17:54 -07:00
parent e78c73e093
commit 8dca622947
13 changed files with 540 additions and 296 deletions

View File

@@ -6,7 +6,7 @@
[auto-ap.ssr.components :as com]
[auto-ap.ssr.svg :as svg]
[auto-ap.ssr.ui :refer [base-page]]
[auto-ap.ssr.utils :refer [html-response]]
[auto-ap.ssr.utils :refer [html-response form-data->map path->name]]
[bidi.bidi :as bidi]
[clojure.string :as str]
[datomic.api :as dc]
@@ -53,7 +53,6 @@
[(>= ?d #inst "2022-01-01T08:00")]
[(< ?d #inst "2023-01-01T08:00")]
[?p :payment/type :payment-type/check]
[?p :payment/amount ?a]
[?p :payment/vendor ?v]]
(dc/db conn)
@@ -113,7 +112,6 @@
[(>= ?d #inst "2022-01-01T08:00")]
[(< ?d #inst "2023-01-01T08:00")]
[?p :payment/type :payment-type/check]
[?p :payment/amount ?a]
[?p :payment/vendor ?v]]
(dc/db conn)
@@ -125,134 +123,97 @@
[(:client/code client ) amount]))
(into []))))
(defn row* [{:keys [client vendor amount flash?]}]
(com/data-grid-row
{:class (when flash?
"live-added")}
(com/data-grid-cell {} (:client/code client))
(com/data-grid-cell
{}
[:div.flex.whitespace-nowrap.items-center.gap-4
[:div [:div (:vendor/name vendor)]
[:div.text-sm.text-gray-400
(or (-> vendor :vendor/legal-entity-name not-empty)
(str (-> vendor :vendor/legal-entity-first-name) " "
(-> vendor :vendor/legal-entity-middle-name) " "
(-> vendor :vendor/legal-entity-last-name)))]]
(when-let [t99-type (some-> vendor :vendor/legal-entity-1099-type :db/ident name)]
(com/pill
{:class "text-xs font-medium"
:color :primary}
(str/capitalize t99-type))
)])
(com/data-grid-cell
{:class "hidden md:table-cell"}
[:div.flex.gap-4
(when-let [tin (-> vendor :vendor/legal-entity-tin)]
[:span {:class "text-xs font-medium py-0.5 "}
tin])
(when-let [tin-type (some-> vendor :vendor/legal-entity-tin-type :db/ident name)]
(com/pill {:class "text-xs font-medium"
:color :yellow}
(name tin-type)))])
(com/data-grid-cell
{:class "hidden lg:table-cell"}
(if (-> vendor :vendor/address :address/street1)
[:div
[:div (-> vendor :vendor/address :address/street1)] " "
[:div
(-> vendor :vendor/address :address/street2)] " "
[:div
(-> vendor :vendor/address :address/city) " "
(-> vendor :vendor/address :address/state) ","
(-> vendor :vendor/address :address/zip)]]
[:p.text-sm.italic.text-gray-400 "No address"]))
(com/data-grid-cell {}
(com/pill {:class "text-xs font-medium"
:color :primary}
"Paid $" (Math/round amount)))
(com/data-grid-right-stack-cell
{}
(if (cannot-overwrite? vendor)
[:div (com/link {:href "mailto:ben@integreatconsult.com"} "Contact Integreat")]
(com/icon-button {:hx-get (bidi/path-for ssr-routes/only-routes
:company-1099-vendor-dialog
:vendor-id (:db/id vendor))
:hx-target "#modal-holder"
:hx-swap "outerHTML"}
svg/pencil)))))
(defn table* [{:keys [identity session query-params hx-query-params]} & {:keys [flash-id]}]
(println hx-query-params)
(let [start (or (some-> (or (get query-params "start") (get hx-query-params "start")) not-empty (Long/parseLong ))
(let [start (or (some-> (or (get query-params "start") (get hx-query-params "start")) not-empty (Long/parseLong ))
0)
per-page (or (some-> (or (get query-params "per-page") (get hx-query-params "per-page")) not-empty (Long/parseLong ))
per-page (or (some-> (or (get query-params "per-page") (get hx-query-params "per-page")) not-empty (Long/parseLong ))
30)
companies (get-1099-companies identity session)
total (count companies)
total (count companies)
companies (subvec companies (Math/min start total) (Math/min (+ start per-page) total))]
[:div#vendor-table {:hx-get (bidi/path-for ssr-routes/only-routes
:company-1099-vendor-table
:request-method :get)
:hx-trigger "clientSelected from:body"
:hx-swap "outerHTML swap:300ms"}
(com/content-card {}
[:div {:class "flex flex-col px-4 py-3 space-y-3 lg:flex-row lg:items-center lg:justify-between lg:space-y-0 lg:space-x-4 text-gray-800 dark:text-gray-100"}
[:div
[:h1.text-2xl.mb-3.font-bold "1099 Vendor Info"]
[:div {:class "flex items-center flex-1 space-x-4"}
[:h5
[:span "Total Vendors:"]
[:span {:class "dark:text-white pl-4"} (count companies)]]]]
[:div {:class "flex flex-col flex-shrink-0 space-y-3 md:flex-row md:items-center lg:justify-end md:space-y-0 md:space-x-3"}
(com/button {:color :primary}
(com/button-icon {} svg/refresh)
"Add new product")
(com/button {:color :secondary}
(com/button-icon {} svg/refresh)
"Update stocks 1/250")
(com/icon-button {}
svg/upload)]]
[:div {:class "overflow-x-auto"}
(apply com/data-grid {:headers [(com/data-grid-header {} "Client")
(com/data-grid-header {} "Vendor Name")
(com/data-grid-header {:class "hidden md:table-cell"} "TIN")
(com/data-grid-header {:class "hidden lg:table-cell"} "Address")
(com/data-grid-header {})
(com/data-grid-header {})]}
(for [[client vendor amount] companies]
(com/data-grid-row
{:class (when (= flash-id
(:db/id vendor))
"live-added")}
(com/data-grid-cell {} (:client/code client))
(com/data-grid-cell
{}
[:div.flex.whitespace-nowrap.items-center.gap-4
[:div [:div (:vendor/name vendor)]
[:div.text-sm.text-gray-400
(or (-> vendor :vendor/legal-entity-name not-empty)
(str (-> vendor :vendor/legal-entity-first-name) " "
(-> vendor :vendor/legal-entity-middle-name) " "
(-> vendor :vendor/legal-entity-last-name)))]]
(when-let [t99-type (some-> vendor :vendor/legal-entity-1099-type :db/ident name)]
(com/pill
{:class "text-xs font-medium"
:color :primary}
(str/capitalize t99-type))
)])
(com/data-grid-cell
{:class "hidden md:table-cell"}
[:div.flex.gap-4
(when-let [tin (-> vendor :vendor/legal-entity-tin)]
[:span {:class "text-xs font-medium py-0.5 "}
tin])
(when-let [tin-type (some-> vendor :vendor/legal-entity-tin-type :db/ident name)]
(com/pill {:class "text-xs font-medium"
:color :yellow}
(name tin-type)))])
(com/data-grid-cell
{:class "hidden lg:table-cell"}
(if (-> vendor :vendor/address :address/street1)
[:div
[:div (-> vendor :vendor/address :address/street1)] " "
[:div
(-> vendor :vendor/address :address/street2)] " "
[:div
(-> vendor :vendor/address :address/city) " "
(-> vendor :vendor/address :address/state) ","
(-> vendor :vendor/address :address/zip)]]
[:p.text-sm.italic.text-gray-400 "No address"]))
(com/data-grid-cell {}
(com/pill {:class "text-xs font-medium"
:color :primary}
"Paid $" (Math/round amount)))
(com/data-grid-right-stack-cell
{}
(if (cannot-overwrite? vendor)
[:div (com/link {:href "mailto:ben@integreatconsult.com"} "Contact Integreat")]
(com/icon-button {:hx-get (bidi/path-for ssr-routes/only-routes
:company-1099-vendor-dialog
:vendor-id (:db/id vendor))
:hx-target "#modal-holder"
:hx-swap "outerHTML"}
svg/pencil))))))]
(com/paginator {:start start
:end (Math/min (+ start per-page) total)
:per-page per-page
:total total
:a-params (fn [page]
{:hx-get (str (bidi/path-for ssr-routes/only-routes
:company-1099-vendor-table
:request-method :get)
"?start=" (* page per-page))
:hx-target "#vendor-table"
:hx-swap "outerHTML show:#app:top"})}))]))
(defn form-data->map [form-data]
(reduce-kv
(fn [acc k v]
(cond (and (string? v)
(empty? v))
acc
:else
(assoc-in acc (->> (str/split k #"_")
(mapv #(apply keyword (str/split % #"/"))))
v)))
{}
form-data))
(defn path->name [k]
(cond (keyword? k)
(str (namespace k) "/" (name k))
(seq k)
(str/join "_" (map path->name k))
:else k))
(com/data-grid-card {:id "vendor-table"
:title "1099 Vendor Info"
:entity-name "vendors"
:route :company-1099-vendor-table
:start start
:per-page per-page
:total total
:action-buttons [(com/button {:color :primary}
(com/button-icon {} svg/refresh)
"Add new product")
(com/button {:color :secondary}
(com/button-icon {} svg/refresh)
"Update stocks 1/250")
(com/icon-button {}
svg/upload)]
:rows (for [[client vendor amount] companies]
(row* {:client client
:vendor vendor
:amount amount
:flash? (= flash-id
(:db/id vendor))}))
:headers [(com/data-grid-header {} "Client")
(com/data-grid-header {} "Vendor Name")
(com/data-grid-header {:class "hidden md:table-cell"} "TIN")
(com/data-grid-header {:class "hidden lg:table-cell"} "Address")
(com/data-grid-header {})
(com/data-grid-header {})]})))
(defn vendor-save [{:keys [form-params identity route-params] :as request}]
(when-not (cannot-overwrite? (dc/pull (dc/db conn) '[*] (Long/parseLong (:vendor-id route-params))))
@@ -265,8 +226,6 @@
(table* request :flash-id (Long/parseLong (:vendor-id route-params)))
:headers {"hx-trigger" "closeModal"}))
(defn vendor-dialog [request]
(let [vendor (dc/pull (dc/db conn) '[* {:vendor/legal-entity-1099-type [:db/ident]
:vendor/legal-entity-tin-type [:db/ident]}] (Long/parseLong (:vendor-id (:params request))))] ;; TODO perms
@@ -276,86 +235,86 @@
:company-1099-vendor-save
:request-method :post
:vendor-id (Long/parseLong (:vendor-id (:params request)))))
:hx-target "#vendor-table"
:hx-swap "outerHTML swap:300ms"}
[:fieldset {:class "hx-disable"}
(com/modal-card {}
[:div.flex [:div.p-2 "Vendor 1099 Info"] [:p.ml-2.rounded.bg-gray-200.p-2.dark:bg-gray-600 (:vendor/name vendor)]]
[:div.space-y-6
[:div.grid.grid-cols-6.gap-4
[:h4.text-xl.border-b.col-span-6 "Address"]
[:div.col-span-6
(com/field {:label "Street 1"}
(com/text-input {:name (path->name [:vendor/address :address/street1])
:value (-> vendor :vendor/address :address/street1)
:placeholder "1700 Pennsylvania Ave"
:autofocus true}))]
[:div.col-span-6
(com/field {:label "Street 2"}
(com/text-input {:name (path->name [:vendor/address :address/street2])
:value (-> vendor :vendor/address :address/street2)
:placeholder "Suite 200"}))]
[:div.col-span-3
(com/field {:label "City"}
(com/text-input {:name (path->name [:vendor/address :address/city])
:value (-> vendor :vendor/address :address/city)
:placeholder "Cupertino"}))]
[:div.col-span-1
(com/field {:label "State"}
(com/text-input {:name (path->name [:vendor/address :address/state])
:value (-> vendor :vendor/address :address/state)
:placeholder "CA"}))]
[:div.col-span-2
(com/field {:label "Zip"}
(com/text-input {:name (path->name [:vendor/address :address/zip])
:value (-> vendor :vendor/address :address/zip)
:placeholder "98102"}))]
[:h4.text-xl.border-b.col-span-6 "Legal Entity"]
[:div.col-span-6
(com/field {:label "Legal Entity Name"}
(com/text-input {:name (path->name [:vendor/legal-entity-name])
:value (-> vendor :vendor/legal-entity-name)
:placeholder "Good Restaurant LLC"}))]
[:div.col-span-6.text-center " - OR -"]
[:div.col-span-2
(com/field {:label "First Name"}
(com/text-input {:name (path->name [:vendor/legal-entity-first-name])
:value (-> vendor :vendor/legal-entity-first-name)
:placeholder "John"}))]
[:div.col-span-2
(com/field {:label "Middle Name"}
(com/text-input {:name (path->name [:vendor/legal-entity-middle-name])
:value (-> vendor :vendor/legal-entity-middle-name)
:placeholder "C."}))]
[:div.col-span-2
(com/field {:label "Last Name"}
(com/text-input {:name (path->name [:vendor/legal-entity-last-name])
:value (-> vendor :vendor/legal-entity-last-name)
:placeholder "Riley"}))]
[:div.col-span-2
(com/field {:label "TIN"}
(com/text-input {:name (path->name [:vendor/legal-entity-tin])
:value (-> vendor :vendor/legal-entity-tin)
:placeholder "John"}))]
[:div.col-span-2
(com/field {:label "TIN Type"}
(com/select {:name (path->name [:vendor/legal-entity-tin-type])
:allow-blank? true
:value (some-> vendor :vendor/legal-entity-tin-type :db/ident name)
:options [["ein" "EIN"]
["ssn" "SSN"]]}))]
[:div.col-span-2
(com/field {:label "1099 Type"}
(com/select {:name (path->name [:vendor/legal-entity-1099-type])
:allow-blank? true
:value (some-> vendor :vendor/legal-entity-1099-type :db/ident name)
:options [["none" "None"]
["misc" "Misc"]
["landlord" "Landlord"]]}))]
[:div.col-span-6
(com/button {:color :primary}
"Save")]]]
[:div])]]))))
:hx-target "#vendor-table"
:hx-swap "outerHTML swap:300ms"}
[:fieldset {:class "hx-disable"}
(com/modal-card {}
[:div.flex [:div.p-2 "Vendor 1099 Info"] [:p.ml-2.rounded.bg-gray-200.p-2.dark:bg-gray-600 (:vendor/name vendor)]]
[:div.space-y-6
[:div.grid.grid-cols-6.gap-4
[:h4.text-xl.border-b.col-span-6 "Address"]
[:div.col-span-6
(com/field {:label "Street 1"}
(com/text-input {:name (path->name [:vendor/address :address/street1])
:value (-> vendor :vendor/address :address/street1)
:placeholder "1700 Pennsylvania Ave"
:autofocus true}))]
[:div.col-span-6
(com/field {:label "Street 2"}
(com/text-input {:name (path->name [:vendor/address :address/street2])
:value (-> vendor :vendor/address :address/street2)
:placeholder "Suite 200"}))]
[:div.col-span-3
(com/field {:label "City"}
(com/text-input {:name (path->name [:vendor/address :address/city])
:value (-> vendor :vendor/address :address/city)
:placeholder "Cupertino"}))]
[:div.col-span-1
(com/field {:label "State"}
(com/text-input {:name (path->name [:vendor/address :address/state])
:value (-> vendor :vendor/address :address/state)
:placeholder "CA"}))]
[:div.col-span-2
(com/field {:label "Zip"}
(com/text-input {:name (path->name [:vendor/address :address/zip])
:value (-> vendor :vendor/address :address/zip)
:placeholder "98102"}))]
[:h4.text-xl.border-b.col-span-6 "Legal Entity"]
[:div.col-span-6
(com/field {:label "Legal Entity Name"}
(com/text-input {:name (path->name [:vendor/legal-entity-name])
:value (-> vendor :vendor/legal-entity-name)
:placeholder "Good Restaurant LLC"}))]
[:div.col-span-6.text-center " - OR -"]
[:div.col-span-2
(com/field {:label "First Name"}
(com/text-input {:name (path->name [:vendor/legal-entity-first-name])
:value (-> vendor :vendor/legal-entity-first-name)
:placeholder "John"}))]
[:div.col-span-2
(com/field {:label "Middle Name"}
(com/text-input {:name (path->name [:vendor/legal-entity-middle-name])
:value (-> vendor :vendor/legal-entity-middle-name)
:placeholder "C."}))]
[:div.col-span-2
(com/field {:label "Last Name"}
(com/text-input {:name (path->name [:vendor/legal-entity-last-name])
:value (-> vendor :vendor/legal-entity-last-name)
:placeholder "Riley"}))]
[:div.col-span-2
(com/field {:label "TIN"}
(com/text-input {:name (path->name [:vendor/legal-entity-tin])
:value (-> vendor :vendor/legal-entity-tin)
:placeholder "John"}))]
[:div.col-span-2
(com/field {:label "TIN Type"}
(com/select {:name (path->name [:vendor/legal-entity-tin-type])
:allow-blank? true
:value (some-> vendor :vendor/legal-entity-tin-type :db/ident name)
:options [["ein" "EIN"]
["ssn" "SSN"]]}))]
[:div.col-span-2
(com/field {:label "1099 Type"}
(com/select {:name (path->name [:vendor/legal-entity-1099-type])
:allow-blank? true
:value (some-> vendor :vendor/legal-entity-1099-type :db/ident name)
:options [["none" "None"]
["misc" "Misc"]
["landlord" "Landlord"]]}))]
[:div.col-span-6
(com/button {:color :primary}
"Save")]]]
[:div])]]))))
(defn vendor-table [request]
(html-response (table* request)

View File

@@ -0,0 +1,120 @@
(ns auto-ap.ssr.company.reports
(:require
[amazonica.aws.s3 :as s3]
[auto-ap.datomic :refer [conn]]
[auto-ap.datomic.reports :as r]
[auto-ap.graphql.utils :refer [assert-admin is-admin?]]
[auto-ap.ssr-routes :as ssr-routes]
[auto-ap.ssr.components :as com]
[auto-ap.ssr.svg :as svg]
[auto-ap.ssr.ui :refer [base-page]]
[auto-ap.ssr.utils :refer [html-response]]
[auto-ap.time :as atime]
[bidi.bidi :as bidi]
[config.core :refer [env]]
[datomic.api :as dc]
[hiccup2.core :as hiccup]))
(defn row* [{:keys [flash? report identity delete-after-settle?]}]
(com/data-grid-row
{:class (when flash?
"live-added")
"_" (hiccup/raw (when delete-after-settle?" on htmx:afterSettle wait 400ms then remove me"))}
(com/data-grid-cell
{}
(:report/name report))
(com/data-grid-cell
{}
(when (:report/creator report)
(com/pill {:color :primary }
(:report/creator report))))
(com/data-grid-cell
{}
(atime/unparse-local (:report/created report)
atime/normal-date))
(com/data-grid-right-stack-cell
{}
(com/a-icon-button {:href (:report/url report)}
svg/download)
(when (is-admin? identity)
[:form
[:input {:type :hidden :name "id" :value (:db/id report)}]
(com/icon-button {:hx-delete (str (bidi/path-for ssr-routes/only-routes
:company-reports-delete
:request-method :delete))
:hx-target "closest tr"}
svg/trash)]))))
(defn table* [{:keys [client start per-page identity session flash-id]}]
(let [start (or start 0)
per-page (or per-page 30)
[reports total] (r/get-graphql {:id identity
:start start
:per-page per-page
:client-id (:db/id client)
:sort nil})]
(com/data-grid-card {:id "report-table"
:title "Reports"
:entity-name "reports"
:route :company-reports-table
:start start
:per-page per-page
:total total
:action-buttons [(com/button {:color :primary}
(com/button-icon {} svg/refresh)
"Add new product")
(com/button {:color :secondary}
(com/button-icon {} svg/refresh)
"Update stocks 1/250")
(com/icon-button {}
svg/upload)]
:rows (for [report reports]
(row* {:report report
:flash? (= flash-id
(:db/id report))
:identity identity}))
:headers [(com/data-grid-header {} "Name")
(com/data-grid-header {:class "hidden md:table-cell"} "Created by")
(com/data-grid-header {:class "hidden md:table-cell"} "Created")
(com/data-grid-header {})]})))
(defn delete-report [{:keys [query-params hx-query-params form-params identity session] :as request}]
(let [[id-to-delete key] (first (dc/q '[:find ?i ?k
:in $ ?i
:where [?i :report/key ?k]]
(dc/db conn)
(some-> (get form-params "id") not-empty Long/parseLong)))
report (dc/pull (dc/db conn) r/default-read id-to-delete)]
(when id-to-delete
(s3/delete-object :bucket-name (:data-bucket env)
:key key)
@(dc/transact conn [[:db/retractEntity id-to-delete]]))
(html-response
(row* {:report report
:flash? true
:identity identity
:delete-after-settle? true}))))
(defn reports-table [{:keys [query-params hx-query-params identity session] :as request}]
(html-response (table* {:client (:client (:session request))
:start (some-> (or (get query-params "start") (get hx-query-params "start")) not-empty (Long/parseLong ))
:per-page (some-> (or (get query-params "per-page") (get hx-query-params "per-page")) not-empty (Long/parseLong ))
:identity identity
:session session})
:headers {"hx-push-url" (str "?start=" (get (:query-params request) "start"))}))
(defn page [{:keys [query-params hx-query-params identity session] :as request}]
(base-page
request
(com/page {:nav (com/company-aside-nav)
:active-client (:client (:session request))
:identity (:identity request)}
(com/breadcrumbs {}
[:a {:href "#"} "My Company"]
[:a {:href "#"} "Reports"])
(table* {:client (:client (:session request))
:start (some-> (or (get query-params "start") (get hx-query-params "start")) not-empty (Long/parseLong ))
:per-page (some-> (or (get query-params "per-page") (get hx-query-params "per-page")) not-empty (Long/parseLong ))
:identity identity
:session session}))
nil))