Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add notifications; render as pop-ups ("toasts") #226

Merged
merged 15 commits into from
Jul 31, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 22 additions & 6 deletions client/common/src/flybot/client/common/db/event.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,14 @@

(rf/reg-event-db
:fx.http/failure
[(rf/path :app/errors)]
(fn [errors [_ result]]
(fn [db [_ result]]
;; result is a map containing details of the failure
(assoc errors :failure-http-result result)))
(-> db
(assoc-in [:app/errors :failure-http-result] result)
flybot-nam-nguyenhoai marked this conversation as resolved.
Show resolved Hide resolved
(assoc :app/notification #:notification{:id (utils/mk-uuid)
:type :error
:title "HTTP failure"
:body result}))))

(rf/reg-event-fx
:fx.http/all-success
Expand Down Expand Up @@ -302,13 +306,25 @@
(fn [_ [_ new-options]]
(edn/read-string new-options)))

;; ------- Notifications ------

(rf/reg-event-fx
:evt.app/toast-notify
(fn [{:keys [db]} [_ notification]]
(let [theme (-> db :app/theme name)]
{:fx [[:fx.ui/toast-notify [notification {"theme" theme}]]]})))

;; ---------- Errors ----------

(rf/reg-event-db
:evt.error/set-validation-errors
[(rf/path :app/errors)]
(fn [errors [_ validation-err]]
(assoc errors :validation-errors validation-err)))
(fn [db [_ validation-err]]
(-> db
(assoc-in [:app/errors :validation-errors] validation-err)
(assoc :app/notification #:notification{:id (utils/mk-uuid)
:type :error
:title "Validation error"
:body validation-err}))))

(rf/reg-event-db
:evt.error/clear-errors
Expand Down
31 changes: 28 additions & 3 deletions client/common/src/flybot/client/common/db/fx.cljs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
(ns flybot.client.common.db.fx
(:require [re-frame.core :as rf]
[reitit.frontend.easy :as rfe]))
(:require [cljsjs.react-toastify]
[re-frame.core :as rf]
[reitit.frontend.easy :as rfe]
[reagent.core :as r]))

;; ---------- Routing ----------

Expand All @@ -13,4 +15,27 @@
(rf/reg-fx
:fx.log/message
(fn [messages]
(.log js/console (apply str messages))))
(.log js/console (apply str messages))))

;; ---- Toast notifications ----

(rf/reg-fx
:fx.ui/toast-notify
(fn [[{:notification/keys [type title body]} options]]
(let [type-options (case type
:info {"type" "info"
"autoClose" 10000
"pauseOnHover" true}
:success {"type" "success"
"autoClose" 5000
"pauseOnHover" false}
:warning {"type" "warning"
"autoClose" 10000
"pauseOnHover" true}
:error {"type" "error"
"autoClose" 10000
"pauseOnHover" true}
{})]
(.toast js/ReactToastify
(r/as-element [:<> [:strong (str title)] [:p (str body)]])
(clj->js (merge type-options options))))))
10 changes: 6 additions & 4 deletions client/web/src/flybot/client/web/core/dom.cljs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
(ns flybot.client.web.core.dom
(:require [flybot.client.web.core.dom.header :refer [header-comp]]
[flybot.client.web.core.dom.page :refer [page]]
(:require [flybot.client.web.core.db]
[flybot.client.web.core.dom.footer :refer [footer-comp]]
[flybot.client.web.core.db]
[flybot.client.web.core.dom.header :refer [header-comp]]
[flybot.client.web.core.dom.page :refer [page]]
[flybot.client.web.core.dom.page.notifications :as notifications]
[re-frame.core :as rf]))

(defn current-page []
Expand All @@ -16,4 +17,5 @@
[:div
[header-comp]
[current-page]
[footer-comp]])
[footer-comp]
[notifications/toast-notification-comp]])
14 changes: 0 additions & 14 deletions client/web/src/flybot/client/web/core/dom/common/error.cljs

This file was deleted.

