Skip to content

Commit ded27c1

Browse files
authored
Merge branch 'main' into harry/MMQA-1711
2 parents a6e3726 + 036608e commit ded27c1

25 files changed

Lines changed: 1164 additions & 180 deletions

app/components/Views/confirmations/components/recipient-input/recipient-input.test.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,6 @@ describe('RecipientInput', () => {
8080
loading: false,
8181
resolvedAddress: undefined,
8282
toAddressError: undefined,
83-
toAddressErrorAllowAcknowledge: false,
8483
toAddressValidated: undefined,
8584
toAddressWarning: undefined,
8685
});

app/components/Views/confirmations/components/send/recipient/recipient.test.tsx

Lines changed: 57 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { useContacts } from '../../../hooks/send/useContacts';
1010
import { useToAddressValidation } from '../../../hooks/send/useToAddressValidation';
1111
import { useRecipientSelectionMetrics } from '../../../hooks/send/metrics/useRecipientSelectionMetrics';
1212
import { useSendActions } from '../../../hooks/send/useSendActions';
13+
import { useSendAlerts } from '../../../hooks/send/alerts/useSendAlerts';
1314
import { useSendType } from '../../../hooks/send/useSendType';
1415
import { RecipientType } from '../../UI/recipient';
1516
import { Recipient } from './recipient';
@@ -65,6 +66,10 @@ jest.mock('../../../hooks/send/useToAddressValidation', () => ({
6566
useToAddressValidation: jest.fn(),
6667
}));
6768

