import type { BrokerPortfolio } from '../../../api/responses';
import {
buildBrokerAllocation,
type BrokerAllocationItem,
} from '../../../entities/broker-position';
const RADIUS = 44;
const CIRCUMFERENCE = 2 * Math.PI * RADIUS;
function formatMoneyValue(value: number, currency: string) {
return new Intl.NumberFormat('ru-RU', {
style: 'currency',
currency,
maximumFractionDigits: 2,
}).format(value);
}
function allocationCurrency(portfolio: BrokerPortfolio) {
return (
portfolio.totals.portfolio?.currency ||
Object.values(portfolio.totals).find((total) => total?.currency)?.currency ||
'RUB'
);
}
export function BrokerAllocationBar({
items,
title,
}: {
items: BrokerAllocationItem[];
title: string;
}) {
const positiveItems = items.filter((item) => item.value > 0);
if (positiveItems.length === 0) {
return
Нет данных для распределения
;
}
return (
{positiveItems.map((item) => (
))}
{positiveItems.map((item) => (
-
{item.label}
{item.percent.toFixed(0)}%
))}
);
}
export function BrokerAllocationChart({ portfolio }: { portfolio: BrokerPortfolio }) {
const { sectors, negative } = buildBrokerAllocation(portfolio);
const currency = allocationCurrency(portfolio);
let remaining = CIRCUMFERENCE;
const arcs = sectors.map((sector) => {
const dashOffset = -(CIRCUMFERENCE - remaining);
const rawDashLength = (sector.percent / 100) * CIRCUMFERENCE;
const dashLength = Math.min(Math.max(rawDashLength, 0), remaining);
remaining = Math.max(0, remaining - dashLength);
return { ...sector, dashOffset, dashLength };
});
return (
{sectors.length === 0 ? (
Нет данных для распределения
) : (
{sectors.map((sector) => (
-
{sector.label}: {formatMoneyValue(sector.value, currency)} ·{' '}
{sector.percent.toFixed(1)}%
))}
)}
{negative.length > 0 && (
{negative.map((item) => (
-
{item.label}: отрицательное значение {formatMoneyValue(item.value, currency)}
))}
)}
);
}