"use client"; import { useIdentityData } from "./IdentityProvider"; import { Popover } from "./Popover"; import { Modal } from "./Modal"; import { ButtonPrimary } from "./Buttons"; import { ActionButton } from "./ActionBar/ActionButton"; import { AccountSmall } from "./Icons/AccountSmall"; import { AtmosphericHandleInfo } from "./Subscribe/HandleSubscribe"; import { HandleInput } from "./Subscribe/HandleInput"; import { EmailInput, EmailConfirm } from "./Subscribe/EmailSubscribe"; import { useState } from "react"; import { GoToArrow } from "./Icons/GoToArrow"; import { ToggleGroup } from "./ToggleGroup"; import { useToaster } from "./Toast"; import { BlueskyTiny } from "./Icons/BlueskyTiny"; import { requestAuthEmailToken, confirmEmailAuthToken, } from "actions/emailAuth"; import { loginWithEmailToken } from "actions/login"; import { getHomeDocs } from "app/(app)/(home-pages)/(writer)/home/storage"; import { mutate } from "swr"; import { buildOauthLoginUrl, mainSiteAuthBase } from "src/utils/customDomain"; export const LoginModal = (props: { noEmailLogin?: boolean; trigger?: React.ReactNode; asChild?: boolean; redirectRoute?: string; action?: string; open?: boolean; onOpenChange?: (open: boolean) => void; }) => { let [internalOpen, setInternalOpen] = useState(false); let isControlled = props.open !== undefined; let open = props.open ?? internalOpen; let setOpen = (o: boolean) => { if (!isControlled) setInternalOpen(o); props.onOpenChange?.(o); }; return ( setOpen(false)} /> ); }; export const LoginContent = (props: { pageView?: boolean; noEmailLogin?: boolean; redirectRoute?: string; action?: string; open?: boolean; onSuccess?: () => void; className?: string; // Logging into an additional account from the switcher while a session is // still active: render the normal login form (not the link/merge prompts) // and keep the new session fully separate from the current identity. addAccount?: boolean; }) => { let identityData = useIdentityData(); let [state, setState] = useState< "log in" | "sign up" | "email log in" | "email confirm" >("log in"); let [loginEmail, setLoginEmail] = useState(""); let [tokenId, setTokenId] = useState(null); let [loading, setLoading] = useState(false); let toaster = useToaster(); if (!props.addAccount) { if (identityData.identity?.atp_did) return null; if (identityData.identity?.email && !identityData.identity.atp_did) { return ( ); } } const handleEmailSubmit = async () => { setLoading(true); try { // On a custom domain, complete email auth on the main site: it checks for // an existing session and hands it back if found, otherwise it emails a // code and collects it there before bouncing back. This keeps the // canonical session first-party on the main site. let base = mainSiteAuthBase(); if (base) { let loginUrl = new URL("/api/auth/email-login", base); loginUrl.searchParams.set("email", loginEmail); loginUrl.searchParams.set("redirect", window.location.href); window.location.href = loginUrl.toString(); return; } const id = await requestAuthEmailToken(loginEmail); setTokenId(id); setState("email confirm"); } catch (e) { toaster({ content: (
We couldnt send the email. Please try again!
), type: "error", }); } finally { setLoading(false); } }; const handleCodeSubmit = async (code: string) => { if (!tokenId) return; setLoading(true); const confirmedToken = await confirmEmailAuthToken(tokenId, code); if (!confirmedToken) { setLoading(false); toaster({ content:
Incorrect code!
, type: "error", }); return; } // Local pre-login drafts belong to whoever first signs in on this browser, // never to an additional account added alongside an existing session. const localLeaflets = props.addAccount ? [] : getHomeDocs().filter((l) => !l.hidden); await loginWithEmailToken(localLeaflets, props.redirectRoute); if (props.addAccount) { // The session cookie now points at the added account; navigate rather // than mutate in place since page state is keyed to the old identity. window.location.href = "/home"; return; } mutate("identity"); toaster({ content:
Logged in! Welcome!
, type: "success", }); setLoading(false); props.onSuccess?.(); }; return (
{state === "log in" ? ( <>

Log in with
Atmosphere account

What's the Atmosphere?
} />
} loading={loading} onSubmit={(handle) => { setLoading(true); window.location.href = buildOauthLoginUrl({ handle, redirect: props.redirectRoute || window.location.href, action: props.action, addAccount: props.addAccount, }); }} /> {props.noEmailLogin ? null : ( <>
)} ) : state === "email log in" ? (
{ e.preventDefault(); e.stopPropagation(); handleEmailSubmit(); }} >

Log in with Email

{ e.preventDefault(); e.stopPropagation(); handleEmailSubmit(); }} > } />
) : state === "email confirm" ? ( setState("email log in")} /> ) : (

Leaflet is part of
the Atmosphere.

Create an Atmosphere account on Bluesky to get started!
{ window.location.href = buildOauthLoginUrl({ redirect: props.redirectRoute || "/", signup: true, action: props.action, addAccount: props.addAccount, }); }} > Sign up via Bluesky
)}
); }; const LinkAtmosphereContent = (props: { pageView?: boolean; redirectRoute?: string; action?: string; open?: boolean; }) => { let [loading, setLoading] = useState(false); return (

Link your
Atmosphere account

What's the Atmosphere?
} />
} loading={loading} onSubmit={(handle) => { setLoading(true); window.location.href = buildOauthLoginUrl({ handle, redirect: props.redirectRoute || window.location.href, action: props.action, link: true, }); }} />
); };