69+
jest.mock('../../../hooks/send/alerts/useSendAlerts', () => ({
70+
useSendAlerts: jest.fn(),
71+
}));
72+
6873
jest.mock('../../../hooks/send/metrics/useRecipientSelectionMetrics', () => ({
6974
useRecipientSelectionMetrics: jest.fn(),
7075
}));
@@ -149,21 +154,20 @@ jest.mock('../send-alert-modal', () => ({
149154
isOpen,
150155
onAcknowledge,
151156
onClose,
152-
title,
153-
errorMessage,
157+
alerts,
154158
}: {
155159
isOpen: boolean;
156160
onAcknowledge: () => void;
157161
onClose: () => void;
158-
title: string;
159-
errorMessage: string;
162+
alerts: { title: string; message: string }[];
160163
}) => {
161164
const { View, Text, Pressable } = jest.requireActual('react-native');
162-
if (!isOpen) return null;
165+
if (!isOpen || !alerts?.length) return null;
166+
const first = alerts[0];
163167
return (
164168
<View testID="send-alert-modal">
165-
<Text testID="alert-modal-title">{title}</Text>
166-
<Text testID="alert-modal-error">{errorMessage}</Text>
169+
<Text testID="alert-modal-title">{first.title}</Text>
170+
<Text testID="alert-modal-error">{first.message}</Text>
167171
<Pressable testID="alert-modal-acknowledge" onPress={onAcknowledge}>
168172
<Text>Acknowledge</Text>
169173
</Pressable>
@@ -199,6 +203,7 @@ const mockUseRecipientSelectionMetrics = jest.mocked(
199203
useRecipientSelectionMetrics,
200204
);
201205
const mockUseSendActions = jest.mocked(useSendActions);
206+
const mockUseSendAlerts = jest.mocked(useSendAlerts);
202207
const mockUseSendType = jest.mocked(useSendType);
203208

204209
function createMockUseSendType(
@@ -239,11 +244,17 @@ describe('Recipient', () => {
239244
loading: false,
240245
resolvedAddress: undefined,
241246
toAddressError: undefined,
242-
toAddressErrorAllowAcknowledge: false,
243247
toAddressValidated: undefined,
244248
toAddressWarning: undefined,
245249
});
246250

251+
mockUseSendAlerts.mockReturnValue({
252+
alerts: [],
253+
hasUnacknowledgedAlerts: false,
254+
acknowledgeAlerts: jest.fn(),
255+
isAlertCheckPending: false,
256+
});
257+
247258
mockUseRecipientSelectionMetrics.mockReturnValue({
248259
captureRecipientSelected: mockCaptureRecipientSelected,
249260
});
@@ -342,7 +353,6 @@ describe('Recipient', () => {
342353
loading: false,
343354
resolvedAddress: 'some_dummy_address',
344355
toAddressError: undefined,
345-
toAddressErrorAllowAcknowledge: false,
346356
toAddressValidated: undefined,
347357
toAddressWarning: undefined,
348358
});
@@ -435,7 +445,6 @@ describe('Recipient', () => {
435445
loading: false,
436446
resolvedAddress: undefined,
437447
toAddressError: undefined,
438-
toAddressErrorAllowAcknowledge: false,
439448
toAddressValidated: undefined,
440449
toAddressWarning: 'Warning',
441450
});
@@ -463,7 +472,6 @@ describe('Recipient', () => {
463472
loading: false,
464473
resolvedAddress: undefined,
465474
toAddressError: 'Error',
466-
toAddressErrorAllowAcknowledge: false,
467475
toAddressValidated: undefined,
468476
toAddressWarning: 'Warning',
469477
});
@@ -501,7 +509,6 @@ describe('Recipient', () => {
501509
loading: true,
502510
resolvedAddress: undefined,
503511
toAddressError: undefined,
504-
toAddressErrorAllowAcknowledge: false,
505512
toAddressValidated: undefined,
506513
toAddressWarning: 'Warning',
507514
});
@@ -569,7 +576,6 @@ describe('Recipient pastedRecipient effect gating (lines 96-101)', () => {
569576
loading: false,
570577
resolvedAddress: '0xresolved',
571578
toAddressError: undefined,
572-
toAddressErrorAllowAcknowledge: false,
573579
toAddressValidated: '0xother',
574580
toAddressWarning: undefined,
575581
});
@@ -585,7 +591,6 @@ describe('Recipient pastedRecipient effect gating (lines 96-101)', () => {
585591
loading: false,
586592
resolvedAddress: '0xresolved',
587593
toAddressError: 'Invalid address',
588-
toAddressErrorAllowAcknowledge: false,
589594
toAddressValidated: '0xvalid',
590595
toAddressWarning: undefined,
591596
});
@@ -601,7 +606,6 @@ describe('Recipient pastedRecipient effect gating (lines 96-101)', () => {
601606
loading: false,
602607
resolvedAddress: '0xresolved',
603608
toAddressError: undefined,
604-
toAddressErrorAllowAcknowledge: false,
605609
toAddressValidated: '0xvalid',
606610
toAddressWarning: 'Warning',
607611
});
@@ -617,7 +621,6 @@ describe('Recipient pastedRecipient effect gating (lines 96-101)', () => {
617621
loading: true,
618622
resolvedAddress: '0xresolved',
619623
toAddressError: undefined,
620-
toAddressErrorAllowAcknowledge: false,
621624
toAddressValidated: '0xvalid',
622625
toAddressWarning: undefined,
623626
});
@@ -634,7 +637,6 @@ describe('Recipient pastedRecipient effect gating (lines 96-101)', () => {
634637
loading: false,
635638
resolvedAddress: undefined,
636639
toAddressError: undefined,
637-
toAddressErrorAllowAcknowledge: false,
638640
toAddressValidated: undefined,
639641
toAddressWarning: undefined,
640642
});
@@ -668,7 +670,6 @@ describe('Recipient pastedRecipient effect gating (lines 96-101)', () => {
668670
loading: false,
669671
resolvedAddress: undefined,
670672
toAddressError: undefined,
671-
toAddressErrorAllowAcknowledge: false,
672673
toAddressValidated: undefined,
673674
toAddressWarning: undefined,
674675
});
@@ -706,7 +707,6 @@ describe('Recipient pastedRecipient effect gating (lines 96-101)', () => {
706707
loading: false,
707708
resolvedAddress: undefined,
708709
toAddressError: 'Error',
709-
toAddressErrorAllowAcknowledge: false,
710710
toAddressValidated: undefined,
711711
toAddressWarning: undefined,
712712
});
@@ -744,7 +744,10 @@ describe('SendAlertModal integration', () => {
744744
let mockHandleSubmitPressLocal: jest.Mock;
745745

746746
const setupTokenContractScenario = (
747-
overrides: Partial<ReturnType<typeof useToAddressValidation>> = {},
747+
validationOverrides: Partial<
748+
ReturnType<typeof useToAddressValidation>
749+
> = {},
750+
sendAlertsOverrides: Partial<ReturnType<typeof useSendAlerts>> = {},
748751
) => {
749752
mockHandleSubmitPressLocal = jest.fn();
750753
mockUseSendActions.mockReturnValue({
@@ -771,11 +774,24 @@ describe('SendAlertModal integration', () => {
771774
mockUseToAddressValidation.mockReturnValue({
772775
loading: false,
773776
resolvedAddress: undefined,
774-
toAddressError: 'Token contract warning',
775-
toAddressErrorAllowAcknowledge: true,
777+
toAddressError: undefined,
776778
toAddressValidated: '0x1234567890123456789012345678901234567890',
777779
toAddressWarning: undefined,
778-
...overrides,
780+
...validationOverrides,
781+
});
782+
783+
mockUseSendAlerts.mockReturnValue({
784+
alerts: [
785+
{
786+
key: 'tokenContract',
787+
title: 'Smart contract address',
788+
message: 'You are sending to a smart contract address',
789+
},
790+
],
791+
hasUnacknowledgedAlerts: true,
792+
acknowledgeAlerts: jest.fn(),
793+
isAlertCheckPending: false,
794+
...sendAlertsOverrides,
779795
});
780796

781797
mockUseRecipientSelectionMetrics.mockReturnValue({
@@ -793,7 +809,7 @@ describe('SendAlertModal integration', () => {
793809
jest.clearAllMocks();
794810
});
795811

796-
it('opens alert modal when review pressed and toAddressErrorAllowAcknowledge is true', () => {
812+
it('opens alert modal when review pressed and has unacknowledged send alerts', () => {
797813
setupTokenContractScenario();
798814

799815
const { getByTestId } = renderWithProvider(<Recipient />);
@@ -841,11 +857,16 @@ describe('SendAlertModal integration', () => {
841857
);
842858
});
843859

844-
it('does not show alert modal when toAddressErrorAllowAcknowledge is false', () => {
845-
setupTokenContractScenario({
846-
toAddressError: 'Some error',
847-
toAddressErrorAllowAcknowledge: false,
848-
});
860+
it('does not show alert modal when there are no unacknowledged send alerts', () => {
861+
setupTokenContractScenario(
862+
{
863+
toAddressError: 'Some error',
864+
},
865+
{
866+
alerts: [],
867+
hasUnacknowledgedAlerts: false,
868+
},
869+
);
849870

850871
const { getByTestId, queryByTestId } = renderWithProvider(<Recipient />);
851872

@@ -892,11 +913,17 @@ describe('SendAlertModal integration', () => {
892913
loading: false,
893914
resolvedAddress: undefined,
894915
toAddressError: undefined,
895-
toAddressErrorAllowAcknowledge: false,
896916
toAddressValidated: '0xvalid',
897917
toAddressWarning: undefined,
898918
});
899919

920+
mockUseSendAlerts.mockReturnValue({
921+
alerts: [],
922+
hasUnacknowledgedAlerts: false,
923+
acknowledgeAlerts: jest.fn(),
924+
isAlertCheckPending: false,
925+
});
926+
900927
mockUseAccounts.mockReturnValue(mockAccounts);
901928
mockUseContacts.mockReturnValue(mockContacts);
902929
mockUseSendType.mockReturnValue({

app/components/Views/confirmations/components/send/recipient/recipient.tsx

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import Banner, {
1515
} from '../../../../../../component-library/components/Banners/Banner';
1616
import { useSendContext } from '../../../context/send-context/send-context';
1717
import { RecipientInputMethod } from '../../../context/send-context/send-metrics-context';
18+
import { useSendAlerts } from '../../../hooks/send/alerts/useSendAlerts';
1819
import { useRecipientSelectionMetrics } from '../../../hooks/send/metrics/useRecipientSelectionMetrics';
1920
import { useAccounts } from '../../../hooks/send/useAccounts';
2021
import { useContacts } from '../../../hooks/send/useContacts';
@@ -41,15 +42,20 @@ export const Recipient = () => {
4142
const styles = styleSheet();
4243
const {
4344
toAddressError,
44-
toAddressErrorAllowAcknowledge,
4545
toAddressWarning,
4646
toAddressValidated,
4747
loading,
4848
resolvedAddress,
4949
} = useToAddressValidation();
5050

51-
const hasBlockingError =
52-
Boolean(toAddressError) && !toAddressErrorAllowAcknowledge;
51+
const {
52+
alerts,
53+
hasUnacknowledgedAlerts,
54+
acknowledgeAlerts,
55+
isAlertCheckPending,
56+
} = useSendAlerts();
57+
58+
const hasBlockingError = Boolean(toAddressError);
5359
// This hook needs to be called to update ERC721 NFTs in send flow
5460
// because that flow is triggered directly from the asset details page and user is redirected to the recipient page
5561
useRouteParams();
@@ -98,23 +104,24 @@ export const Recipient = () => {
98104

99105
const handleAlertModalAcknowledge = useCallback(async () => {
100106
setIsAlertModalOpen(false);
107+
acknowledgeAlerts();
101108
await proceedWithSubmit(false);
102-
}, [proceedWithSubmit]);
109+
}, [acknowledgeAlerts, proceedWithSubmit]);
103110

104111
const handleReview = useCallback(
105112
async (isPasted?: boolean) => {
106113
if (hasBlockingError || isSubmittingTransaction) {
107114
return;
108115
}
109-
if (toAddressErrorAllowAcknowledge) {
116+
if (hasUnacknowledgedAlerts) {
110117
setIsAlertModalOpen(true);
111118
return;
112119
}
113120
await proceedWithSubmit(isPasted);
114121
},
115122
[
116123
hasBlockingError,
117-
toAddressErrorAllowAcknowledge,
124+
hasUnacknowledgedAlerts,
118125
isSubmittingTransaction,
119126
proceedWithSubmit,
120127
],
@@ -126,7 +133,9 @@ export const Recipient = () => {
126133
pastedRecipient === toAddressValidated &&
127134
!toAddressError &&
128135
!toAddressWarning &&
129-
!loading
136+
!loading &&
137+
!isAlertCheckPending &&
138+
!hasUnacknowledgedAlerts
130139
) {
131140
handleReview(true);
132141
}
@@ -137,6 +146,8 @@ export const Recipient = () => {
137146
toAddressValidated,
138147
toAddressWarning,
139148
loading,
149+
isAlertCheckPending,
150+
hasUnacknowledgedAlerts,
140151
]);
141152

142153
const onRecipientSelected = useCallback(
@@ -240,7 +251,10 @@ export const Recipient = () => {
240251
twClassName="w-full"
241252
isDanger={!loading && hasBlockingError}
242253
disabled={
243-
hasBlockingError || isSubmittingTransaction || loading
254+
hasBlockingError ||
255+
isSubmittingTransaction ||
256+
loading ||
257+
isAlertCheckPending
244258
}
245259
isLoading={isSubmittingTransaction || loading}
246260
>
@@ -250,8 +264,7 @@ export const Recipient = () => {
250264
)}
251265
<SendAlertModal
252266
isOpen={isAlertModalOpen}
253-
title={strings('send.smart_contract_address')}
254-
errorMessage={strings('send.smart_contract_address_warning')}
267+
alerts={alerts}
255268
onAcknowledge={handleAlertModalAcknowledge}
256269
onClose={handleAlertModalClose}
257270
/>

0 commit comments

Comments
 (0)