fetch notofication/categories for notification types dropdown

This commit is contained in:
Sean Yesmunt 2021-04-29 15:10:20 -04:00
parent b9fc9b6319
commit 3808c61148
8 changed files with 93 additions and 49 deletions

View file

@ -36,3 +36,8 @@ declare type WebNotification = {
user_id: number,
group_count?: number,
};
declare type NotificationCategory = {
name: string,
types: ?Array<string>,
};

View file

@ -229,6 +229,7 @@ export const MEDIA_PAUSE = 'MEDIA_PAUSE';
export const NOTIFICATION_LIST_STARTED = 'NOTIFICATION_LIST_STARTED';
export const NOTIFICATION_LIST_COMPLETED = 'NOTIFICATION_LIST_COMPLETED';
export const NOTIFICATION_LIST_FAILED = 'NOTIFICATION_LIST_FAILED';
export const NOTIFICATION_CATEGORIES_COMPLETED = 'NOTIFICATION_CATEGORIES_COMPLETED';
export const NOTIFICATION_READ_STARTED = 'NOTIFICATION_READ_STARTED';
export const NOTIFICATION_READ_COMPLETED = 'NOTIFICATION_READ_COMPLETED';
export const NOTIFICATION_READ_FAILED = 'NOTIFICATION_READ_FAILED';

View file

@ -6,7 +6,7 @@ export const DAILY_WATCH_REMIND = 'daily_watch_remind';
export const NEW_CONTENT = 'new_content';
export const NEW_LIVESTREAM = 'new_livestream';
export const NOTIFICATION_RULE_NONE = '';
export const NOTIFICATION_NAME_ALL = 'All';
export const NOTIFICATION_RULE_COMMENTS = 'comments';
export const NOTIFICATION_RULE_REPLIES = 'comment_replies';
export const NOTIFICATION_RULE_FOLLOWERS = 'followers';

View file

