Merge branch 'develop' into chore.migrate-redux-server-to-ts
This commit is contained in:
commit
2889a1cc0f
|
@ -1,8 +0,0 @@
|
|||
import * as types from './actionsTypes';
|
||||
|
||||
export function setCustomEmojis(emojis) {
|
||||
return {
|
||||
type: types.SET_CUSTOM_EMOJIS,
|
||||
emojis
|
||||
};
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
import { Action } from 'redux';
|
||||
|
||||
import { ICustomEmojis } from '../reducers/customEmojis';
|
||||
import { SET_CUSTOM_EMOJIS } from './actionsTypes';
|
||||
|
||||
export interface ISetCustomEmojis extends Action {
|
||||
emojis: ICustomEmojis;
|
||||
}
|
||||
|
||||
export type TActionCustomEmojis = ISetCustomEmojis;
|
||||
|
||||
export function setCustomEmojis(emojis: ICustomEmojis): ISetCustomEmojis {
|
||||
return {
|
||||
type: SET_CUSTOM_EMOJIS,
|
||||
emojis
|
||||
};
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
import * as types from './actionsTypes';
|
||||
|
||||
export function encryptionInit() {
|
||||
return {
|
||||
type: types.ENCRYPTION.INIT
|
||||
};
|
||||
}
|
||||
|
||||
export function encryptionStop() {
|
||||
return {
|
||||
type: types.ENCRYPTION.STOP
|
||||
};
|
||||
}
|
||||
|
||||
export function encryptionSet(enabled = false, banner = null) {
|
||||
return {
|
||||
type: types.ENCRYPTION.SET,
|
||||
enabled,
|
||||
banner
|
||||
};
|
||||
}
|
||||
|
||||
export function encryptionSetBanner(banner) {
|
||||
return {
|
||||
type: types.ENCRYPTION.SET_BANNER,
|
||||
banner
|
||||
};
|
||||
}
|
||||
|
||||
export function encryptionDecodeKey(password) {
|
||||
return {
|
||||
type: types.ENCRYPTION.DECODE_KEY,
|
||||
password
|
||||
};
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
import { Action } from 'redux';
|
||||
|
||||
import { IBanner } from '../reducers/encryption';
|
||||
import { ENCRYPTION } from './actionsTypes';
|
||||
|
||||
export interface IEncryptionSet extends Action {
|
||||
enabled: boolean;
|
||||
banner: IBanner;
|
||||
}
|
||||
|
||||
export interface IEncryptionSetBanner extends Action {
|
||||
banner: IBanner;
|
||||
}
|
||||
export interface IEncryptionDecodeKey extends Action {
|
||||
password: string;
|
||||
}
|
||||
|
||||
export type TActionEncryption = IEncryptionSet & IEncryptionSetBanner & IEncryptionDecodeKey;
|
||||
|
||||
export function encryptionInit(): Action {
|
||||
return {
|
||||
type: ENCRYPTION.INIT
|
||||
};
|
||||
}
|
||||
|
||||
export function encryptionStop(): Action {
|
||||
return {
|
||||
type: ENCRYPTION.STOP
|
||||
};
|
||||
}
|
||||
|
||||
export function encryptionSet(enabled = false, banner: IBanner = ''): IEncryptionSet {
|
||||
return {
|
||||
type: ENCRYPTION.SET,
|
||||
enabled,
|
||||
banner
|
||||
};
|
||||
}
|
||||
|
||||
export function encryptionSetBanner(banner: IBanner = ''): IEncryptionSetBanner {
|
||||
return {
|
||||
type: ENCRYPTION.SET_BANNER,
|
||||
banner
|
||||
};
|
||||
}
|
||||
|
||||
export function encryptionDecodeKey(password: string): IEncryptionDecodeKey {
|
||||
return {
|
||||
type: ENCRYPTION.DECODE_KEY,
|
||||
password
|
||||
};
|
||||
}
|
|
@ -1,12 +1,15 @@
|
|||
// ACTIONS
|
||||
import { TActionServer } from '../../actions/server';
|
||||
import { TActionActiveUsers } from '../../actions/activeUsers';
|
||||
import { TActionCustomEmojis } from '../../actions/customEmojis';
|
||||
import { TActionEncryption } from '../../actions/encryption';
|
||||
import { TActionInviteLinks } from '../../actions/inviteLinks';
|
||||
import { IActionRoles } from '../../actions/roles';
|
||||
import { TActionSelectedUsers } from '../../actions/selectedUsers';
|
||||
import { IActionSettings } from '../../actions/settings';
|
||||
// REDUCERS
|
||||
import { IActiveUsers } from '../../reducers/activeUsers';
|
||||
import { IEncryption } from '../../reducers/encryption';
|
||||
import { IInviteLinks } from '../../reducers/inviteLinks';
|
||||
import { IRoles } from '../../reducers/roles';
|
||||
import { ISelectedUsers } from '../../reducers/selectedUsers';
|
||||
|
@ -32,14 +35,16 @@ export interface IApplicationState {
|
|||
createDiscussion: any;
|
||||
inquiry: any;
|
||||
enterpriseModules: any;
|
||||
encryption: any;
|
||||
encryption: IEncryption;
|
||||
permissions: any;
|
||||
roles: IRoles;
|
||||
}
|
||||
|
||||
export type TApplicationActions = TActionActiveUsers &
|
||||
TActionSelectedUsers &
|
||||
TActionCustomEmojis &
|
||||
TActionInviteLinks &
|
||||
IActionRoles &
|
||||
IActionSettings &
|
||||
TActionEncryption &
|
||||
TActionServer;
|
||||
|
|
|
@ -1,14 +0,0 @@
|
|||
import { SET_CUSTOM_EMOJIS } from '../actions/actionsTypes';
|
||||
|
||||
const initialState = {
|
||||
customEmojis: {}
|
||||
};
|
||||
|
||||
export default function customEmojis(state = initialState, action) {
|
||||
switch (action.type) {
|
||||
case SET_CUSTOM_EMOJIS:
|
||||
return action.emojis;
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
import { setCustomEmojis } from '../actions/customEmojis';
|
||||
import { ICustomEmojis, initialState } from './customEmojis';
|
||||
import { mockedStore } from './mockedStore';
|
||||
|
||||
describe('test reducer', () => {
|
||||
it('should return initial state', () => {
|
||||
const state = mockedStore.getState().customEmojis;
|
||||
expect(state).toEqual(initialState);
|
||||
});
|
||||
it('should return modified store after action', () => {
|
||||
const emojis: ICustomEmojis = { dog: { name: 'dog', extension: 'jpg' }, cat: { name: 'cat', extension: 'jpg' } };
|
||||
mockedStore.dispatch(setCustomEmojis(emojis));
|
||||
const state = mockedStore.getState().customEmojis;
|
||||
expect(state).toEqual(emojis);
|
||||
});
|
||||
});
|
|
@ -0,0 +1,23 @@
|
|||
import { SET_CUSTOM_EMOJIS } from '../actions/actionsTypes';
|
||||
import { TApplicationActions } from '../definitions';
|
||||
|
||||
// There are at least three interfaces for emoji, but none of them includes only this data.
|
||||
interface IEmoji {
|
||||
name: string;
|
||||
extension: string;
|
||||
}
|
||||
|
||||
export interface ICustomEmojis {
|
||||
[key: string]: IEmoji;
|
||||
}
|
||||
|
||||
export const initialState: ICustomEmojis = {};
|
||||
|
||||
export default function customEmojis(state = initialState, action: TApplicationActions): ICustomEmojis {
|
||||
switch (action.type) {
|
||||
case SET_CUSTOM_EMOJIS:
|
||||
return action.emojis;
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
import { encryptionSet, encryptionInit, encryptionSetBanner } from '../actions/encryption';
|
||||
import { mockedStore } from './mockedStore';
|
||||
import { initialState } from './encryption';
|
||||
|
||||
describe('test encryption reducer', () => {
|
||||
it('should return initial state', () => {
|
||||
const state = mockedStore.getState().encryption;
|
||||
expect(state).toEqual(initialState);
|
||||
});
|
||||
|
||||
it('should return modified store after encryptionSet', () => {
|
||||
mockedStore.dispatch(encryptionSet(true, 'BANNER'));
|
||||
const state = mockedStore.getState().encryption;
|
||||
expect(state).toEqual({ banner: 'BANNER', enabled: true });
|
||||
});
|
||||
|
||||
it('should return empty store after encryptionInit', () => {
|
||||
mockedStore.dispatch(encryptionInit());
|
||||
const state = mockedStore.getState().encryption;
|
||||
expect(state).toEqual({ banner: '', enabled: false });
|
||||
});
|
||||
|
||||
it('should return initial state after encryptionSetBanner', () => {
|
||||
mockedStore.dispatch(encryptionSetBanner('BANNER_NEW'));
|
||||
const state = mockedStore.getState().encryption;
|
||||
expect(state).toEqual({ banner: 'BANNER_NEW', enabled: false });
|
||||
});
|
||||
});
|
|
@ -1,11 +1,18 @@
|
|||
import { ENCRYPTION } from '../actions/actionsTypes';
|
||||
import { TApplicationActions } from '../definitions';
|
||||
|
||||
const initialState = {
|
||||
export type IBanner = string;
|
||||
export interface IEncryption {
|
||||
enabled: boolean;
|
||||
banner: IBanner;
|
||||
}
|
||||
|
||||
export const initialState: IEncryption = {
|
||||
enabled: false,
|
||||
banner: null
|
||||
banner: ''
|
||||
};
|
||||
|
||||
export default function encryption(state = initialState, action) {
|
||||
export default function encryption(state = initialState, action: TApplicationActions): IEncryption {
|
||||
switch (action.type) {
|
||||
case ENCRYPTION.SET:
|
||||
return {
|
|
@ -1,23 +1,23 @@
|
|||
import { StackNavigationOptions } from '@react-navigation/stack';
|
||||
import React from 'react';
|
||||
import { ScrollView, StyleSheet, Text } from 'react-native';
|
||||
import { connect } from 'react-redux';
|
||||
import { Dispatch } from 'redux';
|
||||
import { StackNavigationOptions, StackNavigationProp } from '@react-navigation/stack';
|
||||
|
||||
import I18n from '../i18n';
|
||||
import { withTheme } from '../theme';
|
||||
import Button from '../containers/Button';
|
||||
import { encryptionDecodeKey } from '../actions/encryption';
|
||||
import { themes } from '../constants/colors';
|
||||
import TextInput from '../containers/TextInput';
|
||||
import SafeAreaView from '../containers/SafeAreaView';
|
||||
import Button from '../containers/Button';
|
||||
import * as HeaderButton from '../containers/HeaderButton';
|
||||
import { encryptionDecodeKey as encryptionDecodeKeyAction } from '../actions/encryption';
|
||||
import scrollPersistTaps from '../utils/scrollPersistTaps';
|
||||
import KeyboardView from '../presentation/KeyboardView';
|
||||
import SafeAreaView from '../containers/SafeAreaView';
|
||||
import StatusBar from '../containers/StatusBar';
|
||||
import { events, logEvent } from '../utils/log';
|
||||
import sharedStyles from './Styles';
|
||||
import TextInput from '../containers/TextInput';
|
||||
import { IBaseScreen } from '../definitions';
|
||||
import I18n from '../i18n';
|
||||
import KeyboardView from '../presentation/KeyboardView';
|
||||
import { E2EEnterYourPasswordStackParamList } from '../stacks/types';
|
||||
import { withTheme } from '../theme';
|
||||
import { events, logEvent } from '../utils/log';
|
||||
import scrollPersistTaps from '../utils/scrollPersistTaps';
|
||||
import sharedStyles from './Styles';
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
|
@ -34,21 +34,17 @@ interface IE2EEnterYourPasswordViewState {
|
|||
password: string;
|
||||
}
|
||||
|
||||
interface IE2EEnterYourPasswordViewProps {
|
||||
encryptionDecodeKey: (password: string) => void;
|
||||
theme: string;
|
||||
navigation: StackNavigationProp<E2EEnterYourPasswordStackParamList, 'E2EEnterYourPasswordView'>;
|
||||
}
|
||||
type TE2EEnterYourPasswordViewProps = IBaseScreen<E2EEnterYourPasswordStackParamList, 'E2EEnterYourPasswordView'>;
|
||||
|
||||
class E2EEnterYourPasswordView extends React.Component<IE2EEnterYourPasswordViewProps, IE2EEnterYourPasswordViewState> {
|
||||
class E2EEnterYourPasswordView extends React.Component<TE2EEnterYourPasswordViewProps, IE2EEnterYourPasswordViewState> {
|
||||
private passwordInput?: TextInput;
|
||||
|
||||
static navigationOptions = ({ navigation }: Pick<IE2EEnterYourPasswordViewProps, 'navigation'>): StackNavigationOptions => ({
|
||||
static navigationOptions = ({ navigation }: Pick<TE2EEnterYourPasswordViewProps, 'navigation'>): StackNavigationOptions => ({
|
||||
headerLeft: () => <HeaderButton.CloseModal navigation={navigation} testID='e2e-enter-your-password-view-close' />,
|
||||
title: I18n.t('Enter_Your_E2E_Password')
|
||||
});
|
||||
|
||||
constructor(props: IE2EEnterYourPasswordViewProps) {
|
||||
constructor(props: TE2EEnterYourPasswordViewProps) {
|
||||
super(props);
|
||||
this.state = {
|
||||
password: ''
|
||||
|
@ -58,8 +54,8 @@ class E2EEnterYourPasswordView extends React.Component<IE2EEnterYourPasswordView
|
|||
submit = () => {
|
||||
logEvent(events.E2E_ENTER_PW_SUBMIT);
|
||||
const { password } = this.state;
|
||||
const { encryptionDecodeKey } = this.props;
|
||||
encryptionDecodeKey(password);
|
||||
const { dispatch } = this.props;
|
||||
dispatch(encryptionDecodeKey(password));
|
||||
};
|
||||
|
||||
render() {
|
||||
|
@ -109,7 +105,4 @@ class E2EEnterYourPasswordView extends React.Component<IE2EEnterYourPasswordView
|
|||
}
|
||||
}
|
||||
|
||||
const mapDispatchToProps = (dispatch: Dispatch) => ({
|
||||
encryptionDecodeKey: (password: string) => dispatch(encryptionDecodeKeyAction(password))
|
||||
});
|
||||
export default connect(null, mapDispatchToProps)(withTheme(E2EEnterYourPasswordView));
|
||||
export default connect(null)(withTheme(E2EEnterYourPasswordView));
|
||||
|
|
|
@ -1,25 +1,24 @@
|
|||
import React from 'react';
|
||||
import { StackNavigationProp } from '@react-navigation/stack';
|
||||
import { Dispatch } from 'redux';
|
||||
import { connect } from 'react-redux';
|
||||
import { Clipboard, ScrollView, StyleSheet, Text, View } from 'react-native';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { encryptionSetBanner as encryptionSetBannerAction } from '../actions/encryption';
|
||||
import { E2E_RANDOM_PASSWORD_KEY } from '../lib/encryption/constants';
|
||||
import { encryptionSetBanner } from '../actions/encryption';
|
||||
import { themes } from '../constants/colors';
|
||||
import Button from '../containers/Button';
|
||||
import * as HeaderButton from '../containers/HeaderButton';
|
||||
import scrollPersistTaps from '../utils/scrollPersistTaps';
|
||||
import SafeAreaView from '../containers/SafeAreaView';
|
||||
import UserPreferences from '../lib/userPreferences';
|
||||
import { events, logEvent } from '../utils/log';
|
||||
import StatusBar from '../containers/StatusBar';
|
||||
import { LISTENER } from '../containers/Toast';
|
||||
import { themes } from '../constants/colors';
|
||||
import EventEmitter from '../utils/events';
|
||||
import Button from '../containers/Button';
|
||||
import { withTheme } from '../theme';
|
||||
import { IApplicationState, IBaseScreen } from '../definitions';
|
||||
import I18n from '../i18n';
|
||||
import sharedStyles from './Styles';
|
||||
import { E2E_RANDOM_PASSWORD_KEY } from '../lib/encryption/constants';
|
||||
import UserPreferences from '../lib/userPreferences';
|
||||
import { E2ESaveYourPasswordStackParamList } from '../stacks/types';
|
||||
import { withTheme } from '../theme';
|
||||
import EventEmitter from '../utils/events';
|
||||
import { events, logEvent } from '../utils/log';
|
||||
import scrollPersistTaps from '../utils/scrollPersistTaps';
|
||||
import sharedStyles from './Styles';
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
|
@ -59,11 +58,8 @@ interface IE2ESaveYourPasswordViewState {
|
|||
password: string;
|
||||
}
|
||||
|
||||
interface IE2ESaveYourPasswordViewProps {
|
||||
interface IE2ESaveYourPasswordViewProps extends IBaseScreen<E2ESaveYourPasswordStackParamList, 'E2ESaveYourPasswordView'> {
|
||||
server: string;
|
||||
navigation: StackNavigationProp<E2ESaveYourPasswordStackParamList, 'E2ESaveYourPasswordView'>;
|
||||
encryptionSetBanner(): void;
|
||||
theme: string;
|
||||
}
|
||||
|
||||
class E2ESaveYourPasswordView extends React.Component<IE2ESaveYourPasswordViewProps, IE2ESaveYourPasswordViewState> {
|
||||
|
@ -103,11 +99,11 @@ class E2ESaveYourPasswordView extends React.Component<IE2ESaveYourPasswordViewPr
|
|||
|
||||
onSaved = async () => {
|
||||
logEvent(events.E2E_SAVE_PW_SAVED);
|
||||
const { navigation, server, encryptionSetBanner } = this.props;
|
||||
const { navigation, server, dispatch } = this.props;
|
||||
// Remove stored password
|
||||
await UserPreferences.removeItem(`${server}-${E2E_RANDOM_PASSWORD_KEY}`);
|
||||
// Hide encryption banner
|
||||
encryptionSetBanner();
|
||||
dispatch(encryptionSetBanner());
|
||||
navigation.pop();
|
||||
};
|
||||
|
||||
|
@ -173,10 +169,8 @@ class E2ESaveYourPasswordView extends React.Component<IE2ESaveYourPasswordViewPr
|
|||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = (state: any) => ({
|
||||
const mapStateToProps = (state: IApplicationState) => ({
|
||||
server: state.server.server
|
||||
});
|
||||
const mapDispatchToProps = (dispatch: Dispatch) => ({
|
||||
encryptionSetBanner: () => dispatch(encryptionSetBannerAction())
|
||||
});
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(withTheme(E2ESaveYourPasswordView));
|
||||
|
||||
export default connect(mapStateToProps)(withTheme(E2ESaveYourPasswordView));
|
||||
|
|
Loading…
Reference in New Issue