import { EmailCard, emailBrandFromContext, resolveEmailBrand, type EmailBrand, } from "@dbx-tools/shared-email-template"; import { Button } from "@dbx-tools/ui-appkit/react"; import { useBrand } from "@dbx-tools/ui-branding/react"; import { CheckIcon, MailIcon, PaperclipIcon, XIcon } from "lucide-react"; import { attachmentNames, joinAddresses, type EmailDraft } from "./fields.ts"; // Presentational pieces for an outbound email awaiting a human Approve / // Deny: a mail-client chrome (sender, recipients, subject, attachments) // around the shared React Email card, plus an approval card wrapping it. // State and the resolve transport belong to the caller; these components // only render and report intent. The editable counterpart is // `EmailComposeView` in `./email-compose`; both share `./fields` and // `./email-body`. export type { EmailDraft } from "./fields.ts"; /** Props for {@link EmailPreview}. */ export interface EmailPreviewProps { email: EmailDraft; /** Optional email-only brand. Defaults to the active `BrandProvider` context. */ brand?: EmailBrand; } /** Initials for the sender avatar when no logo is available. */ function senderInitials(name: string): string { const parts = name.trim().split(/\s+/).filter(Boolean); if (parts.length === 0) return "?"; if (parts.length === 1) return parts[0]!.slice(0, 2).toUpperCase(); return `${parts[0]![0] ?? ""}${parts[1]![0] ?? ""}`.toUpperCase(); } /** One muted "Label: value" row in the client chrome. */ const ChromeRow = ({ label, value }: { label: string; value: string }) => (
{label} {value}
); /** * Render an email draft the way a mail client shows a received message: sender * identity, recipients, subject, and attachment chips in chrome around the * same branded React Email card used for delivery. Envelope fields stay out of * the delivered HTML — they are transport metadata, not body content. */ export const EmailPreview = ({ email, brand }: EmailPreviewProps) => { const { context } = useBrand(); const theme = resolveEmailBrand(brand ?? emailBrandFromContext(context)); const to = joinAddresses(email.to); const cc = joinAddresses(email.cc); const bcc = joinAddresses(email.bcc); const subject = email.subject?.trim() || "Message"; const files = email.attachments?.map((att) => att.filename).filter(Boolean) ?? []; const attachmentSummary = attachmentNames(email.attachments); return ({theme.name}
{theme.website ? ({theme.website}
) : null}{subject}