Skip to content

Commit 39264fa

Browse files
refactor(bridge): use MMDS HeaderStandard (#29700)
## **Description** Bridge **Default** and **Custom** slippage bottom sheets still used `HeaderCompactStandard` from `component-library`. This migrates both to **`HeaderStandard`** from `@metamask/design-system-react-native` so slippage UI follows the same header pattern as the rest of the app and reduces reliance on the temporary header component. --- ## **Changelog** CHANGELOG entry: null --- ## **Related issues** Fixes: https://consensyssoftware.atlassian.net/browse/DSYS-697 --- ## **Manual testing steps** ```gherkin Feature: Bridge slippage modal header Scenario: Default slippage sheet shows expected header and closes Given the user is on the Bridge flow with slippage configurable When the user opens the default slippage modal Then the sheet title shows the slippage string (same as before) And the user can dismiss the sheet with the close control Scenario: Custom slippage sheet shows expected header and closes Given the user is on the Bridge flow with custom slippage available When the user opens the custom slippage modal Then the sheet title shows the slippage string (same as before) And the user can dismiss the sheet with the close control ``` --- ## **Screenshots/Recordings** ### **Before** ### **After** --- ## **Pre-merge author checklist** <!-- Every checklist item must be consciously assessed before marking this PR as "Ready for review". A checked box means you deliberately considered that responsibility, not that you literally performed every action listed. Unchecked boxes are ambiguous: they are not an implicit "N/A" and they are not a silent "skip". See `docs/readme/ready-for-review.md` for the full checklist semantics. --> - [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. #### Performance checks (if applicable) - [ ] I've tested on Android - Ideally on a mid-range device; emulator is acceptable - [ ] I've tested with a power user scenario - Use these [power-user SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93) to import wallets with many accounts and tokens - [ ] I've instrumented key operations with Sentry traces for production performance metrics - See [`trace()`](/app/util/trace.ts) for usage and [`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274) for an example For performance guidelines and tooling, see the [Performance Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers). ## **Pre-merge reviewer checklist** <!-- Reviewer checklist items follow the same semantics as the author checklist: an unchecked box is ambiguous, a checked box means the reviewer consciously assessed that responsibility. See `docs/readme/ready-for-review.md`. --> - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] 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. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Low risk UI refactor limited to swapping header components and updating accessibility labels/translations; behavior changes should be confined to close button props and related tests. > > **Overview** > Bridge slippage bottom sheets (default and custom) now use MMDS `HeaderStandard` instead of the temporary `HeaderCompactStandard`, wiring `onClose` through the new header API. > > Adds a localized `bridge.close` string and updates modal tests to assert the header close button via `accessibilityLabel` from i18n rather than a hardcoded "Close" mock. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 566ed03. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY --> --------- Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent ff95f16 commit 39264fa

5 files changed

Lines changed: 18 additions & 49 deletions

File tree

app/components/UI/Bridge/components/SlippageModal/CustomSlippageModal.test.tsx

Lines changed: 4 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -25,27 +25,6 @@ jest.mock(
2525
},
2626
);
2727

