Skip to content

Commit 6e96377

Browse files
authored
Merge branch 'main' into rn-upgrade/0.81.5-no-unit-tests
2 parents 856b700 + 2433e3e commit 6e96377

25 files changed

Lines changed: 730 additions & 155 deletions

File tree

app/components/UI/Predict/components/PredictMarket/PredictMarket.tsx

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,19 @@ interface PredictMarketProps {
1212
testID?: string;
1313
entryPoint?: PredictEntryPoint;
1414
isCarousel?: boolean;
15+
/** Called synchronously before the card's navigation press fires. */
16+
onCardPress?: () => void;
17+
/** Called when the user taps a buy button (before betslip opens). */
18+
onBuyButtonPress?: (marketId: string) => void;
1519
}
1620

1721
const PredictMarket: React.FC<PredictMarketProps> = ({
1822
market,
1923
testID,
2024
entryPoint: propEntryPoint,
2125
isCarousel = false,
26+
onCardPress,
27+
onBuyButtonPress,
2228
}) => {
2329
const contextEntryPoint = usePredictEntryPoint();
2430
const entryPoint =
@@ -32,6 +38,8 @@ const PredictMarket: React.FC<PredictMarketProps> = ({
3238
testID={testID}
3339
entryPoint={entryPoint}
3440
isCarousel={isCarousel}
41+
onCardPress={onCardPress}
42+
onBuyButtonPress={onBuyButtonPress}
3543
/>
3644
);
3745
}
@@ -43,6 +51,8 @@ const PredictMarket: React.FC<PredictMarketProps> = ({
4351
testID={testID}
4452
entryPoint={entryPoint}
4553
isCarousel={isCarousel}
54+
onCardPress={onCardPress}
55+
onBuyButtonPress={onBuyButtonPress}
4656
/>
4757
);
4858
}
@@ -53,6 +63,8 @@ const PredictMarket: React.FC<PredictMarketProps> = ({
5363
testID={testID}
5464
entryPoint={entryPoint}
5565
isCarousel={isCarousel}
66+
onCardPress={onCardPress}
67+
onBuyButtonPress={onBuyButtonPress}
5668
/>
5769
);
5870
};

app/components/UI/Predict/components/PredictMarketMultiple/PredictMarketMultiple.tsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,13 +50,19 @@ interface PredictMarketMultipleProps {
5050
testID?: string;
5151
entryPoint?: PredictEntryPoint;
5252
isCarousel?: boolean;
53+
/** Called synchronously before the card's navigation press fires. */
54+
onCardPress?: () => void;
55+
/** Called when the user taps a buy button (before betslip opens). */
56+
onBuyButtonPress?: (marketId: string) => void;
5357
}
5458

5559
const PredictMarketMultiple: React.FC<PredictMarketMultipleProps> = ({
5660
market,
5761
testID,
5862
entryPoint: propEntryPoint,
5963
isCarousel = false,
64+
onCardPress,
65+
onBuyButtonPress,
6066
}) => {
6167
const contextEntryPoint = usePredictEntryPoint();
6268
const baseEntryPoint =
@@ -137,6 +143,7 @@ const PredictMarketMultiple: React.FC<PredictMarketMultipleProps> = ({
137143
outcome: PredictOutcome,
138144
outcomeToken: PredictOutcomeToken,
139145
) => {
146+
onBuyButtonPress?.(market.id);
140147
executeGuardedAction(
141148
() => {
142149
openBuySheet({
@@ -161,6 +168,7 @@ const PredictMarketMultiple: React.FC<PredictMarketMultipleProps> = ({
161168
<TouchableOpacity
162169
testID={testID}
163170
onPress={() => {
171+
onCardPress?.();
164172
navigation.navigate(Routes.PREDICT.ROOT, {
165173
screen: Routes.PREDICT.MARKET_DETAILS,
166174
params: {

app/components/UI/Predict/components/PredictMarketSingle/PredictMarketSingle.tsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,13 +128,19 @@ interface PredictMarketSingleProps {
128128
testID?: string;
129129
entryPoint?: PredictEntryPoint;
130130
isCarousel?: boolean;
131+
/** Called synchronously before the card's navigation press fires. */
132+
onCardPress?: () => void;
133+
/** Called when the user taps a buy button (before betslip opens). */
134+
onBuyButtonPress?: (marketId: string) => void;
131135
}
132136

133137
const PredictMarketSingle: React.FC<PredictMarketSingleProps> = ({
134138
market,
135139
testID,
136140
entryPoint: propEntryPoint,
137141
isCarousel = false,
142+
onCardPress,
143+
onBuyButtonPress,
138144
}) => {
139145
const contextEntryPoint = usePredictEntryPoint();
140146
const baseEntryPoint =
@@ -185,6 +191,7 @@ const PredictMarketSingle: React.FC<PredictMarketSingleProps> = ({
185191
const yesPercentage = getYesPercentage();
186192

187193
const handleBuy = (token: PredictOutcomeToken) => {
194+
onBuyButtonPress?.(market.id);
188195
executeGuardedAction(
189196
() => {
190197
openBuySheet({
@@ -204,6 +211,7 @@ const PredictMarketSingle: React.FC<PredictMarketSingleProps> = ({
204211
<TouchableOpacity
205212
testID={testID}
206213
onPress={() => {
214+
onCardPress?.();
207215
navigation.navigate(Routes.PREDICT.ROOT, {
208216
screen: Routes.PREDICT.MARKET_DETAILS,
209217
params: {

app/components/UI/Predict/components/PredictMarketSportCard/PredictMarketSportCard.tsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@ interface PredictMarketSportCardProps {
2727
entryPoint?: PredictEntryPoint;
2828
onDismiss?: () => void;
2929
isCarousel?: boolean;
30+
/** Called synchronously before the card's navigation press fires. */
31+
onCardPress?: () => void;
32+
/** Called when the user taps a buy button (before betslip opens). */
33+
onBuyButtonPress?: (marketId: string) => void;
3034
}
3135

3236
const PredictMarketSportCard: React.FC<PredictMarketSportCardProps> = ({
@@ -35,6 +39,8 @@ const PredictMarketSportCard: React.FC<PredictMarketSportCardProps> = ({
3539
entryPoint: propEntryPoint,
3640
onDismiss,
3741
isCarousel,
42+
onCardPress,
43+
onBuyButtonPress,
3844
}) => {
3945
const tw = useTailwind();
4046
const contextEntryPoint = usePredictEntryPoint();
@@ -57,6 +63,7 @@ const PredictMarketSportCard: React.FC<PredictMarketSportCardProps> = ({
5763
style={tw.style(isCarousel ? '' : 'my-[8px]')}
5864
testID={testID}
5965
onPress={() => {
66+
onCardPress?.();
6067
navigation.navigate(Routes.PREDICT.ROOT, {
6168
screen: Routes.PREDICT.MARKET_DETAILS,
6269
params: {
@@ -102,6 +109,7 @@ const PredictMarketSportCard: React.FC<PredictMarketSportCardProps> = ({
102109
entryPoint={resolvedEntryPoint}
103110
testID={testID ? `${testID}-footer` : undefined}
104111
isCarousel={isCarousel}
112+
onBuyButtonPress={onBuyButtonPress}
105113
/>
106114
</Box>
107115
</Box>

app/components/UI/Predict/components/PredictSportCardFooter/PredictSportCardFooter.tsx

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,16 @@ interface PredictSportCardFooterProps {
2727
testID?: string;
2828
entryPoint?: PredictEntryPoint;
2929
isCarousel?: boolean;
30+
/** Called when the user taps a buy button (before betslip opens). */
31+
onBuyButtonPress?: (marketId: string) => void;
3032
}
3133

3234
const PredictSportCardFooter: React.FC<PredictSportCardFooterProps> = ({
3335
market,
3436
testID,
3537
entryPoint: propEntryPoint,
3638
isCarousel,
39+
onBuyButtonPress,
3740
}) => {
3841
const tw = useTailwind();
3942
const navigation =
@@ -82,6 +85,7 @@ const PredictSportCardFooter: React.FC<PredictSportCardFooterProps> = ({
8285
),
8386
) ?? market.outcomes?.[0];
8487

88+
onBuyButtonPress?.(market.id);
8589
executeGuardedAction(
8690
() => {
8791
openBuySheet({
@@ -96,7 +100,13 @@ const PredictSportCardFooter: React.FC<PredictSportCardFooterProps> = ({
96100
},
97101
);
98102
},
99-
[executeGuardedAction, resolvedEntryPoint, openBuySheet, market],
103+
[
104+
executeGuardedAction,
105+
resolvedEntryPoint,
106+
openBuySheet,
107+
market,
108+
onBuyButtonPress,
109+
],
100110
);
101111

102112
const handleClaimPress = useCallback(async () => {

app/components/UI/Trending/components/TrendingTokenRowItem/TrendingTokenRowItem.tsx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,11 @@ interface TrendingTokenRowItemProps {
7272
* asset details screen (including network-add logic and analytics tracking).
7373
*/
7474
onPress?: (token: TrendingAsset) => void;
75+
/**
76+
* Called synchronously before the card's press handler fires.
77+
* Useful for injecting analytics without overriding navigation.
78+
*/
79+
onCardPress?: () => void;
7580
/**
7681
* When the same token row appears in multiple Explore sections, set this to keep
7782
* `testID` (and E2E selectors) unique per instance.
@@ -126,6 +131,7 @@ const TrendingTokenRowItem = ({
126131
tokenDetailsSource = TokenDetailsSource.Trending,
127132
transactionActiveAbTests,
128133
onPress,
134+
onCardPress,
129135
testIdInstanceKey,
130136
}: TrendingTokenRowItemProps) => {
131137
const { styles } = useStyles(styleSheet, {});
@@ -165,12 +171,13 @@ const TrendingTokenRowItem = ({
165171
});
166172

167173
const handlePress = useCallback(async () => {
174+
onCardPress?.();
168175
if (onPress) {
169176
onPress(token);
170177
return;
171178
}
172179
await defaultOnPress();
173-
}, [onPress, token, defaultOnPress]);
180+
}, [onPress, onCardPress, token, defaultOnPress]);
174181

175182
const rowTestId = testIdInstanceKey
176183
? `trending-token-row-item-${testIdInstanceKey}-${token.assetId}`

app/components/Views/TrendingView/TrendingView.tsx

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, { useCallback, useEffect } from 'react';
1+
import React, { useCallback, useEffect, useRef } from 'react';
22
import { TouchableOpacity } from 'react-native';
33
import { SafeAreaView } from 'react-native-safe-area-context';
44
import { useNavigation } from '@react-navigation/native';
@@ -33,6 +33,19 @@ import SportsTab from './tabs/SportsTab';
3333
import DappsTab from './tabs/DappsTab';
3434
import { TrendingViewSelectorsIDs } from './TrendingView.testIds';
3535
import ExplorePageV1 from './ExplorePageV1';
36+
import {
37+
trackExploreInteracted,
38+
type ExploreTabName,
39+
} from './search/analytics';
40+
41+
const TAB_NAMES: ExploreTabName[] = [
42+
'Now',
43+
'Macro',
44+
'RWAs',
45+
'Crypto',
46+
'Sports',
47+
'Sites',
48+
];
3649

3750
export const ExploreFeed: React.FC = () => {
3851
const tw = useTailwind();
@@ -89,6 +102,19 @@ export const ExploreFeed: React.FC = () => {
89102
navigation.navigate(Routes.EXPLORE_SEARCH);
90103
}, [navigation]);
91104

105+
const previousTabRef = useRef<ExploreTabName>('Now');
106+
107+
const handleTabChange = useCallback(({ i }: { i: number }) => {
108+
const destinationTab = TAB_NAMES[i];
109+
if (!destinationTab) return;
110+
trackExploreInteracted({
111+
interaction_type: 'tab_switched',
112+
tab_name: destinationTab,
113+
previous_tab: previousTabRef.current,
114+
});
115+
previousTabRef.current = destinationTab;
116+
}, []);
117+
92118
return (
93119
<SafeAreaView
94120
edges={{ top: 'additive' }}
@@ -123,7 +149,10 @@ export const ExploreFeed: React.FC = () => {
123149
{!isBasicFunctionalityEnabled ? (
124150
<BasicFunctionalityEmptyState />
125151
) : isExplorePageV2Enabled ? (
126-
<TabsList tabsListContentTwClassName="px-0 pb-3">
152+
<TabsList
153+
tabsListContentTwClassName="px-0 pb-3"
154+
onChangeTab={handleTabChange}
155+
>
127156
<Box
128157
key="now"
129158
twClassName="flex-1"
Lines changed: 44 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,66 @@
1-
import React from 'react';
1+
import React, { useCallback } from 'react';
22
import {
33
Text,
44
TextVariant,
55
TextColor,
66
} from '@metamask/design-system-react-native';
77
import BaseSectionHeader from '../../../../component-library/components-temp/SectionHeader';
8+
import {
9+
trackExploreInteracted,
10+
type ExploreTabName,
11+
type ExploreSectionName,
12+
} from '../search/analytics';
813

914
export interface SectionHeaderProps {
1015
title: string;
1116
subtitle?: string;
1217
/** When provided, the title becomes tappable with a trailing chevron. */
1318
onViewAll?: () => void;
1419
testID?: string;
20+
/** Tab context for analytics — required when onViewAll is set. */
21+
tabName?: ExploreTabName;
22+
/** Section context for analytics — required when onViewAll is set. */
23+
sectionName?: ExploreSectionName;
1524
}
1625

1726
const SectionHeader: React.FC<SectionHeaderProps> = ({
1827
title,
1928
subtitle,
2029
onViewAll,
2130
testID,
22-
}) => (
23-
<>
24-
<BaseSectionHeader
25-
testID={testID}
26-
title={title}
27-
onPress={onViewAll}
28-
twClassName={`px-0 ${subtitle ? 'mb-0.5' : 'mb-2'}`}
29-
/>
30-
{subtitle && (
31-
<Text
32-
variant={TextVariant.BodySm}
33-
color={TextColor.TextAlternative}
34-
twClassName="mt-1"
35-
>
36-
{subtitle}
37-
</Text>
38-
)}
39-
</>
40-
);
31+
tabName,
32+
sectionName,
33+
}) => {
34+
const handleViewAll = useCallback(() => {
35+
if (tabName && sectionName) {
36+
trackExploreInteracted({
37+
interaction_type: 'section_see_all_tapped',
38+
tab_name: tabName,
39+
section_name: sectionName,
40+
});
41+
}
42+
onViewAll?.();
43+
}, [onViewAll, tabName, sectionName]);
44+
45+
return (
46+
<>
47+
<BaseSectionHeader
48+
testID={testID}
49+
title={title}
50+
onPress={onViewAll ? handleViewAll : undefined}
51+
twClassName={`px-0 ${subtitle ? 'mb-0.5' : 'mb-2'}`}
52+
/>
53+
{subtitle && (
54+
<Text
55+
variant={TextVariant.BodySm}
56+
color={TextColor.TextAlternative}
57+
twClassName="mt-1"
58+
>
59+
{subtitle}
60+
</Text>
61+
)}
62+
</>
63+
);
64+
};
4165

4266
export default SectionHeader;

app/components/Views/TrendingView/feeds/dapps/SiteTileRowItem.tsx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,17 +55,23 @@ const styleSheet = ({ theme }: { theme: Theme }) =>
5555

5656
interface SiteTileRowItemProps {
5757
site: SiteData;
58+
/** Called synchronously before the card's navigation press fires. */
59+
onCardPress?: () => void;
5860
}
5961

6062
/**
6163
* Compact tile (icon, title, url) for Explore "Recents" / "Networks" carousels.
6264
*/
63-
const SiteTileRowItem: React.FC<SiteTileRowItemProps> = ({ site }) => {
65+
const SiteTileRowItem: React.FC<SiteTileRowItemProps> = ({
66+
site,
67+
onCardPress,
68+
}) => {
6469
const navigation = useNavigation<AppNavigationProp>();
6570
const { styles } = useStyles(styleSheet);
6671
const tw = useTailwind();
6772

6873
const onPress = () => {
74+
onCardPress?.();
6975
navigation.navigate(Routes.BROWSER.HOME, {
7076
screen: Routes.BROWSER.VIEW,
7177
params: {

0 commit comments

Comments
 (0)