feat(form-builder): extend public form backend for S3a PR 2
- Seed AVAILABILITY_PICKER and SECTION_PRIORITY demo fields in the
event_registration showcase, and augment seedEchtFeesten with a
parent-level VOLUNTEER time slot pair + a standard registration-
visible section whose name duplicates a child section so the
PublicFormController dedup path is exercised end-to-end.
- Validate SECTION_PRIORITY value shape in FormValueService: arrays of
{ section_id, priority } with unique section_ids + priorities in 1..5,
max 5 entries, and section_ids scoped to the schema's event tree
(parent + children). Error envelope is the standard VALIDATION_FAILED
FieldValidationException shape so the portal renders errors next to
the field.
- Enrich admin-facing FormSubmissionResource with a nested identity_match
block mirroring the PublicFormSubmissionResource contract (status only;
leaves room for future matched_user_id / confidence).
- Lock in the FORM-05 stub contract with 6 tests against the existing
TriggerPersonIdentityMatchOnFormSubmit listener (no new listener was
needed — the current one already writes 'pending' for public
event_registration submissions per ARCH §31.1).
- 24 new backend assertions across seeder, shape validation, listener
state matrix, and resource serialisation.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -285,6 +285,21 @@ class DevSeeder extends Seeder
|
||||
'show_in_registration' => false,
|
||||
]);
|
||||
|
||||
// Parent-level standard section that mirrors a child name — exercises
|
||||
// PublicFormController::sections() dedup across parent+child.
|
||||
FestivalSection::create([
|
||||
'event_id' => $festival->id,
|
||||
'name' => 'Hoofdpodium Bar',
|
||||
'type' => 'standard',
|
||||
'category' => 'Bar',
|
||||
'icon' => 'tabler-beer',
|
||||
'sort_order' => 5,
|
||||
'responder_self_checkin' => true,
|
||||
'crew_auto_accepts' => true,
|
||||
'show_in_registration' => true,
|
||||
'registration_description' => 'Overkoepelende barinzet — je draait mee op het hoofdpodium over alle dagen',
|
||||
]);
|
||||
|
||||
// ── Sub-event sections (5 per sub-event) ──
|
||||
|
||||
$sectionDefs = [
|
||||
@@ -324,6 +339,11 @@ class DevSeeder extends Seeder
|
||||
$fSlots['nacht_za'] = TimeSlot::create(['event_id' => $festival->id, 'name' => 'Nachtsecurity za→zo', 'person_type' => 'CREW', 'date' => '2026-07-11', 'start_time' => '23:00', 'end_time' => '07:00', 'duration_hours' => 8.00]);
|
||||
$fSlots['afbraak'] = TimeSlot::create(['event_id' => $festival->id, 'name' => 'Afbraak', 'person_type' => 'CREW', 'date' => '2026-07-13', 'start_time' => '08:00', 'end_time' => '18:00', 'duration_hours' => 10.00]);
|
||||
|
||||
// Parent-level VOLUNTEER slots — ensures PublicFormController::timeSlots
|
||||
// surfaces both parent and child events in the merged response.
|
||||
$fSlots['vol_opbouw_vr'] = TimeSlot::create(['event_id' => $festival->id, 'name' => 'Vrijwilligers opbouw vrijdag', 'person_type' => 'VOLUNTEER', 'date' => '2026-07-10', 'start_time' => '09:00', 'end_time' => '12:00', 'duration_hours' => 3.00]);
|
||||
$fSlots['vol_afbraak_zo'] = TimeSlot::create(['event_id' => $festival->id, 'name' => 'Vrijwilligers afbraak zondag', 'person_type' => 'VOLUNTEER', 'date' => '2026-07-13', 'start_time' => '10:00', 'end_time' => '16:00', 'duration_hours' => 6.00]);
|
||||
|
||||
// ── Sub-event time slots (program-specific) ──
|
||||
|
||||
$ts = [];
|
||||
|
||||
@@ -293,6 +293,29 @@ final class FormBuilderDevSeeder
|
||||
'display_width' => 'full',
|
||||
'value_storage_hint' => FormValueStorageHint::JSON,
|
||||
],
|
||||
[
|
||||
'type' => FormFieldType::AVAILABILITY_PICKER,
|
||||
'slug' => 'beschikbaarheid',
|
||||
'label' => 'Wanneer ben je beschikbaar?',
|
||||
'help_text' => 'Vink alle dagdelen aan waarop je kunt werken.',
|
||||
'is_required' => true,
|
||||
'is_filterable' => false,
|
||||
'display_width' => 'full',
|
||||
'value_storage_hint' => FormValueStorageHint::JSON,
|
||||
],
|
||||
[
|
||||
'type' => FormFieldType::SECTION_PRIORITY,
|
||||
'slug' => 'sectie_voorkeur',
|
||||
'label' => 'Bij welke sectie wil je het liefst werken?',
|
||||
'help_text' => 'Sleep je voorkeuren in volgorde. Nummer 1 is je eerste keuze.',
|
||||
// UI soft cap; the hard cap of 5 lives in
|
||||
// FormValueService shape validation.
|
||||
'validation_rules' => ['max_priorities' => 3],
|
||||
'is_required' => false,
|
||||
'is_filterable' => false,
|
||||
'display_width' => 'full',
|
||||
'value_storage_hint' => FormValueStorageHint::JSON,
|
||||
],
|
||||
[
|
||||
'type' => FormFieldType::TEXTAREA,
|
||||
'slug' => 'opmerkingen',
|
||||
@@ -340,6 +363,7 @@ final class FormBuilderDevSeeder
|
||||
'field_type' => $def['type']->value,
|
||||
'slug' => $def['slug'],
|
||||
'label' => $def['label'],
|
||||
'help_text' => $def['help_text'] ?? null,
|
||||
'options' => $def['options'] ?? null,
|
||||
'validation_rules' => $def['validation_rules'] ?? null,
|
||||
'is_required' => $def['is_required'] ?? false,
|
||||
|
||||
Reference in New Issue
Block a user