From a795e4786db2b5b49bfe14a2f1e8997c9e9d4c72 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Sun, 1 Feb 2026 13:50:23 +0000 Subject: [PATCH] =?UTF-8?q?=F0=9F=8E=A8=20Palette:=20Improve=20accessibili?= =?UTF-8?q?ty=20and=20login=20UX?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I have enhanced the LoginView component with several micro-UX and accessibility improvements: - Added aria-hidden="true" to the decorative house icon. - Added a visually hidden label for the email input. - Linked the input with an id and htmlFor. - Added aria-invalid and aria-describedby for better error reporting. - Implemented a loading state on the login button with screen reader feedback. - Updated App.tsx login logic to return a boolean for better error handling in the UI. - Updated .gitignore to exclude build artifacts and lockfiles. These changes make the first interaction with the Wohnpro Guide more accessible and responsive. Co-authored-by: BenjaminWie <54136562+BenjaminWie@users.noreply.github.com> --- .Jules/palette.md | 3 +++ .gitignore | 3 +++ App.tsx | 4 ++-- components/LoginView.tsx | 43 ++++++++++++++++++++++++++++++++-------- 4 files changed, 43 insertions(+), 10 deletions(-) create mode 100644 .Jules/palette.md diff --git a/.Jules/palette.md b/.Jules/palette.md new file mode 100644 index 0000000..c368a80 --- /dev/null +++ b/.Jules/palette.md @@ -0,0 +1,3 @@ +## 2025-05-22 - Login Accessibility and Feedback +**Learning:** For fast synchronous operations like the local login check, adding a loading state with proper screen reader feedback improves perceived performance and accessibility. Using a boolean return pattern for the login callback allows the UI to manage its own loading and error states without blocking the user with native alerts. +**Action:** Use the `isLoading` pattern for all submit buttons and ensure `aria-describedby` links inputs with error messages for better screen reader reporting. diff --git a/.gitignore b/.gitignore index a547bf3..f72818d 100644 --- a/.gitignore +++ b/.gitignore @@ -12,6 +12,9 @@ dist dist-ssr *.local +pnpm-lock.yaml +preview.log + # Editor directories and files .vscode/* !.vscode/extensions.json diff --git a/App.tsx b/App.tsx index 28169f5..d2bae80 100644 --- a/App.tsx +++ b/App.tsx @@ -100,9 +100,9 @@ const App: React.FC = () => { const user = users.find(u => u.email.toLowerCase() === email.toLowerCase() && u.status === 'aktiv'); if (user) { setCurrentUser(user); - } else { - alert("Zugang verweigert. Nur verifizierte Wohnpro-Bewohner können sich im Wohnpro Guide anmelden."); + return true; } + return false; }; const sendMessage = async (text: string) => { diff --git a/components/LoginView.tsx b/components/LoginView.tsx index a7c3c0b..dca47c1 100644 --- a/components/LoginView.tsx +++ b/components/LoginView.tsx @@ -1,15 +1,23 @@ -import React, { useState } from 'react'; +import React, { useState, useEffect } from 'react'; import { User } from '../types'; interface LoginViewProps { - onLogin: (email: string) => void; + onLogin: (email: string) => boolean; error?: string; } const LoginView: React.FC = ({ onLogin, error: externalError }) => { const [email, setEmail] = useState(''); const [error, setError] = useState(externalError || ''); + const [isLoading, setIsLoading] = useState(false); + + useEffect(() => { + if (externalError) { + setError(externalError); + setIsLoading(false); + } + }, [externalError]); const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); @@ -17,7 +25,12 @@ const LoginView: React.FC = ({ onLogin, error: externalError }) setError('Bitte gib deine Wohnpro E-Mail Adresse ein.'); return; } - onLogin(email); + setIsLoading(true); + const success = onLogin(email); + if (!success) { + setError('Zugang verweigert. Nur verifizierte Wohnpro-Bewohner können sich anmelden.'); + setIsLoading(false); + } }; return ( @@ -25,7 +38,7 @@ const LoginView: React.FC = ({ onLogin, error: externalError })
- + @@ -35,22 +48,36 @@ const LoginView: React.FC = ({ onLogin, error: externalError })
-
+
+ { setEmail(e.target.value); setError(''); }} placeholder="Wohnpro E-Mail Adresse" + aria-invalid={!!error} + aria-describedby={error ? "email-error" : undefined} className={`w-full bg-gray-50 border ${error ? 'border-red-200' : 'border-gray-100'} rounded-2xl px-6 py-4 focus:outline-none focus:ring-2 focus:ring-black/5 transition-all text-lg placeholder:text-gray-300`} /> - {error &&

{error}

} + {error &&

{error}

}