Skip to content

Commit

Permalink
fix(12945): privacy mode and account selection bottom sheet (#12989)
Browse files Browse the repository at this point in the history
## **Description**

Issue: Privacy mode was not hiding account balances within the account
selector bottom sheet at all

Solution: Have the account selector bottom sheet component subscribe to
the `privacyMode` prop which hides the balance of all accounts,
introduce the `disablePrivacyMode` route params so that the account
selector bottom sheet can opt out of privacy mode completely for certain
flows. Cases where this is needed is in the send flow and swap flow. We
do not hide the balance when a user needs to switch between accounts
when sending/swapping

## **Related issues**

Fixes:
[#12945](#12945)

## **Manual testing steps**

1. Turn on privacy mode by clicking the eye icon within the portfolio
balance at the top
2. Click on the account selector in the top to confirm balances for
other accounts are hidden
3. Goto send and swap flow to confirm balances are NOT hidden even when
privacy mode is ON

## **Screenshots/Recordings**

### Send Flow
| Before | After |
|:---:|:---:|

|![before_swap_flow](https://github.com/user-attachments/assets/1a2f5430-8d40-4079-8d8b-187bde859022)|![after_swap_flow](https://github.com/user-attachments/assets/abe20b7d-1ba0-49f0-9848-41085f40bd87)|

### Swap Flow
| Before | After |
|:---:|:---:|

|![before_send_flow](https://github.com/user-attachments/assets/7a43ea0e-a060-454c-9bed-d317e2c768a1)|![after_send_flow](https://github.com/user-attachments/assets/f7e4ed14-0c4e-4a3a-b8ae-812ce92efb4e)|

### **Before**

NA

### **After**

NA

## **Pre-merge author checklist**

- [x] I’ve followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding
Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [x] I've completed the PR template to the best of my ability
- [x] I’ve included tests if applicable
- [x] I’ve documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [x] I’ve applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

## **Pre-merge reviewer checklist**

- [x] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [x] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.
vinnyhoward authored Jan 15, 2025

Verified

This commit was signed with the committer’s verified signature.
Rjvs Robert J Spencer
1 parent b047169 commit 34f0a55
Showing 7 changed files with 22 additions and 71 deletions.
6 changes: 5 additions & 1 deletion app/components/UI/Ramp/components/AccountSelector.tsx
Original file line number Diff line number Diff line change
@@ -35,7 +35,11 @@ const AccountSelector = () => {
const selectedInternalAccount = useSelector(selectSelectedInternalAccount);

const openAccountSelector = () =>
navigation.navigate(...createAccountSelectorNavDetails());
navigation.navigate(
...createAccountSelectorNavDetails({
disablePrivacyMode: true,
}),
);

return (
<SelectorButton onPress={openAccountSelector} style={styles.selector}>
57 changes: 0 additions & 57 deletions app/components/UI/WalletAccount/WalletAccount.test.tsx
Original file line number Diff line number Diff line change
@@ -9,7 +9,6 @@ import renderWithProvider, {
DeepPartial,
} from '../../../util/test/renderWithProvider';
import ClipboardManager from '../../../core/ClipboardManager';
import { createAccountSelectorNavDetails } from '../../../components/Views/AccountSelector';
import { backgroundState } from '../../../util/test/initial-root-state';
import { Account } from '../../hooks/useAccounts';
import {
@@ -134,19 +133,6 @@ describe('WalletAccount', () => {
fireEvent.press(getByTestId(WalletViewSelectorsIDs.ACCOUNT_COPY_BUTTON));
expect(ClipboardManager.setString).toHaveBeenCalledTimes(1);
});

it('should navigate to the account selector screen on account press', () => {
const { getByTestId } = renderWithProvider(<WalletAccount />, {
state: mockInitialState,
});

fireEvent.press(getByTestId(WalletViewSelectorsIDs.ACCOUNT_ICON));
expect(mockNavigate).toHaveBeenCalledWith(
...createAccountSelectorNavDetails({
privacyMode: false,
}),
);
});
it('displays the correct account name', () => {
const { getByText } = renderWithProvider(<WalletAccount />, {
state: mockInitialState,
@@ -176,47 +162,4 @@ describe('WalletAccount', () => {
expect(getByText(customAccountName)).toBeDefined();
});
});

it('should navigate to account selector with privacy mode disabled', () => {
const { getByTestId } = renderWithProvider(<WalletAccount />, {
state: mockInitialState,
});

fireEvent.press(getByTestId(WalletViewSelectorsIDs.ACCOUNT_ICON));
expect(mockNavigate).toHaveBeenCalledWith(
...createAccountSelectorNavDetails({
privacyMode: false,
}),
);
});

it('should navigate to account selector with privacy mode enabled', () => {
const stateWithPrivacyMode = {
...mockInitialState,
engine: {
...mockInitialState.engine,
backgroundState: {
...mockInitialState.engine?.backgroundState,
PreferencesController: {
privacyMode: true,
},
},
},
};

mockSelector.mockImplementation((callback) =>
callback(stateWithPrivacyMode),
);

const { getByTestId } = renderWithProvider(<WalletAccount />, {
state: stateWithPrivacyMode,
});

fireEvent.press(getByTestId(WalletViewSelectorsIDs.ACCOUNT_ICON));
expect(mockNavigate).toHaveBeenCalledWith(
...createAccountSelectorNavDetails({
privacyMode: true,
}),
);
});
});
8 changes: 1 addition & 7 deletions app/components/UI/WalletAccount/WalletAccount.tsx
Original file line number Diff line number Diff line change
@@ -5,7 +5,6 @@ import { useNavigation } from '@react-navigation/native';
import { View } from 'react-native';

// External dependencies
import { selectPrivacyMode } from '../../../selectors/preferencesController';
import { IconName } from '../../../component-library/components/Icons/Icon';
import PickerAccount from '../../../component-library/components/Pickers/PickerAccount';
import { AvatarAccountType } from '../../../component-library/components/Avatars/Avatar/variants/AvatarAccount';
@@ -38,7 +37,6 @@ const WalletAccount = ({ style }: WalletAccountProps, ref: React.Ref<any>) => {
const yourAccountRef = useRef(null);
const accountActionsRef = useRef(null);
const selectedAccount = useSelector(selectSelectedInternalAccount);
const privacyMode = useSelector(selectPrivacyMode);
const { ensName } = useEnsNameByAddress(selectedAccount?.address);
const defaultName = selectedAccount?.metadata?.name;
const accountName = useMemo(
@@ -88,11 +86,7 @@ const WalletAccount = ({ style }: WalletAccountProps, ref: React.Ref<any>) => {
tags: getTraceTags(store.getState()),
op: TraceOperation.AccountList,
});
navigate(
...createAccountSelectorNavDetails({
privacyMode,
}),
);
navigate(...createAccountSelectorNavDetails());
}}
accountTypeLabel={
getLabelTextByAddress(selectedAccount?.address) || undefined
Original file line number Diff line number Diff line change
@@ -59,6 +59,9 @@ const mockInitialState = {
},
},
},
PreferencesController: {
privacyMode: false,
},
},
},
accounts: {
@@ -101,7 +104,7 @@ const mockRoute: AccountSelectorProps['route'] = {
params: {
onSelectAccount: jest.fn((address: string) => address),
checkBalanceError: (balance: string) => balance,
privacyMode: false,
disablePrivacyMode: false,
} as AccountSelectorParams,
};

12 changes: 9 additions & 3 deletions app/components/Views/AccountSelector/AccountSelector.tsx
Original file line number Diff line number Diff line change
@@ -25,6 +25,8 @@ import Button, {
} from '../../../component-library/components/Buttons/Button';
import AddAccountActions from '../AddAccountActions';
import { AccountListBottomSheetSelectorsIDs } from '../../../../e2e/selectors/wallet/AccountListBottomSheet.selectors';
import { selectPrivacyMode } from '../../../selectors/preferencesController';

// Internal dependencies.
import {
AccountSelectorProps,
@@ -40,13 +42,14 @@ import { TraceName, endTrace } from '../../../util/trace';
const AccountSelector = ({ route }: AccountSelectorProps) => {
const dispatch = useDispatch();
const { trackEvent, createEventBuilder } = useMetrics();
const { onSelectAccount, checkBalanceError, privacyMode } =
const { onSelectAccount, checkBalanceError, disablePrivacyMode } =
route.params || {};

const { reloadAccounts } = useSelector((state: RootState) => state.accounts);
// TODO: Replace "any" with type
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const Engine = UntypedEngine as any;
const privacyMode = useSelector(selectPrivacyMode);
const sheetRef = useRef<BottomSheetRef>(null);
const { accounts, ensByAccountAddress } = useAccounts({
checkBalanceError,
@@ -100,7 +103,7 @@ const AccountSelector = ({ route }: AccountSelectorProps) => {
accounts={accounts}
ensByAccountAddress={ensByAccountAddress}
isRemoveAccountEnabled
privacyMode={privacyMode}
privacyMode={privacyMode && !disablePrivacyMode}
testID={AccountListBottomSheetSelectorsIDs.ACCOUNT_LIST_ID}
/>
<View style={styles.sheet}>
@@ -110,7 +113,9 @@ const AccountSelector = ({ route }: AccountSelectorProps) => {
width={ButtonWidthTypes.Full}
size={ButtonSize.Lg}
onPress={() => setScreen(AccountSelectorScreens.AddAccountActions)}
testID={AccountListBottomSheetSelectorsIDs.ACCOUNT_LIST_ADD_BUTTON_ID}
testID={
AccountListBottomSheetSelectorsIDs.ACCOUNT_LIST_ADD_BUTTON_ID
}
/>
</View>
</Fragment>
@@ -121,6 +126,7 @@ const AccountSelector = ({ route }: AccountSelectorProps) => {
ensByAccountAddress,
onRemoveImportedAccount,
privacyMode,
disablePrivacyMode,
],
);

4 changes: 2 additions & 2 deletions app/components/Views/AccountSelector/AccountSelector.types.ts
Original file line number Diff line number Diff line change
@@ -36,9 +36,9 @@ export interface AccountSelectorParams {
*/
checkBalanceError?: UseAccountsParams['checkBalanceError'];
/**
* Optional boolean to indicate if privacy mode is enabled.
* Optional boolean to indicate if privacy mode is disabled.
*/
privacyMode?: boolean;
disablePrivacyMode?: boolean;
}

/**
Original file line number Diff line number Diff line change
@@ -131,6 +131,7 @@ const SendFlowAddressFrom = ({
params: {
isSelectOnly: true,
onSelectAccount,
disablePrivacyMode: true,
},
});
};

0 comments on commit 34f0a55

Please sign in to comment.