Spaces:
Sleeping
Sleeping
| import { useState } from 'react' | |
| import { useNavigate, useSearchParams } from 'react-router-dom' | |
| import { useAuth } from '../context/AuthContext' | |
| export default function AuthPage() { | |
| const [searchParams] = useSearchParams() | |
| const [tab, setTab] = useState(searchParams.get('tab') === 'signup' ? 'signup' : 'login') | |
| const [error, setError] = useState('') | |
| const [loading, setLoading] = useState(false) | |
| // Login fields | |
| const [identity, setIdentity] = useState('') | |
| const [loginPw, setLoginPw] = useState('') | |
| // Signup fields | |
| const [uname, setUname] = useState('') | |
| const [email, setEmail] = useState('') | |
| const [signupPw, setSignupPw] = useState('') | |
| const { login, signup } = useAuth() | |
| const navigate = useNavigate() | |
| async function handleLogin(e) { | |
| e.preventDefault() | |
| setError(''); setLoading(true) | |
| try { | |
| await login(identity, loginPw) | |
| navigate('/app/dashboard') | |
| } catch (err) { setError(err.message) } | |
| finally { setLoading(false) } | |
| } | |
| async function handleSignup(e) { | |
| e.preventDefault() | |
| setError(''); setLoading(true) | |
| try { | |
| await signup(uname, email, signupPw) | |
| navigate('/app/dashboard') | |
| } catch (err) { setError(err.message) } | |
| finally { setLoading(false) } | |
| } | |
| return ( | |
| <div className="auth-screen"> | |
| {/* Breathing rings */} | |
| <div className="breath-rings"> | |
| {[1,2,3,4].map(i => <div key={i} className={`ring ring-${i}`} />)} | |
| </div> | |
| <div className="auth-card"> | |
| {/* Brand */} | |
| <div className="auth-brand"> | |
| <img src="/logo.svg" alt="BREATHE" className="auth-logo" /> | |
| <p className="auth-subtitle">Stress Intelligence Platform</p> | |
| </div> | |
| {/* Tabs */} | |
| <div className="auth-tabs"> | |
| <button className={`auth-tab ${tab==='login' ? 'auth-tab--active' : ''}`} onClick={() => { setTab('login'); setError('') }}>Log In</button> | |
| <button className={`auth-tab ${tab==='signup' ? 'auth-tab--active' : ''}`} onClick={() => { setTab('signup'); setError('') }}>Sign Up</button> | |
| </div> | |
| {error && <div className="form-error">{error}</div>} | |
| {/* Login form */} | |
| {tab === 'login' && ( | |
| <form className="auth-form" onSubmit={handleLogin}> | |
| <div className="field"> | |
| <label>Email or Username</label> | |
| <input type="text" placeholder="you@example.com" value={identity} | |
| onChange={e => setIdentity(e.target.value)} autoComplete="username" required /> | |
| </div> | |
| <div className="field"> | |
| <label>Password</label> | |
| <input type="password" placeholder="••••••••" value={loginPw} | |
| onChange={e => setLoginPw(e.target.value)} autoComplete="current-password" required /> | |
| </div> | |
| <button type="submit" className="btn-primary btn--full" disabled={loading}> | |
| {loading ? <span className="btn-spinner" /> : 'Log In →'} | |
| </button> | |
| </form> | |
| )} | |
| {/* Signup form */} | |
| {tab === 'signup' && ( | |
| <form className="auth-form" onSubmit={handleSignup}> | |
| <div className="field"> | |
| <label>Username</label> | |
| <input type="text" placeholder="breatheuser" value={uname} | |
| onChange={e => setUname(e.target.value)} autoComplete="username" required /> | |
| </div> | |
| <div className="field"> | |
| <label>Email</label> | |
| <input type="email" placeholder="you@example.com" value={email} | |
| onChange={e => setEmail(e.target.value)} autoComplete="email" required /> | |
| </div> | |
| <div className="field"> | |
| <label>Password <small>(min 8 characters)</small></label> | |
| <input type="password" placeholder="••••••••" value={signupPw} | |
| onChange={e => setSignupPw(e.target.value)} autoComplete="new-password" required /> | |
| </div> | |
| <button type="submit" className="btn-primary btn--full" disabled={loading}> | |
| {loading ? <span className="btn-spinner" /> : 'Create Account →'} | |
| </button> | |
| </form> | |
| )} | |
| </div> | |
| </div> | |
| ) | |
| } | |