diff --git a/resources/public/css/main.css b/resources/public/css/main.css index f3714bac..6d2f8ba6 100644 --- a/resources/public/css/main.css +++ b/resources/public/css/main.css @@ -487,3 +487,11 @@ table.balance-sheet th.total { border-right-color: transparent; border-top-color: transparent; } + +.loader.is-table-loader { + height: 30px !important; + width: 30px !important; + border: 2px solid #00d1b2; + border-right-color: transparent; + border-top-color: transparent; +} diff --git a/src/cljs/auto_ap/views/components/grid.cljs b/src/cljs/auto_ap/views/components/grid.cljs new file mode 100644 index 00000000..1a856cea --- /dev/null +++ b/src/cljs/auto_ap/views/components/grid.cljs @@ -0,0 +1,154 @@ +(ns auto-ap.views.components.grid + (:require [reagent.core :as r])) + +(defn toggle-sort-by [params sort-key sort-name] + (let [[found? sort] (reduce + (fn [[found? sort] sort-item] + (if (= sort-key (:sort-key sort-item)) + [true (conj sort + (update sort-item :asc not))] + [found? (conj sort sort-item)])) + [false []] + (:sort params)) + sort (if found? + sort + (conj sort {:sort-key sort-key + :sort-name sort-name + :asc true}))] + + (-> params + (assoc :sort sort)))) + +(defn sort-icon [which sort] + (let [sort-item (first (filter #(= which (:sort-key %)) sort))] + (cond + (and sort-item (:asc sort-item)) + [:span.icon + [:i.fa.fa-sort-up]] + + (and sort-item (not (:asc sort-item))) + [:span.icon + [:i.fa.fa-sort-down]] + + :else + [:span.icon + [:i.fa.fa-sort]]))) + +(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 100 + 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 + ^ {:key -1} [:li [:span.pagination-ellipsis "…"]] + ^ {:key -2} (last all-buttons))) + + extended-first-page-button (when (not= first-page-button 0) + (list + ^{:key -1} (first all-buttons) + ^{:key -2} [: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 + "Showing " (Math/min (inc start) total) "-" end "/" total]])) + +(defn sort-by-list [{:keys [sort on-change]}] + [:div.field.is-grouped.is-grouped-multiline + (for [{:keys [sort-key sort-name asc]} sort] + ^{:key sort-key} + [:div.control + [:div.tags.has-addons + [:div.tag.is-medium [:span.icon (if asc + [:i.fa.fa-sort-up] + [:i.fa.fa-sort-down])] + [:span sort-name] ] + [:a.tag.is-medium.is-delete {:on-click (fn [] + (on-change {:sort (filter #(not= sort-key (:sort-key %)) sort)}))}]]])]) + +(defn grid [{:keys [on-params-change params status column-count]}] + {:grid-container (fn grid-container [{:keys [start end count total]}] + (into [:div + [:div.level + [:div.level-left + [:div.level-item + [paginator {:start start :end end :count count :total total + :on-change on-params-change}]] + [:div.level-item + [sort-by-list {:sort (:sort @params) + :on-change on-params-change}]]]]] + (r/children (r/current-component)))) + :table (fn table [] + (r/create-class {:reagent-render + (fn [{:keys [fullwidth]}] + (into + [:table.table.compact {:class (if fullwidth + ["is-fullwidth"])}] + (r/children (r/current-component))))})) + :table-header (fn table-head [] + (r/create-class {:reagent-render + (fn [{:keys []}] + (into + [:thead] + (r/children (r/current-component))))})) + :table-header-cell (fn table-header-cell [{:keys [style class]}] + (into [:th {:style style + :class class}] + (r/children (r/current-component)))) + + :table-row (fn table-row [{:keys [class]}] + (into [:tr {:class class}] + (r/children (r/current-component)))) + :table-cell (fn table-cell [params] + (into [:td params] + (r/children (r/current-component)))) + :table-body (fn table-body [] + (if (:loading @status) + [:tbody + [:tr + [:td {:col-span column-count} + [:div.container + [:div.columns.is-centered + [:div.column.is-narrow + [:div.loader.is-loading.is-active.is-table-loader.is-centered]]]]] + ]] + (into [:tbody] + (r/children (r/current-component))))) + :table-sortable-header-cell (fn table-sortable-header-cell [{:keys [style class sort-key sort-name asc]}] + (conj (into + [:th {:on-click (fn [e] + (on-params-change + (toggle-sort-by {:sort (:sort @params)} sort-key sort-name))) + :style (assoc style + :cursor "pointer") + :class class}] + (r/children (r/current-component))) + (sort-icon sort-key (:sort @params))))}) diff --git a/src/cljs/auto_ap/views/pages/admin/rules.cljs b/src/cljs/auto_ap/views/pages/admin/rules.cljs index 491299cc..8d934add 100644 --- a/src/cljs/auto_ap/views/pages/admin/rules.cljs +++ b/src/cljs/auto_ap/views/pages/admin/rules.cljs @@ -67,10 +67,12 @@ :<- [::last-params] :<- [::subs/client] :<- [::side-bar/filter-params] + :<- [::table/table-params] (fn [[last-params client filter-params table-params]] (let [params (cond-> {} client (assoc :client-id (:id client)) - (seq filter-params) (merge filter-params))] + (seq filter-params) (merge filter-params) + (seq table-params) (merge table-params))] (when (not= params last-params) (re-frame/dispatch [::params-change])) params))) @@ -117,6 +119,7 @@ :rule-page (re-frame/subscribe [::page]) :status (re-frame/subscribe [::subs/status]) :on-params-change (fn [params] + (println "CHANGING PARAMS TO" params) (re-frame/dispatch [::params-change params]))}] ])) {:component-will-mount #(do (re-frame/dispatch-sync [::params-change {}]) diff --git a/src/cljs/auto_ap/views/pages/admin/rules/table.cljs b/src/cljs/auto_ap/views/pages/admin/rules/table.cljs index b222e2c1..699a8e0b 100644 --- a/src/cljs/auto_ap/views/pages/admin/rules/table.cljs +++ b/src/cljs/auto_ap/views/pages/admin/rules/table.cljs @@ -5,8 +5,11 @@ [auto-ap.views.components.paginator :refer [paginator]] [auto-ap.views.components.sort-by-list :refer [sort-by-list]] [auto-ap.views.pages.admin.rules.results-modal :as results-modal] - [auto-ap.views.components.sorter :refer [sorted-column]] - [re-frame.core :as re-frame])) + [auto-ap.views.components.sorter :refer [sorted-column toggle-sort-by sort-icon]] + [auto-ap.views.components.grid :refer [grid]] + [re-frame.core :as re-frame] + [reagent.core :as reagent] + [reagent.core :as r])) (re-frame/reg-event-fx ::run-clicked @@ -33,94 +36,90 @@ (fn [{:keys [db]} [_ transaction-rule-id result]] {:dispatch [::results-modal/opening (:run-transaction-rule result) transaction-rule-id true]})) +(re-frame/reg-sub + ::specific-table-params + (fn [db] + (::table-params db))) + +(re-frame/reg-sub + ::table-params + :<- [::specific-table-params] + :<- [::subs/query-params] + (fn [[specific-table-params query-params]] + (merge (select-keys query-params #{:start :sort}) specific-table-params ))) + +(re-frame/reg-event-fx + ::params-changed + [(re-frame/path [::table-params])] + (fn [{table-params :db} [_ params :as z]] + {:db (merge table-params params)})) + + + (defn table [{:keys [id rule-page on-params-change params status]}] (let [opc (fn [p] - (on-params-change (merge @params p )))] - (fn [{:keys [id rule-page on-params-change params status]}] - (let [{:keys [sort asc]} @params - {:keys [transaction-rules start end count total]} @rule-page - selected-client @(re-frame/subscribe [::subs/client])] - [:div - [:div.level - [:div.level-left - [:div.level-item - [paginator {:start start :end end :count count :total total - :on-change (fn [p ] - (on-params-change (merge @params p)))}]] - [:div.level-item - [sort-by-list {:sort sort - :on-change opc}]]]] - [:table.table.is-fullwidth.compact - [:thead - [:tr - [sorted-column {:on-sort opc - :style {:width "25%" :cursor "pointer"} - :sort-key "client" - :sort-name "Client" - :sort sort} - "Client"] + (re-frame/dispatch [::params-changed p])) + {:keys [table-sortable-header-cell + table + table-header + table-row + table-header-cell + table-body + table-cell + grid-container]} + (grid {:on-params-change opc + :params (re-frame/subscribe [::table-params]) + :status status + :column-count 5})] + (fn [] + (let [] + (fn [{:keys [id rule-page on-params-change params status]}] + (let [{:keys [sort asc]} @params + {:keys [transaction-rules start end count total]} @rule-page + selected-client @(re-frame/subscribe [::subs/client])] + [grid-container {:start start :end end :count count :total total} + [table {:fullwidth true } + [table-header + [table-row {} + [table-sortable-header-cell {:sort-key "client" + :sort-name "Client"} + "Client"] - [sorted-column {:on-sort opc - :style {:width "25%" :cursor "pointer"} - :sort-key "bank-account" - :sort-name "Bank Account" - :sort sort} - "Bank Account"] + [table-sortable-header-cell {:sort-key "bank-account" + :sort-name "Bank Account"} + "Bank Account"] - [sorted-column {:on-sort opc - :style {:width "25%" :cursor "pointer"} - :sort-key "description" - :sort-name "Description" - :sort sort} - "Description"] + [table-sortable-header-cell {:sort-key "description" + :sort-name "Description"} + "Description"] - #_[sorted-column {:on-sort opc - :style {:width "8em" :cukjsor "pointer"} - :class "has-text-right" - :sort-key "amount-gte" - :sort sort} - "Amount"] - [:th.has-text-right {:style {:width "12em"}} "Amount"] - #_[sorted-column {:on-sort opc - :class "has-text-right" - :style {:width "8em" :cursor "pointer"} - :sort-key "amount-lte" - :sort sort} - "<="] + [table-header-cell {:style {:width "12em"}} "Amount"] - [sorted-column {:on-sort opc - :style {:width "25%" :cursor "pointer"} - :sort-key "note" - :sort-name "Note" - :sort sort} - "Note"] - [:th {:style {:width "9em"}} - ]]] - [:tbody - (if (:loading @status) - [:tr - [:td {:col-span 5} - [:i.fa.fa-spin.fa-spinner]]] - (for [{:keys [client bank-account description amount-lte amount-gte note id] :as r} transaction-rules] - ^{:key id} - [:tr {:class (:class r)} - [:td (:name client)] - [:td (:name bank-account)] - [:td description] - [:td.has-text-right - (cond (and amount-gte amount-lte) - (str (->$ amount-gte) " - " (->$ amount-lte)) + [table-sortable-header-cell {:sort-key "note" + :sort-name "Note"} + "Note"] - amount-gte - (str ">=" (->$ amount-gte)) + [table-header-cell {:style {:width "9em"}}]]] + [table-body + (for [{:keys [client bank-account description amount-lte amount-gte note id] :as r} transaction-rules] + ^{:key id} + [table-row {:class (:class r)} + [table-cell {} (:name client)] + [table-cell {} (:name bank-account)] + [table-cell {} description] + [table-cell {:class "has-text-right"} + (cond (and amount-gte amount-lte) + (str (->$ amount-gte) " - " (->$ amount-lte)) - amount-lte - (str "<=" (->$ amount-lte)) + amount-gte + (str ">=" (->$ amount-gte)) - :else - "")] - [:td note] - [:td - [:div.buttons - [:a.button {:on-click (dispatch-event [::run-clicked r])} [:span.icon [:i.fa.fa-play]]] - [:a.button {:on-click (dispatch-event [::form/editing r])} [:span.icon [:i.fa.fa-pencil]]]]]]))]]])))) + amount-lte + (str "<=" (->$ amount-lte)) + + :else + "")] + [table-cell {} note] + [table-cell {} [:div.buttons + [:a.button {:on-click (dispatch-event [::run-clicked r])} [:span.icon [:i.fa.fa-play]]] + [:a.button {:on-click (dispatch-event [::form/editing r])} [:span.icon [:i.fa.fa-pencil]]]]]])]]]))))))