Running
This commit is contained in:
19
app/Domains/Event/Views/ListAvailable.vue
Normal file
19
app/Domains/Event/Views/ListAvailable.vue
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
<script setup>
|
||||||
|
import AppLayout from "../../../../resources/js/layouts/AppLayout.vue";
|
||||||
|
import AvailableEvents from "./Partials/AvailableEvents.vue";
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
events: Array,
|
||||||
|
})
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<AppLayout title="Verfügbare Veranstaltungen">
|
||||||
|
<AvailableEvents :events="props.events" />
|
||||||
|
</AppLayout>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
||||||
150
app/Domains/Event/Views/Partials/SignUpForm/SignupForm.vue
Normal file
150
app/Domains/Event/Views/Partials/SignUpForm/SignupForm.vue
Normal file
@@ -0,0 +1,150 @@
|
|||||||
|
<script setup>
|
||||||
|
import { useSignupForm } from './composables/useSignupForm.js'
|
||||||
|
import StepAge from './steps/StepAge.vue'
|
||||||
|
import StepContactPerson from './steps/StepContactPerson.vue'
|
||||||
|
import StepPersonalData from './steps/StepPersonalData.vue'
|
||||||
|
import StepRegistrationMode from './steps/StepRegistrationMode.vue'
|
||||||
|
import StepArrival from './steps/StepArrival.vue'
|
||||||
|
import StepAddons from './steps/StepAddons.vue'
|
||||||
|
import StepPhotoPermissions from './steps/StepPhotoPermissions.vue'
|
||||||
|
import StepAllergies from './steps/StepAllergies.vue'
|
||||||
|
import StepSummary from './steps/StepSummary.vue'
|
||||||
|
import SubmitSuccess from './after-submit/SubmitSuccess.vue'
|
||||||
|
import SubmitAlreadyExists from './after-submit/SubmitAlreadyExists.vue'
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
event: Object,
|
||||||
|
participantData: Object,
|
||||||
|
localGroups: Array,
|
||||||
|
})
|
||||||
|
|
||||||
|
console.log(props.participantData);
|
||||||
|
|
||||||
|
const emit = defineEmits(['registrationDone'])
|
||||||
|
|
||||||
|
const {
|
||||||
|
currentStep, goToStep, formData, selectedAddons,
|
||||||
|
submit, submitting, submitResult, summaryLoading, summaryAmount
|
||||||
|
} = useSignupForm(props.event, props.participantData)
|
||||||
|
|
||||||
|
const steps = [
|
||||||
|
{ step: 1, label: 'Alter' },
|
||||||
|
{ step: 2, label: 'Kontaktperson' },
|
||||||
|
{ step: 3, label: 'Persönliche Daten' },
|
||||||
|
{ step: 4, label: 'An-/Abreise' },
|
||||||
|
{ step: 5, label: 'Teilnahmegruppe' },
|
||||||
|
{ step: 6, label: 'Zusatzoptionen' },
|
||||||
|
{ step: 7, label: 'Fotoerlaubnis' },
|
||||||
|
{ step: 8, label: 'Allergien' },
|
||||||
|
{ step: 9, label: 'Zusammenfassung' },
|
||||||
|
]
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<!-- Nach Submit -->
|
||||||
|
<SubmitSuccess v-if="submitResult?.type === 'success'" :data="submitResult.data" />
|
||||||
|
<SubmitAlreadyExists v-else-if="submitResult?.type === 'exists'" :data="submitResult.data" />
|
||||||
|
|
||||||
|
<template v-else>
|
||||||
|
<!-- Fortschrittsleiste (ab Step 2) -->
|
||||||
|
<div v-if="currentStep > 1" style="margin-bottom: 28px;">
|
||||||
|
<div style="display: flex; gap: 6px; flex-wrap: wrap; align-items: center;">
|
||||||
|
<template v-for="(s, index) in steps.filter(s => s.step > 1)" :key="s.step">
|
||||||
|
<!-- Trennlinie zwischen Pills -->
|
||||||
|
<div v-if="index > 0" style="flex-shrink: 0; width: 16px; height: 2px; background: #e5e7eb; border-radius: 1px;"></div>
|
||||||
|
<div
|
||||||
|
:style="{
|
||||||
|
padding: '5px 14px',
|
||||||
|
borderRadius: '999px',
|
||||||
|
fontSize: '0.78rem',
|
||||||
|
fontWeight: '600',
|
||||||
|
whiteSpace: 'nowrap',
|
||||||
|
border: '2px solid',
|
||||||
|
borderColor: currentStep === s.step ? '#2563eb' : currentStep > s.step ? '#bbf7d0' : '#e5e7eb',
|
||||||
|
background: currentStep === s.step ? '#2563eb' : currentStep > s.step ? '#f0fdf4' : '#f9fafb',
|
||||||
|
color: currentStep === s.step ? 'white' : currentStep > s.step ? '#15803d' : '#9ca3af',
|
||||||
|
cursor: currentStep > s.step ? 'pointer' : 'default',
|
||||||
|
}"
|
||||||
|
@click="currentStep > s.step ? goToStep(s.step) : null"
|
||||||
|
>
|
||||||
|
<span v-if="currentStep > s.step" style="margin-right: 4px;">✓</span>
|
||||||
|
{{ s.label }}
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
<!-- Fortschrittsbalken -->
|
||||||
|
<div style="margin-top: 10px; height: 3px; background: #e5e7eb; border-radius: 2px; overflow: hidden;">
|
||||||
|
<div
|
||||||
|
:style="{
|
||||||
|
height: '100%',
|
||||||
|
background: 'linear-gradient(90deg, #2563eb, #3b82f6)',
|
||||||
|
borderRadius: '2px',
|
||||||
|
width: ((currentStep - 2) / (steps.length - 2) * 100) + '%',
|
||||||
|
transition: 'width 0.3s ease',
|
||||||
|
}"
|
||||||
|
></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Steps -->
|
||||||
|
<form @submit.prevent="submit">
|
||||||
|
<StepAge v-if="currentStep === 1" :event="event" @next="goToStep" />
|
||||||
|
<StepContactPerson v-if="currentStep === 2" :formData="formData" :event="event" @next="goToStep" @back="goToStep" />
|
||||||
|
<StepPersonalData v-if="currentStep === 3" :formData="formData" :localGroups="localGroups" @next="goToStep" @back="goToStep" />
|
||||||
|
<StepArrival v-if="currentStep === 4" :formData="formData" :event="event" @next="goToStep" @back="goToStep" />
|
||||||
|
<StepRegistrationMode v-if="currentStep === 5" :formData="formData" :event="event" @next="goToStep" @back="goToStep" />
|
||||||
|
<StepAddons v-if="currentStep === 6" :formData="formData" :event="event" :selectedAddons="selectedAddons" @next="goToStep" @back="goToStep" />
|
||||||
|
<StepPhotoPermissions v-if="currentStep === 7" :formData="formData" :event="event" @next="goToStep" @back="goToStep" />
|
||||||
|
<StepAllergies v-if="currentStep === 8" :formData="formData" :event="event" @next="goToStep" @back="goToStep" />
|
||||||
|
<StepSummary
|
||||||
|
v-if="currentStep === 9"
|
||||||
|
:formData="formData"
|
||||||
|
:event="event"
|
||||||
|
:summaryAmount="summaryAmount"
|
||||||
|
:summaryLoading="summaryLoading"
|
||||||
|
:submitting="submitting"
|
||||||
|
@back="goToStep"
|
||||||
|
@submit="submit"
|
||||||
|
/>
|
||||||
|
</form>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.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 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; }
|
||||||
|
.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;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
119
app/Domains/Event/Views/Signup.vue
Normal file
119
app/Domains/Event/Views/Signup.vue
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
<script setup>
|
||||||
|
|
||||||
|
import AppLayout from "../../../../resources/js/layouts/AppLayout.vue";
|
||||||
|
import ShadowedBox from "../../../Views/Components/ShadowedBox.vue";
|
||||||
|
import SignupForm from './Partials/SignUpForm/SignupForm.vue'
|
||||||
|
import FullScreenModal from "../../../Views/Components/FullScreenModal.vue";
|
||||||
|
import AvailableEvents from "./Partials/AvailableEvents.vue";
|
||||||
|
import {ref} from "vue";
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
event: Object,
|
||||||
|
availableEvents: Array,
|
||||||
|
participantData: Object,
|
||||||
|
localGroups: Array,
|
||||||
|
})
|
||||||
|
|
||||||
|
const showSignup = ref(true)
|
||||||
|
const registrationDone = ref(false)
|
||||||
|
function close() {
|
||||||
|
showSignup.value = false
|
||||||
|
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<AppLayout title="Für Veranstaltung anmelden">
|
||||||
|
<FullScreenModal :show="showSignup" @close="close">
|
||||||
|
|
||||||
|
<shadowed-box style="width: 95%; margin: 30px auto; padding: 0; overflow: hidden; border-radius: 12px;">
|
||||||
|
|
||||||
|
<!-- Header -->
|
||||||
|
<div v-if="props.event.registrationAllowed" style="background: linear-gradient(135deg, #1e40af, #3b82f6); padding: 28px 32px; color: white;">
|
||||||
|
<div style="display: flex; align-items: center; gap: 14px; flex-wrap: wrap;">
|
||||||
|
<h2 style="margin: 0; font-size: 1.5rem; font-weight: 700;">{{ props.event.name }}</h2>
|
||||||
|
<span style="background: rgba(255,255,255,0.2); color: white; padding: 4px 14px; border-radius: 999px; font-size: 0.8rem; font-weight: 600; white-space: nowrap; border: 1px solid rgba(255,255,255,0.4);">
|
||||||
|
✓ Anmeldung offen
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<p style="margin: 8px 0 0 0; opacity: 0.85; font-size: 0.95rem;">
|
||||||
|
📍 {{ props.event.postalCode }} {{ props.event.location }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div v-else style="background: linear-gradient(135deg, #991b1b, #dc2626); padding: 28px 32px; color: white;">
|
||||||
|
<div style="display: flex; align-items: center; gap: 14px; flex-wrap: wrap;">
|
||||||
|
<h2 style="margin: 0; font-size: 1.5rem; font-weight: 700;">{{ props.event.name }}</h2>
|
||||||
|
<span style="background: rgba(255,0,0,0.2); color: #fecaca; padding: 4px 14px; border-radius: 999px; font-size: 0.8rem; font-weight: 600; white-space: nowrap; border: 1px solid rgba(255,100,100,0.4);">
|
||||||
|
✗ Anmeldung geschlossen
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<p style="margin: 8px 0 0 0; opacity: 0.85; font-size: 0.95rem;">
|
||||||
|
📍 {{ props.event.postalCode }} {{ props.event.location }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Body -->
|
||||||
|
<div style="padding: 28px 32px;">
|
||||||
|
|
||||||
|
<!-- Info-Grid -->
|
||||||
|
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 16px; margin-bottom: 24px;">
|
||||||
|
|
||||||
|
<!-- Zeile 1 links: Zeitraum -->
|
||||||
|
<div style="background: #f8fafc; border-radius: 8px; padding: 16px;">
|
||||||
|
<div style="font-size: 0.75rem; color: #6b7280; font-weight: 600; text-transform: uppercase; letter-spacing: 0.05em; margin-bottom: 4px;">Veranstaltungszeitraum</div>
|
||||||
|
<div style="font-size: 1rem; color: #111827; font-weight: 500;">{{ props.event.eventBegin }} – {{ props.event.eventEnd }}</div>
|
||||||
|
<div style="font-size: 0.85rem; color: #6b7280;">{{ props.event.duration }} Tage</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Zeile 1 rechts: Erstattungsrichtlinien -->
|
||||||
|
<div style="background: #f0f9ff; border-radius: 8px; padding: 16px; border-left: 3px solid #0ea5e9;">
|
||||||
|
<div style="font-size: 0.75rem; color: #0369a1; font-weight: 600; text-transform: uppercase; letter-spacing: 0.05em; margin-bottom: 8px;">Erstattungsrichtlinien</div>
|
||||||
|
<div style="color: #0c4a6e; font-size: 0.875rem; line-height: 1.8;">
|
||||||
|
<div>100 % bis {{ props.event.earlyBirdEnd.formatted }}</div>
|
||||||
|
<div>{{ props.event.refundAfterEarlyBirdEnd }} % bis {{ props.event.registrationFinalEnd.formatted }}</div>
|
||||||
|
<div>Danach nur bei Nachrückplätzen</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Zeile 2 links: Anmeldeschluss -->
|
||||||
|
<div style="background: #f8fafc; border-radius: 8px; padding: 16px;">
|
||||||
|
<div style="font-size: 0.75rem; color: #6b7280; font-weight: 600; text-transform: uppercase; letter-spacing: 0.05em; margin-bottom: 4px;">Anmeldeschluss</div>
|
||||||
|
<div style="font-size: 1rem; color: #111827; font-weight: 500; margin-bottom: 20px;">{{ props.event.registrationFinalEnd.formatted }}</div>
|
||||||
|
|
||||||
|
<div style="font-size: 0.75rem; color: #366a34; font-weight: 600; text-transform: uppercase; letter-spacing: 0.05em; margin-bottom: 4px;">Frühbucher bis</div>
|
||||||
|
<div style="font-size: 1rem; color: #366a34; font-weight: 500;">{{ props.event.earlyBirdEnd.formatted }}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Zeile 2 rechts: Kontakt -->
|
||||||
|
<div style="background: #f8fafc; border-radius: 8px; padding: 16px;">
|
||||||
|
<div style="font-size: 0.75rem; color: #6b7280; font-weight: 600; text-transform: uppercase; letter-spacing: 0.05em; margin-bottom: 6px;">Kontakt</div>
|
||||||
|
<p style="margin: 0 0 6px 0; color: #374151; font-size: 0.9rem; line-height: 1.6;">
|
||||||
|
Hast du Fragen zur Veranstaltung oder deiner Anmeldung? Kontaktiere uns per E-Mail:
|
||||||
|
</p>
|
||||||
|
<a :href="'mailto:' + props.event.email" style="font-size: 0.95rem; color: #2563eb; text-decoration: none; font-weight: 500;">{{ props.event.email }}</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<hr style="margin: 0 32px; border: none; border-top: 1px solid #e5e7eb;" />
|
||||||
|
<div style="padding: 28px 32px;">
|
||||||
|
<SignupForm
|
||||||
|
:event="props.event"
|
||||||
|
:participantData="props.participantData ?? {}"
|
||||||
|
:localGroups="props.localGroups ?? []"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</shadowed-box>
|
||||||
|
</FullScreenModal>
|
||||||
|
<AvailableEvents v-if="!registrationDone" :events="props.availableEvents" />
|
||||||
|
<div v-else style="text-align: center; padding: 20px;">
|
||||||
|
Registrierung komplett
|
||||||
|
</div>
|
||||||
|
</AppLayout>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
||||||
Reference in New Issue
Block a user