Transforme la bibliographie en écran de travail D1 à D5
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
co-authored by
Copilot
parent
ddc60898da
commit
359f4f59c6
@@ -86,6 +86,10 @@ else if (_bibliographie is { } biblio)
|
||||
<p class="compteur">
|
||||
@biblio.Oeuvres.Count œuvre@(biblio.Oeuvres.Count > 1 ? "s" : "")
|
||||
— @_possedees déjà chez vous
|
||||
@if (_masquees > 0)
|
||||
{
|
||||
<text> — @_masquees masquée@(_masquees > 1 ? "s" : "")</text>
|
||||
}
|
||||
</p>
|
||||
|
||||
@* Deux phrases distinctes plutôt qu'une seule à trous : enchaîner des fragments
|
||||
@@ -124,16 +128,37 @@ else if (_bibliographie is { } biblio)
|
||||
<p class="message-erreur" role="alert">@_message</p>
|
||||
}
|
||||
|
||||
@* Filtre sur une seule question : « qu'est-ce qui me manque ? ». Les livres possédés ne
|
||||
sont jamais masqués par défaut — le grisage est l'information principale de l'écran. *@
|
||||
<div class="filtres">
|
||||
<div class="segments" role="group" aria-label="Filtrer la bibliographie">
|
||||
<button type="button" class="segment @(_seulementManquants ? null : "segment-actif")"
|
||||
@onclick="() => _seulementManquants = false">Tout</button>
|
||||
<button type="button" class="segment @(_seulementManquants ? "segment-actif" : null)"
|
||||
@onclick="() => _seulementManquants = true">Ce qui me manque</button>
|
||||
</div>
|
||||
<div class="actions-formulaire">
|
||||
<button type="button" class="bouton bouton-discret"
|
||||
@onclick="() => _filtresOuverts = !_filtresOuverts"
|
||||
aria-expanded="@_filtresOuverts">
|
||||
Filtrer (@NombreFiltres)
|
||||
</button>
|
||||
</div>
|
||||
@if (_filtresOuverts)
|
||||
{
|
||||
<div class="filtres">
|
||||
<div class="segments" role="group" aria-label="Possession">
|
||||
<button type="button" class="segment @(_modePossession == 0 ? "segment-actif" : null)"
|
||||
@onclick="() => _modePossession = 0">Tout</button>
|
||||
<button type="button" class="segment @(_modePossession == 1 ? "segment-actif" : null)"
|
||||
@onclick="() => _modePossession = 1">Ceux que j'ai déjà</button>
|
||||
<button type="button" class="segment @(_modePossession == 2 ? "segment-actif" : null)"
|
||||
@onclick="() => _modePossession = 2">Ce qui me manque</button>
|
||||
</div>
|
||||
@if (_masquees > 0)
|
||||
{
|
||||
<div class="segments">
|
||||
<button type="button" class="segment @(_afficherMasquees ? "segment-actif" : null)"
|
||||
@onclick="() => _afficherMasquees = true">
|
||||
Afficher les masquées (@_masquees)
|
||||
</button>
|
||||
<button type="button" class="segment @(!_afficherMasquees ? "segment-actif" : null)"
|
||||
@onclick="() => _afficherMasquees = false">Masquer les masquées</button>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
|
||||
<ul class="liste-bibliographie">
|
||||
@foreach (var oeuvre in Affichees(biblio))
|
||||
@@ -204,16 +229,51 @@ else if (_bibliographie is { } biblio)
|
||||
|
||||
@if (oeuvre.ADecouvrir)
|
||||
{
|
||||
<button type="button" class="bouton bouton-compact bouton-principal"
|
||||
disabled="@_enCours" @onclick="() => SouhaiterAsync(oeuvre)"
|
||||
aria-label="@($"Ajouter « {oeuvre.Titre} » à ma liste d'envies")">
|
||||
Je le veux
|
||||
<div class="actions-formulaire">
|
||||
<label class="selection-oeuvre">
|
||||
<input type="checkbox"
|
||||
checked="@_selection.Contains(oeuvre.Titre)"
|
||||
@onchange="e => Selectionner(oeuvre.Titre, e.Value is true)" />
|
||||
Sélectionner
|
||||
</label>
|
||||
<button type="button" class="bouton bouton-compact bouton-principal"
|
||||
disabled="@_enCours" @onclick="() => SouhaiterAsync(oeuvre)"
|
||||
aria-label="@($"Ajouter « {oeuvre.Titre} » à ma liste d'envies")">
|
||||
Je le veux
|
||||
</button>
|
||||
</div>
|
||||
}
|
||||
|
||||
@if (!oeuvre.Masquee)
|
||||
{
|
||||
<button type="button" class="bouton bouton-compact bouton-discret"
|
||||
disabled="@_enCours" @onclick="() => MasquerAsync(oeuvre)">
|
||||
Masquer
|
||||
</button>
|
||||
}
|
||||
else
|
||||
{
|
||||
<button type="button" class="bouton bouton-compact bouton-discret"
|
||||
disabled="@_enCours" @onclick="() => DemasquerAsync(oeuvre)">
|
||||
Réafficher
|
||||
</button>
|
||||
}
|
||||
</li>
|
||||
}
|
||||
</ul>
|
||||
|
||||
@if (_selection.Count > 0)
|
||||
{
|
||||
<div class="actions-flottantes">
|
||||
<button type="button" class="bouton bouton-principal"
|
||||
disabled="@(_enCours || !Reseau.EnLigne)"
|
||||
title="@(Reseau.EnLigne ? null : EtatReseau.MotifHorsLigne)"
|
||||
@onclick="AjouterSelectionAsync">
|
||||
Ajouter la sélection aux envies (@_selection.Count)
|
||||
</button>
|
||||
</div>
|
||||
}
|
||||
|
||||
@* Le rapprochement est fait par titre, et il rate des choses (voir CleOeuvre). Le dire
|
||||
franchement vaut mieux que laisser l'utilisateur découvrir seul qu'un livre qu'il
|
||||
possède n'est pas grisé. *@
|
||||
@@ -239,7 +299,9 @@ else if (_bibliographie is { } biblio)
|
||||
public int AuteurId { get; set; }
|
||||
|
||||
private BibliographieDto? _bibliographie;
|
||||
private bool _seulementManquants;
|
||||
private int _modePossession;
|
||||
private bool _filtresOuverts;
|
||||
private bool _afficherMasquees;
|
||||
private bool _enCours;
|
||||
private bool _chargement;
|
||||
|
||||
@@ -250,13 +312,22 @@ else if (_bibliographie is { } biblio)
|
||||
private string? _message;
|
||||
|
||||
private int _possedees;
|
||||
private int _masquees;
|
||||
private IReadOnlyList<LivreDto> _livresCatalogue = [];
|
||||
private readonly HashSet<string> _oeuvresOuvertes = [];
|
||||
private readonly HashSet<string> _selection = [];
|
||||
|
||||
protected override async Task OnParametersSetAsync() => await ChargerAsync();
|
||||
|
||||
private IEnumerable<OeuvreBibliographie> Affichees(BibliographieDto biblio) =>
|
||||
_seulementManquants ? biblio.Oeuvres.Where(o => o.ADecouvrir) : biblio.Oeuvres;
|
||||
biblio.Oeuvres.Where(o =>
|
||||
(_afficherMasquees || !o.Masquee)
|
||||
&& (_modePossession == 0
|
||||
|| (_modePossession == 1 && o.Possede)
|
||||
|| (_modePossession == 2 && o.ADecouvrir)));
|
||||
|
||||
private int NombreFiltres =>
|
||||
(_modePossession == 0 ? 0 : 1) + (_masquees > 0 && !_afficherMasquees ? 1 : 0);
|
||||
|
||||
private async Task ChargerAsync()
|
||||
{
|
||||
@@ -278,6 +349,7 @@ else if (_bibliographie is { } biblio)
|
||||
}
|
||||
|
||||
_possedees = _bibliographie.Oeuvres.Count(o => o.Possede);
|
||||
_masquees = _bibliographie.Oeuvres.Count(o => o.Masquee);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
@@ -300,6 +372,70 @@ else if (_bibliographie is { } biblio)
|
||||
}
|
||||
}
|
||||
|
||||
private void Selectionner(string titre, bool selectionnee)
|
||||
{
|
||||
if (selectionnee)
|
||||
{
|
||||
_selection.Add(titre);
|
||||
}
|
||||
else
|
||||
{
|
||||
_selection.Remove(titre);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task AjouterSelectionAsync()
|
||||
{
|
||||
if (_bibliographie is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var saisies = _bibliographie.Oeuvres
|
||||
.Where(o => _selection.Contains(o.Titre) && o.ADecouvrir)
|
||||
.Select(o => new EnregistrementSouhait
|
||||
{
|
||||
Titre = o.Titre,
|
||||
Auteur = _bibliographie.Auteur.Nom,
|
||||
Editeur = o.Editeur,
|
||||
Annee = o.Annee,
|
||||
Isbn = o.Isbn,
|
||||
})
|
||||
.ToList();
|
||||
|
||||
_enCours = true;
|
||||
_message = null;
|
||||
var resultats = await Api.AjouterSouhaitsAsync(saisies);
|
||||
_enCours = false;
|
||||
var erreurs = resultats.Where(r => !r.EstOk).Select(r => r.Erreur).Where(e => e is not null).ToList();
|
||||
_message = erreurs.Count == 0 ? null : string.Join(" ", erreurs);
|
||||
_selection.Clear();
|
||||
await ChargerAsync();
|
||||
}
|
||||
|
||||
private async Task MasquerAsync(OeuvreBibliographie oeuvre)
|
||||
{
|
||||
await ModifierMasquageAsync(oeuvre, false);
|
||||
}
|
||||
|
||||
private async Task DemasquerAsync(OeuvreBibliographie oeuvre)
|
||||
{
|
||||
await ModifierMasquageAsync(oeuvre, true);
|
||||
}
|
||||
|
||||
private async Task ModifierMasquageAsync(OeuvreBibliographie oeuvre, bool demasquer)
|
||||
{
|
||||
_enCours = true;
|
||||
_message = demasquer
|
||||
? await Api.DemasquerOeuvreBibliographieAsync(AuteurId, oeuvre.Titre)
|
||||
: await Api.MasquerOeuvreBibliographieAsync(AuteurId, oeuvre.Titre);
|
||||
_enCours = false;
|
||||
if (_message is null)
|
||||
{
|
||||
await ChargerAsync();
|
||||
}
|
||||
}
|
||||
|
||||
private void BasculerOeuvre(string titre)
|
||||
{
|
||||
if (!_oeuvresOuvertes.Add(titre))
|
||||
|
||||
Reference in New Issue
Block a user