Skip to content

Commit d194816

Browse files
authored
Merge branch 'main' into chore/update-text-for-rewards-accounts
2 parents e65b323 + 44c33a8 commit d194816

File tree

81 files changed

+6493
-4319
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

81 files changed

+6493
-4319
lines changed

.github/actions/smart-e2e-selection/action.yml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,10 @@ runs:
4646
- name: Fetch base branch for comparison
4747
shell: bash
4848
run: |
49-
# Fetch base branch with enough depth to compute merge base for git diff
50-
git fetch origin main --depth=100 2>/dev/null || git fetch origin master --depth=100 2>/dev/null || true
49+
# Unshallow the repository first (if it's shallow)
50+
git fetch --unshallow 2>/dev/null || true
51+
# Then fetch base branch to ensure merge-base exists
52+
git fetch origin main 2>/dev/null || true
5153
5254
- name: Setup Node.js
5355
uses: actions/setup-node@v4

android/app/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ android {
187187
applicationId "io.metamask"
188188
minSdkVersion rootProject.ext.minSdkVersion
189189
targetSdkVersion rootProject.ext.targetSdkVersion
190-
versionName "7.60.0"
190+
versionName "7.61.0"
191191
versionCode 2993
192192
testBuildType System.getProperty('testBuildType', 'debug')
193193
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"

app/components/Nav/App/App.test.tsx

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1010,7 +1010,27 @@ describe('App', () => {
10101010
const { getByTestId } = renderAppWithRouteState(routeState);
10111011

10121012
await waitFor(() => {
1013-
expect(getByTestId('eligibility-failed-modal')).toBeTruthy();
1013+
expect(getByTestId('eligibility-failed-modal')).toBeOnTheScreen();
1014+
});
1015+
});
1016+
1017+
it('registers the ramp unsupported modal route', async () => {
1018+
const routeState = {
1019+
index: 0,
1020+
routes: [
1021+
{
1022+
name: Routes.MODAL.ROOT_MODAL_FLOW,
1023+
params: {
1024+
screen: Routes.SHEET.UNSUPPORTED_REGION_MODAL,
1025+
},
1026+
},
1027+
],
1028+
};
1029+
1030+
const { getByTestId } = renderAppWithRouteState(routeState);
1031+
1032+
await waitFor(() => {
1033+
expect(getByTestId('ramp-unsupported-modal')).toBeOnTheScreen();
10141034
});
10151035
});
10161036
});

