Skip to content

Commit 34a0717

Browse files
authored
Merge branch 'main' into MMQA-1633
2 parents 84c5b31 + ec66ea6 commit 34a0717

35 files changed

Lines changed: 1768 additions & 315 deletions

app/components/UI/AssetOverview/Balance/Balance.tsx

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,6 @@ import BadgeWrapper, {
2323
} from '../../../../component-library/components/Badges/BadgeWrapper';
2424
import { BadgeVariant } from '../../../../component-library/components/Badges/Badge/Badge.types';
2525
import Badge from '../../../../component-library/components/Badges/Badge/Badge';
26-
import AvatarToken from '../../../../component-library/components/Avatars/Avatar/variants/AvatarToken';
27-
import { AvatarSize } from '../../../../component-library/components/Avatars/Avatar';
2826
import NetworkAssetLogo from '../../NetworkAssetLogo';
2927
import Text, {
3028
TextColor,
@@ -53,6 +51,7 @@ import { ACCOUNT_TYPE_LABELS } from '../../../../constants/account-type-labels';
5351
import { useRWAToken } from '../../Bridge/hooks/useRWAToken';
5452
import { BridgeToken } from '../../Bridge/types';
5553
import StockBadge from '../../shared/StockBadge';
54+
import AssetLogo from '../../Assets/components/AssetLogo/AssetLogo';
5655

5756
export const ACCOUNT_TYPE_LABEL_TEST_ID = 'account-type-label';
5857

@@ -186,13 +185,7 @@ const Balance = ({
186185
);
187186
}
188187

189-
return (
190-
<AvatarToken
191-
name={asset.symbol}
192-
imageSource={{ uri: asset.image }}
193-
size={AvatarSize.Lg}
194-
/>
195-
);
188+
return <AssetLogo asset={asset} />;
196189
}, [asset, styles.ethLogo]);
197190

