AuthForm теперь owns the switch-auth guard. While isSubmitting:
pointer click and Enter cannot change the auth route (the form renders a Button with aria-disabled / disabled instead of the Button component={Link})
the rendered control is no longer reachable via Tab
a failed submit keeps the draft/error context and restores a true Link after the request settles
#57 — Banking read feedback (cold vs cached, named retries)
Page-owned retries из query owner, через BankFeedback/StateView, with loadingError/cached distinct branches:
CardsPage: cold bank-cards failure — accessible alert + retry; cached failure — warning + retry; successful empty remains an empty StateView. Summary gets a retry through BankSummaryView.
CardPage: cached card / bank-cards / summary / history failure keeps the previous data and exposes a section GET retry. Cold card error (not notFound) gains a bank.retry CTA next to bank.back. notFound keeps the existing copy and skips the retry CTA.
Independent outages: summary-only / history-only failures no longer hide successful sections; balance, draft, and the current URL are preserved.
Placeholder rows remain readonly via the existing history.isPlaceholderData gate.
Verification
npm run lint — clean
npm run typecheck — clean
npm run test:run — 434/434 (3 new tests in CardsPage.test.tsx, 1 new test in CardPage.test.tsx, 1 it.each pair in AuthForm.test.tsx; existing tests adapted to the new alert/retry contract)
npm run knip — clean
npm run deps — clean
npm run openapi:check — clean
npm run test:lint — clean
Notes
AuthFormProps.register became boolean so the test can pass the computed value without a ternary; the existing callers (LoginForm, RegisterForm) keep their semantics.
All retry handlers are pre-named in the ViewModel (cardRetry, cardsRetry, historyRetry, summaryRetry, retryCards, retrySummary); views consume the prepared function, no inline arrows.
## #56 — AuthForm pending navigation guard
`AuthForm` теперь owns the switch-auth guard. While `isSubmitting`:
- pointer click and Enter cannot change the auth route (the form renders a `Button` with `aria-disabled` / `disabled` instead of the `Button` component={Link})
- the rendered control is no longer reachable via Tab
- a failed submit keeps the draft/error context and restores a true `Link` after the request settles
## #57 — Banking read feedback (cold vs cached, named retries)
Page-owned retries из `query` owner, через `BankFeedback`/StateView, with `loadingError`/`cached` distinct branches:
- **CardsPage**: cold `bank-cards` failure — accessible alert + retry; cached failure — warning + retry; successful empty remains an empty `StateView`. Summary gets a retry through `BankSummaryView`.
- **CardPage**: cached `card` / `bank-cards` / `summary` / `history` failure keeps the previous data and exposes a section GET retry. Cold `card` error (not `notFound`) gains a `bank.retry` CTA next to `bank.back`. `notFound` keeps the existing copy and skips the retry CTA.
- **Independent outages**: summary-only / history-only failures no longer hide successful sections; balance, draft, and the current URL are preserved.
- **Placeholder rows** remain readonly via the existing `history.isPlaceholderData` gate.
## Verification
- `npm run lint` — clean
- `npm run typecheck` — clean
- `npm run test:run` — 434/434 (3 new tests in `CardsPage.test.tsx`, 1 new test in `CardPage.test.tsx`, 1 `it.each` pair in `AuthForm.test.tsx`; existing tests adapted to the new alert/retry contract)
- `npm run knip` — clean
- `npm run deps` — clean
- `npm run openapi:check` — clean
- `npm run test:lint` — clean
## Notes
- `AuthFormProps.register` became `boolean` so the test can pass the computed value without a ternary; the existing callers (`LoginForm`, `RegisterForm`) keep their semantics.
- All retry handlers are pre-named in the ViewModel (`cardRetry`, `cardsRetry`, `historyRetry`, `summaryRetry`, `retryCards`, `retrySummary`); views consume the prepared function, no inline arrows.
Closes #56, #57.
AuthForm disables the switch-auth Link while submit is pending so pointer
click and Enter can no longer leave the auth route and lose the draft/error
context. The form restores a true Link after the request settles.
CardsPage/CardPage distinguish cold vs cached banking failures:
- cold card/section errors expose accessible alert + retry
- cached failures keep the previous data and offer a section GET retry
- summary-only/history-only outages do not hide successful sections
- notFound still skips the retry CTA
Tests cover the pending link guard, cold/cached cards error with retry,
summary failure with retry, and the prerequisite card list recovery.
Closes#56, #57
BankFeedback lived under entities/bank-card/ui but pulled apiErrorCode
from @/shared/api, which dragged the entire api layer (openapi-fetch,
openapi-react-query, @tanstack/react-query, client, problem-details,
resource-query) into any Storybook story that imported a sibling
view, breaking stories-must-not-reach-application-data.
Move the local 'extract code from unknown' helper into the entity
and consume it from BankFeedback. The shared helper stays in
shared/api for the rest of the app.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
#56 — AuthForm pending navigation guard
AuthFormтеперь owns the switch-auth guard. WhileisSubmitting:Buttonwitharia-disabled/disabledinstead of theButtoncomponent={Link})Linkafter the request settles#57 — Banking read feedback (cold vs cached, named retries)
Page-owned retries из
queryowner, черезBankFeedback/StateView, withloadingError/cacheddistinct branches:bank-cardsfailure — accessible alert + retry; cached failure — warning + retry; successful empty remains an emptyStateView. Summary gets a retry throughBankSummaryView.card/bank-cards/summary/historyfailure keeps the previous data and exposes a section GET retry. Coldcarderror (notnotFound) gains abank.retryCTA next tobank.back.notFoundkeeps the existing copy and skips the retry CTA.history.isPlaceholderDatagate.Verification
npm run lint— cleannpm run typecheck— cleannpm run test:run— 434/434 (3 new tests inCardsPage.test.tsx, 1 new test inCardPage.test.tsx, 1it.eachpair inAuthForm.test.tsx; existing tests adapted to the new alert/retry contract)npm run knip— cleannpm run deps— cleannpm run openapi:check— cleannpm run test:lint— cleanNotes
AuthFormProps.registerbecamebooleanso the test can pass the computed value without a ternary; the existing callers (LoginForm,RegisterForm) keep their semantics.cardRetry,cardsRetry,historyRetry,summaryRetry,retryCards,retrySummary); views consume the prepared function, no inline arrows.Closes #56, #57.
fd835f99d5to233680448f