feat: registration section preferences with show_in_registration filtering and deduplication

Add show_in_registration and registration_description columns to festival_sections.
Registration form now shows deduplicated sections by name (across sub-events),
filtered by show_in_registration=true, grouped by category with card-based UI.
Section preferences use section_name instead of section_id.
Add GET/PUT registration-settings endpoints for festival-level bulk management.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-10 20:03:54 +02:00
parent 3400e4cc7e
commit c21bc085e9
22 changed files with 1443 additions and 104 deletions

View File

@@ -32,6 +32,8 @@ const form = ref({
type: 'standard' as SectionType,
crew_auto_accepts: false,
responder_self_checkin: true,
show_in_registration: false,
registration_description: null as string | null,
})
const errors = ref<Record<string, string>>({})
@@ -56,6 +58,8 @@ function resetForm() {
type: 'standard',
crew_auto_accepts: false,
responder_self_checkin: true,
show_in_registration: false,
registration_description: null,
}
errors.value = {}
refVForm.value?.resetValidation()
@@ -76,6 +80,8 @@ function onSubmit() {
sort_order: props.nextSortOrder,
crew_auto_accepts: form.value.crew_auto_accepts,
responder_self_checkin: form.value.responder_self_checkin,
show_in_registration: form.value.show_in_registration,
registration_description: form.value.registration_description || null,
},
{
onSuccess: (result) => {
@@ -188,6 +194,29 @@ function onSubmit() {
persistent-hint
/>
</VCol>
<VCol cols="12">
<VSwitch
v-model="form.show_in_registration"
label="Toon in vrijwilligersregistratie"
hint="Dit werkgebied verschijnt in het aanmeldformulier voor vrijwilligers"
persistent-hint
/>
</VCol>
<VCol
v-if="form.show_in_registration"
cols="12"
>
<VTextarea
v-model="form.registration_description"
label="Beschrijving voor vrijwilligers"
:counter="500"
rows="2"
auto-grow
hint="Korte uitleg zodat vrijwilligers weten wat dit werkgebied inhoudt"
persistent-hint
:error-messages="errors.registration_description"
/>
</VCol>
</VRow>
</VCardText>
<VCardActions>

View File

@@ -28,6 +28,8 @@ const form = ref({
type: 'standard' as SectionType,
crew_auto_accepts: false,
responder_self_checkin: true,
show_in_registration: false,
registration_description: null as string | null,
})
const errors = ref<Record<string, string>>({})
@@ -52,6 +54,8 @@ watch(
type: section.type,
crew_auto_accepts: section.crew_auto_accepts,
responder_self_checkin: section.responder_self_checkin,
show_in_registration: section.show_in_registration,
registration_description: section.registration_description,
}
}
},
@@ -79,6 +83,8 @@ function onSubmit() {
icon: form.value.icon || null,
crew_auto_accepts: form.value.crew_auto_accepts,
responder_self_checkin: form.value.responder_self_checkin,
show_in_registration: form.value.show_in_registration,
registration_description: form.value.registration_description || null,
},
{
onSuccess: () => {
@@ -180,6 +186,29 @@ function onSubmit() {
persistent-hint
/>
</VCol>
<VCol cols="12">
<VSwitch
v-model="form.show_in_registration"
label="Toon in vrijwilligersregistratie"
hint="Dit werkgebied verschijnt in het aanmeldformulier voor vrijwilligers"
persistent-hint
/>
</VCol>
<VCol
v-if="form.show_in_registration"
cols="12"
>
<VTextarea
v-model="form.registration_description"
label="Beschrijving voor vrijwilligers"
:counter="500"
rows="2"
auto-grow
hint="Korte uitleg zodat vrijwilligers weten wat dit werkgebied inhoudt"
persistent-hint
:error-messages="errors.registration_description"
/>
</VCol>
</VRow>
</VCardText>
<VCardActions>

View File

@@ -18,6 +18,8 @@ export interface FestivalSection {
crew_need: number | null
crew_auto_accepts: boolean
responder_self_checkin: boolean
show_in_registration: boolean
registration_description: string | null
created_at: string
}
@@ -39,6 +41,8 @@ export interface Shift {
status: ShiftStatus
filled_slots: number
fill_rate: number
is_overbooked: boolean
overbooking_count: number
effective_start_time: string
effective_end_time: string
time_slot: TimeSlot | null
@@ -61,6 +65,8 @@ export interface CreateSectionPayload {
sort_order?: number
crew_auto_accepts?: boolean
responder_self_checkin?: boolean
show_in_registration?: boolean
registration_description?: string | null
}
export interface UpdateSectionPayload extends Partial<CreateSectionPayload> {}