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

@@ -22,9 +22,19 @@ final class StoreRegistrationFieldTemplateRequest extends FormRequest
$fieldType = $this->input('field_type');
$type = RegistrationFieldType::tryFrom($fieldType);
return [
$rules = [
'label' => ['required', 'string', 'max:255'],
'field_type' => ['required', Rule::in(array_column(RegistrationFieldType::cases(), 'value'))],
'help_text' => ['nullable', 'string', 'max:5000'],
'sort_order' => ['nullable', 'integer', 'min:0'],
'display_width' => ['sometimes', Rule::in(array_column(FieldDisplayWidth::cases(), 'value'))],
];
if ($type?->isStructural()) {
return $rules;
}
return array_merge($rules, [
'options' => [
$type?->requiresOptions() ? 'required' : 'nullable',
$type?->prohibitsOptions() ? 'prohibited' : 'nullable',
@@ -42,10 +52,6 @@ final class StoreRegistrationFieldTemplateRequest extends FormRequest
'is_filterable' => ['nullable', 'boolean'],
'is_portal_visible' => ['nullable', 'boolean'],
'is_admin_only' => ['nullable', 'boolean'],
'section' => ['nullable', 'string', 'max:100'],
'help_text' => ['nullable', 'string', 'max:5000'],
'sort_order' => ['nullable', 'integer', 'min:0'],
'display_width' => ['sometimes', Rule::in(array_column(FieldDisplayWidth::cases(), 'value'))],
];
]);
}
}

View File

@@ -22,9 +22,19 @@ final class StoreRegistrationFormFieldRequest extends FormRequest
$fieldType = $this->input('field_type');
$type = RegistrationFieldType::tryFrom($fieldType);
return [
$rules = [
'label' => ['required', 'string', 'max:255'],
'field_type' => ['required', Rule::in(array_column(RegistrationFieldType::cases(), 'value'))],
'help_text' => ['nullable', 'string', 'max:5000'],
'sort_order' => ['nullable', 'integer', 'min:0'],
'display_width' => ['sometimes', Rule::in(array_column(FieldDisplayWidth::cases(), 'value'))],
];
if ($type?->isStructural()) {
return $rules;
}
return array_merge($rules, [
'options' => [
$type?->requiresOptions() ? 'required' : 'nullable',
$type?->prohibitsOptions() ? 'prohibited' : 'nullable',
@@ -42,10 +52,6 @@ final class StoreRegistrationFormFieldRequest extends FormRequest
'is_portal_visible' => ['nullable', 'boolean'],
'is_admin_only' => ['nullable', 'boolean'],
'is_filterable' => ['nullable', 'boolean'],
'section' => ['nullable', 'string', 'max:100'],
'help_text' => ['nullable', 'string', 'max:5000'],
'sort_order' => ['nullable', 'integer', 'min:0'],
'display_width' => ['sometimes', Rule::in(array_column(FieldDisplayWidth::cases(), 'value'))],
];
]);
}
}

View File

@@ -30,7 +30,6 @@ final class UpdateRegistrationFieldTemplateRequest extends FormRequest
'is_filterable' => ['nullable', 'boolean'],
'is_portal_visible' => ['nullable', 'boolean'],
'is_admin_only' => ['nullable', 'boolean'],
'section' => ['nullable', 'string', 'max:100'],
'help_text' => ['nullable', 'string', 'max:5000'],
'sort_order' => ['nullable', 'integer', 'min:0'],
'display_width' => ['sometimes', Rule::in(array_column(FieldDisplayWidth::cases(), 'value'))],

View File

@@ -29,7 +29,6 @@ final class UpdateRegistrationFormFieldRequest extends FormRequest
'is_portal_visible' => ['nullable', 'boolean'],
'is_admin_only' => ['nullable', 'boolean'],
'is_filterable' => ['nullable', 'boolean'],
'section' => ['nullable', 'string', 'max:100'],
'help_text' => ['nullable', 'string', 'max:5000'],
'sort_order' => ['nullable', 'integer', 'min:0'],
'display_width' => ['sometimes', Rule::in(array_column(FieldDisplayWidth::cases(), 'value'))],