enabled creating interest preorders without any wohneinheit

This commit is contained in:
Luca Haid
2025-07-15 14:03:23 +02:00
parent 26c0afce5d
commit 6d7260f917
2 changed files with 112 additions and 88 deletions

View File

@@ -197,13 +197,21 @@
if (!addressForm.housenumber) return;
isLoading.value = true;
try {
const params = { ...addressForm, ...areaIdentifierParams.value, format: 'flat' };
const params = { ...addressForm, ...areaIdentifierParams.value, format: 'flat', orderType: orderType.value };
const response = await api.get('/findAddress', { params });
const addresses = (response.data?.addresses || []).filter(a => a.preorderTypes?.includes(orderType.value));
const addresses = response.data?.addresses || [];
if (addresses.length === 0) { currentStep.value = 'noOrderPossible'; }
else if (addresses.length === 1) { selectAddress(addresses[0]); }
else { units.value = addresses; addressStep.value = 'unit'; }
if (addresses.length === 0) {
currentStep.value = 'noOrderPossible';
} else if (addresses.length === 1) {
// This path is taken for 'interest' orders (which return one building-level address)
// and for 'order' orders with only a single available unit.
selectAddress(addresses[0]);
} else {
// This path is only taken for 'order' types when multiple units are available.
units.value = addresses;
addressStep.value = 'unit';
}
} catch (e) { handleError(e, 'Adresse konnte nicht verifiziert werden.'); }
finally { isLoading.value = false; }
}
@@ -267,91 +275,91 @@
};
},
template: `
<div class="bg-white p-6 sm:p-10 rounded-2xl shadow-xl transition-all duration-500 w-full">
<header class="text-center mb-8">
<h1 class="text-4xl font-extrabold text-slate-800 tracking-tight">
<span v-if="orderType === 'interest'">Glasfaser Interesse</span>
<span v-else>Glasfaser Bestellung</span>
</h1>
<p class="text-slate-500 mt-2 text-lg">
<span v-if="orderType === 'interest'">Bekunden Sie unverbindlich Ihr Interesse.</span>
<span v-else>In wenigen Schritten zu Ihrem Anschluss.</span>
</p>
</header>
<div class="bg-white p-6 sm:p-10 rounded-2xl shadow-xl transition-all duration-500 w-full">
<header class="text-center mb-8">
<h1 class="text-4xl font-extrabold text-slate-800 tracking-tight">
<span v-if="orderType === 'interest'">Glasfaser Interesse</span>
<span v-else>Glasfaser Bestellung</span>
</h1>
<p class="text-slate-500 mt-2 text-lg">
<span v-if="orderType === 'interest'">Bekunden Sie unverbindlich Ihr Interesse.</span>
<span v-else>In wenigen Schritten zu Ihrem Anschluss.</span>
</p>
</header>
<main>
<transition name="slide-fade" mode="out-in">
<div v-if="currentStep === 'loading'" class="text-center p-8">
<div class="flex justify-center items-center"><svg class="animate-spin -ml-1 mr-3 h-8 w-8 text-[var(--color-primary-600)]" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"><circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle><path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path></svg><span class="text-slate-600 text-lg">Lade...</span></div>
</div>
<main>
<transition name="slide-fade" mode="out-in">
<div v-if="currentStep === 'loading'" class="text-center p-8">
<div class="flex justify-center items-center"><svg class="animate-spin -ml-1 mr-3 h-8 w-8 text-[var(--color-primary-600)]" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"><circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle><path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path></svg><span class="text-slate-600 text-lg">Lade...</span></div>
</div>
<div v-else-if="currentStep === 'clusterSelect'" class="space-y-4 max-w-lg mx-auto">
<label class="block text-xl font-medium text-slate-700 text-center">Bitte wählen Sie Ihr Ausbaugebiet:</label>
<SearchableSelect v-model="clusterId" :options="clusters" :get-option-key="(c) => c.id" :get-option-label="(c) => c.name" placeholder="Gebiet auswählen..." />
<button @click="handleClusterSelection" :disabled="!clusterId" class="w-full bg-[var(--color-primary-600)] text-[var(--color-text-on-primary)] font-bold py-3 px-4 rounded-md hover:bg-[var(--color-primary-700)] disabled:bg-slate-400">Weiter</button>
</div>
<div v-else-if="currentStep === 'clusterSelect'" class="space-y-4 max-w-lg mx-auto">
<label class="block text-xl font-medium text-slate-700 text-center">Bitte wählen Sie Ihr Ausbaugebiet:</label>
<SearchableSelect v-model="clusterId" :options="clusters" :get-option-key="(c) => c.id" :get-option-label="(c) => c.name" placeholder="Gebiet auswählen..." />
<button @click="handleClusterSelection" :disabled="!clusterId" class="w-full bg-[var(--color-primary-600)] text-[var(--color-text-on-primary)] font-bold py-3 px-4 rounded-md hover:bg-[var(--color-primary-700)] disabled:bg-slate-400">Weiter</button>
</div>
<div v-else-if="currentStep === 'addressSearch'" class="max-w-xl mx-auto">
<h3 class="text-xl font-semibold text-slate-800 text-center mb-6">1. Adresse prüfen</h3>
<div class="space-y-4">
<div class="p-4 rounded-lg border border-slate-300 transition-all" :class="{'wizard-step-active': addressStep === 'zip'}"><div class="flex justify-between items-center"><p class="font-semibold text-slate-700">Postleitzahl</p><button v-if="addressStep !== 'zip'" @click="goBackToStep('zip')" class="text-sm font-semibold text-[var(--color-primary-600)] hover:text-[var(--color-primary-800)]">Ändern</button></div><div v-if="addressStep === 'zip'" class="mt-2"><input v-model.trim="addressForm.zip" type="text" placeholder="PLZ eingeben, z.B. 8010" class="form-input w-full rounded-md border-slate-300 shadow-sm py-2.5 px-3"></div><p v-else class="text-slate-600 mt-1 font-medium">{{ addressForm.zip }}</p></div>
<div v-if="addressStep === 'city' || addressForm.city" class="p-4 rounded-lg border border-slate-300 transition-all" :class="{'wizard-step-active': addressStep === 'city'}"><div class="flex justify-between items-center"><p class="font-semibold text-slate-700">Ort</p><button v-if="addressStep !== 'zip' && addressStep !== 'city'" @click="goBackToStep('city')" class="text-sm font-semibold text-[var(--color-primary-600)] hover:text-[var(--color-primary-800)]">Ändern</button></div><div v-if="addressStep === 'city'" class="mt-2"><SearchableSelect v-model="addressForm.city" :options="cities" :disabled="isLoading" placeholder="Ort auswählen..." /></div><p v-else class="text-slate-600 mt-1 font-medium">{{ addressForm.city }}</p></div>
<div v-if="addressStep === 'street' || addressForm.street" class="p-4 rounded-lg border border-slate-300 transition-all" :class="{'wizard-step-active': addressStep === 'street'}"><div class="flex justify-between items-center"><p class="font-semibold text-slate-700">Straße</p><button v-if="addressStep !== 'zip' && addressStep !== 'city' && addressStep !== 'street'" @click="goBackToStep('street')" class="text-sm font-semibold text-[var(--color-primary-600)] hover:text-[var(--color-primary-800)]">Ändern</button></div><div v-if="addressStep === 'street'" class="mt-2"><SearchableSelect v-model="addressForm.street" :options="streets" :disabled="isLoading" placeholder="Straße auswählen..." /></div><p v-else class="text-slate-600 mt-1 font-medium">{{ addressForm.street }}</p></div>
<div v-if="addressStep === 'housenumber' || addressStep === 'unit'" class="p-4 rounded-lg border border-slate-300 transition-all" :class="{'wizard-step-active': true}"><p class="font-semibold text-slate-700">Hausnummer & Einheit</p>
<div v-if="addressStep === 'housenumber'" class="mt-2">
<label for="housenumber" class="block text-sm text-slate-500 mb-1">Hausnummer eingeben und prüfen</label>
<div class="flex items-center space-x-2"><input id="housenumber" v-model.trim="addressForm.housenumber" @keyup.enter="findAddress" type="text" placeholder="z.B. 12A" class="form-input w-full rounded-md border-slate-300 shadow-sm py-2.5 px-3"><button @click="findAddress" :disabled="!addressForm.housenumber || isLoading" class="py-2.5 px-4 bg-[var(--color-primary-600)] text-[var(--color-text-on-primary)] rounded-md hover:bg-[var(--color-primary-700)] disabled:bg-slate-400 flex-shrink-0"><svg v-if="isLoading" class="animate-spin h-5 w-5" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"><circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle><path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"></path></svg><span v-else>Prüfen</span></button></div>
</div>
<div v-if="addressStep === 'unit'" class="mt-2"><label class="block text-sm text-slate-500 mb-1">Mehrere Einheiten gefunden, bitte wählen</label><SearchableSelect v-model="addressForm.wohneinheit_id" :options="units" :get-option-key="(u) => u.wohneinheit_id" :get-option-label="(u) => u.showText" placeholder="Einheit auswählen..." /></div>
</div>
</div>
</div>
<div v-else-if="currentStep === 'addressSearch'" class="max-w-xl mx-auto">
<h3 class="text-xl font-semibold text-slate-800 text-center mb-6">1. Adresse prüfen</h3>
<div class="space-y-4">
<div class="p-4 rounded-lg border border-slate-300 transition-all" :class="{'wizard-step-active': addressStep === 'zip'}"><div class="flex justify-between items-center"><p class="font-semibold text-slate-700">Postleitzahl</p><button v-if="addressStep !== 'zip'" @click="goBackToStep('zip')" class="text-sm font-semibold text-[var(--color-primary-600)] hover:text-[var(--color-primary-800)]">Ändern</button></div><div v-if="addressStep === 'zip'" class="mt-2"><input v-model.trim="addressForm.zip" type="text" placeholder="PLZ eingeben, z.B. 8010" class="form-input w-full rounded-md border-slate-300 shadow-sm py-2.5 px-3"></div><p v-else class="text-slate-600 mt-1 font-medium">{{ addressForm.zip }}</p></div>
<div v-if="addressStep === 'city' || addressForm.city" class="p-4 rounded-lg border border-slate-300 transition-all" :class="{'wizard-step-active': addressStep === 'city'}"><div class="flex justify-between items-center"><p class="font-semibold text-slate-700">Ort</p><button v-if="addressStep !== 'zip' && addressStep !== 'city'" @click="goBackToStep('city')" class="text-sm font-semibold text-[var(--color-primary-600)] hover:text-[var(--color-primary-800)]">Ändern</button></div><div v-if="addressStep === 'city'" class="mt-2"><SearchableSelect v-model="addressForm.city" :options="cities" :disabled="isLoading" placeholder="Ort auswählen..." /></div><p v-else class="text-slate-600 mt-1 font-medium">{{ addressForm.city }}</p></div>
<div v-if="addressStep === 'street' || addressForm.street" class="p-4 rounded-lg border border-slate-300 transition-all" :class="{'wizard-step-active': addressStep === 'street'}"><div class="flex justify-between items-center"><p class="font-semibold text-slate-700">Straße</p><button v-if="addressStep !== 'zip' && addressStep !== 'city' && addressStep !== 'street'" @click="goBackToStep('street')" class="text-sm font-semibold text-[var(--color-primary-600)] hover:text-[var(--color-primary-800)]">Ändern</button></div><div v-if="addressStep === 'street'" class="mt-2"><SearchableSelect v-model="addressForm.street" :options="streets" :disabled="isLoading" placeholder="Straße auswählen..." /></div><p v-else class="text-slate-600 mt-1 font-medium">{{ addressForm.street }}</p></div>
<div v-if="addressStep === 'housenumber' || addressStep === 'unit'" class="p-4 rounded-lg border border-slate-300 transition-all" :class="{'wizard-step-active': true}"><p class="font-semibold text-slate-700">Hausnummer & Einheit</p>
<div v-if="addressStep === 'housenumber'" class="mt-2">
<label for="housenumber" class="block text-sm text-slate-500 mb-1">Hausnummer eingeben und prüfen</label>
<div class="flex items-center space-x-2"><input id="housenumber" v-model.trim="addressForm.housenumber" @keyup.enter="findAddress" type="text" placeholder="z.B. 12A" class="form-input w-full rounded-md border-slate-300 shadow-sm py-2.5 px-3"><button @click="findAddress" :disabled="!addressForm.housenumber || isLoading" class="py-2.5 px-4 bg-[var(--color-primary-600)] text-[var(--color-text-on-primary)] rounded-md hover:bg-[var(--color-primary-700)] disabled:bg-slate-400 flex-shrink-0"><svg v-if="isLoading" class="animate-spin h-5 w-5" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"><circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle><path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"></path></svg><span v-else>Prüfen</span></button></div>
</div>
<div v-if="addressStep === 'unit'" class="mt-2"><label class="block text-sm text-slate-500 mb-1">Mehrere Einheiten gefunden, bitte wählen</label><SearchableSelect v-model="addressForm.wohneinheit_id" :options="units" :get-option-key="(u) => u.wohneinheit_id" :get-option-label="(u) => u.showText" placeholder="Einheit auswählen..." /></div>
</div>
</div>
</div>
<div v-else-if="currentStep === 'orderForm' && selectedAddress" class="space-y-8">
<div class="p-4 bg-[var(--color-primary-50)] border-l-4 border-[var(--color-primary-500)] rounded-r-lg">
<h3 class="font-bold text-[var(--color-primary-800)]">Anschlussadresse ausgewählt:</h3>
<p class="text-[var(--color-primary-700)]">{{ selectedAddress.street }} {{ selectedAddress.housenumber }}, {{ selectedAddress.zip }} {{ selectedAddress.city }}</p>
<button @click="startNewOrder" class="text-sm text-[var(--color-primary-600)] hover:underline mt-1 font-semibold">Neue Adresse suchen</button>
</div>
<h3 class="text-xl font-semibold text-slate-800 text-center">2. Daten eingeben</h3>
<form @submit.prevent="submitOrder" class="space-y-6">
<fieldset>
<legend class="text-lg font-semibold text-slate-800 mb-2">Kunde</legend>
<div class="flex items-center space-x-6"><label class="flex items-center space-x-2 cursor-pointer"><input type="radio" v-model="form.customerType" value="Privatkunde" class="form-radio h-5 w-5 text-[var(--color-primary-600)]"><span class="text-slate-700">Privatkunde</span></label><label class="flex items-center space-x-2 cursor-pointer"><input type="radio" v-model="form.customerType" value="Businesskunde" class="form-radio h-5 w-5 text-[var(--color-primary-600)]"><span class="text-slate-700">Businesskunde</span></label></div>
</fieldset>
<div v-else-if="currentStep === 'orderForm' && selectedAddress" class="space-y-8">
<div class="p-4 bg-[var(--color-primary-50)] border-l-4 border-[var(--color-primary-500)] rounded-r-lg">
<h3 class="font-bold text-[var(--color-primary-800)]">Anschlussadresse ausgewählt:</h3>
<p class="text-[var(--color-primary-700)]">{{ selectedAddress.street }} {{ selectedAddress.housenumber }}, {{ selectedAddress.zip }} {{ selectedAddress.city }}</p>
<button @click="startNewOrder" class="text-sm text-[var(--color-primary-600)] hover:underline mt-1 font-semibold">Neue Adresse suchen</button>
</div>
<h3 class="text-xl font-semibold text-slate-800 text-center">2. Daten eingeben</h3>
<form @submit.prevent="submitOrder" class="space-y-6">
<fieldset>
<legend class="text-lg font-semibold text-slate-800 mb-2">Kunde</legend>
<div class="flex items-center space-x-6"><label class="flex items-center space-x-2 cursor-pointer"><input type="radio" v-model="form.customerType" value="Privatkunde" class="form-radio h-5 w-5 text-[var(--color-primary-600)]"><span class="text-slate-700">Privatkunde</span></label><label class="flex items-center space-x-2 cursor-pointer"><input type="radio" v-model="form.customerType" value="Businesskunde" class="form-radio h-5 w-5 text-[var(--color-primary-600)]"><span class="text-slate-700">Businesskunde</span></label></div>
</fieldset>
<fieldset v-if="orderType === 'order'">
<legend class="text-lg font-semibold text-slate-800 mb-2">Anschlussart</legend>
<div>
<label for="connectionType" class="block text-sm font-medium text-slate-600 mb-2">Anschlussart *</label>
<div v-if="selectedAddress.building_type === 2" class="space-y-2"><div class="p-4 border-2 border-[var(--color-primary-600)] rounded-md bg-[var(--color-primary-50)]"><div class="flex items-center justify-between"><span class="font-medium text-slate-800">Wohnungs-Anschluss</span><span class="font-bold text-[var(--color-primary-600)]" v-text="form.customerType === 'Privatkunde' ? '150€' : '125€'"/></div></div><input type="hidden" v-model="form.connectionType" value="wohnung"></div>
<div v-else-if="selectedAddress.building_type === 1" class="space-y-3"><label class="flex items-center p-4 border-2 rounded-md cursor-pointer" :class="form.connectionType === 'vorsorge' ? 'border-[var(--color-primary-600)] bg-[var(--color-primary-50)]' : 'border-slate-300'"><input type="radio" v-model="form.connectionType" value="vorsorge" class="form-radio h-5 w-5 text-[var(--color-primary-600)] mr-3"><div class="flex-1 flex justify-between"><span class="font-medium text-slate-800">Vorsorgeanschluss</span><span class="font-bold text-[var(--color-primary-600)]" v-text="form.customerType !== 'Privatkunde' ? '500€' : '600€'"/></div></label><label class="flex items-center p-4 border-2 rounded-md cursor-pointer" :class="form.connectionType === 'voll' ? 'border-[var(--color-primary-600)] bg-[var(--color-primary-50)]' : 'border-slate-300'"><input type="radio" v-model="form.connectionType" value="voll" class="form-radio h-5 w-5 text-[var(--color-primary-600)] mr-3"><div class="flex-1"><div class="flex justify-between mb-1"><span class="font-medium text-slate-800">Vollanschluss</span><span class="font-bold text-[var(--color-primary-600)]" v-text="form.customerType !== 'Privatkunde' ? '250€' : '300€'"/></div><p class="text-xs text-slate-600 mt-1">Vollanschluss-Preis nur bei Aktivierung innerhalb von 8 Wochen nach Fertigstellung</p></div></label></div>
<div v-else class="p-4 border border-slate-300 rounded-md bg-slate-50"><p class="text-slate-600">Keine Anschlussart für diesen Gebäudetyp verfügbar.</p></div>
</div>
</fieldset>
<fieldset v-if="orderType === 'order'">
<legend class="text-lg font-semibold text-slate-800 mb-2">Anschlussart</legend>
<div>
<label for="connectionType" class="block text-sm font-medium text-slate-600 mb-2">Anschlussart *</label>
<div v-if="selectedAddress.building_type === 2" class="space-y-2"><div class="p-4 border-2 border-[var(--color-primary-600)] rounded-md bg-[var(--color-primary-50)]"><div class="flex items-center justify-between"><span class="font-medium text-slate-800">Wohnungs-Anschluss</span><span class="font-bold text-[var(--color-primary-600)]" v-text="form.customerType === 'Privatkunde' ? '150€' : '125€'"/></div></div><input type="hidden" v-model="form.connectionType" value="wohnung"></div>
<div v-else-if="selectedAddress.building_type === 1" class="space-y-3"><label class="flex items-center p-4 border-2 rounded-md cursor-pointer" :class="form.connectionType === 'vorsorge' ? 'border-[var(--color-primary-600)] bg-[var(--color-primary-50)]' : 'border-slate-300'"><input type="radio" v-model="form.connectionType" value="vorsorge" class="form-radio h-5 w-5 text-[var(--color-primary-600)] mr-3"><div class="flex-1 flex justify-between"><span class="font-medium text-slate-800">Vorsorgeanschluss</span><span class="font-bold text-[var(--color-primary-600)]" v-text="form.customerType !== 'Privatkunde' ? '500€' : '600€'"/></div></label><label class="flex items-center p-4 border-2 rounded-md cursor-pointer" :class="form.connectionType === 'voll' ? 'border-[var(--color-primary-600)] bg-[var(--color-primary-50)]' : 'border-slate-300'"><input type="radio" v-model="form.connectionType" value="voll" class="form-radio h-5 w-5 text-[var(--color-primary-600)] mr-3"><div class="flex-1"><div class="flex justify-between mb-1"><span class="font-medium text-slate-800">Vollanschluss</span><span class="font-bold text-[var(--color-primary-600)]" v-text="form.customerType !== 'Privatkunde' ? '250€' : '300€'"/></div><p class="text-xs text-slate-600 mt-1">Vollanschluss-Preis nur bei Aktivierung innerhalb von 8 Wochen nach Fertigstellung</p></div></label></div>
<div v-else class="p-4 border border-slate-300 rounded-md bg-slate-50"><p class="text-slate-600">Keine Anschlussart für diesen Gebäudetyp verfügbar.</p></div>
</div>
</fieldset>
<fieldset><legend class="text-lg font-semibold text-slate-800 mb-2">Persönliche Daten</legend><div class="grid grid-cols-1 sm:grid-cols-2 gap-4"><div><label for="title" class="block text-sm font-medium text-slate-600">Titel</label><input id="title" v-model="form.title" type="text" placeholder="z.B. Dr." class="form-input mt-1 block w-full rounded-md border-slate-300"></div><div><label for="birthDate" class="block text-sm font-medium text-slate-600">Geburtsdatum</label><input id="birthDate" v-model="form.birthDate" type="date" class="form-input mt-1 block w-full rounded-md border-slate-300"></div><div><label for="firstName" class="block text-sm font-medium text-slate-600">Vorname *</label><input id="firstName" v-model="form.firstName" required type="text" placeholder="Max" class="form-input mt-1 block w-full rounded-md border-slate-300"></div><div><label for="lastName" class="block text-sm font-medium text-slate-600">Nachname *</label><input id="lastName" v-model="form.lastName" required type="text" placeholder="Mustermann" class="form-input mt-1 block w-full rounded-md border-slate-300"></div><div><label for="phone" class="block text-sm font-medium text-slate-600">Telefon</label><input id="phone" v-model="form.phone" type="tel" placeholder="+43 664 1234567" class="form-input mt-1 block w-full rounded-md border-slate-300"></div><div><label for="email" class="block text-sm font-medium text-slate-600">E-Mail *</label><input id="email" v-model="form.email" required type="email" placeholder="max.mustermann@email.com" class="form-input mt-1 block w-full rounded-md border-slate-300"></div><div class="sm:col-span-2"><p class="block text-sm font-medium text-slate-600">Ich bin Eigentümer der Liegenschaft *</p><div class="flex items-center space-x-4 mt-1"><label class="flex items-center space-x-2 cursor-pointer"><input type="radio" v-model="form.isOwner" value="Ja" class="form-radio h-4 w-4 text-[var(--color-primary-600)]"><span class="text-slate-700">Ja</span></label><label class="flex items-center space-x-2 cursor-pointer"><input type="radio" v-model="form.isOwner" value="Nein" class="form-radio h-4 w-4 text-[var(--color-primary-600)]"><span class="text-slate-700">Nein</span></label></div></div></div></fieldset>
<fieldset><legend class="text-lg font-semibold text-slate-800 mb-2">Anmerkungen</legend><div><label for="notes" class="block text-sm font-medium text-slate-600">Ihre Anmerkungen zur Anschlussadresse</label><textarea id="notes" v-model="form.notes" rows="3" placeholder="z.B. Hinterhaus, bei Firma XY läuten" class="form-textarea mt-1 block w-full rounded-md border-slate-300"></textarea></div></fieldset>
<fieldset><legend class="text-lg font-semibold text-slate-800 mb-2">Adresse zur Rechnungszusendung</legend><div class="flex items-center space-x-6 mb-4"><label class="flex items-center space-x-2 cursor-pointer"><input type="radio" v-model="form.billingAddressChoice" value="Anschlussadresse" class="form-radio h-5 w-5 text-[var(--color-primary-600)]"><span class="text-slate-700">Anschlussadresse</span></label><label class="flex items-center space-x-2 cursor-pointer"><input type="radio" v-model="form.billingAddressChoice" value="Andere" class="form-radio h-5 w-5 text-[var(--color-primary-600)]"><span class="text-slate-700">Andere Adresse</span></label></div><transition name="slide-fade"><div v-if="form.billingAddressChoice === 'Andere'" class="grid grid-cols-1 sm:grid-cols-2 gap-4 p-4 border rounded-md bg-slate-50"><div class="sm:col-span-2"><label for="billingName" class="block text-sm font-medium text-slate-600">Name/Firma *</label><input id="billingName" v-model="form.billing.name" required type="text" placeholder="Maxi Mustermann GmbH" class="form-input mt-1 block w-full rounded-md border-slate-300"></div><div><label for="billingStreet" class="block text-sm font-medium text-slate-600">Straße *</label><input id="billingStreet" v-model="form.billing.street" required type="text" placeholder="Musterstraße" class="form-input mt-1 block w-full rounded-md border-slate-300"></div><div><label for="billingHousenumber" class="block text-sm font-medium text-slate-600">Hausnr. *</label><input id="billingHousenumber" v-model="form.billing.housenumber" required type="text" placeholder="1" class="form-input mt-1 block w-full rounded-md border-slate-300"></div><div><label for="billingZip" class="block text-sm font-medium text-slate-600">PLZ *</label><input id="billingZip" v-model="form.billing.zip" required type="text" placeholder="8010" class="form-input mt-1 block w-full rounded-md border-slate-300"></div><div><label for="billingCity" class="block text-sm font-medium text-slate-600">Ort *</label><input id="billingCity" v-model="form.billing.city" required type="text" placeholder="Graz" class="form-input mt-1 block w-full rounded-md border-slate-300"></div></div></transition></fieldset>
<fieldset><legend class="text-lg font-semibold text-slate-800 mb-2">Zustimmungen</legend><div class="space-y-4"><template v-for="(consent, key) in iframeConsents" :key="key"><label v-if="consent.activated" class="flex items-start space-x-3 cursor-pointer"><input type="checkbox" v-model="form[key]" class="form-checkbox h-5 w-5 text-[var(--color-primary-600)] mt-0.5 flex-shrink-0"><span class="text-slate-600 text-sm"><template v-if="consent.replace && consent.url">{{ consent.text.split(consent.replace)[0] }}<a :href="consent.url" target="_blank" class="text-[var(--color-primary-600)] hover:underline">{{ consent.replace }}</a>{{ consent.text.split(consent.replace)[1] }}</template><template v-else>{{ consent.text }}</template><span v-if="consent.required" class="text-red-500">*</span></span></label></template></div></fieldset>
<fieldset><legend class="text-lg font-semibold text-slate-800 mb-2">Persönliche Daten</legend><div class="grid grid-cols-1 sm:grid-cols-2 gap-4"><div><label for="title" class="block text-sm font-medium text-slate-600">Titel</label><input id="title" v-model="form.title" type="text" placeholder="z.B. Dr." class="form-input mt-1 block w-full rounded-md border-slate-300"></div><div><label for="birthDate" class="block text-sm font-medium text-slate-600">Geburtsdatum</label><input id="birthDate" v-model="form.birthDate" type="date" class="form-input mt-1 block w-full rounded-md border-slate-300"></div><div><label for="firstName" class="block text-sm font-medium text-slate-600">Vorname *</label><input id="firstName" v-model="form.firstName" required type="text" placeholder="Max" class="form-input mt-1 block w-full rounded-md border-slate-300"></div><div><label for="lastName" class="block text-sm font-medium text-slate-600">Nachname *</label><input id="lastName" v-model="form.lastName" required type="text" placeholder="Mustermann" class="form-input mt-1 block w-full rounded-md border-slate-300"></div><div><label for="phone" class="block text-sm font-medium text-slate-600">Telefon</label><input id="phone" v-model="form.phone" type="tel" placeholder="+43 664 1234567" class="form-input mt-1 block w-full rounded-md border-slate-300"></div><div><label for="email" class="block text-sm font-medium text-slate-600">E-Mail *</label><input id="email" v-model="form.email" required type="email" placeholder="max.mustermann@email.com" class="form-input mt-1 block w-full rounded-md border-slate-300"></div><div class="sm:col-span-2"><p class="block text-sm font-medium text-slate-600">Ich bin Eigentümer der Liegenschaft *</p><div class="flex items-center space-x-4 mt-1"><label class="flex items-center space-x-2 cursor-pointer"><input type="radio" v-model="form.isOwner" value="Ja" class="form-radio h-4 w-4 text-[var(--color-primary-600)]"><span class="text-slate-700">Ja</span></label><label class="flex items-center space-x-2 cursor-pointer"><input type="radio" v-model="form.isOwner" value="Nein" class="form-radio h-4 w-4 text-[var(--color-primary-600)]"><span class="text-slate-700">Nein</span></label></div></div></div></fieldset>
<fieldset><legend class="text-lg font-semibold text-slate-800 mb-2">Anmerkungen</legend><div><label for="notes" class="block text-sm font-medium text-slate-600">Ihre Anmerkungen zur Anschlussadresse</label><textarea id="notes" v-model="form.notes" rows="3" placeholder="z.B. Hinterhaus, bei Firma XY läuten" class="form-textarea mt-1 block w-full rounded-md border-slate-300"></textarea></div></fieldset>
<fieldset><legend class="text-lg font-semibold text-slate-800 mb-2">Adresse zur Rechnungszusendung</legend><div class="flex items-center space-x-6 mb-4"><label class="flex items-center space-x-2 cursor-pointer"><input type="radio" v-model="form.billingAddressChoice" value="Anschlussadresse" class="form-radio h-5 w-5 text-[var(--color-primary-600)]"><span class="text-slate-700">Anschlussadresse</span></label><label class="flex items-center space-x-2 cursor-pointer"><input type="radio" v-model="form.billingAddressChoice" value="Andere" class="form-radio h-5 w-5 text-[var(--color-primary-600)]"><span class="text-slate-700">Andere Adresse</span></label></div><transition name="slide-fade"><div v-if="form.billingAddressChoice === 'Andere'" class="grid grid-cols-1 sm:grid-cols-2 gap-4 p-4 border rounded-md bg-slate-50"><div class="sm:col-span-2"><label for="billingName" class="block text-sm font-medium text-slate-600">Name/Firma *</label><input id="billingName" v-model="form.billing.name" required type="text" placeholder="Maxi Mustermann GmbH" class="form-input mt-1 block w-full rounded-md border-slate-300"></div><div><label for="billingStreet" class="block text-sm font-medium text-slate-600">Straße *</label><input id="billingStreet" v-model="form.billing.street" required type="text" placeholder="Musterstraße" class="form-input mt-1 block w-full rounded-md border-slate-300"></div><div><label for="billingHousenumber" class="block text-sm font-medium text-slate-600">Hausnr. *</label><input id="billingHousenumber" v-model="form.billing.housenumber" required type="text" placeholder="1" class="form-input mt-1 block w-full rounded-md border-slate-300"></div><div><label for="billingZip" class="block text-sm font-medium text-slate-600">PLZ *</label><input id="billingZip" v-model="form.billing.zip" required type="text" placeholder="8010" class="form-input mt-1 block w-full rounded-md border-slate-300"></div><div><label for="billingCity" class="block text-sm font-medium text-slate-600">Ort *</label><input id="billingCity" v-model="form.billing.city" required type="text" placeholder="Graz" class="form-input mt-1 block w-full rounded-md border-slate-300"></div></div></transition></fieldset>
<fieldset><legend class="text-lg font-semibold text-slate-800 mb-2">Zustimmungen</legend><div class="space-y-4"><template v-for="(consent, key) in iframeConsents" :key="key"><label v-if="consent.activated" class="flex items-start space-x-3 cursor-pointer"><input type="checkbox" v-model="form[key]" class="form-checkbox h-5 w-5 text-[var(--color-primary-600)] mt-0.5 flex-shrink-0"><span class="text-slate-600 text-sm"><template v-if="consent.replace && consent.url">{{ consent.text.split(consent.replace)[0] }}<a :href="consent.url" target="_blank" class="text-[var(--color-primary-600)] hover:underline">{{ consent.replace }}</a>{{ consent.text.split(consent.replace)[1] }}</template><template v-else>{{ consent.text }}</template><span v-if="consent.required" class="text-red-500">*</span></span></label></template></div></fieldset>
<div class="pt-4 border-t">
<p class="text-xs text-slate-500 mb-4">* Pflichtfelder</p>
<button type="submit" :disabled="isFormInvalid || isLoading" class="w-full bg-[var(--color-primary-600)] text-[var(--color-text-on-primary)] font-bold py-4 px-4 rounded-md hover:bg-[var(--color-primary-700)] flex items-center justify-center text-lg">
<svg v-if="isLoading" class="animate-spin -ml-1 mr-3 h-5 w-5" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"><circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle><path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path></svg>
<span v-if="orderType === 'interest'">Interesse bekunden</span>
<span v-else>Kostenpflichtig bestellen</span>
</button>
</div>
</form>
</div>
<div class="pt-4 border-t">
<p class="text-xs text-slate-500 mb-4">* Pflichtfelder</p>
<button type="submit" :disabled="isFormInvalid || isLoading" class="w-full bg-[var(--color-primary-600)] text-[var(--color-text-on-primary)] font-bold py-4 px-4 rounded-md hover:bg-[var(--color-primary-700)] flex items-center justify-center text-lg">
<svg v-if="isLoading" class="animate-spin -ml-1 mr-3 h-5 w-5" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"><circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle><path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path></svg>
<span v-if="orderType === 'interest'">Interesse bekunden</span>
<span v-else>Kostenpflichtig bestellen</span>
</button>
</div>
</form>
</div>
<div v-else-if="currentStep === 'noOrderPossible'" class="text-center p-8 bg-amber-50 rounded-lg"><svg class="mx-auto h-12 w-12 text-amber-500" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"/></svg><h2 class="mt-4 text-2xl font-bold text-slate-800">Keine Verfügbarkeit</h2><p class="mt-2 text-slate-600">Leider ist an der von Ihnen gewählten Adresse derzeit kein Glasfaseranschluss verfügbar.</p><button @click="startNewOrder" class="mt-6 bg-[var(--color-primary-600)] text-[var(--color-text-on-primary)] font-bold py-2 px-6 rounded-md hover:bg-[var(--color-primary-700)]">Andere Adresse suchen</button></div>
<div v-else-if="currentStep === 'confirmation' && orderResponse" class="text-center p-8 bg-green-50 rounded-lg"><svg class="mx-auto h-16 w-16 text-green-500" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" /></svg><h2 class="mt-4 text-2xl font-bold text-slate-800">Vielen Dank!</h2><p class="mt-2 text-slate-600">Ihre Anfrage wurde erfolgreich übermittelt.</p><div class="mt-6 p-4 bg-white border border-green-200 rounded-md inline-block"><p class="text-slate-600">Ihre Referenznummer:</p><p class="text-2xl font-mono font-bold text-green-700 tracking-wider">{{ orderResponse.orderCode }}</p></div><button @click="startNewOrder" class="mt-8 block w-full text-center bg-[var(--color-primary-600)] text-[var(--color-text-on-primary)] font-bold py-3 px-4 rounded-md">Neue Anfrage</button></div>
<div v-else-if="currentStep === 'error'" class="text-center p-8 bg-red-50 rounded-lg"><svg class="mx-auto h-12 w-12 text-red-500" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" /></svg><h2 class="mt-4 text-2xl font-bold text-slate-800">Ein Fehler ist aufgetreten</h2><p class="mt-2 text-red-700 bg-red-100 p-3 rounded-md">{{ errorMessage }}</p><button @click="startNewOrder" class="mt-6 bg-[var(--color-primary-600)] text-[var(--color-text-on-primary)] font-bold py-2 px-6 rounded-md">Erneut versuchen</button></div>
</transition>
</main>
</div>
<div v-else-if="currentStep === 'noOrderPossible'" class="text-center p-8 bg-amber-50 rounded-lg"><svg class="mx-auto h-12 w-12 text-amber-500" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"/></svg><h2 class="mt-4 text-2xl font-bold text-slate-800">Keine Verfügbarkeit</h2><p class="mt-2 text-slate-600">Leider ist an der von Ihnen gewählten Adresse derzeit kein Glasfaseranschluss verfügbar.</p><button @click="startNewOrder" class="mt-6 bg-[var(--color-primary-600)] text-[var(--color-text-on-primary)] font-bold py-2 px-6 rounded-md hover:bg-[var(--color-primary-700)]">Andere Adresse suchen</button></div>
<div v-else-if="currentStep === 'confirmation' && orderResponse" class="text-center p-8 bg-green-50 rounded-lg"><svg class="mx-auto h-16 w-16 text-green-500" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" /></svg><h2 class="mt-4 text-2xl font-bold text-slate-800">Vielen Dank!</h2><p class="mt-2 text-slate-600">Ihre Anfrage wurde erfolgreich übermittelt.</p><div class="mt-6 p-4 bg-white border border-green-200 rounded-md inline-block"><p class="text-slate-600">Ihre Referenznummer:</p><p class="text-2xl font-mono font-bold text-green-700 tracking-wider">{{ orderResponse.orderCode }}</p></div><button @click="startNewOrder" class="mt-8 block w-full text-center bg-[var(--color-primary-600)] text-[var(--color-text-on-primary)] font-bold py-3 px-4 rounded-md">Neue Anfrage</button></div>
<div v-else-if="currentStep === 'error'" class="text-center p-8 bg-red-50 rounded-lg"><svg class="mx-auto h-12 w-12 text-red-500" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" /></svg><h2 class="mt-4 text-2xl font-bold text-slate-800">Ein Fehler ist aufgetreten</h2><p class="mt-2 text-red-700 bg-red-100 p-3 rounded-md">{{ errorMessage }}</p><button @click="startNewOrder" class="mt-6 bg-[var(--color-primary-600)] text-[var(--color-text-on-primary)] font-bold py-2 px-6 rounded-md">Erneut versuchen</button></div>
</transition>
</main>
</div>
`
});