198191
const isDisabled = useMemo(

app/components/UI/Predict/components/PredictActionButtons/PredictActionButtons.tsx

Lines changed: 50 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, { useMemo } from 'react';
1+
import React, { useCallback, useMemo } from 'react';
22
import { Box } from '@metamask/design-system-react-native';
33
import PredictBetButtons from './PredictBetButtons';
44
import PredictClaimButton from './PredictClaimButton';
@@ -166,30 +166,60 @@ const PredictActionButtons: React.FC<PredictActionButtonsProps> = ({
166166
}
167167

168168
if (market.status === PredictMarketStatus.OPEN && buttonConfig) {
169-
const drawToken = buttonConfig.drawToken;
170-
171169
return (
172-
<Box twClassName="w-full mt-4">
173-
<PredictBetButtons
174-
yesLabel={buttonConfig.yesLabel}
175-
yesPrice={buttonConfig.yesPrice}
176-
onYesPress={() => onBetPress(buttonConfig.yesToken)}
177-
drawLabel={buttonConfig.drawLabel}
178-
drawPrice={buttonConfig.drawPrice}
179-
onDrawPress={drawToken ? () => onBetPress(drawToken) : undefined}
180-
noLabel={buttonConfig.noLabel}
181-
noPrice={buttonConfig.noPrice}
182-
onNoPress={() => onBetPress(buttonConfig.noToken)}
183-
yesTeamColor={buttonConfig.yesTeamColor}
184-
noTeamColor={buttonConfig.noTeamColor}
185-
testID={`${testID}${PREDICT_ACTION_BUTTONS_TEST_IDS.PREDICT_BET_BUTTON}`}
186-
isCarousel={isCarousel}
187-
/>
188-
</Box>
170+
<PredictBetButtonsContainer
171+
buttonConfig={buttonConfig}
172+
onBetPress={onBetPress}
173+
testID={testID}
174+
isCarousel={isCarousel}
175+
/>
189176
);
190177
}
191178

192179
return null;
193180
};
194181

182+
function PredictBetButtonsContainer(props: {
183+
buttonConfig: ButtonConfig;
184+
onBetPress: (token: PredictOutcomeToken) => void;
185+
testID: string;
186+
isCarousel?: boolean;
187+
}) {
188+
const { buttonConfig, onBetPress, testID, isCarousel } = props;
189+
const { yesToken, drawToken, noToken } = buttonConfig;
190+
191+
const onYesPress = useCallback(
192+
() => onBetPress(yesToken),
193+
[onBetPress, yesToken],
194+
);
195+
const onDrawPress = useMemo(
196+
() => (drawToken ? () => onBetPress(drawToken) : undefined),
197+
[onBetPress, drawToken],
198+
);
199+
const onNoPress = useCallback(
200+
() => onBetPress(noToken),
201+
[onBetPress, noToken],
202+
);
203+
204+
return (
205+
<Box twClassName="w-full mt-4">
206+
<PredictBetButtons
207+
yesLabel={buttonConfig.yesLabel}
208+
yesPrice={buttonConfig.yesPrice}
209+
onYesPress={onYesPress}
210+
drawLabel={buttonConfig.drawLabel}
211+
drawPrice={buttonConfig.drawPrice}
212+
onDrawPress={onDrawPress}
213+
noLabel={buttonConfig.noLabel}
214+
noPrice={buttonConfig.noPrice}
215+
onNoPress={onNoPress}
216+
yesTeamColor={buttonConfig.yesTeamColor}
217+
noTeamColor={buttonConfig.noTeamColor}
218+
testID={`${testID}${PREDICT_ACTION_BUTTONS_TEST_IDS.PREDICT_BET_BUTTON}`}
219+
isCarousel={isCarousel}
220+
/>
221+
</Box>
222+
);
223+
}
224+
195225
export default PredictActionButtons;

app/components/UI/Predict/constants/transactions.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,15 @@ export const PREDICT_BALANCE_CHAIN_ID = '0x89' as Hex;
77

88
export const MINIMUM_BET = 1; // $1 minimum bet
99

10+
// Keeps the CTA locked long enough for the payment selector to close and the
11+
// new quote-loading state to arrive, while avoiding a laggy return to the buy
12+
// sheet after normal blur/focus navigation.
13+
export const PAYMENT_SELECTOR_NAVIGATION_UNLOCK_DELAY_MS = 1000;
14+
15+
// Fallback recovery if the payment-selector route does not emit the expected
16+
// blur/focus events, such as transparent modal or interrupted navigation cases.
17+
export const PAYMENT_SELECTOR_NAVIGATION_SAFETY_UNLOCK_MS = 5000;
18+
1019
export const PREDICT_BALANCE_TOKEN_KEY = 'predict-balance';
1120

1221
export const PREDICTION_ERROR_TRANSACTION_BATCH_ID = 'NA';
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import type { PredictWorldCupConfig } from '../types/flags';
2+
3+
export const PREDICT_WORLD_CUP_FEED_PARAM = 'world-cup';
4+
5+
export const PREDICT_WORLD_CUP_TAB_KEYS = {
6+
ALL: 'all',
7+
LIVE: 'live',
8+
PROPS: 'props',
9+
} as const;
10+
11+
export type PredictWorldCupTabKey = string;
12+
13+
export const getPredictWorldCupAvailableTabKeys = (
14+
config?: Pick<PredictWorldCupConfig, 'stages'>,
15+
): string[] => [
16+
...Object.values(PREDICT_WORLD_CUP_TAB_KEYS),
17+
...(config?.stages ?? []).map((stage) => stage.key),
18+
];
19+
20+
export const resolvePredictWorldCupInitialTab = (
21+
requestedTab?: string | null,
22+
config?: Pick<PredictWorldCupConfig, 'stages'>,
23+
): PredictWorldCupTabKey => {
24+
const normalizedTab = requestedTab?.toLowerCase();
25+
26+
if (!normalizedTab) {
27+
return PREDICT_WORLD_CUP_TAB_KEYS.ALL;
28+
}
29+
30+
const availableTabKeys = getPredictWorldCupAvailableTabKeys(config);
31+
32+
return availableTabKeys.includes(normalizedTab)
33+
? normalizedTab
34+
: PREDICT_WORLD_CUP_TAB_KEYS.ALL;
35+
};

app/components/UI/Predict/routes/index.test.tsx

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,11 @@ jest.mock('../views/PredictFeed', () => {
4343
);
4444
});
4545

