From c1a8674f164117018236bf461bd457208ac9ad00 Mon Sep 17 00:00:00 2001 From: Sergey Krylov Date: Wed, 26 Aug 2026 13:55:44 +0300 Subject: [PATCH] feat(account): wrap portfolio sections in Mantine Accordion All portfolio sections (stocks, bonds, other, cash, recent operations, recent events) are now collapsible via Mantine Accordion. Sections expand by default. Accordion control label uses h2 size to match previous Section headings. Panel horizontal padding removed. Smooth hover transition added. Removed unused Section component. Updated lazy-route bundle baseline for account chunk. --- scripts/lazy-route-bundle-baseline.json | 2 +- src/pages/account/ui/AccountPage.module.css | 17 ++++++ src/pages/account/ui/AccountPage.test.tsx | 4 +- src/pages/account/ui/AccountPage.view.tsx | 59 ++++++++++++++----- .../ui/components/PositionSection.view.tsx | 38 ++++++------ .../ui/components/RecentEvents.view.tsx | 7 +-- .../ui/components/RecentOperations.view.tsx | 7 +-- .../account/ui/components/Section.view.tsx | 19 ------ src/pages/account/ui/components/index.ts | 1 - 9 files changed, 88 insertions(+), 66 deletions(-) delete mode 100644 src/pages/account/ui/components/Section.view.tsx diff --git a/scripts/lazy-route-bundle-baseline.json b/scripts/lazy-route-bundle-baseline.json index 06978a1..9c3cff3 100644 --- a/scripts/lazy-route-bundle-baseline.json +++ b/scripts/lazy-route-bundle-baseline.json @@ -2,7 +2,7 @@ "src/app/routes/ProtectedLayout.tsx": 3057, "src/pages/account-events/index.ts": 4364, "src/pages/account-operations/index.ts": 13854, - "src/pages/account/index.ts": 25407, + "src/pages/account/index.ts": 32466, "src/pages/accounts/index.ts": 6145, "src/pages/login/index.ts": 662, "src/pages/not-found/index.ts": 877, diff --git a/src/pages/account/ui/AccountPage.module.css b/src/pages/account/ui/AccountPage.module.css index 98c49fb..38b459e 100644 --- a/src/pages/account/ui/AccountPage.module.css +++ b/src/pages/account/ui/AccountPage.module.css @@ -90,3 +90,20 @@ .mono { font-family: var(--mantine-font-family-monospace); } + +.accordionControl { + transition: + background-color 150ms ease, + color 150ms ease; +} + +.accordionLabel { + font-size: var(--mantine-h2-font-size); + font-weight: var(--mantine-h2-font-weight); + line-height: var(--mantine-h2-line-height); +} + +.accordionPanel { + padding-left: 0; + padding-right: 0; +} diff --git a/src/pages/account/ui/AccountPage.test.tsx b/src/pages/account/ui/AccountPage.test.tsx index 2ef1891..1a31fb4 100644 --- a/src/pages/account/ui/AccountPage.test.tsx +++ b/src/pages/account/ui/AccountPage.test.tsx @@ -154,9 +154,9 @@ describe("AccountPage states", () => { "T-Bank временно недоступен. Показан последний успешный снимок.", ), ).toBeInTheDocument(); - expect(screen.getByRole("heading", { name: "Акции" })).toBeInTheDocument(); + expect(screen.getByRole("button", { name: "Акции" })).toBeInTheDocument(); expect( - screen.getByRole("heading", { name: "Облигации" }), + screen.getByRole("button", { name: "Облигации" }), ).toBeInTheDocument(); const positions = screen .getAllByText(/Вторая|Первая/) diff --git a/src/pages/account/ui/AccountPage.view.tsx b/src/pages/account/ui/AccountPage.view.tsx index 3d7c111..e250f3d 100644 --- a/src/pages/account/ui/AccountPage.view.tsx +++ b/src/pages/account/ui/AccountPage.view.tsx @@ -1,4 +1,4 @@ -import { Alert, Button, Stack, Text } from "@mantine/core"; +import { Accordion, Alert, Button, Stack, Text } from "@mantine/core"; import type { FC } from "react"; import { useTranslation } from "react-i18next"; import { Link } from "react-router"; @@ -20,7 +20,6 @@ import { PositionSection, RecentEvents, RecentOperations, - Section, } from "./components"; type AccountPageErrorProps = { @@ -167,18 +166,50 @@ const AccountPageLoaded: FC = (props) => { })} - {positionSections.map((section) => ( - - ))} -
- -
- - + s.kind), + "cash", + "recentOperations", + "recentEvents", + ]} + classNames={{ + control: classes.accordionControl, + label: classes.accordionLabel, + chevron: classes.accordionChevron, + panel: classes.accordionPanel, + }} + > + {positionSections.map((section) => ( + + + {t(positionSectionTitleKey(section.kind))} + + + + + + ))} + + {t("portfolio.cashBalances")} + + + + + + {t("ledger.recentTitle")} + + + + + + {t("events.recentTitle")} + + + + + ); }; diff --git a/src/pages/account/ui/components/PositionSection.view.tsx b/src/pages/account/ui/components/PositionSection.view.tsx index aa3c229..765af70 100644 --- a/src/pages/account/ui/components/PositionSection.view.tsx +++ b/src/pages/account/ui/components/PositionSection.view.tsx @@ -2,35 +2,31 @@ import { SimpleGrid } from "@mantine/core"; import type { FC } from "react"; import type { AccountPagePositionSection } from "../AccountPage.vm"; import { PositionCard } from "./PositionCard.view"; -import { Section } from "./Section.view"; type PositionSectionProps = { - title: string; section: AccountPagePositionSection; }; const PositionSection: FC = (props) => { - const { title, section } = props; + const { section } = props; return ( -
- - {section.positions.map((position) => ( - - ))} - -
+ + {section.positions.map((position) => ( + + ))} + ); }; diff --git a/src/pages/account/ui/components/RecentEvents.view.tsx b/src/pages/account/ui/components/RecentEvents.view.tsx index f72df75..aec379d 100644 --- a/src/pages/account/ui/components/RecentEvents.view.tsx +++ b/src/pages/account/ui/components/RecentEvents.view.tsx @@ -1,4 +1,4 @@ -import { Alert, Button, Paper, Text } from "@mantine/core"; +import { Alert, Button, Paper, Stack, Text } from "@mantine/core"; import type { FC } from "react"; import { useTranslation } from "react-i18next"; import { Link } from "react-router"; @@ -6,7 +6,6 @@ import type { BrokerageEvent } from "@/entities/brokerage-event"; import { formatMoney } from "@/entities/portfolio"; import classes from "../AccountPage.module.css"; import type { AccountPageRecentEvents } from "../AccountPage.vm"; -import { Section } from "./Section.view"; type RecentEventsProps = { events: AccountPageRecentEvents; @@ -21,7 +20,7 @@ const RecentEvents: FC = (props) => { const { t } = useTranslation(); return ( -
+ {events.state === "loading" ? ( {t("events.recentLoading")} ) : null} @@ -42,7 +41,7 @@ const RecentEvents: FC = (props) => { -
+ ); }; diff --git a/src/pages/account/ui/components/RecentOperations.view.tsx b/src/pages/account/ui/components/RecentOperations.view.tsx index 517d135..9ff379c 100644 --- a/src/pages/account/ui/components/RecentOperations.view.tsx +++ b/src/pages/account/ui/components/RecentOperations.view.tsx @@ -1,11 +1,10 @@ -import { Alert, Button, Paper, Text } from "@mantine/core"; +import { Alert, Button, Paper, Stack, Text } from "@mantine/core"; import type { FC } from "react"; import { useTranslation } from "react-i18next"; import { Link } from "react-router"; import { formatMoney } from "@/entities/portfolio"; import classes from "../AccountPage.module.css"; import type { AccountPageRecentOperations } from "../AccountPage.vm"; -import { Section } from "./Section.view"; type RecentOperationsProps = { operations: AccountPageRecentOperations; @@ -16,7 +15,7 @@ const RecentOperations: FC = (props) => { const { t } = useTranslation(); return ( -
+ {operations.state === "loading" ? ( {t("ledger.recentLoading")} ) : null} @@ -41,7 +40,7 @@ const RecentOperations: FC = (props) => { -
+ ); }; diff --git a/src/pages/account/ui/components/Section.view.tsx b/src/pages/account/ui/components/Section.view.tsx deleted file mode 100644 index 8480ac5..0000000 --- a/src/pages/account/ui/components/Section.view.tsx +++ /dev/null @@ -1,19 +0,0 @@ -import { Stack, Title } from "@mantine/core"; -import type { FC, PropsWithChildren } from "react"; - -type SectionProps = PropsWithChildren<{ - title: string; -}>; - -const Section: FC = (props) => { - const { title, children } = props; - - return ( - - {title} - {children} - - ); -}; - -export { Section }; diff --git a/src/pages/account/ui/components/index.ts b/src/pages/account/ui/components/index.ts index 8386eb4..90d7ece 100644 --- a/src/pages/account/ui/components/index.ts +++ b/src/pages/account/ui/components/index.ts @@ -5,4 +5,3 @@ export { PortfolioTotals } from "./PortfolioTotals.view"; export { PositionSection } from "./PositionSection.view"; export { RecentEvents } from "./RecentEvents.view"; export { RecentOperations } from "./RecentOperations.view"; -export { Section } from "./Section.view";