"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;
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;
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: (
,
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: