From 7c28a423dd8a3cc4a5bdcb49b8de7018979df413 Mon Sep 17 00:00:00 2001 From: Sergey Krylov Date: Tue, 29 Sep 2026 06:15:31 +0300 Subject: [PATCH] refactor: tighten types and reuse instrument UI --- .ai/conventions/ui.md | 4 +- dependency-cruiser.cjs | 9 +++ eslint.config.mjs | 3 + packages/icons/tsconfig.json | 5 +- .../ui/src/EntryCard/EntryCard.module.css | 10 +++ .../ui/src/EntryCard/EntryCard.stories.tsx | 2 + packages/ui/src/EntryCard/EntryCard.tsx | 8 ++- packages/ui/tsconfig.json | 5 +- scripts/test-eslint.mjs | 15 +++++ src/app/routes/AppRoutes/AppRoutes.test.tsx | 2 + .../RouteErrorBoundary/RouteErrorBoundary.tsx | 6 +- src/app/routes/RouteGuards.tsx | 7 ++- src/entities/bank-card/api/banking.test.tsx | 4 +- src/entities/bank-card/api/mutations.ts | 20 +++--- src/entities/bank-card/api/queries.ts | 3 +- .../ui/BankCardForm/BankCardForm.tsx | 7 +-- .../ui/BankCardForm/useOpeningDateField.ts | 2 +- .../bank-card/ui/BankForms.module.css | 6 -- .../ui/BankSummary/BankSummary.view.tsx | 2 + .../CategoryManager/CategoryManager.test.tsx | 9 +-- .../ui/CategoryManager/CategoryManager.tsx | 9 ++- .../brokerage-event/ui/BrokerageEventCard.tsx | 2 +- src/features/auth/model/auth.test.tsx | 4 +- .../auth/ui/AuthForm/AuthForm.module.css | 4 -- src/features/auth/ui/AuthForm/AuthForm.tsx | 21 +++---- src/features/instrument-details/index.ts | 3 + .../model/useInstrumentParameters.ts | 10 +-- .../ui/InstrumentDetails.module.css | 29 +++++++++ .../ui/InstrumentMetric.view.tsx} | 6 +- .../ui/InstrumentQuoteStatus.view.tsx | 33 ++++++++++ .../tbank-connection/model/screen-sync.ts | 2 +- .../AccountEventsPage.test.tsx | 4 +- src/pages/account-income/model/display.ts | 5 +- .../AccountIncomePage.test.tsx | 2 +- .../AccountOperationsPage.test.tsx | 8 ++- src/pages/account/model/positions.fixtures.ts | 6 +- src/pages/account/model/positions.test.ts | 22 +++---- src/pages/account/model/positions.ts | 2 +- .../ui/AccountPage/AccountPage.test.tsx | 6 +- .../ui/AccountPage/position-groups.test.tsx | 6 +- .../position-layout.browser.test.tsx | 3 +- .../bond/ui/BondPage/BondPage.module.css | 33 ---------- src/pages/bond/ui/BondPage/BondPage.view.tsx | 46 +++++--------- .../BondPage/components/BondCoupons.view.tsx | 8 +-- .../BondPage/components/BondMetrics.view.tsx | 37 +++++------ src/pages/bonds/ui/BondsPage/BondsPage.vm.ts | 2 +- .../card/ui/CardPage/CardPage.module.css | 13 ---- src/pages/card/ui/CardPage/CardPage.view.tsx | 5 +- .../ui/CardPage/CardPagePresentation.vm.ts | 2 +- .../ui/OperationForm/OperationFields.vm.ts | 2 +- .../ui/OperationForm/OperationForm.module.css | 6 -- .../ui/OperationForm/OperationForm.schema.ts | 2 +- .../ui/OperationForm/OperationForm.test.tsx | 2 +- .../ui/OperationForm/OperationForm.view.tsx | 9 ++- .../cards/ui/CardsPage/CardsPage.test.tsx | 10 +-- .../cards/ui/CardsPage/CardsPage.view.tsx | 2 + .../stock/ui/StockPage/StockPage.module.css | 32 +--------- .../stock/ui/StockPage/StockPage.view.tsx | 62 ++++++++----------- .../stocks/ui/StocksPage/StocksPage.vm.ts | 2 +- src/shared/api/authenticated-query.test.tsx | 6 +- src/shared/lib/calendar.ts | 14 +++-- src/shared/lib/display.ts | 36 ++++++----- src/shared/theme/Foundations.stories.tsx | 5 +- src/shared/theme/contrast.test.ts | 40 ++++++++---- tsconfig.app.json | 10 +-- tsconfig.base.json | 15 +++++ tsconfig.node.json | 10 +-- 67 files changed, 380 insertions(+), 347 deletions(-) delete mode 100644 src/entities/bank-card/ui/BankForms.module.css delete mode 100644 src/features/auth/ui/AuthForm/AuthForm.module.css rename src/{pages/bond/ui/BondPage/components/Metric.view.tsx => features/instrument-details/ui/InstrumentMetric.view.tsx} (57%) create mode 100644 src/features/instrument-details/ui/InstrumentQuoteStatus.view.tsx delete mode 100644 src/pages/bond/ui/BondPage/BondPage.module.css delete mode 100644 src/pages/card/ui/OperationForm/OperationForm.module.css create mode 100644 tsconfig.base.json diff --git a/.ai/conventions/ui.md b/.ai/conventions/ui.md index 69db119..432d6ec 100644 --- a/.ai/conventions/ui.md +++ b/.ai/conventions/ui.md @@ -110,8 +110,8 @@ Render-helper замени самостоятельным presentation component При переносе обновляй imports, ссылки документации и проверки, зависящие от пути. Пример: [BankCardForm](../../src/entities/bank-card/ui/BankCardForm/BankCardForm.tsx) -лежит рядом со своим view, тестом и story; общий `BankForms.module.css` -остаётся в `bank-card/ui`. +лежит рядом со своим view, тестом и story. Формы используют Mantine +`Fieldset variant="unstyled"` для групповой блокировки полей без локального CSS. ## Формы diff --git a/dependency-cruiser.cjs b/dependency-cruiser.cjs index 777da44..39beab8 100644 --- a/dependency-cruiser.cjs +++ b/dependency-cruiser.cjs @@ -1,5 +1,14 @@ module.exports = { forbidden: [ + { + from: { + path: "^(src|packages/[^/]+/src)/", + pathNot: "[.](test|stories|fixtures)[.]|^src/test/", + }, + name: "production-must-not-depend-on-test-code", + severity: "error", + to: { path: "[.](test|stories|fixtures)[.]|^src/test/" }, + }, { from: {}, name: "no-unresolved", diff --git a/eslint.config.mjs b/eslint.config.mjs index 2885a5a..1222ea7 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -153,11 +153,13 @@ export default defineConfig( }, }, rules: { + "@typescript-eslint/consistent-type-imports": "error", // React ignores event handler return values; floating promises are still checked in bodies. "@typescript-eslint/no-misused-promises": [ "error", { checksVoidReturn: { attributes: false } }, ], + "@typescript-eslint/no-non-null-assertion": "error", "@typescript-eslint/switch-exhaustiveness-check": "error", }, }, @@ -197,6 +199,7 @@ export default defineConfig( ignoreTypeIndexes: true, }, ], + "@typescript-eslint/no-unnecessary-condition": ["error", { allowConstantLoopConditions: true }], }, }, { diff --git a/packages/icons/tsconfig.json b/packages/icons/tsconfig.json index 77d9d3e..a937da9 100644 --- a/packages/icons/tsconfig.json +++ b/packages/icons/tsconfig.json @@ -1,15 +1,12 @@ { + "extends": "../../tsconfig.base.json", "compilerOptions": { - "target": "ES2023", "lib": [ "ES2023", "DOM" ], "module": "ESNext", "moduleResolution": "Bundler", - "strict": true, - "skipLibCheck": true, - "verbatimModuleSyntax": true, "declaration": true, "emitDeclarationOnly": true, "rootDir": "src", diff --git a/packages/ui/src/EntryCard/EntryCard.module.css b/packages/ui/src/EntryCard/EntryCard.module.css index 2aca6de..fbdcf96 100644 --- a/packages/ui/src/EntryCard/EntryCard.module.css +++ b/packages/ui/src/EntryCard/EntryCard.module.css @@ -93,3 +93,13 @@ transition: none; } } + +.row[data-wrap] p { + white-space: normal; + overflow-wrap: anywhere; +} +@media (min-width: 36em) { + .row[data-wrap] { + grid-template-columns: auto minmax(0, 1fr) minmax(0, 40%); + } +} diff --git a/packages/ui/src/EntryCard/EntryCard.stories.tsx b/packages/ui/src/EntryCard/EntryCard.stories.tsx index 3d06295..063520c 100644 --- a/packages/ui/src/EntryCard/EntryCard.stories.tsx +++ b/packages/ui/src/EntryCard/EntryCard.stories.tsx @@ -39,3 +39,5 @@ export default meta; type Story = StoryObj; export const LongContentAndFallback: Story = {}; + +export const WrappedOperation: Story = { args: { value: "−123 456 789 012 345 678,90 ₽", wrap: true } }; diff --git a/packages/ui/src/EntryCard/EntryCard.tsx b/packages/ui/src/EntryCard/EntryCard.tsx index 9f5d9c0..8a63f82 100644 --- a/packages/ui/src/EntryCard/EntryCard.tsx +++ b/packages/ui/src/EntryCard/EntryCard.tsx @@ -18,6 +18,7 @@ type EntryCardProps = { | "positive"; value: string; valueLabel: string; + wrap?: boolean; }; const EntryCard: FC = (props) => { @@ -31,7 +32,12 @@ const EntryCard: FC = (props) => { const valueLabelClass = `${classes[props.tone]} ${props.actions ? classes.valueLabel : ""}`; return ( - +