Merge branch 'reducer-records' into 'develop'

Refactor some reducers with Immutable.Record

See merge request soapbox-pub/soapbox-fe!1093
This commit is contained in:
Alex Gleason 2022-03-11 21:01:15 +00:00
commit 6be0b61569
14 changed files with 600 additions and 724 deletions

View File

@ -0,0 +1,17 @@
import { Record as ImmutableRecord, fromJS } from 'immutable';
import { normalizeNotification } from '../notification';
describe('normalizeNotification()', () => {
it('normalizes an empty map', () => {
const notification = fromJS({});
const result = normalizeNotification(notification);
expect(ImmutableRecord.isRecord(result)).toBe(true);
expect(result.type).toEqual('');
expect(result.account).toBe(null);
expect(result.target).toBe(null);
expect(result.status).toBe(null);
expect(result.id).toEqual('');
});
});

View File

@ -60,7 +60,7 @@ const InstanceRecord = ImmutableRecord({
}); });
// Build Mastodon configuration from Pleroma instance // Build Mastodon configuration from Pleroma instance
const pleromaToMastodonConfig = instance => { const pleromaToMastodonConfig = (instance: ImmutableMap<string, any>) => {
return ImmutableMap({ return ImmutableMap({
statuses: ImmutableMap({ statuses: ImmutableMap({
max_characters: instance.get('max_toot_chars'), max_characters: instance.get('max_toot_chars'),
@ -75,10 +75,10 @@ const pleromaToMastodonConfig = instance => {
}; };
// Get the software's default attachment limit // Get the software's default attachment limit
const getAttachmentLimit = software => software === PLEROMA ? Infinity : 4; const getAttachmentLimit = (software: string) => software === PLEROMA ? Infinity : 4;
// Normalize instance (Pleroma, Mastodon, etc.) to Mastodon's format // Normalize instance (Pleroma, Mastodon, etc.) to Mastodon's format
export const normalizeInstance = instance => { export const normalizeInstance = (instance: ImmutableMap<string, any>) => {
const { software } = parseVersion(instance.get('version')); const { software } = parseVersion(instance.get('version'));
const mastodonConfig = pleromaToMastodonConfig(instance); const mastodonConfig = pleromaToMastodonConfig(instance);

View File

@ -0,0 +1,20 @@
import {
Map as ImmutableMap,
Record as ImmutableRecord,
} from 'immutable';
// https://docs.joinmastodon.org/entities/notification/
const NotificationRecord = ImmutableRecord({
account: null,
chat_message: null, // pleroma:chat_mention
created_at: new Date(),
emoji: null, // pleroma:emoji_reaction
id: '',
status: null,
target: null, // move
type: '',
});
export const normalizeNotification = (notification: ImmutableMap<string, any>) => {
return NotificationRecord(notification);
};

View File

@ -11,7 +11,7 @@ import { IStatus } from 'soapbox/types';
import { mergeDefined, makeEmojiMap } from 'soapbox/utils/normalizers'; import { mergeDefined, makeEmojiMap } from 'soapbox/utils/normalizers';
const StatusRecord = ImmutableRecord({ const StatusRecord = ImmutableRecord({
account: ImmutableMap(), account: null,
application: null, application: null,
bookmarked: false, bookmarked: false,
card: null, card: null,

View File

@ -1,21 +1,11 @@
import { import { Record as ImmutableRecord } from 'immutable';
Map as ImmutableMap,
List as ImmutableList,
OrderedSet as ImmutableOrderedSet,
} from 'immutable';
import reducer from '../admin'; import reducer from '../admin';
describe('admin reducer', () => { describe('admin reducer', () => {
it('should return the initial state', () => { it('should return the initial state', () => {
expect(reducer(undefined, {})).toEqual(ImmutableMap({ const result = reducer(undefined, {});
reports: ImmutableMap(), expect(ImmutableRecord.isRecord(result)).toBe(true);
openReports: ImmutableOrderedSet(), expect(result.needsReboot).toBe(false);
users: ImmutableMap(),
latestUsers: ImmutableOrderedSet(),
awaitingApproval: ImmutableOrderedSet(),
configs: ImmutableList(),
needsReboot: false,
}));
}); });
}); });

View File

@ -1,6 +1,11 @@
import { List as ImmutableList } from 'immutable'; import { Record as ImmutableRecord, List as ImmutableList } from 'immutable';
import * as actions from 'soapbox/actions/alerts'; import {
ALERT_SHOW,
ALERT_DISMISS,
ALERT_CLEAR,
} from 'soapbox/actions/alerts';
import { applyActions } from 'soapbox/test_helpers';
import reducer from '../alerts'; import reducer from '../alerts';
@ -9,66 +14,65 @@ describe('alerts reducer', () => {
expect(reducer(undefined, {})).toEqual(ImmutableList()); expect(reducer(undefined, {})).toEqual(ImmutableList());
}); });
it('should handle ALERT_SHOW', () => { describe('ALERT_SHOW', () => {
const state = ImmutableList([]); it('imports the alert', () => {
const action = { const action = {
type: actions.ALERT_SHOW, type: ALERT_SHOW,
title: 'alert_title', title: 'alert_title',
message: 'this is an alert message', message: 'this is an alert message',
}; };
expect(reducer(state, action).toJS()).toMatchObject([
{ const expected = [{
key: 0, key: 0,
message: 'this is an alert message', message: 'this is an alert message',
title: 'alert_title', title: 'alert_title',
}, }];
]);
const result = reducer(undefined, action);
expect(ImmutableRecord.isRecord(result.get(0))).toBe(true);
expect(result.toJS()).toMatchObject(expected);
});
}); });
// it('should handle ALERT_DISMISS', () => { describe('ALERT_CLEAR', () => {
// const state = ImmutableList([ it('deletes the alerts', () => {
// { const actions = [{
// key: 0, type: ALERT_SHOW,
// message: 'message_1', title: 'Oops!',
// title: 'title_1', message: 'Server is down',
// }, }, {
// { type: ALERT_SHOW,
// key: 1, title: 'Uh-oh!',
// message: 'message_2', message: 'Shit done fucked up',
// title: 'title_2', }, {
// }, type: ALERT_CLEAR,
// ]); }];
// const action = {
// type: actions.ALERT_DISMISS,
// alert: { key: 0 },
// };
// expect(reducer(state, action).toJS()).toMatchObject([
// {
// key: 1,
// message: 'message_2',
// title: 'title_2',
// }
// ]);
// });
it('should handle ALERT_CLEAR', () => { const result = applyActions(undefined, actions, reducer);
const state = ImmutableList([ expect(result.isEmpty()).toBe(true);
{ });
});
describe('ALERT_DISMISS', () => {
it('deletes an individual alert', () => {
const actions = [{
type: ALERT_SHOW,
title: 'Oops!',
message: 'Server is down',
}, {
type: ALERT_SHOW,
title: 'Uh-oh!',
message: 'Shit done fucked up',
}, {
type: ALERT_DISMISS,
alert: {
key: 0, key: 0,
message: 'message_1',
title: 'title_1',
}, },
{ }];
key: 1,
message: 'message_2',
title: 'title_2',
},
]);
const action = {
type: actions.ALERT_CLEAR,
};
expect(reducer(state, action).toJS()).toMatchObject({
});
});
const result = applyActions(undefined, actions, reducer);
expect(result.size).toEqual(1);
expect(result.get(0).key).toEqual(1);
});
});
}); });

View File

@ -1,9 +1,11 @@
import { Map as ImmutableMap } from 'immutable'; import { Record as ImmutableRecord } from 'immutable';
import reducer from '../meta'; import reducer from '../meta';
describe('meta reducer', () => { describe('meta reducer', () => {
it('should return the initial state', () => { it('should return the initial state', () => {
expect(reducer(undefined, {})).toEqual(ImmutableMap()); const result = reducer(undefined, {});
expect(ImmutableRecord.isRecord(result)).toBe(true);
expect(result.instance_fetch_failed).toBe(false);
}); });
}); });

View File

@ -1,4 +1,8 @@
import { Map as ImmutableMap, OrderedMap as ImmutableOrderedMap, fromJS } from 'immutable'; import {
Map as ImmutableMap,
OrderedMap as ImmutableOrderedMap,
Record as ImmutableRecord,
} from 'immutable';
import { take } from 'lodash'; import { take } from 'lodash';
import intlMessages from 'soapbox/__fixtures__/intlMessages.json'; import intlMessages from 'soapbox/__fixtures__/intlMessages.json';
@ -24,27 +28,31 @@ import {
NOTIFICATIONS_MARK_READ_REQUEST, NOTIFICATIONS_MARK_READ_REQUEST,
} from 'soapbox/actions/notifications'; } from 'soapbox/actions/notifications';
import { TIMELINE_DELETE } from 'soapbox/actions/timelines'; import { TIMELINE_DELETE } from 'soapbox/actions/timelines';
import { applyActions } from 'soapbox/test_helpers';
import reducer from '../notifications'; import reducer from '../notifications';
const initialState = reducer(undefined, {});
describe('notifications reducer', () => { describe('notifications reducer', () => {
it('should return the initial state', () => { it('should return the initial state', () => {
expect(reducer(undefined, {})).toEqual(ImmutableMap({ const expected = {
items: ImmutableOrderedMap(), items: {},
hasMore: true, hasMore: true,
top: false, top: false,
unread: 0, unread: 0,
isLoading: false, isLoading: false,
queuedNotifications: ImmutableOrderedMap(), queuedNotifications: {},
totalQueuedNotificationsCount: 0, totalQueuedNotificationsCount: 0,
lastRead: -1, lastRead: -1,
})); };
expect(ImmutableRecord.isRecord(initialState)).toBe(true);
expect(initialState.toJS()).toMatchObject(expected);
}); });
describe('NOTIFICATIONS_EXPAND_SUCCESS', () => { describe('NOTIFICATIONS_EXPAND_SUCCESS', () => {
it('imports the notifications', () => { it('imports the notifications', () => {
const state = undefined;
const action = { const action = {
type: NOTIFICATIONS_EXPAND_SUCCESS, type: NOTIFICATIONS_EXPAND_SUCCESS,
notifications: take(notifications, 3), notifications: take(notifications, 3),
@ -52,47 +60,17 @@ describe('notifications reducer', () => {
skipLoading: true, skipLoading: true,
}; };
expect(reducer(state, action)).toEqual(ImmutableMap({ const result = reducer(undefined, action);
items: ImmutableOrderedMap([
['10744', ImmutableMap({ // The items are parsed as records
id: '10744', expect(ImmutableOrderedMap.isOrderedMap(result.items)).toBe(true);
type: 'pleroma:emoji_reaction', expect(ImmutableRecord.isRecord(result.items.get('10743'))).toBe(true);
account: '9vMAje101ngtjlMj7w',
target: null, // We can get an item
created_at: '2020-06-10T02:54:39.000Z', expect(result.items.get('10744').emoji).toEqual('😢');
status: '9vvNxoo5EFbbnfdXQu',
emoji: '😢', // hasMore is set to false because `next` is null
chat_message: undefined, expect(result.hasMore).toBe(false);
})],
['10743', ImmutableMap({
id: '10743',
type: 'favourite',
account: '9v5c6xSEgAi3Zu1Lv6',
target: null,
created_at: '2020-06-10T02:51:05.000Z',
status: '9vvNxoo5EFbbnfdXQu',
emoji: undefined,
chat_message: undefined,
})],
['10741', ImmutableMap({
id: '10741',
type: 'favourite',
account: '9v5cKMOPGqPcgfcWp6',
target: null,
created_at: '2020-06-10T02:05:06.000Z',
status: '9vvNxoo5EFbbnfdXQu',
emoji: undefined,
chat_message: undefined,
})],
]),
hasMore: false,
top: false,
unread: 0,
isLoading: false,
queuedNotifications: ImmutableOrderedMap(),
totalQueuedNotificationsCount: 0,
lastRead: -1,
}));
}); });
it('drops invalid notifications', () => { it('drops invalid notifications', () => {
@ -109,200 +87,132 @@ describe('notifications reducer', () => {
skipLoading: true, skipLoading: true,
}; };
const expected = ImmutableOrderedMap([ const result = reducer(undefined, action);
['4', fromJS({
id: '4',
type: 'mention',
account: '7',
target: null,
created_at: undefined,
status: 'a',
emoji: undefined,
chat_message: undefined,
})],
]);
expect(reducer(undefined, action).get('items')).toEqual(expected); // Only '4' is valid
expect(result.items.size).toEqual(1);
expect(result.items.get('4').id).toEqual('4');
}); });
}); });
it('should handle NOTIFICATIONS_EXPAND_REQUEST', () => { describe('NOTIFICATIONS_EXPAND_REQUEST', () => {
const state = ImmutableMap({ it('sets isLoading to true', () => {
isLoading: false, const state = initialState.set('isLoading', false);
const action = { type: NOTIFICATIONS_EXPAND_REQUEST };
expect(reducer(state, action).isLoading).toBe(true);
}); });
const action = {
type: NOTIFICATIONS_EXPAND_REQUEST,
};
expect(reducer(state, action)).toEqual(ImmutableMap({
isLoading: true,
}));
}); });
it('should handle NOTIFICATIONS_EXPAND_FAIL', () => { describe('NOTIFICATIONS_EXPAND_FAIL', () => {
const state = ImmutableMap({ it('sets isLoading to false', () => {
isLoading: true, const state = initialState.set('isLoading', true);
const action = { type: NOTIFICATIONS_EXPAND_FAIL };
expect(reducer(state, action).isLoading).toBe(false);
}); });
const action = {
type: NOTIFICATIONS_EXPAND_FAIL,
};
expect(reducer(state, action)).toEqual(ImmutableMap({
isLoading: false,
}));
}); });
it('should handle NOTIFICATIONS_FILTER_SET', () => { describe('NOTIFICATIONS_FILTER_SET', () => {
const state = ImmutableMap({ it('clears the items', () => {
items: ImmutableOrderedMap([ const actions = [{
['10744', ImmutableMap({ type: NOTIFICATIONS_EXPAND_SUCCESS,
id: '10744', notifications: [
type: 'pleroma:emoji_reaction', { id: '1', type: 'mention', status: { id: '4' }, account: { id: '7' } },
account: '9vMAje101ngtjlMj7w', { id: '2', type: 'mention', status: { id: '5' }, account: { id: '8' } },
target: null, { id: '3', type: 'mention', status: { id: '6' }, account: { id: '9' } },
created_at: '2020-06-10T02:54:39.000Z', ],
status: '9vvNxoo5EFbbnfdXQu', next: null,
emoji: '😢', skipLoading: true,
chat_message: undefined, }, {
})],
['10743', ImmutableMap({
id: '10743',
type: 'favourite',
account: '9v5c6xSEgAi3Zu1Lv6',
target: null,
created_at: '2020-06-10T02:51:05.000Z',
status: '9vvNxoo5EFbbnfdXQu',
emoji: undefined,
chat_message: undefined,
})],
['10741', ImmutableMap({
id: '10741',
type: 'favourite',
account: '9v5cKMOPGqPcgfcWp6',
target: null,
created_at: '2020-06-10T02:05:06.000Z',
status: '9vvNxoo5EFbbnfdXQu',
emoji: undefined,
chat_message: undefined,
})],
]),
hasMore: false,
top: false,
unread: 1,
isLoading: false,
queuedNotifications: ImmutableOrderedMap(),
totalQueuedNotificationsCount: 0,
lastRead: -1,
});
const action = {
type: NOTIFICATIONS_FILTER_SET, type: NOTIFICATIONS_FILTER_SET,
}; }];
expect(reducer(state, action)).toEqual(ImmutableMap({
items: ImmutableOrderedMap(), // Setup by expanding, then calling `NOTIFICATIONS_FILTER_SET`
hasMore: true, const result = applyActions(initialState, actions, reducer);
top: false,
unread: 1, // Setting the filter wipes notifications
isLoading: false, expect(result.items.isEmpty()).toBe(true);
queuedNotifications: ImmutableOrderedMap(),
totalQueuedNotificationsCount: 0,
lastRead: -1,
}));
}); });
it('should handle NOTIFICATIONS_SCROLL_TOP by changing unread to 0 when top = true', () => { it('sets hasMore to true', () => {
const state = ImmutableMap({ const state = initialState.set('hasMore', false);
unread: 1, const action = { type: NOTIFICATIONS_FILTER_SET };
const result = reducer(state, action);
expect(result.hasMore).toBe(true);
}); });
const action = {
type: NOTIFICATIONS_SCROLL_TOP,
top: true,
};
expect(reducer(state, action)).toEqual(ImmutableMap({
unread: 0,
top: true,
}));
}); });
it('should handle NOTIFICATIONS_SCROLL_TOP by not changing unread val when top = false', () => { describe('NOTIFICATIONS_SCROLL_TOP', () => {
const state = ImmutableMap({ it('resets `unread` counter to 0 when top is true (ie, scrolled to the top)', () => {
unread: 3, const state = initialState.set('unread', 1);
}); const action = { type: NOTIFICATIONS_SCROLL_TOP, top: true };
const action = { const result = reducer(state, action);
type: NOTIFICATIONS_SCROLL_TOP,
top: false, expect(result.unread).toEqual(0);
}; expect(result.top).toBe(true);
expect(reducer(state, action)).toEqual(ImmutableMap({
unread: 3,
top: false,
}));
}); });
it('should handle NOTIFICATIONS_UPDATE, when top = false, increment unread', () => { it('leaves `unread` alone when top is false (ie, not scrolled to top)', () => {
const state = ImmutableMap({ const state = initialState.set('unread', 3);
items: ImmutableOrderedMap(), const action = { type: NOTIFICATIONS_SCROLL_TOP, top: false };
top: false, const result = reducer(state, action);
unread: 1,
expect(result.unread).toEqual(3);
expect(result.top).toBe(false);
}); });
const action = {
type: NOTIFICATIONS_UPDATE,
notification: notification,
};
expect(reducer(state, action)).toEqual(ImmutableMap({
items: ImmutableOrderedMap([
['10743', ImmutableMap({
id: '10743',
type: 'favourite',
account: '9v5c6xSEgAi3Zu1Lv6',
target: null,
created_at: '2020-06-10T02:51:05.000Z',
status: '9vvNxoo5EFbbnfdXQu',
emoji: undefined,
chat_message: undefined,
})],
]),
top: false,
unread: 2,
}));
}); });
it('should handle NOTIFICATIONS_UPDATE_QUEUE', () => { describe('NOTIFICATIONS_UPDATE', () => {
const state = ImmutableMap({ it('imports the notification', () => {
items: ImmutableOrderedMap(), const action = { type: NOTIFICATIONS_UPDATE, notification };
queuedNotifications: ImmutableOrderedMap(), const result = reducer(initialState, action);
totalQueuedNotificationsCount: 0,
expect(result.items.get('10743').type).toEqual('favourite');
}); });
it('increments `unread` counter when top is false', () => {
const action = { type: NOTIFICATIONS_UPDATE, notification };
const result = reducer(initialState, action);
expect(result.unread).toEqual(1);
});
});
describe('NOTIFICATIONS_UPDATE_QUEUE', () => {
it('adds the notification to the queue (and increases the counter)', () => {
const action = { const action = {
type: NOTIFICATIONS_UPDATE_QUEUE, type: NOTIFICATIONS_UPDATE_QUEUE,
notification: notification, notification,
intlMessages: intlMessages, intlMessages,
intlLocale: 'en', intlLocale: 'en',
}; };
expect(reducer(state, action)).toEqual(ImmutableMap({
items: ImmutableOrderedMap(), const result = reducer(initialState, action);
queuedNotifications: ImmutableOrderedMap([[notification.id, {
notification: notification, // Doesn't add it as a regular item
intlMessages: intlMessages, expect(result.items.isEmpty()).toBe(true);
intlLocale: 'en',
}]]), // Adds it to the queued items
totalQueuedNotificationsCount: 1, expect(result.queuedNotifications.size).toEqual(1);
})); expect(result.totalQueuedNotificationsCount).toEqual(1);
expect(result.queuedNotifications.getIn(['10743', 'notification', 'type'])).toEqual('favourite');
});
}); });
it('should handle NOTIFICATIONS_DEQUEUE', () => { describe('NOTIFICATIONS_DEQUEUE', () => {
const state = ImmutableMap({ it('resets the queued counter to 0', () => {
items: ImmutableOrderedMap(), const state = initialState.set('totalQueuedNotificationsCount', 1);
queuedNotifications: take(notifications, 1), const action = { type: NOTIFICATIONS_DEQUEUE };
totalQueuedNotificationsCount: 1, const result = reducer(state, action);
expect(result.totalQueuedNotificationsCount).toEqual(0);
}); });
const action = {
type: NOTIFICATIONS_DEQUEUE,
};
expect(reducer(state, action)).toEqual(ImmutableMap({
items: ImmutableOrderedMap(),
queuedNotifications: ImmutableOrderedMap(),
totalQueuedNotificationsCount: 0,
}));
}); });
it('should handle NOTIFICATIONS_EXPAND_SUCCESS with non-empty items and next set true', () => { describe('NOTIFICATIONS_EXPAND_SUCCESS', () => {
it('with non-empty items and next set true', () => {
const state = ImmutableMap({ const state = ImmutableMap({
items: ImmutableOrderedMap([ items: ImmutableOrderedMap([
['10734', ImmutableMap({ ['10734', ImmutableMap({
@ -313,19 +223,21 @@ describe('notifications reducer', () => {
created_at: '2020-06-10T02:54:39.000Z', created_at: '2020-06-10T02:54:39.000Z',
status: '9vvNxoo5EFbbnfdXQu', status: '9vvNxoo5EFbbnfdXQu',
emoji: '😢', emoji: '😢',
chat_message: undefined, chat_message: null,
})], })],
]), ]),
unread: 1, unread: 1,
hasMore: true, hasMore: true,
isLoading: false, isLoading: false,
}); });
const action = { const action = {
type: NOTIFICATIONS_EXPAND_SUCCESS, type: NOTIFICATIONS_EXPAND_SUCCESS,
notifications: take(notifications, 3), notifications: take(notifications, 3),
next: true, next: true,
}; };
expect(reducer(state, action)).toEqual(ImmutableMap({
const expected = ImmutableMap({
items: ImmutableOrderedMap([ items: ImmutableOrderedMap([
['10744', ImmutableMap({ ['10744', ImmutableMap({
id: '10744', id: '10744',
@ -335,7 +247,7 @@ describe('notifications reducer', () => {
created_at: '2020-06-10T02:54:39.000Z', created_at: '2020-06-10T02:54:39.000Z',
status: '9vvNxoo5EFbbnfdXQu', status: '9vvNxoo5EFbbnfdXQu',
emoji: '😢', emoji: '😢',
chat_message: undefined, chat_message: null,
})], })],
['10743', ImmutableMap({ ['10743', ImmutableMap({
id: '10743', id: '10743',
@ -344,8 +256,8 @@ describe('notifications reducer', () => {
target: null, target: null,
created_at: '2020-06-10T02:51:05.000Z', created_at: '2020-06-10T02:51:05.000Z',
status: '9vvNxoo5EFbbnfdXQu', status: '9vvNxoo5EFbbnfdXQu',
emoji: undefined, emoji: null,
chat_message: undefined, chat_message: null,
})], })],
['10741', ImmutableMap({ ['10741', ImmutableMap({
id: '10741', id: '10741',
@ -354,8 +266,8 @@ describe('notifications reducer', () => {
target: null, target: null,
created_at: '2020-06-10T02:05:06.000Z', created_at: '2020-06-10T02:05:06.000Z',
status: '9vvNxoo5EFbbnfdXQu', status: '9vvNxoo5EFbbnfdXQu',
emoji: undefined, emoji: null,
chat_message: undefined, chat_message: null,
})], })],
['10734', ImmutableMap({ ['10734', ImmutableMap({
id: '10734', id: '10734',
@ -365,28 +277,32 @@ describe('notifications reducer', () => {
created_at: '2020-06-10T02:54:39.000Z', created_at: '2020-06-10T02:54:39.000Z',
status: '9vvNxoo5EFbbnfdXQu', status: '9vvNxoo5EFbbnfdXQu',
emoji: '😢', emoji: '😢',
chat_message: undefined, chat_message: null,
})], })],
]), ]),
unread: 1, unread: 1,
hasMore: true, hasMore: true,
isLoading: false, isLoading: false,
}));
}); });
it('should handle NOTIFICATIONS_EXPAND_SUCCESS with empty items and next set true', () => { expect(reducer(state, action).toJS()).toEqual(expected.toJS());
});
it('with empty items and next set true', () => {
const state = ImmutableMap({ const state = ImmutableMap({
items: ImmutableOrderedMap(), items: ImmutableOrderedMap(),
unread: 1, unread: 1,
hasMore: true, hasMore: true,
isLoading: false, isLoading: false,
}); });
const action = { const action = {
type: NOTIFICATIONS_EXPAND_SUCCESS, type: NOTIFICATIONS_EXPAND_SUCCESS,
notifications: take(notifications, 3), notifications: take(notifications, 3),
next: true, next: true,
}; };
expect(reducer(state, action)).toEqual(ImmutableMap({
const expected = ImmutableMap({
items: ImmutableOrderedMap([ items: ImmutableOrderedMap([
['10744', ImmutableMap({ ['10744', ImmutableMap({
id: '10744', id: '10744',
@ -396,7 +312,7 @@ describe('notifications reducer', () => {
created_at: '2020-06-10T02:54:39.000Z', created_at: '2020-06-10T02:54:39.000Z',
status: '9vvNxoo5EFbbnfdXQu', status: '9vvNxoo5EFbbnfdXQu',
emoji: '😢', emoji: '😢',
chat_message: undefined, chat_message: null,
})], })],
['10743', ImmutableMap({ ['10743', ImmutableMap({
id: '10743', id: '10743',
@ -405,8 +321,8 @@ describe('notifications reducer', () => {
target: null, target: null,
created_at: '2020-06-10T02:51:05.000Z', created_at: '2020-06-10T02:51:05.000Z',
status: '9vvNxoo5EFbbnfdXQu', status: '9vvNxoo5EFbbnfdXQu',
emoji: undefined, emoji: null,
chat_message: undefined, chat_message: null,
})], })],
['10741', ImmutableMap({ ['10741', ImmutableMap({
id: '10741', id: '10741',
@ -415,17 +331,21 @@ describe('notifications reducer', () => {
target: null, target: null,
created_at: '2020-06-10T02:05:06.000Z', created_at: '2020-06-10T02:05:06.000Z',
status: '9vvNxoo5EFbbnfdXQu', status: '9vvNxoo5EFbbnfdXQu',
emoji: undefined, emoji: null,
chat_message: undefined, chat_message: null,
})], })],
]), ]),
unread: 1, unread: 1,
hasMore: true, hasMore: true,
isLoading: false, isLoading: false,
}));
}); });
it('should handle ACCOUNT_BLOCK_SUCCESS', () => { expect(reducer(state, action).toJS()).toEqual(expected.toJS());
});
});
describe('ACCOUNT_BLOCK_SUCCESS', () => {
it('should handle', () => {
const state = ImmutableMap({ const state = ImmutableMap({
items: ImmutableOrderedMap([ items: ImmutableOrderedMap([
['10744', ImmutableMap({ ['10744', ImmutableMap({
@ -436,7 +356,7 @@ describe('notifications reducer', () => {
created_at: '2020-06-10T02:54:39.000Z', created_at: '2020-06-10T02:54:39.000Z',
status: '9vvNxoo5EFbbnfdXQu', status: '9vvNxoo5EFbbnfdXQu',
emoji: '😢', emoji: '😢',
chat_message: undefined, chat_message: null,
})], })],
['10743', ImmutableMap({ ['10743', ImmutableMap({
id: '10743', id: '10743',
@ -445,8 +365,8 @@ describe('notifications reducer', () => {
target: null, target: null,
created_at: '2020-06-10T02:51:05.000Z', created_at: '2020-06-10T02:51:05.000Z',
status: '9vvNxoo5EFbbnfdXQu', status: '9vvNxoo5EFbbnfdXQu',
emoji: undefined, emoji: null,
chat_message: undefined, chat_message: null,
})], })],
['10741', ImmutableMap({ ['10741', ImmutableMap({
id: '10741', id: '10741',
@ -455,14 +375,14 @@ describe('notifications reducer', () => {
target: null, target: null,
created_at: '2020-06-10T02:05:06.000Z', created_at: '2020-06-10T02:05:06.000Z',
status: '9vvNxoo5EFbbnfdXQu', status: '9vvNxoo5EFbbnfdXQu',
emoji: undefined, emoji: null,
chat_message: undefined, chat_message: null,
})], })],
]), ]),
}); });
const action = { const action = {
type: ACCOUNT_BLOCK_SUCCESS, type: ACCOUNT_BLOCK_SUCCESS,
relationship: relationship, relationship,
}; };
expect(reducer(state, action)).toEqual(ImmutableMap({ expect(reducer(state, action)).toEqual(ImmutableMap({
items: ImmutableOrderedMap([ items: ImmutableOrderedMap([
@ -473,8 +393,8 @@ describe('notifications reducer', () => {
target: null, target: null,
created_at: '2020-06-10T02:51:05.000Z', created_at: '2020-06-10T02:51:05.000Z',
status: '9vvNxoo5EFbbnfdXQu', status: '9vvNxoo5EFbbnfdXQu',
emoji: undefined, emoji: null,
chat_message: undefined, chat_message: null,
})], })],
['10741', ImmutableMap({ ['10741', ImmutableMap({
id: '10741', id: '10741',
@ -483,14 +403,16 @@ describe('notifications reducer', () => {
target: null, target: null,
created_at: '2020-06-10T02:05:06.000Z', created_at: '2020-06-10T02:05:06.000Z',
status: '9vvNxoo5EFbbnfdXQu', status: '9vvNxoo5EFbbnfdXQu',
emoji: undefined, emoji: null,
chat_message: undefined, chat_message: null,
})], })],
]), ]),
})); }));
}); });
});
it('should handle ACCOUNT_MUTE_SUCCESS', () => { describe('ACCOUNT_MUTE_SUCCESS', () => {
it('should handle', () => {
const state = ImmutableMap({ const state = ImmutableMap({
items: ImmutableOrderedMap([ items: ImmutableOrderedMap([
['10744', ImmutableMap({ ['10744', ImmutableMap({
@ -501,7 +423,7 @@ describe('notifications reducer', () => {
created_at: '2020-06-10T02:54:39.000Z', created_at: '2020-06-10T02:54:39.000Z',
status: '9vvNxoo5EFbbnfdXQu', status: '9vvNxoo5EFbbnfdXQu',
emoji: '😢', emoji: '😢',
chat_message: undefined, chat_message: null,
})], })],
['10743', ImmutableMap({ ['10743', ImmutableMap({
id: '10743', id: '10743',
@ -510,8 +432,8 @@ describe('notifications reducer', () => {
target: null, target: null,
created_at: '2020-06-10T02:51:05.000Z', created_at: '2020-06-10T02:51:05.000Z',
status: '9vvNxoo5EFbbnfdXQu', status: '9vvNxoo5EFbbnfdXQu',
emoji: undefined, emoji: null,
chat_message: undefined, chat_message: null,
})], })],
['10741', ImmutableMap({ ['10741', ImmutableMap({
id: '10741', id: '10741',
@ -520,8 +442,8 @@ describe('notifications reducer', () => {
target: null, target: null,
created_at: '2020-06-10T02:05:06.000Z', created_at: '2020-06-10T02:05:06.000Z',
status: '9vvNxoo5EFbbnfdXQu', status: '9vvNxoo5EFbbnfdXQu',
emoji: undefined, emoji: null,
chat_message: undefined, chat_message: null,
})], })],
]), ]),
}); });
@ -538,8 +460,8 @@ describe('notifications reducer', () => {
target: null, target: null,
created_at: '2020-06-10T02:51:05.000Z', created_at: '2020-06-10T02:51:05.000Z',
status: '9vvNxoo5EFbbnfdXQu', status: '9vvNxoo5EFbbnfdXQu',
emoji: undefined, emoji: null,
chat_message: undefined, chat_message: null,
})], })],
['10741', ImmutableMap({ ['10741', ImmutableMap({
id: '10741', id: '10741',
@ -548,157 +470,57 @@ describe('notifications reducer', () => {
target: null, target: null,
created_at: '2020-06-10T02:05:06.000Z', created_at: '2020-06-10T02:05:06.000Z',
status: '9vvNxoo5EFbbnfdXQu', status: '9vvNxoo5EFbbnfdXQu',
emoji: undefined, emoji: null,
chat_message: undefined, chat_message: null,
})], })],
]), ]),
})); }));
}); });
it('should handle NOTIFICATIONS_CLEAR', () => {
const state = ImmutableMap({
items: ImmutableOrderedMap(),
hasMore: true,
});
const action = {
type: NOTIFICATIONS_CLEAR,
};
expect(reducer(state, action)).toEqual(ImmutableMap({
items: ImmutableOrderedMap(),
hasMore: false,
}));
}); });
it('should handle NOTIFICATIONS_MARK_READ_REQUEST', () => { describe('NOTIFICATIONS_CLEAR', () => {
const state = ImmutableMap({ it('clears the items', () => {
items: ImmutableOrderedMap(), const state = initialState.set('items', ImmutableOrderedMap([['1', {}], ['2', {}]]));
const action = { type: NOTIFICATIONS_CLEAR };
const result = reducer(state, action);
expect(result.items.isEmpty()).toBe(true);
}); });
const action = {
type: NOTIFICATIONS_MARK_READ_REQUEST,
lastRead: 35098814,
};
expect(reducer(state, action)).toEqual(ImmutableMap({
items: ImmutableOrderedMap(),
lastRead: 35098814,
}));
}); });
it('should handle TIMELINE_DELETE', () => { describe('NOTIFICATIONS_MARK_READ_REQUEST', () => {
const state = ImmutableMap({ it('sets lastRead to the one in the action', () => {
items: ImmutableOrderedMap([ const action = { type: NOTIFICATIONS_MARK_READ_REQUEST, lastRead: '1234' };
['10744', ImmutableMap({ const result = reducer(undefined, action);
id: '10744',
type: 'pleroma:emoji_reaction', expect(result.lastRead).toEqual('1234');
account: '9vMAje101ngtjlMj7w',
target: null,
created_at: '2020-06-10T02:54:39.000Z',
status: '9vvNxoo5EFbbnfdXQu',
emoji: '😢',
chat_message: undefined,
})],
['10743', ImmutableMap({
id: '10743',
type: 'favourite',
account: '9v5c6xSEgAi3Zu1Lv6',
target: null,
created_at: '2020-06-10T02:51:05.000Z',
status: '9vvNxoo5EFbbnfdXQu',
emoji: undefined,
chat_message: undefined,
})],
['10741', ImmutableMap({
id: '10741',
type: 'favourite',
account: '9v5cKMOPGqPcgfcWp6',
target: null,
created_at: '2020-06-10T02:05:06.000Z',
status: '9vvNxoo5EFbbnfdXQu',
emoji: undefined,
chat_message: undefined,
})],
]),
}); });
const action = { });
describe('TIMELINE_DELETE', () => {
it('deletes notifications corresponding to the status ID', () => {
const actions = [{
type: NOTIFICATIONS_EXPAND_SUCCESS,
notifications: [
{ id: '1', type: 'mention', status: { id: '4' }, account: { id: '7' } },
{ id: '2', type: 'mention', status: { id: '5' }, account: { id: '8' } },
{ id: '3', type: 'mention', status: { id: '6' }, account: { id: '9' } },
{ id: '4', type: 'mention', status: { id: '5' }, account: { id: '7' } },
],
next: null,
skipLoading: true,
}, {
type: TIMELINE_DELETE, type: TIMELINE_DELETE,
id: '9vvNxoo5EFbbnfdXQu', id: '5',
}; }];
expect(reducer(state, action)).toEqual(ImmutableMap({
items: ImmutableOrderedMap(),
}));
});
// Disable for now // Setup by expanding, then calling `NOTIFICATIONS_FILTER_SET`
// https://gitlab.com/soapbox-pub/soapbox-fe/-/issues/432 const result = applyActions(initialState, actions, reducer);
//
// it('should handle TIMELINE_DISCONNECT', () => { expect(result.items.size).toEqual(2);
// const state = ImmutableMap({ expect(result.items.get('5')).toBe(undefined);
// items: ImmutableOrderedSet([ });
// ImmutableMap({ });
// id: '10744',
// type: 'pleroma:emoji_reaction',
// account: '9vMAje101ngtjlMj7w',
// created_at: '2020-06-10T02:54:39.000Z',
// status: '9vvNxoo5EFbbnfdXQu',
// emoji: '😢',
// chat_message: undefined,
// }),
// ImmutableMap({
// id: '10743',
// type: 'favourite',
// account: '9v5c6xSEgAi3Zu1Lv6',
// created_at: '2020-06-10T02:51:05.000Z',
// status: '9vvNxoo5EFbbnfdXQu',
// emoji: undefined,
// chat_message: undefined,
// }),
// ImmutableMap({
// id: '10741',
// type: 'favourite',
// account: '9v5cKMOPGqPcgfcWp6',
// created_at: '2020-06-10T02:05:06.000Z',
// status: '9vvNxoo5EFbbnfdXQu',
// emoji: undefined,
// chat_message: undefined,
// }),
// ]),
// });
// const action = {
// type: TIMELINE_DISCONNECT,
// timeline: 'home',
// };
// expect(reducer(state, action)).toEqual(ImmutableMap({
// items: ImmutableOrderedSet([
// null,
// ImmutableMap({
// id: '10744',
// type: 'pleroma:emoji_reaction',
// account: '9vMAje101ngtjlMj7w',
// created_at: '2020-06-10T02:54:39.000Z',
// status: '9vvNxoo5EFbbnfdXQu',
// emoji: '😢',
// chat_message: undefined,
// }),
// ImmutableMap({
// id: '10743',
// type: 'favourite',
// account: '9v5c6xSEgAi3Zu1Lv6',
// created_at: '2020-06-10T02:51:05.000Z',
// status: '9vvNxoo5EFbbnfdXQu',
// emoji: undefined,
// chat_message: undefined,
// }),
// ImmutableMap({
// id: '10741',
// type: 'favourite',
// account: '9v5cKMOPGqPcgfcWp6',
// created_at: '2020-06-10T02:05:06.000Z',
// status: '9vvNxoo5EFbbnfdXQu',
// emoji: undefined,
// chat_message: undefined,
// }),
// ]),
// }));
// });
describe('MARKER_FETCH_SUCCESS', () => { describe('MARKER_FETCH_SUCCESS', () => {
it('sets lastRead', () => { it('sets lastRead', () => {

View File

@ -2,6 +2,7 @@ import {
Map as ImmutableMap, Map as ImmutableMap,
List as ImmutableList, List as ImmutableList,
Set as ImmutableSet, Set as ImmutableSet,
Record as ImmutableRecord,
OrderedSet as ImmutableOrderedSet, OrderedSet as ImmutableOrderedSet,
fromJS, fromJS,
is, is,
@ -20,7 +21,7 @@ import {
ADMIN_USERS_APPROVE_SUCCESS, ADMIN_USERS_APPROVE_SUCCESS,
} from '../actions/admin'; } from '../actions/admin';
const initialState = ImmutableMap({ const ReducerRecord = ImmutableRecord({
reports: ImmutableMap(), reports: ImmutableMap(),
openReports: ImmutableOrderedSet(), openReports: ImmutableOrderedSet(),
users: ImmutableMap(), users: ImmutableMap(),
@ -126,7 +127,7 @@ function handleReportDiffs(state, reports) {
}); });
} }
export default function admin(state = initialState, action) { export default function admin(state = ReducerRecord(), action) {
switch(action.type) { switch(action.type) {
case ADMIN_CONFIG_FETCH_SUCCESS: case ADMIN_CONFIG_FETCH_SUCCESS:
case ADMIN_CONFIG_UPDATE_SUCCESS: case ADMIN_CONFIG_UPDATE_SUCCESS:

View File

@ -1,12 +1,13 @@
import { import {
Map as ImmutableMap, Map as ImmutableMap,
Record as ImmutableRecord,
OrderedSet as ImmutableOrderedSet, OrderedSet as ImmutableOrderedSet,
fromJS, fromJS,
} from 'immutable'; } from 'immutable';
import { ADMIN_LOG_FETCH_SUCCESS } from 'soapbox/actions/admin'; import { ADMIN_LOG_FETCH_SUCCESS } from 'soapbox/actions/admin';
const initialState = ImmutableMap({ const ReducerRecord = ImmutableRecord({
items: ImmutableMap(), items: ImmutableMap(),
index: ImmutableOrderedSet(), index: ImmutableOrderedSet(),
total: 0, total: 0,
@ -34,7 +35,7 @@ const importItems = (state, items, total) => {
}); });
}; };
export default function admin_log(state = initialState, action) { export default function admin_log(state = ReducerRecord(), action) {
switch(action.type) { switch(action.type) {
case ADMIN_LOG_FETCH_SUCCESS: case ADMIN_LOG_FETCH_SUCCESS:
return importItems(state, action.items, action.total); return importItems(state, action.items, action.total);

View File

@ -1,4 +1,4 @@
import { Map as ImmutableMap, List as ImmutableList } from 'immutable'; import { Record as ImmutableRecord, List as ImmutableList } from 'immutable';
import { import {
ALERT_SHOW, ALERT_SHOW,
@ -6,21 +6,38 @@ import {
ALERT_CLEAR, ALERT_CLEAR,
} from '../actions/alerts'; } from '../actions/alerts';
const initialState = ImmutableList([]); const AlertRecord = ImmutableRecord({
key: 0,
title: '',
message: '',
severity: 'info',
actionLabel: '',
actionLink: '',
});
const initialState = ImmutableList();
// Get next key based on last alert
const getNextKey = state => state.size > 0 ? state.last().get('key') + 1 : 0;
// Import the alert
const importAlert = (state, alert) => {
const key = getNextKey(state);
const record = AlertRecord({ ...alert, key });
return state.push(record);
};
// Delete an alert by its key
const deleteAlert = (state, alert) => {
return state.filterNot(item => item.key === alert.key);
};
export default function alerts(state = initialState, action) { export default function alerts(state = initialState, action) {
switch(action.type) { switch(action.type) {
case ALERT_SHOW: case ALERT_SHOW:
return state.push(ImmutableMap({ return importAlert(state, action);
key: state.size > 0 ? state.last().get('key') + 1 : 0,
title: action.title,
message: action.message,
severity: action.severity || 'info',
actionLabel: action.actionLabel,
actionLink: action.actionLink,
}));
case ALERT_DISMISS: case ALERT_DISMISS:
return state.filterNot(item => item.get('key') === action.alert.key); return deleteAlert(state, action.alert);
case ALERT_CLEAR: case ALERT_CLEAR:
return state.clear(); return state.clear();
default: default:

View File

@ -1,12 +1,14 @@
'use strict'; 'use strict';
import { Map as ImmutableMap } from 'immutable'; import { Record as ImmutableRecord } from 'immutable';
import { INSTANCE_FETCH_FAIL } from 'soapbox/actions/instance'; import { INSTANCE_FETCH_FAIL } from 'soapbox/actions/instance';
const initialState = ImmutableMap(); const ReducerRecord = ImmutableRecord({
instance_fetch_failed: false,
});
export default function meta(state = initialState, action) { export default function meta(state = ReducerRecord(), action) {
switch(action.type) { switch(action.type) {
case INSTANCE_FETCH_FAIL: case INSTANCE_FETCH_FAIL:
return state.set('instance_fetch_failed', true); return state.set('instance_fetch_failed', true);

View File

@ -1,10 +1,10 @@
import { Map as ImmutableMap, OrderedMap as ImmutableOrderedMap, fromJS } from 'immutable';
import { import {
MARKER_FETCH_SUCCESS, Record as ImmutableRecord,
MARKER_SAVE_REQUEST, OrderedMap as ImmutableOrderedMap,
MARKER_SAVE_SUCCESS, fromJS,
} from 'soapbox/actions/markers'; } from 'immutable';
import { normalizeNotification } from 'soapbox/normalizers/notification';
import { import {
ACCOUNT_BLOCK_SUCCESS, ACCOUNT_BLOCK_SUCCESS,
@ -12,6 +12,11 @@ import {
FOLLOW_REQUEST_AUTHORIZE_SUCCESS, FOLLOW_REQUEST_AUTHORIZE_SUCCESS,
FOLLOW_REQUEST_REJECT_SUCCESS, FOLLOW_REQUEST_REJECT_SUCCESS,
} from '../actions/accounts'; } from '../actions/accounts';
import {
MARKER_FETCH_SUCCESS,
MARKER_SAVE_REQUEST,
MARKER_SAVE_SUCCESS,
} from '../actions/markers';
import { import {
NOTIFICATIONS_UPDATE, NOTIFICATIONS_UPDATE,
NOTIFICATIONS_EXPAND_SUCCESS, NOTIFICATIONS_EXPAND_SUCCESS,
@ -27,7 +32,7 @@ import {
} from '../actions/notifications'; } from '../actions/notifications';
import { TIMELINE_DELETE } from '../actions/timelines'; import { TIMELINE_DELETE } from '../actions/timelines';
const initialState = ImmutableMap({ const ReducerRecord = ImmutableRecord({
items: ImmutableOrderedMap(), items: ImmutableOrderedMap(),
hasMore: true, hasMore: true,
top: false, top: false,
@ -48,16 +53,16 @@ const comparator = (a, b) => {
return 0; return 0;
}; };
const notificationToMap = notification => ImmutableMap({ const minifyNotification = notification => {
id: notification.id, return notification.mergeWith((o, n) => n || o, {
type: notification.type, account: notification.getIn(['account', 'id']),
account: notification.account.id, status: notification.getIn(['status', 'id']),
target: notification.target ? notification.target.id : null,
created_at: notification.created_at,
status: notification.status ? notification.status.id : null,
emoji: notification.emoji,
chat_message: notification.chat_message,
}); });
};
const fixNotification = notification => {
return minifyNotification(normalizeNotification(notification));
};
const isValid = notification => { const isValid = notification => {
try { try {
@ -88,7 +93,7 @@ const countFuture = (notifications, lastId) => {
}, 0); }, 0);
}; };
const normalizeNotification = (state, notification) => { const importNotification = (state, notification) => {
const top = state.get('top'); const top = state.get('top');
if (!top) state = state.update('unread', unread => unread + 1); if (!top) state = state.update('unread', unread => unread + 1);
@ -98,7 +103,7 @@ const normalizeNotification = (state, notification) => {
map = map.take(20); map = map.take(20);
} }
return map.set(notification.id, notificationToMap(notification)).sort(comparator); return map.set(notification.id, fixNotification(notification)).sort(comparator);
}); });
}; };
@ -106,7 +111,7 @@ const processRawNotifications = notifications => (
ImmutableOrderedMap( ImmutableOrderedMap(
notifications notifications
.filter(isValid) .filter(isValid)
.map(n => [n.id, notificationToMap(n)]), .map(n => [n.id, fixNotification(n)]),
)); ));
const expandNormalizedNotifications = (state, notifications, next) => { const expandNormalizedNotifications = (state, notifications, next) => {
@ -176,23 +181,23 @@ const importMarker = (state, marker) => {
}); });
}; };
export default function notifications(state = initialState, action) { export default function notifications(state = ReducerRecord(), action) {
switch(action.type) { switch(action.type) {
case NOTIFICATIONS_EXPAND_REQUEST: case NOTIFICATIONS_EXPAND_REQUEST:
return state.set('isLoading', true); return state.set('isLoading', true);
case NOTIFICATIONS_EXPAND_FAIL: case NOTIFICATIONS_EXPAND_FAIL:
return state.set('isLoading', false); return state.set('isLoading', false);
case NOTIFICATIONS_FILTER_SET: case NOTIFICATIONS_FILTER_SET:
return state.set('items', ImmutableOrderedMap()).set('hasMore', true); return state.delete('items').set('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:
return normalizeNotification(state, action.notification); return importNotification(state, action.notification);
case NOTIFICATIONS_UPDATE_QUEUE: case NOTIFICATIONS_UPDATE_QUEUE:
return updateNotificationsQueue(state, action.notification, action.intlMessages, action.intlLocale); return updateNotificationsQueue(state, action.notification, action.intlMessages, action.intlLocale);
case NOTIFICATIONS_DEQUEUE: case NOTIFICATIONS_DEQUEUE:
return state.withMutations(mutable => { return state.withMutations(mutable => {
mutable.set('queuedNotifications', ImmutableOrderedMap()); mutable.delete('queuedNotifications');
mutable.set('totalQueuedNotificationsCount', 0); mutable.set('totalQueuedNotificationsCount', 0);
}); });
case NOTIFICATIONS_EXPAND_SUCCESS: case NOTIFICATIONS_EXPAND_SUCCESS:
@ -205,7 +210,7 @@ export default function notifications(state = initialState, action) {
case FOLLOW_REQUEST_REJECT_SUCCESS: case FOLLOW_REQUEST_REJECT_SUCCESS:
return filterNotificationIds(state, [action.id], 'follow_request'); return filterNotificationIds(state, [action.id], 'follow_request');
case NOTIFICATIONS_CLEAR: case NOTIFICATIONS_CLEAR:
return state.set('items', ImmutableOrderedMap()).set('hasMore', false); return state.delete('items').set('hasMore', false);
case NOTIFICATIONS_MARK_READ_REQUEST: case NOTIFICATIONS_MARK_READ_REQUEST:
return state.set('lastRead', action.lastRead); return state.set('lastRead', action.lastRead);
case MARKER_FETCH_SUCCESS: case MARKER_FETCH_SUCCESS:
@ -214,16 +219,6 @@ export default function notifications(state = initialState, action) {
return importMarker(state, fromJS(action.marker)); return importMarker(state, fromJS(action.marker));
case TIMELINE_DELETE: case TIMELINE_DELETE:
return deleteByStatus(state, action.id); return deleteByStatus(state, action.id);
// Disable for now
// https://gitlab.com/soapbox-pub/soapbox-fe/-/issues/432
//
// case TIMELINE_DISCONNECT:
// // This is kind of a hack - `null` renders a LoadGap in the component
// // https://github.com/tootsuite/mastodon/pull/6886
// return action.timeline === 'home' ?
// state.update('items', items => items.first() ? ImmutableOrderedSet([null]).union(items) : items) :
// state;
default: default:
return state; return state;
} }

View File

@ -33,3 +33,8 @@ export const createComponent = (children, props = {}) => {
</Provider>, </Provider>,
); );
}; };
// Apply actions to the state, one at a time
export const applyActions = (state, actions, reducer) => {
return actions.reduce((state, action) => reducer(state, action), state);
};