import { useState } from 'react'; import { Link, useNavigate } from 'react-router-dom'; import { register, initiateGoogleLogin } from '../services/authService'; import { useAuthStore } from '../store/useAuthStore'; import { RESERVED_USERNAMES } from '../utils/reservedUsernames'; export const RegisterPage: React.FC = () => { const navigate = useNavigate(); const setUser = useAuthStore((s) => s.setUser); const [username, setUsername] = useState(''); const [email, setEmail] = useState(''); const [password, setPassword] = useState(''); const [error, setError] = useState(''); const [loading, setLoading] = useState(false); const validateUsername = (name: string): string | null => { const lower = name.toLowerCase(); if (RESERVED_USERNAMES.has(lower)) return 'That username is reserved.'; if (!/^[a-z0-9_-]{3,30}$/.test(lower)) return 'Username must be 3-30 chars (a-z, 0-9, _, -)'; return null; }; const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); setError(''); const usernameErr = validateUsername(username); if (usernameErr) { setError(usernameErr); return; } if (password.length < 8) { setError('Password must be at least 8 characters.'); return; } setLoading(true); try { const user = await register(username.toLowerCase(), email, password); setUser(user); navigate('/editor'); } catch (err: any) { setError(err?.response?.data?.detail || 'Registration failed.'); } finally { setLoading(false); } }; return (

Create account

{error &&
{error}
}
setUsername(e.target.value)} required style={styles.input} autoFocus placeholder="e.g. alice" /> setEmail(e.target.value)} required style={styles.input} /> setPassword(e.target.value)} required style={styles.input} placeholder="At least 8 characters" />
or

Already have an account? Sign in

); }; const styles: Record = { page: { minHeight: '100vh', display: 'flex', alignItems: 'center', justifyContent: 'center', background: '#1e1e1e' }, card: { background: '#252526', border: '1px solid #3c3c3c', borderRadius: 8, padding: '2rem', width: 360, display: 'flex', flexDirection: 'column', gap: 12 }, title: { color: '#ccc', margin: 0, fontSize: 22, fontWeight: 600, textAlign: 'center' }, form: { display: 'flex', flexDirection: 'column', gap: 8 }, label: { color: '#9d9d9d', fontSize: 13 }, input: { background: '#3c3c3c', border: '1px solid #555', borderRadius: 4, padding: '8px 10px', color: '#ccc', fontSize: 14, outline: 'none' }, primaryBtn: { marginTop: 8, background: '#0e639c', border: 'none', borderRadius: 4, color: '#fff', padding: '9px', fontSize: 14, cursor: 'pointer', fontWeight: 500 }, divider: { textAlign: 'center', color: '#555', fontSize: 13 }, googleBtn: { display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 10, background: '#fff', border: 'none', borderRadius: 4, color: '#333', padding: '9px', fontSize: 14, cursor: 'pointer', fontWeight: 500 }, footer: { color: '#9d9d9d', fontSize: 13, textAlign: 'center', margin: 0 }, link: { color: '#4fc3f7' }, error: { background: '#5a1d1d', border: '1px solid #f44747', borderRadius: 4, color: '#f44747', padding: '8px 12px', fontSize: 13 }, };