Skip to content

Commit

Permalink
refactor(1702-3): batch account balance component (#11368)
Browse files Browse the repository at this point in the history
## **Description**

This PR is part of a series that breaks down the original [large PR
#11127](#11127) into
smaller, more manageable chunks.

The `BatchAccountBalance` functionality is valuable beyond its original
implementation. By converting it into a reusable component, we can:
1. Improve code maintainability
2. Reduce duplication
3. Enhance consistency across the application and ease of use

### Changes
- Extracted `BatchAccountBalance` logic from its original location
`SecuritySettings` and into a separate component file
- Included new tests
- Updated the `SecuritySettings` to use the new component
- Removed related tests/constants within `SecuritySettings` and moved
them into the new component folder

### Impact
This refactored component will be used in:
- Its current original screen which is `SecuritySettings`
- New screens coming from the enhanced onboarding settings
[#1702](MetaMask/mobile-planning#1702) that is
currently under progress

## **Related issues**

Feature:
[#1702](MetaMask/mobile-planning#1702)

## **Manual testing steps**

1. Make sure to have at least 2 accounts with a balance
2. On the wallet home screen click on the accounts drop down and you
will see a bottom sheet modal appear with your account names as well as
a balance for all of your accounts
3. Goto the security settings screen, find the "Batch account balance
requests" section, and tap to toggle off
4. Go back to the wallet home screen and click on the account picker
once again
5. Your active account should show your balance in the bottom sheet
however inactive account balances will not be shown
6. Repeat steps to toggle on/off to see your inactive balance appear and
disappear

## **Screenshots/Recordings**


![batch_account](https://github.com/user-attachments/assets/769a012e-f8ff-47da-baf4-dbc7d797dba3)

### **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.
  • Loading branch information
vinnyhoward authored Oct 4, 2024
1 parent 4093fdf commit bdc9043
Show file tree
Hide file tree
Showing 9 changed files with 316 additions and 60 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`BatchAccountBalanceSettings should render correctly 1`] = `
<View
style={
{
"marginTop": 16,
}
}
testID="batch-balance-requests-section"
>
<View
style={
{
"alignItems": "center",
"flexDirection": "row",
}
}
>
<Text
accessibilityRole="text"
style={
{
"color": "#141618",
"flex": 1,
"fontFamily": "EuclidCircularB-Medium",
"fontSize": 16,
"fontWeight": "500",
"letterSpacing": 0,
"lineHeight": 24,
}
}
>
Batch account balance requests
</Text>
<View
style={
{
"marginLeft": 16,
}
}
>
<RCTSwitch
accessibilityRole="switch"
onChange={[Function]}
onResponderTerminationRequest={[Function]}
onStartShouldSetResponder={[Function]}
onTintColor="#0376c9"
style={
[
{
"height": 31,
"width": 51,
},
[
{
"alignSelf": "flex-start",
},
{
"backgroundColor": "#bbc0c566",
"borderRadius": 16,
},
],
]
}
testID="security-settings-multi-account-balances-switch"
thumbTintColor="#ffffff"
tintColor="#bbc0c566"
value={false}
/>
</View>
</View>
<Text
accessibilityRole="text"
style={
{
"color": "#6a737d",
"fontFamily": "EuclidCircularB-Regular",
"fontSize": 14,
"fontWeight": "400",
"letterSpacing": 0,
"lineHeight": 22,
"marginTop": 8,
}
}
>
We batch accounts and query Infura to responsively show your balances. If you turn this off, only active accounts will be queried. Some dApps won’t work unless you connect your wallet.
</Text>
</View>
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export const BATCH_BALANCE_REQUESTS_SECTION = 'batch-balance-requests-section';
export const SECURITY_PRIVACY_MULTI_ACCOUNT_BALANCES_TOGGLE_ID =
'security-settings-multi-account-balances-switch';
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { StyleSheet } from 'react-native';

const styleSheet = () =>
StyleSheet.create({
titleContainer: {
flexDirection: 'row',
alignItems: 'center',
},
title: {
flex: 1,
},
switchElement: {
marginLeft: 16,
},
switch: {
alignSelf: 'flex-start',
},
halfSetting: {
marginTop: 16,
},
desc: {
marginTop: 8,
},
});

export default styleSheet;
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
import React from 'react';
import { fireEvent } from '@testing-library/react-native';
import Engine from '../../../../core/Engine';
import renderWithProvider from '../../../../util/test/renderWithProvider';
import { backgroundState } from '../../../../util/test/initial-root-state';
import BatchAccountBalanceSettings from './';
import { SECURITY_PRIVACY_MULTI_ACCOUNT_BALANCES_TOGGLE_ID } from './index.constants';

let mockSetIsMultiAccountBalancesEnabled: jest.Mock;

beforeEach(() => {
mockSetIsMultiAccountBalancesEnabled.mockClear();
});

const mockEngine = Engine;

jest.mock('../../../../core/Engine', () => {
mockSetIsMultiAccountBalancesEnabled = jest.fn();
return {
init: () => mockEngine.init({}),
context: {
PreferencesController: {
setIsMultiAccountBalancesEnabled: mockSetIsMultiAccountBalancesEnabled,
},
},
};
});

describe('BatchAccountBalanceSettings', () => {
beforeEach(() => {
jest.clearAllMocks();
});

const initialState = {
engine: {
backgroundState: {
...backgroundState,
PreferencesController: {
...backgroundState.PreferencesController,
isMultiAccountBalancesEnabled: false,
},
},
},
};

it('should render correctly', () => {
const tree = renderWithProvider(<BatchAccountBalanceSettings />, {
state: initialState,
});
expect(tree).toMatchSnapshot();
});

it('should display correct initial state of multi-account balances toggle', () => {
const stateWithMultiAccountBalancesEnabled = {
...initialState,
engine: {
backgroundState: {
...initialState.engine.backgroundState,
PreferencesController: {
...initialState.engine.backgroundState.PreferencesController,
isMultiAccountBalancesEnabled: true,
},
},
},
};

const { getByTestId } = renderWithProvider(
<BatchAccountBalanceSettings />,
{
state: stateWithMultiAccountBalancesEnabled,
},
);

const multiAccountBalancesToggle = getByTestId(
SECURITY_PRIVACY_MULTI_ACCOUNT_BALANCES_TOGGLE_ID,
);

expect(multiAccountBalancesToggle.props.value).toBe(true);
});

it('should call setIsMultiAccountBalancesEnabled when toggle is pressed', () => {
const { getByTestId } = renderWithProvider(
<BatchAccountBalanceSettings />,
{
state: initialState,
},
);

const multiAccountBalancesToggle = getByTestId(
SECURITY_PRIVACY_MULTI_ACCOUNT_BALANCES_TOGGLE_ID,
);

fireEvent(multiAccountBalancesToggle, 'onValueChange', true);

expect(mockSetIsMultiAccountBalancesEnabled).toHaveBeenCalledWith(true);
});

it('should call setIsMultiAccountBalancesEnabled with correct values when toggled', () => {
const { getByTestId } = renderWithProvider(
<BatchAccountBalanceSettings />,
{
state: initialState,
},
);

const multiAccountBalancesToggle = getByTestId(
SECURITY_PRIVACY_MULTI_ACCOUNT_BALANCES_TOGGLE_ID,
);

expect(multiAccountBalancesToggle.props.value).toBe(false);

fireEvent(multiAccountBalancesToggle, 'onValueChange', true);

expect(mockSetIsMultiAccountBalancesEnabled).toHaveBeenCalledWith(true);

fireEvent(multiAccountBalancesToggle, 'onValueChange', false);

expect(mockSetIsMultiAccountBalancesEnabled).toHaveBeenCalledWith(false);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import React, { useCallback } from 'react';
import { View, Switch, Platform } from 'react-native';
import { useSelector } from 'react-redux';
import Engine from '../../../../core/Engine';
import { selectIsMultiAccountBalancesEnabled } from '../../../../selectors/preferencesController';
import { strings } from '../../../../../locales/i18n';
import { useTheme } from '../../../../util/theme';
import { useStyles } from '../../../../component-library/hooks';
import Text, {
TextVariant,
TextColor,
} from '../../../../component-library/components/Texts/Text';
import generateTestId from '../../../../../wdio/utils/generateTestId';
import styleSheet from './index.styles';
import {
BATCH_BALANCE_REQUESTS_SECTION,
SECURITY_PRIVACY_MULTI_ACCOUNT_BALANCES_TOGGLE_ID,
} from './index.constants';

const BatchAccountBalanceSettings = () => {
const { PreferencesController } = Engine.context;
const theme = useTheme();
const { colors } = theme;
const { styles } = useStyles(styleSheet, {});

const isMultiAccountBalancesEnabled = useSelector(
selectIsMultiAccountBalancesEnabled,
);

const toggleIsMultiAccountBalancesEnabled = useCallback(
(multiAccountBalancesEnabled: boolean) => {
PreferencesController.setIsMultiAccountBalancesEnabled(
multiAccountBalancesEnabled,
);
},
[PreferencesController],
);

return (
<View style={styles.halfSetting} testID={BATCH_BALANCE_REQUESTS_SECTION}>
<View style={styles.titleContainer}>
<Text variant={TextVariant.BodyLGMedium} style={styles.title}>
{strings('app_settings.batch_balance_requests_title')}
</Text>
<View style={styles.switchElement}>
<Switch
value={isMultiAccountBalancesEnabled}
onValueChange={toggleIsMultiAccountBalancesEnabled}
trackColor={{
true: colors.primary.default,
false: colors.border.muted,
}}
thumbColor={theme.brandColors.white}
style={styles.switch}
ios_backgroundColor={colors.border.muted}
{...generateTestId(
Platform,
SECURITY_PRIVACY_MULTI_ACCOUNT_BALANCES_TOGGLE_ID,
)}
/>
</View>
</View>
<Text
variant={TextVariant.BodyMD}
color={TextColor.Alternative}
style={styles.desc}
>
{strings('app_settings.batch_balance_requests_description')}
</Text>
</View>
);
};

export default BatchAccountBalanceSettings;
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ export const META_METRICS_DATA_MARKETING_SECTION =
export const DELETE_METRICS_BUTTON = 'delete-metrics-button';
export const SECURITY_SETTINGS_DELETE_WALLET_BUTTON =
'security-settings-delete-wallet-buttons';
export const BATCH_BALANCE_REQUESTS_SECTION = 'batch-balance-requests-section';
export const THIRD_PARTY_SECTION = 'third-party-section';
export const NFT_DISPLAY_MEDIA_MODE_SECTION = 'nft-display-media-mode-section';
export const NFT_AUTO_DETECT_MODE_SECTION =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import SecuritySettings from './SecuritySettings';
import { backgroundState } from '../../../../util/test/initial-root-state';
import { AUTO_LOCK_SECTION } from './Sections/AutoLock/constants';
import {
BATCH_BALANCE_REQUESTS_SECTION,
CLEAR_BROWSER_HISTORY_SECTION,
CLEAR_PRIVACY_SECTION,
DELETE_METRICS_BUTTON,
Expand Down Expand Up @@ -108,7 +107,6 @@ describe('SecuritySettings', () => {
expect(getByTestId(DELETE_METRICS_BUTTON)).toBeTruthy();
expect(getByTestId(META_METRICS_DATA_MARKETING_SECTION)).toBeTruthy();
expect(getByTestId(SECURITY_SETTINGS_DELETE_WALLET_BUTTON)).toBeTruthy();
expect(getByTestId(BATCH_BALANCE_REQUESTS_SECTION)).toBeTruthy();
expect(SecurityPrivacyViewSelectorsIDs.INCOMING_TRANSACTIONS).toBeTruthy();
expect(getByTestId(NFT_DISPLAY_MEDIA_MODE_SECTION)).toBeTruthy();
expect(getByTestId(NFT_AUTO_DETECT_MODE_SECTION)).toBeTruthy();
Expand Down
Loading

0 comments on commit bdc9043

Please sign in to comment.