Files
MtoRagSystem/templates/admin/user/index.html.twig
2026-05-11 14:26:09 +02:00

189 lines
9.2 KiB
Twig

{% extends 'admin/base.html.twig' %}
{% block title %}Benutzerverwaltung{% endblock %}
{% block body %}
<div class="d-flex justify-content-between align-items-center mb-4 flex-wrap gap-2">
<div>
<h1 class="h3 mb-1">
<i class="bi bi-people-fill"></i> Benutzerverwaltung
</h1>
<div class="small text-muted">
Benutzer anlegen, Rollen zuweisen und Zugänge aktivieren oder deaktivieren.
</div>
</div>
<a href="{{ path('admin_users_create') }}" class="btn btn-sm btn-outline-info">
<i class="bi bi-person-plus-fill"></i> Neuer Benutzer
</a>
</div>
{% for message in app.flashes('success') %}
<div class="alert alert-success shadow-sm">{{ message }}</div>
{% endfor %}
{% for message in app.flashes('danger') %}
<div class="alert alert-danger shadow-sm">{{ message }}</div>
{% endfor %}
{% for message in app.flashes('info') %}
<div class="alert alert-info shadow-sm">{{ message }}</div>
{% endfor %}
<div class="row g-3 mb-4">
<div class="col-md-4 col-xl-3">
<div class="card bg-black border-secondary text-light shadow-sm h-100">
<div class="card-body">
<div class="small text-muted mb-1">Benutzer gesamt</div>
<div class="h3 mb-0">{{ total }}</div>
</div>
</div>
</div>
<div class="col-md-4 col-xl-3">
<div class="card bg-black border-secondary text-light shadow-sm h-100">
<div class="card-body">
<div class="small text-muted mb-1">Aktiv</div>
<div class="h3 mb-0 text-success">{{ active_total }}</div>
</div>
</div>
</div>
<div class="col-md-4 col-xl-3">
<div class="card bg-black border-secondary text-light shadow-sm h-100">
<div class="card-body">
<div class="small text-muted mb-1">Inaktiv</div>
<div class="h3 mb-0 text-warning">{{ inactive_total }}</div>
</div>
</div>
</div>
<div class="col-md-12 col-xl-3">
<div class="card bg-dark border-secondary text-light shadow-sm h-100">
<div class="card-body small">
<strong class="text-info">Schutzregeln aktiv</strong><br>
Der letzte aktive Super-Admin kann nicht deaktiviert oder demotet werden.
</div>
</div>
</div>
</div>
<div class="card bg-dark border-secondary text-light mb-4 shadow-sm">
<div class="card-body">
<form method="get" action="{{ path('admin_users_index') }}" class="row g-3 align-items-end">
<div class="col-lg-4">
<label class="form-label small text-muted" for="user-search">Suche</label>
<input id="user-search"
type="search"
name="q"
value="{{ filters.q }}"
class="form-control bg-black text-light border-secondary"
placeholder="E-Mail suchen">
</div>
<div class="col-lg-3">
<label class="form-label small text-muted" for="user-status">Status</label>
<select id="user-status" name="status" class="form-select bg-black text-light border-secondary">
<option value="all" {{ filters.status == 'all' ? 'selected' : '' }}>Alle</option>
<option value="active" {{ filters.status == 'active' ? 'selected' : '' }}>Aktiv</option>
<option value="inactive" {{ filters.status == 'inactive' ? 'selected' : '' }}>Inaktiv</option>
</select>
</div>
<div class="col-lg-3">
<label class="form-label small text-muted" for="user-role">Rolle</label>
<select id="user-role" name="role" class="form-select bg-black text-light border-secondary">
<option value="all" {{ filters.role == 'all' ? 'selected' : '' }}>Alle Rollen</option>
{% for role, label in role_choices %}
<option value="{{ role }}" {{ filters.role == role ? 'selected' : '' }}>{{ label }}</option>
{% endfor %}
</select>
</div>
<div class="col-lg-2 d-flex gap-2">
<button class="btn btn-outline-info w-100" type="submit">
Filtern
</button>
<a class="btn btn-outline-secondary" href="{{ path('admin_users_index') }}" title="Filter zurücksetzen">
<i class="bi bi-x-lg"></i>
</a>
</div>
</form>
</div>
</div>
<div class="card bg-black border-secondary shadow-sm">
<div class="card-body p-0">
<div class="d-flex justify-content-between align-items-center px-3 py-3 border-bottom border-secondary flex-wrap gap-2">
<div>
<strong class="text-info">Benutzer</strong>
<span class="small text-muted ms-2">{{ filtered_total }} von {{ total }} Einträgen</span>
</div>
<div class="small text-muted">Sortiert nach E-Mail.</div>
</div>
<div class="table-responsive">
<table class="table table-dark table-striped table-hover align-middle mb-0">
<thead class="table-secondary text-dark">
<tr>
<th>E-Mail</th>
<th>Status</th>
<th>Rollen</th>
<th>Erstellt</th>
<th>Aktualisiert</th>
<th class="text-end">Aktionen</th>
</tr>
</thead>
<tbody>
{% for user in users %}
<tr>
<td>
<div class="fw-semibold text-light">{{ user.email }}</div>
{% if app.user and user.id == app.user.id %}
<span class="badge bg-info text-dark mt-1">Du</span>
{% endif %}
</td>
<td>
{% if user.active %}
<span class="badge bg-success">Aktiv</span>
{% else %}
<span class="badge bg-warning text-dark">Inaktiv</span>
{% endif %}
</td>
<td>
<div class="d-flex flex-wrap gap-1">
{% for role, label in role_choices %}
{% if role in user.roles %}
<span class="badge {{ role == 'ROLE_SUPER_ADMIN' ? 'bg-danger' : 'bg-secondary' }}">{{ label }}</span>
{% endif %}
{% endfor %}
</div>
</td>
<td class="small text-muted">
{{ user.createdAt ? user.createdAt|date('d.m.Y H:i') : '—' }}
</td>
<td class="small text-muted">
{{ user.updatedAt ? user.updatedAt|date('d.m.Y H:i') : '—' }}
</td>
<td class="text-end">
<a href="{{ path('admin_users_edit', {id: user.id}) }}" class="btn btn-sm btn-outline-info me-1">
Bearbeiten
</a>
<form method="post"
action="{{ path('admin_users_toggle_active', {id: user.id}) }}"
class="d-inline"
onsubmit="return confirm('{{ user.active ? 'Benutzer wirklich deaktivieren?' : 'Benutzer wirklich aktivieren?' }}');">
<input type="hidden" name="_token" value="{{ csrf_token('admin_user_toggle_active_' ~ user.id) }}">
<button class="btn btn-sm {{ user.active ? 'btn-outline-warning' : 'btn-outline-success' }}">
{{ user.active ? 'Deaktivieren' : 'Aktivieren' }}
</button>
</form>
</td>
</tr>
{% else %}
<tr>
<td colspan="6" class="text-center py-4 text-muted">
Keine Benutzer gefunden.
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
{% endblock %}