diff --git a/src/cljs/auto_ap/effects.cljs b/src/cljs/auto_ap/effects.cljs index 4c759f00..bfb03d5d 100644 --- a/src/cljs/auto_ap/effects.cljs +++ b/src/cljs/auto_ap/effects.cljs @@ -35,15 +35,10 @@ (and (string? node) (re-matches is-8601 node)) - (do - (println node) - (format/parse (format/formatters :date-time) node)) + (format/parse (format/formatters :date-time) node) (instance? js/Date node) - (do - (println node) - (time/to-default-time-zone (c/from-date node))) - + (time/to-default-time-zone (c/from-date node)) :else node)) diff --git a/src/cljs/auto_ap/events/admin/reminders.cljs b/src/cljs/auto_ap/events/admin/reminders.cljs index 43931211..33bdefee 100644 --- a/src/cljs/auto_ap/events/admin/reminders.cljs +++ b/src/cljs/auto_ap/events/admin/reminders.cljs @@ -4,22 +4,4 @@ [auto-ap.routes :as routes] [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)))))) - diff --git a/src/cljs/auto_ap/subs.cljs b/src/cljs/auto_ap/subs.cljs index 2012c492..a1909f50 100644 --- a/src/cljs/auto_ap/subs.cljs +++ b/src/cljs/auto_ap/subs.cljs @@ -24,11 +24,6 @@ (fn [db] (:user db))) -(re-frame/reg-sub - ::reminders - (fn [db] - (:reminders db))) - (re-frame/reg-sub ::vendors (fn [db] diff --git a/src/cljs/auto_ap/views/components/invoice_table.cljs b/src/cljs/auto_ap/views/components/invoice_table.cljs index ad36c7f5..338ef67b 100644 --- a/src/cljs/auto_ap/views/components/invoice_table.cljs +++ b/src/cljs/auto_ap/views/components/invoice_table.cljs @@ -2,29 +2,15 @@ (:require [re-frame.core :as re-frame] [auto-ap.subs :as subs] [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] [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 query [params] {:venia/queries [[:invoice_page @@ -35,72 +21,55 @@ :start :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]}] - (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]}] (let [{:keys [sort-by asc]} @state {:keys [invoices start end count total]} @invoice-page] [: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 [:table.table.is-fullwidth [:thead [:tr - [:th {:on-click (fn [e] - (on-params-change (swap! state toggle-sort-by "vendor"))) :style {:width "25%" :cursor "pointer"}} "Vendor" - (sort-icon "vendor" sort-by asc)] - [:th {:on-click (fn [e] (on-params-change (swap! state toggle-sort-by "company"))) :style {:width "25%" :cursor "pointer"}} "Company" - (sort-icon "company" sort-by asc)] - [:th {:on-click (fn [e] (on-params-change (swap! state toggle-sort-by "invoice-number"))) :style {:width "18%" :cursor "pointer"}} "Invoice #" - (sort-icon "invoice-number" sort-by asc)] - [:th {:on-click (fn [e] (on-params-change (swap! state toggle-sort-by "date"))) :style {:width "16%" :cursor "pointer"}} "Date" - (sort-icon "date" sort-by asc)] - [:th {:on-click (fn [e] (on-params-change (swap! state toggle-sort-by "total"))) :style {:width "16%" :cursor "pointer"}} "Amount" - (sort-icon "total" sort-by asc)]]] + [sorted-column {:on-sort opc + :style {:width "25%" :cursor "pointer"} + :sort-key "vendor" + :sort-by sort-by + :asc asc} + "Vendor"] + [sorted-column {:on-sort opc + :style {:width "25%" :cursor "pointer"} + :sort-key "company" + :sort-by sort-by + :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 (if (:loading @status) [:tr diff --git a/src/cljs/auto_ap/views/components/paginator.cljs b/src/cljs/auto_ap/views/components/paginator.cljs new file mode 100644 index 00000000..c6e9fdc4 --- /dev/null +++ b/src/cljs/auto_ap/views/components/paginator.cljs @@ -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]])) diff --git a/src/cljs/auto_ap/views/components/sorter.cljs b/src/cljs/auto_ap/views/components/sorter.cljs new file mode 100644 index 00000000..13502ae6 --- /dev/null +++ b/src/cljs/auto_ap/views/components/sorter.cljs @@ -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)]) diff --git a/src/cljs/auto_ap/views/pages/admin/reminders.cljs b/src/cljs/auto_ap/views/pages/admin/reminders.cljs index 45f3aec0..5fa80c02 100644 --- a/src/cljs/auto_ap/views/pages/admin/reminders.cljs +++ b/src/cljs/auto_ap/views/pages/admin/reminders.cljs @@ -1,6 +1,8 @@ (ns auto-ap.views.pages.admin.reminders (:require-macros [cljs.core.async.macros :refer [go]]) (: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] [auto-ap.subs :as subs] [auto-ap.events.admin.reminders :as events] @@ -10,24 +12,78 @@ [auto-ap.routes :as routes] [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 [] - (let [reminders (or @(re-frame/subscribe [::subs/reminders]) [])] - [:table {:class "table", :style {:width "100%"}} - [:thead - [:tr - [:th "Vendor"] - [:th "Scheduled Date"] - [:th "Status"] - [:th "Email"]]] - [:tbody (for [{:keys [id vendor scheduled sent email ]} reminders] - ^{:key id} - [:tr - [:td (:name vendor)] - [:td (date->str scheduled)] - [:td (when sent - [:span [:span.icon [:i.fa.fa-check]] "Sent " (date-time->str sent)]) ] - [:td email]])]])) + (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%"}} + [:thead + [:tr + (for [[sort-key name] [["vendor" "Vendor"] + ["scheduled" "Scheduled Date"] + ["sent" "Status"] + ["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] + ^{:key id} + [:tr + [:td (:name vendor)] + [:td (date->str scheduled)] + [:td (when sent + [:span [:span.icon [:i.fa.fa-check]] "Sent " (date-time->str sent)]) ] + [:td email]])]]])) (defn admin-reminders-page [] @@ -37,4 +93,4 @@ [:h1.title "Reminders"] [reminders-table]]) {:component-did-mount (fn [] - (re-frame/dispatch [::events/mounted]))})]) + (re-frame/dispatch [::mounted]))})]) diff --git a/src/cljs/auto_ap/views/utils.cljs b/src/cljs/auto_ap/views/utils.cljs index 46517462..9de6a354 100644 --- a/src/cljs/auto_ap/views/utils.cljs +++ b/src/cljs/auto_ap/views/utils.cljs @@ -18,8 +18,9 @@ (defn dispatch-event [event] (fn [e] - (.stopPropagation e) - (.preventDefault e) + (when (.-stopPropagation e) + (.stopPropagation e) + (.preventDefault e)) (re-frame/dispatch event))) (def pretty-long (format/formatter "MM/dd/yyyy HH:mm:ss")) @@ -33,8 +34,6 @@ (when d (format/unparse pretty-long d))) - - (defmulti do-bind (fn [_ {:keys [type]}] type))