497 lines
20 KiB
Vue
497 lines
20 KiB
Vue
<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>
|