diff --git a/clinic/src/cljs/clinic/router.cljs b/clinic/src/cljs/clinic/router.cljs index 52391b5..2a04ccf 100644 --- a/clinic/src/cljs/clinic/router.cljs +++ b/clinic/src/cljs/clinic/router.cljs @@ -21,12 +21,25 @@ (defn start! [] (pushy/start! history)) -(defn replace-token! [token] - (pushy/replace-token! history token)) +(rf/reg-event-fx ::set-current-view + (fn [{db :db} [_ view-id params]] + {:db (assoc db ::current-view {::id view-id ::params params}) + :dispatch [::on-current-view-changed]})) -(defn set-token! [token] - (pushy/set-token! history token)) +(rf/reg-sub ::current-view get-in) (rf/reg-fx ::set-token (fn router-set-token-effect [token] - (set-token! token))) + (pushy/set-token! history token))) + +(rf/reg-fx ::replace-token + (fn router-replace-token-effect [token] + (pushy/replace-token! history token))) + +(rf/reg-event-fx ::set-token + (fn [_ [_ token]] + {::set-token token})) + +(rf/reg-event-fx ::replace-token + (fn [_ [_ token]] + {::replace-token token})) diff --git a/clinic/src/cljs/clinic/views/core.cljs b/clinic/src/cljs/clinic/views/core.cljs index 9266df1..60ef497 100644 --- a/clinic/src/cljs/clinic/views/core.cljs +++ b/clinic/src/cljs/clinic/views/core.cljs @@ -9,16 +9,6 @@ [clinic.views.view-patient :as view-patient] [re-frame.core :as rf])) -(def ^:private views {::router/home home/root - ::router/create-patient create-patient/root - ::router/view-patient view-patient/root - ::router/search-patients list-patients/root}) - -(def ^:private titles {::router/home "Home" - ::router/create-patient "Add Patient" - ::router/view-patient "Patient Info" - ::router/search-patients "Search Patients"}) - (rf/reg-fx ::set-window-title (fn [title] (set! (.-title js/document) @@ -26,19 +16,27 @@ (or "Page Not Found") (str " - Acme Clinic"))))) -(rf/reg-event-fx ::router/set-current-view - (fn [{db :db} [_ view-id params]] - {:db (assoc db ::current-view {::id view-id ::params params}) - ::set-window-title (titles view-id)})) - -(rf/reg-sub ::current-view :-> ::current-view) +(rf/reg-event-fx ::router/on-current-view-changed + (fn [{db :db} _] + (let [{view-id ::router/id + params ::router/params} (::router/current-view db)] + (case view-id + ::router/home {::set-window-title "Home"} + ::router/create-patient {::set-window-title "Add Patient"} + ::router/view-patient {::set-window-title "Patient Info" + :dispatch [::view-patient/fetch-patient params]} + ::router/search-patients {::set-window-title "Search Patients" + :dispatch [::list-patients/fetch-patients params]})))) (defn root [] - (let [current-role (user-role/get) - current-view (rf/subscribe [::current-view])] - (fn [] - [components/page {:logout-enabled @current-role - :on-logout-click #(do (user-role/clear) - (router/replace-token! "/"))} - [(get views (::id @current-view) not-found/root) - (::params @current-view)]]))) + (let [current-role @(user-role/get) + current-view-id @(rf/subscribe [::router/current-view ::router/id])] + [components/page {:logout-enabled current-role + :on-logout-click #(do (user-role/clear) + (rf/dispatch [::router/replace-token "/"]))} + [(case current-view-id + ::router/home home/root + ::router/create-patient create-patient/root + ::router/view-patient view-patient/root + ::router/search-patients list-patients/root + not-found/root)]])) diff --git a/clinic/src/cljs/clinic/views/list_patients.cljs b/clinic/src/cljs/clinic/views/list_patients.cljs index bf7b29c..f4da22c 100644 --- a/clinic/src/cljs/clinic/views/list_patients.cljs +++ b/clinic/src/cljs/clinic/views/list_patients.cljs @@ -6,26 +6,25 @@ [reagent.core :as r])) (rf/reg-event-db ::fetch-patients-success - (fn [db [_ phone page result]] - (assoc-in db [::patients phone page] {::loading false - ::data result}))) + (fn [db [_ result]] + (assoc db ::patients {::loading false ::data result}))) (rf/reg-event-db ::fetch-patients-failure - (fn [db [_ phone page {error-code :status}]] - (assoc-in db [::patients phone page] {::loading false - ::error-code error-code}))) + (fn [db [_ {error-code :status}]] + (assoc db ::patients {::loading false ::error-code error-code}))) (rf/reg-event-fx ::fetch-patients - (fn [{db :db} [_ phone page]] - {:db (assoc-in db [::patients phone page] {::loading true}) - :http-xhrio {:method :get - :uri (str "/api/v1/patients/") - :params (cond-> {:count 10 - :offset (* 10 (dec page))} - phone (assoc :phone phone)) - :response-format (ajax/json-response-format {:keywords? true}) - :on-success [::fetch-patients-success phone page] - :on-failure [::fetch-patients-failure phone page]}})) + (fn [{db :db} [_ {:keys [phone page] :or {page "1"}}]] + (let [page-num (parse-long page)] + {:db (assoc db ::patients {::loading true}) + :http-xhrio {:method :get + :uri (str "/api/v1/patients/") + :params (cond-> {:count 10 + :offset (* 10 (dec page-num))} + phone (assoc :phone phone)) + :response-format (ajax/json-response-format {:keywords? true}) + :on-success [::fetch-patients-success] + :on-failure [::fetch-patients-failure]}}))) (rf/reg-sub ::patients get-in) @@ -33,22 +32,29 @@ (let [{:keys [index patient]} (r/props (r/current-component))] [:tr {:class [(if (odd? index) "bg-gray-50" "bg-white") "hover:bg-gray-100" "hover:cursor-pointer"] - :on-click #(router/set-token! (str "/patients/" (:id patient)))} + :on-click #(rf/dispatch [::router/set-token + (str "/patients/" (:id patient))])} [:td {:class ["px-6" "py-2"]} (inc index)] [:td {:class ["px-6" "py-2"]} (:first-name patient) " " (:last-name patient)] [:td {:class ["px-6" "py-2"]} (:birth-date patient)] [:td {:class ["px-6" "py-2"]} (:phone patient)]])) (defn root [] - (let [props (r/props (r/current-component)) - page (parse-long (get props :page "1")) - phone (:phone props) - loading? (rf/subscribe [::patients phone page ::loading]) - patients (rf/subscribe [::patients phone page ::data]) - error-code (rf/subscribe [::patients phone page ::error-code])] - (rf/dispatch [::fetch-patients phone page]) + (let [params @(rf/subscribe [::router/current-view ::router/params]) + page (parse-long (get params :page "1")) + phone (:phone params) + loading? @(rf/subscribe [::patients ::loading]) + patients @(rf/subscribe [::patients ::data]) + error-code @(rf/subscribe [::patients ::error-code])] [:section {:class ["flex" "flex-col" "gap-8"]} - [:div {:class ["flex" "flex-row" "self-center" "items-center" "gap-6"]} + [:form {:class ["flex" "flex-row" "self-center" "items-center" "gap-6"] + ;; TODO: better way to handle submission of this GET form. + :on-submit #(do (.preventDefault %) + (rf/dispatch [::router/set-token + (-> js/document + (.getElementById "phone") + (.-value) + ((partial str "/patients?phone=")))]))} [:input {:id "phone" :name "phone" :placeholder "Search by phone" @@ -58,26 +64,22 @@ "rounded" "py-2.5" "px-4" "leading-tight" "focus:outline-none" "focus:bg-white" "focus:border-gray-500"]}] - [:button {:class ["bg-blue-600" "hover:bg-blue-800" "text-white" - "font-bold" "py-2" "px-4" "rounded-full"] - :on-click #(-> js/document - (.getElementById "phone") - (.-value) - ((partial str "/patients?phone=")) - (router/set-token!))} - "Search"]] + [:input {:type "submit" + :value "Search" + :class ["bg-blue-600" "hover:bg-blue-800" "text-white" + "font-bold" "py-2" "px-4" "rounded-full"]}]] (cond - @loading? + loading? [components/spinner {:class ["block" "self-center" "w-8" "h-8" "m-16" "text-blue-600"]}] - @error-code + error-code [components/danger-alert "There was an error while fetching patient data. Please try again!"] - (empty? @patients) + (empty? patients) [:p {:class ["self-center" "text-center"]} "No patients found matching this criteria!"] - @patients + patients [:<> [:table {:class ["w-full" "table-auto" "self-center" "text-center"]} [:thead @@ -88,7 +90,7 @@ [:th {:class ["px-6" "py-2"]} "Phone Number"]]] (into [:tbody] (map-indexed #(do [patient-row {:index %1 :patient %2}]) - @patients))] + patients))] [:div {:class ["flex" "flex-row" "justify-center" "gap-8"]} [:a {:class ["text-blue-600" "hover:underline" (when (<= page 1) "invisible")] @@ -97,7 +99,7 @@ "Prev"] [:p {:class ["font-medium"]} "Page" " " page] [:a {:class ["text-blue-600" "hover:underline" - (when (< (count @patients) 10) "invisible")] + (when (< (count patients) 10) "invisible")] :href (cond-> (str "/patients?page=" (inc page)) phone (str "&phone=" phone))} "Next"]]])])) diff --git a/clinic/src/cljs/clinic/views/view_patient.cljs b/clinic/src/cljs/clinic/views/view_patient.cljs index 088f75c..d1b2f14 100644 --- a/clinic/src/cljs/clinic/views/view_patient.cljs +++ b/clinic/src/cljs/clinic/views/view_patient.cljs @@ -7,27 +7,21 @@ (rf/reg-event-db ::fetch-patient-success - (fn [db [_ patient-id result]] - (assoc-in db - [::patient patient-id] - {::loading false - ::data result}))) + (fn [db [_ result]] + (assoc db ::patient {::loading false ::data result}))) (rf/reg-event-db ::fetch-patient-failure - (fn [db [_ patient-id {error-code :status}]] - (assoc-in db - [::patient patient-id] - {::loading false - ::error-code error-code}))) + (fn [db [_ {error-code :status}]] + (assoc db ::patient {::loading false ::error-code error-code}))) (rf/reg-event-fx ::fetch-patient - (fn [{db :db} [_ patient-id]] + (fn [{db :db} [_ {patient-id :id}]] {:db (assoc-in db [::patient patient-id] {::loading true}) :http-xhrio {:method :get :uri (str "/api/v1/patients/" patient-id) :response-format (ajax/json-response-format {:keywords? true}) - :on-success [::fetch-patient-success patient-id] - :on-failure [::fetch-patient-failure patient-id]}})) + :on-success [::fetch-patient-success] + :on-failure [::fetch-patient-failure]}})) (rf/reg-sub ::patient get-in) @@ -57,13 +51,9 @@ "Unknown")) (defn root [] - (let [patient-id (-> (r/current-component) - (r/props) - (:id)) - loading? @(rf/subscribe [::patient patient-id ::loading]) - patient @(rf/subscribe [::patient patient-id ::data]) - error-code @(rf/subscribe [::patient patient-id ::error-code])] - (rf/dispatch [::fetch-patient patient-id]) + (let [loading? @(rf/subscribe [::patient ::loading]) + patient @(rf/subscribe [::patient ::data]) + error-code @(rf/subscribe [::patient ::error-code])] [:section {:class ["flex" "flex-col"]} (cond loading? [components/spinner {:class ["block" "self-center" "w-8" "h-8" "m-16" "text-blue-600"]}]