Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .Jules/palette.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,3 +94,7 @@
## 2025-06-16 - [Functional Matchers for Complex Buttons and Utility-First Layout]
**Learning:** React Testing Library's `findByText` can fail on buttons containing Materialize icons due to text node fragmentation and the icon's name being part of the `textContent`. Using a functional matcher that checks for partial content and tag name is more robust. Additionally, strictly adhering to utility classes (e.g., 'center-align') instead of inline styles ensures compliance with repository constraints and theme consistency.
**Action:** Always use functional matchers for testing interactive elements with icons and avoid inline styles by leveraging existing CSS utility classes.

## 2025-06-18 - [Standardized Accessibility and Password Visibility in V2 Auth Forms]
**Learning:** In V2 authentication flows, maintaining feature parity between Login, Signup, and Forgot Password pages—specifically regarding password visibility toggles and label-input associations—ensures a predictable and accessible user experience. Missing `id` and `htmlFor` attributes on inputs breaks screen reader navigation even if the layout looks correct.
**Action:** Always audit the full authentication suite (Login, Signup, Recovery) for accessibility parity and ensure interactive password fields consistently offer visibility toggles.
7 changes: 4 additions & 3 deletions src/v2/pages/V2ForgotPassword.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ const V2ForgotPassword = () => {
display: 'flex', alignItems: 'center', justifyContent: 'center',
margin: '0 auto 16px'
}}>
<i className="material-icons" style={{ fontSize: '40px' }}>lock_reset</i>
<i className="material-icons" style={{ fontSize: '40px' }} aria-hidden="true">lock_reset</i>
</div>
<h1 className="v2-headline-medium" style={{ color: 'var(--md-sys-color-primary)' }}>Recuperar Acceso</h1>
<p className="v2-body-large" style={{ opacity: 0.7 }}>
Expand All @@ -48,8 +48,9 @@ const V2ForgotPassword = () => {
{!submitted ? (
<form onSubmit={handleResetRequest} style={{ display: 'flex', flexDirection: 'column', gap: '20px', textAlign: 'left' }}>
<div className="v2-input-outlined">
<label>Correo Electrónico</label>
<label htmlFor="email">Correo Electrónico</label>
<input
id="email"
type="email"
placeholder="doctor@medical.com"
value={email}
Expand All @@ -60,7 +61,7 @@ const V2ForgotPassword = () => {

<button type="submit" className="v2-btn-filled" style={{ justifyContent: 'center', height: '56px' }} disabled={loading}>
{loading ? 'Procesando...' : 'Enviar Instrucciones'}
{!loading && <i className="material-icons">send</i>}
{!loading && <i className="material-icons" aria-hidden="true">send</i>}
</button>
</form>
) : (
Expand Down
44 changes: 36 additions & 8 deletions src/v2/pages/V2Signup.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ const V2Signup = () => {
username: '',
password: ''
});
const [showPassword, setShowPassword] = useState(false);
const [loading, setLoading] = useState(false);
const history = useHistory();

Expand Down Expand Up @@ -53,16 +54,17 @@ const V2Signup = () => {
display: 'flex', alignItems: 'center', justifyContent: 'center',
margin: '0 auto 16px'
}}>
<i className="material-icons" style={{ fontSize: '40px' }}>app_registration</i>
<i className="material-icons" style={{ fontSize: '40px' }} aria-hidden="true">app_registration</i>
</div>
<h1 className="v2-headline-medium" style={{ color: 'var(--md-sys-color-primary)' }}>Crear Cuenta</h1>
<p className="v2-body-large" style={{ opacity: 0.7 }}>Únete a la comunidad de médicos de élite</p>
</div>

<form onSubmit={handleSignup} style={{ display: 'flex', flexDirection: 'column', gap: '16px', textAlign: 'left' }}>
<div className="v2-input-outlined">
<label>Nombre Completo</label>
<label htmlFor="name">Nombre Completo</label>
<input
id="name"
type="text"
name="name"
placeholder="Dr. García"
Expand All @@ -73,8 +75,9 @@ const V2Signup = () => {
</div>

<div className="v2-input-outlined">
<label>Correo Electrónico</label>
<label htmlFor="email">Correo Electrónico</label>
<input
id="email"
type="email"
name="email"
placeholder="doctor@medical.com"
Expand All @@ -85,8 +88,9 @@ const V2Signup = () => {
</div>

<div className="v2-input-outlined">
<label>Nombre de Usuario</label>
<label htmlFor="username">Nombre de Usuario</label>
<input
id="username"
type="text"
name="username"
placeholder="drgarcia"
Expand All @@ -96,21 +100,45 @@ const V2Signup = () => {
/>
</div>

<div className="v2-input-outlined">
<label>Contraseña</label>
<div className="v2-input-outlined" style={{ position: 'relative' }}>
<label htmlFor="password">Contraseña</label>
<input
type="password"
id="password"
type={showPassword ? "text" : "password"}
name="password"
placeholder="••••••••"
value={formData.password}
onChange={handleChange}
required
style={{ paddingRight: '48px' }}
/>
<button
type="button"
onClick={() => setShowPassword(!showPassword)}
aria-label={showPassword ? "Ocultar contraseña" : "Mostrar contraseña"}
title={showPassword ? "Ocultar contraseña" : "Mostrar contraseña"}
style={{
position: 'absolute',
right: '12px',
top: '50%',
transform: 'translateY(-50%)',
background: 'none',
border: 'none',
cursor: 'pointer',
color: 'var(--md-sys-color-outline)',
display: 'flex',
alignItems: 'center',
padding: '8px',
marginTop: '12px'
}}
>
<i className="material-icons">{showPassword ? 'visibility_off' : 'visibility'}</i>
</button>
</div>

<button type="submit" className="v2-btn-filled" style={{ justifyContent: 'center', height: '56px', marginTop: '8px' }} disabled={loading}>
{loading ? 'Creando cuenta...' : 'Registrarse'}
{!loading && <i className="material-icons">person_add</i>}
{!loading && <i className="material-icons" aria-hidden="true">person_add</i>}
</button>
</form>

Expand Down
Loading