393 lines
12 KiB
Vue
393 lines
12 KiB
Vue
<script setup>
|
||
import { reactive, ref } from 'vue'
|
||
import { request } from '../../../../resources/js/components/HttpClient.js'
|
||
import AppLayout from "../../../../resources/js/layouts/AppLayout.vue";
|
||
import ShadowedBox from "../../../Views/Components/ShadowedBox.vue";
|
||
import {toast} from "vue3-toastify";
|
||
import IbanInput from "../../../Views/Components/IbanInput.vue";
|
||
|
||
const props = defineProps({
|
||
personalData: Object,
|
||
})
|
||
|
||
const form = reactive({
|
||
nickname: props.personalData.nickname ?? '',
|
||
email: props.personalData.email ?? '',
|
||
phone: props.personalData.phone ?? '',
|
||
address1: props.personalData.address1 ?? '',
|
||
address2: props.personalData.address2 ?? '',
|
||
postcode: props.personalData.postcode ?? '',
|
||
city: props.personalData.city ?? '',
|
||
birthday: props.personalData.birthday ?? '',
|
||
tetanusVaccination: props.personalData.tetanusVaccination ?? '',
|
||
medications: props.personalData.medications ?? '',
|
||
allergies: props.personalData.allergies ?? '',
|
||
intolerances: props.personalData.intolerances ?? '',
|
||
eatingHabits: props.personalData.eatingHabits ?? '',
|
||
swimmingPermission: props.personalData.swimmingPermission ?? '',
|
||
firstAidPermission: props.personalData.firstAidPermission ?? '',
|
||
bankAccountOwner: props.personalData.bankAccountOwner ?? '',
|
||
bankAccountIban: props.personalData.bankAccountIban ?? '',
|
||
})
|
||
|
||
const saving = ref(false)
|
||
const successMessage = ref('')
|
||
const errorMessage = ref('')
|
||
|
||
const submit = async () => {
|
||
saving.value = true
|
||
successMessage.value = ''
|
||
errorMessage.value = ''
|
||
|
||
const result = await request('/api/v1/dashboard/personal-data', {
|
||
method: 'POST',
|
||
body: { ...form },
|
||
})
|
||
|
||
saving.value = false
|
||
|
||
if (result?.success) {
|
||
toast.success(result.message)
|
||
} else {
|
||
toast.error(result.message)
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<template>
|
||
<AppLayout title='Persönliche Daten'>
|
||
<shadowed-box class="personal-data-box">
|
||
|
||
<form @submit.prevent="submit">
|
||
<!-- Sektion: Stammdaten -->
|
||
<fieldset class="pd-fieldset">
|
||
<legend>Stammdaten</legend>
|
||
|
||
<div class="pd-grid">
|
||
<div class="pd-field pd-field--readonly">
|
||
<label>Vorname</label>
|
||
<div class="pd-readonly">{{ personalData.firstname }}</div>
|
||
</div>
|
||
|
||
<div class="pd-field pd-field--readonly">
|
||
<label>Nachname</label>
|
||
<div class="pd-readonly">{{ personalData.lastname }}</div>
|
||
</div>
|
||
|
||
<div class="pd-field">
|
||
<label for="nickname">Pfadiname</label>
|
||
<input id="nickname" type="text" v-model="form.nickname" />
|
||
</div>
|
||
|
||
<div class="pd-field">
|
||
<label for="birthday">Geburtsdatum</label>
|
||
<input id="birthday" type="date" v-model="form.birthday" />
|
||
</div>
|
||
</div>
|
||
</fieldset>
|
||
|
||
<!-- Sektion: Kontakt -->
|
||
<fieldset class="pd-fieldset">
|
||
<legend>Kontakt</legend>
|
||
|
||
<div class="pd-grid">
|
||
<div class="pd-field">
|
||
<label for="email">E-Mail</label>
|
||
<input id="email" type="email" v-model="form.email" />
|
||
</div>
|
||
|
||
<div class="pd-field">
|
||
<label for="phone">Telefon</label>
|
||
<input id="phone" type="text" v-model="form.phone" />
|
||
</div>
|
||
|
||
<div class="pd-field pd-field--full">
|
||
<label for="address1">Straße / Hausnummer</label>
|
||
<input id="address1" type="text" v-model="form.address1" />
|
||
</div>
|
||
|
||
<div class="pd-field pd-field--full">
|
||
<label for="address2">Adresszusatz</label>
|
||
<input id="address2" type="text" v-model="form.address2" />
|
||
</div>
|
||
|
||
<div class="pd-field pd-field--narrow">
|
||
<label for="postcode">PLZ</label>
|
||
<input id="postcode" type="text" v-model="form.postcode" maxlength="5" />
|
||
</div>
|
||
|
||
<div class="pd-field pd-field--wide">
|
||
<label for="city">Ort</label>
|
||
<input id="city" type="text" v-model="form.city" />
|
||
</div>
|
||
</div>
|
||
</fieldset>
|
||
|
||
<!-- Sektion: Gesundheit -->
|
||
<fieldset class="pd-fieldset">
|
||
<legend>Gesundheit</legend>
|
||
|
||
<div class="pd-grid">
|
||
<div class="pd-field pd-field--full">
|
||
<label for="medications">Medikamente</label>
|
||
<input id="medications" type="text" v-model="form.medications" />
|
||
</div>
|
||
|
||
<div class="pd-field pd-field--full">
|
||
<label for="allergies">Allergien</label>
|
||
<input id="allergies" type="text" v-model="form.allergies" />
|
||
</div>
|
||
|
||
<div class="pd-field pd-field--full">
|
||
<label for="intolerances">Unverträglichkeiten</label>
|
||
<input id="intolerances" type="text" v-model="form.intolerances" />
|
||
</div>
|
||
|
||
<div class="pd-field">
|
||
<label for="tetanus">Letzte Tetanus-Impfung</label>
|
||
<input id="tetanus" type="date" v-model="form.tetanusVaccination" />
|
||
</div>
|
||
|
||
<div class="pd-field">
|
||
<label for="eating">Ernährungsgewohnheiten</label>
|
||
<select id="eating" v-model="form.eatingHabits">
|
||
<option value="EATING_HABIT_VEGAN">Vegan</option>
|
||
<option value="EATING_HABIT_VEGETARIAN">Vegetarisch</option>
|
||
<option value="EATING_HABIT_OMNIVOR">Omnivor</option>
|
||
</select>
|
||
</div>
|
||
</div>
|
||
</fieldset>
|
||
|
||
<!-- Sektion: Erlaubnisse -->
|
||
<fieldset class="pd-fieldset">
|
||
<legend>Erlaubnisse</legend>
|
||
|
||
<div class="pd-grid">
|
||
<div class="pd-field pd-field--full">
|
||
<label for="swimming">Badeerlaubnis</label>
|
||
<select id="swimming" v-model="form.swimmingPermission">
|
||
<option value="SWIMMING_PERMISSION_ALLOWED">Erteilt, kann schwimmen</option>
|
||
<option value="SWIMMING_PERMISSION_LIMITED">Erteilt, kann nicht schwimmen</option>
|
||
<option value="SWIMMING_PERMISSION_DENIED">Nicht erteilt</option>
|
||
</select>
|
||
</div>
|
||
|
||
<div class="pd-field pd-field--full">
|
||
<label for="firstaid">Erste-Hilfe-Erlaubnis</label>
|
||
<select id="firstaid" v-model="form.firstAidPermission">
|
||
<option value="FIRST_AID_PERMISSION_ALLOWED">Erweiterte Erste Hilfe erlaubt</option>
|
||
<option value="FIRST_AID_PERMISSION_DENIED">Erweiterte Erste Hilfe verweigert</option>
|
||
</select>
|
||
</div>
|
||
</div>
|
||
</fieldset>
|
||
|
||
<!-- Sektion: Bankverbindung -->
|
||
<fieldset class="pd-fieldset">
|
||
<legend>Bankverbindung</legend>
|
||
|
||
<div class="pd-grid">
|
||
<div class="pd-field pd-field--full">
|
||
<label for="owner">Kontoinhaber*in</label>
|
||
<input id="owner" type="text" v-model="form.bankAccountOwner" />
|
||
</div>
|
||
|
||
<div class="pd-field pd-field--full">
|
||
<label for="iban">IBAN</label>
|
||
<IbanInput id="iban" v-model="form.bankAccountIban" />
|
||
</div>
|
||
</div>
|
||
</fieldset>
|
||
|
||
<div class="pd-actions">
|
||
<button type="submit" class="button pd-submit" :disabled="saving">
|
||
{{ saving ? 'Wird gespeichert…' : 'Speichern' }}
|
||
</button>
|
||
</div>
|
||
</form>
|
||
</shadowed-box>
|
||
</AppLayout>
|
||
</template>
|
||
|
||
<style scoped>
|
||
.personal-data-box {
|
||
width: 95%;
|
||
margin: 20px auto;
|
||
padding: 20px;
|
||
overflow-x: hidden;
|
||
}
|
||
|
||
.pd-fieldset {
|
||
border: 1px solid #e5e7eb;
|
||
border-radius: 10px;
|
||
padding: 16px 20px 20px;
|
||
margin-bottom: 18px;
|
||
background-color: #ffffff;
|
||
box-shadow: 0 0 8px #efefef;
|
||
}
|
||
|
||
.pd-fieldset legend {
|
||
font-weight: 700;
|
||
font-size: 1rem;
|
||
padding: 4px 12px;
|
||
background-color: #f8fafc;
|
||
border: 1px solid #e5e7eb;
|
||
border-radius: 8px;
|
||
color: #1d4899;
|
||
}
|
||
|
||
/* Grid: 2-spaltig auf Desktop */
|
||
.pd-grid {
|
||
display: grid;
|
||
grid-template-columns: 1fr 1fr;
|
||
gap: 14px 20px;
|
||
}
|
||
|
||
.pd-field {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 4px;
|
||
min-width: 0;
|
||
}
|
||
|
||
.pd-field--full {
|
||
grid-column: 1 / -1;
|
||
}
|
||
|
||
.pd-field--narrow {
|
||
grid-column: span 1;
|
||
max-width: 180px;
|
||
}
|
||
|
||
.pd-field--wide {
|
||
grid-column: span 1;
|
||
}
|
||
|
||
.pd-field label {
|
||
font-size: 0.85rem;
|
||
font-weight: 600;
|
||
color: #374151;
|
||
}
|
||
|
||
.pd-field input,
|
||
.pd-field select {
|
||
width: 100%;
|
||
padding: 8px 10px;
|
||
border: 1px solid #d1d5db;
|
||
border-radius: 6px;
|
||
font-size: 0.95rem;
|
||
box-sizing: border-box;
|
||
background-color: #ffffff;
|
||
}
|
||
|
||
.pd-field input:focus,
|
||
.pd-field select:focus {
|
||
outline: none;
|
||
border-color: #1d4899;
|
||
}
|
||
|
||
.pd-readonly {
|
||
padding: 8px 10px;
|
||
border: 1px dashed #e5e7eb;
|
||
border-radius: 6px;
|
||
background-color: #f9fafb;
|
||
color: #6b7280;
|
||
font-size: 0.95rem;
|
||
}
|
||
|
||
.pd-actions {
|
||
display: flex;
|
||
justify-content: flex-end;
|
||
padding-top: 8px;
|
||
}
|
||
|
||
.pd-submit {
|
||
padding: 10px 28px;
|
||
font-weight: 600;
|
||
cursor: pointer;
|
||
border: 1px solid #809dd5;
|
||
background-color: #ffffff;
|
||
}
|
||
|
||
.pd-submit:hover:not(:disabled) {
|
||
background-color: #1d4899;
|
||
color: #ffffff;
|
||
}
|
||
|
||
.pd-submit:disabled {
|
||
opacity: 0.6;
|
||
cursor: not-allowed;
|
||
}
|
||
|
||
/* ─── Tablet (640–1023px) ─── */
|
||
@media (max-width: 1023px) {
|
||
.personal-data-box {
|
||
width: 100%;
|
||
margin: 10px auto;
|
||
padding: 14px;
|
||
}
|
||
|
||
.pd-fieldset {
|
||
padding: 12px 14px 16px;
|
||
}
|
||
|
||
.pd-grid {
|
||
gap: 12px 16px;
|
||
}
|
||
}
|
||
|
||
/* ─── Smartphone (< 640px) ─── */
|
||
@media (max-width: 639px) {
|
||
.personal-data-box {
|
||
width: 100%;
|
||
margin: 0;
|
||
padding: 10px;
|
||
border-radius: 0;
|
||
}
|
||
|
||
.pd-fieldset {
|
||
padding: 10px 12px 14px;
|
||
margin-bottom: 14px;
|
||
}
|
||
|
||
.pd-fieldset legend {
|
||
font-size: 0.9rem;
|
||
padding: 3px 10px;
|
||
}
|
||
|
||
/* Grid: 1-spaltig auf Smartphone */
|
||
.pd-grid {
|
||
grid-template-columns: 1fr;
|
||
gap: 10px;
|
||
}
|
||
|
||
/* Auch "narrow" und "wide" werden volle Breite */
|
||
.pd-field--narrow,
|
||
.pd-field--wide,
|
||
.pd-field--full {
|
||
grid-column: 1 / -1;
|
||
max-width: 100%;
|
||
}
|
||
|
||
.pd-field label {
|
||
font-size: 0.82rem;
|
||
}
|
||
|
||
.pd-field input,
|
||
.pd-field select {
|
||
padding: 10px;
|
||
font-size: 1rem; /* iOS Zoom-Prevention bei >=16px */
|
||
}
|
||
|
||
.pd-actions {
|
||
justify-content: stretch;
|
||
}
|
||
|
||
.pd-submit {
|
||
width: 100%;
|
||
padding: 14px;
|
||
}
|
||
}
|
||
</style>
|