Harden artifact paths and fusion uploads, repair pool reconnect and login ID tracking, fix agent/fusion/frontend regressions, and refresh PROBLEMS.md with the full findings list.
82 lines
2.5 KiB
TypeScript
82 lines
2.5 KiB
TypeScript
import { useEffect, useState, type ReactNode } from 'react';
|
|
import { getStoredAuth, setStoredAuth } from '../api/auth';
|
|
|
|
export default function SessionGate({ children }: { children: ReactNode }) {
|
|
const [ready, setReady] = useState(false);
|
|
const [authed, setAuthed] = useState(!!getStoredAuth());
|
|
const [user, setUser] = useState('drjones');
|
|
const [pass, setPass] = useState('');
|
|
const [err, setErr] = useState('');
|
|
|
|
useEffect(() => {
|
|
const token = getStoredAuth();
|
|
if (!token) {
|
|
setAuthed(false);
|
|
setReady(true);
|
|
return;
|
|
}
|
|
fetch('/api/v1/config', { headers: { Authorization: `Basic ${token}` } })
|
|
.then((r) => {
|
|
setAuthed(r.ok);
|
|
setReady(true);
|
|
})
|
|
.catch(() => {
|
|
setAuthed(false);
|
|
setReady(true);
|
|
});
|
|
}, []);
|
|
|
|
const handleLogin = async (e: React.FormEvent) => {
|
|
e.preventDefault();
|
|
setErr('');
|
|
const token = btoa(`${user}:${pass}`);
|
|
try {
|
|
const res = await fetch('/api/v1/config', { headers: { Authorization: `Basic ${token}` } });
|
|
if (!res.ok) {
|
|
setErr('Login failed — check username and password.');
|
|
return;
|
|
}
|
|
setStoredAuth(user, pass);
|
|
setAuthed(true);
|
|
} catch {
|
|
setErr('Cannot reach server — check that miner-server is running.');
|
|
}
|
|
};
|
|
|
|
if (!ready) {
|
|
return (
|
|
<div className="session-gate">
|
|
<p className="font-tech">Starting AetherForge…</p>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
if (!authed) {
|
|
return (
|
|
<div className="session-gate">
|
|
<form className="session-gate-card card" onSubmit={handleLogin}>
|
|
<h1 className="font-display">AetherForge</h1>
|
|
<p className="form-hint">Sign in to open the command deck.</p>
|
|
<label className="label">Username</label>
|
|
<input className="input" value={user} onChange={(e) => setUser(e.target.value)} autoComplete="username" />
|
|
<label className="label">Password</label>
|
|
<input
|
|
className="input"
|
|
type="password"
|
|
value={pass}
|
|
onChange={(e) => setPass(e.target.value)}
|
|
autoComplete="current-password"
|
|
/>
|
|
{err && <p className="form-hint" style={{ color: 'var(--accent-red)' }}>{err}</p>}
|
|
<button type="submit" className="btn btn-primary btn-lg">
|
|
Enter Command Deck
|
|
</button>
|
|
<p className="form-hint">Default: drjones / czapiewski (change under Calibrate → Users)</p>
|
|
</form>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
return <>{children}</>;
|
|
}
|