Login: bare sign-in page at /login; Telegram bridge connection guide
This commit is contained in:
parent
d313ce0bec
commit
22f9e12141
2 changed files with 157 additions and 5 deletions
|
|
@ -1,9 +1,71 @@
|
|||
import { redirect } from "next/navigation";
|
||||
"use client";
|
||||
|
||||
import { useState, type FormEvent } from "react";
|
||||
import Link from "next/link";
|
||||
import { Button, Card, Input } from "../../components/ui/primitives";
|
||||
import { api, errorMessage } from "../../lib/api-client";
|
||||
import { useAuth } from "../../lib/auth-store";
|
||||
|
||||
/**
|
||||
* /login — the sign-in door. The onboarding page holds both forms; this route
|
||||
* deep-links into sign-in mode (register stays the default at /signup).
|
||||
* /login — bare sign-in: username and password, nothing else. Account creation
|
||||
* lives at /signup; collective joining happens with an invite link.
|
||||
*/
|
||||
export default function LoginRedirect(): React.ReactElement {
|
||||
redirect("/onboarding?mode=signin");
|
||||
export default function LoginPage(): React.ReactElement {
|
||||
const { login } = useAuth();
|
||||
const [username, setUsername] = useState("");
|
||||
const [password, setPassword] = useState("");
|
||||
const [busy, setBusy] = useState(false);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
async function submit(e: FormEvent): Promise<void> {
|
||||
e.preventDefault();
|
||||
setBusy(true);
|
||||
setError(null);
|
||||
try {
|
||||
await api.post<unknown>("/auth/login", { username: username.trim(), password }, { redirectOn401: false });
|
||||
window.location.assign("/streams");
|
||||
} catch (err) {
|
||||
setError(errorMessage(err));
|
||||
setBusy(false);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex min-h-full items-center justify-center bg-bg p-6">
|
||||
<Card className="w-[420px] max-w-full p-6">
|
||||
<div className="mb-5 text-center">
|
||||
<h1 className="text-xl font-semibold tracking-tight">Sign in</h1>
|
||||
<p className="mt-1 text-2xs text-text-faint">Tactical Media Broadcast Hub</p>
|
||||
</div>
|
||||
<form onSubmit={(e) => void submit(e)}>
|
||||
<div className="space-y-2">
|
||||
<Input
|
||||
type="text"
|
||||
value={username}
|
||||
onChange={(e) => setUsername(e.target.value)}
|
||||
placeholder="username"
|
||||
autoComplete="username"
|
||||
autoFocus
|
||||
/>
|
||||
<Input
|
||||
type="password"
|
||||
value={password}
|
||||
onChange={(e) => setPassword(e.target.value)}
|
||||
placeholder="Password"
|
||||
autoComplete="current-password"
|
||||
/>
|
||||
</div>
|
||||
{error !== null && <p className="mt-2 text-xs text-danger">{error}</p>}
|
||||
<div className="mt-6 flex items-center justify-between">
|
||||
<Link href="/signup" className="text-xs text-text-faint underline hover:text-text">
|
||||
Create an account
|
||||
</Link>
|
||||
<Button type="submit" variant="primary" disabled={busy || username.trim() === "" || password === ""}>
|
||||
{busy ? "Signing in…" : "Sign in"}
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue