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>
This commit is contained in:
Rhino
2026-03-02 07:30:37 +01:00
commit 2e24a40d68
9633 changed files with 1300799 additions and 0 deletions

View File

@@ -0,0 +1,71 @@
<x-layouts.admin :title="__('admin.new_player')">
<h1 class="text-2xl font-bold mb-6">{{ __('admin.new_player') }}</h1>
<div class="bg-white rounded-lg shadow p-6 max-w-lg">
<form method="POST" action="{{ route('admin.players.store') }}">
@csrf
<div class="grid grid-cols-2 gap-4 mb-4">
<div>
<label for="first_name" class="block text-sm font-medium text-gray-700 mb-1">{{ __('admin.first_name') }} *</label>
<input type="text" name="first_name" id="first_name" value="{{ old('first_name') }}" required
class="w-full px-3 py-2 border border-gray-300 rounded-md @error('first_name') border-red-500 @enderror">
@error('first_name')<p class="mt-1 text-sm text-red-600">{{ $message }}</p>@enderror
</div>
<div>
<label for="last_name" class="block text-sm font-medium text-gray-700 mb-1">{{ __('admin.last_name') }} *</label>
<input type="text" name="last_name" id="last_name" value="{{ old('last_name') }}" required
class="w-full px-3 py-2 border border-gray-300 rounded-md @error('last_name') border-red-500 @enderror">
@error('last_name')<p class="mt-1 text-sm text-red-600">{{ $message }}</p>@enderror
</div>
</div>
<div class="mb-4">
<label for="team_id" class="block text-sm font-medium text-gray-700 mb-1">Team *</label>
<select name="team_id" id="team_id" required class="w-full px-3 py-2 border border-gray-300 rounded-md">
<option value="">{{ __('admin.please_select') }}</option>
@foreach ($teams as $team)
<option value="{{ $team->id }}" {{ old('team_id') == $team->id ? 'selected' : '' }}>{{ $team->name }}</option>
@endforeach
</select>
@error('team_id')<p class="mt-1 text-sm text-red-600">{{ $message }}</p>@enderror
</div>
<div class="grid grid-cols-2 gap-4 mb-4">
<div>
<label for="birth_year" class="block text-sm font-medium text-gray-700 mb-1">{{ __('admin.birth_year') }}</label>
<input type="number" name="birth_year" id="birth_year" value="{{ old('birth_year') }}" min="2000" max="2030"
class="w-full px-3 py-2 border border-gray-300 rounded-md">
</div>
<div>
<label for="jersey_number" class="block text-sm font-medium text-gray-700 mb-1">{{ __('admin.jersey_number') }}</label>
<input type="number" name="jersey_number" id="jersey_number" value="{{ old('jersey_number') }}" min="1" max="99"
class="w-full px-3 py-2 border border-gray-300 rounded-md">
</div>
</div>
<div class="mb-4 space-y-2">
<label class="flex items-center">
<input type="hidden" name="is_active" value="0">
<input type="checkbox" name="is_active" value="1" {{ old('is_active', '1') == '1' ? 'checked' : '' }} class="rounded border-gray-300 mr-2">
<span class="text-sm text-gray-700">{{ __('admin.active') }}</span>
</label>
<label class="flex items-center">
<input type="hidden" name="photo_permission" value="0">
<input type="checkbox" name="photo_permission" value="1" {{ old('photo_permission') ? 'checked' : '' }} class="rounded border-gray-300 mr-2">
<span class="text-sm text-gray-700">{{ __('admin.photo_permission') }}</span>
</label>
</div>
<div class="mb-4">
<label for="notes" class="block text-sm font-medium text-gray-700 mb-1">{{ __('admin.notes') }}</label>
<textarea name="notes" id="notes" rows="2" class="w-full px-3 py-2 border border-gray-300 rounded-md">{{ old('notes') }}</textarea>
</div>
<div class="flex items-center gap-3">
<button type="submit" class="bg-blue-600 text-white px-4 py-2 rounded-md hover:bg-blue-700 text-sm font-medium">{{ __('ui.create') }}</button>
<a href="{{ route('admin.players.index') }}" class="text-sm text-gray-600 hover:underline">{{ __('ui.cancel') }}</a>
</div>
</form>
</div>
</x-layouts.admin>

