Lot V, interface : les types du contrat (tallyPending, tallySimulated, myVoteState, vote.simulated, mode des bulletins, publication.waitsFor, messages « ballot ») ; i18n des états (simulé, écarté par une objection, messages d'un vote écarté) en fr, en, es ; la boîte « Messages » dit les votes écartés ; « Tes bulletins » marque un vote simulé

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Yvv
2026-11-03 05:49:57 +01:00
co-authored by Claude Opus 5.5
parent e8e9633b75
commit f62347cc6b
8 changed files with 111 additions and 16 deletions
+5 -2
View File
@@ -27,6 +27,8 @@
function standing(b: BallotEntry): string {
if (b.status === 'pending') return t('ballots.status.pending');
// A vote of the simulation (ADR 0012): counted for the session, never on the chain.
if (b.status === 'confirmed' && b.mode === 'simulated') return t('ballots.status.simulated', { name: b.voter ?? '' });
if (b.status === 'confirmed') return t('ballots.status.confirmed', { name: b.voter ?? '' });
if (b.status === 'refused') return t('ballots.status.refused', { reason: t(`ballot.reason.${b.reason ?? 'transfer'}`) });
return t('ballots.status.expired');
@@ -62,7 +64,7 @@
{#each data.value.ballots as b (b.id)}
<li class="card block ballot">
<p class="small faint">{i18n.date(b.createdAt)} · {titleOf(b.doc.title)} · {i18n.plural('ballots.lines', b.lines)}</p>
<p class="state {b.status}">
<p class="state {b.status}" class:simulated={b.mode === 'simulated'}>
{standing(b)}{#if b.block !== null}<span class="faint"> · {t('ballots.block', { n: i18n.number(b.block) })}</span>{/if}
</p>
<code class="comment">{b.comment}</code>
@@ -159,7 +161,8 @@
.state.confirmed {
color: var(--moss);
}
.state.pending {
.state.pending,
.state.confirmed.simulated {
color: var(--water);
}
.state.refused,
+22 -2
View File
@@ -2,7 +2,8 @@
// The box « Messages » of trustinWallet, in the application (2026-10-31, lot F,
// ADR 0010): what waits for a gesture of the person — an objection to answer,
// to lift or to reiterate, a typo fix to validate or refuse —, each with its
// deadline. A message dealt with offers no gesture any more. No mail.
// deadline. A message dealt with offers no gesture any more. No mail. A ballot set
// aside (ADR 0012) is told here too, without gesture: one votes again in the text.
import { onMount } from 'svelte';
import { goto } from '$app/navigation';
import { api } from '$lib/api';
@@ -44,10 +45,27 @@
await reload();
}
/** The lines of a ballot a message is about: those set aside by an objection, or all. */
function linesOf(m: Message) {
const lines = m.ballot?.lines ?? [];
const held = lines.filter((l) => l.outcome === 'objection');
return m.kind === 'ballot_objection' && held.length ? held : lines;
}
/** The text of a message, in the language of the reader, from its subject. */
function textOf(m: Message): string {
const o = m.objection;
const fix = m.typo;
const b = m.ballot;
if (b) {
const articles = linesOf(m)
.map((l) => l.code)
.join(', ');
const date = i18n.date(b.createdAt);
if (m.kind === 'ballot_expired') return t('messages.ballot_expired', { date, articles });
if (m.kind === 'ballot_refused') return t('messages.ballot_refused', { date, articles, reason: t(`ballot.reason.${b.reason ?? 'transfer'}`) });
return t('messages.ballot_objection', { articles });
}
if (o) {
const held = o.heldVersion?.title ?? '';
if (m.kind === 'objection_raised') return t(`messages.objection_raised.${o.kind}`, { name: o.objector ?? '', held, other: o.other.title ?? '' });
@@ -73,6 +91,8 @@
function hrefOf(m: Message): string {
const v = m.objection?.heldVersion ?? m.typo?.version ?? null;
const base = `/g/${m.doc.groupSlug}/docs/${m.doc.slug}`;
const line = linesOf(m)[0];
if (line) return `${base}?${panelSearch({ tab: 'details', unitId: line.unitId, proposalId: line.proposalId }, null)}`;
if (!v) return base;
return `${base}?${panelSearch({ tab: 'details', unitId: v.unitId ?? null, proposalId: v.id }, null)}`;
}
@@ -149,7 +169,7 @@
<p class="text">{textOf(m)}</p>
{#if m.objection?.reason && m.kind !== 'objection_answered'}<p class="reason">{m.objection.reason}</p>{/if}
{#if m.typo}<DiffText parts={condense(m.typo.diff)} />{/if}
{#if m.done}
{#if m.done && m.topic !== 'ballot'}
<p class="outcome">{outcomeOf(m)}</p>
{:else if m.dueAt}
<p class="due">{t('messages.due', { date: i18n.date(m.dueAt) })}</p>