aboutsummaryrefslogtreecommitdiff
path: root/src/frontend
diff options
context:
space:
mode:
authorMiguel Ángel Moreno <mail@migalmoreno.com>2024-04-19 16:20:50 +0200
committerMiguel Ángel Moreno <mail@migalmoreno.com>2024-04-19 16:35:55 +0200
commit758c276bf65f1be6d60736d1694f00c7e59d6cae (patch)
tree63ecee5be8d8f5cfa7e79e49727c98e39fae4568 /src/frontend
parent0019d7e79c09f498b8b12c49fe966e58d028f52e (diff)
feat: add notification support
Diffstat (limited to 'src/frontend')
-rw-r--r--src/frontend/tubo/components/notification.cljs28
-rw-r--r--src/frontend/tubo/events.cljs70
-rw-r--r--src/frontend/tubo/subs.cljs5
-rw-r--r--src/frontend/tubo/views.cljs2
4 files changed, 92 insertions, 13 deletions
diff --git a/src/frontend/tubo/components/notification.cljs b/src/frontend/tubo/components/notification.cljs
new file mode 100644
index 0000000..61c10ad
--- /dev/null
+++ b/src/frontend/tubo/components/notification.cljs
@@ -0,0 +1,28 @@
+(ns tubo.components.notification
+ (:require
+ [re-frame.core :as rf]
+ [tubo.events :as events]))
+
+(defn notification-content
+ [{:keys [failure parse-error status status-text] :as notification} key]
+ (when notification
+ [:div.py-4.pl-4.pr-8.rounded.backdrop-blur.flex.flex-col.justify-center.shadow.shadow-neutral-700
+ {:class (clojure.string/join
+ "" (case failure
+ :success ["bg-green-600/90 text-white"]
+ :error ["bg-red-600/90 text-white"]
+ ["bg-neutral-300"]))}
+ [:button.text-lg.absolute.top-1.right-2
+ {:on-click #(rf/dispatch [::events/remove-notification key])}
+ [:i.fa-solid.fa-close]]
+ [:span.font-bold (str (when status (str status ": ")) status-text)]
+ (when parse-error
+ [:span.line-clamp-1 (:status-text parse-error)])]))
+
+(defn notifications-panel
+ []
+ (fn []
+ (let [notifications @(rf/subscribe [:notifications])]
+ [:div.fixed.flex.flex-col.items-end.gap-2.top-16.z-20.w-full.py-1.px-2
+ (for [[i notification] (map-indexed vector notifications)]
+ ^{:key i} [notification-content notification i])])))
diff --git a/src/frontend/tubo/events.cljs b/src/frontend/tubo/events.cljs
index 678a0db..5aecfec 100644
--- a/src/frontend/tubo/events.cljs
+++ b/src/frontend/tubo/events.cljs
@@ -4,6 +4,7 @@
[day8.re-frame.http-fx]
[goog.object :as gobj]
[nano-id.core :refer [nano-id]]
+ [reagent.core :as r]
[re-frame.core :as rf]
[reitit.frontend.easy :as rfe]
[reitit.frontend.controllers :as rfc]
@@ -257,11 +258,42 @@
(fn [{:keys [name params query]}]
(rfe/push-state name params query)))
+(defonce timeouts! (r/atom {}))
+
+(rf/reg-fx
+ ::timeout!
+ (fn [{:keys [id event time]}]
+ (when-some [existing (get @timeouts! id)]
+ (js/clearTimeout existing)
+ (swap! timeouts! dissoc id))
+ (when (some? event)
+ (swap! timeouts! assoc id
+ (js/setTimeout #(rf/dispatch event) time)))))
+
+(rf/reg-event-fx
+ ::add-notification
+ (fn [{:keys [db]} [_ data time]]
+ (let [updated-db (update db :notifications #(into [] (conj %1 %2)) data)]
+ {:db updated-db
+ :fx (when time
+ [[::timeout! {:id (-> updated-db :notifications count dec)
+ :event [::pop-notification]
+ :time time}]])})))
+
+(rf/reg-event-fx
+ ::pop-notification
+ (fn [{:keys [db]} _]
+ {:fx [[:dispatch [::remove-notification (dec (count (:notifications db)))]]]}))
+
(rf/reg-event-db
+ ::remove-notification
+ (fn [db [_ pos]]
+ (update db :notifications #(into (subvec % 0 pos) (subvec % (inc pos))))))
+
+(rf/reg-event-fx
::bad-response
- (fn [db [_ res]]
- (.log js/console (clj->js res))
- (assoc db :http-response (get-in res [:response :error]))))
+ (fn [{:keys [db]} [_ res]]
+ {:fx [[:dispatch [::add-notification res 2000]]]}))
(rf/reg-event-db
::change-search-query
@@ -466,7 +498,9 @@
(let [updated-db (update db :bookmarks conj (assoc bookmark :id (nano-id)))]
{:db updated-db
:store (assoc store :bookmarks (:bookmarks updated-db))
- :fx [[:dispatch [::close-modal]]]})))
+ :fx [[:dispatch [::close-modal]]
+ [:dispatch [::add-notification {:status-text (str "Added playlist \"" (:name bookmark) "\"")
+ :failure :success} 2000]]]})))
(rf/reg-event-fx
::back-to-bookmark-list-modal
@@ -483,9 +517,12 @@
::remove-bookmark-list
[(rf/inject-cofx :store)]
(fn [{:keys [db store]} [_ id]]
- (let [updated-db (update db :bookmarks #(into [] (remove (fn [bookmark] (= (:id bookmark) id)) %)))]
+ (let [bookmark (first (filter #(= (:id %) id) (:bookmarks db)))
+ updated-db (update db :bookmarks #(into [] (remove (fn [bookmark] (= (:id bookmark) id)) %)))]
{:db updated-db
- :store (assoc store :bookmarks (:bookmarks updated-db))})))
+ :store (assoc store :bookmarks (:bookmarks updated-db))
+ :fx [[:dispatch [::add-notification {:status-text (str "Removed playlist \"" (:name bookmark) "\"")
+ :failure :success} 2000]]]})))
(rf/reg-event-fx
::add-to-likes
@@ -495,7 +532,8 @@
(let [updated-db (update-in db [:bookmarks 0 :items] #(into [] (conj (into [] %1) %2))
(assoc bookmark :bookmark-id (-> db :bookmarks first :id)))]
{:db updated-db
- :store (assoc store :bookmarks (:bookmarks updated-db))}))))
+ :store (assoc store :bookmarks (:bookmarks updated-db))
+ :fx [[:dispatch [::add-notification {:status-text "Added to favorites" :failure :success} 2000]]]}))))
(rf/reg-event-fx
::remove-from-likes
@@ -503,7 +541,8 @@
(fn [{:keys [db store]} [_ bookmark]]
(let [updated-db (update-in db [:bookmarks 0 :items] #(remove (fn [item] (= (:url item) (:url bookmark))) %))]
{:db updated-db
- :store (assoc store :bookmarks (:bookmarks updated-db))})))
+ :store (assoc store :bookmarks (:bookmarks updated-db))
+ :fx [[:dispatch [::add-notification {:status-text "Removed from favorites" :failure :success} 2000]]]})))
(rf/reg-event-fx
::add-to-bookmark-list
@@ -517,16 +556,21 @@
(assoc item :bookmark-id (:id bookmark))))]
{:db updated-db
:store (assoc store :bookmarks (:bookmarks updated-db))
- :fx [[:dispatch [::close-modal]]]})))
+ :fx [[:dispatch [::close-modal]]
+ [:dispatch [::add-notification {:status-text (str "Added to playlist \"" (:name bookmark-list) "\"")
+ :failure :success} 2000]]]})))
(rf/reg-event-fx
::remove-from-bookmark-list
[(rf/inject-cofx :store)]
(fn [{:keys [db store]} [_ bookmark]]
- (let [bookmark-list (.indexOf (:bookmarks db) (first (filter #(= (:id %) (:bookmark-id bookmark)) (:bookmarks db))))
- updated-db (update-in db [:bookmarks bookmark-list :items] #(remove (fn [item] (= (:url item) (:url bookmark))) %))]
- {:db updated-db
- :store (assoc store :bookmarks (:bookmarks updated-db))})))
+ (let [bookmark-list (first (filter #(= (:id %) (:bookmark-id bookmark)) (:bookmarks db)))
+ pos (.indexOf (:bookmarks db) bookmark-list)
+ updated-db (update-in db [:bookmarks pos :items] #(remove (fn [item] (= (:url item) (:url bookmark))) %))]
+ {:db updated-db
+ :store (assoc store :bookmarks (:bookmarks updated-db))
+ :fx [[:dispatch [::add-notification {:status-text (str "Removed from playlist \"" (:name bookmark-list) "\"")
+ :failure :success} 2000]]]})))
(rf/reg-event-db
::load-services
diff --git a/src/frontend/tubo/subs.cljs b/src/frontend/tubo/subs.cljs
index 9a82d6a..eec5ec8 100644
--- a/src/frontend/tubo/subs.cljs
+++ b/src/frontend/tubo/subs.cljs
@@ -72,6 +72,11 @@
(:search-results db)))
(rf/reg-sub
+ :notifications
+ (fn [db _]
+ (:notifications db)))
+
+(rf/reg-sub
:modal
(fn [db _]
(:modal db)))
diff --git a/src/frontend/tubo/views.cljs b/src/frontend/tubo/views.cljs
index 0618b51..3abc4e2 100644
--- a/src/frontend/tubo/views.cljs
+++ b/src/frontend/tubo/views.cljs
@@ -3,6 +3,7 @@
[re-frame.core :as rf]
[tubo.components.audio-player :as player]
[tubo.components.navigation :as navigation]
+ [tubo.components.notification :as notification]
[tubo.components.play-queue :as queue]
[tubo.events :as events]))
@@ -14,6 +15,7 @@
[:div.min-h-screen.flex.flex-col.h-full.dark:text-white.dark:bg-neutral-900.relative
[navigation/navbar current-match]
[:div.flex.flex-col.flex-auto.justify-between.relative.font-nunito
+ [notification/notifications-panel]
(when-let [view (-> current-match :data :view)]
[view current-match])
[queue/queue]