Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
…to component/4080-badge
  • Loading branch information
brianacnguyen committed Aug 18, 2022
2 parents 4cdd0e4 + 63b3efe commit d726caf
Show file tree
Hide file tree
Showing 64 changed files with 1,698 additions and 522 deletions.
20 changes: 20 additions & 0 deletions app/actions/security/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/* eslint-disable import/prefer-default-export */
import type { Action } from 'redux';

export enum ActionType {
SET_ALLOW_LOGIN_WITH_REMEMBER_ME = 'SET_ALLOW_LOGIN_WITH_REMEMBER_ME',
}

export interface AllowLoginWithRememberMeUpdated
extends Action<ActionType.SET_ALLOW_LOGIN_WITH_REMEMBER_ME> {
enabled: boolean;
}

export type Action = AllowLoginWithRememberMeUpdated;

export const setAllowLoginWithRememberMe = (
enabled: boolean,
): AllowLoginWithRememberMeUpdated => ({
type: ActionType.SET_ALLOW_LOGIN_WITH_REMEMBER_ME,
enabled,
});
3 changes: 3 additions & 0 deletions app/actions/security/state.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export interface SecuritySettingsState {
allowLoginWithRememberMe: boolean;
}
5 changes: 5 additions & 0 deletions app/components/Nav/App/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ import ModalConfirmation from '../../../component-library/components/Modals/Moda
import Toast, {
ToastContext,
} from '../../../component-library/components/Toast';
import { TurnOffRememberMeModal } from '../../../components/UI/TurnOffRememberMeModal';

