Anpassungen event-create + Fehlermeldungen in login und signup

This commit is contained in:
Ysabelle Moser 2026-04-23 00:56:09 +02:00
parent 7ecc2cf91a
commit 485254d3e7
9 changed files with 254 additions and 120 deletions

View File

@ -310,32 +310,31 @@ textarea:focus {
align-items: center;
}
.error-message {
margin: 0;
text-align: center;
width: 100%;
}
.progress-wrap {
width: min(100%, var(--content-width));
margin: 0 auto;
flex: 1;
position: relative;
display: flex;
align-items: center;
gap: 0.75rem;
align-self: center;
min-height: 2.75rem;
}
.progress-label {
flex-shrink: 0;
position: absolute;
top: -1.1rem;
left: 50%;
transform: translateX(-50%);
font-size: 1rem;
font-weight: 400;
color: var(--black);
white-space: nowrap;
text-align: center;
}
.progress {
flex: 1;
height: 0.3rem;
width: 100%;
height: 0.45rem;
background: var(--olive-light);
border-radius: var(--radius-sm);
overflow: hidden;
@ -360,9 +359,16 @@ textarea:focus {
}
.flow-actions-right {
position: relative;
display: flex;
align-items: center;
gap: var(--space-4);
justify-content: flex-end;
}
.error-message--callout {
position: absolute;
right: 0;
bottom: calc(100% + 1.25rem);
}
.button--ghost:hover {
@ -454,6 +460,26 @@ textarea:focus-visible {
align-items: stretch;
}
.error-message--callout {
position: static;
width: 100%;
max-width: 100%;
margin-bottom: var(--space-2);
}
.progress-wrap {
min-height: auto;
}
.progress-label {
position: static;
transform: none;
}
.error-message--callout::after {
display: none;
}
.event-flow-header {
justify-content: flex-start;
}
@ -477,4 +503,4 @@ textarea:focus-visible {
.option-grid--4 {
grid-template-columns: repeat(4, minmax(0, 1fr));
}
}
}

View File

@ -68,6 +68,10 @@ h1 {
margin-bottom: var(--space-4);
}
.form-group.has-error {
margin-bottom: var(--space-2);
}
label {
display: block;
margin-bottom: var(--space-1);
@ -138,9 +142,10 @@ button[type="submit"]:active {
/* --- Hints & errors --- */
.error-message {
margin-top: 5px;
.error-message--field-callout {
display: none;
margin-top: 0.65rem;
margin-left: auto;
}
.form-group.has-error input {
@ -148,7 +153,7 @@ button[type="submit"]:active {
box-shadow: 0 0 5px rgba(212, 75, 36, 0.3);
}
.form-group.has-error .error-message {
.form-group.has-error .error-message--field-callout {
display: block;
}
@ -272,6 +277,16 @@ button[type="submit"]:active {
.image-section {
min-height: 300px;
}
.error-message--field-callout {
margin-top: var(--space-1);
max-width: 100%;
white-space: normal;
}
.error-message--field-callout::after {
display: none;
}
}
@ -299,4 +314,4 @@ button[type="submit"]:active {
.snackbar--visible {
transform: translateX(-50%) translateY(0);
opacity: 1;
}
}

View File

@ -175,8 +175,74 @@ label {
}
.error-message {
color: var(--error-text);
font-family: var(--font-main);
font-size: 1rem;
line-height: 1.4;
}
.error-message--inline {
color: var(--error-text);
}
.error-message--field-callout {
display: none;
width: fit-content;
max-width: min(100%, 20rem);
padding: 0.35rem 0.8rem;
border-radius: var(--radius-md);
background: var(--error);
color: var(--white);
text-align: center;
font-size: 0.8125rem;
line-height: 1.2;
white-space: normal;
overflow-wrap: anywhere;
position: relative;
}
.error-message--field-callout::after {
content: "";
position: absolute;
top: -0.35rem;
right: 1.6rem;
width: 0.8rem;
height: 0.8rem;
background: inherit;
border-top-left-radius: 0.2rem;
transform: rotate(45deg);
}
.error-message--callout {
display: none;
width: max-content;
max-width: 15rem;
padding: 0.7rem 1.15rem;
border-radius: 1rem;
background: var(--error);
color: #ffffff;
text-align: center;
font-size: 0.95rem;
line-height: 1.25;
white-space: normal;
overflow-wrap: anywhere;
box-shadow: var(--shadow-interaction);
z-index: 1;
}
.error-message--callout:not(:empty) {
display: block;
}
.error-message--callout::after {
content: "";
position: absolute;
right: 2.1rem;
bottom: -0.55rem;
width: 1.1rem;
height: 1.1rem;
background: inherit;
border-bottom-right-radius: 0.25rem;
transform: rotate(45deg);
}
/* Margins */

View File

@ -240,7 +240,7 @@
<div class="form-field">
<label for="eventTime">Uhrzeit</label>
<input type="time" id="eventTime" name="eventTime" required />
<input type="time" id="eventTime" name="eventTime" value="00:00" required />
</div>
</div>
</div>
@ -379,9 +379,6 @@
<div class="flow-footer layout-narrow" id="flowFooter" hidden>
<p id="errorMessage" class="error-message" role="alert" aria-live="assertive"></p>
<div class="flow-actions">
<button type="button" id="backButton" class="button-secondary">
Zurück
@ -396,14 +393,17 @@
</div>
</div>
<div class="flow-actions-right">
<p
id="errorMessage"
class="error-message error-message--callout"
role="alert"
aria-live="assertive"
></p>
<button type="button" id="nextButton" class="button-primary">
Weiter
</button>
</div>
<div class="flow-actions-right">
<p id="errorMessage" class="error-message" role="alert" aria-live="assertive"></p>
</div>
</div>

View File

@ -23,6 +23,7 @@ const CURRENT_USER_KEY = "socialCookingCurrentUser";
// =============================
let currentStep = 0;
const lastStep = steps.length - 1;
let reviewReturnStep = null;
// Text für den Weiter-Button je nach Schritt
const nextLabels = {
@ -151,10 +152,14 @@ function showStep(index, pushHistory = true) {
*/
function updateFlowVisibility(stepIndex) {
const isIntroStep = stepIndex === 0;
const isReviewReturnMode = reviewReturnStep === lastStep && stepIndex < lastStep;
flowFooter.hidden = isIntroStep;
backButton.hidden = isIntroStep;
nextButton.textContent = nextLabels[stepIndex];
backButton.textContent = "Zurück";
nextButton.textContent = isReviewReturnMode
? "Zurück zur Übersicht"
: nextLabels[stepIndex];
}
@ -567,6 +572,10 @@ function validateRequiredFields(fields) {
* Wenn der User im ersten Formularschritt ist, geht es zurück zum Intro.
*/
function handleBackClick() {
if (reviewReturnStep === lastStep && currentStep < lastStep) {
reviewReturnStep = null;
}
if (currentStep > 1) {
showStep(currentStep - 1);
} else {
@ -582,6 +591,12 @@ function handleBackClick() {
function handleNextClick() {
if (!validateCurrentStep()) return;
if (reviewReturnStep === lastStep && currentStep < lastStep) {
showStep(lastStep);
reviewReturnStep = null;
return;
}
if (currentStep < lastStep) {
showStep(currentStep + 1);
} else {
@ -701,6 +716,8 @@ function registerReviewEditHandlers() {
const stepIndex = Number(item.dataset.editStep);
const fieldName = item.dataset.editField;
// Öffnet einen Schritt aus der Übersicht und springt danach direkt zurück zu Schritt 7.
reviewReturnStep = lastStep;
showStep(stepIndex);
focusFieldByName(fieldName);
};

View File

@ -50,69 +50,74 @@ function createFallbackUser(email, passwort) {
// Validierungsfunktion
function validateForm(event) {
event.preventDefault();
let isValid = true;
// Email-Validierung
// Wir zeigen bewusst immer nur den ersten Fehler im Formular an.
// So bleibt der Ablauf ruhig und führt den Nutzer Feld für Feld.
const emailValue = emailInput.value.trim();
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
const emailGroup = emailInput.parentElement;
const passwortGroup = passwortInput.parentElement;
emailGroup.classList.remove('has-error');
passwortGroup.classList.remove('has-error');
if (!emailValue) {
emailGroup.classList.add('has-error');
emailError.textContent = 'Bitte gib deine E-Mail Adresse ein.';
isValid = false;
} else if (!emailRegex.test(emailValue)) {
emailInput.focus();
return;
}
if (!emailRegex.test(emailValue)) {
emailGroup.classList.add('has-error');
emailError.textContent = 'Bitte gib eine gültige E-Mail Adresse ein.';
isValid = false;
} else {
emailGroup.classList.remove('has-error');
emailInput.focus();
return;
}
// Passwort-Validierung
const passwortValue = passwortInput.value;
const passwortGroup = passwortInput.parentElement;
if (!passwortValue) {
passwortGroup.classList.add('has-error');
passwortError.textContent = 'Bitte gib dein Passwort ein.';
isValid = false;
} else if (passwortValue.length < 6) {
passwortInput.focus();
return;
}
if (passwortValue.length < 6) {
passwortGroup.classList.add('has-error');
passwortError.textContent = 'Dein Passwort ist zu kurz. Bitte überprüfe dein Passwort.';
isValid = false;
} else {
passwortGroup.classList.remove('has-error');
passwortInput.focus();
return;
}
// Wenn alle Validierungen bestanden, prüfen wir:
// 1) gibt es den Benutzer schon?
// 2) ist das Passwort korrekt?
// Danach speichern wir die aktive Session.
if (isValid) {
const users = getStoredUsers();
const matchedUser = users.find(user => user.email?.toLowerCase() === emailValue.toLowerCase());
const users = getStoredUsers();
const matchedUser = users.find(user => user.email?.toLowerCase() === emailValue.toLowerCase());
if (matchedUser && matchedUser.passwort !== passwortValue) {
passwortGroup.classList.add('has-error');
passwortError.textContent = 'Das Passwort ist nicht korrekt.';
return;
}
if (matchedUser && matchedUser.passwort !== passwortValue) {
passwortGroup.classList.add('has-error');
passwortError.textContent = 'Das Passwort ist nicht korrekt.';
passwortInput.focus();
return;
}
const userToLogin = matchedUser || createFallbackUser(emailValue, passwortValue);
setCurrentUser(userToLogin);
const userToLogin = matchedUser || createFallbackUser(emailValue, passwortValue);
setCurrentUser(userToLogin);
// Snackbar anzeigen und dann zur Event-Übersicht weiterleiten.
var snackbar = document.getElementById('snackbar');
if (snackbar) {
snackbar.classList.add('snackbar--visible');
setTimeout(function() {
window.location.href = 'event_overview.html';
}, 2000);
} else {
// Snackbar anzeigen und dann zur Event-Übersicht weiterleiten.
var snackbar = document.getElementById('snackbar');
if (snackbar) {
snackbar.classList.add('snackbar--visible');
setTimeout(function() {
window.location.href = 'event_overview.html';
}
}, 2000);
} else {
window.location.href = 'event_overview.html';
}
}
@ -132,4 +137,4 @@ passwortInput.addEventListener('input', function() {
});
// Form Submit Event
loginForm.addEventListener('submit', validateForm);
loginForm.addEventListener('submit', validateForm);

View File

@ -52,95 +52,100 @@ function closeWelcomeModal() {
// Hauptfunktion für Formularvalidierung und Speicherung.
function validateForm(event) {
event.preventDefault();
let isValid = true;
// Vorname-Validierung
// Wir zeigen pro Submit nur den ersten Fehler an.
// So bleibt der Formularfluss klar und ruhig.
const vornameValue = vornameInput.value.trim();
const vornameGroup = vornameInput.parentElement;
const nachnameGroup = nachnameInput.parentElement;
const emailGroup = emailInput.parentElement;
const passwortGroup = passwortInput.parentElement;
vornameGroup.classList.remove('has-error');
nachnameGroup.classList.remove('has-error');
emailGroup.classList.remove('has-error');
passwortGroup.classList.remove('has-error');
if (!vornameValue) {
vornameGroup.classList.add('has-error');
isValid = false;
} else {
vornameGroup.classList.remove('has-error');
vornameInput.focus();
return;
}
// Nachname-Validierung
const nachnameValue = nachnameInput.value.trim();
const nachnameGroup = nachnameInput.parentElement;
if (!nachnameValue) {
nachnameGroup.classList.add('has-error');
isValid = false;
} else {
nachnameGroup.classList.remove('has-error');
nachnameInput.focus();
return;
}
// Email-Validierung
const emailValue = emailInput.value.trim();
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
const emailGroup = emailInput.parentElement;
if (!emailValue) {
emailGroup.classList.add('has-error');
document.getElementById('emailError').textContent = 'Bitte gib deine E-Mail Adresse ein.';
isValid = false;
} else if (!emailRegex.test(emailValue)) {
emailInput.focus();
return;
}
if (!emailRegex.test(emailValue)) {
emailGroup.classList.add('has-error');
document.getElementById('emailError').textContent = 'Bitte gib eine gültige E-Mail Adresse ein.';
isValid = false;
} else {
emailGroup.classList.remove('has-error');
emailInput.focus();
return;
}
// Passwort-Validierung
const passwortValue = passwortInput.value;
const passwortGroup = passwortInput.parentElement;
if (!passwortValue) {
passwortGroup.classList.add('has-error');
document.getElementById('passwortError').textContent = 'Bitte gib ein Passwort ein.';
isValid = false;
} else if (passwortValue.length < 8) {
passwortInput.focus();
return;
}
if (passwortValue.length < 8) {
passwortGroup.classList.add('has-error');
document.getElementById('passwortError').textContent = 'Dein Passwort muss mindestens 8 Zeichen lang sein.';
isValid = false;
} else {
passwortGroup.classList.remove('has-error');
passwortInput.focus();
return;
}
// Wenn alles gültig ist:
// 1) auf doppelte E-Mail prüfen
// 2) neuen Benutzer speichern
// 3) als aktuellen Benutzer einloggen
if (isValid) {
const existingUsers = getStoredUsers();
const emailLower = emailValue.toLowerCase();
const emailAlreadyUsed = existingUsers.some(user => user.email?.toLowerCase() === emailLower);
const existingUsers = getStoredUsers();
const emailLower = emailValue.toLowerCase();
const emailAlreadyUsed = existingUsers.some(user => user.email?.toLowerCase() === emailLower);
if (emailAlreadyUsed) {
emailGroup.classList.add('has-error');
document.getElementById('emailError').textContent = 'Diese E-Mail ist bereits registriert. Bitte nutze den Login.';
return;
}
const newUser = {
id: Date.now(),
vorname: vornameValue,
nachname: nachnameValue,
email: emailValue,
passwort: passwortValue,
createdAt: new Date().toISOString(),
source: 'signup'
};
setStoredUsers([newUser, ...existingUsers]);
setCurrentUser(newUser);
openWelcomeModal();
// Weiterleitung erfolgt beim Klick auf "Weiter zu den Events".
if (emailAlreadyUsed) {
emailGroup.classList.add('has-error');
document.getElementById('emailError').textContent = 'Diese E-Mail ist bereits registriert. Bitte nutze den Login.';
emailInput.focus();
return;
}
const newUser = {
id: Date.now(),
vorname: vornameValue,
nachname: nachnameValue,
email: emailValue,
passwort: passwortValue,
createdAt: new Date().toISOString(),
source: 'signup'
};
setStoredUsers([newUser, ...existingUsers]);
setCurrentUser(newUser);
openWelcomeModal();
// Weiterleitung erfolgt beim Klick auf "Weiter zu den Events".
}
// Fehlerbehandlung bei Input-Änderung (entfernt Fehler wenn Benutzer korrigiert)
@ -180,4 +185,4 @@ welcomeModal.addEventListener('click', function(event) {
});
// Form Submit Event
signupForm.addEventListener('submit', validateForm);
signupForm.addEventListener('submit', validateForm);

View File

@ -35,17 +35,17 @@
<div class="form-section">
<h1>Login</h1>
<form id="loginForm">
<form id="loginForm" novalidate>
<div class="form-group">
<label for="email">E-Mail</label>
<input type="email" id="email" name="email" required placeholder="deine.email@example.com">
<div class="error-message" id="emailError">Bitte gib eine gültige E-Mail Adresse ein.</div>
<div class="error-message error-message--field-callout" id="emailError">Bitte gib eine gültige E-Mail Adresse ein.</div>
</div>
<div class="form-group">
<label for="passwort">Passwort</label>
<input type="password" id="passwort" name="passwort" required placeholder="Gib dein Passwort ein">
<div class="error-message" id="passwortError">Bitte gib dein Passwort ein.</div>
<div class="error-message error-message--field-callout" id="passwortError">Bitte gib dein Passwort ein.</div>
</div>
<button type="submit" class="button-primary">Login</button>
@ -76,4 +76,4 @@
</div>
</div>
</body>
</html>
</html>

View File

@ -39,29 +39,29 @@
<strong>Hinweis:</strong> Sichtbar auf der Plattform ist nur dein Vorname. Erst einer Anmeldung zum Event ist der Nachname für die Teilnehmenden sichtbar.
</div>
<form id="signupForm">
<form id="signupForm" novalidate>
<div class="form-group">
<label for="vorname">Vorname *</label>
<input type="text" id="vorname" name="vorname" required placeholder="Dein Vorname">
<div class="error-message" id="vornameError">Bitte gib deinen Vornamen ein.</div>
<div class="error-message error-message--field-callout" id="vornameError">Bitte gib deinen Vornamen ein.</div>
</div>
<div class="form-group">
<label for="nachname">Nachname *</label>
<input type="text" id="nachname" name="nachname" required placeholder="Dein Nachname">
<div class="error-message" id="nachnameError">Bitte gib deinen Nachnamen ein.</div>
<div class="error-message error-message--field-callout" id="nachnameError">Bitte gib deinen Nachnamen ein.</div>
</div>
<div class="form-group">
<label for="email">E-Mail *</label>
<input type="email" id="email" name="email" required placeholder="deine.email@example.com">
<div class="error-message" id="emailError">Bitte gib eine gültige E-Mail Adresse ein.</div>
<div class="error-message error-message--field-callout" id="emailError">Bitte gib eine gültige E-Mail Adresse ein.</div>
</div>
<div class="form-group">
<label for="passwort">Passwort *</label>
<input type="password" id="passwort" name="passwort" required placeholder="Mindestens 8 Zeichen">
<div class="error-message" id="passwortError">Dein Passwort muss mindestens 8 Zeichen lang sein.</div>
<div class="error-message error-message--field-callout" id="passwortError">Dein Passwort muss mindestens 8 Zeichen lang sein.</div>
</div>
<button type="submit" class="button-primary">Konto erstellen</button>
@ -108,4 +108,4 @@
</div>
</div>
</body>
</html>
</html>