View File

@@ -118,17 +118,34 @@ class PreorderIFrameModel extends mfBaseModel
$results = $this->db->fetch_all_assoc($this->db->query($query));
if (empty($results)) return [];
$orderType = $params['orderType'] ?? 'order';
// For 'interest' order type, return a single entry for the whole building.
if ($orderType === 'interest') {
$representativeAddress = $this->formatAddressRow($results[0]);
$representativeAddress['wohneinheit_id'] = null; // Critical: No specific unit
$representativeAddress['oaid'] = $results[0]['oaid']; // Use building OAID
$representativeAddress['showText'] = "Gesamtes Gebäude";
$representativeAddress['preorderTypes'] = ['interest'];
return [$representativeAddress]; // Return one item, so frontend proceeds directly.
}
// Original logic for 'order' type
$addresses = [];
$topCounter = 1;
if (count($results) > 1 && $results[0]['wohneinheit_id'] !== null) {
foreach ($results as $row) {
$addresses[] = array_merge($this->formatAddressRow($row), [
'showText' => $this->buildShowText($row, $topCounter++)
]);
$address = $this->formatAddressRow($row);
$address['showText'] = $this->buildShowText($row, $topCounter++);
$address['preorderTypes'] = ['order'];
$addresses[] = $address;
}
} else {
$addresses[] = $this->formatAddressRow($results[0]);
// Single unit or building without units
$address = $this->formatAddressRow($results[0]);
$address['preorderTypes'] = ['order'];
$addresses[] = $address;
}
return $addresses;
@@ -139,7 +156,7 @@ class PreorderIFrameModel extends mfBaseModel
return [
'oaid' => $row['unit_oaid'] ?? $row['oaid'],
'street' => $row['street'],
'housenumber' => $row['hausnummer'],
'housenumber' => $row['housenumber'],
'hausnummer_id' => $row['hausnummer_id'],
'wohneinheit_id' => $row['wohneinheit_id'],
'building_type' => intval($row['building_type']),
@@ -151,7 +168,6 @@ class PreorderIFrameModel extends mfBaseModel
'zusatz' => $row['zusatz'],
'building_unit_count' => $row['building_unit_count'],
'showText' => $this->buildShowText($row, 1),
'preorderTypes' => ['order', 'interest'] // Can be used for both
];
}