5 changes: 3 additions & 2 deletions client/web/src/flybot/client/web/core/dom/page.cljs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
(ns flybot.client.web.core.dom.page
(:require [clojure.string :as str]
[flybot.client.web.core.dom.page.post :as post :refer [blog-post-short page-post]]
(:require [cljsjs.react-toastify]
[clojure.string :as str]
[flybot.client.web.core.dom.page.admin :refer [admin-panel]]
[flybot.client.web.core.dom.page.options :as page.options]
[flybot.client.web.core.dom.page.post :as post :refer [blog-post-short page-post]]
[flybot.client.web.core.utils :as web.utils]
[re-frame.core :as rf]))

Expand Down
6 changes: 1 addition & 5 deletions client/web/src/flybot/client/web/core/dom/page/admin.cljs
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
(ns flybot.client.web.core.dom.page.admin
(:require [flybot.client.web.core.dom.common.error :refer [errors]]
[flybot.client.web.core.dom.common.role :as role]
(:require [flybot.client.web.core.dom.common.role :as role]
[flybot.client.web.core.dom.common.svg :as svg]
[re-frame.core :as rf]))



;;---------- Button ----------
(defn submit-role-button
[role]
Expand Down Expand Up @@ -42,7 +39,6 @@
[:h1 "Admin"]
(if (role/has-role? :owner)
[:<>
[errors "admin-page" [:validation-errors :failure-http-result]]
[:div
[:form
[submit-role-button :admin]]
Expand Down
32 changes: 32 additions & 0 deletions client/web/src/flybot/client/web/core/dom/page/notifications.cljs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
(ns flybot.client.web.core.dom.page.notifications
"Rendering app notifications as pop-up (\"toast\") notifications in the DOM."
(:require [cljsjs.react-toastify]
[re-frame.core :as rf]))

(def toast-notification-container
"A container for pop-up notifications, with default settings.

This container should be stacked above other HTML elements (either by
using the `z-index` property or by declaring it last) so that notifications
properly cover them."
[:> (-> (.-ToastContainer js/ReactToastify)
js->clj
(update "defaultProps" #(merge % {"position" "bottom-center"
"hideProgressBar" true
"newestOnTop" true
"pauseOnFocusLoss" false
"pauseOnHover" false
"closeButton" false}))
clj->js)])

(defn toast-notification-subscription
[]
(let [notification @(rf/subscribe [:subs/pattern {:app/notification '?x}])]
(when notification
(rf/dispatch [:evt.app/toast-notify notification]))))

(defn toast-notification-comp
[]
[:<>
[toast-notification-subscription]
toast-notification-container])
4 changes: 1 addition & 3 deletions client/web/src/flybot/client/web/core/dom/page/post.cljs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
(ns flybot.client.web.core.dom.page.post
(:require [clojure.walk :as walk]
[flybot.client.web.core.dom.common.error :refer [errors]]
[flybot.client.web.core.dom.common.link :as link]
[flybot.client.web.core.dom.common.role :as role]
[flybot.client.web.core.dom.common.svg :as svg]
Expand Down Expand Up @@ -270,8 +269,7 @@
[submit-button]
[edit-button id]
(when-not (utils/temporary-id? id)
[trash-button])])
[errors id [:validation-errors :failure-http-result]]]
[trash-button])])]
(when @(rf/subscribe [:subs/pattern '{:form/fields {:post/to-delete? ?x}}])
[delete-form id])
(if (= :preview @(rf/subscribe [:subs/pattern '{:form/fields {:post/view ?x}}]))
Expand Down
17 changes: 13 additions & 4 deletions client/web/test/flybot/client/web/core/db_test.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,9 @@
user (rf/subscribe [:subs/pattern '{:app/user ?x}])
navbar-open? (rf/subscribe [:subs/pattern '{:nav/navbar-open? ?x}])
posts (rf/subscribe [:subs.post/posts :home])
http-error (rf/subscribe [:subs/pattern '{:app/errors {:failure-http-result ?x}}])]
http-error (rf/subscribe [:subs/pattern '{:app/errors {:failure-http-result ?x}}])
http-error-notification
(rf/subscribe [:subs/pattern {:app/notification '?x}])]
;;---------- SERVER ERROR
;; Mock failure http request
(rf/reg-fx :http-xhrio
Expand All @@ -50,7 +52,11 @@
;; Initialize db
(rf/dispatch [:evt.app/initialize])
(testing "Initital db state is accurate in case of server error."
(is (= "ERROR-SERVER" @http-error)))
(is (= "ERROR-SERVER" @http-error))
(is (= #:notification{:type :error
:body "ERROR-SERVER"}
(select-keys @http-error-notification [:notification/type
:notification/body]))))

;;---------- SUCCESS
;; Mock success http request
Expand Down Expand Up @@ -125,6 +131,8 @@
posts (rf/subscribe [:subs.post/posts :home])
errors (rf/subscribe [:subs/pattern '{:app/errors ?x}])
validation-error (rf/subscribe [:subs/pattern '{:app/errors {:validation-errors ?x}}])
validation-error-notification
(rf/subscribe [:subs/pattern {:app/notification '?x}])
new-post-1 (assoc s/post-1
:post/md-content "#New Content 1"
:post/last-edit-date (utils/mk-date))]
Expand Down Expand Up @@ -156,7 +164,8 @@
;; Send post but validation error
(rf/dispatch [:evt.post.form/send-post])
(testing "Validation error added to db."
(is @validation-error))
(is @validation-error)
(is @validation-error-notification))

;;---------- SEND POST SUCCESS
;; Mock success http request
Expand Down Expand Up @@ -260,4 +269,4 @@
{:posts {:removed-post {:post/id s/post-1-id}}}])))
(rf/dispatch [:evt.post/remove-post s/post-1-id])
(testing "Post got removed."
(is (= [] @posts))))))
(is (= [] @posts))))))
1 change: 1 addition & 0 deletions deps.edn
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
reagent/reagent {:mvn/version "1.2.0"}
cljsjs/react {:mvn/version "18.2.0-1"}
cljsjs/react-dom {:mvn/version "18.2.0-1"}
cljsjs/react-toastify {:mvn/version "9.1.0-0"}
cljs-ajax/cljs-ajax {:mvn/version "0.8.4"}
re-frame/re-frame {:mvn/version "1.3.0"}
day8.re-frame/http-fx {:mvn/version "0.2.4"}
Expand Down
Loading