feat: implement admin dashboard with authentication, session monitoring, and user management UI
This commit is contained in:
@@ -23,9 +23,14 @@
|
||||
Manage guest bandwidth caps, session durations, and monitor live PostgreSQL accounting.
|
||||
</p>
|
||||
</div>
|
||||
<button class="btn-sm btn-secondary" @onclick="RefreshData" disabled="@isLoading">
|
||||
<i class="bi bi-arrow-clockwise"></i> Refresh Data
|
||||
</button>
|
||||
<div style="display: flex; gap: 0.5rem; align-items: center;">
|
||||
<button class="btn-sm btn-secondary" @onclick="RefreshData" disabled="@isLoading">
|
||||
<i class="bi bi-arrow-clockwise"></i> Refresh Data
|
||||
</button>
|
||||
<button class="btn-sm btn-danger" @onclick="LogoutAdmin">
|
||||
<i class="bi bi-box-arrow-right"></i> Logout (@AuthService.CurrentAdminUsername)
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@if (notificationMessage != null)
|
||||
@@ -196,7 +201,7 @@
|
||||
<i class="bi bi-slash-circle"></i>
|
||||
</button>
|
||||
}
|
||||
<button class="btn-sm btn-secondary" style="color: var(--accent-rose);" title="Delete User" @onclick="() => DeleteUser(user.ProfileId)">
|
||||
<button class="btn-sm btn-secondary" style="color: var(--accent-rose);" title="Delete User" @onclick="() => OpenDeleteModal(user)">
|
||||
<i class="bi bi-trash"></i>
|
||||
</button>
|
||||
</div>
|
||||
@@ -364,6 +369,37 @@
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
<!-- Delete Confirmation Modal Overlay -->
|
||||
@if (selectedUserForDelete != null)
|
||||
{
|
||||
<div style="position: fixed; top: 0; left: 0; right: 0; bottom: 0; background: rgba(0,0,0,0.75); backdrop-filter: blur(8px); display: flex; align-items: center; justify-content: center; z-index: 1000; padding: 1rem;">
|
||||
<div class="glass-card" style="max-width: 480px; width: 100%; border-color: rgba(244, 63, 94, 0.4);">
|
||||
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 1.5rem;">
|
||||
<h3 style="font-size: 1.25rem; font-weight: 700; color: var(--accent-rose);">
|
||||
<i class="bi bi-exclamation-triangle-fill"></i> Delete Guest Account
|
||||
</h3>
|
||||
<button class="btn-sm btn-secondary" @onclick="() => selectedUserForDelete = null">
|
||||
<i class="bi bi-x-lg"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<p style="color: var(--text-muted); font-size: 0.95rem; margin-bottom: 1rem;">
|
||||
Are you sure you want to permanently delete guest account <strong style="color: var(--text-primary);">@selectedUserForDelete.GuestName</strong> (<code style="color: var(--accent-teal);">@selectedUserForDelete.Username</code>)?
|
||||
</p>
|
||||
<p style="color: var(--text-dim); font-size: 0.825rem; margin-bottom: 1.5rem;">
|
||||
This will remove their RADIUS credentials from <code style="color: var(--accent-teal);">radcheck</code> and <code style="color: var(--accent-teal);">radreply</code> tables. This action cannot be undone.
|
||||
</p>
|
||||
|
||||
<div style="display: flex; gap: 0.75rem; justify-content: flex-end;">
|
||||
<button class="btn-sm btn-secondary" @onclick="() => selectedUserForDelete = null">Cancel</button>
|
||||
<button class="btn-sm btn-danger" style="padding: 0.5rem 1.25rem;" @onclick="ConfirmDeleteUser">
|
||||
<i class="bi bi-trash-fill"></i> Delete User
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
</div>
|
||||
|
||||
@@ -385,16 +421,28 @@
|
||||
private long editModalDataLimit;
|
||||
private string editModalNewPassword = string.Empty;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
await AuthService.InitializeAsync();
|
||||
if (!AuthService.IsAuthenticated)
|
||||
{
|
||||
NavManager.NavigateTo("/admin/login");
|
||||
return;
|
||||
}
|
||||
private UserUsageDto? selectedUserForDelete;
|
||||
|
||||
await LoadDataAsync();
|
||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||
{
|
||||
if (firstRender)
|
||||
{
|
||||
await AuthService.InitializeAsync();
|
||||
if (!AuthService.IsAuthenticated)
|
||||
{
|
||||
NavManager.NavigateTo("/admin/login");
|
||||
return;
|
||||
}
|
||||
|
||||
await LoadDataAsync();
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
|
||||
private async Task LogoutAdmin()
|
||||
{
|
||||
await AuthService.LogoutAsync();
|
||||
NavManager.NavigateTo("/admin/login");
|
||||
}
|
||||
|
||||
private async Task LoadDataAsync()
|
||||
@@ -495,13 +543,23 @@
|
||||
}
|
||||
}
|
||||
|
||||
private async Task DeleteUser(int profileId)
|
||||
private void OpenDeleteModal(UserUsageDto user)
|
||||
{
|
||||
selectedUserForDelete = user;
|
||||
}
|
||||
|
||||
private async Task ConfirmDeleteUser()
|
||||
{
|
||||
if (selectedUserForDelete == null) return;
|
||||
|
||||
int profileId = selectedUserForDelete.ProfileId;
|
||||
selectedUserForDelete = null;
|
||||
|
||||
try
|
||||
{
|
||||
await RadiusService.DeleteUserAsync(profileId);
|
||||
await LoadDataAsync();
|
||||
ShowNotification("User deleted.");
|
||||
ShowNotification("User account deleted successfully.");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
@@ -143,26 +143,30 @@
|
||||
private bool isSubmitting = false;
|
||||
private string errorMessage = string.Empty;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||
{
|
||||
await AuthService.InitializeAsync();
|
||||
if (AuthService.IsAuthenticated)
|
||||
if (firstRender)
|
||||
{
|
||||
NavManager.NavigateTo("/admin");
|
||||
return;
|
||||
}
|
||||
try
|
||||
{
|
||||
await AuthService.InitializeAsync();
|
||||
if (AuthService.IsAuthenticated)
|
||||
{
|
||||
NavManager.NavigateTo("/admin");
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
isFirstRun = !await AuthService.HasAnyAdminAsync();
|
||||
}
|
||||
catch
|
||||
{
|
||||
isFirstRun = false;
|
||||
}
|
||||
finally
|
||||
{
|
||||
isCheckingFirstRun = false;
|
||||
isFirstRun = !await AuthService.HasAnyAdminAsync();
|
||||
}
|
||||
catch
|
||||
{
|
||||
isFirstRun = false;
|
||||
}
|
||||
finally
|
||||
{
|
||||
isCheckingFirstRun = false;
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user