Passe l'edition utilisateur admin dans une modal

This commit is contained in:
2026-04-15 22:12:12 +02:00
parent 99a3f6d0aa
commit cd576f941d
2 changed files with 231 additions and 153 deletions

View File

@@ -222,38 +222,52 @@
} }
</section> </section>
<section class="panel panel-wide admin-detail-panel"> }
</main>
</div>
<section class="modal @(ShowEditModal ? string.Empty : "hidden")" aria-hidden="@BoolString(!ShowEditModal)">
<div class="modal-backdrop" @onclick="CloseEditModal"></div>
<div class="modal-card admin-modal-card">
<div class="modal-head">
<div>
<p class="eyebrow">Edition</p>
<h2>@BuildEditModalTitle()</h2>
</div>
<button class="button ghost small" type="button" @onclick="CloseEditModal" disabled="@IsSaving">Fermer</button>
</div>
@if (IsLoadingDetail) @if (IsLoadingDetail)
{ {
<p class="eyebrow">Chargement</p> <p class="section-copy">La fiche utilisateur est en cours de chargement.</p>
<h2>Recuperation de la fiche utilisateur</h2>
<p class="section-copy">Les details du compte sont en cours de chargement.</p>
} }
else if (!string.IsNullOrWhiteSpace(DetailError)) else if (!string.IsNullOrWhiteSpace(DetailError))
{ {
<p class="eyebrow">Serveur</p>
<h2>Impossible de charger cette fiche</h2>
<p class="profile-feedback error">@DetailError</p> <p class="profile-feedback error">@DetailError</p>
<div class="modal-actions">
<button class="button secondary" type="button" @onclick="ReloadSelectedUserAsync">Recharger</button>
<button class="button ghost" type="button" @onclick="CloseEditModal">Fermer</button>
</div>
} }
else if (SelectedUser is null) else if (SelectedUser is null)
{ {
<p class="eyebrow">Edition</p> <p class="section-copy">Cette fiche n'est plus disponible pour le moment.</p>
<h2>Choisis un utilisateur dans le tableau</h2>
<p class="section-copy">
Le bouton `Modifier` charge la fiche detaillee ici pour editer le compte et le profil du site.
</p>
} }
else else
{ {
<div class="section-heading">
<div>
<p class="eyebrow">Edition</p>
<h2>@SelectedUser.DisplayName</h2>
</div>
<p class="section-copy"> <p class="section-copy">
Les roles restent geres dans Keycloak. Cette fiche couvre l'etat du compte et le profil du site. Les roles restent geres dans Keycloak. Cette fiche couvre l'etat du compte et le profil du site.
</p> </p>
</div>
@if (!string.IsNullOrWhiteSpace(SaveError))
{
<p class="profile-feedback error">@SaveError</p>
}
@if (!string.IsNullOrWhiteSpace(SaveMessage))
{
<p class="profile-feedback success">@SaveMessage</p>
}
<div class="profile-meta-grid"> <div class="profile-meta-grid">
<article class="profile-meta-card"> <article class="profile-meta-card">
@@ -366,14 +380,13 @@
<button class="button secondary" type="submit" disabled="@IsSaving"> <button class="button secondary" type="submit" disabled="@IsSaving">
@(IsSaving ? "Enregistrement..." : "Enregistrer les modifications") @(IsSaving ? "Enregistrement..." : "Enregistrer les modifications")
</button> </button>
<button class="button ghost" type="button" @onclick="CloseEditModal" disabled="@IsSaving">Fermer</button>
<p class="section-copy">Le profil site est cree automatiquement lors du premier enregistrement.</p> <p class="section-copy">Le profil site est cree automatiquement lors du premier enregistrement.</p>
</div> </div>
</EditForm> </EditForm>
} }
</section>
}
</main>
</div> </div>
</section>
<section class="modal @(ShowCreateModal ? string.Empty : "hidden")" aria-hidden="@BoolString(!ShowCreateModal)"> <section class="modal @(ShowCreateModal ? string.Empty : "hidden")" aria-hidden="@BoolString(!ShowCreateModal)">
<div class="modal-backdrop" @onclick="CloseCreateModal"></div> <div class="modal-backdrop" @onclick="CloseCreateModal"></div>
@@ -553,6 +566,7 @@
private bool IsSaving; private bool IsSaving;
private bool IsCreating; private bool IsCreating;
private bool IsDeleting; private bool IsDeleting;
private bool ShowEditModal;
private bool ShowCreateModal; private bool ShowCreateModal;
private bool ShowDeleteModal; private bool ShowDeleteModal;
private string? LoadError; private string? LoadError;
@@ -627,6 +641,7 @@
Users.Clear(); Users.Clear();
SelectedSubject = null; SelectedSubject = null;
SelectedUser = null; SelectedUser = null;
ShowEditModal = false;
EditFormModel.Reset(); EditFormModel.Reset();
return; return;
} }
@@ -638,6 +653,7 @@
Users.Clear(); Users.Clear();
SelectedSubject = null; SelectedSubject = null;
SelectedUser = null; SelectedUser = null;
ShowEditModal = false;
EditFormModel.Reset(); EditFormModel.Reset();
return; return;
} }
@@ -650,6 +666,7 @@
{ {
SelectedSubject = null; SelectedSubject = null;
SelectedUser = null; SelectedUser = null;
ShowEditModal = false;
EditFormModel.Reset(); EditFormModel.Reset();
return; return;
} }
@@ -658,22 +675,46 @@
? preferredSubject ? preferredSubject
: Users.Any(user => user.Subject == SelectedSubject) : Users.Any(user => user.Subject == SelectedSubject)
? SelectedSubject ? SelectedSubject
: Users[0].Subject; : null;
if (!string.IsNullOrWhiteSpace(nextSubject)) if (!string.IsNullOrWhiteSpace(nextSubject))
{
SelectedSubject = nextSubject;
if (ShowEditModal)
{ {
await LoadUserDetailAsync(nextSubject, keepFeedback: true); await LoadUserDetailAsync(nextSubject, keepFeedback: true);
} }
else
{
SelectedUser = null;
EditFormModel.Reset();
}
}
else
{
SelectedSubject = null;
SelectedUser = null;
EditFormModel.Reset();
}
} }
catch (HttpRequestException) catch (HttpRequestException)
{ {
LoadError = "Le service d'administration est temporairement indisponible."; LoadError = "Le service d'administration est temporairement indisponible.";
Users.Clear(); Users.Clear();
SelectedSubject = null;
SelectedUser = null;
ShowEditModal = false;
EditFormModel.Reset();
} }
catch (TaskCanceledException) catch (TaskCanceledException)
{ {
LoadError = "Le chargement de l'administration a pris trop de temps."; LoadError = "Le chargement de l'administration a pris trop de temps.";
Users.Clear(); Users.Clear();
SelectedSubject = null;
SelectedUser = null;
ShowEditModal = false;
EditFormModel.Reset();
} }
finally finally
{ {
@@ -686,6 +727,7 @@
{ {
SaveError = null; SaveError = null;
SaveMessage = null; SaveMessage = null;
ShowEditModal = true;
await LoadUserDetailAsync(subject, keepFeedback: false); await LoadUserDetailAsync(subject, keepFeedback: false);
} }
@@ -798,6 +840,27 @@
} }
} }
private void CloseEditModal()
{
if (IsSaving)
{
return;
}
ShowEditModal = false;
DetailError = null;
}
private async Task ReloadSelectedUserAsync()
{
if (SelectedSubject is null)
{
return;
}
await LoadUserDetailAsync(SelectedSubject, keepFeedback: true);
}
private void OpenCreateModal() private void OpenCreateModal()
{ {
CreateFormModel.Reset(); CreateFormModel.Reset();
@@ -988,6 +1051,7 @@
SelectedSubject = null; SelectedSubject = null;
SelectedUser = null; SelectedUser = null;
PendingDeleteUser = null; PendingDeleteUser = null;
ShowEditModal = false;
ShowCreateModal = false; ShowCreateModal = false;
ShowDeleteModal = false; ShowDeleteModal = false;
EditFormModel.Reset(); EditFormModel.Reset();
@@ -1018,6 +1082,21 @@
? "is-selected" ? "is-selected"
: string.Empty; : string.Empty;
private string BuildEditModalTitle()
{
if (SelectedUser is not null)
{
return !string.IsNullOrWhiteSpace(SelectedUser.DisplayName)
? SelectedUser.DisplayName
: SelectedUser.Username;
}
var summary = Users.FirstOrDefault(user => user.Subject == SelectedSubject);
return summary?.IdentityDisplayName
?? summary?.Username
?? "Modifier un utilisateur";
}
private static string BuildUserCardFootnote(AdminUserSummaryResponse user) private static string BuildUserCardFootnote(AdminUserSummaryResponse user)
=> user.SiteProfileUpdatedUtc is not null => user.SiteProfileUpdatedUtc is not null
? FormatDate(user.SiteProfileUpdatedUtc) ? FormatDate(user.SiteProfileUpdatedUtc)

View File

@@ -1598,8 +1598,7 @@ body.site-menu-hidden .site-menu-shell {
margin-top: 0.8rem; margin-top: 0.8rem;
} }
.admin-table-panel, .admin-table-panel {
.admin-detail-panel {
display: grid; display: grid;
align-content: start; align-content: start;
gap: 1rem; gap: 1rem;