← back to Ken
src/app/page.js
86 lines
'use client';
import { useState, useEffect } from 'react';
export default function LoginPage() {
const [username, setUsername] = useState('');
const [password, setPassword] = useState('');
const [error, setError] = useState('');
const [loading, setLoading] = useState(true);
useEffect(() => {
fetch('/api/health').then(r => r.json()).then(d => {
if (d.authenticated) window.location.href = '/dashboard';
else setLoading(false);
}).catch(() => setLoading(false));
}, []);
async function handleLogin(e) {
e.preventDefault();
setError('');
const res = await fetch('/api/health', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ username, password })
});
const data = await res.json();
if (data.token) {
document.cookie = `bertha_token=${data.token}; path=/; max-age=${7*86400}`;
window.location.href = '/dashboard';
} else {
setError(data.error || 'Login failed');
}
}
if (loading) return (
<div className="min-h-screen flex items-center justify-center">
<div className="animate-spin w-8 h-8 border-2 border-blue-500 border-t-transparent rounded-full" />
</div>
);
return (
<div className="min-h-screen flex items-center justify-center p-4">
<div className="w-full max-w-md">
<div className="text-center mb-8">
<div className="inline-flex items-center justify-center w-20 h-20 rounded-2xl mb-4" style={{ background: 'linear-gradient(135deg, #3b82f6, #8b5cf6)' }}>
<svg width="40" height="40" viewBox="0 0 24 24" fill="none" stroke="white" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
<path d="M2 12s3-7 10-7 10 7 10 7-3 7-10 7-10-7-10-7Z"/>
<circle cx="12" cy="12" r="3"/>
</svg>
</div>
<h1 className="text-3xl font-extrabold bg-gradient-to-r from-blue-400 to-purple-400 bg-clip-text text-transparent">BERTHA</h1>
<p className="text-gray-400 mt-2 text-sm">Weather Forecast Micro-Betting System</p>
<p className="text-gray-500 text-xs mt-1">Polymarket Edge Detection + Risk Management</p>
</div>
<form onSubmit={handleLogin} className="card space-y-4">
{error && <div className="text-red-400 text-sm bg-red-500/10 rounded-lg p-3">{error}</div>}
<div>
<label className="block text-xs font-medium text-gray-400 mb-1.5">Username</label>
<input type="text" value={username} onChange={e => setUsername(e.target.value)} required
className="w-full bg-gray-800/50 border border-gray-700 rounded-lg px-3 py-2.5 text-sm focus:outline-none focus:border-blue-500 transition" placeholder="admin" />
</div>
<div>
<label className="block text-xs font-medium text-gray-400 mb-1.5">Password</label>
<input type="password" value={password} onChange={e => setPassword(e.target.value)} required
className="w-full bg-gray-800/50 border border-gray-700 rounded-lg px-3 py-2.5 text-sm focus:outline-none focus:border-blue-500 transition" placeholder="Enter password" />
</div>
<button type="submit" className="btn btn-primary w-full py-2.5">Sign In</button>
</form>
<div className="mt-6 grid grid-cols-3 gap-2 text-center">
{[
{ label: 'Bankroll', value: '$50', color: 'text-green-400' },
{ label: 'Mode', value: 'Paper', color: 'text-yellow-400' },
{ label: 'Status', value: 'Active', color: 'text-blue-400' }
].map(s => (
<div key={s.label} className="card !p-3">
<div className={`text-lg font-bold ${s.color}`}>{s.value}</div>
<div className="text-[10px] text-gray-500 uppercase">{s.label}</div>
</div>
))}
</div>
</div>
</div>
);
}