From 52b87bab3e010b6feca857f04a18d29969839b34 Mon Sep 17 00:00:00 2001 From: Icaro Motta Date: Fri, 3 Mar 2023 09:17:35 -0300 Subject: [PATCH] Redesign and simplify Activity Center app db (#15216) Fixes #15215. Redesign the app db state for the Activity Center. Please, see the issue being fixed for more details about the problems being solved. TL;DR: There's a lot less state to keep track and reconcile and way less nesting in the app db because we're only managing the state of the *current tab*, not all tabs. Additionally: - [x] While updating unit tests, found a bug on the sorting notifications' logic. - [x] While updating unit tests, found a bug where notifications that are not of the type *contact request* were being removed from the app db. - [x] Fixed regression where pressing on a notification would not open the chat. - [x] Hardened unit tests. #### Platforms - Android - iOS ##### Non-functional - Less memory consumption. - Faster reconciliation of notification coming from signals and from synchronous responses from RPC calls. --- src/status_im/data_store/activities.cljs | 7 +- src/status_im/data_store/activities_test.cljs | 10 + src/status_im/multiaccounts/login/core.cljs | 2 +- .../contexts/activity_center/events.cljs | 272 ++++---- .../contexts/activity_center/events_test.cljs | 589 +++++++----------- .../notification/contact_requests/view.cljs | 2 +- .../contexts/activity_center/view.cljs | 2 +- src/status_im2/contexts/contacts/events.cljs | 3 +- src/status_im2/subs/activity_center.cljs | 18 +- src/status_im2/subs/activity_center_test.cljs | 25 - 10 files changed, 377 insertions(+), 553 deletions(-) diff --git a/src/status_im/data_store/activities.cljs b/src/status_im/data_store/activities.cljs index 90cacd61cd..20396f6704 100644 --- a/src/status_im/data_store/activities.cljs +++ b/src/status_im/data_store/activities.cljs @@ -1,13 +1,18 @@ (ns status-im.data-store.activities (:require [clojure.set :as set] - [status-im2.constants :as constants] [status-im.data-store.messages :as messages] + [status-im2.constants :as constants] [status-im2.contexts.activity-center.notification-types :as notification-types])) (defn mark-notifications-as-read [notifications] (map #(assoc % :read true) notifications)) +(defn pending-contact-request? + [contact-id {:keys [type author]}] + (and (= type notification-types/contact-request) + (= contact-id author))) + (defn- rpc->type [{:keys [type name] :as chat}] (case type diff --git a/src/status_im/data_store/activities_test.cljs b/src/status_im/data_store/activities_test.cljs index 23f5353ddd..c80d154b67 100644 --- a/src/status_im/data_store/activities_test.cljs +++ b/src/status_im/data_store/activities_test.cljs @@ -97,3 +97,13 @@ (assoc :type notification-types/one-to-one-chat) store/<-rpc (select-keys [:name :chat-type :chat-name :public? :group-chat])))))) + +(deftest remove-pending-contact-request-test + (is (true? (store/pending-contact-request? + "contact-id" + {:type notification-types/contact-request + :author "contact-id"}))) + (is (false? (store/pending-contact-request? + "contact-id" + {:type notification-types/contact-request + :author "contactzzzz"})))) diff --git a/src/status_im/multiaccounts/login/core.cljs b/src/status_im/multiaccounts/login/core.cljs index 2e1cc7108e..3d883869df 100644 --- a/src/status_im/multiaccounts/login/core.cljs +++ b/src/status_im/multiaccounts/login/core.cljs @@ -409,7 +409,7 @@ (get-node-config) (communities/fetch) (logging/set-log-level (:log-level multiaccount)) - (activity-center/notifications-fetch-unread-contact-requests) + (activity-center/notifications-fetch-pending-contact-requests) (activity-center/notifications-fetch-unread-count)))) (re-frame/reg-fx diff --git a/src/status_im2/contexts/activity_center/events.cljs b/src/status_im2/contexts/activity_center/events.cljs index 8ddc821535..5fa566d425 100644 --- a/src/status_im2/contexts/activity_center/events.cljs +++ b/src/status_im2/contexts/activity_center/events.cljs @@ -1,15 +1,16 @@ (ns status-im2.contexts.activity-center.events - (:require [status-im.data-store.activities :as data-store.activities] + (:require [quo2.foundations.colors :as colors] + [status-im.data-store.activities :as activities] [status-im.data-store.chats :as data-store.chats] - [status-im2.contexts.activity-center.notification-types :as types] - [status-im2.contexts.chat.events :as chat.events] [status-im2.common.toasts.events :as toasts] + [status-im2.constants :as constants] + [status-im2.contexts.activity-center.notification-types :as types] status-im2.contexts.activity-center.notification.contact-requests.events + [status-im2.contexts.chat.events :as chat.events] [taoensso.timbre :as log] - [utils.re-frame :as rf] + [utils.collection :as collection] [utils.i18n :as i18n] - [quo2.foundations.colors :as colors] - [status-im2.constants :as constants])) + [utils.re-frame :as rf])) (def defaults {:filter-status :unread @@ -48,127 +49,58 @@ ;;;; Notification reconciliation -(defn- notification-type->filter-type - [type] - (if (some types/membership [type]) - types/membership - type)) - (defn- update-notifications - "Insert `new-notifications` in `db-notifications`. - - Although correct, this is a naive implementation for reconciling notifications - because for every notification in `new-notifications`, linear scans will be - performed to remove it and sorting will be performed for every new insertion. - If the number of existing notifications cached in the app db becomes - ~excessively~ big, this implementation will probably need to be revisited." - [db-notifications new-notifications] - (reduce (fn [acc {:keys [id read] :as notification}] - (let [filter-type (notification-type->filter-type (:type notification)) - remove-notification (fn [data] - (remove #(= id (:id %)) data)) - insert-and-sort (fn [data] - (->> notification - (conj data) - (sort-by (juxt :timestamp :id)) - reverse))] - (as-> acc $ - (update-in $ [filter-type :all :data] remove-notification) - (update-in $ [types/no-type :all :data] remove-notification) - (update-in $ [filter-type :unread :data] remove-notification) - (update-in $ [types/no-type :unread :data] remove-notification) - (if (:deleted notification) - $ - (cond-> (-> $ - (update-in [filter-type :all :data] insert-and-sort) - (update-in [types/no-type :all :data] insert-and-sort)) - (not read) (update-in [filter-type :unread :data] insert-and-sort) - (not read) (update-in [types/no-type :unread :data] insert-and-sort)))))) - db-notifications - new-notifications)) + [db-notifications new-notifications {filter-type :type filter-status :status}] + (->> new-notifications + (reduce (fn [acc {:keys [id type deleted read] :as notification}] + (if (or deleted + (and (= :unread filter-status) read) + (and (set? filter-type) + (not (contains? filter-type type))) + (and (not (set? filter-type)) + (not= filter-type types/no-type) + (not= filter-type type))) + (dissoc acc id) + (assoc acc id notification))) + (collection/index-by :id db-notifications)) + (vals) + (sort-by (juxt :timestamp :id) + #(compare %2 %1)))) (rf/defn notifications-reconcile {:events [:activity-center.notifications/reconcile]} [{:keys [db]} new-notifications] (when (seq new-notifications) - {:db (update-in db - [:activity-center :notifications] - update-notifications - new-notifications) - :dispatch [:activity-center.notifications/fetch-unread-count]})) - -(rf/defn show-toasts - {:events [:activity-center.notifications/show-toasts]} - [{:keys [db]} new-notifications] - (let [my-public-key (get-in db [:multiaccount :public-key])] - (reduce (fn [cofx {:keys [author type accepted dismissed message name] :as x}] - (cond - (and (not= author my-public-key) - (= type types/contact-request) - (not accepted) - (not dismissed)) - (toasts/upsert cofx - {:icon :placeholder - :icon-color colors/primary-50-opa-40 - :title (i18n/label :t/contact-request-sent-toast - {:name name}) - :text (get-in message [:content :text])}) - - (and (= author my-public-key) ;; we show it for user who sent the request - (= type types/contact-request) - accepted - (not dismissed)) - (toasts/upsert cofx - {:icon :placeholder - :icon-color colors/primary-50-opa-40 - :title (i18n/label :t/contact-request-accepted-toast - {:name (:alias message)})}) - - :else - cofx)) - {:db db} - new-notifications))) + {:db (update-in db + [:activity-center :notifications] + update-notifications + new-notifications + (get-in db [:activity-center :filter])) + :dispatch-n [[:activity-center.notifications/fetch-unread-count] + [:activity-center.notifications/fetch-pending-contact-requests]]})) (rf/defn notifications-reconcile-from-response {:events [:activity-center/reconcile-notifications-from-response]} [cofx response] (->> response :activityCenterNotifications - (map data-store.activities/<-rpc) + (map activities/<-rpc) (notifications-reconcile cofx))) -(defn- remove-pending-contact-request - [notifications contact-id] - (remove #(= contact-id (:author %)) - notifications)) - (rf/defn notifications-remove-pending-contact-request {:events [:activity-center/remove-pending-contact-request]} [{:keys [db]} contact-id] - {:db (-> db - (update-in [:activity-center :notifications types/no-type :all :data] - remove-pending-contact-request - contact-id) - (update-in [:activity-center :notifications types/no-type :unread :data] - remove-pending-contact-request - contact-id) - (update-in [:activity-center :notifications types/contact-request :all :data] - remove-pending-contact-request - contact-id) - (update-in [:activity-center :notifications types/contact-request :unread :data] - remove-pending-contact-request - contact-id))}) + {:db (update-in db + [:activity-center :notifications] + (fn [notifications] + (remove #(activities/pending-contact-request? contact-id %) + notifications)))}) ;;;; Status changes (read/dismissed/deleted) (defn- get-notification [db notification-id] - (->> (get-in db - [:activity-center - :notifications - (get-in db [:activity-center :filter :type]) - (get-in db [:activity-center :filter :status]) - :data]) + (->> (get-in db [:activity-center :notifications]) (filter #(= notification-id (:id %))) first)) @@ -237,20 +169,23 @@ {:db (-> db (update-in [:activity-center :notifications] update-notifications - notifications) + notifications + (get-in db [:activity-center :filter])) (update :activity-center dissoc :mark-all-as-read-undoable-till))}) (rf/defn mark-all-as-read-locally {:events [:activity-center.notifications/mark-all-as-read-locally]} [{:keys [db now]} get-toast-ui-props] - (let [unread-notifications (get-in db [:activity-center :notifications types/no-type :unread :data]) + (let [unread-notifications (filter #(not (:read %)) + (get-in db [:activity-center :notifications])) undo-time-limit-ms constants/activity-center-mark-all-as-read-undo-time-limit-ms undoable-till (+ now undo-time-limit-ms)] {:db (-> db (update-in [:activity-center :notifications] update-notifications - (data-store.activities/mark-notifications-as-read - unread-notifications)) + (activities/mark-notifications-as-read + unread-notifications) + (get-in db [:activity-center :filter])) (assoc-in [:activity-center :mark-all-as-read-undoable-till] undoable-till)) :dispatch [:toasts/upsert @@ -379,7 +314,7 @@ (def start-or-end-cursor "") -(defn- valid-cursor? +(defn- fetch-more? [cursor] (and (some? cursor) (not= cursor start-or-end-cursor))) @@ -411,12 +346,10 @@ (rf/defn notifications-fetch [{:keys [db]} {:keys [cursor per-page filter-type filter-status reset-data?]}] - (when-not (get-in db [:activity-center :notifications filter-type filter-status :loading?]) + (when-not (get-in db [:activity-center :loading?]) (let [per-page (or per-page (defaults :notifications-per-page)) accepted? true] - {:db (assoc-in db - [:activity-center :notifications filter-type filter-status :loading?] - true) + {:db (assoc-in db [:activity-center :loading?] true) :json-rpc/call [{:method "wakuext_activityCenterNotificationsBy" :params [cursor per-page @@ -424,7 +357,7 @@ (status filter-status) accepted?] :on-success #(rf/dispatch [:activity-center.notifications/fetch-success - filter-type filter-status reset-data? %]) + reset-data? %]) :on-error #(rf/dispatch [:activity-center.notifications/fetch-error filter-type filter-status %])}]}))) @@ -452,8 +385,8 @@ {:events [:activity-center.notifications/fetch-next-page]} [{:keys [db] :as cofx}] (let [{:keys [type status]} (get-in db [:activity-center :filter]) - {:keys [cursor]} (get-in db [:activity-center :notifications type status])] - (when (valid-cursor? cursor) + cursor (get-in db [:activity-center :cursor])] + (when (fetch-more? cursor) (notifications-fetch cofx {:cursor cursor :filter-type type @@ -462,36 +395,59 @@ (rf/defn notifications-fetch-success {:events [:activity-center.notifications/fetch-success]} - [{:keys [db]} - filter-type - filter-status - reset-data? - {:keys [cursor notifications]}] - (let [processed (map data-store.activities/<-rpc notifications)] + [{:keys [db]} reset-data? {:keys [cursor notifications]}] + (let [processed (map activities/<-rpc notifications)] {:db (-> db - (assoc-in [:activity-center :notifications filter-type filter-status :cursor] cursor) - (update-in [:activity-center :notifications filter-type filter-status] dissoc :loading?) - (update-in [:activity-center :notifications filter-type filter-status :data] + (assoc-in [:activity-center :cursor] cursor) + (update :activity-center dissoc :loading?) + (update-in [:activity-center :notifications] (if reset-data? (constantly processed) - #(concat %1 processed))))})) + #(concat % processed))))})) -(rf/defn notifications-fetch-unread-contact-requests +(rf/defn notifications-fetch-pending-contact-requests "Unread contact requests are, in practical terms, the same as pending contact - requests in the new Activity Center, because pending contact requests are - always marked as unread, and once the user declines/accepts the request, they - are marked as read. + requests in the Activity Center, because pending contact requests are always + marked as unread in status-go, and once the user declines/accepts the request, + they are marked as read. If this relationship ever changes, we will probably need to change the backend to explicitly support fetching notifications for 'pending' contact requests." - {:events [:activity-center.notifications/fetch-unread-contact-requests]} - [cofx] - (notifications-fetch cofx - {:cursor start-or-end-cursor - :filter-status :unread - :filter-type types/contact-request - :per-page 20 - :reset-data? true})) + {:events [:activity-center.notifications/fetch-pending-contact-requests]} + [{:keys [db]}] + (let [accepted? true] + {:db (assoc-in db [:activity-center :loading?] true) + :json-rpc/call + [{:method "wakuext_activityCenterNotificationsBy" + :params [start-or-end-cursor + 20 + [types/contact-request] + (status :unread) + accepted?] + :on-success #(rf/dispatch [:activity-center.notifications/fetch-pending-contact-requests-success + %]) + :on-error #(rf/dispatch [:activity-center.notifications/fetch-error + types/contact-request :unread %])}]})) + +(rf/defn notifications-fetch-pending-contact-requests-success + {:events [:activity-center.notifications/fetch-pending-contact-requests-success]} + [{:keys [db]} {:keys [notifications]}] + {:db (-> db + (update :activity-center dissoc :loading?) + (assoc-in [:activity-center :contact-requests] + (->> notifications + (map activities/<-rpc) + (filter (fn [notification] + (= constants/contact-request-message-state-pending + (get-in notification [:message :contact-request-state])))))))}) + +(rf/defn notifications-fetch-error + {:events [:activity-center.notifications/fetch-error]} + [{:keys [db]} error] + (log/warn "Failed to load Activity Center notifications" error) + {:db (update db :activity-center dissoc :loading?)}) + +;;;; Unread counters (rf/defn notifications-fetch-unread-count {:events [:activity-center.notifications/fetch-unread-count]} @@ -521,8 +477,36 @@ (log/error "Failed to fetch count of notifications" {:error error}) nil) -(rf/defn notifications-fetch-error - {:events [:activity-center.notifications/fetch-error]} - [{:keys [db]} filter-type filter-status error] - (log/warn "Failed to load Activity Center notifications" error) - {:db (update-in db [:activity-center :notifications filter-type filter-status] dissoc :loading?)}) +;;;; Toasts + +(rf/defn show-toasts + {:events [:activity-center.notifications/show-toasts]} + [{:keys [db]} new-notifications] + (let [my-public-key (get-in db [:multiaccount :public-key])] + (reduce (fn [cofx {:keys [author type accepted dismissed message name] :as x}] + (cond + (and (not= author my-public-key) + (= type types/contact-request) + (not accepted) + (not dismissed)) + (toasts/upsert cofx + {:icon :placeholder + :icon-color colors/primary-50-opa-40 + :title (i18n/label :t/contact-request-sent-toast + {:name name}) + :text (get-in message [:content :text])}) + + (and (= author my-public-key) ;; we show it for user who sent the request + (= type types/contact-request) + accepted + (not dismissed)) + (toasts/upsert cofx + {:icon :placeholder + :icon-color colors/primary-50-opa-40 + :title (i18n/label :t/contact-request-accepted-toast + {:name (:alias message)})}) + + :else + cofx)) + {:db db} + new-notifications))) diff --git a/src/status_im2/contexts/activity_center/events_test.cljs b/src/status_im2/contexts/activity_center/events_test.cljs index d6ad9c4172..6b5525f118 100644 --- a/src/status_im2/contexts/activity_center/events_test.cljs +++ b/src/status_im2/contexts/activity_center/events_test.cljs @@ -3,7 +3,6 @@ [status-im2.constants :as constants] status-im.events [test-helpers.unit :as h] - [status-im2.contexts.activity-center.events :as activity-center] [status-im2.contexts.activity-center.notification-types :as types] [utils.re-frame :as rf])) @@ -53,15 +52,13 @@ (testing "opens the activity center without custom filters" (h/run-test-sync - (let [spy-queue (atom []) - existing-filters {:status :all}] + (let [spy-queue (atom [])] (setup) (h/spy-fx spy-queue :show-popover) - (rf/dispatch [:test/assoc-in [:activity-center :filter] existing-filters]) (rf/dispatch [:activity-center/open]) - (is (= existing-filters + (is (= {:status :unread :type types/no-type} (get-in (h/db) [:activity-center :filter]))) (is (= [{:id :show-popover :args nil}] @spy-queue)))))) @@ -72,16 +69,10 @@ (setup) (let [spy-queue (atom [])] (h/spy-fx spy-queue :json-rpc/call) - (let [notifications {types/one-to-one-chat - {:all {:cursor "" - :data [{:id notification-id - :read false - :type types/one-to-one-chat}]} - :unread {:cursor "" :data []}}}] - (rf/dispatch [:test/assoc-in [:activity-center] - {:notifications notifications - :filter {:type types/one-to-one-chat - :status :all}}]) + (let [notifications [{:id notification-id + :read false + :type types/one-to-one-chat}]] + (rf/dispatch [:test/assoc-in [:activity-center :notifications] notifications]) (rf/dispatch [:activity-center.notifications/mark-as-read "0x666"]) @@ -98,30 +89,15 @@ new-notif-2 (assoc notif-2 :read true)] (h/stub-fx-with-callbacks :json-rpc/call :on-success (constantly nil)) (rf/dispatch [:test/assoc-in [:activity-center] - {:notifications {types/one-to-one-chat - {:all {:cursor "" :data [notif-3 notif-2 notif-1]} - :unread {:cursor "" :data [notif-3 notif-2]}}} - :filter {:type types/one-to-one-chat - :status :unread}}]) + {:filter {:status :all :type types/no-type} + :notifications [notif-3 notif-2 notif-1]}]) (rf/dispatch [:activity-center.notifications/mark-as-read (:id notif-2)]) - (is (= {types/one-to-one-chat - {:all {:cursor "" :data [notif-3 new-notif-2 notif-1]} - :unread {:cursor "" :data [notif-3]}} - - types/no-type - {:all {:data [new-notif-2]} - :unread {:data []}}} + (is (= [notif-3 new-notif-2 notif-1] (get-in (h/db) [:activity-center :notifications]))) (rf/dispatch [:activity-center.notifications/mark-as-read (:id notif-3)]) - (is (= {types/one-to-one-chat - {:all {:cursor "" :data [new-notif-3 new-notif-2 notif-1]} - :unread {:cursor "" :data []}} - - types/no-type - {:all {:data [new-notif-3 new-notif-2]} - :unread {:data []}}} + (is (= [new-notif-3 new-notif-2 notif-1] (get-in (h/db) [:activity-center :notifications])))))) (testing "logs on failure" @@ -131,15 +107,10 @@ :action :notification/mark-as-read :before-test (fn [] (rf/dispatch - [:test/assoc-in [:activity-center] - {:notifications {types/one-to-one-chat - {:all {:cursor "" - :data [{:id notification-id - :read false - :type types/one-to-one-chat}]} - :unread {:cursor "" :data []}}} - :filter {:type types/one-to-one-chat - :status :all}}]))}))) + [:test/assoc-in [:activity-center :notifications] + [{:id notification-id + :read false + :type types/one-to-one-chat}]]))}))) ;;;; Acceptance/dismissal @@ -147,27 +118,25 @@ (testing "marks notification as accepted and read, then reconciles" (h/run-test-sync (setup) - (let [notif-1 {:id "0x1" :type types/private-group-chat} - notif-2 {:id "0x2" :type types/private-group-chat} - notif-3 {:id "0x3" :type types/admin} - notif-2-new (assoc notif-2 :accepted true :read true)] + (let [notif-1 {:id "0x1" :type types/private-group-chat} + notif-2 {:id "0x2" :type types/private-group-chat} + notif-2-accepted (assoc notif-2 :accepted true :read true)] (h/stub-fx-with-callbacks :json-rpc/call :on-success (constantly notif-2)) (rf/dispatch [:test/assoc-in [:activity-center] - {:notifications {types/membership - {:unread {:cursor "" :data [notif-2 notif-1]}} - - types/admin - {:all {:cursor "" :data [notif-3]}}} - :filter {:type types/membership - :status :unread}}]) + {:filter {:type types/no-type :status :all} + :notifications [notif-2 notif-1]}]) (rf/dispatch [:activity-center.notifications/accept (:id notif-2)]) - (is (= {types/no-type {:all {:data [notif-2-new]} - :unread {:data []}} - types/membership {:all {:data [notif-2-new]} - :unread {:cursor "" :data [notif-1]}} - types/admin {:all {:cursor "" :data [notif-3]}}} + (is (= [notif-2-accepted notif-1] + (get-in (h/db) [:activity-center :notifications]))) + + ;; Ignores accepted notification if the Unread filter is enabled because + ;; accepted notifications are also marked as read in status-go. + (rf/dispatch [:test/assoc-in [:activity-center :filter] + {:filter {:type types/no-type :status :unread}}]) + (rf/dispatch [:activity-center.notifications/accept (:id notif-2)]) + (is (= [notif-1] (get-in (h/db) [:activity-center :notifications])))))) (testing "logs on failure" @@ -184,24 +153,12 @@ notif-2 {:id "0x2" :type types/admin} dismissed-notif-1 (assoc notif-1 :dismissed true)] (h/stub-fx-with-callbacks :json-rpc/call :on-success (constantly notif-2)) - (rf/dispatch [:test/assoc-in [:activity-center] - {:notifications {types/no-type - {:all {:cursor "" :data [notif-2 notif-1]}} - - types/membership - {:unread {:cursor "" :data [notif-1]}}} - :filter {:type types/membership - :status :unread}}]) + (rf/dispatch [:test/assoc-in [:activity-center :notifications] + [notif-2 notif-1]]) (rf/dispatch [:activity-center.notifications/dismiss (:id notif-1)]) - (is (= {types/no-type - {:all {:cursor "" :data [notif-2 dismissed-notif-1]} - :unread {:data [dismissed-notif-1]}} - - types/membership - {:all {:data [dismissed-notif-1]} - :unread {:cursor "" :data [dismissed-notif-1]}}} + (is (= [notif-2 dismissed-notif-1] (get-in (h/db) [:activity-center :notifications])))))) (testing "logs on failure" @@ -254,36 +211,23 @@ :timestamp 1666647286000 :type types/contact-verification}) -(defn test-contact-verification-event - [{:keys [event expected-rpc-call]}] - (h/run-test-sync - (setup) - (let [spy-queue (atom [])] - (h/stub-fx-with-callbacks :json-rpc/call - :on-success - (constantly contact-verification-rpc-response)) - (h/spy-fx spy-queue :json-rpc/call) - (rf/dispatch event) - - (is (= {types/no-type - {:all {:data [contact-verification-expected-notification]} - :unread {:data []}} - types/contact-verification - {:all {:data [contact-verification-expected-notification]} - :unread {:data []}}} - (get-in (h/db) [:activity-center :notifications]))) - - (is (= expected-rpc-call - (-> @spy-queue - (get-in [0 :args 0]) - (select-keys [:method :params]))))))) - (deftest contact-verification-decline-test (testing "declines notification and reconciles" - (test-contact-verification-event - {:event [:activity-center.contact-verification/decline notification-id] - :expected-rpc-call {:method "wakuext_declineContactVerificationRequest" - :params [notification-id]}})) + (h/run-test-sync + (setup) + (let [spy-queue (atom [])] + (h/stub-fx-with-callbacks :json-rpc/call + :on-success + (constantly contact-verification-rpc-response)) + (h/spy-fx spy-queue :json-rpc/call) + (rf/dispatch [:test/assoc-in [:activity-center] + {:filter {:type types/contact-verification :status :all}}]) + + (rf/dispatch [:activity-center.contact-verification/decline notification-id]) + + (is (= [contact-verification-expected-notification] + (get-in (h/db) [:activity-center :notifications])))))) + (testing "logs on failure" (test-log-on-failure {:notification-id notification-id @@ -293,10 +237,21 @@ (deftest contact-verification-reply-test (testing "sends reply and reconciles" (let [reply "any answer"] - (test-contact-verification-event - {:event [:activity-center.contact-verification/reply notification-id reply] - :expected-rpc-call {:method "wakuext_acceptContactVerificationRequest" - :params [notification-id reply]}}))) + (h/run-test-sync + (setup) + (let [spy-queue (atom [])] + (h/stub-fx-with-callbacks :json-rpc/call + :on-success + (constantly contact-verification-rpc-response)) + (h/spy-fx spy-queue :json-rpc/call) + (rf/dispatch [:test/assoc-in [:activity-center] + {:filter {:type types/contact-verification :status :all}}]) + + (rf/dispatch [:activity-center.contact-verification/reply notification-id reply]) + + (is (= [contact-verification-expected-notification] + (get-in (h/db) [:activity-center :notifications]))))))) + (testing "logs on failure" (test-log-on-failure {:notification-id notification-id @@ -304,11 +259,25 @@ :action :contact-verification/reply}))) (deftest contact-verification-mark-as-trusted-test - (testing "marks notification as trusted and reconciles" - (test-contact-verification-event - {:event [:activity-center.contact-verification/mark-as-trusted notification-id] - :expected-rpc-call {:method "wakuext_verifiedTrusted" - :params [{:id notification-id}]}})) + (testing "app db reconciliation" + (h/run-test-sync + (setup) + (h/stub-fx-with-callbacks :json-rpc/call + :on-success + (constantly contact-verification-rpc-response)) + + ;; With "Unread" filter disabled + (rf/dispatch [:test/assoc-in [:activity-center] + {:filter {:type types/no-type :status :all}}]) + (rf/dispatch [:activity-center.contact-verification/mark-as-trusted notification-id]) + (is (= [contact-verification-expected-notification] + (get-in (h/db) [:activity-center :notifications]))) + + ;; With "Unread" filter enabled + (rf/dispatch [:test/assoc-in [:activity-center :filter :status] :unread]) + (rf/dispatch [:activity-center.contact-verification/mark-as-trusted notification-id]) + (is (= [] (get-in (h/db) [:activity-center :notifications]))))) + (testing "logs on failure" (test-log-on-failure {:notification-id notification-id @@ -316,11 +285,26 @@ :action :contact-verification/mark-as-trusted}))) (deftest contact-verification-mark-as-untrustworthy-test - (testing "marks notification as untrustworthy and reconciles" - (test-contact-verification-event - {:event [:activity-center.contact-verification/mark-as-untrustworthy notification-id] - :expected-rpc-call {:method "wakuext_verifiedUntrustworthy" - :params [{:id notification-id}]}})) + (testing "app db reconciliation" + (h/run-test-sync + (setup) + (h/stub-fx-with-callbacks + :json-rpc/call + :on-success + (constantly contact-verification-rpc-response)) + + ;; With "Unread" filter disabled + (rf/dispatch [:test/assoc-in [:activity-center] + {:filter {:type types/no-type :status :all}}]) + (rf/dispatch [:activity-center.contact-verification/mark-as-untrustworthy notification-id]) + (is (= [contact-verification-expected-notification] + (get-in (h/db) [:activity-center :notifications]))) + + ;; With "Unread" filter enabled + (rf/dispatch [:test/assoc-in [:activity-center :filter :status] :unread]) + (rf/dispatch [:activity-center.contact-verification/mark-as-untrustworthy notification-id]) + (is (= [] (get-in (h/db) [:activity-center :notifications]))))) + (testing "logs on failure" (test-log-on-failure {:notification-id notification-id @@ -330,132 +314,100 @@ ;;;; Notification reconciliation (deftest notifications-reconcile-test - (testing "does nothing when there are no new notifications" - (h/run-test-sync - (setup) - (let [notifications {types/one-to-one-chat - {:all {:cursor "" - :data [{:id "0x1" - :read true - :type types/one-to-one-chat} - {:id "0x2" - :read false - :type types/one-to-one-chat}]} - :unread {:cursor "" - :data [{:id "0x3" - :read false - :type types/one-to-one-chat}]}} - types/private-group-chat - {:unread {:cursor "" - :data [{:id "0x4" - :read false - :type types/private-group-chat}]}}}] - (rf/dispatch [:test/assoc-in [:activity-center :notifications] notifications]) - - (rf/dispatch [:activity-center.notifications/reconcile nil]) - - (is (= notifications (get-in (h/db) [:activity-center :notifications])))))) - - (testing "removes deleted notifications" - (h/run-test-sync - (setup) - (let [notif-1 {:id "0x1" :read true :type types/one-to-one-chat} - notif-2 {:id "0x2" :read false :type types/one-to-one-chat} - notif-3 {:id "0x3" :read false :type types/system :dismissed true} - notif-4 {:id "0x4" :read true :type types/system} - notif-5 {:id "0x5" :read false :type types/system :accepted true}] - (rf/dispatch [:test/assoc-in [:activity-center :notifications] - {types/one-to-one-chat - {:all {:cursor "" :data [notif-1 notif-2]} - :unread {:cursor "" :data [notif-2]}} - types/system - {:all {:cursor "" :data [notif-4]} - :unread {:cursor "" :data [notif-3 notif-5]}}}]) - - (rf/dispatch [:activity-center.notifications/reconcile - [(assoc notif-1 :deleted true) - (assoc notif-4 :deleted true) - notif-5]]) - - (is (= {types/no-type - {:all {:data [notif-5]} - :unread {:data [notif-5]}} - types/one-to-one-chat - {:all {:cursor "" :data [notif-2]} - :unread {:cursor "" :data [notif-2]}} - types/system - {:all {:cursor "" :data [notif-5]} - :unread {:cursor "" :data [notif-5 notif-3]}}} - (get-in (h/db) [:activity-center :notifications])))))) - - (testing "replaces old notifications with newly arrived ones" + (testing "All tab + All filter" (h/run-test-sync (setup) (let [notif-1 {:id "0x1" :read true :type types/one-to-one-chat} - notif-4 {:id "0x4" :read false :type types/system} - notif-6 {:id "0x6" :read false :type types/system} - new-notif-1 (assoc notif-1 :last-message {}) - new-notif-4 (assoc notif-4 :author "0xabc")] - (rf/dispatch [:test/assoc-in [:activity-center :notifications] - {types/no-type - {:all {:cursor "" :data [notif-1]} - :unread {:cursor "" :data [notif-4 notif-6]}} - types/one-to-one-chat - {:all {:cursor "" :data [notif-1]}} - types/system - {:unread {:cursor "" :data [notif-4 notif-6]}}}]) + notif-2 {:id "0x2" :read false :type types/system} + new-notif-3 {:id "0x3" :read false :type types/system} + new-notif-4 {:id "0x4" :read true :type types/system} + new-notif-2 (assoc notif-2 :read true)] + (rf/dispatch [:test/assoc-in [:activity-center] + {:filter {:type types/no-type :status :all} + :notifications [notif-2 notif-1]}]) - (rf/dispatch [:activity-center.notifications/reconcile [new-notif-1 new-notif-4 notif-6]]) + (rf/dispatch + [:activity-center.notifications/reconcile + [(assoc notif-1 :deleted true) ; will be removed + new-notif-2 + new-notif-3 + new-notif-4]]) - (is (= {types/no-type - {:all {:cursor "" :data [notif-6 new-notif-4 new-notif-1]} - :unread {:cursor "" :data [notif-6 new-notif-4]}} - types/one-to-one-chat - {:all {:cursor "" :data [new-notif-1]} - :unread {:data []}} - types/system - {:all {:data [notif-6 new-notif-4]} - :unread {:cursor "" :data [notif-6 new-notif-4]}}} + (is (= [new-notif-4 new-notif-3 new-notif-2] (get-in (h/db) [:activity-center :notifications])))))) - (testing "reconciles notifications that switched their read/unread status" + (testing "All tab + Unread filter" (h/run-test-sync (setup) - (let [notif-1 {:id "0x1" :read true :type types/one-to-one-chat} - new-notif-1 (assoc notif-1 :read false)] - (rf/dispatch [:test/assoc-in [:activity-center :notifications] - {types/one-to-one-chat - {:all {:cursor "" :data [notif-1]}}}]) + (let [notif-1 {:id "0x1" :read false :type types/one-to-one-chat} + notif-2 {:id "0x2" :read false :type types/system} + new-notif-2 (assoc notif-2 :read true) + new-notif-3 {:id "0x3" :read false :type types/system} + new-notif-4 {:id "0x4" :read true :type types/system} + notif-5 {:id "0x5" :type types/system}] + (rf/dispatch [:test/assoc-in [:activity-center] + {:filter {:type types/no-type :status :unread} + :notifications [notif-5 notif-2 notif-1]}]) - (rf/dispatch [:activity-center.notifications/reconcile [new-notif-1]]) + (rf/dispatch + [:activity-center.notifications/reconcile + [new-notif-2 ; will be removed because it's read + new-notif-3 ; will be inserted + new-notif-4 ; will be ignored because it's read + (assoc notif-5 :deleted true) ; will be removed + ]]) - (is (= {types/no-type - {:all {:data [new-notif-1]} - :unread {:data [new-notif-1]}} - - types/one-to-one-chat - {:all {:cursor "" :data [new-notif-1]} - :unread {:data [new-notif-1]}}} + (is (= [new-notif-3 notif-1] (get-in (h/db) [:activity-center :notifications])))))) - (testing "membership notifications" + (testing "Contact request tab + All filter" (h/run-test-sync (setup) - (let [notif {:read false - :dismissed false - :accepted false - :type types/private-group-chat - :id "0x7" - :timestamp 1673445663000}] - (rf/dispatch [:activity-center.notifications/reconcile [notif]]) + (let [notif-1 {:id "0x1" :read true :type types/contact-request} + notif-2 {:id "0x2" :read false :type types/contact-request} + new-notif-2 (assoc notif-2 :read true) + new-notif-3 {:id "0x3" :read false :type types/contact-request} + new-notif-4 {:id "0x4" :read true :type types/system} + notif-5 {:id "0x5" :read false :type types/contact-request}] + (rf/dispatch [:test/assoc-in [:activity-center] + {:filter {:type types/contact-request :status :all} + :notifications [notif-5 notif-2 notif-1]}]) - (is (= {types/no-type - {:all {:data [notif]} - :unread {:data [notif]}} + (rf/dispatch + [:activity-center.notifications/reconcile + [new-notif-2 ; will be updated + new-notif-3 ; will be inserted + new-notif-4 ; will be ignored because it's not a contact request + (assoc notif-5 :deleted true) ; will be removed + ]]) - types/membership - {:all {:data [notif]} - :unread {:data [notif]}}} + (is (= [new-notif-3 new-notif-2 notif-1] + (get-in (h/db) [:activity-center :notifications])))))) + + (testing "Contact request tab + Unread filter" + (h/run-test-sync + (setup) + (let [notif-1 {:id "0x1" :read false :type types/contact-request} + notif-2 {:id "0x2" :read false :type types/contact-request} + new-notif-2 (assoc notif-2 :read true) + new-notif-3 {:id "0x3" :read false :type types/contact-request} + new-notif-4 {:id "0x4" :read true :type types/contact-request} + new-notif-5 {:id "0x5" :read true :type types/system} + notif-6 {:id "0x6" :read false :type types/contact-request}] + (rf/dispatch [:test/assoc-in [:activity-center] + {:filter {:type types/contact-request :status :unread} + :notifications [notif-6 notif-2 notif-1]}]) + + (rf/dispatch + [:activity-center.notifications/reconcile + [new-notif-2 ; will be removed because it's read + new-notif-3 ; will be inserted + new-notif-4 ; will be ignored because it's read + new-notif-5 ; will be ignored because it's not a contact request + (assoc notif-6 :deleted true) ; will be removed + ]]) + + (is (= [new-notif-3 notif-1] (get-in (h/db) [:activity-center :notifications])))))) ;; Sorting by timestamp and ID is compatible with what the backend does when @@ -463,56 +415,38 @@ (testing "sorts notifications by timestamp and id in descending order" (h/run-test-sync (setup) - (let [notif-1 {:id "0x1" :read true :type types/one-to-one-chat :timestamp 1} - notif-2 {:id "0x2" :read true :type types/one-to-one-chat :timestamp 1} - notif-3 {:id "0x3" :read false :type types/one-to-one-chat :timestamp 50} - notif-4 {:id "0x4" :read false :type types/one-to-one-chat :timestamp 100} - notif-5 {:id "0x5" :read false :type types/one-to-one-chat :timestamp 100} + (let [notif-1 {:id "0x1" :timestamp 1} + notif-2 {:id "0x2" :timestamp 1} + notif-3 {:id "0x3" :timestamp 50} + notif-4 {:id "0x4" :timestamp 100} + notif-5 {:id "0x5" :timestamp 100} new-notif-1 (assoc notif-1 :last-message {}) new-notif-4 (assoc notif-4 :last-message {})] (rf/dispatch [:test/assoc-in [:activity-center :notifications] - {types/one-to-one-chat - {:all {:cursor "" :data [notif-1 notif-2]} - :unread {:cursor "" :data [notif-3 notif-4 notif-5]}}}]) + [notif-1 notif-3 notif-4 notif-2 notif-5]]) (rf/dispatch [:activity-center.notifications/reconcile [new-notif-1 new-notif-4]]) - (is (= {types/no-type - {:all {:data [new-notif-4 new-notif-1]} - :unread {:data [new-notif-4]}} - types/one-to-one-chat - {:all {:cursor "" :data [new-notif-4 notif-2 new-notif-1]} - :unread {:cursor "" :data [notif-5 new-notif-4 notif-3]}}} + (is (= [notif-5 new-notif-4 notif-3 notif-2 new-notif-1] (get-in (h/db) [:activity-center :notifications]))))))) (deftest remove-pending-contact-request-test (testing "removes notification from all related filter types and status" (h/run-test-sync (setup) - (let [contact-pub-key "0x99" - notif-1 {:id "0x1" :read true :type types/contact-request} - notif-2 {:id "0x2" :read false :type types/contact-request :author contact-pub-key} - notif-3 {:id "0x3" :read false :type types/private-group-chat} - notifications {types/contact-request - {:all {:cursor "" :data [notif-2 notif-1]} - :unread {:cursor "" :data [notif-2]}} - types/private-group-chat - {:unread {:cursor "" :data [notif-3]}} - types/no-type - {:all {:cursor "" :data [notif-3 notif-2 notif-1]} - :unread {:cursor "" :data [notif-2 notif-3]}}}] - (rf/dispatch [:test/assoc-in [:activity-center :notifications] notifications]) + (let [author "0x99" + notif-1 {:id "0x1" :read true :type types/contact-request} + notif-2 {:id "0x2" :read false :type types/contact-request :author author} + notif-3 {:id "0x3" :read false :type types/private-group-chat :author author}] + (rf/dispatch [:test/assoc-in [:activity-center :notifications] + [notif-3 ; will be ignored because it's not a contact request + notif-2 ; will be removed + notif-1 ; will be ignored because it's not from the same author + ]]) - (rf/dispatch [:activity-center/remove-pending-contact-request contact-pub-key]) + (rf/dispatch [:activity-center/remove-pending-contact-request author]) - (is (= {types/contact-request - {:all {:cursor "" :data [notif-1]} - :unread {:cursor "" :data []}} - types/private-group-chat - {:unread {:cursor "" :data [notif-3]}} - types/no-type - {:all {:cursor "" :data [notif-3 notif-1]} - :unread {:cursor "" :data [notif-3]}}} + (is (= [notif-3 notif-1] (get-in (h/db) [:activity-center :notifications]))))))) ;;;; Notifications fetching and pagination @@ -538,19 +472,18 @@ (is (= :unread (get-in (h/db) [:activity-center :filter :status]))) (is (= "" (get-in @spy-queue [0 :args 0 :params 0])) "Should be called with empty cursor when fetching first page") - (is (= {types/one-to-one-chat - {:unread {:cursor "10" - :data [{:chat-id "0x9" - :chat-name nil - :chat-type types/one-to-one-chat - :group-chat false - :id "0x1" - :public? false - :last-message nil - :message nil - :read false - :reply-message nil - :type types/one-to-one-chat}]}}} + (is (= "10" (get-in (h/db) [:activity-center :cursor]))) + (is (= [{:chat-id "0x9" + :chat-name nil + :chat-type types/one-to-one-chat + :group-chat false + :id "0x1" + :public? false + :last-message nil + :message nil + :read false + :reply-message nil + :type types/one-to-one-chat}] (get-in (h/db) [:activity-center :notifications])))))) (testing "does not fetch next page when pagination cursor reached the end" @@ -558,36 +491,9 @@ (setup) (let [spy-queue (atom [])] (h/spy-fx spy-queue :json-rpc/call) - (rf/dispatch [:test/assoc-in [:activity-center :filter :status] - :unread]) - (rf/dispatch [:test/assoc-in [:activity-center :filter :type] - types/one-to-one-chat]) - (rf/dispatch [:test/assoc-in - [:activity-center :notifications types/one-to-one-chat :unread :cursor] - ""]) + (rf/dispatch [:test/assoc-in [:activity-center :cursor] ""]) (rf/dispatch [:activity-center.notifications/fetch-next-page]) - - (is (= [] @spy-queue))))) - - ;; The cursor can be nil sometimes because the reconciliation doesn't care - ;; about updating the cursor value, but we have to make sure the next page is - ;; only fetched if the current cursor is valid. - (testing "does not fetch next page when cursor is nil" - (h/run-test-sync - (setup) - (let [spy-queue (atom [])] - (h/spy-fx spy-queue :json-rpc/call) - (rf/dispatch [:test/assoc-in [:activity-center :filter :status] - :unread]) - (rf/dispatch [:test/assoc-in [:activity-center :filter :type] - types/one-to-one-chat]) - (rf/dispatch [:test/assoc-in - [:activity-center :notifications types/one-to-one-chat :unread :cursor] - nil]) - - (rf/dispatch [:activity-center.notifications/fetch-next-page]) - (is (= [] @spy-queue))))) (testing "fetches next page when pagination cursor is not empty" @@ -603,50 +509,27 @@ :read false :chatId "0x9"}]})) (h/spy-fx spy-queue :json-rpc/call) - (rf/dispatch [:test/assoc-in [:activity-center :filter :status] - :unread]) - (rf/dispatch [:test/assoc-in [:activity-center :filter :type] - types/mention]) - (rf/dispatch [:test/assoc-in [:activity-center :notifications types/mention :unread :cursor] - "10"]) + (rf/dispatch [:test/assoc-in [:activity-center] + {:filter {:status :unread :type types/mention} + :cursor "10"}]) (rf/dispatch [:activity-center.notifications/fetch-next-page]) (is (= "wakuext_activityCenterNotificationsBy" (get-in @spy-queue [0 :args 0 :method]))) (is (= "10" (get-in @spy-queue [0 :args 0 :params 0])) "Should be called with current cursor") - (is (= {types/mention - {:unread {:cursor "" - :data [{:chat-id "0x9" - :chat-name nil - :chat-type 3 - :id "0x1" - :last-message nil - :message nil - :read false - :reply-message nil - :type types/mention}]}}} + (is (= "" (get-in (h/db) [:activity-center :cursor]))) + (is (= [{:chat-id "0x9" + :chat-name nil + :chat-type 3 + :id "0x1" + :last-message nil + :message nil + :read false + :reply-message nil + :type types/mention}] (get-in (h/db) [:activity-center :notifications])))))) - (testing "does not fetch next page while it is still loading" - (h/run-test-sync - (setup) - (let [spy-queue (atom [])] - (h/spy-fx spy-queue :json-rpc/call) - (rf/dispatch [:test/assoc-in [:activity-center :filter :status] - :all]) - (rf/dispatch [:test/assoc-in [:activity-center :filter :type] - types/one-to-one-chat]) - (rf/dispatch [:test/assoc-in [:activity-center :notifications types/one-to-one-chat :all :cursor] - "10"]) - (rf/dispatch [:test/assoc-in - [:activity-center :notifications types/one-to-one-chat :all :loading?] - true]) - - (rf/dispatch [:activity-center.notifications/fetch-next-page]) - - (is (= [] @spy-queue))))) - (testing "resets loading flag after an error" (h/run-test-sync (setup) @@ -654,41 +537,19 @@ (h/stub-fx-with-callbacks :json-rpc/call :on-error (constantly :fake-error)) (h/spy-event-fx spy-queue :activity-center.notifications/fetch-error) (h/spy-fx spy-queue :json-rpc/call) - (rf/dispatch [:test/assoc-in [:activity-center :filter :status] - :unread]) - (rf/dispatch [:test/assoc-in [:activity-center :filter :type] - types/one-to-one-chat]) - (rf/dispatch [:test/assoc-in - [:activity-center :notifications types/one-to-one-chat :unread :cursor] - ""]) + (rf/dispatch [:test/assoc-in [:activity-center] + {:filter {:status :unread :type types/one-to-one-chat} + :cursor ""}]) (rf/dispatch [:activity-center.notifications/fetch-first-page]) - (is (nil? (get-in (h/db) - [:activity-center :notifications types/one-to-one-chat :unread :loading?]))) + (is (nil? (get-in (h/db) [:activity-center :loading?]))) (is (= [:activity-center.notifications/fetch-error types/one-to-one-chat :unread :fake-error] (:args (last @spy-queue)))))))) -(deftest notifications-fetch-unread-contact-requests-test - (testing "fetches latest unread contact requests" - (let [actual (activity-center/notifications-fetch-unread-contact-requests {:db {}}) - per-page 20] - (is (= {:activity-center - {:notifications - {types/contact-request - {:unread {:loading? true}}}}} - (:db actual))) - - (is (= {:method "wakuext_activityCenterNotificationsBy" - :params ["" per-page [types/contact-request] activity-center/status-unread true]} - (-> actual - :json-rpc/call - first - (select-keys [:method :params]))))))) - (deftest notifications-fetch-unread-count-test (testing "fetches total notification count and store in db" (h/run-test-sync diff --git a/src/status_im2/contexts/activity_center/notification/contact_requests/view.cljs b/src/status_im2/contexts/activity_center/notification/contact_requests/view.cljs index 6472c94a48..f1e433c778 100644 --- a/src/status_im2/contexts/activity_center/notification/contact_requests/view.cljs +++ b/src/status_im2/contexts/activity_center/notification/contact_requests/view.cljs @@ -134,7 +134,7 @@ [gesture/touchable-without-feedback {:on-press (fn [] (rf/dispatch [:hide-popover]) - (rf/dispatch [:chat.ui/start-chat {:public-key author}]))} + (rf/dispatch [:chat.ui/start-chat author]))} [incoming-contact-request-view notification set-swipeable-height]] :else diff --git a/src/status_im2/contexts/activity_center/view.cljs b/src/status_im2/contexts/activity_center/view.cljs index b3ab5f133a..2272dead75 100644 --- a/src/status_im2/contexts/activity_center/view.cljs +++ b/src/status_im2/contexts/activity_center/view.cljs @@ -209,7 +209,7 @@ (rn/use-effect-once #(rf/dispatch [:activity-center.notifications/fetch-first-page])) [safe-area/consumer (fn [{:keys [top bottom]}] - (let [notifications (rf/sub [:activity-center/filtered-notifications]) + (let [notifications (rf/sub [:activity-center/notifications]) window-width (rf/sub [:dimensions/window-width])] [rn/view {:style (style/screen-container window-width top bottom)} [header request-close] diff --git a/src/status_im2/contexts/contacts/events.cljs b/src/status_im2/contexts/contacts/events.cljs index e9d4962e42..32ce589454 100644 --- a/src/status_im2/contexts/contacts/events.cljs +++ b/src/status_im2/contexts/contacts/events.cljs @@ -51,7 +51,8 @@ chats-js (.-chatsForContacts response-js) events (reduce (prepare-events-for-contact db chats-js) - [[:activity-center.notifications/fetch-unread-count]] + [[:activity-center.notifications/fetch-unread-count] + [:activity-center.notifications/fetch-pending-contact-requests]] contacts-cljs)] (js-delete response-js "contacts") (js-delete response-js "chatsForContacts") diff --git a/src/status_im2/subs/activity_center.cljs b/src/status_im2/subs/activity_center.cljs index 2694e55e77..2f49c29af1 100644 --- a/src/status_im2/subs/activity_center.cljs +++ b/src/status_im2/subs/activity_center.cljs @@ -1,6 +1,5 @@ (ns status-im2.subs.activity-center (:require [re-frame.core :as re-frame] - [status-im2.constants :as constants] [status-im2.contexts.activity-center.notification-types :as types])) (re-frame/reg-sub @@ -53,14 +52,6 @@ (fn [activity-center] (get-in activity-center [:filter :type] types/no-type))) -(re-frame/reg-sub - :activity-center/filtered-notifications - :<- [:activity-center/filter-type] - :<- [:activity-center/filter-status] - :<- [:activity-center/notifications] - (fn [[filter-type filter-status notifications]] - (get-in notifications [filter-type filter-status :data]))) - (re-frame/reg-sub :activity-center/filter-status-unread-enabled? :<- [:activity-center/filter-status] @@ -69,9 +60,6 @@ (re-frame/reg-sub :activity-center/pending-contact-requests - :<- [:activity-center/notifications] - (fn [notifications] - (filter (fn [{:keys [message]}] - (= constants/contact-request-message-state-pending - (:contact-request-state message))) - (get-in notifications [types/contact-request :unread :data])))) + :<- [:activity-center] + (fn [activity-center] + (:contact-requests activity-center))) diff --git a/src/status_im2/subs/activity_center_test.cljs b/src/status_im2/subs/activity_center_test.cljs index 7d93b25df3..cd03600adc 100644 --- a/src/status_im2/subs/activity_center_test.cljs +++ b/src/status_im2/subs/activity_center_test.cljs @@ -1,7 +1,6 @@ (ns status-im2.subs.activity-center-test (:require [cljs.test :refer [is testing]] [re-frame.db :as rf-db] - [status-im2.constants :as constants] [status-im2.contexts.activity-center.notification-types :as types] status-im2.subs.activity-center [test-helpers.unit :as h] @@ -64,27 +63,3 @@ types/admin 7}) (is (= 28 (rf/sub [sub-name])))) - -(h/deftest-sub :activity-center/pending-contact-requests - [sub-name] - (testing "returns only contact request notifications in the pending state" - (let [pending {:id "0x2" - :type types/contact-request - :message {:contact-request-state - constants/contact-request-message-state-pending}}] - (swap! rf-db/app-db assoc-in - [:activity-center :notifications types/contact-request :unread :data] - [{:id "0x1" - :type types/contact-request - :message {:contact-request-state constants/contact-request-message-state-none}} - pending - {:id "0x3" - :type types/contact-request - :message {:contact-request-state constants/contact-request-message-state-accepted}} - {:id "0x4" - :type types/contact-request - :message {:contact-request-state constants/contact-request-message-state-declined}} - {:id "0x5" - :type types/mention}]) - - (is (= [pending] (rf/sub [sub-name]))))))