From 1e4c79cf068ba3ca933a0f90c747bee2b64cf19c Mon Sep 17 00:00:00 2001
From: infinite-persistence <inf.persistence@gmail.com>
Date: Thu, 4 Mar 2021 19:00:15 +0800
Subject: [PATCH] Don't clear all notifications when only 1 is clicked.

## Issue:
Closes 5515: All videos marked as read when clicking a single notification from notification list

## Change:
- Augment `doReadNotifications` to only clear the given IDs. If the argument is `null` or is not a valid array (e.g. when used as a click handlers, the click event object is passed in), all notifications will be cleared.

- Augment `NOTIFICATION_READ_COMPLETED` to only clear the given IDs.

## Notes:
- Wasn't sure of the API will fail if the ID is invalid, so I start from `unreadNotifications` first, then only filtering it further with the given ID. Otherwise, we could just skip the `unreadNotifications` filtering.
---
 ui/redux/actions/notifications.js  | 24 +++++++++++++++---------
 ui/redux/reducers/notifications.js | 10 +++++++++-
 2 files changed, 24 insertions(+), 10 deletions(-)

diff --git a/ui/redux/actions/notifications.js b/ui/redux/actions/notifications.js
index 8a7d96b37..564ab35e3 100644
--- a/ui/redux/actions/notifications.js
+++ b/ui/redux/actions/notifications.js
@@ -76,21 +76,27 @@ export function doNotificationList() {
   };
 }
 
-export function doReadNotifications() {
+export function doReadNotifications(notificationsIds: Array<number>) {
   return (dispatch: Dispatch, getState: GetState) => {
     const state = getState();
     const notifications = selectNotifications(state);
-    const unreadNotifications =
-      notifications &&
-      notifications
-        .filter((notification) => !notification.is_read)
-        .map((notification) => notification.id)
-        .join(',');
+    const unreadNotifications = notifications && notifications.filter((notification) => !notification.is_read);
+
+    let ids;
+    if (notificationsIds && Array.isArray(notificationsIds) && notificationsIds.length !== 0) {
+      // Wipe specified notications.
+      ids = unreadNotifications
+        .filter((notification) => notificationsIds.includes(notification.id))
+        .map((notification) => notification.id);
+    } else {
+      // A null or invalid argument will wipe all unread notifications.
+      ids = unreadNotifications.map((notification) => notification.id);
+    }
 
     dispatch({ type: ACTIONS.NOTIFICATION_READ_STARTED });
-    return Lbryio.call('notification', 'edit', { notification_ids: unreadNotifications, is_read: true })
+    return Lbryio.call('notification', 'edit', { notification_ids: ids.join(','), is_read: true })
       .then(() => {
-        dispatch({ type: ACTIONS.NOTIFICATION_READ_COMPLETED });
+        dispatch({ type: ACTIONS.NOTIFICATION_READ_COMPLETED, data: { notificationIds: ids } });
       })
       .catch((error) => {
         dispatch({ type: ACTIONS.NOTIFICATION_READ_FAILED, data: { error } });
diff --git a/ui/redux/reducers/notifications.js b/ui/redux/reducers/notifications.js
index cf2208717..1807c2c73 100644
--- a/ui/redux/reducers/notifications.js
+++ b/ui/redux/reducers/notifications.js
@@ -55,8 +55,16 @@ export default handleActions(
     },
     [ACTIONS.NOTIFICATION_READ_COMPLETED]: (state, action) => {
       const { notifications } = state;
+      const { notificationIds } = action.data;
       const newNotifications =
-        notifications && notifications.map((notification) => ({ ...notification, is_read: true }));
+        notifications &&
+        notifications.map((notification) => {
+          if (notificationIds.includes(notification.id)) {
+            return { ...notification, is_read: true };
+          } else {
+            return { ...notification };
+          }
+        });
       return {
         ...state,
         notifications: newNotifications,