Files
WebAPP/resources/views/admin/events/index.blade.php
Rhino 8ccadbe89f Feature-Toggles, Administration, wiederkehrende Events und Event-Serien
- Administration & Rollenmanagement: Neuer Admin-Bereich mit Feature-Toggles
  und Sichtbarkeitseinstellungen pro Rolle (11 Toggles, 24 Visibility-Settings)
- AdministrationController mit eigenem Settings-Tab, aus SettingsController extrahiert
- Feature-Toggle-Guards in Controllers (Invitation, File, ListGenerator, Comment)
  und Views (events/show, events/edit, events/create)
- Setting::isFeatureEnabled() und isFeatureVisibleFor() Hilfsmethoden
- Wiederkehrende Trainings: Täglich/Wöchentlich/2-Wöchentlich mit Ende per
  Datum oder Anzahl (max. 52), Vorschau im Formular
- Event-Serien: Verknüpfung über event_series_id (UUID), Modal-Dialog beim
  Speichern und Löschen mit Optionen "nur dieses" / "alle folgenden"
- Löschen-Button direkt in der Event-Bearbeitung mit Serien-Dialog
- DemoDataSeeder: 4 Trainings als Serie mit gemeinsamer event_series_id
- Übersetzungen in allen 6 Sprachen (de, en, pl, ru, ar, tr)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 08:38:45 +01:00

