@page "/" @inject ServiceLivresApi Api @implements IDisposable MaBibli — catalogue

Catalogue

@foreach (var format in Enum.GetValues()) { }
@foreach (var statut in Enum.GetValues()) { }
@if (_erreur is not null) { } @if (_chargement && _livres is null) {

Chargement…

} else if (_livres is { Count: 0 }) {

@(EstFiltre ? "Aucun livre ne correspond à cette recherche." : "La bibliothèque est vide. Ajoutez un premier livre.")

} else if (_livres is not null) {

@_livres.Count livre@(_livres.Count > 1 ? "s" : "")

} @code { private IReadOnlyList? _livres; private string _recherche = string.Empty; private Format? _format; private Statut? _statut; private bool _chargement; private string? _erreur; private int? _statutEnCours; // Une frappe au clavier annule la recherche précédente encore en vol. private CancellationTokenSource _cts = new(); private bool EstFiltre => !string.IsNullOrWhiteSpace(_recherche) || _format is not null || _statut is not null; protected override Task OnInitializedAsync() => ChargerAsync(); private async Task SurRecherche(ChangeEventArgs e) { _recherche = e.Value?.ToString() ?? string.Empty; await ChargerAsync(); } private Task FiltrerFormat(Format? format) { _format = format; return ChargerAsync(); } private Task FiltrerStatut(Statut? statut) { _statut = statut; return ChargerAsync(); } private async Task ChargerAsync() { _cts.Cancel(); _cts.Dispose(); _cts = new CancellationTokenSource(); var jeton = _cts.Token; _chargement = true; _erreur = null; try { var criteres = new CritereLivres { Recherche = _recherche, Format = _format, Statut = _statut }; _livres = await Api.ListerAsync(criteres, jeton); } catch (OperationCanceledException) { return; // Une recherche plus récente a pris le relais. } catch (Exception ex) { _erreur = $"Impossible de charger le catalogue : {ex.Message}"; } finally { if (!jeton.IsCancellationRequested) { _chargement = false; } } } private async Task ChangerStatut(LivreDto livre, Statut statut) { if (livre.Statut == statut) { return; } _statutEnCours = livre.Id; var resultat = await Api.ChangerStatutAsync(livre.Id, statut); _statutEnCours = null; if (!resultat.EstOk) { _erreur = resultat.Erreur; return; } if (_statut is not null) { // Un filtre par statut est actif : le livre vient peut-être de sortir de la sélection, // il faut donc recharger plutôt que corriger la liste en place. await ChargerAsync(); return; } // Remplacement local : évite de recharger toute la liste pour un seul champ. _livres = _livres!.Select(l => l.Id == livre.Id ? resultat.Valeur! : l).ToList(); } public void Dispose() { _cts.Cancel(); _cts.Dispose(); } }