frontend-rw #1
1 changed files with 61 additions and 42 deletions
|
@ -1,4 +1,5 @@
|
||||||
import { Record as ImmutableRecord, OrderedMap as ImmutableOrderedMap } from 'immutable';
|
import { OrderedMap as ImmutableOrderedMap } from 'immutable';
|
||||||
|
import { create } from 'mutative';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
ACCOUNT_BLOCK_SUCCESS,
|
ACCOUNT_BLOCK_SUCCESS,
|
||||||
|
@ -26,16 +27,23 @@ import { TIMELINE_DELETE, type TimelineAction } from '../actions/timelines';
|
||||||
import type { Notification as BaseNotification, Markers, NotificationGroup, PaginatedResponse, Relationship } from 'pl-api';
|
import type { Notification as BaseNotification, Markers, NotificationGroup, PaginatedResponse, Relationship } from 'pl-api';
|
||||||
import type { AnyAction } from 'redux';
|
import type { AnyAction } from 'redux';
|
||||||
|
|
||||||
const ReducerRecord = ImmutableRecord({
|
interface State {
|
||||||
items: ImmutableOrderedMap<string, NotificationGroup>(),
|
items: ImmutableOrderedMap<string, NotificationGroup>;
|
||||||
|
hasMore: boolean;
|
||||||
|
top: boolean;
|
||||||
|
unread: number;
|
||||||
|
isLoading: boolean;
|
||||||
|
lastRead: string | -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const initialState: State = {
|
||||||
|
items: ImmutableOrderedMap(),
|
||||||
hasMore: true,
|
hasMore: true,
|
||||||
top: false,
|
top: false,
|
||||||
unread: 0,
|
unread: 0,
|
||||||
isLoading: false,
|
isLoading: false,
|
||||||
lastRead: -1 as string | -1,
|
lastRead: -1,
|
||||||
});
|
};
|
||||||
|
|
||||||
type State = ReturnType<typeof ReducerRecord>;
|
|
||||||
|
|
||||||
const parseId = (id: string | number) => parseInt(id as string, 10);
|
const parseId = (id: string | number) => parseInt(id as string, 10);
|
||||||
|
|
||||||
|
@ -57,41 +65,45 @@ const countFuture = (notifications: ImmutableOrderedMap<string, NotificationGrou
|
||||||
}
|
}
|
||||||
}, 0);
|
}, 0);
|
||||||
|
|
||||||
const importNotification = (state: State, notification: NotificationGroup) => {
|
const importNotification = (state: State, notification: NotificationGroup) =>
|
||||||
const top = state.top;
|
create(state, (draft) => {
|
||||||
|
const top = draft.top;
|
||||||
|
if (!top) draft.unread += 1;
|
||||||
|
|
||||||
if (!top) state = state.update('unread', unread => unread + 1);
|
draft.items = draft.items.set(notification.group_key, notification).sort(comparator);
|
||||||
|
});
|
||||||
return state.update('items', map => map.set(notification.group_key, notification).sort(comparator));
|
|
||||||
};
|
const expandNormalizedNotifications = (state: State, notifications: NotificationGroup[], next: (() => Promise<PaginatedResponse<BaseNotification>>) | null) =>
|
||||||
|
create(state, (draft) => {
|
||||||
const expandNormalizedNotifications = (state: State, notifications: NotificationGroup[], next: (() => Promise<PaginatedResponse<BaseNotification>>) | null) => {
|
const items = ImmutableOrderedMap(notifications.map(n => [n.group_key, n]));
|
||||||
const items = ImmutableOrderedMap(notifications.map(n => [n.group_key, n]));
|
draft.items = draft.items.merge(items).sort(comparator);
|
||||||
|
|
||||||
return state.withMutations(mutable => {
|
if (!next) draft.hasMore = false;
|
||||||
mutable.update('items', map => map.merge(items).sort(comparator));
|
draft.isLoading = false;
|
||||||
|
|
||||||
if (!next) mutable.set('hasMore', false);
|
|
||||||
mutable.set('isLoading', false);
|
|
||||||
});
|
});
|
||||||
};
|
|
||||||
|
|
||||||
const filterNotifications = (state: State, relationship: Relationship) =>
|
const filterNotifications = (state: State, relationship: Relationship) =>
|
||||||
state.update('items', map => map.filterNot(item => item !== null && item.sample_account_ids.includes(relationship.id)));
|
create(state, (draft) => {
|
||||||
|
draft.items = draft.items.filterNot(item => item !== null && item.sample_account_ids.includes(relationship.id));
|
||||||
|
});
|
||||||
|
|
||||||
const filterNotificationIds = (state: State, accountIds: Array<string>, type?: string) => {
|
const filterNotificationIds = (state: State, accountIds: Array<string>, type?: string) =>
|
||||||
const helper = (list: ImmutableOrderedMap<string, NotificationGroup>) => list.filterNot(item => item !== null && accountIds.includes(item.sample_account_ids[0]) && (type === undefined || type === item.type));
|
create(state, (draft) => {
|
||||||
return state.update('items', helper);
|
const helper = (list: ImmutableOrderedMap<string, NotificationGroup>) => list.filterNot(item => item !== null && accountIds.includes(item.sample_account_ids[0]) && (type === undefined || type === item.type));
|
||||||
};
|
draft.items = helper(draft.items);
|
||||||
|
});
|
||||||
|
|
||||||
const updateTop = (state: State, top: boolean) => {
|
const updateTop = (state: State, top: boolean) =>
|
||||||
if (top) state = state.set('unread', 0);
|
create(state, (draft) => {
|
||||||
return state.set('top', top);
|
if (top) draft.unread = 0;
|
||||||
};
|
draft.top = top;
|
||||||
|
});
|
||||||
|
|
||||||
const deleteByStatus = (state: State, statusId: string) =>
|
const deleteByStatus = (state: State, statusId: string) =>
|
||||||
// @ts-ignore
|
create(state, (draft) => {
|
||||||
state.update('items', map => map.filterNot(item => item !== null && item.status === statusId));
|
// @ts-ignore
|
||||||
|
draft.items = draft.items.filterNot(item => item !== null && item.status_id === statusId);
|
||||||
|
});
|
||||||
|
|
||||||
const importMarker = (state: State, marker: Markers) => {
|
const importMarker = (state: State, marker: Markers) => {
|
||||||
const lastReadId = marker.notifications.last_read_id || -1 as string | -1;
|
const lastReadId = marker.notifications.last_read_id || -1 as string | -1;
|
||||||
|
@ -100,24 +112,31 @@ const importMarker = (state: State, marker: Markers) => {
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
||||||
return state.withMutations(state => {
|
return create(state, (draft) => {
|
||||||
const notifications = state.items;
|
const notifications = draft.items;
|
||||||
const unread = countFuture(notifications, lastReadId);
|
const unread = countFuture(notifications, lastReadId);
|
||||||
|
|
||||||
state.set('unread', unread);
|
draft.unread = unread;
|
||||||
state.set('lastRead', lastReadId);
|
draft.lastRead = lastReadId;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const notifications = (state: State = ReducerRecord(), action: AccountsAction | AnyAction | NotificationsAction | TimelineAction) => {
|
const notifications = (state: State = initialState, action: AccountsAction | AnyAction | NotificationsAction | TimelineAction): State => {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case NOTIFICATIONS_EXPAND_REQUEST:
|
case NOTIFICATIONS_EXPAND_REQUEST:
|
||||||
return state.set('isLoading', true);
|
return create(state, (draft) => {
|
||||||
|
draft.isLoading = true;
|
||||||
|
});
|
||||||
case NOTIFICATIONS_EXPAND_FAIL:
|
case NOTIFICATIONS_EXPAND_FAIL:
|
||||||
if (action.error?.message === 'canceled') return state;
|
if (action.error?.message === 'canceled') return state;
|
||||||
return state.set('isLoading', false);
|
return create(state, (draft) => {
|
||||||
|
draft.isLoading = false;
|
||||||
|
});
|
||||||
case NOTIFICATIONS_FILTER_SET:
|
case NOTIFICATIONS_FILTER_SET:
|
||||||
return state.set('items', ImmutableOrderedMap()).set('hasMore', true);
|
return create(state, (draft) => {
|
||||||
|
draft.items = ImmutableOrderedMap();
|
||||||
|
draft.hasMore = true;
|
||||||
|
});
|
||||||
case NOTIFICATIONS_SCROLL_TOP:
|
case NOTIFICATIONS_SCROLL_TOP:
|
||||||
return updateTop(state, action.top);
|
return updateTop(state, action.top);
|
||||||
case NOTIFICATIONS_UPDATE:
|
case NOTIFICATIONS_UPDATE:
|
||||||
|
|
Loading…
Reference in a new issue