Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> # Conflicts: # MaBibli.Client/wwwroot/css/app.css
153 lines
5.6 KiB
Plaintext
153 lines
5.6 KiB
Plaintext
@page "/auteurs"
|
|
@inject ServiceLivresApi Api
|
|
@inject EtatReseau Reseau
|
|
@implements IDisposable
|
|
|
|
<PageTitle>MaBibli — auteurs</PageTitle>
|
|
|
|
<h1 class="titre-page">Auteurs</h1>
|
|
|
|
@if (_erreur is not null)
|
|
{
|
|
<p class="message-erreur" role="alert">@_erreur</p>
|
|
}
|
|
|
|
@if (_suggestions is { Count: > 0 })
|
|
{
|
|
@*
|
|
Ce qui arrive ici est ce que la machine REFUSE de trancher. Les variantes sûres — casse,
|
|
accents, ordre « Nom, Prénom », initiales abrégées — ont déjà été réunies à l'écriture et
|
|
n'apparaissent jamais dans cette liste. Restent les cas ambigus, typiquement un patronyme
|
|
seul face à un nom complet : deux personnes d'une même famille écrivent aussi des livres.
|
|
*@
|
|
<section class="rapprochements">
|
|
<h2 class="titre-section">Rapprochements possibles</h2>
|
|
<p class="message-discret">
|
|
Ces noms se ressemblent sans qu'on puisse l'affirmer. Un patronyme seul peut désigner
|
|
une autre personne de la même famille — à vous de trancher. Une fusion se défait mal.
|
|
</p>
|
|
|
|
<ul class="liste-rapprochements">
|
|
@foreach (var suggestion in _suggestions)
|
|
{
|
|
<li class="carte-rapprochement" @key="(suggestion.Source.Id, suggestion.Cible.Id)">
|
|
<p class="rapprochement-noms">
|
|
<strong>@suggestion.Source.Nom</strong>
|
|
(@Livres(suggestion.Source.NombreDeLivres))
|
|
est-il <strong>@suggestion.Cible.Nom</strong>
|
|
(@Livres(suggestion.Cible.NombreDeLivres)) ?
|
|
</p>
|
|
|
|
<div class="actions-formulaire">
|
|
@* Une fusion est une écriture : elle demande le réseau, comme le reste. *@
|
|
<button type="button" class="bouton bouton-principal"
|
|
disabled="@(_enCours || !Reseau.EnLigne)" title="@MotifBlocage"
|
|
@onclick="() => AccepterAsync(suggestion)">
|
|
Oui, réunir sous « @suggestion.Cible.Nom »
|
|
</button>
|
|
<button type="button" class="bouton bouton-discret"
|
|
disabled="@(_enCours || !Reseau.EnLigne)" title="@MotifBlocage"
|
|
@onclick="() => RefuserAsync(suggestion)">
|
|
Non, deux personnes
|
|
</button>
|
|
</div>
|
|
</li>
|
|
}
|
|
</ul>
|
|
</section>
|
|
}
|
|
|
|
@if (_auteurs is null)
|
|
{
|
|
<p class="message-discret">Chargement…</p>
|
|
}
|
|
else if (_auteurs.Count == 0)
|
|
{
|
|
<p class="message-discret">Aucun auteur : la bibliothèque est vide.</p>
|
|
}
|
|
else
|
|
{
|
|
<p class="compteur">@_auteurs.Count auteur@(_auteurs.Count > 1 ? "s" : "")</p>
|
|
|
|
<ul class="liste-auteurs">
|
|
@foreach (var auteur in _auteurs)
|
|
{
|
|
<li class="carte-auteur-ligne" @key="auteur.Id">
|
|
<a class="lien-auteur" href="@($"?auteur={auteur.Id}")">@auteur.Nom</a>
|
|
<span class="etiquette">@Livres(auteur.NombreDeLivres)</span>
|
|
@* Le declencheur decrit dans IDEES.md : depuis un auteur qu'on a deja, voir
|
|
tout ce qu'il a ecrit et marquer ce qui manque. *@
|
|
<a class="bouton bouton-compact bouton-discret"
|
|
href="@($"auteurs/{auteur.Id}/bibliographie")">Bibliographie</a>
|
|
</li>
|
|
}
|
|
</ul>
|
|
}
|
|
|
|
<nav class="actions-flottantes">
|
|
<a class="bouton bouton-discret" href="">Retour au catalogue</a>
|
|
<a class="bouton bouton-discret" href="souhaits">Ma liste d'envies</a>
|
|
</nav>
|
|
|
|
@code {
|
|
private IReadOnlyList<AuteurDto>? _auteurs;
|
|
private IReadOnlyList<SuggestionRapprochement>? _suggestions;
|
|
private bool _enCours;
|
|
private string? _erreur;
|
|
|
|
protected override void OnInitialized() => Reseau.Change += SurChangementReseau;
|
|
|
|
private void SurChangementReseau() => _ = InvokeAsync(async () =>
|
|
{
|
|
await ChargerAsync();
|
|
StateHasChanged();
|
|
});
|
|
|
|
public void Dispose() => Reseau.Change -= SurChangementReseau;
|
|
|
|
/// <summary>Raison du blocage des fusions, ou <c>null</c> en ligne.</summary>
|
|
private string? MotifBlocage => Reseau.EnLigne ? null : EtatReseau.MotifHorsLigne;
|
|
|
|
protected override Task OnInitializedAsync() => ChargerAsync();
|
|
|
|
private static string Livres(int nombre) => $"{nombre} livre{(nombre > 1 ? "s" : "")}";
|
|
|
|
private async Task ChargerAsync()
|
|
{
|
|
_erreur = null;
|
|
|
|
try
|
|
{
|
|
_auteurs = await Api.ListerAuteursAsync();
|
|
_suggestions = await Api.ListerRapprochementsAsync();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_erreur = $"Impossible de charger les auteurs : {ex.Message}";
|
|
}
|
|
}
|
|
|
|
private Task AccepterAsync(SuggestionRapprochement suggestion) =>
|
|
DeciderAsync(() => Api.AccepterRapprochementAsync(suggestion.Source.Id, suggestion.Cible.Id));
|
|
|
|
private Task RefuserAsync(SuggestionRapprochement suggestion) =>
|
|
DeciderAsync(() => Api.RefuserRapprochementAsync(suggestion.Source.Id, suggestion.Cible.Id));
|
|
|
|
private async Task DeciderAsync(Func<Task<string?>> action)
|
|
{
|
|
_enCours = true;
|
|
var erreur = await action();
|
|
_enCours = false;
|
|
|
|
if (erreur is not null)
|
|
{
|
|
_erreur = erreur;
|
|
return;
|
|
}
|
|
|
|
// Une fusion peut en rendre d'autres caduques (l'un des deux noms disparaît) : on relit
|
|
// la liste complète plutôt que de retirer la ligne traitée à la main.
|
|
await ChargerAsync();
|
|
}
|
|
}
|