Skip to content

Commit aa2970e

Browse files
committed
Aligned more section across wallet and perps
1 parent 597b803 commit aa2970e

17 files changed

Lines changed: 232 additions & 444 deletions

File tree

app/components/UI/Money/components/MoneyMoreSheet/MoneyMoreSheet.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ const MoneyMoreSheet = () => {
104104
},
105105
{
106106
label: strings('money.more_sheet.contact_support'),
107-
icon: IconName.MessageQuestion,
107+
icon: IconName.Sms,
108108
onPress: handleContactSupport,
109109
testID: MoneyMoreSheetTestIds.CONTACT_SUPPORT_OPTION,
110110
},

app/components/UI/Perps/Perps.testIds.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -417,6 +417,7 @@ export const PerpsMarketDetailsViewSelectorsIDs = {
417417
OPEN_INTEREST_INFO_ICON: 'perps-market-details-open-interest-info-icon',
418418
FUNDING_RATE_INFO_ICON: 'perps-market-details-funding-rate-info-icon',
419419
BOTTOM_SHEET_TOOLTIP: 'perps-market-details-bottom-sheet-tooltip',
420+
MORE_SECTION: 'perps-market-details-more-section',
420421
GEO_BLOCK_BOTTOM_SHEET_TOOLTIP:
421422
'perps-market-details-geo-block-bottom-sheet-tooltip',
422423
MARKET_HOURS_BANNER: 'perps-market-hours-banner',

app/components/UI/Perps/Views/PerpsHomeView/PerpsHomeView.test.tsx

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -369,18 +369,21 @@ jest.mock(
369369
},
370370
);
371371
jest.mock('../../components/PerpsCard', () => 'PerpsCard');
372-
jest.mock('../../components/PerpsNavigationCard/PerpsNavigationCard', () => {
372+
jest.mock('../../components/PerpsMoreSection', () => {
373373
const { View, TouchableOpacity, Text } = jest.requireActual('react-native');
374374

375375
return {
376376
__esModule: true,
377-
default: function MockPerpsNavigationCard({
377+
default: function MockPerpsMoreSection({
378378
items,
379+
testID,
379380
}: {
380381
items: { label: string; onPress: () => void; testID?: string }[];
382+
testID?: string;
381383
}) {
382384
return (
383-
<View testID="perps-navigation-card">
385+
<View testID={testID ?? 'perps-more-section'}>
386+
<Text>More</Text>
384387
{items.map(
385388
(
386389
item: { label: string; onPress: () => void; testID?: string },
@@ -783,16 +786,14 @@ describe('PerpsHomeView', () => {
783786
});
784787

785788
// Note: PerpsHomeView does not render a bottom tab bar
786-
// The component uses PerpsNavigationCard for navigation instead
787-
it('renders navigation card', () => {
788-
// Arrange & Act
789-
const { getByTestId } = render(<PerpsHomeView />);
789+
// The component uses PerpsMoreSection for footer actions
790+
it('renders more section', () => {
791+
const { getByTestId, getByText } = render(<PerpsHomeView />);
790792

791-
// Assert - Verify navigation card is rendered (if it has a testID)
792-
// Or just verify component renders without error
793-
// The navigation card is tested separately
793+
expect(getByText('More')).toBeTruthy();
794+
expect(getByTestId(PerpsHomeViewSelectorsIDs.SUPPORT_BUTTON)).toBeTruthy();
794795
expect(
795-
getByTestId(PerpsHomeViewSelectorsIDs.BACK_HOME_BUTTON),
796+
getByTestId(PerpsHomeViewSelectorsIDs.LEARN_MORE_BUTTON),
796797
).toBeTruthy();
797798
});
798799

app/components/UI/Perps/Views/PerpsHomeView/PerpsHomeView.tsx

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -113,9 +113,9 @@ import {
113113
import PerpsCloseAllPositionsView from '../PerpsCloseAllPositionsView/PerpsCloseAllPositionsView';
114114
import PerpsCancelAllOrdersView from '../PerpsCancelAllOrdersView/PerpsCancelAllOrdersView';
115115
import { BottomSheetRef } from '../../../../../component-library/components/BottomSheets/BottomSheet';
116-
import PerpsNavigationCard, {
117-
NavigationItem,
118-
} from '../../components/PerpsNavigationCard/PerpsNavigationCard';
116+
import PerpsMoreSection, {
117+
type PerpsMoreItem,
118+
} from '../../components/PerpsMoreSection';
119119
import PerpsServiceInterruptionBanner from '../../components/PerpsServiceInterruptionBanner';
120120
import PerpsCompetitionBanner from '../../components/PerpsCompetitionBanner';
121121
import PerpsProducts from '../../components/PerpsProducts';
@@ -619,26 +619,28 @@ const PerpsHomeView = ({
619619
});
620620
}, [trackEvent, createEventBuilder, navigation]);
621621

622-
const navigationItems: NavigationItem[] = useMemo(() => {
623-
const items: NavigationItem[] = [
622+
const moreItems: PerpsMoreItem[] = useMemo(() => {
623+
const items: PerpsMoreItem[] = [
624624
{
625625
label: strings(SUPPORT_CONFIG.TitleKey),
626+
startIconName: IconName.Sms,
626627
onPress: () => navigateToContactSupport(),
627628
testID: PerpsHomeViewSelectorsIDs.SUPPORT_BUTTON,
628629
},
629630
];
630631

631-
// Add feedback button when feature flag is enabled
632632
if (isFeedbackEnabled) {
633633
items.push({
634634
label: strings(FEEDBACK_CONFIG.TitleKey),
635+
startIconName: IconName.Mail,
635636
onPress: handleGiveFeedback,
636637
testID: PerpsHomeViewSelectorsIDs.FEEDBACK_BUTTON,
637638
});
638639
}
639640

640641
items.push({
641642
label: strings(LEARN_MORE_CONFIG.TitleKey),
643+
startIconName: IconName.Book,
642644
onPress: () => navigtateToTutorial(),
643645
testID: PerpsHomeViewSelectorsIDs.LEARN_MORE_BUTTON,
644646
});
@@ -899,6 +901,11 @@ const PerpsHomeView = ({
899901
/>
900902
),
901903
},
904+
{
905+
key: 'more',
906+
visible: true,
907+
content: <PerpsMoreSection items={moreItems} />,
908+
},
902909
],
903910
[
904911
isLoading,
@@ -933,6 +940,7 @@ const PerpsHomeView = ({
933940
sortBy,
934941
recentActivity,
935942
handleSectionLayout,
943+
moreItems,
936944
],
937945
);
938946

@@ -1141,10 +1149,6 @@ const PerpsHomeView = ({
11411149

11421150
<PerpsHomeSectionList sections={homeSections} />
11431151

1144-
<View style={styles.sectionContent}>
1145-
<PerpsNavigationCard items={navigationItems} />
1146-
</View>
1147-
11481152
{/* Bottom spacing for tab bar */}
11491153
<View style={bottomSpacerStyle} />
11501154
</Reanimated.ScrollView>

app/components/UI/Perps/Views/PerpsMarketDetailsView/PerpsMarketDetailsView.tsx

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {
55
ButtonSemanticSeverity,
66
ButtonVariant,
77
ButtonSize as ButtonSizeRNDesignSystem,
8+
IconName,
89
Text,
910
TextColor,
1011
TextVariant,
@@ -63,9 +64,9 @@ import PerpsMarketInlineHeader from '../../components/PerpsMarketInlineHeader';
6364
import PerpsMarketHoursBanner from '../../components/PerpsMarketHoursBanner';
6465
import PerpsMarketStatisticsCard from '../../components/PerpsMarketStatisticsCard';
6566
import PerpsMarketTradesList from '../../components/PerpsMarketTradesList';
66-
import PerpsNavigationCard, {
67-
type NavigationItem,
68-
} from '../../components/PerpsNavigationCard/PerpsNavigationCard';
67+
import PerpsMoreSection, {
68+
type PerpsMoreItem,
69+
} from '../../components/PerpsMoreSection';
6970
import PerpsNotificationTooltip from '../../components/PerpsNotificationTooltip';
7071
import PerpsOHLCVBar from '../../components/PerpsOHLCVBar';
7172
import PerpsOICapWarning from '../../components/PerpsOICapWarning';
@@ -1277,10 +1278,11 @@ const PerpsMarketDetailsView: React.FC<PerpsMarketDetailsViewProps> = () => {
12771278
);
12781279

12791280
// Define navigation items for the card
1280-
const navigationItems: NavigationItem[] = useMemo(
1281+
const moreItems: PerpsMoreItem[] = useMemo(
12811282
() => [
12821283
{
12831284
label: strings('perps.tutorial.card.title'),
1285+
startIconName: IconName.Book,
12841286
onPress: () => navigateToTutorial(),
12851287
testID: PerpsTutorialSelectorsIDs.TUTORIAL_CARD,
12861288
},
@@ -1403,6 +1405,16 @@ const PerpsMarketDetailsView: React.FC<PerpsMarketDetailsViewProps> = () => {
14031405
<PerpsMarketTradesList symbol={market.symbol} />
14041406
) : null,
14051407
},
1408+
{
1409+
key: 'more',
1410+
visible: moreItems.length > 0,
1411+
content: (
1412+
<PerpsMoreSection
1413+
items={moreItems}
1414+
testID={PerpsMarketDetailsViewSelectorsIDs.MORE_SECTION}
1415+
/>
1416+
),
1417+
},
14061418
],
14071419
[
14081420
market,
@@ -1411,6 +1423,7 @@ const PerpsMarketDetailsView: React.FC<PerpsMarketDetailsViewProps> = () => {
14111423
isOrderBookEnabled,
14121424
handleOrderBookPress,
14131425
isRelatedMarketsVisible,
1426+
moreItems,
14141427
],
14151428
);
14161429

@@ -1605,12 +1618,6 @@ const PerpsMarketDetailsView: React.FC<PerpsMarketDetailsViewProps> = () => {
16051618

16061619
<PerpsHomeSectionList sections={postMarketInsightsSections} />
16071620

1608-
{navigationItems.length > 0 ? (
1609-
<View style={styles.chromeBlock}>
1610-
<PerpsNavigationCard items={navigationItems} />
1611-
</View>
1612-
) : null}
1613-
16141621
<View style={styles.chromeBlock}>
16151622
<Text
16161623
style={styles.riskDisclaimer}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { StyleSheet } from 'react-native';
2+
3+
const styles = StyleSheet.create({
4+
row: {
5+
alignItems: 'center',
6+
flexDirection: 'row',
7+
paddingHorizontal: 16,
8+
paddingVertical: 12,
9+
},
10+
startIcon: {
11+
marginRight: 16,
12+
},
13+
label: {
14+
flex: 1,
15+
},
16+
});
17+
18+
export default styles;
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import React from 'react';
2+
import { fireEvent, render, screen } from '@testing-library/react-native';
3+
import { IconName } from '@metamask/design-system-react-native';
4+
import PerpsMoreSection, { type PerpsMoreItem } from './PerpsMoreSection';
5+
import { PerpsMoreSectionTestIds } from './PerpsMoreSection.testIds';
6+
7+
describe('PerpsMoreSection', () => {
8+
const mockOnPressSupport = jest.fn();
9+
const mockOnPressLearn = jest.fn();
10+
11+
const items: PerpsMoreItem[] = [
12+
{
13+
label: 'Contact support',
14+
startIconName: IconName.Sms,
15+
onPress: mockOnPressSupport,
16+
testID: 'perps-more-support-button',
17+
},
18+
{
19+
label: 'Learn the basics of perps',
20+
startIconName: IconName.Book,
21+
onPress: mockOnPressLearn,
22+
testID: 'perps-more-learn-button',
23+
},
24+
];
25+
26+
beforeEach(() => {
27+
jest.clearAllMocks();
28+
});
29+
30+
it('renders the More section title and items', () => {
31+
render(<PerpsMoreSection items={items} />);
32+
33+
expect(screen.getByText('More')).toBeOnTheScreen();
34+
expect(screen.getByText('Contact support')).toBeOnTheScreen();
35+
expect(screen.getByText('Learn the basics of perps')).toBeOnTheScreen();
36+
expect(
37+
screen.getByTestId(PerpsMoreSectionTestIds.SECTION),
38+
).toBeOnTheScreen();
39+
});
40+
41+
it('calls onPress when an item is pressed', () => {
42+
render(<PerpsMoreSection items={items} />);
43+
44+
fireEvent.press(screen.getByTestId('perps-more-support-button'));
45+
fireEvent.press(screen.getByTestId('perps-more-learn-button'));
46+
47+
expect(mockOnPressSupport).toHaveBeenCalledTimes(1);
48+
expect(mockOnPressLearn).toHaveBeenCalledTimes(1);
49+
});
50+
51+
it('renders end icon when provided', () => {
52+
const itemsWithEndIcon: PerpsMoreItem[] = [
53+
{
54+
label: 'Contact support',
55+
startIconName: IconName.Sms,
56+
endIconName: IconName.Export,
57+
onPress: mockOnPressSupport,
58+
testID: 'perps-more-support-button',
59+
},
60+
];
61+
62+
render(<PerpsMoreSection items={itemsWithEndIcon} />);
63+
64+
expect(screen.getByText('Contact support')).toBeOnTheScreen();
65+
});
66+
});
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export const PerpsMoreSectionTestIds = {
2+
SECTION: 'perps-more-section',
3+
};
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
import React from 'react';
2+
import { TouchableOpacity, View } from 'react-native';
3+
import {
4+
FontWeight,
5+
Icon,
6+
IconColor,
7+
IconName,
8+
IconSize,
9+
SectionHeader,
10+
Text,
11+
TextColor,
12+
TextVariant,
13+
} from '@metamask/design-system-react-native';
14+
import { strings } from '../../../../../../locales/i18n';
15+
import styles from './PerpsMoreSection.styles';
16+
import { PerpsMoreSectionTestIds } from './PerpsMoreSection.testIds';
17+
18+
export interface PerpsMoreItem {
19+
label: string;
20+
startIconName: IconName;
21+
endIconName?: IconName;
22+
onPress: () => void;
23+
testID: string;
24+
}
25+
26+
interface PerpsMoreSectionProps {
27+
items: PerpsMoreItem[];
28+
testID?: string;
29+
}
30+
31+
interface PerpsMoreActionRowProps {
32+
label: string;
33+
startIconName: IconName;
34+
endIconName?: IconName;
35+
onPress: () => void;
36+
testID: string;
37+
}
38+
39+
const PerpsMoreActionRow = ({
40+
label,
41+
startIconName,
42+
endIconName,
43+
onPress,
44+
testID,
45+
}: PerpsMoreActionRowProps) => (
46+
<TouchableOpacity
47+
accessibilityRole="button"
48+
onPress={onPress}
49+
style={styles.row}
50+
testID={testID}
51+
>
52+
<Icon
53+
name={startIconName}
54+
size={IconSize.Md}
55+
color={IconColor.IconDefault}
56+
style={styles.startIcon}
57+
/>
58+
<Text
59+
variant={TextVariant.BodyMd}
60+
fontWeight={FontWeight.Medium}
61+
color={TextColor.TextDefault}
62+
style={styles.label}
63+
>
64+
{label}
65+
</Text>
66+
{endIconName ? (
67+
<Icon
68+
name={endIconName}
69+
size={IconSize.Md}
70+
color={IconColor.IconAlternative}
71+
/>
72+
) : null}
73+
</TouchableOpacity>
74+
);
75+
76+
const PerpsMoreSection = ({
77+
items,
78+
testID = PerpsMoreSectionTestIds.SECTION,
79+
}: PerpsMoreSectionProps) => (
80+
<View testID={testID}>
81+
<SectionHeader title={strings('homepage.sections.more.title')} />
82+
{items.map((item) => (
83+
<PerpsMoreActionRow
84+
key={item.testID}
85+
label={item.label}
86+
startIconName={item.startIconName}
87+
endIconName={item.endIconName}
88+
onPress={item.onPress}
89+
testID={item.testID}
90+
/>
91+
))}
92+
</View>
93+
);
94+
95+
export default PerpsMoreSection;

0 commit comments

Comments
 (0)