Kurzanmeldungen
This commit is contained in:
@@ -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>
|
||||
Reference in New Issue
Block a user