using System.Text.Json.Serialization; using MaBibli.Shared.Entites; using MaBibli.Shared.Textes; namespace MaBibli.Shared.Dtos; /// /// Charge utile de création et de modification d'un livre. /// /// /// n'y figure pas volontairement : il est déterminé par le serveur /// à partir de l'utilisateur authentifié, jamais par le client. /// public record EnregistrementLivre { /// Séparateur des auteurs dans la forme texte d'un champ de saisie. /// /// Le point-virgule, et non la virgule : celle-ci est déjà prise par la forme /// bibliographique « Zola, Émile », qu'on doit pouvoir taper telle quelle. /// public const char SeparateurAuteurs = ';'; /// Facultatif : certains livres n'ont pas d'ISBN. Normalisé par le serveur. public string? Isbn { get; set; } public string Titre { get; set; } = string.Empty; /// /// Auteurs, dans l'ordre de la couverture, chacun avec son rôle sur ce livre. Le /// serveur les rattache aux fiches existantes quand c'est sûr, et en crée sinon. /// public List Auteurs { get; set; } = []; /// Thèmes saisis manuellement, séparés par des points-virgules dans l'interface. public List Themes { get; set; } = []; public string? Editeur { get; set; } public Format Format { get; set; } /// Roman, bande dessinée… Facultatif : « non précisé » est une réponse valable. public TypeDocument TypeDocument { get; set; } /// /// Statut de lecture de l'appelant. null = non commencé, et aucune ligne n'est /// alors écrite en base. /// public Statut? Statut { get; set; } /// /// Nombre de pages. null = non renseigné, et surtout pas 0. /// /// /// Peut arriver prérempli depuis dc:format de la BnF ; c'est alors une /// proposition, que la saisie corrige ou efface. /// public int? NombrePages { get; set; } public string? CoverUrl { get; set; } /// /// Notice ayant servi au préremplissage, ou null pour une saisie manuelle. /// public string? UrlNotice { get; set; } /// /// Vue « une seule ligne » de , pour les champs de saisie simples. /// /// /// ⚠️ Ce n'est plus un champ de saisie : le formulaire remplit la liste un auteur à /// la fois (voir SaisieListe), un champ relié à chaque frappe sur cette propriété /// ayant rendu son propre séparateur intapable. Elle ne sert plus qu'au préremplissage /// depuis une notice, qui donne les auteurs sur une ligne — une seule affectation, jamais /// une par caractère. /// [JsonIgnore] public string? Auteur { get => Auteurs.Count == 0 ? null : string.Join($"{SeparateurAuteurs} ", Auteurs.Select(a => a.Nom)); set => Auteurs = Decouper(value, Auteurs); } /// /// Découpe une saisie texte en auteurs, en écartant les entrées vides. /// /// /// Auteurs déjà saisis, dont les rôles sont repris quand le nom réapparaît. /// /// /// ⚠️ La reprise des rôles a été écrite pour un champ qui se reconstruisait à chaque frappe. /// Ce champ n'existe plus — le formulaire corrige un nom sans toucher à son rôle /// (NomsAuteurs) — mais elle reste juste, et gratuite, pour un préremplissage qui /// écraserait sinon des rôles déjà posés. /// public static List Decouper(string? saisie, IEnumerable? connus = null) { if (string.IsNullOrWhiteSpace(saisie)) { return []; } var roles = new Dictionary(StringComparer.Ordinal); foreach (var connu in connus ?? []) { roles.TryAdd(NormalisationTexte.Normaliser(connu.Nom), connu.Role); } return saisie .Split(SeparateurAuteurs, StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries) .Select(nom => new AuteurSaisi( nom, roles.GetValueOrDefault(NormalisationTexte.Normaliser(nom), RoleAuteur.NonPrecise))) .ToList(); } /// /// Découpe une ligne de thèmes. Séparateur : le point-virgule, la virgule restant /// acceptée — un thème n'en contient jamais. /// /// ⚠️ Plus aucun champ ne s'y lie : les thèmes se saisissent un par un. Cela reste la façon /// de relire une ligne venue d'ailleurs. /// /// public static List DecouperThemes(string? saisie) => ListeSaisie.Decouper(saisie); } /// Un auteur tel qu'il est saisi : son nom, et son rôle sur ce livre. /// /// Le rôle n'appartient pas à la personne mais au lien : le même auteur scénarise un /// album et dessine le suivant. Voir . /// public record AuteurSaisi(string Nom, RoleAuteur Role = RoleAuteur.NonPrecise); /// Demande de renommage d'une fiche auteur. public record RenommerAuteur(string Nom); /// Résultat d'un renommage, avec collision éventuelle à confirmer. public record ResultatRenommageAuteur { public AuteurDto? Auteur { get; init; } public AuteurDto? Collision { get; init; } public bool EstCollision => Collision is not null; } /// Charge utile du changement de statut de lecture — l'action la plus fréquente. /// /// Le statut posé est toujours celui de l'appelant : il n'y a pas de champ « utilisateur », /// et il ne doit jamais y en avoir. Personne ne coche « lu » à la place d'un autre. /// public record ChangementStatut { /// null retire le statut : le livre redevient « non commencé » pour l'appelant. public Statut? Statut { get; set; } }