[ADD] application: clock, translation, formatting, displayed name
The screens need one clock, one translation mechanism and one way to
format and name, or each component grows its own. horloge.js is the only
code that reads time and arms timers, injected so tests drive it.
traduction.js keys texts by domain, in two families of tables, raises on a
missing key and never shows a raw key; libelles/ splits the label table by
domain. format.js formats numbers and dates in French, and personnes.js
composes the displayed name the frozen labels use. Nothing persists
between sessions.
Checked: 1773 node and 43 browser tests.
--- FR ---
[ADD] application : horloge, traduction, mise en forme, nom affiché
Les écrans exigent une horloge, un mécanisme de traduction et une façon de
mettre en forme et de nommer, sans quoi chaque composant ferait les siens.
horloge.js est le seul code qui lit l'heure et arme des minuteries, injecté
pour que les épreuves le pilotent. traduction.js range les textes par
domaine, en deux familles de tables, lève sur une clé absente et ne montre
jamais une clé brute ; libelles/ découpe la table des libellés par domaine.
format.js met en forme nombres et dates en français, et personnes.js
compose le nom affiché qu'emploient les libellés figés. Rien ne persiste
d'une séance à l'autre.
Vérifié : 1773 node et 43 navigateur.
Assisted-by: Claude Opus 5.5
2026-10-07 02:33:39 -04:00
|
|
|
// © 2026 TechnoLibre (http://www.technolibre.ca)
|
|
|
|
|
// License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl)
|
|
|
|
|
|
[ADD] application: furniture — tables, default, tours, capacity checks
Changing a table, the default seat count or the number of tours reshapes
a plan the operator may already have retained. Eight commands create,
remove and resize tables and set the default and the tours; every change
of capacity first passes controlerCapacite, which refuses to cut a reserved
or titled seat, states who goes to the reserve, and only brings back a
reserved person the display showed seated (§ 6.1, § 6.2). bilans.js states
the figures of a change before it applies.
Checked: 2033 node and 127 browser tests.
--- FR ---
[ADD] application : mobilier — tables, défaut, tours, contrôles
Changer une table, le défaut de sièges ou le nombre de tours remodèle un
plan que l'opérateur a peut-être retenu. Huit commandes créent, retirent et
redimensionnent les tables, et règlent le défaut et les tours ; tout
changement de capacité passe d'abord par controlerCapacite, qui refuse de
couper un siège réservé ou titré, dit qui part en réserve, et ne ramène une
personne réservée que si l'écran la montrait assise (§ 6.1, § 6.2).
bilans.js énonce les chiffres d'un changement avant qu'il s'applique.
Vérifié : 2033 node et 127 navigateur.
Assisted-by: Claude Opus 5.5
2026-10-07 05:12:43 -04:00
|
|
|
// Les textes des commandes du mobilier — tables, sièges, tours, réglages
|
|
|
|
|
// (§ 4, § 6, § 7.1, § 8.2, § 14.6) : les refus d'une capacité et d'un nombre
|
|
|
|
|
// de tours, leurs avertissements, les causes d'un siège retiré et les
|
|
|
|
|
// libellés figés du journal. Les détails désignent tables et personnes par
|
|
|
|
|
// identifiant : le refus se pose sur la table qu'il concerne, et son texte ne
|
|
|
|
|
// les nomme pas. Un libellé figé reçoit le numéro de table que la commande
|
|
|
|
|
// lit dans la charge.
|
|
|
|
|
import { cite, compte, enumeration, nomDans } from './aides.js';
|
|
|
|
|
|
|
|
|
|
// Le nom de chaque réglage que modifierReglage change, tel que le journal le
|
|
|
|
|
// fige (§ 5.3, § 5.10).
|
|
|
|
|
const NOMS_DES_REGLAGES = new Map([
|
|
|
|
|
['separerAppartenances', 'Séparer les appartenances'],
|
|
|
|
|
['nouveauxVoisins', 'Nouveaux voisins à chaque tour'],
|
|
|
|
|
['nouvelleTable', 'Nouvelle table à chaque tour'],
|
|
|
|
|
['varierAppartenances', 'Varier les appartenances rencontrées'],
|
|
|
|
|
['attribuerSieges', 'Attribuer les sièges'],
|
|
|
|
|
['generation.nombre', 'Propositions par génération'],
|
|
|
|
|
['generation.arret', 'Mouvements par proposition'],
|
|
|
|
|
['generation.historique', "Historique d'acceptation"],
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
// La valeur d'un réglage dans un libellé : activé ou désactivé pour un
|
|
|
|
|
// interrupteur, le nombre sinon.
|
|
|
|
|
const valeurDeReglage = (valeur) => (typeof valeur === 'boolean' ? (valeur ? 'activé' : 'désactivé') : String(valeur));
|
|
|
|
|
|
|
|
|
|
// Ce qu'une saisie refusée est : vide, ou un texte qui n'est pas un entier.
|
|
|
|
|
const saisieCitee = (saisie) => (String(saisie).trim() === '' ? 'La saisie est vide' : `${cite(String(saisie))} n'est pas un nombre entier`);
|
|
|
|
|
|
|
|
|
|
export const TABLE = new Map([
|
|
|
|
|
// --- Les saisies (§ 6.2) ---------------------------------------------------
|
|
|
|
|
[
|
|
|
|
|
'NON_ENTIER',
|
|
|
|
|
({ saisie }) => `${saisieCitee(saisie)} : un nombre entier, sans signe ni décimale, est attendu.`,
|
|
|
|
|
],
|
|
|
|
|
[
|
|
|
|
|
'MOINS_DE_DEUX',
|
|
|
|
|
() => "Une table compte au moins 2 places : seule à sa table, une personne ne rencontrerait personne.",
|
|
|
|
|
],
|
|
|
|
|
['MOINS_D_UN_TOUR', () => 'Une soirée compte au moins un tour.'],
|
|
|
|
|
|
|
|
|
|
// --- Les refus d'une capacité (§ 6.2, § 7.1) -------------------------------
|
|
|
|
|
[
|
|
|
|
|
'SOUS_RESERVATIONS',
|
|
|
|
|
({ n, tour }) =>
|
|
|
|
|
`La table porte ${compte(n, 'réservation', 'réservations')} au tour ${tour} : ` +
|
|
|
|
|
`elle ne descend pas sous ${compte(n, 'place', 'places')}.`,
|
|
|
|
|
],
|
|
|
|
|
[
|
|
|
|
|
'SOUS_OCCUPES',
|
|
|
|
|
({ n, tour }) =>
|
|
|
|
|
`Au tour ${tour}, la table occupe ${compte(n, 'place', 'places')} : la poignée ne descend pas en deçà.`,
|
|
|
|
|
],
|
|
|
|
|
[
|
|
|
|
|
'SIEGES_RETIRES',
|
|
|
|
|
// Sièges non attribués (titres présent), un titre se compte : son siège
|
|
|
|
|
// est une place d'affichage, que l'opérateur n'a pas choisie.
|
|
|
|
|
({ sieges, titres }, texte) => {
|
|
|
|
|
const listes = titres === undefined ? sieges : sieges.filter(({ cause }) => cause !== 'SIEGE_TITRE');
|
|
|
|
|
const termes = listes.map((siege) => texte(siege.cause, siege));
|
|
|
|
|
if (titres !== undefined && titres > 0) termes.push(compte(titres, 'siège porte un titre', 'sièges portent un titre'));
|
|
|
|
|
return `Réduire la table retire des sièges qui portent une saisie : ${enumeration(termes)}.`;
|
|
|
|
|
},
|
|
|
|
|
],
|
|
|
|
|
[
|
|
|
|
|
'SIEGE_RESERVE',
|
|
|
|
|
({ siege, suspendue }) => `le siège ${siege} est réservé${suspendue ? ', par une réservation suspendue' : ''}`,
|
|
|
|
|
],
|
|
|
|
|
['SIEGE_TITRE', ({ siege, libelle }) => `le siège ${siege} porte le titre ${cite(libelle)}`],
|
|
|
|
|
|
|
|
|
|
// --- Les avertissements d'une capacité (§ 6.2) -----------------------------
|
|
|
|
|
[
|
|
|
|
|
'SURNUMERAIRES',
|
|
|
|
|
({ tour, personnes }) =>
|
|
|
|
|
`Au tour ${tour}, ${compte(personnes.length, 'personne passe', 'personnes passent')} dans la réserve : ` +
|
|
|
|
|
`la table n'a plus de chaise pour ${personnes.length <= 1 ? 'elle' : 'elles'}.`,
|
|
|
|
|
],
|
|
|
|
|
[
|
|
|
|
|
'AU_DELA_LISIBLE',
|
|
|
|
|
({ seuil }) => `Au-delà de ${seuil} places, la liste des noms de la table cesse d'être lisible sur le plan.`,
|
|
|
|
|
],
|
|
|
|
|
|
|
|
|
|
// --- Les libellés figés du journal (§ 8.2) ---------------------------------
|
|
|
|
|
['ENTREE_CREER_TABLE', ({ numero }) => `Ajouté la table ${numero}`],
|
|
|
|
|
[
|
|
|
|
|
'ENTREE_SUPPRIMER_TABLE',
|
|
|
|
|
({ numero, reservations, titres }) => {
|
|
|
|
|
const retires = [];
|
|
|
|
|
if (reservations > 0) retires.push(compte(reservations, 'réservation', 'réservations'));
|
|
|
|
|
if (titres > 0) retires.push(compte(titres, 'titre', 'titres'));
|
|
|
|
|
return `Supprimé la table ${numero}${retires.length > 0 ? ` ; retirés : ${enumeration(retires)}` : ''}`;
|
|
|
|
|
},
|
|
|
|
|
],
|
|
|
|
|
['ENTREE_DEPLACER_TABLE', ({ numero }) => `Déplacé la table ${numero}`],
|
|
|
|
|
['ENTREE_CHANGER_PLACES_TABLE', ({ numero, sieges }) => `Table ${numero} : ${compte(sieges, 'place', 'places')}`],
|
|
|
|
|
['ENTREE_REALIGNER_TABLE', ({ numero, sieges }) => `Table ${numero} : suit le défaut (${compte(sieges, 'place', 'places')})`],
|
|
|
|
|
[
|
|
|
|
|
'ENTREE_CHANGER_DEFAUT',
|
|
|
|
|
({ sieges, realignees }) =>
|
|
|
|
|
`Sièges par défaut : ${sieges}${realignees > 0 ? ` ; ${compte(realignees, 'table réalignée', 'tables réalignées')}` : ''}`,
|
|
|
|
|
],
|
|
|
|
|
[
|
|
|
|
|
'ENTREE_CHANGER_TOURS',
|
|
|
|
|
({ tours, retirees }) =>
|
|
|
|
|
`Nombre de tours : ${tours}${retirees > 0 ? ` ; ${compte(retirees, 'réservation retirée', 'réservations retirées')}` : ''}`,
|
|
|
|
|
],
|
|
|
|
|
[
|
|
|
|
|
'ENTREE_MODIFIER_REGLAGE',
|
|
|
|
|
({ cle, valeur }) => `${nomDans(NOMS_DES_REGLAGES, cle, 'réglage')} : ${valeurDeReglage(valeur)}`,
|
|
|
|
|
],
|
|
|
|
|
]);
|