Files
points-of-interest/client/src/lib/utils.ts
T
2025-10-10 16:13:48 +02:00

81 lines
2.1 KiB
TypeScript

import { type ClassValue, clsx } from "clsx";
import { twMerge } from "tailwind-merge";
export type Coordinates = {
lat: number;
lng: number;
};
export function cn(...inputs: ClassValue[]): string {
return twMerge(clsx(inputs));
}
export function formatCoordinate(value: number, locale = "en-US"): string {
const formatter = new Intl.NumberFormat(locale, {
minimumFractionDigits: 3,
maximumFractionDigits: 3,
});
return formatter.format(value);
}
export function formatRelativeTime(dateIso: string, locale = "en-US"): string {
const date = new Date(dateIso);
const now = new Date();
const diff = Math.max(0, now.getTime() - date.getTime());
const seconds = Math.floor(diff / 1000);
const rtf = new Intl.RelativeTimeFormat(locale, { numeric: "auto" });
if (seconds < 60) {
return rtf.format(-seconds, "second");
}
const minutes = Math.floor(seconds / 60);
if (minutes < 60) {
return rtf.format(-minutes, "minute");
}
const hours = Math.floor(minutes / 60);
if (hours < 24) {
return rtf.format(-hours, "hour");
}
const days = Math.floor(hours / 24);
if (days < 7) {
return rtf.format(-days, "day");
}
const weeks = Math.floor(days / 7);
return rtf.format(-weeks, "week");
}
export function formatTimestamp(dateIso: string, locale = "en-US"): string {
const date = new Date(dateIso);
return new Intl.DateTimeFormat(locale, {
month: "short",
day: "numeric",
hour: "numeric",
minute: "2-digit",
}).format(date);
}
const EARTH_RADIUS_KM = 6371;
export function distanceInKm(a: Coordinates, b: Coordinates): number {
const lat1 = toRadians(a.lat);
const lat2 = toRadians(b.lat);
const deltaLat = toRadians(b.lat - a.lat);
const deltaLng = toRadians(b.lng - a.lng);
const haversine =
Math.sin(deltaLat / 2) * Math.sin(deltaLat / 2) +
Math.cos(lat1) * Math.cos(lat2) * Math.sin(deltaLng / 2) * Math.sin(deltaLng / 2);
const c = 2 * Math.atan2(Math.sqrt(haversine), Math.sqrt(1 - haversine));
return EARTH_RADIUS_KM * c;
}
function toRadians(value: number): number {
return (value * Math.PI) / 180;
}