eeg_portal/eeg_frontend/src/app/pages/admin-user-approval/admin-user-approval.html
Bernhard Müller 2bf1d49af1 feat(frontend): add tab navigation and all-users table to AdminUserApprovalComponent
- Add activeTab signal ('pending' | 'all') with tab navigation UI
- Add allUsers signal with loadAllUsers() using generated AdminIAMService.getAllUsers()
- Add getStatusLabel() helper for German status labels (Ausstehend/Aktiv/Freigeschaltet/Inaktiv/Abgelehnt)
- Add getStatusBadgeClass() for color-coded status badges (yellow/green/red)
- Fix duplicate 'Status' column header bug in pending users table
- All-users tab shows Name, Email, Status badge, Rolle columns (no action buttons)
- Add 22 passing tests covering signals, helpers, tab switching, approve/reject, and template
2026-07-23 14:32:02 +02:00

168 lines
6.6 KiB
HTML

<div class="container mx-auto p-6 max-w-6xl">
<div class="mb-8">
<h1 class="text-3xl font-bold text-gray-900">User Freigabe</h1>
<p class="text-gray-600 mt-2">Prüfung der ausstehenden Anmeldungen und EDA-Netz-Checks.</p>
</div>
<!-- Tab Navigation -->
<div class="border-b border-gray-200 mb-6">
<nav class="flex gap-8" aria-label="Tabs">
<button
role="tab"
[attr.aria-selected]="activeTab() === 'pending'"
[class]="
activeTab() === 'pending'
? 'border-b-2 border-indigo-500 text-indigo-600 py-3 px-1 text-sm font-medium'
: 'border-b-2 border-transparent text-gray-500 hover:text-gray-700 py-3 px-1 text-sm font-medium'
"
(click)="switchTab('pending')"
>
Ausstehende Anträge
</button>
<button
role="tab"
[attr.aria-selected]="activeTab() === 'all'"
[class]="
activeTab() === 'all'
? 'border-b-2 border-indigo-500 text-indigo-600 py-3 px-1 text-sm font-medium'
: 'border-b-2 border-transparent text-gray-500 hover:text-gray-700 py-3 px-1 text-sm font-medium'
"
(click)="switchTab('all')"
>
Alle Benutzer
</button>
</nav>
</div>
@if (errorMessage()) {
<div class="bg-red-50 border-l-4 border-red-500 text-red-700 p-4 mb-6" role="alert">
{{ errorMessage() }}
</div>
}
@if (isLoading()) {
<div class="flex items-center justify-center py-12">
<div class="text-gray-500 text-lg">Lade Daten...</div>
</div>
}
@if (!isLoading() && activeTab() === 'pending') {
@if (pendingUsers().length === 0) {
<div class="bg-gray-50 border border-gray-200 rounded-lg p-8 text-center">
<p class="text-gray-600 text-lg">Aktuell gibt es keine neuen User im Status PENDING.</p>
</div>
} @else {
<div class="bg-white shadow-sm border border-gray-200 rounded-lg overflow-hidden">
<div class="overflow-x-auto">
<table class="w-full text-left border-collapse">
<thead>
<tr class="bg-gray-50 border-b border-gray-200">
<th class="p-4 text-sm font-semibold text-gray-700 uppercase tracking-wider">
Benutzer
</th>
<th class="p-4 text-sm font-semibold text-gray-700 uppercase tracking-wider">
Status
</th>
<th
class="p-4 text-sm font-semibold text-gray-700 uppercase tracking-wider text-right"
>
Aktionen
</th>
</tr>
</thead>
<tbody class="divide-y divide-gray-200">
@for (user of pendingUsers(); track user.id) {
<tr class="hover:bg-gray-50 transition-colors">
<td class="p-4">
<div class="font-medium text-gray-900">
{{ user.firstName }} {{ user.lastName }}
</div>
<div class="text-sm text-gray-500">{{ user.email }}</div>
</td>
<td class="p-4">
<span
[class]="
'inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium ' +
getStatusBadgeClass(user.status || 'PENDING')
"
>
{{ getStatusLabel(user.status || 'PENDING') }}
</span>
</td>
<td class="p-4 flex justify-end gap-3">
<button
(click)="approveUser(user.id)"
class="inline-flex items-center justify-center px-4 py-2 border border-transparent text-sm font-medium rounded-md text-white bg-green-600 hover:bg-green-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-green-500 transition"
>
Freigeben
</button>
<button
(click)="rejectUser(user)"
class="inline-flex items-center justify-center px-4 py-2 border border-gray-300 text-sm font-medium rounded-md text-red-700 bg-white hover:bg-red-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500 transition"
>
Ablehnen
</button>
</td>
</tr>
}
</tbody>
</table>
</div>
</div>
}
}
@if (!isLoading() && activeTab() === 'all') {
@if (allUsers().length === 0) {
<div class="bg-gray-50 border border-gray-200 rounded-lg p-8 text-center">
<p class="text-gray-600 text-lg">Keine Benutzer vorhanden.</p>
</div>
} @else {
<div class="bg-white shadow-sm border border-gray-200 rounded-lg overflow-hidden">
<div class="overflow-x-auto">
<table class="w-full text-left border-collapse">
<thead>
<tr class="bg-gray-50 border-b border-gray-200">
<th class="p-4 text-sm font-semibold text-gray-700 uppercase tracking-wider">
Benutzer
</th>
<th class="p-4 text-sm font-semibold text-gray-700 uppercase tracking-wider">
Status
</th>
<th class="p-4 text-sm font-semibold text-gray-700 uppercase tracking-wider">
Rolle
</th>
</tr>
</thead>
<tbody class="divide-y divide-gray-200">
@for (user of allUsers(); track user.id) {
<tr class="hover:bg-gray-50 transition-colors">
<td class="p-4">
<div class="font-medium text-gray-900">
{{ user.firstName }} {{ user.lastName }}
</div>
<div class="text-sm text-gray-500">{{ user.email }}</div>
</td>
<td class="p-4">
<span
[class]="
'inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium ' +
getStatusBadgeClass(user.status || 'UNKNOWN')
"
>
{{ getStatusLabel(user.status || 'UNKNOWN') }}
</span>
</td>
<td class="p-4 text-sm text-gray-700">
{{ user.participantType === 'COMPANY' ? 'Unternehmen' : 'Privatperson' }}
</td>
</tr>
}
</tbody>
</table>
</div>
</div>
}
}
</div>