@page "/revues/{Id:int}" @inject ServiceLivresApi Api @inject NavigationManager Navigation @inject EtatReseau Reseau @implements IDisposable MaBibli — @(_revue?.Titre ?? "revue") @if (_revue is null) {

@(_chargement ? "Chargement…" : "Cette revue n'est pas dans les données enregistrées sur cet appareil.")

} else {

@_revue.Titre

@if (!string.IsNullOrWhiteSpace(_revue.Issn)) { ISSN @_revue.Issn } @if (!string.IsNullOrWhiteSpace(_revue.Editeur)) { @_revue.Editeur }

@if (_erreur is not null) { }

Numéros possédés

@if (_revue.Numeros.Count == 0) {

Aucun numéro recensé pour l'instant.

} else { @* Du plus récent au plus ancien : devant un kiosque, la question est « ai-je le dernier ? », pas « par quoi ai-je commencé ». C'est l'inverse d'une série, qui suit son ordre de lecture. *@ }

Ajouter un numéro

@* ⚠️ Le numéro se saisit à la main, et ce n'est pas un oubli : les deux chiffres de parution du code-barres ne sont PAS un numéro fiable (CLAUDE.md), et l'add-on EAN-2 qui le porterait vraiment n'a pas pu être vérifié sur un magazine réel. *@

La revue

@if (_confirmeSuppression) {

Les @_revue.Numeros.Count numéro(s) recensés disparaîtront avec elle : ils n'existent que par leur revue.

} } @code { [Parameter] public int Id { get; set; } private RevueDto? _revue; private bool _chargement = true; private bool _enCours; private string? _erreur; private bool _confirmeSuppression; private string _titre = string.Empty; private string? _issn; private string? _editeur; private string _numero = string.Empty; private DateTime? _parution; private string? _note; private string? MotifBlocage => Reseau.EnLigne ? null : EtatReseau.MotifHorsLigne; protected override void OnInitialized() => Reseau.Change += SurChangementReseau; private void SurChangementReseau() => _ = InvokeAsync(async () => { await ChargerAsync(); StateHasChanged(); }); public void Dispose() => Reseau.Change -= SurChangementReseau; protected override Task OnParametersSetAsync() => ChargerAsync(); private async Task ChargerAsync() { _chargement = true; _revue = (await Api.ListerRevuesAsync()).FirstOrDefault(r => r.Id == Id); _chargement = false; if (_revue is not null) { _titre = _revue.Titre; _issn = _revue.Issn; _editeur = _revue.Editeur; } } private void Appliquer(RevueDto revue) { _revue = revue; _titre = revue.Titre; _issn = revue.Issn; _editeur = revue.Editeur; } private async Task SurTouche(KeyboardEventArgs e) { if (e.Key == "Enter" && !string.IsNullOrWhiteSpace(_numero) && Reseau.EnLigne) { await AjouterAsync(); } } private async Task AjouterAsync() { _enCours = true; _erreur = null; // Comme pour les prêts : le produit une date SANS fuseau. Elle est // déclarée locale avant conversion, sans quoi la parution se décalerait d'un jour pour // la moitié du globe. var parution = _parution is { } date ? DateTime.SpecifyKind(date, DateTimeKind.Local).ToUniversalTime() : (DateTime?)null; var resultat = await Api.AjouterNumeroAsync(Id, new AjoutNumeroRevue { Numero = _numero, DateParution = parution, Note = _note, }); _enCours = false; if (!resultat.EstOk) { _erreur = resultat.Erreur; return; } Appliquer(resultat.Valeur!); _numero = string.Empty; _parution = null; _note = null; } private async Task RetirerAsync(NumeroRevueDto numero) { _enCours = true; _erreur = await Api.RetirerNumeroAsync(numero.Id); _enCours = false; if (_erreur is null) { await ChargerAsync(); } } private async Task EnregistrerAsync() { _enCours = true; _erreur = null; var resultat = await Api.ModifierRevueAsync( Id, new EnregistrementRevue { Titre = _titre, Issn = _issn, Editeur = _editeur }); _enCours = false; if (!resultat.EstOk) { _erreur = resultat.Erreur; return; } Appliquer(resultat.Valeur!); } private async Task SupprimerAsync() { if (!_confirmeSuppression) { _confirmeSuppression = true; return; } _enCours = true; _erreur = await Api.SupprimerRevueAsync(Id); _enCours = false; if (_erreur is null) { Navigation.NavigateTo("revues"); } } }