From cf208e059e4d3c189b3f7e07ff5f137e859249d6 Mon Sep 17 00:00:00 2001 From: Sergey Krylov Date: Thu, 18 Jun 2026 06:54:03 +0300 Subject: [PATCH] docs: add pagination loading overlay design spec (C3) --- ...06-18-pagination-loading-overlay-design.md | 116 ++++++++++++++++++ 1 file changed, 116 insertions(+) create mode 100644 docs/superpowers/specs/2026-06-18-pagination-loading-overlay-design.md diff --git a/docs/superpowers/specs/2026-06-18-pagination-loading-overlay-design.md b/docs/superpowers/specs/2026-06-18-pagination-loading-overlay-design.md new file mode 100644 index 0000000..86e5c79 --- /dev/null +++ b/docs/superpowers/specs/2026-06-18-pagination-loading-overlay-design.md @@ -0,0 +1,116 @@ +# Индикация загрузки при переключении страниц в таблицах брокера + +Дата: 2026-06-18 +Статус: черновик + +## Контекст + +Страница детального просмотра брокерского счёта (`BrokerAccountDetailPage.tsx`) содержит несколько таблиц с пагинацией: + +- **PositionGroupTable** — Акции, Облигации, ETF, Фонды (4 независимые таблицы с курсорной пагинацией) +- **BrokerOperationsTable** — Операции (курсорная пагинация, управляемая из родительского компонента) + +Текущее поведение при переключении страниц: `isLoading === true` → таблица скрывается, показывается `TableSkeleton` (shimmer-строки). Это создаёт визуальный flash: контент исчезает → скелетон → новые данные. При этом `placeholderData: keepPreviousData` уже настроен в хуках, но компоненты его не используют — они проверяют `isLoading`, а не `data`. + +## Цель + +Добавить плавную индикацию загрузки при переключении страниц, чтобы пользователь видел, что данные обновляются, но не терял визуальный контекст. + +## Дизайн (выбран C3) + +### Визуальное поведение + +1. При нажатии «→» (вперед) или «←» (назад): + - Текущее содержимое таблицы **остаётся видимым** (предыдущая страница) + - Поверх таблицы появляется **полупрозрачный overlay** с центрированным спиннером + - Кнопка пагинации показывает спиннер и блокируется +2. Когда новые данные загружены: + - Overlay исчезает с fade-out + - Таблица обновляется новыми данными +3. При первой загрузке (initial load): + - Overlay не используется (нет старых данных для показа) + - Показывается `TableSkeleton` (как сейчас) + +### Как это работает технически + +TanStack Query v5 предоставляет два флага: + +- `isLoading` — true, когда данных **нет** и идёт первый запрос (initial load) +- `isFetching` — true при любом запросе (включая фоновые refetch'и при смене cursor) + +Логика рендеринга для таблиц: + +``` +if isLoading → TableSkeleton (первая загрузка, данных нет) +if isFetching && data → TableLoadingOverlay + старые данные (переключение страниц) +иначе → рендер таблицы с данными +``` + +### Компонент TableLoadingOverlay + +```tsx +interface TableLoadingOverlayProps { + pageNumber?: number; +} + +function TableLoadingOverlay({ pageNumber }: TableLoadingOverlayProps) { + return ( +
+
+ {pageNumber !== undefined && ( + + Загрузка страницы {pageNumber}… + + )} +
+ ); +} +``` + +### Пагинация: спиннер в кнопке + +При `isFetching` кнопка «→» или «←» показывает спиннер вместо стрелки и становится disabled. + +```css +@keyframes loading-spin { + to { transform: rotate(360deg); } +} + +.loading-spinner { + width: 20px; height: 20px; + border: 2px solid var(--color-border); + border-top-color: var(--color-accent); + border-radius: 50%; + animation: loading-spin 0.8s linear infinite; +} +``` + +## Где применяется + +| Компонент | Что меняется | +|---|---| +| `BrokerPositionsSection.tsx` (PositionGroupTable) | Overlay вместо TableSkeleton при isFetching. Спиннер в кнопках пагинации | +| `BrokerOperationsTable.tsx` | Overlay вместо TableSkeleton при isFetching. Спиннер в кнопках пагинации | + +## Файлы для изменения + +| Файл | Изменение | +|---|---| +| `apps/frontend/src/styles.css` | Добавить `@keyframes loading-spin`, `.loading-spinner`, `.table-loading-overlay` | +| `apps/frontend/src/pages/broker/BrokerPositionsSection.tsx` | Overlay + спиннер в пагинации. Использовать `isFetching` из хука | +| `apps/frontend/src/pages/broker/BrokerOperationsTable.tsx` | Overlay + спиннер в пагинации. Использовать `isFetching` из хука | +| `apps/frontend/src/pages/broker/BrokerAccountDetailPage.tsx` | Прокинуть `isFetching` для операций (из useBrokerOperations) | +| `apps/frontend/src/pages/broker/BrokerPages.test.tsx` | Обновить тесты для overlay-логики | + +## Тестирование + +- `npm run test:frontend` — существующие тесты проходят с учётом изменений +- Ручная проверка: переключение страниц в Акциях, Облигациях, Операциях — overlay появляется/исчезает +- Ручная проверка: при первой загрузке — skeleton (не overlay) +- Ручная проверка: при быстром переключении (быстрее, чем загрузка) — overlay остаётся, данные не мигают