feat: registration form field display_width and option descriptions

Add configurable column widths (full/half) and optional descriptions
for radio/select/checkbox options on registration form fields.

- Migration adds display_width column to both tables
- FieldDisplayWidth enum with smart defaults per field type
- normalized_options accessor for backwards-compatible option format
- Portal form renderer uses display_width for VRow/VCol grid layout
- Radio/select/checkbox options render with descriptions
- Admin field editor supports display_width toggle and description input
- System templates updated with appropriate widths and descriptions

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-16 07:46:36 +02:00
parent c4a23b6763
commit 9718e27029
25 changed files with 634 additions and 84 deletions

View File

@@ -4,6 +4,7 @@ declare(strict_types=1);
namespace Database\Factories;
use App\Enums\FieldDisplayWidth;
use App\Enums\RegistrationFieldType;
use App\Models\Organisation;
use App\Models\RegistrationFieldTemplate;
@@ -34,6 +35,7 @@ final class RegistrationFieldTemplateFactory extends Factory
'section' => null,
'help_text' => null,
'sort_order' => fake()->numberBetween(0, 20),
'display_width' => FieldDisplayWidth::FULL,
'is_system' => false,
'is_active' => true,
];
@@ -57,6 +59,7 @@ final class RegistrationFieldTemplateFactory extends Factory
'field_type' => RegistrationFieldType::SELECT,
'options' => ['XS', 'S', 'M', 'L', 'XL', 'XXL', 'XXXL'],
'is_filterable' => true,
'display_width' => FieldDisplayWidth::HALF,
]);
}
@@ -67,6 +70,7 @@ final class RegistrationFieldTemplateFactory extends Factory
'slug' => 'ehbo-bhv-diploma',
'field_type' => RegistrationFieldType::BOOLEAN,
'is_filterable' => true,
'display_width' => FieldDisplayWidth::HALF,
]);
}
@@ -77,6 +81,7 @@ final class RegistrationFieldTemplateFactory extends Factory
'slug' => 'certificaten-vaardigheden',
'field_type' => RegistrationFieldType::TAG_PICKER,
'is_filterable' => true,
'display_width' => FieldDisplayWidth::FULL,
]);
}
}

View File

@@ -4,6 +4,7 @@ declare(strict_types=1);
namespace Database\Factories;
use App\Enums\FieldDisplayWidth;
use App\Enums\RegistrationFieldType;
use App\Models\Event;
use App\Models\RegistrationFormField;
@@ -34,6 +35,7 @@ final class RegistrationFormFieldFactory extends Factory
'section' => null,
'help_text' => null,
'sort_order' => fake()->numberBetween(0, 20),
'display_width' => FieldDisplayWidth::FULL,
];
}
@@ -44,6 +46,7 @@ final class RegistrationFormFieldFactory extends Factory
'slug' => 'noodcontact-naam',
'field_type' => RegistrationFieldType::TEXT,
'section' => 'Noodcontact',
'display_width' => FieldDisplayWidth::HALF,
]);
}
@@ -55,6 +58,7 @@ final class RegistrationFormFieldFactory extends Factory
'field_type' => RegistrationFieldType::SELECT,
'options' => ['XS', 'S', 'M', 'L', 'XL', 'XXL', 'XXXL'],
'is_filterable' => true,
'display_width' => FieldDisplayWidth::HALF,
]);
}
@@ -66,6 +70,7 @@ final class RegistrationFormFieldFactory extends Factory
'field_type' => RegistrationFieldType::MULTISELECT,
'options' => ['Vegetarisch', 'Veganistisch', 'Halal', 'Glutenvrij', 'Lactosevrij', 'Geen pinda\'s', 'Geen noten'],
'is_filterable' => true,
'display_width' => FieldDisplayWidth::FULL,
]);
}
@@ -78,6 +83,7 @@ final class RegistrationFormFieldFactory extends Factory
'is_required' => true,
'section' => 'Toestemming',
'help_text' => 'Ik geef toestemming voor de verwerking van mijn persoonsgegevens conform de AVG.',
'display_width' => FieldDisplayWidth::FULL,
]);
}
@@ -88,6 +94,7 @@ final class RegistrationFormFieldFactory extends Factory
'slug' => 'vaardigheden',
'field_type' => RegistrationFieldType::TAG_PICKER,
'is_filterable' => true,
'display_width' => FieldDisplayWidth::FULL,
]);
}
@@ -97,8 +104,13 @@ final class RegistrationFormFieldFactory extends Factory
'label' => 'Vergoeding',
'slug' => 'vergoeding',
'field_type' => RegistrationFieldType::RADIO,
'options' => ['Pro Deo', 'Entreeticket', 'Vrijwilligersvergoeding'],
'options' => [
['label' => 'Pro Deo', 'description' => 'Je werkt als vrijwilliger zonder financiële vergoeding'],
['label' => 'Entreeticket', 'description' => 'Je ontvangt een gratis festivalticket als dank voor je inzet'],
['label' => 'Vrijwilligersvergoeding', 'description' => 'Je ontvangt een vergoeding conform de vrijwilligersregeling'],
],
'section' => 'Vergoeding',
'display_width' => FieldDisplayWidth::FULL,
]);
}
@@ -108,6 +120,7 @@ final class RegistrationFormFieldFactory extends Factory
'label' => 'Opmerkingen',
'slug' => 'opmerkingen',
'field_type' => RegistrationFieldType::TEXTAREA,
'display_width' => FieldDisplayWidth::FULL,
]);
}
}

View File

@@ -0,0 +1,32 @@
<?php
declare(strict_types=1);
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::table('registration_form_fields', function (Blueprint $table) {
$table->string('display_width', 10)->default('full')->after('sort_order');
});
Schema::table('registration_field_templates', function (Blueprint $table) {
$table->string('display_width', 10)->default('full')->after('sort_order');
});
}
public function down(): void
{
Schema::table('registration_form_fields', function (Blueprint $table) {
$table->dropColumn('display_width');
});
Schema::table('registration_field_templates', function (Blueprint $table) {
$table->dropColumn('display_width');
});
}
};