Refactor campaign recipient and review presentation
This commit is contained in:
@@ -0,0 +1,176 @@
|
||||
import { Check, Search } from "lucide-react";
|
||||
import {
|
||||
StatusBadge,
|
||||
TableActionGroup,
|
||||
type DataGridColumn,
|
||||
type DataGridListOption
|
||||
} from "@govoplan/core-webui";
|
||||
import type { MockMailboxMessage } from "../../../api/mail";
|
||||
import type { CampaignMessagePreviewAttachment } from "../components/MessagePreviewOverlay";
|
||||
import { asArray, asRecord, stringifyPreview } from "../utils/campaignView";
|
||||
import { builtMessageKey } from "./builtMessageQuery";
|
||||
import { countResolvedAttachments, formatAddressList } from "./reviewFormatters";
|
||||
|
||||
const MESSAGE_VALIDATION_OPTIONS: DataGridListOption[] = [
|
||||
{ value: "ready", label: "i18n:govoplan-campaign.ready.20c7c552" },
|
||||
{ value: "warning", label: "i18n:govoplan-campaign.warning.e9c45563" },
|
||||
{ value: "needs_review", label: "i18n:govoplan-campaign.needs_review.33a506cf" },
|
||||
{ value: "blocked", label: "i18n:govoplan-campaign.blocked.99613c74" },
|
||||
{ value: "excluded", label: "i18n:govoplan-campaign.excluded.9804952b" }];
|
||||
|
||||
|
||||
export function builtMessageColumns(
|
||||
openMessage: (row: Record<string, unknown>) => void,
|
||||
reviewedKeys: Set<string>)
|
||||
: DataGridColumn<Record<string, unknown>>[] {
|
||||
return [
|
||||
{ id: "number", header: "#", width: 70, sortable: true, filterType: "integer", sticky: "start", value: (row, index) => Number(row.entry_index ?? index + 1) },
|
||||
{ id: "recipient", header: "i18n:govoplan-campaign.recipient.90343260", width: 250, resizable: true, sortable: true, filterable: true, value: (row) => formatAddressList(asRecord(row.resolved_recipients).to) || String(row.recipient_email ?? "—") },
|
||||
{ id: "subject", header: "i18n:govoplan-campaign.subject.8d183dbd", width: "minmax(260px, 1fr)", maxWidth: 640, resizable: true, sortable: true, filterable: true, value: (row) => String(row.subject ?? "—") },
|
||||
{
|
||||
id: "validation",
|
||||
header: "i18n:govoplan-campaign.validation.dd74d182",
|
||||
width: 145,
|
||||
sortable: true,
|
||||
filterable: true,
|
||||
columnType: "from-list",
|
||||
list: { options: MESSAGE_VALIDATION_OPTIONS, display: "pill" },
|
||||
value: (row) => String(row.validation_status ?? "unknown")
|
||||
},
|
||||
{
|
||||
id: "postboxTargets",
|
||||
header: "Postbox targets",
|
||||
width: 145,
|
||||
align: "right",
|
||||
sortable: true,
|
||||
filterType: "integer",
|
||||
value: (row) => Number(row.postbox_target_count ?? 0),
|
||||
render: (row) => {
|
||||
const count = Number(row.postbox_target_count ?? 0);
|
||||
return count > 0 ? (
|
||||
<StatusBadge status="info" label={`${count} frozen`} />
|
||||
) : (
|
||||
<span className="muted">—</span>
|
||||
);
|
||||
}
|
||||
},
|
||||
{ id: "attachments", header: "i18n:govoplan-campaign.attachments.6771ade6", width: 125, sortable: true, filterable: true, filterType: "integer", align: "right", value: (row) => Number(row.attachment_count ?? countResolvedAttachments(row.attachments)) },
|
||||
{ id: "reviewed", header: "i18n:govoplan-campaign.reviewed.31ef8593", width: 110, sortable: true, filterable: true, columnType: "from-list", list: { options: [{ value: "yes", label: "i18n:govoplan-campaign.reviewed.31ef8593" }, { value: "no", label: "i18n:govoplan-campaign.not_reviewed.0a0e3cff" }] }, render: (row, index) => row.reviewed === true || reviewedKeys.has(String(row.review_key ?? builtMessageKey(row, index))) ? <Check size={17} aria-label="i18n:govoplan-campaign.reviewed.31ef8593" /> : <span className="muted">—</span>, value: (row, index) => row.reviewed === true || reviewedKeys.has(String(row.review_key ?? builtMessageKey(row, index))) ? "yes" : "no" },
|
||||
{ id: "actions", header: "i18n:govoplan-campaign.actions.c3cd636a", width: 72, sticky: "end", render: (row) => <TableActionGroup actions={[{ id: "review", label: "i18n:govoplan-campaign.review.e29a79fe", icon: <Search aria-hidden="true" />, onClick: () => openMessage(row) }]} /> }];
|
||||
|
||||
}
|
||||
|
||||
export function mockSendResultColumns(): DataGridColumn<Record<string, unknown>>[] {
|
||||
const options: DataGridListOption[] = [
|
||||
{ value: "sent", label: "i18n:govoplan-campaign.sent.35f49dcf" },
|
||||
{ value: "failed", label: "i18n:govoplan-campaign.failed.09fef5d8" },
|
||||
{ value: "skipped", label: "i18n:govoplan-campaign.skipped.5a000ad7" },
|
||||
{ value: "ready", label: "i18n:govoplan-campaign.ready.20c7c552" }];
|
||||
|
||||
return [
|
||||
{ id: "number", header: "#", width: 70, sortable: true, filterType: "integer", sticky: "start", value: (row, index) => Number(row.entry_index ?? index + 1) },
|
||||
{ id: "status", header: "i18n:govoplan-campaign.status.bae7d5be", width: 130, sortable: true, filterable: true, columnType: "from-list", list: { options, display: "pill" }, value: (row) => String(row.status ?? "info") },
|
||||
{ id: "recipient", header: "i18n:govoplan-campaign.recipient.90343260", width: 250, resizable: true, sortable: true, filterable: true, value: (row) => formatAddressList(row.to) || asArray(row.envelope_recipients).join(", ") || "—" },
|
||||
{ id: "smtp", header: "i18n:govoplan-campaign.smtp.efff9cca", width: 190, sortable: true, filterable: true, value: (row) => String(row.smtp_message_id ?? row.status ?? "—") },
|
||||
{ id: "imap", header: "i18n:govoplan-campaign.imap.271f9ef2", width: 190, sortable: true, filterable: true, value: (row) => String(row.imap_message_id ?? row.imap_status ?? "—") },
|
||||
{ id: "message", header: "i18n:govoplan-campaign.message.68f4145f", width: "minmax(260px, 1fr)", maxWidth: 720, resizable: true, filterable: true, value: (row) => String(row.message ?? "—") }];
|
||||
|
||||
}
|
||||
|
||||
export function sendResultColumns(): DataGridColumn<Record<string, unknown>>[] {
|
||||
const statuses: DataGridListOption[] = [
|
||||
{ value: "smtp_accepted", label: "i18n:govoplan-campaign.smtp_accepted.e3aa7603" },
|
||||
{ value: "already_accepted", label: "i18n:govoplan-campaign.already_accepted.826e68f2" },
|
||||
{ value: "outcome_unknown", label: "i18n:govoplan-campaign.outcome_unknown.6e929fca" },
|
||||
{ value: "failed", label: "i18n:govoplan-campaign.failed.09fef5d8" },
|
||||
{ value: "cancelled", label: "i18n:govoplan-campaign.cancelled.a1bf92ef" },
|
||||
{ value: "not_claimed", label: "i18n:govoplan-campaign.not_claimed.aa712c1b" },
|
||||
{ value: "dry_run", label: "i18n:govoplan-campaign.dry_run.485a3d15" }];
|
||||
|
||||
return [
|
||||
{ id: "status", header: "i18n:govoplan-campaign.status.bae7d5be", width: 160, sortable: true, filterable: true, sticky: "start", columnType: "from-list", list: { options: statuses, display: "pill" }, render: (row) => <StatusBadge status={String(row.status ?? "info")} />, value: (row) => String(row.status ?? "info") },
|
||||
{ id: "job", header: "i18n:govoplan-campaign.job.30c8cb83", width: 180, sortable: true, filterable: true, value: (row) => String(row.job_id ?? row.version_id ?? "—") },
|
||||
{ id: "message", header: "i18n:govoplan-campaign.message.68f4145f", width: "minmax(320px, 1fr)", maxWidth: 720, resizable: true, filterable: true, value: (row) => String(row.message ?? stringifyPreview(row, 180)) }];
|
||||
|
||||
}
|
||||
|
||||
export function imapAppendResultColumns(): DataGridColumn<Record<string, unknown>>[] {
|
||||
return [
|
||||
{ id: "status", header: "i18n:govoplan-campaign.status.bae7d5be", width: 150, sticky: "start", sortable: true, filterable: true, render: (row) => <StatusBadge status={String(row.status ?? "info")} />, value: (row) => String(row.status ?? "info") },
|
||||
{ id: "job", header: "i18n:govoplan-campaign.job.30c8cb83", width: 180, sortable: true, filterable: true, value: (row) => String(row.job_id ?? "-") },
|
||||
{ id: "folder", header: "i18n:govoplan-campaign.folder.30baa249", width: 190, sortable: true, filterable: true, value: (row) => String(row.folder ?? "-") },
|
||||
{ id: "message", header: "i18n:govoplan-campaign.message.68f4145f", width: "minmax(300px, 1fr)", maxWidth: 720, resizable: true, filterable: true, value: (row) => String(row.message ?? stringifyPreview(row, 180)) }];
|
||||
|
||||
}
|
||||
|
||||
export function imapDiagnosticColumns(openDetail: (jobId: string) => Promise<void>): DataGridColumn<Record<string, unknown>>[] {
|
||||
return [
|
||||
{ id: "recipient", header: "i18n:govoplan-campaign.recipient.90343260", width: 240, sticky: "start", resizable: true, sortable: true, filterable: true, value: (row) => formatAddressList(asRecord(row.resolved_recipients).to) || String(row.recipient_email ?? "-") },
|
||||
{ id: "subject", header: "i18n:govoplan-campaign.subject.8d183dbd", width: "minmax(260px, 1fr)", maxWidth: 640, resizable: true, sortable: true, filterable: true, value: (row) => String(row.subject ?? "-") },
|
||||
{ id: "send", header: "i18n:govoplan-campaign.smtp.efff9cca", width: 150, sortable: true, filterable: true, render: (row) => <StatusBadge status={String(row.send_status ?? "info")} />, value: (row) => String(row.send_status ?? "-") },
|
||||
{ id: "imap", header: "i18n:govoplan-campaign.imap.271f9ef2", width: 150, sortable: true, filterable: true, render: (row) => <StatusBadge status={String(row.imap_status ?? "info")} />, value: (row) => String(row.imap_status ?? "-") },
|
||||
{ id: "error", header: "i18n:govoplan-campaign.last_error.5e4df866", width: "minmax(260px, 1fr)", maxWidth: 720, resizable: true, filterable: true, value: (row) => String(row.last_error ?? "-") },
|
||||
{ id: "actions", header: "i18n:govoplan-campaign.actions.c3cd636a", width: 72, sticky: "end", render: (row) => <TableActionGroup actions={[{ id: "details", label: "i18n:govoplan-campaign.details.dc3decbb", icon: <Search aria-hidden="true" />, onClick: () => void openDetail(String(row.id ?? "")) }]} /> }];
|
||||
|
||||
}
|
||||
|
||||
export function mockMailboxColumns(openMessage: (id: string) => Promise<void>): DataGridColumn<Record<string, unknown>>[] {
|
||||
const options: DataGridListOption[] = [
|
||||
{ value: "smtp", label: "i18n:govoplan-campaign.smtp.efff9cca" },
|
||||
{ value: "imap_append", label: "i18n:govoplan-campaign.imap_append.8c0d9e96" }];
|
||||
|
||||
return [
|
||||
{ id: "kind", header: "i18n:govoplan-campaign.kind.e00ac23f", width: 125, sortable: true, filterable: true, sticky: "start", columnType: "from-list", list: { options, display: "pill" }, value: (row) => String(row.kind ?? "mock") },
|
||||
{ id: "subject", header: "i18n:govoplan-campaign.subject.8d183dbd", width: "minmax(260px, 1fr)", maxWidth: 640, resizable: true, sortable: true, filterable: true, value: (row) => String(row.subject ?? "—") },
|
||||
{ id: "envelope", header: "i18n:govoplan-campaign.envelope_folder.9f30740d", width: 300, resizable: true, filterable: true, value: (row) => `${String(row.envelope_from ?? row.folder ?? "—")} → ${asArray(row.envelope_recipients).join(", ") || String(row.folder ?? "—")}` },
|
||||
{ id: "attachments", header: "i18n:govoplan-campaign.attachments.6771ade6", width: 125, sortable: true, filterable: true, filterType: "integer", align: "right", value: (row) => Number(row.attachment_count ?? 0) },
|
||||
{ id: "actions", header: "i18n:govoplan-campaign.actions.c3cd636a", width: 72, sticky: "end", render: (row) => <TableActionGroup actions={[{ id: "review", label: "i18n:govoplan-campaign.review.e29a79fe", icon: <Search aria-hidden="true" />, onClick: () => void openMessage(String(row.id ?? "")) }]} /> }];
|
||||
|
||||
}
|
||||
|
||||
export function mockMessageMetaItems(message: MockMailboxMessage) {
|
||||
return [
|
||||
{ label: "i18n:govoplan-campaign.from.3f66052a", value: message.from_header || message.envelope_from || "—" },
|
||||
{ label: "i18n:govoplan-campaign.to.ae79ea1e", value: message.to_header || message.envelope_recipients?.join(", ") || "—" },
|
||||
{ label: "i18n:govoplan-campaign.cc.1fd6a880", value: message.cc_header || null },
|
||||
{ label: "i18n:govoplan-campaign.bcc.8431acad", value: message.bcc_header || null },
|
||||
{ label: "i18n:govoplan-campaign.kind.e00ac23f", value: message.kind || "—" },
|
||||
{ label: "i18n:govoplan-campaign.folder.30baa249", value: message.folder || "—" },
|
||||
{ label: "i18n:govoplan-campaign.message_id.fa0e4fdd", value: message.message_id || "—" },
|
||||
{ label: "i18n:govoplan-campaign.size.b7152342", value: `${message.size_bytes || 0} bytes` }];
|
||||
|
||||
}
|
||||
|
||||
export function mockMessageAttachments(message: MockMailboxMessage): CampaignMessagePreviewAttachment[] {
|
||||
return (message.attachments ?? []).map((attachment, index) => ({
|
||||
filename: attachment.filename || `Attachment ${index + 1}`,
|
||||
contentType: attachment.content_type || undefined,
|
||||
sizeBytes: attachment.size_bytes ?? undefined
|
||||
}));
|
||||
}
|
||||
|
||||
export function synchronousSendReason(option: Record<string, unknown>): string {
|
||||
const configuredMessage = String(option.message ?? "").trim();
|
||||
if (configuredMessage) return configuredMessage;
|
||||
switch (String(option.reason ?? "")) {
|
||||
case "recipient_limit_exceeded":return "i18n:govoplan-campaign.the_exact_built_run_exceeds_the_effective_limit_.d7812d6a";
|
||||
case "no_eligible_recipient_jobs":return "i18n:govoplan-campaign.the_built_run_has_no_eligible_message.48e5410c";
|
||||
case "version_not_ready":return "i18n:govoplan-campaign.validate_lock_build_and_review_the_current_versi.d0567dcc";
|
||||
case "policy_configuration_invalid":return "i18n:govoplan-campaign.the_delivery_policy_configuration_is_invalid.a804a8f8";
|
||||
default:return "i18n:govoplan-campaign.delivery_options_are_still_being_evaluated.8395096e";
|
||||
}
|
||||
}
|
||||
|
||||
export function deliveryControlProgressMessage(action: "pause" | "resume" | "cancel"): string {
|
||||
if (action === "pause") return "i18n:govoplan-campaign.pausing_eligible_delivery_jobs_.eb6b9d58";
|
||||
if (action === "resume") return "i18n:govoplan-campaign.resuming_eligible_delivery_jobs_.dd12c5a2";
|
||||
return "i18n:govoplan-campaign.cancelling_eligible_delivery_jobs_.4090fa47";
|
||||
}
|
||||
|
||||
export function deliveryPolicySourceLabel(source: string): string {
|
||||
if (source === "tenant") return "i18n:govoplan-campaign.tenant.3ca93c78";
|
||||
if (source === "deployment") return "i18n:govoplan-campaign.deployment.327a55f8";
|
||||
if (source === "deployment_default") return "i18n:govoplan-campaign.deployment_default.aa39f7b4";
|
||||
if (source === "deployment_ceiling") return "i18n:govoplan-campaign.deployment_ceiling.abbec75b";
|
||||
return "i18n:govoplan-campaign.not_available.d1a17af1";
|
||||
}
|
||||
Reference in New Issue
Block a user