// Dates du jeu-concours affichées au public. Elles viennent de l'API (date de // début fixée par l'admin) ; en attendant la réponse, ou si le jeu n'est pas // configuré, on affiche les dates prévues par le règlement : 2 → 31 octobre 2026. const TIME_ZONE = 'Europe/Paris' const DAY_MS = 24 * 60 * 60 * 1000 // Mêmes durées que backend/src/utils/gameWindow.js. const GAME_DURATION_DAYS = 30 const CLAIM_EXTENSION_DAYS = 30 export const DEFAULT_START_DATE = '2026-10-02T00:00:00+02:00' function windowFromStart(startDate) { const start = new Date(startDate) return { start, participationDeadline: new Date(start.getTime() + GAME_DURATION_DAYS * DAY_MS), claimDeadline: new Date(start.getTime() + (GAME_DURATION_DAYS + CLAIM_EXTENSION_DAYS) * DAY_MS), } } // Les échéances sont des instants exclusifs (début + 30 j) : le dernier jour // affiché est celui qui précède immédiatement l'échéance. function lastDayBefore(deadline) { return new Date(deadline.getTime() - 1) } export function toGameDates(gameWindow) { const source = gameWindow?.configured && gameWindow.startDate ? { start: new Date(gameWindow.startDate), participationDeadline: new Date(gameWindow.participationDeadline), claimDeadline: new Date(gameWindow.claimDeadline), } : windowFromStart(DEFAULT_START_DATE) return { start: source.start, lastPlayDay: lastDayBefore(source.participationDeadline), lastClaimDay: lastDayBefore(source.claimDeadline), } } // Même calcul à partir d'une date de début seule (aperçu dans l'admin). export function gameDatesFromStart(startDate) { return toGameDates({ configured: true, startDate, ...windowFromStart(startDate) }) } function parts(date) { const values = {} new Intl.DateTimeFormat('fr-FR', { timeZone: TIME_ZONE, day: 'numeric', month: 'long', year: 'numeric' }) .formatToParts(date) .forEach(({ type, value }) => { values[type] = value }) return values } // « 30 novembre 2026 » export function formatDay(date) { const { day, month, year } = parts(date) return `${day} ${month} ${year}` } // « 2 au 31 octobre 2026 », « 15 octobre au 13 novembre 2026 », // « 20 décembre 2026 au 18 janvier 2027 ». Sans « du » : l'appelant choisit // la majuscule. `padDay` écrit « 02 », `withYear: false` omet l'année. export function formatRange(start, end, { padDay = false, withYear = true } = {}) { const a = parts(start) const b = parts(end) const startDay = padDay ? a.day.padStart(2, '0') : a.day const year = withYear ? ` ${b.year}` : '' if (a.year !== b.year) { return `${startDay} ${a.month}${withYear ? ` ${a.year}` : ''} au ${b.day} ${b.month}${year}` } if (a.month !== b.month) { return `${startDay} ${a.month} au ${b.day} ${b.month}${year}` } return `${startDay} au ${b.day} ${b.month}${year}` }