173 lines · 6.2 KB
import { useState } from "react";
import { addEmail, removeEmail, resendVerificationEmail, setPrimaryEmail } from "~/fns/account-security";
import type { getSecuritySettings } from "~/fns/account-security";
import { useAction } from "~/hooks/use-action";
import { Button } from "~/ui/Button";
import { TextField } from "~/ui/Field";
import { ErrorBanner } from "~/ui/Callout";
import { Badge } from "~/ui/Badge";
import { Panel } from "~/ui/Panel";

type AccountEmail = Awaited<ReturnType<typeof getSecuritySettings>>["emails"][number];

type Notice = { text: string; devMailUrl?: string | null };
type RowProps = { entry: AccountEmail; hasPassword: boolean; onNotice: (notice: Notice) => void };

function openDevMail(url: string | null) {
  if (url) window.open(url, "_blank", "noopener");
}

function EmailRow({ entry, hasPassword, onNotice }: RowProps) {
  const resend = useAction(resendVerificationEmail, { invalidate: false });
  const remove = useAction(removeEmail);
  const makePrimary = useAction(setPrimaryEmail);
  const [confirming, setConfirming] = useState(false);
  const error = resend.error ?? remove.error ?? makePrimary.error;
  const canMakePrimary = !entry.primary && entry.verified;

  async function promote(password: string) {
    if (await makePrimary.run({ data: { email: entry.email, password } })) {
      setConfirming(false);
      onNotice({ text: `${entry.email} is now your primary address.` });
    }
  }

  return (
    <li className="space-y-2 px-4 py-3">
      <ErrorBanner message={error} />
      <div className="flex flex-wrap items-center gap-2">
        <span className="min-w-0 truncate font-medium text-gray-100">{entry.email}</span>
        {entry.primary && <Badge tone="accent">Primary</Badge>}