import { ReactElement } from 'react'; import { PaginationState, ColumnDef } from '@tanstack/react-table'; import { EmailStatus } from './email-marketing-primitives.mjs'; /** * Email campaign table (BUILD-2285 / BUILD-2283): one column factory used by both the * Email Marketing **Overview** tab ("Recent campaigns") and the **Campaigns** tab (full * list, with toolbar) so the two stay column-consistent — GHL-style: Campaign · Status · * Recipients · Delivered · Opened · Clicked · Bounced · Schedule, plus an optional * row-actions ("…") column when action handlers are supplied. * * Rates are numeric percentages; pass `formatRate` to change the default one-decimal * "42.1%" rendering. */ /** One campaign row — shared by the Overview recent list and the Campaigns tab. */ interface EmailCampaignRow { id: string; name: string; status: EmailStatus; templateName?: string; /** Staff who created it — its audience is whatever contacts that person can see. */ createdByName?: string; scheduleSummary?: string; /** Undefined while the count is still being fetched — the cell shows a pending marker. */ recipientCount?: number; /** Engagement + delivery rates as percentages (e.g. 42.1) — present once sending started. */ openRate?: number; clickRate?: number; /** SES-tracked delivery / bounce rates (once sending has started). */ deliveredRate?: number; bounceRate?: number; /** Why the campaign errored — shown beside the badge; only set for `status: "error"`. */ errorReason?: string; /** Recurring campaigns only — surfaced under Schedule. */ isRecurring?: boolean; lastSentLabel?: string; nextSendLabel?: string; } type CampaignRateFormatter = (value: number) => string; interface CampaignColumnHandlers { /** Row title click → open the campaign (status-aware in the parent). */ onOpenCampaign?: (id: string) => void; /** Row "…" actions — supplying any of these adds the actions column. */ onEditCampaign?: (id: string) => void; /** Pause a running campaign / resume a paused one (label flips by status). */ onTogglePause?: (id: string) => void; onDeleteCampaign?: (id: string) => void; /** Renders every rate column; defaults to one-decimal percent. */ formatRate?: CampaignRateFormatter; } /** * Build the campaign table columns. Always returns the base GHL columns; if any * row-action handler is passed, appends a trailing "…" actions column. */ declare function buildCampaignColumns(handlers?: CampaignColumnHandlers): ColumnDef[]; /** Statuses a campaign can filter by (drip-only `active`/`ended` excluded). */ type CampaignStatusFilter = Extract; /** * Server-driven campaign table. Supply it and the component renders exactly the rows it is * given, reporting status/search/page intent through callbacks; omit it and the table filters * and pages the rows it holds, which is only correct when those rows are every campaign. */ interface EmailCampaignTableQuery { status: CampaignStatusFilter | "all"; onStatusChange: (status: CampaignStatusFilter | "all") => void; search: string; onSearchChange: (search: string) => void; pagination: PaginationState; onPaginationChange: (pagination: PaginationState) => void; /** Campaigns matching the active filters, across every page. */ rowCount: number; /** Per-status totals for the whole set; omit to count the loaded rows. */ statusCounts?: Partial>; isLoading?: boolean; } interface EmailCampaignTableProps extends CampaignColumnHandlers { campaigns: EmailCampaignRow[]; onNewCampaign?: () => void; className?: string; /** Omit for the client-side table; supply for server-driven filtering/search/paging. */ query?: EmailCampaignTableQuery; } declare function EmailCampaignTable({ campaigns, onNewCampaign, className, query: serverQuery, ...handlers }: EmailCampaignTableProps): ReactElement; export { type CampaignColumnHandlers, type CampaignRateFormatter, type CampaignStatusFilter, type EmailCampaignRow, EmailCampaignTable, type EmailCampaignTableProps, type EmailCampaignTableQuery, buildCampaignColumns, EmailCampaignTable as default };