app/components/Nav/App/App.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@ import SuccessErrorSheet from '../../Views/SuccessErrorSheet';
130130
import ConfirmTurnOnBackupAndSyncModal from '../../UI/Identity/ConfirmTurnOnBackupAndSyncModal/ConfirmTurnOnBackupAndSyncModal';
131131
import AddNewAccountBottomSheet from '../../Views/AddNewAccount/AddNewAccountBottomSheet';
132132
import EligibilityFailedModal from '../../UI/Ramp/components/EligibilityFailedModal';
133+
import RampUnsupportedModal from '../../UI/Ramp/components/RampUnsupportedModal';
133134
import SwitchAccountTypeModal from '../../Views/confirmations/components/modals/switch-account-type-modal';
134135
import { AccountDetails } from '../../Views/MultichainAccounts/AccountDetails/AccountDetails';
135136
import { AccountGroupDetails } from '../../Views/MultichainAccounts/AccountGroupDetails/AccountGroupDetails';
@@ -408,6 +409,10 @@ const RootModalFlow = (props: RootModalFlowProps) => (
408409
name={Routes.SHEET.ELIGIBILITY_FAILED_MODAL}
409410
component={EligibilityFailedModal}
410411
/>
412+
<Stack.Screen
413+
name={Routes.SHEET.UNSUPPORTED_REGION_MODAL}
414+
component={RampUnsupportedModal}
415+
/>
411416
<Stack.Screen
412417
name={Routes.SHEET.ACCOUNT_SELECTOR}
413418
component={AccountSelector}

app/components/UI/Bridge/components/BridgeDestTokenSelector/__snapshots__/BridgeDestTokenSelector.test.tsx.snap

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -884,7 +884,13 @@ exports[`BridgeDestTokenSelector renders with initial state and displays tokens
884884
</View>
885885
</View>
886886
</View>
887-
<View>
887+
<View
888+
style={
889+
{
890+
"flex": 1,
891+
}
892+
}
893+
>
888894
<RCTScrollView
889895
ListEmptyComponent={
890896
{
@@ -895,6 +901,11 @@ exports[`BridgeDestTokenSelector renders with initial state and displays tokens
895901
}
896902
bounces={true}
897903
collapsable={false}
904+
contentContainerStyle={
905+
{
906+
"paddingBottom": 0,
907+
}
908+
}
898909
data={
899910
[
900911
{
@@ -962,6 +973,7 @@ exports[`BridgeDestTokenSelector renders with initial state and displays tokens
962973
stickyHeaderIndices={[]}
963974
style={
964975
{
976+
"flex": 1,
965977
"marginTop": 10,
966978
}
967979
}

app/components/UI/Bridge/components/BridgeSourceTokenSelector/__snapshots__/BridgeSourceTokenSelector.test.tsx.snap

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -889,7 +889,13 @@ exports[`BridgeSourceTokenSelector renders with initial state and displays token
889889
</View>
890890
</View>
891891
</View>
892-
<View>
892+
<View
893+
style={
894+
{
895+
"flex": 1,
896+
}
897+
}
898+
>
893899
<RCTScrollView
894900
ListEmptyComponent={
895901
{
@@ -900,6 +906,11 @@ exports[`BridgeSourceTokenSelector renders with initial state and displays token
900906
}
901907
bounces={true}
902908
collapsable={false}
909+
contentContainerStyle={
910+
{
911+
"paddingBottom": 0,
912+
}
913+
}
903914
data={
904915
[
905916
{
@@ -1027,6 +1038,7 @@ exports[`BridgeSourceTokenSelector renders with initial state and displays token
10271038
stickyHeaderIndices={[]}
10281039
style={
10291040
{
1041+
"flex": 1,
10301042
"marginTop": 10,
10311043
}
10321044
}

app/components/UI/Bridge/components/BridgeTokenSelectorBase.tsx

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,13 @@ const createStyles = (params: { theme: Theme }) => {
5454
},
5555
tokensList: {
5656
marginTop: 10,
57+
flex: 1,
58+
},
59+
tokensListContent: {
60+
paddingBottom: 0,
61+
},
62+
tokensListContainer: {
63+
flex: 1,
5764
},
5865
searchInput: {
5966
borderRadius: 12,
@@ -242,9 +249,10 @@ export const BridgeTokenSelectorBase: React.FC<BridgeTokenSelectorBaseProps> =
242249
</Box>
243250

244251
{/* Need this extra View to fix tokens not being reliably pressable on Android hardware, no idea why */}
245-
<View>
252+
<View style={styles.tokensListContainer}>
246253
<ListComponent
247254
style={styles.tokensList}
255+
contentContainerStyle={styles.tokensListContent}
248256
key={scrollResetKey}
249257
data={
250258
shouldRenderOverallLoading

app/components/UI/Card/components/Onboarding/PersonalDetails.tsx

Lines changed: 33 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -172,11 +172,20 @@ const PersonalDetails = () => {
172172
!lastName ||
173173
!dateOfBirth ||
174174
!nationality ||
175-
(!debouncedSSN && selectedCountry === 'US')
175+
(!SSN && selectedCountry === 'US')
176176
) {
177177
return;
178178
}
179179

180+
// Validate SSN before submitting if it's a US user
181+
if (selectedCountry === 'US') {
182+
const isSSNValid = /^\d{9}$/.test(SSN);
183+
if (!isSSNValid) {
184+
setIsSSNError(true);
185+
return;
186+
}
187+
}
188+
180189
try {
181190
trackEvent(
182191
createEventBuilder(MetaMetricsEvents.CARD_BUTTON_CLICKED)
@@ -192,7 +201,7 @@ const PersonalDetails = () => {
192201
lastName,
193202
dateOfBirth: formatDateOfBirth(dateOfBirth),
194203
countryOfNationality: nationality,
195-
ssn: debouncedSSN,
204+
ssn: SSN,
196205
});
197206

198207
if (user) {
@@ -223,32 +232,35 @@ const PersonalDetails = () => {
223232
);
224233
}, [trackEvent, createEventBuilder]);
225234

226-
const isDisabled = useMemo(
227-
() =>
235+
const isDisabled = useMemo(() => {
236+
// Check the actual SSN value, not the debounced one
237+
const isSSNValid =
238+
SSN && selectedCountry === 'US' ? /^\d{9}$/.test(SSN) : true;
239+
240+
return (
228241
registerLoading ||
229242
registerIsError ||
230243
!firstName ||
231244
!lastName ||
232245
!dateOfBirth ||
233246
!nationality ||
234-
(!debouncedSSN && selectedCountry === 'US') ||
235-
isSSNError ||
247+
(!SSN && selectedCountry === 'US') ||
248+
!isSSNValid ||
236249
!!dateError ||
237-
!onboardingId,
238-
[
239-
registerLoading,
240-
registerIsError,
241-
firstName,
242-
lastName,
243-
dateOfBirth,
244-
nationality,
245-
debouncedSSN,
246-
selectedCountry,
247-
isSSNError,
248-
dateError,
249-
onboardingId,
250-
],
251-
);
250+
!onboardingId
251+
);
252+
}, [
253+
registerLoading,
254+
registerIsError,
255+
firstName,
256+
lastName,
257+
dateOfBirth,
258+
nationality,
259+
SSN,
260+
selectedCountry,
261+
dateError,
262+
onboardingId,
263+
]);
252264

253265
const renderFormFields = () => (
254266
<>

app/components/UI/Card/components/Onboarding/SetPhoneNumber.tsx

Lines changed: 32 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -84,11 +84,13 @@ const SetPhoneNumber = () => {
8484
}, [trackEvent, createEventBuilder]);
8585

8686
const handleContinue = async () => {
87-
if (
88-
!debouncedPhoneNumber ||
89-
!selectedCountryAreaCode ||
90-
!contactVerificationId
91-
) {
87+
if (!phoneNumber || !selectedCountryAreaCode || !contactVerificationId) {
88+
return;
89+
}
90+
91+
const isCurrentPhoneNumberValid = /^\d{4,15}$/.test(phoneNumber);
92+
if (!isCurrentPhoneNumberValid) {
93+
setIsPhoneNumberError(true);
9294
return;
9395
}
9496

@@ -103,21 +105,21 @@ const SetPhoneNumber = () => {
103105
);
104106
const { success } = await sendPhoneVerification({
105107
phoneCountryCode: selectedCountryAreaCode,
106-
phoneNumber: debouncedPhoneNumber,
108+
phoneNumber,
107109
contactVerificationId,
108110
});
111+
109112
if (success) {
110113
navigation.navigate(Routes.CARD.ONBOARDING.CONFIRM_PHONE_NUMBER, {
111114
phoneCountryCode: selectedCountryAreaCode,
112-
phoneNumber: debouncedPhoneNumber,
115+
phoneNumber,
113116
});
114117
}
115-
} catch (error) {
118+
} catch (err: unknown) {
116119
if (
117-
error instanceof CardError &&
118-
error.message.includes('Invalid or expired contact verification ID')
120+
err instanceof CardError &&
121+
err.message.includes('Invalid or expired contact verification ID')
119122
) {
120-
// navigate back and restart the flow
121123
dispatch(resetOnboardingState());
122124
navigation.navigate(Routes.CARD.ONBOARDING.SIGN_UP);
123125
}
@@ -141,29 +143,29 @@ const SetPhoneNumber = () => {
141143
return;
142144
}
143145

144-
setIsPhoneNumberError(
145-
// 4-15 digits
146-
!/^\d{4,15}$/.test(debouncedPhoneNumber),
147-
);
146+
setIsPhoneNumberError(!/^\d{4,15}$/.test(debouncedPhoneNumber));
148147
}, [debouncedPhoneNumber]);
149148

150-
const isDisabled = useMemo(
151-
() =>
152-
!debouncedPhoneNumber ||
149+
const isDisabled = useMemo(() => {
150+
const isCurrentPhoneNumberValid = phoneNumber
151+
? /^\d{4,15}$/.test(phoneNumber)
152+
: false;
153+
154+
return (
155+
!phoneNumber ||
153156
!selectedCountryAreaCode ||
154157
!contactVerificationId ||
155-
isPhoneNumberError ||
158+
!isCurrentPhoneNumberValid ||
156159
phoneVerificationIsLoading ||
157-
phoneVerificationIsError,
158-
[
159-
debouncedPhoneNumber,
160-
selectedCountryAreaCode,
161-
contactVerificationId,
162-
isPhoneNumberError,
163-
phoneVerificationIsLoading,
164-
phoneVerificationIsError,
165-
],
166-
);
160+
phoneVerificationIsError
161+
);
162+
}, [
163+
phoneNumber,
164+
selectedCountryAreaCode,
165+
contactVerificationId,
166+
phoneVerificationIsLoading,
167+
phoneVerificationIsError,
168+
]);
167169

168170
const renderFormFields = () => (
169171
<Box>
@@ -204,7 +206,7 @@ const SetPhoneNumber = () => {
204206
/>
205207
</Box>
206208
</Box>
207-
{debouncedPhoneNumber && phoneVerificationIsError ? (
209+
{phoneNumber && phoneVerificationIsError ? (
208210
<Text
209211
variant={TextVariant.BodySm}
210212
testID="set-phone-number-phone-number-error"

0 commit comments

Comments
 (0)