fetch notofication/categories for notification types dropdown
This commit is contained in:
parent
b9fc9b6319
commit
3808c61148
8 changed files with 93 additions and 49 deletions
5
flow-typed/notification.js
vendored
5
flow-typed/notification.js
vendored
|
@ -36,3 +36,8 @@ declare type WebNotification = {
|
|||
user_id: number,
|
||||
group_count?: number,
|
||||
};
|
||||
|
||||
declare type NotificationCategory = {
|
||||
name: string,
|
||||
types: ?Array<string>,
|
||||
};
|
||||
|
|
|
@ -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';
|
||||
|
|
|
@ -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';
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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) => {
|
||||
|
|
|
@ -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 } });
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 =
|
||||
|
|
Loading…
Add table
Reference in a new issue