Bénévoles : ajout manuel, import de fichier guidé et gestion complète
Écran « Bénévoles & import » remanié autour des trois méthodes d'ajout demandées (la 3e — formulaire d'inscription en ligne — reste à faire) : - Ajout manuel : formulaire complet (prénom, nom, email, téléphone, taille de t-shirt, régime, commentaire, compétences) ; l'erreur 409 `volunteer.duplicate_email` est affichée. - Import de fichier : assistant en 3 étapes (fichier → association des colonnes + colonnes de disponibilité optionnelles → simulation puis import réel) avec aperçu et rapport ligne par ligne. - Gestion : recherche par nom / email, fiche éditable étendue (régime et commentaire ajoutés), suppression RGPD en cascade inchangée. Le bouton « créer 4 exemples » (maquette) est retiré. Traductions `config.vol.*` et miroir des messages `import.*` du back-end. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017uUsRg7XzopkCPWimwg9ZM
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
df8d6733db
commit
ccf3438eef
@@ -4,10 +4,8 @@
|
||||
"action.close": "Fermer",
|
||||
"action.remove": "Retirer",
|
||||
"action.add": "Ajouter",
|
||||
|
||||
"app.loading": "Chargement…",
|
||||
"app.error.generic": "Une erreur est survenue",
|
||||
|
||||
"error.generic": "Erreur inattendue",
|
||||
"error.not_found": "Ressource introuvable",
|
||||
"error.forbidden": "Accès refusé",
|
||||
@@ -20,11 +18,9 @@
|
||||
"shift.position_wrong_edition": "Le poste n'appartient pas à cette édition",
|
||||
"auth.invalid_credentials": "Email ou mot de passe incorrect",
|
||||
"auth.invalid_token": "Ce lien de connexion est invalide ou expiré",
|
||||
|
||||
"role.coordinator": "Coordination",
|
||||
"role.lead": "Référent",
|
||||
"role.volunteer": "Bénévole",
|
||||
|
||||
"auth.logout": "Déconnexion",
|
||||
"auth.email": "Email",
|
||||
"auth.password": "Mot de passe",
|
||||
@@ -46,17 +42,14 @@
|
||||
"auth.magic.verifyTitle": "Connexion en cours",
|
||||
"auth.magic.verifying": "Vérification du lien…",
|
||||
"auth.magic.retry": "Demander un nouveau lien",
|
||||
|
||||
"header.title": "GESTION DES BÉNÉVOLES",
|
||||
"header.meta": "BÉNÉVOLAT · {count} INSCRITS",
|
||||
"header.mockMode": "DONNÉES DE DÉMO",
|
||||
|
||||
"tab.grille": "Grille des besoins",
|
||||
"tab.volunteers": "Vue par bénévole",
|
||||
"tab.mobileVolunteer": "Bénévole · mobile",
|
||||
"tab.mobileLead": "Référent · mobile",
|
||||
"tab.config": "Configuration",
|
||||
|
||||
"position.category.bar": "Bar",
|
||||
"position.category.ticketing": "Billetterie",
|
||||
"position.category.welcome": "Accueil",
|
||||
@@ -66,7 +59,6 @@
|
||||
"position.category.setup": "Montage",
|
||||
"position.category.stage": "Régie",
|
||||
"position.category.other": "Autre",
|
||||
|
||||
"validation.SHIFT_OVERLAP": "Se chevauche avec un autre créneau",
|
||||
"validation.SHIFT_OVERLAP.at": "Déjà affecté sur {position} au même moment",
|
||||
"validation.SHIFT_OVERLAP.rule": "Deux créneaux d'un même bénévole se chevauchent.",
|
||||
@@ -79,7 +71,6 @@
|
||||
"validation.INSUFFICIENT_REST.rule": "Moins de 8 h 00 entre la fin d'un créneau et le début du suivant.",
|
||||
"validation.MISSING_REQUIRED_SKILL": "Compétence requise manquante : {skill}",
|
||||
"validation.MISSING_REQUIRED_SKILL.rule": "Le bénévole n'a pas une compétence requise par le créneau.",
|
||||
|
||||
"grille.filter.day": "JOUR",
|
||||
"grille.filter.position": "POSTE",
|
||||
"grille.legend.critical": "SOUS-EFFECTIF CRITIQUE",
|
||||
@@ -107,7 +98,6 @@
|
||||
"grille.panel.blocked": "BLOQUÉ",
|
||||
"grille.panel.blockingPrefix": "BLOQUANT — {reason}",
|
||||
"grille.panel.warningsTitle": "⚠ AVERTISSEMENTS — AFFECTATION POSSIBLE",
|
||||
|
||||
"volunteers.filter.show": "AFFICHER",
|
||||
"volunteers.filter.all": "TOUS",
|
||||
"volunteers.filter.overloaded": "SURCHARGÉS",
|
||||
@@ -122,9 +112,7 @@
|
||||
"volunteers.empty": "Aucun bénévole ne correspond à ce filtre — bonne nouvelle. Repassez sur « TOUS » pour revoir l'ensemble de l'équipe.",
|
||||
"volunteers.noData": "Aucun bénévole pour le moment. Ajoutez-les dans Configuration → « Bénévoles & import ».",
|
||||
"volunteers.footnote": "Surcharge = plus de 8 h sur une même journée ou moins de 8 h entre deux créneaux. Oublié = aucune affectation.",
|
||||
|
||||
"design.noteTitle": "CHOIX DE CONCEPTION",
|
||||
|
||||
"mobileVol.statusTime": "9:41",
|
||||
"mobileVol.kicker": "MON PLANNING BÉNÉVOLE",
|
||||
"mobileVol.greeting": "SALUT {name}",
|
||||
@@ -136,7 +124,6 @@
|
||||
"mobileVol.noAccount": "Ce compte n'est rattaché à aucun bénévole. Contactez la coordination.",
|
||||
"mobileVol.detailsUnavailable": "Le détail des créneaux (poste, horaires) n'est pas encore exposé aux bénévoles par l'API.",
|
||||
"mobileVol.designNote": "Lisibilité plein soleil : fonds opaques, texte noir sur jaune ou blanc, aucun gris clair. Cibles tactiles à 52–62 px de haut. Une seule action par créneau. Les données proviennent des affectations réelles de l'API.",
|
||||
|
||||
"mobileLead.statusTime": "18:07",
|
||||
"mobileLead.kicker": "RÉFÉRENT DE POSTE",
|
||||
"mobileLead.inProgress": "CRÉNEAU · {hours}",
|
||||
@@ -150,14 +137,12 @@
|
||||
"mobileLead.markAbsent": "ABSENT",
|
||||
"mobileLead.emptyTeam": "Aucun bénévole affecté à ce créneau.",
|
||||
"mobileLead.designNote": "Le référent ne voit que son poste et un créneau. Le pointage est un geste unique par personne. Il est local à cette maquette : le pointage sur site est hors périmètre (CLAUDE.md §4).",
|
||||
|
||||
"config.admin": "ADMINISTRATION",
|
||||
"config.reserved": "RÉSERVÉ À LA COORDINATION",
|
||||
"config.tab.grid": "POSTES & CRÉNEAUX",
|
||||
"config.tab.volunteers": "BÉNÉVOLES & IMPORT",
|
||||
"config.tab.mail": "MESSAGES",
|
||||
"config.tab.rules": "RÈGLES & ÉDITION",
|
||||
|
||||
"config.grid.positionsHeader": "POSTES · {count} CRÉNEAUX",
|
||||
"config.grid.slotsCount": "{count} créneaux",
|
||||
"config.grid.addPosition": "+ AJOUTER UN POSTE",
|
||||
@@ -172,10 +157,8 @@
|
||||
"config.grid.generateShifts": "GÉNÉRER LES CRÉNEAUX",
|
||||
"config.grid.generated": "{count} créneau(x) ajouté(s).",
|
||||
"config.grid.note": "Effectifs, créneaux, nom et catégorie du poste sont enregistrés immédiatement via l'API. Pour ajouter ou retirer des jours, modifiez les dates de l'édition dans l'onglet « Règles & édition ».",
|
||||
|
||||
"config.vol.importTitle": "IMPORTER DES INSCRIPTIONS",
|
||||
"config.vol.importHint": "L'import de fichier CSV / Excel se fait via l'endpoint dédié. Ce bouton crée 4 bénévoles d'exemple via l'API.",
|
||||
"config.vol.importButton": "CRÉER 4 EXEMPLES",
|
||||
"config.vol.importTitle": "IMPORTER DES BÉNÉVOLES",
|
||||
"config.vol.importHint": "Trois façons d'ajouter des bénévoles : saisie manuelle, import d'un fichier CSV / Excel, ou (à venir) le formulaire d'inscription en ligne.",
|
||||
"config.vol.profiles": "PROFILS ENREGISTRÉS",
|
||||
"config.vol.colName": "NOM",
|
||||
"config.vol.colPhone": "TÉLÉPHONE",
|
||||
@@ -193,7 +176,6 @@
|
||||
"config.vol.delete": "SUPPRIMER (RGPD — EFFACEMENT COMPLET)",
|
||||
"config.vol.deleteConfirm": "Supprimer définitivement ce bénévole et toutes ses données (disponibilités, affectations) ?",
|
||||
"config.vol.note": "Modifications enregistrées immédiatement via l'API. La suppression est un effacement complet en cascade (RGPD).",
|
||||
|
||||
"config.mail.smtpBanner": "Envoie un récapitulatif de planning à chaque bénévole. L'email part si le serveur SMTP est configuré (EMAIL_ENABLED) ; sinon il est seulement journalisé.",
|
||||
"config.mail.templateTitle": "MODÈLE DE MESSAGE",
|
||||
"config.mail.senderNote": "Expéditeur défini côté serveur (SMTP_FROM).",
|
||||
@@ -208,7 +190,6 @@
|
||||
"config.mail.loginLinkLine": "Accède à ton planning : {lien_connexion}",
|
||||
"config.mail.previewTitle": "APERÇU",
|
||||
"config.mail.previewSender": "DE : expéditeur configuré côté serveur",
|
||||
|
||||
"config.rules.editionTitle": "ÉDITION",
|
||||
"config.rules.editionName": "Nom",
|
||||
"config.rules.editionStart": "Premier jour",
|
||||
@@ -238,5 +219,78 @@
|
||||
"config.rules.roleLead": "Référent de poste",
|
||||
"config.rules.roleLeadDesc": "Lecture sur l'édition, écriture sur ses postes",
|
||||
"config.rules.roleVolunteer": "Bénévole",
|
||||
"config.rules.roleVolunteerDesc": "Ses seules données, lien magique par email"
|
||||
"config.rules.roleVolunteerDesc": "Ses seules données, lien magique par email",
|
||||
"config.vol.addButton": "AJOUTER MANUELLEMENT",
|
||||
"config.vol.importButton2": "IMPORTER UN FICHIER",
|
||||
"config.vol.search": "Rechercher un nom, un email…",
|
||||
"config.vol.emptyList": "Aucun bénévole pour l'instant. Ajoutez-en un ou importez un fichier.",
|
||||
"config.vol.noMatch": "Aucun bénévole ne correspond à la recherche.",
|
||||
"config.vol.count": "{count} bénévole(s)",
|
||||
"config.vol.cancel": "ANNULER",
|
||||
"config.vol.field.firstName": "Prénom",
|
||||
"config.vol.field.lastName": "Nom",
|
||||
"config.vol.field.email": "Email (lien magique)",
|
||||
"config.vol.field.phone": "Téléphone",
|
||||
"config.vol.field.tshirt": "Taille de t-shirt",
|
||||
"config.vol.field.diet": "Régime alimentaire",
|
||||
"config.vol.field.comment": "Commentaire",
|
||||
"config.vol.field.skills": "Compétences",
|
||||
"config.vol.addTitle": "NOUVEAU BÉNÉVOLE",
|
||||
"config.vol.addHint": "Le bénévole reçoit un accès par lien magique uniquement si un email est renseigné.",
|
||||
"config.vol.create": "CRÉER LE BÉNÉVOLE",
|
||||
"config.vol.requiredNames": "Le prénom et le nom sont obligatoires.",
|
||||
"config.vol.wiz.title": "IMPORTER UN FICHIER",
|
||||
"config.vol.wiz.step1": "1 · FICHIER",
|
||||
"config.vol.wiz.step2": "2 · COLONNES",
|
||||
"config.vol.wiz.step3": "3 · APERÇU & IMPORT",
|
||||
"config.vol.wiz.pickFile": "CHOISIR UN FICHIER CSV OU EXCEL",
|
||||
"config.vol.wiz.fileHint": "Une ligne par bénévole. La première ligne contient les intitulés de colonnes. En mode démonstration, seuls les fichiers CSV sont pris en charge.",
|
||||
"config.vol.wiz.analyzing": "Analyse du fichier…",
|
||||
"config.vol.wiz.detected": "{rows} ligne(s) · {cols} colonne(s) détectée(s)",
|
||||
"config.vol.wiz.preview": "APERÇU DES PREMIÈRES LIGNES",
|
||||
"config.vol.wiz.mapTitle": "ASSOCIER LES COLONNES",
|
||||
"config.vol.wiz.mapHint": "« Prénom » et « Nom » sont obligatoires. Laissez « — » pour ignorer une colonne.",
|
||||
"config.vol.wiz.ignore": "—",
|
||||
"config.vol.wiz.availTitle": "DISPONIBILITÉS (OPTIONNEL)",
|
||||
"config.vol.wiz.availHint": "Associez une colonne du fichier à une date et une demi-journée pour importer les disponibilités déclarées.",
|
||||
"config.vol.wiz.availAdd": "AJOUTER UNE COLONNE DE DISPONIBILITÉ",
|
||||
"config.vol.wiz.availColumn": "Colonne",
|
||||
"config.vol.wiz.availDate": "Date",
|
||||
"config.vol.wiz.availPart": "Demi-journée",
|
||||
"config.vol.wiz.mapMissing": "Associez au moins les colonnes « Prénom » et « Nom ».",
|
||||
"config.vol.wiz.simulate": "SIMULER",
|
||||
"config.vol.wiz.runImport": "IMPORTER POUR DE VRAI",
|
||||
"config.vol.wiz.back": "RETOUR",
|
||||
"config.vol.wiz.next": "SUIVANT",
|
||||
"config.vol.wiz.dryRunTitle": "SIMULATION — RIEN N'A ÉTÉ ENREGISTRÉ",
|
||||
"config.vol.wiz.doneTitle": "IMPORT TERMINÉ",
|
||||
"config.vol.wiz.created": "{count} créé(s)",
|
||||
"config.vol.wiz.updated": "{count} mis à jour",
|
||||
"config.vol.wiz.skipped": "{count} ignoré(s)",
|
||||
"config.vol.wiz.availWritten": "{count} disponibilité(s)",
|
||||
"config.vol.wiz.skillsCreated": "Compétences créées : {list}",
|
||||
"config.vol.wiz.rowsWithIssues": "LIGNES AVEC REMARQUES",
|
||||
"config.vol.wiz.line": "Ligne {line}",
|
||||
"config.vol.wiz.noIssues": "Aucune remarque : tout est prêt à être importé.",
|
||||
"config.vol.wiz.close": "FERMER",
|
||||
"import.error.empty_file": "Le fichier est vide.",
|
||||
"import.error.encoding": "L'encodage du fichier n'est pas reconnu.",
|
||||
"import.error.unreadable_file": "Fichier illisible ou format non pris en charge.",
|
||||
"import.error.file_too_large": "Le fichier est trop volumineux (5 Mo maximum).",
|
||||
"import.error.xlsx_demo_only": "En mode démonstration, l'import Excel n'est pas disponible : exportez votre fichier en CSV.",
|
||||
"import.mapping.invalid": "Le paramétrage des colonnes est invalide.",
|
||||
"import.mapping.required_field_missing": "Le champ « {field} » doit être associé à une colonne.",
|
||||
"import.mapping.column_not_found": "La colonne « {column} » est absente du fichier.",
|
||||
"import.mapping.unknown_day_part": "Demi-journée « {day_part_code} » inconnue (colonne « {column} »).",
|
||||
"import.mapping.date_outside_edition": "La date {date} de la colonne « {column} » est hors des dates de l’édition.",
|
||||
"import.mapping.duplicate_availability_column": "La colonne « {column} » est associée plusieurs fois.",
|
||||
"import.row.missing_required_field": "Champ obligatoire manquant : {field}.",
|
||||
"import.row.invalid_email": "Adresse email invalide : {value}.",
|
||||
"import.row.duplicate_email_in_file": "Email déjà présent à la ligne {first_line} du fichier.",
|
||||
"import.row.duplicate_name_in_file": "Nom et prénom déjà présents à la ligne {first_line} du fichier.",
|
||||
"import.row.updated_existing": "Bénévole existant mis à jour.",
|
||||
"import.row.possible_duplicate_name": "Un bénévole portant le même nom existe déjà dans l’édition.",
|
||||
"import.row.invalid_tshirt_size": "Taille de t-shirt non reconnue : {value}.",
|
||||
"import.row.skill_created": "Nouvelle compétence créée : {label}.",
|
||||
"import.row.unknown_availability_value": "Valeur de disponibilité non comprise « {value} » (colonne « {column} »)."
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user