- Replace two MUI DatePicker components with a single visual range field - Click opens Popover with community DateCalendar (no DateRangePicker/pro) - First click sets start, second sets end; if end < start, range resets - Remove isOpen/onToggle props — Popover managed locally - Add BrokerDashboardTableSkeleton for events/income loading - Set default weekly range (today-7d / today) for both events and income - Remove 'Фильтр' label, rename 'Показать' → 'Применить период' - Install @mui/x-date-pickers@7 - Update tests for new UI and skeleton loading states - Align spec.md, plan.md, tasks.md with implementation
196 lines
18 KiB
Markdown
196 lines
18 KiB
Markdown
# План реализации редизайна обзора брокерского счёта
|
||
|
||
> **Для агентных исполнителей:** ОБЯЗАТЕЛЬНЫЙ SUB-SKILL: использовать `superpowers:subagent-driven-development` (предпочтительно) или `superpowers:executing-plans` для пошагового выполнения. Шаги ведутся чекбоксами `- [ ]`.
|
||
|
||
**Цель:** превратить `/broker/:accountId` в компактный инвестиционный дашборд на текущей светлой теме без изменения backend-контрактов и URL-структуры.
|
||
|
||
**Архитектура:** маршрут и FSD-границы остаются прежними. Композиция собирается в `widgets/broker-dashboard`, данные продолжают приходить из существующих `entities/*` hooks. Навигация счёта остаётся в `BrokerAccountLayout`, а dashboard использует только локальные presentation/helpers без выноса брокерской логики в design system.
|
||
|
||
**Технологии:** React 18, TanStack Router, TanStack Query, MUI через `@moex-vibe/design-system`, MUI X DateCalendar community (`@mui/x-date-pickers`) с Day.js, Vitest, Testing Library.
|
||
|
||
---
|
||
|
||
## Область реализации
|
||
|
||
### Файлы
|
||
|
||
- Modify: `apps/frontend/src/widgets/broker-account-layout/ui/BrokerAccountLayout.tsx` — горизонтальные вкладки над контентом обзора и подробных разделов.
|
||
- Modify: `apps/frontend/src/pages/broker-account/ui/BrokerAccountOverviewPage.tsx` — точка входа обзора через dashboard.
|
||
- Create/Modify: `apps/frontend/src/widgets/broker-dashboard/index.ts` — публичный API dashboard-виджета.
|
||
- Create/Modify: `apps/frontend/src/widgets/broker-dashboard/ui/BrokerDashboard.tsx` — верхнеуровневая композиция и управление filter state.
|
||
- Create/Modify: `apps/frontend/src/widgets/broker-dashboard/ui/BrokerDashboardHero.tsx` — hero KPI с fallback-значениями и выравниванием `Metric`.
|
||
- Create/Modify: `apps/frontend/src/widgets/broker-dashboard/ui/BrokerDashboardCard.tsx` — локальный паттерн карточки.
|
||
- Create/Modify: `apps/frontend/src/widgets/broker-dashboard/ui/BrokerDashboardEventsCard.tsx` — карточка событий.
|
||
- Create/Modify: `apps/frontend/src/widgets/broker-dashboard/ui/BrokerDashboardDateFilter.tsx` — переиспользуемое управление периодом с draft/apply поведением.
|
||
- Create/Modify: `apps/frontend/src/widgets/broker-dashboard/ui/BrokerDashboardIncomeCard.tsx` — карточка доходов.
|
||
- Create/Modify: `apps/frontend/src/widgets/broker-dashboard/ui/BrokerDashboardAnalyticsCard.tsx` — карточка аналитики доходности.
|
||
- Create/Modify: `apps/frontend/src/widgets/broker-dashboard/ui/BrokerDashboardAllocationCard.tsx` — карточка аллокации с горизонтальными барами.
|
||
- Create/Modify: `apps/frontend/src/widgets/broker-dashboard/ui/BrokerDashboardSkeleton.tsx` — skeleton-форма dashboard.
|
||
- Create/Modify: `apps/frontend/src/widgets/broker-dashboard/ui/BrokerDashboard.test.tsx` — компонентные тесты композиции и фильтров.
|
||
- Create/Modify: `apps/frontend/src/widgets/broker-dashboard/lib/dashboardIncome.ts` — чистые helpers доходных операций.
|
||
- Create/Modify: `apps/frontend/src/widgets/broker-dashboard/lib/dashboardIncome.test.ts` — unit-тесты income helpers.
|
||
- Create/Modify: `apps/frontend/src/widgets/broker-dashboard/lib/dashboardFilters.ts` — пресеты дат, validate и mapping income types.
|
||
- Create/Modify: `apps/frontend/src/widgets/broker-dashboard/lib/dashboardFormatters.ts` — локальные formatter/helpers для fallback и event labels.
|
||
- Modify: `apps/frontend/package.json` — добавить community-пакет `@mui/x-date-pickers`, если зависимость ещё не подключена; `@mui/x-date-pickers-pro` не добавлять.
|
||
- Modify: `docs/features/broker-dashboard-redesign/tasks.md` — фиксация статусов выполнения.
|
||
|
||
### Источники данных
|
||
|
||
- Портфель: `useBrokerAccountContext().portfolio`.
|
||
- События: `useBrokerEvents(accountId, { from, to, types })`.
|
||
- Операции: `useBrokerOperations(accountId, { from, to, operationTypes, cursor, limit: 10 })`.
|
||
- Аналитика: `useBrokerAnalytics(accountId)`.
|
||
- Аллокация: `buildBrokerAllocation(portfolio)`.
|
||
|
||
## Технические решения
|
||
|
||
### 1. Композиция страницы
|
||
|
||
- Dashboard на desktop и mobile строится в одну колонку: `Hero`, `События`, `Доходы`, `Аналитика доходности`, `Аллокация`.
|
||
- Двухколоночный layout из прототипа не переносится.
|
||
- Навигация счёта находится над контентом в `BrokerAccountLayout` и не дублируется внутри dashboard.
|
||
|
||
### 2. Hero KPI
|
||
|
||
- Hero показывает название счёта, стоимость портфеля, доходность, дневное изменение и всего полученных доходов.
|
||
- Приоритет доходности: `analytics.totalReturnPercent`, затем `portfolio.yields.expectedPercent`, иначе `—`.
|
||
- Дневное изменение берётся из `portfolio.yields.daily` и `portfolio.yields.dailyPercent`, при недоступности показывается `—`.
|
||
- Все `Metric` должны иметь одинаковую высоту; supporting text не должен ломать вертикальный ритм.
|
||
|
||
### 3. События
|
||
|
||
- Типы событий переключаются chip-фильтрами с немедленным применением.
|
||
- Диапазон дат по умолчанию: `сегодня - 7 дней` / `сегодня`.
|
||
- Диапазон дат редактируется отдельно от применённого состояния: draft state меняется локально, запрос уходит только по действию применения периода.
|
||
- В шапке управления периодом не используется слово `Фильтр`; роль управления считывается через иконку календаря, применённый диапазон, раскрытие панели и пресеты.
|
||
- Native `<input type="date">` не используется; период выбирается через одно визуальное поле и popover с community `DateCalendar` из `@mui/x-date-pickers`.
|
||
- `DateRangePicker` и `@mui/x-date-pickers-pro` не используются; выбор начала/конца периода реализуется локальной логикой dashboard.
|
||
- При пустом выборе типов запрос отключается, карточка показывает валидационное сообщение.
|
||
- Пагинация локальная, по 10 событий на страницу, сбрасывается при смене применённых фильтров.
|
||
- При загрузке карточка показывает skeleton таблицы событий с колонками дата, инструмент, тип, сумма, статус.
|
||
|
||
### 4. Доходы
|
||
|
||
- Доходы строятся на существующем endpoint операций только для `OPERATION_TYPE_DIVIDEND`, `OPERATION_TYPE_DIV_EXT`, `OPERATION_TYPE_COUPON`.
|
||
- Типы доходов переключаются chip-фильтрами с немедленным применением.
|
||
- Диапазон дат по умолчанию: `сегодня - 7 дней` / `сегодня`, чтобы не загружать большой объём операций на первом открытии.
|
||
- Диапазон дат использует тот же draft/apply паттерн, что и события.
|
||
- В шапке управления периодом не используется слово `Фильтр`; действие применения периода не называется `Показать`.
|
||
- Native `<input type="date">` не используется; период выбирается через одно визуальное поле и popover с community `DateCalendar` из `@mui/x-date-pickers`.
|
||
- `DateRangePicker` и `@mui/x-date-pickers-pro` не используются; выбор начала/конца периода реализуется локальной логикой dashboard.
|
||
- Пагинация cursor-based, размер страницы 10, сбрасывается при смене применённых фильтров.
|
||
- При загрузке карточка показывает skeleton таблицы доходов с колонками дата, инструмент, тип, сумма.
|
||
|
||
### 5. Аналитика и аллокация
|
||
|
||
- Карточка аналитики использует существующий analytics endpoint и показывает спокойное empty state при отсутствии данных.
|
||
- Карточка аллокации не использует donut chart. Она строит список горизонтальных bar rows по `buildBrokerAllocation`.
|
||
- Отрицательные значения показываются текстом без полосы.
|
||
|
||
### 6. Ошибки и пустые состояния
|
||
|
||
- Ошибка `portfolio` роняет весь обзор.
|
||
- Ошибки `events`, `income`, `analytics` локальны соответствующим карточкам.
|
||
- Пустые данные показываются отдельными сообщениями, а не нулевыми значениями.
|
||
|
||
## Задачи
|
||
|
||
### Задача 1: Базовые helpers и локальные dashboard-patterns
|
||
|
||
**Файлы:**
|
||
- `apps/frontend/src/widgets/broker-dashboard/lib/dashboardIncome.ts`
|
||
- `apps/frontend/src/widgets/broker-dashboard/lib/dashboardIncome.test.ts`
|
||
- `apps/frontend/src/widgets/broker-dashboard/lib/dashboardFilters.ts`
|
||
- `apps/frontend/src/widgets/broker-dashboard/lib/dashboardFormatters.ts`
|
||
- `apps/frontend/src/widgets/broker-dashboard/ui/BrokerDashboardCard.tsx`
|
||
|
||
- [ ] Убедиться, что income helpers покрывают только допустимые типы доходов и умеют считать итог отображаемых строк.
|
||
- [ ] Убедиться, что filter helpers содержат default state, date presets, validate и mapping income type -> operation types.
|
||
- [ ] Убедиться, что formatters покрывают fallback-значения, label типов событий и label статусов.
|
||
- [ ] Использовать локальный `BrokerDashboardCard` как основной контейнер карточек; design system расширять только если без этого нельзя реализовать требования спецификации.
|
||
|
||
### Задача 2: Hero и layout overview
|
||
|
||
**Файлы:**
|
||
- `apps/frontend/src/widgets/broker-dashboard/ui/BrokerDashboardHero.tsx`
|
||
- `apps/frontend/src/widgets/broker-dashboard/ui/BrokerDashboardSkeleton.tsx`
|
||
- `apps/frontend/src/widgets/broker-dashboard/ui/BrokerDashboard.tsx`
|
||
- `apps/frontend/src/pages/broker-account/ui/BrokerAccountOverviewPage.tsx`
|
||
- `apps/frontend/src/widgets/broker-account-layout/ui/BrokerAccountLayout.tsx`
|
||
|
||
- [ ] Собрать обзор через `BrokerDashboard` и `BrokerDashboardSkeleton`.
|
||
- [ ] Оставить навигацию счёта в `BrokerAccountLayout` как горизонтальные вкладки над контентом.
|
||
- [ ] Исправить hero так, чтобы все `Metric` были одной высоты и поддерживающий текст не поднимал одну ячейку выше остальных.
|
||
- [ ] Проверить, что dashboard остаётся одноколоночным и на desktop, и на mobile.
|
||
|
||
### Задача 3: Карточка событий
|
||
|
||
**Файлы:**
|
||
- `apps/frontend/src/widgets/broker-dashboard/ui/BrokerDashboardDateFilter.tsx`
|
||
- `apps/frontend/src/widgets/broker-dashboard/ui/BrokerDashboardEventsCard.tsx`
|
||
- `apps/frontend/src/widgets/broker-dashboard/ui/BrokerDashboard.tsx`
|
||
- `apps/frontend/src/widgets/broker-dashboard/lib/dashboardFilters.ts`
|
||
- `apps/frontend/package.json`
|
||
|
||
- [ ] Добавить или подтвердить зависимость community-пакета `@mui/x-date-pickers` и использовать Day.js adapter.
|
||
- [ ] Не добавлять `@mui/x-date-pickers-pro` и не использовать `DateRangePicker`.
|
||
- [ ] Обновить `BrokerDashboardDateFilter`: убрать слово `Фильтр` из пользовательского текста, заменить `Показать` на понятное действие применения периода и визуально собрать chips, диапазон, сброс и применение в аккуратную шапку.
|
||
- [ ] Заменить native date inputs на одно визуальное поле периода, которое открывает MUI `Popover` с community `DateCalendar`.
|
||
- [ ] Реализовать локальную логику выбора диапазона: первый клик задаёт начало, второй — конец; если конец раньше начала, диапазон пересобирается от выбранной даты.
|
||
- [ ] Настроить default range событий на `сегодня - 7 дней` / `сегодня`.
|
||
- [ ] Подключить для событий draft/applied state: типы применяются сразу, даты только по действию применения периода.
|
||
- [ ] Сохранять локальную пагинацию по 10 событий и сбрасывать её при смене применённых фильтров.
|
||
- [ ] Заменить текстовую загрузку событий на skeleton таблицы.
|
||
- [ ] Оставить локальные error/empty states внутри карточки.
|
||
|
||
### Задача 4: Карточка доходов
|
||
|
||
**Файлы:**
|
||
- `apps/frontend/src/widgets/broker-dashboard/ui/BrokerDashboardIncomeCard.tsx`
|
||
- `apps/frontend/src/widgets/broker-dashboard/ui/BrokerDashboard.tsx`
|
||
- `apps/frontend/src/widgets/broker-dashboard/lib/dashboardFilters.ts`
|
||
|
||
- [ ] Подключить тот же `BrokerDashboardDateFilter` для доходов с draft/applied state.
|
||
- [ ] Настроить default range доходов на `сегодня - 7 дней` / `сегодня` вместо периода с начала года.
|
||
- [ ] Оставить chip-фильтры типов доходов с немедленным применением.
|
||
- [ ] Сохранить cursor pagination по 10 операций и сбрасывать её при смене применённых фильтров.
|
||
- [ ] Заменить текстовую загрузку доходов на skeleton таблицы.
|
||
- [ ] Если endpoint операций даёт недостаточно релевантных строк для dashboard, зафиксировать ограничение в заметках по реализации, а не расширять backend в рамках этой фичи.
|
||
|
||
### Задача 5: Карточки аналитики и аллокации
|
||
|
||
**Файлы:**
|
||
- `apps/frontend/src/widgets/broker-dashboard/ui/BrokerDashboardAnalyticsCard.tsx`
|
||
- `apps/frontend/src/widgets/broker-dashboard/ui/BrokerDashboardAllocationCard.tsx`
|
||
|
||
- [ ] Довести карточку аналитики до соответствия спецификации по полям и состояниям.
|
||
- [ ] Заменить donut chart на горизонтальные бары, построенные из `buildBrokerAllocation`.
|
||
- [ ] Отрицательные значения аллокации выводить отдельно текстом без bar.
|
||
|
||
### Задача 6: Тесты и верификация
|
||
|
||
**Файлы:**
|
||
- `apps/frontend/src/widgets/broker-dashboard/ui/BrokerDashboard.test.tsx`
|
||
- `docs/features/broker-dashboard-redesign/tasks.md`
|
||
|
||
- [ ] Обновить компонентные тесты dashboard так, чтобы они покрывали текущую композицию, фильтры и основные empty/error states.
|
||
- [ ] Обновить тесты, которые ищут `Фильтр дат` или `Показать`, под новые тексты и accessible labels единого поля периода.
|
||
- [ ] Добавить/обновить тесты default weekly range для событий и доходов.
|
||
- [ ] Добавить/обновить тесты skeleton-таблиц для loading state событий и доходов.
|
||
- [ ] Прогнать `rtk npm run test:frontend -- --run src/widgets/broker-dashboard`.
|
||
- [ ] Прогнать `rtk npm run test:frontend`.
|
||
- [ ] Прогнать `rtk npm run test:design-system && rtk npm run lint -w apps/frontend && rtk npm run build:frontend`.
|
||
- [ ] Проверить вручную desktop layout `/broker/2084014113`.
|
||
- [ ] Проверить вручную mobile layout `/broker/2084014113` на viewport `390x844`.
|
||
- [ ] После завершения обновить `docs/features/broker-dashboard-redesign/tasks.md` и выполнить `graphify update .`.
|
||
|
||
## Проверка покрытия спецификации
|
||
|
||
- Общая композиция и горизонтальная навигация: задачи 2 и 6.
|
||
- Hero KPI и equal-height `Metric`: задача 2.
|
||
- События с chip filters, date filters и локальной пагинацией: задача 3.
|
||
- Доходы с chip filters, date filters и cursor pagination: задача 4.
|
||
- Community DateCalendar range control, weekly default range и skeleton loading tables: задачи 3, 4 и 6.
|
||
- Аналитика и аллокация с горизонтальными барами: задача 5.
|
||
- Ошибки, empty states, тесты и ручная верификация: задача 6.
|