@*
Formulaire d'une fiche livre, partagé par l'ajout (ISBN ou manuel) et l'édition.
Le pré-remplissage par ISBN est une AIDE, pas une contrainte : tous les champs restent
modifiables, et une fiche incomplète peut toujours être complétée à la main (CLAUDE.md).
*@
}
@*
⚠️ L'ORDRE DES CHAMPS EST UNE DÉCISION (lot Q, 2026-08-21), pas une mise en page.
Type de document, puis thèmes, puis auteurs (chacun avec son rôle) : c'est l'ordre dans
lequel on regarde un livre qu'on tient en main, et surtout le type COMMANDE LA SUITE de
la saisie — les rôles ne se posent que là. Relégué en bas, il obligeait à descendre tout le formulaire
pour dire « c'est une BD », c'est-à-dire après avoir saisi ce qui en dépend.
⚠️ Remonter le champ le rend visible ; le PRÉREMPLIR écrirait quelque chose de faux. Le
défaut reste « non précisé », qui ne prétend rien (décision actée) — c'est aussi ce qui
rend l'étiquette honnête dans les listes : elle ne s'affiche que si un type a été choisi.
*@
@*
⚠️ Thèmes et auteurs se saisissent UN PAR UN, et non plus sur une ligne à séparateurs.
Le champ unique se reliait à chaque frappe sur une propriété qui découpait puis
recomposait la liste : le point-virgule tapé y était élagué (entrée vide) et l'espace
qui le suit rogné — le séparateur était le seul caractère qu'on ne pouvait pas taper.
Voir CLAUDE.md.
*@
@*
Un auteur par ligne, et son RÔLE avec lui.
⚠️ Le rôle vit sur le LIEN, pas sur la personne : le même auteur scénarise un album et
dessine le suivant. C'est aussi pourquoi renommer une ligne conserve son rôle
(NomsAuteurs) — on corrige un nom, on ne désigne pas quelqu'un d'autre.
⚠️ Les rôles n'apparaissent qu'à partir de DEUX auteurs, décision inchangée : un roman
n'a qu'un signataire dont le rôle ne se pose pas. Le défaut reste « non précisé ».
*@
@if (Saisie.Auteurs.Count > 1)
{
@foreach (var role in Roles)
{
}
}
@*
Le format n'est plus affiché dans les listes que pour les ebooks : un livre y est donc
physique par défaut. Cette valeur DOIT rester présélectionnée ici, sinon on créerait
des fiches sans format en croyant que « rien d'affiché = physique ».
C'est le cas sans code particulier : Format.Physique vaut 0, valeur par défaut de
l'énumération, et le segment correspondant est donc actif dès l'ouverture.
*@
@*
⚠️ Le champ reste VIDE quand on ne sait pas : « 0 » se lirait comme une donnée. C'est
aussi pourquoi la valeur proposée par la BnF arrive ici et non en base directement —
une pagination lue dans une phrase (« 1 vol. (349 p.) ») se corrige d'un geste.
*@
@if (!string.IsNullOrEmpty(Erreur))
{
@Erreur
}
@* Un enregistrement impossible se dit AVANT le clic : un bouton qui échoue en silence est
pire que pas de bouton du tout (CLAUDE.md, stratégie hors-ligne). *@
@if (!string.IsNullOrEmpty(MessageBlocage))
{
@MessageBlocage
}
@if (OnAnnuler.HasDelegate)
{
}
@code {
private static readonly Format[] Formats = Enum.GetValues();
private static readonly TypeDocument[] Types = Enum.GetValues();
private static readonly RoleAuteur[] Roles = Enum.GetValues();
///
/// Pose le rôle d'un auteur.
///
///
/// est un record : on remplace l'entrée plutôt que de la muter,
/// et la liste reste celle que la propriété Auteur saura relire pour préserver les
/// rôles à la frappe suivante.
///
private void PoserRole(int index, RoleAuteur role) =>
Saisie.Auteurs[index] = Saisie.Auteurs[index] with { Role = role };
///
/// Les noms des auteurs, vus comme une liste de chaînes par SaisieListe.
///
///
/// ⚠️ Sa référence doit rester stable tant que la saisie ne change pas : le composant
/// se remet à zéro quand la liste qu'on lui prête change d'identité, et il perdrait donc à
/// chaque rendu ce qui est en cours de frappe.
///
private NomsAuteurs _noms = default!;
private EnregistrementLivre? _saisiePrecedente;
protected override void OnParametersSet()
{
if (!ReferenceEquals(_saisiePrecedente, Saisie))
{
_saisiePrecedente = Saisie;
_noms = new NomsAuteurs(Saisie.Auteurs);
}
}
[Parameter, EditorRequired] public EnregistrementLivre Saisie { get; set; } = new();
[Parameter] public string LibelleValidation { get; set; } = "Enregistrer";
[Parameter] public string? Erreur { get; set; }
[Parameter] public bool EnCours { get; set; }
///
/// Raison pour laquelle l'enregistrement est impossible (typiquement l'absence de réseau).
/// Renseignée, elle désactive la validation et s'affiche : la saisie reste lisible, mais
/// l'utilisateur sait pourquoi il ne peut pas valider.
///
[Parameter] public string? MessageBlocage { get; set; }
private bool Bloque => !string.IsNullOrEmpty(MessageBlocage);
[Parameter] public EventCallback OnValider { get; set; }
[Parameter] public EventCallback OnAnnuler { get; set; }
private Task Valider() => OnValider.InvokeAsync();
}