const Stack = createStackNavigator();
/**
Expand Down Expand Up @@ -351,6 +352,10 @@ const App = ({ userLoggedIn }) => {
component={ModalConfirmation}
/>
<Stack.Screen name={Routes.MODAL.WHATS_NEW} component={WhatsNewModal} />
<Stack.Screen
name={Routes.MODAL.TURN_OFF_REMEMBER_ME}
component={TurnOffRememberMeModal}
/>
</Stack.Navigator>
);

Expand Down
19 changes: 18 additions & 1 deletion app/components/UI/AccountOverview/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,9 @@ class AccountOverview extends PureComponent {
}
};

isAccountLabelDefined = (accountLabel) =>
!!accountLabel && !!accountLabel.trim().length;

input = React.createRef();

componentDidMount = () => {
Expand All @@ -245,6 +248,11 @@ class AccountOverview extends PureComponent {
InteractionManager.runAfterInteractions(() => {
this.doENSLookup();
});

const { PreferencesController } = Engine.context;
if (!this.isAccountLabelDefined(accountLabel)) {
PreferencesController.setAccountLabel(selectedAddress, 'Account');
}
};

componentDidUpdate(prevProps) {
Expand All @@ -262,7 +270,16 @@ class AccountOverview extends PureComponent {
const { PreferencesController } = Engine.context;
const { selectedAddress } = this.props;
const { accountLabel } = this.state;
PreferencesController.setAccountLabel(selectedAddress, accountLabel);

const lastAccountLabel =
PreferencesController.state.identities[selectedAddress].name;

PreferencesController.setAccountLabel(
selectedAddress,
this.isAccountLabelDefined(accountLabel)
? accountLabel
: lastAccountLabel,
);
this.setState({ accountLabelEditable: false });
};

Expand Down
39 changes: 39 additions & 0 deletions app/components/UI/LoginOptionsSwitch/LoginOptionsSwitch.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import React from 'react';
import { shallow } from 'enzyme';
import LoginOptionsSwitch from './LoginOptionsSwitch';
import { BIOMETRY_TYPE } from 'react-native-keychain';
import { Provider } from 'react-redux';
import configureMockStore from 'redux-mock-store';
describe('LoginWithBiometricsSwitch', () => {
const mockStore = configureMockStore();
// eslint-disable-next-line @typescript-eslint/no-empty-function
const handleUpdate = (_biometricsEnabled: boolean) => {};
it('should render correctly', () => {
const store = mockStore({});
const wrapper = shallow(
<Provider store={store}>
<LoginOptionsSwitch
shouldRenderBiometricOption={BIOMETRY_TYPE.FACE}
biometryChoiceState
onUpdateBiometryChoice={handleUpdate}
onUpdateRememberMe={handleUpdate}
/>
</Provider>,
);
expect(wrapper).toMatchSnapshot();
});

it('should return empty object when shouldRenderBiometricOption is undefined and allowLoginWithRememberMe is false in settings', () => {
const store = mockStore({});
const wrapper = shallow(
<Provider store={store}>
<LoginOptionsSwitch
onUpdateBiometryChoice={handleUpdate}
onUpdateRememberMe={handleUpdate}
biometryChoiceState
/>
</Provider>,
);
expect(wrapper).toMatchObject({});
});
});
96 changes: 96 additions & 0 deletions app/components/UI/LoginOptionsSwitch/LoginOptionsSwitch.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import React, { useCallback, useState } from 'react';
import { View, Switch, Text } from 'react-native';
import { mockTheme, useAppThemeFromContext } from '../../../util/theme';
import { strings } from '../../../../locales/i18n';
import { BIOMETRY_TYPE } from 'react-native-keychain';
import { createStyles } from './styles';
import {
LOGIN_WITH_BIOMETRICS_SWITCH,
LOGIN_WITH_REMEMBER_ME_SWITCH,
} from '../../../constants/test-ids';
import { useSelector } from 'react-redux';

interface Props {
shouldRenderBiometricOption: BIOMETRY_TYPE | null;
biometryChoiceState: boolean;
onUpdateBiometryChoice: (biometryEnabled: boolean) => void;
onUpdateRememberMe: (rememberMeEnabled: boolean) => void;
}

/**
* View that renders the toggle for login options
* The highest priority login option is biometrics and will always get rendered over other options IF it is enabled.
* If the user has enabled login with remember me in settings and has turned off biometrics then remember me will be the option
* If both of these features are disabled then no options will be rendered
*/
const LoginOptionsSwitch = ({
shouldRenderBiometricOption,
biometryChoiceState,
onUpdateBiometryChoice,
onUpdateRememberMe,
}: Props) => {
const { colors } = useAppThemeFromContext() || mockTheme;
const styles = createStyles(colors);
const allowLoginWithRememberMe = useSelector(
(state: any) => state.security.allowLoginWithRememberMe,
);
const [rememberMeEnabled, setRememberMeEnabled] = useState<boolean>(false);
const onBiometryValueChanged = useCallback(
async (newBiometryChoice: boolean) => {
onUpdateBiometryChoice(newBiometryChoice);
},
[onUpdateBiometryChoice],
);

const onRememberMeValueChanged = useCallback(async () => {
onUpdateRememberMe(!rememberMeEnabled);
setRememberMeEnabled(!rememberMeEnabled);
}, [onUpdateRememberMe, rememberMeEnabled]);

// should only render remember me option if biometrics are disabled and rememberOptionMeEnabled is enabled in security settings
// if both are disabled then this component returns null
if (shouldRenderBiometricOption !== null) {
return (
<View style={styles.container} testID={LOGIN_WITH_BIOMETRICS_SWITCH}>
<Text style={styles.label}>
{strings(
`biometrics.enable_${shouldRenderBiometricOption.toLowerCase()}`,
)}
</Text>
<Switch
onValueChange={onBiometryValueChanged}
value={biometryChoiceState}
style={styles.switch}
trackColor={{
true: colors.primary.default,
false: colors.border.muted,
}}
thumbColor={colors.white}
ios_backgroundColor={colors.border.muted}
/>
</View>
);
} else if (shouldRenderBiometricOption === null && allowLoginWithRememberMe) {
return (
<View style={styles.container} testID={LOGIN_WITH_REMEMBER_ME_SWITCH}>
<Text style={styles.label}>
{strings(`choose_password.remember_me`)}
</Text>
<Switch
onValueChange={onRememberMeValueChanged}
value={rememberMeEnabled}
style={styles.switch}
trackColor={{
true: colors.primary.default,
false: colors.border.muted,
}}
thumbColor={colors.white}
ios_backgroundColor={colors.border.muted}
/>
</View>
);
}
return null;
};

export default React.memo(LoginOptionsSwitch);
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`LoginWithBiometricsSwitch should render correctly 1`] = `
<Component
biometryChoiceState={true}
onUpdateBiometryChoice={[Function]}
onUpdateRememberMe={[Function]}
shouldRenderBiometricOption="Face"
/>
`;
2 changes: 2 additions & 0 deletions app/components/UI/LoginOptionsSwitch/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// eslint-disable-next-line import/prefer-default-export
export { default as LoginOptionsSwitch } from './LoginOptionsSwitch';
27 changes: 27 additions & 0 deletions app/components/UI/LoginOptionsSwitch/styles.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/* eslint-disable import/prefer-default-export */
import { fontStyles } from '../../../styles/common';
import { StyleSheet } from 'react-native';

