Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ export interface BridgeTokenSelectorRouteParams {
}

const MIN_SEARCH_LENGTH = 3;
const ESTIMATED_ITEM_HEIGHT = 72;
const ESTIMATED_ITEM_HEIGHT = 68; // container paddingVertical(4×2) + itemWrapper paddingVertical(10×2) + AvatarSize.Lg(40px)
const LOAD_MORE_DISTANCE_THRESHOLD = 300; // Distance from bottom to trigger load

export const BridgeTokenSelector: React.FC = () => {
Expand Down Expand Up @@ -546,6 +546,10 @@ export const BridgeTokenSelector: React.FC = () => {
ListFooterComponent={renderFooter}
ListEmptyComponent={renderEmptyState}
onLayout={handleFlatListLayout}
initialNumToRender={8}
maxToRenderPerBatch={5}
windowSize={5}
removeClippedSubviews
/>
</SafeAreaView>
);
Expand Down
48 changes: 23 additions & 25 deletions app/components/UI/Bridge/components/TokenButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@ import Text, {
} from '../../../../component-library/components/Texts/Text';
import { useStyles } from '../../../../component-library/hooks';
import { Theme } from '../../../../util/theme/models';
import { Box } from '../../Box/Box';
import { FlexDirection, AlignItems, JustifyContent } from '../../Box/box.types';
import BadgeWrapper, {
BadgePosition,
} from '../../../../component-library/components/Badges/BadgeWrapper';
Expand Down Expand Up @@ -42,6 +40,10 @@ const createStyles = (params: StylesParams) => {
borderRadius: 16,
},
pillContainer: {
flexDirection: 'row' as const,
alignItems: 'flex-end' as const,
justifyContent: 'flex-end' as const,
gap: 8,
backgroundColor: theme.colors.background.muted,
borderRadius: 100,
paddingLeft: 8,
Expand All @@ -67,31 +69,27 @@ export const TokenButton: React.FC<TokenProps> = ({
}) => {
const { styles } = useStyles(createStyles, {});
return (
<TouchableOpacity onPress={onPress} testID={testID}>
<Box
style={styles.pillContainer}
flexDirection={FlexDirection.Row}
alignItems={AlignItems.flexEnd}
justifyContent={JustifyContent.flexEnd}
gap={8}
<TouchableOpacity
onPress={onPress}
testID={testID}
style={styles.pillContainer}
>
<BadgeWrapper
badgePosition={BadgePosition.BottomRight}
badgeElement={
<Badge
variant={BadgeVariant.Network}
imageSource={networkImageSource}
name={networkName}
/>
}
>
<BadgeWrapper
badgePosition={BadgePosition.BottomRight}
badgeElement={
<Badge
variant={BadgeVariant.Network}
imageSource={networkImageSource}
name={networkName}
/>
}
>
<TokenIcon symbol={symbol} icon={iconUrl} style={styles.icon} />
</BadgeWrapper>
<TokenIcon symbol={symbol} icon={iconUrl} style={styles.icon} />
</BadgeWrapper>

<Text style={styles.tokenSymbol} variant={TextVariant.HeadingLG}>
{symbol}
</Text>
</Box>
<Text style={styles.tokenSymbol} variant={TextVariant.HeadingLG}>
{symbol}
</Text>
</TouchableOpacity>
);
};
75 changes: 48 additions & 27 deletions app/components/UI/Bridge/components/TokenSelectorItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,17 @@ const TokenBalanceView = ({
);
};

export const TokenSelectorItem: React.FC<TokenSelectorItemProps> = ({
const TOP_ROW_BALANCE_TEXT_STYLE = {
textVariant: TextVariant.BodyMDMedium,
textColor: TextColor.Default,
} as const;

const BOTTOM_ROW_BALANCE_TEXT_STYLE = {
textVariant: TextVariant.BodySM,
textColor: TextColor.Alternative,
} as const;

const TokenSelectorItemInner: React.FC<TokenSelectorItemProps> = ({
token,
onPress,
networkName,
Expand Down Expand Up @@ -303,27 +313,10 @@ export const TokenSelectorItem: React.FC<TokenSelectorItemProps> = ({

const isNative = token.address === ethers.constants.AddressZero;

// to check if the token is a stock by checking if the name includes 'ondo' or 'stock'
const { isStockToken } = useRWAToken();

const fiatBalance = shouldShowBalance ? fiatValue : undefined;
const tokenBalance = shouldShowBalance ? cryptoBalance : undefined;
const topRowBalanceTextStyle = {
textVariant: TextVariant.BodyMDMedium,
textColor: TextColor.Default,
};
const bottomRowBalanceTextStyle = {
textVariant: TextVariant.BodySM,
textColor: TextColor.Alternative,
};
const topRowTokenBalanceTextStyle = {
...topRowBalanceTextStyle,
...tokenBalanceTextProps,
};
const bottomRowTokenBalanceTextStyle = {
...bottomRowBalanceTextStyle,
...tokenBalanceTextProps,
};

const label = token.accountType
? ACCOUNT_TYPE_LABELS[token.accountType]
Expand All @@ -348,6 +341,7 @@ export const TokenSelectorItem: React.FC<TokenSelectorItemProps> = ({

return (
<Box
accessible={false}
flexDirection={FlexDirection.Row}
alignItems={AlignItems.center}
style={styles.container}
Expand All @@ -361,6 +355,7 @@ export const TokenSelectorItem: React.FC<TokenSelectorItemProps> = ({
testID={getAssetTestId(`${token.chainId}-${token.symbol}`)}
>
<Box
accessible={false}
flexDirection={FlexDirection.Row}
alignItems={AlignItems.center}
gap={4}
Expand All @@ -384,19 +379,20 @@ export const TokenSelectorItem: React.FC<TokenSelectorItemProps> = ({
tokenAvatar
)}

{/* Token symbol/name on the left, balances on the right (extension layout pattern) */}
<Box
accessible={false}
style={styles.tokenInfo}
flexDirection={FlexDirection.Column}
gap={4}
>
<Box
accessible={false}
flexDirection={FlexDirection.Row}
alignItems={AlignItems.center}
justifyContent={JustifyContent.spaceBetween}
>
<Box style={styles.tokenMainInfo} gap={4}>
<Box style={styles.tokenSymbolRow}>
<Box accessible={false} style={styles.tokenMainInfo} gap={4}>
<Box accessible={false} style={styles.tokenSymbolRow}>
<Text
variant={TextVariant.BodyMDMedium}
numberOfLines={1}
Expand Down Expand Up @@ -449,20 +445,32 @@ export const TokenSelectorItem: React.FC<TokenSelectorItemProps> = ({
<TokenBalanceView
balance={tokenBalance}
isSelected={shouldShowSelectedStyle}
textStyle={styles.rightValue}
{...topRowTokenBalanceTextStyle}
textStyle={[
styles.rightValue,
tokenBalanceTextProps?.textStyle,
]}
textVariant={
tokenBalanceTextProps?.textVariant ??
TOP_ROW_BALANCE_TEXT_STYLE.textVariant
}
textColor={
tokenBalanceTextProps?.textColor ??
TOP_ROW_BALANCE_TEXT_STYLE.textColor
}
/>
) : (
<FiatBalanceView
balance={fiatBalance}
isSelected={shouldShowSelectedStyle}
textStyle={styles.rightValue}
{...topRowBalanceTextStyle}
textVariant={TOP_ROW_BALANCE_TEXT_STYLE.textVariant}
textColor={TOP_ROW_BALANCE_TEXT_STYLE.textColor}
/>
)}
</Box>

<Box
accessible={false}
flexDirection={FlexDirection.Row}
alignItems={AlignItems.center}
justifyContent={JustifyContent.spaceBetween}
Expand Down Expand Up @@ -491,14 +499,25 @@ export const TokenSelectorItem: React.FC<TokenSelectorItemProps> = ({
balance={fiatBalance}
isSelected={shouldShowSelectedStyle}
textStyle={styles.rightValue}
{...bottomRowBalanceTextStyle}
textVariant={BOTTOM_ROW_BALANCE_TEXT_STYLE.textVariant}
textColor={BOTTOM_ROW_BALANCE_TEXT_STYLE.textColor}
/>
) : (
<TokenBalanceView
balance={tokenBalance}
isSelected={shouldShowSelectedStyle}
textStyle={styles.rightValue}
{...bottomRowTokenBalanceTextStyle}
textStyle={[
styles.rightValue,
tokenBalanceTextProps?.textStyle,
]}
textVariant={
tokenBalanceTextProps?.textVariant ??
BOTTOM_ROW_BALANCE_TEXT_STYLE.textVariant
}
textColor={
tokenBalanceTextProps?.textColor ??
BOTTOM_ROW_BALANCE_TEXT_STYLE.textColor
}
/>
)}
</Box>
Expand All @@ -511,3 +530,5 @@ export const TokenSelectorItem: React.FC<TokenSelectorItemProps> = ({
</Box>
);
};

export const TokenSelectorItem = React.memo(TokenSelectorItemInner);
1 change: 1 addition & 0 deletions app/components/UI/Card/components/Onboarding/Complete.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ const Complete = () => {
description=""
formFields={renderFormFields()}
actions={renderActions()}
headerMode="back"
/>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,7 @@ const ConfirmEmail = () => {
formFields={renderFormFields()}
actions={renderActions()}
stickyActions
headerMode="back"
/>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,7 @@ const ConfirmPhoneNumber = () => {
formFields={renderFormFields()}
actions={renderActions()}
stickyActions
headerMode="close-with-confirmation"
/>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,14 @@ jest.mock('@metamask/design-system-react-native', () => {
HeadingLg: 'HeadingLg',
BodyMd: 'BodyMd',
},
HeaderStandard: () => null,
};
});

jest.mock('../../hooks/useCardOnboardingNavigationHandlers', () => ({
useCardOnboardingNavigationHandlers: jest.fn(() => ({})),
}));

describe('OnboardingStep Component', () => {
const defaultProps = {
title: 'Test Title',
Expand Down
35 changes: 33 additions & 2 deletions app/components/UI/Card/components/Onboarding/OnboardingStep.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,18 @@
import React from 'react';
import { KeyboardAvoidingView, Platform, ScrollView } from 'react-native';
import { useTailwind } from '@metamask/design-system-twrnc-preset';
import { Box, Text, TextVariant } from '@metamask/design-system-react-native';
import {
Box,
HeaderStandard,
Text,
TextVariant,
} from '@metamask/design-system-react-native';
import { KeyboardAwareScrollView } from 'react-native-keyboard-aware-scroll-view';
import { SafeAreaView } from 'react-native-safe-area-context';
import {
useCardOnboardingNavigationHandlers,
type CardOnboardingHeaderMode,
} from '../../hooks/useCardOnboardingNavigationHandlers';

interface OnboardingStepProps {
title: string;
Expand All @@ -16,6 +25,11 @@ interface OnboardingStepProps {
* @default false
*/
stickyActions?: boolean;
/**
* Controls the in-screen header rendered via HeaderStandard.
* Navigator headers are hidden; onboarding screens own their header chrome.
*/
headerMode?: CardOnboardingHeaderMode;
}

const OnboardingStep = ({
Expand All @@ -24,8 +38,24 @@ const OnboardingStep = ({
formFields,
actions,
stickyActions = false,
headerMode = 'none',
}: OnboardingStepProps) => {
const tw = useTailwind();
const headerHandlers = useCardOnboardingNavigationHandlers(headerMode);

const renderHeader = () => {
if (headerMode === 'none') {
return null;
}

return (
<HeaderStandard
includesTopInset
twClassName="bg-background-default"
{...headerHandlers}
/>
);
};

const renderContent = () => (
<>
Expand Down Expand Up @@ -63,10 +93,10 @@ const OnboardingStep = ({
style={tw.style('flex-1 bg-background-default')}
edges={['bottom']}
>
{renderHeader()}
<KeyboardAvoidingView
behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
style={tw.style('flex-1')}
keyboardVerticalOffset={Platform.OS === 'ios' ? 90 : 0}
>
<ScrollView
contentContainerStyle={tw.style('flex-grow px-4')}
Expand Down Expand Up @@ -94,6 +124,7 @@ const OnboardingStep = ({
style={tw.style('flex-1 bg-background-default')}
edges={['bottom']}
>
{renderHeader()}
<KeyboardAwareScrollView
contentContainerStyle={tw.style('flex-grow px-4')}
showsVerticalScrollIndicator={false}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -465,6 +465,7 @@ const PersonalDetails = () => {
description={strings('card.card_onboarding.personal_details.description')}
formFields={renderFormFields()}
actions={renderActions()}
headerMode="close-with-confirmation"
/>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -822,6 +822,7 @@ const PhysicalAddress = () => {
description={strings('card.card_onboarding.physical_address.description')}
formFields={renderFormFields()}
actions={renderActions()}
headerMode="close-with-confirmation"
/>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,7 @@ const SetPhoneNumber = () => {
formFields={renderFormFields()}
actions={renderActions()}
stickyActions
headerMode="close-with-confirmation"
/>
);
};
Expand Down
1 change: 1 addition & 0 deletions app/components/UI/Card/components/Onboarding/SignUp.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -417,6 +417,7 @@ const SignUp = () => {
description={strings('card.card_onboarding.sign_up.description')}
formFields={renderFormFields()}
actions={renderActions()}
headerMode="back"
/>
);
};
Expand Down
Loading
Loading