View File

@@ -0,0 +1,192 @@
<x-layouts.admin :title="__('admin.players_title')">
<h1 class="text-2xl font-bold mb-6">{{ __('admin.players_title') }}: {{ $player->full_name }}</h1>
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
{{-- Spieler-Daten --}}
<div class="bg-white rounded-lg shadow p-6">
<h2 class="font-semibold mb-4">{{ __('admin.player_data') }}</h2>
<form method="POST" action="{{ route('admin.players.update', $player) }}" enctype="multipart/form-data">
@csrf
@method('PUT')
{{-- Profilbild --}}
<div class="mb-5" x-data="{ preview: null }">
<label class="block text-sm font-medium text-gray-700 mb-2">{{ __('admin.profile_picture') }}</label>
<div class="flex items-center gap-4">
<div class="relative">
@if ($player->getAvatarUrl())
<img src="{{ $player->getAvatarUrl() }}" alt="{{ $player->full_name }}" class="w-14 h-14 rounded-full object-cover border-2 border-gray-200" x-show="!preview">
@else
<div class="w-14 h-14 rounded-full bg-gray-100 flex items-center justify-center text-gray-500 font-semibold border-2 border-gray-200" x-show="!preview">
{{ $player->getInitials() }}
</div>
@endif
<img :src="preview" x-show="preview" class="w-14 h-14 rounded-full object-cover border-2 border-blue-400" x-cloak>
</div>
<div class="flex flex-col gap-1">
<label class="cursor-pointer bg-gray-100 text-gray-700 px-3 py-1.5 rounded-md text-xs hover:bg-gray-200 inline-block">
{{ __('admin.upload_picture') }}
<input type="file" name="profile_picture" accept="image/jpeg,image/png,image/gif,image/webp" class="hidden"
@change="if ($event.target.files[0]) { preview = URL.createObjectURL($event.target.files[0]) }">
</label>
<span class="text-xs text-gray-400">{{ __('admin.max_picture_size') }}</span>
@error('profile_picture')
<p class="text-red-600 text-xs">{{ $message }}</p>
@enderror
</div>
</div>
</div>
<div class="grid grid-cols-2 gap-4 mb-4">
<div>
<label for="first_name" class="block text-sm font-medium text-gray-700 mb-1">{{ __('admin.first_name') }} *</label>
<input type="text" name="first_name" id="first_name" value="{{ old('first_name', $player->first_name) }}" required
class="w-full px-3 py-2 border border-gray-300 rounded-md @error('first_name') border-red-500 @enderror">
@error('first_name')<p class="mt-1 text-sm text-red-600">{{ $message }}</p>@enderror
</div>
<div>
<label for="last_name" class="block text-sm font-medium text-gray-700 mb-1">{{ __('admin.last_name') }} *</label>
<input type="text" name="last_name" id="last_name" value="{{ old('last_name', $player->last_name) }}" required
class="w-full px-3 py-2 border border-gray-300 rounded-md @error('last_name') border-red-500 @enderror">
@error('last_name')<p class="mt-1 text-sm text-red-600">{{ $message }}</p>@enderror
</div>
</div>
<div class="mb-4">
<label for="team_id" class="block text-sm font-medium text-gray-700 mb-1">Team *</label>
<select name="team_id" id="team_id" required class="w-full px-3 py-2 border border-gray-300 rounded-md">
@foreach ($teams as $team)
<option value="{{ $team->id }}" {{ old('team_id', $player->team_id) == $team->id ? 'selected' : '' }}>{{ $team->name }}</option>
@endforeach
</select>
</div>
<div class="grid grid-cols-2 gap-4 mb-4">
<div>
<label for="birth_year" class="block text-sm font-medium text-gray-700 mb-1">{{ __('admin.birth_year') }}</label>
<input type="number" name="birth_year" id="birth_year" value="{{ old('birth_year', $player->birth_year) }}" min="2000" max="2030"
class="w-full px-3 py-2 border border-gray-300 rounded-md">
</div>
<div>
<label for="jersey_number" class="block text-sm font-medium text-gray-700 mb-1">{{ __('admin.jersey_number') }}</label>
<input type="number" name="jersey_number" id="jersey_number" value="{{ old('jersey_number', $player->jersey_number) }}" min="1" max="99"
class="w-full px-3 py-2 border border-gray-300 rounded-md">
</div>
</div>
<div class="mb-4">
<label class="flex items-center">
<input type="hidden" name="photo_permission" value="0">
<input type="checkbox" name="photo_permission" value="1" {{ old('photo_permission', $player->photo_permission) ? 'checked' : '' }} class="rounded border-gray-300 mr-2">
<span class="text-sm text-gray-700">{{ __('admin.photo_permission') }}</span>
</label>
</div>
<div class="mb-4">
<label for="notes" class="block text-sm font-medium text-gray-700 mb-1">{{ __('admin.notes') }}</label>
<textarea name="notes" id="notes" rows="2" class="w-full px-3 py-2 border border-gray-300 rounded-md">{{ old('notes', $player->notes) }}</textarea>
</div>
<button type="submit" class="bg-blue-600 text-white px-4 py-2 rounded-md hover:bg-blue-700 text-sm font-medium">{{ __('ui.save') }}</button>
</form>
@if ($player->getAvatarUrl())
<div class="mt-3 pt-3 border-t">
<form method="POST" action="{{ route('admin.players.remove-picture', $player) }}" class="inline" onsubmit="return confirm(@js(__('admin.confirm_delete_file')))">
@csrf
@method('DELETE')
<button type="submit" class="text-xs text-red-500 hover:text-red-700">{{ __('admin.remove_picture') }}</button>
</form>
</div>
@endif
</div>
{{-- Eltern-Zuordnung --}}
<div class="bg-white rounded-lg shadow p-6">
<h2 class="font-semibold mb-4">{{ __('admin.parent_assignment') }}</h2>
@if ($player->parents->isNotEmpty())
<div class="mb-4 space-y-2">
@foreach ($player->parents as $parent)
<div class="flex items-center justify-between bg-gray-50 rounded px-3 py-2">
<div>
<span class="font-medium text-sm">{{ $parent->name }}</span>
@if ($parent->pivot->relationship_label)
<span class="text-xs text-gray-500">({{ $parent->pivot->relationship_label }})</span>
@endif
<span class="text-xs text-gray-400 block">{{ $parent->email }}</span>
</div>
<form method="POST" action="{{ route('admin.players.remove-parent', [$player, $parent]) }}" onsubmit="return confirm(@js(__('admin.confirm_remove_parent')))">
@csrf
@method('DELETE')
<button type="submit" class="text-red-500 hover:text-red-700 text-xs">{{ __('admin.remove') }}</button>
</form>
</div>
@endforeach
</div>
@else
<p class="text-sm text-gray-500 mb-4">{{ __('admin.no_parents_yet') }}</p>
@endif
<form method="POST" action="{{ route('admin.players.assign-parent', $player) }}" class="border-t pt-4">
@csrf
<div class="mb-3">
<label for="parent_id" class="block text-sm font-medium text-gray-700 mb-1">{{ __('admin.add_parent') }}</label>
<select name="parent_id" id="parent_id" required class="w-full px-3 py-2 border border-gray-300 rounded-md text-sm">
<option value="">{{ __('admin.select_user') }}</option>
@foreach ($users as $user)
<option value="{{ $user->id }}">{{ $user->name }} ({{ $user->email }})</option>
@endforeach
</select>
</div>
<div class="mb-3">
<label for="relationship_label" class="block text-sm font-medium text-gray-700 mb-1">{{ __('admin.relationship_label') }}</label>
<input type="text" name="relationship_label" id="relationship_label" placeholder="{{ __('admin.relationship_placeholder') }}"
class="w-full px-3 py-2 border border-gray-300 rounded-md text-sm">
</div>
<button type="submit" class="bg-gray-800 text-white px-3 py-1.5 rounded-md hover:bg-gray-900 text-sm">{{ __('admin.assign') }}</button>
</form>
</div>
</div>
{{-- Spieler deaktivieren / löschen --}}
<div class="mt-6 bg-white rounded-lg shadow p-6 border border-red-200">
<h2 class="font-semibold text-red-700 mb-2">{{ __('admin.danger_zone') }}</h2>
{{-- Deaktivieren / Aktivieren --}}
<div class="flex items-center justify-between py-3">
<div>
<p class="text-sm font-medium text-gray-900">{{ __('admin.player_status_label') }}</p>
<p class="text-xs text-gray-500">
{{ $player->is_active ? __('admin.deactivate_player_hint') : __('admin.activate_player_hint') }}
</p>
</div>
<form method="POST" action="{{ route('admin.players.toggle-active', $player) }}">
@csrf
@method('PUT')
<button type="submit" class="px-4 py-2 rounded-md text-sm font-medium {{ $player->is_active ? 'bg-yellow-500 text-white hover:bg-yellow-600' : 'bg-green-600 text-white hover:bg-green-700' }}">
{{ $player->is_active ? __('admin.deactivate') : __('admin.activate') }}
</button>
</form>
</div>
{{-- Löschen --}}
<div class="flex items-center justify-between py-3 border-t border-red-100">
<div>
<p class="text-sm font-medium text-gray-900">{{ __('admin.delete_player') }}</p>
<p class="text-xs text-gray-500">{{ __('admin.delete_player_hint') }}</p>
</div>
<form method="POST" action="{{ route('admin.players.destroy', $player) }}" onsubmit="return confirm(@js(__('admin.confirm_delete_player')))">
@csrf
@method('DELETE')
<button type="submit" class="bg-red-600 text-white px-4 py-2 rounded-md hover:bg-red-700 text-sm font-medium">
{{ __('admin.delete') }}
</button>
</form>
</div>
</div>
<div class="mt-4">
<a href="{{ route('admin.players.index') }}" class="text-sm text-gray-600 hover:underline">{{ __('admin.back_to_list') }}</a>
</div>
</x-layouts.admin>

