Extract loading/error/loaded state views from the single AccountOperationsPage.view.tsx into dedicated files under components/. Document the "one state per view file" rule as a mandatory review convention in CONVENTIONS.md and UI-PATTERN.md. Co-Authored-By: opencode <opencode@anthropic.com>
37 lines
3.3 KiB
Markdown
37 lines
3.3 KiB
Markdown
# UI Pattern
|
|
|
|
Формы используют `react-hook-form`, `zodResolver` и `FormProvider`. Form state создаётся в контейнере или VM, чистое представление получает `onSubmit` и `disabled`, а поля подключает через `useFormContext`.
|
|
|
|
Во время submit все действия формы блокируются. Ошибки Zod отображаются у поля; ошибки сети сохраняют введённые значения и показываются отдельным `Alert`.
|
|
|
|
Запросные экраны без успешных данных выбирают состояние в порядке loading, error, empty, loaded. Если query уже содержит данные, они остаются видимыми при фоновом refetch и его ошибке: рядом показываются неблокирующий progress и локальное предупреждение с retry. Такое состояние называется Client Cached Snapshot; оно не заменяет доменное server-side stale/fallback состояние.
|
|
|
|
Для finance-экранов используется граница `container -> ViewModel -> view`.
|
|
`*.tsx` без суффикса — container: он вызывает единственный page VM hook и
|
|
выбирает top-level Loading/Error/Empty/Loaded view. `*.vm.ts` владеет data
|
|
fetching, auth/route inputs, state selection, retry callbacks, domain grouping
|
|
и derived presentation data. `*.view.tsx` и соседние presentation components
|
|
получают props и рендерят JSX.
|
|
|
|
View modules не вызывают data/auth/router/navigation/VM hooks: никаких
|
|
`useBrokerage*`, `usePortfolio`, `useAuth`, `useParams`, `useNavigate` или
|
|
page VM hooks внутри `*.view.tsx` и `components/*.view.tsx`. View modules также
|
|
не группируют domain collections и не считают derived collection values вроде
|
|
долей Portfolio Position. Эти значения готовит VM.
|
|
|
|
Допустимые hooks во view: `useTranslation()` для labels, form-context hooks в
|
|
form views и локальный UI-only state для rendering fallback, например failed
|
|
image state. Простое форматирование одного переданного значения через
|
|
существующий formatter остаётся presentation concern; вычисления из всей
|
|
коллекции остаются во VM.
|
|
|
|
View files дробятся по смысловой нагрузке, а не только по количеству строк.
|
|
Каждый top-level state и каждый именуемый section страницы — отдельный
|
|
`*.view.tsx` в `components/`, а не накопление внутри одного большого
|
|
`*.view.tsx`. Контейнер импортирует state views из `./components` и выбирает
|
|
нужный по `viewModel.state`. Держать loading/error/empty/loaded components в
|
|
одном файле view нельзя.
|
|
|
|
Known API errors, retry и stale snapshot остаются local views, а непойманные
|
|
route errors обрабатывает общий route-keyed ErrorBoundary.
|