learning_ai_common_plat/packages/auth-ui/src/ResetPasswordForm.tsx
saravanakumardb1 43439e9c85 feat(auth-ui): complete Auth UI Kit (3.2) — 7 new components, 54 tests
New components:
- RegisterForm — name, email, password, confirm, terms, password strength
- ForgotPasswordForm — email input with success/error states, back link
- ResetPasswordForm — new password + confirm with strength indicator
- VerifyEmailForm — 6-digit code input with resend, numeric-only filter
- OnboardingShell — step indicator, progress bar, back/next/complete nav
- AuthPageLayout — full-page centered card with product branding
- PasswordStrengthBar — visual bar + label (weak/fair/good/strong)

Existing components preserved: LoginForm, MfaChallenge, SocialButtons
All styled via --bl-* CSS custom properties for product theming
54 tests (13 existing + 41 new) — all passing
2026-03-19 20:25:57 -07:00

132 lines
3.8 KiB
TypeScript

import { useState, type FormEvent } from 'react';
import { PasswordStrengthBar } from './PasswordStrengthBar.js';
import type { ResetPasswordFormProps } from './types.js';
/**
* Reset password form — new password + confirm, with strength indicator.
* Styled via CSS custom properties (inherits --bl-* from host app).
*/
export function ResetPasswordForm({
onSubmit,
isLoading = false,
error,
success,
className,
}: ResetPasswordFormProps) {
const [password, setPassword] = useState('');
const [confirm, setConfirm] = useState('');
const passwordMismatch = confirm.length > 0 && password !== confirm;
const canSubmit = password.length >= 8 && !passwordMismatch && !isLoading;
function handleSubmit(e: FormEvent) {
e.preventDefault();
if (!canSubmit) return;
onSubmit(password);
}
const inputStyle = {
padding: '10px 12px',
border: '1px solid var(--bl-border, #ccc)',
borderRadius: 'var(--bl-radius, 6px)',
fontSize: '14px',
width: '100%',
boxSizing: 'border-box' as const,
};
return (
<div className={className} data-testid="bl-reset-password-form">
<form
onSubmit={handleSubmit}
style={{ display: 'flex', flexDirection: 'column', gap: '12px' }}
>
<div style={{ fontSize: '14px', color: 'var(--bl-text, #333)' }}>
Enter your new password.
</div>
<label style={{ fontSize: '13px', fontWeight: 500, color: 'var(--bl-text, #333)' }}>
New password
<input
type="password"
placeholder="Min 8 characters"
value={password}
onChange={e => setPassword(e.target.value)}
required
minLength={8}
disabled={isLoading}
data-testid="bl-reset-password"
style={{ ...inputStyle, marginTop: '4px', display: 'block' }}
/>
</label>
<PasswordStrengthBar password={password} />
<label style={{ fontSize: '13px', fontWeight: 500, color: 'var(--bl-text, #333)' }}>
Confirm password
<input
type="password"
placeholder="Re-enter password"
value={confirm}
onChange={e => setConfirm(e.target.value)}
required
disabled={isLoading}
data-testid="bl-reset-confirm"
style={{
...inputStyle,
marginTop: '4px',
display: 'block',
borderColor: passwordMismatch ? 'var(--bl-error, #dc3545)' : undefined,
}}
/>
</label>
{passwordMismatch && (
<div
data-testid="bl-reset-mismatch"
style={{ color: 'var(--bl-error, #dc3545)', fontSize: '12px' }}
>
Passwords do not match
</div>
)}
{error && (
<div
data-testid="bl-reset-error"
style={{ color: 'var(--bl-error, #dc3545)', fontSize: '13px' }}
>
{error}
</div>
)}
{success && (
<div
data-testid="bl-reset-success"
style={{ color: 'var(--bl-success, #22c55e)', fontSize: '13px' }}
>
{success}
</div>
)}
<button
type="submit"
disabled={!canSubmit}
data-testid="bl-reset-submit"
style={{
padding: '10px 16px',
border: 'none',
borderRadius: 'var(--bl-radius, 6px)',
background: 'var(--bl-primary, #0066ff)',
color: '#fff',
cursor: !canSubmit ? 'not-allowed' : 'pointer',
fontSize: '14px',
fontWeight: 600,
opacity: !canSubmit ? 0.6 : 1,
}}
>
{isLoading ? 'Updating...' : 'Update password'}
</button>
</form>
</div>
);
}