Le numéro d'un bénévole se distingue, et se lit à voix haute - #57
Merged
Merged
Conversation
Le pli et le gris ont été corrigés au commit précédent : les inscrits s'affichent sous leur créneau, coordonnées cliquables à 7,24:1. Restaient quatre choses, vérifiées sur l'écran tel qu'il est aujourd'hui. Le téléphone ne se distinguait pas de l'adresse. Les deux sortaient en text-xs slate-600, l'un sous l'autre, sans rien pour dire lequel on vient chercher. Le numéro passe devant, en text-sm brand-700 (6,78:1), avec son icône ; l'adresse reste en text-xs slate-600 (7,24:1), avec la sienne. Les liens n'avaient pas de nom. Un lecteur d'écran annonçait « lien, +33634580545 » sans dire à qui. Le nom est préfixé en sr-only plutôt que posé en aria-label : un aria-label aurait REMPLACÉ le nom accessible, donc retiré le numéro visible de ce qui est annoncé, et cassé la commande vocale — c'est le critère 2.5.3 « Label in Name ». Le motif est celui que le bouton « Retirer » utilisait déjà. Trois cibles restaient sous 44 px, alors que le commit précédent annonçait le contraire : « Retirer » n'avait aucune hauteur minimale (~20 px), et Modifier / Dupliquer / Supprimer étaient à min-h-8. Le débordement n'était traité qu'à moitié. L'adresse portait `break-all`, qui coupe n'importe où — y compris un numéro entre deux chiffres — et le téléphone ne portait rien du tout, alors qu'il accepte 40 caractères sans séparateur. Les deux passent à `[overflow-wrap:anywhere]`, qui ne coupe qu'en dernier recours et qui, contrairement à `break-words`, entre dans le calcul de min-content : c'est ce qui empêche la carte de sortir de l'écran à 320 px. Le nom le reçoit aussi. Déplier coûte de la hauteur — douze inscrits font environ 1 300 px sur une colonne. Elle est reprise en largeur, deux colonnes dès 640 px et trois dès 1280 px, plutôt qu'en repliant à nouveau ce qu'on vient de montrer. Deux échecs silencieux au passage : le bloc d'erreur n'était rendu que si le formulaire d'ajout était ouvert, alors que la duplication, la suppression d'un créneau et le retrait d'un inscrit alimentent le même `error` — une duplication qui échouait ne disait rien. Il sort du formulaire, et les deux suppressions, qui n'attrapaient même pas leur exception, la signalent. Côté réunion, le même traitement : icône, taille et couleur identiques, nom accessible, et le badge « invité » quitte slate-100/slate-500 (4,34:1, sous le seuil) pour slate-200/slate-600 (6,15:1). Les deux écrans montrent la même chose ; ils la montrent enfin de la même façon. Enfin la dernière lecture publique qui ramenait trop : getUpcomingPublishedEvents chargeait la ligne d'inscription entière — nom, e-mail, téléphone, jeton d'annulation — pour l'accueil et /rejoindre, qui n'en lisent que `.length`. Elle ne charge plus que l'identifiant. Aucun effet visible, et la fuite devient impossible par construction plutôt que par discipline. Ce qui n'est PAS fait, volontairement : les événements lisent toujours `signup.phone` brut, sans le repli vers la fiche d'adhérent que les réunions obtiennent par telephonePresent(). Un membre connecté qui s'inscrit sans retaper son numéro apparaît donc sans téléphone. Le corriger demande de joindre associationMember dans getEventWithDetails, qui a cinq appelants — dont l'outil MCP get_event, qui relaie l'objet entier et sortirait le numéro privé d'un adhérent. C'est un autre changement, avec sa propre revue. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014SfQYBU4xXTeSEHKhHQXdD
flocom
force-pushed
the
benevoles-coordonnees-lisibles
branch
from
September 19, 2026 07:41
3247505 to
8223860
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Suite de « Les coordonnées des bénévoles se voient enfin » (75fa224), qui avait supprimé le pli et remonté le contraste. Cette PR traite ce qui restait, vérifié sur l'écran tel qu'il est aujourd'hui — pas sur celui d'avant.
Ce qui était encore cassé
text-xs text-slate-600text-sm text-brand-700(6,78:1) + icône ; e-mailtext-xs text-slate-600(7,24:1) + icônesr-only« Appeler Marie au … »min-h-11 min-w-11min-h-8(32 px)min-h-11(44 px)break-allsur l'e-mail, rien sur le téléphone[overflow-wrap:anywhere]sur nom, téléphone et e-mailPourquoi
sr-onlyet pasaria-labelUn
aria-labelremplace le nom accessible. Poseraria-label="Appeler Marie Dupont"sur un lien dont le texte visible est le numéro retire ce numéro de ce qui est annoncé : échec du critère WCAG 2.5.3 « Label in Name » (niveau A), et la commande vocale ne reconnaît plus ce que l'utilisateur lit à l'écran. Le préfixesr-onlydonne « Appeler Marie Dupont au +33634580545 » — le texte visible reste contenu dans le nom accessible. C'est le motif que le bouton « Retirer » utilisait déjà.Pourquoi
[overflow-wrap:anywhere]et pasbreak-wordsbreak-wordsne participe pas au calcul demin-content: un e-mail ou un numéro sans point de coupure pousse la carte hors de la fenêtre malgrémax-w-full.anywherey participe, tout en ne coupant qu'en dernier recours — contrairement àbreak-all, qui scindait « +33634580545 » entre deux chiffres.phonen'est validé que parz.string().trim().max(40): 40 caractères sans séparateur sont acceptés, et ne débordent plus.Le coût, chiffré
Déplier coûte de la hauteur : douze inscrits font environ 1 300 px sur une colonne. Repris en largeur —
sm:grid-cols-2 xl:grid-cols-3— plutôt qu'en repliant à nouveau ce qu'on vient de montrer. Largeur de colonne réelle mesurée, barre latéralelg:w-[18rem]comprise : ~282 px à 1280 px, ~272 px à 640 px, ~232 px de texte à 320 px.Deux échecs silencieux
canManage && showAdd, alors queduplicateSlot,saveSlot,deleteSlotetremoveSignupalimentent le mêmeerror. Une duplication qui échouait ne disait rien. Il sort du formulaire.deleteSlotetremoveSignupn'attrapaient même pas leur exception. Elles la signalent.Frontière public/privé
Rien de nouveau ne traverse. La projection serveur→client (
page.tsxl.155-168) reste la liste blanche{ id, name, email, phone }— pas de spread, pas decancelToken, pas deuserId, pas decreatedAt.phoneétait déjà sérialisé dans la charge RSC : cette PR le rend lisible à qui a déjà le droit de le lire.SlotManagern'a toujours qu'un seul montage (dashboard/events/[id]/page.tsx), sous lerequireUser()du layout. Aucun composant partagé n'est extrait — le seul garde-fou structurel est qu'un composant sachant afficher un téléphone d'inscrit n'existe qu'à un endroit, importé une fois.Une fuite refermée en plus.
getUpcomingPublishedEvents()chargeait encore la ligne d'inscription entière — nom, e-mail, téléphone et jeton d'annulation — pour l'accueil/et/rejoindre, qui n'en lisent que.length(vérifié :page.tsxl.55 et l.226,rejoindrel.209 et l.222). Elle ne charge plus que l'identifiant. Aucun effet visible ; la fuite devient impossible par construction plutôt que par discipline. C'était la dernière des trois lectures publiques encore ouverte.Ce qui n'est PAS fait, volontairement
Les événements lisent toujours
signup.phonebrut, sans le repli vers la fiche d'adhérent que les réunions obtiennent partelephonePresent(). Un membre connecté qui s'inscrit sans retaper son numéro apparaît donc sans téléphone, alors que l'association le connaît. Le corriger demande de joindreassociationMemberdansgetEventWithDetails, qui a cinq appelants — dont l'outil MCPget_event, qui faittoolResult({ event })et relaierait donc le numéro privé d'un adhérent. C'est un autre changement, avec sa propre revue.Point à trancher séparément, signalé sans être décidé ici :
/dashboard/events/[id]n'exige querequireUser(). Ces coordonnées sont visibles de tout membre connecté, pas seulement d'un manager — c'était déjà vrai avant, le pli ne protégeait rien puisque la donnée était déjà dans le HTML. Restreindre serait une décision de produit, côté serveur, pas un effet de bord d'une correction d'accessibilité.Vérification
npx tsc --noEmit: 0 erreurnpx next lint: aucun avertissementnpx next build: succèsmin-w-11,overflow-wrap:anywhere,.xl\:grid-cols-3sousmin-width:1280px,gap-1.5tailwind.config.ts🤖 Generated with Claude Code
https://claude.ai/code/session_014SfQYBU4xXTeSEHKhHQXdD
Generated by Claude Code