Files
rf4-spotter/apps/web/src/lib/presentation.ts
T

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] ?? "Состояние не определено";
}