diff --git a/css/event_create.css b/css/event_create.css
index c781e36..4bb5f02 100644
--- a/css/event_create.css
+++ b/css/event_create.css
@@ -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));
}
-}
\ No newline at end of file
+}
diff --git a/css/login_signup.css b/css/login_signup.css
index b2c8683..b257730 100644
--- a/css/login_signup.css
+++ b/css/login_signup.css
@@ -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;
-}
\ No newline at end of file
+}
diff --git a/css/stylesheet_global.css b/css/stylesheet_global.css
index fdd8e2d..1ff4ed6 100644
--- a/css/stylesheet_global.css
+++ b/css/stylesheet_global.css
@@ -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 */
diff --git a/event_create.html b/event_create.html
index 245d70d..4651b48 100644
--- a/event_create.html
+++ b/event_create.html
@@ -240,7 +240,7 @@
-
+
@@ -379,9 +379,6 @@
+
-
-
diff --git a/js/event_create.js b/js/event_create.js
index 2f53f1e..557edc1 100644
--- a/js/event_create.js
+++ b/js/event_create.js
@@ -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);
};
diff --git a/js/login.js b/js/login.js
index fc1414e..aa8118e 100644
--- a/js/login.js
+++ b/js/login.js
@@ -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);
\ No newline at end of file
+loginForm.addEventListener('submit', validateForm);
diff --git a/js/signup.js b/js/signup.js
index 9329f96..8afb01d 100644
--- a/js/signup.js
+++ b/js/signup.js
@@ -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);
\ No newline at end of file
+signupForm.addEventListener('submit', validateForm);
diff --git a/login.html b/login.html
index 6c8455d..946f00f 100644
--- a/login.html
+++ b/login.html
@@ -35,17 +35,17 @@