Redesign sign-in / create-account page: split layout, benefits panel, show/hide password, real form submit; v2.10.6
Publish Container / build (push) Has been cancelled
Publish Container / build (push) Has been cancelled
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
b708371cc5
commit
640d0c1c18
3 files changed
+234
-50
No files matched your search
+52
-49
@@ -1130,6 +1130,7 @@ export function StudySignupPage() {
|
||||
const [resendStatus, setResendStatus] = useState<'idle' | 'sending' | 'sent'>('idle')
|
||||
// Forgot-password state
|
||||
const [forgotSent, setForgotSent] = useState(false)
|
||||
const [showPassword, setShowPassword] = useState(false)
|
||||
|
||||
useEffect(() => {
|
||||
readJson<StudyAuthStatusResponse>('/api/study-auth/status')
|
||||
@@ -1215,10 +1216,38 @@ export function StudySignupPage() {
|
||||
}
|
||||
}, [email])
|
||||
|
||||
const showAside = !done && mode !== 'forgot' && !totpPendingToken
|
||||
|
||||
return (
|
||||
<main className="thanks-page" aria-label={mode === 'signup' ? 'Create account' : mode === 'forgot' ? 'Reset password' : 'Sign in'}>
|
||||
<div className="thanks-card study-signup-page-card">
|
||||
<p className="eyebrow">Free Student Account</p>
|
||||
<main className="auth-page" aria-label={mode === 'signup' ? 'Create account' : mode === 'forgot' ? 'Reset password' : 'Sign in'}>
|
||||
<div className={`auth-shell${showAside ? '' : ' auth-shell--single'}`}>
|
||||
{showAside && (
|
||||
<aside className="auth-aside" aria-label={mode === 'signup' ? 'Why create an account' : 'Welcome back'}>
|
||||
{mode === 'signup' ? (
|
||||
<>
|
||||
<p className="eyebrow">Free Student Account</p>
|
||||
<h2 className="auth-aside-title">Make every lesson your own.</h2>
|
||||
<ul className="auth-benefits">
|
||||
<li><span aria-hidden="true">📝</span><div><strong>Notes on every lesson</strong><p>Up to 500 notes across all tracks, each holding about 2,000 words.</p></div></li>
|
||||
<li><span aria-hidden="true">✅</span><div><strong>Track your progress</strong><p>Pick up exactly where you left off, on any device.</p></div></li>
|
||||
<li><span aria-hidden="true">🔒</span><div><strong>Private to you</strong><p>Your notes are tied to your account. Nobody else can read them.</p></div></li>
|
||||
<li><span aria-hidden="true">⚡</span><div><strong>Free, no ads</strong><p>Just an email and password. You stay signed in for 30 days.</p></div></li>
|
||||
</ul>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<p className="eyebrow">Free Student Account</p>
|
||||
<h2 className="auth-aside-title">Pick up where you left off.</h2>
|
||||
<ul className="auth-benefits">
|
||||
<li><span aria-hidden="true">📝</span><div><strong>Your notes</strong><p>Every lesson note you've saved, waiting for you.</p></div></li>
|
||||
<li><span aria-hidden="true">✅</span><div><strong>Your progress</strong><p>Resume your studies right where you stopped.</p></div></li>
|
||||
</ul>
|
||||
</>
|
||||
)}
|
||||
</aside>
|
||||
)}
|
||||
<div className="auth-card">
|
||||
<p className="eyebrow auth-card-eyebrow">{mode === 'signup' ? 'Create account' : mode === 'forgot' ? 'Account recovery' : 'Sign in'}</p>
|
||||
<h1>{mode === 'signup' ? 'Create Your Account' : mode === 'forgot' ? 'Reset Your Password' : 'Welcome Back'}</h1>
|
||||
|
||||
{done ? (
|
||||
@@ -1317,7 +1346,7 @@ export function StudySignupPage() {
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
<div className="study-signup-form">
|
||||
<form className="study-signup-form" noValidate onSubmit={e => { e.preventDefault(); void submit() }}>
|
||||
<label htmlFor="signup-email">Email</label>
|
||||
<input
|
||||
id="signup-email"
|
||||
@@ -1337,9 +1366,10 @@ export function StudySignupPage() {
|
||||
/>
|
||||
{fieldErrors.email && <p className="study-signup-field-error">{fieldErrors.email}</p>}
|
||||
<label htmlFor="signup-password">Password</label>
|
||||
<div className="auth-password-wrap">
|
||||
<input
|
||||
id="signup-password"
|
||||
type="password"
|
||||
type={showPassword ? 'text' : 'password'}
|
||||
value={password}
|
||||
onChange={e => { setPassword(e.target.value); if (fieldErrors.password) setFieldErrors(prev => ({ ...prev, password: undefined })) }}
|
||||
onBlur={() => {
|
||||
@@ -1349,10 +1379,13 @@ export function StudySignupPage() {
|
||||
setFieldErrors(prev => ({ ...prev, password: undefined }))
|
||||
}
|
||||
}}
|
||||
placeholder="At least 8 characters"
|
||||
placeholder={mode === 'signup' ? 'At least 8 characters' : 'Your password'}
|
||||
autoComplete={mode === 'signup' ? 'new-password' : 'current-password'}
|
||||
onKeyDown={e => e.key === 'Enter' && submit()}
|
||||
/>
|
||||
<button type="button" className="auth-password-toggle" aria-pressed={showPassword} onClick={() => setShowPassword(v => !v)}>
|
||||
{showPassword ? 'Hide' : 'Show'}
|
||||
</button>
|
||||
</div>
|
||||
{fieldErrors.password && <p className="study-signup-field-error">{fieldErrors.password}</p>}
|
||||
{mode === 'login' && (
|
||||
<button type="button" onClick={() => { setMode('forgot'); setMessage(''); setForgotSent(false) }} style={{ background: 'none', border: 'none', color: '#c9a84c', cursor: 'pointer', fontSize: '0.85rem', textDecoration: 'underline', padding: 0, textAlign: 'left', marginTop: '0.5rem', alignSelf: 'flex-start' }}>
|
||||
@@ -1369,56 +1402,26 @@ export function StudySignupPage() {
|
||||
<span>Send me updates from Verse by Verse with Nate. I can unsubscribe anytime.</span>
|
||||
</label>
|
||||
)}
|
||||
{message && <p className="study-signup-error">{message}</p>}
|
||||
{message && <p className="study-signup-error" role="alert">{message}</p>}
|
||||
<div className="study-signup-actions">
|
||||
<button type="button" className="btn-primary" disabled={busy} onClick={submit}>
|
||||
<button type="submit" className="btn-primary" disabled={busy}>
|
||||
{busy ? (mode === 'signup' ? 'Creating...' : 'Signing in...') : (mode === 'signup' ? 'Create Account' : 'Sign In')}
|
||||
</button>
|
||||
</div>
|
||||
<div className="study-signup-actions" style={{ marginTop: '1rem' }}>
|
||||
{mode === 'login' && (
|
||||
<button type="button" className="btn-secondary" onClick={() => { setMode('signup'); setMessage('') }}>
|
||||
Don't have an account? Sign up here
|
||||
</button>
|
||||
)}
|
||||
{mode === 'signup' && (
|
||||
<button type="button" className="btn-secondary" onClick={() => { setMode('login'); setMessage('') }}>
|
||||
Already have an account? Sign in instead
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<p className="auth-switch">
|
||||
{mode === 'login' ? "Don't have an account? " : 'Already have an account? '}
|
||||
<button type="button" className="auth-link" onClick={() => { setMode(mode === 'login' ? 'signup' : 'login'); setMessage('') }}>
|
||||
{mode === 'login' ? 'Sign up' : 'Sign in'}
|
||||
</button>
|
||||
</p>
|
||||
</form>
|
||||
|
||||
{mode === 'signup' && (
|
||||
<div className="study-signup-why-grid" style={{ marginTop: '2rem' }}>
|
||||
<article className="study-signup-why-card">
|
||||
<p className="study-signup-why-icon" aria-hidden="true">📝</p>
|
||||
<h3>Notes on Every Lesson</h3>
|
||||
<p>Save your own notes per lesson — up to 500 notes across all tracks.</p>
|
||||
</article>
|
||||
<article className="study-signup-why-card">
|
||||
<p className="study-signup-why-icon" aria-hidden="true">📖</p>
|
||||
<h3>Space to Go Deep</h3>
|
||||
<p>Each note holds ~2,000 words so you can write as much as you need.</p>
|
||||
</article>
|
||||
<article className="study-signup-why-card">
|
||||
<p className="study-signup-why-icon" aria-hidden="true">🔒</p>
|
||||
<h3>Private to You</h3>
|
||||
<p>Your notes are tied to your account. Nobody else can read them.</p>
|
||||
</article>
|
||||
<article className="study-signup-why-card">
|
||||
<p className="study-signup-why-icon" aria-hidden="true">⚡</p>
|
||||
<h3>Free Forever</h3>
|
||||
<p>Just an email and password. No charge, no ads. Stay signed in 30 days.</p>
|
||||
</article>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
|
||||
<div className="study-signup-actions" style={{ marginTop: '1.5rem' }}>
|
||||
<Link to="/study/account" className="btn-secondary">My Account</Link>
|
||||
<Link to="/study" className="btn-secondary">Back to Studies</Link>
|
||||
<p className="auth-footer-links">
|
||||
<Link to="/study">← Back to Studies</Link>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
Reference in new issue
Block a user