183 lines
5.4 KiB
TypeScript
183 lines
5.4 KiB
TypeScript
|
import { createReducer, isAnyOf } from '@reduxjs/toolkit';
|
||
|
|
||
|
import {
|
||
|
blockAccountSuccess,
|
||
|
muteAccountSuccess,
|
||
|
} from 'mastodon/actions/accounts';
|
||
|
import {
|
||
|
fetchNotificationRequests,
|
||
|
expandNotificationRequests,
|
||
|
fetchNotificationRequest,
|
||
|
fetchNotificationsForRequest,
|
||
|
expandNotificationsForRequest,
|
||
|
acceptNotificationRequest,
|
||
|
dismissNotificationRequest,
|
||
|
acceptNotificationRequests,
|
||
|
dismissNotificationRequests,
|
||
|
} from 'mastodon/actions/notification_requests';
|
||
|
import type { NotificationRequest } from 'mastodon/models/notification_request';
|
||
|
import { createNotificationRequestFromJSON } from 'mastodon/models/notification_request';
|
||
|
|
||
|
import { notificationToMap } from './notifications';
|
||
|
|
||
|
interface NotificationsListState {
|
||
|
items: unknown[]; // TODO
|
||
|
isLoading: boolean;
|
||
|
next: string | null;
|
||
|
}
|
||
|
|
||
|
interface CurrentNotificationRequestState {
|
||
|
item: NotificationRequest | null;
|
||
|
isLoading: boolean;
|
||
|
removed: boolean;
|
||
|
notifications: NotificationsListState;
|
||
|
}
|
||
|
|
||
|
interface NotificationRequestsState {
|
||
|
items: NotificationRequest[];
|
||
|
isLoading: boolean;
|
||
|
next: string | null;
|
||
|
current: CurrentNotificationRequestState;
|
||
|
}
|
||
|
|
||
|
const initialState: NotificationRequestsState = {
|
||
|
items: [],
|
||
|
isLoading: false,
|
||
|
next: null,
|
||
|
current: {
|
||
|
item: null,
|
||
|
isLoading: false,
|
||
|
removed: false,
|
||
|
notifications: {
|
||
|
isLoading: false,
|
||
|
items: [],
|
||
|
next: null,
|
||
|
},
|
||
|
},
|
||
|
};
|
||
|
|
||
|
const removeRequest = (state: NotificationRequestsState, id: string) => {
|
||
|
if (state.current.item?.id === id) {
|
||
|
state.current.removed = true;
|
||
|
}
|
||
|
|
||
|
state.items = state.items.filter((item) => item.id !== id);
|
||
|
};
|
||
|
|
||
|
const removeRequestByAccount = (
|
||
|
state: NotificationRequestsState,
|
||
|
account_id: string,
|
||
|
) => {
|
||
|
if (state.current.item?.account_id === account_id) {
|
||
|
state.current.removed = true;
|
||
|
}
|
||
|
|
||
|
state.items = state.items.filter((item) => item.account_id !== account_id);
|
||
|
};
|
||
|
|
||
|
export const notificationRequestsReducer =
|
||
|
createReducer<NotificationRequestsState>(initialState, (builder) => {
|
||
|
builder
|
||
|
.addCase(fetchNotificationRequests.fulfilled, (state, action) => {
|
||
|
state.items = action.payload.requests
|
||
|
.map(createNotificationRequestFromJSON)
|
||
|
.concat(state.items);
|
||
|
state.isLoading = false;
|
||
|
state.next ??= action.payload.next ?? null;
|
||
|
})
|
||
|
.addCase(expandNotificationRequests.fulfilled, (state, action) => {
|
||
|
state.items = state.items.concat(
|
||
|
action.payload.requests.map(createNotificationRequestFromJSON),
|
||
|
);
|
||
|
state.isLoading = false;
|
||
|
state.next = action.payload.next ?? null;
|
||
|
})
|
||
|
.addCase(blockAccountSuccess, (state, action) => {
|
||
|
removeRequestByAccount(state, action.payload.relationship.id);
|
||
|
})
|
||
|
.addCase(muteAccountSuccess, (state, action) => {
|
||
|
if (action.payload.relationship.muting_notifications)
|
||
|
removeRequestByAccount(state, action.payload.relationship.id);
|
||
|
})
|
||
|
.addCase(fetchNotificationRequest.pending, (state) => {
|
||
|
state.current = { ...initialState.current, isLoading: true };
|
||
|
})
|
||
|
.addCase(fetchNotificationRequest.rejected, (state) => {
|
||
|
state.current.isLoading = false;
|
||
|
})
|
||
|
.addCase(fetchNotificationRequest.fulfilled, (state, action) => {
|
||
|
state.current.isLoading = false;
|
||
|
state.current.item = createNotificationRequestFromJSON(action.payload);
|
||
|
})
|
||
|
.addCase(fetchNotificationsForRequest.fulfilled, (state, action) => {
|
||
|
state.current.notifications.isLoading = false;
|
||
|
state.current.notifications.items.unshift(
|
||
|
...action.payload.notifications.map(notificationToMap),
|
||
|
);
|
||
|
state.current.notifications.next ??= action.payload.next ?? null;
|
||
|
})
|
||
|
.addCase(expandNotificationsForRequest.fulfilled, (state, action) => {
|
||
|
state.current.notifications.isLoading = false;
|
||
|
state.current.notifications.items.push(
|
||
|
...action.payload.notifications.map(notificationToMap),
|
||
|
);
|
||
|
state.current.notifications.next = action.payload.next ?? null;
|
||
|
})
|
||
|
.addMatcher(
|
||
|
isAnyOf(
|
||
|
fetchNotificationRequests.pending,
|
||
|
expandNotificationRequests.pending,
|
||
|
),
|
||
|
(state) => {
|
||
|
state.isLoading = true;
|
||
|
},
|
||
|
)
|
||
|
.addMatcher(
|
||
|
isAnyOf(
|
||
|
fetchNotificationRequests.rejected,
|
||
|
expandNotificationRequests.rejected,
|
||
|
),
|
||
|
(state) => {
|
||
|
state.isLoading = false;
|
||
|
},
|
||
|
)
|
||
|
.addMatcher(
|
||
|
isAnyOf(
|
||
|
acceptNotificationRequest.pending,
|
||
|
dismissNotificationRequest.pending,
|
||
|
),
|
||
|
(state, action) => {
|
||
|
removeRequest(state, action.meta.arg.id);
|
||
|
},
|
||
|
)
|
||
|
.addMatcher(
|
||
|
isAnyOf(
|
||
|
acceptNotificationRequests.pending,
|
||
|
dismissNotificationRequests.pending,
|
||
|
),
|
||
|
(state, action) => {
|
||
|
action.meta.arg.ids.forEach((id) => {
|
||
|
removeRequest(state, id);
|
||
|
});
|
||
|
},
|
||
|
)
|
||
|
.addMatcher(
|
||
|
isAnyOf(
|
||
|
fetchNotificationsForRequest.pending,
|
||
|
expandNotificationsForRequest.pending,
|
||
|
),
|
||
|
(state) => {
|
||
|
state.current.notifications.isLoading = true;
|
||
|
},
|
||
|
)
|
||
|
.addMatcher(
|
||
|
isAnyOf(
|
||
|
fetchNotificationsForRequest.rejected,
|
||
|
expandNotificationsForRequest.rejected,
|
||
|
),
|
||
|
(state) => {
|
||
|
state.current.notifications.isLoading = false;
|
||
|
},
|
||
|
);
|
||
|
});
|