91 lines
4.2 KiB
TypeScript
91 lines
4.2 KiB
TypeScript
import { i18n, t, type Key } from './i18n/index.svelte';
|
|
import type { Inertia, Proposal, Unit } from './types';
|
|
|
|
/** « 3 / 5 · moyenne ». */
|
|
export function inertiaLevel(k: Inertia): string {
|
|
return t('inertia.level', { k, name: t(`inertia.name.${k}`) });
|
|
}
|
|
|
|
/** « inertie 3 / 5 · moyenne ». */
|
|
export function inertiaBadge(k: Inertia): string {
|
|
return t('inertia.badge', { level: inertiaLevel(k) });
|
|
}
|
|
|
|
const SECTIONS = ['introduction', 'fondamental', 'technique', 'conclusion', 'annexe', 'formule', 'inertie', 'ordonnancement'];
|
|
|
|
/** The name of a section of the seed, or null. */
|
|
export function sectionLabel(s: string | null | undefined): string | null {
|
|
return s && SECTIONS.includes(s) ? t(`section.${s}` as Key) : null;
|
|
}
|
|
|
|
/**
|
|
* The sections whose articles carry the title already (Yvv, 2026-11-03: « Enlève les titres
|
|
* Introduction et Engagements fondamentaux, les titres sont déjà dans les contenus à voter. Ça
|
|
* embrouille. »): not named again where the text is read. They keep their name elsewhere — the
|
|
* order of the section, the basket, the open proposals.
|
|
*/
|
|
const TITLED_BY_THEIR_ARTICLES = ['introduction', 'fondamental'];
|
|
|
|
/** The name of a section where the text is read, or null. */
|
|
export function readerSectionLabel(s: string | null | undefined): string | null {
|
|
return s && TITLED_BY_THEIR_ARTICLES.includes(s) ? null : sectionLabel(s);
|
|
}
|
|
|
|
/** The name of a module (ADR 0009): « Titre du document », « Ordre des articles · Conclusion ». */
|
|
export function moduleName(unit: Unit): string {
|
|
if (unit.kind === 'title') return t('module.title.name');
|
|
const section = sectionLabel(unit.section) ?? unit.section;
|
|
return section ? t('module.order.named', { section }) : t('module.order.name');
|
|
}
|
|
|
|
/** What a proposal is, in words, whatever its kind. */
|
|
export function titleOf(p: Proposal, unit: Unit | undefined): string {
|
|
if (p.kind === 'inertia' && p.inertiaTarget) {
|
|
return t('deep.inertia', { level: inertiaLevel(p.inertiaTarget) });
|
|
}
|
|
if (p.kind === 'remove') return t('deep.removal', { title: unit?.inForce?.title ?? p.title });
|
|
if (p.kind === 'order') return unit ? moduleName(unit) : t('module.order.name');
|
|
return p.title;
|
|
}
|
|
|
|
/** Its relation to the text in force. */
|
|
export function relationOf(p: Proposal, unit: Unit | undefined): string {
|
|
if (p.kind !== 'text' && p.kind !== 'title') return '';
|
|
if (unit?.inForce && unit.inForce.id !== p.id) return t('deep.rival', { title: unit.inForce.title });
|
|
return '';
|
|
}
|
|
|
|
/** What an order version says of itself: completed at the end, or the order in force already. */
|
|
export function orderNote(p: Proposal): string[] {
|
|
const o = p.order;
|
|
if (!o || p.status === 'in_force') return [];
|
|
const notes: string[] = [];
|
|
if (o.added.length) notes.push(i18n.plural('module.order.added', o.added.length));
|
|
if (o.dropped.length) notes.push(i18n.plural('module.order.dropped', o.dropped.length));
|
|
if (o.same) notes.push(t('module.order.same'));
|
|
return notes;
|
|
}
|
|
|
|
|
|
/**
|
|
* How many « oui » pass a version, how many « non » block it (Yvv, 2026-11-02: « combien il
|
|
* faut de oui pour passer et combien de non pour maintenir l'opposition »), from what the
|
|
* server says (ADR 0013): `yesNeeded`, the total of *for* that passes with the *against* cast
|
|
* now; `noNeeded`, the total of *against* that holds the *for* cast now in check — 0 when
|
|
* the quorum holds them alone. Before any vote: « 9 oui sur 12 votants ». The quorum goes
|
|
* to the tooltip (`title`), never to the title of a line.
|
|
*/
|
|
export function needOf(p: Proposal): { long: string; short: string; title: string } | null {
|
|
const e = p.evaluation;
|
|
if (!e || e.yesNeeded === undefined || e.noNeeded === undefined || e.quorum === undefined) return null;
|
|
const yes = e.yesNeeded;
|
|
const no = e.noNeeded;
|
|
const quorum = e.quorum;
|
|
const title = i18n.plural('vote.need.title', quorum);
|
|
if (e.cast === 0) {
|
|
return { long: i18n.plural('vote.need.first', quorum, { yes, quorum }), short: t('vote.need.short.first', { yes, quorum }), title };
|
|
}
|
|
if (no === 0) return { long: t('vote.need.quorum', { yes }), short: t('vote.need.short.quorum', { yes }), title };
|
|
return { long: t('vote.need', { yes, no }), short: t('vote.need.short', { yes, no }), title };
|
|
}
|