diff --git a/app/actions/encryption.js b/app/actions/encryption.js deleted file mode 100644 index 390dfe903..000000000 --- a/app/actions/encryption.js +++ /dev/null @@ -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 - }; -} diff --git a/app/actions/encryption.ts b/app/actions/encryption.ts new file mode 100644 index 000000000..ca3be8ce5 --- /dev/null +++ b/app/actions/encryption.ts @@ -0,0 +1,51 @@ +import { Action } from 'redux'; + +import { ENCRYPTION } from './actionsTypes'; + +export interface IEncryptionSet extends Action { + enabled: boolean; + banner: any; +} + +export interface IEncryptionSetBanner extends Action { + banner: any; +} +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: any = null): IEncryptionSet { + return { + type: ENCRYPTION.SET, + enabled, + banner + }; +} + +export function encryptionSetBanner(banner: any = null): IEncryptionSetBanner { + return { + type: ENCRYPTION.SET_BANNER, + banner + }; +} + +export function encryptionDecodeKey(password: string): IEncryptionDecodeKey { + return { + type: ENCRYPTION.DECODE_KEY, + password + }; +} diff --git a/app/definitions/redux/index.ts b/app/definitions/redux/index.ts index e95763e29..1e4216df0 100644 --- a/app/definitions/redux/index.ts +++ b/app/definitions/redux/index.ts @@ -1,7 +1,9 @@ -import { TActionSelectedUsers } from '../../actions/selectedUsers'; import { TActionActiveUsers } from '../../actions/activeUsers'; +import { TActionEncryption } from '../../actions/encryption'; +import { TActionSelectedUsers } from '../../actions/selectedUsers'; // REDUCERS import { IActiveUsers } from '../../reducers/activeUsers'; +import { IEncryption } from '../../reducers/encryption'; import { ISelectedUsers } from '../../reducers/selectedUsers'; export interface IApplicationState { @@ -23,9 +25,9 @@ export interface IApplicationState { createDiscussion: any; inquiry: any; enterpriseModules: any; - encryption: any; + encryption: IEncryption; permissions: any; roles: any; } -export type TApplicationActions = TActionActiveUsers & TActionSelectedUsers; +export type TApplicationActions = TActionActiveUsers & TActionSelectedUsers & TActionEncryption; diff --git a/app/reducers/encryption.test.ts b/app/reducers/encryption.test.ts new file mode 100644 index 000000000..cf2a8118b --- /dev/null +++ b/app/reducers/encryption.test.ts @@ -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, true)); + const state = mockedStore.getState().encryption; + expect(state).toEqual({ banner: true, enabled: true }); + }); + + it('should return empty store after encryptionInit', () => { + mockedStore.dispatch(encryptionInit()); + const state = mockedStore.getState().encryption; + expect(state).toEqual({ banner: null, enabled: false }); + }); + + it('should return initial state after encryptionSetBanner', () => { + mockedStore.dispatch(encryptionSetBanner(true)); + const state = mockedStore.getState().encryption; + expect(state).toEqual({ banner: true, enabled: false }); + }); +}); diff --git a/app/reducers/encryption.js b/app/reducers/encryption.ts similarity index 58% rename from app/reducers/encryption.js rename to app/reducers/encryption.ts index 0145ae2d1..5854c75ad 100644 --- a/app/reducers/encryption.js +++ b/app/reducers/encryption.ts @@ -1,11 +1,18 @@ import { ENCRYPTION } from '../actions/actionsTypes'; +import { TApplicationActions } from '../definitions'; -const initialState = { +export interface IEncryption { + enabled: boolean; + // TODO + banner: any; +} + +export const initialState: IEncryption = { enabled: false, banner: null }; -export default function encryption(state = initialState, action) { +export default function encryption(state = initialState, action: TApplicationActions): IEncryption { switch (action.type) { case ENCRYPTION.SET: return { diff --git a/app/views/E2EEnterYourPasswordView.tsx b/app/views/E2EEnterYourPasswordView.tsx index 6d63f90dd..6e08b07b9 100644 --- a/app/views/E2EEnterYourPasswordView.tsx +++ b/app/views/E2EEnterYourPasswordView.tsx @@ -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; -} +type TE2EEnterYourPasswordViewProps = IBaseScreen; -class E2EEnterYourPasswordView extends React.Component { +class E2EEnterYourPasswordView extends React.Component { private passwordInput?: TextInput; - static navigationOptions = ({ navigation }: Pick): StackNavigationOptions => ({ + static navigationOptions = ({ navigation }: Pick): StackNavigationOptions => ({ headerLeft: () => , 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 { 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 ({ - encryptionDecodeKey: (password: string) => dispatch(encryptionDecodeKeyAction(password)) -}); -export default connect(null, mapDispatchToProps)(withTheme(E2EEnterYourPasswordView)); +export default connect(null)(withTheme(E2EEnterYourPasswordView)); diff --git a/app/views/E2ESaveYourPasswordView.tsx b/app/views/E2ESaveYourPasswordView.tsx index 3d9a32ee1..cc7bac83f 100644 --- a/app/views/E2ESaveYourPasswordView.tsx +++ b/app/views/E2ESaveYourPasswordView.tsx @@ -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 { server: string; - navigation: StackNavigationProp; - encryptionSetBanner(): void; - theme: string; } class E2ESaveYourPasswordView extends React.Component { @@ -103,11 +99,11 @@ class E2ESaveYourPasswordView extends React.Component { 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 ({ +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));