"use client"; import { FormEvent, Suspense, useEffect, useState } from "react"; import Link from "next/link"; import { useRouter, useSearchParams } from "next/navigation"; import { useAccount } from "@/contexts/AccountContext"; function SignInContent() { const router = useRouter(); const searchParams = useSearchParams(); const { user, hydrated, signIn } = useAccount(); const [username, setUsername] = useState(""); const [password, setPassword] = useState(""); const [error, setError] = useState(null); const [busy, setBusy] = useState(false); useEffect(() => { if (!hydrated || !user) return; const next = searchParams.get("next"); router.replace(next && next.startsWith("/") ? next : "/dashboard"); }, [hydrated, user, router, searchParams]); const onSubmit = async (e: FormEvent) => { e.preventDefault(); setError(null); setBusy(true); const res = await signIn(username, password); setBusy(false); if (!res.ok) { setError(res.error); return; } const next = searchParams.get("next"); router.push(next && next.startsWith("/") ? next : "/dashboard"); }; if (!hydrated || user) { return (
Loading…
); } return (

session

Sign in

Client-side vault unlock — your handle ties together forum posts, listings, and checkout history on{" "} this device. Use a unique passphrase; staff never log access to your secrets.

Using a different .onion host?{" "} Register or import on every mirror .

{error ? (

{error}

) : null}
setUsername(e.target.value)} autoComplete="username" required className="glass w-full rounded-xl border border-white/10 bg-transparent px-4 py-3 font-mono text-sm" placeholder="your_alias" />
setPassword(e.target.value)} autoComplete="current-password" required className="glass w-full rounded-xl border border-white/10 bg-transparent px-4 py-3 font-mono text-sm" />

Need an identity?{" "} Create account

← Hub

); } export default function SignInPage() { return ( Loading… } > ); }