use counter for loading

This commit is contained in:
Daniel O'Connell 2021-03-11 19:41:02 +01:00
parent 67464f1d46
commit c9c0b5f4bd
6 changed files with 340 additions and 27 deletions

View File

@ -7,4 +7,4 @@
;; This tells shadow cljs what to build and should match a key in your shadow-cljs.edn
;; build map. e.g :builds {:<some-key> {...}}
;; pramas passed to shadow-cljs to start nrepl via cider-jack-in
(cider-shadow-default-options . "frontend -A:dev")))
(cider-shadow-default-options . "frontend")))

View File

@ -0,0 +1,296 @@
@keyframes spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
html {
height: 100%;
}
html body {
height: 100%;
}
html body .hidden {
display: none;
}
html body .loader-container {
position: absolute;
width: 100%;
height: 100%;
z-index: 1000;
background-color: rgba(0,0,0,0.4);
}
html body .loader-container .loader {
width: 30px;
top: 40%;
height: 30px;
margin: auto;
border: 5px solid #f3f3f3;
position: relative;
animation: spin 1s linear infinite;
border-top: 5px solid #3498db;
border-radius: 50%;
}
html body .full-height {
height: 100%;
}
html body .scroll-bar {
position: absolute;
right: 10px;
width: 50px;
}
html body .scroll-bar #scroll-down {
position: fixed;
right: 0;
bottom: 0;
}
html body .popup {
position: fixed;
height: 100%;
width: 100%;
overflow: auto;
z-index: 1;
background-color: rgba(0,0,0,0.4);
}
html body .popup .popup-content {
background-color: #fefefe;
margin: 15% auto;
padding: 20px;
border: 1px solid #888;
width: 15%;
}
html body .popup .popup-content .input-item label {
min-width: 60px;
display: inline-block;
}
html body .popup .popup-content ..popup-form-buttons {
margin: 10px;
}
html body .popup .popup-content ..popup-form-buttons * {
margin: 20px;
}
html body .scroll-button {
display: none;
}
@media (max-width: 800px) {
html body .scroll-bar {
display: none;
}
html body .menu-button {
width: 100%;
font-size: 3em;
display: inherit;
}
html body .popup .popup-content {
background-color: #fefefe;
margin: 3% auto;
padding: 20px;
border: 1px solid #888;
width: 60%;
}
html body .popup .popup-content .product-items-edit {
margin-top: 1.5em;
}
html body .popup .popup-content .product-items-edit .product-item-edit label {
display: none;
}
html body .calendar .day {
min-height: 12em;
}
}
@media (min-width: 800px) {
html body .popup .popup-content {
background-color: #fefefe;
margin: 15% auto;
padding: 20px;
border: 1px solid #888;
width: 15%;
}
html body .calendar {
display: grid;
grid-template-columns: 25% 25% 25% 25%;
grid-template-rows: 50% 50%;
}
}
@media (min-width: 1200px) {
html body .calendar {
display: grid;
grid-template-columns: 14% 14% 14% 14% 14% 14% 14%;
grid-template-rows: 50% 50%;
}
}
html body .calendar .day-header {
border: 2px solid black;
text-align: center;
font-size: 2em;
}
html body .calendar .day.today {
border: 0.4em solid red;
}
html body .calendar .day {
border: 2px solid black;
overflow: auto;
}
html body .calendar .day .day-header {
border: none;
border-bottom: 2px solid black;
}
html body .calendar .day .orders {
padding-left: 25px;
}
html body .calendar .day .orders .actions {
display: none;
float: right;
}
html body .calendar .day .orders .order:hover .actions {
display: inline;
}
html body .calendar .day .orders .order.pending {
color: grey;
}
html body .calendar .day .orders .order.fulfilled {
color: red;
}
html body .calendar .day .orders .who {
font-size: 18px;
font-weight: bold;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
html body .calendar .day .product {
margin-bottom: 5px;
}
html body .calendar .day .product .product-name {
width: 5em;
display: inline-block;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
margin-right: 10px;
}
html body .calendar .day .product .product-amount {
width: 40px;
max-height: 5px;
}
html body .calendar .day .summary {
margin-top: 10px;
}
html body .stock-modal .add-product {
float: right;
}
html body .stock-modal .stock-product {
margin: 1em 0;
}
html body .stock-modal .stock-product .product-name {
display: inline-block;
width: 6em;
}
html body .stock-modal .stock-product .stock-product-amount {
display: inline-block;
}
html body .stock-modal .stock-product .stock-product-amount .input-item {
display: inline;
}
html body .stock-modal .stock-product .stock-product-amount .input-item input {
width: 40px;
}
html body .stock-modal .stock-product .stock-product-amount .input-item label {
display: none;
}
html body .customers-modal details {
padding: 0.5em;
}
html body .customers-modal details.customer-order {
margin-left: 1em;
padding: 0.5em;
}
html body .customers-modal details.customer-order .order-date-picker {
display: inline-block;
width: 75%;
cursor: pointer;
}
html body .customers-modal details.customer-order .product-item-edit {
margin-left: 1em;
}
input::-webkit-outer-spin-button {
-webkit-appearance: none;
margin: 0;
}
input::-webkit-inner-spin-button {
-webkit-appearance: none;
margin: 0;
}
input[type=number] {
-moz-appearance: textfield;
}

View File

@ -33,7 +33,10 @@
:editable-number-inputs (get-setting :editable-number-inputs false) ; only allow number modifications in the edit modal
:hide-fulfilled-orders (get-setting :hide-fulfilled-orders false)
:backend-url (get-setting :backend-url (str (.. js/window -location -href) "api/")) ; "http://localhost:3000/"
:backend-url (get-setting :backend-url
(if (= (.. js/window -location -href) "http://localhost:8280/")
"http://localhost:3000/api/"
(str (.. js/window -location -href) "api/")))
})