@ -5,6 +5,7 @@ import {
selectIsFetchingNotifications,
selectUnreadNotificationCount,
selectUnseenNotificationCount,
selectNotificationCategories,
} from 'redux/selectors/notifications';
import { doReadNotifications, doNotificationList, doSeeAllNotifications } from 'redux/actions/notifications';
import NotificationsPage from './view';
@ -12,6 +13,7 @@ import NotificationsPage from './view';
const select = (state) => ({
notifications: selectNotifications(state),
notificationsFiltered: selectNotificationsFiltered(state),
notificationCategories: selectNotificationCategories(state),
fetching: selectIsFetchingNotifications(state),
unreadCount: selectUnreadNotificationCount(state),
unseenCount: selectUnseenNotificationCount(state),

View file

@ -11,24 +11,16 @@ 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<Notification>,
notificationsFiltered: Array<Notification>,
notificationCategories: Array<NotificationCategory>,
fetching: boolean,
unreadCount: number,
unseenCount: number,
doSeeAllNotifications: () => void,
doReadNotifications: () => void,
doNotificationList: (string) => void,
doNotificationList: (?Array<string>) => void,
};
export default function NotificationsPage(props: Props) {
@ -41,17 +33,17 @@ export default function NotificationsPage(props: Props) {
doSeeAllNotifications,
doReadNotifications,
doNotificationList,
notificationCategories,
} = props;
const initialFetchDone = useFetched(fetching);
const [rule, setRule] = usePersistedState('notifications--rule', NOTIFICATIONS.NOTIFICATION_RULE_NONE);
const isFiltered = rule !== NOTIFICATIONS.NOTIFICATION_RULE_NONE;
const [name, setName] = usePersistedState('notifications--rule', NOTIFICATIONS.NOTIFICATION_NAME_ALL);
const isFiltered = name !== NOTIFICATIONS.NOTIFICATION_NAME_ALL;
const list = isFiltered ? notificationsFiltered : notifications;
React.useEffect(() => {
if (unseenCount > 0 || unreadCount > 0) {
// If there are unread notifications when entering the page, reset to All.
setRule(NOTIFICATIONS.NOTIFICATION_RULE_NONE);
setName(NOTIFICATIONS.NOTIFICATION_NAME_ALL);
}
}, []);
@ -61,14 +53,26 @@ export default function NotificationsPage(props: Props) {
}
}, [unseenCount, doSeeAllNotifications]);
const stringifiedNotificationCategories = JSON.stringify(notificationCategories);
React.useEffect(() => {
if (rule && rule !== '') {
// Fetch filtered list when:
// (1) 'rule' changed
// (2) new "all" notifications received (e.g. from websocket).
doNotificationList(rule);
if (stringifiedNotificationCategories) {
const arrayNotificationCategories = JSON.parse(stringifiedNotificationCategories);
if (name !== NOTIFICATIONS.NOTIFICATION_NAME_ALL) {
// Fetch filtered list when:
// (1) 'name' changed
// (2) new "all" notifications received (e.g. from websocket).
try {
const matchingCategory = arrayNotificationCategories.find((category) => category.name === name);
if (matchingCategory) {
doNotificationList(matchingCategory.types);
}
} catch (e) {
console.error(e);
}
}
}
}, [rule, notifications]);
}, [name, notifications, stringifiedNotificationCategories]);
const notificationListElement = (
<>
@ -80,24 +84,26 @@ export default function NotificationsPage(props: Props) {
{unreadCount > 0 && (
<Button icon={ICONS.EYE} onClick={doReadNotifications} button="secondary" label={__('Mark all as read')} />
)}
<FormField
className="notification__filter"
type="select"
name="filter"
value={rule}
onChange={(e) => setRule(e.target.value)}
>
{Object.entries(RULE_LABELS).map((r) => {
return (
<option key={r[0]} value={r[0]}>
{__(String(r[1]))}
</option>
);
})}
</FormField>
{notificationCategories && (
<FormField
className="notification__filter"
type="select"
name="filter"
value={name}
onChange={(e) => setName(e.target.value)}
>
{notificationCategories.map((category) => {
return (
<option key={category.name} value={category.name}>
{__(category.name)}
</option>
);
})}
</FormField>
)}
</div>
</div>
{list && list.length > 0 ? (
{list && list.length > 0 && !(isFiltered && fetching) ? (
<div className="card">
<div className="notification_list">
{list.map((notification, index) => {

View file

@ -3,7 +3,11 @@ import * as ACTIONS from 'constants/action_types';
import * as NOTIFICATIONS from 'constants/notifications';
import { Lbryio } from 'lbryinc';
import { v4 as uuid } from 'uuid';
import { selectNotifications, selectNotificationsFiltered } from 'redux/selectors/notifications';
import {
selectNotifications,
selectNotificationsFiltered,
selectNotificationCategories,
} from 'redux/selectors/notifications';
import { doResolveUris } from 'lbry-redux';
export function doToast(params: ToastParams) {
@ -41,17 +45,32 @@ export function doDismissError() {
};
}
export function doNotificationList(rule: string = '') {
return (dispatch: Dispatch) => {
export function doNotificationList(types?: Array<string>) {
return async (dispatch: Dispatch, getState: GetState) => {
const state = getState();
const notificationTypes = selectNotificationCategories(state);
dispatch({ type: ACTIONS.NOTIFICATION_LIST_STARTED });
let params: any = { is_app_readable: true };
if (rule && rule !== NOTIFICATIONS.NOTIFICATION_RULE_NONE) {
params.type = rule;
if (types) {
params.type = types.join(',');
}
return Lbryio.call('notification', 'list', params)
.then((response) => {
try {
if (!notificationTypes) {
const notificationCategories = await Lbryio.call('notification', 'categories');
if (notificationCategories) {
dispatch({
type: ACTIONS.NOTIFICATION_CATEGORIES_COMPLETED,
data: {
notificationCategories: notificationCategories.reverse(),
},
});
}
}
return Lbryio.call('notification', 'list', params).then((response) => {
const notifications = response || [];
const channelsToResolve = notifications
.filter((notification: WebNotification) => {
@ -78,13 +97,13 @@ export function doNotificationList(rule: string = '') {
type: ACTIONS.NOTIFICATION_LIST_COMPLETED,
data: {
newNotifications: notifications,
filterRule: rule,
filterRule: Boolean(types),
},
});
})
.catch((error) => {
dispatch({ type: ACTIONS.NOTIFICATION_LIST_FAILED, data: { error } });
});
} catch (error) {
dispatch({ type: ACTIONS.NOTIFICATION_LIST_FAILED, data: { error } });
}
};
}

View file

@ -5,6 +5,7 @@ import { handleActions } from 'util/redux-utils';
const defaultState: NotificationState = {
notifications: [],
notificationsFiltered: [],
notificationCategories: undefined,
fetchingNotifications: false,
toasts: [],
errors: [],
@ -42,7 +43,7 @@ export default handleActions(
},
[ACTIONS.NOTIFICATION_LIST_COMPLETED]: (state, action) => {
const { filterRule, newNotifications } = action.data;
if (filterRule && filterRule !== '') {
if (filterRule) {
return {
...state,
notificationsFiltered: newNotifications,
@ -62,6 +63,14 @@ export default handleActions(
fetchingNotifications: false,
};
},
[ACTIONS.NOTIFICATION_CATEGORIES_COMPLETED]: (state, action) => {
const { notificationCategories } = action.data;
return {
...state,
notificationCategories,
};
},
[ACTIONS.NOTIFICATION_READ_COMPLETED]: (state, action) => {
const { notifications, notificationsFiltered } = state;
const { notificationIds } = action.data;

View file

@ -6,6 +6,8 @@ export const selectNotifications = createSelector(selectState, (state) => state.
export const selectNotificationsFiltered = createSelector(selectState, (state) => state.notificationsFiltered);
export const selectNotificationCategories = createSelector(selectState, (state) => state.notificationCategories);
export const makeSelectNotificationForCommentId = (id) =>
createSelector(selectNotifications, (notifications) => {
const match =