Felder Validierung für E-Mail, PLZ und Telefonnummer. Eingabe akzeptieren wenn wenniger als 3 Plätze vorhanden sind.

This commit is contained in:
titver968
2026-01-09 09:34:08 +01:00
parent a99ddf6fa9
commit 0e21b78a4c
2 changed files with 257 additions and 71 deletions

Binary file not shown.

View File

@@ -44,6 +44,10 @@
let alterFehler = ''; let alterFehler = '';
let notenFehler = ''; let notenFehler = '';
let sozialverhaltenFehler = ''; let sozialverhaltenFehler = '';
let emailFehler = '';
let telefonFehler = '';
let notfallTelefonFehler = '';
let plzFehler = '';
// Hinweis für IGS/KGS mit Lernentwicklungsbericht // Hinweis für IGS/KGS mit Lernentwicklungsbericht
$: zeigeIgsKgsHinweis = $: zeigeIgsKgsHinweis =
@@ -80,6 +84,92 @@
} }
} }
// Echtzeit-Validierung: E-Mail
$: {
if (email) {
// RFC 5322 konforme E-Mail-Validierung (vereinfacht)
const emailRegex = /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+$/;
if (!emailRegex.test(email)) {
emailFehler = 'Bitte gib eine gültige E-Mail-Adresse ein.';
} else {
emailFehler = '';
}
} else {
emailFehler = '';
}
}
// Echtzeit-Validierung: Telefonnummer
// Deutsche Telefonnummern: Festnetz 10-11 Ziffern, Mobil 11-12 Ziffern (mit führender 0)
// Erlaubt: Ziffern, Leerzeichen, Bindestriche, Schrägstriche, Klammern, + am Anfang
$: {
if (telefon) {
// Entferne alle Formatierungszeichen für die Ziffernzählung
const nurZiffern = telefon.replace(/[\s\-\/\(\)\+]/g, '');
// Prüfe ob nur erlaubte Zeichen enthalten sind
const erlaubteZeichenRegex = /^[\d\s\-\/\(\)\+]+$/;
if (!erlaubteZeichenRegex.test(telefon)) {
telefonFehler = 'Die Telefonnummer enthält ungültige Zeichen.';
} else if (!/^\d+$/.test(nurZiffern)) {
telefonFehler = 'Die Telefonnummer muss Ziffern enthalten.';
} else if (nurZiffern.length < 10) {
telefonFehler = 'Die Telefonnummer ist zu kurz (mindestens 10 Ziffern).';
} else if (nurZiffern.length > 15) {
telefonFehler = 'Die Telefonnummer ist zu lang (maximal 15 Ziffern).';
} else {
telefonFehler = '';
}
} else {
telefonFehler = '';
}
}
// Echtzeit-Validierung: Notfall-Telefonnummer
$: {
if (notfallTelefon) {
const nurZiffern = notfallTelefon.replace(/[\s\-\/\(\)\+]/g, '');
const erlaubteZeichenRegex = /^[\d\s\-\/\(\)\+]+$/;
if (!erlaubteZeichenRegex.test(notfallTelefon)) {
notfallTelefonFehler = 'Die Telefonnummer enthält ungültige Zeichen.';
} else if (!/^\d+$/.test(nurZiffern)) {
notfallTelefonFehler = 'Die Telefonnummer muss Ziffern enthalten.';
} else if (nurZiffern.length < 10) {
notfallTelefonFehler = 'Die Telefonnummer ist zu kurz (mindestens 10 Ziffern).';
} else if (nurZiffern.length > 15) {
notfallTelefonFehler = 'Die Telefonnummer ist zu lang (maximal 15 Ziffern).';
} else {
notfallTelefonFehler = '';
}
} else {
notfallTelefonFehler = '';
}
}
// Echtzeit-Validierung: PLZ (genau 5 Ziffern für deutsche PLZ)
$: {
if (plz) {
const plzRegex = /^\d{5}$/;
if (!plzRegex.test(plz)) {
if (!/^\d*$/.test(plz)) {
plzFehler = 'Die Postleitzahl darf nur Ziffern enthalten.';
} else if (plz.length < 5) {
plzFehler = 'Die Postleitzahl muss genau 5 Ziffern haben.';
} else if (plz.length > 5) {
plzFehler = 'Die Postleitzahl darf maximal 5 Ziffern haben.';
} else {
plzFehler = 'Bitte gib eine gültige Postleitzahl ein.';
}
} else {
plzFehler = '';
}
} else {
plzFehler = '';
}
}
// Echtzeit-Validierung: Noten // Echtzeit-Validierung: Noten
$: { $: {
const deutsch = parseInt(noteDeutsch); const deutsch = parseInt(noteDeutsch);
@@ -125,8 +215,18 @@
} }
} }
// Prüfen ob Formular gültig ist // Prüfen ob alle erforderlichen Wünsche ausgewählt wurden (abhängig von verfügbaren Dienststellen)
$: formHatFehler = alterFehler !== '' || notenFehler !== '' || sozialverhaltenFehler !== ''; $: wuenscheVollstaendig = (() => {
const anzahl = filteredDienststellen.length;
if (anzahl === 0) return false;
if (anzahl === 1) return !!wunsch1Id;
if (anzahl === 2) return !!wunsch1Id && !!wunsch2Id;
return !!wunsch1Id && !!wunsch2Id && !!wunsch3Id;
})();
// Prüfen ob Formular gültig ist (erweitert um neue Validierungen)
$: formHatFehler = alterFehler !== '' || notenFehler !== '' || sozialverhaltenFehler !== '' ||
emailFehler !== '' || telefonFehler !== '' || notfallTelefonFehler !== '' || plzFehler !== '';
// Dienststellen laden wenn Zeitraum sich ändert // Dienststellen laden wenn Zeitraum sich ändert
async function ladeDienststellen(zeitraumId: string) { async function ladeDienststellen(zeitraumId: string) {
@@ -222,6 +322,10 @@
alterFehler = ''; alterFehler = '';
notenFehler = ''; notenFehler = '';
sozialverhaltenFehler = ''; sozialverhaltenFehler = '';
emailFehler = '';
telefonFehler = '';
notfallTelefonFehler = '';
plzFehler = '';
dienststellen = []; dienststellen = [];
} }
@@ -300,10 +404,55 @@
<input bind:value={geburtsdatum} type="date" placeholder="Geburtsdatum" required class="input" /> <input bind:value={geburtsdatum} type="date" placeholder="Geburtsdatum" required class="input" />
<input bind:value={strasse} placeholder="Straße" required class="input" /> <input bind:value={strasse} placeholder="Straße" required class="input" />
<input bind:value={hausnummer} placeholder="Hausnummer" required class="input" /> <input bind:value={hausnummer} placeholder="Hausnummer" required class="input" />
<input bind:value={plz} placeholder="Postleitzahl" required class="input" />
<!-- PLZ mit Validierung -->
<div>
<input
bind:value={plz}
placeholder="Postleitzahl"
required
class="input"
class:input-error={plzFehler}
maxlength="5"
inputmode="numeric"
/>
{#if plzFehler}
<p class="text-red-600 text-sm mt-1">{plzFehler}</p>
{/if}
</div>
<input bind:value={ort} placeholder="Ort" required class="input" /> <input bind:value={ort} placeholder="Ort" required class="input" />
<input bind:value={telefon} placeholder="Telefonnummer" required class="input col-span-2" />
<input bind:value={email} type="email" placeholder="E-Mail-Adresse" required class="input col-span-2" /> <!-- Telefonnummer mit Validierung -->
<div class="col-span-2">
<input
bind:value={telefon}
type="tel"
placeholder="Telefonnummer (z.B. 0511 1234567 oder 0171 1234567)"
required
class="input"
class:input-error={telefonFehler}
/>
{#if telefonFehler}
<p class="text-red-600 text-sm mt-1">{telefonFehler}</p>
{/if}
</div>
<!-- E-Mail mit Validierung -->
<div class="col-span-2">
<input
bind:value={email}
type="email"
placeholder="E-Mail-Adresse"
required
class="input"
class:input-error={emailFehler}
/>
{#if emailFehler}
<p class="text-red-600 text-sm mt-1">{emailFehler}</p>
{/if}
</div>
<select bind:value={schulart} required class="input"> <select bind:value={schulart} required class="input">
<option value="" disabled selected hidden>Schulart wählen</option> <option value="" disabled selected hidden>Schulart wählen</option>
<option value="Gymnasium">Gymnasium</option> <option value="Gymnasium">Gymnasium</option>
@@ -423,6 +572,22 @@
Lade verfügbare Dienststellen... Lade verfügbare Dienststellen...
</div> </div>
{:else} {:else}
<!-- Hinweis wenn nur begrenzte Auswahl möglich -->
{#if zeitraum && filteredDienststellen.length > 0 && filteredDienststellen.length < 3}
<div class="p-3 bg-blue-50 border border-blue-200 rounded-xl">
<div class="flex items-start">
<svg class="w-5 h-5 text-blue-500 mr-2 mt-0.5 flex-shrink-0" fill="currentColor" viewBox="0 0 20 20">
<path fill-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z" clip-rule="evenodd" />
</svg>
<p class="text-sm text-blue-700">
Für diesen Zeitraum {filteredDienststellen.length === 1 ? 'ist nur noch 1 Dienststelle' : 'sind nur noch ' + filteredDienststellen.length + ' Dienststellen'} verfügbar.
</p>
</div>
</div>
{/if}
<!-- 1. Wunsch - immer anzeigen wenn Dienststellen vorhanden -->
{#if filteredDienststellen.length >= 1}
<select bind:value={wunsch1Id} required disabled={!zeitraum} class="input" class:opacity-50={!zeitraum}> <select bind:value={wunsch1Id} required disabled={!zeitraum} class="input" class:opacity-50={!zeitraum}>
<option value="" disabled selected> <option value="" disabled selected>
{zeitraum ? '1. Wunschdienststelle' : 'Bitte zuerst Zeitraum wählen'} {zeitraum ? '1. Wunschdienststelle' : 'Bitte zuerst Zeitraum wählen'}
@@ -431,14 +596,20 @@
<option value={d.id}>{d.name} ({d.plaetze} {d.plaetze === 1 ? 'Platz' : 'Plätze'} frei)</option> <option value={d.id}>{d.name} ({d.plaetze} {d.plaetze === 1 ? 'Platz' : 'Plätze'} frei)</option>
{/each} {/each}
</select> </select>
{/if}
<!-- 2. Wunsch - nur anzeigen wenn mindestens 2 Dienststellen verfügbar -->
{#if filteredDienststellen.length >= 2}
<select bind:value={wunsch2Id} required disabled={!zeitraum || !wunsch1Id} class="input" class:opacity-50={!zeitraum || !wunsch1Id}> <select bind:value={wunsch2Id} required disabled={!zeitraum || !wunsch1Id} class="input" class:opacity-50={!zeitraum || !wunsch1Id}>
<option value="" disabled selected>2. Wunschdienststelle</option> <option value="" disabled selected>2. Wunschdienststelle</option>
{#each filteredDienststellen.filter(d => d.id != wunsch1Id) as d} {#each filteredDienststellen.filter(d => d.id != wunsch1Id) as d}
<option value={d.id}>{d.name} ({d.plaetze} {d.plaetze === 1 ? 'Platz' : 'Plätze'} frei)</option> <option value={d.id}>{d.name} ({d.plaetze} {d.plaetze === 1 ? 'Platz' : 'Plätze'} frei)</option>
{/each} {/each}
</select> </select>
{/if}
<!-- 3. Wunsch - nur anzeigen wenn mindestens 3 Dienststellen verfügbar -->
{#if filteredDienststellen.length >= 3}
<select bind:value={wunsch3Id} required disabled={!zeitraum || !wunsch2Id} class="input" class:opacity-50={!zeitraum || !wunsch2Id}> <select bind:value={wunsch3Id} required disabled={!zeitraum || !wunsch2Id} class="input" class:opacity-50={!zeitraum || !wunsch2Id}>
<option value="" disabled selected>3. Wunschdienststelle</option> <option value="" disabled selected>3. Wunschdienststelle</option>
{#each filteredDienststellen.filter(d => d.id != wunsch1Id && d.id != wunsch2Id) as d} {#each filteredDienststellen.filter(d => d.id != wunsch1Id && d.id != wunsch2Id) as d}
@@ -446,6 +617,7 @@
{/each} {/each}
</select> </select>
{/if} {/if}
{/if}
<!-- Hinweis wenn keine Dienststellen verfügbar --> <!-- Hinweis wenn keine Dienststellen verfügbar -->
{#if zeitraum && !isLoadingDienststellen && filteredDienststellen.length === 0} {#if zeitraum && !isLoadingDienststellen && filteredDienststellen.length === 0}
@@ -488,7 +660,21 @@
<div class="grid grid-cols-2 gap-4"> <div class="grid grid-cols-2 gap-4">
<input bind:value={notfallVorname} placeholder="Vorname Notfallkontakt" required class="input" /> <input bind:value={notfallVorname} placeholder="Vorname Notfallkontakt" required class="input" />
<input bind:value={notfallNachname} placeholder="Nachname Notfallkontakt" required class="input" /> <input bind:value={notfallNachname} placeholder="Nachname Notfallkontakt" required class="input" />
<input bind:value={notfallTelefon} type="tel" placeholder="Mobilnummer Notfallkontakt" required class="input col-span-2" />
<!-- Notfall-Telefonnummer mit Validierung -->
<div class="col-span-2">
<input
bind:value={notfallTelefon}
type="tel"
placeholder="Mobilnummer Notfallkontakt (z.B. 0171 1234567)"
required
class="input"
class:input-error={notfallTelefonFehler}
/>
{#if notfallTelefonFehler}
<p class="text-red-600 text-sm mt-1">{notfallTelefonFehler}</p>
{/if}
</div>
</div> </div>
</div> </div>
@@ -509,13 +695,13 @@
<!-- Button - deaktiviert bei Validierungsfehlern oder fehlenden Pflichtfeldern --> <!-- Button - deaktiviert bei Validierungsfehlern oder fehlenden Pflichtfeldern -->
<button <button
type="submit" type="submit"
disabled={formHatFehler || !zeitraum || !wunsch1Id || !wunsch2Id || !wunsch3Id} disabled={formHatFehler || !zeitraum || !wuenscheVollstaendig}
class="w-full py-3 rounded-xl transition-all" class="w-full py-3 rounded-xl transition-all"
class:bg-blue-600={!formHatFehler && zeitraum && wunsch1Id && wunsch2Id && wunsch3Id} class:bg-blue-600={!formHatFehler && zeitraum && wuenscheVollstaendig}
class:hover:bg-blue-700={!formHatFehler && zeitraum && wunsch1Id && wunsch2Id && wunsch3Id} class:hover:bg-blue-700={!formHatFehler && zeitraum && wuenscheVollstaendig}
class:text-white={!formHatFehler && zeitraum && wunsch1Id && wunsch2Id && wunsch3Id} class:text-white={!formHatFehler && zeitraum && wuenscheVollstaendig}
class:bg-gray-400={formHatFehler || !zeitraum || !wunsch1Id || !wunsch2Id || !wunsch3Id} class:bg-gray-400={formHatFehler || !zeitraum || !wuenscheVollstaendig}
class:cursor-not-allowed={formHatFehler || !zeitraum || !wunsch1Id || !wunsch2Id || !wunsch3Id} class:cursor-not-allowed={formHatFehler || !zeitraum || !wuenscheVollstaendig}
> >
Jetzt anmelden Jetzt anmelden
</button> </button>