53 lines
2.7 KiB
TypeScript
53 lines
2.7 KiB
TypeScript
export function kg(grams: number) { return `${(grams / 1000).toFixed(2)} кг`; }
|
|
|
|
export function plural(number: number, forms: readonly [string, string, string]) {
|
|
const absolute = Math.abs(number) % 100;
|
|
const last = absolute % 10;
|
|
if (absolute > 10 && absolute < 20) return forms[2];
|
|
if (last === 1) return forms[0];
|
|
if (last >= 2 && last <= 4) return forms[1];
|
|
return forms[2];
|
|
}
|
|
|
|
export function activityLevel(score: number) {
|
|
if (score >= 80) return { short: "Очень высокий", description: "Очень высокая активность" };
|
|
if (score >= 60) return { short: "Высокий", description: "Высокая активность" };
|
|
if (score >= 40) return { short: "Средний", description: "Средняя активность" };
|
|
return { short: "Низкий", description: "Низкая активность" };
|
|
}
|
|
|
|
export function ago(value: string) {
|
|
const minutes = Math.max(0, Math.round((Date.now() - new Date(value).getTime()) / 60000));
|
|
return minutes < 60 ? `${minutes} мин назад` : `${Math.floor(minutes / 60)} ч назад`;
|
|
}
|
|
|
|
export function freshnessStatus(value: string | null | undefined, now = Date.now()): "fresh" | "stale" | "unknown" {
|
|
if (!value) return "unknown";
|
|
const timestamp = new Date(value).getTime();
|
|
if (!Number.isFinite(timestamp)) return "unknown";
|
|
return now - timestamp > 48 * 60 * 60 * 1000 ? "stale" : "fresh";
|
|
}
|
|
|
|
export type CoordinatePrecision = "exact" | "approximate" | "area" | "missing";
|
|
|
|
export function coordinatePrecisionLabel(value: CoordinatePrecision | string | null | undefined): string {
|
|
return ({ exact: "точные", approximate: "приблизительные", area: "район", missing: "не указаны" } as Record<string, string>)[value ?? ""] ?? "не указаны";
|
|
}
|
|
|
|
export type PassportStatus = "verified" | "unverified" | "incomplete" | "insufficient" | "blocked";
|
|
export type PassportDisplayStatus = PassportStatus | "conflict" | "stale";
|
|
|
|
export function passportDisplayStatus(status: PassportStatus, freshness: "fresh" | "stale" | "unknown", hasConflicts: boolean): PassportDisplayStatus {
|
|
if (hasConflicts) return "conflict";
|
|
if (status === "verified" && freshness === "stale") return "stale";
|
|
return status;
|
|
}
|
|
|
|
export function sourceStatusLabel(status: string) {
|
|
const labels: Record<string, string> = {
|
|
healthy: "Актуален", stale: "Данные устарели", temporarily_limited: "Источник временно ограничен",
|
|
source_changed: "Источник изменился", waiting: "Ожидает запуска", disabled: "Выключен",
|
|
};
|
|
return labels[status] ?? "Состояние не определено";
|
|
}
|