Girl Scout Cookie tracking app with Express/SQLite API and React/Vite client. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
58 lines
1.7 KiB
JavaScript
58 lines
1.7 KiB
JavaScript
import { useState } from 'react';
|
|
import { useNavigate, useLocation } from 'react-router-dom';
|
|
import { api } from '../api';
|
|
|
|
export default function Login({ onLogin }) {
|
|
const [password, setPassword] = useState('');
|
|
const [error, setError] = useState('');
|
|
const [loading, setLoading] = useState(false);
|
|
const navigate = useNavigate();
|
|
const location = useLocation();
|
|
const from = location.state?.from?.pathname || location.pathname || '/';
|
|
|
|
async function handleSubmit(e) {
|
|
e.preventDefault();
|
|
setError('');
|
|
setLoading(true);
|
|
try {
|
|
const res = await api('/auth/login', { method: 'POST', body: { password } });
|
|
if (!res.ok) {
|
|
setError('Invalid password');
|
|
setLoading(false);
|
|
return;
|
|
}
|
|
onLogin?.();
|
|
navigate(from, { replace: true });
|
|
} catch {
|
|
setError('Something went wrong');
|
|
}
|
|
setLoading(false);
|
|
}
|
|
|
|
return (
|
|
<div className="login-page">
|
|
<div className="card" style={{ maxWidth: 360, margin: '2rem auto' }}>
|
|
<h1 className="page-title" style={{ marginBottom: '1rem' }}>Log in</h1>
|
|
<form onSubmit={handleSubmit}>
|
|
<div className="form-group">
|
|
<label htmlFor="login-password">Password</label>
|
|
<input
|
|
id="login-password"
|
|
type="password"
|
|
value={password}
|
|
onChange={(e) => setPassword(e.target.value)}
|
|
autoComplete="current-password"
|
|
autoFocus
|
|
disabled={loading}
|
|
/>
|
|
</div>
|
|
{error && <p className="error">{error}</p>}
|
|
<button type="submit" disabled={loading}>
|
|
{loading ? 'Logging in…' : 'Log in'}
|
|
</button>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|