Files
mareike/app/Domains/Event/Views/Partials/ParticipantData.vue
T
2026-08-12 17:18:45 +02:00

497 lines
20 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<script setup>
import {computed, onMounted, reactive, watch} from "vue";
import AmountInput from "../../../../Views/Components/AmountInput.vue";
import DialableTelephoneNumber from "../../../../Views/Components/DialableTelephoneNumber.vue";
const staticProps = defineProps({
editMode: Boolean,
participant: Object,
event: Object,
});
const props = reactive({
participant: staticProps.participant,
});
onMounted(async () => {
const response = await fetch('/api/v1/event/participant/' + staticProps.participant.identifier + '/');
const data = await response.json();
Object.assign(props, data);
});
const emit = defineEmits([
'closeParticipantDetails',
'markCocExisting',
'paymentComplete',
'cancelParticipation',
'editParticipant',
'saveParticipant',
]);
const form = reactive({
firstname: '',
lastname: '',
nickname: '',
address_1: '',
address_2: '',
postcode: '',
city: '',
localgroup: '',
birthday: '',
email_1: '',
phone_1: '',
contact_person: '',
email_2: '',
phone_2: '',
arrival: '',
departure: '',
participationType: '',
eatingHabit: '',
paymentMethod: '',
allergies: '',
intolerances: '',
medications: '',
extendedFirstAid: '',
swimmingPermission: '',
tetanusVaccination: '',
notes: '',
amountPaid: '',
amountExpected: '',
cocStatus: '',
participationOptions: {},
selectedAddons: {},
});
// Teilnahmeoptionen des Events (Definition mit Titel/Frage/Optionen).
const participationQuestions = computed(() => staticProps.event?.participationOptions ?? []);
// Zusatzoptionen (Event-Addons) des Events.
const eventAddons = computed(() => staticProps.event?.addons ?? []);
// Gewählte Antwort (Options-Label) eines Teilnehmers zu einer Frage für die Ansicht „Titel: Antwort".
function answerLabelFor(questionKey) {
const answer = (props.participant?.participationOptions ?? []).find(o => o.questionKey === questionKey);
return answer?.valueLabel ?? '—';
}
// Hat der Teilnehmer diesen Zusatz gebucht? für die Ansicht.
function isAddonSelected(addonKey) {
return (props.participant?.selectedAddons ?? []).some(a => a.addonKey === addonKey);
}
watch(
() => props.participant,
(participant) => {
form.firstname = participant?.firstname ?? '';
form.lastname = participant?.lastname ?? '';
form.nickname = participant?.nickname ?? '';
form.address_1 = participant?.address_1 ?? '';
form.address_2 = participant?.address_2 ?? '';
form.postcode = participant?.postcode ?? '';
form.city = participant?.city ?? '';
form.localgroup = participant?.local_group ?? '';
form.birthday = participant?.birthdayDate ?? '';
form.email_1 = participant?.email_1 ?? '';
form.phone_1 = participant?.phone_1 ?? '';
form.contact_person = participant?.contact_person ?? '';
form.email_2 = participant?.email_2 ?? '';
form.phone_2 = participant?.phone_2 ?? '';
form.arrival = participant?.arrivalDate ?? '';
form.departure = participant?.departureDate ?? '';
form.participationType = participant?.participation_type ?? '';
form.eatingHabit = participant?.eating_habit ?? '';
form.paymentMethod = participant?.payment_method ?? '';
form.allergies = participant?.allergies ?? '';
form.intolerances = participant?.intolerances ?? '';
form.medications = participant?.medications ?? '';
form.extendedFirstAid = participant?.first_aid_permission ?? '';
form.swimmingPermission = participant?.swimming_permission ?? '';
form.tetanusVaccination = participant?.tetanusVaccinationEdit ?? '';
form.notes = participant?.notes ?? '';
form.amountPaid = participant?.amountPaid.short ?? '';
form.amountExpected = participant?.amountExpected.short ?? '';
form.cocStatus = participant?.efz_status ?? '';
form.participationOptions = Object.fromEntries(
(participant?.participationOptions ?? []).map(o => [o.questionKey, o.value])
);
form.selectedAddons = Object.fromEntries(
(participant?.selectedAddons ?? []).map(a => [a.addonKey, true])
);
},
{ immediate: true }
);
function markCocExisting(participant) {
emit('markCocExisting', participant);
close();
}
function paymentComplete(participant) {
emit('paymentComplete', participant);
close();
}
function close() {
emit('closeParticipantDetails');
}
function cancelParticipation(participant) {
emit('cancelParticipation', participant);
close();
}
function enableEditMode() {
emit('editParticipant');
}
function saveParticipant() {
emit('saveParticipant', { ...form });
close();
}
</script>
<template>
<div>
<h2>Anmeldedetails</h2>
<div class="participationData">
<div>
<h3>Persönliche Daten</h3>
<table>
<tr>
<th>Name</th>
<td>
<span v-if="!staticProps.editMode">
{{ props.participant.firstname }} {{ props.participant.lastname }}
</span>
<span v-else>
<input v-model="form.firstname" type="text" placeholder="Vorname" />
<input v-model="form.lastname" type="text" placeholder="Nachname" />
</span>
</td>
</tr>
<tr>
<th>Pfadiname</th>
<td>
<span v-if="!staticProps.editMode">{{ props.participant.nickname }}</span>
<input v-else v-model="form.nickname" type="text" />
</td>
</tr>
<tr>
<th>Anschrift</th>
<td>
<span v-if="!staticProps.editMode">
{{ props.participant.address_1 }}<br />
{{ props.participant.address_2 }}<br />
{{ props.participant.postcode }}
{{ props.participant.city }}
</span>
<span v-else>
<input v-model="form.address_1" type="text" placeholder="Adresse 1" />
<input v-model="form.address_2" type="text" placeholder="Adresse 2" />
<input v-model="form.postcode" type="text" placeholder="PLZ" />
<input v-model="form.city" type="text" placeholder="Ort" />
</span>
</td>
</tr>
<tr>
<th>Stamm</th>
<td>
<span v-if="!staticProps.editMode">{{ props.participant.localgroup }}</span>
<select v-else v-model="form.localgroup">
<option v-for="group in staticProps.event.contributingLocalGroups" :key="group.id" :value="group.slug">{{ group.name }}</option>
</select>
</td>
</tr>
<tr>
<th>Geburtsdatum</th>
<td>
<span v-if="!staticProps.editMode">{{ props.participant.birthday }}</span>
<input v-else v-model="form.birthday" type="date" />
</td>
</tr>
</table>
</div>
<div>
<h3>Kontaktdaten</h3>
<table>
<tr>
<th>E-Mail</th>
<td>
<span v-if="!staticProps.editMode">{{ props.participant.email_1 }}</span>
<input v-else v-model="form.email_1" type="email" />
</td>
</tr>
<tr>
<th>Telefon</th>
<td>
<DialableTelephoneNumber v-if="!staticProps.editMode" :number="props.participant.phone_1" />
<input v-else v-model="form.phone_1" type="text" />
</td>
</tr>
<tr>
<th>Ansprechperson</th>
<td>
<span v-if="!staticProps.editMode">{{ props.participant.contact_person }}</span>
<input v-else v-model="form.contact_person" type="text" />
</td>
</tr>
<tr>
<th>Ansprechperson E-Mail</th>
<td>
<span v-if="!staticProps.editMode">{{ props.participant.email_2 }}</span>
<input v-else v-model="form.email_2" type="email" />
</td>
</tr>
<tr>
<th>Ansprechperson Telefon</th>
<td>
<DialableTelephoneNumber v-if="!staticProps.editMode" :number="props.participant.phone_2" />
<input v-else v-model="form.phone_2" type="text" />
</td>
</tr>
</table>
</div>
</div>
<div class="participationData">
<div>
<h3>Teilnahmedetails</h3>
<table>
<tr>
<th>Anreise</th>
<td>
<span v-if="!staticProps.editMode">{{ props.participant.arrival }}</span>
<input v-else v-model="form.arrival" type="date" />
</td>
</tr>
<tr>
<th>Abreise</th>
<td>
<span v-if="!staticProps.editMode">{{ props.participant.departure }}</span>
<input v-else v-model="form.departure" type="date" />
</td>
</tr>
<tr>
<th>Teilnahmegruppe</th>
<td>
<span v-if="!staticProps.editMode">{{ props.participant.participationType }}</span>
<select v-else v-model="form.participationType">
<option
v-for="participationType in staticProps.event.participationTypes"
:value="participationType.type.slug"
>
{{ participationType.type.name }}
</option>
</select>
</td>
</tr>
<tr>
<th>Ernährung</th>
<td>
<span v-if="!staticProps.editMode">{{ props.participant.eatingHabit }}</span>
<select v-else v-model="form.eatingHabit">
<option
v-for="eatingHabit in staticProps.event.eatingHabits"
:value="eatingHabit.slug"
>
{{ eatingHabit.name }}
</option>
</select>
</td>
</tr>
<tr>
<th>Zahlungsmethode</th>
<td>
<span v-if="!staticProps.editMode">{{ props.participant.paymentMethod }}</span>
<select v-else v-model="form.paymentMethod">
<option
v-for="paymentMethod in staticProps.event.paymentMethods"
:value="paymentMethod.slug"
>
{{ paymentMethod.name }}
</option>
</select>
</td>
</tr>
<tr>
<th>eFZ-Status</th>
<td>
<span v-if="!staticProps.editMode">{{ props.participant.efzStatusReadable }}</span>
<select v-else v-model="form.cocStatus">
<option value="not_checked">Nicht geprüft</option>
<option value="not_required">Nicht erforderlich</option>
<option value="checked_valid">Geprüft und Vorhanden</option>
<option value="checked_invalid">Nicht vorhanden</option>
</select>
</td>
</tr>
<tr>
<th>Beitrag</th>
<td>
<span v-if="!staticProps.editMode">{{ props.participant.amountPaid.readable }} / {{ props.participant.amountExpected.readable }}</span>
<span v-else>
<AmountInput v-model="form.amountPaid" style="width:74px" /> Euro
/
<AmountInput v-model="form.amountExpected" style="width: 74px" /> Euro
</span>
</td>
</tr>
</table>
</div>
<div>
<h3>Medizinische Informationen</h3>
<table>
<tr>
<th>Allergien</th>
<td>
<span v-if="!staticProps.editMode">{{ props.participant.allergies }}</span>
<input type="text" v-else v-model="form.allergies" />
</td>
</tr>
<tr>
<th>Unverträglichkeiten</th>
<td>
<span v-if="!staticProps.editMode">{{ props.participant.intolerances }}</span>
<input type="text" v-else v-model="form.intolerances" />
</td>
</tr>
<tr>
<th>Medikamente</th>
<td>
<span v-if="!staticProps.editMode">{{ props.participant.medications }}</span>
<input type="text" v-else v-model="form.medications" />
</td>
</tr>
<tr>
<th>Erweiterte Erste Hilfe</th>
<td>
<span v-if="!staticProps.editMode">{{ props.participant.extendedFirstAid }}</span>
<select v-else v-model="form.extendedFirstAid">
<option value="FIRST_AID_PERMISSION_ALLOWED">Erlaubt</option>
<option value="FIRST_AID_PERMISSION_DENIED">Verweigert</option>
</select>
</td>
</tr>
<tr>
<th>Badeerlaubnis</th>
<td>
<span v-if="!staticProps.editMode">{{ props.participant.swimmingPermission }}</span>
<select v-else v-model="form.swimmingPermission">
<option value="SWIMMING_PERMISSION_ALLOWED">Vorhanden, kann schwimmen</option>
<option value="SWIMMING_PERMISSION_LIMITED">Vorhanden, kann nicht schwimmen</option>
<option value="SWIMMING_PERMISSION_DENIED">Verweigert</option>
</select>
</td>
</tr>
<tr>
<th>Letzte Tetanus-Impfung</th>
<td>
<span v-if="!staticProps.editMode">{{ props.participant.tetanusVaccination }}</span>
<input v-else v-model="form.tetanusVaccination" type="date" />
</td>
</tr>
<tr>
<th>Anmerkungen</th>
<td>
<span v-if="!staticProps.editMode">{{ props.participant.notes }}</span>
<textarea v-else v-model="form.notes"></textarea>
</td>
</tr>
</table>
</div>
</div>
<div class="participationData" v-if="participationQuestions.length > 0 || eventAddons.length > 0">
<div>
<template v-if="participationQuestions.length > 0">
<h3>Teilnahmeoptionen</h3>
<table>
<tr v-for="question in participationQuestions" :key="question.key">
<th>{{ question.title || question.label }}</th>
<td>
<span v-if="!staticProps.editMode">{{ answerLabelFor(question.key) }}</span>
<select v-else v-model="form.participationOptions[question.key]">
<option value=""> keine </option>
<option v-for="option in question.options" :key="option.value"
:value="option.value">
{{ option.label }}
</option>
</select>
</td>
</tr>
</table>
</template>
</div>
<div>
<template v-if="eventAddons.length > 0">
<h3>Zusatzoptionen</h3>
<table>
<tr v-for="addon in eventAddons" :key="addon.key">
<th>{{ addon.title }}</th>
<td>
<span v-if="!staticProps.editMode">{{ isAddonSelected(addon.key) ? 'Ja' : '—' }}</span>
<input v-else type="checkbox" v-model="form.selectedAddons[addon.key]"/>
</td>
</tr>
</table>
</template>
</div>
</div>
</div>
<button v-if="!staticProps.editMode" class="button" @click="enableEditMode">Bearbeiten</button>
<button v-else class="button" @click="saveParticipant">Speichern</button>
<button v-if="!props.participant.unregistered" class="button" @click="paymentComplete(props.participant)">Zahlung vollständig</button>
<button v-if="!props.participant.unregistered" class="button" @click="markCocExisting(props.participant)">eFZ liegt vor</button>
<button v-if="!props.participant.unregistered" class="button" @click="cancelParticipation(props.participant)">Abmelden</button>
<button class="button" @click="close">Schließen</button>
</template>
<style scoped>
.participationData {
display: flex;
margin-bottom: 20px;
gap: 20px;
}
.participationData table tr th {
width: 200px;
}
.participationData div {
flex: 1;
vertical-align: top;
}
input[type="text"],
input[type="email"],
input[type="date"],
textarea
{
width: 250px
}
textarea {
height: 100px;
}
select {
width: 262px;
}
</style>