initial commit of the paytime session frontend

This commit is contained in:
jenz
2026-08-22 14:53:27 +02:00
parent 4ad037bd13
commit 9e8e8378a2
43 changed files with 2936 additions and 0 deletions
@@ -0,0 +1,44 @@
// Converts a Steam2 id ("STEAM_0:1:12345678", as stored by the plugin) into
// a Steam64 id, which is what profile URLs and avatar lookups need.
const STEAM64_BASE = 76561197960265728n;
export function steam2ToSteam64(steamId2: string): string | null {
const match = /^STEAM_[0-5]:([01]):(\d+)$/.exec(steamId2.trim());
if (!match) return null;
const y = BigInt(match[1]);
const z = BigInt(match[2]);
return (STEAM64_BASE + y + z * 2n).toString();
}
export function steamProfileUrl(steamId2: string): string | null {
const id64 = steam2ToSteam64(steamId2);
return id64 ? `https://steamcommunity.com/profiles/${id64}` : null;
}
// Formats total minutes as "123h 45m" for display.
export function formatMinutes(totalMinutes: number | null): string {
if (totalMinutes == null || Number.isNaN(totalMinutes)) return '—';
const h = Math.floor(totalMinutes / 60);
const m = totalMinutes % 60;
return `${h}h ${m}m`;
}
// ISO 3166-1 alpha-2 -> flag emoji, e.g. "DE" -> "🇩🇪". No external assets needed.
export function countryCodeToFlag(code: string | null): string {
if (!code || code.length !== 2) return '🏳️';
const codePoints = [...code.toUpperCase()].map((c) => 0x1f1a5 + c.charCodeAt(0));
return String.fromCodePoint(...codePoints);
}
// ISO 3166-1 alpha-2 -> English display name, e.g. "DE" -> "Germany".
// Uses the built-in Intl.DisplayNames (Node 14+ / all modern browsers) —
// no extra dependency or lookup table needed.
const regionNames = new Intl.DisplayNames(['en'], { type: 'region' });
export function countryCodeToName(code: string | null): string {
if (!code || code.length !== 2) return 'Unknown';
try {
return regionNames.of(code.toUpperCase()) ?? code;
} catch {
return code;
}
}