mirror of https://github.com/mastodon/mastodon.git
Handle removals from notification groups
parent
74a7297e87
commit
e1c2bedde7
|
@ -1,4 +1,7 @@
|
|||
import { apiFetchNotifications } from 'mastodon/api/notifications';
|
||||
import {
|
||||
apiClearNotifications,
|
||||
apiFetchNotifications,
|
||||
} from 'mastodon/api/notifications';
|
||||
import type { ApiAccountJSON } from 'mastodon/api_types/accounts';
|
||||
import type {
|
||||
ApiNotificationGroupJSON,
|
||||
|
@ -103,7 +106,7 @@ export const fetchNotificationsGap = createDataLoadingThunk(
|
|||
|
||||
export const processNewNotificationForGroups = createAppAsyncThunk(
|
||||
'notificationsGroups/processNew',
|
||||
(notification: NotificationJSON, { dispatch }) => {
|
||||
(notification: ApiNotificationJSON, { dispatch }) => {
|
||||
dispatchAssociatedRecords(dispatch, [notification]);
|
||||
|
||||
return notification;
|
||||
|
@ -123,3 +126,8 @@ export const setNotificationsFilter = createAppAsyncThunk(
|
|||
dispatch(saveSettings());
|
||||
},
|
||||
);
|
||||
|
||||
export const clearNotifications = createDataLoadingThunk(
|
||||
'notifications/clear',
|
||||
() => apiClearNotifications(),
|
||||
);
|
||||
|
|
|
@ -24,6 +24,8 @@ import { saveSettings } from './settings';
|
|||
|
||||
export * from "./notifications_typed";
|
||||
|
||||
export { clearNotifications } from "./notification_groups";
|
||||
|
||||
export const NOTIFICATIONS_UPDATE_NOOP = 'NOTIFICATIONS_UPDATE_NOOP';
|
||||
|
||||
export const NOTIFICATIONS_EXPAND_REQUEST = 'NOTIFICATIONS_EXPAND_REQUEST';
|
||||
|
@ -32,7 +34,6 @@ export const NOTIFICATIONS_EXPAND_FAIL = 'NOTIFICATIONS_EXPAND_FAIL';
|
|||
|
||||
export const NOTIFICATIONS_FILTER_SET = 'NOTIFICATIONS_FILTER_SET';
|
||||
|
||||
export const NOTIFICATIONS_CLEAR = 'NOTIFICATIONS_CLEAR';
|
||||
export const NOTIFICATIONS_SCROLL_TOP = 'NOTIFICATIONS_SCROLL_TOP';
|
||||
export const NOTIFICATIONS_LOAD_PENDING = 'NOTIFICATIONS_LOAD_PENDING';
|
||||
|
||||
|
@ -257,16 +258,6 @@ export function expandNotificationsFail(error, isLoadingMore) {
|
|||
};
|
||||
}
|
||||
|
||||
export function clearNotifications() {
|
||||
return (dispatch) => {
|
||||
dispatch({
|
||||
type: NOTIFICATIONS_CLEAR,
|
||||
});
|
||||
|
||||
api().post('/api/v1/notifications/clear');
|
||||
};
|
||||
}
|
||||
|
||||
export function scrollTopNotifications(top) {
|
||||
return {
|
||||
type: NOTIFICATIONS_SCROLL_TOP,
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import api, { getLinks } from 'mastodon/api';
|
||||
import api, { apiRequest, getLinks } from 'mastodon/api';
|
||||
import type { ApiNotificationGroupJSON } from 'mastodon/api_types/notifications';
|
||||
|
||||
export const apiFetchNotifications = async (
|
||||
|
@ -15,3 +15,6 @@ export const apiFetchNotifications = async (
|
|||
|
||||
return { notifications: response.data, links: getLinks(response) };
|
||||
};
|
||||
|
||||
export const apiClearNotifications = () =>
|
||||
apiRequest<undefined>('POST', 'v1/notifications/clear');
|
||||
|
|
|
@ -22,7 +22,6 @@ import {
|
|||
NOTIFICATIONS_EXPAND_REQUEST,
|
||||
NOTIFICATIONS_EXPAND_FAIL,
|
||||
NOTIFICATIONS_FILTER_SET,
|
||||
NOTIFICATIONS_CLEAR,
|
||||
NOTIFICATIONS_SCROLL_TOP,
|
||||
NOTIFICATIONS_LOAD_PENDING,
|
||||
NOTIFICATIONS_MOUNT,
|
||||
|
@ -30,6 +29,7 @@ import {
|
|||
NOTIFICATIONS_MARK_AS_READ,
|
||||
NOTIFICATIONS_SET_BROWSER_SUPPORT,
|
||||
NOTIFICATIONS_SET_BROWSER_PERMISSION,
|
||||
clearNotifications,
|
||||
} from '../actions/notifications';
|
||||
import { disconnectTimeline } from '../actions/timelines';
|
||||
import { compareId } from '../compare_id';
|
||||
|
@ -290,7 +290,7 @@ export default function notifications(state = initialState, action) {
|
|||
case authorizeFollowRequestSuccess.type:
|
||||
case rejectFollowRequestSuccess.type:
|
||||
return filterNotifications(state, [action.payload.id], 'follow_request');
|
||||
case NOTIFICATIONS_CLEAR:
|
||||
case clearNotifications.pending.type:
|
||||
return state.set('items', ImmutableList()).set('pendingItems', ImmutableList()).set('hasMore', false);
|
||||
case timelineDelete.type:
|
||||
return deleteByStatus(state, action.payload.statusId);
|
||||
|
|
|
@ -1,10 +1,22 @@
|
|||
import { createReducer, isAnyOf } from '@reduxjs/toolkit';
|
||||
|
||||
import {
|
||||
authorizeFollowRequestSuccess,
|
||||
blockAccountSuccess,
|
||||
muteAccountSuccess,
|
||||
rejectFollowRequestSuccess,
|
||||
} from 'mastodon/actions/accounts_typed';
|
||||
import { blockDomainSuccess } from 'mastodon/actions/domain_blocks_typed';
|
||||
import {
|
||||
clearNotifications,
|
||||
fetchNotifications,
|
||||
fetchNotificationsGap,
|
||||
processNewNotificationForGroups,
|
||||
} from 'mastodon/actions/notification_groups';
|
||||
import {
|
||||
disconnectTimeline,
|
||||
timelineDelete,
|
||||
} from 'mastodon/actions/timelines_typed';
|
||||
import {
|
||||
NOTIFICATIONS_GROUP_MAX_AVATARS,
|
||||
createNotificationGroupFromJSON,
|
||||
|
@ -33,6 +45,48 @@ const initialState: NotificationGroupsState = {
|
|||
readMarkerId: '0',
|
||||
};
|
||||
|
||||
function removeNotificationsForAccounts(
|
||||
state: NotificationGroupsState,
|
||||
accountIds: string[],
|
||||
onlyForType?: string,
|
||||
) {
|
||||
state.groups = state.groups
|
||||
.map((group) => {
|
||||
if (
|
||||
group.type !== 'gap' &&
|
||||
(!onlyForType || group.type === onlyForType)
|
||||
) {
|
||||
const previousLength = group.sampleAccountsIds.length;
|
||||
|
||||
group.sampleAccountsIds = group.sampleAccountsIds.filter(
|
||||
(id) => !accountIds.includes(id),
|
||||
);
|
||||
|
||||
const newLength = group.sampleAccountsIds.length;
|
||||
const removed = previousLength - newLength;
|
||||
|
||||
group.notifications_count -= removed;
|
||||
}
|
||||
|
||||
return group;
|
||||
})
|
||||
.filter(
|
||||
(group) => group.type === 'gap' || group.sampleAccountsIds.length > 0,
|
||||
);
|
||||
}
|
||||
|
||||
function removeNotificationsForStatus(
|
||||
state: NotificationGroupsState,
|
||||
statusId: string,
|
||||
) {
|
||||
state.groups = state.groups.filter(
|
||||
(group) =>
|
||||
group.type === 'gap' ||
|
||||
!('statusId' in group) ||
|
||||
group.statusId !== statusId,
|
||||
);
|
||||
}
|
||||
|
||||
export const notificationsGroupsReducer =
|
||||
createReducer<NotificationGroupsState>(initialState, (builder) => {
|
||||
builder
|
||||
|
@ -106,6 +160,46 @@ export const notificationsGroupsReducer =
|
|||
);
|
||||
}
|
||||
})
|
||||
.addCase(disconnectTimeline, (state, action) => {
|
||||
if (action.payload.timeline === 'home')
|
||||
state.groups.unshift({
|
||||
type: 'gap',
|
||||
loadUrl: 'TODO_LOAD_URL_TOP_OF_TL', // TODO
|
||||
});
|
||||
})
|
||||
.addCase(timelineDelete, (state, action) => {
|
||||
removeNotificationsForStatus(state, action.payload.statusId);
|
||||
})
|
||||
.addCase(clearNotifications.pending, (state) => {
|
||||
state.groups = [];
|
||||
state.unread = 0;
|
||||
state.hasMore = false;
|
||||
})
|
||||
.addCase(blockAccountSuccess, (state, action) => {
|
||||
removeNotificationsForAccounts(state, [action.payload.relationship.id]);
|
||||
})
|
||||
.addCase(muteAccountSuccess, (state, action) => {
|
||||
if (action.payload.relationship.muting_notifications)
|
||||
removeNotificationsForAccounts(state, [
|
||||
action.payload.relationship.id,
|
||||
]);
|
||||
})
|
||||
.addCase(blockDomainSuccess, (state, action) => {
|
||||
removeNotificationsForAccounts(
|
||||
state,
|
||||
action.payload.accounts.map((account) => account.id),
|
||||
);
|
||||
})
|
||||
.addMatcher(
|
||||
isAnyOf(authorizeFollowRequestSuccess, rejectFollowRequestSuccess),
|
||||
(state, action) => {
|
||||
removeNotificationsForAccounts(
|
||||
state,
|
||||
[action.payload.id],
|
||||
'follow_request',
|
||||
);
|
||||
},
|
||||
)
|
||||
.addMatcher(
|
||||
isAnyOf(fetchNotifications.pending, fetchNotificationsGap.pending),
|
||||
(state) => {
|
||||
|
|
Loading…
Reference in New Issue