28-
// Mock HeaderCompactStandard
29-
jest.mock(
30-
'../../../../../component-library/components-temp/HeaderCompactStandard',
31-
() => {
32-
const ReactNative = jest.requireActual('react-native');
33-
const { View, Text, TouchableOpacity } = ReactNative;
34-
35-
return {
36-
__esModule: true,
37-
default: (props: { title: string; onClose: () => void }) => (
38-
<View testID="header-center">
39-
<Text>{props.title}</Text>
40-
<TouchableOpacity onPress={props.onClose} accessibilityLabel="Close">
41-
<Text>Close</Text>
42-
</TouchableOpacity>
43-
</View>
44-
),
45-
};
46-
},
47-
);
48-
4928
// Mock InputStepper
5029
jest.mock('../InputStepper', () => ({
5130
InputStepper: jest.fn(
@@ -172,6 +151,7 @@ jest.mock('../../../../../../locales/i18n', () => ({
172151
'bridge.slippage': 'Slippage',
173152
'bridge.cancel': 'Cancel',
174153
'bridge.confirm': 'Confirm',
154+
'bridge.close': 'Close',
175155
};
176156
return translations[key] || key;
177157
}),
@@ -183,6 +163,7 @@ import { useSlippageStepperDescription } from '../../hooks/useSlippageStepperDes
183163
import { useParams } from '../../../../../util/navigation/navUtils';
184164
import { InputStepper } from '../InputStepper';
185165
import Keypad from '../../../../Base/Keypad';
166+
import { strings } from '../../../../../../locales/i18n';
186167

187168
const mockUseSlippageConfig = useSlippageConfig as jest.MockedFunction<
188169
typeof useSlippageConfig
@@ -1041,7 +1022,7 @@ describe('CustomSlippageModal', () => {
10411022
it('closes modal via header close button', () => {
10421023
const { getByLabelText } = render(<CustomSlippageModal />);
10431024

1044-
const closeButton = getByLabelText('Close');
1025+
const closeButton = getByLabelText(strings('bridge.close'));
10451026
fireEvent.press(closeButton);
10461027

10471028
// Verify it doesn't throw and component handles close
@@ -1051,7 +1032,7 @@ describe('CustomSlippageModal', () => {
10511032
it('does not dispatch slippage when closing without confirm', () => {
10521033
const { getByLabelText } = render(<CustomSlippageModal />);
10531034

1054-
const closeButton = getByLabelText('Close');
1035+
const closeButton = getByLabelText(strings('bridge.close'));
10551036
fireEvent.press(closeButton);
10561037

10571038
expect(mockDispatch).not.toHaveBeenCalled();

app/components/UI/Bridge/components/SlippageModal/CustomSlippageModal.tsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,13 @@ import React, { useCallback, useRef, useState } from 'react';
22
import BottomSheet, {
33
BottomSheetRef,
44
} from '../../../../../component-library/components/BottomSheets/BottomSheet';
5-
import HeaderCompactStandard from '../../../../../component-library/components-temp/HeaderCompactStandard';
65
import { strings } from '../../../../../../locales/i18n';
76
import { View } from 'react-native';
87
import {
98
Button,
109
ButtonSize,
1110
ButtonVariant,
11+
HeaderStandard,
1212
} from '@metamask/design-system-react-native';
1313
import Keypad from '../../../../Base/Keypad';
1414
import { InputStepper } from '../InputStepper';
@@ -97,9 +97,12 @@ export const CustomSlippageModal = () => {
9797

9898
return (
9999
<BottomSheet ref={sheetRef}>
100-
<HeaderCompactStandard
100+
<HeaderStandard
101101
title={strings('bridge.slippage')}
102102
onClose={handleClose}
103+
closeButtonProps={{
104+
accessibilityLabel: strings('bridge.close'),
105+
}}
103106
/>
104107
<View style={customSlippageModalStyles.stepperContainer}>
105108
<InputStepper

app/components/UI/Bridge/components/SlippageModal/DefaultSlippageModal.test.tsx

Lines changed: 3 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -22,27 +22,6 @@ jest.mock(
2222
},
2323
);
2424

25-
// Mock HeaderCompactStandard
26-
jest.mock(
27-
'../../../../../component-library/components-temp/HeaderCompactStandard',
28-
() => {
29-
const ReactNative = jest.requireActual('react-native');
30-
const { View, Text, TouchableOpacity } = ReactNative;
31-
32-
return {
33-
__esModule: true,
34-
default: (props: { title: string; onClose: () => void }) => (
35-
<View testID="header-center">
36-
<Text>{props.title}</Text>
37-
<TouchableOpacity onPress={props.onClose} accessibilityLabel="Close">
38-
<Text>Close</Text>
39-
</TouchableOpacity>
40-
</View>
41-
),
42-
};
43-
},
44-
);
45-
4625
// Mock dependencies
4726
jest.mock('./DefaultSlippageButtonGroup', () => ({
4827
DefaultSlippageButtonGroup: jest.fn(({ options }) => {
@@ -106,6 +85,7 @@ jest.mock('../../../../../../locales/i18n', () => ({
10685
'bridge.slippage': 'Slippage',
10786
'bridge.default_slippage_description': 'Set your slippage tolerance',
10887
'bridge.submit': 'Submit',
88+
'bridge.close': 'Close',
10989
};
11090
return translations[key] || key;
11191
}),
@@ -115,6 +95,7 @@ import { useGetSlippageOptions } from '../../hooks/useGetSlippageOptions';
11595
import { useSlippageConfig } from '../../hooks/useSlippageConfig';
11696
import { useParams } from '../../../../../util/navigation/navUtils';
11797
import { AUTO_SLIPPAGE_VALUE } from './constants';
98+
import { strings } from '../../../../../../locales/i18n';
11899

119100
const mockUseGetSlippageOptions = useGetSlippageOptions as jest.MockedFunction<
120101
typeof useGetSlippageOptions
@@ -215,7 +196,7 @@ describe('DefaultSlippageModal', () => {
215196
it('closes bottom sheet when close is called', () => {
216197
const { getByLabelText } = render(<DefaultSlippageModal />);
217198

218-
const closeButton = getByLabelText('Close');
199+
const closeButton = getByLabelText(strings('bridge.close'));
219200
fireEvent.press(closeButton);
220201

221202
// Bottom sheet close is handled internally by ref

app/components/UI/Bridge/components/SlippageModal/DefaultSlippageModal.tsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import React, { useCallback, useRef, useState } from 'react';
2-
import HeaderCompactStandard from '../../../../../component-library/components-temp/HeaderCompactStandard';
32
import BottomSheet, {
43
BottomSheetRef,
54
} from '../../../../../component-library/components/BottomSheets/BottomSheet';
@@ -9,6 +8,7 @@ import {
98
Button,
109
ButtonSize,
1110
ButtonVariant,
11+
HeaderStandard,
1212
Text,
1313
} from '@metamask/design-system-react-native';
1414
import { DefaultSlippageButtonGroup } from './DefaultSlippageButtonGroup';
@@ -80,9 +80,12 @@ export const DefaultSlippageModal = () => {
8080

8181
return (
8282
<BottomSheet ref={sheetRef}>
83-
<HeaderCompactStandard
83+
<HeaderStandard
8484
title={strings('bridge.slippage')}
8585
onClose={handleClose}
86+
closeButtonProps={{
87+
accessibilityLabel: strings('bridge.close'),
88+
}}
8689
/>
8790
<View style={styles.descriptionContainer}>
8891
<Text style={styles.descriptionText}>

locales/languages/en.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7368,6 +7368,7 @@
73687368
"price_impact_execution_description": "You'll lose approximately {{priceImpact}} of your token's value on this swap. Try lowering the amount or choosing a more liquid route.",
73697369
"proceed": "Proceed",
73707370
"cancel": "Cancel",
7371+
"close": "Close",
73717372
"slippage_info_title": "Slippage",
73727373
"slippage_info_description": "The % change in price you're willing to allow before your transaction is canceled.",
73737374
"blockaid_error_title": "This transaction will be reverted",

0 commit comments

Comments
 (0)