Files
WebAPP/resources/views/admin/users/index.blade.php
Rhino 2e24a40d68 Stand: SMTP-Test, Admin-Mail-Tab, Notifiable-Fix, Lazy-Quill
- Fix: Notifiable-Trait zum User-Model hinzugefuegt (behebt notify()-500er)
- Installer: SMTP-Verbindungstest mit EsmtpTransport + Ueberspringen-Link
- Admin: Neuer E-Mail-Tab mit SMTP-Konfiguration + Verbindungstest
- Admin: Lazy Quill-Initialisierung (nur sichtbare Locale wird geladen)
- Uebersetzungen: 17 neue Mail-Keys in allen 6 Sprachen

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 07:30:37 +01:00

202 lines
15 KiB
PHP
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<x-layouts.admin :title="__('admin.users_title')">
<h1 class="text-2xl font-bold mb-6">{{ __('admin.users_title') }}</h1>
<div class="bg-white rounded-lg shadow overflow-hidden overflow-x-auto">
<table class="w-full text-sm">
<thead class="bg-gray-50 border-b">
<tr>
<th class="text-left px-4 py-3 font-medium text-gray-700">
<a href="{{ request()->fullUrlWithQuery(['sort' => 'name', 'direction' => ($sort === 'name' && $direction === 'asc') ? 'desc' : 'asc']) }}"
class="inline-flex items-center gap-1 hover:text-blue-600 {{ $sort === 'name' ? 'text-blue-600' : '' }}">
{{ __('ui.name') }}
@if ($sort === 'name')
<svg class="w-3 h-3" fill="currentColor" viewBox="0 0 20 20">
@if ($direction === 'asc')
<path fill-rule="evenodd" d="M5.293 9.707a1 1 0 010-1.414l4-4a1 1 0 011.414 0l4 4a1 1 0 01-1.414 1.414L10 6.414l-3.293 3.293a1 1 0 01-1.414 0z" clip-rule="evenodd"/>
@else
<path fill-rule="evenodd" d="M14.707 10.293a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 111.414-1.414L10 13.586l3.293-3.293a1 1 0 011.414 0z" clip-rule="evenodd"/>
@endif
</svg>
@endif
</a>
</th>
<th class="text-left px-4 py-3 font-medium text-gray-700">
<a href="{{ request()->fullUrlWithQuery(['sort' => 'email', 'direction' => ($sort === 'email' && $direction === 'asc') ? 'desc' : 'asc']) }}"
class="inline-flex items-center gap-1 hover:text-blue-600 {{ $sort === 'email' ? 'text-blue-600' : '' }}">
{{ __('ui.email') }}
@if ($sort === 'email')
<svg class="w-3 h-3" fill="currentColor" viewBox="0 0 20 20">
@if ($direction === 'asc')
<path fill-rule="evenodd" d="M5.293 9.707a1 1 0 010-1.414l4-4a1 1 0 011.414 0l4 4a1 1 0 01-1.414 1.414L10 6.414l-3.293 3.293a1 1 0 01-1.414 0z" clip-rule="evenodd"/>
@else
<path fill-rule="evenodd" d="M14.707 10.293a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 111.414-1.414L10 13.586l3.293-3.293a1 1 0 011.414 0z" clip-rule="evenodd"/>
@endif
</svg>
@endif
</a>
</th>
<th class="text-left px-4 py-3 font-medium text-gray-700">{{ __('admin.phone') }}</th>
<th class="text-center px-4 py-3 font-medium text-gray-700">
<a href="{{ request()->fullUrlWithQuery(['sort' => 'role', 'direction' => ($sort === 'role' && $direction === 'asc') ? 'desc' : 'asc']) }}"
class="inline-flex items-center gap-1 hover:text-blue-600 {{ $sort === 'role' ? 'text-blue-600' : '' }}">
{{ __('ui.role') }}
@if ($sort === 'role')
<svg class="w-3 h-3" fill="currentColor" viewBox="0 0 20 20">
@if ($direction === 'asc')
<path fill-rule="evenodd" d="M5.293 9.707a1 1 0 010-1.414l4-4a1 1 0 011.414 0l4 4a1 1 0 01-1.414 1.414L10 6.414l-3.293 3.293a1 1 0 01-1.414 0z" clip-rule="evenodd"/>
@else
<path fill-rule="evenodd" d="M14.707 10.293a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 111.414-1.414L10 13.586l3.293-3.293a1 1 0 011.414 0z" clip-rule="evenodd"/>
@endif
</svg>
@endif
</a>
</th>
<th class="text-left px-4 py-3 font-medium text-gray-700">{{ __('admin.children') }}</th>
<th class="text-center px-4 py-3 font-medium text-gray-700">{{ __('admin.dsgvo_short') }}</th>
<th class="text-center px-4 py-3 font-medium text-gray-700">
<a href="{{ request()->fullUrlWithQuery(['sort' => 'last_login_at', 'direction' => ($sort === 'last_login_at' && $direction === 'asc') ? 'desc' : 'asc']) }}"
class="inline-flex items-center gap-1 hover:text-blue-600 {{ $sort === 'last_login_at' ? 'text-blue-600' : '' }}">
{{ __('admin.last_login') }}
@if ($sort === 'last_login_at')
<svg class="w-3 h-3" fill="currentColor" viewBox="0 0 20 20">
@if ($direction === 'asc')
<path fill-rule="evenodd" d="M5.293 9.707a1 1 0 010-1.414l4-4a1 1 0 011.414 0l4 4a1 1 0 01-1.414 1.414L10 6.414l-3.293 3.293a1 1 0 01-1.414 0z" clip-rule="evenodd"/>
@else
<path fill-rule="evenodd" d="M14.707 10.293a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 111.414-1.414L10 13.586l3.293-3.293a1 1 0 011.414 0z" clip-rule="evenodd"/>
@endif
</svg>
@endif
</a>
</th>
<th class="text-center px-4 py-3 font-medium text-gray-700">
<a href="{{ request()->fullUrlWithQuery(['sort' => 'is_active', 'direction' => ($sort === 'is_active' && $direction === 'asc') ? 'desc' : 'asc']) }}"
class="inline-flex items-center gap-1 hover:text-blue-600 {{ $sort === 'is_active' ? 'text-blue-600' : '' }}">
{{ __('admin.status') }}
@if ($sort === 'is_active')
<svg class="w-3 h-3" fill="currentColor" viewBox="0 0 20 20">
@if ($direction === 'asc')
<path fill-rule="evenodd" d="M5.293 9.707a1 1 0 010-1.414l4-4a1 1 0 011.414 0l4 4a1 1 0 01-1.414 1.414L10 6.414l-3.293 3.293a1 1 0 01-1.414 0z" clip-rule="evenodd"/>
@else
<path fill-rule="evenodd" d="M14.707 10.293a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 111.414-1.414L10 13.586l3.293-3.293a1 1 0 011.414 0z" clip-rule="evenodd"/>
@endif
</svg>
@endif
</a>
</th>
<th class="text-right px-4 py-3 font-medium text-gray-700">{{ __('admin.actions') }}</th>
</tr>
</thead>
<tbody class="divide-y divide-gray-100">
@foreach ($users as $user)
<tr class="hover:bg-gray-50">
<td class="px-4 py-3 font-medium text-gray-900">
<div class="flex items-center gap-2">
<img src="{{ $user->getAvatarUrl() ?? asset('images/profil_empty.png') }}" alt="" class="w-7 h-7 rounded-full object-cover flex-shrink-0">
{{ $user->name }}
</div>
</td>
<td class="px-4 py-3 text-gray-600">{{ $user->email }}</td>
<td class="px-4 py-3 text-gray-600 text-sm whitespace-nowrap">
@if ($user->phone)
<a href="tel:{{ $user->phone }}" class="hover:text-blue-600">{{ $user->phone }}</a>
@else
<span class="text-gray-400"></span>
@endif
</td>
<td class="px-4 py-3 text-center">
@if ($user->id !== auth()->id())
<form method="POST" action="{{ route('admin.users.role', $user) }}" class="inline">
@csrf
@method('PUT')
<select name="role" onchange="this.form.submit()" class="text-xs border border-gray-300 rounded-md px-2 py-1">
<option value="user" {{ $user->role === \App\Enums\UserRole::User ? 'selected' : '' }}>{{ __('ui.enums.user_role.user') }}</option>
<option value="parent_rep" {{ $user->role === \App\Enums\UserRole::ParentRep ? 'selected' : '' }}>{{ __('ui.enums.user_role.parent_rep') }}</option>
<option value="coach" {{ $user->role === \App\Enums\UserRole::Coach ? 'selected' : '' }}>{{ __('ui.enums.user_role.coach') }}</option>
@if (auth()->user()->isAdmin())
<option value="admin" {{ $user->role === \App\Enums\UserRole::Admin ? 'selected' : '' }}>{{ __('ui.enums.user_role.admin') }}</option>
@endif
</select>
</form>
@else
<span class="text-xs font-medium text-gray-500">{{ __('ui.enums.user_role.' . $user->role->value) }} {{ __('admin.you_suffix') }}</span>
@endif
</td>
<td class="px-4 py-3 text-xs text-gray-600">
@foreach ($user->children as $child)
{{ $child->first_name }}@if (!$loop->last), @endif
@endforeach
@if ($user->children->isEmpty())
<span class="text-gray-400"></span>
@endif
</td>
<td class="px-4 py-3 text-center">
@if ($user->isDsgvoConfirmed())
<span class="inline-block px-2 py-0.5 rounded-full text-xs font-medium bg-green-100 text-green-800" title="{{ __('admin.dsgvo_confirmed_tooltip') }}">&#10003;</span>
@elseif ($user->hasDsgvoConsent())
<span class="inline-block px-2 py-0.5 rounded-full text-xs font-medium bg-yellow-100 text-yellow-800" title="{{ __('admin.dsgvo_pending_tooltip') }}">!</span>
@else
<span class="text-gray-400" title="{{ __('admin.dsgvo_missing_tooltip') }}"></span>
@endif
</td>
<td class="px-4 py-3 text-center text-xs text-gray-500">
{{ $user->last_login_at ? $user->last_login_at->diffForHumans() : __('admin.never') }}
</td>
<td class="px-4 py-3 text-center">
@if ($user->is_active)
<span class="inline-block px-2 py-0.5 rounded-full text-xs font-medium bg-green-100 text-green-800">{{ __('admin.active') }}</span>
@else
<span class="inline-block px-2 py-0.5 rounded-full text-xs font-medium bg-red-100 text-red-800">{{ __('admin.deactivated_label') }}</span>
@endif
</td>
<td class="px-4 py-3 text-right">
<a href="{{ route('admin.users.edit', $user) }}" class="text-xs text-blue-600 hover:text-blue-800">{{ __('admin.edit') }}</a>
</td>
</tr>
@endforeach
</tbody>
</table>
</div>
<div class="mt-4">{{ $users->links() }}</div>
{{-- Papierkorb --}}
@if ($trashedUsers->isNotEmpty())
<div class="mt-8">
<h2 class="text-lg font-semibold text-gray-700 mb-3">{{ __('admin.trash') }}</h2>
<div class="bg-white rounded-lg shadow overflow-hidden overflow-x-auto border border-red-200">
<table class="w-full text-sm">
<thead class="bg-red-50 border-b border-red-200">
<tr>
<th class="text-left px-4 py-3 font-medium text-gray-700">{{ __('ui.name') }}</th>
<th class="text-left px-4 py-3 font-medium text-gray-700">{{ __('ui.email') }}</th>
<th class="text-center px-4 py-3 font-medium text-gray-700">{{ __('admin.deleted_at') }}</th>
<th class="text-right px-4 py-3 font-medium text-gray-700">{{ __('admin.actions') }}</th>
</tr>
</thead>
<tbody class="divide-y divide-gray-100">
@foreach ($trashedUsers as $user)
<tr class="hover:bg-red-50/50">
<td class="px-4 py-3 font-medium text-gray-500">
<div class="flex items-center gap-2">
<img src="{{ $user->getAvatarUrl() ?? asset('images/profil_empty.png') }}" alt="" class="w-7 h-7 rounded-full object-cover flex-shrink-0 opacity-50">
{{ $user->name }}
</div>
</td>
<td class="px-4 py-3 text-gray-400">{{ $user->email }}</td>
<td class="px-4 py-3 text-center text-xs text-gray-500">{{ $user->deleted_at->diffForHumans() }}</td>
<td class="px-4 py-3 text-right">
<form method="POST" action="{{ route('admin.users.restore', $user->id) }}" class="inline">
@csrf
@method('PUT')
<button type="submit" class="text-xs text-green-600 hover:text-green-800 font-medium">{{ __('admin.restore') }}</button>
</form>
</td>
</tr>
@endforeach
</tbody>
</table>
</div>
</div>
@endif
</x-layouts.admin>