Skip to content

Commit 14991d2

Browse files
feat: add network fees modal
1 parent 04975be commit 14991d2

11 files changed

Lines changed: 211 additions & 7 deletions

File tree

app/components/UI/Bridge/components/BatchSellFinalReviewModal/BatchSellFinalReviewModal.test.tsx

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ describe('BatchSellFinalReviewModal', () => {
131131
expect(getByText('UNI • 0.5% slippage')).toBeOnTheScreen();
132132
});
133133

134-
it('swaps to the minimum received info modal when the info button is pressed', () => {
134+
it('switches to the minimum received info modal when the info button is pressed', () => {
135135
const { getByTestId } = renderModal();
136136

137137
fireEvent.press(
@@ -151,6 +151,26 @@ describe('BatchSellFinalReviewModal', () => {
151151
);
152152
});
153153

154+
it('switches to the network fee info modal when the info button is pressed', () => {
155+
const { getByTestId } = renderModal();
156+
157+
fireEvent.press(
158+
getByTestId(
159+
BatchSellFinalReviewModalSelectorsIDs.NETWORK_FEE_INFO_BUTTON,
160+
),
161+
);
162+
163+
expect(mockReplace).toHaveBeenCalledWith(
164+
Routes.BRIDGE.MODALS.BATCH_SELL_NETWORK_FEE_INFO_MODAL,
165+
{
166+
sourceModal: {
167+
screen: Routes.BRIDGE.MODALS.BATCH_SELL_FINAL_REVIEW_MODAL,
168+
params: defaultParams,
169+
},
170+
},
171+
);
172+
});
173+
154174
it('renders quote amount skeletons while loading', () => {
155175
const { getByTestId, getByText, queryByText } = renderModal({
156176
isLoading: true,

app/components/UI/Bridge/components/BatchSellFinalReviewModal/BatchSellFinalReviewModal.testIds.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ export const BatchSellFinalReviewModalSelectorsIDs = {
55
YOU_SELL_TOGGLE_BUTTON: 'batch-sell-final-review-you-sell-toggle-button',
66
SOURCE_TOKEN_AVATAR: 'batch-sell-final-review-source-token-avatar',
77
NETWORK_FEE_ROW: 'batch-sell-final-review-network-fee-row',
8+
NETWORK_FEE_INFO_BUTTON: 'batch-sell-final-review-network-fee-info-button',
89
SELL_ALL_BUTTON: 'batch-sell-final-review-sell-all-button',
910
METAMASK_FEE_DISCLOSURE: 'batch-sell-final-review-metamask-fee-disclosure',
1011
};

app/components/UI/Bridge/components/BatchSellFinalReviewModal/index.tsx

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -133,9 +133,11 @@ function YouSellRow({
133133
function NetworkFeeRow({
134134
networkFee,
135135
networkFeeFiat,
136+
onInfoPress,
136137
}: {
137138
networkFee: string;
138139
networkFeeFiat: string;
140+
onInfoPress: () => void;
139141
}) {
140142
return (
141143
<Box
@@ -158,11 +160,17 @@ function NetworkFeeRow({
158160
>
159161
{strings('bridge.network_fee')}
160162
</Text>
161-
<Icon
162-
name={IconName.Info}
163-
size={IconSize.Sm}
164-
color={IconColor.IconAlternative}
165-
/>
163+
<Pressable
164+
onPress={onInfoPress}
165+
testID={BatchSellFinalReviewModalSelectorsIDs.NETWORK_FEE_INFO_BUTTON}
166+
accessibilityRole="button"
167+
>
168+
<Icon
169+
name={IconName.Info}
170+
size={IconSize.Sm}
171+
color={IconColor.IconAlternative}
172+
/>
173+
</Pressable>
166174
</Box>
167175
<Box
168176
flexDirection={BoxFlexDirection.Row}
@@ -214,6 +222,15 @@ export function BatchSellFinalReviewModal() {
214222
);
215223
};
216224

225+
const handleOpenNetworkFeeInfo = () => {
226+
navigation.replace(Routes.BRIDGE.MODALS.BATCH_SELL_NETWORK_FEE_INFO_MODAL, {
227+
sourceModal: {
228+
screen: Routes.BRIDGE.MODALS.BATCH_SELL_FINAL_REVIEW_MODAL,
229+
params,
230+
},
231+
});
232+
};
233+
217234
return (
218235
<BottomSheet
219236
testID={BatchSellFinalReviewModalSelectorsIDs.SHEET}
@@ -244,6 +261,7 @@ export function BatchSellFinalReviewModal() {
244261
<NetworkFeeRow
245262
networkFee={params.networkFee}
246263
networkFeeFiat={params.networkFeeFiat}
264+
onInfoPress={handleOpenNetworkFeeInfo}
247265
/>
248266
<Box paddingHorizontal={4} paddingTop={4} paddingBottom={4} gap={2}>
249267
<Button
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
import React from 'react';
2+
import { fireEvent, render } from '@testing-library/react-native';
3+
4+
import { strings } from '../../../../../../locales/i18n';
5+
import { BatchSellNetworkFeeInfoModal } from './index';
6+
import { BatchSellNetworkFeeInfoModalSelectorsIDs } from './BatchSellNetworkFeeInfoModal.testIds';
7+
import { BatchSellNetworkFeeInfoModalParams } from './BatchSellNetworkFeeInfoModal.types';
8+
9+
const mockGoBack = jest.fn();
10+
const mockReplace = jest.fn();
11+
let mockRouteParams: BatchSellNetworkFeeInfoModalParams;
12+
13+
jest.mock('@react-navigation/native', () => ({
14+
useNavigation: () => ({
15+
goBack: mockGoBack,
16+
replace: mockReplace,
17+
}),
18+
}));
19+
20+
jest.mock('../../../../../util/navigation/navUtils', () => ({
21+
useParams: () => mockRouteParams,
22+
}));
23+
24+
function renderModal(params: BatchSellNetworkFeeInfoModalParams = {}) {
25+
mockRouteParams = params;
26+
27+
return render(<BatchSellNetworkFeeInfoModal />);
28+
}
29+
30+
describe('BatchSellNetworkFeeInfoModal', () => {
31+
beforeEach(() => {
32+
jest.clearAllMocks();
33+
mockRouteParams = {};
34+
});
35+
36+
it('renders the network fee information', () => {
37+
const { getByTestId, getByText } = renderModal();
38+
39+
expect(
40+
getByTestId(BatchSellNetworkFeeInfoModalSelectorsIDs.SHEET),
41+
).toBeOnTheScreen();
42+
expect(
43+
getByText(strings('bridge.network_fee_info_title')),
44+
).toBeOnTheScreen();
45+
expect(
46+
getByTestId(BatchSellNetworkFeeInfoModalSelectorsIDs.DESCRIPTION),
47+
).toBeOnTheScreen();
48+
expect(
49+
getByText(strings('bridge.network_fee_info_content')),
50+
).toBeOnTheScreen();
51+
});
52+
53+
it('closes with navigation when the close button is pressed', () => {
54+
const { getByTestId } = renderModal();
55+
56+
fireEvent.press(
57+
getByTestId(BatchSellNetworkFeeInfoModalSelectorsIDs.CLOSE_BUTTON),
58+
);
59+
60+
expect(mockGoBack).toHaveBeenCalledTimes(1);
61+
});
62+
63+
it('restores the source modal when the back button is pressed', () => {
64+
const sourceModal = {
65+
screen: 'BatchSellFinalReviewModal',
66+
params: {
67+
networkFee: '1.20 USDC',
68+
},
69+
};
70+
const { getByTestId } = renderModal({ sourceModal });
71+
72+
fireEvent.press(
73+
getByTestId(BatchSellNetworkFeeInfoModalSelectorsIDs.BACK_BUTTON),
74+
);
75+
76+
expect(mockReplace).toHaveBeenCalledWith(
77+
sourceModal.screen,
78+
sourceModal.params,
79+
);
80+
});
81+
82+
it('does not render a back button without a source modal', () => {
83+
const { queryByTestId } = renderModal();
84+
85+
expect(
86+
queryByTestId(BatchSellNetworkFeeInfoModalSelectorsIDs.BACK_BUTTON),
87+
).toBeNull();
88+
});
89+
});
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
export const BatchSellNetworkFeeInfoModalSelectorsIDs = {
2+
SHEET: 'batch-sell-network-fee-info-modal-sheet',
3+
BACK_BUTTON: 'batch-sell-network-fee-info-modal-back-button',
4+
CLOSE_BUTTON: 'batch-sell-network-fee-info-modal-close-button',
5+
DESCRIPTION: 'batch-sell-network-fee-info-modal-description',
6+
};
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
export interface BatchSellNetworkFeeInfoModalParams {
2+
sourceModal?: {
3+
screen: string;
4+
params?: object;
5+
};
6+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import { useNavigation } from '@react-navigation/native';
2+
import { StackNavigationProp } from '@react-navigation/stack';
3+
import React from 'react';
4+
import {
5+
BottomSheet,
6+
BottomSheetHeader,
7+
Box,
8+
ButtonIconSize,
9+
Text,
10+
TextColor,
11+
TextVariant,
12+
} from '@metamask/design-system-react-native';
13+
14+
import { strings } from '../../../../../../locales/i18n';
15+
import { useParams } from '../../../../../util/navigation/navUtils';
16+
import { BatchSellNetworkFeeInfoModalSelectorsIDs } from './BatchSellNetworkFeeInfoModal.testIds';
17+
import { BatchSellNetworkFeeInfoModalParams } from './BatchSellNetworkFeeInfoModal.types';
18+
19+
export function BatchSellNetworkFeeInfoModal() {
20+
const navigation =
21+
useNavigation<StackNavigationProp<Record<string, object | undefined>>>();
22+
const { sourceModal } = useParams<BatchSellNetworkFeeInfoModalParams>();
23+
const handleBack = sourceModal
24+
? () => navigation.replace(sourceModal.screen, sourceModal.params)
25+
: undefined;
26+
27+
return (
28+
<BottomSheet
29+
testID={BatchSellNetworkFeeInfoModalSelectorsIDs.SHEET}
30+
goBack={navigation.goBack}
31+
>
32+
<BottomSheetHeader
33+
onBack={handleBack}
34+
backButtonProps={{
35+
testID: BatchSellNetworkFeeInfoModalSelectorsIDs.BACK_BUTTON,
36+
}}
37+
onClose={navigation.goBack}
38+
closeButtonProps={{
39+
size: ButtonIconSize.Md,
40+
testID: BatchSellNetworkFeeInfoModalSelectorsIDs.CLOSE_BUTTON,
41+
}}
42+
>
43+
{strings('bridge.network_fee_info_title')}
44+
</BottomSheetHeader>
45+
<Box paddingHorizontal={4} paddingTop={2} paddingBottom={4}>
46+
<Text
47+
variant={TextVariant.BodySm}
48+
color={TextColor.TextAlternative}
49+
testID={BatchSellNetworkFeeInfoModalSelectorsIDs.DESCRIPTION}
50+
>
51+
{strings('bridge.network_fee_info_content')}
52+
</Text>
53+
</Box>
54+
</BottomSheet>
55+
);
56+
}

app/components/UI/Bridge/components/BatchSellQuoteDetailsModal/BatchSellQuoteDetailsModal.test.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ describe('BatchSellQuoteDetailsModal', () => {
173173
expect(onMinimumReceivedInfoPress).toHaveBeenCalledTimes(1);
174174
});
175175

176-
it('swaps to the minimum received info modal when the info button is pressed', () => {
176+
it('switches to the minimum received info modal when the info button is pressed', () => {
177177
const { getByTestId } = renderModal();
178178

179179
fireEvent.press(

app/components/UI/Bridge/routes.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import { HighRateAlertModal } from './components/HighRateAlertModal';
2626
import { BatchSellDestinationTokenSelectorModal } from './components/BatchSellDestinationTokenSelectorModal';
2727
import { BatchSellQuoteDetailsModal } from './components/BatchSellQuoteDetailsModal';
2828
import { BatchSellFinalReviewModal } from './components/BatchSellFinalReviewModal';
29+
import { BatchSellNetworkFeeInfoModal } from './components/BatchSellNetworkFeeInfoModal';
2930
import { BatchSellMinimumReceivedInfoModal } from './components/BatchSellMinimumReceivedInfoModal';
3031

3132
// eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -128,6 +129,10 @@ export const BridgeModalStack = () => (
128129
name={Routes.BRIDGE.MODALS.BATCH_SELL_FINAL_REVIEW_MODAL}
129130
component={BatchSellFinalReviewModal}
130131
/>
132+
<ModalStack.Screen
133+
name={Routes.BRIDGE.MODALS.BATCH_SELL_NETWORK_FEE_INFO_MODAL}
134+
component={BatchSellNetworkFeeInfoModal}
135+
/>
131136
<ModalStack.Screen
132137
name={Routes.BRIDGE.MODALS.BATCH_SELL_MINIMUM_RECEIVED_INFO_MODAL}
133138
component={BatchSellMinimumReceivedInfoModal}

app/constants/navigation/Routes.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,7 @@ const Routes = {
331331
'BatchSellDestinationTokenSelectorModal',
332332
BATCH_SELL_QUOTE_DETAILS_MODAL: 'BatchSellQuoteDetailsModal',
333333
BATCH_SELL_FINAL_REVIEW_MODAL: 'BatchSellFinalReviewModal',
334+
BATCH_SELL_NETWORK_FEE_INFO_MODAL: 'BatchSellNetworkFeeInfoModal',
334335
BATCH_SELL_MINIMUM_RECEIVED_INFO_MODAL:
335336
'BatchSellMinimumReceivedInfoModal',
336337
},

0 commit comments

Comments
 (0)