55 lines · 1.9 KB
import { Link } from "@tanstack/react-router";
import { cn } from "~/utils/cn";
import { TONE_SURFACE, type Tone } from "~/ui/tones";
import { EMAIL_UNVERIFIED_MESSAGE, VERIFY_EMAIL_PATH } from "~/lib/email-verification";

type Props = {
  tone?: Tone;
  /** `output` renders a live region for values that appear after an action (tokens, secrets). */
  as?: "div" | "output" | "p" | "li";
  /** Use `alert` for errors that need announcing. */
  role?: "alert" | "status";
  children: React.ReactNode;
  className?: string;
};

export function Callout({ tone = "neutral", as: Tag = "div", role, children, className }: Props) {
  return (
    <Tag role={role} className={cn("block rounded-lg px-3 py-2 text-sm", TONE_SURFACE[tone], className)}>
      {children}
    </Tag>
  );
}

export function ErrorBanner({ message }: { message: string | null }) {
  if (!message) return null;
  // Server functions arrive as plain Errors, so the unverified-email refusal (AUTH-B1) is matched by its text.
  if (message === EMAIL_UNVERIFIED_MESSAGE) {
    return (
      <Callout tone="warning" role="alert">
        Verify your email address first: open the link we sent you.{" "}
        <Link to={VERIFY_EMAIL_PATH} className="underline underline-offset-2">
          Resend the verification email
        </Link>
      </Callout>
    );
  }
  return (
    <Callout tone="danger" role="alert">
      {message}
    </Callout>