diff --git a/app/components/UI/Perps/Perps.testIds.ts b/app/components/UI/Perps/Perps.testIds.ts index ccd6d5fefcde..e850e672edd3 100644 --- a/app/components/UI/Perps/Perps.testIds.ts +++ b/app/components/UI/Perps/Perps.testIds.ts @@ -456,6 +456,29 @@ export const PerpsMarketDetailsViewSelectorsIDs = { 'perps-market-details-service-interruption-banner', }; +// ======================================== +// PERPS PRO MARKET VIEW SELECTORS +// ======================================== + +export const PerpsProMarketViewSelectorsIDs = { + CONTAINER: 'perps-pro-market-view', + ERROR: 'perps-pro-market-error', + SCROLL_VIEW: 'perps-pro-market-scroll-view', + HEADER: 'perps-pro-market-header', + HEADER_SYMBOL: 'perps-pro-market-header-symbol', + MARKET_SUMMARY: 'perps-pro-market-summary', + CHART_PANEL: 'perps-pro-market-chart-panel', + CHART_CONTENT: 'perps-pro-market-chart-content', + STATS_BAR: 'perps-pro-market-stats-bar', + LAYOUT: 'perps-pro-market-layout', + LEFT_COLUMN: 'perps-pro-market-left-column', + RIGHT_COLUMN: 'perps-pro-market-right-column', + VERTICAL_DIVIDER: 'perps-pro-market-vertical-divider', + ORDER_FORM_PANEL: 'perps-pro-market-order-form-panel', + ORDER_BOOK_PANEL: 'perps-pro-market-order-book-panel', + POSITIONS_PANEL: 'perps-pro-market-positions-panel', +}; + // ======================================== // PERPS MARKET HEADER SELECTORS // ======================================== diff --git a/app/components/UI/Perps/Views/PerpsMarketDetailsRouter/PerpsMarketDetailsRouter.test.tsx b/app/components/UI/Perps/Views/PerpsMarketDetailsRouter/PerpsMarketDetailsRouter.test.tsx new file mode 100644 index 000000000000..df42ba6c9a4a --- /dev/null +++ b/app/components/UI/Perps/Views/PerpsMarketDetailsRouter/PerpsMarketDetailsRouter.test.tsx @@ -0,0 +1,50 @@ +import React from 'react'; +import { render } from '@testing-library/react-native'; +import PerpsMarketDetailsRouter from './PerpsMarketDetailsRouter'; +import { usePerpsProModeEnabled } from './usePerpsProModeEnabled'; + +jest.mock('./usePerpsProModeEnabled'); + +jest.mock('../PerpsProMarketView', () => { + const { View } = jest.requireActual('react-native'); + return { + __esModule: true, + default: () => , + }; +}); + +jest.mock('../PerpsMarketDetailsView', () => { + const { View } = jest.requireActual('react-native'); + return { + __esModule: true, + default: () => , + }; +}); + +const mockUsePerpsProModeEnabled = jest.mocked(usePerpsProModeEnabled); + +describe('PerpsMarketDetailsRouter', () => { + afterEach(() => { + jest.clearAllMocks(); + }); + + it('renders PerpsProMarketView when Pro mode is enabled', () => { + mockUsePerpsProModeEnabled.mockReturnValue(true); + + const { getByTestId, queryByTestId } = render(); + + expect(getByTestId('mock-pro-market-view')).toBeOnTheScreen(); + expect( + queryByTestId('mock-lite-market-details-view'), + ).not.toBeOnTheScreen(); + }); + + it('renders PerpsMarketDetailsView when Pro mode is disabled', () => { + mockUsePerpsProModeEnabled.mockReturnValue(false); + + const { getByTestId, queryByTestId } = render(); + + expect(getByTestId('mock-lite-market-details-view')).toBeOnTheScreen(); + expect(queryByTestId('mock-pro-market-view')).not.toBeOnTheScreen(); + }); +}); diff --git a/app/components/UI/Perps/Views/PerpsMarketDetailsRouter/PerpsMarketDetailsRouter.tsx b/app/components/UI/Perps/Views/PerpsMarketDetailsRouter/PerpsMarketDetailsRouter.tsx new file mode 100644 index 000000000000..999a1e21ddd3 --- /dev/null +++ b/app/components/UI/Perps/Views/PerpsMarketDetailsRouter/PerpsMarketDetailsRouter.tsx @@ -0,0 +1,20 @@ +import React from 'react'; +import PerpsMarketDetailsView from '../PerpsMarketDetailsView'; +import PerpsProMarketView from '../PerpsProMarketView'; +import { usePerpsProModeEnabled } from './usePerpsProModeEnabled'; + +/** + * Route component registered for `Routes.PERPS.MARKET_DETAILS`. + * + * Renders the Pro-mode market layout (`PerpsProMarketView`) when Pro mode is + * enabled, otherwise the lite `PerpsMarketDetailsView`. The route name and + * navigation params are identical for both modes; only the rendered component + * differs, so market-list navigation is unaffected. + */ +const PerpsMarketDetailsRouter: React.FC = () => { + const isProModeEnabled = usePerpsProModeEnabled(); + + return isProModeEnabled ? : ; +}; + +export default PerpsMarketDetailsRouter; diff --git a/app/components/UI/Perps/Views/PerpsMarketDetailsRouter/index.ts b/app/components/UI/Perps/Views/PerpsMarketDetailsRouter/index.ts new file mode 100644 index 000000000000..83afde2a77d1 --- /dev/null +++ b/app/components/UI/Perps/Views/PerpsMarketDetailsRouter/index.ts @@ -0,0 +1,2 @@ +export { default } from './PerpsMarketDetailsRouter'; +export { usePerpsProModeEnabled } from './usePerpsProModeEnabled'; diff --git a/app/components/UI/Perps/Views/PerpsMarketDetailsRouter/usePerpsProModeEnabled.test.ts b/app/components/UI/Perps/Views/PerpsMarketDetailsRouter/usePerpsProModeEnabled.test.ts new file mode 100644 index 000000000000..3a884177527d --- /dev/null +++ b/app/components/UI/Perps/Views/PerpsMarketDetailsRouter/usePerpsProModeEnabled.test.ts @@ -0,0 +1,10 @@ +import { renderHook } from '@testing-library/react-native'; +import { usePerpsProModeEnabled } from './usePerpsProModeEnabled'; + +describe('usePerpsProModeEnabled', () => { + it('returns false by default while Pro mode is not yet reachable (TAT-3551)', () => { + const { result } = renderHook(() => usePerpsProModeEnabled()); + + expect(result.current).toBe(false); + }); +}); diff --git a/app/components/UI/Perps/Views/PerpsMarketDetailsRouter/usePerpsProModeEnabled.ts b/app/components/UI/Perps/Views/PerpsMarketDetailsRouter/usePerpsProModeEnabled.ts new file mode 100644 index 000000000000..1b1686cf15eb --- /dev/null +++ b/app/components/UI/Perps/Views/PerpsMarketDetailsRouter/usePerpsProModeEnabled.ts @@ -0,0 +1,12 @@ +/** + * Temporary gate for the Perps Pro-mode layout. + * + * TODO(TAT-3551): replace this placeholder once the mobile feature-flag and + * mode selectors land. The Pro view should render only when the feature flag + * is enabled and the persisted controller mode is `PerpsMode.Pro`. Until then + * this always returns `false`, so every user keeps the lite + * `PerpsMarketDetailsView` and the Pro layout is not user-reachable. + * + * @returns Whether the Perps Pro-mode layout is enabled for the current user. + */ +export const usePerpsProModeEnabled = (): boolean => false; diff --git a/app/components/UI/Perps/Views/PerpsProMarketView/PerpsProMarketView.styles.ts b/app/components/UI/Perps/Views/PerpsProMarketView/PerpsProMarketView.styles.ts new file mode 100644 index 000000000000..32143248b45c --- /dev/null +++ b/app/components/UI/Perps/Views/PerpsProMarketView/PerpsProMarketView.styles.ts @@ -0,0 +1,16 @@ +import { StyleSheet } from 'react-native'; +import type { Theme } from '../../../../../util/theme/models'; + +export const createStyles = ({ theme }: { theme: Theme }) => + StyleSheet.create({ + container: { + flex: 1, + backgroundColor: theme.colors.background.default, + }, + scrollView: { + flex: 1, + }, + scrollContent: { + paddingBottom: 16, + }, + }); diff --git a/app/components/UI/Perps/Views/PerpsProMarketView/PerpsProMarketView.test.tsx b/app/components/UI/Perps/Views/PerpsProMarketView/PerpsProMarketView.test.tsx new file mode 100644 index 000000000000..930a1217ffa3 --- /dev/null +++ b/app/components/UI/Perps/Views/PerpsProMarketView/PerpsProMarketView.test.tsx @@ -0,0 +1,141 @@ +import React from 'react'; +import { within } from '@testing-library/react-native'; +import PerpsProMarketView from './'; +import renderWithProvider from '../../../../../util/test/renderWithProvider'; +import { backgroundState } from '../../../../../util/test/initial-root-state'; +import { PerpsProMarketViewSelectorsIDs } from '../../Perps.testIds'; + +interface MockRouteParams { + market?: { symbol: string }; +} + +let mockRouteParams: MockRouteParams | undefined = { + market: { symbol: 'BTC' }, +}; + +jest.mock('@react-navigation/native', () => { + const actualNav = jest.requireActual('@react-navigation/native'); + return { + ...actualNav, + useRoute: () => ({ params: mockRouteParams }), + }; +}); + +const renderView = () => + renderWithProvider(, { + state: { engine: { backgroundState } }, + }); + +describe('PerpsProMarketView', () => { + beforeEach(() => { + mockRouteParams = { market: { symbol: 'BTC' } }; + }); + + it.each([ + ['params', undefined], + ['market', {}], + ['symbol', { market: { symbol: '' } }], + ] as const)( + 'renders the error state when route %s are invalid', + (_missingField, params) => { + mockRouteParams = params; + + const { getByTestId, queryByTestId, getByText } = renderView(); + + expect( + getByTestId(PerpsProMarketViewSelectorsIDs.ERROR), + ).toBeOnTheScreen(); + expect( + getByText('Market data not found. Please go back and try again.'), + ).toBeOnTheScreen(); + expect( + queryByTestId(PerpsProMarketViewSelectorsIDs.CONTAINER), + ).not.toBeOnTheScreen(); + }, + ); + + it('renders the screen inside every safe-area edge', () => { + const { getByTestId } = renderView(); + + expect(getByTestId(PerpsProMarketViewSelectorsIDs.CONTAINER)).toHaveProp( + 'edges', + ['top', 'bottom', 'left', 'right'], + ); + }); + + it('renders every top-level scaffold slot', () => { + const { getByTestId } = renderView(); + + expect( + getByTestId(PerpsProMarketViewSelectorsIDs.HEADER), + ).toBeOnTheScreen(); + expect( + getByTestId(PerpsProMarketViewSelectorsIDs.MARKET_SUMMARY), + ).toBeOnTheScreen(); + expect( + getByTestId(PerpsProMarketViewSelectorsIDs.CHART_PANEL), + ).toBeOnTheScreen(); + expect( + getByTestId(PerpsProMarketViewSelectorsIDs.STATS_BAR), + ).toBeOnTheScreen(); + expect( + getByTestId(PerpsProMarketViewSelectorsIDs.LAYOUT), + ).toBeOnTheScreen(); + expect( + getByTestId(PerpsProMarketViewSelectorsIDs.ORDER_FORM_PANEL), + ).toBeOnTheScreen(); + expect( + getByTestId(PerpsProMarketViewSelectorsIDs.ORDER_BOOK_PANEL), + ).toBeOnTheScreen(); + expect( + getByTestId(PerpsProMarketViewSelectorsIDs.POSITIONS_PANEL), + ).toBeOnTheScreen(); + }); + + it('keeps the header fixed while the market summary scrolls', () => { + const { getByTestId } = renderView(); + + const scrollView = getByTestId(PerpsProMarketViewSelectorsIDs.SCROLL_VIEW); + + expect( + within(scrollView).queryByTestId(PerpsProMarketViewSelectorsIDs.HEADER), + ).not.toBeOnTheScreen(); + expect( + within(scrollView).getByTestId( + PerpsProMarketViewSelectorsIDs.MARKET_SUMMARY, + ), + ).toBeOnTheScreen(); + }); + + it('shows the asset symbol from route params in the header', () => { + const { getByTestId } = renderView(); + + expect( + getByTestId(PerpsProMarketViewSelectorsIDs.HEADER_SYMBOL), + ).toHaveTextContent(/^BTC$/); + }); + + it('removes the HIP-3 dex prefix from the header symbol', () => { + mockRouteParams = { market: { symbol: 'xyz:TSLA' } }; + + const { getByTestId } = renderView(); + + expect( + getByTestId(PerpsProMarketViewSelectorsIDs.HEADER_SYMBOL), + ).toHaveTextContent(/^TSLA$/); + }); + + it('uses the Figma shell heights', () => { + const { getByTestId } = renderView(); + + expect(getByTestId(PerpsProMarketViewSelectorsIDs.HEADER)).toHaveStyle({ + height: 64, + }); + expect( + getByTestId(PerpsProMarketViewSelectorsIDs.MARKET_SUMMARY), + ).toHaveStyle({ height: 76 }); + expect( + getByTestId(PerpsProMarketViewSelectorsIDs.CHART_CONTENT), + ).toHaveStyle({ height: 344 }); + }); +}); diff --git a/app/components/UI/Perps/Views/PerpsProMarketView/PerpsProMarketView.tsx b/app/components/UI/Perps/Views/PerpsProMarketView/PerpsProMarketView.tsx new file mode 100644 index 000000000000..37c12e40c83e --- /dev/null +++ b/app/components/UI/Perps/Views/PerpsProMarketView/PerpsProMarketView.tsx @@ -0,0 +1,88 @@ +import { + Box, + SectionDivider, + Text, + TextColor, + TextVariant, +} from '@metamask/design-system-react-native'; +import { getPerpsDisplaySymbol } from '@metamask/perps-controller'; +import { useRoute, type RouteProp } from '@react-navigation/native'; +import React from 'react'; +import { ScrollView } from 'react-native'; +import { SafeAreaView } from 'react-native-safe-area-context'; +import { strings } from '../../../../../../locales/i18n'; +import { useStyles } from '../../../../../component-library/hooks'; +import { PerpsProMarketViewSelectorsIDs } from '../../Perps.testIds'; +import type { PerpsStackParamList } from '../../types/navigation'; +import PerpsProChartPanel from './components/PerpsProChartPanel'; +import PerpsProMarketHeader from './components/PerpsProMarketHeader'; +import PerpsProMarketLayout from './components/PerpsProMarketLayout'; +import PerpsProMarketSummary from './components/PerpsProMarketSummary'; +import PerpsProOrderBookPanel from './components/PerpsProOrderBookPanel'; +import PerpsProOrderFormPanel from './components/PerpsProOrderFormPanel'; +import PerpsProPositionsPanel from './components/PerpsProPositionsPanel'; +import PerpsProStatsBar from './components/PerpsProStatsBar'; +import { createStyles } from './PerpsProMarketView.styles'; + +/** + * Pro-mode replacement for `PerpsMarketDetailsView`. + * + * Scaffold only: lays out the full Pro trading screen (header, chart, stats + * bar, two-column order form / order book, and positions/orders section) as + * placeholder containers matching Figma node 10041:12979. Each panel can be + * populated by its owning capability without changing the top-level layout. + */ +const PerpsProMarketView = () => { + const { styles } = useStyles(createStyles, {}); + const route = + useRoute>(); + const market = route.params?.market; + + if (!market?.symbol) { + return ( + + + + {strings('perps.market.details.error_message')} + + + + ); + } + + const symbol = getPerpsDisplaySymbol(market.symbol); + + return ( + + + + + + + } + orderBook={} + /> + + + + + ); +}; + +export default PerpsProMarketView; diff --git a/app/components/UI/Perps/Views/PerpsProMarketView/components/PerpsProChartPanel.tsx b/app/components/UI/Perps/Views/PerpsProMarketView/components/PerpsProChartPanel.tsx new file mode 100644 index 000000000000..9a3dd291bc52 --- /dev/null +++ b/app/components/UI/Perps/Views/PerpsProMarketView/components/PerpsProChartPanel.tsx @@ -0,0 +1,31 @@ +import { Box } from '@metamask/design-system-react-native'; +import React from 'react'; +import { StyleSheet } from 'react-native'; +import { PerpsProMarketViewSelectorsIDs } from '../../../Perps.testIds'; + +const styles = StyleSheet.create({ + chart: { + height: 344, + }, +}); + +/** + * Pro-mode chart area placeholder. + * + * Scaffold only: empty container sized to the Figma chart height. Real chart + * content is added by the chart capability. + */ +const PerpsProChartPanel = () => ( + + + +); + +export default PerpsProChartPanel; diff --git a/app/components/UI/Perps/Views/PerpsProMarketView/components/PerpsProMarketHeader.tsx b/app/components/UI/Perps/Views/PerpsProMarketView/components/PerpsProMarketHeader.tsx new file mode 100644 index 000000000000..e7bc20dd6ff1 --- /dev/null +++ b/app/components/UI/Perps/Views/PerpsProMarketView/components/PerpsProMarketHeader.tsx @@ -0,0 +1,48 @@ +import { + Box, + BoxAlignItems, + BoxFlexDirection, + BoxJustifyContent, + Text, + TextVariant, +} from '@metamask/design-system-react-native'; +import React from 'react'; +import { StyleSheet } from 'react-native'; +import { PerpsProMarketViewSelectorsIDs } from '../../../Perps.testIds'; + +interface PerpsProMarketHeaderProps { + symbol: string; +} + +const styles = StyleSheet.create({ + container: { + height: 64, + }, +}); + +/** + * Fixed Pro-mode market header. + * + * Scaffold only: renders the normalized asset symbol for orientation. Header + * actions remain placeholders until their owning capability is implemented. + */ +const PerpsProMarketHeader = ({ symbol }: PerpsProMarketHeaderProps) => ( + + + {symbol} + + + +); + +export default PerpsProMarketHeader; diff --git a/app/components/UI/Perps/Views/PerpsProMarketView/components/PerpsProMarketLayout.test.tsx b/app/components/UI/Perps/Views/PerpsProMarketView/components/PerpsProMarketLayout.test.tsx new file mode 100644 index 000000000000..3931694d9211 --- /dev/null +++ b/app/components/UI/Perps/Views/PerpsProMarketView/components/PerpsProMarketLayout.test.tsx @@ -0,0 +1,42 @@ +import React from 'react'; +import { View } from 'react-native'; +import { render, within } from '@testing-library/react-native'; +import { PerpsProMarketViewSelectorsIDs } from '../../../Perps.testIds'; +import PerpsProMarketLayout from './PerpsProMarketLayout'; + +const renderLayout = () => + render( + } + orderBook={} + />, + ); + +describe('PerpsProMarketLayout', () => { + it('places the order form left and the order book right', () => { + const { getByTestId } = renderLayout(); + + const leftColumn = getByTestId(PerpsProMarketViewSelectorsIDs.LEFT_COLUMN); + const rightColumn = getByTestId( + PerpsProMarketViewSelectorsIDs.RIGHT_COLUMN, + ); + + expect(within(leftColumn).getByTestId('mock-order-form')).toBeOnTheScreen(); + expect( + within(rightColumn).getByTestId('mock-order-book'), + ).toBeOnTheScreen(); + expect(leftColumn).toHaveStyle({ flex: 1 }); + expect(rightColumn).toHaveStyle({ width: 132 }); + }); + + it('uses the Figma trading-area dimensions', () => { + const { getByTestId } = renderLayout(); + + expect(getByTestId(PerpsProMarketViewSelectorsIDs.LAYOUT)).toHaveStyle({ + minHeight: 682, + }); + expect( + getByTestId(PerpsProMarketViewSelectorsIDs.VERTICAL_DIVIDER), + ).toHaveStyle({ width: 24 }); + }); +}); diff --git a/app/components/UI/Perps/Views/PerpsProMarketView/components/PerpsProMarketLayout.tsx b/app/components/UI/Perps/Views/PerpsProMarketView/components/PerpsProMarketLayout.tsx new file mode 100644 index 000000000000..73fb3ad60960 --- /dev/null +++ b/app/components/UI/Perps/Views/PerpsProMarketView/components/PerpsProMarketLayout.tsx @@ -0,0 +1,73 @@ +import { Box, BoxFlexDirection } from '@metamask/design-system-react-native'; +import React, { type ReactNode } from 'react'; +import { StyleSheet } from 'react-native'; +import { PerpsProMarketViewSelectorsIDs } from '../../../Perps.testIds'; + +interface PerpsProMarketLayoutProps { + orderForm: ReactNode; + orderBook: ReactNode; +} + +const PRO_TRADING_AREA_MIN_HEIGHT = 682; +const PRO_DIVIDER_COLUMN_WIDTH = 24; +const PRO_ORDER_BOOK_COLUMN_WIDTH = 132; + +const styles = StyleSheet.create({ + container: { + minHeight: PRO_TRADING_AREA_MIN_HEIGHT, + }, + dividerColumn: { + width: PRO_DIVIDER_COLUMN_WIDTH, + }, + dividerLine: { + width: 1, + }, + orderFormColumn: { + flex: 1, + }, + orderBookColumn: { + width: PRO_ORDER_BOOK_COLUMN_WIDTH, + }, +}); + +/** + * Two-column trading area for the Pro-mode market screen. + * + * Matches the current Figma layout: the order form fills the left column and + * the order book occupies the fixed-width right column. Configurable panel + * positioning is deferred until the rearrangeable-layout feature consumes the + * controller preferences. + */ +const PerpsProMarketLayout = ({ + orderForm, + orderBook, +}: PerpsProMarketLayoutProps) => ( + + + {orderForm} + + + + + + {orderBook} + + +); + +export default PerpsProMarketLayout; diff --git a/app/components/UI/Perps/Views/PerpsProMarketView/components/PerpsProMarketSummary.tsx b/app/components/UI/Perps/Views/PerpsProMarketView/components/PerpsProMarketSummary.tsx new file mode 100644 index 000000000000..0befe273cbd9 --- /dev/null +++ b/app/components/UI/Perps/Views/PerpsProMarketView/components/PerpsProMarketSummary.tsx @@ -0,0 +1,38 @@ +import { + Box, + BoxAlignItems, + BoxFlexDirection, + BoxJustifyContent, +} from '@metamask/design-system-react-native'; +import React from 'react'; +import { StyleSheet } from 'react-native'; +import { PerpsProMarketViewSelectorsIDs } from '../../../Perps.testIds'; + +const styles = StyleSheet.create({ + container: { + height: 76, + }, +}); + +/** + * Scroll-contained market price and 24-hour change placeholder. + * + * The fixed app header remains outside the scroll view. Price content and the + * compact chart action are populated by the panel implementation that owns + * live market data. + */ +const PerpsProMarketSummary = () => ( + + + + +); + +export default PerpsProMarketSummary; diff --git a/app/components/UI/Perps/Views/PerpsProMarketView/components/PerpsProOrderBookPanel.tsx b/app/components/UI/Perps/Views/PerpsProMarketView/components/PerpsProOrderBookPanel.tsx new file mode 100644 index 000000000000..92e59f4caedd --- /dev/null +++ b/app/components/UI/Perps/Views/PerpsProMarketView/components/PerpsProOrderBookPanel.tsx @@ -0,0 +1,20 @@ +import { Box } from '@metamask/design-system-react-native'; +import React from 'react'; +import { PerpsProMarketViewSelectorsIDs } from '../../../Perps.testIds'; + +/** + * Pro-mode order book column placeholder (right column). + * + * Scaffold only: empty container sized to fill the fixed-width column. The + * inline order-book capability populates this slot. + */ +const PerpsProOrderBookPanel = () => ( + + + +); + +export default PerpsProOrderBookPanel; diff --git a/app/components/UI/Perps/Views/PerpsProMarketView/components/PerpsProOrderFormPanel.tsx b/app/components/UI/Perps/Views/PerpsProMarketView/components/PerpsProOrderFormPanel.tsx new file mode 100644 index 000000000000..4c4bc3f98c06 --- /dev/null +++ b/app/components/UI/Perps/Views/PerpsProMarketView/components/PerpsProOrderFormPanel.tsx @@ -0,0 +1,20 @@ +import { Box } from '@metamask/design-system-react-native'; +import React from 'react'; +import { PerpsProMarketViewSelectorsIDs } from '../../../Perps.testIds'; + +/** + * Pro-mode order form column placeholder (left column). + * + * Scaffold only: empty container sized to the Figma order-form column. The + * inline order-form capability populates this slot. + */ +const PerpsProOrderFormPanel = () => ( + + + +); + +export default PerpsProOrderFormPanel; diff --git a/app/components/UI/Perps/Views/PerpsProMarketView/components/PerpsProPositionsPanel.tsx b/app/components/UI/Perps/Views/PerpsProMarketView/components/PerpsProPositionsPanel.tsx new file mode 100644 index 000000000000..178564da4dff --- /dev/null +++ b/app/components/UI/Perps/Views/PerpsProMarketView/components/PerpsProPositionsPanel.tsx @@ -0,0 +1,27 @@ +import { Box } from '@metamask/design-system-react-native'; +import React from 'react'; +import { StyleSheet } from 'react-native'; +import { PerpsProMarketViewSelectorsIDs } from '../../../Perps.testIds'; + +const styles = StyleSheet.create({ + body: { + minHeight: 200, + }, +}); + +/** + * Pro-mode positions/orders section placeholder. + * + * Scaffold only: empty container matching the Figma tabs/filter/summary/list + * area. No ticket currently scopes its content. + */ +const PerpsProPositionsPanel = () => ( + + + +); + +export default PerpsProPositionsPanel; diff --git a/app/components/UI/Perps/Views/PerpsProMarketView/components/PerpsProStatsBar.tsx b/app/components/UI/Perps/Views/PerpsProMarketView/components/PerpsProStatsBar.tsx new file mode 100644 index 000000000000..f4173d5b5844 --- /dev/null +++ b/app/components/UI/Perps/Views/PerpsProMarketView/components/PerpsProStatsBar.tsx @@ -0,0 +1,33 @@ +import { + Box, + BoxAlignItems, + BoxFlexDirection, +} from '@metamask/design-system-react-native'; +import React from 'react'; +import { StyleSheet } from 'react-native'; +import { PerpsProMarketViewSelectorsIDs } from '../../../Perps.testIds'; + +const styles = StyleSheet.create({ + row: { + height: 36, + }, +}); + +/** + * Pro-mode stats bar placeholder (funding, 24h vol, open interest, prices). + * + * Scaffold only: empty row with the Figma top/bottom borders. Real stat values + * are added by a later Pro-mode ticket. + */ +const PerpsProStatsBar = () => ( + + + +); + +export default PerpsProStatsBar; diff --git a/app/components/UI/Perps/Views/PerpsProMarketView/index.ts b/app/components/UI/Perps/Views/PerpsProMarketView/index.ts new file mode 100644 index 000000000000..487b5c21bcb9 --- /dev/null +++ b/app/components/UI/Perps/Views/PerpsProMarketView/index.ts @@ -0,0 +1 @@ +export { default } from './PerpsProMarketView'; diff --git a/app/components/UI/Perps/routes/index.tsx b/app/components/UI/Perps/routes/index.tsx index 7a1b6160b114..64f49013bf86 100644 --- a/app/components/UI/Perps/routes/index.tsx +++ b/app/components/UI/Perps/routes/index.tsx @@ -19,7 +19,7 @@ import { PerpsConnectionProvider } from '../providers/PerpsConnectionProvider'; import { PerpsGlobalErrorGate } from '../components/PerpsGlobalErrorGate'; import { PerpsStreamProvider } from '../providers/PerpsStreamManager'; import PerpsHomeView from '../Views/PerpsHomeView/PerpsHomeView'; -import PerpsMarketDetailsView from '../Views/PerpsMarketDetailsView'; +import PerpsMarketDetailsRouter from '../Views/PerpsMarketDetailsRouter'; import PerpsMarketListView from '../Views/PerpsMarketListView'; import PerpsRedirect from '../Views/PerpsRedirect'; import PerpsOrderRedirect from '../Views/PerpsOrderRedirect'; @@ -300,7 +300,7 @@ const PerpsScreenStack = () => {