Kurzanmeldungen
This commit is contained in:
@@ -35,6 +35,8 @@ const emit = defineEmits(['close'])
|
||||
eatingHabits: eatingHabits.value,
|
||||
sendWeeklyReports: props.event.sendWeeklyReports,
|
||||
registrationAllowed: props.event.registrationAllowed,
|
||||
shortRegistration: props.event.shortRegistration,
|
||||
swimmingPermissionRequired: props.event.swimmingPermissionRequired,
|
||||
flatSupport: props.event.flatSupportEdit,
|
||||
supportPerson: props.event.supportPersonIndex,
|
||||
})
|
||||
@@ -64,6 +66,8 @@ const emit = defineEmits(['close'])
|
||||
alcoholicsAge: formData.alcoholicsAge,
|
||||
sendWeeklyReports: formData.sendWeeklyReports,
|
||||
registrationAllowed: formData.registrationAllowed,
|
||||
shortRegistration: formData.shortRegistration,
|
||||
swimmingPermissionRequired: formData.swimmingPermissionRequired,
|
||||
flatSupport: formData.flatSupport,
|
||||
supportPerson: formData.supportPerson,
|
||||
contributingLocalGroups: contributingLocalGroups.value,
|
||||
@@ -172,6 +176,27 @@ const emit = defineEmits(['close'])
|
||||
<label for="registrationAllowed">Veranstaltung ist für Anmeldungen geöffnet</label>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
<input type="checkbox" v-model="formData.shortRegistration" id="shortRegistration" />
|
||||
<label for="shortRegistration">Verkürzte Anmeldung verwenden</label><br />
|
||||
<span style="font-size: 0.8rem; color: #6b7280;">
|
||||
Fragt nur die nötigsten Daten ab (Name, Kontakt, Allergien, Foto-Erlaubnis).
|
||||
Nicht erhobene Angaben wie Anschrift und An-/Abreise werden automatisch gefüllt.
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
<input type="checkbox" v-model="formData.swimmingPermissionRequired" id="swimmingPermissionRequired" />
|
||||
<label for="swimmingPermissionRequired">Badeerlaubnis abfragen</label><br />
|
||||
<span style="font-size: 0.8rem; color: #6b7280;">
|
||||
Ist die Abfrage deaktiviert, wird für Minderjährige „Keine Badeerlaubnis" hinterlegt.
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
|
||||
@@ -233,6 +233,7 @@ function saveParticipant() {
|
||||
<td>
|
||||
<span v-if="!staticProps.editMode">{{ props.participant.localgroup }}</span>
|
||||
<select v-else v-model="form.localgroup">
|
||||
<option value="">Kein Stamm</option>
|
||||
<option v-for="group in staticProps.event.contributingLocalGroups" :key="group.id" :value="group.slug">{{ group.name }}</option>
|
||||
</select>
|
||||
</td>
|
||||
|
||||
@@ -0,0 +1,138 @@
|
||||
<script setup>
|
||||
import {computed} from 'vue'
|
||||
import {useShortSignupForm} from './composables/useShortSignupForm.js'
|
||||
import {
|
||||
SHORT_STEP_PERSON,
|
||||
SHORT_STEP_PARTICIPATION_OPTIONS,
|
||||
SHORT_STEP_PHOTO,
|
||||
SHORT_STEP_PAYMENT,
|
||||
SHORT_STEP_SUMMARY,
|
||||
stepVisible,
|
||||
} from './composables/shortStepFlow.js'
|
||||
import ShortStepPerson from './steps/ShortStepPerson.vue'
|
||||
import ShortStepSummary from './steps/ShortStepSummary.vue'
|
||||
import StepParticipationOptions from '../SignUpForm/steps/StepParticipationOptions.vue'
|
||||
import StepPhotoPermissions from '../SignUpForm/steps/StepPhotoPermissions.vue'
|
||||
import StepPaymentMethod from '../SignUpForm/steps/StepPaymentMethod.vue'
|
||||
import SubmitSuccess from '../SignUpForm/after-submit/SubmitSuccess.vue'
|
||||
import SubmitAlreadyExists from '../SignUpForm/after-submit/SubmitAlreadyExists.vue'
|
||||
|
||||
const props = defineProps({
|
||||
event: Object,
|
||||
participantData: Object,
|
||||
})
|
||||
|
||||
const {
|
||||
currentStep, goToStep, goNext, goBack, formData, isMinor, localGroups, needsLocalGroup,
|
||||
submit, submitting, submitResult, submitError,
|
||||
summaryLoading, summaryAmount, summaryAmountValue,
|
||||
} = useShortSignupForm(props.event, props.participantData)
|
||||
|
||||
// Die aus dem langen Prozess übernommenen Schritte emittieren ihre Zielnummer aus jenem Flow mit. Hier zählt
|
||||
// nur, dass "weiter" bzw. "zurück" gedrückt wurde -- die Reihenfolge kennt dieser Host.
|
||||
const onNext = () => goNext()
|
||||
const onBack = () => goBack()
|
||||
|
||||
const allSteps = [
|
||||
{step: SHORT_STEP_PERSON, label: 'Person'},
|
||||
{step: SHORT_STEP_PARTICIPATION_OPTIONS, label: 'Teilnahmeoptionen'},
|
||||
{step: SHORT_STEP_PHOTO, label: 'Fotoerlaubnis'},
|
||||
{step: SHORT_STEP_PAYMENT, label: 'Zahlungsart'},
|
||||
{step: SHORT_STEP_SUMMARY, label: 'Zusammenfassung'},
|
||||
]
|
||||
|
||||
// Nur die tatsächlich vorkommenden Schritte anzeigen, sonst zeigt die Leiste Schritte, die nie erscheinen.
|
||||
const steps = computed(() =>
|
||||
allSteps.filter(s => stepVisible(props.event, s.step, summaryAmountValue.value))
|
||||
)
|
||||
|
||||
const currentIndex = computed(() => steps.value.findIndex(s => s.step === currentStep.value))
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<!-- Nach Submit -->
|
||||
<SubmitSuccess
|
||||
v-if="submitResult?.status === 'success'"
|
||||
:participant="submitResult?.participant"
|
||||
:event="event"
|
||||
/>
|
||||
<SubmitAlreadyExists v-else-if="submitResult?.status === 'exists'" :event="event" />
|
||||
|
||||
<template v-else>
|
||||
<!-- Fortschrittsleiste -->
|
||||
<div class="signup-progress">
|
||||
<div class="signup-progress-pills">
|
||||
<template v-for="(s, index) in steps" :key="s.step">
|
||||
<div v-if="index > 0" class="signup-progress-separator"></div>
|
||||
<div
|
||||
class="signup-pill"
|
||||
:class="{
|
||||
'signup-pill--active': currentStep === s.step,
|
||||
'signup-pill--done': currentStep > s.step,
|
||||
'signup-pill--upcoming': currentStep < s.step,
|
||||
}"
|
||||
@click="currentStep > s.step ? goToStep(s.step) : null"
|
||||
>
|
||||
<span v-if="currentStep > s.step" class="signup-pill__check">✓</span>
|
||||
{{ s.label }}
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<div class="signup-progress-bar">
|
||||
<div
|
||||
class="signup-progress-bar__fill"
|
||||
:style="{ width: (steps.length > 1 ? (currentIndex / (steps.length - 1)) * 100 : 100) + '%' }"
|
||||
></div>
|
||||
</div>
|
||||
|
||||
<div class="signup-progress-mobile">
|
||||
Schritt {{ currentIndex + 1 }} von {{ steps.length }}:
|
||||
<strong>{{ steps.find(s => s.step === currentStep)?.label }}</strong>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Steps -->
|
||||
<form @submit.prevent="submit">
|
||||
<ShortStepPerson
|
||||
v-if="currentStep === SHORT_STEP_PERSON"
|
||||
:formData="formData" :event="event" :isMinor="isMinor"
|
||||
:localGroups="localGroups" :needsLocalGroup="needsLocalGroup"
|
||||
@next="onNext"
|
||||
/>
|
||||
<StepParticipationOptions
|
||||
v-if="currentStep === SHORT_STEP_PARTICIPATION_OPTIONS"
|
||||
:formData="formData" :event="event"
|
||||
@next="onNext" @back="onBack"
|
||||
/>
|
||||
<StepPhotoPermissions
|
||||
v-if="currentStep === SHORT_STEP_PHOTO"
|
||||
:formData="formData" :event="event"
|
||||
@next="onNext" @back="onBack"
|
||||
/>
|
||||
<StepPaymentMethod
|
||||
v-if="currentStep === SHORT_STEP_PAYMENT"
|
||||
:formData="formData" :event="event"
|
||||
@next="onNext" @back="onBack"
|
||||
/>
|
||||
<ShortStepSummary
|
||||
v-if="currentStep === SHORT_STEP_SUMMARY"
|
||||
:formData="formData"
|
||||
:event="event"
|
||||
:isMinor="isMinor"
|
||||
:summaryAmount="summaryAmount"
|
||||
:summaryAmountValue="summaryAmountValue"
|
||||
:summaryLoading="summaryLoading"
|
||||
:submitting="submitting"
|
||||
:submitError="submitError"
|
||||
@back="onBack"
|
||||
@submit="submit"
|
||||
/>
|
||||
</form>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- Unscoped und mit dem langen Anmeldeprozess geteilt. -->
|
||||
<style src="../SignUpForm/signupForm.css"></style>
|
||||
@@ -0,0 +1,37 @@
|
||||
// Schrittreihenfolge der Kurzanmeldung. Zwei Schritte sind optional: die Teilnahmeoptionen entfallen, wenn für
|
||||
// die Veranstaltung keine definiert sind, die Zahlungsart entfällt bei Betrag 0 oder wenn es ohnehin nur eine
|
||||
// Zahlungsart gibt (die wird dann vorausgewählt).
|
||||
export const SHORT_STEP_PERSON = 1
|
||||
export const SHORT_STEP_PARTICIPATION_OPTIONS = 2
|
||||
export const SHORT_STEP_PHOTO = 3
|
||||
export const SHORT_STEP_PAYMENT = 4
|
||||
export const SHORT_STEP_SUMMARY = 5
|
||||
|
||||
export function stepVisible(event, step, amountValue) {
|
||||
if (step === SHORT_STEP_PARTICIPATION_OPTIONS) {
|
||||
return (event.participationOptions?.length ?? 0) > 0
|
||||
}
|
||||
|
||||
if (step === SHORT_STEP_PAYMENT) {
|
||||
const activeMethods = (event.paymentMethods ?? []).filter(m => m.active)
|
||||
return amountValue > 0 && activeMethods.length > 1
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
export function nextVisibleFrom(event, step, amountValue) {
|
||||
let candidate = step + 1
|
||||
while (candidate < SHORT_STEP_SUMMARY && !stepVisible(event, candidate, amountValue)) {
|
||||
candidate++
|
||||
}
|
||||
return candidate
|
||||
}
|
||||
|
||||
export function prevVisibleFrom(event, step, amountValue) {
|
||||
let candidate = step - 1
|
||||
while (candidate > SHORT_STEP_PERSON && !stepVisible(event, candidate, amountValue)) {
|
||||
candidate--
|
||||
}
|
||||
return candidate
|
||||
}
|
||||
@@ -0,0 +1,155 @@
|
||||
import {computed, reactive, ref} from 'vue'
|
||||
import axios from 'axios'
|
||||
import {differenceInYears, parseISO} from 'date-fns'
|
||||
import {SHORT_STEP_PERSON, nextVisibleFrom, prevVisibleFrom} from './shortStepFlow.js'
|
||||
|
||||
export function useShortSignupForm(event, participantData) {
|
||||
const currentStep = ref(SHORT_STEP_PERSON)
|
||||
const submitting = ref(false)
|
||||
const summaryLoading = ref(false)
|
||||
const submitResult = ref(null) // null | { status: 'success'|'exists', participant: {} }
|
||||
const submitError = ref('')
|
||||
|
||||
// Gibt es nur eine Zahlungsart, wird sie vorausgewählt und der Zahlungsschritt entfällt.
|
||||
const activeMethods = (event.paymentMethods ?? []).filter(m => m.active)
|
||||
|
||||
// Bei genau einem teilnehmenden Stamm wird dieser gesetzt, ohne danach zu fragen; erst ab zwei
|
||||
// Stämmen erscheint das Auswahlfeld.
|
||||
const localGroups = event.contributingLocalGroups ?? []
|
||||
const needsLocalGroup = localGroups.length > 1
|
||||
|
||||
const formData = reactive({
|
||||
userId: participantData.id,
|
||||
vorname: participantData.firstname ?? '',
|
||||
nachname: participantData.lastname ?? '',
|
||||
pfadiname: participantData.nickname ?? '',
|
||||
geburtsdatum: participantData.birthday ?? '',
|
||||
email_1: participantData.email ?? '',
|
||||
telefon_1: participantData.phone ?? '',
|
||||
localGroup: localGroups.length === 1 ? localGroups[0].id : (participantData.localGroup ?? '-1'),
|
||||
ansprechpartner: '',
|
||||
email_2: '',
|
||||
allergien: participantData.allergies ?? '',
|
||||
intolerances: participantData.intolerances ?? '',
|
||||
first_aid: '-1',
|
||||
badeerlaubnis: '-1',
|
||||
// Antworten auf die event-spezifischen Teilnahmeoptionen: { [question.key]: option.value }
|
||||
participationOptions: {},
|
||||
foto: {socialmedia: false, print: false, webseite: false, partner: false, intern: false},
|
||||
paymentMethod: activeMethods.length === 1 ? activeMethods[0].slug : null,
|
||||
paymentOptions: {},
|
||||
summary_information_correct: false,
|
||||
summary_accept_terms: false,
|
||||
legal_accepted: false,
|
||||
payment: false,
|
||||
})
|
||||
|
||||
// Minderjährigkeit steuert Kontaktperson, Erweiterte Erste Hilfe und Badeerlaubnis. Die Grenze von 18 Jahren
|
||||
// entspricht Age::isfullAged() im Backend.
|
||||
const isMinor = computed(() => {
|
||||
if (!formData.geburtsdatum) {
|
||||
return false
|
||||
}
|
||||
return differenceInYears(new Date(), parseISO(formData.geburtsdatum)) < 18
|
||||
})
|
||||
|
||||
const summaryAmount = ref('')
|
||||
const summaryAmountValue = ref(0)
|
||||
const amountLoaded = ref(false)
|
||||
|
||||
// Der Betrag steht für die ganze Anmeldung fest (feste Teilnahmegruppe, fester Zeitraum) und wird deshalb
|
||||
// genau einmal geholt. Er entscheidet, ob der Zahlungsschritt überhaupt vorkommt.
|
||||
const ensureAmount = async () => {
|
||||
if (amountLoaded.value) {
|
||||
return
|
||||
}
|
||||
|
||||
summaryLoading.value = true
|
||||
try {
|
||||
const res = await axios.post('/api/v1/event/' + event.id + '/short-calculate-amount')
|
||||
summaryAmount.value = res.data.amount
|
||||
summaryAmountValue.value = Number(res.data.amountValue ?? 0)
|
||||
amountLoaded.value = true
|
||||
|
||||
if (summaryAmountValue.value <= 0) {
|
||||
formData.paymentMethod = null
|
||||
formData.paymentOptions = {}
|
||||
}
|
||||
} finally {
|
||||
summaryLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const goToStep = (step) => {
|
||||
currentStep.value = step
|
||||
}
|
||||
|
||||
const goNext = async () => {
|
||||
await ensureAmount()
|
||||
goToStep(nextVisibleFrom(event, currentStep.value, summaryAmountValue.value))
|
||||
}
|
||||
|
||||
const goBack = async () => {
|
||||
await ensureAmount()
|
||||
goToStep(prevVisibleFrom(event, currentStep.value, summaryAmountValue.value))
|
||||
}
|
||||
|
||||
const submit = async () => {
|
||||
if (!formData.summary_information_correct || !formData.summary_accept_terms || !formData.legal_accepted) {
|
||||
return
|
||||
}
|
||||
|
||||
submitting.value = true
|
||||
submitError.value = ''
|
||||
try {
|
||||
const res = await axios.post('/api/v1/event/' + event.id + '/short-signup', {
|
||||
firstname: formData.vorname,
|
||||
lastname: formData.nachname,
|
||||
nickname: formData.pfadiname || null,
|
||||
birthday: formData.geburtsdatum,
|
||||
email: formData.email_1,
|
||||
phone: formData.telefon_1,
|
||||
localGroup: formData.localGroup !== '-1' ? formData.localGroup : null,
|
||||
contactPerson: isMinor.value ? formData.ansprechpartner : null,
|
||||
contactEmail: isMinor.value ? formData.email_2 : null,
|
||||
allergies: formData.allergien || null,
|
||||
intolerances: formData.intolerances || null,
|
||||
firstAidPermission: isMinor.value && formData.first_aid !== '-1' ? formData.first_aid : null,
|
||||
swimmingPermission: isMinor.value && formData.badeerlaubnis !== '-1' ? formData.badeerlaubnis : null,
|
||||
foto: formData.foto,
|
||||
participationOptions: formData.participationOptions,
|
||||
paymentMethod: formData.paymentMethod,
|
||||
paymentOptions: formData.paymentOptions,
|
||||
})
|
||||
|
||||
submitResult.value = {
|
||||
status: res.data.status,
|
||||
participant: res.data.participant,
|
||||
}
|
||||
} catch (error) {
|
||||
submitError.value = error.response?.data?.message
|
||||
?? 'Die Anmeldung konnte nicht gespeichert werden. Bitte versuche es später erneut.'
|
||||
} finally {
|
||||
submitting.value = false
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
currentStep,
|
||||
goToStep,
|
||||
goNext,
|
||||
goBack,
|
||||
formData,
|
||||
isMinor,
|
||||
localGroups,
|
||||
needsLocalGroup,
|
||||
submit,
|
||||
submitting,
|
||||
submitResult,
|
||||
submitError,
|
||||
summaryLoading,
|
||||
summaryAmount,
|
||||
summaryAmountValue,
|
||||
ensureAmount,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,218 @@
|
||||
<script setup>
|
||||
import ErrorText from "../../../../../../Views/Components/ErrorText.vue";
|
||||
import {reactive} from "vue";
|
||||
|
||||
const props = defineProps({
|
||||
formData: Object,
|
||||
event: Object,
|
||||
isMinor: Boolean,
|
||||
localGroups: {type: Array, default: () => []},
|
||||
needsLocalGroup: Boolean,
|
||||
})
|
||||
const emit = defineEmits(['next'])
|
||||
|
||||
const errors = reactive({
|
||||
vorname: '',
|
||||
nachname: '',
|
||||
geburtsdatum: '',
|
||||
localGroup: '',
|
||||
email_1: '',
|
||||
telefon_1: '',
|
||||
ansprechpartner: '',
|
||||
email_2: '',
|
||||
first_aid: '',
|
||||
badeerlaubnis: '',
|
||||
})
|
||||
|
||||
// Nur sichtbare Felder werden geprüft -- Kontaktperson und Erlaubnisse gibt es bei Volljährigen nicht.
|
||||
const next = () => {
|
||||
Object.keys(errors).forEach(key => errors[key] = '')
|
||||
|
||||
let hasError = false
|
||||
|
||||
if (!props.formData.vorname) {
|
||||
errors.vorname = 'Bitte einen Vornamen angeben.'
|
||||
hasError = true
|
||||
}
|
||||
|
||||
if (!props.formData.nachname) {
|
||||
errors.nachname = 'Bitte einen Nachnamen angeben.'
|
||||
hasError = true
|
||||
}
|
||||
|
||||
if (!props.formData.geburtsdatum) {
|
||||
errors.geburtsdatum = 'Bitte ein Geburtsdatum angeben.'
|
||||
hasError = true
|
||||
}
|
||||
|
||||
if (props.needsLocalGroup && (!props.formData.localGroup || props.formData.localGroup === '-1')) {
|
||||
errors.localGroup = 'Bitte einen Stamm auswählen.'
|
||||
hasError = true
|
||||
}
|
||||
|
||||
if (!props.formData.email_1) {
|
||||
errors.email_1 = 'Bitte eine E-Mail-Adresse angeben.'
|
||||
hasError = true
|
||||
}
|
||||
|
||||
if (!props.formData.telefon_1) {
|
||||
errors.telefon_1 = 'Bitte eine Telefonnummer angeben.'
|
||||
hasError = true
|
||||
}
|
||||
|
||||
if (props.isMinor) {
|
||||
if (!props.formData.ansprechpartner) {
|
||||
errors.ansprechpartner = 'Bitte eine Kontaktperson angeben.'
|
||||
hasError = true
|
||||
}
|
||||
|
||||
if (!props.formData.email_2) {
|
||||
errors.email_2 = 'Bitte eine E-Mail-Adresse der Kontaktperson angeben.'
|
||||
hasError = true
|
||||
}
|
||||
|
||||
if (props.formData.first_aid === '-1') {
|
||||
errors.first_aid = 'Bitte triff eine Entscheidung. Bist du dir unsicher, kontaktiere bitte die Aktionsleitung.'
|
||||
hasError = true
|
||||
}
|
||||
|
||||
if (props.event.swimmingPermissionRequired && props.formData.badeerlaubnis === '-1') {
|
||||
errors.badeerlaubnis = 'Bitte triff eine Entscheidung. Bist du dir unsicher, kontaktiere bitte die Aktionsleitung.'
|
||||
hasError = true
|
||||
}
|
||||
}
|
||||
|
||||
if (hasError) {
|
||||
return
|
||||
}
|
||||
|
||||
emit('next')
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<h3>Angaben zur Person</h3>
|
||||
<table class="form-table">
|
||||
<tr>
|
||||
<td>Vorname:</td>
|
||||
<td>
|
||||
<input type="text" v-model="formData.vorname" />
|
||||
<ErrorText :message="errors.vorname" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Pfadiname:</td>
|
||||
<td>
|
||||
<input type="text" v-model="formData.pfadiname" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Nachname:</td>
|
||||
<td>
|
||||
<input type="text" v-model="formData.nachname" />
|
||||
<ErrorText :message="errors.nachname" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Geburtsdatum:</td>
|
||||
<td>
|
||||
<input type="date" v-model="formData.geburtsdatum" />
|
||||
<ErrorText :message="errors.geburtsdatum" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-if="needsLocalGroup">
|
||||
<td>Stamm:</td>
|
||||
<td>
|
||||
<select v-model="formData.localGroup">
|
||||
<option value="-1">Bitte wählen</option>
|
||||
<option v-for="group in localGroups" :key="group.id" :value="group.id">{{ group.name }}</option>
|
||||
</select>
|
||||
<ErrorText :message="errors.localGroup" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>E-Mail:</td>
|
||||
<td>
|
||||
<input type="email" v-model="formData.email_1" />
|
||||
<ErrorText :message="errors.email_1" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Telefon:</td>
|
||||
<td>
|
||||
<input type="text" v-model="formData.telefon_1" />
|
||||
<ErrorText :message="errors.telefon_1" />
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<template v-if="isMinor">
|
||||
<tr>
|
||||
<td>Kontaktperson (Nachname, Vorname):</td>
|
||||
<td>
|
||||
<input type="text" v-model="formData.ansprechpartner" />
|
||||
<ErrorText :message="errors.ansprechpartner" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>E-Mail der Kontaktperson:</td>
|
||||
<td>
|
||||
<input type="email" v-model="formData.email_2" />
|
||||
<ErrorText :message="errors.email_2" />
|
||||
</td>
|
||||
</tr>
|
||||
</template>
|
||||
|
||||
<tr>
|
||||
<td>Allergien:</td>
|
||||
<td>
|
||||
<input type="text" v-model="formData.allergien" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Unverträglichkeiten:</td>
|
||||
<td>
|
||||
<input type="text" v-model="formData.intolerances" />
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<template v-if="isMinor">
|
||||
<tr>
|
||||
<td>Erweiterte Erste Hilfe erlaubt:</td>
|
||||
<td>
|
||||
<select v-model="formData.first_aid">
|
||||
<option value="-1">Bitte wählen</option>
|
||||
<option
|
||||
v-for="firstAidPermission in event.firstAidPermissions"
|
||||
:key="firstAidPermission.slug"
|
||||
:value="firstAidPermission.slug">{{ firstAidPermission.name }}</option>
|
||||
</select><br />
|
||||
<span style="font-size: 0.8rem; color: #6b7280;">
|
||||
Nicht dringend-notwendige Erste-Hilfe-Maßnahmen, beinhaltet das Entfernen von Zecken und Splittern sowie das Kleben von Pflastern.
|
||||
</span>
|
||||
<ErrorText :message="errors.first_aid" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-if="event.swimmingPermissionRequired">
|
||||
<td>Badeerlaubnis:</td>
|
||||
<td>
|
||||
<select v-model="formData.badeerlaubnis">
|
||||
<option value="-1">Bitte wählen</option>
|
||||
<option
|
||||
v-for="swimmingPermission in event.swimmingPermissions"
|
||||
:key="swimmingPermission.slug"
|
||||
:value="swimmingPermission.slug">{{ swimmingPermission.name }}</option>
|
||||
</select>
|
||||
<ErrorText :message="errors.badeerlaubnis" />
|
||||
</td>
|
||||
</tr>
|
||||
</template>
|
||||
|
||||
<tr>
|
||||
<td colspan="2" class="btn-row">
|
||||
<button type="button" class="btn-primary" @click="next">Weiter →</button>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</template>
|
||||
@@ -0,0 +1,187 @@
|
||||
<script setup>
|
||||
import {computed} from "vue";
|
||||
|
||||
const PAYMENT_ACCOUNT_TRANSACTION = 'PAYMENT_ACCOUNT_TRANSACTION'
|
||||
|
||||
const props = defineProps({
|
||||
formData: Object,
|
||||
event: Object,
|
||||
isMinor: Boolean,
|
||||
summaryAmount: String,
|
||||
summaryAmountValue: {type: Number, default: 0},
|
||||
summaryLoading: Boolean,
|
||||
submitting: Boolean,
|
||||
submitError: {type: String, default: ''},
|
||||
})
|
||||
const emit = defineEmits(['back', 'submit'])
|
||||
|
||||
const selectedMethod = computed(() =>
|
||||
(props.event.paymentMethods ?? []).find(m => m.slug === props.formData.paymentMethod) ?? null
|
||||
)
|
||||
|
||||
// Die Überweisungs-Bestätigung wird nur bei Banküberweisung verlangt.
|
||||
const requiresPaymentConfirmation = computed(() =>
|
||||
props.formData.paymentMethod === PAYMENT_ACCOUNT_TRANSACTION
|
||||
)
|
||||
|
||||
// Bestätigungstext ist ein admin-konfigurierbarer Freitext ({amount}-Platzhalter), sonst Default.
|
||||
const paymentConfirmationText = computed(() => {
|
||||
const configured = selectedMethod.value?.configuration?.summary_confirmation_text
|
||||
const template = (configured && String(configured).trim() !== '')
|
||||
? configured
|
||||
: 'Ich bestätige, den Betrag von {amount} zu überweisen.'
|
||||
return template.replaceAll('{amount}', props.summaryAmount ?? '')
|
||||
})
|
||||
|
||||
// Gewählte Teilnahmeoptionen für die Zusammenfassung (Label statt Wert anzeigen).
|
||||
const selectedParticipationOptions = computed(() =>
|
||||
(props.event.participationOptions ?? []).map(question => {
|
||||
const value = props.formData.participationOptions[question.key]
|
||||
const option = (question.options ?? []).find(o => o.value === value)
|
||||
return {label: question.title || question.label, value: option?.label ?? ''}
|
||||
}).filter(entry => entry.value !== '')
|
||||
)
|
||||
|
||||
// Der Stamm steht entweder fest (genau ein teilnehmender Stamm) oder wurde auf Seite 1 gewählt.
|
||||
const localGroupName = computed(() =>
|
||||
(props.event.contributingLocalGroups ?? []).find(g => g.id === props.formData.localGroup)?.name ?? null
|
||||
)
|
||||
|
||||
const permissionName = (list, slug) =>
|
||||
(list ?? []).find(entry => entry.slug === slug)?.name ?? '—'
|
||||
|
||||
const canSubmit = computed(() =>
|
||||
props.formData.summary_information_correct
|
||||
&& props.formData.summary_accept_terms
|
||||
&& props.formData.legal_accepted
|
||||
&& (!requiresPaymentConfirmation.value || props.formData.payment)
|
||||
&& !props.submitting
|
||||
)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<h3>Zusammenfassung</h3>
|
||||
|
||||
<div v-if="summaryLoading" style="color: #6b7280; padding: 20px 0;">Wird geladen…</div>
|
||||
<div v-else>
|
||||
<table class="form-table" style="margin-bottom: 20px;">
|
||||
<tr>
|
||||
<td>Dein Name:</td>
|
||||
<td>{{ formData.vorname }} {{ formData.nachname }}</td>
|
||||
</tr>
|
||||
<tr v-if="formData.pfadiname">
|
||||
<td>Pfadiname:</td>
|
||||
<td>{{ formData.pfadiname }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Deine E-Mail:</td>
|
||||
<td>{{ formData.email_1 }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Deine Telefonnummer:</td>
|
||||
<td>{{ formData.telefon_1 }}</td>
|
||||
</tr>
|
||||
<tr v-if="localGroupName">
|
||||
<td>Stamm:</td>
|
||||
<td>{{ localGroupName }}</td>
|
||||
</tr>
|
||||
|
||||
<template v-if="isMinor">
|
||||
<tr>
|
||||
<td>Kontaktperson:</td>
|
||||
<td>{{ formData.ansprechpartner }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>E-Mail der Kontaktperson:</td>
|
||||
<td>{{ formData.email_2 }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Erweiterte Erste Hilfe:</td>
|
||||
<td>{{ permissionName(event.firstAidPermissions, formData.first_aid) }}</td>
|
||||
</tr>
|
||||
<tr v-if="event.swimmingPermissionRequired">
|
||||
<td>Badeerlaubnis:</td>
|
||||
<td>{{ permissionName(event.swimmingPermissions, formData.badeerlaubnis) }}</td>
|
||||
</tr>
|
||||
</template>
|
||||
|
||||
<tr>
|
||||
<td>Allergien:</td>
|
||||
<td>{{ formData.allergien || 'Keine Angabe' }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Unverträglichkeiten:</td>
|
||||
<td>{{ formData.intolerances || 'Keine Angabe' }}</td>
|
||||
</tr>
|
||||
|
||||
<tr v-for="option in selectedParticipationOptions" :key="option.label">
|
||||
<td>{{ option.label }}:</td>
|
||||
<td>{{ option.value }}</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>Foto-Erlaubnis:</td>
|
||||
<td>
|
||||
<strong>Social Media:</strong> {{ formData.foto.socialmedia ? 'Ja' : 'Nein' }},
|
||||
<strong>Printmedien:</strong> {{ formData.foto.print ? 'Ja' : 'Nein' }},
|
||||
<strong>Webseite:</strong> {{ formData.foto.webseite ? 'Ja' : 'Nein' }},
|
||||
<strong>Partnerorganisationen:</strong> {{ formData.foto.partner ? 'Ja' : 'Nein' }},
|
||||
<strong>Interne Zwecke:</strong> {{ formData.foto.intern ? 'Ja' : 'Nein' }}
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr><td>Veranstaltung:</td><td><strong>{{ event.name }}</strong></td></tr>
|
||||
<tr><td>Zeitraum:</td><td>{{ event.eventBegin }} – {{ event.eventEnd }}</td></tr>
|
||||
</table>
|
||||
|
||||
<h4 style="margin: 0 0 8px 0;">Kostenübersicht</h4>
|
||||
<table class="form-table cost-table" style="margin-bottom: 20px;">
|
||||
<tr class="cost-total">
|
||||
<td><strong>Teilnahmebeitrag:</strong></td>
|
||||
<td><strong>{{ summaryAmount }}</strong></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<div style="display: flex; flex-direction: column; gap: 10px; margin-bottom: 20px;">
|
||||
<label style="display: flex; gap: 10px; cursor: pointer;">
|
||||
<input type="checkbox" v-model="formData.summary_information_correct" />
|
||||
Ich bestätige, dass alle Angaben korrekt sind.
|
||||
</label>
|
||||
<label style="display: flex; gap: 10px; cursor: pointer;">
|
||||
<input type="checkbox" v-model="formData.summary_accept_terms" />
|
||||
Ich akzeptiere die Teilnahmebedingungen.
|
||||
</label>
|
||||
<label style="display: flex; gap: 10px; cursor: pointer;">
|
||||
<input type="checkbox" v-model="formData.legal_accepted" />
|
||||
Ich stimme der Datenschutzerklärung zu.
|
||||
</label>
|
||||
<label v-if="requiresPaymentConfirmation" style="display: flex; gap: 10px; cursor: pointer;">
|
||||
<input type="checkbox" v-model="formData.payment" />
|
||||
{{ paymentConfirmationText }}
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<p v-if="submitError" style="color: #991b1b; font-weight: 600;">{{ submitError }}</p>
|
||||
|
||||
<div class="btn-row">
|
||||
<button type="button" class="btn-secondary" @click="emit('back')">← Zurück</button>
|
||||
<button
|
||||
type="submit"
|
||||
class="btn-primary"
|
||||
:disabled="!canSubmit"
|
||||
style="background: #059669;"
|
||||
>
|
||||
{{ submitting ? 'Wird gesendet…' : 'Jetzt anmelden ✓' }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.cost-table .cost-total td {
|
||||
border-top: 1px solid #d1d5db;
|
||||
padding-top: 8px;
|
||||
}
|
||||
</style>
|
||||
@@ -122,170 +122,5 @@ const steps = [
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
/* ─── Progress (Step-Pills) ─── */
|
||||
.signup-progress {
|
||||
margin-bottom: 28px;
|
||||
}
|
||||
|
||||
.signup-progress-pills {
|
||||
display: flex;
|
||||
gap: 6px;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.signup-progress-separator {
|
||||
flex-shrink: 0;
|
||||
width: 16px;
|
||||
height: 2px;
|
||||
background: #e5e7eb;
|
||||
border-radius: 1px;
|
||||
}
|
||||
|
||||
.signup-pill {
|
||||
padding: 5px 14px;
|
||||
border-radius: 999px;
|
||||
font-size: 0.78rem;
|
||||
font-weight: 600;
|
||||
white-space: nowrap;
|
||||
border: 2px solid;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.signup-pill__check { margin-right: 4px; }
|
||||
|
||||
.signup-pill--active {
|
||||
border-color: #2563eb;
|
||||
background: #2563eb;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.signup-pill--done {
|
||||
border-color: #bbf7d0;
|
||||
background: #f0fdf4;
|
||||
color: #15803d;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.signup-pill--upcoming {
|
||||
border-color: #e5e7eb;
|
||||
background: #f9fafb;
|
||||
color: #9ca3af;
|
||||
}
|
||||
|
||||
.signup-progress-bar {
|
||||
margin-top: 10px;
|
||||
height: 3px;
|
||||
background: #e5e7eb;
|
||||
border-radius: 2px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.signup-progress-bar__fill {
|
||||
height: 100%;
|
||||
background: linear-gradient(90deg, #2563eb, #3b82f6);
|
||||
border-radius: 2px;
|
||||
transition: width 0.3s ease;
|
||||
}
|
||||
|
||||
.signup-progress-mobile {
|
||||
display: none;
|
||||
margin-top: 8px;
|
||||
font-size: 0.9rem;
|
||||
color: #374151;
|
||||
}
|
||||
|
||||
/* ─── Form-Table ─── */
|
||||
.form-table { width: 100%; border-collapse: collapse; }
|
||||
.form-table td { padding: 8px 12px 8px 0; vertical-align: top; }
|
||||
.form-table td:first-child { width: 220px; color: #374151; font-weight: 500; }
|
||||
.form-table input[type="text"],
|
||||
.form-table input[type="date"],
|
||||
.form-table input[type="email"],
|
||||
.form-table input[type="number"],
|
||||
.form-table select,
|
||||
.form-table textarea {
|
||||
width: 100%;
|
||||
padding: 6px 10px;
|
||||
border: 1px solid #d1d5db;
|
||||
border-radius: 6px;
|
||||
font-size: 0.95rem;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.btn-row { display: flex; gap: 10px; padding-top: 16px; flex-wrap: wrap; }
|
||||
.btn-primary {
|
||||
padding: 8px 20px;
|
||||
background: #2563eb;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
}
|
||||
.btn-primary:disabled { opacity: 0.5; cursor: not-allowed; }
|
||||
.btn-secondary {
|
||||
padding: 8px 20px;
|
||||
background: #f3f4f6;
|
||||
color: #374151;
|
||||
border: 1px solid #d1d5db;
|
||||
border-radius: 8px;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/* ─── Tablet ─── */
|
||||
@media (max-width: 1023px) {
|
||||
.form-table td:first-child {
|
||||
width: 160px;
|
||||
}
|
||||
}
|
||||
|
||||
/* ─── Smartphone ─── */
|
||||
@media (max-width: 639px) {
|
||||
/* Pills auf Mobile: kompakter, Trennstriche ausblenden */
|
||||
.signup-progress-pills {
|
||||
display: none;
|
||||
}
|
||||
.signup-progress-mobile {
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* Form-Table: Label oberhalb des Feldes */
|
||||
.form-table,
|
||||
.form-table tbody,
|
||||
.form-table tr {
|
||||
display: block;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.form-table td {
|
||||
display: block;
|
||||
width: 100% !important;
|
||||
padding: 4px 0;
|
||||
}
|
||||
|
||||
.form-table td:first-child {
|
||||
width: 100% !important;
|
||||
font-weight: 600;
|
||||
color: #374151;
|
||||
padding-top: 10px;
|
||||
}
|
||||
|
||||
.form-table td[colspan] {
|
||||
width: 100% !important;
|
||||
}
|
||||
|
||||
.btn-row {
|
||||
flex-direction: column-reverse;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.btn-primary,
|
||||
.btn-secondary {
|
||||
width: 100%;
|
||||
padding: 12px 20px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<!-- Unscoped und mit der Kurzanmeldung geteilt (ShortSignupForm.vue bindet dieselbe Datei ein). -->
|
||||
<style src="./signupForm.css"></style>
|
||||
|
||||
@@ -0,0 +1,167 @@
|
||||
/* Geteilte Styles der Anmelde-Wizards (langer Prozess und Kurzanmeldung). */
|
||||
|
||||
/* ─── Progress (Step-Pills) ─── */
|
||||
.signup-progress {
|
||||
margin-bottom: 28px;
|
||||
}
|
||||
|
||||
.signup-progress-pills {
|
||||
display: flex;
|
||||
gap: 6px;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.signup-progress-separator {
|
||||
flex-shrink: 0;
|
||||
width: 16px;
|
||||
height: 2px;
|
||||
background: #e5e7eb;
|
||||
border-radius: 1px;
|
||||
}
|
||||
|
||||
.signup-pill {
|
||||
padding: 5px 14px;
|
||||
border-radius: 999px;
|
||||
font-size: 0.78rem;
|
||||
font-weight: 600;
|
||||
white-space: nowrap;
|
||||
border: 2px solid;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.signup-pill__check { margin-right: 4px; }
|
||||
|
||||
.signup-pill--active {
|
||||
border-color: #2563eb;
|
||||
background: #2563eb;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.signup-pill--done {
|
||||
border-color: #bbf7d0;
|
||||
background: #f0fdf4;
|
||||
color: #15803d;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.signup-pill--upcoming {
|
||||
border-color: #e5e7eb;
|
||||
background: #f9fafb;
|
||||
color: #9ca3af;
|
||||
}
|
||||
|
||||
.signup-progress-bar {
|
||||
margin-top: 10px;
|
||||
height: 3px;
|
||||
background: #e5e7eb;
|
||||
border-radius: 2px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.signup-progress-bar__fill {
|
||||
height: 100%;
|
||||
background: linear-gradient(90deg, #2563eb, #3b82f6);
|
||||
border-radius: 2px;
|
||||
transition: width 0.3s ease;
|
||||
}
|
||||
|
||||
.signup-progress-mobile {
|
||||
display: none;
|
||||
margin-top: 8px;
|
||||
font-size: 0.9rem;
|
||||
color: #374151;
|
||||
}
|
||||
|
||||
/* ─── Form-Table ─── */
|
||||
.form-table { width: 100%; border-collapse: collapse; }
|
||||
.form-table td { padding: 8px 12px 8px 0; vertical-align: top; }
|
||||
.form-table td:first-child { width: 220px; color: #374151; font-weight: 500; }
|
||||
.form-table input[type="text"],
|
||||
.form-table input[type="date"],
|
||||
.form-table input[type="email"],
|
||||
.form-table input[type="number"],
|
||||
.form-table select,
|
||||
.form-table textarea {
|
||||
width: 100%;
|
||||
padding: 6px 10px;
|
||||
border: 1px solid #d1d5db;
|
||||
border-radius: 6px;
|
||||
font-size: 0.95rem;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.btn-row { display: flex; gap: 10px; padding-top: 16px; flex-wrap: wrap; }
|
||||
.btn-primary {
|
||||
padding: 8px 20px;
|
||||
background: #2563eb;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
}
|
||||
.btn-primary:disabled { opacity: 0.5; cursor: not-allowed; }
|
||||
.btn-secondary {
|
||||
padding: 8px 20px;
|
||||
background: #f3f4f6;
|
||||
color: #374151;
|
||||
border: 1px solid #d1d5db;
|
||||
border-radius: 8px;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/* ─── Tablet ─── */
|
||||
@media (max-width: 1023px) {
|
||||
.form-table td:first-child {
|
||||
width: 160px;
|
||||
}
|
||||
}
|
||||
|
||||
/* ─── Smartphone ─── */
|
||||
@media (max-width: 639px) {
|
||||
/* Pills auf Mobile: kompakter, Trennstriche ausblenden */
|
||||
.signup-progress-pills {
|
||||
display: none;
|
||||
}
|
||||
.signup-progress-mobile {
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* Form-Table: Label oberhalb des Feldes */
|
||||
.form-table,
|
||||
.form-table tbody,
|
||||
.form-table tr {
|
||||
display: block;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.form-table td {
|
||||
display: block;
|
||||
width: 100% !important;
|
||||
padding: 4px 0;
|
||||
}
|
||||
|
||||
.form-table td:first-child {
|
||||
width: 100% !important;
|
||||
font-weight: 600;
|
||||
color: #374151;
|
||||
padding-top: 10px;
|
||||
}
|
||||
|
||||
.form-table td[colspan] {
|
||||
width: 100% !important;
|
||||
}
|
||||
|
||||
.btn-row {
|
||||
flex-direction: column-reverse;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.btn-primary,
|
||||
.btn-secondary {
|
||||
width: 100%;
|
||||
padding: 12px 20px;
|
||||
}
|
||||
}
|
||||
@@ -42,7 +42,7 @@ const next = () => {
|
||||
hasError = true
|
||||
}
|
||||
|
||||
if (props.formData.badeerlaubnis === '-1') {
|
||||
if (props.event.swimmingPermissionRequired && props.formData.badeerlaubnis === '-1') {
|
||||
errors.badeerlaubnis = 'Bitte triff eine Entscheidung. Bist du dir unsicher, kontaktiere bitte die Aktionsleitung'
|
||||
hasError = true
|
||||
}
|
||||
@@ -86,7 +86,7 @@ const next = () => {
|
||||
<ErrorText :message="errors.email_2" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<tr v-if="event.swimmingPermissionRequired">
|
||||
<td>Badeerlaubnis:</td>
|
||||
<td>
|
||||
<select v-model="formData.badeerlaubnis">
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
import AppLayout from "../../../../resources/js/layouts/AppLayout.vue";
|
||||
import ShadowedBox from "../../../Views/Components/ShadowedBox.vue";
|
||||
import SignupForm from './Partials/SignUpForm/SignupForm.vue'
|
||||
import ShortSignupForm from './Partials/ShortSignUpForm/ShortSignupForm.vue'
|
||||
import FullScreenModal from "../../../Views/Components/FullScreenModal.vue";
|
||||
import AvailableEvents from "./Partials/AvailableEvents.vue";
|
||||
import {ref} from "vue";
|
||||
@@ -98,8 +99,13 @@ function close() {
|
||||
<hr class="signup-divider" />
|
||||
|
||||
<div class="signup-body">
|
||||
<ShortSignupForm
|
||||
v-if="props.event.registrationAllowed && props.event.shortRegistration"
|
||||
:event="props.event"
|
||||
:participantData="props.participantData ?? {}"
|
||||
/>
|
||||
<SignupForm
|
||||
v-if="props.event.registrationAllowed"
|
||||
v-else-if="props.event.registrationAllowed"
|
||||
:event="props.event"
|
||||
:participantData="props.participantData ?? {}"
|
||||
:localGroups="props.localGroups ?? []"
|
||||
|
||||
Reference in New Issue
Block a user