pagination and sorting for reminders.
This commit is contained in:
@@ -35,15 +35,10 @@
|
|||||||
|
|
||||||
(and (string? node)
|
(and (string? node)
|
||||||
(re-matches is-8601 node))
|
(re-matches is-8601 node))
|
||||||
(do
|
(format/parse (format/formatters :date-time) node)
|
||||||
(println node)
|
|
||||||
(format/parse (format/formatters :date-time) node))
|
|
||||||
|
|
||||||
(instance? js/Date node)
|
(instance? js/Date node)
|
||||||
(do
|
(time/to-default-time-zone (c/from-date node))
|
||||||
(println node)
|
|
||||||
(time/to-default-time-zone (c/from-date node)))
|
|
||||||
|
|
||||||
|
|
||||||
:else
|
:else
|
||||||
node))
|
node))
|
||||||
|
|||||||
@@ -4,22 +4,4 @@
|
|||||||
[auto-ap.routes :as routes]
|
[auto-ap.routes :as routes]
|
||||||
[auto-ap.effects :as effects]))
|
[auto-ap.effects :as effects]))
|
||||||
|
|
||||||
(re-frame/reg-event-fx
|
|
||||||
::mounted
|
|
||||||
(fn [{:keys [db]} _]
|
|
||||||
{:graphql {:token (:user db)
|
|
||||||
:query-obj {:venia/queries [[:reminder_page
|
|
||||||
|
|
||||||
[[:reminders [:id :email :sent :scheduled :subject :body [:vendor [:name :id]] ]]
|
|
||||||
:total
|
|
||||||
:start
|
|
||||||
:end]]]}
|
|
||||||
|
|
||||||
:on-success [::received]}}))
|
|
||||||
|
|
||||||
(re-frame/reg-event-db
|
|
||||||
::received
|
|
||||||
(fn [db [_ reminders]]
|
|
||||||
(assoc db :reminders (:reminders (first (:reminder-page reminders))))))
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -24,11 +24,6 @@
|
|||||||
(fn [db]
|
(fn [db]
|
||||||
(:user db)))
|
(:user db)))
|
||||||
|
|
||||||
(re-frame/reg-sub
|
|
||||||
::reminders
|
|
||||||
(fn [db]
|
|
||||||
(:reminders db)))
|
|
||||||
|
|
||||||
(re-frame/reg-sub
|
(re-frame/reg-sub
|
||||||
::vendors
|
::vendors
|
||||||
(fn [db]
|
(fn [db]
|
||||||
|
|||||||
@@ -2,29 +2,15 @@
|
|||||||
(:require [re-frame.core :as re-frame]
|
(:require [re-frame.core :as re-frame]
|
||||||
[auto-ap.subs :as subs]
|
[auto-ap.subs :as subs]
|
||||||
[auto-ap.views.utils :refer [date->str]]
|
[auto-ap.views.utils :refer [date->str]]
|
||||||
|
[auto-ap.views.components.paginator :refer [paginator]]
|
||||||
|
[auto-ap.views.components.sorter :refer [sorted-column]]
|
||||||
[reagent.core :as reagent]
|
[reagent.core :as reagent]
|
||||||
[clojure.string :as str]
|
[clojure.string :as str]
|
||||||
[cljs-time.format :as format]))
|
[cljs-time.format :as format]))
|
||||||
|
|
||||||
(defn toggle-sort-by [params key]
|
|
||||||
|
|
||||||
(-> params
|
|
||||||
(assoc :sort-by key)
|
|
||||||
(update :asc not)))
|
|
||||||
|
|
||||||
(defn sort-icon [which sort-by asc]
|
|
||||||
(cond
|
|
||||||
(and (= sort-by which) asc)
|
|
||||||
[:span.icon
|
|
||||||
[:i.fa.fa-sort-up]]
|
|
||||||
|
|
||||||
(and (= sort-by which) (not asc))
|
|
||||||
[:span.icon
|
|
||||||
[:i.fa.fa-sort-down]]
|
|
||||||
|
|
||||||
:else
|
|
||||||
[:span.icon
|
|
||||||
[:i.fa.fa-sort]]))
|
|
||||||
|
|
||||||
(defn query [params]
|
(defn query [params]
|
||||||
{:venia/queries [[:invoice_page
|
{:venia/queries [[:invoice_page
|
||||||
@@ -35,72 +21,55 @@
|
|||||||
:start
|
:start
|
||||||
:end]]]})
|
:end]]]})
|
||||||
|
|
||||||
(defn bound [x y z]
|
|
||||||
(cond
|
|
||||||
(< z x)
|
|
||||||
x
|
|
||||||
(< y x)
|
|
||||||
x
|
|
||||||
(> y z)
|
|
||||||
z
|
|
||||||
:else
|
|
||||||
y))
|
|
||||||
|
|
||||||
(defn buttons-for [start end count total on-params-change state]
|
|
||||||
(let [per-page 20
|
|
||||||
max-buttons 5
|
|
||||||
buttons-before (Math/floor (/ max-buttons 2))
|
|
||||||
total-pages (Math/ceil (/ total per-page))
|
|
||||||
current-page (Math/floor (/ start per-page))
|
|
||||||
first-page-button (bound 0 (- current-page buttons-before) (- total-pages max-buttons))
|
|
||||||
all-buttons (into [] (for [x (range total-pages)]
|
|
||||||
^{:key x} [:button.button {:class (str/join " " [(when (= current-page x)
|
|
||||||
"is-active")])
|
|
||||||
:on-click (fn [e] (on-params-change (swap! state assoc :start (* x per-page))))} (inc x)]))
|
|
||||||
|
|
||||||
|
|
||||||
last-page-button (Math/min total-pages (+ max-buttons first-page-button))
|
|
||||||
|
|
||||||
extended-last-page-button (when (not= last-page-button total-pages)
|
|
||||||
[:span "..." [:button.button {:on-click (fn [e] (on-params-change (swap! state assoc :start (* (dec total-pages) per-page))))} total-pages]])
|
|
||||||
|
|
||||||
extended-first-page-button (when (not= first-page-button 0)
|
|
||||||
[:span [:button.button {:on-click (fn [e] (on-params-change (swap! state assoc :start 0)))} 1] "..."])
|
|
||||||
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
[:div.is-pulled-right
|
|
||||||
[:div
|
|
||||||
extended-first-page-button
|
|
||||||
(apply list (subvec all-buttons first-page-button last-page-button))
|
|
||||||
|
|
||||||
extended-last-page-button]]
|
|
||||||
))
|
|
||||||
|
|
||||||
(defn invoice-table [{:keys [id invoice-page status on-params-change vendors params]}]
|
(defn invoice-table [{:keys [id invoice-page status on-params-change vendors params]}]
|
||||||
(let [state (reagent/atom (or @params {}))]
|
(let [state (reagent/atom (or @params {}))
|
||||||
|
opc (fn [p]
|
||||||
|
(swap! state merge p)
|
||||||
|
(on-params-change p))]
|
||||||
(fn [{:keys [id invoice-page status on-params-change vendors]}]
|
(fn [{:keys [id invoice-page status on-params-change vendors]}]
|
||||||
(let [{:keys [sort-by asc]} @state
|
(let [{:keys [sort-by asc]} @state
|
||||||
{:keys [invoices start end count total]} @invoice-page]
|
{:keys [invoices start end count total]} @invoice-page]
|
||||||
[:div
|
[:div
|
||||||
[buttons-for start end count total on-params-change state]
|
[paginator {:start start :end end :count count :total total
|
||||||
|
:on-change (fn [p ]
|
||||||
|
(on-params-change (swap! state merge p)))}]
|
||||||
"Showing " (inc start) "-" end "/" total
|
"Showing " (inc start) "-" end "/" total
|
||||||
|
|
||||||
[:table.table.is-fullwidth
|
[:table.table.is-fullwidth
|
||||||
[:thead
|
[:thead
|
||||||
[:tr
|
[:tr
|
||||||
[:th {:on-click (fn [e]
|
[sorted-column {:on-sort opc
|
||||||
(on-params-change (swap! state toggle-sort-by "vendor"))) :style {:width "25%" :cursor "pointer"}} "Vendor"
|
:style {:width "25%" :cursor "pointer"}
|
||||||
(sort-icon "vendor" sort-by asc)]
|
:sort-key "vendor"
|
||||||
[:th {:on-click (fn [e] (on-params-change (swap! state toggle-sort-by "company"))) :style {:width "25%" :cursor "pointer"}} "Company"
|
:sort-by sort-by
|
||||||
(sort-icon "company" sort-by asc)]
|
:asc asc}
|
||||||
[:th {:on-click (fn [e] (on-params-change (swap! state toggle-sort-by "invoice-number"))) :style {:width "18%" :cursor "pointer"}} "Invoice #"
|
"Vendor"]
|
||||||
(sort-icon "invoice-number" sort-by asc)]
|
[sorted-column {:on-sort opc
|
||||||
[:th {:on-click (fn [e] (on-params-change (swap! state toggle-sort-by "date"))) :style {:width "16%" :cursor "pointer"}} "Date"
|
:style {:width "25%" :cursor "pointer"}
|
||||||
(sort-icon "date" sort-by asc)]
|
:sort-key "company"
|
||||||
[:th {:on-click (fn [e] (on-params-change (swap! state toggle-sort-by "total"))) :style {:width "16%" :cursor "pointer"}} "Amount"
|
:sort-by sort-by
|
||||||
(sort-icon "total" sort-by asc)]]]
|
:asc asc}
|
||||||
|
"Company"]
|
||||||
|
[sorted-column {:on-sort opc
|
||||||
|
:style {:width "18%" :cursor "pointer"}
|
||||||
|
:sort-key "invoice-number"
|
||||||
|
:sort-by sort-by
|
||||||
|
:asc asc}
|
||||||
|
"Invoice #"]
|
||||||
|
[sorted-column {:on-sort opc
|
||||||
|
:style {:width "16%" :cursor "pointer"}
|
||||||
|
:sort-key "date"
|
||||||
|
:sort-by sort-by
|
||||||
|
:asc asc}
|
||||||
|
"Date"]
|
||||||
|
[sorted-column {:on-sort opc
|
||||||
|
:style {:width "16%" :cursor "pointer"}
|
||||||
|
:sort-key "total"
|
||||||
|
:sort-by sort-by
|
||||||
|
:asc asc}
|
||||||
|
"Amount"]]]
|
||||||
[:tbody
|
[:tbody
|
||||||
(if (:loading @status)
|
(if (:loading @status)
|
||||||
[:tr
|
[:tr
|
||||||
|
|||||||
54
src/cljs/auto_ap/views/components/paginator.cljs
Normal file
54
src/cljs/auto_ap/views/components/paginator.cljs
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
(ns auto-ap.views.components.paginator
|
||||||
|
(:require [re-frame.core :as re-frame]
|
||||||
|
[auto-ap.subs :as subs]
|
||||||
|
[auto-ap.views.utils :refer [date->str]]
|
||||||
|
[reagent.core :as reagent]
|
||||||
|
[clojure.string :as str]
|
||||||
|
[cljs-time.format :as format]))
|
||||||
|
|
||||||
|
|
||||||
|
(defn bound [x y z]
|
||||||
|
(cond
|
||||||
|
(< z x)
|
||||||
|
x
|
||||||
|
(< y x)
|
||||||
|
x
|
||||||
|
(> y z)
|
||||||
|
z
|
||||||
|
:else
|
||||||
|
y))
|
||||||
|
|
||||||
|
(defn paginator [{:keys [start end count total on-change]}]
|
||||||
|
(let [per-page 20
|
||||||
|
max-buttons 5
|
||||||
|
buttons-before (Math/floor (/ max-buttons 2))
|
||||||
|
total-pages (Math/ceil (/ total per-page))
|
||||||
|
current-page (Math/floor (/ start per-page))
|
||||||
|
first-page-button (bound 0 (- current-page buttons-before) (- total-pages max-buttons))
|
||||||
|
all-buttons (into [] (for [x (range total-pages)]
|
||||||
|
^{:key x}
|
||||||
|
[:li
|
||||||
|
[:a.pagination-link {:class (when (= current-page x)
|
||||||
|
"is-current")
|
||||||
|
:on-click (fn [e] (on-change {:start (* x per-page)}))}
|
||||||
|
(inc x)]]))
|
||||||
|
|
||||||
|
|
||||||
|
last-page-button (Math/min total-pages (+ max-buttons first-page-button))
|
||||||
|
|
||||||
|
extended-last-page-button (when (not= last-page-button total-pages)
|
||||||
|
(list
|
||||||
|
[:li [:span.pagination-ellipsis "…"]]
|
||||||
|
(last all-buttons)))
|
||||||
|
|
||||||
|
extended-first-page-button (when (not= first-page-button 0)
|
||||||
|
(list
|
||||||
|
(first all-buttons)
|
||||||
|
[:li [:span.pagination-ellipsis "…"]]))]
|
||||||
|
|
||||||
|
|
||||||
|
[:nav.pagination {:role "pagination"}
|
||||||
|
[:ul.pagination-list
|
||||||
|
extended-first-page-button
|
||||||
|
(apply list (subvec all-buttons first-page-button last-page-button))
|
||||||
|
extended-last-page-button]]))
|
||||||
33
src/cljs/auto_ap/views/components/sorter.cljs
Normal file
33
src/cljs/auto_ap/views/components/sorter.cljs
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
(ns auto-ap.views.components.sorter
|
||||||
|
(:require [re-frame.core :as re-frame]
|
||||||
|
[auto-ap.subs :as subs]
|
||||||
|
[auto-ap.views.utils :refer [date->str]]
|
||||||
|
[reagent.core :as reagent]
|
||||||
|
[clojure.string :as str]
|
||||||
|
[cljs-time.format :as format]))
|
||||||
|
(defn toggle-sort-by [params key]
|
||||||
|
|
||||||
|
(-> params
|
||||||
|
(assoc :sort-by key)
|
||||||
|
(update :asc not)))
|
||||||
|
|
||||||
|
(defn sort-icon [which sort-by asc]
|
||||||
|
(cond
|
||||||
|
(and (= sort-by which) asc)
|
||||||
|
[:span.icon
|
||||||
|
[:i.fa.fa-sort-up]]
|
||||||
|
|
||||||
|
(and (= sort-by which) (not asc))
|
||||||
|
[:span.icon
|
||||||
|
[:i.fa.fa-sort-down]]
|
||||||
|
|
||||||
|
:else
|
||||||
|
[:span.icon
|
||||||
|
[:i.fa.fa-sort]]))
|
||||||
|
|
||||||
|
(defn sorted-column [{:keys [on-sort sort-key sort-by asc style]} & rest]
|
||||||
|
|
||||||
|
[:th {:on-click (fn [e] (on-sort (toggle-sort-by {:asc asc} sort-key)))
|
||||||
|
:style style}
|
||||||
|
rest
|
||||||
|
(sort-icon sort-key sort-by asc)])
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
(ns auto-ap.views.pages.admin.reminders
|
(ns auto-ap.views.pages.admin.reminders
|
||||||
(:require-macros [cljs.core.async.macros :refer [go]])
|
(:require-macros [cljs.core.async.macros :refer [go]])
|
||||||
(:require [re-frame.core :as re-frame]
|
(:require [re-frame.core :as re-frame]
|
||||||
|
[auto-ap.views.components.paginator :refer [paginator]]
|
||||||
|
[auto-ap.views.components.sorter :refer [sorted-column]]
|
||||||
[reagent.core :as reagent]
|
[reagent.core :as reagent]
|
||||||
[auto-ap.subs :as subs]
|
[auto-ap.subs :as subs]
|
||||||
[auto-ap.events.admin.reminders :as events]
|
[auto-ap.events.admin.reminders :as events]
|
||||||
@@ -10,16 +12,70 @@
|
|||||||
[auto-ap.routes :as routes]
|
[auto-ap.routes :as routes]
|
||||||
[bidi.bidi :as bidi]))
|
[bidi.bidi :as bidi]))
|
||||||
|
|
||||||
|
(re-frame/reg-sub
|
||||||
|
::reminder-page
|
||||||
|
(fn [db]
|
||||||
|
(::reminder-page db)))
|
||||||
|
|
||||||
|
(re-frame/reg-sub
|
||||||
|
::reminder-params
|
||||||
|
(fn [db]
|
||||||
|
(::reminder-params db)))
|
||||||
|
|
||||||
|
(re-frame/reg-event-fx
|
||||||
|
::mounted
|
||||||
|
(fn [{:keys [db]} _]
|
||||||
|
{:db (assoc db ::reminder-params {:start 0})
|
||||||
|
:dispatch [::invalidated]}))
|
||||||
|
|
||||||
|
(re-frame/reg-event-fx
|
||||||
|
::params-changed
|
||||||
|
(fn [{:keys [db]} [_ params]]
|
||||||
|
{:db (update db ::reminder-params merge params)
|
||||||
|
:dispatch [::invalidated]}))
|
||||||
|
|
||||||
|
(re-frame/reg-event-fx
|
||||||
|
::invalidated
|
||||||
|
(fn [{:keys [db]}]
|
||||||
|
{:graphql {:token (:user db)
|
||||||
|
:query-obj {:venia/queries [[:reminder_page
|
||||||
|
(::reminder-params db)
|
||||||
|
|
||||||
|
[[:reminders [:id :email :sent :scheduled :subject :body [:vendor [:name :id]] ]]
|
||||||
|
:total
|
||||||
|
:start
|
||||||
|
:end]]]}
|
||||||
|
|
||||||
|
:on-success [::received]}}))
|
||||||
|
|
||||||
|
|
||||||
|
(re-frame/reg-event-db
|
||||||
|
::received
|
||||||
|
(fn [db [_ reminders]]
|
||||||
|
(assoc db ::reminder-page (first (:reminder-page reminders)))))
|
||||||
|
|
||||||
(defn reminders-table []
|
(defn reminders-table []
|
||||||
(let [reminders (or @(re-frame/subscribe [::subs/reminders]) [])]
|
(let [{:keys [reminders start end total count]} @(re-frame/subscribe [::reminder-page])
|
||||||
|
{:keys [sort-by asc]} @(re-frame/subscribe [::reminder-params])
|
||||||
|
reminders (or reminders [])]
|
||||||
|
[:div
|
||||||
|
[:div.is-pulled-right
|
||||||
|
[paginator {:start start :end end :total total :count count :on-change (fn [params]
|
||||||
|
(re-frame/dispatch [::params-changed params]))}]]
|
||||||
[:table {:class "table", :style {:width "100%"}}
|
[:table {:class "table", :style {:width "100%"}}
|
||||||
[:thead
|
[:thead
|
||||||
[:tr
|
[:tr
|
||||||
[:th "Vendor"]
|
(for [[sort-key name] [["vendor" "Vendor"]
|
||||||
[:th "Scheduled Date"]
|
["scheduled" "Scheduled Date"]
|
||||||
[:th "Status"]
|
["sent" "Status"]
|
||||||
[:th "Email"]]]
|
["email" "Email"]]]
|
||||||
|
^{:key name}
|
||||||
|
[sorted-column {:on-sort (fn [params] (re-frame/dispatch [::params-changed params]))
|
||||||
|
:style {:width "20%" :cursor "pointer"}
|
||||||
|
:sort-key sort-key
|
||||||
|
:sort-by sort-by
|
||||||
|
:asc asc}
|
||||||
|
name])]]
|
||||||
[:tbody (for [{:keys [id vendor scheduled sent email ]} reminders]
|
[:tbody (for [{:keys [id vendor scheduled sent email ]} reminders]
|
||||||
^{:key id}
|
^{:key id}
|
||||||
[:tr
|
[:tr
|
||||||
@@ -27,7 +83,7 @@
|
|||||||
[:td (date->str scheduled)]
|
[:td (date->str scheduled)]
|
||||||
[:td (when sent
|
[:td (when sent
|
||||||
[:span [:span.icon [:i.fa.fa-check]] "Sent " (date-time->str sent)]) ]
|
[:span [:span.icon [:i.fa.fa-check]] "Sent " (date-time->str sent)]) ]
|
||||||
[:td email]])]]))
|
[:td email]])]]]))
|
||||||
|
|
||||||
|
|
||||||
(defn admin-reminders-page []
|
(defn admin-reminders-page []
|
||||||
@@ -37,4 +93,4 @@
|
|||||||
[:h1.title "Reminders"]
|
[:h1.title "Reminders"]
|
||||||
[reminders-table]])
|
[reminders-table]])
|
||||||
{:component-did-mount (fn []
|
{:component-did-mount (fn []
|
||||||
(re-frame/dispatch [::events/mounted]))})])
|
(re-frame/dispatch [::mounted]))})])
|
||||||
|
|||||||
@@ -18,8 +18,9 @@
|
|||||||
|
|
||||||
(defn dispatch-event [event]
|
(defn dispatch-event [event]
|
||||||
(fn [e]
|
(fn [e]
|
||||||
|
(when (.-stopPropagation e)
|
||||||
(.stopPropagation e)
|
(.stopPropagation e)
|
||||||
(.preventDefault e)
|
(.preventDefault e))
|
||||||
(re-frame/dispatch event)))
|
(re-frame/dispatch event)))
|
||||||
|
|
||||||
(def pretty-long (format/formatter "MM/dd/yyyy HH:mm:ss"))
|
(def pretty-long (format/formatter "MM/dd/yyyy HH:mm:ss"))
|
||||||
@@ -33,8 +34,6 @@
|
|||||||
(when d
|
(when d
|
||||||
(format/unparse pretty-long d)))
|
(format/unparse pretty-long d)))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
(defmulti do-bind (fn [_ {:keys [type]}]
|
(defmulti do-bind (fn [_ {:keys [type]}]
|
||||||
type))
|
type))
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user