Files
frontend/src/entities/portfolio/model/display.ts
T

65 lines
1.7 KiB
TypeScript

import type { Portfolio } from "../api/usePortfolio";
type Money = Portfolio["totalsByCurrency"][number];
function formatDecimal(value: string): string {
const [integer, fraction] = value.split(".");
const sign = integer.startsWith("-") ? "-" : "";
const grouped = (sign ? integer.slice(1) : integer).replace(
/\B(?=(\d{3})+(?!\d))/g,
" ",
);
return `${sign}${grouped}${fraction ? `,${fraction}` : ""}`;
}
function formatMoney(money: Money | null): string {
if (!money) return "—";
return `${formatDecimal(money.value)} ${money.currency === "RUB" ? "₽" : money.currency}`;
}
function formatShare(
numerator: Money | null,
denominator: Money | null,
): string | null {
if (!numerator || !denominator) return null;
const total = Number(denominator.value);
if (!Number.isFinite(total) || total <= 0) return null;
const percent = (Number(numerator.value) / total) * 100;
if (!Number.isFinite(percent)) return null;
const rounded = new Intl.NumberFormat("ru-RU", {
maximumFractionDigits: 1,
}).format(percent);
return `${rounded} %`;
}
function formatSnapshotTime(value: string): string {
return new Intl.DateTimeFormat("ru-RU", {
dateStyle: "medium",
timeStyle: "short",
timeZone: "UTC",
}).format(new Date(value));
}
function portfolioErrorCode(error: unknown): string | undefined {
return typeof error === "object" && error !== null && "code" in error
? String(error.code)
: undefined;
}
const logoSize = 160;
function instrumentLogoUrl(logoName: string | null | undefined): string | null {
const stem = logoName?.trim().replace(/\.png$/i, "");
return stem
? `https://invest-brands.cdn-tinkoff.ru/${stem}x${logoSize}.png`
: null;
}
export {
formatMoney,
formatShare,
formatSnapshotTime,
instrumentLogoUrl,
portfolioErrorCode,
};