import { Eye, EyeOff } from "lucide-react"; import { useEffect, useState } from "react"; import { Link, Navigate } from "react-router-dom"; import { Button, Field, Spinner, inputClass } from "@/components/ui"; import { errorMessage } from "@/lib/api"; import { hasBackend } from "@/lib/backend"; import { cn } from "@/lib/cn"; import { e621ErrorMessage, verifyE621Credentials, type E621Credentials, } from "@/lib/e621"; import { useAuth } from "@/store/auth"; import { useE621 } from "@/store/e621"; import { toast } from "@/store/toasts"; import { AvatarCard } from "./AvatarCard"; import { PreferencesCard } from "./PreferencesCard"; import { TokensCard } from "./TokensCard"; const BASE_URL_OPTIONS = [ { value: "https://e621.net", label: "e621.net — main site" }, { value: "https://e926.net", label: "e926.net — safe mirror" }, { value: "custom", label: "Custom…" }, ]; function AccountForm({ credentials }: { credentials: E621Credentials | null }) { const save = useE621((state) => state.save); const [username, setUsername] = useState(credentials?.username ?? ""); const [apiKey, setApiKey] = useState(credentials?.api_key ?? ""); const savedBase = credentials?.base_url ?? "https://e621.net"; const savedBaseIsKnown = BASE_URL_OPTIONS.some( (option) => option.value === savedBase, ); const [baseChoice, setBaseChoice] = useState( savedBaseIsKnown ? savedBase : "custom", ); const [customBase, setCustomBase] = useState(savedBaseIsKnown ? "" : savedBase); const [showKey, setShowKey] = useState(false); const [saving, setSaving] = useState(false); const [testing, setTesting] = useState(false); const baseUrl = (baseChoice === "custom" ? customBase.trim() : baseChoice).replace( /\/+$/, "", ); const values = { username: username.trim(), api_key: apiKey.trim(), base_url: baseUrl, }; async function handleSave() { setSaving(true); try { await save(values); toast.ok("e621 credentials saved."); } catch (error) { toast.error(errorMessage(error)); } finally { setSaving(false); } } async function handleTest() { setTesting(true); try { const user = await verifyE621Credentials({ ...values, configured: true }); toast.ok( `Connected as ${user.name}${ typeof user.favorite_count === "number" ? ` — ${user.favorite_count} favorites` : "" }.`, ); } catch (error) { toast.error(e621ErrorMessage(error)); } finally { setTesting(false); } } return (

e621 credentials

Generate an API key under Account → My profile on e621, then paste it here.

{credentials?.configured ? "Configured" : "Not configured"}
setUsername(event.target.value)} autoComplete="off" />
setApiKey(event.target.value)} autoComplete="off" />
{baseChoice === "custom" ? ( setCustomBase(event.target.value)} /> ) : null}

{hasBackend() ? "Stored on your server and fetched by this app when needed. e621 requests are made directly from your browser, throttled to one per second." : "Stored in this browser only (local mode). e621 requests are made directly from here, throttled to one per second."}

); } export default function AccountPage() { const user = useAuth((state) => state.user); const credentials = useE621((state) => state.credentials); const loading = useE621((state) => state.loading); const load = useE621((state) => state.load); const backend = hasBackend(); useEffect(() => { void load(); }, [load]); // Local mode: the e621 credentials live in this browser. if (!backend) { return (

e621 account

No backend is connected, so these credentials are stored in this browser only and sent straight to e621 from here.

{loading && !credentials ? (
) : ( )}

Connect a backend {" "} to unlock the library, follows and account settings.

); } if (!user) { return ; } return (

Account

Signed in as {user.username}. {user.role} {user.is_superuser ? ( admin ) : null}

{loading && !credentials ? (
) : ( )}
); }