55 lines
1.4 KiB
TypeScript
55 lines
1.4 KiB
TypeScript
import { useState, FormEvent } from 'react'
|
|
|
|
interface LoginPageProps {
|
|
onLogin: (email: string, password: string) => Promise<void>
|
|
}
|
|
|
|
export function LoginPage({ onLogin }: LoginPageProps) {
|
|
const [email, setEmail] = useState('')
|
|
const [password, setPassword] = useState('')
|
|
const [error, setError] = useState('')
|
|
const [loading, setLoading] = useState(false)
|
|
|
|
async function handleSubmit(e: FormEvent) {
|
|
e.preventDefault()
|
|
setError('')
|
|
setLoading(true)
|
|
try {
|
|
await onLogin(email, password)
|
|
} catch {
|
|
setError('Invalid credentials')
|
|
} finally {
|
|
setLoading(false)
|
|
}
|
|
}
|
|
|
|
return (
|
|
<div className="login-page">
|
|
<form className="login-card" onSubmit={handleSubmit}>
|
|
<h2>Research Workbench</h2>
|
|
{error && <div className="login-error">{error}</div>}
|
|
<label htmlFor="email">Email</label>
|
|
<input
|
|
id="email"
|
|
type="email"
|
|
value={email}
|
|
onChange={e => setEmail(e.target.value)}
|
|
autoFocus
|
|
required
|
|
/>
|
|
<label htmlFor="password">Password</label>
|
|
<input
|
|
id="password"
|
|
type="password"
|
|
value={password}
|
|
onChange={e => setPassword(e.target.value)}
|
|
required
|
|
/>
|
|
<button type="submit" disabled={loading}>
|
|
{loading ? 'Signing in...' : 'Sign In'}
|
|
</button>
|
|
</form>
|
|
</div>
|
|
)
|
|
}
|