dodil/erp-ui

src/components/status-badge/StatusBadge.tsx

import { Badge } from "@radix-ui/themes";

/** The tone a status reads as. Bricks use UPPERCASE or lower-case states; the mapping ignores case. */
export type Tone = "neutral" | "info" | "success" | "warning" | "danger";

const COLOR = { neutral: "gray", info: "blue", success: "green", warning: "amber", danger: "red" } as const;

const DEFAULT_TONES: Record<string, Tone> = {
  draft: "neutral", open: "info", sent: "info", active: "success", accepted: "success", done: "success",
  closed_won: "success", won: "success", expired: "warning", blocked: "danger", declined: "danger",
  closed_lost: "danger", lost: "danger", cancelled: "neutral", superseded: "neutral", archived: "neutral",
  left: "neutral",
};

/** A state as a coloured badge. Pass `tones` to colour a brick's own states; unknown ones are neutral. */
export function StatusBadge({ status, tones }: { status: string; tones?: Record<string, Tone> }) {
  const key = status.toLowerCase();
  const tone = tones?.[key] ?? tones?.[status] ?? DEFAULT_TONES[key] ?? "neutral";
  return (
    // highContrast: a soft green/blue/amber badge's text is under 4.5:1 on its own background (axe, in a real
    // browser, on the CRM screens — 2026-10-17); the high-contrast text keeps the colour and passes.
    <Badge color={COLOR[tone]} variant="soft" radius="full" highContrast>
      {status.replace(/_/g, " ").toLowerCase()}
    </Badge>
  );
}