Two pure modules: statut-mairie.js (string[] -> string[] status logic) and ics-categories.js, which rewrites CATEGORIES in an iCalendar resource behind a structural guard: nothing is written if anything but CATEGORIES changed.
68 lines
2.5 KiB
JavaScript
68 lines
2.5 KiB
JavaScript
// Statut mairie porté par les CATEGORIES de l'événement Nextcloud : `string[]`
|
|
// → `string[]`. Fonctions PURES (aucun DOM, aucun réseau, aucun ICS) : c'est le
|
|
// cœur logique de la persistance partagée, testé à fond.
|
|
//
|
|
// `mairie:` est NOTRE espace de noms : les autres catégories appartiennent aux
|
|
// bénévoles et gardent leur ordre et leur casse.
|
|
|
|
const PREFIXE = "mairie:";
|
|
// NFC explicite : « é » s'écrit de deux façons en Unicode (précomposée ou
|
|
// « e » + accent combinant) qui ne sont PAS `===`. Sans normalisation, un tag
|
|
// écrit par un autre client CalDAV serait relu comme « aucun » — panne
|
|
// silencieuse. On normalise ce qu'on écrit ET ce qu'on lit.
|
|
const IGNORE = `${PREFIXE}ignoré`.normalize("NFC");
|
|
const SOUMIS = `${PREFIXE}soumis`;
|
|
|
|
const JOUR = /^\d{4}-\d{2}-\d{2}$/;
|
|
|
|
const FORMAT_JOUR_PARIS = new Intl.DateTimeFormat("en-CA", {
|
|
timeZone: "Europe/Paris",
|
|
year: "numeric",
|
|
month: "2-digit",
|
|
day: "2-digit",
|
|
});
|
|
|
|
// Écriture concurrente (deux bénévoles, deux clients) : plusieurs tags peuvent
|
|
// cohabiter. La DERNIÈRE valeur reconnue l'emporte, comme indexerCartes.
|
|
// Un tag `mairie:` inconnu (posé par une version future) est traité comme
|
|
// « aucun » : il ne doit jamais casser la liste d'aujourd'hui.
|
|
export function lireStatut(categories) {
|
|
let statut = { type: "aucun" };
|
|
for (const categorie of categories) {
|
|
const reconnu = reconnaitre(categorie.normalize("NFC"));
|
|
if (reconnu) statut = reconnu;
|
|
}
|
|
return statut;
|
|
}
|
|
|
|
function reconnaitre(categorie) {
|
|
if (categorie === IGNORE) return { type: "ignoré" };
|
|
if (categorie === SOUMIS) return { type: "soumis", jour: null };
|
|
if (categorie.startsWith(`${SOUMIS}:`)) {
|
|
// L'intention prime sur sa décoration : une date illisible n'annule pas
|
|
// l'envoi, on affichera « Soumis » sans date.
|
|
const jour = categorie.slice(SOUMIS.length + 1);
|
|
return { type: "soumis", jour: JOUR.test(jour) ? jour : null };
|
|
}
|
|
return null;
|
|
}
|
|
|
|
export function poserIgnore(categories) {
|
|
return [...retirerStatut(categories), IGNORE];
|
|
}
|
|
|
|
export function poserSoumis(categories, jour) {
|
|
return [...retirerStatut(categories), `${SOUMIS}:${jour}`];
|
|
}
|
|
|
|
export function retirerStatut(categories) {
|
|
return categories.filter((categorie) => !categorie.startsWith(PREFIXE));
|
|
}
|
|
|
|
// « AAAA-MM-JJ » à Cugnaux : en-CA rend directement cette forme (cf.
|
|
// publication.js). `maintenant` injecté (obligatoire) pour des tests
|
|
// déterministes.
|
|
export function jourParis(maintenant) {
|
|
return FORMAT_JOUR_PARIS.format(maintenant);
|
|
}
|