From a03e3c024064d0ff2c18c0645496a76c8a34538e Mon Sep 17 00:00:00 2001 From: Sergey Krylov Date: Sat, 20 Jun 2026 12:04:46 +0300 Subject: [PATCH] refactor(frontend): add broker fsd page entrypoints --- .../src/pages/broker-account/index.ts | 1 + .../ui/BrokerAccountOverviewPage.tsx | 1 + .../src/pages/broker-accounts/index.ts | 1 + .../broker-accounts/ui/BrokerAccountsPage.tsx | 1 + .../src/pages/broker-operations/index.ts | 1 + .../ui/BrokerOperationsPage.tsx | 1 + .../src/pages/broker-positions/index.ts | 1 + .../ui/BrokerPositionsPage.tsx | 1 + .../src/pages/broker/BrokerPages.test.tsx | 74 ++++++++++++++++++- apps/frontend/src/routes.tsx | 8 +- 10 files changed, 82 insertions(+), 8 deletions(-) create mode 100644 apps/frontend/src/pages/broker-account/index.ts create mode 100644 apps/frontend/src/pages/broker-account/ui/BrokerAccountOverviewPage.tsx create mode 100644 apps/frontend/src/pages/broker-accounts/index.ts create mode 100644 apps/frontend/src/pages/broker-accounts/ui/BrokerAccountsPage.tsx create mode 100644 apps/frontend/src/pages/broker-operations/index.ts create mode 100644 apps/frontend/src/pages/broker-operations/ui/BrokerOperationsPage.tsx create mode 100644 apps/frontend/src/pages/broker-positions/index.ts create mode 100644 apps/frontend/src/pages/broker-positions/ui/BrokerPositionsPage.tsx diff --git a/apps/frontend/src/pages/broker-account/index.ts b/apps/frontend/src/pages/broker-account/index.ts new file mode 100644 index 0000000..1db6b6b --- /dev/null +++ b/apps/frontend/src/pages/broker-account/index.ts @@ -0,0 +1 @@ +export { BrokerAccountOverviewPage } from './ui/BrokerAccountOverviewPage'; diff --git a/apps/frontend/src/pages/broker-account/ui/BrokerAccountOverviewPage.tsx b/apps/frontend/src/pages/broker-account/ui/BrokerAccountOverviewPage.tsx new file mode 100644 index 0000000..6270d13 --- /dev/null +++ b/apps/frontend/src/pages/broker-account/ui/BrokerAccountOverviewPage.tsx @@ -0,0 +1 @@ +export { BrokerAccountOverviewPage } from '../../broker/BrokerAccountOverviewPage'; diff --git a/apps/frontend/src/pages/broker-accounts/index.ts b/apps/frontend/src/pages/broker-accounts/index.ts new file mode 100644 index 0000000..a708da2 --- /dev/null +++ b/apps/frontend/src/pages/broker-accounts/index.ts @@ -0,0 +1 @@ +export { BrokerAccountsPage } from './ui/BrokerAccountsPage'; diff --git a/apps/frontend/src/pages/broker-accounts/ui/BrokerAccountsPage.tsx b/apps/frontend/src/pages/broker-accounts/ui/BrokerAccountsPage.tsx new file mode 100644 index 0000000..815e9f3 --- /dev/null +++ b/apps/frontend/src/pages/broker-accounts/ui/BrokerAccountsPage.tsx @@ -0,0 +1 @@ +export { BrokerAccountsPage } from '../../broker/BrokerAccountsPage'; diff --git a/apps/frontend/src/pages/broker-operations/index.ts b/apps/frontend/src/pages/broker-operations/index.ts new file mode 100644 index 0000000..b6ce2df --- /dev/null +++ b/apps/frontend/src/pages/broker-operations/index.ts @@ -0,0 +1 @@ +export { BrokerOperationsPage } from './ui/BrokerOperationsPage'; diff --git a/apps/frontend/src/pages/broker-operations/ui/BrokerOperationsPage.tsx b/apps/frontend/src/pages/broker-operations/ui/BrokerOperationsPage.tsx new file mode 100644 index 0000000..5c3281e --- /dev/null +++ b/apps/frontend/src/pages/broker-operations/ui/BrokerOperationsPage.tsx @@ -0,0 +1 @@ +export { BrokerOperationsPage } from '../../broker/BrokerOperationsPage'; diff --git a/apps/frontend/src/pages/broker-positions/index.ts b/apps/frontend/src/pages/broker-positions/index.ts new file mode 100644 index 0000000..f1ff7a6 --- /dev/null +++ b/apps/frontend/src/pages/broker-positions/index.ts @@ -0,0 +1 @@ +export { BrokerPositionsPage } from './ui/BrokerPositionsPage'; diff --git a/apps/frontend/src/pages/broker-positions/ui/BrokerPositionsPage.tsx b/apps/frontend/src/pages/broker-positions/ui/BrokerPositionsPage.tsx new file mode 100644 index 0000000..50b6bc0 --- /dev/null +++ b/apps/frontend/src/pages/broker-positions/ui/BrokerPositionsPage.tsx @@ -0,0 +1 @@ +export { BrokerPositionsPage } from '../../broker/BrokerPositionsPage'; diff --git a/apps/frontend/src/pages/broker/BrokerPages.test.tsx b/apps/frontend/src/pages/broker/BrokerPages.test.tsx index 5c3d63a..64c2c1d 100644 --- a/apps/frontend/src/pages/broker/BrokerPages.test.tsx +++ b/apps/frontend/src/pages/broker/BrokerPages.test.tsx @@ -5,14 +5,18 @@ import { type ReactElement } from 'react'; import { MemoryRouter, Route, Routes } from 'react-router-dom'; import { describe, expect, it, vi } from 'vitest'; import * as operationsHook from '../../hooks/useBrokerOperations'; +import * as brokerAccountsHook from '../../hooks/useBrokerAccounts'; +import * as brokerAccountPortfoliosHook from '../../hooks/useBrokerAccountPortfolios'; import * as portfolioHook from '../../hooks/useBrokerPortfolio'; import * as positionsHook from '../../hooks/useBrokerPositions'; -import type { BrokerPortfolio, BrokerPosition } from '../../api/responses'; +import type { BrokerAccount, BrokerPortfolio, BrokerPosition } from '../../api/responses'; +import { AppRoutes } from '../../routes'; +import { renderWithProviders } from '../../test/test-utils'; import { BrokerAccountLayout, useBrokerAccountContext } from './BrokerAccountLayout'; -import { BrokerAccountOverviewPage } from './BrokerAccountOverviewPage'; -import { BrokerPositionsPage } from './BrokerPositionsPage'; -import { BrokerOperationsPage } from './BrokerOperationsPage'; +import { BrokerAccountOverviewPage } from '../broker-account'; +import { BrokerPositionsPage } from '../broker-positions'; +import { BrokerOperationsPage } from '../broker-operations'; function renderWithClient(ui: ReactElement, initialEntries = ['/broker']) { const client = new QueryClient({ defaultOptions: { queries: { retry: false } } }); @@ -81,6 +85,19 @@ function createOverviewPortfolio(overrides: Partial = {}): Brok }; } +function createBrokerAccount( + overrides: Partial & Pick, +): BrokerAccount { + return { + id: overrides.id, + name: overrides.name, + type: overrides.type ?? 'brokerage', + status: overrides.status ?? 'ACCOUNT_STATUS_OPEN', + openedAt: overrides.openedAt ?? null, + accessLevel: overrides.accessLevel ?? null, + }; +} + function mockOverviewOperations(overrides: Record = {}) { return vi.spyOn(operationsHook, 'useBrokerOperations').mockReturnValue({ data: { @@ -142,6 +159,55 @@ function BrokerAccountContextProbe({ expectedPortfolio }: { expectedPortfolio: u } describe('Broker pages', () => { + it('renders broker routes through fsd entrypoints', async () => { + const account = createBrokerAccount({ id: 'acc-1', name: 'Основной брокерский счёт' }); + + vi.spyOn(brokerAccountsHook, 'useBrokerAccounts').mockReturnValue({ + data: [account], + isLoading: false, + isFetching: false, + error: null, + } as any); + vi.spyOn(brokerAccountPortfoliosHook, 'useBrokerAccountPortfolios').mockReturnValue([ + { + account, + query: { + data: createOverviewPortfolio({ account }), + isLoading: false, + isFetching: false, + isPending: false, + error: null, + refetch: vi.fn(), + }, + }, + ] as any); + vi.spyOn(portfolioHook, 'useBrokerPortfolio').mockReturnValue({ + data: createOverviewPortfolio({ account }), + isLoading: false, + isFetching: false, + error: null, + } as any); + vi.spyOn(positionsHook, 'useBrokerPositions').mockReturnValue({ + data: { + accountId: 'acc-1', + items: [], + nextCursor: null, + hasNext: false, + asOf: '2026-06-19T00:00:00.000Z', + }, + isLoading: false, + isFetching: false, + error: null, + } as any); + mockOverviewOperations(); + + renderWithProviders(, { route: '/broker' }); + + expect( + await screen.findByRole('heading', { level: 1, name: /брокерские счета/i }), + ).toBeInTheDocument(); + }); + it('renders account section navigation with the current nested route', () => { vi.spyOn(portfolioHook, 'useBrokerPortfolio').mockReturnValue({ data: { diff --git a/apps/frontend/src/routes.tsx b/apps/frontend/src/routes.tsx index f239f18..c477d63 100644 --- a/apps/frontend/src/routes.tsx +++ b/apps/frontend/src/routes.tsx @@ -10,11 +10,11 @@ import { ProtectedRoute } from './components/ProtectedRoute'; import { PortfoliosListPage } from './pages/portfolios/PortfoliosListPage'; import { PortfolioDetailPage } from './pages/portfolios/PortfolioDetailPage'; import { ScreenerPage } from './pages/screener/ScreenerPage'; -import { BrokerAccountsPage } from './pages/broker/BrokerAccountsPage'; +import { BrokerAccountsPage } from './pages/broker-accounts'; import { BrokerAccountLayout } from './pages/broker/BrokerAccountLayout'; -import { BrokerAccountOverviewPage } from './pages/broker/BrokerAccountOverviewPage'; -import { BrokerPositionsPage } from './pages/broker/BrokerPositionsPage'; -import { BrokerOperationsPage } from './pages/broker/BrokerOperationsPage'; +import { BrokerAccountOverviewPage } from './pages/broker-account'; +import { BrokerPositionsPage } from './pages/broker-positions'; +import { BrokerOperationsPage } from './pages/broker-operations'; export function AppRoutes() { return (