feat(api): extend registration endpoints with dynamic fields and section preferences

- PublicRegistrationData now returns registration_fields (portal-visible only),
  form toggles, and available_tags for tag_picker fields
- Volunteer registration accepts field_values and section_preferences with
  festival_section_id, processed via existing services
- PortalMe eager-loads fieldValues and sectionPreferences
- Section preferences now use the proper relational table instead of custom_fields JSON

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-12 23:44:26 +02:00
parent a9dcee0fc7
commit 73c8e6c466
6 changed files with 395 additions and 9 deletions

View File

@@ -0,0 +1,42 @@
<?php
declare(strict_types=1);
namespace App\Http\Controllers\Api\V1;
use App\Http\Controllers\Controller;
use App\Http\Requests\Api\V1\PortalMeRequest;
use App\Http\Resources\Api\V1\PersonResource;
use App\Models\Event;
use App\Models\Person;
use Illuminate\Http\JsonResponse;
final class PortalMeController extends Controller
{
public function index(PortalMeRequest $request): JsonResponse
{
$event = Event::findOrFail($request->validated('event_id'));
if ($event->isSubEvent()) {
$event = $event->parent;
}
$person = Person::where('user_id', $request->user()->id)
->where('event_id', $event->id)
->with([
'crowdType',
'shiftAssignments.shift.festivalSection',
'shiftAssignments.shift.timeSlot',
'volunteerAvailabilities.timeSlot',
'fieldValues.registrationFormField',
'sectionPreferences.festivalSection',
])
->first();
if (! $person) {
return $this->notFound('No registration found for this event');
}
return $this->success(new PersonResource($person));
}
}

View File

@@ -7,6 +7,8 @@ namespace App\Http\Controllers\Api\V1;
use App\Http\Controllers\Controller;
use App\Models\Event;
use App\Models\FestivalSection;
use App\Models\PersonTag;
use App\Models\RegistrationFormField;
use App\Models\TimeSlot;
use Illuminate\Http\JsonResponse;
@@ -52,6 +54,13 @@ final class PublicRegistrationDataController extends Controller
->where('person_type', 'VOLUNTEER')
->values();
$registrationFields = RegistrationFormField::where('event_id', $festivalEvent->id)
->portalVisible()
->ordered()
->get();
$organisationId = $festivalEvent->organisation_id;
return response()->json([
'data' => [
'event' => [
@@ -59,10 +68,12 @@ final class PublicRegistrationDataController extends Controller
'name' => $festivalEvent->name,
'start_date' => $festivalEvent->start_date->toDateString(),
'end_date' => $festivalEvent->end_date->toDateString(),
'organisation_id' => $festivalEvent->organisation_id,
'organisation_id' => $organisationId,
'registration_banner_url' => $festivalEvent->registration_banner_url,
'registration_welcome_text' => $festivalEvent->registration_welcome_text,
'registration_logo_url' => $festivalEvent->registration_logo_url,
'registration_show_section_preferences' => (bool) $festivalEvent->registration_show_section_preferences,
'registration_show_availability' => (bool) $festivalEvent->registration_show_availability,
],
'sections' => $sections->map(fn (FestivalSection $section) => [
'id' => $section->id,
@@ -79,6 +90,38 @@ final class PublicRegistrationDataController extends Controller
'end_time' => $slot->end_time,
'duration_hours' => $slot->duration_hours,
]),
'registration_fields' => $registrationFields->map(function (RegistrationFormField $field) use ($organisationId) {
$data = [
'id' => $field->id,
'label' => $field->label,
'slug' => $field->slug,
'field_type' => $field->field_type->value,
'options' => $field->options,
'tag_category' => $field->tag_category,
'is_required' => $field->is_required,
'section' => $field->section,
'help_text' => $field->help_text,
];
if ($field->field_type === \App\Enums\RegistrationFieldType::TAG_PICKER) {
$query = PersonTag::where('organisation_id', $organisationId)
->where('is_active', true);
if ($field->tag_category) {
$query->where('category', $field->tag_category);
}
$data['available_tags'] = $query->orderBy('sort_order')
->get()
->map(fn (PersonTag $tag) => [
'id' => $tag->id,
'name' => $tag->name,
'category' => $tag->category,
]);
}
return $data;
}),
],
]);
}