feat: migrate BrokerSummary, BrokerAssetCards and BrokerAccountOverviewPage

This commit is contained in:
Sergey Krylov 2026-06-21 18:14:49 +03:00
parent 3682f43aa6
commit ef97fd7136
3 changed files with 91 additions and 39 deletions

View File

@ -1,4 +1,6 @@
import { Link } from 'react-router-dom';
import { Box } from '@mui/material';
import { Text } from '@moex-vibe/design-system';
import { useBrokerOperations } from '@/entities/broker-operation';
import { useBrokerAccountContext } from '@/widgets/broker-account-layout';
import { BrokerAllocationChart } from '@/widgets/broker-allocation-chart';
@ -11,16 +13,22 @@ export function BrokerAccountOverviewPage() {
if (portfolio.isLoading) return <BrokerOverviewSkeleton />;
if (portfolio.error || !portfolio.data) {
return <p role="alert">Не удалось загрузить сводку счёта</p>;
return (
<Text component="p" role="alert" tone="negative">
Не удалось загрузить сводку счёта
</Text>
);
}
return (
<div className="broker-overview">
<Box component="div" sx={{ display: 'grid', gap: 3 }}>
<BrokerSummary portfolio={portfolio.data} />
<BrokerAllocationChart portfolio={portfolio.data} />
<BrokerAssetCards accountId={accountId} portfolio={portfolio.data} />
{operations.error ? (
<p role="alert">Не удалось загрузить последние операции</p>
<Text component="p" role="alert" tone="negative">
Не удалось загрузить последние операции
</Text>
) : (
<BrokerOperationsTable
title="Последние операции"
@ -33,6 +41,6 @@ export function BrokerAccountOverviewPage() {
page={operations.data}
/>
)}
</div>
</Box>
);
}

View File

@ -1,4 +1,6 @@
import { Link } from 'react-router-dom';
import { Box } from '@mui/material';
import { Text } from '@moex-vibe/design-system';
import type { BrokerMoney, BrokerPortfolio } from '@/shared/api/responses';
import { formatBrokerMoney, pluralize } from '@/shared/lib/formatters';
@ -11,6 +13,16 @@ function formatAllocationPercent(value: number | null) {
return value === null ? '\u2014' : `${value.toFixed(1)}%`;
}
const cardSx = {
p: 2,
border: '1px solid',
borderColor: 'divider',
borderRadius: 2,
bgcolor: 'surface.default',
display: 'grid',
gap: 1,
};
export function BrokerAssetCards({
accountId,
portfolio,
@ -37,23 +49,23 @@ export function BrokerAssetCards({
];
return (
<section className="broker-overview__assets" aria-label="Основные классы активов">
<Box component="section" sx={{ display: 'grid', gap: 2 }} aria-label="Основные классы активов">
{cards.map((card) => (
<Link
className="broker-overview__card broker-overview__asset-link"
key={card.label}
to={card.path}
>
<strong className="broker-overview__asset-title">{card.label}</strong>
<span>
{card.count} {card.countLabel}
</span>
<span>{formatBrokerMoney(card.value)}</span>
<span>
{formatAllocationPercent(allocationPercent(card.value, portfolio.totals.portfolio))}
</span>
<Link key={card.label} to={card.path}>
<Box sx={{ ...cardSx, color: 'inherit', textDecoration: 'none' }}>
<Box component="span" sx={{ color: 'primary.main', fontSize: 18, fontWeight: 700 }}>
{card.label}
</Box>
<Text>
{card.count} {card.countLabel}
</Text>
<Text>{formatBrokerMoney(card.value)}</Text>
<Text>
{formatAllocationPercent(allocationPercent(card.value, portfolio.totals.portfolio))}
</Text>
</Box>
</Link>
))}
</section>
</Box>
);
}

View File

@ -1,3 +1,5 @@
import { Box } from '@mui/material';
import { Text } from '@moex-vibe/design-system';
import type { BrokerPortfolio } from '@/shared/api/responses';
import {
formatBrokerMoney as formatMoney,
@ -6,31 +8,61 @@ import {
export function BrokerSummary({ portfolio }: { portfolio: BrokerPortfolio }) {
return (
<section className="broker-overview__summary" aria-label="Сводка счёта">
<div className="broker-overview__card">
<span className="broker-overview__label">Стоимость портфеля</span>
<strong className="broker-overview__total">
<Box component="section" sx={{ display: 'grid', gap: 2 }} aria-label="Сводка счёта">
<Box
sx={{
p: 2,
border: '1px solid',
borderColor: 'divider',
borderRadius: 2,
bgcolor: 'surface.default',
display: 'grid',
gap: 1,
}}
>
<Text variant="label" tone="secondary">
Стоимость портфеля
</Text>
<Box component="span" sx={{ fontWeight: 700, fontSize: 24 }}>
{formatMoney(portfolio.totals.portfolio)}
</strong>
<span>За день: {formatMoney(portfolio.yields.daily)}</span>
<span>Дневная доходность: {formatPercent(portfolio.yields.dailyPercent)}</span>
<span>Ожидаемая доходность: {formatPercent(portfolio.yields.expectedPercent)}</span>
</div>
<div className="broker-overview__card">
<span className="broker-overview__label">Денежный остаток</span>
</Box>
<Text>За день: {formatMoney(portfolio.yields.daily)}</Text>
<Text>Дневная доходность: {formatPercent(portfolio.yields.dailyPercent)}</Text>
<Text>Ожидаемая доходность: {formatPercent(portfolio.yields.expectedPercent)}</Text>
</Box>
<Box
sx={{
p: 2,
border: '1px solid',
borderColor: 'divider',
borderRadius: 2,
bgcolor: 'surface.default',
display: 'grid',
gap: 1,
}}
>
<Text variant="label" tone="secondary">
Денежный остаток
</Text>
{portfolio.cash.length === 0 ? (
<span>Нет денежных остатков</span>
<Text>Нет денежных остатков</Text>
) : (
<ul className="broker-overview__cash">
<Box component="ul" sx={{ listStyle: 'none', display: 'grid', gap: 1 }}>
{portfolio.cash.map((money, index) => (
<li key={`${money.currency}-${index}`}>
<span>{money.currency}</span>
<strong>{formatMoney(money)}</strong>
</li>
<Box
component="li"
key={`${money.currency}-${index}`}
sx={{ display: 'flex', justifyContent: 'space-between', gap: 1.5 }}
>
<Text>{money.currency}</Text>
<Box component="span" sx={{ fontWeight: 700 }}>
{formatMoney(money)}
</Box>
</Box>
))}
</ul>
</Box>
)}
</div>
</section>
</Box>
</Box>
);
}