Merge branch 'main' into captcha-modal
This commit is contained in:
commit
2aa21874f7
|
@ -132,7 +132,6 @@
|
|||
"react-error-boundary": "^4.0.11",
|
||||
"react-helmet": "^6.1.0",
|
||||
"react-hot-toast": "^2.4.0",
|
||||
"react-immutable-pure-component": "^2.2.2",
|
||||
"react-inlinesvg": "^4.0.0",
|
||||
"react-intl": "^6.0.0",
|
||||
"react-motion": "^0.5.2",
|
||||
|
@ -147,7 +146,6 @@
|
|||
"react-swipeable-views": "^0.14.0",
|
||||
"react-virtuoso": "^4.10.4",
|
||||
"redux": "^5.0.0",
|
||||
"redux-immutable": "^4.0.0",
|
||||
"redux-thunk": "^3.1.0",
|
||||
"reselect": "^5.0.0",
|
||||
"sass": "^1.69.5",
|
||||
|
|
|
@ -73,15 +73,17 @@ describe('fetchAccount()', () => {
|
|||
avatar: 'test.jpg',
|
||||
});
|
||||
|
||||
const state = rootState
|
||||
.set('entities', {
|
||||
const state = {
|
||||
...rootState,
|
||||
entities: {
|
||||
'ACCOUNTS': {
|
||||
store: {
|
||||
[id]: account,
|
||||
},
|
||||
lists: {},
|
||||
},
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
store = mockStore(state);
|
||||
|
||||
|
@ -170,15 +172,17 @@ describe('fetchAccountByUsername()', () => {
|
|||
birthday: undefined,
|
||||
});
|
||||
|
||||
state = rootState
|
||||
.set('entities', {
|
||||
state = {
|
||||
...rootState,
|
||||
entities: {
|
||||
'ACCOUNTS': {
|
||||
store: {
|
||||
[id]: account,
|
||||
},
|
||||
lists: {},
|
||||
},
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
store = mockStore(state);
|
||||
|
||||
|
@ -189,16 +193,19 @@ describe('fetchAccountByUsername()', () => {
|
|||
|
||||
describe('when "accountByUsername" feature is enabled', () => {
|
||||
beforeEach(() => {
|
||||
const state = rootState
|
||||
.set('instance', buildInstance({
|
||||
const state = {
|
||||
...rootState,
|
||||
me: '123',
|
||||
instance: buildInstance({
|
||||
version: '2.7.2 (compatible; Pleroma 2.4.52-1337-g4779199e.gleasonator+soapbox)',
|
||||
pleroma: {
|
||||
metadata: {
|
||||
features: [],
|
||||
},
|
||||
},
|
||||
}))
|
||||
.set('me', '123');
|
||||
}),
|
||||
};
|
||||
|
||||
store = mockStore(state);
|
||||
});
|
||||
|
||||
|
@ -252,16 +259,19 @@ describe('fetchAccountByUsername()', () => {
|
|||
|
||||
describe('when "accountLookup" feature is enabled', () => {
|
||||
beforeEach(() => {
|
||||
const state = rootState
|
||||
.set('instance', buildInstance({
|
||||
const state = {
|
||||
...rootState,
|
||||
me: '123',
|
||||
instance: buildInstance({
|
||||
version: '3.4.1 (compatible; TruthSocial 1.0.0)',
|
||||
pleroma: {
|
||||
metadata: {
|
||||
features: [],
|
||||
},
|
||||
},
|
||||
}))
|
||||
.set('me', '123');
|
||||
}),
|
||||
};
|
||||
|
||||
store = mockStore(state);
|
||||
});
|
||||
|
||||
|
@ -317,7 +327,7 @@ describe('fetchAccountByUsername()', () => {
|
|||
|
||||
describe('when using the accountSearch function', () => {
|
||||
beforeEach(() => {
|
||||
const state = rootState.set('me', '123');
|
||||
const state = { ...rootState, me: '123' };
|
||||
store = mockStore(state);
|
||||
});
|
||||
|
||||
|
@ -384,7 +394,7 @@ describe('blockAccount()', () => {
|
|||
|
||||
describe('when logged out', () => {
|
||||
beforeEach(() => {
|
||||
const state = rootState.set('me', null);
|
||||
const state = { ...rootState, me: null };
|
||||
store = mockStore(state);
|
||||
});
|
||||
|
||||
|
@ -398,7 +408,7 @@ describe('blockAccount()', () => {
|
|||
|
||||
describe('when logged in', () => {
|
||||
beforeEach(() => {
|
||||
const state = rootState.set('me', '123');
|
||||
const state = { ...rootState, me: '123' };
|
||||
store = mockStore(state);
|
||||
});
|
||||
|
||||
|
@ -451,7 +461,7 @@ describe('unblockAccount()', () => {
|
|||
|
||||
describe('when logged out', () => {
|
||||
beforeEach(() => {
|
||||
const state = rootState.set('me', null);
|
||||
const state = { ...rootState, me: null };
|
||||
store = mockStore(state);
|
||||
});
|
||||
|
||||
|
@ -465,7 +475,7 @@ describe('unblockAccount()', () => {
|
|||
|
||||
describe('when logged in', () => {
|
||||
beforeEach(() => {
|
||||
const state = rootState.set('me', '123');
|
||||
const state = { ...rootState, me: '123' };
|
||||
store = mockStore(state);
|
||||
});
|
||||
|
||||
|
@ -517,7 +527,7 @@ describe('muteAccount()', () => {
|
|||
|
||||
describe('when logged out', () => {
|
||||
beforeEach(() => {
|
||||
const state = rootState.set('me', null);
|
||||
const state = { ...rootState, me: null };
|
||||
store = mockStore(state);
|
||||
});
|
||||
|
||||
|
@ -531,7 +541,7 @@ describe('muteAccount()', () => {
|
|||
|
||||
describe('when logged in', () => {
|
||||
beforeEach(() => {
|
||||
const state = rootState.set('me', '123');
|
||||
const state = { ...rootState, me: '123' };
|
||||
store = mockStore(state);
|
||||
});
|
||||
|
||||
|
@ -584,7 +594,7 @@ describe('unmuteAccount()', () => {
|
|||
|
||||
describe('when logged out', () => {
|
||||
beforeEach(() => {
|
||||
const state = rootState.set('me', null);
|
||||
const state = { ...rootState, me: null };
|
||||
store = mockStore(state);
|
||||
});
|
||||
|
||||
|
@ -598,7 +608,7 @@ describe('unmuteAccount()', () => {
|
|||
|
||||
describe('when logged in', () => {
|
||||
beforeEach(() => {
|
||||
const state = rootState.set('me', '123');
|
||||
const state = { ...rootState, me: '123' };
|
||||
store = mockStore(state);
|
||||
});
|
||||
|
||||
|
@ -650,7 +660,7 @@ describe('subscribeAccount()', () => {
|
|||
|
||||
describe('when logged out', () => {
|
||||
beforeEach(() => {
|
||||
const state = rootState.set('me', null);
|
||||
const state = { ...rootState, me: null };
|
||||
store = mockStore(state);
|
||||
});
|
||||
|
||||
|
@ -664,7 +674,7 @@ describe('subscribeAccount()', () => {
|
|||
|
||||
describe('when logged in', () => {
|
||||
beforeEach(() => {
|
||||
const state = rootState.set('me', '123');
|
||||
const state = { ...rootState, me: '123' };
|
||||
store = mockStore(state);
|
||||
});
|
||||
|
||||
|
@ -716,7 +726,7 @@ describe('unsubscribeAccount()', () => {
|
|||
|
||||
describe('when logged out', () => {
|
||||
beforeEach(() => {
|
||||
const state = rootState.set('me', null);
|
||||
const state = { ...rootState, me: null };
|
||||
store = mockStore(state);
|
||||
});
|
||||
|
||||
|
@ -730,7 +740,7 @@ describe('unsubscribeAccount()', () => {
|
|||
|
||||
describe('when logged in', () => {
|
||||
beforeEach(() => {
|
||||
const state = rootState.set('me', '123');
|
||||
const state = { ...rootState, me: '123' };
|
||||
store = mockStore(state);
|
||||
});
|
||||
|
||||
|
@ -782,7 +792,7 @@ describe('removeFromFollowers()', () => {
|
|||
|
||||
describe('when logged out', () => {
|
||||
beforeEach(() => {
|
||||
const state = rootState.set('me', null);
|
||||
const state = { ...rootState, me: null };
|
||||
store = mockStore(state);
|
||||
});
|
||||
|
||||
|
@ -796,7 +806,7 @@ describe('removeFromFollowers()', () => {
|
|||
|
||||
describe('when logged in', () => {
|
||||
beforeEach(() => {
|
||||
const state = rootState.set('me', '123');
|
||||
const state = { ...rootState, me: '123' };
|
||||
store = mockStore(state);
|
||||
});
|
||||
|
||||
|
@ -848,7 +858,7 @@ describe('fetchFollowers()', () => {
|
|||
|
||||
describe('when logged in', () => {
|
||||
beforeEach(() => {
|
||||
const state = rootState.set('me', '123');
|
||||
const state = { ...rootState, me: '123' };
|
||||
store = mockStore(state);
|
||||
});
|
||||
|
||||
|
@ -905,7 +915,7 @@ describe('expandFollowers()', () => {
|
|||
|
||||
describe('when logged out', () => {
|
||||
beforeEach(() => {
|
||||
const state = rootState.set('me', null);
|
||||
const state = { ...rootState, me: null };
|
||||
store = mockStore(state);
|
||||
});
|
||||
|
||||
|
@ -919,29 +929,35 @@ describe('expandFollowers()', () => {
|
|||
|
||||
describe('when logged in', () => {
|
||||
beforeEach(() => {
|
||||
const state = rootState
|
||||
.set('user_lists', ReducerRecord({
|
||||
const state = {
|
||||
...rootState,
|
||||
me: '123',
|
||||
user_lists: ReducerRecord({
|
||||
followers: ImmutableMap({
|
||||
[id]: ListRecord({
|
||||
next: 'next_url',
|
||||
}),
|
||||
}),
|
||||
}))
|
||||
.set('me', '123');
|
||||
}),
|
||||
};
|
||||
|
||||
store = mockStore(state);
|
||||
});
|
||||
|
||||
describe('when the url is null', () => {
|
||||
beforeEach(() => {
|
||||
const state = rootState
|
||||
.set('user_lists', ReducerRecord({
|
||||
const state = {
|
||||
...rootState,
|
||||
me: '123',
|
||||
user_lists: ReducerRecord({
|
||||
followers: ImmutableMap({
|
||||
[id]: ListRecord({
|
||||
next: null,
|
||||
}),
|
||||
}),
|
||||
}))
|
||||
.set('me', '123');
|
||||
}),
|
||||
};
|
||||
|
||||
store = mockStore(state);
|
||||
});
|
||||
|
||||
|
@ -1006,7 +1022,7 @@ describe('fetchFollowing()', () => {
|
|||
|
||||
describe('when logged in', () => {
|
||||
beforeEach(() => {
|
||||
const state = rootState.set('me', '123');
|
||||
const state = { ...rootState, me: '123' };
|
||||
store = mockStore(state);
|
||||
});
|
||||
|
||||
|
@ -1063,7 +1079,7 @@ describe('expandFollowing()', () => {
|
|||
|
||||
describe('when logged out', () => {
|
||||
beforeEach(() => {
|
||||
const state = rootState.set('me', null);
|
||||
const state = { ...rootState, me: null };
|
||||
store = mockStore(state);
|
||||
});
|
||||
|
||||
|
@ -1077,29 +1093,35 @@ describe('expandFollowing()', () => {
|
|||
|
||||
describe('when logged in', () => {
|
||||
beforeEach(() => {
|
||||
const state = rootState
|
||||
.set('user_lists', ReducerRecord({
|
||||
const state = {
|
||||
...rootState,
|
||||
me: '123',
|
||||
user_lists: ReducerRecord({
|
||||
following: ImmutableMap({
|
||||
[id]: ListRecord({
|
||||
next: 'next_url',
|
||||
}),
|
||||
}),
|
||||
}))
|
||||
.set('me', '123');
|
||||
}),
|
||||
};
|
||||
|
||||
store = mockStore(state);
|
||||
});
|
||||
|
||||
describe('when the url is null', () => {
|
||||
beforeEach(() => {
|
||||
const state = rootState
|
||||
.set('user_lists', ReducerRecord({
|
||||
const state = {
|
||||
...rootState,
|
||||
me: '123',
|
||||
user_lists: ReducerRecord({
|
||||
following: ImmutableMap({
|
||||
[id]: ListRecord({
|
||||
next: null,
|
||||
}),
|
||||
}),
|
||||
}))
|
||||
.set('me', '123');
|
||||
}),
|
||||
};
|
||||
|
||||
store = mockStore(state);
|
||||
});
|
||||
|
||||
|
@ -1164,7 +1186,7 @@ describe('fetchRelationships()', () => {
|
|||
|
||||
describe('when logged out', () => {
|
||||
beforeEach(() => {
|
||||
const state = rootState.set('me', null);
|
||||
const state = { ...rootState, me: null };
|
||||
store = mockStore(state);
|
||||
});
|
||||
|
||||
|
@ -1178,16 +1200,18 @@ describe('fetchRelationships()', () => {
|
|||
|
||||
describe('when logged in', () => {
|
||||
beforeEach(() => {
|
||||
const state = rootState
|
||||
.set('me', '123');
|
||||
const state = { ...rootState, me: '123' };
|
||||
store = mockStore(state);
|
||||
});
|
||||
|
||||
describe('without newAccountIds', () => {
|
||||
beforeEach(() => {
|
||||
const state = rootState
|
||||
.set('relationships', ImmutableMap({ [id]: buildRelationship() }))
|
||||
.set('me', '123');
|
||||
const state = {
|
||||
...rootState,
|
||||
me: '123',
|
||||
relationships: ImmutableMap({ [id]: buildRelationship() }),
|
||||
};
|
||||
|
||||
store = mockStore(state);
|
||||
});
|
||||
|
||||
|
@ -1201,9 +1225,12 @@ describe('fetchRelationships()', () => {
|
|||
|
||||
describe('with a successful API request', () => {
|
||||
beforeEach(() => {
|
||||
const state = rootState
|
||||
.set('relationships', ImmutableMap({}))
|
||||
.set('me', '123');
|
||||
const state = {
|
||||
...rootState,
|
||||
me: '123',
|
||||
relationships: ImmutableMap(),
|
||||
};
|
||||
|
||||
store = mockStore(state);
|
||||
|
||||
__stub((mock) => {
|
||||
|
@ -1255,7 +1282,7 @@ describe('fetchRelationships()', () => {
|
|||
describe('fetchFollowRequests()', () => {
|
||||
describe('when logged out', () => {
|
||||
beforeEach(() => {
|
||||
const state = rootState.set('me', null);
|
||||
const state = { ...rootState, me: null };
|
||||
store = mockStore(state);
|
||||
});
|
||||
|
||||
|
@ -1269,16 +1296,18 @@ describe('fetchFollowRequests()', () => {
|
|||
|
||||
describe('when logged in', () => {
|
||||
beforeEach(() => {
|
||||
const state = rootState
|
||||
.set('me', '123');
|
||||
const state = { ...rootState, me: '123' };
|
||||
store = mockStore(state);
|
||||
});
|
||||
|
||||
describe('with a successful API request', () => {
|
||||
beforeEach(() => {
|
||||
const state = rootState
|
||||
.set('relationships', ImmutableMap({}))
|
||||
.set('me', '123');
|
||||
const state = {
|
||||
...rootState,
|
||||
me: '123',
|
||||
relationships: ImmutableMap(),
|
||||
};
|
||||
|
||||
store = mockStore(state);
|
||||
|
||||
__stub((mock) => {
|
||||
|
@ -1329,7 +1358,7 @@ describe('fetchFollowRequests()', () => {
|
|||
describe('expandFollowRequests()', () => {
|
||||
describe('when logged out', () => {
|
||||
beforeEach(() => {
|
||||
const state = rootState.set('me', null);
|
||||
const state = { ...rootState, me: null };
|
||||
store = mockStore(state);
|
||||
});
|
||||
|
||||
|
@ -1343,25 +1372,29 @@ describe('expandFollowRequests()', () => {
|
|||
|
||||
describe('when logged in', () => {
|
||||
beforeEach(() => {
|
||||
const state = rootState
|
||||
.set('user_lists', ReducerRecord({
|
||||
const state = {
|
||||
...rootState,
|
||||
me: '123',
|
||||
user_lists: ReducerRecord({
|
||||
follow_requests: ListRecord({
|
||||
next: 'next_url',
|
||||
}),
|
||||
}))
|
||||
.set('me', '123');
|
||||
}),
|
||||
};
|
||||
store = mockStore(state);
|
||||
});
|
||||
|
||||
describe('when the url is null', () => {
|
||||
beforeEach(() => {
|
||||
const state = rootState
|
||||
.set('user_lists', ReducerRecord({
|
||||
const state = {
|
||||
...rootState,
|
||||
me: '123',
|
||||
user_lists: ReducerRecord({
|
||||
follow_requests: ListRecord({
|
||||
next: null,
|
||||
}),
|
||||
}))
|
||||
.set('me', '123');
|
||||
}),
|
||||
};
|
||||
store = mockStore(state);
|
||||
});
|
||||
|
||||
|
@ -1425,7 +1458,7 @@ describe('authorizeFollowRequest()', () => {
|
|||
|
||||
describe('when logged out', () => {
|
||||
beforeEach(() => {
|
||||
const state = rootState.set('me', null);
|
||||
const state = { ...rootState, me: null };
|
||||
store = mockStore(state);
|
||||
});
|
||||
|
||||
|
@ -1439,7 +1472,7 @@ describe('authorizeFollowRequest()', () => {
|
|||
|
||||
describe('when logged in', () => {
|
||||
beforeEach(() => {
|
||||
const state = rootState.set('me', '123');
|
||||
const state = { ...rootState, me: '123' };
|
||||
store = mockStore(state);
|
||||
});
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ describe('fetchBlocks()', () => {
|
|||
|
||||
describe('if logged out', () => {
|
||||
beforeEach(() => {
|
||||
const state = rootState.set('me', null);
|
||||
const state = { ...rootState, me: null };
|
||||
store = mockStore(state);
|
||||
});
|
||||
|
||||
|
@ -30,7 +30,7 @@ describe('fetchBlocks()', () => {
|
|||
|
||||
describe('if logged in', () => {
|
||||
beforeEach(() => {
|
||||
const state = rootState.set('me', '1234');
|
||||
const state = { ...rootState, me: '1234' };
|
||||
store = mockStore(state);
|
||||
});
|
||||
|
||||
|
@ -89,7 +89,7 @@ describe('expandBlocks()', () => {
|
|||
|
||||
describe('if logged out', () => {
|
||||
beforeEach(() => {
|
||||
const state = rootState.set('me', null);
|
||||
const state = { ...rootState, me: null };
|
||||
store = mockStore(state);
|
||||
});
|
||||
|
||||
|
@ -103,15 +103,18 @@ describe('expandBlocks()', () => {
|
|||
|
||||
describe('if logged in', () => {
|
||||
beforeEach(() => {
|
||||
const state = rootState.set('me', '1234');
|
||||
const state = { ...rootState, me: '1234' };
|
||||
store = mockStore(state);
|
||||
});
|
||||
|
||||
describe('without a url', () => {
|
||||
beforeEach(() => {
|
||||
const state = rootState
|
||||
.set('me', '1234')
|
||||
.set('user_lists', UserListsRecord({ blocks: ListRecord({ next: null }) }));
|
||||
const state = {
|
||||
...rootState,
|
||||
me: '1234',
|
||||
user_lists: UserListsRecord({ blocks: ListRecord({ next: null }) }),
|
||||
};
|
||||
|
||||
store = mockStore(state);
|
||||
});
|
||||
|
||||
|
@ -125,9 +128,11 @@ describe('expandBlocks()', () => {
|
|||
|
||||
describe('with a url', () => {
|
||||
beforeEach(() => {
|
||||
const state = rootState
|
||||
.set('me', '1234')
|
||||
.set('user_lists', UserListsRecord({ blocks: ListRecord({ next: 'example' }) }));
|
||||
const state = {
|
||||
...rootState,
|
||||
me: '1234',
|
||||
user_lists: UserListsRecord({ blocks: ListRecord({ next: 'example' }) }),
|
||||
};
|
||||
store = mockStore(state);
|
||||
});
|
||||
|
||||
|
|
|
@ -25,10 +25,12 @@ describe('uploadCompose()', () => {
|
|||
},
|
||||
});
|
||||
|
||||
const state = rootState
|
||||
.set('me', '1234')
|
||||
.set('instance', instance)
|
||||
.setIn(['compose', 'home'], ReducerCompose());
|
||||
const state = {
|
||||
...rootState,
|
||||
me: '1234',
|
||||
instance,
|
||||
compose: rootState.compose.set('home', ReducerCompose()),
|
||||
};
|
||||
|
||||
store = mockStore(state);
|
||||
files = [{
|
||||
|
@ -71,10 +73,12 @@ describe('uploadCompose()', () => {
|
|||
},
|
||||
});
|
||||
|
||||
const state = rootState
|
||||
.set('me', '1234')
|
||||
.set('instance', instance)
|
||||
.setIn(['compose', 'home'], ReducerCompose());
|
||||
const state = {
|
||||
...rootState,
|
||||
me: '1234',
|
||||
instance,
|
||||
compose: rootState.compose.set('home', ReducerCompose()),
|
||||
};
|
||||
|
||||
store = mockStore(state);
|
||||
files = [{
|
||||
|
@ -105,9 +109,11 @@ describe('uploadCompose()', () => {
|
|||
|
||||
describe('submitCompose()', () => {
|
||||
it('inserts mentions from text', async() => {
|
||||
const state = rootState
|
||||
.set('me', '123')
|
||||
.setIn(['compose', 'home'], ReducerCompose({ text: '@alex hello @mkljczk@pl.fediverse.pl @gg@汉语/漢語.com alex@alexgleason.me' }));
|
||||
const state = {
|
||||
...rootState,
|
||||
me: '1234',
|
||||
compose: rootState.compose.set('home', ReducerCompose({ text: '@alex hello @mkljczk@pl.fediverse.pl @gg@汉语/漢語.com alex@alexgleason.me' })),
|
||||
};
|
||||
|
||||
const store = mockStore(state);
|
||||
await store.dispatch(submitCompose('home'));
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
import { createAsyncThunk } from '@reduxjs/toolkit';
|
||||
import get from 'lodash/get';
|
||||
import { gte } from 'semver';
|
||||
|
||||
import { instanceSchema } from 'soapbox/schemas';
|
||||
import { RootState } from 'soapbox/store';
|
||||
import { getAuthUserUrl, getMeUrl } from 'soapbox/utils/auth';
|
||||
import { MASTODON, parseVersion, PLEROMA, REBASED } from 'soapbox/utils/features';
|
||||
import { getFeatures } from 'soapbox/utils/features';
|
||||
|
||||
import api from '../api';
|
||||
|
||||
|
@ -19,18 +18,6 @@ export const getHost = (state: RootState) => {
|
|||
}
|
||||
};
|
||||
|
||||
const supportsInstanceV2 = (instance: Record<string, any>): boolean => {
|
||||
const v = parseVersion(get(instance, 'version'));
|
||||
return (v.software === MASTODON && gte(v.compatVersion, '4.0.0')) ||
|
||||
(v.software === PLEROMA && v.build === REBASED && gte(v.version, '2.5.54'));
|
||||
};
|
||||
|
||||
/** We may need to fetch nodeinfo on Pleroma < 2.1 */
|
||||
const needsNodeinfo = (instance: Record<string, any>): boolean => {
|
||||
const v = parseVersion(get(instance, 'version'));
|
||||
return v.software === PLEROMA && !get(instance, ['pleroma', 'metadata']);
|
||||
};
|
||||
|
||||
interface InstanceData {
|
||||
instance: Record<string, any>;
|
||||
host: string | null | undefined;
|
||||
|
@ -40,15 +27,14 @@ export const fetchInstance = createAsyncThunk<InstanceData, InstanceData['host']
|
|||
'instance/fetch',
|
||||
async(host, { dispatch, getState, rejectWithValue }) => {
|
||||
try {
|
||||
const { data: instance } = await api(getState).get('/api/v1/instance');
|
||||
const { data } = await api(getState).get('/api/v1/instance');
|
||||
const instance = instanceSchema.parse(data);
|
||||
const features = getFeatures(instance);
|
||||
|
||||
if (supportsInstanceV2(instance)) {
|
||||
if (features.instanceV2) {
|
||||
dispatch(fetchInstanceV2(host));
|
||||
}
|
||||
|
||||
if (needsNodeinfo(instance)) {
|
||||
dispatch(fetchNodeinfo());
|
||||
}
|
||||
return { instance, host };
|
||||
} catch (e) {
|
||||
return rejectWithValue(e);
|
||||
|
@ -67,8 +53,3 @@ export const fetchInstanceV2 = createAsyncThunk<InstanceData, InstanceData['host
|
|||
}
|
||||
},
|
||||
);
|
||||
|
||||
export const fetchNodeinfo = createAsyncThunk<void, void, { state: RootState }>(
|
||||
'nodeinfo/fetch',
|
||||
async(_arg, { getState }) => await api(getState).get('/nodeinfo/2.1.json'),
|
||||
);
|
||||
|
|
|
@ -37,23 +37,25 @@ describe('fetchMe()', () => {
|
|||
const token = '123';
|
||||
|
||||
beforeEach(() => {
|
||||
const state = rootState
|
||||
.set('auth', ReducerRecord({
|
||||
const state = {
|
||||
...rootState,
|
||||
auth: ReducerRecord({
|
||||
me: accountUrl,
|
||||
users: ImmutableMap({
|
||||
[accountUrl]: AuthUserRecord({
|
||||
'access_token': token,
|
||||
}),
|
||||
}),
|
||||
}))
|
||||
.set('entities', {
|
||||
}),
|
||||
entities: {
|
||||
'ACCOUNTS': {
|
||||
store: {
|
||||
[accountUrl]: buildAccount({ url: accountUrl }),
|
||||
},
|
||||
lists: {},
|
||||
},
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
store = mockStore(state);
|
||||
});
|
||||
|
|
|
@ -14,10 +14,14 @@ describe('markReadNotifications()', () => {
|
|||
'10': normalizeNotification({ id: '10' }),
|
||||
});
|
||||
|
||||
const state = rootState
|
||||
.set('me', '123')
|
||||
.setIn(['notifications', 'lastRead'], '9')
|
||||
.setIn(['notifications', 'items'], items);
|
||||
const state = {
|
||||
...rootState,
|
||||
me: '123',
|
||||
notifications: rootState.notifications.merge({
|
||||
lastRead: '9',
|
||||
items,
|
||||
}),
|
||||
};
|
||||
|
||||
const store = mockStore(state);
|
||||
|
||||
|
|
|
@ -16,7 +16,8 @@ describe('checkOnboarding()', () => {
|
|||
it('does nothing if localStorage item is not set', async() => {
|
||||
mockGetItem = vi.fn().mockReturnValue(null);
|
||||
|
||||
const state = rootState.setIn(['onboarding', 'needsOnboarding'], false);
|
||||
const state = { ...rootState };
|
||||
state.onboarding.needsOnboarding = false;
|
||||
const store = mockStore(state);
|
||||
|
||||
await store.dispatch(checkOnboardingStatus());
|
||||
|
@ -29,7 +30,8 @@ describe('checkOnboarding()', () => {
|
|||
it('does nothing if localStorage item is invalid', async() => {
|
||||
mockGetItem = vi.fn().mockReturnValue('invalid');
|
||||
|
||||
const state = rootState.setIn(['onboarding', 'needsOnboarding'], false);
|
||||
const state = { ...rootState };
|
||||
state.onboarding.needsOnboarding = false;
|
||||
const store = mockStore(state);
|
||||
|
||||
await store.dispatch(checkOnboardingStatus());
|
||||
|
@ -42,7 +44,8 @@ describe('checkOnboarding()', () => {
|
|||
it('dispatches the correct action', async() => {
|
||||
mockGetItem = vi.fn().mockReturnValue('1');
|
||||
|
||||
const state = rootState.setIn(['onboarding', 'needsOnboarding'], false);
|
||||
const state = { ...rootState };
|
||||
state.onboarding.needsOnboarding = false;
|
||||
const store = mockStore(state);
|
||||
|
||||
await store.dispatch(checkOnboardingStatus());
|
||||
|
@ -65,7 +68,8 @@ describe('startOnboarding()', () => {
|
|||
});
|
||||
|
||||
it('dispatches the correct action', async() => {
|
||||
const state = rootState.setIn(['onboarding', 'needsOnboarding'], false);
|
||||
const state = { ...rootState };
|
||||
state.onboarding.needsOnboarding = false;
|
||||
const store = mockStore(state);
|
||||
|
||||
await store.dispatch(startOnboarding());
|
||||
|
@ -88,7 +92,8 @@ describe('endOnboarding()', () => {
|
|||
});
|
||||
|
||||
it('dispatches the correct action', async() => {
|
||||
const state = rootState.setIn(['onboarding', 'needsOnboarding'], false);
|
||||
const state = { ...rootState };
|
||||
state.onboarding.needsOnboarding = false;
|
||||
const store = mockStore(state);
|
||||
|
||||
await store.dispatch(endOnboarding());
|
||||
|
|
|
@ -45,7 +45,7 @@ const unsubscribe = ({ registration, subscription }: {
|
|||
const sendSubscriptionToBackend = (subscription: PushSubscription, me: Me) =>
|
||||
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||
const alerts = getState().push_notifications.alerts.toJS();
|
||||
const params = { subscription, data: { alerts } };
|
||||
const params = { subscription: subscription.toJSON(), data: { alerts } };
|
||||
|
||||
if (me) {
|
||||
const data = pushNotificationsSetting.get(me);
|
||||
|
@ -54,7 +54,7 @@ const sendSubscriptionToBackend = (subscription: PushSubscription, me: Me) =>
|
|||
}
|
||||
}
|
||||
|
||||
return dispatch(createPushSubscription(params) as any);
|
||||
return dispatch(createPushSubscription(params));
|
||||
};
|
||||
|
||||
// Last one checks for payload support: https://web-push-book.gauntface.com/chapter-06/01-non-standards-browsers/#no-payload
|
||||
|
|
|
@ -18,7 +18,15 @@ const PUSH_SUBSCRIPTION_DELETE_FAIL = 'PUSH_SUBSCRIPTION_DELETE_FAIL';
|
|||
|
||||
import type { AppDispatch, RootState } from 'soapbox/store';
|
||||
|
||||
const createPushSubscription = (params: Record<string, any>) =>
|
||||
interface CreatePushSubscriptionParams {
|
||||
subscription: PushSubscriptionJSON;
|
||||
data?: {
|
||||
alerts?: Record<string, boolean>;
|
||||
policy?: 'all' | 'followed' | 'follower' | 'none';
|
||||
};
|
||||
}
|
||||
|
||||
const createPushSubscription = (params: CreatePushSubscriptionParams) =>
|
||||
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||
dispatch({ type: PUSH_SUBSCRIPTION_CREATE_REQUEST, params });
|
||||
return api(getState).post('/api/v1/push/subscription', params).then(({ data: subscription }) =>
|
||||
|
|
|
@ -1,21 +0,0 @@
|
|||
import { rootState } from 'soapbox/jest/test-helpers';
|
||||
import { RootState } from 'soapbox/store';
|
||||
|
||||
import { getSoapboxConfig } from './soapbox';
|
||||
|
||||
const ASCII_HEART = '❤'; // '\u2764\uFE0F'
|
||||
const RED_HEART_RGI = '❤️'; // '\u2764'
|
||||
|
||||
describe('getSoapboxConfig()', () => {
|
||||
it('returns RGI heart on Pleroma > 2.3', () => {
|
||||
const state = rootState.setIn(['instance', 'version'], '2.7.2 (compatible; Pleroma 2.3.0)') as RootState;
|
||||
expect(getSoapboxConfig(state).allowedEmoji.includes(RED_HEART_RGI)).toBe(true);
|
||||
expect(getSoapboxConfig(state).allowedEmoji.includes(ASCII_HEART)).toBe(false);
|
||||
});
|
||||
|
||||
it('returns an ASCII heart on Pleroma < 2.3', () => {
|
||||
const state = rootState.setIn(['instance', 'version'], '2.7.2 (compatible; Pleroma 2.0.0)') as RootState;
|
||||
expect(getSoapboxConfig(state).allowedEmoji.includes(ASCII_HEART)).toBe(true);
|
||||
expect(getSoapboxConfig(state).allowedEmoji.includes(RED_HEART_RGI)).toBe(false);
|
||||
});
|
||||
});
|
|
@ -26,7 +26,7 @@ describe('fetchStatusQuotes()', () => {
|
|||
let store: ReturnType<typeof mockStore>;
|
||||
|
||||
beforeEach(() => {
|
||||
const state = rootState.set('me', '1234');
|
||||
const state = { ...rootState, me: '1234' };
|
||||
store = mockStore(state);
|
||||
});
|
||||
|
||||
|
@ -81,9 +81,12 @@ describe('expandStatusQuotes()', () => {
|
|||
|
||||
describe('without a url', () => {
|
||||
beforeEach(() => {
|
||||
const state = rootState
|
||||
.set('me', '1234')
|
||||
.set('status_lists', ImmutableMap({ [`quotes:${statusId}`]: StatusListRecord({ next: null }) }));
|
||||
const state = {
|
||||
...rootState,
|
||||
me: '1234',
|
||||
status_lists: ImmutableMap({ [`quotes:${statusId}`]: StatusListRecord({ next: null }) }),
|
||||
};
|
||||
|
||||
store = mockStore(state);
|
||||
});
|
||||
|
||||
|
@ -97,8 +100,12 @@ describe('expandStatusQuotes()', () => {
|
|||
|
||||
describe('with a url', () => {
|
||||
beforeEach(() => {
|
||||
const state = rootState.set('me', '1234')
|
||||
.set('status_lists', ImmutableMap({ [`quotes:${statusId}`]: StatusListRecord({ next: 'example' }) }));
|
||||
const state = {
|
||||
...rootState,
|
||||
status_lists: ImmutableMap({ [`quotes:${statusId}`]: StatusListRecord({ next: 'example' }) }),
|
||||
me: '1234',
|
||||
};
|
||||
|
||||
store = mockStore(state);
|
||||
});
|
||||
|
||||
|
|
|
@ -30,7 +30,7 @@ describe('deleteStatus()', () => {
|
|||
|
||||
describe('if logged out', () => {
|
||||
beforeEach(() => {
|
||||
const state = rootState.set('me', null);
|
||||
const state = { ...rootState, me: null };
|
||||
store = mockStore(state);
|
||||
});
|
||||
|
||||
|
@ -49,11 +49,14 @@ describe('deleteStatus()', () => {
|
|||
});
|
||||
|
||||
beforeEach(() => {
|
||||
const state = rootState
|
||||
.set('me', '1234')
|
||||
.set('statuses', fromJS({
|
||||
const state = {
|
||||
...rootState,
|
||||
me: '1234',
|
||||
statuses: fromJS({
|
||||
[statusId]: cachedStatus,
|
||||
}) as any);
|
||||
}) as any,
|
||||
};
|
||||
|
||||
store = mockStore(state);
|
||||
});
|
||||
|
||||
|
|
|
@ -316,11 +316,12 @@ const toggleStatusHidden = (status: Status) => {
|
|||
}
|
||||
};
|
||||
|
||||
const translateStatus = (id: string, targetLanguage?: string) => (dispatch: AppDispatch, getState: () => RootState) => {
|
||||
const translateStatus = (id: string, lang?: string) => (dispatch: AppDispatch, getState: () => RootState) => {
|
||||
dispatch({ type: STATUS_TRANSLATE_REQUEST, id });
|
||||
|
||||
api(getState).post(`/api/v1/statuses/${id}/translate`, {
|
||||
target_language: targetLanguage,
|
||||
lang, // Mastodon API
|
||||
target_language: lang, // HACK: Rebased and Pleroma compatibility
|
||||
}).then(response => {
|
||||
dispatch({
|
||||
type: STATUS_TRANSLATE_SUCCESS,
|
||||
|
|
|
@ -5,7 +5,13 @@ import { renderHook, rootState, waitFor } from 'soapbox/jest/test-helpers';
|
|||
import { useGroupLookup } from './useGroupLookup';
|
||||
|
||||
const group = buildGroup({ id: '1', slug: 'soapbox' });
|
||||
const state = rootState.setIn(['instance', 'version'], '3.4.1 (compatible; TruthSocial 1.0.0)');
|
||||
const state = {
|
||||
...rootState,
|
||||
instance: {
|
||||
...rootState.instance,
|
||||
version: '3.4.1 (compatible; TruthSocial 1.0.0)',
|
||||
},
|
||||
};
|
||||
|
||||
describe('useGroupLookup hook', () => {
|
||||
describe('with a successful request', () => {
|
||||
|
|
|
@ -105,8 +105,8 @@ export default (getState: () => RootState, authType: string = 'user'): AxiosInst
|
|||
const me = state.me;
|
||||
const baseURL = me ? getAuthBaseURL(state, me) : '';
|
||||
|
||||
const relayUrl = state.getIn(['instance', 'nostr', 'relay']) as string | undefined;
|
||||
const pubkey = state.getIn(['instance', 'nostr', 'pubkey']) as string | undefined;
|
||||
const relayUrl = state.instance?.nostr?.relay;
|
||||
const pubkey = state.instance?.nostr?.pubkey;
|
||||
const nostrSign = Boolean(relayUrl && pubkey);
|
||||
|
||||
return baseClient(accessToken, baseURL, nostrSign);
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import clsx from 'clsx';
|
||||
import { List as ImmutableList } from 'immutable';
|
||||
import React from 'react';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import React, { PureComponent } from 'react';
|
||||
|
||||
import AutosuggestEmoji from 'soapbox/components/autosuggest-emoji';
|
||||
import Icon from 'soapbox/components/icon';
|
||||
|
@ -35,7 +34,7 @@ export interface IAutosuggestInput extends Pick<React.HTMLAttributes<HTMLInputEl
|
|||
theme?: InputThemes;
|
||||
}
|
||||
|
||||
export default class AutosuggestInput extends ImmutablePureComponent<IAutosuggestInput> {
|
||||
export default class AutosuggestInput extends PureComponent<IAutosuggestInput> {
|
||||
|
||||
static defaultProps = {
|
||||
autoFocus: false,
|
||||
|
|
|
@ -22,7 +22,7 @@ describe('<QuotedStatus />', () => {
|
|||
contentHtml: 'hello world',
|
||||
}) as ReducerStatus;
|
||||
|
||||
const state = rootState.setIn(['accounts', '1'], account);
|
||||
const state = rootState/*.accounts.set('1', account)*/;
|
||||
|
||||
render(<QuotedStatus status={status} />, undefined, state);
|
||||
screen.getByText(/hello world/i);
|
||||
|
|
|
@ -21,7 +21,7 @@ const status = normalizeStatus({
|
|||
}) as ReducerStatus;
|
||||
|
||||
describe('<Status />', () => {
|
||||
const state = rootState.setIn(['accounts', '1'], account);
|
||||
const state = rootState/*.accounts.set('1', account)*/;
|
||||
|
||||
it('renders content', () => {
|
||||
render(<Status status={status} />, undefined, state);
|
||||
|
|
|
@ -94,10 +94,12 @@ describe('<SensitiveContentOverlay />', () => {
|
|||
|
||||
beforeEach(() => {
|
||||
status = normalizeStatus({ sensitive: true }) as ReducerStatus;
|
||||
store = rootState
|
||||
.set('settings', ImmutableMap({
|
||||
store = {
|
||||
...rootState,
|
||||
settings: ImmutableMap({
|
||||
displayMedia: 'show_all',
|
||||
}));
|
||||
}),
|
||||
};
|
||||
});
|
||||
|
||||
it('displays the "Under review" warning', () => {
|
||||
|
|
|
@ -39,8 +39,8 @@ const AccountTimeline: React.FC<IAccountTimeline> = ({ params, withReplies = fal
|
|||
const isBlocked = useAppSelector(state => state.relationships.getIn([account?.id, 'blocked_by']) === true);
|
||||
const unavailable = isBlocked && !features.blockersVisible;
|
||||
const patronEnabled = soapboxConfig.getIn(['extensions', 'patron', 'enabled']) === true;
|
||||
const isLoading = useAppSelector(state => state.getIn(['timelines', `account:${path}`, 'isLoading']) === true);
|
||||
const hasMore = useAppSelector(state => state.getIn(['timelines', `account:${path}`, 'hasMore']) === true);
|
||||
const isLoading = useAppSelector(state => state.timelines.getIn([`account:${path}`, 'isLoading']) === true);
|
||||
const hasMore = useAppSelector(state => state.timelines.getIn([`account:${path}`, 'hasMore']) === true);
|
||||
const next = useAppSelector(state => state.timelines.get(`account:${path}`)?.next);
|
||||
|
||||
const accountUsername = account?.username || params.username;
|
||||
|
|
|
@ -74,8 +74,8 @@ const ChatComposer = React.forwardRef<HTMLTextAreaElement | null, IChatComposer>
|
|||
|
||||
const { chat } = useChatContext();
|
||||
|
||||
const isBlocked = useAppSelector((state) => state.getIn(['relationships', chat?.account?.id, 'blocked_by']));
|
||||
const isBlocking = useAppSelector((state) => state.getIn(['relationships', chat?.account?.id, 'blocking']));
|
||||
const isBlocked = useAppSelector((state) => state.relationships.getIn([chat?.account?.id, 'blocked_by']));
|
||||
const isBlocking = useAppSelector((state) => state.relationships.getIn([chat?.account?.id, 'blocking']));
|
||||
const maxCharacterCount = useAppSelector((state) => state.instance.configuration.chats.max_characters);
|
||||
const attachmentLimit = useAppSelector(state => state.instance.configuration.chats.max_media_attachments);
|
||||
|
||||
|
|
|
@ -35,8 +35,8 @@ const ChatListItem: React.FC<IChatListItemInterface> = ({ chat, onClick }) => {
|
|||
|
||||
const { isUsingMainChatPage } = useChatContext();
|
||||
const { deleteChat } = useChatActions(chat?.id as string);
|
||||
const isBlocked = useAppSelector((state) => state.getIn(['relationships', chat.account.id, 'blocked_by']));
|
||||
const isBlocking = useAppSelector((state) => state.getIn(['relationships', chat?.account?.id, 'blocking']));
|
||||
const isBlocked = useAppSelector((state) => state.relationships.getIn([chat.account.id, 'blocked_by']));
|
||||
const isBlocking = useAppSelector((state) => state.relationships.getIn([chat?.account?.id, 'blocking']));
|
||||
|
||||
const menu = useMemo((): Menu => [{
|
||||
text: intl.formatMessage(messages.leaveChat),
|
||||
|
|
|
@ -68,9 +68,11 @@ Object.assign(navigator, {
|
|||
},
|
||||
});
|
||||
|
||||
const store = rootState
|
||||
.set('me', '1')
|
||||
.set('instance', buildInstance({ version: '3.4.1 (compatible; TruthSocial 1.0.0+unreleased)' }));
|
||||
const store = {
|
||||
...rootState,
|
||||
me: '1',
|
||||
instance: buildInstance({ version: '3.4.1 (compatible; TruthSocial 1.0.0+unreleased)' }),
|
||||
};
|
||||
|
||||
const renderComponentWithChatContext = () => render(
|
||||
<VirtuosoMockContext.Provider value={{ viewportHeight: 300, itemHeight: 100 }}>
|
||||
|
|
|
@ -91,7 +91,7 @@ const ChatMessageList: React.FC<IChatMessageList> = ({ chat }) => {
|
|||
|
||||
const formattedChatMessages = chatMessages || [];
|
||||
|
||||
const isBlocked = useAppSelector((state) => state.getIn(['relationships', chat.account.id, 'blocked_by']));
|
||||
const isBlocked = useAppSelector((state) => state.relationships.getIn([chat.account.id, 'blocked_by']));
|
||||
|
||||
const lastChatMessage = chatMessages ? chatMessages[chatMessages.length - 1] : null;
|
||||
|
||||
|
|
|
@ -60,7 +60,7 @@ const ChatPageMain = () => {
|
|||
|
||||
const handleUpdateChat = (value: MessageExpirationValues) => updateChat.mutate({ message_expiration: value });
|
||||
|
||||
const isBlocking = useAppSelector((state) => state.getIn(['relationships', chat?.account?.id, 'blocking']));
|
||||
const isBlocking = useAppSelector((state) => state.relationships.getIn([chat?.account?.id, 'blocking']));
|
||||
|
||||
const handleBlockUser = () => {
|
||||
dispatch(openModal('CONFIRM', {
|
||||
|
|
|
@ -17,16 +17,18 @@ const account = buildAccount({
|
|||
},
|
||||
});
|
||||
|
||||
const store = rootState
|
||||
.set('me', id)
|
||||
.set('entities', {
|
||||
const store = {
|
||||
...rootState,
|
||||
me: id,
|
||||
entities: {
|
||||
'ACCOUNTS': {
|
||||
store: {
|
||||
[id]: account,
|
||||
},
|
||||
lists: {},
|
||||
},
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
describe('<ChatWidget />', () => {
|
||||
describe('when on the /chats endpoint', () => {
|
||||
|
|
|
@ -40,7 +40,7 @@ const ChatSettings = () => {
|
|||
|
||||
const handleUpdateChat = (value: MessageExpirationValues) => updateChat.mutate({ message_expiration: value });
|
||||
|
||||
const isBlocking = useAppSelector((state) => state.getIn(['relationships', chat?.account?.id, 'blocking']));
|
||||
const isBlocking = useAppSelector((state) => state.relationships.getIn([chat?.account?.id, 'blocking']));
|
||||
|
||||
const closeSettings = () => {
|
||||
changeScreen(ChatWidgetScreens.CHAT, chat?.id);
|
||||
|
|
|
@ -116,11 +116,11 @@ describe('useChatMessages', () => {
|
|||
|
||||
describe('when the user is blocked', () => {
|
||||
beforeEach(() => {
|
||||
const state = rootState
|
||||
.set(
|
||||
'relationships',
|
||||
ImmutableMap({ '1': buildRelationship({ blocked_by: true }) }),
|
||||
);
|
||||
const state = {
|
||||
...rootState,
|
||||
relationships: ImmutableMap({ '1': buildRelationship({ blocked_by: true }) }),
|
||||
};
|
||||
|
||||
store = mockStore(state);
|
||||
});
|
||||
|
||||
|
|
|
@ -79,7 +79,7 @@ const isLastMessage = (chatMessageId: string): boolean => {
|
|||
|
||||
const useChatMessages = (chat: IChat) => {
|
||||
const api = useApi();
|
||||
const isBlocked = useAppSelector((state) => state.getIn(['relationships', chat.account.id, 'blocked_by']));
|
||||
const isBlocked = useAppSelector((state) => state.relationships.getIn([chat.account.id, 'blocked_by']));
|
||||
|
||||
const getChatMessages = async (chatId: string, pageParam?: any): Promise<PaginatedResult<ChatMessage>> => {
|
||||
const nextPageLink = pageParam?.link;
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import { Record as ImmutableRecord } from 'immutable';
|
||||
import { combineReducers } from 'redux-immutable';
|
||||
import { combineReducers } from '@reduxjs/toolkit';
|
||||
|
||||
import { AUTH_LOGGED_OUT } from 'soapbox/actions/auth';
|
||||
import * as BuildConfig from 'soapbox/build-config';
|
||||
|
@ -120,39 +119,29 @@ const reducers = {
|
|||
user_lists,
|
||||
};
|
||||
|
||||
// Build a default state from all reducers: it has the key and `undefined`
|
||||
export const StateRecord = ImmutableRecord(
|
||||
Object.keys(reducers).reduce((params: Record<string, any>, reducer) => {
|
||||
params[reducer] = undefined;
|
||||
return params;
|
||||
}, {}),
|
||||
);
|
||||
const appReducer = combineReducers(reducers);
|
||||
|
||||
const appReducer = combineReducers(reducers, StateRecord);
|
||||
type AppState = ReturnType<typeof appReducer>;
|
||||
|
||||
// Clear the state (mostly) when the user logs out
|
||||
const logOut = (state: any = StateRecord()): ReturnType<typeof appReducer> => {
|
||||
const logOut = (state: AppState): ReturnType<typeof appReducer> => {
|
||||
if (BuildConfig.NODE_ENV === 'production') {
|
||||
location.href = '/login';
|
||||
}
|
||||
|
||||
const whitelist: string[] = ['instance', 'soapbox', 'custom_emojis', 'auth'];
|
||||
const newState = rootReducer(undefined, { type: '' });
|
||||
|
||||
return StateRecord(
|
||||
whitelist.reduce((acc: Record<string, any>, curr) => {
|
||||
acc[curr] = state.get(curr);
|
||||
return acc;
|
||||
}, {}),
|
||||
) as unknown as ReturnType<typeof appReducer>;
|
||||
const { instance, soapbox, custom_emojis, auth } = state;
|
||||
return { ...newState, instance, soapbox, custom_emojis, auth };
|
||||
};
|
||||
|
||||
const rootReducer: typeof appReducer = (state, action) => {
|
||||
switch (action.type) {
|
||||
case AUTH_LOGGED_OUT:
|
||||
return appReducer(logOut(state), action);
|
||||
return appReducer(logOut(state as AppState), action);
|
||||
default:
|
||||
return appReducer(state, action);
|
||||
}
|
||||
};
|
||||
|
||||
export default rootReducer;
|
||||
export default appReducer;
|
||||
|
|
|
@ -711,6 +711,7 @@ const getInstanceFeatures = (instance: Instance) => {
|
|||
instanceV2: any([
|
||||
v.software === MASTODON && gte(v.compatVersion, '4.0.0'),
|
||||
v.software === PLEROMA && v.build === REBASED && gte(v.version, '2.5.54'),
|
||||
v.software === DITTO,
|
||||
]),
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,17 +0,0 @@
|
|||
// Type definitions for redux-immutable v4.0.0
|
||||
// Project: https://github.com/gajus/redux-immutable
|
||||
// Definitions by: Sebastian Sebald <https://github.com/sebald>
|
||||
// Gavin Gregory <https://github.com/gavingregory>
|
||||
// Kanitkorn Sujautra <https://github.com/lukyth>
|
||||
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
|
||||
// TypeScript Version: 2.3
|
||||
|
||||
declare module 'redux-immutable' {
|
||||
import { Collection, Record } from 'immutable';
|
||||
import { ReducersMapObject, Reducer, Action } from 'redux';
|
||||
|
||||
export function combineReducers<S, A extends Action, T>(reducers: ReducersMapObject<S, A>, getDefaultState?: () => Collection.Keyed<T, S>): Reducer<S, A>;
|
||||
export function combineReducers<S, A extends Action>(reducers: ReducersMapObject<S, A>, getDefaultState?: () => Collection.Indexed<S>): Reducer<S, A>;
|
||||
export function combineReducers<S>(reducers: ReducersMapObject<S, any>, getDefaultState?: () => Collection.Indexed<S>): Reducer<S>;
|
||||
export function combineReducers<S extends object, T extends object>(reducers: ReducersMapObject<S, any>, getDefaultState?: Record.Factory<T>): Reducer<ReturnType<Record.Factory<S>>>;
|
||||
}
|
10
yarn.lock
10
yarn.lock
|
@ -7192,11 +7192,6 @@ react-hot-toast@^2.4.0:
|
|||
dependencies:
|
||||
goober "^2.1.10"
|
||||
|
||||
react-immutable-pure-component@^2.2.2:
|
||||
version "2.2.2"
|
||||
resolved "https://registry.yarnpkg.com/react-immutable-pure-component/-/react-immutable-pure-component-2.2.2.tgz#3014d3e20cd5a7a4db73b81f1f1464f4d351684b"
|
||||
integrity sha512-vkgoMJUDqHZfXXnjVlG3keCxSO/U6WeDQ5/Sl0GK2cH8TOxEzQ5jXqDXHEL/jqk6fsNxV05oH5kD7VNMUE2k+A==
|
||||
|
||||
react-inlinesvg@^4.0.0:
|
||||
version "4.0.3"
|
||||
resolved "https://registry.yarnpkg.com/react-inlinesvg/-/react-inlinesvg-4.0.3.tgz#69aa4d9c01b037abb800bfa103cb5591c6f3fe76"
|
||||
|
@ -7443,11 +7438,6 @@ redent@^3.0.0:
|
|||
indent-string "^4.0.0"
|
||||
strip-indent "^3.0.0"
|
||||
|
||||
redux-immutable@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/redux-immutable/-/redux-immutable-4.0.0.tgz#3a1a32df66366462b63691f0e1dc35e472bbc9f3"
|
||||
integrity sha1-Ohoy32Y2ZGK2NpHw4dw15HK7yfM=
|
||||
|
||||
redux-thunk@^3.1.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/redux-thunk/-/redux-thunk-3.1.0.tgz#94aa6e04977c30e14e892eae84978c1af6058ff3"
|
||||
|
|
Loading…
Reference in New Issue