"use client" import { useState, useEffect } from "react" import { useRouter } from "next/navigation" import { setCredentials, isAuthenticated } from "@/lib/auth" import { fetchStudioConfig, testToken, NozApiError } from "@/lib/api" export default function LoginPage() { const router = useRouter() const devServer = process.env.NEXT_PUBLIC_DEV_SERVER ?? "" const devToken = process.env.NEXT_PUBLIC_DEV_TOKEN ?? "" const [url, setUrl] = useState(devServer || "https://noz.kryptomnrx.de") const [token, setToken] = useState(devToken) const [loading, setLoading] = useState(false) const [error, setError] = useState(null) // Fixture-Modus oder bereits angemeldet → direkt zum Editor useEffect(() => { if (isAuthenticated()) router.replace("/editor") }, [router]) async function handleConnect(e: React.FormEvent) { e.preventDefault() if (!url.trim() || !token.trim()) { setError("Bitte Server-URL und Token eingeben.") return } setLoading(true) setError(null) try { // Schritt 1: Server als noz-Instanz verifizieren await fetchStudioConfig(url.trim()) // Schritt 2: Token validieren await testToken(url.trim(), token.trim()) // Erfolg: Credentials speichern + weiterleiten setCredentials(url.trim(), token.trim()) router.push("/editor") } catch (err) { if (err instanceof NozApiError) { setError(err.message) } else { setError("Unbekannter Fehler — bitte erneut versuchen.") } setLoading(false) } } return (
{/* Nebula glows */}
{/* Card */}
{/* Logo */}
noz studio
{/* Fehlermeldung */} {error && (
{error}
)}
{ setUrl(e.target.value); setError(null) }} placeholder="https://noz.example.com" disabled={loading} required className="w-full bg-surface border border-border rounded-lg px-3 py-2 text-sm text-foreground placeholder:text-muted-fg/30 focus:outline-none focus:border-accent transition-colors font-mono disabled:opacity-50" />
{ setToken(e.target.value); setError(null) }} placeholder="••••••••••••••••••••••••" disabled={loading} required className="w-full bg-surface border border-border rounded-lg px-3 py-2 text-sm text-foreground placeholder:text-muted-fg/30 focus:outline-none focus:border-accent transition-colors font-mono disabled:opacity-50" />
{/* Divider */}
oder
{/* Authentik — noch nicht implementiert */}

Token aus{" "} noosphere.toml [cli]

) } /* ── Icons ──────────────────────────────────────────── */ function OrbitalIcon({ className }: { className?: string }) { return ( ) } function AuthentikIcon() { return ( ) } function ErrorIcon() { return ( ) } function SpinnerIcon() { return ( ) }