feat: HEADING field type for registration forms — replace section property with structural field

Replace the per-field `section` text property with a dedicated HEADING field type that
organizers add as a separate block for visual grouping. Also fixes duplicate heading bug
on portal radio fields, replaces cramped VBtnToggle with VSelect for field width, and
adds grouped field type dropdown with structure/input categories.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-16 16:40:41 +02:00
parent 9718e27029
commit d57dcdb616
27 changed files with 667 additions and 480 deletions

View File

@@ -152,7 +152,7 @@ class RegistrationFieldTemplateTest extends TestCase
->where('is_system', true)
->count();
$this->assertEquals(11, $count);
$this->assertEquals(16, $count);
}
public function test_create_field_from_template(): void

View File

@@ -492,4 +492,58 @@ class RegistrationFormFieldTest extends TestCase
$this->assertEquals('full', $field['display_width']);
$this->assertNotNull($field['normalized_options']);
}
public function test_store_heading_field_without_options(): void
{
Sanctum::actingAs($this->orgAdmin);
$response = $this->postJson("/api/v1/organisations/{$this->organisation->id}/events/{$this->event->id}/registration-fields", [
'label' => 'Persoonlijke voorkeuren',
'field_type' => 'heading',
'help_text' => 'Vertel ons wat we over jou moeten weten',
]);
$response->assertCreated()
->assertJsonPath('data.field_type', 'heading')
->assertJsonPath('data.label', 'Persoonlijke voorkeuren')
->assertJsonPath('data.help_text', 'Vertel ons wat we over jou moeten weten')
->assertJsonPath('data.display_width', 'full');
}
public function test_heading_field_skips_options_validation(): void
{
Sanctum::actingAs($this->orgAdmin);
$response = $this->postJson("/api/v1/organisations/{$this->organisation->id}/events/{$this->event->id}/registration-fields", [
'label' => 'Sectiekop',
'field_type' => 'heading',
]);
$response->assertCreated();
}
public function test_heading_field_display_width_defaults_to_full(): void
{
Sanctum::actingAs($this->orgAdmin);
$response = $this->postJson("/api/v1/organisations/{$this->organisation->id}/events/{$this->event->id}/registration-fields", [
'label' => 'Noodcontact',
'field_type' => 'heading',
]);
$response->assertCreated()
->assertJsonPath('data.display_width', 'full');
}
public function test_seeder_creates_heading_fields(): void
{
\App\Services\RegistrationFieldTemplateService::seedSystemTemplates($this->organisation);
$headingCount = \App\Models\RegistrationFieldTemplate::where('organisation_id', $this->organisation->id)
->where('is_system', true)
->where('field_type', 'heading')
->count();
$this->assertEquals(5, $headingCount);
}
}