View File

@ -50,8 +50,8 @@
[:dispatch [::fetch-orders]]]}))
(re-frame/reg-event-db ::hide-modal (fn [db [_ modal]] (assoc-in db [modal :show] nil)))
(re-frame/reg-event-db ::start-loading (fn [db _] (assoc db :loading? true)))
(re-frame/reg-event-db ::stop-loading (fn [db _] (assoc db :loading? nil)))
(re-frame/reg-event-db ::start-loading (fn [db _] (update db :loading? inc)))
(re-frame/reg-event-db ::stop-loading (fn [db _] (update db :loading? dec)))
(re-frame/reg-event-fx
::confirm-action
@ -68,10 +68,9 @@
(re-frame/reg-event-fx
::failed-request
(fn [{db :db} [_ response]]
{:db (-> db
(assoc :loading? false)
(update :current-user #(when-not (= (:status response) 401) %)))
:dispatch [::log-error (str response)]}))
{:db (update db :current-user #(when-not (= (:status response) 401) %))
:fx [[:dispatch [::log-error (str response)]]
[:dispatch [::stop-loading]]]}))
(re-frame/reg-event-fx
::remove-order
@ -114,15 +113,15 @@
(select-keys order [:id :day :hour :state])
(select-keys form [:id :day :hour :state :who :notes :products])))}))
(re-frame/reg-event-db
(re-frame/reg-event-fx
::process-fetched-days
(fn [db [_ days]]
(-> db
(assoc :loading? nil)
(fn [{db :db} [_ days]]
{:db (-> db
(update :current-days (fn [current-days]
(for [[day orders] current-days]
[day (if (contains? days day) (days day) orders)])))
(update :orders #(reduce (fn [m order] (assoc m (:id order) order)) % (mapcat second days))))))
(update :orders #(reduce (fn [m order] (assoc m (:id order) order)) % (mapcat second days))))
:dispatch [::stop-loading]}))
(re-frame/reg-event-fx
::scroll-weeks
@ -134,16 +133,16 @@
(time/date-offset (* 7 offset))
time/iso-date)]]]}))
(re-frame/reg-event-db
(re-frame/reg-event-fx
::show-from-date
(fn [{:keys [start-date orders] :as db} [_ day]]
(fn [{{:keys [start-date orders] :as db} :db} [_ day]]
(let [day (or day start-date)
days (into #{} (time/get-weeks day 2))
filtered-orders (->> orders vals (filter (comp days :day)) (group-by :day))]
(assoc db
:loading? nil
{:db (assoc db
:start-date day
:current-days (map #(vector % (get filtered-orders %)) (sort days))))))
:current-days (map #(vector % (get filtered-orders %)) (sort days)))
:dispatch [::stop-loading]})))
(re-frame/reg-event-fx
::fetch-orders

View File

@ -4,7 +4,7 @@
(re-frame/reg-sub ::name (fn [db] (:name db)))
(re-frame/reg-sub ::current-user (fn [db] (:current-user db)))
(re-frame/reg-sub ::settings (fn [db] (:settings db)))
(re-frame/reg-sub ::loading? (fn [db] (:loading? db)))
(re-frame/reg-sub ::loading? (fn [db] (-> db :loading? pos?)))
(re-frame/reg-sub ::available-products (fn [db] (:products db)))
(re-frame/reg-sub ::available-customers (fn [db] (:customers db)))

View File

@ -55,7 +55,7 @@
(testing "loader gets set"
(rf-test/run-test-sync
(set-db {:loading? nil})
(is (nil? @(rf/subscribe [::subs/loading?])))
(is (not @(rf/subscribe [::subs/loading?])))
(rf/dispatch [::sut/start-loading])
(is @(rf/subscribe [::subs/loading?]))))
@ -64,7 +64,22 @@
(set-db {:loading? true})
(is @(rf/subscribe [::subs/loading?]))
(rf/dispatch [::sut/stop-loading])
(is (nil? @(rf/subscribe [::subs/loading?]))))))
(is (not @(rf/subscribe [::subs/loading?])))))
(testing "multiple loads handled"
(rf-test/run-test-sync
(is (not @(rf/subscribe [::subs/loading?])))
(rf/dispatch [::sut/start-loading])
(rf/dispatch [::sut/start-loading])
(rf/dispatch [::sut/start-loading])
(is @(rf/subscribe [::subs/loading?]))
(rf/dispatch [::sut/stop-loading])
(is @(rf/subscribe [::subs/loading?]))
(rf/dispatch [::sut/stop-loading])
(rf/dispatch [::sut/stop-loading])
(is (not @(rf/subscribe [::subs/loading?]))))))
(deftest confirm-action-test
(testing "when confirmed, the provided event is called"
@ -212,7 +227,7 @@
(set-db {:orders {} :current-days {} :loading? true})
(rf/dispatch [::sut/process-fetched-days {}])
(is (nil? @(rf/subscribe [::subs/loading?])))))
(is (not @(rf/subscribe [::subs/loading?])))))
(testing "orders get set correctly"
(rf-test/run-test-sync
@ -270,7 +285,7 @@
(set-db {:orders {} :current-days {} :loading? true})
(rf/dispatch [::sut/show-from-date "2020-01-01"])
(is (nil? @(rf/subscribe [::subs/loading?])))))
(is (not @(rf/subscribe [::subs/loading?])))))
(testing "showing from date works"
(rf-test/run-test-sync