View File

@@ -0,0 +1,231 @@
<x-layouts.admin :title="__('admin.players_title')">
<div class="flex justify-between items-center mb-6">
<h1 class="text-2xl font-bold">{{ __('admin.players_title') }}</h1>
<a href="{{ route('admin.players.create') }}" class="bg-blue-600 text-white px-4 py-2 rounded-md hover:bg-blue-700 text-sm font-medium">
{{ __('admin.new_player') }}
</a>
</div>
{{-- Filter --}}
<form method="GET" class="mb-4">
@if (request('sort'))
<input type="hidden" name="sort" value="{{ request('sort') }}">
<input type="hidden" name="direction" value="{{ request('direction') }}">
@endif
<select name="team_id" onchange="this.form.submit()" class="px-3 py-2 border border-gray-300 rounded-md text-sm">
<option value="">{{ __('ui.all_teams') }}</option>
@foreach ($teams as $team)
<option value="{{ $team->id }}" {{ request('team_id') == $team->id ? 'selected' : '' }}>{{ $team->name }}</option>
@endforeach
</select>
</form>
<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' => 'team', 'direction' => ($sort === 'team' && $direction === 'asc') ? 'desc' : 'asc']) }}"
class="inline-flex items-center gap-1 hover:text-blue-600 {{ $sort === 'team' ? 'text-blue-600' : '' }}">
{{ __('admin.nav_teams') }}
@if ($sort === 'team')
<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' => 'jersey_number', 'direction' => ($sort === 'jersey_number' && $direction === 'asc') ? 'desc' : 'asc']) }}"
class="inline-flex items-center gap-1 hover:text-blue-600 {{ $sort === 'jersey_number' ? 'text-blue-600' : '' }}">
{{ __('admin.nr') }}
@if ($sort === 'jersey_number')
<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.parents') }}</th>
<th class="text-center px-4 py-3 font-medium text-gray-700">{{ __('admin.photo') }}</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.action') }}</th>
</tr>
</thead>
<tbody class="divide-y divide-gray-100">
@forelse ($players as $player)
<tr class="hover:bg-gray-50" x-data="playerRow({{ $player->id }}, '{{ $player->team_id }}', '{{ $player->photo_permission ? 1 : 0 }}')">
<td class="px-4 py-3 font-medium text-gray-900">
<a href="{{ route('admin.players.edit', $player) }}" class="flex items-center gap-2 hover:underline">
<img src="{{ $player->getAvatarUrl() ?? asset('images/profil_empty.png') }}" alt="" class="w-7 h-7 rounded-full object-cover flex-shrink-0">
{{ $player->full_name }}
</a>
</td>
<td class="px-4 py-3">
<select
x-model="teamId"
@change="save({ team_id: teamId })"
class="px-2 py-1 border border-gray-200 rounded text-xs bg-white focus:ring-1 focus:ring-blue-500 focus:border-blue-500"
>
@foreach ($teams as $team)
<option value="{{ $team->id }}" {{ $player->team_id == $team->id ? 'selected' : '' }}>{{ $team->name }}</option>
@endforeach
</select>
</td>
<td class="px-4 py-3 text-center text-gray-600">{{ $player->jersey_number ?? '' }}</td>
<td class="px-4 py-3 text-gray-600 text-xs">
@foreach ($player->parents as $parent)
{{ $parent->name }}{{ $parent->pivot->relationship_label ? " ({$parent->pivot->relationship_label})" : '' }}@if (!$loop->last), @endif
@endforeach
@if ($player->parents->isEmpty())
<span class="text-gray-400"></span>
@endif
</td>
<td class="px-4 py-3 text-center">
<select
x-model="photo"
@change="save({ photo_permission: photo })"
class="px-2 py-1 border border-gray-200 rounded text-xs bg-white focus:ring-1 focus:ring-blue-500 focus:border-blue-500"
:class="photo == '1' ? 'text-green-700' : 'text-red-600'"
>
<option value="1" {{ $player->photo_permission ? 'selected' : '' }}>{{ __('ui.yes') }}</option>
<option value="0" {{ !$player->photo_permission ? 'selected' : '' }}>{{ __('ui.no') }}</option>
</select>
</td>
<td class="px-4 py-3 text-center">
@if ($player->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.inactive') }}</span>
@endif
</td>
<td class="px-4 py-3 text-right space-x-2">
<span x-show="saving" class="text-xs text-gray-400">...</span>
<span x-show="saved" x-cloak class="text-xs text-green-600">&#10003;</span>
<a x-show="!saving && !saved" href="{{ route('admin.players.edit', $player) }}" class="text-blue-600 hover:underline text-sm">{{ __('ui.edit') }}</a>
</td>
</tr>
@empty
<tr>
<td colspan="7" class="px-4 py-8 text-center text-gray-500">{{ __('admin.no_players_yet') }}</td>
</tr>
@endforelse
</tbody>
</table>
</div>
<div class="mt-4">{{ $players->links() }}</div>
{{-- Papierkorb --}}
@if ($trashedPlayers->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">{{ __('admin.nav_teams') }}</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 ($trashedPlayers as $player)
<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="{{ $player->getAvatarUrl() ?? asset('images/profil_empty.png') }}" alt="" class="w-7 h-7 rounded-full object-cover flex-shrink-0 opacity-50">
{{ $player->full_name }}
</div>
</td>
<td class="px-4 py-3 text-gray-400">{{ $player->team?->name ?? '' }}</td>
<td class="px-4 py-3 text-center text-xs text-gray-500">{{ $player->deleted_at->diffForHumans() }}</td>
<td class="px-4 py-3 text-right">
<form method="POST" action="{{ route('admin.players.restore', $player->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
@push('scripts')
<script>
function playerRow(playerId, initialTeam, initialPhoto) {
return {
teamId: initialTeam,
photo: initialPhoto,
saving: false,
saved: false,
async save(data) {
this.saving = true;
this.saved = false;
try {
const res = await fetch(`/admin/players/${playerId}/quick-update`, {
method: 'PATCH',
headers: {
'Content-Type': 'application/json',
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').content,
'Accept': 'application/json',
},
body: JSON.stringify(data),
});
if (res.ok) {
this.saved = true;
setTimeout(() => this.saved = false, 1500);
}
} catch (e) {
console.error(e);
} finally {
this.saving = false;
}
}
};
}
</script>
@endpush
</x-layouts.admin>