- PlayerPosition Enum (7 Handball-Positionen) mit Label/ShortLabel - Spielerstatistik pro Spiel (Tore, Würfe, TW-Paraden, Bemerkung) - Position-Dropdown in Spieler-Editor und Event-Stats-Formular - Statistik-Seite: TW zuerst, Trennlinie, Feldspieler, Position-Badges - Spielfeld-SVG mit Ampel-Performance (grün/gelb/rot) - Anklickbare Spieler im Spielfeld öffnen Detail-Modal - Fahrgemeinschaften (Anbieten, Zuordnen, Zurückziehen) - Übersetzungen in allen 6 Sprachen (de, en, pl, ru, ar, tr) - .gitignore für Laravel hinzugefügt - Demo-Daten mit Positionen und Statistiken Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
138 lines
4.9 KiB
PHP
Executable File
138 lines
4.9 KiB
PHP
Executable File
<?php
|
|
|
|
namespace App\Http\Controllers;
|
|
|
|
use App\Enums\EventStatus;
|
|
use App\Enums\EventType;
|
|
use App\Models\ActivityLog;
|
|
use App\Models\Event;
|
|
use App\Models\Setting;
|
|
use App\Models\Team;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\View\View;
|
|
|
|
class EventController extends Controller
|
|
{
|
|
public function index(Request $request): View
|
|
{
|
|
$user = auth()->user();
|
|
|
|
$query = Event::with(['team', 'participants'])
|
|
->withCount([
|
|
'caterings as caterings_yes_count' => fn ($q) => $q->where('status', 'yes'),
|
|
'timekeepers as timekeepers_yes_count' => fn ($q) => $q->where('status', 'yes'),
|
|
]);
|
|
|
|
// Admins sehen auch Entwürfe, Eltern nur published
|
|
if ($user->canAccessAdminPanel()) {
|
|
$teams = Team::where('is_active', true)->orderBy('name')->get();
|
|
} else {
|
|
$teamIds = $user->accessibleTeamIds();
|
|
$query->published()->whereIn('team_id', $teamIds);
|
|
$teams = Team::whereIn('id', $teamIds)->orderBy('name')->get();
|
|
}
|
|
|
|
// Filter: Team (nur Integer-IDs akzeptieren)
|
|
if ($request->filled('team_id')) {
|
|
$query->where('team_id', (int) $request->team_id);
|
|
}
|
|
|
|
// Filter: Typ (nur gueltige EventType-Werte)
|
|
if ($request->filled('type')) {
|
|
$validTypes = array_column(EventType::cases(), 'value');
|
|
if (in_array($request->type, $validTypes)) {
|
|
$query->where('type', $request->type);
|
|
}
|
|
}
|
|
|
|
// Filter: Zeitraum
|
|
if ($request->input('period') === 'past') {
|
|
$query->where('start_at', '<', now())->orderByDesc('start_at');
|
|
} else {
|
|
$query->where('start_at', '>=', now())->orderBy('start_at');
|
|
}
|
|
|
|
$events = $query->paginate(15)->withQueryString();
|
|
|
|
return view('events.index', compact('events', 'teams'));
|
|
}
|
|
|
|
public function show(Event $event): View
|
|
{
|
|
$user = auth()->user();
|
|
|
|
// Entwürfe nur für Admins
|
|
if ($event->status === EventStatus::Draft && !$user->canAccessAdminPanel()) {
|
|
abort(403);
|
|
}
|
|
|
|
// Kinder einmal laden, für Zugriffsprüfung + Teilnahme-Buttons
|
|
$userChildren = $user->children()->select('players.id', 'players.team_id', 'players.first_name', 'players.last_name')->get();
|
|
|
|
// Zugriffsbeschraenkung: User muss Zugang zum Team haben (ueber accessibleTeamIds)
|
|
if (!$user->canAccessAdminPanel()) {
|
|
$accessibleTeamIds = $user->accessibleTeamIds();
|
|
if (!$accessibleTeamIds->contains($event->team_id)) {
|
|
abort(403);
|
|
}
|
|
}
|
|
|
|
$event->syncParticipants($user->id);
|
|
|
|
$isMeeting = $event->type === EventType::Meeting;
|
|
|
|
$relations = ['team', 'comments.user', 'files.category'];
|
|
$relations[] = $isMeeting ? 'participants.user' : 'participants.player';
|
|
$relations[] = 'participants.setByUser';
|
|
if ($event->type->hasCatering()) {
|
|
$relations[] = 'caterings.user';
|
|
}
|
|
if ($event->type->hasTimekeepers()) {
|
|
$relations[] = 'timekeepers.user';
|
|
}
|
|
if ($event->type->hasCarpool()) {
|
|
$relations[] = 'carpools.driver';
|
|
$relations[] = 'carpools.passengers.player';
|
|
}
|
|
$event->load($relations);
|
|
|
|
$userChildIds = $userChildren->pluck('id');
|
|
|
|
// Eigener Catering-Status
|
|
$myCatering = $event->type->hasCatering()
|
|
? $event->caterings->where('user_id', $user->id)->first()
|
|
: null;
|
|
|
|
// Eigener Zeitnehmer-Status
|
|
$myTimekeeper = $event->type->hasTimekeepers()
|
|
? $event->timekeepers->where('user_id', $user->id)->first()
|
|
: null;
|
|
|
|
// Eigene Fahrgemeinschaft
|
|
$myCarpool = $event->type->hasCarpool()
|
|
? $event->carpools->where('user_id', $user->id)->first()
|
|
: null;
|
|
|
|
// Catering/Zeitnehmer-Verlauf für Staff (chronologische Statusänderungen)
|
|
$cateringHistory = collect();
|
|
$timekeeperHistory = collect();
|
|
|
|
if ($user->canAccessAdminPanel() && Setting::isFeatureVisibleFor('catering_history', $user)) {
|
|
$statusLogs = ActivityLog::where('model_type', 'Event')
|
|
->where('model_id', $event->id)
|
|
->where('action', 'status_changed')
|
|
->orderBy('created_at')
|
|
->get();
|
|
|
|
$cateringHistory = $statusLogs->filter(
|
|
fn ($log) => ($log->properties['new']['source'] ?? null) === 'catering'
|
|
);
|
|
$timekeeperHistory = $statusLogs->filter(
|
|
fn ($log) => ($log->properties['new']['source'] ?? null) === 'timekeeper'
|
|
);
|
|
}
|
|
|
|
return view('events.show', compact('event', 'userChildIds', 'userChildren', 'myCatering', 'myTimekeeper', 'myCarpool', 'cateringHistory', 'timekeeperHistory'));
|
|
}
|
|
}
|