Contributions fiables : prénom, mot d'accompagnement, liens gardés

- Prénom demandé à l'envoi d'une contribution et d'un souvenir, retenu
  sur l'appareil pour la fois suivante (submittedByLabel). Le propriétaire
  lit « par Camille » au lieu de « par Contributeur ».
- Mot d'accompagnement enregistré (ContributionSession.comment, migration
  additive) et affiché à la relecture.
- Une personne ajoutée par la famille garde ses liens : identifiant
  provisoire « tmp:… » remplacé par le vrai id à l'application ; un lien
  vers une personne refusée est écarté au lieu de faire échouer la
  relecture. Frère ou sœur : parents calculés aussi pour la famille.
- Soumission et relecture en transaction, appliquées dans l'ordre
  personnes, unions, liens : tout ou rien.
- Bouton « Ajouter une personne » pour la famille sur ordinateur ; après
  l'ajout, le panneau se ferme et un message confirme que la personne est
  dans les modifications ; il ne réapparaît plus au retour en édition.
- Relecture : les liens se lisent « Léon, enfant de Marc ».

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
IliesAllaliandClaude Opus 5.5 committed 2026-09-25 13:52:23 +02:00
1 parent 66752aa1b6
commit 8bfc78b2f5
12 files changed
+491 -141

No files matched your search

@@ -2,6 +2,7 @@ import { useState, useEffect } from 'react'
import { Send, X } from 'lucide-react'
import './ContributionSessionModal.css'
import PzBusy from './PzBusy.jsx'
import { readContributorName } from '../utils/contributorName'
function formatAction(action) {
if (action === 'create') return 'Ajout'
@@ -23,13 +24,15 @@ function formatAction(action) {
* @param {Function} props.onSubmit - Handler soumission ({ comment })
* @param {Function} props.onCancel - Handler annulation
*/
function ContributionSessionModal({ visible, changes = [], recap = {}, loading = false, error = '', onSubmit, onCancel }) {
function ContributionSessionModal({ visible, changes = [], recap = {}, loading = false, error = '', askName = true, onSubmit, onCancel }) {
const [comment, setComment] = useState('')
const [name, setName] = useState('')
// Reset à l'ouverture
// Reset à l'ouverture ; le prénom déjà donné sur cet appareil est repris
useEffect(() => {
if (visible) {
setComment('')
setName(readContributorName())
}
}, [visible])
@@ -47,7 +50,8 @@ function ContributionSessionModal({ visible, changes = [], recap = {}, loading =
const handleSubmit = (e) => {
e.preventDefault()
onSubmit({ comment: comment.trim() })
if (askName && !name.trim()) return
onSubmit({ comment: comment.trim(), name: name.trim() })
}
const totalChanges = (recap.added || 0) + (recap.modified || 0) + (recap.deleted || 0)
@@ -94,6 +98,20 @@ function ContributionSessionModal({ visible, changes = [], recap = {}, loading =
)}
<form className="cs-form" onSubmit={handleSubmit}>
{askName && (
<div className="pz-field">
<label htmlFor="cs-name">Votre prénom</label>
<input
id="cs-name"
type="text"
value={name}
onChange={(e) => setName(e.target.value.slice(0, 120))}
placeholder="Pour que la famille sache qui a ajouté quoi"
autoComplete="given-name"
required
/>
</div>
)}
<div className="pz-field">
<label htmlFor="cs-comment">
Un mot pour accompagner <span className="cs-optional">facultatif</span>
@@ -115,7 +133,7 @@ function ContributionSessionModal({ visible, changes = [], recap = {}, loading =
<button type="button" className="pz-btn pz-btn--ghost" onClick={onCancel} disabled={loading}>
Annuler
</button>
<button type="submit" className="pz-btn pz-btn--primary" disabled={loading}>
<button type="submit" className="pz-btn pz-btn--primary" disabled={loading || (askName && !name.trim())}>
<Send size={16} strokeWidth={2} />
<PzBusy busy={loading} busyLabel="Envoi en cours">Envoyer mes contributions</PzBusy>
</button>