From 3bab4feeca77a0d1f86ab96d3b7e6072ca6a950c Mon Sep 17 00:00:00 2001 From: infinite-persistence Date: Thu, 25 Mar 2021 12:37:53 +0800 Subject: [PATCH] Update GUI to use queried notification filter. - Re-organize the return statement of 'NotificationsPage' a bit, otherwise the entire page will reload (blink) every time the drop-down value is changed due to the 'fetching' flag. - Retained the original behavior of (only showing a blank page + spinner) on the very first load. I think there is merit in not showing the buttons immediately (e.g. when not logged in and `/$/notifications` is accessed directly). --- static/app-strings.json | 4 +- ui/page/notifications/index.js | 4 +- ui/page/notifications/view.jsx | 192 +++++++++++++++++---------------- 3 files changed, 105 insertions(+), 95 deletions(-) diff --git a/static/app-strings.json b/static/app-strings.json index efcff16b8..8f73223d5 100644 --- a/static/app-strings.json +++ b/static/app-strings.json @@ -1358,8 +1358,8 @@ "Terms": "Terms", "Privacy Policy": "Privacy Policy", "Comment replies": "Comment replies", - "Daily watch availability": "Daily watch availability", - "Daily watch reminders": "Daily watch reminders", + "Replies": "Replies", + "Others": "Others", "New content": "New content", "No notifications": "No notifications", "Try selecting another filter.": "Try selecting another filter.", diff --git a/ui/page/notifications/index.js b/ui/page/notifications/index.js index d4b1d98a2..b33bb02db 100644 --- a/ui/page/notifications/index.js +++ b/ui/page/notifications/index.js @@ -1,6 +1,7 @@ import { connect } from 'react-redux'; import { selectNotifications, + selectNotificationsFiltered, selectIsFetchingNotifications, selectUnreadNotificationCount, selectUnseenNotificationCount, @@ -8,8 +9,9 @@ import { import { doReadNotifications, doNotificationList, doSeeAllNotifications } from 'redux/actions/notifications'; import NotificationsPage from './view'; -const select = state => ({ +const select = (state) => ({ notifications: selectNotifications(state), + notificationsFiltered: selectNotificationsFiltered(state), fetching: selectIsFetchingNotifications(state), unreadCount: selectUnreadNotificationCount(state), unseenCount: selectUnseenNotificationCount(state), diff --git a/ui/page/notifications/view.jsx b/ui/page/notifications/view.jsx index f586bee1e..176c2815f 100644 --- a/ui/page/notifications/view.jsx +++ b/ui/page/notifications/view.jsx @@ -9,128 +9,136 @@ import Button from 'component/button'; import usePersistedState from 'effects/use-persisted-state'; import Yrbl from 'component/yrbl'; import * as NOTIFICATIONS from 'constants/notifications'; +import useFetched from 'effects/use-fetched'; + +const RULE_LABELS = { + [NOTIFICATIONS.NOTIFICATION_RULE_NONE]: 'All', + [NOTIFICATIONS.NOTIFICATION_RULE_COMMENTS]: 'Comments', + [NOTIFICATIONS.NOTIFICATION_RULE_REPLIES]: 'Replies', + [NOTIFICATIONS.NOTIFICATION_RULE_FOLLOWERS]: 'Followers', + [NOTIFICATIONS.NOTIFICATION_RULE_NEW_CONTENT]: 'New content', + [NOTIFICATIONS.NOTIFICATION_RULE_OTHERS]: 'Others', +}; type Props = { notifications: Array, + notificationsFiltered: Array, fetching: boolean, unreadCount: number, unseenCount: number, doSeeAllNotifications: () => void, doReadNotifications: () => void, + doNotificationList: (string) => void, }; -const ALL_NOTIFICATIONS = 'all'; - export default function NotificationsPage(props: Props) { - const { notifications, fetching, unreadCount, unseenCount, doSeeAllNotifications, doReadNotifications } = props; - const hasNotifications = notifications.length > 0; - const [filterBy, setFilterBy] = usePersistedState('notifications--filter-by', 'all'); - const [filteredNotifications, setFilteredNotifications] = React.useState(notifications); - const isFiltered = filterBy !== ALL_NOTIFICATIONS; + const { + notifications, + notificationsFiltered, + fetching, + unreadCount, + unseenCount, + doSeeAllNotifications, + doReadNotifications, + doNotificationList, + } = props; - const NOTIFICATION_FILTER_TYPES = [ - ALL_NOTIFICATIONS, - NOTIFICATIONS.NOTIFICATION_CREATOR_SUBSCRIBER, - NOTIFICATIONS.NOTIFICATION_COMMENT, - NOTIFICATIONS.NOTIFICATION_REPLY, - NOTIFICATIONS.DAILY_WATCH_AVAILABLE, - NOTIFICATIONS.DAILY_WATCH_REMIND, - NOTIFICATIONS.NEW_CONTENT, - ]; + const initialFetchDone = useFetched(fetching); + const [rule, setRule] = usePersistedState('notifications--rule', NOTIFICATIONS.NOTIFICATION_RULE_NONE); + const isFiltered = rule !== NOTIFICATIONS.NOTIFICATION_RULE_NONE; + const list = isFiltered ? notificationsFiltered : notifications; React.useEffect(() => { if (unseenCount > 0 || unreadCount > 0) { // If there are unread notifications when entering the page, reset to All. - setFilterBy(ALL_NOTIFICATIONS); + setRule(NOTIFICATIONS.NOTIFICATION_RULE_NONE); } }, []); - React.useEffect(() => { - if (notifications && filterBy !== ALL_NOTIFICATIONS) { - setFilteredNotifications(notifications.filter((n) => n.notification_rule === filterBy)); - } else { - setFilteredNotifications(notifications); - } - }, [notifications, filterBy]); - React.useEffect(() => { if (unseenCount > 0) { doSeeAllNotifications(); } }, [unseenCount, doSeeAllNotifications]); + React.useEffect(() => { + if (rule && rule !== '') { + // Fetch filtered list when: + // (1) 'rule' changed + // (2) new "all" notifications received (e.g. from websocket). + doNotificationList(rule); + } + }, [rule, notifications]); + + const notificationListElement = ( + <> +
+

{__('Notifications')}

+
+ {fetching && } + + {unreadCount > 0 && ( +
+
+ {list && list.length > 0 ? ( +
+
+ {list.map((notification, index) => { + return ; + })} +
+
+ ) : ( +
+ {!fetching && ( + + {isFiltered + ? __('Try selecting another filter.') + : __("You don't have any notifications yet, but they will be here when you do!")} +

+ } + actions={ +
+
+ } + /> + )} +
+ )} + + ); + return ( - {fetching && !hasNotifications && ( + {initialFetchDone ? ( + notificationListElement + ) : fetching ? (
- )} - {!fetching && ( - <> -
-

{__('Notifications')}

-
- {fetching && } - - {unreadCount > 0 && ( -
-
- {filteredNotifications && filteredNotifications.length > 0 ? ( -
-
- {filteredNotifications.map((notification, index) => { - return ; - })} -
-
- ) : ( -
- - {isFiltered - ? __('Try selecting another filter.') - : __("You don't have any notifications yet, but they will be here when you do!")} -

- } - actions={ -
-
- } - /> -
- )} - + ) : ( + notificationListElement )}
);