Sergey Krylov 1774c7ffd6
Some checks failed
CI / ci (pull_request) Failing after 2m32s
CI / ci (push) Failing after 2m17s
refactor(frontend): bring FSD architecture into compliance
- Remove cross-entity import (broker-position -> broker-operation)
- Extract duplicated formatters to shared/lib/formatters.ts
- Flatten shared/ui/broker-allocation-bar nesting
- Clean up entities/stock/index.ts public API

All 111 tests pass, build clean.
2026-06-20 22:43:44 +03:00

165 lines
5.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { SkeletonBlock } from '@/shared/ui/SkeletonBlock';
import type { BrokerAccountsAggregate } from '@/entities/broker-account';
import { buildBrokerAllocation } from '@/entities/broker-position';
import { BrokerAllocationBar } from '@/shared/ui/broker-allocation-bar';
import {
formatBrokerCurrencyValue,
formatBrokerSignedCurrencyValue,
formatBrokerSignedPercent,
} from '@/shared/lib/formatters';
export function BrokerAccountsSummary({
aggregate,
availableCount,
totalCount,
isLoading,
}: {
aggregate: BrokerAccountsAggregate;
availableCount: number;
totalCount: number;
isLoading: boolean;
}) {
if (isLoading) {
return (
<section className="broker-accounts-summary broker-accounts-summary--loading">
<div className="broker-accounts-summary__hero">
<SkeletonBlock height={18} width="34%" />
<SkeletonBlock height={52} width="48%" />
<SkeletonBlock height={18} width="28%" />
</div>
<div className="broker-accounts-summary__metrics">
{[1, 2, 3].map((item) => (
<div className="broker-accounts-summary__metric" key={item}>
<SkeletonBlock height={14} width="45%" />
<SkeletonBlock height={26} width="70%" />
</div>
))}
</div>
</section>
);
}
return (
<section className="broker-accounts-summary" aria-label="Общая сводка по счетам">
<div className="broker-accounts-summary__hero">
<div>
<p className="broker-accounts-summary__eyebrow">Финансовый обзор</p>
<h2 className="broker-accounts-summary__title">Счета в одном кадре</h2>
</div>
<div className="broker-accounts-summary__status">
<span>{totalCount} счетов</span>
{availableCount !== totalCount ? (
<span>
Доступно по {availableCount} из {totalCount} счетов
</span>
) : null}
</div>
</div>
<div className="broker-accounts-summary__currency-grid">
{aggregate.portfolios.map((portfolioSummary) => {
const allocation = buildBrokerAllocation({
account: {
id: 'aggregate',
type: 'brokerage',
name: 'aggregate',
status: 'ACCOUNT_STATUS_OPEN',
openedAt: null,
accessLevel: null,
},
positionCounts: { shares: 0, bonds: 0, etf: 0, other: 0 },
totals: {
shares: {
currency: portfolioSummary.currency,
units: '0',
nano: 0,
value: portfolioSummary.allocation.shares,
},
bonds: {
currency: portfolioSummary.currency,
units: '0',
nano: 0,
value: portfolioSummary.allocation.bonds,
},
etf:
portfolioSummary.allocation.etf > 0
? {
currency: portfolioSummary.currency,
units: '0',
nano: 0,
value: portfolioSummary.allocation.etf,
}
: null,
currencies: {
currency: portfolioSummary.currency,
units: '0',
nano: 0,
value: portfolioSummary.allocation.cash,
},
futures: null,
options: null,
structuredProducts: null,
dfa: null,
portfolio: {
currency: portfolioSummary.currency,
units: '0',
nano: 0,
value: portfolioSummary.total,
},
},
yields: { expectedPercent: null, daily: null, dailyPercent: null },
cash: [],
blockedCash: [],
asOf: '',
});
return (
<article
className="broker-accounts-summary__currency-card"
key={portfolioSummary.currency}
>
<div className="broker-accounts-summary__currency-header">
<span className="broker-accounts-summary__currency">
{portfolioSummary.currency}
</span>
<strong className="broker-accounts-summary__total">
{formatBrokerCurrencyValue(portfolioSummary.currency, portfolioSummary.total)}
</strong>
</div>
<dl className="broker-accounts-summary__metrics">
<div className="broker-accounts-summary__metric">
<dt>За день</dt>
<dd>
{formatBrokerSignedCurrencyValue(
portfolioSummary.currency,
portfolioSummary.daily,
)}
</dd>
</div>
<div className="broker-accounts-summary__metric">
<dt>Динамика</dt>
<dd>{formatBrokerSignedPercent(portfolioSummary.dailyPercent)}</dd>
</div>
<div className="broker-accounts-summary__metric">
<dt>Свободные деньги</dt>
<dd>
{formatBrokerCurrencyValue(
portfolioSummary.currency,
aggregate.cash.find((cash) => cash.currency === portfolioSummary.currency)
?.value ?? 0,
)}
</dd>
</div>
</dl>
<BrokerAllocationBar
title={`Распределение активов ${portfolioSummary.currency}`}
items={allocation.sectors}
/>
</article>
);
})}
</div>
</section>
);
}