108 lines
2.9 KiB
TypeScript
108 lines
2.9 KiB
TypeScript
'use client';
|
|
|
|
import { useRef, useState } from 'react';
|
|
|
|
export default function LoginPage() {
|
|
const [error, setError] = useState('');
|
|
const [loading, setLoading] = useState(false);
|
|
const inputRef = useRef<HTMLInputElement>(null);
|
|
|
|
async function handleLogin() {
|
|
const password = inputRef.current?.value || '';
|
|
if (!password || loading) return;
|
|
setLoading(true);
|
|
setError('');
|
|
try {
|
|
const res = await fetch('/api/auth/login', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
credentials: 'include',
|
|
body: JSON.stringify({ password }),
|
|
});
|
|
if (!res.ok) throw new Error('bad');
|
|
window.location.href = '/';
|
|
} catch {
|
|
setError('Invalid password');
|
|
setLoading(false);
|
|
}
|
|
}
|
|
|
|
return (
|
|
<div style={{
|
|
minHeight: '100dvh',
|
|
display: 'flex',
|
|
alignItems: 'center',
|
|
justifyContent: 'center',
|
|
padding: '16px',
|
|
background: '#faf9f6',
|
|
fontFamily: 'system-ui, sans-serif',
|
|
}}>
|
|
<div style={{
|
|
width: '100%',
|
|
maxWidth: '360px',
|
|
background: '#f0ede6',
|
|
border: '1px solid #dddad2',
|
|
borderRadius: '16px',
|
|
padding: '32px',
|
|
}}>
|
|
<div style={{ textAlign: 'center', marginBottom: '32px' }}>
|
|
<div style={{ fontSize: '22px', fontWeight: 500, color: '#1a1a18', marginBottom: '4px' }}>
|
|
Aaron AI
|
|
</div>
|
|
<div style={{ fontSize: '13px', color: '#999990' }}>
|
|
personal knowledge assistant
|
|
</div>
|
|
</div>
|
|
|
|
<input
|
|
ref={inputRef}
|
|
type="password"
|
|
placeholder="Password"
|
|
autoComplete="current-password"
|
|
onKeyDown={e => { if (e.key === 'Enter') handleLogin(); }}
|
|
style={{
|
|
width: '100%',
|
|
background: '#faf9f6',
|
|
border: `1px solid ${error ? '#a32d2d' : '#ccc9c0'}`,
|
|
borderRadius: '10px',
|
|
padding: '12px 16px',
|
|
fontSize: '16px',
|
|
color: '#1a1a18',
|
|
outline: 'none',
|
|
marginBottom: error ? '6px' : '16px',
|
|
display: 'block',
|
|
boxSizing: 'border-box',
|
|
WebkitAppearance: 'none',
|
|
}}
|
|
/>
|
|
|
|
{error && (
|
|
<div style={{ fontSize: '12px', color: '#a32d2d', marginBottom: '16px' }}>
|
|
{error}
|
|
</div>
|
|
)}
|
|
|
|
<button
|
|
onPointerUp={handleLogin}
|
|
style={{
|
|
width: '100%',
|
|
background: '#2d5a3d',
|
|
color: '#e8f5ed',
|
|
border: 'none',
|
|
borderRadius: '10px',
|
|
padding: '12px',
|
|
fontSize: '15px',
|
|
cursor: 'pointer',
|
|
display: 'block',
|
|
boxSizing: 'border-box',
|
|
WebkitAppearance: 'none',
|
|
touchAction: 'manipulation',
|
|
}}
|
|
>
|
|
{loading ? 'Signing in...' : 'Sign in'}
|
|
</button>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|