import { useState } from "react"; import { startAuthentication } from "@simplewebauthn/browser"; import { api } from "./api.js"; export function Login({ pdsHostname, passwordLogin, pendingAdmins, onLoggedIn, }: { pdsHostname: string; passwordLogin: boolean; pendingAdmins: boolean; onLoggedIn: () => void; }) { const [password, setPassword] = useState(""); const [showPassword, setShowPassword] = useState(false); // invited admins prove their DID via atproto OAuth before creating a passkey const [showNewAdmin, setShowNewAdmin] = useState(false); const [adminHandle, setAdminHandle] = useState(""); const [error, setError] = useState(() => { const err = new URLSearchParams(window.location.search).get("adminError"); if (err) window.history.replaceState(null, "", "/"); return err; }); const [busy, setBusy] = useState(false); const submit = async (e: React.FormEvent) => { e.preventDefault(); setBusy(true); setError(null); try { await api.login(password); onLoggedIn(); } catch (e) { setError((e as Error).message); } finally { setBusy(false); } }; const passkeySignIn = async () => { setBusy(true); setError(null); try { const options = await api.passkeyLoginOptions(); const response = await startAuthentication({ optionsJSON: options }); await api.passkeyLogin(response); onLoggedIn(); } catch (e) { const err = e as Error; // user dismissing the browser's passkey prompt isn't an error worth showing if (err.name !== "NotAllowedError") setError(err.message); } finally { setBusy(false); } }; return (
{pdsHostname ? `${pdsHostname} — operator` : "pds operator"} {passwordLogin && (showPassword ? ( <> setPassword(e.target.value)} autoFocus /> ) : ( ))} {pendingAdmins && (showNewAdmin ? ( <> setAdminHandle(e.target.value)} autoFocus /> ) : ( ))} {error && {error}}
); }