Mock requests

This commit is contained in:
Daniel O'Connell 2020-11-22 18:11:14 +01:00
parent fa69a0ed98
commit 5870093a4c
12 changed files with 279 additions and 66 deletions

View File

@ -44,6 +44,8 @@
[:.actions {:display :none
:float :right}]
[:.order:hover [:.actions {:display :inline}]]
[:.order.pending {:color :grey}]
[:.order.fulfilled {:color :red}]
[:.who {:font-size "18px"
:font-weight :bold

View File

@ -9,7 +9,7 @@
[chicken-master.time :as time]))
(defn add-order [date]
(defn edit-order []
(html/modal
[:div
(html/input :who "kto"
@ -25,14 +25,19 @@
(for [[i {product :prod amount :amount}] (map-indexed vector selected-prods)]
(prod/product-item product amount available-prods i))])
[:button {:type :button :on-click #(re-frame/dispatch [::event/add-product])} "+"]]
js/console.log))
;; On success
(fn [] (re-frame/dispatch [::event/save-order]))))
(defn format-order [{:keys [id who day hour products]}]
[:li {:class :order :key (gensym)}
(defn format-order [{:keys [id who day hour products state]}]
[:li {:class [:order state] :key (gensym)}
[:div {:class :actions}
[:button "O"]
(condp = state
:waiting [:button {:on-click #(re-frame/dispatch [::event/fulfill-order id])} "✓"]
:fulfilled [:button {:on-click #(re-frame/dispatch [::event/reset-order id])} "X"]
:pending nil
:default nil)
[:button {:on-click #(re-frame/dispatch [::event/edit-order day id])} "E"]
[:button "-"]]
[:button {:on-click #(re-frame/dispatch [::event/remove-order id])} "-"]]
[:div {:class :who} who]
(if (settings :show-order-time)
[:div {:class :when} hour])
@ -45,17 +50,21 @@
[:div {:class :day-header} (time/format-date date)]
[:div
[:ul {:class :orders}
(map format-order customers)
(if (settings :hide-fulfilled-orders)
(->> customers (remove (comp #{:fulfilled} :state)) (map format-order))
(map format-order customers))
[:button {:type :button
:on-click #(re-frame/dispatch [::event/edit-order date])} "+"]]]])
:on-click #(re-frame/dispatch [::event/edit-order (time/iso-date date)])} "+"]]]])
(defn calendar-header []
(->> (settings :day-names)
(->> (:day-names settings)
cycle (drop (:first-day-offset settings))
(take 7)
(map (fn [day] [:div {:class :day-header} day]))
(into [])))
(defn calendar [days]
(->> days
(map day)
(concat (when-not (settings :always-day-names) (calendar-header)))
(concat (when (settings :calendar-heading) (calendar-header)))
(into [:div {:class [:calendar :full-height]}])))

View File

@ -3,7 +3,13 @@
(def debug?
^boolean goog.DEBUG)
(def settings {:first-day-offset 1
:day-names ["Niedz" "Pon" "Wt" "Śr" "Czw" "Pt" "Sob"]
:always-day-names true
:show-order-time false})
(def settings {:first-day-offset 1 ; which is the first day of the week (add the offset to `day-names`)
:day-names ["Niedz" "Pon" "Wt" "Śr" "Czw" "Pt" "Sob"] ; how day should be displayed in the calendar view
:calendar-heading false ; show a header with the names of days
:show-date true ; display the date for each day
:show-day-name-with-date true ; add the day name to each date
:show-order-time false ; display the time of each order
:editable-number-inputs false ; only allow number modifications in the edit modal
:hide-fulfilled-orders false
})

View File

@ -20,6 +20,6 @@
(defn init []
(re-frame/dispatch-sync [::events/initialize-db])
(re-frame/dispatch-sync [::events/show-from-date (new js/Date "2020-09-05")])
(re-frame/dispatch-sync [::events/show-from-date (new js/Date)])
(dev-setup)
(mount-root))

View File

@ -1,31 +1,26 @@
(ns chicken-master.db)
(def default-db
{:name "re-frame"
:order-edit {:show nil
:who "mr. blobby"
:when "12:32"
:products [{:prod :eggs :amount 2}
{:prod :milk :amount 5}
{}]}
:customers {1 {:id 1 :who "mr.blobby (649 234 234)" :day "2020-10-10" :hour "02:12" :products {:eggs 2 :milk 3}}
2 {:id 2 :who "da police (0118 999 881 999 119 725 123123 12 3123 123 )" :day "2020-10-10" :hour "02:12" :products {:eggs 12}}
3 {:id 3 :who "johnny" :day "2020-10-10" :hour "02:12" :products {:eggs 5}}}
:days {"2020-09-05" [1 2 3]
"2020-09-06" [1 2 3]
"2020-09-07" [1 2 3]
"2020-09-08" [1 2 3]
"2020-09-09" [1 2 3]
"2020-09-10" [1 2 3]
"2020-09-11" [1 2 3]
"2020-09-12" [1 2 3]
"2020-09-13" [1 2 3]
"2020-09-14" [1 2 3]
"2020-09-15" [1 2 3]
"2020-09-16" [1 2 3]
"2020-09-17" [1 2 3]
"2020-09-18" [1 2 3]}
{;; set automatically
;; :customers {1 {:id 1 :who "mr.blobby (649 234 234)" :day "2020-10-10" :hour "02:12" :products {:eggs 2 :milk 3}}
;; 2 {:id 2 :who "da police (0118 999 881 999 119 725 123123 12 3123 123 )" :day "2020-10-10" :hour "02:12" :products {:eggs 12}}
;; 3 {:id 3 :who "johnny" :day "2020-10-10" :hour "02:12" :products {:eggs 5}}}
;; :days {"2020-10-05" [1 2 3]
;; "2020-10-06" [1 2 3]
;; "2020-10-07" [1 2 3]
;; "2020-10-08" [1 2 3]
;; "2020-10-09" [1 2 3]
;; "2020-10-10" [1 2 3]
;; "2020-10-11" [1 2 3]
;; "2020-10-12" [1 2 3]
;; "2020-10-13" [1 2 3]
;; "2020-10-14" [1 2 3]
;; "2020-10-15" [1 2 3]
;; "2020-10-16" [1 2 3]
;; "2020-10-17" [1 2 3]
;; "2020-10-18" [1 2 3]}
:products {:eggs {}
:milk {}
:cabbage {}
:carrots {}}})
:carrots {}}
})

View File

@ -2,11 +2,22 @@
(:require
[re-frame.core :as re-frame]
[chicken-master.db :as db]
[chicken-master.orders :as orders]
[chicken-master.time :as time]))
(re-frame/reg-event-db ::initialize-db (fn [_ _] db/default-db))
(re-frame/reg-event-db ::hide-modal (fn [db _] (assoc db :order-edit {})))
(re-frame/reg-event-fx
::remove-order
(fn [_ [_ id]]
{:http {:method :post
:url "delete-order"
:params {:id id}
:on-success [::process-fetched-days]
:on-fail [::failed-blah]}}))
(re-frame/reg-event-db
::edit-order
(fn [{customers :customers :as db} [_ day id]]
@ -16,6 +27,38 @@
(update :products (comp vec (partial map (partial zipmap [:prod :amount]))))
(merge {:show true :day day})))))
(re-frame/reg-event-fx
::fulfill-order
(fn [{db :db} [_ id]]
{:db (assoc-in db [:customers id :state] :pending)
:fx [[:dispatch [::set-current-days]]]
:http {:method :post
:url "fulfill-order"
:params {:id id}
:on-success [::process-fetched-days]
:on-fail [::failed-blah]}}))
(re-frame/reg-event-fx
::reset-order
(fn [{db :db} [_ id]]
{:db (assoc-in db [:customers id :state] :waiting)
:fx [[:dispatch [::set-current-days]]]
:http {:method :post
:url "reset-order"
:params {:id id}
:on-success [::process-fetched-days]
:on-fail [::failed-blah]}}))
(re-frame/reg-event-fx
::save-order
(fn [{{order :order-edit} :db} _]
{:fx [[:dispatch [::hide-modal]]]
:http {:method :post
:url "save-order"
:params (orders/clean-order order)
:on-success [::process-fetched-days]
:on-fail [::failed-blah]}}))
(re-frame/reg-event-db ::add-product (fn [db _] (update-in db [:order-edit :products] conj {})))
(re-frame/reg-event-db
::selected-product
@ -34,12 +77,66 @@
(get days)
(map customers))})
(re-frame/reg-event-db
::show-from-date
(fn [db [_ date]]
(->> date
::set-current-days
(fn [{start-day :start-date :as db} _]
(->> start-day
time/parse-date
time/start-of-week
(time/days-range 14)
(map (partial get-day db))
(assoc db :current-days))))
(re-frame/reg-event-fx
::process-fetched-days
(fn [{db :db} [_ days]]
(println "fetched days" days)
{:db (-> db
(update :days #(reduce-kv (fn [m k v] (assoc m k (map :id v))) % days))
(update :customers #(reduce (fn [m cust] (assoc m (:id cust) cust)) % (-> days vals flatten))))
:fx [[:dispatch [::set-current-days]]]}))
(defn missing-days
"Return a map of missing days to be fetched."
[db day]
(let [missing-days (->> day
time/parse-date
time/start-of-week
(time/days-range 28)
(remove (comp (:days db {}) time/iso-date)))]
(when (seq missing-days)
{:from (->> missing-days (sort time/before?) first time/iso-date)
:to (->> missing-days (sort time/before?) last time/iso-date)})))
(re-frame/reg-event-fx
::show-from-date
(fn [{db :db} [_ day]]
(let [missing (missing-days db day)
effects {:db (assoc db :start-date day)
:fx [[:dispatch [::set-current-days]]]}]
(if-not missing
effects
(assoc effects :http {:method :get
:url "get-days"
:params missing
:on-success [::process-fetched-days]
:on-fail [::failed-blah]})))))
(comment
(re-frame/dispatch-sync [::show-from-date "2020-11-11"])
)
;;;;;;;; Backend mocks
(re-frame/reg-fx
:http
(fn [{:keys [method url params on-success on-fail]}]
(println params)
(condp = url
"get-days" (re-frame/dispatch (conj on-success (orders/fetch-days params)))
"save-order" (re-frame/dispatch (conj on-success (orders/replace-order params)))
"delete-order" (re-frame/dispatch (conj on-success (orders/delete-order params)))
"fulfill-order" (re-frame/dispatch (conj on-success (orders/order-state (assoc params :state :fulfilled))))
"reset-order" (re-frame/dispatch (conj on-success (orders/order-state (assoc params :state :waiting))))
)))

View File

@ -16,7 +16,11 @@
(defn modal [content on-submit]
[:div {:class :popup}
[:form {:action "#" :on-submit on-submit}
[:form {:action "#"
:on-submit (fn [e]
(.preventDefault e)
(when (on-submit)
(re-frame/dispatch [::event/hide-modal])))}
content
[:div {:class :form-buttons}
[:button "add"]

View File

@ -0,0 +1,78 @@
(ns chicken-master.orders
(:require [chicken-master.time :as time]))
(defn clean-order [order]
(-> order
(update :products #(->> %
(group-by :prod)
(reduce-kv (fn [m k v]
(assoc m k (->> v
(map :amount)
(reduce +)))) {})))
(select-keys [:id :who :day :hour :products])))
;;;;;;;; Backend mocks
(def id-counter (atom -1))
(def days (atom
(->> (time/date-offset (new js/Date) -50)
(time/days-range 90)
(map (fn [date]
[(time/iso-date date) (repeatedly (rand-int 6) #(swap! id-counter inc))]))
(into {}))))
(def products (atom [:eggs :milk :cabbage :carrots]))
(def customer-names (atom ["mr.blobby (649 234 234)" "da police (0118 999 881 999 119 725 123123 12 3123 123 )" "johnny"]))
(def customers
(atom
(->> @days
(map (fn [[day ids]]
(map (fn [i]
{:id i :day day :hour "02:12" :state :waiting
:who (rand-nth @customer-names)
:products (->> @products
(random-sample 0.4)
(map #(vector % (rand-int 10)))
(into {}))
}) ids)
))
flatten
(map #(vector (:id %) %))
(into {}))))
(defn- day-customers [day] [day (->> day (get @days) (map (partial get @customers)))])
(defn- days-between [from to]
(time/days-range
(int (/ (- (time/parse-date to) (time/parse-date from)) (* 24 3600000)))
(time/parse-date from)))
(defn fetch-days [{:keys [from to]}]
(->> (days-between from to)
(map time/iso-date)
(map day-customers)
(into {})))
(defn- replace-order [order]
(println "replacing order" order)
(let [order (update order :id #(or % (swap! id-counter inc)))]
(swap! days (fn [ds] (update ds (:day order) #(distinct (conj % (:id order))))))
(swap! customers #(assoc % (:id order) order))
{(->> order :day) (->> order :day day-customers second)}))
(defn- delete-order [{id :id}]
(println "deleting order" id)
(let [day (-> (get @customers id) :day)]
(swap! days (fn [ds] (update ds day (partial remove #{id}))))
(swap! customers #(dissoc % id))
{day (->> day day-customers second)}))
(defn- order-state [{id :id state :state}]
(println "fulfilling order" id)
(let [day (-> (get @customers id) :day)]
(swap! customers #(assoc-in % [id :state] state))
(println id (get @customers id))
{day (->> day day-customers second)}))
(comment
(replace-order
{:id 194, :day "2020-11-21", :hour "02:12", :who "mr.blobby (649 234 234)", :products {:eggs 13 :milk 4 :cabbage 7}})
)

View File

@ -1,6 +1,7 @@
(ns chicken-master.products
(:require
[re-frame.core :as re-frame]
[chicken-master.config :refer [settings]]
[chicken-master.html :as html]
[chicken-master.events :as event]))
@ -15,9 +16,13 @@
[:option {:key (gensym) :value product} (name product)])]]
(html/input :amount "ile"
{:type :number :default amount :min 0
:on-blur #(re-frame/dispatch [::event/changed-amount (-> % .-target .-value) product-no])})])
;; :on-blur #(re-frame/dispatch [::event/changed-amount (-> % .-target .-value) product-no])
:on-input #(re-frame/dispatch [::event/changed-amount (-> % .-target .-value) product-no])
})])
(defn format-product [[product amount]]
[:li {:key (gensym) :class :product}
(if (settings :editable-number-inputs)
[:input {:class :product-amount :type :number :min 0 :defaultValue amount}]
[:span {:class :product-amount} amount])
[:span {:class :product-name} product]])

View File

@ -1,7 +1,5 @@
(ns chicken-master.subs
(:require
[re-frame.core :as re-frame]
[chicken-master.time :as time]))
(:require [re-frame.core :as re-frame]))
(re-frame/reg-sub ::name (fn [db] (:name db)))
(re-frame/reg-sub ::available-products (fn [db] (-> db :products keys)))
@ -11,5 +9,4 @@
(re-frame/reg-sub ::order-edit-when (fn [db] (-> db :order-edit :hour)))
(re-frame/reg-sub ::order-edit-products (fn [db] (-> db :order-edit :products)))
(re-frame/reg-sub ::current-days (fn [db] (:current-days db)))

View File

@ -2,6 +2,8 @@
(:require [chicken-master.config :refer [settings]])
(:import [goog.date DateTime Date Interval]))
(defn parse-date [date] (new Date (js/Date. date)))
(defn date-offset
"Return the `date` offset by the given number of `days`"
[date days]
@ -12,15 +14,17 @@
(defn start-of-week
"Get the start of the week for the given `date"
[date]
(->> (.getDay date)
(- (settings :first-day-offset))
(date-offset date)))
(let [offset (mod (+ 7 (.getDay date) (- (settings :first-day-offset))) 7)]
(date-offset date (- offset))))
(defn days-range
"Return dates starting from `date`"
([date] (map (partial date-offset date) (range)))
([n date] (take n (days-range date))))
(defn before? [d1 d2] (< (Date/compare d1 d2) 0))
(defn after? [d1 d2] (> (Date/compare d1 d2) 0))
(defn same-day?
"Returns true when both dates are from the same day" [d1 d2]
(-> (new Date d1)
@ -29,8 +33,24 @@
(defn today? "true when `d1` is today" [d1] (same-day? (js/Date.) d1))
(defn format-date [date]
(when (settings :show-date)
(if (settings :show-day-name-with-date)
(str
(->> date .getDay (nth (settings :day-names)))
" " (.getMonth date) "/" (.getDate date)))
" " (inc (.getMonth date)) "/" (.getDate date))
(str (inc (.getMonth date)) "/" (.getDate date)))))
(defn iso-date [date] (.toIsoString ^js/goog.date.Date date true))
(comment
(with-redefs [settings {:first-day-offset 0}]
(= (->> (parse-date "2020-11-22") start-of-week iso-date) "2020-11-22")
(filter #(= (-> (parse-date %) start-of-week iso-date) "2020-11-22")
["2020-11-22" "2020-11-23" "2020-11-24" "2020-11-25" "2020-11-26" "2020-11-27" "2020-11-28"]))
(with-redefs [settings {:first-day-offset 1}]
(= (->> (parse-date "2020-11-22") start-of-week iso-date) "2020-11-16")
(filter #(= (-> (parse-date %) start-of-week iso-date) "2020-11-23")
["2020-11-23" "2020-11-24" "2020-11-25" "2020-11-26" "2020-11-27" "2020-11-28" "2020-11-29" ]))
)

View File

@ -10,6 +10,6 @@
(let [name (re-frame/subscribe [::subs/name])]
[:div {:class :full-height}
(when @(re-frame/subscribe [::subs/show-edit-modal])
(cal/add-order (new js/Date)))
(cal/edit-order))
(cal/calendar @(re-frame/subscribe [::subs/current-days]))
]))