diff --git a/.gitignore b/.gitignore
index 474bbfc02..77db043b0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -87,6 +87,7 @@ ios/sentry.properties
# Testing
.nyc_output
coverage
+.tmp
# Bundle artifact
*.jsbundle
diff --git a/NOTICE.txt b/NOTICE.txt
index 5e32b8b45..3b3c63bae 100644
--- a/NOTICE.txt
+++ b/NOTICE.txt
@@ -2410,41 +2410,6 @@ SOFTWARE.
---
-## redux-offline
-
-This product contains 'redux-offline' by redux-offline.
-
-Build Offline-First Apps for Web and React Native
-
-* HOMEPAGE:
- * https://github.com/redux-offline/redux-offline
-
-* LICENSE: MIT
-
-MIT License
-
-Copyright (c) 2017 Jani Eväkallio
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-
----
-
## redux-persist
This product contains 'redux-persist' by Zack Story.
diff --git a/app/actions/device/index.js b/app/actions/device/index.js
index 87778046e..4fc3cf4bc 100644
--- a/app/actions/device/index.js
+++ b/app/actions/device/index.js
@@ -1,21 +1,16 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
-import {networkStatusChangedAction} from 'redux-offline';
-import {batchActions} from 'redux-batched-actions';
-
import {DeviceTypes} from 'app/constants';
export function connection(isOnline) {
return async (dispatch, getState) => {
const state = getState();
if (isOnline !== undefined && isOnline !== state.device.connection) { //eslint-disable-line no-undefined
- dispatch(batchActions([
- networkStatusChangedAction(isOnline), {
- type: DeviceTypes.CONNECTION_CHANGED,
- data: isOnline,
- },
- ], 'BATCH_CONNECTION_CHANGED'));
+ dispatch({
+ type: DeviceTypes.CONNECTION_CHANGED,
+ data: isOnline,
+ });
}
};
}
diff --git a/app/actions/views/login.test.js b/app/actions/views/login.test.js
index 92cc6e00f..dd2a6028f 100644
--- a/app/actions/views/login.test.js
+++ b/app/actions/views/login.test.js
@@ -4,6 +4,7 @@
import configureStore from 'redux-mock-store';
import thunk from 'redux-thunk';
+import {Client4} from '@mm-redux/client';
import * as GeneralActions from '@mm-redux/actions/general';
import {handleSuccessfulLogin} from 'app/actions/views/login';
@@ -46,8 +47,8 @@ describe('Actions.Views.Login', () => {
});
test('handleSuccessfulLogin gets config and license ', async () => {
- const getClientConfig = jest.spyOn(GeneralActions, 'getClientConfig');
- const getLicenseConfig = jest.spyOn(GeneralActions, 'getLicenseConfig');
+ const getClientConfig = jest.spyOn(Client4, 'getClientConfigOld');
+ const getLicenseConfig = jest.spyOn(Client4, 'getClientLicenseOld');
await store.dispatch(handleSuccessfulLogin());
expect(getClientConfig).toHaveBeenCalled();
diff --git a/app/actions/views/root.js b/app/actions/views/root.js
index 04ca28283..2bd227a01 100644
--- a/app/actions/views/root.js
+++ b/app/actions/views/root.js
@@ -4,15 +4,19 @@
import {batchActions} from 'redux-batched-actions';
import {ChannelTypes, GeneralTypes, TeamTypes} from '@mm-redux/action_types';
-import {Client4} from '@mm-redux/client';
-import {General} from '@mm-redux/constants';
import {fetchMyChannelsAndMembers} from '@mm-redux/actions/channels';
import {getClientConfig, getDataRetentionPolicy, getLicenseConfig} from '@mm-redux/actions/general';
import {receivedNewPost} from '@mm-redux/actions/posts';
import {getMyTeams, getMyTeamMembers} from '@mm-redux/actions/teams';
+import {Client4} from '@mm-redux/client';
+import {General} from '@mm-redux/constants';
+import EventEmitter from '@mm-redux/utils/event_emitter';
-import {ViewTypes} from 'app/constants';
+import {NavigationTypes, ViewTypes} from '@constants';
+import initialState from 'app/initial_state';
+import {persistor} from 'app/store';
import EphemeralStore from 'app/store/ephemeral_store';
+import {getStateForReset} from 'app/store/utils';
import {recordTime} from 'app/utils/segment';
import {markChannelViewedAndRead} from './channel';
@@ -29,24 +33,36 @@ export function startDataCleanup() {
export function loadConfigAndLicense() {
return async (dispatch, getState) => {
const {currentUserId} = getState().entities.users;
- const [configData, licenseData] = await Promise.all([
- getClientConfig()(dispatch, getState),
- getLicenseConfig()(dispatch, getState),
- ]);
- const config = configData.data || {};
- const license = licenseData.data || {};
+ try {
+ const [config, license] = await Promise.all([
+ Client4.getClientConfigOld(),
+ Client4.getClientLicenseOld(),
+ ]);
- if (currentUserId) {
- if (config.DataRetentionEnableMessageDeletion && config.DataRetentionEnableMessageDeletion === 'true' &&
- license.IsLicensed === 'true' && license.DataRetention === 'true') {
- dispatch(getDataRetentionPolicy());
- } else {
- dispatch({type: GeneralTypes.RECEIVED_DATA_RETENTION_POLICY, data: {}});
+ const actions = [{
+ type: GeneralTypes.CLIENT_CONFIG_RECEIVED,
+ data: config,
+ }, {
+ type: GeneralTypes.CLIENT_LICENSE_RECEIVED,
+ data: license,
+ }];
+
+ if (currentUserId) {
+ if (config.DataRetentionEnableMessageDeletion && config.DataRetentionEnableMessageDeletion === 'true' &&
+ license.IsLicensed === 'true' && license.DataRetention === 'true') {
+ dispatch(getDataRetentionPolicy());
+ } else {
+ actions.push({type: GeneralTypes.RECEIVED_DATA_RETENTION_POLICY, data: {}});
+ }
}
- }
- return {config, license};
+ dispatch(batchActions(actions, 'BATCH_LOAD_CONFIG_AND_LICENSE'));
+
+ return {config, license};
+ } catch (error) {
+ return {error};
+ }
};
}
@@ -126,7 +142,18 @@ export function handleSelectTeamAndChannel(teamId, channelId) {
}
export function purgeOfflineStore() {
- return {type: General.OFFLINE_STORE_PURGE};
+ return (dispatch, getState) => {
+ const currentState = getState();
+ persistor.purge();
+ dispatch({
+ type: General.OFFLINE_STORE_PURGE,
+ state: getStateForReset(initialState, currentState),
+ });
+ persistor.flush();
+ persistor.persist();
+
+ EventEmitter.emit(NavigationTypes.RESTART_APP);
+ };
}
// A non-optimistic version of the createPost action in app/mm-redux with the file handling
diff --git a/app/actions/views/user.js b/app/actions/views/user.js
index d841fe82d..27b6d8464 100644
--- a/app/actions/views/user.js
+++ b/app/actions/views/user.js
@@ -3,12 +3,14 @@
import {batchActions} from 'redux-batched-actions';
+import {NavigationTypes} from 'app/constants';
import {GeneralTypes, RoleTypes, UserTypes} from '@mm-redux/action_types';
import {getDataRetentionPolicy} from '@mm-redux/actions/general';
import * as HelperActions from '@mm-redux/actions/helpers';
import {autoUpdateTimezone} from '@mm-redux/actions/timezone';
import {Client4} from '@mm-redux/client';
import {General} from '@mm-redux/constants';
+import EventEmitter from '@mm-redux/utils/event_emitter';
import {getConfig, getLicense} from '@mm-redux/selectors/entities/general';
import {isTimezoneEnabled} from '@mm-redux/selectors/entities/timezone';
import {getCurrentUserId, getStatusForUserId} from '@mm-redux/selectors/entities/users';
@@ -194,7 +196,7 @@ export function ssoLogin(token) {
}
export function logout(skipServerLogout = false) {
- return async (dispatch) => {
+ return async () => {
if (!skipServerLogout) {
try {
Client4.logout();
@@ -203,7 +205,8 @@ export function logout(skipServerLogout = false) {
}
}
- dispatch({type: UserTypes.LOGOUT_SUCCESS});
+ EventEmitter.emit(NavigationTypes.NAVIGATION_RESET);
+ return {data: true};
};
}
diff --git a/app/components/reactions/reactions.test.js b/app/components/reactions/reactions.test.js
index 48a2a0da3..28021283a 100644
--- a/app/components/reactions/reactions.test.js
+++ b/app/components/reactions/reactions.test.js
@@ -2,7 +2,7 @@
// See LICENSE.txt for license information.
import React from 'react';
-import {shallow} from 'enzyme';
+import {shallowWithIntl} from 'test/intl-test-helper.js';
import Reactions from './reactions';
@@ -31,12 +31,12 @@ describe('Reactions', () => {
};
test('should match snapshot', () => {
- const wrapper = shallow();
+ const wrapper = shallowWithIntl();
expect(wrapper.getElement()).toMatchSnapshot();
});
test('should match snapshot with canAddReaction = false', () => {
- const wrapper = shallow(
+ const wrapper = shallowWithIntl(
{
const botsResult = state.entities.bots.accounts[bot.user_id];
assert.equal(bot.owner_id, botsResult.owner_id);
});
-
- it('logout', async () => {
- // Fill redux store with somthing
- const bot = TestHelper.fakeBot();
- nock(Client4.getBaseRoute()).
- post('/bots').
- reply(200, bot);
- await store.dispatch(BotActions.createBot(bot));
-
- // Should be cleared by logout
- nock(Client4.getUsersRoute()).
- post('/logout').
- reply(200, {status: 'OK'});
- await store.dispatch(UserActions.logout());
-
- // Check is clear
- const state = store.getState();
- assert.equal(0, Object.keys(state.entities.bots.accounts).length);
- });
});
diff --git a/app/mm-redux/actions/channels.test.js b/app/mm-redux/actions/channels.test.js
index 1febe3b97..4c339c354 100644
--- a/app/mm-redux/actions/channels.test.js
+++ b/app/mm-redux/actions/channels.test.js
@@ -23,7 +23,14 @@ describe('Actions.Channels', () => {
});
beforeEach(async () => {
- store = await configureStore();
+ const initialState = {
+ entities: {
+ users: {
+ currentUserId: TestHelper.basicUser.id,
+ },
+ },
+ };
+ store = await configureStore(initialState);
});
afterAll(async () => {
@@ -1954,52 +1961,38 @@ describe('Actions.Channels', () => {
assert.deepEqual(channel.purpose, purpose);
});
- it('leaveChannel', (done) => {
- async function test() {
- TestHelper.mockLogin();
- await store.dispatch(login(TestHelper.basicUser.email, 'password1'));
- nock(Client4.getBaseRoute()).
- get(`/channels/${TestHelper.basicChannel.id}`).
- reply(200, TestHelper.basicChannel);
+ it('leaveChannel', async () => {
+ TestHelper.mockLogin();
+ await store.dispatch(login(TestHelper.basicUser.email, 'password1'));
+ nock(Client4.getBaseRoute()).
+ get(`/channels/${TestHelper.basicChannel.id}`).
+ reply(200, TestHelper.basicChannel);
- nock(Client4.getBaseRoute()).
- post(`/channels/${TestHelper.basicChannel.id}/members`).
- reply(201, {channel_id: TestHelper.basicChannel.id, roles: 'channel_user', user_id: TestHelper.basicUser.id});
+ nock(Client4.getBaseRoute()).
+ post(`/channels/${TestHelper.basicChannel.id}/members`).
+ reply(201, {channel_id: TestHelper.basicChannel.id, roles: 'channel_user', user_id: TestHelper.basicUser.id});
- await store.dispatch(Actions.joinChannel(TestHelper.basicUser.id, TestHelper.basicTeam.id, TestHelper.basicChannel.id));
+ await store.dispatch(Actions.joinChannel(TestHelper.basicUser.id, TestHelper.basicTeam.id, TestHelper.basicChannel.id));
- const {channels, myMembers} = store.getState().entities.channels;
- assert.ok(channels[TestHelper.basicChannel.id]);
- assert.ok(myMembers[TestHelper.basicChannel.id]);
+ let channelsState = store.getState().entities.channels;
+ assert.ok(channelsState.channels[TestHelper.basicChannel.id]);
+ assert.ok(channelsState.myMembers[TestHelper.basicChannel.id]);
- nock(Client4.getBaseRoute()).
- delete(`/channels/${TestHelper.basicChannel.id}/members/${TestHelper.basicUser.id}`).
- reply(400, {});
+ nock(Client4.getBaseRoute()).
+ delete(`/channels/${TestHelper.basicChannel.id}/members/${TestHelper.basicUser.id}`).
+ reply(200, OK_RESPONSE);
- nock(Client4.getBaseRoute()).
- delete(`/channels/${TestHelper.basicChannel.id}/members/${TestHelper.basicUser.id}`).
- reply(200, OK_RESPONSE);
+ await store.dispatch(Actions.leaveChannel(TestHelper.basicChannel.id));
- // This action will retry after 1000ms
- await store.dispatch(Actions.leaveChannel(TestHelper.basicChannel.id));
+ channelsState = store.getState().entities.channels;
- setTimeout(test2, 300);
- }
-
- async function test2() {
- // retry will have completed and should have left the channel successfully
- const {channels, myMembers} = store.getState().entities.channels;
-
- assert.ok(channels[TestHelper.basicChannel.id]);
- assert.ifError(myMembers[TestHelper.basicChannel.id]);
- done();
- }
-
- test();
+ assert.ok(channelsState.channels[TestHelper.basicChannel.id]);
+ assert.ifError(channelsState.myMembers[TestHelper.basicChannel.id]);
});
it('leave private channel', async () => {
const newChannel = {
+ ...TestHelper.fakeChannelWithId(TestHelper.basicChannel.id),
team_id: TestHelper.basicTeam.id,
name: 'redux-test-private',
display_name: 'Redux Test',
@@ -2010,14 +2003,14 @@ describe('Actions.Channels', () => {
nock(Client4.getBaseRoute()).
post('/channels').
- reply(201, {...TestHelper.fakeChannelWithId(TestHelper.basicTeam.id), ...newChannel});
+ reply(201, newChannel);
const {data: channel} = await store.dispatch(Actions.createChannel(newChannel, TestHelper.basicUser.id));
let channels = store.getState().entities.channels.channels;
assert.ok(channels[channel.id]);
nock(Client4.getBaseRoute()).
- delete(`/channels/${TestHelper.basicChannel.id}/members/${TestHelper.basicUser.id}`).
+ delete(`/channels/${channel.id}/members/${TestHelper.basicUser.id}`).
reply(200, OK_RESPONSE);
await store.dispatch(Actions.leaveChannel(channel.id));
diff --git a/app/mm-redux/actions/channels.ts b/app/mm-redux/actions/channels.ts
index e22bfd4b0..b652c9b04 100644
--- a/app/mm-redux/actions/channels.ts
+++ b/app/mm-redux/actions/channels.ts
@@ -636,26 +636,23 @@ export function leaveChannel(channelId: string): ActionFunc {
team_id: channel.team_id,
type: channel.type,
},
- meta: {
- offline: {
- effect: () => Client4.removeFromChannel(currentUserId, channelId),
- commit: {type: 'do_nothing'}, // redux-offline always needs to dispatch something on commit
- rollback: () => {
- dispatch(batchActions([
- {
- type: ChannelTypes.RECEIVED_CHANNEL,
- data: channel,
- },
- {
- type: ChannelTypes.RECEIVED_MY_CHANNEL_MEMBER,
- data: member,
- },
- ]));
- },
- },
- },
});
+ try {
+ await Client4.removeFromChannel(currentUserId, channelId);
+ } catch (error) {
+ dispatch(batchActions([
+ {
+ type: ChannelTypes.RECEIVED_CHANNEL,
+ data: channel,
+ },
+ {
+ type: ChannelTypes.RECEIVED_MY_CHANNEL_MEMBER,
+ data: member,
+ },
+ ]));
+ }
+
return {data: true};
};
}
@@ -1399,7 +1396,7 @@ export function favoriteChannel(channelId: string): ActionFunc {
Client4.trackEvent('action', 'action_channels_favorite');
- return savePreferences(currentUserId, [preference])(dispatch);
+ return dispatch(savePreferences(currentUserId, [preference]));
};
}
diff --git a/app/mm-redux/actions/helpers.test.js b/app/mm-redux/actions/helpers.test.js
index d70a97c6a..fa7b44160 100644
--- a/app/mm-redux/actions/helpers.test.js
+++ b/app/mm-redux/actions/helpers.test.js
@@ -60,28 +60,6 @@ describe('Actions.Helpers', () => {
assert.deepEqual(dispatch.actions, []);
});
- it('should trigger logout when passed a 401 server error', async () => {
- const store = await configureStore({
- entities: {
- users: {
- currentUserId: 'user',
- },
- },
- });
- const dispatch = mockDispatch(store.dispatch);
-
- const error = new ClientError(Client4.getUrl(), {
- message: 'Failed to do something',
- status_code: 401,
- url: '/api/v4/foo/bar',
- });
-
- forceLogoutIfNecessary(error, dispatch, store.getState);
-
- assert.notEqual(Client4.token, token);
- assert.deepEqual(dispatch.actions, [{type: UserTypes.LOGOUT_SUCCESS, data: {}}]);
- });
-
it('should do nothing when failing to log in', async () => {
const store = await configureStore({
entities: {
diff --git a/app/mm-redux/actions/helpers.ts b/app/mm-redux/actions/helpers.ts
index 3f20887c1..1070ec753 100644
--- a/app/mm-redux/actions/helpers.ts
+++ b/app/mm-redux/actions/helpers.ts
@@ -1,7 +1,7 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
-import {Client4} from '@mm-redux/client';
-import {UserTypes} from '@mm-redux/action_types';
+
+import {logout} from '@actions/views/user';
import {Client4Error} from '@mm-redux/types/client4';
import {batchActions, Action, ActionFunc, GenericAction, DispatchFunc, GetStateFunc} from '@mm-redux/types/actions';
@@ -13,8 +13,7 @@ export function forceLogoutIfNecessary(err: Client4Error, dispatch: DispatchFunc
const {currentUserId} = getState().entities.users;
if ('status_code' in err && err.status_code === HTTP_UNAUTHORIZED && err.url && err.url.indexOf('/login') === -1 && currentUserId) {
- Client4.setToken('');
- dispatch({type: UserTypes.LOGOUT_SUCCESS, data: {}});
+ dispatch(logout(false));
}
}
diff --git a/app/mm-redux/actions/posts.test.js b/app/mm-redux/actions/posts.test.js
index a6694d246..409b43ac7 100644
--- a/app/mm-redux/actions/posts.test.js
+++ b/app/mm-redux/actions/posts.test.js
@@ -206,6 +206,10 @@ describe('Actions.Posts', () => {
await Actions.createPost(TestHelper.fakePost(channelId))(store.dispatch, store.getState);
const initialPosts = store.getState().entities.posts;
const postId = Object.keys(initialPosts.posts)[0];
+
+ nock(Client4.getBaseRoute()).
+ delete(`/posts/${postId}`).
+ reply(200, {});
await Actions.deletePost(initialPosts.posts[postId])(store.dispatch, store.getState);
const state = store.getState();
@@ -243,6 +247,9 @@ describe('Actions.Posts', () => {
assert.ok(reactions[post1.id]);
assert.ok(reactions[post1.id][TestHelper.basicUser.id + '-' + emojiName]);
+ nock(Client4.getBaseRoute()).
+ delete(`/posts/${post1.id}`).
+ reply(200, {});
await Actions.deletePost(post1)(store.dispatch, store.getState);
reactions = store.getState().entities.posts.reactions;
diff --git a/app/mm-redux/actions/posts.ts b/app/mm-redux/actions/posts.ts
index d5dde5a3d..8930679ce 100644
--- a/app/mm-redux/actions/posts.ts
+++ b/app/mm-redux/actions/posts.ts
@@ -2,7 +2,7 @@
// See LICENSE.txt for license information.
import {Client4, DEFAULT_LIMIT_AFTER, DEFAULT_LIMIT_BEFORE} from '@mm-redux/client';
-import {General, Preferences, Posts} from '../constants';
+import {General, Preferences, Posts} from '@mm-redux/constants';
import {WebsocketEvents} from '@constants';
import {PostTypes, ChannelTypes, FileTypes, IntegrationTypes} from '@mm-redux/action_types';
@@ -33,7 +33,6 @@ import {Action, ActionResult, batchActions, DispatchFunc, GetStateFunc, GenericA
import {ChannelUnread} from '@mm-redux/types/channels';
import {GlobalState} from '@mm-redux/types/store';
import {Post} from '@mm-redux/types/posts';
-import {Error} from '@mm-redux/types/errors';
import {Reaction} from '@mm-redux/types/reactions';
import {UserProfile} from '@mm-redux/types/users';
import {Dictionary} from '@mm-redux/types/utilities';
@@ -169,9 +168,9 @@ export function createPost(post: Post, files: any[] = []) {
return async (dispatch: DispatchFunc, getState: GetStateFunc) => {
const state = getState();
const currentUserId = state.entities.users.currentUserId;
-
const timestamp = Date.now();
const pendingPostId = post.pending_post_id || `${currentUserId}:${timestamp}`;
+ let actions: Array = [];
if (Selectors.isPostIdSending(state, pendingPostId)) {
return {data: true};
@@ -197,79 +196,78 @@ export function createPost(post: Post, files: any[] = []) {
file_ids: fileIds,
};
- dispatch({
+ actions.push({
type: FileTypes.RECEIVED_FILES_FOR_POST,
postId: pendingPostId,
data: files,
});
}
- dispatch({
+ actions.push({
type: PostTypes.RECEIVED_NEW_POST,
data: {
id: pendingPostId,
...newPost,
},
- meta: {
- offline: {
- effect: () => Client4.createPost({...newPost, create_at: 0}),
- commit: (result: any, payload: any) => {
- const actions: Action[] = [
- receivedPost(payload),
- {
- type: PostTypes.CREATE_POST_SUCCESS,
- },
- {
- type: ChannelTypes.INCREMENT_TOTAL_MSG_COUNT,
- data: {
- channelId: newPost.channel_id,
- amount: 1,
- },
- },
- {
- type: ChannelTypes.DECREMENT_UNREAD_MSG_COUNT,
- data: {
- channelId: newPost.channel_id,
- amount: 1,
- },
- },
- ];
+ });
- if (files) {
- actions.push({
- type: FileTypes.RECEIVED_FILES_FOR_POST,
- postId: payload.id,
- data: files,
- });
- }
+ dispatch(batchActions(actions, 'BATCH_CREATE_POST_INIT'));
- dispatch(batchActions(actions));
- },
- maxRetry: 0,
- offlineRollback: true,
- rollback: (result: any, error: Error) => {
- const data = {
- ...newPost,
- id: pendingPostId,
- failed: true,
- update_at: Date.now(),
- };
- dispatch({type: PostTypes.CREATE_POST_FAILURE, error});
+ try {
+ const created = await Client4.createPost({...newPost, create_at: 0});
- // If the failure was because: the root post was deleted or
- // TownSquareIsReadOnly=true then remove the post
- if (error.server_error_id === 'api.post.create_post.root_id.app_error' ||
- error.server_error_id === 'api.post.create_post.town_square_read_only' ||
- error.server_error_id === 'plugin.message_will_be_posted.dismiss_post'
- ) {
- dispatch(removePost(data) as any);
- } else {
- dispatch(receivedPost(data));
- }
+ actions = [
+ receivedPost(created),
+ {
+ type: PostTypes.CREATE_POST_SUCCESS,
+ },
+ {
+ type: ChannelTypes.INCREMENT_TOTAL_MSG_COUNT,
+ data: {
+ channelId: newPost.channel_id,
+ amount: 1,
},
},
- },
- });
+ {
+ type: ChannelTypes.DECREMENT_UNREAD_MSG_COUNT,
+ data: {
+ channelId: newPost.channel_id,
+ amount: 1,
+ },
+ },
+ ];
+
+ if (files) {
+ actions.push({
+ type: FileTypes.RECEIVED_FILES_FOR_POST,
+ postId: created.id,
+ data: files,
+ });
+ }
+
+ dispatch(batchActions(actions, 'BATCH_CREATE_POST'));
+ } catch (error) {
+ const data = {
+ ...newPost,
+ id: pendingPostId,
+ failed: true,
+ update_at: Date.now(),
+ };
+ actions = [{type: PostTypes.CREATE_POST_FAILURE, error}];
+
+ // If the failure was because: the root post was deleted or
+ // TownSquareIsReadOnly=true then remove the post
+ if (error.server_error_id === 'api.post.create_post.root_id.app_error' ||
+ error.server_error_id === 'api.post.create_post.town_square_read_only' ||
+ error.server_error_id === 'plugin.message_will_be_posted.dismiss_post'
+ ) {
+ actions.push(removePost(data) as any);
+ } else {
+ actions.push(receivedPost(data));
+ }
+
+ dispatch(batchActions(actions, 'BATCH_CREATE_POST_FAILED'));
+ }
return {data: true};
};
@@ -363,11 +361,10 @@ export function resetCreatePostRequest() {
}
export function deletePost(post: ExtendedPost) {
- return (dispatch: DispatchFunc, getState: GetStateFunc) => {
+ return async (dispatch: DispatchFunc, getState: GetStateFunc) => {
const state = getState();
- const delPost = {...post};
- if (delPost.type === Posts.POST_TYPES.COMBINED_USER_ACTIVITY && delPost.system_post_ids) {
- delPost.system_post_ids.forEach((systemPostId) => {
+ if (post.type === Posts.POST_TYPES.COMBINED_USER_ACTIVITY && post.system_post_ids) {
+ post.system_post_ids.forEach((systemPostId) => {
const systemPost = Selectors.getPost(state, systemPostId);
if (systemPost) {
dispatch(deletePost(systemPost));
@@ -376,15 +373,14 @@ export function deletePost(post: ExtendedPost) {
} else {
dispatch({
type: PostTypes.POST_DELETED,
- data: delPost,
- meta: {
- offline: {
- effect: () => Client4.deletePost(post.id),
- commit: {type: 'do_nothing'}, // redux-offline always needs to dispatch something on commit
- rollback: receivedPost(delPost),
- },
- },
+ data: post,
});
+
+ try {
+ await Client4.deletePost(post.id);
+ } catch (error) {
+ dispatch(receivedPost(post));
+ }
}
return {data: true};
diff --git a/app/mm-redux/actions/preferences.test.js b/app/mm-redux/actions/preferences.test.js
index d2954f9c1..a24dd3de1 100644
--- a/app/mm-redux/actions/preferences.test.js
+++ b/app/mm-redux/actions/preferences.test.js
@@ -21,7 +21,14 @@ describe('Actions.Preferences', () => {
});
beforeEach(async () => {
- store = await configureStore();
+ const initialState = {
+ entities: {
+ users: {
+ currentUserId: TestHelper.basicUser.id,
+ },
+ },
+ };
+ store = await configureStore(initialState);
});
afterAll(async () => {
@@ -241,7 +248,7 @@ describe('Actions.Preferences', () => {
nock(Client4.getUsersRoute()).
get('/me/preferences').
reply(200, existingPreferences);
- await Actions.getMyPreferences()(store.dispatch, store.getState);
+ await store.dispatch(Actions.getMyPreferences());
const newTheme = {
type: 'Mattermost Dark',
@@ -249,7 +256,7 @@ describe('Actions.Preferences', () => {
nock(Client4.getUsersRoute()).
put(`/${TestHelper.basicUser.id}/preferences`).
reply(200, OK_RESPONSE);
- await Actions.saveTheme(team.id, newTheme)(store.dispatch, store.getState);
+ await store.dispatch(Actions.saveTheme(team.id, newTheme));
const state = store.getState();
const {myPreferences} = state.entities.preferences;
diff --git a/app/mm-redux/actions/preferences.ts b/app/mm-redux/actions/preferences.ts
index aa566a5d1..78e72c706 100644
--- a/app/mm-redux/actions/preferences.ts
+++ b/app/mm-redux/actions/preferences.ts
@@ -14,28 +14,26 @@ import {PreferenceType} from '@mm-redux/types/preferences';
import {bindClientFunc} from './helpers';
import {getProfilesByIds, getProfilesInChannel} from './users';
import {getChannelAndMyMember, getMyChannelMember} from './channels';
+
export function deletePreferences(userId: string, preferences: Array): ActionFunc {
return async (dispatch: DispatchFunc, getState: GetStateFunc) => {
const state = getState();
const myPreferences = getMyPreferencesSelector(state);
const currentPreferences = preferences.map((pref) => myPreferences[getPreferenceKey(pref.category, pref.name)]);
- dispatch({
- type: PreferenceTypes.DELETED_PREFERENCES,
- data: preferences,
- meta: {
- offline: {
- effect: () => Client4.deletePreferences(userId, preferences),
- commit: {
- type: PreferenceTypes.DELETED_PREFERENCES,
- },
- rollback: {
- type: PreferenceTypes.RECEIVED_PREFERENCES,
- data: currentPreferences,
- },
- },
- },
- });
+ try {
+ dispatch({
+ type: PreferenceTypes.DELETED_PREFERENCES,
+ data: preferences,
+ });
+
+ await Client4.deletePreferences(userId, preferences);
+ } catch {
+ dispatch({
+ type: PreferenceTypes.RECEIVED_PREFERENCES,
+ data: currentPreferences,
+ });
+ }
return {data: true};
};
@@ -104,22 +102,21 @@ export function makeGroupMessageVisibleIfNecessary(channelId: string): ActionFun
export function savePreferences(userId: string, preferences: Array) {
return async (dispatch: DispatchFunc) => {
- dispatch({
- type: PreferenceTypes.RECEIVED_PREFERENCES,
- data: preferences,
- meta: {
- offline: {
- effect: () => Client4.savePreferences(userId, preferences),
- commit: {
- type: PreferenceTypes.RECEIVED_PREFERENCES,
- },
- rollback: {
- type: PreferenceTypes.DELETED_PREFERENCES,
- data: preferences,
- },
- },
- },
- });
+ try {
+ // Optimistic action
+ dispatch({
+ type: PreferenceTypes.RECEIVED_PREFERENCES,
+ data: preferences,
+ });
+
+ await Client4.savePreferences(userId, preferences);
+ } catch (error) {
+ dispatch({
+ type: PreferenceTypes.DELETED_PREFERENCES,
+ data: preferences,
+ });
+ return {error};
+ }
return {data: true};
};
diff --git a/app/mm-redux/actions/users.test.js b/app/mm-redux/actions/users.test.js
index d524337b4..a05e2d5f9 100644
--- a/app/mm-redux/actions/users.test.js
+++ b/app/mm-redux/actions/users.test.js
@@ -5,14 +5,20 @@ import assert from 'assert';
import nock from 'nock';
import fs from 'fs';
+import {NavigationTypes} from '@constants';
+import {logout} from '@actions/views/user';
import * as Actions from '@mm-redux/actions/users';
import {Client4} from '@mm-redux/client';
import {RequestStatus} from '../constants';
import TestHelper from 'test/test_helper';
import configureStore from 'test/test_store';
import deepFreeze from '@mm-redux/utils/deep_freeze';
+import EventEmitter from '@mm-redux/utils/event_emitter';
+
+import initialState from '@mm-redux/store/initial_state';
const OK_RESPONSE = {status: 'OK'};
+const UNAUTHORIZED = {status_code: 401};
describe('Actions.Users', () => {
let store;
@@ -21,7 +27,17 @@ describe('Actions.Users', () => {
});
beforeEach(async () => {
- store = await configureStore();
+ const initial = {
+ ...initialState,
+ entities: {
+ ...initialState.entities,
+ users: {
+ ...initialState.entities.users,
+ currentUserId: 'current-user-id',
+ },
+ },
+ };
+ store = await configureStore(initial);
});
afterAll(async () => {
@@ -171,50 +187,13 @@ describe('Actions.Users', () => {
});
it('logout', async () => {
+ const emit = jest.spyOn(EventEmitter, 'emit');
nock(Client4.getBaseRoute()).
post('/users/logout').
reply(200, OK_RESPONSE);
- await Actions.logout()(store.dispatch, store.getState);
-
- const state = store.getState();
- const logoutRequest = state.requests.users.logout;
- const general = state.entities.general;
- const users = state.entities.users;
- const teams = state.entities.teams;
- const channels = state.entities.channels;
- const posts = state.entities.posts;
- const preferences = state.entities.preferences;
-
- if (logoutRequest.status === RequestStatus.FAILURE) {
- throw new Error(JSON.stringify(logoutRequest.error));
- }
-
- assert.deepStrictEqual(general.config, {}, 'config not empty');
- assert.deepStrictEqual(general.license, {}, 'license not empty');
- assert.strictEqual(users.currentUserId, '', 'current user id not empty');
- assert.deepStrictEqual(users.mySessions, [], 'user sessions not empty');
- assert.deepStrictEqual(users.myAudits, [], 'user audits not empty');
- assert.deepStrictEqual(users.profiles, {}, 'user profiles not empty');
- assert.deepStrictEqual(users.profilesInTeam, {}, 'users profiles in team not empty');
- assert.deepStrictEqual(users.profilesInChannel, {}, 'users profiles in channel not empty');
- assert.deepStrictEqual(users.profilesNotInChannel, {}, 'users profiles NOT in channel not empty');
- assert.deepStrictEqual(users.statuses, {}, 'users statuses not empty');
- assert.strictEqual(teams.currentTeamId, '', 'current team id is not empty');
- assert.deepStrictEqual(teams.teams, {}, 'teams is not empty');
- assert.deepStrictEqual(teams.myMembers, {}, 'team members is not empty');
- assert.deepStrictEqual(teams.membersInTeam, {}, 'members in team is not empty');
- assert.deepStrictEqual(teams.stats, {}, 'team stats is not empty');
- assert.strictEqual(channels.currentChannelId, '', 'current channel id is not empty');
- assert.deepStrictEqual(channels.channels, {}, 'channels is not empty');
- assert.deepStrictEqual(channels.channelsInTeam, {}, 'channelsInTeam is not empty');
- assert.deepStrictEqual(channels.myMembers, {}, 'channel members is not empty');
- assert.deepStrictEqual(channels.stats, {}, 'channel stats is not empty');
- assert.strictEqual(posts.selectedPostId, '', 'selected post id is not empty');
- assert.strictEqual(posts.currentFocusedPostId, '', 'current focused post id is not empty');
- assert.deepStrictEqual(posts.posts, {}, 'posts is not empty');
- assert.deepStrictEqual(posts.postsInChannel, {}, 'posts by channel is not empty');
- assert.deepStrictEqual(preferences.myPreferences, {}, 'user preferences not empty');
+ await store.dispatch(logout(false));
+ expect(emit).toHaveBeenCalledWith(NavigationTypes.NAVIGATION_RESET);
nock(Client4.getBaseRoute()).
post('/users/login').
@@ -625,7 +604,7 @@ describe('Actions.Users', () => {
assert.strictEqual(sessions.length, 0);
TestHelper.mockLogin();
- await Actions.loginById(user.id, 'password1')(store.dispatch, store.getState);
+ await store.dispatch(Actions.loginById(user.id, 'password1'));
nock(Client4.getBaseRoute()).
post('/users/login').
@@ -635,7 +614,7 @@ describe('Actions.Users', () => {
nock(Client4.getBaseRoute()).
get(`/users/${user.id}/sessions`).
reply(200, [{id: TestHelper.generateId(), create_at: 1507756921338, expires_at: 1510348921338, last_activity_at: 1507821125630, user_id: TestHelper.basicUser.id, device_id: '', roles: 'system_admin system_user'}, {id: TestHelper.generateId(), create_at: 1507756921338, expires_at: 1510348921338, last_activity_at: 1507821125630, user_id: TestHelper.basicUser.id, device_id: '', roles: 'system_admin system_user'}]);
- await Actions.getSessions(user.id)(store.dispatch, store.getState);
+ await store.dispatch(Actions.getSessions(user.id));
sessions = store.getState().entities.users.mySessions;
assert.ok(sessions.length > 1);
@@ -643,23 +622,14 @@ describe('Actions.Users', () => {
nock(Client4.getBaseRoute()).
post(`/users/${user.id}/sessions/revoke/all`).
reply(200, OK_RESPONSE);
- const {data} = await Actions.revokeAllSessionsForUser(user.id)(store.dispatch, store.getState);
+ const {data} = await store.dispatch(Actions.revokeAllSessionsForUser(user.id));
assert.deepEqual(data, true);
nock(Client4.getBaseRoute()).
get('/users').
query(true).
- reply(401, {});
- await Actions.getProfiles(0)(store.dispatch, store.getState);
-
- const logoutRequest = store.getState().requests.users.logout;
- if (logoutRequest.status === RequestStatus.FAILURE) {
- throw new Error(JSON.stringify(logoutRequest.error));
- }
-
- sessions = store.getState().entities.users.mySessions;
-
- assert.strictEqual(sessions.length, 0);
+ reply(401, UNAUTHORIZED);
+ await store.dispatch(Actions.getProfiles(0));
nock(Client4.getBaseRoute()).
post('/users/login').
@@ -669,6 +639,11 @@ describe('Actions.Users', () => {
it('revokeSessionsForAllUsers', async () => {
const user = TestHelper.basicUser;
+
+ nock(Client4.getBaseRoute()).
+ post('/roles/names').
+ reply(200, []);
+
nock(Client4.getBaseRoute()).
post('/users/logout').
reply(200, OK_RESPONSE);
@@ -678,7 +653,7 @@ describe('Actions.Users', () => {
assert.strictEqual(sessions.length, 0);
TestHelper.mockLogin();
- await Actions.loginById(user.id, 'password1')(store.dispatch, store.getState);
+ await store.dispatch(Actions.loginById(user.id, 'password1'));
nock(Client4.getBaseRoute()).
post('/users/login').
@@ -688,7 +663,7 @@ describe('Actions.Users', () => {
nock(Client4.getBaseRoute()).
get(`/users/${user.id}/sessions`).
reply(200, [{id: TestHelper.generateId(), create_at: 1507756921338, expires_at: 1510348921338, last_activity_at: 1507821125630, user_id: TestHelper.basicUser.id, device_id: '', roles: 'system_admin system_user'}, {id: TestHelper.generateId(), create_at: 1507756921338, expires_at: 1510348921338, last_activity_at: 1507821125630, user_id: TestHelper.basicUser.id, device_id: '', roles: 'system_admin system_user'}]);
- await Actions.getSessions(user.id)(store.dispatch, store.getState);
+ await store.dispatch(Actions.getSessions(user.id));
sessions = store.getState().entities.users.mySessions;
assert.ok(sessions.length > 1);
@@ -696,24 +671,9 @@ describe('Actions.Users', () => {
nock(Client4.getBaseRoute()).
post('/users/sessions/revoke/all').
reply(200, OK_RESPONSE);
- const {data} = await Actions.revokeSessionsForAllUsers(user.id)(store.dispatch, store.getState);
+ const {data} = await store.dispatch(Actions.revokeSessionsForAllUsers(user.id));
assert.deepEqual(data, true);
- nock(Client4.getBaseRoute()).
- get('/users').
- query(true).
- reply(401, {});
- await Actions.getProfiles(0)(store.dispatch, store.getState);
-
- const logoutRequest = store.getState().requests.users.logout;
- if (logoutRequest.status === RequestStatus.FAILURE) {
- throw new Error(JSON.stringify(logoutRequest.error));
- }
-
- sessions = store.getState().entities.users.mySessions;
-
- assert.strictEqual(sessions.length, 0);
-
nock(Client4.getBaseRoute()).
post('/users/login').
reply(200, TestHelper.basicUser);
diff --git a/app/mm-redux/actions/users.ts b/app/mm-redux/actions/users.ts
index 67e25c532..260105dc4 100644
--- a/app/mm-redux/actions/users.ts
+++ b/app/mm-redux/actions/users.ts
@@ -242,22 +242,6 @@ export function loadMe(): ActionFunc {
};
}
-export function logout(): ActionFunc {
- return async (dispatch: DispatchFunc, getState: GetStateFunc) => {
- dispatch({type: UserTypes.LOGOUT_REQUEST, data: null});
-
- try {
- await Client4.logout();
- } catch (error) {
- // nothing to do here
- }
-
- dispatch({type: UserTypes.LOGOUT_SUCCESS, data: null});
-
- return {data: true};
- };
-}
-
export function getTotalUsersStats(): ActionFunc {
return bindClientFunc({
clientFunc: Client4.getTotalUsersStats,
@@ -1421,7 +1405,6 @@ export default {
checkMfa,
generateMfaSecret,
login,
- logout,
getProfiles,
getProfilesByIds,
getProfilesInTeam,
diff --git a/app/mm-redux/constants/general.ts b/app/mm-redux/constants/general.ts
index ac79ddb4d..0c7a4a09a 100644
--- a/app/mm-redux/constants/general.ts
+++ b/app/mm-redux/constants/general.ts
@@ -51,7 +51,7 @@ export default {
GM_CHANNEL: 'G',
PUSH_NOTIFY_APPLE_REACT_NATIVE: 'apple_rn',
PUSH_NOTIFY_ANDROID_REACT_NATIVE: 'android_rn',
- STORE_REHYDRATION_COMPLETE: 'store_hydation_complete',
+ STORE_REHYDRATION_COMPLETE: 'store_hydration_complete',
OFFLINE_STORE_RESET: 'offline_store_reset',
OFFLINE_STORE_PURGE: 'offline_store_purge',
TEAMMATE_NAME_DISPLAY: {
@@ -68,4 +68,5 @@ export default {
DISABLED: 'disabled',
DEFAULT_ON: 'default_on',
DEFAULT_OFF: 'default_off',
+ REHYDRATED: 'app/REHYDRATED',
};
diff --git a/app/mm-redux/reducers/entities/bots.ts b/app/mm-redux/reducers/entities/bots.ts
index 11790a1e9..2dab6547b 100644
--- a/app/mm-redux/reducers/entities/bots.ts
+++ b/app/mm-redux/reducers/entities/bots.ts
@@ -1,7 +1,7 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {combineReducers} from 'redux';
-import {BotTypes, UserTypes} from '@mm-redux/action_types';
+import {BotTypes} from '@mm-redux/action_types';
import {GenericAction} from '@mm-redux/types/actions';
import {Dictionary} from '@mm-redux/types/utilities';
import {Bot} from '@mm-redux/types/bots';
@@ -22,8 +22,6 @@ function accounts(state: Dictionary = {}, action: GenericAction) {
nextState[bot.user_id] = bot;
return nextState;
}
- case UserTypes.LOGOUT_SUCCESS:
- return {};
default:
return state;
}
diff --git a/app/mm-redux/reducers/entities/channel_categories.ts b/app/mm-redux/reducers/entities/channel_categories.ts
index 1f5e61124..f057eb385 100644
--- a/app/mm-redux/reducers/entities/channel_categories.ts
+++ b/app/mm-redux/reducers/entities/channel_categories.ts
@@ -5,7 +5,7 @@ import {combineReducers} from 'redux';
import {CategoryTypes} from '../../constants/channel_categories';
-import {ChannelCategoryTypes, TeamTypes, UserTypes} from '@mm-redux/action_types';
+import {ChannelCategoryTypes, TeamTypes} from '@mm-redux/action_types';
import {GenericAction} from '@mm-redux/types/actions';
import {ChannelCategory} from '@mm-redux/types/channel_categories';
@@ -79,8 +79,6 @@ export function byId(state: IDMappedObjects = {}, action: Gener
return nextState;
}
- case UserTypes.LOGOUT_SUCCESS:
- return {};
default:
return state;
}
@@ -141,8 +139,6 @@ export function orderByTeam(state: RelationOneToOne[]
return nextState;
}
- case UserTypes.LOGOUT_SUCCESS:
- return {};
default:
return state;
}
diff --git a/app/mm-redux/reducers/entities/channels.test.js b/app/mm-redux/reducers/entities/channels.test.js
index 31126bb7e..21a710fec 100644
--- a/app/mm-redux/reducers/entities/channels.test.js
+++ b/app/mm-redux/reducers/entities/channels.test.js
@@ -433,18 +433,6 @@ describe('channels', () => {
});
expect(nextState.channel1).toBe(undefined);
});
- test('remove all marks if user logs out', () => {
- const state = deepFreeze({
- channel1: true,
- channel231: false,
- });
- const nextState = Reducers.manuallyUnread(state, {
- type: UserTypes.LOGOUT_SUCCESS,
- data: {},
- });
- expect(nextState.channel1).toBe(undefined);
- expect(nextState.channel231).toBe(undefined);
- });
});
describe('RECEIVED_CHANNELS', () => {
test('should not remove current channel', () => {
diff --git a/app/mm-redux/reducers/entities/channels.ts b/app/mm-redux/reducers/entities/channels.ts
index b266efb18..2c17cefd7 100644
--- a/app/mm-redux/reducers/entities/channels.ts
+++ b/app/mm-redux/reducers/entities/channels.ts
@@ -42,8 +42,6 @@ function currentChannelId(state = '', action: GenericAction) {
switch (action.type) {
case ChannelTypes.SELECT_CHANNEL:
return action.data;
- case UserTypes.LOGOUT_SUCCESS:
- return '';
default:
return state;
}
@@ -182,8 +180,6 @@ function channels(state: IDMappedObjects = {}, action: GenericAction) {
return hasNewValues ? nextState : state;
}
- case UserTypes.LOGOUT_SUCCESS:
- return {};
default:
return state;
}
@@ -217,8 +213,6 @@ function channelsInTeam(state: RelationOneToMany = {}, action: Ge
};
return channelListToSet(state, values);
}
- case UserTypes.LOGOUT_SUCCESS:
- return {};
default:
return state;
}
@@ -396,8 +390,6 @@ function myMembers(state: RelationOneToOne = {}, act
return state;
}
- case UserTypes.LOGOUT_SUCCESS:
- return {};
default:
return state;
}
@@ -462,8 +454,6 @@ function membersInChannel(state: RelationOneToOne = {}, action: Gene
return state;
}
- case UserTypes.LOGOUT_SUCCESS:
- return {};
default:
return state;
}
@@ -633,11 +621,6 @@ export function manuallyUnread(state: RelationOneToOne = {}, a
}
return state;
}
- case UserTypes.LOGOUT_SUCCESS: {
- // user is logging out, remove any reference
- return {};
- }
-
case ChannelTypes.ADD_MANUALLY_UNREAD:
case ChannelTypes.POST_UNREAD_SUCCESS: {
return {...state, [action.data.channelId]: true};
diff --git a/app/mm-redux/reducers/entities/emojis.ts b/app/mm-redux/reducers/entities/emojis.ts
index d0fbb91d3..f4b965553 100644
--- a/app/mm-redux/reducers/entities/emojis.ts
+++ b/app/mm-redux/reducers/entities/emojis.ts
@@ -1,7 +1,7 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {combineReducers} from 'redux';
-import {EmojiTypes, PostTypes, UserTypes} from '@mm-redux/action_types';
+import {EmojiTypes, PostTypes} from '@mm-redux/action_types';
import {EmojisState, CustomEmoji} from '@mm-redux/types/emojis';
import * as types from '@mm-redux/types';
@@ -25,7 +25,6 @@ export function customEmoji(state: types.utilities.IDMappedObjects
return nextState;
}
case EmojiTypes.CLEAR_CUSTOM_EMOJIS:
- case UserTypes.LOGOUT_SUCCESS:
return {};
case PostTypes.RECEIVED_NEW_POST:
@@ -94,7 +93,6 @@ function nonExistentEmoji(state: Set = new Set(), action: types.actions.
return changed ? nextState : state;
}
case EmojiTypes.CLEAR_CUSTOM_EMOJIS:
- case UserTypes.LOGOUT_SUCCESS:
return new Set();
default:
diff --git a/app/mm-redux/reducers/entities/files.ts b/app/mm-redux/reducers/entities/files.ts
index 7c28aab9c..9fd739362 100644
--- a/app/mm-redux/reducers/entities/files.ts
+++ b/app/mm-redux/reducers/entities/files.ts
@@ -2,7 +2,7 @@
// See LICENSE.txt for license information.
import {combineReducers} from 'redux';
-import {FileTypes, PostTypes, UserTypes} from '@mm-redux/action_types';
+import {FileTypes, PostTypes} from '@mm-redux/action_types';
import {GenericAction} from '@mm-redux/types/actions';
import {Post} from '@mm-redux/types/posts';
import {FileInfo} from '@mm-redux/types/files';
@@ -50,8 +50,6 @@ export function files(state: Dictionary = {}, action: GenericAction) {
return state;
}
- case UserTypes.LOGOUT_SUCCESS:
- return {};
default:
return state;
}
@@ -109,8 +107,6 @@ export function fileIdsByPostId(state: Dictionary> = {}, action: G
return state;
}
- case UserTypes.LOGOUT_SUCCESS:
- return {};
default:
return state;
}
@@ -132,8 +128,6 @@ function filePublicLink(state: {link: string} = {link: ''}, action: GenericActio
case FileTypes.RECEIVED_FILE_PUBLIC_LINK: {
return action.data;
}
- case UserTypes.LOGOUT_SUCCESS:
- return {link: ''};
default:
return state;
diff --git a/app/mm-redux/reducers/entities/general.ts b/app/mm-redux/reducers/entities/general.ts
index a0fded765..6c3876a23 100644
--- a/app/mm-redux/reducers/entities/general.ts
+++ b/app/mm-redux/reducers/entities/general.ts
@@ -14,8 +14,6 @@ function config(state: Partial = {}, action: GenericAction) {
case GeneralTypes.SET_CONFIG_AND_LICENSE:
return Object.assign({}, state, action.data.config);
case GeneralTypes.CLIENT_CONFIG_RESET:
- case UserTypes.LOGOUT_SUCCESS:
- return {};
default:
return state;
}
@@ -40,8 +38,6 @@ function credentials(state: any = {}, action: GenericAction) {
return {
url: action.data.url,
};
- case UserTypes.LOGOUT_SUCCESS:
- return {};
default:
return state;
}
@@ -51,8 +47,6 @@ function dataRetentionPolicy(state: any = {}, action: GenericAction) {
switch (action.type) {
case GeneralTypes.RECEIVED_DATA_RETENTION_POLICY:
return action.data;
- case UserTypes.LOGOUT_SUCCESS:
- return {};
default:
return state;
}
@@ -74,8 +68,6 @@ function license(state: any = {}, action: GenericAction) {
case GeneralTypes.SET_CONFIG_AND_LICENSE:
return Object.assign({}, state, action.data.license);
case GeneralTypes.CLIENT_LICENSE_RESET:
- case UserTypes.LOGOUT_SUCCESS:
- return {};
default:
return state;
}
@@ -85,8 +77,6 @@ function timezones(state: string[] = [], action: GenericAction) {
switch (action.type) {
case GeneralTypes.SUPPORTED_TIMEZONES_RECEIVED:
return action.data;
- case UserTypes.LOGOUT_SUCCESS:
- return [];
default:
return state;
}
@@ -96,8 +86,6 @@ function serverVersion(state = '', action: GenericAction) {
switch (action.type) {
case GeneralTypes.RECEIVED_SERVER_VERSION:
return action.data;
- case UserTypes.LOGOUT_SUCCESS:
- return '';
default:
return state;
}
diff --git a/app/mm-redux/reducers/entities/integrations.ts b/app/mm-redux/reducers/entities/integrations.ts
index e0285755d..76828e8f5 100644
--- a/app/mm-redux/reducers/entities/integrations.ts
+++ b/app/mm-redux/reducers/entities/integrations.ts
@@ -2,7 +2,7 @@
// See LICENSE.txt for license information.
import {combineReducers} from 'redux';
-import {IntegrationTypes, UserTypes, ChannelTypes} from '@mm-redux/action_types';
+import {IntegrationTypes, ChannelTypes} from '@mm-redux/action_types';
import {GenericAction} from '@mm-redux/types/actions';
import {Command, IncomingWebhook, OutgoingWebhook, OAuthApp} from '@mm-redux/types/integrations';
import {Dictionary, IDMappedObjects} from '@mm-redux/types/utilities';
@@ -42,8 +42,6 @@ function incomingHooks(state: IDMappedObjects = {}, action: Gen
return state;
}
- case UserTypes.LOGOUT_SUCCESS:
- return {};
default:
return state;
@@ -85,8 +83,6 @@ function outgoingHooks(state: IDMappedObjects = {}, action: Gen
return state;
}
- case UserTypes.LOGOUT_SUCCESS:
- return {};
default:
return state;
@@ -131,8 +127,6 @@ function commands(state: IDMappedObjects = {}, action: GenericAction) {
Reflect.deleteProperty(nextState, action.data.id);
return nextState;
}
- case UserTypes.LOGOUT_SUCCESS:
- return {};
default:
return state;
@@ -159,8 +153,6 @@ function systemCommands(state: IDMappedObjects = {}, action: GenericAct
}
return state;
- case UserTypes.LOGOUT_SUCCESS:
- return {};
default:
return state;
@@ -186,8 +178,6 @@ function oauthApps(state: IDMappedObjects = {}, action: GenericAction)
Reflect.deleteProperty(nextState, action.data.id);
return nextState;
}
- case UserTypes.LOGOUT_SUCCESS:
- return {};
default:
return state;
diff --git a/app/mm-redux/reducers/entities/posts.ts b/app/mm-redux/reducers/entities/posts.ts
index 6fdea6e95..9158940b4 100644
--- a/app/mm-redux/reducers/entities/posts.ts
+++ b/app/mm-redux/reducers/entities/posts.ts
@@ -1,6 +1,6 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
-import {ChannelTypes, GeneralTypes, PostTypes, UserTypes} from '@mm-redux/action_types';
+import {ChannelTypes, GeneralTypes, PostTypes} from '@mm-redux/action_types';
import {Posts} from '../../constants';
import {comparePosts} from '@mm-redux/utils/post_utils';
import {Post, PostsState, PostOrderBlock, MessageHistory} from '@mm-redux/types/posts';
@@ -165,9 +165,6 @@ export function handlePosts(state: RelationOneToOne = {}, action: Ge
return nextState;
}
-
- case UserTypes.LOGOUT_SUCCESS:
- return {};
default:
return state;
}
@@ -653,9 +650,6 @@ export function postsInChannel(state: Dictionary> = {}, ac
return nextState;
}
-
- case UserTypes.LOGOUT_SUCCESS:
- return {};
default:
return state;
}
@@ -937,9 +931,6 @@ export function postsInThread(state: RelationOneToMany = {}, action:
return nextState;
}
-
- case UserTypes.LOGOUT_SUCCESS:
- return {};
default:
return state;
}
@@ -949,8 +940,6 @@ function selectedPostId(state = '', action: GenericAction) {
switch (action.type) {
case PostTypes.RECEIVED_POST_SELECTED:
return action.data;
- case UserTypes.LOGOUT_SUCCESS:
- return '';
default:
return state;
}
@@ -960,8 +949,6 @@ function currentFocusedPostId(state = '', action: GenericAction) {
switch (action.type) {
case PostTypes.RECEIVED_FOCUSED_POST:
return action.data;
- case UserTypes.LOGOUT_SUCCESS:
- return '';
default:
return state;
}
@@ -1033,8 +1020,6 @@ export function reactions(state: RelationOneToOne> =
return state;
}
- case UserTypes.LOGOUT_SUCCESS:
- return {};
default:
return state;
}
@@ -1079,8 +1064,6 @@ export function openGraph(state: RelationOneToOne = {}, action: Gener
return posts.reduce(storeOpenGraphForPost, state);
}
- case UserTypes.LOGOUT_SUCCESS:
- return {};
default:
return state;
}
@@ -1165,16 +1148,6 @@ function messagesHistory(state: Partial = {}, action: GenericAct
index: nextIndex,
};
}
- case UserTypes.LOGOUT_SUCCESS: {
- const index: Dictionary = {};
- index[Posts.MESSAGE_TYPES.POST] = -1;
- index[Posts.MESSAGE_TYPES.COMMENT] = -1;
-
- return {
- messages: [],
- index,
- };
- }
default:
return state;
}
diff --git a/app/mm-redux/reducers/entities/preferences.ts b/app/mm-redux/reducers/entities/preferences.ts
index 3d8f57565..b78afdb4b 100644
--- a/app/mm-redux/reducers/entities/preferences.ts
+++ b/app/mm-redux/reducers/entities/preferences.ts
@@ -53,9 +53,6 @@ function myPreferences(state: Dictionary = {}, action: GenericAc
return nextState;
}
-
- case UserTypes.LOGOUT_SUCCESS:
- return {};
default:
return state;
}
diff --git a/app/mm-redux/reducers/entities/roles.ts b/app/mm-redux/reducers/entities/roles.ts
index 3e5be7ff4..80482e658 100644
--- a/app/mm-redux/reducers/entities/roles.ts
+++ b/app/mm-redux/reducers/entities/roles.ts
@@ -2,7 +2,7 @@
// See LICENSE.txt for license information.
import {combineReducers} from 'redux';
-import {RoleTypes, UserTypes} from '@mm-redux/action_types';
+import {RoleTypes} from '@mm-redux/action_types';
import {GenericAction} from '@mm-redux/types/actions';
import {Dictionary} from '@mm-redux/types/utilities';
import {Role} from '@mm-redux/types/roles';
@@ -11,8 +11,6 @@ function pending(state: Set = new Set(), action: GenericAction) {
switch (action.type) {
case RoleTypes.SET_PENDING_ROLES:
return action.data;
- case UserTypes.LOGOUT_SUCCESS:
- return new Set();
default:
return state;
}
@@ -49,9 +47,6 @@ function roles(state: Dictionary = {}, action: GenericAction) {
return state;
}
-
- case UserTypes.LOGOUT_SUCCESS:
- return {};
default:
return state;
}
diff --git a/app/mm-redux/reducers/entities/schemes.ts b/app/mm-redux/reducers/entities/schemes.ts
index ec7985cb1..5957dfd85 100644
--- a/app/mm-redux/reducers/entities/schemes.ts
+++ b/app/mm-redux/reducers/entities/schemes.ts
@@ -1,7 +1,7 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {combineReducers} from 'redux';
-import {SchemeTypes, UserTypes} from '@mm-redux/action_types';
+import {SchemeTypes} from '@mm-redux/action_types';
import {GenericAction} from '@mm-redux/types/actions';
import {SchemesState, Scheme} from '@mm-redux/types/schemes';
@@ -34,9 +34,6 @@ function schemes(state: {
return nextState;
}
- case UserTypes.LOGOUT_SUCCESS:
- return {};
-
default:
return state;
}
diff --git a/app/mm-redux/reducers/entities/search.test.js b/app/mm-redux/reducers/entities/search.test.js
index 07fa2eca1..509a52965 100644
--- a/app/mm-redux/reducers/entities/search.test.js
+++ b/app/mm-redux/reducers/entities/search.test.js
@@ -100,17 +100,6 @@ describe('reducers.entities.search', () => {
const actualState = reducer({results: inputState}, action);
assert.deepEqual(actualState.results, expectedState);
});
-
- describe('UserTypes.LOGOUT_SUCCESS', () => {
- const inputState = ['abcd', 'efgh'];
- const action = {
- type: UserTypes.LOGOUT_SUCCESS,
- };
- const expectedState = [];
-
- const actualState = reducer({results: inputState}, action);
- assert.deepEqual(actualState.results, expectedState);
- });
});
describe('matches', () => {
@@ -251,20 +240,6 @@ describe('reducers.entities.search', () => {
const actualState = reducer({matches: inputState}, action);
assert.deepEqual(actualState.matches, expectedState);
});
-
- describe('UserTypes.LOGOUT_SUCCESS', () => {
- const inputState = {
- abcd: ['test', 'testing'],
- efgh: ['tests'],
- };
- const action = {
- type: UserTypes.LOGOUT_SUCCESS,
- };
- const expectedState = [];
-
- const actualState = reducer({matches: inputState}, action);
- assert.deepEqual(actualState.matches, expectedState);
- });
});
describe('pinned', () => {
diff --git a/app/mm-redux/reducers/entities/search.ts b/app/mm-redux/reducers/entities/search.ts
index a97e67691..f70227937 100644
--- a/app/mm-redux/reducers/entities/search.ts
+++ b/app/mm-redux/reducers/entities/search.ts
@@ -1,7 +1,7 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {combineReducers} from 'redux';
-import {PostTypes, PreferenceTypes, SearchTypes, UserTypes} from '@mm-redux/action_types';
+import {PostTypes, PreferenceTypes, SearchTypes} from '@mm-redux/action_types';
import {Preferences} from '../../constants';
import {PreferenceType} from '@mm-redux/types/preferences';
import {GenericAction} from '@mm-redux/types/actions';
@@ -28,7 +28,6 @@ function results(state: Array = [], action: GenericAction) {
return state;
}
case SearchTypes.REMOVE_SEARCH_POSTS:
- case UserTypes.LOGOUT_SUCCESS:
return [];
default:
@@ -53,7 +52,6 @@ function matches(state: Dictionary> = {}, action: GenericAction) {
return newState;
}
case SearchTypes.REMOVE_SEARCH_POSTS:
- case UserTypes.LOGOUT_SUCCESS:
return [];
default:
@@ -115,7 +113,6 @@ function flagged(state: Array = [], action: GenericAction) {
return state;
}
case SearchTypes.REMOVE_SEARCH_POSTS:
- case UserTypes.LOGOUT_SUCCESS:
return [];
default:
@@ -187,8 +184,6 @@ function pinned(state: Dictionary> = {}, action: GenericAction) {
return state;
}
- case UserTypes.LOGOUT_SUCCESS:
- return [];
default:
return state;
@@ -232,8 +227,6 @@ function recent(state: Dictionary> = {}, action: GenericAction) {
return nextState;
}
- case UserTypes.LOGOUT_SUCCESS:
- return {};
default:
return state;
@@ -254,8 +247,6 @@ function current(state: any = {}, action: GenericAction) {
},
};
}
- case UserTypes.LOGOUT_SUCCESS:
- return {};
default:
return state;
diff --git a/app/mm-redux/reducers/entities/teams.ts b/app/mm-redux/reducers/entities/teams.ts
index 321468f3a..a2cc2f7e1 100644
--- a/app/mm-redux/reducers/entities/teams.ts
+++ b/app/mm-redux/reducers/entities/teams.ts
@@ -13,8 +13,6 @@ function currentTeamId(state = '', action: GenericAction) {
case TeamTypes.SELECT_TEAM:
return action.data;
- case UserTypes.LOGOUT_SUCCESS:
- return '';
default:
return state;
}
@@ -61,9 +59,6 @@ function teams(state: IDMappedObjects = {}, action: GenericAction) {
return {...state, [teamId]: {...team, scheme_id: schemeId}};
}
- case UserTypes.LOGOUT_SUCCESS:
- return {};
-
default:
return state;
}
@@ -248,8 +243,6 @@ function myMembers(state: RelationOneToOne = {}, action: G
return nextState;
}
- case UserTypes.LOGOUT_SUCCESS:
- return {};
default:
return state;
}
@@ -328,8 +321,6 @@ function membersInTeam(state: RelationOneToOne {
const newState = reducer(state, action);
assert.deepEqual(newState.profilesInChannel, expectedState.profilesInChannel);
});
-
- it('UserTypes.LOGOUT_SUCCESS, existing profiles', () => {
- const state = {
- profilesInChannel: {
- id: new Set().add('old_user_id'),
- other_id: new Set().add('other_user_id'),
- },
- };
- const action = {
- type: UserTypes.LOGOUT_SUCCESS,
- };
- const expectedState = {
- profilesInChannel: {},
- };
-
- const newState = reducer(state, action);
- assert.deepEqual(newState.profilesInChannel, expectedState.profilesInChannel);
- });
});
describe('profilesNotInChannel', () => {
@@ -545,23 +527,5 @@ describe('Reducers.users', () => {
const newState = reducer(state, action);
assert.deepEqual(newState.profilesNotInChannel, expectedState.profilesNotInChannel);
});
-
- it('UserTypes.LOGOUT_SUCCESS, existing profiles', () => {
- const state = {
- profilesNotInChannel: {
- id: new Set().add('old_user_id'),
- other_id: new Set().add('other_user_id'),
- },
- };
- const action = {
- type: UserTypes.LOGOUT_SUCCESS,
- };
- const expectedState = {
- profilesNotInChannel: {},
- };
-
- const newState = reducer(state, action);
- assert.deepEqual(newState.profilesNotInChannel, expectedState.profilesNotInChannel);
- });
});
});
diff --git a/app/mm-redux/reducers/entities/users.ts b/app/mm-redux/reducers/entities/users.ts
index 210274a02..e23971043 100644
--- a/app/mm-redux/reducers/entities/users.ts
+++ b/app/mm-redux/reducers/entities/users.ts
@@ -102,10 +102,7 @@ function currentUserId(state = '', action: GenericAction) {
return user ? user.id : state;
}
- case UserTypes.LOGOUT_SUCCESS:
- return '';
}
-
return state;
}
@@ -139,9 +136,6 @@ function mySessions(state: Array<{id: string}> = [], action: GenericAction) {
case UserTypes.REVOKE_SESSIONS_FOR_ALL_USERS_SUCCESS:
return [];
- case UserTypes.LOGOUT_SUCCESS:
- return [];
-
default:
return state;
}
@@ -152,9 +146,6 @@ function myAudits(state = [], action: GenericAction) {
case UserTypes.RECEIVED_AUDITS:
return [...action.data];
- case UserTypes.LOGOUT_SUCCESS:
- return [];
-
default:
return state;
}
@@ -212,8 +203,6 @@ function profiles(state: IDMappedObjects = {}, action: GenericActio
return state;
}
- case UserTypes.LOGOUT_SUCCESS:
- return {};
case UserTypes.RECEIVED_TERMS_OF_SERVICE_STATUS: {
const data = action.data || action.payload;
return {
@@ -255,9 +244,6 @@ function profilesInTeam(state: RelationOneToMany = {}, action
case UserTypes.RECEIVED_PROFILES_LIST_NOT_IN_TEAM:
return removeProfileListFromSet(state, action);
- case UserTypes.LOGOUT_SUCCESS:
- return {};
-
case UserTypes.PROFILE_NO_LONGER_VISIBLE:
return removeProfileFromTeams(state, action);
@@ -283,9 +269,6 @@ function profilesNotInTeam(state: RelationOneToMany = {}, act
case UserTypes.RECEIVED_PROFILES_LIST_IN_TEAM:
return removeProfileListFromSet(state, action);
- case UserTypes.LOGOUT_SUCCESS:
- return {};
-
case UserTypes.PROFILE_NO_LONGER_VISIBLE:
return removeProfileFromTeams(state, action);
@@ -312,9 +295,6 @@ function profilesWithoutTeam(state: Set = new Set(), action: GenericActi
nextSet.delete(action.data.id);
return nextSet;
}
- case UserTypes.LOGOUT_SUCCESS:
- return new Set();
-
default:
return state;
}
@@ -342,9 +322,6 @@ function profilesInChannel(state: RelationOneToMany = {},
user_id: action.data.user_id,
}});
- case UserTypes.LOGOUT_SUCCESS:
- return {};
-
case UserTypes.PROFILE_NO_LONGER_VISIBLE:
return removeProfileFromTeams(state, action);
@@ -396,9 +373,6 @@ function profilesNotInChannel(state: RelationOneToMany = {
user_id: action.data.user_id,
}});
- case UserTypes.LOGOUT_SUCCESS:
- return {};
-
case UserTypes.PROFILE_NO_LONGER_VISIBLE:
return removeProfileFromTeams(state, action);
@@ -424,8 +398,6 @@ function statuses(state: RelationOneToOne = {}, action: Gen
return nextState;
}
- case UserTypes.LOGOUT_SUCCESS:
- return {};
case UserTypes.PROFILE_NO_LONGER_VISIBLE: {
if (state[action.data.user_id]) {
const newState = {...state};
@@ -483,8 +455,6 @@ function isManualStatus(state: RelationOneToOne = {}, acti
return nextState;
}
- case UserTypes.LOGOUT_SUCCESS:
- return {};
case UserTypes.PROFILE_NO_LONGER_VISIBLE: {
if (state[action.data.user_id]) {
const newState = {...state};
@@ -541,7 +511,6 @@ function myUserAccessTokens(state: any = {}, action: GenericAction) {
}
case UserTypes.CLEAR_MY_USER_ACCESS_TOKENS:
- case UserTypes.LOGOUT_SUCCESS:
return {};
default:
diff --git a/app/mm-redux/reducers/requests/users.ts b/app/mm-redux/reducers/requests/users.ts
index c90ca486f..1d08e694c 100644
--- a/app/mm-redux/reducers/requests/users.ts
+++ b/app/mm-redux/reducers/requests/users.ts
@@ -20,9 +20,6 @@ function checkMfa(state: RequestStatusType = initialRequestState(), action: Gene
case UserTypes.CHECK_MFA_FAILURE:
return {...state, status: RequestStatus.FAILURE, error: action.error};
- case UserTypes.LOGOUT_SUCCESS:
- return {...state, status: RequestStatus.NOT_STARTED, error: null};
-
default:
return state;
}
@@ -39,28 +36,6 @@ function login(state: RequestStatusType = initialRequestState(), action: Generic
case UserTypes.LOGIN_FAILURE:
return {...state, status: RequestStatus.FAILURE, error: action.error};
- case UserTypes.LOGOUT_SUCCESS:
- return {...state, status: RequestStatus.NOT_STARTED, error: null};
-
- default:
- return state;
- }
-}
-
-function logout(state: RequestStatusType = initialRequestState(), action: GenericAction): RequestStatusType {
- switch (action.type) {
- case UserTypes.LOGOUT_REQUEST:
- return {...state, status: RequestStatus.STARTED};
-
- case UserTypes.LOGOUT_SUCCESS:
- return {...state, status: RequestStatus.SUCCESS, error: null};
-
- case UserTypes.LOGOUT_FAILURE:
- return {...state, status: RequestStatus.FAILURE, error: action.error};
-
- case UserTypes.RESET_LOGOUT_STATE:
- return initialRequestState();
-
default:
return state;
}
@@ -72,7 +47,7 @@ function autocompleteUsers(state: RequestStatusType = initialRequestState(), act
UserTypes.AUTOCOMPLETE_USERS_SUCCESS,
UserTypes.AUTOCOMPLETE_USERS_FAILURE,
state,
- action
+ action,
);
}
@@ -82,14 +57,13 @@ function updateMe(state: RequestStatusType = initialRequestState(), action: Gene
UserTypes.UPDATE_ME_SUCCESS,
UserTypes.UPDATE_ME_FAILURE,
state,
- action
+ action,
);
}
export default (combineReducers({
checkMfa,
login,
- logout,
autocompleteUsers,
updateMe,
}) as (b: UsersRequestsStatuses, a: GenericAction) => UsersRequestsStatuses);
diff --git a/app/mm-redux/reducers/websocket.ts b/app/mm-redux/reducers/websocket.ts
index 4be89bad2..daa9e1517 100644
--- a/app/mm-redux/reducers/websocket.ts
+++ b/app/mm-redux/reducers/websocket.ts
@@ -27,9 +27,5 @@ export default function(state = getInitialState(), action: GenericAction) {
};
}
- if (action.type === UserTypes.LOGOUT_SUCCESS) {
- return getInitialState();
- }
-
return state;
}
diff --git a/app/mm-redux/store/configureStore.dev.ts b/app/mm-redux/store/configureStore.dev.ts
deleted file mode 100644
index 66adff4f6..000000000
--- a/app/mm-redux/store/configureStore.dev.ts
+++ /dev/null
@@ -1,102 +0,0 @@
-// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See LICENSE.txt for license information.
-
-/* eslint-disable no-undefined */
-import * as redux from 'redux';
-import {createOfflineReducer, networkStatusChangedAction, offlineCompose} from 'redux-offline';
-import defaultOfflineConfig from 'redux-offline/lib/defaults';
-import reducerRegistry from './reducer_registry';
-import devTools from 'remote-redux-devtools';
-
-const globalAny = global as any;
-const window = globalAny.window;
-
-const devToolsEnhancer = typeof window !== 'undefined' && window.__REDUX_DEVTOOLS_EXTENSION__ ? // eslint-disable-line no-underscore-dangle
- window.__REDUX_DEVTOOLS_EXTENSION__ : // eslint-disable-line no-underscore-dangle
- () => {
- return devTools({
- name: 'Mattermost',
- hostname: 'localhost',
- port: 5678,
- realtime: true,
- });
- };
-import serviceReducer from '../reducers';
-import deepFreezeAndThrowOnMutation from '@mm-redux/utils/deep_freeze';
-import initialState from './initial_state';
-import {offlineConfig, createReducer} from './helpers';
-import {createMiddleware} from './middleware';
-import {Reducer, Action} from '@mm-redux/types/actions';
-import {GlobalState} from '@mm-redux/types/store';
-
-/**
- * Configures and constructs the redux store. Accepts the following parameters:
- * preloadedState - Any preloaded state to be applied to the store after it is initially configured.
- * appReducer - An object containing any app-specific reducer functions that the client needs.
- * userOfflineConfig - Any additional configuration data to be passed into redux-offline aside from the default values.
- * getAppReducer - A function that returns the appReducer as defined above. Only used in development to enable hot reloading.
- * clientOptions - An object containing additional options used when configuring the redux store. The following options are available:
- * additionalMiddleware - func | array - Allows for single or multiple additional middleware functions to be passed in from the client side.
- * enableBuffer - bool - default = true - If true, the store will buffer all actions until offline state rehydration occurs.
- * enableThunk - bool - default = true - If true, include the thunk middleware automatically. If false, thunk must be provided as part of additionalMiddleware.
- */
-export default function configureServiceStore(preloadedState: any, appReducer: any, userOfflineConfig: any, getAppReducer: any, clientOptions: any) {
- const baseOfflineConfig = Object.assign({}, defaultOfflineConfig, offlineConfig, userOfflineConfig);
- const baseState = Object.assign({}, initialState, preloadedState);
-
- const loadReduxDevtools = process.env.NODE_ENV !== 'test'; //eslint-disable-line no-process-env
-
- const store = redux.createStore(
- createOfflineReducer(createDevReducer(baseState, serviceReducer, appReducer)),
- baseState,
- offlineCompose(baseOfflineConfig)(
- createMiddleware(clientOptions),
- loadReduxDevtools ? [devToolsEnhancer()] : []
- )
- );
-
- reducerRegistry.setChangeListener((reducers: any) => {
- store.replaceReducer(createOfflineReducer(createDevReducer(baseState, reducers)));
- });
-
- // launch store persistor
- if (baseOfflineConfig.persist) {
- baseOfflineConfig.persist(store, baseOfflineConfig.persistOptions, baseOfflineConfig.persistCallback);
- }
-
- if (baseOfflineConfig.detectNetwork) {
- baseOfflineConfig.detectNetwork((online: boolean) => {
- store.dispatch(networkStatusChangedAction(online));
- });
- }
-
- if ((module as any).hot) {
- // Enable Webpack hot module replacement for reducers
- (module as any).hot.accept(() => {
- const nextServiceReducer = require('../reducers').default; // eslint-disable-line global-require
- let nextAppReducer;
- if (getAppReducer) {
- nextAppReducer = getAppReducer(); // eslint-disable-line global-require
- }
- store.replaceReducer(createDevReducer(baseState, reducerRegistry.getReducers(), nextServiceReducer, nextAppReducer));
- });
- }
-
- return store;
-}
-
-function createDevReducer(baseState: any, ...reducers: any) {
- return enableFreezing(createReducer(baseState, ...reducers));
-}
-
-function enableFreezing(reducer: Reducer) {
- return (state: GlobalState, action: Action) => {
- const nextState = reducer(state, action);
-
- if (nextState !== state) {
- deepFreezeAndThrowOnMutation(nextState);
- }
-
- return nextState;
- };
-}
diff --git a/app/mm-redux/store/configureStore.prod.ts b/app/mm-redux/store/configureStore.prod.ts
deleted file mode 100644
index f1d456386..000000000
--- a/app/mm-redux/store/configureStore.prod.ts
+++ /dev/null
@@ -1,57 +0,0 @@
-// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See LICENSE.txt for license information.
-
-import * as redux from 'redux';
-import reducerRegistry from './reducer_registry';
-
-import serviceReducer from '../reducers';
-
-import {offlineConfig, createReducer} from './helpers';
-import initialState from './initial_state';
-import {createMiddleware} from './middleware';
-
-import {createOfflineReducer, networkStatusChangedAction, offlineCompose} from 'redux-offline';
-import defaultOfflineConfig from 'redux-offline/lib/defaults';
-
-/**
- * Configures and constructs the redux store. Accepts the following parameters:
- * preloadedState - Any preloaded state to be applied to the store after it is initially configured.
- * appReducer - An object containing any app-specific reducer functions that the client needs.
- * userOfflineConfig - Any additional configuration data to be passed into redux-offline aside from the default values.
- * getAppReducer - A function that returns the appReducer as defined above. Only used in development to enable hot reloading.
- * clientOptions - An object containing additional options used when configuring the redux store. The following options are available:
- * additionalMiddleware - func | array - Allows for single or multiple additional middleware functions to be passed in from the client side.
- * enableBuffer - bool - default = true - If true, the store will buffer all actions until offline state rehydration occurs.
- * enableThunk - bool - default = true - If true, include the thunk middleware automatically. If false, thunk must be provided as part of additionalMiddleware.
- */
-export default function configureOfflineServiceStore(preloadedState: any, appReducer: any, userOfflineConfig: any, getAppReducer: any, clientOptions = {}) {
- const baseState = Object.assign({}, initialState, preloadedState);
-
- const baseOfflineConfig = Object.assign({}, defaultOfflineConfig, offlineConfig, userOfflineConfig);
-
- const store = redux.createStore(
- createOfflineReducer(createReducer(baseState, serviceReducer as any, appReducer)),
- baseState,
- offlineCompose(baseOfflineConfig)(
- createMiddleware(clientOptions),
- []
- )
- );
-
- reducerRegistry.setChangeListener((reducers: any) => {
- store.replaceReducer(createOfflineReducer(createReducer(baseState, reducers)));
- });
-
- // launch store persistor
- if (baseOfflineConfig.persist) {
- baseOfflineConfig.persist(store, baseOfflineConfig.persistOptions, baseOfflineConfig.persistCallback);
- }
-
- if (baseOfflineConfig.detectNetwork) {
- baseOfflineConfig.detectNetwork((online: boolean) => {
- store.dispatch(networkStatusChangedAction(online));
- });
- }
-
- return store;
-}
diff --git a/app/mm-redux/store/helpers.ts b/app/mm-redux/store/helpers.ts
index 4904ffec6..c578c0094 100644
--- a/app/mm-redux/store/helpers.ts
+++ b/app/mm-redux/store/helpers.ts
@@ -1,42 +1,38 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
+
import {combineReducers} from 'redux';
-import {General} from '../constants';
import reducerRegistry from './reducer_registry';
-import {enableBatching, Action, Reducer} from '@mm-redux/types/actions';
-export const offlineConfig = {
- effect: (effect: Function, action: Action) => {
- if (typeof effect !== 'function') {
- throw new Error('Offline Action: effect must be a function.');
- } else if (!('meta' in action && action.meta && action.meta.offline.commit)) {
- throw new Error('Offline Action: commit action must be present.');
- }
+import {enableBatching, Reducer} from '@mm-redux/types/actions';
+import AsyncStorage from '@react-native-community/async-storage';
- return effect();
- },
- discard: (error: Error, action: Action, retries: number) => {
- if ('meta' in action && action.meta && action.meta.offline.hasOwnProperty('maxRetry')) {
- return retries >= action.meta.offline.maxRetry;
- }
+/* eslint-disable no-console */
- return retries > 10;
- },
-};
-
-export function createReducer(baseState: any, ...reducers: Reducer[]) {
+export function createReducer(...reducers: Reducer[]) {
reducerRegistry.setReducers(Object.assign({}, ...reducers));
const baseReducer = combineReducers(reducerRegistry.getReducers());
- // Root reducer wrapper that listens for reset events.
- // Returns whatever is passed for the data property
- // as the new state.
- function offlineReducer(state = {}, action: Action) {
- if ('type' in action && 'data' in action && action.type === General.OFFLINE_STORE_RESET) {
- return baseReducer(action.data || baseState, action);
- }
+ return enableBatching(baseReducer);
+}
- return baseReducer(state, action as any);
+const KEY_PREFIX = 'reduxPersist:';
+
+export async function getStoredState() {
+ const restoredState: Record = {};
+ let storeKeys: Array = [];
+
+ try {
+ const allKeys: Array = await AsyncStorage.getAllKeys();
+ storeKeys = allKeys.filter((key) => key.includes(KEY_PREFIX));
+
+ const values = await AsyncStorage.multiGet(storeKeys);
+
+ values.forEach(([key, data]: [string, string]) => {
+ restoredState[key.slice(KEY_PREFIX.length)] = JSON.parse(data);
+ });
+ } catch (error) {
+ console.log('ERROR GETTING FROM AsyncStorage', error);
}
- return enableBatching(offlineReducer);
-}
+ return {storeKeys, restoredState};
+}
\ No newline at end of file
diff --git a/app/mm-redux/store/index.ts b/app/mm-redux/store/index.ts
index 2c2a0e8d3..5fa3b4f01 100644
--- a/app/mm-redux/store/index.ts
+++ b/app/mm-redux/store/index.ts
@@ -1,6 +1,108 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
-/* eslint-disable global-require, no-process-env */
-const config = process.env.NODE_ENV === 'production' ? require('./configureStore.prod').default : require('./configureStore.dev').default;
-export default config;
+import * as redux from 'redux';
+import {persistReducer, persistStore, Persistor, createPersistoid} from 'redux-persist';
+import AsyncStorage from '@react-native-community/async-storage';
+
+import {General} from '@mm-redux/constants';
+import serviceReducer from '@mm-redux/reducers';
+
+import {createReducer, getStoredState} from './helpers';
+import initialState from './initial_state';
+import {createMiddleware} from './middleware';
+import reducerRegistry from './reducer_registry';
+
+/**
+ * Configures and constructs the redux store. Accepts the following parameters:
+ * preloadedState - Any preloaded state to be applied to the store after it is initially configured.
+ * appReducer - An object containing any app-specific reducer functions that the client needs.
+ * persistConfig - Configuration for redux-persist.
+ * getAppReducer - A function that returns the appReducer as defined above. Only used in development to enable hot reloading.
+ * clientOptions - An object containing additional options used when configuring the redux store. The following options are available:
+ * additionalMiddleware - func | array - Allows for single or multiple additional middleware functions to be passed in from the client side.
+ * enableBuffer - bool - default = true - If true, the store will buffer all actions until offline state rehydration occurs.
+ * enableThunk - bool - default = true - If true, include the thunk middleware automatically. If false, thunk must be provided as part of additionalMiddleware.
+ */
+
+type ReduxStore = {
+ store: redux.Store;
+ persistor: Persistor;
+}
+
+type ClientOptions = {
+ additionalMiddleware: [];
+ enableBuffer: boolean;
+ enableThunk: boolean;
+ enhancers: [];
+}
+
+type V4Store = {
+ storeKeys: Array;
+ restoredState: any;
+}
+
+const defaultClientOptions: ClientOptions = {
+ additionalMiddleware: [],
+ enableBuffer: true,
+ enableThunk: true,
+ enhancers: [],
+};
+
+export default function configureStore(preloadedState: any, appReducer: any, persistConfig: any, clientOptions: ClientOptions): ReduxStore {
+ const baseState = Object.assign({}, initialState, preloadedState);
+ const rootReducer = createReducer(serviceReducer as any, appReducer);
+ const persistedReducer = persistReducer({...persistConfig}, rootReducer);
+ const options = Object.assign({}, defaultClientOptions, clientOptions);
+
+ const store = redux.createStore(
+ persistedReducer,
+ baseState,
+ redux.compose(
+ redux.applyMiddleware(
+ ...createMiddleware(options),
+ ),
+ ...options.enhancers,
+ ),
+ );
+
+ reducerRegistry.setChangeListener((reducers: any) => {
+ const reducer = persistReducer(persistConfig, createReducer(baseState, reducers));
+
+ store.replaceReducer(reducer);
+ });
+
+ const persistor = persistStore(store, null);
+
+ getStoredState().then(({storeKeys, restoredState}: V4Store) => {
+ if (Object.keys(restoredState).length) {
+ const state = {
+ ...restoredState,
+ views: {
+ ...restoredState.views,
+ root: {
+ hydrationComplete: true,
+ },
+ },
+ _persist: persistor.getState(),
+ };
+
+ store.dispatch({
+ type: General.OFFLINE_STORE_PURGE,
+ state,
+ });
+
+ console.log('HYDRATED FROM v4', storeKeys); // eslint-disable-line no-console
+ const persistoid = createPersistoid(persistConfig);
+ store.subscribe(() => {
+ persistoid.update(store.getState());
+ });
+ store.dispatch({type: General.REHYDRATED});
+ AsyncStorage.multiRemove(storeKeys);
+ } else {
+ store.dispatch({type: General.REHYDRATED});
+ }
+ });
+
+ return {store, persistor};
+}
diff --git a/app/mm-redux/store/initial_state.ts b/app/mm-redux/store/initial_state.ts
index efac8c741..b00da8f99 100644
--- a/app/mm-redux/store/initial_state.ts
+++ b/app/mm-redux/store/initial_state.ts
@@ -205,10 +205,6 @@ const state: GlobalState = {
status: 'not_started',
error: null,
},
- logout: {
- status: 'not_started',
- error: null,
- },
autocompleteUsers: {
status: 'not_started',
error: null,
diff --git a/app/mm-redux/store/middleware.ts b/app/mm-redux/store/middleware.ts
index 88a1ca420..39990dbc7 100644
--- a/app/mm-redux/store/middleware.ts
+++ b/app/mm-redux/store/middleware.ts
@@ -3,20 +3,15 @@
import thunk, {ThunkMiddleware} from 'redux-thunk';
import createActionBuffer from 'redux-action-buffer';
-import {REHYDRATE} from 'redux-persist/constants';
+import {PERSIST} from 'redux-persist';
+import {General} from '@mm-redux/constants';
-const defaultOptions = {
- additionalMiddleware: [],
- enableBuffer: true,
- enableThunk: true,
-};
export function createMiddleware(clientOptions: any): ThunkMiddleware[] {
- const options = Object.assign({}, defaultOptions, clientOptions);
const {
additionalMiddleware,
enableBuffer,
enableThunk,
- } = options;
+ } = clientOptions;
const middleware: ThunkMiddleware[] = [];
if (enableThunk) {
@@ -32,7 +27,7 @@ export function createMiddleware(clientOptions: any): ThunkMiddleware[] {
}
if (enableBuffer) {
- middleware.push(createActionBuffer(REHYDRATE));
+ middleware.push(createActionBuffer({breaker: General.REHYDRATED, passthrough: [PERSIST]}));
}
return middleware;
diff --git a/app/mm-redux/store/mmkv_adapter.ts b/app/mm-redux/store/mmkv_adapter.ts
new file mode 100644
index 000000000..2fe360a8e
--- /dev/null
+++ b/app/mm-redux/store/mmkv_adapter.ts
@@ -0,0 +1,142 @@
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
+
+/* eslint-disable no-console */
+
+import MMKV from 'react-native-mmkv-storage';
+
+type ReadOnlyArrayString = ReadonlyArray;
+
+type MultiGetCallbackFunction = (
+ errors: ReadonlyArray | null | undefined,
+ result: ReadonlyArray | null | undefined,
+) => void;
+
+type MultiRequest = {
+ keys: ReadonlyArray;
+ callback: MultiGetCallbackFunction | null | undefined;
+ keyIndex: number;
+ resolve: (
+ result?: Promise | null | undefined>,
+ ) => void | null | undefined;
+ reject: (error?: any) => void | null | undefined;
+};
+
+function checkValidInput(usedKey: string, value?: any) {
+ const isValuePassed = arguments.length > 1;
+
+ if (typeof usedKey !== 'string') {
+ console.warn(
+ `[MMKVStorageAdapter] Using ${typeof usedKey} type is not suppported. This can lead to unexpected behavior/errors. Use string instead.\nKey passed: ${usedKey}\n`,
+ );
+ }
+
+ if (isValuePassed && typeof value !== 'string') {
+ if (value == null) {
+ throw new Error(
+ `[MMKVStorageAdapter] Passing null/undefined as value is not supported. If you want to remove value, Use .remove method instead.\nPassed value: ${value}\nPassed key: ${usedKey}\n`,
+ );
+ } else {
+ console.warn(
+ `[MMKVStorageAdapter] The value for key "${usedKey}" is not a string. This can lead to unexpected behavior/errors. Consider stringifying it.\nPassed value: ${value}\nPassed key: ${usedKey}\n`,
+ );
+ }
+ }
+}
+
+const MMKVStorageAdapter = {
+ _getRequests: [] as Array,
+ _getKeys: [] as Array,
+ _immediate: null as number | null | undefined,
+
+ getItem: (
+ key: string,
+ callback?: (
+ error: Error | null | undefined,
+ result: string | null,
+ ) => void | null | undefined,
+ ): Promise => {
+ return new Promise((resolve, reject) => {
+ checkValidInput(key);
+ MMKV.getStringAsync(key).then((result: string) => {
+ if (callback) {
+ callback(null, result);
+ }
+ resolve(result);
+ }).catch((error) => {
+ if (callback) {
+ callback(null, error);
+ }
+
+ reject(error);
+ });
+ });
+ },
+
+ setItem: (
+ key: string,
+ value: string,
+ callback?: (
+ error: Error | null | undefined
+ ) => void | null | undefined,
+ ): Promise => {
+ return new Promise((resolve, reject) => {
+ checkValidInput(key, value);
+ MMKV.setStringAsync(key, value).then(() => {
+ if (callback) {
+ callback(null);
+ }
+ resolve(null);
+ }).catch((error) => {
+ if (callback) {
+ callback(error);
+ }
+ reject(error);
+ });
+ });
+ },
+
+ removeItem: (
+ key: string,
+ callback?: (
+ error: Error | null | undefined
+ ) => void | null | undefined,
+ ): Promise => {
+ checkValidInput(key);
+ if (callback) {
+ callback(null);
+ }
+ return MMKV.removeItem(key);
+ },
+
+ clear: (callback?: (error: Error | null | undefined) => void | null | undefined): Promise => {
+ if (callback) {
+ callback(null);
+ }
+
+ return MMKV.clearStore();
+ },
+
+ getAllKeys: (
+ callback?: (
+ error: Error | null | undefined,
+ keys: ReadOnlyArrayString | null | undefined
+ ) => void,
+ ): Promise => {
+ return new Promise((resolve, reject) => {
+ MMKV.getKeysAsync().then((keys: Array) => {
+ if (callback) {
+ callback(null, keys);
+ }
+ resolve(keys);
+ }).catch((error) => {
+ if (callback) {
+ callback(error, null);
+ }
+ reject(error);
+ });
+ });
+ },
+};
+
+export default MMKVStorageAdapter;
\ No newline at end of file
diff --git a/app/mm-redux/types/module.d.ts b/app/mm-redux/types/module.d.ts
index 3dd9c11aa..37097c51a 100644
--- a/app/mm-redux/types/module.d.ts
+++ b/app/mm-redux/types/module.d.ts
@@ -1,8 +1,6 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
declare module 'gfycat-sdk';
-declare module 'redux-offline';
-declare module 'redux-offline/lib/defaults';
declare module 'remote-redux-devtools';
declare module 'redux-persist';
declare module 'redux-persist/constants';
diff --git a/app/mm-redux/types/requests.ts b/app/mm-redux/types/requests.ts
index 5e25e17e5..a00ed204e 100644
--- a/app/mm-redux/types/requests.ts
+++ b/app/mm-redux/types/requests.ts
@@ -34,7 +34,6 @@ export type TeamsRequestsStatuses = {
export type UsersRequestsStatuses = {
checkMfa: RequestStatusType;
login: RequestStatusType;
- logout: RequestStatusType;
autocompleteUsers: RequestStatusType;
updateMe: RequestStatusType;
};
diff --git a/app/reducers/device/connection.js b/app/reducers/device/connection.js
index a25f75783..4164308e8 100644
--- a/app/reducers/device/connection.js
+++ b/app/reducers/device/connection.js
@@ -1,16 +1,12 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
-import {UserTypes} from '@mm-redux/action_types';
-import {DeviceTypes} from 'app/constants';
+import {DeviceTypes} from '@constants';
export default function connection(state = true, action) {
switch (action.type) {
case DeviceTypes.CONNECTION_CHANGED:
return action.data;
-
- case UserTypes.LOGOUT_SUCCESS:
- return true;
}
return state;
diff --git a/app/reducers/device/dimension.js b/app/reducers/device/dimension.js
index eea7ce361..66a06debe 100644
--- a/app/reducers/device/dimension.js
+++ b/app/reducers/device/dimension.js
@@ -3,8 +3,7 @@
import {Dimensions} from 'react-native';
-import {UserTypes} from '@mm-redux/action_types';
-import {DeviceTypes} from 'app/constants';
+import {DeviceTypes} from '@constants';
const {height, width} = Dimensions.get('window');
const initialState = {
@@ -21,8 +20,6 @@ export default function dimension(state = initialState, action) {
}
break;
}
- case UserTypes.LOGOUT_SUCCESS:
- return initialState;
}
return state;
diff --git a/app/reducers/index.js b/app/reducers/index.js
index 41af49601..d3acc0d17 100644
--- a/app/reducers/index.js
+++ b/app/reducers/index.js
@@ -3,12 +3,10 @@
import app from './app';
import device from './device';
-import navigation from './navigation';
import views from './views';
export default {
app,
device,
- navigation,
views,
};
diff --git a/app/reducers/navigation/index.js b/app/reducers/navigation/index.js
deleted file mode 100644
index 23b20ef1d..000000000
--- a/app/reducers/navigation/index.js
+++ /dev/null
@@ -1,18 +0,0 @@
-// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See LICENSE.txt for license information.
-
-import {NavigationTypes} from 'app/constants';
-import {UserTypes} from '@mm-redux/action_types';
-import EventEmitter from '@mm-redux/utils/event_emitter';
-
-export default function(state = '', action) {
- switch (action.type) {
- case UserTypes.LOGOUT_SUCCESS:
- setTimeout(() => {
- EventEmitter.emit(NavigationTypes.NAVIGATION_RESET);
- });
- break;
- }
-
- return state;
-}
diff --git a/app/reducers/views/announcement.js b/app/reducers/views/announcement.js
index e2be3726a..f5f2575e6 100644
--- a/app/reducers/views/announcement.js
+++ b/app/reducers/views/announcement.js
@@ -1,16 +1,12 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
-import {UserTypes} from '@mm-redux/action_types';
-
-import {ViewTypes} from 'app/constants';
+import {ViewTypes} from '@constants';
export default function banner(state = '', action) {
switch (action.type) {
case ViewTypes.ANNOUNCEMENT_BANNER:
return action.data;
- case UserTypes.LOGOUT_SUCCESS:
- return '';
default:
return state;
}
diff --git a/app/reducers/views/channel.js b/app/reducers/views/channel.js
index e365106bd..cc4dae997 100644
--- a/app/reducers/views/channel.js
+++ b/app/reducers/views/channel.js
@@ -2,15 +2,14 @@
// See LICENSE.txt for license information.
import {combineReducers} from 'redux';
+
+import {ViewTypes} from '@constants';
import {
ChannelTypes,
FileTypes,
PostTypes,
- UserTypes,
} from '@mm-redux/action_types';
-import {ViewTypes} from 'app/constants';
-
function displayName(state = '', action) {
switch (action.type) {
case ViewTypes.SET_CHANNEL_DISPLAY_NAME:
@@ -355,9 +354,6 @@ function keepChannelIdAsUnread(state = null, action) {
}
return state;
}
-
- case UserTypes.LOGOUT_SUCCESS:
- return null;
default:
return state;
}
diff --git a/app/reducers/views/emoji.js b/app/reducers/views/emoji.js
index f32a47a89..53c1ed208 100644
--- a/app/reducers/views/emoji.js
+++ b/app/reducers/views/emoji.js
@@ -2,16 +2,13 @@
// See LICENSE.txt for license information.
import {combineReducers} from 'redux';
-import {UserTypes} from '@mm-redux/action_types';
-import {ViewTypes} from 'app/constants';
+import {ViewTypes} from '@constants';
function emojiPickerCustomPage(state = 0, action) {
switch (action.type) {
case ViewTypes.INCREMENT_EMOJI_PICKER_PAGE:
return state + 1;
- case UserTypes.LOGOUT_SUCCESS:
- return 0;
default:
return state;
}
diff --git a/app/reducers/views/i18n.js b/app/reducers/views/i18n.js
index d64683e05..96f0ec830 100644
--- a/app/reducers/views/i18n.js
+++ b/app/reducers/views/i18n.js
@@ -14,8 +14,6 @@ function locale(state = defaultLocale, action) {
const data = action.data || action.payload;
return data.locale;
}
- case UserTypes.LOGOUT_SUCCESS:
- return defaultLocale;
}
return state;
diff --git a/app/reducers/views/post.js b/app/reducers/views/post.js
index 92bbcc96c..e805928b7 100644
--- a/app/reducers/views/post.js
+++ b/app/reducers/views/post.js
@@ -31,8 +31,6 @@ function submittedMenuActions(state = {}, action) {
return nextState;
}
- case UserTypes.LOGOUT_SUCCESS:
- return {};
default:
return state;
}
diff --git a/app/reducers/views/search.js b/app/reducers/views/search.js
index a4645cc70..a5ac96802 100644
--- a/app/reducers/views/search.js
+++ b/app/reducers/views/search.js
@@ -1,16 +1,13 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
-import {ViewTypes} from 'app/constants';
-import {UserTypes} from '@mm-redux/action_types';
+import {ViewTypes} from '@constants';
export default function search(state = '', action) {
switch (action.type) {
case ViewTypes.SEARCH_DRAFT_CHANGED: {
return action.text;
}
- case UserTypes.LOGOUT_SUCCESS:
- return '';
default:
return state;
diff --git a/app/store/index.js b/app/store/index.js
index ec5b0c483..1d32a81cd 100644
--- a/app/store/index.js
+++ b/app/store/index.js
@@ -4,6 +4,7 @@
import initialState from 'app/initial_state';
import configureAppStore from './store';
-const store = configureAppStore(initialState);
+const {store, persistor} = configureAppStore(initialState);
+export {persistor};
export default store;
diff --git a/app/store/middleware.js b/app/store/middleware.js
index 2b6c86152..75c624d2c 100644
--- a/app/store/middleware.js
+++ b/app/store/middleware.js
@@ -3,22 +3,14 @@
import {Platform} from 'react-native';
import DeviceInfo from 'react-native-device-info';
-import {batchActions} from 'redux-batched-actions';
-import AsyncStorage from '@react-native-community/async-storage';
-import {purgeStoredState} from 'redux-persist';
+import {REHYDRATE} from 'redux-persist';
-import {NavigationTypes, ViewTypes} from 'app/constants';
+import {ViewTypes} from 'app/constants';
import initialState from 'app/initial_state';
import {throttle} from 'app/utils/general';
-import {General} from '@mm-redux/constants';
-import {ErrorTypes, GeneralTypes} from '@mm-redux/action_types';
-import EventEmitter from '@mm-redux/utils/event_emitter';
-
import mattermostBucket from 'app/mattermost_bucket';
-import {getStateForReset} from './utils';
-
import {
captureException,
LOGGER_JAVASCRIPT_WARNING,
@@ -35,115 +27,92 @@ const SAVE_STATE_ACTIONS = [
'WEBSOCKET_SUCCESS',
];
+export const middlewares = () => {
+ const middlewareFunctions = [
+ messageRetention,
+ ];
+
+ if (Platform.OS === 'ios') {
+ middlewareFunctions.push(saveShareExtensionState);
+ }
+
+ return middlewareFunctions;
+};
+
// This middleware stores key parts of state entities into a file (in the App Group container) on certain actions.
// iOS only. Allows the share extension to work, without having access available to the redux store object.
// Remove this middleware if/when state is moved to a persisted solution.
-const saveShareExtensionState = (store) => {
+function saveShareExtensionState(store) {
return (next) => (action) => {
if (SAVE_STATE_ACTIONS.includes(action.type)) {
throttle(saveStateToFile(store));
}
return next(action);
};
-};
+}
-const saveStateToFile = async (store) => {
- if (Platform.OS === 'ios') {
- const state = store.getState();
+async function saveStateToFile(store) {
+ const state = store.getState();
- if (state.entities) {
- const channelsInTeam = {...state.entities.channels.channelsInTeam};
- Object.keys(channelsInTeam).forEach((teamId) => {
- channelsInTeam[teamId] = Array.from(channelsInTeam[teamId]);
- });
+ if (state.entities) {
+ const channelsInTeam = {...state.entities.channels.channelsInTeam};
+ Object.keys(channelsInTeam).forEach((teamId) => {
+ channelsInTeam[teamId] = Array.from(channelsInTeam[teamId]);
+ });
- const profilesInChannel = {...state.entities.users.profilesInChannel};
- Object.keys(profilesInChannel).forEach((channelId) => {
- profilesInChannel[channelId] = Array.from(profilesInChannel[channelId]);
- });
+ const profilesInChannel = {...state.entities.users.profilesInChannel};
+ Object.keys(profilesInChannel).forEach((channelId) => {
+ profilesInChannel[channelId] = Array.from(profilesInChannel[channelId]);
+ });
- let url;
- if (state.entities.users.currentUserId) {
- url = state.entities.general.credentials.url || state.views.selectServer.serverUrl;
+ let url;
+ if (state.entities.users.currentUserId) {
+ url = state.entities.general.credentials.url || state.views.selectServer.serverUrl;
+ }
+
+ const entities = {
+ ...state.entities,
+ general: {
+ ...state.entities.general,
+ credentials: {
+ url,
+ },
+ },
+ channels: {
+ ...state.entities.channels,
+ channelsInTeam,
+ },
+ users: {
+ ...state.entities.users,
+ profilesInChannel,
+ profilesNotInTeam: [],
+ profilesWithoutTeam: [],
+ profilesNotInChannel: [],
+ },
+ };
+
+ mattermostBucket.writeToFile('entities', JSON.stringify(entities));
+ }
+}
+
+function messageRetention(store) {
+ return (next) => (action) => {
+ if (action.type === REHYDRATE) {
+ // On first run payload is not set (when installed)
+ if (!action.payload) {
+ action.payload = {
+ app: {
+ build: DeviceInfo.getBuildNumber(),
+ version: DeviceInfo.getVersion(),
+ },
+ views: {
+ root: {
+ hydrationComplete: true,
+ },
+ },
+ };
}
- const entities = {
- ...state.entities,
- general: {
- ...state.entities.general,
- credentials: {
- url,
- },
- },
- channels: {
- ...state.entities.channels,
- channelsInTeam,
- },
- users: {
- ...state.entities.users,
- profilesInChannel,
- profilesNotInTeam: [],
- profilesWithoutTeam: [],
- profilesNotInChannel: [],
- },
- };
-
- mattermostBucket.writeToFile('entities', JSON.stringify(entities));
- }
- }
-};
-
-const purgeAppCacheWrapper = (persistConfig) => (store) => {
- return (next) => (action) => {
- if (action.type === General.OFFLINE_STORE_PURGE) {
- purgeStoredState({...persistConfig, storage: AsyncStorage});
-
- const state = store.getState();
- const resetState = getStateForReset(initialState, state);
-
- store.dispatch(batchActions([
- {
- type: General.OFFLINE_STORE_RESET,
- data: resetState,
- },
- {
- type: ErrorTypes.RESTORE_ERRORS,
- data: [...state.errors],
- },
- {
- type: GeneralTypes.RECEIVED_APP_DEVICE_TOKEN,
- data: state.entities.general.deviceToken,
- },
- {
- type: GeneralTypes.RECEIVED_APP_CREDENTIALS,
- data: {
- url: state.entities.general.credentials.url,
- },
- },
- {
- type: ViewTypes.SERVER_URL_CHANGED,
- serverUrl: state.entities.general.credentials.url || state.views.selectServer.serverUrl,
- },
- {
- type: GeneralTypes.RECEIVED_SERVER_VERSION,
- data: state.entities.general.serverVersion,
- },
- {
- type: General.STORE_REHYDRATION_COMPLETE,
- },
- ], 'BATCH_FOR_RESTART'));
-
- setTimeout(() => {
- EventEmitter.emit(NavigationTypes.RESTART_APP);
- }, 500);
- }
- return next(action);
- };
-};
-
-const messageRetention = (store) => {
- return (next) => (action) => {
- if (action.type === 'persist/REHYDRATE') {
const {app} = action.payload;
const {entities, views} = action.payload;
@@ -153,25 +122,24 @@ const messageRetention = (store) => {
// When a new version of the app has been detected
if (!app || !app.version || app.version !== DeviceInfo.getVersion() || app.build !== DeviceInfo.getBuildNumber()) {
- return next(resetStateForNewVersion(action));
+ action.payload = resetStateForNewVersion(action.payload);
+ return next(action);
}
// Keep only the last 60 messages for the last 5 viewed channels in each team
// and apply data retention on those posts if applies
- let nextAction;
try {
- nextAction = cleanUpState(action);
+ action.payload = cleanUpState(action.payload);
} catch (e) {
// Sometimes, the payload is incomplete so log the error to Sentry and skip the cleanup
console.warn(e); // eslint-disable-line no-console
captureException(e, LOGGER_JAVASCRIPT_WARNING, store);
- nextAction = action;
}
- return next(nextAction);
+ return next(action);
} else if (action.type === ViewTypes.DATA_CLEANUP) {
- const nextAction = cleanUpState(action, true);
- return next(nextAction);
+ action.payload = cleanUpState(action.payload, true);
+ return next(action);
}
/* Uncomment the following lines to log the actions being dispatched */
@@ -185,10 +153,9 @@ const messageRetention = (store) => {
return next(action);
};
-};
+}
-function resetStateForNewVersion(action) {
- const {payload} = action;
+function resetStateForNewVersion(payload) {
const lastChannelForTeam = getLastChannelForTeam(payload);
let general = initialState.entities.general;
@@ -317,29 +284,28 @@ function resetStateForNewVersion(action) {
},
};
- return {
- type: action.type,
- payload: nextState,
- error: action.error,
- };
+ return nextState;
}
function getLastChannelForTeam(payload) {
- const lastChannelForTeam = {...payload.views.team.lastChannelForTeam};
- const convertLastChannelForTeam = Object.values(lastChannelForTeam).some((value) => !Array.isArray(value));
+ if (payload?.views?.team?.lastChannelForTeam) {
+ const lastChannelForTeam = {...payload.views.team.lastChannelForTeam};
+ const convertLastChannelForTeam = Object.values(lastChannelForTeam).some((value) => !Array.isArray(value));
- if (convertLastChannelForTeam) {
- Object.keys(lastChannelForTeam).forEach((id) => {
- lastChannelForTeam[id] = [lastChannelForTeam[id]];
- });
+ if (convertLastChannelForTeam) {
+ Object.keys(lastChannelForTeam).forEach((id) => {
+ lastChannelForTeam[id] = [lastChannelForTeam[id]];
+ });
+ }
+
+ return lastChannelForTeam;
}
- return lastChannelForTeam;
+ return {};
}
-export function cleanUpState(action, keepCurrent = false) {
- const {payload: resetPayload} = resetStateForNewVersion(action);
- const {payload} = action;
+export function cleanUpState(payload, keepCurrent = false) {
+ const resetPayload = resetStateForNewVersion(payload);
const {currentChannelId} = payload.entities.channels;
const {lastChannelForTeam} = resetPayload.views.team;
@@ -470,6 +436,9 @@ export function cleanUpState(action, keepCurrent = false) {
...resetPayload.views.channel,
...payload.views.channel,
},
+ root: {
+ hydrationComplete: true,
+ },
},
websocket: {
lastConnectAt: payload.websocket?.lastConnectAt,
@@ -479,11 +448,7 @@ export function cleanUpState(action, keepCurrent = false) {
nextState.errors = payload.errors;
- return {
- type: action.type,
- payload: nextState,
- error: action.error,
- };
+ return nextState;
}
// cleanUpPostsInChannel returns a copy of postsInChannel where only the most recent posts in each channel are kept
@@ -564,17 +529,3 @@ function removePendingPost(pendingPostIds, id) {
pendingPostIds.splice(pendingIndex, 1);
}
}
-
-export const middlewares = (persistConfig) => {
- const middlewareFunctions = [
- messageRetention,
- purgeAppCacheWrapper(persistConfig),
- ];
-
- if (Platform.OS === 'ios') {
- middlewareFunctions.push(saveShareExtensionState);
- }
-
- return middlewareFunctions;
-};
-
diff --git a/app/store/middleware.test.js b/app/store/middleware.test.js
index 38f38668a..c02db6a5d 100644
--- a/app/store/middleware.test.js
+++ b/app/store/middleware.test.js
@@ -102,13 +102,13 @@ describe('cleanUpState', () => {
},
};
- const result = cleanUpState({payload: state});
+ const result = cleanUpState(state);
- expect(result.payload.entities.posts.posts.post1).toBeDefined();
- expect(result.payload.entities.posts.posts.post2).toBeUndefined();
- expect(result.payload.entities.posts.postsInChannel.channel1).toEqual([{order: ['post1'], recent: true}]);
- expect(result.payload.entities.search.results).toEqual(['post1', 'post2']);
- expect(result.payload.entities.search.flagged).toEqual(['post1', 'post2', 'post3']);
+ expect(result.entities.posts.posts.post1).toBeDefined();
+ expect(result.entities.posts.posts.post2).toBeUndefined();
+ expect(result.entities.posts.postsInChannel.channel1).toEqual([{order: ['post1'], recent: true}]);
+ expect(result.entities.search.results).toEqual(['post1', 'post2']);
+ expect(result.entities.search.flagged).toEqual(['post1', 'post2', 'post3']);
});
test('should keep failed pending post', () => {
@@ -145,11 +145,11 @@ describe('cleanUpState', () => {
},
};
- const result = cleanUpState({payload: state});
+ const result = cleanUpState(state);
- expect(result.payload.entities.posts.pendingPostIds).toEqual(['pending']);
- expect(result.payload.entities.posts.posts.pending).toBeDefined();
- expect(result.payload.entities.posts.postsInChannel.channel1).toEqual([{order: ['pending', 'post1', 'post2'], recent: true}]);
+ expect(result.entities.posts.pendingPostIds).toEqual(['pending']);
+ expect(result.entities.posts.posts.pending).toBeDefined();
+ expect(result.entities.posts.postsInChannel.channel1).toEqual([{order: ['pending', 'post1', 'post2'], recent: true}]);
});
test('should remove non-failed pending post', () => {
@@ -186,11 +186,11 @@ describe('cleanUpState', () => {
},
};
- const result = cleanUpState({payload: state});
+ const result = cleanUpState(state);
- expect(result.payload.entities.posts.pendingPostIds).toEqual([]);
- expect(result.payload.entities.posts.posts.pending).toBeUndefined();
- expect(result.payload.entities.posts.postsInChannel.channel1).toEqual([{order: ['post1', 'post2'], recent: true}]);
+ expect(result.entities.posts.pendingPostIds).toEqual([]);
+ expect(result.entities.posts.posts.pending).toBeUndefined();
+ expect(result.entities.posts.postsInChannel.channel1).toEqual([{order: ['post1', 'post2'], recent: true}]);
});
test('should remove non-existent pending post', () => {
@@ -226,10 +226,10 @@ describe('cleanUpState', () => {
},
};
- const result = cleanUpState({payload: state});
+ const result = cleanUpState(state);
- expect(result.payload.entities.posts.pendingPostIds).toEqual([]);
- expect(result.payload.entities.posts.postsInChannel.channel1).toEqual([{order: ['post1', 'post2'], recent: true}]);
+ expect(result.entities.posts.pendingPostIds).toEqual([]);
+ expect(result.entities.posts.postsInChannel.channel1).toEqual([{order: ['post1', 'post2'], recent: true}]);
});
});
diff --git a/app/store/store.js b/app/store/store.js
index fbab8f025..9c34b51b6 100644
--- a/app/store/store.js
+++ b/app/store/store.js
@@ -1,26 +1,21 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
-import AsyncStorage from '@react-native-community/async-storage';
import {createBlacklistFilter} from 'redux-persist-transform-filter';
-import {createTransform, persistStore} from 'redux-persist';
+import {createTransform} from 'redux-persist';
+import reduxReset from 'redux-reset';
import {General} from '@mm-redux/constants';
-import {getConfig} from '@mm-redux/selectors/entities/general';
import configureStore from '@mm-redux/store';
+import MMKVStorageAdapter from '@mm-redux/store/mmkv_adapter';
import appReducer from 'app/reducers';
-import {getSiteUrl, setSiteUrl} from 'app/utils/image_cache_manager';
import {createSentryMiddleware} from 'app/utils/sentry/middleware';
import {middlewares} from './middleware';
import {createThunkMiddleware} from './thunk';
import {transformSet} from './utils';
-function getAppReducer() {
- return require('../../app/reducers'); // eslint-disable-line global-require
-}
-
const usersSetTransform = [
'profilesInChannel',
'profilesNotInChannel',
@@ -56,8 +51,9 @@ const channelViewBlackList = {loading: true, refreshing: true, loadingPosts: tru
const channelViewBlackListFilter = createTransform(
(inboundState) => {
const channel = {};
+ const keys = inboundState.channel ? Object.keys(inboundState.channel) : [];
- for (const channelKey of Object.keys(inboundState.channel)) {
+ for (const channelKey of keys) {
if (!channelViewBlackList[channelKey]) {
channel[channelKey] = inboundState.channel[channelKey];
}
@@ -76,8 +72,9 @@ const emojiBlackList = {nonExistentEmoji: true};
const emojiBlackListFilter = createTransform(
(inboundState) => {
const emojis = {};
+ const keys = inboundState.emojis ? Object.keys(inboundState.emojis) : [];
- for (const emojiKey of Object.keys(inboundState.emojis)) {
+ for (const emojiKey of keys) {
if (!emojiBlackList[emojiKey]) {
emojis[emojiKey] = inboundState.emojis[emojiKey];
}
@@ -124,47 +121,16 @@ const setTransformer = createTransform(
);
const persistConfig = {
- effect: (effect, action) => {
- if (typeof effect !== 'function') {
- throw new Error('Offline Action: effect must be a function.');
- } else if (!action.meta.offline.commit) {
- throw new Error('Offline Action: commit action must be present.');
- }
-
- return effect();
- },
- persist: (store, options) => {
- const persistor = persistStore(store, {storage: AsyncStorage, ...options}, () => {
- store.dispatch({
- type: General.STORE_REHYDRATION_COMPLETE,
- });
- });
-
- store.subscribe(async () => {
- const state = store.getState();
- const config = getConfig(state);
-
- if (getSiteUrl() !== config?.SiteURL) {
- setSiteUrl(config.SiteURL);
- }
- });
-
- return persistor;
- },
- persistOptions: {
- autoRehydrate: {
- log: false,
- },
- blacklist: ['device', 'navigation', 'offline', 'requests'],
- debounce: 500,
- transforms: [
- setTransformer,
- viewsBlackListFilter,
- typingBlackListFilter,
- channelViewBlackListFilter,
- emojiBlackListFilter,
- ],
- },
+ key: 'root',
+ storage: MMKVStorageAdapter,
+ blacklist: ['device', 'navigation', 'offline', 'requests'],
+ transforms: [
+ setTransformer,
+ viewsBlackListFilter,
+ typingBlackListFilter,
+ channelViewBlackListFilter,
+ emojiBlackListFilter,
+ ],
};
export default function configureAppStore(initialState) {
@@ -172,10 +138,11 @@ export default function configureAppStore(initialState) {
additionalMiddleware: [
createThunkMiddleware(),
createSentryMiddleware(),
- ...middlewares(persistConfig),
+ ...middlewares(),
],
enableThunk: false, // We override the default thunk middleware
+ enhancers: [reduxReset(General.OFFLINE_STORE_PURGE)],
};
- return configureStore(initialState, appReducer, persistConfig, getAppReducer, clientOptions);
+ return configureStore(initialState, appReducer, persistConfig, clientOptions);
}
diff --git a/app/store/utils.js b/app/store/utils.js
index 355616899..e9f43a10c 100644
--- a/app/store/utils.js
+++ b/app/store/utils.js
@@ -45,14 +45,14 @@ export function transformSet(incoming, setTransforms, toStorage = true) {
export function waitForHydration(store, callback) {
let executed = false; // this is to prevent a race condition when subcription runs before unsubscribed
- if (store.getState().views.root.hydrationComplete && !executed) {
+ if (store.getState().views?.root?.hydrationComplete && !executed) {
if (callback && typeof callback === 'function') {
executed = true;
callback();
}
} else {
const subscription = () => {
- if (store.getState().views.root.hydrationComplete && !executed) {
+ if (store.getState().views?.root?.hydrationComplete && !executed) {
unsubscribeFromStore();
if (callback && typeof callback === 'function') {
executed = true;
@@ -73,6 +73,7 @@ export function getStateForReset(initialState, currentState) {
const resetState = merge(initialState, {
entities: {
+ general: currentState.entities.general,
users: {
currentUserId,
profiles: {
@@ -84,6 +85,15 @@ export function getStateForReset(initialState, currentState) {
},
preferences,
},
+ errors: currentState.errors,
+ views: {
+ selectServer: {
+ serverUrl: currentState.views?.selectServer?.serverUrl,
+ },
+ root: {
+ hydrationComplete: true,
+ },
+ },
});
return resetState;
diff --git a/app/store/utils.test.js b/app/store/utils.test.js
index a055a8dad..0ab1b163c 100644
--- a/app/store/utils.test.js
+++ b/app/store/utils.test.js
@@ -52,6 +52,11 @@ describe('getStateForReset', () => {
},
},
},
+ views: {
+ selectServer: {
+ serverUrl: 'localhost:8065',
+ },
+ },
};
it('should keep the current user\'s ID and profile', () => {
diff --git a/app/utils/push_notifications.js b/app/utils/push_notifications.js
index 1cb556463..c455161b3 100644
--- a/app/utils/push_notifications.js
+++ b/app/utils/push_notifications.js
@@ -80,13 +80,9 @@ class PushNotificationUtils {
if (foreground) {
EventEmitter.emit(ViewTypes.NOTIFICATION_IN_APP, notification);
} else if (userInteraction && !notification?.data?.localNotification) {
- if (getState().views.root.hydrationComplete) { //TODO: Replace when realm is ready
+ waitForHydration(this.store, () => {
this.loadFromNotification(notification);
- } else {
- waitForHydration(this.store, () => {
- this.loadFromNotification(notification);
- });
- }
+ });
}
}
};
diff --git a/babel.config.js b/babel.config.js
index c72284af0..632bec942 100644
--- a/babel.config.js
+++ b/babel.config.js
@@ -15,6 +15,7 @@ module.exports = {
assets: './dist/assets',
'@actions': './app/actions',
'@constants': './app/constants',
+ '@i18n': './app/i18n',
'@selectors': './app/selectors',
'@telemetry': './app/telemetry',
'@utils': './app/utils',
diff --git a/ios/Podfile.lock b/ios/Podfile.lock
index 61fb8529d..968b1f9d4 100644
--- a/ios/Podfile.lock
+++ b/ios/Podfile.lock
@@ -32,6 +32,7 @@ PODS:
- libwebp/mux (1.1.0):
- libwebp/demux
- libwebp/webp (1.1.0)
+ - MMKV (1.0.24)
- Permission-Camera (2.0.10):
- RNPermissions
- Permission-PhotoLibrary (2.0.10):
@@ -212,6 +213,9 @@ PODS:
- React
- react-native-image-picker (2.3.1):
- React
+ - react-native-mmkv-storage (0.2.2):
+ - MMKV (= 1.0.24)
+ - React
- react-native-netinfo (4.4.0):
- React
- react-native-notifications (2.0.6):
@@ -338,6 +342,7 @@ DEPENDENCIES:
- react-native-document-picker (from `../node_modules/react-native-document-picker`)
- react-native-hw-keyboard-event (from `../node_modules/react-native-hw-keyboard-event`)
- react-native-image-picker (from `../node_modules/react-native-image-picker`)
+ - react-native-mmkv-storage (from `../node_modules/react-native-mmkv-storage`)
- "react-native-netinfo (from `../node_modules/@react-native-community/netinfo`)"
- react-native-notifications (from `../node_modules/react-native-notifications`)
- react-native-passcode-status (from `../node_modules/react-native-passcode-status`)
@@ -378,6 +383,7 @@ SPEC REPOS:
https://github.com/cocoapods/specs.git:
- boost-for-react-native
- libwebp
+ - MMKV
- SDWebImage
- SDWebImageWebPCoder
- Sentry
@@ -434,6 +440,8 @@ EXTERNAL SOURCES:
:path: "../node_modules/react-native-hw-keyboard-event"
react-native-image-picker:
:path: "../node_modules/react-native-image-picker"
+ react-native-mmkv-storage:
+ :path: "../node_modules/react-native-mmkv-storage"
react-native-netinfo:
:path: "../node_modules/@react-native-community/netinfo"
react-native-notifications:
@@ -509,6 +517,7 @@ SPEC CHECKSUMS:
glog: 1f3da668190260b06b429bb211bfbee5cd790c28
jail-monkey: d7c5048b2336f22ee9c9e0efa145f1f917338ea9
libwebp: 946cb3063cea9236285f7e9a8505d806d30e07f3
+ MMKV: 758b2edee46b08bdd958db4169191afb9a6d4ebd
Permission-Camera: 8f0e5decca5f28f70f28a8dc31f012c9bad40ad8
Permission-PhotoLibrary: b209bf23b784c9e1409a57d81c6d11ab1d3079c1
RCTRequired: b153add4da6e7dbc44aebf93f3cf4fcae392ddf1
@@ -526,6 +535,7 @@ SPEC CHECKSUMS:
react-native-document-picker: 0573c02d742d4bef38a5d16b5f039754cfa69888
react-native-hw-keyboard-event: b517cefb8d5c659a38049c582de85ff43337dc53
react-native-image-picker: 668e72d0277dc8c12ae90e835507c1eddd2e4f85
+ react-native-mmkv-storage: 84162ebe353ecf7476d235c47becade29789ae2c
react-native-netinfo: 892a5130be97ff8bb69c523739c424a2ffc296d1
react-native-notifications: d5cb54ef8bf3004dcb56c887650dea08ecbddee7
react-native-passcode-status: 88c4f6e074328bc278bd127646b6c694ad5a530a
diff --git a/package-lock.json b/package-lock.json
index a9275264d..076df787d 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -6896,16 +6896,6 @@
"node-int64": "^0.4.0"
}
},
- "buffer": {
- "version": "5.4.3",
- "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.4.3.tgz",
- "integrity": "sha512-zvj65TkFeIt3i6aj5bIvJDzjjQQGs4o/sNoezg1F1kYap9Nu2jcUdpwzRSJTHMMzG0H7bZkn4rNQpImhuxWX2A==",
- "dev": true,
- "requires": {
- "base64-js": "^1.0.2",
- "ieee754": "^1.1.4"
- }
- },
"buffer-crc32": {
"version": "0.2.13",
"resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz",
@@ -7158,12 +7148,6 @@
}
}
},
- "clone": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.1.tgz",
- "integrity": "sha1-0hfR6WERjjrJpLi7oyhVU79kfNs=",
- "dev": true
- },
"co": {
"version": "4.6.0",
"resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
@@ -7266,9 +7250,9 @@
},
"dependencies": {
"minimist": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
- "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ="
+ "version": "1.2.5",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
+ "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw=="
}
}
},
@@ -9801,25 +9785,25 @@
"dependencies": {
"abbrev": {
"version": "1.1.1",
- "resolved": "",
+ "resolved": false,
"integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==",
"optional": true
},
"ansi-regex": {
"version": "2.1.1",
- "resolved": "",
+ "resolved": false,
"integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
"optional": true
},
"aproba": {
"version": "1.2.0",
- "resolved": "",
+ "resolved": false,
"integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==",
"optional": true
},
"are-we-there-yet": {
"version": "1.1.5",
- "resolved": "",
+ "resolved": false,
"integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==",
"optional": true,
"requires": {
@@ -9829,13 +9813,13 @@
},
"balanced-match": {
"version": "1.0.0",
- "resolved": "",
+ "resolved": false,
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
"optional": true
},
"brace-expansion": {
"version": "1.1.11",
- "resolved": "",
+ "resolved": false,
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"optional": true,
"requires": {
@@ -9845,37 +9829,37 @@
},
"chownr": {
"version": "1.1.1",
- "resolved": "",
+ "resolved": false,
"integrity": "sha512-j38EvO5+LHX84jlo6h4UzmOwi0UgW61WRyPtJz4qaadK5eY3BTS5TY/S1Stc3Uk2lIM6TPevAlULiEJwie860g==",
"optional": true
},
"code-point-at": {
"version": "1.1.0",
- "resolved": "",
+ "resolved": false,
"integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=",
"optional": true
},
"concat-map": {
"version": "0.0.1",
- "resolved": "",
+ "resolved": false,
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
"optional": true
},
"console-control-strings": {
"version": "1.1.0",
- "resolved": "",
+ "resolved": false,
"integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=",
"optional": true
},
"core-util-is": {
"version": "1.0.2",
- "resolved": "",
+ "resolved": false,
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
"optional": true
},
"debug": {
"version": "4.1.1",
- "resolved": "",
+ "resolved": false,
"integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
"optional": true,
"requires": {
@@ -9884,25 +9868,25 @@
},
"deep-extend": {
"version": "0.6.0",
- "resolved": "",
+ "resolved": false,
"integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==",
"optional": true
},
"delegates": {
"version": "1.0.0",
- "resolved": "",
+ "resolved": false,
"integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=",
"optional": true
},
"detect-libc": {
"version": "1.0.3",
- "resolved": "",
+ "resolved": false,
"integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=",
"optional": true
},
"fs-minipass": {
"version": "1.2.5",
- "resolved": "",
+ "resolved": false,
"integrity": "sha512-JhBl0skXjUPCFH7x6x61gQxrKyXsxB5gcgePLZCwfyCGGsTISMoIeObbrvVeP6Xmyaudw4TT43qV2Gz+iyd2oQ==",
"optional": true,
"requires": {
@@ -9911,13 +9895,13 @@
},
"fs.realpath": {
"version": "1.0.0",
- "resolved": "",
+ "resolved": false,
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
"optional": true
},
"gauge": {
"version": "2.7.4",
- "resolved": "",
+ "resolved": false,
"integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=",
"optional": true,
"requires": {
@@ -9933,7 +9917,7 @@
},
"glob": {
"version": "7.1.3",
- "resolved": "",
+ "resolved": false,
"integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==",
"optional": true,
"requires": {
@@ -9947,13 +9931,13 @@
},
"has-unicode": {
"version": "2.0.1",
- "resolved": "",
+ "resolved": false,
"integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=",
"optional": true
},
"iconv-lite": {
"version": "0.4.24",
- "resolved": "",
+ "resolved": false,
"integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
"optional": true,
"requires": {
@@ -9962,7 +9946,7 @@
},
"ignore-walk": {
"version": "3.0.1",
- "resolved": "",
+ "resolved": false,
"integrity": "sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ==",
"optional": true,
"requires": {
@@ -9971,7 +9955,7 @@
},
"inflight": {
"version": "1.0.6",
- "resolved": "",
+ "resolved": false,
"integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
"optional": true,
"requires": {
@@ -9981,19 +9965,19 @@
},
"inherits": {
"version": "2.0.3",
- "resolved": "",
+ "resolved": false,
"integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
"optional": true
},
"ini": {
"version": "1.3.5",
- "resolved": "",
+ "resolved": false,
"integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==",
"optional": true
},
"is-fullwidth-code-point": {
"version": "1.0.0",
- "resolved": "",
+ "resolved": false,
"integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
"optional": true,
"requires": {
@@ -10002,13 +9986,13 @@
},
"isarray": {
"version": "1.0.0",
- "resolved": "",
+ "resolved": false,
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
"optional": true
},
"minimatch": {
"version": "3.0.4",
- "resolved": "",
+ "resolved": false,
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
"optional": true,
"requires": {
@@ -10017,13 +10001,13 @@
},
"minimist": {
"version": "0.0.8",
- "resolved": "",
+ "resolved": false,
"integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=",
"optional": true
},
"minipass": {
"version": "2.3.5",
- "resolved": "",
+ "resolved": false,
"integrity": "sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA==",
"optional": true,
"requires": {
@@ -10033,7 +10017,7 @@
},
"minizlib": {
"version": "1.2.1",
- "resolved": "",
+ "resolved": false,
"integrity": "sha512-7+4oTUOWKg7AuL3vloEWekXY2/D20cevzsrNT2kGWm+39J9hGTCBv8VI5Pm5lXZ/o3/mdR4f8rflAPhnQb8mPA==",
"optional": true,
"requires": {
@@ -10042,7 +10026,7 @@
},
"mkdirp": {
"version": "0.5.1",
- "resolved": "",
+ "resolved": false,
"integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
"optional": true,
"requires": {
@@ -10051,13 +10035,13 @@
},
"ms": {
"version": "2.1.1",
- "resolved": "",
+ "resolved": false,
"integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==",
"optional": true
},
"needle": {
"version": "2.3.0",
- "resolved": "",
+ "resolved": false,
"integrity": "sha512-QBZu7aAFR0522EyaXZM0FZ9GLpq6lvQ3uq8gteiDUp7wKdy0lSd2hPlgFwVuW1CBkfEs9PfDQsQzZghLs/psdg==",
"optional": true,
"requires": {
@@ -10068,7 +10052,7 @@
},
"node-pre-gyp": {
"version": "0.12.0",
- "resolved": "",
+ "resolved": false,
"integrity": "sha512-4KghwV8vH5k+g2ylT+sLTjy5wmUOb9vPhnM8NHvRf9dHmnW/CndrFXy2aRPaPST6dugXSdHXfeaHQm77PIz/1A==",
"optional": true,
"requires": {
@@ -10086,7 +10070,7 @@
},
"nopt": {
"version": "4.0.1",
- "resolved": "",
+ "resolved": false,
"integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=",
"optional": true,
"requires": {
@@ -10096,13 +10080,13 @@
},
"npm-bundled": {
"version": "1.0.6",
- "resolved": "",
+ "resolved": false,
"integrity": "sha512-8/JCaftHwbd//k6y2rEWp6k1wxVfpFzB6t1p825+cUb7Ym2XQfhwIC5KwhrvzZRJu+LtDE585zVaS32+CGtf0g==",
"optional": true
},
"npm-packlist": {
"version": "1.4.1",
- "resolved": "",
+ "resolved": false,
"integrity": "sha512-+TcdO7HJJ8peiiYhvPxsEDhF3PJFGUGRcFsGve3vxvxdcpO2Z4Z7rkosRM0kWj6LfbK/P0gu3dzk5RU1ffvFcw==",
"optional": true,
"requires": {
@@ -10112,7 +10096,7 @@
},
"npmlog": {
"version": "4.1.2",
- "resolved": "",
+ "resolved": false,
"integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==",
"optional": true,
"requires": {
@@ -10124,19 +10108,19 @@
},
"number-is-nan": {
"version": "1.0.1",
- "resolved": "",
+ "resolved": false,
"integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=",
"optional": true
},
"object-assign": {
"version": "4.1.1",
- "resolved": "",
+ "resolved": false,
"integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
"optional": true
},
"once": {
"version": "1.4.0",
- "resolved": "",
+ "resolved": false,
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
"optional": true,
"requires": {
@@ -10145,19 +10129,19 @@
},
"os-homedir": {
"version": "1.0.2",
- "resolved": "",
+ "resolved": false,
"integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=",
"optional": true
},
"os-tmpdir": {
"version": "1.0.2",
- "resolved": "",
+ "resolved": false,
"integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=",
"optional": true
},
"osenv": {
"version": "0.1.5",
- "resolved": "",
+ "resolved": false,
"integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==",
"optional": true,
"requires": {
@@ -10167,19 +10151,19 @@
},
"path-is-absolute": {
"version": "1.0.1",
- "resolved": "",
+ "resolved": false,
"integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
"optional": true
},
"process-nextick-args": {
"version": "2.0.0",
- "resolved": "",
+ "resolved": false,
"integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==",
"optional": true
},
"rc": {
"version": "1.2.8",
- "resolved": "",
+ "resolved": false,
"integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==",
"optional": true,
"requires": {
@@ -10199,7 +10183,7 @@
},
"readable-stream": {
"version": "2.3.6",
- "resolved": "",
+ "resolved": false,
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
"optional": true,
"requires": {
@@ -10214,7 +10198,7 @@
},
"rimraf": {
"version": "2.6.3",
- "resolved": "",
+ "resolved": false,
"integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==",
"optional": true,
"requires": {
@@ -10223,43 +10207,43 @@
},
"safe-buffer": {
"version": "5.1.2",
- "resolved": "",
+ "resolved": false,
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
"optional": true
},
"safer-buffer": {
"version": "2.1.2",
- "resolved": "",
+ "resolved": false,
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
"optional": true
},
"sax": {
"version": "1.2.4",
- "resolved": "",
+ "resolved": false,
"integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==",
"optional": true
},
"semver": {
"version": "5.7.0",
- "resolved": "",
+ "resolved": false,
"integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==",
"optional": true
},
"set-blocking": {
"version": "2.0.0",
- "resolved": "",
+ "resolved": false,
"integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=",
"optional": true
},
"signal-exit": {
"version": "3.0.2",
- "resolved": "",
+ "resolved": false,
"integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=",
"optional": true
},
"string-width": {
"version": "1.0.2",
- "resolved": "",
+ "resolved": false,
"integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
"optional": true,
"requires": {
@@ -10270,7 +10254,7 @@
},
"string_decoder": {
"version": "1.1.1",
- "resolved": "",
+ "resolved": false,
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
"optional": true,
"requires": {
@@ -10279,7 +10263,7 @@
},
"strip-ansi": {
"version": "3.0.1",
- "resolved": "",
+ "resolved": false,
"integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
"optional": true,
"requires": {
@@ -10288,13 +10272,13 @@
},
"strip-json-comments": {
"version": "2.0.1",
- "resolved": "",
+ "resolved": false,
"integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=",
"optional": true
},
"tar": {
"version": "4.4.8",
- "resolved": "",
+ "resolved": false,
"integrity": "sha512-LzHF64s5chPQQS0IYBn9IN5h3i98c12bo4NCO7e0sGM2llXQ3p2FGC5sdENN4cTW48O915Sh+x+EXx7XW96xYQ==",
"optional": true,
"requires": {
@@ -10309,13 +10293,13 @@
},
"util-deprecate": {
"version": "1.0.2",
- "resolved": "",
+ "resolved": false,
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
"optional": true
},
"wide-align": {
"version": "1.1.3",
- "resolved": "",
+ "resolved": false,
"integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==",
"optional": true,
"requires": {
@@ -10324,13 +10308,13 @@
},
"wrappy": {
"version": "1.0.2",
- "resolved": "",
+ "resolved": false,
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
"optional": true
},
"yallist": {
"version": "3.0.3",
- "resolved": "",
+ "resolved": false,
"integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==",
"optional": true
}
@@ -10435,12 +10419,6 @@
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz",
"integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w=="
},
- "get-params": {
- "version": "0.1.2",
- "resolved": "https://registry.npmjs.org/get-params/-/get-params-0.1.2.tgz",
- "integrity": "sha1-uuDfq6WIoMYNeDTA2Nwv9g7u8v4=",
- "dev": true
- },
"get-stream": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz",
@@ -10931,12 +10909,6 @@
"safer-buffer": ">= 2.1.2 < 3"
}
},
- "ieee754": {
- "version": "1.1.13",
- "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz",
- "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==",
- "dev": true
- },
"ignore": {
"version": "4.0.6",
"resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz",
@@ -10973,9 +10945,9 @@
"integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o="
},
"in-publish": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/in-publish/-/in-publish-2.0.0.tgz",
- "integrity": "sha1-4g/146KvwmkDILbcVSaCqcf631E="
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/in-publish/-/in-publish-2.0.1.tgz",
+ "integrity": "sha512-oDM0kUSNFC31ShNxHKUyfZKy8ZeXZBWMjMdZHKLOk13uvT27VTL/QzRGfRUcevJhpkZAvlhPYuXkF7eNWrtyxQ=="
},
"indent-string": {
"version": "4.0.0",
@@ -16858,12 +16830,6 @@
"esprima": "^4.0.0"
}
},
- "jsan": {
- "version": "3.1.13",
- "resolved": "https://registry.npmjs.org/jsan/-/jsan-3.1.13.tgz",
- "integrity": "sha512-9kGpCsGHifmw6oJet+y8HaCl14y7qgAsxVdV3pCHDySNR3BfDC30zgkssd7x5LRVAT22dnpbe9JdzzmXZnq9/g==",
- "dev": true
- },
"jsbn": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
@@ -16977,7 +16943,8 @@
"json-stringify-safe": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
- "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus="
+ "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=",
+ "dev": true
},
"json5": {
"version": "2.1.1",
@@ -17106,12 +17073,6 @@
"integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=",
"dev": true
},
- "linked-list": {
- "version": "0.1.0",
- "resolved": "https://registry.npmjs.org/linked-list/-/linked-list-0.1.0.tgz",
- "integrity": "sha1-eYsP+X0bkqT9CEgPVa6k6dSdN78=",
- "dev": true
- },
"load-json-file": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz",
@@ -17180,11 +17141,6 @@
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
"integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A=="
},
- "lodash-es": {
- "version": "4.17.15",
- "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.15.tgz",
- "integrity": "sha512-rlrc3yU3+JNOpZ9zj5pQtxnx2THmvRykwL4Xlxoa8I9lHBlVbbyPhgyPMioxVZ4NqyxaVVtaJnzsyOidQIhyyQ=="
- },
"lodash._baseisequal": {
"version": "3.0.7",
"resolved": "https://registry.npmjs.org/lodash._baseisequal/-/lodash._baseisequal-3.0.7.tgz",
@@ -18357,12 +18313,6 @@
"integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==",
"optional": true
},
- "nanoid": {
- "version": "2.1.7",
- "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-2.1.7.tgz",
- "integrity": "sha512-fmS3qwDldm4bE01HCIRqNk+f255CNjnAoeV3Zzzv0KemObHKqYgirVaZA9DtKcjogicWjYcHkJs4D5A8CjnuVQ==",
- "dev": true
- },
"nanomatch": {
"version": "1.2.13",
"resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz",
@@ -19721,12 +19671,6 @@
"strict-uri-encode": "^2.0.0"
}
},
- "querystring": {
- "version": "0.2.0",
- "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz",
- "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=",
- "dev": true
- },
"querystringify": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.1.1.tgz",
@@ -20310,6 +20254,11 @@
"resolved": "https://registry.npmjs.org/react-native-local-auth/-/react-native-local-auth-1.6.0.tgz",
"integrity": "sha512-36cYGZGCG82pMiVJbQa5WMA93khP4v5JqLutFkMyB/eRpCULHmojNIBlbUPIY9SCeN4sg5VBRFTVGCtTg2r2kA=="
},
+ "react-native-mmkv-storage": {
+ "version": "0.2.2",
+ "resolved": "https://registry.npmjs.org/react-native-mmkv-storage/-/react-native-mmkv-storage-0.2.2.tgz",
+ "integrity": "sha512-QBMQzz7wpS2DGjOn5kIppqiD26p+jOJaJ0Am4DG2PImcUGe9iub5mkamz02mlqjyhq+8EhUes533uLK98APtmw=="
+ },
"react-native-navigation": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/react-native-navigation/-/react-native-navigation-6.3.0.tgz",
@@ -20771,29 +20720,6 @@
"resolved": "https://registry.npmjs.org/redux-batched-actions/-/redux-batched-actions-0.4.1.tgz",
"integrity": "sha512-r6tLDyBP3U9cXNLEHs0n1mX5TQfmk6xE0Y9uinYZ5HOyAWDgIJxYqRRkU/bC6XrJ4nS7tasNbxaHJHVmf9UdkA=="
},
- "redux-devtools-core": {
- "version": "0.2.1",
- "resolved": "https://registry.npmjs.org/redux-devtools-core/-/redux-devtools-core-0.2.1.tgz",
- "integrity": "sha512-RAGOxtUFdr/1USAvxrWd+Gq/Euzgw7quCZlO5TgFpDfG7rB5tMhZUrNyBjpzgzL2yMk0eHnPYIGm7NkIfRzHxQ==",
- "dev": true,
- "requires": {
- "get-params": "^0.1.2",
- "jsan": "^3.1.13",
- "lodash": "^4.17.11",
- "nanoid": "^2.0.0",
- "remotedev-serialize": "^0.1.8"
- }
- },
- "redux-devtools-instrument": {
- "version": "1.9.6",
- "resolved": "https://registry.npmjs.org/redux-devtools-instrument/-/redux-devtools-instrument-1.9.6.tgz",
- "integrity": "sha512-MwvY4cLEB2tIfWWBzrUR02UM9qRG2i7daNzywRvabOSVdvAY7s9BxSwMmVRH1Y/7QWjplNtOwgT0apKhHg2Qew==",
- "dev": true,
- "requires": {
- "lodash": "^4.2.0",
- "symbol-observable": "^1.0.2"
- }
- },
"redux-mock-store": {
"version": "1.5.4",
"resolved": "https://registry.npmjs.org/redux-mock-store/-/redux-mock-store-1.5.4.tgz",
@@ -20803,23 +20729,10 @@
"lodash.isplainobject": "^4.0.6"
}
},
- "redux-offline": {
- "version": "github:mattermost/redux-offline#885024de96b6ec73650c340c8928066585c413df",
- "from": "github:mattermost/redux-offline#885024de96b6ec73650c340c8928066585c413df",
- "requires": {
- "@react-native-community/netinfo": "^4.1.3",
- "redux-persist": "^4.5.0"
- }
- },
"redux-persist": {
- "version": "4.10.2",
- "resolved": "https://registry.npmjs.org/redux-persist/-/redux-persist-4.10.2.tgz",
- "integrity": "sha512-U+e0ieMGC69Zr72929iJW40dEld7Mflh6mu0eJtVMLGfMq/aJqjxUM1hzyUWMR1VUyAEEdPHuQmeq5ti9krIgg==",
- "requires": {
- "json-stringify-safe": "^5.0.1",
- "lodash": "^4.17.4",
- "lodash-es": "^4.17.4"
- }
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/redux-persist/-/redux-persist-6.0.0.tgz",
+ "integrity": "sha512-71LLMbUq2r02ng2We9S215LtPu3fY0KgaGE0k8WRgl6RkqxtGfl7HUozz1Dftwsb0D/5mZ8dwAaPbtnzfvbEwQ=="
},
"redux-persist-node-storage": {
"version": "2.0.0",
@@ -20844,6 +20757,11 @@
"lodash.unset": "^4.5.2"
}
},
+ "redux-reset": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/redux-reset/-/redux-reset-0.3.0.tgz",
+ "integrity": "sha1-q4B5W0ENWyhomYbqxAy4R6ac0BI="
+ },
"redux-thunk": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.3.0.tgz",
@@ -20999,29 +20917,6 @@
"es6-error": "^4.0.1"
}
},
- "remote-redux-devtools": {
- "version": "0.5.16",
- "resolved": "https://registry.npmjs.org/remote-redux-devtools/-/remote-redux-devtools-0.5.16.tgz",
- "integrity": "sha512-xZ2D1VRIWzat5nsvcraT6fKEX9Cfi+HbQBCwzNnUAM8Uicm/anOc60XGalcaDPrVmLug7nhDl2nimEa3bL3K9w==",
- "dev": true,
- "requires": {
- "jsan": "^3.1.13",
- "querystring": "^0.2.0",
- "redux-devtools-core": "^0.2.1",
- "redux-devtools-instrument": "^1.9.4",
- "rn-host-detect": "^1.1.5",
- "socketcluster-client": "^14.2.1"
- }
- },
- "remotedev-serialize": {
- "version": "0.1.8",
- "resolved": "https://registry.npmjs.org/remotedev-serialize/-/remotedev-serialize-0.1.8.tgz",
- "integrity": "sha512-3YG/FDcOmiK22bl5oMRM8RRnbGrFEuPGjbcDG+z2xi5aQaNQNZ8lqoRnZTwXVfaZtutXuiAQOgPRrogzQk8edg==",
- "dev": true,
- "requires": {
- "jsan": "^3.1.13"
- }
- },
"remove-trailing-separator": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz",
@@ -21236,12 +21131,6 @@
}
}
},
- "rn-host-detect": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/rn-host-detect/-/rn-host-detect-1.2.0.tgz",
- "integrity": "sha512-btNg5kzHcjZZ7t7mvvV/4wNJ9e3MPgrWivkRgWURzXL0JJ0pwWlU4zrbmdlz3HHzHOxhBhHB4D+/dbMFfu4/4A==",
- "dev": true
- },
"rn-placeholder": {
"version": "github:mattermost/rn-placeholder#02c629c65d0123a2eee623ada0fd17186415d3c3",
"from": "github:mattermost/rn-placeholder#02c629c65d0123a2eee623ada0fd17186415d3c3",
@@ -21359,27 +21248,6 @@
"xmlchars": "^2.1.1"
}
},
- "sc-channel": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/sc-channel/-/sc-channel-1.2.0.tgz",
- "integrity": "sha512-M3gdq8PlKg0zWJSisWqAsMmTVxYRTpVRqw4CWAdKBgAfVKumFcTjoCV0hYu7lgUXccCtCD8Wk9VkkE+IXCxmZA==",
- "dev": true,
- "requires": {
- "component-emitter": "1.2.1"
- }
- },
- "sc-errors": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/sc-errors/-/sc-errors-2.0.1.tgz",
- "integrity": "sha512-JoVhq3Ud+3Ujv2SIG7W0XtjRHsrNgl6iXuHHsh0s+Kdt5NwI6N2EGAZD4iteitdDv68ENBkpjtSvN597/wxPSQ==",
- "dev": true
- },
- "sc-formatter": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/sc-formatter/-/sc-formatter-3.0.2.tgz",
- "integrity": "sha512-9PbqYBpCq+OoEeRQ3QfFIGE6qwjjBcd2j7UjgDlhnZbtSnuGgHdcRklPKYGuYFH82V/dwd+AIpu8XvA1zqTd+A==",
- "dev": true
- },
"scheduler": {
"version": "0.15.0",
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.15.0.tgz",
@@ -21793,32 +21661,6 @@
}
}
},
- "socketcluster-client": {
- "version": "14.3.1",
- "resolved": "https://registry.npmjs.org/socketcluster-client/-/socketcluster-client-14.3.1.tgz",
- "integrity": "sha512-Sd/T0K/9UlqTfz+HUuFq90dshA5OBJPQbdkRzGtcKIOm52fkdsBTt0FYpiuzzxv5VrU7PWpRm6KIfNXyPwlLpw==",
- "dev": true,
- "requires": {
- "buffer": "^5.2.1",
- "clone": "2.1.1",
- "component-emitter": "1.2.1",
- "linked-list": "0.1.0",
- "querystring": "0.2.0",
- "sc-channel": "^1.2.0",
- "sc-errors": "^2.0.1",
- "sc-formatter": "^3.0.1",
- "uuid": "3.2.1",
- "ws": "7.1.0"
- },
- "dependencies": {
- "uuid": {
- "version": "3.2.1",
- "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.2.1.tgz",
- "integrity": "sha512-jZnMwlb9Iku/O3smGWvZhauCf6cvvpKi4BKRiliS3cxnI+Gz9j5MEpTz2UFuXiKPJocb7gnsLHwiS05ige5BEA==",
- "dev": true
- }
- }
- },
"sort-json": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/sort-json/-/sort-json-2.0.0.tgz",
@@ -23015,9 +22857,9 @@
"dev": true
},
"webpack-cli": {
- "version": "3.3.10",
- "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-3.3.10.tgz",
- "integrity": "sha512-u1dgND9+MXaEt74sJR4PR7qkPxXUSQ0RXYq8x1L6Jg1MYVEmGPrH6Ah6C4arD4r0J1P5HKjRqpab36k0eIzPqg==",
+ "version": "3.3.11",
+ "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-3.3.11.tgz",
+ "integrity": "sha512-dXlfuml7xvAFwYUPsrtQAA9e4DOe58gnzSxhgrO/ZM/gyXTBowrsYeubyN4mqGhYdpXMFNyQ6emjJS9M7OBd4g==",
"dev": true,
"requires": {
"chalk": "2.4.2",
@@ -23119,9 +22961,9 @@
}
},
"yargs-parser": {
- "version": "13.1.1",
- "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.1.tgz",
- "integrity": "sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ==",
+ "version": "13.1.2",
+ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz",
+ "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==",
"dev": true,
"requires": {
"camelcase": "^5.0.0",
diff --git a/package.json b/package.json
index 409864439..2cb3cd563 100644
--- a/package.json
+++ b/package.json
@@ -51,6 +51,7 @@
"react-native-keychain": "4.0.5",
"react-native-linear-gradient": "2.5.6",
"react-native-local-auth": "1.6.0",
+ "react-native-mmkv-storage": "0.2.2",
"react-native-navigation": "6.3.0",
"react-native-notifications": "2.0.6",
"react-native-passcode-status": "1.1.2",
@@ -71,9 +72,9 @@
"redux": "4.0.5",
"redux-action-buffer": "1.2.0",
"redux-batched-actions": "0.4.1",
- "redux-offline": "github:mattermost/redux-offline#885024de96b6ec73650c340c8928066585c413df",
- "redux-persist": "4.10.2",
+ "redux-persist": "6.0.0",
"redux-persist-transform-filter": "0.0.20",
+ "redux-reset": "0.3.0",
"redux-thunk": "2.3.0",
"reselect": "4.0.0",
"rn-fetch-blob": "0.12.0",
@@ -133,7 +134,6 @@
"react-test-renderer": "16.13.0",
"redux-mock-store": "1.5.4",
"redux-persist-node-storage": "2.0.0",
- "remote-redux-devtools": "0.5.16",
"socketcluster": "16.0.1",
"ts-jest": "25.2.1",
"typescript": "3.8.3",
diff --git a/packager/moduleNames.js b/packager/moduleNames.js
index 18dadfa71..277d28d06 100644
--- a/packager/moduleNames.js
+++ b/packager/moduleNames.js
@@ -151,12 +151,10 @@ module.exports = [
'app/mm-redux/selectors/entities/teams.ts',
'app/mm-redux/selectors/entities/timezone.ts',
'app/mm-redux/selectors/entities/users.ts',
- 'app/mm-redux/store/configureStore.prod.ts',
'app/mm-redux/store/helpers.ts',
'app/mm-redux/store/index.ts',
'app/mm-redux/store/initial_state.ts',
'app/mm-redux/store/middleware.ts',
- 'app/mm-redux/store/reducer_registry.ts',
'app/mm-redux/types/actions.ts',
'app/mm-redux/utils/channel_utils.ts',
'app/mm-redux/utils/emoji_utils.ts',
@@ -837,19 +835,6 @@ module.exports = [
'node_modules/react/index.js',
'node_modules/redux-action-buffer/index.js',
'node_modules/redux-batched-actions/lib/index.js',
- 'node_modules/redux-offline/lib/actions.js',
- 'node_modules/redux-offline/lib/config.js',
- 'node_modules/redux-offline/lib/constants.js',
- 'node_modules/redux-offline/lib/defaults/batch.js',
- 'node_modules/redux-offline/lib/defaults/detectNetwork.native.js',
- 'node_modules/redux-offline/lib/defaults/discard.js',
- 'node_modules/redux-offline/lib/defaults/effect.js',
- 'node_modules/redux-offline/lib/defaults/index.js',
- 'node_modules/redux-offline/lib/defaults/persist.native.js',
- 'node_modules/redux-offline/lib/defaults/retry.js',
- 'node_modules/redux-offline/lib/index.js',
- 'node_modules/redux-offline/lib/middleware.js',
- 'node_modules/redux-offline/lib/updater.js',
'node_modules/redux-persist-transform-filter/dist/index.js',
'node_modules/redux-persist/lib/autoRehydrate.js',
'node_modules/redux-persist/lib/constants.js',
diff --git a/packager/modulePaths.js b/packager/modulePaths.js
index 24017d6d8..554863609 100644
--- a/packager/modulePaths.js
+++ b/packager/modulePaths.js
@@ -150,12 +150,10 @@ module.exports = [
'./node_modules/app/mm-redux/selectors/entities/teams.ts',
'./node_modules/app/mm-redux/selectors/entities/timezone.ts',
'./node_modules/app/mm-redux/selectors/entities/users.ts',
- './node_modules/app/mm-redux/store/configureStore.prod.ts',
'./node_modules/app/mm-redux/store/helpers.ts',
'./node_modules/app/mm-redux/store/index.ts',
'./node_modules/app/mm-redux/store/initial_state.ts',
'./node_modules/app/mm-redux/store/middleware.ts',
- './node_modules/app/mm-redux/store/reducer_registry.ts',
'./node_modules/app/mm-redux/types/actions.ts',
'./node_modules/app/mm-redux/utils/channel_utils.ts',
'./node_modules/app/mm-redux/utils/emoji_utils.ts',
@@ -831,19 +829,6 @@ module.exports = [
'./node_modules/node_modules/react/index.js',
'./node_modules/node_modules/redux-action-buffer/index.js',
'./node_modules/node_modules/redux-batched-actions/lib/index.js',
- './node_modules/node_modules/redux-offline/lib/actions.js',
- './node_modules/node_modules/redux-offline/lib/config.js',
- './node_modules/node_modules/redux-offline/lib/constants.js',
- './node_modules/node_modules/redux-offline/lib/defaults/batch.js',
- './node_modules/node_modules/redux-offline/lib/defaults/detectNetwork.native.js',
- './node_modules/node_modules/redux-offline/lib/defaults/discard.js',
- './node_modules/node_modules/redux-offline/lib/defaults/effect.js',
- './node_modules/node_modules/redux-offline/lib/defaults/index.js',
- './node_modules/node_modules/redux-offline/lib/defaults/persist.native.js',
- './node_modules/node_modules/redux-offline/lib/defaults/retry.js',
- './node_modules/node_modules/redux-offline/lib/index.js',
- './node_modules/node_modules/redux-offline/lib/middleware.js',
- './node_modules/node_modules/redux-offline/lib/updater.js',
'./node_modules/node_modules/redux-persist-transform-filter/dist/index.js',
'./node_modules/node_modules/redux-persist/lib/autoRehydrate.js',
'./node_modules/node_modules/redux-persist/lib/constants.js',
diff --git a/test/setup.js b/test/setup.js
index 107437666..fd87fd1c4 100644
--- a/test/setup.js
+++ b/test/setup.js
@@ -87,6 +87,10 @@ jest.doMock('react-native', () => {
pick: jest.fn(),
},
RNPermissions: {},
+ RNFastStorage: {
+ setupLibrary: jest.fn(),
+ setStringAsync: jest.fn(),
+ },
};
return Object.setPrototypeOf({
diff --git a/test/test_store.js b/test/test_store.js
index 4f53732fa..753efbf76 100644
--- a/test/test_store.js
+++ b/test/test_store.js
@@ -1,7 +1,7 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {AsyncNodeStorage} from 'redux-persist-node-storage';
-import {createTransform, persistStore} from 'redux-persist';
+import {createTransform} from 'redux-persist';
import configureStore from '@mm-redux/store';
@@ -11,29 +11,16 @@ export default async function testConfigureStore(preloadedState) {
() => ({}),
);
- const offlineConfig = {
- detectNetwork: (callback) => callback(true),
- persist: (store, options) => {
- return persistStore(store, {storage: new AsyncNodeStorage('./.tmp'), ...options});
- },
- persistOptions: {
- debounce: 1000,
- transforms: [
- storageTransform,
- ],
- whitelist: [],
- },
- retry: (action, retries) => 200 * (retries + 1),
- discard: (error, action, retries) => {
- if (action.meta && action.meta.offline.hasOwnProperty('maxRetry')) {
- return retries >= action.meta.offline.maxRetry;
- }
-
- return retries >= 1;
- },
+ const persistConfig = {
+ key: 'root',
+ storage: new AsyncNodeStorage('./.tmp'),
+ whitelist: [],
+ transforms: [
+ storageTransform,
+ ],
};
- const store = configureStore(preloadedState, {}, offlineConfig, () => ({}), {enableBuffer: false});
+ const {store} = configureStore(preloadedState, {}, persistConfig, () => ({}), {enableBuffer: false});
const wait = () => new Promise((resolve) => setTimeout(resolve), 300); //eslint-disable-line
await wait();
diff --git a/tsconfig.json b/tsconfig.json
index ddb9fc851..8779e1a2d 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -34,6 +34,7 @@
"@actions/*": ["app/actions/*"],
"@constants/*": ["app/constants/*"],
"@constants": ["app/constants/index"],
+ "@i18n": ["app/i18n/index"],
"@selectors/*": ["app/selectors/*"],
"@telemetry/*": ["/app/telemetry/*"],
"@utils/*": ["app/utils/*"],