export const createStyles = (colors: any) =>
StyleSheet.create({
screen: {
flex: 1,
backgroundColor: colors.background.default,
},
container: {
position: 'relative',
marginTop: 20,
marginBottom: 30,
},
label: {
flex: 1,
fontSize: 16,
color: colors.text.default,
...fontStyles.normal,
},
switch: {
position: 'absolute',
top: 0,
right: 0,
},
});
2 changes: 2 additions & 0 deletions app/components/UI/Navbar/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@ export function getNavigationOptionsTitle(
navigation,
isFullScreenModal,
themeColors,
navigationPopEvent,
) {
const innerStyles = StyleSheet.create({
headerTitleStyle: {
Expand All @@ -188,6 +189,7 @@ export function getNavigationOptionsTitle(
},
});
function navigationPop() {
if (navigationPopEvent) trackEvent(navigationPopEvent);
navigation.pop();
}
return {
Expand Down
59 changes: 59 additions & 0 deletions app/components/UI/SecurityOptionToggle/SecurityOptionToggle.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import React, { useCallback } from 'react';
import { Switch, Text, View } from 'react-native';
import { mockTheme, useAppThemeFromContext } from '../../../util/theme';
import { createStyles } from './styles';
import { colors as importedColors } from '../../../styles/common';

interface SecurityOptionsToggleProps {
title: string;
description?: string;
value: boolean;
onOptionUpdated: (enabled: boolean) => void;
testId?: string;
disabled?: boolean;
}

/**
* View that renders the toggle for security options
* This component assumes that the parent will manage the state of the toggle. This is because most of the state is global.
*/
const SecurityOptionToggle = ({
title,
description,
value,
testId,
onOptionUpdated,
disabled,
}: SecurityOptionsToggleProps) => {
const { colors } = useAppThemeFromContext() || mockTheme;
const styles = createStyles(colors);

const handleOnValueChange = useCallback(
(newValue: boolean) => {
onOptionUpdated(newValue);
},
[onOptionUpdated],
);
return (
<View style={styles.setting} testID={testId}>
<Text style={styles.title}>{title}</Text>
{description ? <Text style={styles.desc}>{description}</Text> : null}
<View style={styles.switchElement}>
<Switch
value={value}
onValueChange={(newValue: boolean) => handleOnValueChange(newValue)}
trackColor={{
true: colors.primary.default,
false: colors.border.muted,
}}
thumbColor={importedColors.white}
style={styles.switch}
ios_backgroundColor={colors.border.muted}
disabled={disabled}
/>
</View>
</View>
);
};

export default React.memo(SecurityOptionToggle);
2 changes: 2 additions & 0 deletions app/components/UI/SecurityOptionToggle/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// eslint-disable-next-line import/prefer-default-export
export { default as SecurityOptionToggle } from './SecurityOptionToggle';
32 changes: 32 additions & 0 deletions app/components/UI/SecurityOptionToggle/styles.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/* eslint-disable import/prefer-default-export */
import { fontStyles } from '../../../styles/common';
import { StyleSheet } from 'react-native';

export const createStyles = (colors: any) =>
StyleSheet.create({
title: {
...fontStyles.normal,
color: colors.text.default,
fontSize: 20,
lineHeight: 20,
paddingTop: 4,
marginTop: -4,
},
desc: {
...fontStyles.normal,
color: colors.text.alternative,
fontSize: 14,
lineHeight: 20,
marginTop: 12,
},
switchElement: {
marginTop: 18,
alignSelf: 'flex-start',
},
setting: {
marginTop: 50,
},
switch: {
alignSelf: 'flex-start',
},
});
9 changes: 7 additions & 2 deletions app/components/UI/Transactions/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -369,9 +369,14 @@ class Transactions extends PureComponent {
const colors = this.context.colors || mockTheme.colors;
const styles = createStyles(colors);

const { chainId } = this.props;
const {
chainId,
network: {
provider: { type },
},
} = this.props;
const blockExplorerText = () => {
if (isMainnetByChainId(chainId)) {
if (isMainnetByChainId(chainId) || type !== RPC) {
return strings('transactions.view_full_history_on_etherscan');
}

Expand Down
Loading

0 comments on commit d726caf

Please sign in to comment.