157 lines
10 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.events_title')">
<div class="flex justify-between items-center mb-6">
<h1 class="text-2xl font-bold">{{ __('admin.events_title') }}</h1>
<a href="{{ route('admin.events.create') }}" class="bg-blue-600 text-white px-4 py-2 rounded-md hover:bg-blue-700 text-sm font-medium">
{{ __('admin.new_event') }}
</a>
</div>
{{-- Filter --}}
<form method="GET" class="mb-4 flex flex-wrap gap-3">
<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>
<select name="status" onchange="this.form.submit()" class="px-3 py-2 border border-gray-300 rounded-md text-sm">
<option value="">{{ __('admin.all_status') }}</option>
@foreach (\App\Enums\EventStatus::cases() as $status)
<option value="{{ $status->value }}" {{ request('status') === $status->value ? 'selected' : '' }}>{{ $status->label() }}</option>
@endforeach
</select>
@if ($seasons->isNotEmpty())
<select name="season_id" onchange="this.form.submit()" class="px-3 py-2 border border-gray-300 rounded-md text-sm">
<option value="">{{ __('admin.all_seasons') }}</option>
@foreach ($seasons as $season)
<option value="{{ $season->id }}" {{ request('season_id') == $season->id ? 'selected' : '' }}>{{ $season->name }}{{ $season->is_current ? ' ●' : '' }}</option>
@endforeach
</select>
@endif
</form>
{{-- Event-Karten --}}
@forelse ($events as $event)
@php
$minStatus = $event->minimumsStatus();
$bgClass = match($minStatus) { true => 'bg-green-50 border-green-200', false => 'bg-red-50 border-red-200', default => 'bg-white border-gray-200' };
@endphp
<div class="{{ $bgClass }} border rounded-lg shadow-sm p-4 mb-3">
<div class="flex flex-col lg:flex-row lg:items-center gap-4">
{{-- Links: Typ, Team, Titel, Datum, Ort, Status --}}
<div class="flex-1 min-w-0">
<div class="flex items-center gap-2 mb-1 flex-wrap">
<x-event-type-badge :type="$event->type" />
<span class="text-xs text-gray-500">{{ $event->team->name }}</span>
@if ($event->status === \App\Enums\EventStatus::Published)
<span class="inline-block px-2 py-0.5 rounded-full text-xs font-medium bg-green-100 text-green-800">{{ $event->status->label() }}</span>
@elseif ($event->status === \App\Enums\EventStatus::Cancelled)
<span class="inline-block px-2 py-0.5 rounded-full text-xs font-medium bg-red-100 text-red-800">{{ $event->status->label() }}</span>
@else
<span class="inline-block px-2 py-0.5 rounded-full text-xs font-medium bg-gray-100 text-gray-600">{{ $event->status->label() }}</span>
@endif
</div>
<h3 class="font-semibold text-gray-900 {{ $event->status === \App\Enums\EventStatus::Cancelled ? 'line-through text-gray-400' : '' }}">
{{ $event->title }}
</h3>
<p class="text-sm text-gray-600">
{{ $event->start_at->translatedFormat(__('ui.date_format')) }} {{ __('ui.clock') }}
@if ($event->end_at)
{{ $event->end_at->format('H:i') }} {{ __('ui.clock') }}
@endif
</p>
@if ($event->location_name)
<p class="text-sm text-gray-500">{{ $event->location_name }}</p>
@endif
</div>
{{-- Mitte: Ampel-Boxen --}}
<div class="shrink-0">
<x-event-status-boxes :event="$event" />
</div>
{{-- Rechts: Aktionen --}}
<div class="shrink-0 text-right">
<div class="flex items-center justify-end gap-2">
<a href="{{ route('admin.events.edit', $event) }}" class="text-blue-600 hover:underline text-sm">{{ __('ui.edit') }}</a>
@if ($event->isPartOfSeries())
<div x-data="{ showDeleteModal: false }" class="inline">
<button @click="showDeleteModal = true" class="text-red-600 hover:text-red-800 text-sm">{{ __('ui.delete') }}</button>
<div x-show="showDeleteModal" x-cloak class="fixed inset-0 z-50 flex items-center justify-center bg-black/50" @keydown.escape.window="showDeleteModal = false">
<div class="bg-white rounded-lg shadow-lg p-6 max-w-sm mx-4" @click.outside="showDeleteModal = false">
<h3 class="font-semibold text-gray-900 mb-2">{{ __('admin.delete_series_title') }}</h3>
<p class="text-sm text-gray-600 mb-4">{{ __('admin.delete_series_description') }}</p>
<div class="flex flex-col gap-2">
<form method="POST" action="{{ route('admin.events.destroy', $event) }}">
@csrf @method('DELETE')
<button type="submit" class="w-full text-left px-3 py-2 text-sm bg-gray-100 hover:bg-gray-200 rounded-md">{{ __('admin.delete_only_this') }}</button>
</form>
<form method="POST" action="{{ route('admin.events.destroy', $event) }}">
@csrf @method('DELETE')
<input type="hidden" name="delete_following" value="1">
<button type="submit" class="w-full text-left px-3 py-2 text-sm bg-red-100 hover:bg-red-200 text-red-700 rounded-md">{{ __('admin.delete_this_and_following') }}</button>
</form>
<button @click="showDeleteModal = false" class="text-sm text-gray-500 hover:underline mt-1">{{ __('ui.cancel') }}</button>
</div>
</div>
</div>
</div>
@else
<form method="POST" action="{{ route('admin.events.destroy', $event) }}" class="inline" onsubmit="return confirm(@js(__('admin.confirm_delete_event')))">
@csrf
@method('DELETE')
<button type="submit" class="text-red-600 hover:text-red-800 text-sm">{{ __('ui.delete') }}</button>
</form>
@endif
</div>
</div>
</div>
</div>
@empty
<div class="bg-white rounded-lg shadow p-8 text-center text-gray-500">
{{ __('admin.no_events_yet') }}
</div>
@endforelse
<div class="mt-4">{{ $events->links() }}</div>
{{-- Papierkorb --}}
@if ($trashedEvents->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">{{ __('admin.event_title') }}</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 ($trashedEvents as $event)
<tr class="hover:bg-red-50/50">
<td class="px-4 py-3 font-medium text-gray-500">{{ $event->title }}</td>
<td class="px-4 py-3 text-gray-400">{{ $event->team?->name ?? '' }}</td>
<td class="px-4 py-3 text-center text-xs text-gray-500">{{ $event->deleted_at->diffForHumans() }}</td>
<td class="px-4 py-3 text-right">
@if ($event->isRestorable())
<form method="POST" action="{{ route('admin.events.restore', $event->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>
@else
<span class="text-xs text-gray-400">{{ __('admin.restore_expired') }}</span>
@endif
</td>
</tr>
@endforeach
</tbody>
</table>
</div>
</div>
@endif
</x-layouts.admin>