Skip to content
Open
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 @@ -104,7 +104,7 @@ const MoneyMoreSheet = () => {
},
{
label: strings('money.more_sheet.contact_support'),
icon: IconName.MessageQuestion,
icon: IconName.Sms,
onPress: handleContactSupport,
testID: MoneyMoreSheetTestIds.CONTACT_SUPPORT_OPTION,
},
Expand Down
1 change: 1 addition & 0 deletions app/components/UI/Perps/Perps.testIds.ts
Original file line number Diff line number Diff line change
Expand Up @@ -417,6 +417,7 @@ export const PerpsMarketDetailsViewSelectorsIDs = {
OPEN_INTEREST_INFO_ICON: 'perps-market-details-open-interest-info-icon',
FUNDING_RATE_INFO_ICON: 'perps-market-details-funding-rate-info-icon',
BOTTOM_SHEET_TOOLTIP: 'perps-market-details-bottom-sheet-tooltip',
MORE_SECTION: 'perps-market-details-more-section',
GEO_BLOCK_BOTTOM_SHEET_TOOLTIP:
'perps-market-details-geo-block-bottom-sheet-tooltip',
MARKET_HOURS_BANNER: 'perps-market-hours-banner',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -369,18 +369,21 @@ jest.mock(
},
);
jest.mock('../../components/PerpsCard', () => 'PerpsCard');
jest.mock('../../components/PerpsNavigationCard/PerpsNavigationCard', () => {
jest.mock('../../components/PerpsMoreSection', () => {
const { View, TouchableOpacity, Text } = jest.requireActual('react-native');

return {
__esModule: true,
default: function MockPerpsNavigationCard({
default: function MockPerpsMoreSection({
items,
testID,
}: {
items: { label: string; onPress: () => void; testID?: string }[];
testID?: string;
}) {
return (
<View testID="perps-navigation-card">
<View testID={testID ?? 'perps-more-section'}>
<Text>More</Text>
{items.map(
(
item: { label: string; onPress: () => void; testID?: string },
Expand Down Expand Up @@ -783,16 +786,14 @@ describe('PerpsHomeView', () => {
});

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

// Assert - Verify navigation card is rendered (if it has a testID)
// Or just verify component renders without error
// The navigation card is tested separately
expect(getByText('More')).toBeTruthy();
expect(getByTestId(PerpsHomeViewSelectorsIDs.SUPPORT_BUTTON)).toBeTruthy();
expect(
getByTestId(PerpsHomeViewSelectorsIDs.BACK_HOME_BUTTON),
getByTestId(PerpsHomeViewSelectorsIDs.LEARN_MORE_BUTTON),
).toBeTruthy();
});

Expand Down
24 changes: 14 additions & 10 deletions app/components/UI/Perps/Views/PerpsHomeView/PerpsHomeView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -113,9 +113,9 @@ import {
import PerpsCloseAllPositionsView from '../PerpsCloseAllPositionsView/PerpsCloseAllPositionsView';
import PerpsCancelAllOrdersView from '../PerpsCancelAllOrdersView/PerpsCancelAllOrdersView';
import { BottomSheetRef } from '../../../../../component-library/components/BottomSheets/BottomSheet';
import PerpsNavigationCard, {
NavigationItem,
} from '../../components/PerpsNavigationCard/PerpsNavigationCard';
import PerpsMoreSection, {
type PerpsMoreItem,
} from '../../components/PerpsMoreSection';
import PerpsServiceInterruptionBanner from '../../components/PerpsServiceInterruptionBanner';
import PerpsCompetitionBanner from '../../components/PerpsCompetitionBanner';
import PerpsProducts from '../../components/PerpsProducts';
Expand Down Expand Up @@ -619,26 +619,28 @@ const PerpsHomeView = ({
});
}, [trackEvent, createEventBuilder, navigation]);

const navigationItems: NavigationItem[] = useMemo(() => {
const items: NavigationItem[] = [
const moreItems: PerpsMoreItem[] = useMemo(() => {
const items: PerpsMoreItem[] = [
{
label: strings(SUPPORT_CONFIG.TitleKey),
startIconName: IconName.Sms,
onPress: () => navigateToContactSupport(),
testID: PerpsHomeViewSelectorsIDs.SUPPORT_BUTTON,
},
];

// Add feedback button when feature flag is enabled
if (isFeedbackEnabled) {
items.push({
label: strings(FEEDBACK_CONFIG.TitleKey),
startIconName: IconName.Mail,
onPress: handleGiveFeedback,
testID: PerpsHomeViewSelectorsIDs.FEEDBACK_BUTTON,
});
}

items.push({
label: strings(LEARN_MORE_CONFIG.TitleKey),
startIconName: IconName.Book,
onPress: () => navigtateToTutorial(),
testID: PerpsHomeViewSelectorsIDs.LEARN_MORE_BUTTON,
});
Expand Down Expand Up @@ -899,6 +901,11 @@ const PerpsHomeView = ({
/>
),
},
{
key: 'more',
visible: true,
content: <PerpsMoreSection items={moreItems} />,
},
],
[
isLoading,
Expand Down Expand Up @@ -933,6 +940,7 @@ const PerpsHomeView = ({
sortBy,
recentActivity,
handleSectionLayout,
moreItems,
],
);

Expand Down Expand Up @@ -1141,10 +1149,6 @@ const PerpsHomeView = ({

<PerpsHomeSectionList sections={homeSections} />

<View style={styles.sectionContent}>
<PerpsNavigationCard items={navigationItems} />
</View>

{/* Bottom spacing for tab bar */}
<View style={bottomSpacerStyle} />
</Reanimated.ScrollView>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
ButtonSemanticSeverity,
ButtonVariant,
ButtonSize as ButtonSizeRNDesignSystem,
IconName,
Text,
TextColor,
TextVariant,
Expand Down Expand Up @@ -63,9 +64,9 @@ import PerpsMarketInlineHeader from '../../components/PerpsMarketInlineHeader';
import PerpsMarketHoursBanner from '../../components/PerpsMarketHoursBanner';
import PerpsMarketStatisticsCard from '../../components/PerpsMarketStatisticsCard';
import PerpsMarketTradesList from '../../components/PerpsMarketTradesList';
import PerpsNavigationCard, {
type NavigationItem,
} from '../../components/PerpsNavigationCard/PerpsNavigationCard';
import PerpsMoreSection, {
type PerpsMoreItem,
} from '../../components/PerpsMoreSection';
import PerpsNotificationTooltip from '../../components/PerpsNotificationTooltip';
import PerpsOHLCVBar from '../../components/PerpsOHLCVBar';
import PerpsOICapWarning from '../../components/PerpsOICapWarning';
Expand Down Expand Up @@ -1277,10 +1278,11 @@ const PerpsMarketDetailsView: React.FC<PerpsMarketDetailsViewProps> = () => {
);

// Define navigation items for the card
const navigationItems: NavigationItem[] = useMemo(
const moreItems: PerpsMoreItem[] = useMemo(
() => [
{
label: strings('perps.tutorial.card.title'),
startIconName: IconName.Book,
onPress: () => navigateToTutorial(),
testID: PerpsTutorialSelectorsIDs.TUTORIAL_CARD,
},
Expand Down Expand Up @@ -1403,6 +1405,16 @@ const PerpsMarketDetailsView: React.FC<PerpsMarketDetailsViewProps> = () => {
<PerpsMarketTradesList symbol={market.symbol} />
) : null,
},
{
key: 'more',
visible: moreItems.length > 0,
content: (
<PerpsMoreSection
items={moreItems}
testID={PerpsMarketDetailsViewSelectorsIDs.MORE_SECTION}
/>
),
},
],
[
market,
Expand All @@ -1411,6 +1423,7 @@ const PerpsMarketDetailsView: React.FC<PerpsMarketDetailsViewProps> = () => {
isOrderBookEnabled,
handleOrderBookPress,
isRelatedMarketsVisible,
moreItems,
],
);

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

<PerpsHomeSectionList sections={postMarketInsightsSections} />

{navigationItems.length > 0 ? (
<View style={styles.chromeBlock}>
<PerpsNavigationCard items={navigationItems} />
</View>
) : null}

<View style={styles.chromeBlock}>
<Text
style={styles.riskDisclaimer}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { StyleSheet } from 'react-native';

const styles = StyleSheet.create({
row: {
alignItems: 'center',
flexDirection: 'row',
paddingHorizontal: 16,
paddingVertical: 12,
},
startIcon: {
marginRight: 16,
},
label: {
flex: 1,
},
});

export default styles;
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import React from 'react';
import { fireEvent, render, screen } from '@testing-library/react-native';
import { IconName } from '@metamask/design-system-react-native';
import PerpsMoreSection, { type PerpsMoreItem } from './PerpsMoreSection';
import { PerpsMoreSectionTestIds } from './PerpsMoreSection.testIds';

describe('PerpsMoreSection', () => {
const mockOnPressSupport = jest.fn();
const mockOnPressLearn = jest.fn();

const items: PerpsMoreItem[] = [
{
label: 'Contact support',
startIconName: IconName.Sms,
onPress: mockOnPressSupport,
testID: 'perps-more-support-button',
},
{
label: 'Learn the basics of perps',
startIconName: IconName.Book,
onPress: mockOnPressLearn,
testID: 'perps-more-learn-button',
},
];

beforeEach(() => {
jest.clearAllMocks();
});

it('renders the More section title and items', () => {
render(<PerpsMoreSection items={items} />);

expect(screen.getByText('More')).toBeOnTheScreen();
expect(screen.getByText('Contact support')).toBeOnTheScreen();
expect(screen.getByText('Learn the basics of perps')).toBeOnTheScreen();
expect(
screen.getByTestId(PerpsMoreSectionTestIds.SECTION),
).toBeOnTheScreen();
});

it('calls onPress when an item is pressed', () => {
render(<PerpsMoreSection items={items} />);

fireEvent.press(screen.getByTestId('perps-more-support-button'));
fireEvent.press(screen.getByTestId('perps-more-learn-button'));

expect(mockOnPressSupport).toHaveBeenCalledTimes(1);
expect(mockOnPressLearn).toHaveBeenCalledTimes(1);
});

it('renders end icon when provided', () => {
const itemsWithEndIcon: PerpsMoreItem[] = [
{
label: 'Contact support',
startIconName: IconName.Sms,
endIconName: IconName.Export,
onPress: mockOnPressSupport,
testID: 'perps-more-support-button',
},
];

render(<PerpsMoreSection items={itemsWithEndIcon} />);

expect(screen.getByText('Contact support')).toBeOnTheScreen();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export const PerpsMoreSectionTestIds = {
SECTION: 'perps-more-section',
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import React from 'react';
import { TouchableOpacity, View } from 'react-native';
import {
FontWeight,
Icon,
IconColor,
IconName,
IconSize,
SectionHeader,
Text,
TextColor,
TextVariant,
} from '@metamask/design-system-react-native';
import { strings } from '../../../../../../locales/i18n';
import styles from './PerpsMoreSection.styles';
import { PerpsMoreSectionTestIds } from './PerpsMoreSection.testIds';

export interface PerpsMoreItem {
label: string;
startIconName: IconName;
endIconName?: IconName;
onPress: () => void;
testID: string;
}

interface PerpsMoreSectionProps {
items: PerpsMoreItem[];
testID?: string;
}

interface PerpsMoreActionRowProps {
label: string;
startIconName: IconName;
endIconName?: IconName;
onPress: () => void;
testID: string;
}

const PerpsMoreActionRow = ({
label,
startIconName,
endIconName,
onPress,
testID,
}: PerpsMoreActionRowProps) => (
<TouchableOpacity
accessibilityRole="button"
onPress={onPress}
style={styles.row}
testID={testID}
>
<Icon
name={startIconName}
size={IconSize.Md}
color={IconColor.IconDefault}
style={styles.startIcon}
/>
<Text
variant={TextVariant.BodyMd}
fontWeight={FontWeight.Medium}
color={TextColor.TextDefault}
style={styles.label}
>
{label}
</Text>
{endIconName ? (
<Icon
name={endIconName}
size={IconSize.Md}
color={IconColor.IconAlternative}
/>
) : null}
</TouchableOpacity>
);

const PerpsMoreSection = ({
items,
testID = PerpsMoreSectionTestIds.SECTION,
}: PerpsMoreSectionProps) => (
<View testID={testID}>
<SectionHeader title={strings('homepage.sections.more.title')} />
{items.map((item) => (
<PerpsMoreActionRow
key={item.testID}
label={item.label}
startIconName={item.startIconName}
endIconName={item.endIconName}
onPress={item.onPress}
testID={item.testID}
/>
))}
</View>
);

export default PerpsMoreSection;
Loading
Loading