Cinq retours d'IDEES.md, tous pensés pour le mobile d'abord.
Fiche du livre en deux modes, portés par deux routes : « /livres/{id} »
consulte, « /livres/{id}/edition » modifie. Ouvrir une fiche depuis le
catalogue ne place plus un formulaire vivant sous le pouce. Mettre le mode
dans l'adresse fait du retour navigateur une sortie d'édition naturelle.
Piège rencontré : les deux routes visent le même composant avec le même Id,
donc aucun paramètre ne change et le routeur ne redessine pas — l'URL passait
à « /edition » sans que l'écran bascule, alors qu'un chargement direct de
cette URL marchait, ce qui masque le défaut. Le composant s'abonne donc à
LocationChanged.
Restent hors « Éditer », parce que ce ne sont pas des modifications de la
fiche : le statut de lecture (action la plus fréquente, et personnelle) et
les prêts (gestes du quotidien, donnée du foyer). La suppression, elle, est
réservée au mode édition.
Dans la liste, le statut devient une pastille en lecture seule sur la ligne
des étiquettes ; les trois boutons actionnables par carte partaient trop
facilement en faisant défiler. Le format ne s'affiche plus que pour les
ebooks, le physique étant le cas par défaut — le formulaire le
présélectionne déjà, l'énumération valant 0.
Couverture agrandissable au clic, fermeture au clic extérieur ou par Échap
(le calque est focalisé à l'ouverture, sans quoi Échap resterait sans effet).
Le substitut à initiale n'est jamais cliquable : le déclencheur n'existe que
s'il y a une image.
Le regroupement par auteur existait déjà (table Auteur, page /auteurs, filtre
« ?auteur= ») ; y manquaient les liens depuis la fiche et les styles de la
page auteurs, jamais écrits — la liste sortait en puces brutes.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
109 lines
3.4 KiB
Plaintext
109 lines
3.4 KiB
Plaintext
@page "/prets"
|
|
@inject ServiceLivresApi Api
|
|
|
|
@*
|
|
Ce qui n'est pas à la maison. C'est l'usage principal des prêts : savoir d'un coup d'œil
|
|
quels livres sont dehors, et chez qui.
|
|
|
|
La liste est commune à tout le foyer, sans filtre par utilisateur : n'importe qui doit
|
|
pouvoir constater qu'un livre manque, et noter son retour quand il le récupère.
|
|
*@
|
|
|
|
<PageTitle>MaBibli — prêts en cours</PageTitle>
|
|
|
|
<h1 class="titre-page">Prêts en cours</h1>
|
|
|
|
@if (_erreur is not null)
|
|
{
|
|
<p class="message-erreur" role="alert">@_erreur</p>
|
|
}
|
|
|
|
@if (_prets is null)
|
|
{
|
|
<p class="message-discret">Chargement…</p>
|
|
}
|
|
else if (_prets.Count == 0)
|
|
{
|
|
<p class="message-discret">Tous les livres sont à la maison.</p>
|
|
}
|
|
else
|
|
{
|
|
<p class="compteur">@_prets.Count livre@(_prets.Count > 1 ? "s" : "") dehors</p>
|
|
|
|
<ul class="liste-livres">
|
|
@foreach (var pret in _prets)
|
|
{
|
|
<li class="carte-livre" @key="pret.Id">
|
|
<Couverture Url="@pret.LivreCoverUrl" Titre="@pret.LivreTitre"
|
|
Classe="couverture-petite" Agrandissable="true" />
|
|
|
|
<div class="carte-corps">
|
|
<a class="carte-titre" href="@($"livres/{pret.LivreId}")">@pret.LivreTitre</a>
|
|
|
|
@if (!string.IsNullOrWhiteSpace(pret.LivreAuteurs))
|
|
{
|
|
<p class="carte-auteur">@pret.LivreAuteurs</p>
|
|
}
|
|
|
|
<p class="carte-details">
|
|
<span class="etiquette etiquette-prete">@pret.Emprunteur</span>
|
|
<span>depuis le @pret.DatePret.ToLocalTime().ToString("dd/MM/yyyy")</span>
|
|
<span class="pret-duree">@PretsLivre.Duree(pret.JoursEcoules)</span>
|
|
</p>
|
|
|
|
@* Le retour se note ici : on récupère un livre, on ouvre la liste des prêts,
|
|
on coche. Passer par la fiche du livre serait un détour. *@
|
|
<button type="button" class="bouton bouton-discret bouton-compact"
|
|
disabled="@(_enCours == pret.Id)"
|
|
@onclick="() => RendreAsync(pret)">
|
|
@(_enCours == pret.Id ? "Enregistrement…" : "Rendu")
|
|
</button>
|
|
</div>
|
|
</li>
|
|
}
|
|
</ul>
|
|
}
|
|
|
|
<nav class="actions-flottantes">
|
|
<a class="bouton bouton-discret" href="">Catalogue</a>
|
|
</nav>
|
|
|
|
@code {
|
|
private IReadOnlyList<PretDto>? _prets;
|
|
private string? _erreur;
|
|
private int? _enCours;
|
|
|
|
protected override Task OnInitializedAsync() => ChargerAsync();
|
|
|
|
private async Task ChargerAsync()
|
|
{
|
|
_erreur = null;
|
|
|
|
try
|
|
{
|
|
_prets = await Api.ListerPretsEnCoursAsync();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_erreur = $"Impossible de charger les prêts : {ex.Message}";
|
|
_prets = [];
|
|
}
|
|
}
|
|
|
|
private async Task RendreAsync(PretDto pret)
|
|
{
|
|
_enCours = pret.Id;
|
|
var resultat = await Api.RendreAsync(pret.Id);
|
|
_enCours = null;
|
|
|
|
if (!resultat.EstOk)
|
|
{
|
|
_erreur = resultat.Erreur;
|
|
}
|
|
|
|
// Rechargement complet plutôt que retrait local : quelqu'un d'autre du foyer a pu rendre
|
|
// ou prêter un livre entre-temps, et cette vue est justement celle qu'on garde ouverte.
|
|
await ChargerAsync();
|
|
}
|
|
}
|