Skip to content

Commit 3610633

Browse files
committed
Merge branch 'cherry-pick-7-74-0-7669b20' of https://github.com/MetaMask/metamask-mobile into cherry-pick-7-74-0-7669b20
2 parents d3ed701 + ea1a95c commit 3610633

23 files changed

Lines changed: 720 additions & 125 deletions

android/app/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ android {
188188
minSdkVersion rootProject.ext.minSdkVersion
189189
targetSdkVersion rootProject.ext.targetSdkVersion
190190
versionName "7.74.0"
191-
versionCode 4610
191+
versionCode 4618
192192
testBuildType System.getProperty('testBuildType', 'debug')
193193
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
194194
manifestPlaceholders.MM_BRANCH_KEY_TEST = "$System.env.MM_BRANCH_KEY_TEST"

app/components/UI/Earn/Views/EarnMusdConversionEducationView/index.test.tsx

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import AppConstants from '../../../../../core/AppConstants';
2424
import { MUSD_CONVERSION_NAVIGATION_OVERRIDE } from '../../types/musd.types';
2525
import { selectMusdQuickConvertEnabledFlag } from '../../selectors/featureFlags';
2626
import { MUSD_EVENTS_CONSTANTS } from '../../constants/events';
27+
import { MONEY_EVENTS_CONSTANTS } from '../../../Money/constants/moneyEvents';
2728

2829
const FIXED_NOW_MS = 1730000000000;
2930
const mockTrackEvent = jest.fn();
@@ -995,6 +996,44 @@ describe('EarnMusdConversionEducationView', () => {
995996
expect(mockTrackEvent).toHaveBeenCalledWith({ name: 'mock-built-event' });
996997
});
997998

999+
it('tracks money_hub redirect when continue is pressed with returnTo', async () => {
1000+
mockUseParams.mockReturnValue({
1001+
returnTo: { screen: Routes.WALLET.CASH_TOKENS_FULL_VIEW },
1002+
});
1003+
1004+
const { getByTestId } = renderWithProvider(
1005+
<EarnMusdConversionEducationView />,
1006+
{ state: {} },
1007+
);
1008+
1009+
mockTrackEvent.mockClear();
1010+
mockCreateEventBuilder.mockClear();
1011+
mockAddProperties.mockClear();
1012+
mockBuild.mockClear();
1013+
1014+
await act(async () => {
1015+
fireEvent.press(
1016+
getByTestId(
1017+
EARN_TEST_IDS.MUSD.CONVERSION_EDUCATION_VIEW.PRIMARY_BUTTON,
1018+
),
1019+
);
1020+
});
1021+
1022+
await waitFor(() => {
1023+
expect(mockCreateEventBuilder).toHaveBeenCalledWith(
1024+
MetaMetricsEvents.MUSD_FULLSCREEN_ANNOUNCEMENT_BUTTON_CLICKED,
1025+
);
1026+
1027+
expect(mockAddProperties).toHaveBeenCalledWith({
1028+
location:
1029+
MUSD_EVENTS_CONSTANTS.EVENT_LOCATIONS.CONVERSION_EDUCATION_SCREEN,
1030+
button_type: 'primary',
1031+
button_text: strings('earn.musd_conversion.education.primary_button'),
1032+
redirects_to: MONEY_EVENTS_CONSTANTS.EVENT_LOCATIONS.MONEY_HUB,
1033+
});
1034+
});
1035+
});
1036+
9981037
it('tracks buy button text and buy_screen redirect when deeplink triggers buy flow', async () => {
9991038
mockUseParams.mockReturnValue({
10001039
preferredPaymentToken: null,

app/components/UI/Earn/Views/EarnMusdConversionEducationView/index.tsx

Lines changed: 26 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ import {
4747
import { selectMusdQuickConvertEnabledFlag } from '../../selectors/featureFlags';
4848
import { toChecksumAddress } from '../../../../../util/address';
4949
import { safeFormatChainIdToHex } from '../../../Card/util/safeFormatChainIdToHex';
50+
import { MONEY_EVENTS_CONSTANTS } from '../../../Money/constants/moneyEvents';
5051
interface EarnMusdConversionEducationViewRouteParams {
5152
/**
5253
* Indicates if this navigation originated from a deeplink
@@ -179,20 +180,22 @@ const EarnMusdConversionEducationView = () => {
179180
return strings('earn.musd_conversion.education.primary_button');
180181
}, [deeplinkState]);
181182

182-
const { BUTTON_TYPES, EVENT_LOCATIONS } = MUSD_EVENTS_CONSTANTS;
183+
const { BUTTON_TYPES, EVENT_LOCATIONS: MUSD_EVENT_LOCATIONS } =
184+
MUSD_EVENTS_CONSTANTS;
185+
const { EVENT_LOCATIONS: MONEY_EVENT_LOCATIONS } = MONEY_EVENTS_CONSTANTS;
183186

184187
const submitScreenViewedEvent = useCallback(() => {
185188
trackEvent(
186189
createEventBuilder(
187190
MetaMetricsEvents.MUSD_FULLSCREEN_ANNOUNCEMENT_DISPLAYED,
188191
)
189192
.addProperties({
190-
location: EVENT_LOCATIONS.CONVERSION_EDUCATION_SCREEN,
193+
location: MUSD_EVENT_LOCATIONS.CONVERSION_EDUCATION_SCREEN,
191194
})
192195
.build(),
193196
);
194197
}, [
195-
EVENT_LOCATIONS.CONVERSION_EDUCATION_SCREEN,
198+
MUSD_EVENT_LOCATIONS.CONVERSION_EDUCATION_SCREEN,
196199
createEventBuilder,
197200
trackEvent,
198201
]);
@@ -209,22 +212,22 @@ const EarnMusdConversionEducationView = () => {
209212

210213
const submitContinuePressedEvent = useCallback(() => {
211214
let redirectsTo = isQuickConvertEnabled
212-
? EVENT_LOCATIONS.QUICK_CONVERT_HOME_SCREEN
213-
: EVENT_LOCATIONS.CUSTOM_AMOUNT_SCREEN;
215+
? MUSD_EVENT_LOCATIONS.QUICK_CONVERT_HOME_SCREEN
216+
: MUSD_EVENT_LOCATIONS.CUSTOM_AMOUNT_SCREEN;
214217
if (returnTo) {
215-
redirectsTo = EVENT_LOCATIONS.MONEY_HUB;
218+
redirectsTo = MONEY_EVENT_LOCATIONS.MONEY_HUB;
216219
} else if (deeplinkState?.action === 'navigate_home') {
217-
redirectsTo = EVENT_LOCATIONS.HOME_SCREEN;
220+
redirectsTo = MUSD_EVENT_LOCATIONS.HOME_SCREEN;
218221
} else if (deeplinkState?.action === 'buy') {
219-
redirectsTo = EVENT_LOCATIONS.BUY_SCREEN;
222+
redirectsTo = MUSD_EVENT_LOCATIONS.BUY_SCREEN;
220223
}
221224

222225
trackEvent(
223226
createEventBuilder(
224227
MetaMetricsEvents.MUSD_FULLSCREEN_ANNOUNCEMENT_BUTTON_CLICKED,
225228
)
226229
.addProperties({
227-
location: EVENT_LOCATIONS.CONVERSION_EDUCATION_SCREEN,
230+
location: MUSD_EVENT_LOCATIONS.CONVERSION_EDUCATION_SCREEN,
228231
button_type: BUTTON_TYPES.PRIMARY,
229232
button_text: primaryButtonText,
230233
redirects_to: redirectsTo,
@@ -234,12 +237,12 @@ const EarnMusdConversionEducationView = () => {
234237
}, [
235238
isQuickConvertEnabled,
236239
returnTo,
237-
EVENT_LOCATIONS.QUICK_CONVERT_HOME_SCREEN,
238-
EVENT_LOCATIONS.CUSTOM_AMOUNT_SCREEN,
239-
EVENT_LOCATIONS.CONVERSION_EDUCATION_SCREEN,
240-
EVENT_LOCATIONS.HOME_SCREEN,
241-
EVENT_LOCATIONS.BUY_SCREEN,
242-
EVENT_LOCATIONS.MONEY_HUB,
240+
MUSD_EVENT_LOCATIONS.QUICK_CONVERT_HOME_SCREEN,
241+
MUSD_EVENT_LOCATIONS.CUSTOM_AMOUNT_SCREEN,
242+
MUSD_EVENT_LOCATIONS.CONVERSION_EDUCATION_SCREEN,
243+
MUSD_EVENT_LOCATIONS.HOME_SCREEN,
244+
MUSD_EVENT_LOCATIONS.BUY_SCREEN,
245+
MONEY_EVENT_LOCATIONS.MONEY_HUB,
243246
deeplinkState?.action,
244247
trackEvent,
245248
createEventBuilder,
@@ -253,7 +256,7 @@ const EarnMusdConversionEducationView = () => {
253256
MetaMetricsEvents.MUSD_FULLSCREEN_ANNOUNCEMENT_BUTTON_CLICKED,
254257
)
255258
.addProperties({
256-
location: EVENT_LOCATIONS.CONVERSION_EDUCATION_SCREEN,
259+
location: MUSD_EVENT_LOCATIONS.CONVERSION_EDUCATION_SCREEN,
257260
button_type: BUTTON_TYPES.SECONDARY,
258261
button_text: strings(
259262
'earn.musd_conversion.education.secondary_button',
@@ -269,10 +272,13 @@ const EarnMusdConversionEducationView = () => {
269272
// Mark education as seen so it won't show again
270273
dispatch(setMusdConversionEducationSeen(true));
271274

272-
// returnTo wins: pure navigation, no conversion.
273-
// Use navigate (not replace) because returnTo targets a screen outside
274-
// the Earn stack — replace only works within the current navigator.
275+
// Pop the education screen from the Earn stack before navigating to
276+
// returnTo, so the stale screen doesn't flash when the Earn stack is
277+
// re-entered later (e.g., for conversion confirmation).
275278
if (returnTo) {
279+
if (navigation.canGoBack()) {
280+
navigation.goBack();
281+
}
276282
navigation.navigate(returnTo.screen, returnTo.params);
277283
return;
278284
}
@@ -357,7 +363,7 @@ const EarnMusdConversionEducationView = () => {
357363
trackEvent(
358364
createEventBuilder(MetaMetricsEvents.MUSD_BONUS_TERMS_OF_USE_PRESSED)
359365
.addProperties({
360-
location: EVENT_LOCATIONS.CONVERSION_EDUCATION_SCREEN,
366+
location: MUSD_EVENT_LOCATIONS.CONVERSION_EDUCATION_SCREEN,
361367
url: AppConstants.URLS.MUSD_CONVERSION_BONUS_TERMS_OF_USE,
362368
})
363369
.build(),

app/components/UI/Earn/components/AssetOverviewClaimBonus/AssetOverviewClaimBonus.test.tsx

Lines changed: 68 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import {
1414
import { useAnalytics } from '../../../../hooks/useAnalytics/useAnalytics';
1515
import { MetaMetricsEvents, EVENT_NAME } from '../../../../../core/Analytics';
1616
import { MUSD_EVENTS_CONSTANTS } from '../../constants/events/musdEvents';
17+
import { MONEY_EVENTS_CONSTANTS } from '../../../Money/constants/moneyEvents';
1718
import AppConstants from '../../../../../core/AppConstants';
1819
import { ASSET_OVERVIEW_CLAIM_BONUS_TEST_IDS } from './AssetOverviewClaimBonus.testIds';
1920
import { TokenI } from '../../../Tokens/types';
@@ -712,7 +713,7 @@ describe('AssetOverviewClaimBonus', () => {
712713
});
713714

714715
describe('terms link', () => {
715-
it('opens terms URL and fires analytics when terms link is pressed', () => {
716+
it('opens terms URL and fires analytics with BONUS_CLAIM_TOOLTIP location', () => {
716717
const { getByTestId } = renderWithProvider(
717718
<AssetOverviewClaimBonus asset={createMockAsset()} />,
718719
{ state: mockInitialState },
@@ -735,6 +736,72 @@ describe('AssetOverviewClaimBonus', () => {
735736
expect(mockCreateEventBuilder).toHaveBeenCalledWith(
736737
MetaMetricsEvents.MUSD_BONUS_TERMS_OF_USE_PRESSED,
737738
);
739+
expect(mockAddProperties).toHaveBeenCalledWith(
740+
expect.objectContaining({
741+
location: MUSD_EVENTS_CONSTANTS.EVENT_LOCATIONS.BONUS_CLAIM_TOOLTIP,
742+
url: AppConstants.URLS.MUSD_CONVERSION_BONUS_TERMS_OF_USE,
743+
}),
744+
);
745+
});
746+
});
747+
748+
describe('learn more link', () => {
749+
it('fires MUSD_BONUS_LEARN_MORE_PRESSED and opens learn more URL', () => {
750+
const { getByTestId } = renderWithProvider(
751+
<AssetOverviewClaimBonus asset={createMockAsset()} />,
752+
{ state: mockInitialState },
753+
);
754+
755+
fireEvent.press(
756+
getByTestId(ASSET_OVERVIEW_CLAIM_BONUS_TEST_IDS.INFO_BUTTON),
757+
);
758+
759+
const learnMoreCallback = mockOpenTooltipModal.mock.calls[0][4];
760+
learnMoreCallback();
761+
762+
expect(mockCreateEventBuilder).toHaveBeenCalledWith(
763+
MetaMetricsEvents.MUSD_BONUS_LEARN_MORE_PRESSED,
764+
);
765+
expect(mockAddProperties).toHaveBeenCalledWith(
766+
expect.objectContaining({
767+
location: MUSD_EVENTS_CONSTANTS.EVENT_LOCATIONS.BONUS_CLAIM_TOOLTIP,
768+
url: AppConstants.URLS.MUSD_LEARN_MORE,
769+
}),
770+
);
771+
expect(Linking.openURL).toHaveBeenCalledWith(
772+
AppConstants.URLS.MUSD_LEARN_MORE,
773+
);
774+
});
775+
});
776+
777+
describe('location prop', () => {
778+
it('passes location prop to useMerklBonusClaim', () => {
779+
const customLocation = MONEY_EVENTS_CONSTANTS.EVENT_LOCATIONS.MONEY_HUB;
780+
781+
renderWithProvider(
782+
<AssetOverviewClaimBonus
783+
asset={createMockAsset()}
784+
location={customLocation}
785+
/>,
786+
{ state: mockInitialState },
787+
);
788+
789+
expect(mockUseMerklBonusClaim).toHaveBeenCalledWith(
790+
expect.anything(),
791+
customLocation,
792+
);
793+
});
794+
795+
it('defaults location to ASSET_OVERVIEW when not provided', () => {
796+
renderWithProvider(
797+
<AssetOverviewClaimBonus asset={createMockAsset()} />,
798+
{ state: mockInitialState },
799+
);
800+
801+
expect(mockUseMerklBonusClaim).toHaveBeenCalledWith(
802+
expect.anything(),
803+
MUSD_EVENTS_CONSTANTS.EVENT_LOCATIONS.ASSET_OVERVIEW,
804+
);
738805
});
739806
});
740807
});

app/components/UI/Earn/components/AssetOverviewClaimBonus/AssetOverviewClaimBonus.tsx

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ import TagBase, {
4343
TagSeverity,
4444
} from '../../../../../component-library/base-components/TagBase';
4545

46-
const { EVENT_LOCATIONS } = MUSD_EVENTS_CONSTANTS;
46+
const { EVENT_LOCATIONS: MUSD_EVENT_LOCATIONS } = MUSD_EVENTS_CONSTANTS;
4747

4848
const styles = StyleSheet.create({
4949
bonusTag: { borderRadius: 8, paddingHorizontal: 6 },
@@ -53,11 +53,14 @@ interface AssetOverviewClaimBonusProps {
5353
asset: TokenI;
5454
/** Called with the Merkl refetch function so the parent can trigger a refresh. */
5555
onRefetchReady?: (refetch: () => void) => void;
56+
/** Optional location for analytics. */
57+
location?: string;
5658
}
5759

5860
const AssetOverviewClaimBonus: React.FC<AssetOverviewClaimBonusProps> = ({
5961
asset,
6062
onRefetchReady,
63+
location = MUSD_EVENT_LOCATIONS.ASSET_OVERVIEW,
6164
}) => {
6265
const {
6366
claimableReward,
@@ -66,7 +69,7 @@ const AssetOverviewClaimBonus: React.FC<AssetOverviewClaimBonusProps> = ({
6669
isClaiming,
6770
claimRewards,
6871
refetch,
69-
} = useMerklBonusClaim(asset, EVENT_LOCATIONS.ASSET_OVERVIEW);
72+
} = useMerklBonusClaim(asset, location);
7073

7174
useEffect(() => {
7275
onRefetchReady?.(refetch);
@@ -161,7 +164,7 @@ const AssetOverviewClaimBonus: React.FC<AssetOverviewClaimBonusProps> = ({
161164
trackEvent(
162165
createEventBuilder(MetaMetricsEvents.MUSD_BONUS_TERMS_OF_USE_PRESSED)
163166
.addProperties({
164-
location: EVENT_LOCATIONS.ASSET_OVERVIEW_CLAIMABLE_BONUS_TOOLTIP,
167+
location: MUSD_EVENT_LOCATIONS.BONUS_CLAIM_TOOLTIP,
165168
url: AppConstants.URLS.MUSD_CONVERSION_BONUS_TERMS_OF_USE,
166169
})
167170
.build(),
@@ -171,16 +174,25 @@ const AssetOverviewClaimBonus: React.FC<AssetOverviewClaimBonusProps> = ({
171174
}, [createEventBuilder, trackEvent]);
172175

173176
const handleLearnMorePress = useCallback(() => {
177+
trackEvent(
178+
createEventBuilder(MetaMetricsEvents.MUSD_BONUS_LEARN_MORE_PRESSED)
179+
.addProperties({
180+
location: MUSD_EVENT_LOCATIONS.BONUS_CLAIM_TOOLTIP,
181+
url: AppConstants.URLS.MUSD_LEARN_MORE,
182+
})
183+
.build(),
184+
);
185+
174186
Linking.openURL(AppConstants.URLS.MUSD_LEARN_MORE);
175-
}, []);
187+
}, [createEventBuilder, trackEvent]);
176188

177189
const handleInfoPress = useCallback(() => {
178190
trackEvent(
179191
createEventBuilder(EVENT_NAME.TOOLTIP_OPENED)
180192
.addProperties({
181-
location: EVENT_LOCATIONS.ASSET_OVERVIEW,
193+
location,
182194
tooltip_name: 'your_bonus_info',
183-
related_text: 'Your bonus',
195+
text: 'Your bonus',
184196
})
185197
.build(),
186198
);
@@ -218,11 +230,12 @@ const AssetOverviewClaimBonus: React.FC<AssetOverviewClaimBonusProps> = ({
218230
false,
219231
);
220232
}, [
233+
trackEvent,
234+
createEventBuilder,
235+
location,
221236
openTooltipModal,
222237
handleTermsPress,
223238
handleLearnMorePress,
224-
trackEvent,
225-
createEventBuilder,
226239
]);
227240

228241
const handleClaimPress = useCallback(() => {
@@ -232,9 +245,8 @@ const AssetOverviewClaimBonus: React.FC<AssetOverviewClaimBonusProps> = ({
232245
trackEvent(
233246
createEventBuilder(MetaMetricsEvents.MUSD_CLAIM_BONUS_BUTTON_CLICKED)
234247
.addProperties({
235-
location: EVENT_LOCATIONS.ASSET_OVERVIEW,
248+
location,
236249
action_type: 'claim_bonus',
237-
button_text: ctaLabel,
238250
network_chain_id: asset.chainId,
239251
network_name: network?.name,
240252
asset_symbol: asset.symbol,
@@ -245,9 +257,9 @@ const AssetOverviewClaimBonus: React.FC<AssetOverviewClaimBonusProps> = ({
245257
}, [
246258
isLoading,
247259
ctaDisabled,
248-
ctaLabel,
249260
trackEvent,
250261
createEventBuilder,
262+
location,
251263
asset.chainId,
252264
asset.symbol,
253265
network?.name,

app/components/UI/Earn/components/MerklRewards/hooks/useMerklBonusClaim.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { CHAIN_IDS } from '@metamask/transaction-controller';
33
import { useMerklBonusClaim } from './useMerklBonusClaim';
44
import { TokenI } from '../../../../Tokens/types';
55
import { AGLAMERKL_ADDRESS_MAINNET } from '../constants';
6+
import { MONEY_EVENTS_CONSTANTS } from '../../../../Money/constants/moneyEvents';
67

78
const mockClaimRewards = jest.fn().mockResolvedValue(undefined);
89
const mockMerklRewardsRefetch = jest.fn();

0 commit comments

Comments
 (0)