Commit eea6ad2e authored by Mahmoud Aglan's avatar Mahmoud Aglan

Split attendance page: trainers on top, players below with role-based access

Trainers section (purple header) shows first with max 2-3 records.
Players section (blue header) shows below with full table.

Access control:
- Trainer account: can only mark their own attendance (others disabled)
- Supervisor/head_trainer (role level >= 60): can mark all trainers
Co-Authored-By: 's avatarClaude Opus 4.6 <noreply@anthropic.com>
parent 04dcc7e4
......@@ -11,6 +11,7 @@
use App\Domain\Participant\Models\Participant;
use App\Domain\Training\Models\Enrollment;
use App\Domain\Training\Models\TrainingSession;
use App\Models\User;
use Livewire\Attributes\Layout;
use Livewire\Attributes\Title;
use Livewire\Component;
......@@ -55,6 +56,11 @@ public function saveRecordNote(int $recordId): void
public function markAs(int $recordId, string $status, AttendanceMarkingService $service): void
{
$record = AttendanceRecord::findOrFail($recordId);
if (!$this->canMarkRecord($record)) {
return;
}
$statusEnum = AttendanceStatus::from($status);
$service->markStatus($record, $statusEnum, auth()->user());
}
......@@ -62,6 +68,11 @@ public function markAs(int $recordId, string $status, AttendanceMarkingService $
public function markPresent(int $recordId, AttendanceMarkingService $service): void
{
$record = AttendanceRecord::findOrFail($recordId);
if (!$this->canMarkRecord($record)) {
return;
}
$service->markPresent($record, auth()->user());
}
......@@ -72,9 +83,42 @@ public function markAllPresent(AttendanceMarkingService $service): void
->get();
foreach ($records as $record) {
if ($this->canMarkRecord($record)) {
$service->markPresent($record, auth()->user());
}
}
}
private function canMarkRecord(AttendanceRecord $record): bool
{
$user = auth()->user();
if ($record->subject_type === Participant::class) {
return true;
}
if ($record->subject_type === User::class) {
if ($this->canManageTrainers()) {
return true;
}
return $record->subject_id === $user->id;
}
return true;
}
private function canManageTrainers(): bool
{
$user = auth()->user();
if ($user->is_super_admin) {
return true;
}
$roleLevel = $user->roles->max('level') ?? 0;
return $roleLevel >= 60;
}
public function render()
{
......@@ -84,6 +128,10 @@ public function render()
->orderBy('status')
->get();
// Split into trainers and participants
$trainerRecords = $records->where('subject_type', User::class)->values();
$participantRecords = $records->where('subject_type', Participant::class)->values();
// Populate per-record notes from DB (only on first load or if not yet set)
foreach ($records as $record) {
if (!array_key_exists($record->id, $this->recordNotes)) {
......@@ -92,8 +140,7 @@ public function render()
}
// Detect unpaid/unrenewed participants for red highlight
$participantIds = $records
->where('subject_type', Participant::class)
$participantIds = $participantRecords
->pluck('subject_id')
->unique()
->toArray();
......@@ -130,11 +177,17 @@ public function render()
'excused' => $records->where('status', AttendanceStatus::Excused)->count(),
];
$canManageTrainers = $this->canManageTrainers();
return view('livewire.attendance.take-attendance', [
'trainerRecords' => $trainerRecords,
'participantRecords' => $participantRecords,
'records' => $records,
'summary' => $summary,
'statuses' => AttendanceStatus::cases(),
'notPaidParticipantIds' => $notPaidParticipantIds,
'canManageTrainers' => $canManageTrainers,
'currentUserId' => auth()->id(),
]);
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment