From ff2bf4c2b3fa6c184e9a10efd340557e8a3bfad2 Mon Sep 17 00:00:00 2001 From: Bryce Date: Tue, 9 Apr 2024 23:27:35 -0700 Subject: [PATCH] makes client selection not contanimate other tabs --- resources/public/js/alpine-vals.js | 9 + src/clj/auto_ap/handler.clj | 86 +++++----- src/clj/auto_ap/routes/ezcater_xls.clj | 3 +- src/clj/auto_ap/ssr/admin.clj | 2 +- src/clj/auto_ap/ssr/admin/excel_invoice.clj | 2 +- src/clj/auto_ap/ssr/admin/history.clj | 3 +- src/clj/auto_ap/ssr/company.clj | 3 +- src/clj/auto_ap/ssr/company_dropdown.clj | 25 ++- .../auto_ap/ssr/components/user_dropdown.clj | 3 +- src/clj/auto_ap/ssr/grid_page_helper.clj | 2 +- src/clj/auto_ap/ssr/invoice/glimpse.clj | 3 +- src/clj/auto_ap/ssr/invoices.clj | 12 +- src/clj/auto_ap/ssr/outgoing_invoice/new.clj | 2 +- src/clj/auto_ap/ssr/transaction/insights.clj | 3 +- src/clj/auto_ap/ssr/ui.clj | 7 +- src/clj/auto_ap/ssr/utils.clj | 2 +- src/cljs/auto_ap/client_selection.cljs | 30 ++++ src/cljs/auto_ap/effects.cljs | 38 ++--- src/cljs/auto_ap/events.cljs | 161 +++++++++--------- src/cljs/auto_ap/subs.cljs | 15 +- 20 files changed, 228 insertions(+), 183 deletions(-) create mode 100644 src/cljs/auto_ap/client_selection.cljs diff --git a/resources/public/js/alpine-vals.js b/resources/public/js/alpine-vals.js index 55af6cbf..4dcd57d0 100644 --- a/resources/public/js/alpine-vals.js +++ b/resources/public/js/alpine-vals.js @@ -8,6 +8,15 @@ document.addEventListener('alpine:init', () => { el.removeEventListener('htmx:configRequest', config); }) }) +Alpine.directive('hx-header', (el, { value, expression }, { evaluateLater, effect, cleanup, evaluate }) => { + var config = function(evt) { + evt.detail.headers[value] = evaluate(expression); // add a new parameter into the request + } + el.addEventListener('htmx:configRequest', config); + cleanup(() => { + el.removeEventListener('htmx:configRequest', config); + }) + }) Alpine.directive('dispatch', (el, { value, expression }, { evaluateLater, effect, cleanup, evaluate }) => { let dependent_properties = evaluateLater(expression) diff --git a/src/clj/auto_ap/handler.clj b/src/clj/auto_ap/handler.clj index 864e082a..ace8ffea 100644 --- a/src/clj/auto_ap/handler.clj +++ b/src/clj/auto_ap/handler.clj @@ -2,7 +2,6 @@ (:require [amazonica.core :refer [defcredential]] [auto-ap.client-routes :as client-routes] [auto-ap.datomic :refer [conn pull-many]] - [auto-ap.datomic.clients :as d-clients] [auto-ap.graphql.utils :refer [assert-can-see-client limited-clients]] [auto-ap.logging :as alog] @@ -16,6 +15,7 @@ [auto-ap.routes.yodlee2 :as yodlee2] [auto-ap.ssr-routes :as ssr-routes] [auto-ap.ssr.core :as ssr] + [auto-ap.ssr.utils :refer [entity-id main-transformer]] [bidi.bidi :as bidi] [bidi.ring :refer [->ResourcesMaybe make-handler]] [buddy.auth.backends.session :refer [session-backend]] @@ -26,13 +26,14 @@ [cheshire.core :as cheshire] [clj-time.coerce :as coerce] [clj-time.core :as time] - [clojure.edn :as edn] + [clojure.data.json :as json] [clojure.set :as set] [clojure.string :as str] [com.brunobonacci.mulog :as mu] [config.core :refer [env]] [datomic.api :as dc] [hiccup2.core :as hiccup] + [malli.core :as mc] [ring.middleware.edn :refer [wrap-edn-params]] [ring.middleware.multipart-params :as mp] [ring.middleware.params :refer [wrap-params]] @@ -110,10 +111,10 @@ uri :request-method request-method)) matched-hx-current-url-route (some->> (get headers "hx-current-url") - url/url - :path - (bidi/match-route ssr-routes/only-routes) - :handler)] + url/url + :path + (bidi/match-route ssr-routes/only-routes) + :handler)] (handler (assoc request :matched-route matched-route @@ -135,6 +136,7 @@ (:uri request) :request-method (:request-method request))) + :client-selection (:client-selection request) :source "request" :query (:uri request) :request-method (:request-method request) @@ -185,10 +187,17 @@ request (assoc request :hx-query-params query-params)] (handler request)))) +(def client-selection-schema + (mc/schema + [:orn + [:global [:enum :all :mine]] + [:group-name [:map [:group :string]]] + [:specific [:map [:selected [:vector entity-id]]]]])) + (defn wrap-hydrate-clients [handler] (fn [request] - (let [x-clients (-> request :session :client-selection) + (let [x-clients (-> request :client-selection) identity (or (-> request :identity) (-> request :session :identity)) ideal-ids (set (cond @@ -202,28 +211,21 @@ (= :mine x-clients) (map :db/id (:user/clients identity)) - (= :group (first x-clients)) + (:group x-clients) (->> (dc/q '[:find ?c :in $ ?g :where [?c :client/groups ?g]] (dc/db conn) - (str/upper-case (or (second x-clients) "INVALID"))) + (str/upper-case (or (:group x-clients) "INVALID"))) (map first) set) - (seq x-clients) + (seq (:selected x-clients)) (->> x-clients - (map (fn [c] - (if (string? c) - (try - (Long/parseLong c) - (catch Exception e - nil)) - c))) + :selected (filter #(not (nil? %))) set))) - limited-clients (some->> (limited-clients identity) (map :db/id) set) @@ -236,12 +238,11 @@ (pull-many (dc/db conn) '[:db/id :client/name :client/code :client/locations :client/matches :client/feature-flags - {:client/bank-accounts [:db/id - {:bank-account/type [:db/ident]} + {:client/bank-accounts [:db/id + {:bank-account/type [:db/ident]} :bank-account/number :bank-account/name :bank-account/code]}]))] - (mu/with-context {:clients (take 10 (map :client/code clients))} (handler (assoc request :clients clients @@ -251,33 +252,22 @@ (defn wrap-store-client-in-session [handler] (fn [{:keys [headers identity] :as request}] - (let [x-clients (edn/read-string (get headers "x-clients")) - x-clients (try (if-let [client-id (and x-clients - (sequential? x-clients) - (first x-clients) - (not= :group (first x-clients)) - (first x-clients))] - (do - (assert-can-see-client identity (cond-> client-id - (string? client-id) (Long/parseLong))) - [(if (string? client-id) - (Long/parseLong client-id) - client-id)]) - x-clients) - (catch Exception e - (alog/warn ::cant-access :error e - :identity identity - :x-clients (pr-str x-clients)) - :all)) - new-request (if x-clients - (assoc-in request [:session :client-selection] x-clients) - request)] + (let [client-selection (try (mc/decode client-selection-schema (some-> (get headers "x-clients") not-empty json/read-str) main-transformer) + (catch Exception e + (alog/warn ::cant-access :error e + :identity identity + :x-clients (pr-str (get headers "x-clients"))) + nil)) + + new-request (if client-selection + (assoc-in request [:client-selection] client-selection) + (assoc-in request [:client-selection] (get-in request [:session :client-selection] :all)))] (cond-> (handler new-request) - x-clients (update :session - (fn [new-session] - (-> (:session request) - (into new-session) - (assoc :client-selection x-clients)))))))) + client-selection (update :session + (fn [new-session] + (-> (:session request) + (into new-session) + (assoc :client-selection client-selection)))))))) (defn wrap-gunzip-jwt [handler] @@ -317,9 +307,9 @@ (-> route-handler (wrap-hx-current-url-params) (wrap-guess-route) + (wrap-logging) (wrap-hydrate-clients) (wrap-store-client-in-session) - (wrap-logging) (wrap-gunzip-jwt) (wrap-authorization auth-backend) (wrap-authentication auth-backend diff --git a/src/clj/auto_ap/routes/ezcater_xls.clj b/src/clj/auto_ap/routes/ezcater_xls.clj index ec591ec4..d9af6e75 100644 --- a/src/clj/auto_ap/routes/ezcater_xls.clj +++ b/src/clj/auto_ap/routes/ezcater_xls.clj @@ -193,8 +193,9 @@ (base-page request (com/page {:nav com/admin-aside-nav - :client-selection (:client-selection (:session request)) + :client-selection (:client-selection request) :client (:client request) + :clients (:clients request) :identity (:identity request) :request request :app-params {:hx-get (bidi/path-for ssr-routes/only-routes diff --git a/src/clj/auto_ap/ssr/admin.clj b/src/clj/auto_ap/ssr/admin.clj index 0477acc8..b412afcc 100644 --- a/src/clj/auto_ap/ssr/admin.clj +++ b/src/clj/auto_ap/ssr/admin.clj @@ -45,7 +45,7 @@ (base-page request (com/page {:nav com/admin-aside-nav - :client-selection (:client-selection (:session request)) + :client-selection (:client-selection request) :clients (:clients request) :client (:client request) :identity (:identity request)} diff --git a/src/clj/auto_ap/ssr/admin/excel_invoice.clj b/src/clj/auto_ap/ssr/admin/excel_invoice.clj index 98ae86b0..1149bf44 100644 --- a/src/clj/auto_ap/ssr/admin/excel_invoice.clj +++ b/src/clj/auto_ap/ssr/admin/excel_invoice.clj @@ -243,7 +243,7 @@ (base-page request (com/page {:nav com/admin-aside-nav - :client-selection (:client-selection (:session request)) + :client-selection (:client-selection request) :clients (:clients request) :client (:client request) :identity (:identity request) diff --git a/src/clj/auto_ap/ssr/admin/history.clj b/src/clj/auto_ap/ssr/admin/history.clj index fea7e388..d04ee768 100644 --- a/src/clj/auto_ap/ssr/admin/history.clj +++ b/src/clj/auto_ap/ssr/admin/history.clj @@ -166,8 +166,9 @@ (some-> route-params (get :entity-id) Long/parseLong))] (base-page request (com/page {:nav com/admin-aside-nav - :client-selection (:client-selection (:session request)) + :client-selection (:client-selection request) :client (:client request) + :clients (:clients request) :identity (:identity request) :request request :app-params {:hx-get (bidi/path-for ssr-routes/only-routes diff --git a/src/clj/auto_ap/ssr/company.clj b/src/clj/auto_ap/ssr/company.clj index 17fbb8dd..eba9fa59 100644 --- a/src/clj/auto_ap/ssr/company.clj +++ b/src/clj/auto_ap/ssr/company.clj @@ -131,8 +131,9 @@ (base-page request (com/page {:nav com/company-aside-nav - :client-selection (:client-selection (:session request)) + :client-selection (:client-selection request) :client (:client request) + :clients (:clients request) :identity (:identity request) :app-params {:hx-get (bidi/path-for ssr-routes/only-routes :company) diff --git a/src/clj/auto_ap/ssr/company_dropdown.clj b/src/clj/auto_ap/ssr/company_dropdown.clj index 1d527d08..2a8c3e0f 100644 --- a/src/clj/auto_ap/ssr/company_dropdown.clj +++ b/src/clj/auto_ap/ssr/company_dropdown.clj @@ -1,6 +1,7 @@ (ns auto-ap.ssr.company-dropdown - (:require [auto-ap.datomic :refer [conn pull-attr pull-many]] + (:require [auto-ap.datomic :refer [conn pull-many]] [auto-ap.graphql.utils :refer [cleanse-query]] + [auto-ap.logging :as alog] [auto-ap.solr :as solr] [auto-ap.ssr-routes :as ssr-routes] [auto-ap.ssr.hx :as hx] @@ -10,7 +11,9 @@ [clojure.string :as str] [datomic.api :as dc] [hiccup2.core :as hiccup] - [iol-ion.query :refer [can-see-client?]])) + [iol-ion.query :refer [can-see-client?]] + [clojure.data.json :as json])) + (defn dropdown-search-results* [{:keys [options]}] [:ul @@ -25,6 +28,7 @@ :request-method :put) :hx-target "#company-dropdown" :hx-headers (hx/json {"x-clients" (pr-str [:group group])}) + "@click" (format "globalClientSelection={group: %s}" (hx/json group)) :hx-swap "outerHTML" :hx-trigger "click"} name] @@ -34,6 +38,7 @@ :request-method :put) :hx-target "#company-dropdown" :hx-headers (format "{\"x-clients\": \"[%d]\"}" id) + "@click" (format "globalClientSelection={selected: [%d]}" id) :hx-swap "outerHTML" :hx-trigger "click"} name])]])]) @@ -64,11 +69,18 @@ (dropdown-search-results* {:options (get-clients identity (get (:query-params request) "search-text"))}))) (defn dropdown [{:keys [client-selection client identity clients]}] + (alog/peek ::clients clients) [:div#company-dropdown [:script (hiccup/raw "localStorage.setItem(\"last-client-id\", \"" (:db/id client) "\")" "\n" - "localStorage.setItem(\"last-selected-clients\", " (pr-str (pr-str client-selection)) ")")] + "localStorage.setItem(\"last-selected-clients\", " (json/write-str (json/write-str client-selection)) + #_(cond (:group client-selection) + (:group client-selection) + (:selected client-selection) + (:selected client-selection) + :else + client-selection) ")")] [:div [:button#company-dropdown-button {:class "text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm px-4 py-2.5 text-center inline-flex items-center dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800" :type "button"} @@ -80,7 +92,7 @@ (and client (= 1 (count clients))) - ( :client/name client) + (:client/name client) :else (str (count clients) " Companies")) @@ -116,6 +128,8 @@ :active-client :request-method :put) :hx-target "#company-dropdown" + + "@click" "globalClientSelection=\"mine\"" :hx-headers "{\"x-clients\": \":mine\"}" :hx-swap "outerHTML" :hx-trigger "click"} @@ -127,6 +141,7 @@ :active-client :request-method :put) :hx-target "#company-dropdown" + "@click" "globalClientSelection=\"all\"" :hx-headers "{\"x-clients\": \":all\"}" :hx-swap "outerHTML" :hx-trigger "click"} @@ -161,7 +176,7 @@ function initCompanyDropdown() { (defn active-client [{:keys [identity params] :as request}] (assoc (html-response - (dropdown {:client-selection (:client-selection (:session request)) + (dropdown {:client-selection (:client-selection request) :clients (:clients request) :client (:client request) :identity identity})) diff --git a/src/clj/auto_ap/ssr/components/user_dropdown.clj b/src/clj/auto_ap/ssr/components/user_dropdown.clj index a30cdb71..d244f7fd 100644 --- a/src/clj/auto_ap/ssr/components/user_dropdown.clj +++ b/src/clj/auto_ap/ssr/components/user_dropdown.clj @@ -27,7 +27,8 @@ [:li [:a {:href (bidi/path-for ssr-routes/only-routes :company), :class "block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 dark:text-gray-300 dark:hover:bg-gray-600 dark:hover:text-white", :role "menuitem"} "My Company"]] (when (= "admin" (:user/role identity)) - [:a {:href (bidi/path-for ssr-routes/only-routes :auto-ap.routes.admin/page), :class "block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 dark:text-gray-300 dark:hover:bg-gray-600 dark:hover:text-white", :role "menuitem"} "Admin"]) + [:a {:href (bidi/path-for ssr-routes/only-routes :auto-ap.routes.admin/page), + :class "block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 dark:text-gray-300 dark:hover:bg-gray-600 dark:hover:text-white", :role "menuitem"} "Admin"]) [:li [:a {:href "#", :class "block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 dark:text-gray-300 dark:hover:bg-gray-600 dark:hover:text-white", :role "menuitem" "_" (hiccup/raw "on click toggle .dark on ")} diff --git a/src/clj/auto_ap/ssr/grid_page_helper.clj b/src/clj/auto_ap/ssr/grid_page_helper.clj index 91104757..def70ad0 100644 --- a/src/clj/auto_ap/ssr/grid_page_helper.clj +++ b/src/clj/auto_ap/ssr/grid_page_helper.clj @@ -245,7 +245,7 @@ (com/page {:nav (:nav grid-spec) :page-specific (when-let [page-specific-nav (:page-specific-nav grid-spec)] [:div#page-specific-nav (page-specific-nav request)]) - :client-selection (:client-selection (:session request)) + :client-selection (:client-selection request) :clients (:clients request) :client (:client request) :identity (:identity request) diff --git a/src/clj/auto_ap/ssr/invoice/glimpse.clj b/src/clj/auto_ap/ssr/invoice/glimpse.clj index 87f5580e..19850803 100644 --- a/src/clj/auto_ap/ssr/invoice/glimpse.clj +++ b/src/clj/auto_ap/ssr/invoice/glimpse.clj @@ -421,8 +421,9 @@ invoice_dropzone = new Dropzone(\"#invoice\", { (base-page request (com/page {:nav com/admin-aside-nav - :client-selection (:client-selection (:session request)) + :client-selection (:client-selection request) :client (:client request) + :clients (:clients request) :identity (:identity request) :app-params {:hx-get (bidi/path-for ssr-routes/only-routes :invoice-glimpse) diff --git a/src/clj/auto_ap/ssr/invoices.clj b/src/clj/auto_ap/ssr/invoices.clj index 1f87c5fd..4700254a 100644 --- a/src/clj/auto_ap/ssr/invoices.clj +++ b/src/clj/auto_ap/ssr/invoices.clj @@ -120,8 +120,6 @@ (exact-match-id* request)]]) - - (defn fetch-ids [db {:keys [query-params route-params] :as request}] (let [valid-clients (extract-client-ids (:clients request) (:client-id request) @@ -556,10 +554,10 @@ _ (audit-transact tx identity)] (alog/info ::unvoiding-invoice :transaction :tx) (html-response - (row* identity (dc/pull (dc/db conn) default-read id) {:flash? true - :request request}) - :headers (cond-> {"hx-retarget" (format "#entity-table tr[data-id=\"%d\"]" id) - "hx-reswap" "outerHTML"})))) + (row* identity (dc/pull (dc/db conn) default-read id) {:flash? true + :request request}) + :headers (cond-> {"hx-retarget" (format "#entity-table tr[data-id=\"%d\"]" id) + "hx-reswap" "outerHTML"})))) (defn delete [{invoice :entity :as request identity :identity}] (exception->notification @@ -1137,7 +1135,7 @@ (->> (dc/q '[:find ?i :in $ [?i ...] :where [?i :invoice/status :invoice-status/unpaid] - [?i :invoice/client ?c] ] + [?i :invoice/client ?c]] (dc/db conn) ids) (map first))) diff --git a/src/clj/auto_ap/ssr/outgoing_invoice/new.clj b/src/clj/auto_ap/ssr/outgoing_invoice/new.clj index 790c1372..16e8249b 100644 --- a/src/clj/auto_ap/ssr/outgoing_invoice/new.clj +++ b/src/clj/auto_ap/ssr/outgoing_invoice/new.clj @@ -251,7 +251,7 @@ (base-page request (com/page {:nav com/main-aside-nav - :client-selection (:client-selection (:session request)) + :client-selection (:client-selection request) :clients (:clients request) :client (:client request) :identity (:identity request) diff --git a/src/clj/auto_ap/ssr/transaction/insights.clj b/src/clj/auto_ap/ssr/transaction/insights.clj index 18f9f1a1..545df6a3 100644 --- a/src/clj/auto_ap/ssr/transaction/insights.clj +++ b/src/clj/auto_ap/ssr/transaction/insights.clj @@ -318,8 +318,9 @@ (base-page request (com/page {:nav com/main-aside-nav - :client-selection (:client-selection (:session request)) + :client-selection (:client-selection request) :client (:client request) + :clients (:clients request) :identity (:identity request) :app-params {:hx-get (bidi/path-for ssr-routes/only-routes :transaction-insights) diff --git a/src/clj/auto_ap/ssr/ui.clj b/src/clj/auto_ap/ssr/ui.clj index 89f83ca8..e4021556 100644 --- a/src/clj/auto_ap/ssr/ui.clj +++ b/src/clj/auto_ap/ssr/ui.clj @@ -69,9 +69,10 @@ input::-webkit-inner-spin-button { input[type=number] { -moz-appearance:textfield; /* Firefox */ } "] - - - [:body {:hx-ext "disable-submit, class-tools"} + [:body {:hx-ext "disable-submit, class-tools" + :x-data (hx/json {:globalClientSelection (or (:client-selection request) + :all )}) ;; TODO remove once session is used + :x-hx-header:x-clients "JSON.stringify(globalClientSelection)"} contents [:script {:src "/js/flowbite.min.js"}] diff --git a/src/clj/auto_ap/ssr/utils.clj b/src/clj/auto_ap/ssr/utils.clj index cf7b5df9..56fb3bbd 100644 --- a/src/clj/auto_ap/ssr/utils.clj +++ b/src/clj/auto_ap/ssr/utils.clj @@ -107,7 +107,7 @@ (mt2/transformer {:decoders {:map (fn [m] - (if (not (seq (filter identity (vals m)))) + (if (and (map? m) (not (seq (filter identity (vals m))))) nil m)) :string empty->nil diff --git a/src/cljs/auto_ap/client_selection.cljs b/src/cljs/auto_ap/client_selection.cljs new file mode 100644 index 00000000..bfbbcb0f --- /dev/null +++ b/src/cljs/auto_ap/client_selection.cljs @@ -0,0 +1,30 @@ +(ns auto-ap.client-selection + (:require [clojure.string :as str] + [malli.core :as mc] + [malli.transform :as mt2])) + +;; TODO remove this eventuall +(defn str->keyword [s] + (if (string? s) + (let [[ns k] (str/split s #"/")] + (if (and ns k) + (keyword ns k) + (keyword s))) + s)) + +(defn keyword->str [k] + (subs (str k) 1)) +(def client-selection-schema + (mc/schema + [:orn + [:global [:enum :all :mine]] + [:group-name [:map [:group :string]]] + [:specific [:map [:selected [:vector nat-int?]]]]])) + +(def client-selection-transformer + (mt2/transformer + mt2/json-transformer + mt2/string-transformer + (mt2/key-transformer {:encode keyword->str :decode str->keyword}))) + +;; END TODO \ No newline at end of file diff --git a/src/cljs/auto_ap/effects.cljs b/src/cljs/auto_ap/effects.cljs index ea49046e..5f0ae121 100644 --- a/src/cljs/auto_ap/effects.cljs +++ b/src/cljs/auto_ap/effects.cljs @@ -1,27 +1,25 @@ (ns auto-ap.effects (:require-macros [cljs.core.async.macros :refer [go]]) - (:require - [auto-ap.history :as p] - [auto-ap.status :as status] - [auto-ap.views.utils :refer [date->str standard]] - [cemerick.url :as url] - [cljs-http.client :as http] - [cljs-time.coerce :as c] - [cljs-time.core :as time] - [cljs-time.format :as format] - [cljs.core.async :refer [str standard]] + [cemerick.url :as url] + [cljs-http.client :as http] + [cljs-time.coerce :as c] + [cljs-time.core :as time] + [cljs-time.format :as format] + [cljs.core.async :refer [js (:selected-clients @re-frame.db/app-db)))) headers)) (re-frame/reg-fx diff --git a/src/cljs/auto_ap/events.cljs b/src/cljs/auto_ap/events.cljs index 8a3e08ce..d85f0291 100644 --- a/src/cljs/auto_ap/events.cljs +++ b/src/cljs/auto_ap/events.cljs @@ -1,24 +1,24 @@ (ns auto-ap.events - (:require - [auto-ap.db :as db] - [auto-ap.routes :as routes] - [auto-ap.utils :refer [by]] - [auto-ap.views.pages.data-page :as data-page] - [auto-ap.views.utils :refer [parse-jwt with-user gunzip]] - [bidi.bidi :as bidi] - [clojure.string :as str] - [clojure.edn :as edn] - [goog.crypt.base64 :as b64] - [re-frame.core :as re-frame] - [auto-ap.ssr-routes :as ssr-routes] - [cemerick.url :as url] - [auto-ap.subs :as subs] - [pako])) + (:require [auto-ap.client-selection :refer [client-selection-schema + client-selection-transformer]] + [auto-ap.db :as db] + [auto-ap.routes :as routes] + [auto-ap.ssr-routes :as ssr-routes] + [auto-ap.utils :refer [by]] + [auto-ap.views.pages.data-page :as data-page] + [auto-ap.views.utils :refer [gunzip parse-jwt with-user]] + [bidi.bidi :as bidi] + [cemerick.url :as url] + [clojure.string :as str] + [goog.crypt.base64 :as b64] + [malli.core :as mc] + [pako] + [re-frame.core :as re-frame])) (defn jwt->data [token] - (let [raw (js->clj (.parse js/JSON (b64/decodeString (second (str/split token #"\." ))))) + (let [raw (js->clj (.parse js/JSON (b64/decodeString (second (str/split token #"\."))))) gz-clients (or (:gz-clients raw) (get raw "gz-clients"))] (cond-> raw @@ -29,7 +29,7 @@ (defn client-query [] (cond-> [:id :name :code :email :locations :feature-flags :groups [:emails [:id :email :description]] - [:bank-accounts [:id :code :bank-name :name :type :visible + [:bank-accounts [:id :code :bank-name :name :type :visible :locations :include-in-reports :current-balance :sort-order]]])) @@ -46,18 +46,22 @@ [:plaid-account [:name :id :number]] [:intuit-bank-account [:name :id :external-id]] :use-date-instead-of-post-date - :locations :include-in-reports :current-balance :yodlee-balance-old] ] + :locations :include-in-reports :current-balance :yodlee-balance-old]] [:address [:id :street1 :street2 :city :state :zip]] [:forecasted-transactions [:id :amount :identifier :day-of-month]]] - (= "admin" (or (get (jwt->data token) "role") (get (jwt->data token) "user/role")) ) (into [[:yodlee-provider-accounts [:id [:accounts [:id :name :number :available-balance]]]] - [:plaid-items [:id [:accounts [:id :name :number :balance]]]]]))) + (= "admin" (or (get (jwt->data token) "role") (get (jwt->data token) "user/role"))) (into [[:yodlee-provider-accounts [:id [:accounts [:id :name :number :available-balance]]]] + [:plaid-items [:id [:accounts [:id :name :number :balance]]]]]))) + + + (re-frame/reg-event-fx ::initialize-db (fn [{:keys [_]} [_ token]] (let [handler (:handler (bidi/match-route routes/routes (.. js/window -location -pathname))) last-client-id (.getItem js/localStorage "last-client-id") - last-selected-clients (edn/read-string (.getItem js/localStorage "last-selected-clients")) + last-selected-clients (js->clj (.parse js/JSON (.getItem js/localStorage "last-selected-clients"))) + last-selected-clients (mc/decode client-selection-schema last-selected-clients client-selection-transformer) jwt-data (some-> token jwt->data) selected-client-assignment (cond (and token (= "admin" (get jwt-data "user/role")) @@ -70,9 +74,9 @@ [(js/parseInt last-client-id)] :else - nil)] + nil) ] + - (cond (= :login handler) {:db (cond-> (assoc db/default-db @@ -89,7 +93,7 @@ :selected-clients last-selected-clients :user token)} - (and token (= "none" (or (get jwt-data "role") (get jwt-data "user/role")) )) + (and token (= "none" (or (get jwt-data "role") (get jwt-data "user/role")))) {:redirect "/needs-activation" :db (assoc db/default-db :active-route :needs-activation @@ -112,7 +116,7 @@ :on-success [::received-initial] :on-error [::failed-initial]}} selected-client-assignment - (assoc :set-local-storage ["last-selected-clients" selected-client-assignment])))))) + (assoc :set-local-storage ["last-selected-clients" (.stringify js/JSON selected-client-assignment)])))))) (re-frame/reg-event-db @@ -125,13 +129,13 @@ ::received-initial (fn [{:keys [db]} [_ {clients :client}]] (let [only-one-client (when (= 1 (count clients)) - (->> clients first :id ))] + (->> clients first :id))] (when only-one-client (.setItem js/localStorage "last-client-id" only-one-client) (.setItem js/localStorage "last-selected-clients" (pr-str [(js/parseInt only-one-client)]))) - {:db (cond-> (-> db - (assoc :clients (by :id clients) ) + {:db (cond-> (-> db + (assoc :clients (by :id clients)) (assoc :is-initial-loading? false) (assoc :client (or only-one-client (->> clients @@ -167,30 +171,31 @@ :active-route :initial-error))) (re-frame/reg-event-fx - ::swapped-client - (fn [{:keys [db]} [_ client client-identifier]] - (when (:id client) - (.setItem js/localStorage "last-client-id" (:id client))) - (.setItem js/localStorage "last-selected-clients" - (condp = client-identifier - :all - :all + ::swapped-client + (fn [{:keys [db]} [_ client client-identifier]] + (when (:id client) + (.setItem js/localStorage "last-client-id" (:id client))) + (.setItem js/localStorage "last-selected-clients" + (.stringify js/JSON + (clj->js (condp = client-identifier + :all + :all - :mine - :mine + :mine + :mine - (pr-str [(js/parseInt (:id client))]))) + {:selected [(js/parseInt (:id client))]})))) - {:db (assoc db :client (:id client) - :selected-clients - (condp = client-identifier - :all - :all + {:db (assoc db :client (:id client) + :selected-clients + (condp = client-identifier + :all + :all - :mine - :mine + :mine + :mine - [(js/parseInt (:id client))]))})) + {:selected [(js/parseInt (:id client))]}))})) (re-frame/reg-event-fx ::swap-client @@ -210,7 +215,7 @@ (re-frame/reg-event-fx ::set-active-route (fn [{:keys [db]} [_ handler params route-params]] - (cond + (cond (and (not= :login handler) (not (:user db))) {:redirect (bidi/path-for routes/routes :login) :db (assoc db :active-route :login @@ -256,36 +261,36 @@ (fn [{:keys [db]} _] {:graphql {:token (:user db) :query-obj {:venia/queries [[:yodlee-merchants - [:name :yodlee-id :id]]]} + [:name :yodlee-id :id]]]} :on-success [::yodlee-merchants-received]}})) (re-frame/reg-event-fx - ::vendor-preferences-requested - [with-user] - (fn [{:keys [user]} [_ {:keys [ client-id vendor-id on-success on-failure owns-state]}]] - {:graphql {:token user - :query-obj {:venia/queries [[:vendor-by-id - {:id vendor-id} - [[:automatically-paid-when-due [:id]] - [:schedule-payment-dom [[:client [:id]] :dom]] - [:default-account [:id]]]] - [:account-for-vendor - {:vendor-id vendor-id - :client-id client-id} - [:name :id :numeric-code :location]]]} - :owns-state owns-state - :on-success (fn [r] - (let [schedule-payment-dom (->> r - :vendor-by-id - :schedule-payment-dom - (filter (fn [spd] - (= (-> spd :client :id) - client-id))) - first - :dom) - automatically-paid-when-due (boolean ((->> r :vendor-by-id :automatically-paid-when-due (map :id) set) client-id))] - (conj on-success {:default-account (:account-for-vendor r) - :schedule-payment-dom schedule-payment-dom - :automatically-paid-when-due automatically-paid-when-due - :vendor-autopay? (or automatically-paid-when-due (boolean schedule-payment-dom))}))) - :on-failure on-failure}})) + ::vendor-preferences-requested + [with-user] + (fn [{:keys [user]} [_ {:keys [client-id vendor-id on-success on-failure owns-state]}]] + {:graphql {:token user + :query-obj {:venia/queries [[:vendor-by-id + {:id vendor-id} + [[:automatically-paid-when-due [:id]] + [:schedule-payment-dom [[:client [:id]] :dom]] + [:default-account [:id]]]] + [:account-for-vendor + {:vendor-id vendor-id + :client-id client-id} + [:name :id :numeric-code :location]]]} + :owns-state owns-state + :on-success (fn [r] + (let [schedule-payment-dom (->> r + :vendor-by-id + :schedule-payment-dom + (filter (fn [spd] + (= (-> spd :client :id) + client-id))) + first + :dom) + automatically-paid-when-due (boolean ((->> r :vendor-by-id :automatically-paid-when-due (map :id) set) client-id))] + (conj on-success {:default-account (:account-for-vendor r) + :schedule-payment-dom schedule-payment-dom + :automatically-paid-when-due automatically-paid-when-due + :vendor-autopay? (or automatically-paid-when-due (boolean schedule-payment-dom))}))) + :on-failure on-failure}})) diff --git a/src/cljs/auto_ap/subs.cljs b/src/cljs/auto_ap/subs.cljs index e16f2c39..e9d90ada 100644 --- a/src/cljs/auto_ap/subs.cljs +++ b/src/cljs/auto_ap/subs.cljs @@ -17,7 +17,6 @@ ::client :<- [::selected-clients] (fn [selected-clients] - (println "SELECTED CLIENTS ARE" selected-clients) (when (= 1 (count selected-clients)) (first selected-clients)))) @@ -44,10 +43,6 @@ :<- [::user] :<- [::clients] (fn [[selected-clients user clients]] - (println "SELECTED" selected-clients - "USER" user - "CLIENTS" (count clients)) - (cond (= :mine selected-clients) (sort-by :name (:user/clients user)) @@ -58,17 +53,15 @@ (nil? selected-clients)) clients - (= :group (and (sequential? selected-clients) - (first selected-clients))) - (let [group (second selected-clients)] + (:group selected-clients) + (let [group (:group selected-clients)] (filterv (fn [c] - (println "GROUP" group (:groups c)) ((set (:groups c)) group)) clients)) - (sequential? selected-clients) - (filter (comp (set (map coerce-string-version selected-clients)) coerce-string-version :id) + (:selected selected-clients) + (filter (comp (set (:selected selected-clients)) coerce-string-version :id) clients) :else