tailwind ready

This commit is contained in:
Bryce
2023-06-13 22:05:58 -07:00
parent 3e4b963726
commit 1c245c6427
16 changed files with 454 additions and 243 deletions

View File

@@ -1,5 +1 @@
1. Make admin sidebar
2. Make transaction sidebar
3. Test power users
4. Maybe make dark mode persist
5. redirect when not authenticated

View File

@@ -1380,6 +1380,10 @@ input:checked + .toggle-bg {
flex: 1 1 0%;
}
.flex-none {
flex: none;
}
.flex-shrink {
flex-shrink: 1;
}
@@ -1480,6 +1484,14 @@ input:checked + .toggle-bg {
flex-direction: column;
}
.flex-wrap {
flex-wrap: wrap;
}
.content-start {
align-content: flex-start;
}
.items-start {
align-items: flex-start;
}
@@ -1512,6 +1524,10 @@ input:checked + .toggle-bg {
justify-content: space-between;
}
.justify-items-start {
justify-items: start;
}
.gap-1 {
gap: 0.25rem;
}
@@ -1587,6 +1603,10 @@ input:checked + .toggle-bg {
border-color: rgb(243 244 246 / var(--tw-divide-opacity));
}
.justify-self-start {
justify-self: start;
}
.overflow-auto {
overflow: auto;
}
@@ -1797,6 +1817,21 @@ input:checked + .toggle-bg {
background-color: rgb(253 246 178 / var(--tw-bg-opacity));
}
.bg-green-200 {
--tw-bg-opacity: 1;
background-color: rgb(201 225 171 / var(--tw-bg-opacity));
}
.bg-blue-200 {
--tw-bg-opacity: 1;
background-color: rgb(153 215 247 / var(--tw-bg-opacity));
}
.bg-red-200 {
--tw-bg-opacity: 1;
background-color: rgb(255 154 154 / var(--tw-bg-opacity));
}
.bg-opacity-50 {
--tw-bg-opacity: 0.5;
}
@@ -2346,6 +2381,21 @@ input:checked + .toggle-bg {
background-color: rgb(255 255 255 / var(--tw-bg-opacity));
}
.hover\:bg-green-300:hover {
--tw-bg-opacity: 1;
background-color: rgb(175 211 130 / var(--tw-bg-opacity));
}
.hover\:bg-blue-300:hover {
--tw-bg-opacity: 1;
background-color: rgb(102 196 242 / var(--tw-bg-opacity));
}
.hover\:bg-red-300:hover {
--tw-bg-opacity: 1;
background-color: rgb(255 104 104 / var(--tw-bg-opacity));
}
.hover\:text-blue-600:hover {
--tw-text-opacity: 1;
color: rgb(0 125 187 / var(--tw-text-opacity));
@@ -2437,6 +2487,21 @@ input:checked + .toggle-bg {
--tw-ring-color: rgb(121 181 46 / var(--tw-ring-opacity));
}
.focus\:ring-green-200:focus {
--tw-ring-opacity: 1;
--tw-ring-color: rgb(201 225 171 / var(--tw-ring-opacity));
}
.focus\:ring-blue-200:focus {
--tw-ring-opacity: 1;
--tw-ring-color: rgb(153 215 247 / var(--tw-ring-opacity));
}
.focus\:ring-red-200:focus {
--tw-ring-opacity: 1;
--tw-ring-color: rgb(255 154 154 / var(--tw-ring-opacity));
}
.group:hover .group-hover\:scale-110 {
--tw-scale-x: 1.1;
--tw-scale-y: 1.1;
@@ -2549,6 +2614,26 @@ input:checked + .toggle-bg {
background-color: rgb(99 49 18 / var(--tw-bg-opacity));
}
:is(.dark .dark\:bg-green-500) {
--tw-bg-opacity: 1;
background-color: rgb(121 181 46 / var(--tw-bg-opacity));
}
:is(.dark .dark\:bg-green-700) {
--tw-bg-opacity: 1;
background-color: rgb(73 109 28 / var(--tw-bg-opacity));
}
:is(.dark .dark\:bg-blue-700) {
--tw-bg-opacity: 1;
background-color: rgb(0 94 140 / var(--tw-bg-opacity));
}
:is(.dark .dark\:bg-red-700) {
--tw-bg-opacity: 1;
background-color: rgb(153 2 2 / var(--tw-bg-opacity));
}
:is(.dark .dark\:bg-opacity-80) {
--tw-bg-opacity: 0.8;
}
@@ -2662,6 +2747,16 @@ input:checked + .toggle-bg {
background-color: rgb(73 109 28 / var(--tw-bg-opacity));
}
:is(.dark .dark\:hover\:bg-blue-600:hover) {
--tw-bg-opacity: 1;
background-color: rgb(0 125 187 / var(--tw-bg-opacity));
}
:is(.dark .dark\:hover\:bg-red-600:hover) {
--tw-bg-opacity: 1;
background-color: rgb(204 2 2 / var(--tw-bg-opacity));
}
:is(.dark .dark\:hover\:text-blue-500:hover) {
--tw-text-opacity: 1;
color: rgb(0 156 234 / var(--tw-text-opacity));

View File

@@ -1,8 +1,8 @@
(ns ingest-ml
(:require [datomic.client.api :as dc]
(:require [datomic.api :as dc]
[clojure.java.io :as io]
[clojure.data.csv :as csv]
[iol-ion.tx :refer [upsert-entity]]
#_[iol-ion.tx :refer [upsert-entity]]
[auto-ap.datomic :refer [conn]]))
(println "hi")
@@ -13,23 +13,22 @@
(defn reset-inference []
(doseq [p (->>
(dc/q '[:find ?t
:where [?t :transaction/recommended-account]]
(dc/db conn))
(map (fn [[t]]
`(upsert-entity
~{:db/id t
:transaction/recommended-account nil
:tranasction/vendor-confidence nil
:transaction/account-confidence nil
:transaction/recommended-vendor nil})))
(partition-all 100))]
(dc/transact conn {:tx-data p})))
(doseq [p (->>
(dc/q '[:find ?t
:where [?t :transaction/recommended-account]]
(dc/db conn))
(map (fn [[t]]
[:upsert-entity {:db/id t
:transaction/recommended-account nil
:tranasction/vendor-confidence nil
:transaction/account-confidence nil
:transaction/recommended-vendor nil}]))
(partition-all 100))]
@(dc/transact conn p)))
(defn read-inference []
(with-open [reader (io/reader "/mnt/data/dev2/ml-test/inference-outcome.csv")]
(with-open [reader (io/reader "data/inference-outcome.csv")]
(->> (csv/read-csv reader)
(into []
(comp
@@ -43,7 +42,7 @@
(defn apply-inference [inference]
(doseq [p (->> inference (partition-all 100))]
(dc/transact conn {:tx-data p})))
@(dc/transact conn p)))
(defn check-applied-inference []
@@ -69,3 +68,20 @@
(dc/db conn))
(shuffle)
(take 10))))
(defn random-infer []
(let [n (rand-int 1000)
vs (into [] (map first (dc/q '[:find ?v :in $ :where [?v :vendor/name]] (dc/db conn))))
as (into [] (map first (dc/q '[:find ?v :in $ :where [?v :account/name]] (dc/db conn))))]
(->>
(dc/qseq {:query '[:find ?t
:where [?t :transaction/client]]
:args [(dc/db conn)]})
(map first)
(take n)
(map (fn [t]
{:db/id t
:transaction/recommended-account (rand-nth as)
:transaction/account-confidence (double (/ (double (rand-int 100)) 100.0))
:transaction/recommended-vendor (rand-nth vs)})))))

View File

@@ -0,0 +1,83 @@
;; This buffer is for Clojure experiments and evaluation.
;; Press C-j to evaluate the last expression.
;; You can also press C-u C-j to evaluate the expression and pretty-print its result.
(dc/pull (dc/db conn) [:db/id] [:client/code "NGAK"])
(user/init-repl)
(require '[auto-ap.datomic :refer [pull-attr pull-many]])
(csv/write-csv *out*
(let [clients (pull-many (dc/db conn) '[:db/id :client/code :client/locations] [[:client/code "NGAK"] [:client/code "NGOP"] #_#_[:client/code "NGRV"] [:client/code "NGE1"]])
account->numeric-code (into {} (seq (dc/q '[:find ?i ?n
:in $ [?a ...]
:where [?i ?a ?n]]
(dc/db conn) [:account/numeric-code :bank-account/numeric-code])))
account->name (let [lookup (into {} (seq (dc/q '[:find ?i ?n
:in $
:where [?i :account/name ?n]]
(dc/db conn))))]
(fn [x]
(or (lookup x) "Bank Account")))
account->location (into {} (seq (dc/q '[:find ?i ?l
:in $
:where [?i :account/location ?l]]
(dc/db conn))))
used-accounts (into #{} (for [c clients
d (dc/index-range (dc/db conn)
:journal-entry-line/client+account+location+date
[(:db/id c)]
[(inc (:db/id c))])
:let [[_ account] (:v d)]]
account))]
(for [client clients
:let [all-entries (->> (dc/index-pull (dc/db conn)
{:index :avet
:selector [:db/id :journal-entry-line/running-balance :journal-entry-line/client+account+location+date]
:start [:journal-entry-line/client+account+location+date [(:db/id client)]]
:reverse false
:limit 1})
(take-while (fn [curr]
(= (first (:journal-entry-line/client+account+location+date curr))
(:db/id client)))))
account-lookup (->> all-entries
(reduce
(fn [acc curr]
(let [[client account location date] (:journal-entry-line/client+account+location+date curr)
numeric-code (account->numeric-code account)]
(assoc acc (format "%d-%d-%s-%s" client numeric-code location (atime/unparse-local (clj-time.coerce/to-date-time date) atime/iso-date)) (:journal-entry-line/running-balance curr))))
(sorted-map)))]
a (sort-by account->numeric-code used-accounts)
:let [numeric-code (account->numeric-code a)]
l (or (account->location a) (:client/locations client))
delta (range -60 0)
:let [date (t/plus (c/to-date-time #inst "2023-06-12T08:00:00") (t/days delta))
date-str (atime/unparse-local date atime/iso-date)]
:when (and numeric-code (>= numeric-code 40000))]
(conj [(:client/code client) l numeric-code (account->name a) date-str] (with-precision 2
(double (.setScale (bigdec (or
(some->> (subseq account-lookup >= (format "%d-%d-%s-%s" (:db/id client) numeric-code l "2000-01-01") <= (format "%d-%d-%s-%s" (:db/id client) numeric-code l date-str))
last
last)
0.0))
2 java.math.RoundingMode/HALF_UP))))))
)
(dc/q '[:find (count ?x)
:where [?x :journal-entry-line/dirty true]]
(dc/db conn))
(let [clients (map first
(dc/q '[:find (pull ?c [:client/code :db/id])
:where [?c :client/code]]
(dc/db conn)))]
(doseq [[c i] (map vector clients (range))]
(let [db (dc/db conn)
accounts-needing-rebuild (auto-ap.ledger/accounts-needing-rebuild db (:db/id c))]
(when (seq accounts-needing-rebuild)
(println "C" c "needs" (count accounts-needing-rebuild) "built")
#_(refresh-running-balance-accounts accounts-needing-rebuild clients c i db)
#_(mu/log ::client-completed)))))
,

View File

@@ -20,18 +20,18 @@
(:jwt-secret env)
{:alg :hs512}))
(defn oauth [{{:strs [code]} :query-params {:strs [host]} :headers}]
(defn oauth [{{:strs [code state]} :query-params {:strs [host]} :headers :as request}]
(try
(let [auth (-> "https://accounts.google.com/o/oauth2/token"
(http/post
{:form-params {"client_id" google-client-id
"client_secret" google-client-secret
"code" code
"redirect_uri" (str (:scheme env) "://" host "/api/oauth")
"grant_type" "authorization_code"}
:as :json})
(http/post
{:form-params {"client_id" google-client-id
"client_secret" google-client-secret
"code" code
"redirect_uri" (str (:scheme env) "://" host "/api/oauth")
"grant_type" "authorization_code"}
:as :json})
:body)
token (:access_token auth)
profile (-> (http/get "https://www.googleapis.com/oauth2/v1/userinfo"
{:headers {"Authorization" (str "Bearer " token)} :as :json})
@@ -54,19 +54,18 @@
_ (mu/log ::logged-in-as
:auth auth)]
;; TODO - these namespaces are not being transmitted/deserialized properly
(if (and token user)
(let [jwt (jwt/sign auth
(:jwt-secret env)
{:alg :hs512})]
{:status 301
:headers {"Location" (str "/?jwt=" jwt)}
:headers {"Location" (str (or (not-empty state) "/") "?jwt=" jwt)}
:session {:identity (dissoc auth :exp)}})
{:status 401
:body "Couldn't authenticate"}))
(catch Exception e
(log/warn e )
(log/warn e)
{:status 401
:body (str "Couldn't authenticate " (.toString e))})))

View File

@@ -8,30 +8,33 @@
(defn wrap-secure [handler]
(fn [request]
(cond (authenticated? request)
(handler request)
(handler request)
(get (:headers request) "hx-request")
{:status 401
:headers {"hx-redirect" (str "/login?"
(url/map->query {"redirect-to" (:uri request)}))}}
(get (:headers request) "hx-request")
{:status 401
:headers {"hx-redirect" "/login"}}
:else
{:status 302
:headers {"Location" "/login" }})))
:else
{:status 302
:headers {"Location" (str "/login?"
(url/map->query {"redirect-to" (:uri request)}))}})))
(defn wrap-admin [handler]
(fn [request]
(if (is-admin? (:identity request))
(handler request)
(do
(do
(alog/warn ::unauthenticated)
{:status 302
:headers {"Location" "/login"}}))))
:headers {"Location" (str "/login?"
(url/map->query {"redirect-to" (:uri request)}))}}))))
(defn wrap-client-redirect-unauthenticated [handler]
(fn [request]
(let [response (handler request)]
(if (= 401 (get response :status))
(-> response
(assoc-in [:headers "hx-redirect"] "/login/"))
(-> response
(assoc-in [:headers "hx-redirect"] (str "/login?"
(url/map->query {"redirect-to" (:uri request)}))))
response))))

View File

@@ -126,16 +126,17 @@ function initCompanyDropdown() {
(defn active-client [{:keys [identity params] :as request}]
(let [client-id (some-> (or (:search-client params) (get params "search-client")) not-empty Long/parseLong)]
(println (format "HERE CLIENT ID '%s'" client-id))
(when client-id
(assert-can-see-client identity client-id))
(let [new-session (assoc (:session request) :client
(when client-id
(dc/pull (dc/db conn) [:db/id :client/name :client/code] client-id)))]
(assoc
(html-response
(dropdown {:client (:client new-session)
:identity identity}))
:session
new-session
:headers
{"hx-trigger" "clientSelected"}))))
(assoc
(html-response
(dropdown {:client (:client new-session)
:identity identity}))
:session
new-session
:headers
{"hx-trigger" "clientSelected"}))))

View File

@@ -150,69 +150,90 @@
(defn main-aside-nav- []
[:ul {:class "space-y-2"}
[:li
(menu-button- {:icon svg/pie}
"Dashboard")]
[:li
(menu-button- {:aria-controls "dropdown-invoices",
:data-collapse-toggle "dropdown-invoices"
:icon svg/accounting-invoice-mail}
"Invoices")
(sub-menu- {:id "dropdown-invoices"}
(menu-button- {:href "http://google.com"}
"All")
(menu-button- {:href "http://google.com"}
"Paid")
(menu-button- {:href "http://google.com"}
"Unpaid")
(menu-button- {:href "http://google.com"}
"Voided"))
]
[:li
(menu-button- {:aria-controls "dropdown-sales",
:data-collapse-toggle "dropdown-sales"
:icon svg/receipt-register-1}
"Sales")
(sub-menu- {:id "dropdown-sales"}
(menu-button- {:href "Sales"} "Sales")
(menu-button- {:href "Sales"} "Expected Deposits")
(menu-button- {:href "Sales"} "Cash Shifts")
(menu-button- {:href "Sales"} "Tenders"))]
[:li
(menu-button- {:aria-controls "dropdown-payments"
:data-collapse-toggle "dropdown-payments"
:icon svg/payments}
"Payments")
(sub-menu- {:id "dropdown-payments"}
(menu-button- {:href "Sales"} "All")
(menu-button- {:href "Sales"} "Pending")
(menu-button- {:href "Sales"} "Cleared")
(menu-button- {:href "Sales"} "Voided"))]
[:li
(menu-button- {:aria-controls "dropdown-transactions"
:data-collapse-toggle "dropdown-transactions"
:icon svg/bank}
"Transactions")
(sub-menu- {:id "dropdown-transactions"}
(menu-button- {:href "Sales"} "All")
(menu-button- {:href "Sales"} "Unapproved")
(menu-button- {:href "Sales"} "Client Review")
(menu-button- {:href "Sales"} "Approved")
(menu-button- {:href "Sales"} "Insights"))]
[:li
(menu-button- {:aria-controls "dropdown-ledger"
:data-collapse-toggle "dropdown-ledger"
:icon svg/receipt}
"Ledger")
(sub-menu- {:id "dropdown-ledger"}
(menu-button- {:href "Sales"} "Register")
(menu-button- {:href "Sales"} "Profit & Loss")
(menu-button- {:href "Sales"} "Profit & Loss Detail")
(menu-button- {:href "Sales"} "Cash Flows")
(menu-button- {:href "Sales"} "Balance Sheet")
(menu-button- {:href "Sales"} "External Ledger Import"))]])
[:li
(menu-button- {:icon svg/pie
:href "/"}
"Dashboard")]
[:li
(menu-button- {:aria-controls "dropdown-invoices",
:data-collapse-toggle "dropdown-invoices"
:icon svg/accounting-invoice-mail}
"Invoices")
(sub-menu- {:id "dropdown-invoices"}
(menu-button- {:href (bidi/path-for client-routes/routes
:invoices)}
"All")
(menu-button- {:href (bidi/path-for client-routes/routes
:paid-invoices)}
"Paid")
(menu-button- {:href (bidi/path-for client-routes/routes
:unpaid-invoices)}
"Unpaid")
(menu-button- {:href (bidi/path-for client-routes/routes
:voided-invoices)}
"Voided"))]
[:li
(menu-button- {:aria-controls "dropdown-sales",
:data-collapse-toggle "dropdown-sales"
:icon svg/receipt-register-1}
"Sales")
(sub-menu- {:id "dropdown-sales"}
(menu-button- {:href (bidi/path-for client-routes/routes
:sales-orders)} "Sales")
(menu-button- {:href (bidi/path-for client-routes/routes
:expected-deposits)} "Expected Deposits")
#_(menu-button- {:href "Sales"} "Cash Shifts")
#_(menu-button- {:href "Sales"} "Tenders"))]
[:li
(menu-button- {:aria-controls "dropdown-payments"
:data-collapse-toggle "dropdown-payments"
:icon svg/payments}
"Payments")
(sub-menu- {:id "dropdown-payments"}
(menu-button- {:href (bidi/path-for client-routes/routes
:payments)} "All")
(menu-button- {:href (bidi/path-for client-routes/routes
:payments)} "Pending")
(menu-button- {:href (bidi/path-for client-routes/routes
:payments)} "Cleared")
(menu-button- {:href (bidi/path-for client-routes/routes
:payments)} "Voided"))]
[:li
(menu-button- {:aria-controls "dropdown-transactions"
:data-collapse-toggle "dropdown-transactions"
:icon svg/bank}
"Transactions")
(sub-menu- {:id "dropdown-transactions"}
(menu-button- {:href (bidi/path-for client-routes/routes
:transactions)} "All")
(menu-button- {:href (bidi/path-for client-routes/routes
:unapproved-transactions)} "Unapproved")
(menu-button- {:href (bidi/path-for client-routes/routes
:requires-feedback-transactions)} "Client Review")
(menu-button- {:href (bidi/path-for client-routes/routes
:approved-transactions)} "Approved")
(menu-button- {:href (bidi/path-for ssr-routes/only-routes
:transaction-insights)} "Insights"))]
[:li
(menu-button- {:aria-controls "dropdown-ledger"
:data-collapse-toggle "dropdown-ledger"
:icon svg/receipt}
"Ledger")
(sub-menu- {:id "dropdown-ledger"}
(menu-button- {:href (bidi/path-for client-routes/routes
:ledger)} "Register")
(menu-button- {:href (bidi/path-for client-routes/routes
:profit-and-loss)} "Profit & Loss")
(menu-button- {:href (bidi/path-for client-routes/routes
:profit-and-loss-detail)} "Profit & Loss Detail")
(menu-button- {:href (bidi/path-for client-routes/routes
:cash-flows)} "Cash Flows")
(menu-button- {:href (bidi/path-for client-routes/routes
:balance-sheet)} "Balance Sheet")
(menu-button- {:href (bidi/path-for client-routes/routes
:external-import-ledger)} "External Ledger Import"))]])
(defn company-aside-nav- []
@@ -301,3 +322,5 @@
(menu-button- {:href (bidi/path-for ssr-routes/only-routes
:admin-ezcater-xls)
:hx-boost "true"} "EZCater XLS Import"))]])

View File

@@ -1,50 +1,45 @@
(ns auto-ap.ssr.components.navbar
(:require
[auto-ap.datomic :refer [conn pull-attr]]
[auto-ap.client-routes :as client-routes2]
[auto-ap.graphql.utils :refer [is-admin?]]
[auto-ap.ssr-routes :as ssr-routes]
[auto-ap.ssr.company-dropdown :as cd]
[auto-ap.ssr.components.buttons :refer [icon-button-]]
[auto-ap.ssr.components.user-dropdown :as user-dropdown]
[auto-ap.ssr.svg :as svg]
[bidi.bidi :as bidi]
[datomic.api :as dc]
[hiccup2.core :as hiccup]
[auto-ap.ssr.components.user-dropdown :as user-dropdown]))
[bidi.bidi :as bidi]))
(defn navbar- [{:keys [client identity]}]
[:nav {:class "fixed z-30 w-full bg-white border-b border-gray-200 dark:bg-gray-800 dark:border-gray-700"}
[:div {:class "px-3 py-3 lg:px-5 lg:pl-3"}
[:div {:class "flex items-center justify-between"}
[:div {:class "flex items-center justify-start"}
[:button { :aria-controls "left-nav", :id "left-nav-toggle" :type "button", :class "inline-flex items-center p-2 mt-2 ml-2 mr-2 text-sm text-gray-500 rounded-lg hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-gray-200 dark:text-gray-400 dark:hover:bg-gray-700 dark:focus:ring-gray-600"}
[:span {:class "sr-only"} "Open sidebar"]
[:svg {:class "w-6 h-6", :aria-hidden "true", :fill "currentColor", :viewbox "0 0 20 20", :xmlns "http://www.w3.org/2000/svg"}
[:path {:clip-rule "evenodd", :fill-rule "evenodd", :d "M2 4.75A.75.75 0 012.75 4h14.5a.75.75 0 010 1.5H2.75A.75.75 0 012 4.75zm0 10.5a.75.75 0 01.75-.75h7.5a.75.75 0 010 1.5h-7.5a.75.75 0 01-.75-.75zM2 10a.75.75 0 01.75-.75h14.5a.75.75 0 010 1.5H2.75A.75.75 0 012 10z"}]]]
[:a {:href "/" :class "flex ml-2 md:mr-24"}
[:img {:src "/img/logo-big2.png", :class "h-10 mr-16", :alt "Integreat logo"}]
]
]
[:div {:class "flex items-center gap-4"}
[:button.mt-1.lg:w-96.relative.hidden.lg:block {:class "bg-gray-50 hover:bg-gray-200 dark:hover:bg-gray-700 border border-gray-300 text-gray-900 sm:text-sm rounded-lg focus:ring-primary-500 focus:border-primary-500 w-full pl-10 py-4 pr-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-primary-500 dark:focus:border-primary-500 gap-4 "
:hx-get (bidi/path-for ssr-routes/only-routes
:search)
:hx-target "#modal-holder"
:hx-swap "outerHTML"}
[:div {:class "absolute inset-y-0 left-0 flex items-center pl-3 pointer-events-none text-gray-500"}
[:div.w-4.h-4 svg/search]
[:span.ml-2 "Search"]]]
[:div {:class "hidden mr-3 -mb-1 sm:block"}
[:span]]
(icon-button-
{:id "toggleSidebarMobileSearch", :type "button", :class "p-2 text-gray-500 rounded-lg lg:hidden hover:text-gray-900 hover:bg-gray-100 dark:text-gray-400 dark:hover:bg-gray-700 dark:hover:text-white"
:hx-get (bidi/path-for ssr-routes/only-routes
:search)
:hx-target "#modal-holder"
:hx-swap "outerHTML"}
svg/search)
(cd/dropdown {:client client :identity identity})
(user-dropdown/dropdown {:identity identity})
]]]])
[:div {:class "flex items-center justify-between"}
[:div {:class "flex items-center justify-start"}
[:button {:aria-controls "left-nav", :id "left-nav-toggle" :type "button", :class "inline-flex items-center p-2 mt-2 ml-2 mr-2 text-sm text-gray-500 rounded-lg hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-gray-200 dark:text-gray-400 dark:hover:bg-gray-700 dark:focus:ring-gray-600"}
[:span {:class "sr-only"} "Open sidebar"]
[:svg {:class "w-6 h-6", :aria-hidden "true", :fill "currentColor", :viewbox "0 0 20 20", :xmlns "http://www.w3.org/2000/svg"}
[:path {:clip-rule "evenodd", :fill-rule "evenodd", :d "M2 4.75A.75.75 0 012.75 4h14.5a.75.75 0 010 1.5H2.75A.75.75 0 012 4.75zm0 10.5a.75.75 0 01.75-.75h7.5a.75.75 0 010 1.5h-7.5a.75.75 0 01-.75-.75zM2 10a.75.75 0 01.75-.75h14.5a.75.75 0 010 1.5H2.75A.75.75 0 012 10z"}]]]
[:a {:href "/" :class "flex ml-2 md:mr-24"}
[:img {:src "/img/logo-big2.png", :class "h-10 mr-16", :alt "Integreat logo"}]]]
[:div {:class "flex items-center gap-4"}
(when (is-admin? identity)
[:button.mt-1.lg:w-96.relative.hidden.lg:block {:class "bg-gray-50 hover:bg-gray-200 dark:hover:bg-gray-700 border border-gray-300 text-gray-900 sm:text-sm rounded-lg focus:ring-primary-500 focus:border-primary-500 w-full pl-10 py-4 pr-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-primary-500 dark:focus:border-primary-500 gap-4 "
:hx-get (bidi/path-for ssr-routes/only-routes
:search)
:hx-target "#modal-holder"
:hx-swap "outerHTML"}
[:div {:class "absolute inset-y-0 left-0 flex items-center pl-3 pointer-events-none text-gray-500"}
[:div.w-4.h-4 svg/search]
[:span.ml-2 "Search"]]])
[:div {:class "hidden mr-3 -mb-1 sm:block"}
[:span]]
(icon-button-
{:id "toggleSidebarMobileSearch", :type "button", :class "p-2 text-gray-500 rounded-lg lg:hidden hover:text-gray-900 hover:bg-gray-100 dark:text-gray-400 dark:hover:bg-gray-700 dark:hover:text-white"
:hx-get (bidi/path-for ssr-routes/only-routes
:search)
:hx-target "#modal-holder"
:hx-swap "outerHTML"}
svg/search)
(cd/dropdown {:client client :identity identity})
(user-dropdown/dropdown {:identity identity})]]]])

View File

@@ -20,7 +20,7 @@
:admin-history (wrap-client-redirect-unauthenticated (wrap-secure (wrap-admin history/page)))
:admin-history-search (wrap-client-redirect-unauthenticated (wrap-secure (wrap-admin history/page)))
:admin-history-inspect (wrap-client-redirect-unauthenticated (wrap-secure (wrap-admin history/inspect)))
:active-client (wrap-client-redirect-unauthenticated (wrap-secure (wrap-admin company-dropdown/active-client)))
:active-client (wrap-client-redirect-unauthenticated (wrap-secure (wrap-secure company-dropdown/active-client)))
:company-dropdown-search-results
(wrap-client-redirect-unauthenticated (wrap-secure company-dropdown/dropdown-search-results))
:company (wrap-client-redirect-unauthenticated (wrap-secure company/page))
@@ -35,11 +35,11 @@
:company-reports (wrap-client-redirect-unauthenticated (wrap-secure company-reports/page))
:company-reports-table (wrap-client-redirect-unauthenticated (wrap-secure company-reports/table))
:company-reports-delete (wrap-client-redirect-unauthenticated (wrap-admin company-reports/delete-report))
:transaction-insights (wrap-client-redirect-unauthenticated (wrap-secure insights/page))
:transaction-insight-table (wrap-client-redirect-unauthenticated (wrap-secure insights/insight-table))
:transaction-insight-rows (wrap-client-redirect-unauthenticated (wrap-secure insights/transaction-rows))
:transaction-insight-approve (wrap-client-redirect-unauthenticated (wrap-secure insights/approve))
:transaction-insight-explain (wrap-client-redirect-unauthenticated (wrap-secure insights/explain))
:transaction-insights (wrap-client-redirect-unauthenticated (wrap-admin insights/page))
:transaction-insight-table (wrap-client-redirect-unauthenticated (wrap-admin insights/insight-table))
:transaction-insight-rows (wrap-client-redirect-unauthenticated (wrap-admin insights/transaction-rows))
:transaction-insight-approve (wrap-client-redirect-unauthenticated (wrap-admin insights/approve))
:transaction-insight-explain (wrap-client-redirect-unauthenticated (wrap-admin insights/explain))
:admin-ezcater-xls (wrap-client-redirect-unauthenticated (wrap-admin ezcater-xls/page))
:search (wrap-client-redirect-unauthenticated (wrap-secure search/dialog-contents))})

View File

@@ -205,7 +205,7 @@
(defn page [{:keys [identity matched-route session] :as request}]
(base-page
request
(com/page {:nav (com/admin-aside-nav)
(com/page {:nav (com/main-aside-nav)
:active-client (:client (:session request))
:identity (:identity request)
:app-params {:hx-get (bidi/path-for ssr-routes/only-routes

View File

@@ -1,23 +1,21 @@
(ns auto-ap.views.components.layouts
(:require
[auto-ap.events :as events]
[auto-ap.forms :as forms]
[auto-ap.forms.builder :as form-builder]
[auto-ap.routes :as routes]
[auto-ap.ssr-routes :as ssr-routes]
[auto-ap.subs :as subs]
[auto-ap.views.components.modal :as modal]
[auto-ap.views.components.search :as search]
[auto-ap.views.components.vendor-dialog :as vendor-dialog]
[auto-ap.views.utils
:refer [active-when
appearing
dispatch-event-with-propagation
login-url]]
:refer [active-when appearing dispatch-event-with-propagation login-url]]
[bidi.bidi :as bidi]
[clojure.string :as str]
[re-frame.core :as re-frame]
[reagent.core :as r]
[auto-ap.forms.builder :as form-builder]
[vimsical.re-frame.cofx.inject :as inject]
[auto-ap.forms :as forms]))
[vimsical.re-frame.cofx.inject :as inject]))
(defn navbar-drop-down [{:keys [ class]} _]
(let [!child (r/atom nil)]
@@ -47,19 +45,19 @@
(defn login-dropdown []
(let [user (re-frame/subscribe [::subs/user])]
(if @user
[navbar-drop-down {:header [:span [:span.icon [:i.fa.fa-user] ]
[navbar-drop-down {:header [:span [:span.icon [:i.fa.fa-user]]
[:span (:user/name @user)]]
:id ::account}
[:div
[:a {:class "navbar-item"
:href (bidi/path-for routes/routes :reports)} "My company"]
:href (bidi/path-for auto-ap.ssr-routes/only-routes :company)} "My company"]
[:a.dropdown-item {:on-click (dispatch-event-with-propagation [::vendor-dialog/started {}])} "New Vendor"]
[:a.dropdown-item {:on-click (dispatch-event-with-propagation [::vendor-dialog/edit {}])} "Edit Vendor"]
(when (= "admin" (:user/role @user))
[:a {:class "navbar-item" :href (bidi/path-for routes/routes :admin)} "Administration"])
[:hr {:class "navbar-divider"}]
[:a.navbar-item {:on-click (fn [e] (.preventDefault e) (re-frame/dispatch [::events/logout]))} "Logout"]]]
[:a.navbar-item {:href login-url} "Login"])))
[:a.navbar-item {:on-click (fn [e] (.preventDefault e) (re-frame/dispatch [::events/logout]))} "Logout"]]]
[:a.navbar-item {:href (login-url)} "Login"])))
(re-frame/reg-sub
::client-search

View File

@@ -1,7 +1,8 @@
(ns auto-ap.views.pages.login
(:require
[auto-ap.views.utils :refer [login-url]]
[re-frame.core :as re-frame]))
[re-frame.core :as re-frame]
[cemerick.url :as url]))
(re-frame/reg-sub
::logout-reason
@@ -17,9 +18,9 @@
[:div.notification.is-warning reason])
[:h1.title "Login"]
[:div.box.slideInFromBelow
[:img {:src "/img/logo-big.png"}]
[:div
[:a.button.is-large.is-primary {:href login-url} "Login with Google"]]]
[:a.button.is-large.is-primary {:href (doto (login-url (get (:query (url/url (.-location js/window))) "redirect-to")) println)} "Login with Google"]]]
[:p.has-text-gray
"Copyright Integreat 2018"]]]]]])

View File

@@ -12,11 +12,11 @@
(defn needs-activation-page []
[:div
[:div
[:h2 "Sorry, your user is not activated yet. Please have Ben Skinner enable your account. Click "
[:a {:on-click (fn []
(re-frame/dispatch-sync [::relogin])
true)
:href login-url}
:href (login-url)}
"here"]
" to try again."]])

View File

@@ -21,56 +21,55 @@
user @(re-frame/subscribe [::subs/user])
client @(re-frame/subscribe [::subs/client])]
[:div
[:div [:p.menu-label "Type"]
[:ul.menu-list
[:li.menu-item
[:a.item {:href (bidi/path-for routes/routes :transactions)
:class [(active-when ap = :transactions)]}
[:span {:class "icon" :style {:font-size "25px"}}]
[:span {:class "name"} "All"]]]
[:li.menu-item
[:a.item {:href (bidi/path-for routes/routes :unapproved-transactions)
:class [(active-when ap = :unapproved-transactions)]}
[:span {:class "icon icon-task-list-text-1" :style {:font-size "25px"}}]
[:span {:class "name"} "Unapproved"]]]
[:li.menu-item
[:a.item {:href (bidi/path-for routes/routes :requires-feedback-transactions)
:class [(active-when ap = :requires-feedback-transactions)]}
[:div [:p.menu-label "Type"]
[:ul.menu-list
[:li.menu-item
[:a.item {:href (bidi/path-for routes/routes :transactions)
:class [(active-when ap = :transactions)]}
[:span {:class "icon" :style {:font-size "25px"}}]
[:span {:class "name"} "All"]]]
[:li.menu-item
[:a.item {:href (bidi/path-for routes/routes :unapproved-transactions)
:class [(active-when ap = :unapproved-transactions)]}
[:span {:class "icon icon-task-list-text-1" :style {:font-size "25px"}}]
[:span {:class "name"} "Unapproved"]]]
[:li.menu-item
[:a.item {:href (bidi/path-for routes/routes :requires-feedback-transactions)
:class [(active-when ap = :requires-feedback-transactions)]}
[:span {:class "icon icon-task-list-question" :style {:font-size "25px"}}]
[:span {:class "name"} "Client Review"]]]
[:li.menu-item
[:a.item {:href (bidi/path-for routes/routes :approved-transactions)
:class [(active-when ap = :approved-transactions)]}
[:span {:class "icon icon-task-list-question" :style {:font-size "25px"}}]
[:span {:class "icon icon-task-list-check-1" :style {:font-size "25px"}}]
[:span {:class "name"} "Approved"]]]
[:li.menu-item
[:a.item {:href (bidi/path-for routes/routes :excluded-transactions)
:class [(active-when ap = :excluded-transactions)]}
[:span {:class "name"} "Client Review"]]]
[:li.menu-item
[:a.item {:href (bidi/path-for routes/routes :approved-transactions)
:class [(active-when ap = :approved-transactions)]}
[:span {:class "icon icon-task-list-disable" :style {:font-size "25px"}}]
[:span {:class "name"} "Excluded"]]]
[:span {:class "icon icon-task-list-check-1" :style {:font-size "25px"}}]
[:span {:class "name"} "Approved"]]]
[:li.menu-item
[:a.item {:href (bidi/path-for routes/routes :excluded-transactions)
:class [(active-when ap = :excluded-transactions)]}
[:span {:class "icon icon-task-list-disable" :style {:font-size "25px"}}]
[:span {:class "name"} "Excluded"]]]
(when @(re-frame/subscribe [::subs/is-admin?])
[:li.menu-item
[:a.item {:href (bidi/path-for ssr-routes/only-routes :transaction-insights)
:class [(active-when ap = :transaction-insights)]}
[:span {:class "icon icon-task-list-disable" :style {:font-size "25px"}}]
[:span {:class "name"} "Insights"]]]
]]
(when client
[:<>
[:span {:class "name"} "Insights"]]])]]
(when client
[:<>
[:p.menu-label "Bank Account"]
[:div
[:div
[bank-account-filter
{:on-change-event [::data-page/filter-changed data-page :bank-account]
:value @(re-frame/subscribe [::data-page/filter data-page :bank-account])
:bank-accounts @(re-frame/subscribe [::subs/bank-accounts])}]]])
[:p.menu-label "Financial Account"]
[:div
@@ -79,7 +78,7 @@
{:query i
:client-id (:id client)}
[:name :id]])
:entity->text (fn [x ] (str (:numeric-code x) " - " (:name x)))
:entity->text (fn [x] (str (:numeric-code x) " - " (:name x)))
:type "typeahead-v3"
:on-change #(re-frame/dispatch [::data-page/filter-changed data-page :account (some-> % (select-keys [:name :id :numeric-code]))])
:value @(re-frame/subscribe [::data-page/filter data-page :account])}]]
@@ -94,13 +93,11 @@
:on-change #(re-frame/dispatch [::data-page/filter-changed data-page :vendor %])
:value @(re-frame/subscribe [::data-page/filter data-page :vendor])}]]
[:p.menu-label "Amount"]
[:div
[number-filter
{:on-change-event [::data-page/filter-changed data-page :amount-range]
:value @(re-frame/subscribe [::data-page/filter data-page :amount-range])}]]
[:div
[number-filter
{:on-change-event [::data-page/filter-changed data-page :amount-range]
:value @(re-frame/subscribe [::data-page/filter data-page :amount-range])}]]
[:p.menu-label "Date Range"]
[:div
@@ -108,33 +105,31 @@
{:on-change-event [::data-page/filter-changed data-page :date-range]
:value @(re-frame/subscribe [::data-page/filter data-page :date-range])}]]
[:p.menu-label "Location"]
[:div.field
[:div.control [:input.input {:placeholder "SC"
:style {:width "3em"}
:value @(re-frame/subscribe [::data-page/filter data-page :location])
:on-change (dispatch-value-change [::data-page/filter-changed data-page :location ])} ]]]
:on-change (dispatch-value-change [::data-page/filter-changed data-page :location])}]]]
[:p.menu-label "Description"]
[:div
[:div.field
[:div.control [:input.input {:placeholder "CHECK 123 ABC"
:value @(re-frame/subscribe [::data-page/filter data-page :description])
:on-change (dispatch-value-change [::data-page/filter-changed data-page :description])} ]]]]
[:p.menu-label "Description"]
[:div
[:div.field
[:div.control [:input.input {:placeholder "CHECK 123 ABC"
:value @(re-frame/subscribe [::data-page/filter data-page :description])
:on-change (dispatch-value-change [::data-page/filter-changed data-page :description])}]]]]
(when-let [exact-match-id @(re-frame/subscribe [::data-page/filter data-page :exact-match-id])]
[:div
[:p.menu-label "Specific Transaction"]
[:span.tag.is-medium exact-match-id " "
[:button.delete.is-small {:on-click
(dispatch-event [::data-page/filter-changed data-page :exact-match-id nil])}]]])
(when (= "admin" (:user/role user))
[:<>
[:p.menu-label "Admin only"]
[:div
[:div
[switch-field {:id "unresolved-only"
:checked (boolean @(re-frame/subscribe [::data-page/filter data-page :unresolved]))
:on-change (fn [e]
@@ -149,7 +144,7 @@
[:button.delete.is-small {:on-click
(dispatch-event [::data-page/filter-changed data-page :import-batch-id nil])}]]])
[:div
[:div
[switch-field {:id "potentially-duplicate"
:checked (boolean @(re-frame/subscribe [::data-page/filter data-page :potential-duplicates]))
:on-change (fn [e]

View File

@@ -57,10 +57,16 @@
(when (apply f (into [active-page] rest)) " is-active"))
(def login-url
(let [client-id "264081895820-0nndcfo3pbtqf30sro82vgq5r27h8736.apps.googleusercontent.com"
redirect-uri (js/encodeURI (str (.-origin (.-location js/window)) "/api/oauth"))]
(str "https://accounts.google.com/o/oauth2/auth?access_type=online&client_id=" client-id "&redirect_uri=" redirect-uri "&response_type=code&max_auth_age=0&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.email+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.profile")))
(defn login-url
([] (login-url nil))
([next]
(let [client-id "264081895820-0nndcfo3pbtqf30sro82vgq5r27h8736.apps.googleusercontent.com"
redirect-uri (js/encodeURI (str (.-origin (.-location js/window)) "/api/oauth"
))]
(str "https://accounts.google.com/o/oauth2/auth?access_type=online&client_id=" client-id "&redirect_uri=" redirect-uri "&response_type=code&max_auth_age=0&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.email+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.profile"
(when next
(str "&state=" (js/encodeURIComponent next)))))))
(defn dispatch-value-change [event]
(fn [e]
@@ -249,9 +255,9 @@
:user/role)))))))
(defn query-params []
(reduce-kv
(reduce-kv
(fn [result k v]
(assoc result (keyword k) (edn/read-string v)))
(assoc result (keyword k) (try (edn/read-string v) (catch js/Error e v))))
{}
(:query (cemerick.url/url (.-location js/window)))))