46+
jest.mock('../views/PredictWorldCup', () => {
47+
const { View } = jest.requireActual('react-native');
48+
return () => <View testID="predict-world-cup" />;
49+
});
50+
4651
jest.mock('../views/PredictMarketDetails', () => {
4752
const { View } = jest.requireActual('react-native');
4853
return () => <View testID="predict-market-details" />;
@@ -135,6 +140,16 @@ describe('PredictScreenStack', () => {
135140
expect(screen.getByTestId('predict-market-details')).toBeOnTheScreen();
136141
});
137142

143+
it('navigates to WORLD_CUP screen', async () => {
144+
renderWithNavigation(<PredictScreenStack />);
145+
146+
await act(async () => {
147+
navigationRef.current?.navigate(Routes.PREDICT.WORLD_CUP);
148+
});
149+
150+
expect(screen.getByTestId('predict-world-cup')).toBeOnTheScreen();
151+
});
152+
138153
it('navigates to BUY_PREVIEW with PredictBuyPreview when payWithAnyToken is off', async () => {
139154
mockPayWithAnyTokenEnabled = false;
140155

app/components/UI/Predict/routes/index.tsx

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import PredictActivityDetail from '../components/PredictActivityDetail/PredictAc
1212
import { PredictNavigationParamList } from '../types/navigation';
1313
import PredictAddFundsModal from '../views/PredictAddFundsModal/PredictAddFundsModal';
1414
import PredictFeed from '../views/PredictFeed';
15+
import PredictWorldCup from '../views/PredictWorldCup';
1516
import PredictGTMModal from '../components/PredictGTMModal';
1617
import { Dimensions } from 'react-native';
1718
import { useSelector } from 'react-redux';
@@ -162,6 +163,15 @@ const PredictScreenStack = () => {
162163
}}
163164
/>
164165

166+
<Stack.Screen
167+
name={Routes.PREDICT.WORLD_CUP}
168+
component={PredictWorldCup}
169+
options={{
170+
headerShown: false,
171+
cardStyleInterpolator: slideFromRightInterpolator,
172+
}}
173+
/>
174+
165175
<Stack.Screen
166176
name={Routes.PREDICT.MODALS.BUY_PREVIEW}
167177
component={BuyPreviewComponent}

app/components/UI/Predict/types/navigation.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import {
1313
} from '.';
1414
import { PredictEventValues } from '../constants/eventNames';
1515
import type { TransactionActiveAbTestEntry } from '../../../../util/transactions/transaction-active-ab-test-attribution-registry';
16+
import type { PredictWorldCupTabKey } from '../constants/worldCupTabs';
1617

1718
export type PredictEntryPoint =
1819
| typeof PredictEventValues.ENTRY_POINT.CAROUSEL
@@ -47,6 +48,12 @@ export interface PredictMarketDetailsParams {
4748
transactionActiveAbTests?: TransactionActiveAbTestEntry[];
4849
}
4950

51+
/** Predict World Cup feed parameters */
52+
export interface PredictWorldCupParams {
53+
entryPoint?: string;
54+
initialTab?: PredictWorldCupTabKey;
55+
}
56+
5057
/** Predict activity detail parameters */
5158
export interface PredictActivityDetailParams {
5259
activity: PredictActivityItem;
@@ -100,7 +107,7 @@ export interface PredictNavigationParamList extends ParamListBase {
100107
Predict: undefined;
101108
PredictMarketList: PredictMarketListParams;
102109
PredictMarketDetails: PredictMarketDetailsParams;
103-
PredictWorldCup: undefined;
110+
PredictWorldCup: PredictWorldCupParams | undefined;
104111
PredictSellPreview: PredictSellPreviewParams;
105112
PredictBuyPreview: PredictBuyPreviewParams;
106113
PredictActivityDetail: PredictActivityDetailParams;

0 commit comments

Comments
 (0)