Files
Feeld/web/src/components/LoginPage.tsx
2026-03-20 18:49:48 -05:00

163 lines
4.1 KiB
TypeScript
Executable File

import { useState } from 'react';
import { useAuth } from '../hooks/useAuth';
const styles = {
container: {
minHeight: '100vh',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
background: 'linear-gradient(135deg, #0f0f14 0%, #1a1a24 50%, #0f0f14 100%)',
padding: '20px',
},
card: {
width: '100%',
maxWidth: '400px',
background: '#1a1a24',
borderRadius: '24px',
border: '1px solid rgba(255,255,255,0.08)',
padding: '48px 40px',
boxShadow: '0 25px 50px -12px rgba(0, 0, 0, 0.5)',
},
logo: {
textAlign: 'center' as const,
marginBottom: '40px',
},
logoText: {
fontFamily: "'Clash Display', sans-serif",
fontSize: '42px',
fontWeight: 700,
background: 'linear-gradient(135deg, #c41e3a 0%, #e91e63 100%)',
WebkitBackgroundClip: 'text',
WebkitTextFillColor: 'transparent',
letterSpacing: '-1px',
},
subtitle: {
color: '#6b7280',
fontSize: '14px',
marginTop: '8px',
},
form: {
display: 'flex',
flexDirection: 'column' as const,
gap: '20px',
},
inputGroup: {
display: 'flex',
flexDirection: 'column' as const,
gap: '8px',
},
label: {
fontSize: '12px',
fontWeight: 600,
textTransform: 'uppercase' as const,
letterSpacing: '0.1em',
color: '#6b7280',
},
input: {
padding: '16px 18px',
background: '#24242f',
border: '1px solid rgba(255,255,255,0.1)',
borderRadius: '12px',
color: '#ffffff',
fontSize: '16px',
outline: 'none',
transition: 'border-color 0.2s, box-shadow 0.2s',
},
button: {
padding: '16px 24px',
background: 'linear-gradient(135deg, #c41e3a 0%, #e91e63 100%)',
border: 'none',
borderRadius: '12px',
color: '#ffffff',
fontSize: '16px',
fontWeight: 600,
cursor: 'pointer',
transition: 'opacity 0.2s, transform 0.2s',
marginTop: '8px',
},
error: {
padding: '12px 16px',
background: 'rgba(239, 68, 68, 0.15)',
border: '1px solid rgba(239, 68, 68, 0.3)',
borderRadius: '10px',
color: '#ef4444',
fontSize: '14px',
textAlign: 'center' as const,
},
};
export function LoginPage() {
const { login } = useAuth();
const [username, setUsername] = useState('');
const [password, setPassword] = useState('');
const [error, setError] = useState('');
const [loading, setLoading] = useState(false);
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
setError('');
setLoading(true);
const success = await login(username, password);
if (!success) {
setError('Invalid username or password');
}
setLoading(false);
};
return (
<div style={styles.container}>
<div style={styles.card}>
<div style={styles.logo}>
<div style={styles.logoText}>Feeld</div>
<p style={styles.subtitle}>Web Client</p>
</div>
<form style={styles.form} onSubmit={handleSubmit}>
<div style={styles.inputGroup}>
<label style={styles.label}>Username</label>
<input
type="text"
value={username}
onChange={(e) => setUsername(e.target.value)}
style={styles.input}
placeholder="Enter username"
autoComplete="username"
autoFocus
/>
</div>
<div style={styles.inputGroup}>
<label style={styles.label}>Password</label>
<input
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
style={styles.input}
placeholder="Enter password"
autoComplete="current-password"
/>
</div>
{error && <div style={styles.error}>{error}</div>}
<button
type="submit"
style={{
...styles.button,
opacity: loading ? 0.7 : 1,
cursor: loading ? 'wait' : 'pointer',
}}
disabled={loading}
>
{loading ? 'Signing in...' : 'Sign In'}
</button>
</form>
</div>
</div>
);
}