Files
tgex-frontend/lib/utils/format.ts
2025-11-10 12:07:24 +03:00

165 lines
4.3 KiB
TypeScript
Raw Permalink 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.
// ============================================================================
// Formatting Utilities
// ============================================================================
/**
* Форматирование числа с разделением тысяч
*/
export const formatNumber = (
value: number | null | undefined,
showSign: boolean = false
): string => {
if (value === null || value === undefined) return "—";
const sign = showSign && value > 0 ? "+" : "";
return `${sign}${new Intl.NumberFormat("ru-RU").format(value)}`;
};
/**
* Форматирование валюты (рубли)
*/
export const formatCurrency = (value: number | null | undefined): string => {
if (value === null || value === undefined) return "—";
return new Intl.NumberFormat("ru-RU", {
style: "currency",
currency: "RUB",
minimumFractionDigits: 0,
maximumFractionDigits: 0,
}).format(value);
};
/**
* Форматирование CPF/CPM с двумя знаками после запятой
*/
export const formatMetric = (value: number | null | undefined): string => {
if (value === null || value === undefined) return "—";
return new Intl.NumberFormat("ru-RU", {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
}).format(value);
};
/**
* Форматирование процента
*/
export const formatPercent = (
value: number | null | undefined,
showSign: boolean = false
): string => {
if (value === null || value === undefined) return "—";
const sign = showSign && value > 0 ? "+" : "";
return `${sign}${formatMetric(value)}%`;
};
/**
* Форматирование даты
*/
export const formatDate = (
date: string | Date | null | undefined,
includeTime: boolean = false
): string => {
if (!date) return "—";
const d = typeof date === "string" ? new Date(date) : date;
if (includeTime) {
return new Intl.DateTimeFormat("ru-RU", {
day: "2-digit",
month: "2-digit",
year: "numeric",
hour: "2-digit",
minute: "2-digit",
}).format(d);
}
return new Intl.DateTimeFormat("ru-RU", {
day: "2-digit",
month: "2-digit",
year: "numeric",
}).format(d);
};
/**
* Форматирование относительной даты (сколько прошло)
*/
export const formatRelativeDate = (date: string | Date): string => {
const d = typeof date === "string" ? new Date(date) : date;
const now = new Date();
const diff = now.getTime() - d.getTime();
const seconds = Math.floor(diff / 1000);
const minutes = Math.floor(seconds / 60);
const hours = Math.floor(minutes / 60);
const days = Math.floor(hours / 24);
if (days > 7) {
return formatDate(d);
} else if (days > 0) {
return `${days} ${pluralize(days, "день", "дня", "дней")} назад`;
} else if (hours > 0) {
return `${hours} ${pluralize(hours, "час", "часа", "часов")} назад`;
} else if (minutes > 0) {
return `${minutes} ${pluralize(
minutes,
"минута",
"минуты",
"минут"
)} назад`;
} else {
return "только что";
}
};
/**
* Плюрализация русских слов
*/
export const pluralize = (
count: number,
one: string,
few: string,
many: string
): string => {
const mod10 = count % 10;
const mod100 = count % 100;
if (mod10 === 1 && mod100 !== 11) {
return one;
} else if (mod10 >= 2 && mod10 <= 4 && (mod100 < 10 || mod100 >= 20)) {
return few;
} else {
return many;
}
};
/**
* Сокращение больших чисел (1000 -> 1K)
*/
export const formatCompactNumber = (
value: number | null | undefined
): string => {
if (value === null || value === undefined) return "—";
if (value >= 1000000) {
return `${(value / 1000000).toFixed(1)}M`;
} else if (value >= 1000) {
return `${(value / 1000).toFixed(1)}K`;
}
return formatNumber(value);
};
/**
* Форматирование username (с @)
*/
export const formatUsername = (username: string | null | undefined): string => {
if (!username) return "—";
return username.startsWith("@") ? username : `@${username}`;
};
/**
* Обрезка длинного текста
*/
export const truncate = (text: string, maxLength: number = 50): string => {
if (text.length <= maxLength) return text;
return `${text.substring(0, maxLength)}...`;
};