Files
hidden11/lib/time.ts
T
claude-code 3ce9ab7bf1
Build and push image / build (push) Successful in 3m13s
Add localized SEO pages, puzzle archive and challenge loop
Localized home pages (/es, /fr, /de, /it, /pt) with server-rendered intro,
how-to-play and FAQ plus FAQPage/WebApplication JSON-LD and hreflang.

Puzzle archive at /archive with answer pages (/puzzle/N) for past days only
and replays (/play/N) that never touch stats or the daily streak.

Challenge loop: shared results link back as /?challenge=<code> and the result
screen shows a head-to-head verdict.

Also adds robots.txt, sitemap.xml, the PWA manifest and icons, a compact
share text with WhatsApp/X/copy channels, a next-puzzle countdown, the
social-proof play counter and a spoiler-free /api/teaser for daily posting.

Refs #1

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QvQ1ErZNRUcWgCEkJ9uyrn
2026-08-26 12:23:59 +00:00

53 lines
1.9 KiB
TypeScript

export const SERVER_TIME_ZONE = process.env.NEXT_PUBLIC_SERVER_TIME_ZONE ?? "Europe/Madrid";
export function getDateKeyInTimeZone(date = new Date(), timeZone = SERVER_TIME_ZONE): string {
const formatter = new Intl.DateTimeFormat("en-CA", {
timeZone,
year: "numeric",
month: "2-digit",
day: "2-digit",
});
const parts = formatter.formatToParts(date);
const year = parts.find((part) => part.type === "year")?.value;
const month = parts.find((part) => part.type === "month")?.value;
const day = parts.find((part) => part.type === "day")?.value;
if (!year || !month || !day) {
return date.toISOString().slice(0, 10);
}
return `${year}-${month}-${day}`;
}
export function secondsUntilNextPuzzle(now = new Date(), timeZone = SERVER_TIME_ZONE): number {
const formatter = new Intl.DateTimeFormat("en-GB", {
timeZone,
hour12: false,
hour: "2-digit",
minute: "2-digit",
second: "2-digit",
});
const parts = formatter.formatToParts(now);
const hour = Number(parts.find((part) => part.type === "hour")?.value ?? 0) % 24;
const minute = Number(parts.find((part) => part.type === "minute")?.value ?? 0);
const second = Number(parts.find((part) => part.type === "second")?.value ?? 0);
const elapsedToday = hour * 3600 + minute * 60 + second;
return Math.max(1, 86400 - elapsedToday);
}
export function formatCountdown(totalSeconds: number): string {
const hours = Math.floor(totalSeconds / 3600);
const minutes = Math.floor((totalSeconds % 3600) / 60);
const seconds = totalSeconds % 60;
return `${hours.toString().padStart(2, "0")}:${minutes.toString().padStart(2, "0")}:${seconds
.toString()
.padStart(2, "0")}`;
}
export function formatElapsed(seconds: number): string {
const minutes = Math.floor(seconds / 60);
const remainder = seconds % 60;
return `${minutes}:${remainder.toString().padStart(2, "0")}`;
}