feat: portal cross-event my-shifts endpoint and dashboard page
GET /portal/my-shifts aggregates shift assignments across all events the logged-in user is linked to via Person records. Groups by event then date, showing only active assignments (approved/pending_approval) for approved/pending persons. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -5,6 +5,7 @@ declare(strict_types=1);
|
||||
namespace App\Http\Controllers\Api\V1\Portal;
|
||||
|
||||
use App\Enums\CancellationSource;
|
||||
use App\Enums\PersonStatus;
|
||||
use App\Enums\ShiftAssignmentStatus;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Event;
|
||||
@@ -23,6 +24,98 @@ final class PortalShiftController extends Controller
|
||||
private readonly ShiftAssignmentService $shiftAssignmentService,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* All shifts across all events for the logged-in user.
|
||||
* Groups by event → date, only includes active assignments.
|
||||
*/
|
||||
public function allMyShifts(Request $request): JsonResponse
|
||||
{
|
||||
$user = $request->user();
|
||||
|
||||
// Find all person records linked to this user (across all events).
|
||||
// OrganisationScope is a no-op here since no org/event route param exists.
|
||||
$personIds = Person::where('user_id', $user->id)
|
||||
->whereIn('status', [
|
||||
PersonStatus::APPROVED->value,
|
||||
PersonStatus::PENDING->value,
|
||||
])
|
||||
->pluck('id');
|
||||
|
||||
if ($personIds->isEmpty()) {
|
||||
return $this->success([]);
|
||||
}
|
||||
|
||||
$assignments = ShiftAssignment::whereIn('person_id', $personIds)
|
||||
->active()
|
||||
->with([
|
||||
'shift.festivalSection',
|
||||
'shift.timeSlot',
|
||||
'shift.location',
|
||||
'person.event',
|
||||
])
|
||||
->get()
|
||||
->sortBy(fn (ShiftAssignment $a) => $a->shift->timeSlot->date->format('Y-m-d') . ' ' .
|
||||
Carbon::parse($a->shift->timeSlot->start_time)->format('H:i'))
|
||||
->values();
|
||||
|
||||
$grouped = $assignments
|
||||
->groupBy(fn (ShiftAssignment $a) => $a->person->event_id)
|
||||
->map(function ($eventAssignments) {
|
||||
$event = $eventAssignments->first()->person->event;
|
||||
|
||||
return [
|
||||
'event' => [
|
||||
'id' => $event->id,
|
||||
'name' => $event->name,
|
||||
'start_date' => $event->start_date->format('Y-m-d'),
|
||||
'end_date' => $event->end_date->format('Y-m-d'),
|
||||
],
|
||||
'assignments' => $eventAssignments
|
||||
->groupBy(fn (ShiftAssignment $a) => $a->shift->timeSlot->date->format('Y-m-d'))
|
||||
->map(function ($dateAssignments, string $date) {
|
||||
$carbonDate = Carbon::parse($date);
|
||||
|
||||
return [
|
||||
'date' => $date,
|
||||
'date_label' => ucfirst($carbonDate->translatedFormat('l j F')),
|
||||
'shifts' => $dateAssignments->map(function (ShiftAssignment $a) {
|
||||
$shift = $a->shift;
|
||||
$timeSlot = $shift->timeSlot;
|
||||
|
||||
return [
|
||||
'id' => $a->id,
|
||||
'status' => $a->status->value,
|
||||
'shift' => [
|
||||
'id' => $shift->id,
|
||||
'title' => $shift->title ?? $shift->festivalSection->name,
|
||||
'section_name' => $shift->festivalSection->name,
|
||||
'section_icon' => $shift->festivalSection->icon,
|
||||
'time_slot_name' => $timeSlot->name,
|
||||
'date' => $timeSlot->date->format('Y-m-d'),
|
||||
'start_time' => Carbon::parse($shift->actual_start_time ?? $timeSlot->start_time)->format('H:i'),
|
||||
'end_time' => Carbon::parse($shift->actual_end_time ?? $timeSlot->end_time)->format('H:i'),
|
||||
'report_time' => $shift->report_time
|
||||
? Carbon::parse($shift->report_time)->format('H:i')
|
||||
: null,
|
||||
'location' => $shift->location ? [
|
||||
'name' => $shift->location->name,
|
||||
'address' => $shift->location->address,
|
||||
] : null,
|
||||
],
|
||||
];
|
||||
})->values()->all(),
|
||||
];
|
||||
})
|
||||
->values()
|
||||
->all(),
|
||||
];
|
||||
})
|
||||
->values()
|
||||
->all();
|
||||
|
||||
return $this->success($grouped);
|
||||
}
|
||||
|
||||
public function availableShifts(Request $request, Event $event): JsonResponse
|
||||
{
|
||||
$person = $this->resolvePerson($event);
|
||||
|
||||
Reference in New Issue
Block a user