@aglyn/plugins-outreach 1.0.0-beta.234 → 1.0.0-beta.235

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aglyn/plugins-outreach",
3
- "version": "1.0.0-beta.234",
3
+ "version": "1.0.0-beta.235",
4
4
  "license": "Apache-2.0",
5
5
  "homepage": "https://aglyn.com",
6
6
  "repository": {
@@ -25,19 +25,19 @@
25
25
  "./package.json": "./package.json"
26
26
  },
27
27
  "dependencies": {
28
- "@aglyn/aglyn": "1.0.0-beta.234",
29
- "@aglyn/shared-data-mdi": "1.0.0-beta.234",
30
- "@aglyn/shared-ui-email-campaigns": "1.0.0-beta.234",
31
- "@aglyn/shared-ui-jsx": "1.0.0-beta.234",
32
- "@aglyn/shared-ui-next": "1.0.0-beta.234",
33
- "@aglyn/shared-ui-snackstack": "1.0.0-beta.234",
34
- "@aglyn/shared-util-email": "1.0.0-beta.234",
35
- "@aglyn/shared-util-http": "1.0.0-beta.234",
36
- "@aglyn/shared-util-timestamp": "1.0.0-beta.234",
37
- "@aglyn/shared-util-tools": "1.0.0-beta.234",
38
- "@aglyn/tenant-data-admin": "1.0.0-beta.234",
39
- "@aglyn/tenant-feature-instance": "1.0.0-beta.234",
40
- "@aglyn/tenant-runtime": "1.0.0-beta.234",
28
+ "@aglyn/aglyn": "1.0.0-beta.235",
29
+ "@aglyn/shared-data-mdi": "1.0.0-beta.235",
30
+ "@aglyn/shared-ui-email-campaigns": "1.0.0-beta.235",
31
+ "@aglyn/shared-ui-jsx": "1.0.0-beta.235",
32
+ "@aglyn/shared-ui-next": "1.0.0-beta.235",
33
+ "@aglyn/shared-ui-snackstack": "1.0.0-beta.235",
34
+ "@aglyn/shared-util-email": "1.0.0-beta.235",
35
+ "@aglyn/shared-util-http": "1.0.0-beta.235",
36
+ "@aglyn/shared-util-timestamp": "1.0.0-beta.235",
37
+ "@aglyn/shared-util-tools": "1.0.0-beta.235",
38
+ "@aglyn/tenant-data-admin": "1.0.0-beta.235",
39
+ "@aglyn/tenant-feature-instance": "1.0.0-beta.235",
40
+ "@aglyn/tenant-runtime": "1.0.0-beta.235",
41
41
  "@swc/helpers": "0.5.23"
42
42
  },
43
43
  "peerDependencies": {
@@ -818,7 +818,7 @@ export function OutreachEnrollmentDetail(props) {
818
818
  header: "Activity",
819
819
  subheader: "Newest first",
820
820
  help: pluginDocsHelp('sequences', {
821
- anchor: '#person-history'
821
+ anchor: '#person-activity'
822
822
  }),
823
823
  contentGutterX: true,
824
824
  contentGutterY: true,
@@ -864,7 +864,7 @@ export function OutreachEnrollmentDetail(props) {
864
864
  /*#__PURE__*/ _jsx(CardDisplay, {
865
865
  header: "Details",
866
866
  help: pluginDocsHelp('sequences', {
867
- anchor: '#person-history'
867
+ anchor: '#person-details'
868
868
  }),
869
869
  contentGutterX: true,
870
870
  HeaderProps: {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../../libs/plugins/outreach/src/lib/components/enrollment-detail.tsx"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n'use client'\n\nimport {\n type ConsolePluginOrgMount,\n PageHeaderRecord,\n pluginDocsHelp,\n} from '@aglyn/aglyn'\nimport { pluginRecordHref } from '@aglyn/aglyn/plugin-manager/plugin-record-routes'\nimport {\n mdiAccountCancelOutline,\n mdiAccountOutline,\n mdiAccountPlusOutline,\n mdiAlertCircleOutline,\n mdiCheckCircleOutline,\n mdiChevronDown,\n mdiChevronUp,\n mdiClipboardCheckOutline,\n mdiContentCopy,\n mdiCursorDefaultClickOutline,\n mdiEmailAlertOutline,\n mdiEmailOffOutline,\n mdiEmailOpenOutline,\n mdiEmailOutline,\n mdiHandBackLeftOutline,\n mdiPauseCircleOutline,\n mdiPencilOutline,\n mdiPlayCircleOutline,\n mdiReply,\n mdiShieldSearch,\n mdiSkipNext,\n mdiStopCircleOutline,\n} from '@aglyn/shared-data-mdi'\nimport { AppLink, CardDisplay, MdiIcon } from '@aglyn/shared-ui-jsx'\nimport EmptyStateComponent from '@aglyn/shared-ui-jsx/components/empty-state.component'\nimport RowActionsMenu from '@aglyn/shared-ui-jsx/components/row-actions-menu.component'\nimport { useSnackbar } from '@aglyn/shared-ui-snackstack'\nimport { useOrgContainerOptions, useOrgMemberOptions } from '@aglyn/tenant-feature-instance'\nimport {\n Alert,\n Box,\n Button,\n Card,\n Chip,\n Collapse,\n Divider,\n IconButton,\n Link,\n List,\n ListItem,\n ListItemIcon,\n ListItemText,\n Stack,\n Tooltip,\n Typography,\n} from '@mui/material'\nimport { type ReactNode, useCallback, useMemo, useState } from 'react'\nimport { OUTREACH_MAIL_GATEWAY_LABELS } from '../engine/mail-gateway'\nimport { outreachNextSendState } from '../engine/next-send'\nimport { outreachClickSummary } from '../model/enrollment-engagement'\nimport {\n outreachEnrollmentFigures,\n outreachEnrollmentTimeline,\n outreachStepName,\n type OutreachTimelineEntry,\n type OutreachTimelineKind,\n type OutreachTimelineTone,\n} from '../model/enrollment-timeline'\nimport {\n OUTREACH_ATTESTATION_KINDS,\n OUTREACH_ATTESTATION_LABELS,\n type OutreachEnrollment,\n type OutreachMailbox,\n type OutreachSequence,\n} from '../model/outreach.types'\nimport {\n OUTREACH_ENROLLMENT_ACTION_LABELS,\n outreachEnrollmentActionsFor,\n type OutreachEnrollmentRowAction,\n useOutreachEnrollmentActions,\n} from './enrollment-actions'\nimport { outreachCurrentStepLabel, outreachStepIsCurated, outreachStopLabel } from './enrollments-table'\nimport {\n formatOutreachTime,\n OutreachEnrollmentStatusChip,\n OutreachLoading,\n OutreachLoadProblem,\n} from './outreach-ui'\nimport { outreachNextSendDetail, outreachNextSendLabel, useOutreachNowMs } from './next-send'\nimport { OutreachFigure } from './sequence-report-card'\nimport { useOutreachApi } from './use-outreach-api'\nimport { useOutreachSequence } from './use-outreach-data'\nimport type { OutreachEnrollmentGatewayResponse } from '../model/outreach-api'\nimport {\n useOutreachEnrollment,\n useOutreachEnrollmentGateway,\n useOutreachEnrollmentHistory,\n} from './use-outreach-enrollment'\nimport type { OutreachMailboxesResult } from './use-outreach-mailboxes'\n\n/*==========================================\n * ONE PERSON IN ONE SEQUENCE (AGL-3332):\n * `/[orgSlug]/outreach/sequences/{sequenceId}/enrollments/{enrollmentId}`.\n *\n * A row of the Enrollments tab opens it, and its URL is the person's: a\n * comment or a message can link straight to them.\n *\n * Laid out the way every record page in the console is (the CRM's\n * `CrmRecordHeader` grammar): the page heading names the person; the first\n * card says what the record is, with the way back and the actions in its\n * HEADER — the one that changes things as a button, the rest and the\n * destructive ones behind the menu — and the facts that identify it as\n * chips. Under the chips, five numbers.\n *\n * Then ONE timeline, newest first, which is the page: every send, click,\n * reply, bounce, stop, hold and resume, from `model/enrollment-timeline.ts`.\n * Everything else stored on the enrollment is under Details, closed until\n * asked for — nothing is left out, and nothing is in the way.\n *=========================================*/\n\nexport interface OutreachEnrollmentDetailProps {\n orgId: string\n /** The org the hub is mounted under: its slug and sites, for the CRM record's address. */\n orgMount?: ConsolePluginOrgMount\n /** `/[orgSlug]/outreach/sequences`. */\n sectionPath: string\n sequenceId: string\n enrollmentId: string\n mailboxes: OutreachMailboxesResult\n}\n\n/**\n * Where the CRM record the person is lives — the site's own CRM when the site\n * is known, else the organization's — at the address the plugin that keeps\n * leads and contacts publishes, or `null` where none does.\n */\nexport function outreachCrmRecordHref(\n kind: 'lead' | 'contact',\n id: string | null | undefined,\n hostId: string,\n orgMount: Pick<ConsolePluginOrgMount, 'orgSlug' | 'hosts'> | undefined,\n): string | null {\n if (!id || !orgMount?.orgSlug) return null\n const host = orgMount.hosts.find((entry) => entry.id === hostId)?.subdomain ?? null\n return pluginRecordHref(kind, { orgSlug: orgMount.orgSlug, host }, id)\n}\n\n/**\n * Whether a mailbox's threads open in Gmail. A Microsoft 365 mailbox's\n * conversation has no address of its own in Outlook (AGL-3489), so its\n * thread is shown without a link.\n */\nexport const outreachThreadOpensInGmail = (mailbox: { provider?: string } | null | undefined): boolean =>\n mailbox?.provider !== 'microsoft'\n\n/** A Gmail thread, opened in the mailbox's own account. */\nexport function outreachGmailThreadUrl(threadId: string, mailboxEmail: string | null | undefined): string {\n const account = mailboxEmail ? `?authuser=${encodeURIComponent(mailboxEmail)}` : ''\n return `https://mail.google.com/mail/${account}#all/${encodeURIComponent(threadId)}`\n}\n\nconst KIND_ICONS: Record<OutreachTimelineKind, { path: string }> = {\n enrolled: mdiAccountPlusOutline,\n skipped: mdiSkipNext,\n curated: mdiPencilOutline,\n sent: mdiEmailOutline,\n task: mdiClipboardCheckOutline,\n click: mdiCursorDefaultClickOutline,\n scanner: mdiShieldSearch,\n 'earlier-clicks': mdiCursorDefaultClickOutline,\n open: mdiEmailOpenOutline,\n 'machine-open': mdiShieldSearch,\n paused: mdiPauseCircleOutline,\n resumed: mdiPlayCircleOutline,\n stopped: mdiStopCircleOutline,\n 'do-not-contact': mdiAccountCancelOutline,\n replied: mdiReply,\n bounced: mdiEmailAlertOutline,\n 'opted-out': mdiEmailOffOutline,\n held: mdiHandBackLeftOutline,\n released: mdiPlayCircleOutline,\n failed: mdiAlertCircleOutline,\n finished: mdiCheckCircleOutline,\n}\n\nconst TONE_COLORS: Record<OutreachTimelineTone, string> = {\n default: 'text.secondary',\n success: 'success.main',\n info: 'info.main',\n warning: 'warning.main',\n error: 'error.main',\n}\n\n/** A destination, whole, opening in a new tab. */\nfunction Destination(props: { url: string; label?: string }) {\n return (\n <Typography variant=\"body2\" component=\"span\" sx={{ display: 'block', wordBreak: 'break-all' }}>\n {props.label ? `${props.label}: ` : null}\n <Link href={props.url} target=\"_blank\" rel=\"noopener noreferrer\" underline=\"hover\">\n {props.url}\n </Link>\n </Typography>\n )\n}\n\n/** One line of the timeline. */\nfunction TimelineRow(props: {\n entry: OutreachTimelineEntry\n timeZone: string | null\n mailboxEmail: string | null\n /** False for a mailbox whose threads do not open in Gmail. */\n threadsOpenInGmail?: boolean\n divider: boolean\n}) {\n const { entry } = props\n return (\n <ListItem alignItems=\"flex-start\" divider={props.divider} disableGutters data-kind={entry.kind}>\n <ListItemIcon sx={{ minWidth: 36, mt: 0.75, color: TONE_COLORS[entry.tone] }}>\n <MdiIcon path={KIND_ICONS[entry.kind].path} fontSize=\"small\" />\n </ListItemIcon>\n <ListItemText\n disableTypography\n primary={\n <Stack\n direction={{ xs: 'column', sm: 'row' }}\n spacing={{ xs: 0, sm: 1 }}\n sx={{ justifyContent: 'space-between', alignItems: { sm: 'baseline' } }}\n >\n <Typography variant=\"body2\" sx={{ fontWeight: 500 }}>\n {entry.title}\n </Typography>\n <Typography variant=\"caption\" color=\"text.secondary\" sx={{ whiteSpace: 'nowrap' }}>\n {formatOutreachTime(entry.atMs, props.timeZone)}\n </Typography>\n </Stack>\n }\n secondary={\n <Stack spacing={0.25} sx={{ mt: 0.25 }}>\n {entry.url ? <Destination url={entry.url} label={entry.urlLabel} /> : null}\n {entry.detail ? (\n <Typography variant=\"body2\" sx={{ whiteSpace: 'pre-wrap', wordBreak: 'break-word' }}>\n {entry.detail}\n </Typography>\n ) : null}\n {entry.facts.length || (entry.gmailThreadId && props.threadsOpenInGmail !== false) ? (\n <Typography variant=\"caption\" color=\"text.secondary\" component=\"div\">\n {entry.facts.join(' · ')}\n {entry.gmailThreadId && props.threadsOpenInGmail !== false ? (\n <>\n {entry.facts.length ? ' · ' : null}\n <Link\n href={outreachGmailThreadUrl(entry.gmailThreadId, props.mailboxEmail)}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n underline=\"hover\"\n >\n Open thread in Gmail\n </Link>\n </>\n ) : null}\n </Typography>\n ) : null}\n </Stack>\n }\n />\n </ListItem>\n )\n}\n\n/** One fact of the Details list. */\nfunction Fact(props: { label: string; children: ReactNode }) {\n return (\n <>\n <Typography component=\"dt\" variant=\"body2\" color=\"text.secondary\">\n {props.label}\n </Typography>\n <Box component=\"dd\" sx={{ m: 0, minWidth: 0, typography: 'body2', wordBreak: 'break-word' }}>\n {props.children}\n </Box>\n </>\n )\n}\n\n/** What mail from the sequence's sending domain met at the person's domain, in a line. */\nfunction gatewaySentence(answer: OutreachEnrollmentGatewayResponse, timeZone: string | null): string {\n const { intel, standing } = answer\n if (!intel) return 'Could not be looked up'\n if (intel.status === 'no_mx' || intel.status === 'null_mx') {\n return `${answer.domain ?? 'The domain'} takes no mail · looked up ${formatOutreachTime(intel.resolvedAtMs, timeZone)}`\n }\n const from = answer.sendingDomain ? ` from ${answer.sendingDomain}` : ''\n const parts = [\n OUTREACH_MAIL_GATEWAY_LABELS[intel.gateway],\n intel.mx.length ? `MX ${intel.mx.join(', ')}` : 'no MX; delivered to its address record',\n standing\n ? `${standing.delivered30} delivered, ${standing.blocked30} refused${from} in the last 30 days`\n : null,\n `looked up ${formatOutreachTime(intel.resolvedAtMs, timeZone)}`,\n ]\n return parts.filter(Boolean).join(' · ')\n}\n\n/**\n * Everything else the enrollment holds, all of it, behind one toggle.\n */\nfunction EnrollmentDetails(props: {\n enrollment: OutreachEnrollment\n sequence: OutreachSequence\n mailbox: OutreachMailbox | null\n gateway: OutreachEnrollmentGatewayResponse | null\n /** What the Mail gateway line says while there is no answer to show. */\n gatewayUnread: string\n campaignName: (id: string) => string\n memberName: (uid: string) => string\n orgMount?: ConsolePluginOrgMount\n timeZone: string | null\n}) {\n const { enrollment, sequence, memberName, timeZone } = props\n const { enqueueSnackbar } = useSnackbar()\n const time = (ms: number | null | undefined) => formatOutreachTime(ms, timeZone)\n const leadHref = outreachCrmRecordHref('lead', enrollment.leadId, enrollment.hostId, props.orgMount)\n const contactHref = outreachCrmRecordHref('contact', enrollment.contactId, enrollment.hostId, props.orgMount)\n const clicks = outreachClickSummary(enrollment.engagement)\n const overrides = Object.entries(enrollment.stepOverrides ?? {}).sort(\n ([a], [b]) => Number(a) - Number(b),\n )\n const attested = OUTREACH_ATTESTATION_KINDS.filter((kind) => enrollment.attestations?.[kind])\n const threads = enrollment.gmailThreadIds.length\n ? enrollment.gmailThreadIds\n : enrollment.gmailThreadId\n ? [enrollment.gmailThreadId]\n : []\n const copyId = () => {\n void navigator.clipboard\n ?.writeText(enrollment.id)\n .then(() => enqueueSnackbar('Enrollment id copied.', { variant: 'success' }))\n .catch(() => enqueueSnackbar('The id could not be copied.', { variant: 'error' }))\n }\n const link = (href: string | null, label: string) =>\n href ? (\n <Link {...({ component: AppLink, componentVariant: 'naked' } as object)} href={href} underline=\"hover\">\n {label}\n </Link>\n ) : (\n label\n )\n\n return (\n <Box\n component=\"dl\"\n sx={{\n m: 0,\n display: 'grid',\n gridTemplateColumns: { xs: '1fr', sm: 'minmax(160px, 220px) 1fr' },\n columnGap: 2,\n rowGap: 1.25,\n }}\n >\n <Fact label=\"Personal line\">\n {enrollment.personalLine ? (\n <Typography variant=\"body2\" sx={{ whiteSpace: 'pre-wrap' }}>\n {enrollment.personalLine}\n </Typography>\n ) : (\n '—'\n )}\n </Fact>\n <Fact label=\"Enrolled as\">\n {enrollment.target === 'lead' ? (\n link(leadHref, 'Lead')\n ) : enrollment.leadId ? (\n <>\n {link(contactHref, 'Contact')}\n {', converted from a '}\n {link(leadHref, 'lead')}\n </>\n ) : (\n link(contactHref, 'Contact')\n )}\n </Fact>\n <Fact label=\"Enrolled\">\n {`${time(enrollment.createdAtMs)}${enrollment.enrolledByUid ? ` by ${memberName(enrollment.enrolledByUid)}` : ''}`}\n </Fact>\n <Fact label=\"Cold contact\">\n {enrollment.cold\n ? 'Yes — no inbound capture behind them, so the member confirmed the address before enrolling'\n : 'No'}\n </Fact>\n <Fact label=\"Attestations\">\n {attested.length ? (\n <Stack component=\"ul\" spacing={0.25} sx={{ m: 0, pl: 2.5 }}>\n {attested.map((kind) => {\n const entry = enrollment.attestations?.[kind]\n return (\n <li key={kind}>\n {`${OUTREACH_ATTESTATION_LABELS[kind]} — ${memberName(entry?.uid ?? '')}, ${time(entry?.atMs)}`}\n </li>\n )\n })}\n </Stack>\n ) : (\n '—'\n )}\n </Fact>\n <Fact label=\"Mailbox\">\n {props.mailbox\n ? `${props.mailbox.sendAs || props.mailbox.email}${props.mailbox.sendAs && props.mailbox.sendAs !== props.mailbox.email ? ` (${props.mailbox.email})` : ''}`\n : enrollment.mailboxId\n ? 'No longer connected'\n : '—'}\n </Fact>\n <Fact label=\"Campaigns\">\n {enrollment.campaignIds?.length\n ? enrollment.campaignIds.map(props.campaignName).join(', ')\n : '—'}\n </Fact>\n <Fact label=\"Mail gateway\">\n {props.gateway ? gatewaySentence(props.gateway, timeZone) : props.gatewayUnread}\n </Fact>\n <Fact label=\"Gateway hold\">\n {enrollment.gatewayHold\n ? [\n OUTREACH_MAIL_GATEWAY_LABELS[enrollment.gatewayHold.gateway],\n enrollment.gatewayHold.heldAtMs ? `held ${time(enrollment.gatewayHold.heldAtMs)}` : 'never held',\n enrollment.gatewayHold.releasedAtMs\n ? `released ${time(enrollment.gatewayHold.releasedAtMs)}${enrollment.gatewayHold.releasedByUid ? ` by ${memberName(enrollment.gatewayHold.releasedByUid)}` : ''}`\n : 'not released',\n ].join(' · ')\n : '—'}\n {enrollment.gatewayDeliveredSteps\n ? ` (${enrollment.gatewayDeliveredSteps} of their emails counted as delivered on the gateway ledger)`\n : null}\n </Fact>\n <Fact label=\"Clicks\">\n {clicks.clicks || clicks.machineClicks\n ? [\n `${clicks.clicks} by the person`,\n `${clicks.machineClicks} by scanners, not counted`,\n `${clicks.clicks - clicks.unloggedClicks + clicks.machineClicks - clicks.unloggedMachineClicks} listed one by one`,\n enrollment.engagement?.firstClickAtMs ? `first ${time(enrollment.engagement.firstClickAtMs)}` : null,\n enrollment.engagement?.lastClickAtMs ? `last ${time(enrollment.engagement.lastClickAtMs)}` : null,\n ]\n .filter(Boolean)\n .join(' · ')\n : '—'}\n {clicks.followed.length ? (\n <Box sx={{ mt: 0.5 }}>\n {clicks.followed.map((url) => (\n <Destination key={url} url={url} />\n ))}\n </Box>\n ) : null}\n </Fact>\n <Fact label=\"Curated steps\">\n {overrides.length ? (\n <Stack spacing={1.5}>\n {overrides.map(([key, override]) => (\n <Box key={key}>\n <Typography variant=\"body2\" sx={{ fontWeight: 500 }}>\n {outreachStepName(sequence.steps, Number(key))}\n </Typography>\n <Typography variant=\"caption\" color=\"text.secondary\" component=\"div\">\n {[\n override.source === 'ai' ? (override.edited ? 'AI draft, edited' : 'AI draft') : 'Written by a member',\n override.draftedByUid ? `confirmed by ${memberName(override.draftedByUid)}` : null,\n override.draftedAtMs ? time(override.draftedAtMs) : null,\n override.model ? `model ${override.model}` : null,\n ]\n .filter(Boolean)\n .join(' · ')}\n </Typography>\n {override.subject !== undefined ? (\n <Typography variant=\"body2\">{`Subject: ${override.subject}`}</Typography>\n ) : null}\n {override.body !== undefined ? (\n <Typography\n variant=\"body2\"\n sx={{ whiteSpace: 'pre-wrap', mt: 0.5, pl: 1.5, borderLeft: 2, borderColor: 'divider' }}\n >\n {override.body}\n </Typography>\n ) : null}\n {override.prompt ? (\n <Typography variant=\"caption\" color=\"text.secondary\" component=\"div\" sx={{ whiteSpace: 'pre-wrap', mt: 0.5 }}>\n {`Prompt: ${override.prompt}`}\n </Typography>\n ) : null}\n </Box>\n ))}\n </Stack>\n ) : (\n '—'\n )}\n </Fact>\n <Fact label={outreachThreadOpensInGmail(props.mailbox) ? 'Gmail threads' : 'Threads'}>\n {threads.length ? (\n <Stack spacing={0.25}>\n {threads.map((thread) => (\n <span key={thread}>\n {outreachThreadOpensInGmail(props.mailbox) ? (\n <Link\n href={outreachGmailThreadUrl(thread, props.mailbox?.email)}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n underline=\"hover\"\n >\n {thread}\n </Link>\n ) : (\n <Box component=\"span\" sx={{ wordBreak: 'break-all' }}>\n {thread}\n </Box>\n )}\n {thread === enrollment.gmailThreadId ? ' (current)' : null}\n </span>\n ))}\n {enrollment.threadSubject ? (\n <Typography variant=\"caption\" color=\"text.secondary\">{`Started as “${enrollment.threadSubject}”`}</Typography>\n ) : null}\n {enrollment.messageIds.length ? (\n <Typography variant=\"caption\" color=\"text.secondary\" sx={{ wordBreak: 'break-all' }}>\n {`Message-IDs in the current thread: ${enrollment.messageIds.join(' ')}`}\n </Typography>\n ) : null}\n </Stack>\n ) : (\n '—'\n )}\n </Fact>\n <Fact label=\"Stop\">\n {enrollment.stopReason\n ? `${outreachStopLabel(enrollment)} · ${time(enrollment.stoppedAtMs)}${enrollment.stoppedByUid ? ` · by ${memberName(enrollment.stoppedByUid)}` : ''}`\n : '—'}\n </Fact>\n <Fact label=\"Created · updated\">{`${time(enrollment.createdAtMs)} · ${time(enrollment.updatedAtMs)}`}</Fact>\n <Fact label=\"Enrollment id\">\n <Stack direction=\"row\" spacing={0.5} sx={{ alignItems: 'center' }}>\n <Typography variant=\"body2\" sx={{ fontFamily: 'monospace', wordBreak: 'break-all' }}>\n {enrollment.id}\n </Typography>\n <Tooltip title=\"Copy the id\">\n <IconButton size=\"small\" aria-label=\"Copy the enrollment id\" onClick={copyId}>\n <MdiIcon path={mdiContentCopy.path} fontSize=\"small\" />\n </IconButton>\n </Tooltip>\n </Stack>\n </Fact>\n </Box>\n )\n}\n\nexport function OutreachEnrollmentDetail(props: OutreachEnrollmentDetailProps) {\n const { orgId, sectionPath, sequenceId, enrollmentId, orgMount } = props\n const api = useOutreachApi(orgId)\n const loadedSequence = useOutreachSequence(orgId, sequenceId)\n const loaded = useOutreachEnrollment(orgId, enrollmentId)\n const history = useOutreachEnrollmentHistory(orgId, enrollmentId)\n const gateway = useOutreachEnrollmentGateway(api, enrollmentId)\n const roster = useOrgMemberOptions(orgId, { enabled: true })\n const [detailsOpen, setDetailsOpen] = useState(false)\n const nowMs = useOutreachNowMs()\n const enrollment = loaded.data\n const sequence = loadedSequence.data\n const campaigns = useOrgContainerOptions('campaign', orgId, {\n enabled: detailsOpen && Boolean(enrollment?.campaignIds?.length),\n })\n const steps = useMemo(() => sequence?.steps ?? [], [sequence])\n const actions = useOutreachEnrollmentActions({ api, steps })\n\n const memberName = useCallback(\n (uid: string) => roster.options.find((option) => option.uid === uid)?.label ?? 'a member',\n [roster.options],\n )\n const campaignName = useCallback(\n (id: string) => campaigns.options.find((option) => option.value === id)?.label ?? id,\n [campaigns.options],\n )\n\n const enrollmentsPath = `${sectionPath}/${sequenceId}/enrollments`\n const mailbox =\n props.mailboxes.mailboxes.find((entry) => entry.id === (enrollment?.mailboxId || sequence?.mailboxId)) ?? null\n const timeZone = mailbox?.timezone ?? null\n const time = (ms: number | null | undefined) => formatOutreachTime(ms, timeZone)\n const timeline = useMemo(\n () =>\n enrollment\n ? outreachEnrollmentTimeline({\n enrollment,\n steps,\n history: history.status === 'ready' ? history.data : null,\n memberName,\n formatTime: (ms) => formatOutreachTime(ms, timeZone),\n gateway: gateway.data?.intel?.gateway ?? null,\n })\n : [],\n [enrollment, steps, history, memberName, timeZone, gateway.data],\n )\n\n const back = (\n <Button\n // A real link, as the CRM record header's is: it opens in a new tab when asked.\n {...({ component: AppLink, componentVariant: 'naked', nativeButton: false } as object)}\n href={enrollmentsPath}\n size=\"small\"\n color=\"primary\"\n >\n Back to enrollments\n </Button>\n )\n\n if (loaded.status === 'loading' || loadedSequence.status === 'loading') {\n return <OutreachLoading label=\"Loading this person…\" />\n }\n if (loaded.status === 'error' || loaded.status === 'refused') {\n return <OutreachLoadProblem status={loaded.status} what=\"enrollment\" />\n }\n if (loadedSequence.status === 'error' || loadedSequence.status === 'refused') {\n return <OutreachLoadProblem status={loadedSequence.status} what=\"sequence\" />\n }\n // An id from another sequence reads as not here: the URL names both.\n if (!enrollment || !sequence || enrollment.sequenceId !== sequenceId) {\n return (\n <Card variant=\"outlined\">\n <EmptyStateComponent\n label=\"This person isn’t in this sequence\"\n description=\"They may have been removed from the workspace, or the link names a different sequence.\"\n action={back}\n />\n </Card>\n )\n }\n\n const name = enrollment.contactName || enrollment.email\n const kind = enrollment.target === 'lead' ? 'lead' : 'contact'\n const recordHref = outreachCrmRecordHref(\n kind,\n kind === 'lead' ? enrollment.leadId : enrollment.contactId,\n enrollment.hostId,\n orgMount,\n )\n const figures = outreachEnrollmentFigures(enrollment)\n const trackClicks = sequence.settings.trackClicks || sequence.stats?.clickTracked === true\n // Opens are shown for a sequence that counts them or once did (AGL-3395),\n // and for a person with any recorded, whatever the sequence says now.\n const countOpens =\n sequence.settings.countOpens ||\n sequence.stats?.openTracked === true ||\n figures.opens > 0 ||\n figures.machineOpens > 0\n const open = enrollment.status === 'active' || enrollment.status === 'paused'\n const held = enrollment.status === 'paused' && enrollment.stopReason === 'gateway_blocked_here'\n\n /*\n * The one act that moves the person forward is the button: resuming a\n * paused one, else curating the next email. Everything else is in the\n * menu, the destructive acts included, as on every record page.\n */\n const available = outreachEnrollmentActionsFor(enrollment, steps)\n const primary: OutreachEnrollmentRowAction | null = available.includes('resume')\n ? 'resume'\n : available.includes('curate')\n ? 'curate'\n : null\n const menu = actions.menuItems(enrollment, (action) => action !== primary)\n const dash = (value: number) => (value ? value.toLocaleString() : '—')\n const notTracked = !trackClicks && !figures.clicks && !figures.scannerClicks ? 'Not tracked' : undefined\n const thread = enrollment.gmailThreadId ?? enrollment.gmailThreadIds.at(-1) ?? null\n const nextSend = outreachNextSendState({\n enrollment,\n sequence,\n mailbox: props.mailboxes.status === 'ready' ? mailbox : undefined,\n nowMs,\n })\n const nothingYet =\n enrollment.status === 'active' && enrollment.nextDueAtMs\n ? nextSend.kind === 'queued'\n ? `Nothing yet — step ${enrollment.stepIndex + 1} is due and queued to send.`\n : `Nothing yet — step ${enrollment.stepIndex + 1} sends ${time(enrollment.nextDueAtMs)}.`\n : 'Nothing yet.'\n\n return (\n <Stack spacing={2}>\n {/* The page heading and the trail name the person; the card says what they are in. */}\n <PageHeaderRecord title={name} />\n <CardDisplay\n header=\"Enrollment\"\n subheader={\n <>\n {enrollment.contactName ? `${enrollment.email} · ` : ''}\n {`In ${sequence.name || 'Untitled'}`}\n </>\n }\n help={pluginDocsHelp('sequences', { anchor: '#person-history' })}\n contentGutterX\n contentGutterY\n HeaderProps={{\n action: (\n <Stack useFlexGap direction=\"row\" spacing={1} sx={{ alignItems: 'center', flexWrap: 'wrap', rowGap: 1 }}>\n {back}\n {primary ? (\n <Button\n variant=\"outlined\"\n size=\"small\"\n disabled={actions.busy === enrollment.id}\n onClick={() => actions.choose(enrollment, primary)}\n >\n {held ? 'Resume and send' : OUTREACH_ENROLLMENT_ACTION_LABELS[primary]}\n </Button>\n ) : null}\n {menu.length ? <RowActionsMenu label={name} items={menu} /> : null}\n </Stack>\n ),\n }}\n >\n <Stack spacing={2}>\n <Stack useFlexGap direction=\"row\" spacing={1} sx={{ alignItems: 'center', flexWrap: 'wrap', rowGap: 1 }}>\n <Tooltip\n describeChild\n title={recordHref ? `Open the ${kind} in the CRM` : `The ${kind}’s record can’t be linked`}\n >\n <Chip\n size=\"small\"\n variant=\"outlined\"\n color={recordHref ? 'primary' : 'default'}\n icon={<MdiIcon path={mdiAccountOutline.path} fontSize=\"small\" />}\n label={kind === 'lead' ? 'Lead' : 'Contact'}\n {...(recordHref\n ? ({ component: AppLink, href: recordHref, clickable: true, componentVariant: 'naked' } as object)\n : {})}\n />\n </Tooltip>\n <OutreachEnrollmentStatusChip status={enrollment.status} />\n <Chip size=\"small\" variant=\"outlined\" label={outreachCurrentStepLabel(enrollment, steps)} />\n {outreachStepIsCurated(enrollment) ? (\n <Chip size=\"small\" variant=\"outlined\" color=\"success\" label=\"Curated\" />\n ) : null}\n {open && enrollment.nextDueAtMs ? (\n nextSend.kind === 'queued' ? (\n <Tooltip describeChild title={outreachNextSendDetail(nextSend, timeZone)}>\n <Chip\n size=\"small\"\n variant=\"outlined\"\n color={\n nextSend.reason === 'mailbox_not_sending' || nextSend.reason === 'sequence_not_active'\n ? 'warning'\n : 'default'\n }\n label={`Next send ${outreachNextSendLabel(nextSend, timeZone)}`}\n />\n </Tooltip>\n ) : (\n <Chip size=\"small\" variant=\"outlined\" label={`Next send ${time(enrollment.nextDueAtMs)}`} />\n )\n ) : null}\n </Stack>\n {held ? (\n <Alert severity=\"warning\">\n {enrollment.stopDetail ||\n 'Their mail gateway refused this sender, so the next email is held. Resume to send it anyway.'}\n </Alert>\n ) : null}\n {figures.anything ? (\n <Stack useFlexGap direction=\"row\" spacing={3} sx={{ flexWrap: 'wrap', rowGap: 2 }} role=\"group\" aria-label=\"In numbers\">\n <OutreachFigure label=\"Emails sent\" value={dash(figures.emailsSent)} />\n {countOpens ? (\n <OutreachFigure\n label=\"Opens\"\n value={dash(figures.opens)}\n hint={figures.machineOpens ? `${figures.machineOpens.toLocaleString()} by machines, not counted` : undefined}\n />\n ) : null}\n <OutreachFigure label=\"Clicks\" value={dash(figures.clicks)} hint={notTracked} />\n <OutreachFigure\n label=\"Links followed\"\n value={\n figures.linksFollowed.count\n ? `${figures.linksFollowed.count}${figures.linksFollowed.atLeast ? '+' : ''}`\n : '—'\n }\n hint={\n notTracked ??\n (figures.linksFollowed.atLeast && figures.linksFollowed.count\n ? 'Earlier clicks kept the last link only'\n : undefined)\n }\n />\n <OutreachFigure label=\"Scanner clicks\" value={dash(figures.scannerClicks)} hint={notTracked ?? 'Not counted'} />\n <OutreachFigure label=\"Replies\" value={dash(figures.replies)} />\n </Stack>\n ) : (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {nothingYet}\n </Typography>\n )}\n </Stack>\n </CardDisplay>\n\n <CardDisplay\n header=\"Activity\"\n subheader=\"Newest first\"\n help={pluginDocsHelp('sequences', { anchor: '#person-history' })}\n contentGutterX\n contentGutterY\n HeaderProps={\n thread && outreachThreadOpensInGmail(mailbox)\n ? {\n action: (\n <Button\n size=\"small\"\n href={outreachGmailThreadUrl(thread, mailbox?.email)}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n Open thread in Gmail\n </Button>\n ),\n }\n : undefined\n }\n >\n <Stack spacing={1}>\n {history.status === 'loading' ? <OutreachLoading label=\"Loading their history…\" /> : null}\n {history.status === 'error' || history.status === 'refused' ? (\n <OutreachLoadProblem\n status={history.status}\n what=\"list of their clicks\"\n // Only the one-by-one list is missing: the totals, the sends and\n // every stop above come from the enrollment, which was read.\n message={\n history.status === 'refused'\n ? 'Their clicks can’t be listed one by one here; the numbers above still count them.'\n : 'Their clicks couldn’t be listed one by one. Reload the page to try again.'\n }\n />\n ) : null}\n <List disablePadding aria-label=\"Activity\">\n {timeline.map((entry, index) => (\n <TimelineRow\n key={entry.key}\n entry={entry}\n timeZone={timeZone}\n mailboxEmail={mailbox?.email ?? null}\n threadsOpenInGmail={outreachThreadOpensInGmail(mailbox)}\n divider={index < timeline.length - 1}\n />\n ))}\n </List>\n </Stack>\n </CardDisplay>\n\n <CardDisplay\n header=\"Details\"\n help={pluginDocsHelp('sequences', { anchor: '#person-history' })}\n contentGutterX\n HeaderProps={{\n action: (\n <Button\n size=\"small\"\n aria-expanded={detailsOpen}\n aria-controls=\"outreach-enrollment-details\"\n endIcon={<MdiIcon path={(detailsOpen ? mdiChevronUp : mdiChevronDown).path} fontSize=\"small\" />}\n onClick={() => setDetailsOpen((was) => !was)}\n >\n {detailsOpen ? 'Hide' : 'Show'}\n </Button>\n ),\n }}\n >\n <Collapse in={detailsOpen} unmountOnExit>\n <Box id=\"outreach-enrollment-details\" sx={{ pb: 2 }}>\n <Divider sx={{ mb: 2 }} />\n <EnrollmentDetails\n enrollment={enrollment}\n sequence={sequence}\n mailbox={mailbox}\n gateway={gateway.status === 'ready' ? gateway.data : null}\n gatewayUnread={\n gateway.status === 'loading'\n ? 'Looking it up…'\n : gateway.status === 'refused'\n ? 'Your role cannot look it up'\n : 'Could not be looked up'\n }\n campaignName={campaignName}\n memberName={memberName}\n orgMount={orgMount}\n timeZone={timeZone}\n />\n </Box>\n </Collapse>\n </CardDisplay>\n\n {actions.dialogs}\n </Stack>\n )\n}\nOutreachEnrollmentDetail.displayName = 'OutreachEnrollmentDetail'\n\nexport default OutreachEnrollmentDetail\n"],"names":["PageHeaderRecord","pluginDocsHelp","pluginRecordHref","mdiAccountCancelOutline","mdiAccountOutline","mdiAccountPlusOutline","mdiAlertCircleOutline","mdiCheckCircleOutline","mdiChevronDown","mdiChevronUp","mdiClipboardCheckOutline","mdiContentCopy","mdiCursorDefaultClickOutline","mdiEmailAlertOutline","mdiEmailOffOutline","mdiEmailOpenOutline","mdiEmailOutline","mdiHandBackLeftOutline","mdiPauseCircleOutline","mdiPencilOutline","mdiPlayCircleOutline","mdiReply","mdiShieldSearch","mdiSkipNext","mdiStopCircleOutline","AppLink","CardDisplay","MdiIcon","EmptyStateComponent","RowActionsMenu","useSnackbar","useOrgContainerOptions","useOrgMemberOptions","Alert","Box","Button","Card","Chip","Collapse","Divider","IconButton","Link","List","ListItem","ListItemIcon","ListItemText","Stack","Tooltip","Typography","useCallback","useMemo","useState","OUTREACH_MAIL_GATEWAY_LABELS","outreachNextSendState","outreachClickSummary","outreachEnrollmentFigures","outreachEnrollmentTimeline","outreachStepName","OUTREACH_ATTESTATION_KINDS","OUTREACH_ATTESTATION_LABELS","OUTREACH_ENROLLMENT_ACTION_LABELS","outreachEnrollmentActionsFor","useOutreachEnrollmentActions","outreachCurrentStepLabel","outreachStepIsCurated","outreachStopLabel","formatOutreachTime","OutreachEnrollmentStatusChip","OutreachLoading","OutreachLoadProblem","outreachNextSendDetail","outreachNextSendLabel","useOutreachNowMs","OutreachFigure","useOutreachApi","useOutreachSequence","useOutreachEnrollment","useOutreachEnrollmentGateway","useOutreachEnrollmentHistory","outreachCrmRecordHref","kind","id","hostId","orgMount","orgSlug","host","hosts","find","entry","subdomain","outreachThreadOpensInGmail","mailbox","provider","outreachGmailThreadUrl","threadId","mailboxEmail","account","encodeURIComponent","KIND_ICONS","enrolled","skipped","curated","sent","task","click","scanner","open","paused","resumed","stopped","replied","bounced","held","released","failed","finished","TONE_COLORS","default","success","info","warning","error","Destination","props","variant","component","sx","display","wordBreak","label","href","url","target","rel","underline","TimelineRow","alignItems","divider","disableGutters","data-kind","minWidth","mt","color","tone","path","fontSize","disableTypography","primary","direction","xs","sm","spacing","justifyContent","fontWeight","title","whiteSpace","atMs","timeZone","secondary","urlLabel","detail","facts","length","gmailThreadId","threadsOpenInGmail","join","Fact","m","typography","children","gatewaySentence","answer","intel","standing","status","domain","resolvedAtMs","from","sendingDomain","parts","gateway","mx","delivered30","blocked30","filter","Boolean","EnrollmentDetails","enrollment","sequence","memberName","enqueueSnackbar","time","ms","leadHref","leadId","contactHref","contactId","clicks","engagement","overrides","Object","entries","stepOverrides","sort","a","b","Number","attested","attestations","threads","gmailThreadIds","copyId","navigator","clipboard","writeText","then","catch","link","componentVariant","gridTemplateColumns","columnGap","rowGap","personalLine","createdAtMs","enrolledByUid","cold","pl","map","li","uid","sendAs","email","mailboxId","campaignIds","campaignName","gatewayUnread","gatewayHold","heldAtMs","releasedAtMs","releasedByUid","gatewayDeliveredSteps","machineClicks","unloggedClicks","unloggedMachineClicks","firstClickAtMs","lastClickAtMs","followed","key","override","steps","source","edited","draftedByUid","draftedAtMs","model","subject","undefined","body","borderLeft","borderColor","prompt","thread","span","threadSubject","messageIds","stopReason","stoppedAtMs","stoppedByUid","updatedAtMs","fontFamily","size","aria-label","onClick","OutreachEnrollmentDetail","orgId","sectionPath","sequenceId","enrollmentId","api","loadedSequence","loaded","history","roster","enabled","detailsOpen","setDetailsOpen","nowMs","data","campaigns","actions","options","option","value","enrollmentsPath","mailboxes","timezone","timeline","formatTime","back","nativeButton","what","description","action","name","contactName","recordHref","figures","trackClicks","settings","stats","clickTracked","countOpens","openTracked","opens","machineOpens","available","includes","menu","menuItems","dash","toLocaleString","notTracked","scannerClicks","at","nextSend","nothingYet","nextDueAtMs","stepIndex","header","subheader","help","anchor","contentGutterX","contentGutterY","HeaderProps","useFlexGap","flexWrap","disabled","busy","choose","items","describeChild","icon","clickable","reason","severity","stopDetail","anything","role","emailsSent","hint","linksFollowed","count","atLeast","replies","message","disablePadding","index","aria-expanded","aria-controls","endIcon","was","in","unmountOnExit","pb","mb","dialogs","displayName"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/outreach/src/lib/components/enrollment-detail.tsx"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n'use client'\n\nimport {\n type ConsolePluginOrgMount,\n PageHeaderRecord,\n pluginDocsHelp,\n} from '@aglyn/aglyn'\nimport { pluginRecordHref } from '@aglyn/aglyn/plugin-manager/plugin-record-routes'\nimport {\n mdiAccountCancelOutline,\n mdiAccountOutline,\n mdiAccountPlusOutline,\n mdiAlertCircleOutline,\n mdiCheckCircleOutline,\n mdiChevronDown,\n mdiChevronUp,\n mdiClipboardCheckOutline,\n mdiContentCopy,\n mdiCursorDefaultClickOutline,\n mdiEmailAlertOutline,\n mdiEmailOffOutline,\n mdiEmailOpenOutline,\n mdiEmailOutline,\n mdiHandBackLeftOutline,\n mdiPauseCircleOutline,\n mdiPencilOutline,\n mdiPlayCircleOutline,\n mdiReply,\n mdiShieldSearch,\n mdiSkipNext,\n mdiStopCircleOutline,\n} from '@aglyn/shared-data-mdi'\nimport { AppLink, CardDisplay, MdiIcon } from '@aglyn/shared-ui-jsx'\nimport EmptyStateComponent from '@aglyn/shared-ui-jsx/components/empty-state.component'\nimport RowActionsMenu from '@aglyn/shared-ui-jsx/components/row-actions-menu.component'\nimport { useSnackbar } from '@aglyn/shared-ui-snackstack'\nimport { useOrgContainerOptions, useOrgMemberOptions } from '@aglyn/tenant-feature-instance'\nimport {\n Alert,\n Box,\n Button,\n Card,\n Chip,\n Collapse,\n Divider,\n IconButton,\n Link,\n List,\n ListItem,\n ListItemIcon,\n ListItemText,\n Stack,\n Tooltip,\n Typography,\n} from '@mui/material'\nimport { type ReactNode, useCallback, useMemo, useState } from 'react'\nimport { OUTREACH_MAIL_GATEWAY_LABELS } from '../engine/mail-gateway'\nimport { outreachNextSendState } from '../engine/next-send'\nimport { outreachClickSummary } from '../model/enrollment-engagement'\nimport {\n outreachEnrollmentFigures,\n outreachEnrollmentTimeline,\n outreachStepName,\n type OutreachTimelineEntry,\n type OutreachTimelineKind,\n type OutreachTimelineTone,\n} from '../model/enrollment-timeline'\nimport {\n OUTREACH_ATTESTATION_KINDS,\n OUTREACH_ATTESTATION_LABELS,\n type OutreachEnrollment,\n type OutreachMailbox,\n type OutreachSequence,\n} from '../model/outreach.types'\nimport {\n OUTREACH_ENROLLMENT_ACTION_LABELS,\n outreachEnrollmentActionsFor,\n type OutreachEnrollmentRowAction,\n useOutreachEnrollmentActions,\n} from './enrollment-actions'\nimport { outreachCurrentStepLabel, outreachStepIsCurated, outreachStopLabel } from './enrollments-table'\nimport {\n formatOutreachTime,\n OutreachEnrollmentStatusChip,\n OutreachLoading,\n OutreachLoadProblem,\n} from './outreach-ui'\nimport { outreachNextSendDetail, outreachNextSendLabel, useOutreachNowMs } from './next-send'\nimport { OutreachFigure } from './sequence-report-card'\nimport { useOutreachApi } from './use-outreach-api'\nimport { useOutreachSequence } from './use-outreach-data'\nimport type { OutreachEnrollmentGatewayResponse } from '../model/outreach-api'\nimport {\n useOutreachEnrollment,\n useOutreachEnrollmentGateway,\n useOutreachEnrollmentHistory,\n} from './use-outreach-enrollment'\nimport type { OutreachMailboxesResult } from './use-outreach-mailboxes'\n\n/*==========================================\n * ONE PERSON IN ONE SEQUENCE (AGL-3332):\n * `/[orgSlug]/outreach/sequences/{sequenceId}/enrollments/{enrollmentId}`.\n *\n * A row of the Enrollments tab opens it, and its URL is the person's: a\n * comment or a message can link straight to them.\n *\n * Laid out the way every record page in the console is (the CRM's\n * `CrmRecordHeader` grammar): the page heading names the person; the first\n * card says what the record is, with the way back and the actions in its\n * HEADER — the one that changes things as a button, the rest and the\n * destructive ones behind the menu — and the facts that identify it as\n * chips. Under the chips, five numbers.\n *\n * Then ONE timeline, newest first, which is the page: every send, click,\n * reply, bounce, stop, hold and resume, from `model/enrollment-timeline.ts`.\n * Everything else stored on the enrollment is under Details, closed until\n * asked for — nothing is left out, and nothing is in the way.\n *=========================================*/\n\nexport interface OutreachEnrollmentDetailProps {\n orgId: string\n /** The org the hub is mounted under: its slug and sites, for the CRM record's address. */\n orgMount?: ConsolePluginOrgMount\n /** `/[orgSlug]/outreach/sequences`. */\n sectionPath: string\n sequenceId: string\n enrollmentId: string\n mailboxes: OutreachMailboxesResult\n}\n\n/**\n * Where the CRM record the person is lives — the site's own CRM when the site\n * is known, else the organization's — at the address the plugin that keeps\n * leads and contacts publishes, or `null` where none does.\n */\nexport function outreachCrmRecordHref(\n kind: 'lead' | 'contact',\n id: string | null | undefined,\n hostId: string,\n orgMount: Pick<ConsolePluginOrgMount, 'orgSlug' | 'hosts'> | undefined,\n): string | null {\n if (!id || !orgMount?.orgSlug) return null\n const host = orgMount.hosts.find((entry) => entry.id === hostId)?.subdomain ?? null\n return pluginRecordHref(kind, { orgSlug: orgMount.orgSlug, host }, id)\n}\n\n/**\n * Whether a mailbox's threads open in Gmail. A Microsoft 365 mailbox's\n * conversation has no address of its own in Outlook (AGL-3489), so its\n * thread is shown without a link.\n */\nexport const outreachThreadOpensInGmail = (mailbox: { provider?: string } | null | undefined): boolean =>\n mailbox?.provider !== 'microsoft'\n\n/** A Gmail thread, opened in the mailbox's own account. */\nexport function outreachGmailThreadUrl(threadId: string, mailboxEmail: string | null | undefined): string {\n const account = mailboxEmail ? `?authuser=${encodeURIComponent(mailboxEmail)}` : ''\n return `https://mail.google.com/mail/${account}#all/${encodeURIComponent(threadId)}`\n}\n\nconst KIND_ICONS: Record<OutreachTimelineKind, { path: string }> = {\n enrolled: mdiAccountPlusOutline,\n skipped: mdiSkipNext,\n curated: mdiPencilOutline,\n sent: mdiEmailOutline,\n task: mdiClipboardCheckOutline,\n click: mdiCursorDefaultClickOutline,\n scanner: mdiShieldSearch,\n 'earlier-clicks': mdiCursorDefaultClickOutline,\n open: mdiEmailOpenOutline,\n 'machine-open': mdiShieldSearch,\n paused: mdiPauseCircleOutline,\n resumed: mdiPlayCircleOutline,\n stopped: mdiStopCircleOutline,\n 'do-not-contact': mdiAccountCancelOutline,\n replied: mdiReply,\n bounced: mdiEmailAlertOutline,\n 'opted-out': mdiEmailOffOutline,\n held: mdiHandBackLeftOutline,\n released: mdiPlayCircleOutline,\n failed: mdiAlertCircleOutline,\n finished: mdiCheckCircleOutline,\n}\n\nconst TONE_COLORS: Record<OutreachTimelineTone, string> = {\n default: 'text.secondary',\n success: 'success.main',\n info: 'info.main',\n warning: 'warning.main',\n error: 'error.main',\n}\n\n/** A destination, whole, opening in a new tab. */\nfunction Destination(props: { url: string; label?: string }) {\n return (\n <Typography variant=\"body2\" component=\"span\" sx={{ display: 'block', wordBreak: 'break-all' }}>\n {props.label ? `${props.label}: ` : null}\n <Link href={props.url} target=\"_blank\" rel=\"noopener noreferrer\" underline=\"hover\">\n {props.url}\n </Link>\n </Typography>\n )\n}\n\n/** One line of the timeline. */\nfunction TimelineRow(props: {\n entry: OutreachTimelineEntry\n timeZone: string | null\n mailboxEmail: string | null\n /** False for a mailbox whose threads do not open in Gmail. */\n threadsOpenInGmail?: boolean\n divider: boolean\n}) {\n const { entry } = props\n return (\n <ListItem alignItems=\"flex-start\" divider={props.divider} disableGutters data-kind={entry.kind}>\n <ListItemIcon sx={{ minWidth: 36, mt: 0.75, color: TONE_COLORS[entry.tone] }}>\n <MdiIcon path={KIND_ICONS[entry.kind].path} fontSize=\"small\" />\n </ListItemIcon>\n <ListItemText\n disableTypography\n primary={\n <Stack\n direction={{ xs: 'column', sm: 'row' }}\n spacing={{ xs: 0, sm: 1 }}\n sx={{ justifyContent: 'space-between', alignItems: { sm: 'baseline' } }}\n >\n <Typography variant=\"body2\" sx={{ fontWeight: 500 }}>\n {entry.title}\n </Typography>\n <Typography variant=\"caption\" color=\"text.secondary\" sx={{ whiteSpace: 'nowrap' }}>\n {formatOutreachTime(entry.atMs, props.timeZone)}\n </Typography>\n </Stack>\n }\n secondary={\n <Stack spacing={0.25} sx={{ mt: 0.25 }}>\n {entry.url ? <Destination url={entry.url} label={entry.urlLabel} /> : null}\n {entry.detail ? (\n <Typography variant=\"body2\" sx={{ whiteSpace: 'pre-wrap', wordBreak: 'break-word' }}>\n {entry.detail}\n </Typography>\n ) : null}\n {entry.facts.length || (entry.gmailThreadId && props.threadsOpenInGmail !== false) ? (\n <Typography variant=\"caption\" color=\"text.secondary\" component=\"div\">\n {entry.facts.join(' · ')}\n {entry.gmailThreadId && props.threadsOpenInGmail !== false ? (\n <>\n {entry.facts.length ? ' · ' : null}\n <Link\n href={outreachGmailThreadUrl(entry.gmailThreadId, props.mailboxEmail)}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n underline=\"hover\"\n >\n Open thread in Gmail\n </Link>\n </>\n ) : null}\n </Typography>\n ) : null}\n </Stack>\n }\n />\n </ListItem>\n )\n}\n\n/** One fact of the Details list. */\nfunction Fact(props: { label: string; children: ReactNode }) {\n return (\n <>\n <Typography component=\"dt\" variant=\"body2\" color=\"text.secondary\">\n {props.label}\n </Typography>\n <Box component=\"dd\" sx={{ m: 0, minWidth: 0, typography: 'body2', wordBreak: 'break-word' }}>\n {props.children}\n </Box>\n </>\n )\n}\n\n/** What mail from the sequence's sending domain met at the person's domain, in a line. */\nfunction gatewaySentence(answer: OutreachEnrollmentGatewayResponse, timeZone: string | null): string {\n const { intel, standing } = answer\n if (!intel) return 'Could not be looked up'\n if (intel.status === 'no_mx' || intel.status === 'null_mx') {\n return `${answer.domain ?? 'The domain'} takes no mail · looked up ${formatOutreachTime(intel.resolvedAtMs, timeZone)}`\n }\n const from = answer.sendingDomain ? ` from ${answer.sendingDomain}` : ''\n const parts = [\n OUTREACH_MAIL_GATEWAY_LABELS[intel.gateway],\n intel.mx.length ? `MX ${intel.mx.join(', ')}` : 'no MX; delivered to its address record',\n standing\n ? `${standing.delivered30} delivered, ${standing.blocked30} refused${from} in the last 30 days`\n : null,\n `looked up ${formatOutreachTime(intel.resolvedAtMs, timeZone)}`,\n ]\n return parts.filter(Boolean).join(' · ')\n}\n\n/**\n * Everything else the enrollment holds, all of it, behind one toggle.\n */\nfunction EnrollmentDetails(props: {\n enrollment: OutreachEnrollment\n sequence: OutreachSequence\n mailbox: OutreachMailbox | null\n gateway: OutreachEnrollmentGatewayResponse | null\n /** What the Mail gateway line says while there is no answer to show. */\n gatewayUnread: string\n campaignName: (id: string) => string\n memberName: (uid: string) => string\n orgMount?: ConsolePluginOrgMount\n timeZone: string | null\n}) {\n const { enrollment, sequence, memberName, timeZone } = props\n const { enqueueSnackbar } = useSnackbar()\n const time = (ms: number | null | undefined) => formatOutreachTime(ms, timeZone)\n const leadHref = outreachCrmRecordHref('lead', enrollment.leadId, enrollment.hostId, props.orgMount)\n const contactHref = outreachCrmRecordHref('contact', enrollment.contactId, enrollment.hostId, props.orgMount)\n const clicks = outreachClickSummary(enrollment.engagement)\n const overrides = Object.entries(enrollment.stepOverrides ?? {}).sort(\n ([a], [b]) => Number(a) - Number(b),\n )\n const attested = OUTREACH_ATTESTATION_KINDS.filter((kind) => enrollment.attestations?.[kind])\n const threads = enrollment.gmailThreadIds.length\n ? enrollment.gmailThreadIds\n : enrollment.gmailThreadId\n ? [enrollment.gmailThreadId]\n : []\n const copyId = () => {\n void navigator.clipboard\n ?.writeText(enrollment.id)\n .then(() => enqueueSnackbar('Enrollment id copied.', { variant: 'success' }))\n .catch(() => enqueueSnackbar('The id could not be copied.', { variant: 'error' }))\n }\n const link = (href: string | null, label: string) =>\n href ? (\n <Link {...({ component: AppLink, componentVariant: 'naked' } as object)} href={href} underline=\"hover\">\n {label}\n </Link>\n ) : (\n label\n )\n\n return (\n <Box\n component=\"dl\"\n sx={{\n m: 0,\n display: 'grid',\n gridTemplateColumns: { xs: '1fr', sm: 'minmax(160px, 220px) 1fr' },\n columnGap: 2,\n rowGap: 1.25,\n }}\n >\n <Fact label=\"Personal line\">\n {enrollment.personalLine ? (\n <Typography variant=\"body2\" sx={{ whiteSpace: 'pre-wrap' }}>\n {enrollment.personalLine}\n </Typography>\n ) : (\n '—'\n )}\n </Fact>\n <Fact label=\"Enrolled as\">\n {enrollment.target === 'lead' ? (\n link(leadHref, 'Lead')\n ) : enrollment.leadId ? (\n <>\n {link(contactHref, 'Contact')}\n {', converted from a '}\n {link(leadHref, 'lead')}\n </>\n ) : (\n link(contactHref, 'Contact')\n )}\n </Fact>\n <Fact label=\"Enrolled\">\n {`${time(enrollment.createdAtMs)}${enrollment.enrolledByUid ? ` by ${memberName(enrollment.enrolledByUid)}` : ''}`}\n </Fact>\n <Fact label=\"Cold contact\">\n {enrollment.cold\n ? 'Yes — no inbound capture behind them, so the member confirmed the address before enrolling'\n : 'No'}\n </Fact>\n <Fact label=\"Attestations\">\n {attested.length ? (\n <Stack component=\"ul\" spacing={0.25} sx={{ m: 0, pl: 2.5 }}>\n {attested.map((kind) => {\n const entry = enrollment.attestations?.[kind]\n return (\n <li key={kind}>\n {`${OUTREACH_ATTESTATION_LABELS[kind]} — ${memberName(entry?.uid ?? '')}, ${time(entry?.atMs)}`}\n </li>\n )\n })}\n </Stack>\n ) : (\n '—'\n )}\n </Fact>\n <Fact label=\"Mailbox\">\n {props.mailbox\n ? `${props.mailbox.sendAs || props.mailbox.email}${props.mailbox.sendAs && props.mailbox.sendAs !== props.mailbox.email ? ` (${props.mailbox.email})` : ''}`\n : enrollment.mailboxId\n ? 'No longer connected'\n : '—'}\n </Fact>\n <Fact label=\"Campaigns\">\n {enrollment.campaignIds?.length\n ? enrollment.campaignIds.map(props.campaignName).join(', ')\n : '—'}\n </Fact>\n <Fact label=\"Mail gateway\">\n {props.gateway ? gatewaySentence(props.gateway, timeZone) : props.gatewayUnread}\n </Fact>\n <Fact label=\"Gateway hold\">\n {enrollment.gatewayHold\n ? [\n OUTREACH_MAIL_GATEWAY_LABELS[enrollment.gatewayHold.gateway],\n enrollment.gatewayHold.heldAtMs ? `held ${time(enrollment.gatewayHold.heldAtMs)}` : 'never held',\n enrollment.gatewayHold.releasedAtMs\n ? `released ${time(enrollment.gatewayHold.releasedAtMs)}${enrollment.gatewayHold.releasedByUid ? ` by ${memberName(enrollment.gatewayHold.releasedByUid)}` : ''}`\n : 'not released',\n ].join(' · ')\n : '—'}\n {enrollment.gatewayDeliveredSteps\n ? ` (${enrollment.gatewayDeliveredSteps} of their emails counted as delivered on the gateway ledger)`\n : null}\n </Fact>\n <Fact label=\"Clicks\">\n {clicks.clicks || clicks.machineClicks\n ? [\n `${clicks.clicks} by the person`,\n `${clicks.machineClicks} by scanners, not counted`,\n `${clicks.clicks - clicks.unloggedClicks + clicks.machineClicks - clicks.unloggedMachineClicks} listed one by one`,\n enrollment.engagement?.firstClickAtMs ? `first ${time(enrollment.engagement.firstClickAtMs)}` : null,\n enrollment.engagement?.lastClickAtMs ? `last ${time(enrollment.engagement.lastClickAtMs)}` : null,\n ]\n .filter(Boolean)\n .join(' · ')\n : '—'}\n {clicks.followed.length ? (\n <Box sx={{ mt: 0.5 }}>\n {clicks.followed.map((url) => (\n <Destination key={url} url={url} />\n ))}\n </Box>\n ) : null}\n </Fact>\n <Fact label=\"Curated steps\">\n {overrides.length ? (\n <Stack spacing={1.5}>\n {overrides.map(([key, override]) => (\n <Box key={key}>\n <Typography variant=\"body2\" sx={{ fontWeight: 500 }}>\n {outreachStepName(sequence.steps, Number(key))}\n </Typography>\n <Typography variant=\"caption\" color=\"text.secondary\" component=\"div\">\n {[\n override.source === 'ai' ? (override.edited ? 'AI draft, edited' : 'AI draft') : 'Written by a member',\n override.draftedByUid ? `confirmed by ${memberName(override.draftedByUid)}` : null,\n override.draftedAtMs ? time(override.draftedAtMs) : null,\n override.model ? `model ${override.model}` : null,\n ]\n .filter(Boolean)\n .join(' · ')}\n </Typography>\n {override.subject !== undefined ? (\n <Typography variant=\"body2\">{`Subject: ${override.subject}`}</Typography>\n ) : null}\n {override.body !== undefined ? (\n <Typography\n variant=\"body2\"\n sx={{ whiteSpace: 'pre-wrap', mt: 0.5, pl: 1.5, borderLeft: 2, borderColor: 'divider' }}\n >\n {override.body}\n </Typography>\n ) : null}\n {override.prompt ? (\n <Typography variant=\"caption\" color=\"text.secondary\" component=\"div\" sx={{ whiteSpace: 'pre-wrap', mt: 0.5 }}>\n {`Prompt: ${override.prompt}`}\n </Typography>\n ) : null}\n </Box>\n ))}\n </Stack>\n ) : (\n '—'\n )}\n </Fact>\n <Fact label={outreachThreadOpensInGmail(props.mailbox) ? 'Gmail threads' : 'Threads'}>\n {threads.length ? (\n <Stack spacing={0.25}>\n {threads.map((thread) => (\n <span key={thread}>\n {outreachThreadOpensInGmail(props.mailbox) ? (\n <Link\n href={outreachGmailThreadUrl(thread, props.mailbox?.email)}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n underline=\"hover\"\n >\n {thread}\n </Link>\n ) : (\n <Box component=\"span\" sx={{ wordBreak: 'break-all' }}>\n {thread}\n </Box>\n )}\n {thread === enrollment.gmailThreadId ? ' (current)' : null}\n </span>\n ))}\n {enrollment.threadSubject ? (\n <Typography variant=\"caption\" color=\"text.secondary\">{`Started as “${enrollment.threadSubject}”`}</Typography>\n ) : null}\n {enrollment.messageIds.length ? (\n <Typography variant=\"caption\" color=\"text.secondary\" sx={{ wordBreak: 'break-all' }}>\n {`Message-IDs in the current thread: ${enrollment.messageIds.join(' ')}`}\n </Typography>\n ) : null}\n </Stack>\n ) : (\n '—'\n )}\n </Fact>\n <Fact label=\"Stop\">\n {enrollment.stopReason\n ? `${outreachStopLabel(enrollment)} · ${time(enrollment.stoppedAtMs)}${enrollment.stoppedByUid ? ` · by ${memberName(enrollment.stoppedByUid)}` : ''}`\n : '—'}\n </Fact>\n <Fact label=\"Created · updated\">{`${time(enrollment.createdAtMs)} · ${time(enrollment.updatedAtMs)}`}</Fact>\n <Fact label=\"Enrollment id\">\n <Stack direction=\"row\" spacing={0.5} sx={{ alignItems: 'center' }}>\n <Typography variant=\"body2\" sx={{ fontFamily: 'monospace', wordBreak: 'break-all' }}>\n {enrollment.id}\n </Typography>\n <Tooltip title=\"Copy the id\">\n <IconButton size=\"small\" aria-label=\"Copy the enrollment id\" onClick={copyId}>\n <MdiIcon path={mdiContentCopy.path} fontSize=\"small\" />\n </IconButton>\n </Tooltip>\n </Stack>\n </Fact>\n </Box>\n )\n}\n\nexport function OutreachEnrollmentDetail(props: OutreachEnrollmentDetailProps) {\n const { orgId, sectionPath, sequenceId, enrollmentId, orgMount } = props\n const api = useOutreachApi(orgId)\n const loadedSequence = useOutreachSequence(orgId, sequenceId)\n const loaded = useOutreachEnrollment(orgId, enrollmentId)\n const history = useOutreachEnrollmentHistory(orgId, enrollmentId)\n const gateway = useOutreachEnrollmentGateway(api, enrollmentId)\n const roster = useOrgMemberOptions(orgId, { enabled: true })\n const [detailsOpen, setDetailsOpen] = useState(false)\n const nowMs = useOutreachNowMs()\n const enrollment = loaded.data\n const sequence = loadedSequence.data\n const campaigns = useOrgContainerOptions('campaign', orgId, {\n enabled: detailsOpen && Boolean(enrollment?.campaignIds?.length),\n })\n const steps = useMemo(() => sequence?.steps ?? [], [sequence])\n const actions = useOutreachEnrollmentActions({ api, steps })\n\n const memberName = useCallback(\n (uid: string) => roster.options.find((option) => option.uid === uid)?.label ?? 'a member',\n [roster.options],\n )\n const campaignName = useCallback(\n (id: string) => campaigns.options.find((option) => option.value === id)?.label ?? id,\n [campaigns.options],\n )\n\n const enrollmentsPath = `${sectionPath}/${sequenceId}/enrollments`\n const mailbox =\n props.mailboxes.mailboxes.find((entry) => entry.id === (enrollment?.mailboxId || sequence?.mailboxId)) ?? null\n const timeZone = mailbox?.timezone ?? null\n const time = (ms: number | null | undefined) => formatOutreachTime(ms, timeZone)\n const timeline = useMemo(\n () =>\n enrollment\n ? outreachEnrollmentTimeline({\n enrollment,\n steps,\n history: history.status === 'ready' ? history.data : null,\n memberName,\n formatTime: (ms) => formatOutreachTime(ms, timeZone),\n gateway: gateway.data?.intel?.gateway ?? null,\n })\n : [],\n [enrollment, steps, history, memberName, timeZone, gateway.data],\n )\n\n const back = (\n <Button\n // A real link, as the CRM record header's is: it opens in a new tab when asked.\n {...({ component: AppLink, componentVariant: 'naked', nativeButton: false } as object)}\n href={enrollmentsPath}\n size=\"small\"\n color=\"primary\"\n >\n Back to enrollments\n </Button>\n )\n\n if (loaded.status === 'loading' || loadedSequence.status === 'loading') {\n return <OutreachLoading label=\"Loading this person…\" />\n }\n if (loaded.status === 'error' || loaded.status === 'refused') {\n return <OutreachLoadProblem status={loaded.status} what=\"enrollment\" />\n }\n if (loadedSequence.status === 'error' || loadedSequence.status === 'refused') {\n return <OutreachLoadProblem status={loadedSequence.status} what=\"sequence\" />\n }\n // An id from another sequence reads as not here: the URL names both.\n if (!enrollment || !sequence || enrollment.sequenceId !== sequenceId) {\n return (\n <Card variant=\"outlined\">\n <EmptyStateComponent\n label=\"This person isn’t in this sequence\"\n description=\"They may have been removed from the workspace, or the link names a different sequence.\"\n action={back}\n />\n </Card>\n )\n }\n\n const name = enrollment.contactName || enrollment.email\n const kind = enrollment.target === 'lead' ? 'lead' : 'contact'\n const recordHref = outreachCrmRecordHref(\n kind,\n kind === 'lead' ? enrollment.leadId : enrollment.contactId,\n enrollment.hostId,\n orgMount,\n )\n const figures = outreachEnrollmentFigures(enrollment)\n const trackClicks = sequence.settings.trackClicks || sequence.stats?.clickTracked === true\n // Opens are shown for a sequence that counts them or once did (AGL-3395),\n // and for a person with any recorded, whatever the sequence says now.\n const countOpens =\n sequence.settings.countOpens ||\n sequence.stats?.openTracked === true ||\n figures.opens > 0 ||\n figures.machineOpens > 0\n const open = enrollment.status === 'active' || enrollment.status === 'paused'\n const held = enrollment.status === 'paused' && enrollment.stopReason === 'gateway_blocked_here'\n\n /*\n * The one act that moves the person forward is the button: resuming a\n * paused one, else curating the next email. Everything else is in the\n * menu, the destructive acts included, as on every record page.\n */\n const available = outreachEnrollmentActionsFor(enrollment, steps)\n const primary: OutreachEnrollmentRowAction | null = available.includes('resume')\n ? 'resume'\n : available.includes('curate')\n ? 'curate'\n : null\n const menu = actions.menuItems(enrollment, (action) => action !== primary)\n const dash = (value: number) => (value ? value.toLocaleString() : '—')\n const notTracked = !trackClicks && !figures.clicks && !figures.scannerClicks ? 'Not tracked' : undefined\n const thread = enrollment.gmailThreadId ?? enrollment.gmailThreadIds.at(-1) ?? null\n const nextSend = outreachNextSendState({\n enrollment,\n sequence,\n mailbox: props.mailboxes.status === 'ready' ? mailbox : undefined,\n nowMs,\n })\n const nothingYet =\n enrollment.status === 'active' && enrollment.nextDueAtMs\n ? nextSend.kind === 'queued'\n ? `Nothing yet — step ${enrollment.stepIndex + 1} is due and queued to send.`\n : `Nothing yet — step ${enrollment.stepIndex + 1} sends ${time(enrollment.nextDueAtMs)}.`\n : 'Nothing yet.'\n\n return (\n <Stack spacing={2}>\n {/* The page heading and the trail name the person; the card says what they are in. */}\n <PageHeaderRecord title={name} />\n <CardDisplay\n header=\"Enrollment\"\n subheader={\n <>\n {enrollment.contactName ? `${enrollment.email} · ` : ''}\n {`In ${sequence.name || 'Untitled'}`}\n </>\n }\n help={pluginDocsHelp('sequences', { anchor: '#person-history' })}\n contentGutterX\n contentGutterY\n HeaderProps={{\n action: (\n <Stack useFlexGap direction=\"row\" spacing={1} sx={{ alignItems: 'center', flexWrap: 'wrap', rowGap: 1 }}>\n {back}\n {primary ? (\n <Button\n variant=\"outlined\"\n size=\"small\"\n disabled={actions.busy === enrollment.id}\n onClick={() => actions.choose(enrollment, primary)}\n >\n {held ? 'Resume and send' : OUTREACH_ENROLLMENT_ACTION_LABELS[primary]}\n </Button>\n ) : null}\n {menu.length ? <RowActionsMenu label={name} items={menu} /> : null}\n </Stack>\n ),\n }}\n >\n <Stack spacing={2}>\n <Stack useFlexGap direction=\"row\" spacing={1} sx={{ alignItems: 'center', flexWrap: 'wrap', rowGap: 1 }}>\n <Tooltip\n describeChild\n title={recordHref ? `Open the ${kind} in the CRM` : `The ${kind}’s record can’t be linked`}\n >\n <Chip\n size=\"small\"\n variant=\"outlined\"\n color={recordHref ? 'primary' : 'default'}\n icon={<MdiIcon path={mdiAccountOutline.path} fontSize=\"small\" />}\n label={kind === 'lead' ? 'Lead' : 'Contact'}\n {...(recordHref\n ? ({ component: AppLink, href: recordHref, clickable: true, componentVariant: 'naked' } as object)\n : {})}\n />\n </Tooltip>\n <OutreachEnrollmentStatusChip status={enrollment.status} />\n <Chip size=\"small\" variant=\"outlined\" label={outreachCurrentStepLabel(enrollment, steps)} />\n {outreachStepIsCurated(enrollment) ? (\n <Chip size=\"small\" variant=\"outlined\" color=\"success\" label=\"Curated\" />\n ) : null}\n {open && enrollment.nextDueAtMs ? (\n nextSend.kind === 'queued' ? (\n <Tooltip describeChild title={outreachNextSendDetail(nextSend, timeZone)}>\n <Chip\n size=\"small\"\n variant=\"outlined\"\n color={\n nextSend.reason === 'mailbox_not_sending' || nextSend.reason === 'sequence_not_active'\n ? 'warning'\n : 'default'\n }\n label={`Next send ${outreachNextSendLabel(nextSend, timeZone)}`}\n />\n </Tooltip>\n ) : (\n <Chip size=\"small\" variant=\"outlined\" label={`Next send ${time(enrollment.nextDueAtMs)}`} />\n )\n ) : null}\n </Stack>\n {held ? (\n <Alert severity=\"warning\">\n {enrollment.stopDetail ||\n 'Their mail gateway refused this sender, so the next email is held. Resume to send it anyway.'}\n </Alert>\n ) : null}\n {figures.anything ? (\n <Stack useFlexGap direction=\"row\" spacing={3} sx={{ flexWrap: 'wrap', rowGap: 2 }} role=\"group\" aria-label=\"In numbers\">\n <OutreachFigure label=\"Emails sent\" value={dash(figures.emailsSent)} />\n {countOpens ? (\n <OutreachFigure\n label=\"Opens\"\n value={dash(figures.opens)}\n hint={figures.machineOpens ? `${figures.machineOpens.toLocaleString()} by machines, not counted` : undefined}\n />\n ) : null}\n <OutreachFigure label=\"Clicks\" value={dash(figures.clicks)} hint={notTracked} />\n <OutreachFigure\n label=\"Links followed\"\n value={\n figures.linksFollowed.count\n ? `${figures.linksFollowed.count}${figures.linksFollowed.atLeast ? '+' : ''}`\n : '—'\n }\n hint={\n notTracked ??\n (figures.linksFollowed.atLeast && figures.linksFollowed.count\n ? 'Earlier clicks kept the last link only'\n : undefined)\n }\n />\n <OutreachFigure label=\"Scanner clicks\" value={dash(figures.scannerClicks)} hint={notTracked ?? 'Not counted'} />\n <OutreachFigure label=\"Replies\" value={dash(figures.replies)} />\n </Stack>\n ) : (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {nothingYet}\n </Typography>\n )}\n </Stack>\n </CardDisplay>\n\n <CardDisplay\n header=\"Activity\"\n subheader=\"Newest first\"\n help={pluginDocsHelp('sequences', { anchor: '#person-activity' })}\n contentGutterX\n contentGutterY\n HeaderProps={\n thread && outreachThreadOpensInGmail(mailbox)\n ? {\n action: (\n <Button\n size=\"small\"\n href={outreachGmailThreadUrl(thread, mailbox?.email)}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n Open thread in Gmail\n </Button>\n ),\n }\n : undefined\n }\n >\n <Stack spacing={1}>\n {history.status === 'loading' ? <OutreachLoading label=\"Loading their history…\" /> : null}\n {history.status === 'error' || history.status === 'refused' ? (\n <OutreachLoadProblem\n status={history.status}\n what=\"list of their clicks\"\n // Only the one-by-one list is missing: the totals, the sends and\n // every stop above come from the enrollment, which was read.\n message={\n history.status === 'refused'\n ? 'Their clicks can’t be listed one by one here; the numbers above still count them.'\n : 'Their clicks couldn’t be listed one by one. Reload the page to try again.'\n }\n />\n ) : null}\n <List disablePadding aria-label=\"Activity\">\n {timeline.map((entry, index) => (\n <TimelineRow\n key={entry.key}\n entry={entry}\n timeZone={timeZone}\n mailboxEmail={mailbox?.email ?? null}\n threadsOpenInGmail={outreachThreadOpensInGmail(mailbox)}\n divider={index < timeline.length - 1}\n />\n ))}\n </List>\n </Stack>\n </CardDisplay>\n\n <CardDisplay\n header=\"Details\"\n help={pluginDocsHelp('sequences', { anchor: '#person-details' })}\n contentGutterX\n HeaderProps={{\n action: (\n <Button\n size=\"small\"\n aria-expanded={detailsOpen}\n aria-controls=\"outreach-enrollment-details\"\n endIcon={<MdiIcon path={(detailsOpen ? mdiChevronUp : mdiChevronDown).path} fontSize=\"small\" />}\n onClick={() => setDetailsOpen((was) => !was)}\n >\n {detailsOpen ? 'Hide' : 'Show'}\n </Button>\n ),\n }}\n >\n <Collapse in={detailsOpen} unmountOnExit>\n <Box id=\"outreach-enrollment-details\" sx={{ pb: 2 }}>\n <Divider sx={{ mb: 2 }} />\n <EnrollmentDetails\n enrollment={enrollment}\n sequence={sequence}\n mailbox={mailbox}\n gateway={gateway.status === 'ready' ? gateway.data : null}\n gatewayUnread={\n gateway.status === 'loading'\n ? 'Looking it up…'\n : gateway.status === 'refused'\n ? 'Your role cannot look it up'\n : 'Could not be looked up'\n }\n campaignName={campaignName}\n memberName={memberName}\n orgMount={orgMount}\n timeZone={timeZone}\n />\n </Box>\n </Collapse>\n </CardDisplay>\n\n {actions.dialogs}\n </Stack>\n )\n}\nOutreachEnrollmentDetail.displayName = 'OutreachEnrollmentDetail'\n\nexport default OutreachEnrollmentDetail\n"],"names":["PageHeaderRecord","pluginDocsHelp","pluginRecordHref","mdiAccountCancelOutline","mdiAccountOutline","mdiAccountPlusOutline","mdiAlertCircleOutline","mdiCheckCircleOutline","mdiChevronDown","mdiChevronUp","mdiClipboardCheckOutline","mdiContentCopy","mdiCursorDefaultClickOutline","mdiEmailAlertOutline","mdiEmailOffOutline","mdiEmailOpenOutline","mdiEmailOutline","mdiHandBackLeftOutline","mdiPauseCircleOutline","mdiPencilOutline","mdiPlayCircleOutline","mdiReply","mdiShieldSearch","mdiSkipNext","mdiStopCircleOutline","AppLink","CardDisplay","MdiIcon","EmptyStateComponent","RowActionsMenu","useSnackbar","useOrgContainerOptions","useOrgMemberOptions","Alert","Box","Button","Card","Chip","Collapse","Divider","IconButton","Link","List","ListItem","ListItemIcon","ListItemText","Stack","Tooltip","Typography","useCallback","useMemo","useState","OUTREACH_MAIL_GATEWAY_LABELS","outreachNextSendState","outreachClickSummary","outreachEnrollmentFigures","outreachEnrollmentTimeline","outreachStepName","OUTREACH_ATTESTATION_KINDS","OUTREACH_ATTESTATION_LABELS","OUTREACH_ENROLLMENT_ACTION_LABELS","outreachEnrollmentActionsFor","useOutreachEnrollmentActions","outreachCurrentStepLabel","outreachStepIsCurated","outreachStopLabel","formatOutreachTime","OutreachEnrollmentStatusChip","OutreachLoading","OutreachLoadProblem","outreachNextSendDetail","outreachNextSendLabel","useOutreachNowMs","OutreachFigure","useOutreachApi","useOutreachSequence","useOutreachEnrollment","useOutreachEnrollmentGateway","useOutreachEnrollmentHistory","outreachCrmRecordHref","kind","id","hostId","orgMount","orgSlug","host","hosts","find","entry","subdomain","outreachThreadOpensInGmail","mailbox","provider","outreachGmailThreadUrl","threadId","mailboxEmail","account","encodeURIComponent","KIND_ICONS","enrolled","skipped","curated","sent","task","click","scanner","open","paused","resumed","stopped","replied","bounced","held","released","failed","finished","TONE_COLORS","default","success","info","warning","error","Destination","props","variant","component","sx","display","wordBreak","label","href","url","target","rel","underline","TimelineRow","alignItems","divider","disableGutters","data-kind","minWidth","mt","color","tone","path","fontSize","disableTypography","primary","direction","xs","sm","spacing","justifyContent","fontWeight","title","whiteSpace","atMs","timeZone","secondary","urlLabel","detail","facts","length","gmailThreadId","threadsOpenInGmail","join","Fact","m","typography","children","gatewaySentence","answer","intel","standing","status","domain","resolvedAtMs","from","sendingDomain","parts","gateway","mx","delivered30","blocked30","filter","Boolean","EnrollmentDetails","enrollment","sequence","memberName","enqueueSnackbar","time","ms","leadHref","leadId","contactHref","contactId","clicks","engagement","overrides","Object","entries","stepOverrides","sort","a","b","Number","attested","attestations","threads","gmailThreadIds","copyId","navigator","clipboard","writeText","then","catch","link","componentVariant","gridTemplateColumns","columnGap","rowGap","personalLine","createdAtMs","enrolledByUid","cold","pl","map","li","uid","sendAs","email","mailboxId","campaignIds","campaignName","gatewayUnread","gatewayHold","heldAtMs","releasedAtMs","releasedByUid","gatewayDeliveredSteps","machineClicks","unloggedClicks","unloggedMachineClicks","firstClickAtMs","lastClickAtMs","followed","key","override","steps","source","edited","draftedByUid","draftedAtMs","model","subject","undefined","body","borderLeft","borderColor","prompt","thread","span","threadSubject","messageIds","stopReason","stoppedAtMs","stoppedByUid","updatedAtMs","fontFamily","size","aria-label","onClick","OutreachEnrollmentDetail","orgId","sectionPath","sequenceId","enrollmentId","api","loadedSequence","loaded","history","roster","enabled","detailsOpen","setDetailsOpen","nowMs","data","campaigns","actions","options","option","value","enrollmentsPath","mailboxes","timezone","timeline","formatTime","back","nativeButton","what","description","action","name","contactName","recordHref","figures","trackClicks","settings","stats","clickTracked","countOpens","openTracked","opens","machineOpens","available","includes","menu","menuItems","dash","toLocaleString","notTracked","scannerClicks","at","nextSend","nothingYet","nextDueAtMs","stepIndex","header","subheader","help","anchor","contentGutterX","contentGutterY","HeaderProps","useFlexGap","flexWrap","disabled","busy","choose","items","describeChild","icon","clickable","reason","severity","stopDetail","anything","role","emailsSent","hint","linksFollowed","count","atLeast","replies","message","disablePadding","index","aria-expanded","aria-controls","endIcon","was","in","unmountOnExit","pb","mb","dialogs","displayName"],"mappings":"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"}
@@ -304,7 +304,7 @@ const draftOf = (mailbox)=>{
304
304
  header: mailbox.email,
305
305
  subheader: isMine ? 'Your mailbox' : 'A teammate’s mailbox',
306
306
  help: pluginDocsHelp('sequences', {
307
- anchor: '#connect-a-mailbox'
307
+ anchor: '#mailbox-actions'
308
308
  }),
309
309
  contentGutterX: true,
310
310
  contentGutterY: true,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../../libs/plugins/outreach/src/lib/components/mailbox-card.tsx"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n'use client'\n\nimport { pluginDocsHelp } from '@aglyn/aglyn'\nimport { CardDisplay, useConfirmationContext } from '@aglyn/shared-ui-jsx'\nimport { useSnackbar } from '@aglyn/shared-ui-snackstack'\nimport SenderReadinessPanel from '@aglyn/tenant-feature-instance/components/sender-readiness-panel'\nimport {\n Alert,\n Autocomplete,\n Box,\n Button,\n Chip,\n FormControlLabel,\n FormHelperText,\n MenuItem,\n Stack,\n Switch,\n TextField,\n ToggleButton,\n ToggleButtonGroup,\n Typography,\n} from '@mui/material'\nimport { useEffect, useMemo, useRef, useState } from 'react'\nimport {\n formatMinuteOfDay,\n isValidTimezone,\n OUTREACH_DEFAULT_WINDOW,\n OUTREACH_MAILBOX_STATUS_LABELS,\n OUTREACH_MAX_DAILY_CAP,\n OUTREACH_RAMP_STEPS,\n OUTREACH_WEEKDAY_LABELS,\n outreachEffectiveDailyCap,\n outreachLocalDay,\n summarizeMailboxHealth,\n validateDailyCap,\n validateDisplayName,\n validateSendWindow,\n} from '../mailboxes/mailbox-settings'\nimport type { OutreachMailboxReadinessResponse } from '../mailboxes/mailbox-api'\nimport type {\n OutreachMailbox,\n OutreachMailboxStatus,\n OutreachSendWindow,\n} from '../model/outreach.types'\nimport { outreachPacingNote } from './next-send'\nimport type { OutreachMailboxApi } from './use-outreach-mailbox-api'\n\nexport interface MailboxCardProps {\n mailbox: OutreachMailbox\n /** The viewer is the member who connected it. */\n isMine: boolean\n /** The viewer may change, pause and disconnect it: its member, or an org owner or admin. */\n canManage: boolean\n api: OutreachMailboxApi\n /** Starts a new connect with the mailbox's provider, for a mailbox that needs reconnecting. */\n onReconnect(): void\n /** True while that connect is on its way to the provider. */\n reconnecting?: boolean\n /** The clock the health window and today's limit are read on. */\n nowMs?: number\n}\n\n/**\n * What the card says about a mailbox that paused ITSELF (AGL-2981): the\n * engine's own sentence, when it paused, and — after a complaint — the day\n * resuming stops being premature. Nothing sends from it until a member\n * resumes it.\n */\nexport function autoPauseSentence(mailbox: Pick<OutreachMailbox, 'autoPause' | 'timezone'>): string {\n const pause = mailbox.autoPause\n if (!pause) return ''\n const day = (atMs: number) => {\n try {\n return new Intl.DateTimeFormat('en-US', { dateStyle: 'medium', timeZone: mailbox.timezone }).format(atMs)\n } catch {\n return new Intl.DateTimeFormat('en-US', { dateStyle: 'medium', timeZone: 'UTC' }).format(atMs)\n }\n }\n const until = typeof pause.untilMs === 'number' ? ` Wait until ${day(pause.untilMs)} before resuming it.` : ''\n return `Sequences paused this mailbox on ${day(pause.atMs)}. ${pause.message}${until} Nothing sends from it until it is resumed.`\n}\n\n/** Accessible names of the card's actions, spelled once for the specs. */\nexport const MAILBOX_ACTION_LABELS = {\n save: 'Save settings',\n pause: 'Pause',\n resume: 'Resume',\n test: 'Send a test to myself',\n testElsewhere: 'Send a test',\n testAddress: 'Test address',\n warmUp: 'Warm up gradually',\n disconnect: 'Disconnect',\n reconnect: 'Reconnect',\n recheckReadiness: 'Check DNS again',\n} as const\n\nconst WEEKDAY_NAMES = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']\n\nconst STATUS_COLOR: Record<OutreachMailboxStatus, 'success' | 'default' | 'warning' | 'error'> = {\n connected: 'success',\n paused: 'default',\n reconnect_required: 'warning',\n disconnected: 'error',\n}\n\n/** Every half hour of the day, and midnight at its end. */\nconst MINUTE_OPTIONS = Array.from({ length: 49 }, (_, index) => index * 30)\n\n/** The zones this runtime knows, the mailbox's own included whatever it is. */\nfunction timezoneOptions(current: string): string[] {\n const supported = (Intl as { supportedValuesOf?: (key: string) => string[] }).supportedValuesOf?.('timeZone') ?? []\n const zones = supported.length ? supported : ['UTC']\n return zones.includes(current) ? zones : [current, ...zones]\n}\n\n/** The ramp, as the cap's helper text reads it. */\nconst RAMP_SENTENCE = `Warm-up: ${OUTREACH_RAMP_STEPS.map((step, index) =>\n `week ${step.week}${index === OUTREACH_RAMP_STEPS.length - 1 ? '+' : ''}: ${step.limit}`,\n).join(' · ')} a day, never above the cap.`\n\ninterface Draft {\n sendAs: string\n displayName: string\n dailyCap: string\n window: OutreachSendWindow\n timezone: string\n /** Whether the warm-up ramp applies — `rampStartedAtMs` as a switch. */\n warmUp: boolean\n}\n\nconst draftOf = (mailbox: OutreachMailbox): Draft => ({\n sendAs: mailbox.sendAs ?? mailbox.email,\n displayName: mailbox.displayName ?? '',\n dailyCap: String(mailbox.dailyCap ?? ''),\n window: mailbox.window ?? OUTREACH_DEFAULT_WINDOW,\n timezone: mailbox.timezone ?? 'UTC',\n warmUp: typeof mailbox.rampStartedAtMs === 'number',\n})\n\n/**\n * One connected mailbox (AGL-2978): its account and status, its last seven\n * days, its settings, and pause, test and disconnect.\n *\n * Every control is offered only where the route will allow it: the settings\n * form and pause and disconnect to the member who connected the mailbox or an\n * org owner or admin, and the test and the reconnect to its member alone,\n * because both act in that member's own Google or Microsoft account.\n */\nexport function MailboxCard(props: MailboxCardProps) {\n const { mailbox, isMine, canManage, api, onReconnect, reconnecting = false, nowMs = Date.now() } = props\n const { enqueueSnackbar } = useSnackbar()\n const { confirm } = useConfirmationContext()\n const microsoft = mailbox.provider === 'microsoft'\n const providerName = microsoft ? 'Microsoft' : 'Google'\n const [draft, setDraft] = useState<Draft>(() => draftOf(mailbox))\n const [saving, setSaving] = useState(false)\n const [saveError, setSaveError] = useState<string | null>(null)\n const [busy, setBusy] = useState<'status' | 'test' | 'disconnect' | null>(null)\n // Where a test goes when not to the member themself (AGL-3228): a test to\n // one's own address never leaves the provider and shows no authentication result.\n const [testAddress, setTestAddress] = useState('')\n\n /*\n * SPF, DKIM and DMARC for the address this mailbox sends as (AGL-3328),\n * read by the server and remembered there briefly. Re-read when the\n * send-as address changes; a failed read shows nothing rather than a\n * verdict nobody made.\n */\n const sendAsAddress = mailbox.sendAs || mailbox.email\n const [readiness, setReadiness] = useState<OutreachMailboxReadinessResponse | null>(null)\n const [readinessBusy, setReadinessBusy] = useState(false)\n useEffect(() => {\n let active = true\n api\n .readiness(mailbox.id)\n .then((answer) => {\n if (active) setReadiness(answer)\n })\n .catch(() => {\n if (active) setReadiness(null)\n })\n return () => {\n active = false\n }\n }, [api, mailbox.id, sendAsAddress])\n const recheckReadiness = async () => {\n setReadinessBusy(true)\n try {\n setReadiness(await api.readiness(mailbox.id, true))\n } catch (error) {\n enqueueSnackbar((error as Error).message, { variant: 'error', allowDuplicate: true })\n } finally {\n setReadinessBusy(false)\n }\n }\n\n // A save here, a change made from another tab, or a reconnect rewrites the\n // stored settings; the form follows them, unless the member has unsaved\n // edits of their own, which are never thrown away.\n const stored = useMemo(() => draftOf(mailbox), [mailbox])\n const storedKey = JSON.stringify(stored)\n const seededFrom = useRef(storedKey)\n const dirty = JSON.stringify(draft) !== storedKey\n useEffect(() => {\n if (seededFrom.current === storedKey) return\n const previous = seededFrom.current\n seededFrom.current = storedKey\n setDraft((current) => (JSON.stringify(current) === previous ? stored : current))\n }, [storedKey, stored])\n\n const health = summarizeMailboxHealth(mailbox.health, mailbox.timezone, nowMs)\n // Tests of a sequence step sent today (AGL-3325): counted beside the\n // sends, never among them, so the cap and the seven-day sum stay honest.\n const testsToday = Math.max(\n 0,\n Number(mailbox.health?.daily?.[outreachLocalDay(nowMs, mailbox.timezone)]?.tests) || 0,\n )\n const needsReconnect = mailbox.status === 'reconnect_required' || mailbox.status === 'disconnected'\n const capCheck = validateDailyCap(draft.dailyCap === '' ? Number.NaN : Number(draft.dailyCap))\n const windowCheck = validateSendWindow(draft.window)\n const nameCheck = validateDisplayName(draft.displayName)\n const timezoneValid = isValidTimezone(draft.timezone)\n const invalid =\n typeof capCheck !== 'number' || !('days' in windowCheck) || typeof nameCheck !== 'string' || !timezoneValid\n const todayLimit = outreachEffectiveDailyCap(\n {\n dailyCap: typeof capCheck === 'number' ? capCheck : mailbox.dailyCap,\n // A ramp switched on in the draft reads as starting today.\n rampStartedAtMs: draft.warmUp ? (mailbox.rampStartedAtMs ?? nowMs) : null,\n timezone: timezoneValid ? draft.timezone : mailbox.timezone,\n },\n nowMs,\n )\n\n const save = async () => {\n setSaving(true)\n setSaveError(null)\n try {\n await api.saveSettings({\n mailboxId: mailbox.id,\n ...(draft.sendAs !== stored.sendAs ? { sendAs: draft.sendAs } : {}),\n ...(draft.displayName !== stored.displayName ? { displayName: draft.displayName } : {}),\n ...(draft.dailyCap !== stored.dailyCap ? { dailyCap: Number(draft.dailyCap) } : {}),\n ...(JSON.stringify(draft.window) !== JSON.stringify(stored.window) ? { window: draft.window } : {}),\n ...(draft.timezone !== stored.timezone ? { timezone: draft.timezone } : {}),\n ...(draft.warmUp !== stored.warmUp ? { warmUp: draft.warmUp } : {}),\n })\n enqueueSnackbar('Mailbox settings saved', { variant: 'success' })\n } catch (error) {\n setSaveError((error as Error).message)\n } finally {\n setSaving(false)\n }\n }\n\n const togglePaused = async () => {\n const paused = mailbox.status !== 'paused'\n setBusy('status')\n try {\n await api.setPaused(mailbox.id, paused)\n enqueueSnackbar(paused ? 'Mailbox paused' : 'Mailbox resumed', { variant: 'success' })\n } catch (error) {\n enqueueSnackbar((error as Error).message, { variant: 'error', allowDuplicate: true })\n } finally {\n setBusy(null)\n }\n }\n\n const sendTest = async () => {\n setBusy('test')\n try {\n const to = testAddress.trim()\n const sent = await api.sendTest(mailbox.id, to || undefined)\n enqueueSnackbar(\n to\n ? `Test sent to ${sent.sentTo}. Its original source shows whether the sender authenticated.`\n : `Test sent to ${sent.sentTo}. Check your inbox.`,\n { variant: 'success' },\n )\n } catch (error) {\n enqueueSnackbar((error as Error).message, { variant: 'error', allowDuplicate: true })\n } finally {\n setBusy(null)\n }\n }\n\n const disconnect = async () => {\n const confirmed = await confirm({\n title: 'Disconnect this mailbox?',\n description:\n (microsoft\n ? 'Disconnecting deletes the access stored for this mailbox. '\n : 'Disconnecting deletes the access stored for this mailbox and asks Google to revoke it. ') +\n 'Nothing is sent from it again unless it is connected again.',\n confirmationText: MAILBOX_ACTION_LABELS.disconnect,\n confirmationButtonProps: { color: 'error' },\n })\n .then(() => true)\n .catch(() => false)\n if (!confirmed) return\n setBusy('disconnect')\n try {\n const { revocation } = await api.disconnect(mailbox.id)\n if (revocation === 'failed') {\n enqueueSnackbar(\n 'Mailbox disconnected, but Google could not confirm the access was revoked. ' +\n 'Remove it from the Google Account’s third-party connections to be sure.',\n { variant: 'warning', persist: true },\n )\n } else if (revocation === 'unsupported') {\n enqueueSnackbar(\n 'Mailbox disconnected. To end the access at Microsoft too, remove the app at myapps.microsoft.com.',\n { variant: 'success' },\n )\n } else if (revocation === 'kept-for-other-mailbox') {\n enqueueSnackbar(\n 'Mailbox disconnected. Google access stays in place for another connected mailbox on the same account.',\n { variant: 'success' },\n )\n } else {\n enqueueSnackbar('Mailbox disconnected', { variant: 'success' })\n }\n } catch (error) {\n enqueueSnackbar((error as Error).message, { variant: 'error', allowDuplicate: true })\n setBusy(null)\n }\n }\n\n const sendAsLabel = (email: string) => {\n const option = mailbox.sendAsOptions?.find((entry) => entry.email === email)\n return option?.displayName ? `${option.displayName} <${option.email}>` : email\n }\n\n return (\n <CardDisplay\n header={mailbox.email}\n subheader={isMine ? 'Your mailbox' : 'A teammate’s mailbox'}\n help={pluginDocsHelp('sequences', { anchor: '#connect-a-mailbox' })}\n contentGutterX\n contentGutterY\n HeaderProps={{\n action: (\n <Chip\n size=\"small\"\n label={OUTREACH_MAILBOX_STATUS_LABELS[mailbox.status] ?? mailbox.status}\n color={STATUS_COLOR[mailbox.status] ?? 'default'}\n />\n ),\n }}\n >\n <Stack spacing={2}>\n {needsReconnect ? (\n <Alert\n severity=\"warning\"\n action={\n isMine ? (\n <Button color=\"inherit\" size=\"small\" disabled={reconnecting} onClick={onReconnect}>\n {MAILBOX_ACTION_LABELS.reconnect}\n </Button>\n ) : undefined\n }\n >\n {`${\n mailbox.status === 'disconnected'\n ? 'This mailbox was disconnected.'\n : `${providerName} stopped accepting this mailbox’s connection.`\n } ${\n isMine\n ? 'Nothing sends from it until you connect it again.'\n : 'Only the member who connected it can reconnect it.'\n }`}\n </Alert>\n ) : null}\n {mailbox.status === 'paused' && mailbox.autoPause ? (\n <Alert severity=\"error\" role=\"alert\">\n {autoPauseSentence(mailbox)}\n </Alert>\n ) : null}\n\n <Box>\n <Typography variant=\"subtitle2\">Last 7 days</Typography>\n {health.hasSent ? null : (\n <Typography variant=\"body2\" color=\"text.secondary\">\n No sends yet\n </Typography>\n )}\n <Stack direction=\"row\" spacing={3} sx={{ mt: 0.5 }}>\n {[\n ['Sent', health.sent],\n ['Bounces', health.bounces],\n ['Replies', health.replies],\n ].map(([label, value]) => (\n <Box key={label as string} aria-label={`${label} in the last 7 days`}>\n <Typography variant=\"h6\" component=\"p\">\n {value}\n </Typography>\n <Typography variant=\"caption\" color=\"text.secondary\">\n {label}\n </Typography>\n </Box>\n ))}\n </Stack>\n <Typography variant=\"caption\" color=\"text.secondary\" aria-label=\"Tests today\">\n {`Tests today: ${testsToday}`}\n </Typography>\n <Typography variant=\"caption\" color=\"text.secondary\" component=\"p\" aria-label=\"Pacing\">\n {outreachPacingNote(mailbox, nowMs)}\n </Typography>\n </Box>\n\n {readiness?.readiness ? (\n <Stack spacing={1}>\n <SenderReadinessPanel readiness={readiness.readiness} />\n <Box>\n <Button size=\"small\" disabled={readinessBusy} onClick={() => void recheckReadiness()}>\n {MAILBOX_ACTION_LABELS.recheckReadiness}\n </Button>\n </Box>\n </Stack>\n ) : readiness ? (\n <Typography variant=\"caption\" color=\"text.secondary\">\n {`${providerName} authenticates mail from ${readiness.sendAs.slice(readiness.sendAs.lastIndexOf('@') + 1)} ` +\n 'itself, so there are no records to publish for this address.'}\n </Typography>\n ) : null}\n\n {canManage ? (\n <Stack spacing={2} component=\"form\" onSubmit={(event) => event.preventDefault()}>\n <TextField\n select\n size=\"small\"\n label=\"Send as\"\n value={draft.sendAs}\n onChange={(event) => setDraft({ ...draft, sendAs: event.target.value })}\n helperText=\"Addresses Gmail has verified for this account.\"\n >\n {(mailbox.sendAsOptions?.length ? mailbox.sendAsOptions : [{ email: mailbox.sendAs }]).map((option) => (\n <MenuItem key={option.email} value={option.email}>\n {sendAsLabel(option.email)}\n </MenuItem>\n ))}\n </TextField>\n <TextField\n size=\"small\"\n label=\"Display name\"\n value={draft.displayName}\n onChange={(event) => setDraft({ ...draft, displayName: event.target.value })}\n error={typeof nameCheck !== 'string'}\n helperText={typeof nameCheck !== 'string' ? nameCheck.message : 'The name recipients see beside the address.'}\n />\n <TextField\n size=\"small\"\n type=\"number\"\n label=\"Daily cap\"\n value={draft.dailyCap}\n onChange={(event) => setDraft({ ...draft, dailyCap: event.target.value })}\n error={typeof capCheck !== 'number'}\n slotProps={{ htmlInput: { min: 1, max: OUTREACH_MAX_DAILY_CAP, step: 1 } }}\n helperText={\n typeof capCheck !== 'number'\n ? capCheck.message\n : draft.warmUp\n ? `${RAMP_SENTENCE} Today’s limit: ${todayLimit}.`\n : `No warm-up: today’s limit is the cap, ${todayLimit}.`\n }\n />\n <FormControlLabel\n control={\n <Switch\n checked={draft.warmUp}\n onChange={(event) => setDraft({ ...draft, warmUp: event.target.checked })}\n />\n }\n label={MAILBOX_ACTION_LABELS.warmUp}\n />\n <FormHelperText sx={{ mt: -1 }}>\n {'For a mailbox that is new or has not sent much. One that has sent mail for years already has ' +\n 'its reputation and can start at its cap.'}\n </FormHelperText>\n <Box>\n <Typography variant=\"subtitle2\" gutterBottom>\n Sending window\n </Typography>\n <ToggleButtonGroup\n size=\"small\"\n aria-label=\"Sending days\"\n value={draft.window.days}\n onChange={(_event, days: number[]) =>\n setDraft({ ...draft, window: { ...draft.window, days: [...days].sort((a, b) => a - b) } })\n }\n >\n {OUTREACH_WEEKDAY_LABELS.map((label, day) => (\n <ToggleButton key={label} value={day} aria-label={WEEKDAY_NAMES[day]}>\n {label}\n </ToggleButton>\n ))}\n </ToggleButtonGroup>\n <Stack direction={{ xs: 'column', sm: 'row' }} spacing={2} sx={{ mt: 2 }}>\n <TextField\n select\n size=\"small\"\n label=\"From\"\n value={draft.window.startMinute}\n onChange={(event) =>\n setDraft({ ...draft, window: { ...draft.window, startMinute: Number(event.target.value) } })\n }\n >\n {MINUTE_OPTIONS.slice(0, -1).map((minute) => (\n <MenuItem key={minute} value={minute}>\n {formatMinuteOfDay(minute)}\n </MenuItem>\n ))}\n </TextField>\n <TextField\n select\n size=\"small\"\n label=\"Until\"\n value={draft.window.endMinute}\n onChange={(event) =>\n setDraft({ ...draft, window: { ...draft.window, endMinute: Number(event.target.value) } })\n }\n >\n {MINUTE_OPTIONS.slice(1).map((minute) => (\n <MenuItem key={minute} value={minute}>\n {formatMinuteOfDay(minute)}\n </MenuItem>\n ))}\n </TextField>\n <Autocomplete\n size=\"small\"\n disableClearable\n options={timezoneOptions(mailbox.timezone)}\n value={draft.timezone}\n onChange={(_event, timezone) => setDraft({ ...draft, timezone: timezone ?? draft.timezone })}\n sx={{ minWidth: 240 }}\n renderInput={(params) => <TextField {...params} label=\"Timezone\" />}\n />\n </Stack>\n {'days' in windowCheck ? null : <FormHelperText error>{windowCheck.message}</FormHelperText>}\n </Box>\n {saveError ? <FormHelperText error>{saveError}</FormHelperText> : null}\n <Box>\n <Button variant=\"contained\" disabled={!dirty || invalid || saving} onClick={() => void save()}>\n {MAILBOX_ACTION_LABELS.save}\n </Button>\n </Box>\n </Stack>\n ) : (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {`Sends as ${sendAsLabel(stored.sendAs)}, at most ${stored.dailyCap} a day, ` +\n `${stored.window.days.map((day) => OUTREACH_WEEKDAY_LABELS[day]).join(', ')} ` +\n `${formatMinuteOfDay(stored.window.startMinute)}–${formatMinuteOfDay(stored.window.endMinute)} ` +\n `(${stored.timezone}).`}\n </Typography>\n )}\n\n {isMine && !needsReconnect ? (\n <TextField\n label={MAILBOX_ACTION_LABELS.testAddress}\n value={testAddress}\n onChange={(event) => setTestAddress(event.target.value)}\n disabled={busy !== null}\n size=\"small\"\n type=\"email\"\n helperText={\n 'Leave empty to send the test to yourself. A test to an outside mailbox you can ' +\n 'read is the only one whose original source shows the sender authentication results.'\n }\n fullWidth\n />\n ) : null}\n\n {canManage || isMine ? (\n <Stack direction=\"row\" spacing={1} useFlexGap sx={{ flexWrap: 'wrap' }}>\n {canManage && !needsReconnect ? (\n <Button variant=\"outlined\" disabled={busy !== null} onClick={() => void togglePaused()}>\n {mailbox.status === 'paused' ? MAILBOX_ACTION_LABELS.resume : MAILBOX_ACTION_LABELS.pause}\n </Button>\n ) : null}\n {isMine && !needsReconnect ? (\n <Button variant=\"outlined\" disabled={busy !== null} onClick={() => void sendTest()}>\n {testAddress.trim() ? MAILBOX_ACTION_LABELS.testElsewhere : MAILBOX_ACTION_LABELS.test}\n </Button>\n ) : null}\n {canManage ? (\n <Button color=\"error\" disabled={busy !== null} onClick={() => void disconnect()}>\n {MAILBOX_ACTION_LABELS.disconnect}\n </Button>\n ) : null}\n </Stack>\n ) : null}\n </Stack>\n </CardDisplay>\n )\n}\nMailboxCard.displayName = 'MailboxCard'\n\nexport default MailboxCard\n"],"names":["pluginDocsHelp","CardDisplay","useConfirmationContext","useSnackbar","SenderReadinessPanel","Alert","Autocomplete","Box","Button","Chip","FormControlLabel","FormHelperText","MenuItem","Stack","Switch","TextField","ToggleButton","ToggleButtonGroup","Typography","useEffect","useMemo","useRef","useState","formatMinuteOfDay","isValidTimezone","OUTREACH_DEFAULT_WINDOW","OUTREACH_MAILBOX_STATUS_LABELS","OUTREACH_MAX_DAILY_CAP","OUTREACH_RAMP_STEPS","OUTREACH_WEEKDAY_LABELS","outreachEffectiveDailyCap","outreachLocalDay","summarizeMailboxHealth","validateDailyCap","validateDisplayName","validateSendWindow","outreachPacingNote","autoPauseSentence","mailbox","pause","autoPause","day","atMs","Intl","DateTimeFormat","dateStyle","timeZone","timezone","format","until","untilMs","message","MAILBOX_ACTION_LABELS","save","resume","test","testElsewhere","testAddress","warmUp","disconnect","reconnect","recheckReadiness","WEEKDAY_NAMES","STATUS_COLOR","connected","paused","reconnect_required","disconnected","MINUTE_OPTIONS","Array","from","length","_","index","timezoneOptions","current","supported","supportedValuesOf","zones","includes","RAMP_SENTENCE","map","step","week","limit","join","draftOf","sendAs","email","displayName","dailyCap","String","window","rampStartedAtMs","MailboxCard","props","isMine","canManage","api","onReconnect","reconnecting","nowMs","Date","now","enqueueSnackbar","confirm","microsoft","provider","providerName","draft","setDraft","saving","setSaving","saveError","setSaveError","busy","setBusy","setTestAddress","sendAsAddress","readiness","setReadiness","readinessBusy","setReadinessBusy","active","id","then","answer","catch","error","variant","allowDuplicate","stored","storedKey","JSON","stringify","seededFrom","dirty","previous","health","testsToday","Math","max","Number","daily","tests","needsReconnect","status","capCheck","NaN","windowCheck","nameCheck","timezoneValid","invalid","todayLimit","saveSettings","mailboxId","togglePaused","setPaused","sendTest","to","trim","sent","undefined","sentTo","confirmed","title","description","confirmationText","confirmationButtonProps","color","revocation","persist","sendAsLabel","option","sendAsOptions","find","entry","header","subheader","help","anchor","contentGutterX","contentGutterY","HeaderProps","action","size","label","spacing","severity","disabled","onClick","role","hasSent","direction","sx","mt","bounces","replies","value","aria-label","component","slice","lastIndexOf","onSubmit","event","preventDefault","select","onChange","target","helperText","type","slotProps","htmlInput","min","control","checked","gutterBottom","days","_event","sort","a","b","xs","sm","startMinute","minute","endMinute","disableClearable","options","minWidth","renderInput","params","fullWidth","useFlexGap","flexWrap"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GACD;;;AAEA,SAASA,cAAc,QAAQ,eAAc;AAC7C,SAASC,WAAW,EAAEC,sBAAsB,QAAQ,uBAAsB;AAC1E,SAASC,WAAW,QAAQ,8BAA6B;AACzD,OAAOC,0BAA0B,mEAAkE;AACnG,SACEC,KAAK,EACLC,YAAY,EACZC,GAAG,EACHC,MAAM,EACNC,IAAI,EACJC,gBAAgB,EAChBC,cAAc,EACdC,QAAQ,EACRC,KAAK,EACLC,MAAM,EACNC,SAAS,EACTC,YAAY,EACZC,iBAAiB,EACjBC,UAAU,QACL,gBAAe;AACtB,SAASC,SAAS,EAAEC,OAAO,EAAEC,MAAM,EAAEC,QAAQ,QAAQ,QAAO;AAC5D,SACEC,iBAAiB,EACjBC,eAAe,EACfC,uBAAuB,EACvBC,8BAA8B,EAC9BC,sBAAsB,EACtBC,mBAAmB,EACnBC,uBAAuB,EACvBC,yBAAyB,EACzBC,gBAAgB,EAChBC,sBAAsB,EACtBC,gBAAgB,EAChBC,mBAAmB,EACnBC,kBAAkB,QACb,mCAA+B;AAOtC,SAASC,kBAAkB,QAAQ,iBAAa;AAkBhD;;;;;CAKC,GACD,OAAO,SAASC,kBAAkBC,OAAwD;IACxF,MAAMC,QAAQD,QAAQE,SAAS;IAC/B,IAAI,CAACD,OAAO,OAAO;IACnB,MAAME,MAAM,CAACC;QACX,IAAI;YACF,OAAO,IAAIC,KAAKC,cAAc,CAAC,SAAS;gBAAEC,WAAW;gBAAUC,UAAUR,QAAQS,QAAQ;YAAC,GAAGC,MAAM,CAACN;QACtG,EAAE,eAAM;YACN,OAAO,IAAIC,KAAKC,cAAc,CAAC,SAAS;gBAAEC,WAAW;gBAAUC,UAAU;YAAM,GAAGE,MAAM,CAACN;QAC3F;IACF;IACA,MAAMO,QAAQ,OAAOV,MAAMW,OAAO,KAAK,WAAW,CAAC,YAAY,EAAET,IAAIF,MAAMW,OAAO,EAAE,oBAAoB,CAAC,GAAG;IAC5G,OAAO,CAAC,iCAAiC,EAAET,IAAIF,MAAMG,IAAI,EAAE,EAAE,EAAEH,MAAMY,OAAO,GAAGF,MAAM,2CAA2C,CAAC;AACnI;AAEA,wEAAwE,GACxE,OAAO,MAAMG,wBAAwB;IACnCC,MAAM;IACNd,OAAO;IACPe,QAAQ;IACRC,MAAM;IACNC,eAAe;IACfC,aAAa;IACbC,QAAQ;IACRC,YAAY;IACZC,WAAW;IACXC,kBAAkB;AACpB,EAAU;AAEV,MAAMC,gBAAgB;IAAC;IAAU;IAAU;IAAW;IAAa;IAAY;IAAU;CAAW;AAEpG,MAAMC,eAA2F;IAC/FC,WAAW;IACXC,QAAQ;IACRC,oBAAoB;IACpBC,cAAc;AAChB;AAEA,yDAAyD,GACzD,MAAMC,iBAAiBC,MAAMC,IAAI,CAAC;IAAEC,QAAQ;AAAG,GAAG,CAACC,GAAGC,QAAUA,QAAQ;AAExE,6EAA6E,GAC7E,SAASC,gBAAgBC,OAAe;;IACtC,MAAMC,oBAAY,AAACjC,KAA2DkC,iBAAiB,oBAA7E,AAAClC,KAA2DkC,iBAAiB,MAA5ElC,MAA+E,8BAAe,EAAE;IACnH,MAAMmC,QAAQF,UAAUL,MAAM,GAAGK,YAAY;QAAC;KAAM;IACpD,OAAOE,MAAMC,QAAQ,CAACJ,WAAWG,QAAQ;QAACH;WAAYG;KAAM;AAC9D;AAEA,iDAAiD,GACjD,MAAME,gBAAgB,CAAC,SAAS,EAAEpD,oBAAoBqD,GAAG,CAAC,CAACC,MAAMT,QAC/D,CAAC,KAAK,EAAES,KAAKC,IAAI,GAAGV,UAAU7C,oBAAoB2C,MAAM,GAAG,IAAI,MAAM,GAAG,EAAE,EAAEW,KAAKE,KAAK,EAAE,EACxFC,IAAI,CAAC,OAAO,4BAA4B,CAAC;AAY3C,MAAMC,UAAU,CAAChD;QACPA,iBACKA,sBACIA,mBACTA,iBACEA;WAL0C;QACpDiD,MAAM,GAAEjD,kBAAAA,QAAQiD,MAAM,YAAdjD,kBAAkBA,QAAQkD,KAAK;QACvCC,WAAW,GAAEnD,uBAAAA,QAAQmD,WAAW,YAAnBnD,uBAAuB;QACpCoD,UAAUC,QAAOrD,oBAAAA,QAAQoD,QAAQ,YAAhBpD,oBAAoB;QACrCsD,MAAM,GAAEtD,kBAAAA,QAAQsD,MAAM,YAAdtD,kBAAkBb;QAC1BsB,QAAQ,GAAET,oBAAAA,QAAQS,QAAQ,YAAhBT,oBAAoB;QAC9BoB,QAAQ,OAAOpB,QAAQuD,eAAe,KAAK;IAC7C;;AAEA;;;;;;;;CAQC,GACD,OAAO,SAASC,YAAYC,KAAuB;QAgFZzD,0BAoHpBZ,gDACAqC;QAlIRzB,wCAAAA,uBAAAA,iBA6NKA;IA/Rd,MAAM,EAAEA,OAAO,EAAE0D,MAAM,EAAEC,SAAS,EAAEC,GAAG,EAAEC,WAAW,EAAEC,eAAe,KAAK,EAAEC,QAAQC,KAAKC,GAAG,EAAE,EAAE,GAAGR;IACnG,MAAM,EAAES,eAAe,EAAE,GAAGrG;IAC5B,MAAM,EAAEsG,OAAO,EAAE,GAAGvG;IACpB,MAAMwG,YAAYpE,QAAQqE,QAAQ,KAAK;IACvC,MAAMC,eAAeF,YAAY,cAAc;IAC/C,MAAM,CAACG,OAAOC,SAAS,GAAGxF,SAAgB,IAAMgE,QAAQhD;IACxD,MAAM,CAACyE,QAAQC,UAAU,GAAG1F,SAAS;IACrC,MAAM,CAAC2F,WAAWC,aAAa,GAAG5F,SAAwB;IAC1D,MAAM,CAAC6F,MAAMC,QAAQ,GAAG9F,SAAkD;IAC1E,0EAA0E;IAC1E,kFAAkF;IAClF,MAAM,CAACmC,aAAa4D,eAAe,GAAG/F,SAAS;IAE/C;;;;;GAKC,GACD,MAAMgG,gBAAgBhF,QAAQiD,MAAM,IAAIjD,QAAQkD,KAAK;IACrD,MAAM,CAAC+B,WAAWC,aAAa,GAAGlG,SAAkD;IACpF,MAAM,CAACmG,eAAeC,iBAAiB,GAAGpG,SAAS;IACnDH,UAAU;QACR,IAAIwG,SAAS;QACbzB,IACGqB,SAAS,CAACjF,QAAQsF,EAAE,EACpBC,IAAI,CAAC,CAACC;YACL,IAAIH,QAAQH,aAAaM;QAC3B,GACCC,KAAK,CAAC;YACL,IAAIJ,QAAQH,aAAa;QAC3B;QACF,OAAO;YACLG,SAAS;QACX;IACF,GAAG;QAACzB;QAAK5D,QAAQsF,EAAE;QAAEN;KAAc;IACnC,MAAMzD,mBAAmB;QACvB6D,iBAAiB;QACjB,IAAI;YACFF,aAAa,MAAMtB,IAAIqB,SAAS,CAACjF,QAAQsF,EAAE,EAAE;QAC/C,EAAE,OAAOI,OAAO;YACdxB,gBAAgB,AAACwB,MAAgB7E,OAAO,EAAE;gBAAE8E,SAAS;gBAASC,gBAAgB;YAAK;QACrF,SAAU;YACRR,iBAAiB;QACnB;IACF;IAEA,2EAA2E;IAC3E,wEAAwE;IACxE,mDAAmD;IACnD,MAAMS,SAAS/G,QAAQ,IAAMkE,QAAQhD,UAAU;QAACA;KAAQ;IACxD,MAAM8F,YAAYC,KAAKC,SAAS,CAACH;IACjC,MAAMI,aAAalH,OAAO+G;IAC1B,MAAMI,QAAQH,KAAKC,SAAS,CAACzB,WAAWuB;IACxCjH,UAAU;QACR,IAAIoH,WAAW5D,OAAO,KAAKyD,WAAW;QACtC,MAAMK,WAAWF,WAAW5D,OAAO;QACnC4D,WAAW5D,OAAO,GAAGyD;QACrBtB,SAAS,CAACnC,UAAa0D,KAAKC,SAAS,CAAC3D,aAAa8D,WAAWN,SAASxD;IACzE,GAAG;QAACyD;QAAWD;KAAO;IAEtB,MAAMO,SAAS1G,uBAAuBM,QAAQoG,MAAM,EAAEpG,QAAQS,QAAQ,EAAEsD;IACxE,qEAAqE;IACrE,yEAAyE;IACzE,MAAMsC,aAAaC,KAAKC,GAAG,CACzB,GACAC,QAAOxG,kBAAAA,QAAQoG,MAAM,sBAAdpG,wBAAAA,gBAAgByG,KAAK,sBAArBzG,yCAAAA,qBAAuB,CAACP,iBAAiBsE,OAAO/D,QAAQS,QAAQ,EAAE,qBAAlET,uCAAoE0G,KAAK,KAAK;IAEvF,MAAMC,iBAAiB3G,QAAQ4G,MAAM,KAAK,wBAAwB5G,QAAQ4G,MAAM,KAAK;IACrF,MAAMC,WAAWlH,iBAAiB4E,MAAMnB,QAAQ,KAAK,KAAKoD,OAAOM,GAAG,GAAGN,OAAOjC,MAAMnB,QAAQ;IAC5F,MAAM2D,cAAclH,mBAAmB0E,MAAMjB,MAAM;IACnD,MAAM0D,YAAYpH,oBAAoB2E,MAAMpB,WAAW;IACvD,MAAM8D,gBAAgB/H,gBAAgBqF,MAAM9D,QAAQ;IACpD,MAAMyG,UACJ,OAAOL,aAAa,YAAY,CAAE,CAAA,UAAUE,WAAU,KAAM,OAAOC,cAAc,YAAY,CAACC;IAChG,MAAME,aAAa3H,0BACjB;QACE4D,UAAU,OAAOyD,aAAa,WAAWA,WAAW7G,QAAQoD,QAAQ;QACpE,2DAA2D;QAC3DG,iBAAiBgB,MAAMnD,MAAM,IAAIpB,2BAAAA,QAAQuD,eAAe,YAAvBvD,2BAA2B+D,QAAS;QACrEtD,UAAUwG,gBAAgB1C,MAAM9D,QAAQ,GAAGT,QAAQS,QAAQ;IAC7D,GACAsD;IAGF,MAAMhD,OAAO;QACX2D,UAAU;QACVE,aAAa;QACb,IAAI;YACF,MAAMhB,IAAIwD,YAAY,CAAC;gBACrBC,WAAWrH,QAAQsF,EAAE;eACjBf,MAAMtB,MAAM,KAAK4C,OAAO5C,MAAM,GAAG;gBAAEA,QAAQsB,MAAMtB,MAAM;YAAC,IAAI,CAAC,GAC7DsB,MAAMpB,WAAW,KAAK0C,OAAO1C,WAAW,GAAG;gBAAEA,aAAaoB,MAAMpB,WAAW;YAAC,IAAI,CAAC,GACjFoB,MAAMnB,QAAQ,KAAKyC,OAAOzC,QAAQ,GAAG;gBAAEA,UAAUoD,OAAOjC,MAAMnB,QAAQ;YAAE,IAAI,CAAC,GAC7E2C,KAAKC,SAAS,CAACzB,MAAMjB,MAAM,MAAMyC,KAAKC,SAAS,CAACH,OAAOvC,MAAM,IAAI;gBAAEA,QAAQiB,MAAMjB,MAAM;YAAC,IAAI,CAAC,GAC7FiB,MAAM9D,QAAQ,KAAKoF,OAAOpF,QAAQ,GAAG;gBAAEA,UAAU8D,MAAM9D,QAAQ;YAAC,IAAI,CAAC,GACrE8D,MAAMnD,MAAM,KAAKyE,OAAOzE,MAAM,GAAG;gBAAEA,QAAQmD,MAAMnD,MAAM;YAAC,IAAI,CAAC;YAEnE8C,gBAAgB,0BAA0B;gBAAEyB,SAAS;YAAU;QACjE,EAAE,OAAOD,OAAO;YACdd,aAAa,AAACc,MAAgB7E,OAAO;QACvC,SAAU;YACR6D,UAAU;QACZ;IACF;IAEA,MAAM4C,eAAe;QACnB,MAAM3F,SAAS3B,QAAQ4G,MAAM,KAAK;QAClC9B,QAAQ;QACR,IAAI;YACF,MAAMlB,IAAI2D,SAAS,CAACvH,QAAQsF,EAAE,EAAE3D;YAChCuC,gBAAgBvC,SAAS,mBAAmB,mBAAmB;gBAAEgE,SAAS;YAAU;QACtF,EAAE,OAAOD,OAAO;YACdxB,gBAAgB,AAACwB,MAAgB7E,OAAO,EAAE;gBAAE8E,SAAS;gBAASC,gBAAgB;YAAK;QACrF,SAAU;YACRd,QAAQ;QACV;IACF;IAEA,MAAM0C,WAAW;QACf1C,QAAQ;QACR,IAAI;YACF,MAAM2C,KAAKtG,YAAYuG,IAAI;YAC3B,MAAMC,OAAO,MAAM/D,IAAI4D,QAAQ,CAACxH,QAAQsF,EAAE,EAAEmC,MAAMG;YAClD1D,gBACEuD,KACI,CAAC,aAAa,EAAEE,KAAKE,MAAM,CAAC,6DAA6D,CAAC,GAC1F,CAAC,aAAa,EAAEF,KAAKE,MAAM,CAAC,mBAAmB,CAAC,EACpD;gBAAElC,SAAS;YAAU;QAEzB,EAAE,OAAOD,OAAO;YACdxB,gBAAgB,AAACwB,MAAgB7E,OAAO,EAAE;gBAAE8E,SAAS;gBAASC,gBAAgB;YAAK;QACrF,SAAU;YACRd,QAAQ;QACV;IACF;IAEA,MAAMzD,aAAa;QACjB,MAAMyG,YAAY,MAAM3D,QAAQ;YAC9B4D,OAAO;YACPC,aACE,AAAC5D,CAAAA,YACG,+DACA,yFAAwF,IAC5F;YACF6D,kBAAkBnH,sBAAsBO,UAAU;YAClD6G,yBAAyB;gBAAEC,OAAO;YAAQ;QAC5C,GACG5C,IAAI,CAAC,IAAM,MACXE,KAAK,CAAC,IAAM;QACf,IAAI,CAACqC,WAAW;QAChBhD,QAAQ;QACR,IAAI;YACF,MAAM,EAAEsD,UAAU,EAAE,GAAG,MAAMxE,IAAIvC,UAAU,CAACrB,QAAQsF,EAAE;YACtD,IAAI8C,eAAe,UAAU;gBAC3BlE,gBACE,gFACE,2EACF;oBAAEyB,SAAS;oBAAW0C,SAAS;gBAAK;YAExC,OAAO,IAAID,eAAe,eAAe;gBACvClE,gBACE,qGACA;oBAAEyB,SAAS;gBAAU;YAEzB,OAAO,IAAIyC,eAAe,0BAA0B;gBAClDlE,gBACE,yGACA;oBAAEyB,SAAS;gBAAU;YAEzB,OAAO;gBACLzB,gBAAgB,wBAAwB;oBAAEyB,SAAS;gBAAU;YAC/D;QACF,EAAE,OAAOD,OAAO;YACdxB,gBAAgB,AAACwB,MAAgB7E,OAAO,EAAE;gBAAE8E,SAAS;gBAASC,gBAAgB;YAAK;YACnFd,QAAQ;QACV;IACF;IAEA,MAAMwD,cAAc,CAACpF;YACJlD;QAAf,MAAMuI,UAASvI,yBAAAA,QAAQwI,aAAa,qBAArBxI,uBAAuByI,IAAI,CAAC,CAACC,QAAUA,MAAMxF,KAAK,KAAKA;QACtE,OAAOqF,CAAAA,0BAAAA,OAAQpF,WAAW,IAAG,GAAGoF,OAAOpF,WAAW,CAAC,EAAE,EAAEoF,OAAOrF,KAAK,CAAC,CAAC,CAAC,GAAGA;IAC3E;IAEA,qBACE,KAACvF;QACCgL,QAAQ3I,QAAQkD,KAAK;QACrB0F,WAAWlF,SAAS,iBAAiB;QACrCmF,MAAMnL,eAAe,aAAa;YAAEoL,QAAQ;QAAqB;QACjEC,cAAc;QACdC,cAAc;QACdC,aAAa;YACXC,sBACE,KAAC/K;gBACCgL,MAAK;gBACLC,KAAK,GAAEhK,iDAAAA,8BAA8B,CAACY,QAAQ4G,MAAM,CAAC,YAA9CxH,iDAAkDY,QAAQ4G,MAAM;gBACvEuB,KAAK,GAAE1G,+BAAAA,YAAY,CAACzB,QAAQ4G,MAAM,CAAC,YAA5BnF,+BAAgC;;QAG7C;kBAEA,cAAA,MAAClD;YAAM8K,SAAS;;gBACb1C,+BACC,KAAC5I;oBACCuL,UAAS;oBACTJ,QACExF,uBACE,KAACxF;wBAAOiK,OAAM;wBAAUgB,MAAK;wBAAQI,UAAUzF;wBAAc0F,SAAS3F;kCACnE/C,sBAAsBQ,SAAS;yBAEhCsG;8BAGL,GACC5H,QAAQ4G,MAAM,KAAK,iBACf,mCACA,GAAGtC,aAAa,6CAA6C,CAAC,CACnE,CAAC,EACAZ,SACI,sDACA,sDACJ;qBAEF;gBACH1D,QAAQ4G,MAAM,KAAK,YAAY5G,QAAQE,SAAS,iBAC/C,KAACnC;oBAAMuL,UAAS;oBAAQG,MAAK;8BAC1B1J,kBAAkBC;qBAEnB;8BAEJ,MAAC/B;;sCACC,KAACW;4BAAW+G,SAAQ;sCAAY;;wBAC/BS,OAAOsD,OAAO,GAAG,qBAChB,KAAC9K;4BAAW+G,SAAQ;4BAAQwC,OAAM;sCAAiB;;sCAIrD,KAAC5J;4BAAMoL,WAAU;4BAAMN,SAAS;4BAAGO,IAAI;gCAAEC,IAAI;4BAAI;sCAC9C;gCACC;oCAAC;oCAAQzD,OAAOuB,IAAI;iCAAC;gCACrB;oCAAC;oCAAWvB,OAAO0D,OAAO;iCAAC;gCAC3B;oCAAC;oCAAW1D,OAAO2D,OAAO;iCAAC;6BAC5B,CAACpH,GAAG,CAAC,CAAC,CAACyG,OAAOY,MAAM,iBACnB,MAAC/L;oCAA0BgM,cAAY,GAAGb,MAAM,mBAAmB,CAAC;;sDAClE,KAACxK;4CAAW+G,SAAQ;4CAAKuE,WAAU;sDAChCF;;sDAEH,KAACpL;4CAAW+G,SAAQ;4CAAUwC,OAAM;sDACjCiB;;;mCALKA;;sCAUd,KAACxK;4BAAW+G,SAAQ;4BAAUwC,OAAM;4BAAiB8B,cAAW;sCAC7D,CAAC,aAAa,EAAE5D,YAAY;;sCAE/B,KAACzH;4BAAW+G,SAAQ;4BAAUwC,OAAM;4BAAiB+B,WAAU;4BAAID,cAAW;sCAC3EnK,mBAAmBE,SAAS+D;;;;gBAIhCkB,CAAAA,6BAAAA,UAAWA,SAAS,kBACnB,MAAC1G;oBAAM8K,SAAS;;sCACd,KAACvL;4BAAqBmH,WAAWA,UAAUA,SAAS;;sCACpD,KAAChH;sCACC,cAAA,KAACC;gCAAOiL,MAAK;gCAAQI,UAAUpE;gCAAeqE,SAAS,IAAM,KAAKjI;0CAC/DT,sBAAsBS,gBAAgB;;;;qBAI3C0D,0BACF,KAACrG;oBAAW+G,SAAQ;oBAAUwC,OAAM;8BACjC,GAAG7D,aAAa,yBAAyB,EAAEW,UAAUhC,MAAM,CAACkH,KAAK,CAAClF,UAAUhC,MAAM,CAACmH,WAAW,CAAC,OAAO,GAAG,CAAC,CAAC,GAC1G;qBAEF;gBAEHzG,0BACC,MAACpF;oBAAM8K,SAAS;oBAAGa,WAAU;oBAAOG,UAAU,CAACC,QAAUA,MAAMC,cAAc;;sCAC3E,KAAC9L;4BACC+L,MAAM;4BACNrB,MAAK;4BACLC,OAAM;4BACNY,OAAOzF,MAAMtB,MAAM;4BACnBwH,UAAU,CAACH,QAAU9F,SAAS,aAAKD;oCAAOtB,QAAQqH,MAAMI,MAAM,CAACV,KAAK;;4BACpEW,YAAW;sCAEV,AAAC3K,CAAAA,EAAAA,yBAAAA,QAAQwI,aAAa,qBAArBxI,uBAAuBiC,MAAM,IAAGjC,QAAQwI,aAAa,GAAG;gCAAC;oCAAEtF,OAAOlD,QAAQiD,MAAM;gCAAC;6BAAE,AAAD,EAAGN,GAAG,CAAC,CAAC4F,uBAC1F,KAACjK;oCAA4B0L,OAAOzB,OAAOrF,KAAK;8CAC7CoF,YAAYC,OAAOrF,KAAK;mCADZqF,OAAOrF,KAAK;;sCAK/B,KAACzE;4BACC0K,MAAK;4BACLC,OAAM;4BACNY,OAAOzF,MAAMpB,WAAW;4BACxBsH,UAAU,CAACH,QAAU9F,SAAS,aAAKD;oCAAOpB,aAAamH,MAAMI,MAAM,CAACV,KAAK;;4BACzEtE,OAAO,OAAOsB,cAAc;4BAC5B2D,YAAY,OAAO3D,cAAc,WAAWA,UAAUnG,OAAO,GAAG;;sCAElE,KAACpC;4BACC0K,MAAK;4BACLyB,MAAK;4BACLxB,OAAM;4BACNY,OAAOzF,MAAMnB,QAAQ;4BACrBqH,UAAU,CAACH,QAAU9F,SAAS,aAAKD;oCAAOnB,UAAUkH,MAAMI,MAAM,CAACV,KAAK;;4BACtEtE,OAAO,OAAOmB,aAAa;4BAC3BgE,WAAW;gCAAEC,WAAW;oCAAEC,KAAK;oCAAGxE,KAAKlH;oCAAwBuD,MAAM;gCAAE;4BAAE;4BACzE+H,YACE,OAAO9D,aAAa,WAChBA,SAAShG,OAAO,GAChB0D,MAAMnD,MAAM,GACV,GAAGsB,cAAc,gBAAgB,EAAEyE,WAAW,CAAC,CAAC,GAChD,CAAC,sCAAsC,EAAEA,WAAW,CAAC,CAAC;;sCAGhE,KAAC/I;4BACC4M,uBACE,KAACxM;gCACCyM,SAAS1G,MAAMnD,MAAM;gCACrBqJ,UAAU,CAACH,QAAU9F,SAAS,aAAKD;wCAAOnD,QAAQkJ,MAAMI,MAAM,CAACO,OAAO;;;4BAG1E7B,OAAOtI,sBAAsBM,MAAM;;sCAErC,KAAC/C;4BAAeuL,IAAI;gCAAEC,IAAI,CAAC;4BAAE;sCAC1B,kGACC;;sCAEJ,MAAC5L;;8CACC,KAACW;oCAAW+G,SAAQ;oCAAYuF,YAAY;8CAAC;;8CAG7C,KAACvM;oCACCwK,MAAK;oCACLc,cAAW;oCACXD,OAAOzF,MAAMjB,MAAM,CAAC6H,IAAI;oCACxBV,UAAU,CAACW,QAAQD,OACjB3G,SAAS,aAAKD;4CAAOjB,QAAQ,aAAKiB,MAAMjB,MAAM;gDAAE6H,MAAM;uDAAIA;iDAAK,CAACE,IAAI,CAAC,CAACC,GAAGC,IAAMD,IAAIC;;;8CAGpFhM,wBAAwBoD,GAAG,CAAC,CAACyG,OAAOjJ,oBACnC,KAACzB;4CAAyBsL,OAAO7J;4CAAK8J,cAAYzI,aAAa,CAACrB,IAAI;sDACjEiJ;2CADgBA;;8CAKvB,MAAC7K;oCAAMoL,WAAW;wCAAE6B,IAAI;wCAAUC,IAAI;oCAAM;oCAAGpC,SAAS;oCAAGO,IAAI;wCAAEC,IAAI;oCAAE;;sDACrE,KAACpL;4CACC+L,MAAM;4CACNrB,MAAK;4CACLC,OAAM;4CACNY,OAAOzF,MAAMjB,MAAM,CAACoI,WAAW;4CAC/BjB,UAAU,CAACH,QACT9F,SAAS,aAAKD;oDAAOjB,QAAQ,aAAKiB,MAAMjB,MAAM;wDAAEoI,aAAalF,OAAO8D,MAAMI,MAAM,CAACV,KAAK;;;sDAGvFlI,eAAeqI,KAAK,CAAC,GAAG,CAAC,GAAGxH,GAAG,CAAC,CAACgJ,uBAChC,KAACrN;oDAAsB0L,OAAO2B;8DAC3B1M,kBAAkB0M;mDADNA;;sDAKnB,KAAClN;4CACC+L,MAAM;4CACNrB,MAAK;4CACLC,OAAM;4CACNY,OAAOzF,MAAMjB,MAAM,CAACsI,SAAS;4CAC7BnB,UAAU,CAACH,QACT9F,SAAS,aAAKD;oDAAOjB,QAAQ,aAAKiB,MAAMjB,MAAM;wDAAEsI,WAAWpF,OAAO8D,MAAMI,MAAM,CAACV,KAAK;;;sDAGrFlI,eAAeqI,KAAK,CAAC,GAAGxH,GAAG,CAAC,CAACgJ,uBAC5B,KAACrN;oDAAsB0L,OAAO2B;8DAC3B1M,kBAAkB0M;mDADNA;;sDAKnB,KAAC3N;4CACCmL,MAAK;4CACL0C,gBAAgB;4CAChBC,SAAS1J,gBAAgBpC,QAAQS,QAAQ;4CACzCuJ,OAAOzF,MAAM9D,QAAQ;4CACrBgK,UAAU,CAACW,QAAQ3K,WAAa+D,SAAS,aAAKD;oDAAO9D,QAAQ,EAAEA,mBAAAA,WAAY8D,MAAM9D,QAAQ;;4CACzFmJ,IAAI;gDAAEmC,UAAU;4CAAI;4CACpBC,aAAa,CAACC,uBAAW,KAACxN,wBAAcwN;oDAAQ7C,OAAM;;;;;gCAGzD,UAAUrC,cAAc,qBAAO,KAAC1I;oCAAeqH,KAAK;8CAAEqB,YAAYlG,OAAO;;;;wBAE3E8D,0BAAY,KAACtG;4BAAeqH,KAAK;sCAAEf;6BAA8B;sCAClE,KAAC1G;sCACC,cAAA,KAACC;gCAAOyH,SAAQ;gCAAY4D,UAAU,CAACrD,SAASgB,WAAWzC;gCAAQ+E,SAAS,IAAM,KAAKzI;0CACpFD,sBAAsBC,IAAI;;;;mCAKjC,KAACnC;oBAAW+G,SAAQ;oBAAQwC,OAAM;8BAC/B,CAAC,SAAS,EAAEG,YAAYzC,OAAO5C,MAAM,EAAE,UAAU,EAAE4C,OAAOzC,QAAQ,CAAC,QAAQ,CAAC,GAC3E,GAAGyC,OAAOvC,MAAM,CAAC6H,IAAI,CAACxI,GAAG,CAAC,CAACxC,MAAQZ,uBAAuB,CAACY,IAAI,EAAE4C,IAAI,CAAC,MAAM,CAAC,CAAC,GAC9E,GAAG9D,kBAAkB4G,OAAOvC,MAAM,CAACoI,WAAW,EAAE,CAAC,EAAEzM,kBAAkB4G,OAAOvC,MAAM,CAACsI,SAAS,EAAE,CAAC,CAAC,GAChG,CAAC,CAAC,EAAE/F,OAAOpF,QAAQ,CAAC,EAAE,CAAC;;gBAI5BiD,UAAU,CAACiD,+BACV,KAAClI;oBACC2K,OAAOtI,sBAAsBK,WAAW;oBACxC6I,OAAO7I;oBACPsJ,UAAU,CAACH,QAAUvF,eAAeuF,MAAMI,MAAM,CAACV,KAAK;oBACtDT,UAAU1E,SAAS;oBACnBsE,MAAK;oBACLyB,MAAK;oBACLD,YACE,oFACA;oBAEFuB,SAAS;qBAET;gBAEHvI,aAAaD,uBACZ,MAACnF;oBAAMoL,WAAU;oBAAMN,SAAS;oBAAG8C,UAAU;oBAACvC,IAAI;wBAAEwC,UAAU;oBAAO;;wBAClEzI,aAAa,CAACgD,+BACb,KAACzI;4BAAOyH,SAAQ;4BAAW4D,UAAU1E,SAAS;4BAAM2E,SAAS,IAAM,KAAKlC;sCACrEtH,QAAQ4G,MAAM,KAAK,WAAW9F,sBAAsBE,MAAM,GAAGF,sBAAsBb,KAAK;6BAEzF;wBACHyD,UAAU,CAACiD,+BACV,KAACzI;4BAAOyH,SAAQ;4BAAW4D,UAAU1E,SAAS;4BAAM2E,SAAS,IAAM,KAAKhC;sCACrErG,YAAYuG,IAAI,KAAK5G,sBAAsBI,aAAa,GAAGJ,sBAAsBG,IAAI;6BAEtF;wBACH0C,0BACC,KAACzF;4BAAOiK,OAAM;4BAAQoB,UAAU1E,SAAS;4BAAM2E,SAAS,IAAM,KAAKnI;sCAChEP,sBAAsBO,UAAU;6BAEjC;;qBAEJ;;;;AAIZ;AACAmC,YAAYL,WAAW,GAAG;AAE1B,eAAeK,YAAW"}
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/outreach/src/lib/components/mailbox-card.tsx"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n'use client'\n\nimport { pluginDocsHelp } from '@aglyn/aglyn'\nimport { CardDisplay, useConfirmationContext } from '@aglyn/shared-ui-jsx'\nimport { useSnackbar } from '@aglyn/shared-ui-snackstack'\nimport SenderReadinessPanel from '@aglyn/tenant-feature-instance/components/sender-readiness-panel'\nimport {\n Alert,\n Autocomplete,\n Box,\n Button,\n Chip,\n FormControlLabel,\n FormHelperText,\n MenuItem,\n Stack,\n Switch,\n TextField,\n ToggleButton,\n ToggleButtonGroup,\n Typography,\n} from '@mui/material'\nimport { useEffect, useMemo, useRef, useState } from 'react'\nimport {\n formatMinuteOfDay,\n isValidTimezone,\n OUTREACH_DEFAULT_WINDOW,\n OUTREACH_MAILBOX_STATUS_LABELS,\n OUTREACH_MAX_DAILY_CAP,\n OUTREACH_RAMP_STEPS,\n OUTREACH_WEEKDAY_LABELS,\n outreachEffectiveDailyCap,\n outreachLocalDay,\n summarizeMailboxHealth,\n validateDailyCap,\n validateDisplayName,\n validateSendWindow,\n} from '../mailboxes/mailbox-settings'\nimport type { OutreachMailboxReadinessResponse } from '../mailboxes/mailbox-api'\nimport type {\n OutreachMailbox,\n OutreachMailboxStatus,\n OutreachSendWindow,\n} from '../model/outreach.types'\nimport { outreachPacingNote } from './next-send'\nimport type { OutreachMailboxApi } from './use-outreach-mailbox-api'\n\nexport interface MailboxCardProps {\n mailbox: OutreachMailbox\n /** The viewer is the member who connected it. */\n isMine: boolean\n /** The viewer may change, pause and disconnect it: its member, or an org owner or admin. */\n canManage: boolean\n api: OutreachMailboxApi\n /** Starts a new connect with the mailbox's provider, for a mailbox that needs reconnecting. */\n onReconnect(): void\n /** True while that connect is on its way to the provider. */\n reconnecting?: boolean\n /** The clock the health window and today's limit are read on. */\n nowMs?: number\n}\n\n/**\n * What the card says about a mailbox that paused ITSELF (AGL-2981): the\n * engine's own sentence, when it paused, and — after a complaint — the day\n * resuming stops being premature. Nothing sends from it until a member\n * resumes it.\n */\nexport function autoPauseSentence(mailbox: Pick<OutreachMailbox, 'autoPause' | 'timezone'>): string {\n const pause = mailbox.autoPause\n if (!pause) return ''\n const day = (atMs: number) => {\n try {\n return new Intl.DateTimeFormat('en-US', { dateStyle: 'medium', timeZone: mailbox.timezone }).format(atMs)\n } catch {\n return new Intl.DateTimeFormat('en-US', { dateStyle: 'medium', timeZone: 'UTC' }).format(atMs)\n }\n }\n const until = typeof pause.untilMs === 'number' ? ` Wait until ${day(pause.untilMs)} before resuming it.` : ''\n return `Sequences paused this mailbox on ${day(pause.atMs)}. ${pause.message}${until} Nothing sends from it until it is resumed.`\n}\n\n/** Accessible names of the card's actions, spelled once for the specs. */\nexport const MAILBOX_ACTION_LABELS = {\n save: 'Save settings',\n pause: 'Pause',\n resume: 'Resume',\n test: 'Send a test to myself',\n testElsewhere: 'Send a test',\n testAddress: 'Test address',\n warmUp: 'Warm up gradually',\n disconnect: 'Disconnect',\n reconnect: 'Reconnect',\n recheckReadiness: 'Check DNS again',\n} as const\n\nconst WEEKDAY_NAMES = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']\n\nconst STATUS_COLOR: Record<OutreachMailboxStatus, 'success' | 'default' | 'warning' | 'error'> = {\n connected: 'success',\n paused: 'default',\n reconnect_required: 'warning',\n disconnected: 'error',\n}\n\n/** Every half hour of the day, and midnight at its end. */\nconst MINUTE_OPTIONS = Array.from({ length: 49 }, (_, index) => index * 30)\n\n/** The zones this runtime knows, the mailbox's own included whatever it is. */\nfunction timezoneOptions(current: string): string[] {\n const supported = (Intl as { supportedValuesOf?: (key: string) => string[] }).supportedValuesOf?.('timeZone') ?? []\n const zones = supported.length ? supported : ['UTC']\n return zones.includes(current) ? zones : [current, ...zones]\n}\n\n/** The ramp, as the cap's helper text reads it. */\nconst RAMP_SENTENCE = `Warm-up: ${OUTREACH_RAMP_STEPS.map((step, index) =>\n `week ${step.week}${index === OUTREACH_RAMP_STEPS.length - 1 ? '+' : ''}: ${step.limit}`,\n).join(' · ')} a day, never above the cap.`\n\ninterface Draft {\n sendAs: string\n displayName: string\n dailyCap: string\n window: OutreachSendWindow\n timezone: string\n /** Whether the warm-up ramp applies — `rampStartedAtMs` as a switch. */\n warmUp: boolean\n}\n\nconst draftOf = (mailbox: OutreachMailbox): Draft => ({\n sendAs: mailbox.sendAs ?? mailbox.email,\n displayName: mailbox.displayName ?? '',\n dailyCap: String(mailbox.dailyCap ?? ''),\n window: mailbox.window ?? OUTREACH_DEFAULT_WINDOW,\n timezone: mailbox.timezone ?? 'UTC',\n warmUp: typeof mailbox.rampStartedAtMs === 'number',\n})\n\n/**\n * One connected mailbox (AGL-2978): its account and status, its last seven\n * days, its settings, and pause, test and disconnect.\n *\n * Every control is offered only where the route will allow it: the settings\n * form and pause and disconnect to the member who connected the mailbox or an\n * org owner or admin, and the test and the reconnect to its member alone,\n * because both act in that member's own Google or Microsoft account.\n */\nexport function MailboxCard(props: MailboxCardProps) {\n const { mailbox, isMine, canManage, api, onReconnect, reconnecting = false, nowMs = Date.now() } = props\n const { enqueueSnackbar } = useSnackbar()\n const { confirm } = useConfirmationContext()\n const microsoft = mailbox.provider === 'microsoft'\n const providerName = microsoft ? 'Microsoft' : 'Google'\n const [draft, setDraft] = useState<Draft>(() => draftOf(mailbox))\n const [saving, setSaving] = useState(false)\n const [saveError, setSaveError] = useState<string | null>(null)\n const [busy, setBusy] = useState<'status' | 'test' | 'disconnect' | null>(null)\n // Where a test goes when not to the member themself (AGL-3228): a test to\n // one's own address never leaves the provider and shows no authentication result.\n const [testAddress, setTestAddress] = useState('')\n\n /*\n * SPF, DKIM and DMARC for the address this mailbox sends as (AGL-3328),\n * read by the server and remembered there briefly. Re-read when the\n * send-as address changes; a failed read shows nothing rather than a\n * verdict nobody made.\n */\n const sendAsAddress = mailbox.sendAs || mailbox.email\n const [readiness, setReadiness] = useState<OutreachMailboxReadinessResponse | null>(null)\n const [readinessBusy, setReadinessBusy] = useState(false)\n useEffect(() => {\n let active = true\n api\n .readiness(mailbox.id)\n .then((answer) => {\n if (active) setReadiness(answer)\n })\n .catch(() => {\n if (active) setReadiness(null)\n })\n return () => {\n active = false\n }\n }, [api, mailbox.id, sendAsAddress])\n const recheckReadiness = async () => {\n setReadinessBusy(true)\n try {\n setReadiness(await api.readiness(mailbox.id, true))\n } catch (error) {\n enqueueSnackbar((error as Error).message, { variant: 'error', allowDuplicate: true })\n } finally {\n setReadinessBusy(false)\n }\n }\n\n // A save here, a change made from another tab, or a reconnect rewrites the\n // stored settings; the form follows them, unless the member has unsaved\n // edits of their own, which are never thrown away.\n const stored = useMemo(() => draftOf(mailbox), [mailbox])\n const storedKey = JSON.stringify(stored)\n const seededFrom = useRef(storedKey)\n const dirty = JSON.stringify(draft) !== storedKey\n useEffect(() => {\n if (seededFrom.current === storedKey) return\n const previous = seededFrom.current\n seededFrom.current = storedKey\n setDraft((current) => (JSON.stringify(current) === previous ? stored : current))\n }, [storedKey, stored])\n\n const health = summarizeMailboxHealth(mailbox.health, mailbox.timezone, nowMs)\n // Tests of a sequence step sent today (AGL-3325): counted beside the\n // sends, never among them, so the cap and the seven-day sum stay honest.\n const testsToday = Math.max(\n 0,\n Number(mailbox.health?.daily?.[outreachLocalDay(nowMs, mailbox.timezone)]?.tests) || 0,\n )\n const needsReconnect = mailbox.status === 'reconnect_required' || mailbox.status === 'disconnected'\n const capCheck = validateDailyCap(draft.dailyCap === '' ? Number.NaN : Number(draft.dailyCap))\n const windowCheck = validateSendWindow(draft.window)\n const nameCheck = validateDisplayName(draft.displayName)\n const timezoneValid = isValidTimezone(draft.timezone)\n const invalid =\n typeof capCheck !== 'number' || !('days' in windowCheck) || typeof nameCheck !== 'string' || !timezoneValid\n const todayLimit = outreachEffectiveDailyCap(\n {\n dailyCap: typeof capCheck === 'number' ? capCheck : mailbox.dailyCap,\n // A ramp switched on in the draft reads as starting today.\n rampStartedAtMs: draft.warmUp ? (mailbox.rampStartedAtMs ?? nowMs) : null,\n timezone: timezoneValid ? draft.timezone : mailbox.timezone,\n },\n nowMs,\n )\n\n const save = async () => {\n setSaving(true)\n setSaveError(null)\n try {\n await api.saveSettings({\n mailboxId: mailbox.id,\n ...(draft.sendAs !== stored.sendAs ? { sendAs: draft.sendAs } : {}),\n ...(draft.displayName !== stored.displayName ? { displayName: draft.displayName } : {}),\n ...(draft.dailyCap !== stored.dailyCap ? { dailyCap: Number(draft.dailyCap) } : {}),\n ...(JSON.stringify(draft.window) !== JSON.stringify(stored.window) ? { window: draft.window } : {}),\n ...(draft.timezone !== stored.timezone ? { timezone: draft.timezone } : {}),\n ...(draft.warmUp !== stored.warmUp ? { warmUp: draft.warmUp } : {}),\n })\n enqueueSnackbar('Mailbox settings saved', { variant: 'success' })\n } catch (error) {\n setSaveError((error as Error).message)\n } finally {\n setSaving(false)\n }\n }\n\n const togglePaused = async () => {\n const paused = mailbox.status !== 'paused'\n setBusy('status')\n try {\n await api.setPaused(mailbox.id, paused)\n enqueueSnackbar(paused ? 'Mailbox paused' : 'Mailbox resumed', { variant: 'success' })\n } catch (error) {\n enqueueSnackbar((error as Error).message, { variant: 'error', allowDuplicate: true })\n } finally {\n setBusy(null)\n }\n }\n\n const sendTest = async () => {\n setBusy('test')\n try {\n const to = testAddress.trim()\n const sent = await api.sendTest(mailbox.id, to || undefined)\n enqueueSnackbar(\n to\n ? `Test sent to ${sent.sentTo}. Its original source shows whether the sender authenticated.`\n : `Test sent to ${sent.sentTo}. Check your inbox.`,\n { variant: 'success' },\n )\n } catch (error) {\n enqueueSnackbar((error as Error).message, { variant: 'error', allowDuplicate: true })\n } finally {\n setBusy(null)\n }\n }\n\n const disconnect = async () => {\n const confirmed = await confirm({\n title: 'Disconnect this mailbox?',\n description:\n (microsoft\n ? 'Disconnecting deletes the access stored for this mailbox. '\n : 'Disconnecting deletes the access stored for this mailbox and asks Google to revoke it. ') +\n 'Nothing is sent from it again unless it is connected again.',\n confirmationText: MAILBOX_ACTION_LABELS.disconnect,\n confirmationButtonProps: { color: 'error' },\n })\n .then(() => true)\n .catch(() => false)\n if (!confirmed) return\n setBusy('disconnect')\n try {\n const { revocation } = await api.disconnect(mailbox.id)\n if (revocation === 'failed') {\n enqueueSnackbar(\n 'Mailbox disconnected, but Google could not confirm the access was revoked. ' +\n 'Remove it from the Google Account’s third-party connections to be sure.',\n { variant: 'warning', persist: true },\n )\n } else if (revocation === 'unsupported') {\n enqueueSnackbar(\n 'Mailbox disconnected. To end the access at Microsoft too, remove the app at myapps.microsoft.com.',\n { variant: 'success' },\n )\n } else if (revocation === 'kept-for-other-mailbox') {\n enqueueSnackbar(\n 'Mailbox disconnected. Google access stays in place for another connected mailbox on the same account.',\n { variant: 'success' },\n )\n } else {\n enqueueSnackbar('Mailbox disconnected', { variant: 'success' })\n }\n } catch (error) {\n enqueueSnackbar((error as Error).message, { variant: 'error', allowDuplicate: true })\n setBusy(null)\n }\n }\n\n const sendAsLabel = (email: string) => {\n const option = mailbox.sendAsOptions?.find((entry) => entry.email === email)\n return option?.displayName ? `${option.displayName} <${option.email}>` : email\n }\n\n return (\n <CardDisplay\n header={mailbox.email}\n subheader={isMine ? 'Your mailbox' : 'A teammate’s mailbox'}\n help={pluginDocsHelp('sequences', { anchor: '#mailbox-actions' })}\n contentGutterX\n contentGutterY\n HeaderProps={{\n action: (\n <Chip\n size=\"small\"\n label={OUTREACH_MAILBOX_STATUS_LABELS[mailbox.status] ?? mailbox.status}\n color={STATUS_COLOR[mailbox.status] ?? 'default'}\n />\n ),\n }}\n >\n <Stack spacing={2}>\n {needsReconnect ? (\n <Alert\n severity=\"warning\"\n action={\n isMine ? (\n <Button color=\"inherit\" size=\"small\" disabled={reconnecting} onClick={onReconnect}>\n {MAILBOX_ACTION_LABELS.reconnect}\n </Button>\n ) : undefined\n }\n >\n {`${\n mailbox.status === 'disconnected'\n ? 'This mailbox was disconnected.'\n : `${providerName} stopped accepting this mailbox’s connection.`\n } ${\n isMine\n ? 'Nothing sends from it until you connect it again.'\n : 'Only the member who connected it can reconnect it.'\n }`}\n </Alert>\n ) : null}\n {mailbox.status === 'paused' && mailbox.autoPause ? (\n <Alert severity=\"error\" role=\"alert\">\n {autoPauseSentence(mailbox)}\n </Alert>\n ) : null}\n\n <Box>\n <Typography variant=\"subtitle2\">Last 7 days</Typography>\n {health.hasSent ? null : (\n <Typography variant=\"body2\" color=\"text.secondary\">\n No sends yet\n </Typography>\n )}\n <Stack direction=\"row\" spacing={3} sx={{ mt: 0.5 }}>\n {[\n ['Sent', health.sent],\n ['Bounces', health.bounces],\n ['Replies', health.replies],\n ].map(([label, value]) => (\n <Box key={label as string} aria-label={`${label} in the last 7 days`}>\n <Typography variant=\"h6\" component=\"p\">\n {value}\n </Typography>\n <Typography variant=\"caption\" color=\"text.secondary\">\n {label}\n </Typography>\n </Box>\n ))}\n </Stack>\n <Typography variant=\"caption\" color=\"text.secondary\" aria-label=\"Tests today\">\n {`Tests today: ${testsToday}`}\n </Typography>\n <Typography variant=\"caption\" color=\"text.secondary\" component=\"p\" aria-label=\"Pacing\">\n {outreachPacingNote(mailbox, nowMs)}\n </Typography>\n </Box>\n\n {readiness?.readiness ? (\n <Stack spacing={1}>\n <SenderReadinessPanel readiness={readiness.readiness} />\n <Box>\n <Button size=\"small\" disabled={readinessBusy} onClick={() => void recheckReadiness()}>\n {MAILBOX_ACTION_LABELS.recheckReadiness}\n </Button>\n </Box>\n </Stack>\n ) : readiness ? (\n <Typography variant=\"caption\" color=\"text.secondary\">\n {`${providerName} authenticates mail from ${readiness.sendAs.slice(readiness.sendAs.lastIndexOf('@') + 1)} ` +\n 'itself, so there are no records to publish for this address.'}\n </Typography>\n ) : null}\n\n {canManage ? (\n <Stack spacing={2} component=\"form\" onSubmit={(event) => event.preventDefault()}>\n <TextField\n select\n size=\"small\"\n label=\"Send as\"\n value={draft.sendAs}\n onChange={(event) => setDraft({ ...draft, sendAs: event.target.value })}\n helperText=\"Addresses Gmail has verified for this account.\"\n >\n {(mailbox.sendAsOptions?.length ? mailbox.sendAsOptions : [{ email: mailbox.sendAs }]).map((option) => (\n <MenuItem key={option.email} value={option.email}>\n {sendAsLabel(option.email)}\n </MenuItem>\n ))}\n </TextField>\n <TextField\n size=\"small\"\n label=\"Display name\"\n value={draft.displayName}\n onChange={(event) => setDraft({ ...draft, displayName: event.target.value })}\n error={typeof nameCheck !== 'string'}\n helperText={typeof nameCheck !== 'string' ? nameCheck.message : 'The name recipients see beside the address.'}\n />\n <TextField\n size=\"small\"\n type=\"number\"\n label=\"Daily cap\"\n value={draft.dailyCap}\n onChange={(event) => setDraft({ ...draft, dailyCap: event.target.value })}\n error={typeof capCheck !== 'number'}\n slotProps={{ htmlInput: { min: 1, max: OUTREACH_MAX_DAILY_CAP, step: 1 } }}\n helperText={\n typeof capCheck !== 'number'\n ? capCheck.message\n : draft.warmUp\n ? `${RAMP_SENTENCE} Today’s limit: ${todayLimit}.`\n : `No warm-up: today’s limit is the cap, ${todayLimit}.`\n }\n />\n <FormControlLabel\n control={\n <Switch\n checked={draft.warmUp}\n onChange={(event) => setDraft({ ...draft, warmUp: event.target.checked })}\n />\n }\n label={MAILBOX_ACTION_LABELS.warmUp}\n />\n <FormHelperText sx={{ mt: -1 }}>\n {'For a mailbox that is new or has not sent much. One that has sent mail for years already has ' +\n 'its reputation and can start at its cap.'}\n </FormHelperText>\n <Box>\n <Typography variant=\"subtitle2\" gutterBottom>\n Sending window\n </Typography>\n <ToggleButtonGroup\n size=\"small\"\n aria-label=\"Sending days\"\n value={draft.window.days}\n onChange={(_event, days: number[]) =>\n setDraft({ ...draft, window: { ...draft.window, days: [...days].sort((a, b) => a - b) } })\n }\n >\n {OUTREACH_WEEKDAY_LABELS.map((label, day) => (\n <ToggleButton key={label} value={day} aria-label={WEEKDAY_NAMES[day]}>\n {label}\n </ToggleButton>\n ))}\n </ToggleButtonGroup>\n <Stack direction={{ xs: 'column', sm: 'row' }} spacing={2} sx={{ mt: 2 }}>\n <TextField\n select\n size=\"small\"\n label=\"From\"\n value={draft.window.startMinute}\n onChange={(event) =>\n setDraft({ ...draft, window: { ...draft.window, startMinute: Number(event.target.value) } })\n }\n >\n {MINUTE_OPTIONS.slice(0, -1).map((minute) => (\n <MenuItem key={minute} value={minute}>\n {formatMinuteOfDay(minute)}\n </MenuItem>\n ))}\n </TextField>\n <TextField\n select\n size=\"small\"\n label=\"Until\"\n value={draft.window.endMinute}\n onChange={(event) =>\n setDraft({ ...draft, window: { ...draft.window, endMinute: Number(event.target.value) } })\n }\n >\n {MINUTE_OPTIONS.slice(1).map((minute) => (\n <MenuItem key={minute} value={minute}>\n {formatMinuteOfDay(minute)}\n </MenuItem>\n ))}\n </TextField>\n <Autocomplete\n size=\"small\"\n disableClearable\n options={timezoneOptions(mailbox.timezone)}\n value={draft.timezone}\n onChange={(_event, timezone) => setDraft({ ...draft, timezone: timezone ?? draft.timezone })}\n sx={{ minWidth: 240 }}\n renderInput={(params) => <TextField {...params} label=\"Timezone\" />}\n />\n </Stack>\n {'days' in windowCheck ? null : <FormHelperText error>{windowCheck.message}</FormHelperText>}\n </Box>\n {saveError ? <FormHelperText error>{saveError}</FormHelperText> : null}\n <Box>\n <Button variant=\"contained\" disabled={!dirty || invalid || saving} onClick={() => void save()}>\n {MAILBOX_ACTION_LABELS.save}\n </Button>\n </Box>\n </Stack>\n ) : (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {`Sends as ${sendAsLabel(stored.sendAs)}, at most ${stored.dailyCap} a day, ` +\n `${stored.window.days.map((day) => OUTREACH_WEEKDAY_LABELS[day]).join(', ')} ` +\n `${formatMinuteOfDay(stored.window.startMinute)}–${formatMinuteOfDay(stored.window.endMinute)} ` +\n `(${stored.timezone}).`}\n </Typography>\n )}\n\n {isMine && !needsReconnect ? (\n <TextField\n label={MAILBOX_ACTION_LABELS.testAddress}\n value={testAddress}\n onChange={(event) => setTestAddress(event.target.value)}\n disabled={busy !== null}\n size=\"small\"\n type=\"email\"\n helperText={\n 'Leave empty to send the test to yourself. A test to an outside mailbox you can ' +\n 'read is the only one whose original source shows the sender authentication results.'\n }\n fullWidth\n />\n ) : null}\n\n {canManage || isMine ? (\n <Stack direction=\"row\" spacing={1} useFlexGap sx={{ flexWrap: 'wrap' }}>\n {canManage && !needsReconnect ? (\n <Button variant=\"outlined\" disabled={busy !== null} onClick={() => void togglePaused()}>\n {mailbox.status === 'paused' ? MAILBOX_ACTION_LABELS.resume : MAILBOX_ACTION_LABELS.pause}\n </Button>\n ) : null}\n {isMine && !needsReconnect ? (\n <Button variant=\"outlined\" disabled={busy !== null} onClick={() => void sendTest()}>\n {testAddress.trim() ? MAILBOX_ACTION_LABELS.testElsewhere : MAILBOX_ACTION_LABELS.test}\n </Button>\n ) : null}\n {canManage ? (\n <Button color=\"error\" disabled={busy !== null} onClick={() => void disconnect()}>\n {MAILBOX_ACTION_LABELS.disconnect}\n </Button>\n ) : null}\n </Stack>\n ) : null}\n </Stack>\n </CardDisplay>\n )\n}\nMailboxCard.displayName = 'MailboxCard'\n\nexport default MailboxCard\n"],"names":["pluginDocsHelp","CardDisplay","useConfirmationContext","useSnackbar","SenderReadinessPanel","Alert","Autocomplete","Box","Button","Chip","FormControlLabel","FormHelperText","MenuItem","Stack","Switch","TextField","ToggleButton","ToggleButtonGroup","Typography","useEffect","useMemo","useRef","useState","formatMinuteOfDay","isValidTimezone","OUTREACH_DEFAULT_WINDOW","OUTREACH_MAILBOX_STATUS_LABELS","OUTREACH_MAX_DAILY_CAP","OUTREACH_RAMP_STEPS","OUTREACH_WEEKDAY_LABELS","outreachEffectiveDailyCap","outreachLocalDay","summarizeMailboxHealth","validateDailyCap","validateDisplayName","validateSendWindow","outreachPacingNote","autoPauseSentence","mailbox","pause","autoPause","day","atMs","Intl","DateTimeFormat","dateStyle","timeZone","timezone","format","until","untilMs","message","MAILBOX_ACTION_LABELS","save","resume","test","testElsewhere","testAddress","warmUp","disconnect","reconnect","recheckReadiness","WEEKDAY_NAMES","STATUS_COLOR","connected","paused","reconnect_required","disconnected","MINUTE_OPTIONS","Array","from","length","_","index","timezoneOptions","current","supported","supportedValuesOf","zones","includes","RAMP_SENTENCE","map","step","week","limit","join","draftOf","sendAs","email","displayName","dailyCap","String","window","rampStartedAtMs","MailboxCard","props","isMine","canManage","api","onReconnect","reconnecting","nowMs","Date","now","enqueueSnackbar","confirm","microsoft","provider","providerName","draft","setDraft","saving","setSaving","saveError","setSaveError","busy","setBusy","setTestAddress","sendAsAddress","readiness","setReadiness","readinessBusy","setReadinessBusy","active","id","then","answer","catch","error","variant","allowDuplicate","stored","storedKey","JSON","stringify","seededFrom","dirty","previous","health","testsToday","Math","max","Number","daily","tests","needsReconnect","status","capCheck","NaN","windowCheck","nameCheck","timezoneValid","invalid","todayLimit","saveSettings","mailboxId","togglePaused","setPaused","sendTest","to","trim","sent","undefined","sentTo","confirmed","title","description","confirmationText","confirmationButtonProps","color","revocation","persist","sendAsLabel","option","sendAsOptions","find","entry","header","subheader","help","anchor","contentGutterX","contentGutterY","HeaderProps","action","size","label","spacing","severity","disabled","onClick","role","hasSent","direction","sx","mt","bounces","replies","value","aria-label","component","slice","lastIndexOf","onSubmit","event","preventDefault","select","onChange","target","helperText","type","slotProps","htmlInput","min","control","checked","gutterBottom","days","_event","sort","a","b","xs","sm","startMinute","minute","endMinute","disableClearable","options","minWidth","renderInput","params","fullWidth","useFlexGap","flexWrap"],"mappings":"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"}
@@ -371,8 +371,7 @@ const SequenceSiteField = /*#__PURE__*/ memo(function SequenceSiteField(props) {
371
371
  return /*#__PURE__*/ _jsx(CardDisplay, {
372
372
  header: "Who it sends to, and when",
373
373
  help: pluginDocsHelp('sequences', {
374
- anchor: '#build-a-sequence',
375
- excerpt: 'A sequence sends only to the countries both it and your organization allow, and in its mailbox’s sending hours unless it has its own.'
374
+ anchor: '#sequence-sending-settings'
376
375
  }),
377
376
  contentGutterX: true,
378
377
  contentGutterY: true,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../../libs/plugins/outreach/src/lib/components/sequence-editor.tsx"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n'use client'\n\nimport { pluginDocsHelp, type ConsolePluginOrgMount } from '@aglyn/aglyn'\nimport { consentGroupForHost } from '@aglyn/aglyn/app-utils/consent-groups'\nimport { mdiPlus } from '@aglyn/shared-data-mdi'\nimport { CardDisplay, MdiIcon } from '@aglyn/shared-ui-jsx'\nimport ContainerPicker, {\n type ContainerPickerProps,\n} from '@aglyn/tenant-feature-instance/components/container-picker'\nimport { useSnackbar } from '@aglyn/shared-ui-snackstack'\nimport { useOrgContainerOptions, useUser } from '@aglyn/tenant-feature-instance'\nimport {\n Alert,\n Autocomplete,\n Box,\n Button,\n Chip,\n FormControlLabel,\n Grid,\n Menu,\n MenuItem,\n Stack,\n Switch,\n TextField,\n Typography,\n} from '@mui/material'\nimport { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react'\nimport {\n isInThreadEmailStep,\n OUTREACH_SEQUENCE_NAME_MAX,\n validateOutreachSequence,\n} from '../engine/sequence-validation'\nimport { outreachCountryLabel } from '../model/compliance-settings'\nimport {\n OUTREACH_MAX_EMAIL_STEPS,\n OUTREACH_MAX_STEPS,\n OUTREACH_TASK_KIND_LABELS,\n OUTREACH_TASK_KINDS,\n type OutreachSequence,\n type OutreachSequenceStep,\n type OutreachTaskKind,\n} from '../model/outreach.types'\nimport {\n emptyOutreachSequenceDraft,\n newOutreachEmailStep,\n newOutreachTaskStep,\n outreachSequenceDraftOf,\n type OutreachSequenceDraft,\n type OutreachSequenceIssue,\n} from '../model/sequence-draft'\nimport { OutreachSendWindowFields } from './send-window-fields'\nimport { OutreachSequenceMailboxPicker, OutreachSequenceRotationPicker } from './sequence-mailbox-picker'\nimport { OutreachSequencePreview } from './sequence-preview'\nimport {\n OutreachStepCard,\n type OutreachStepCardProps,\n} from './sequence-step-card'\nimport { OutreachStepTestDialog } from './step-test-dialog'\nimport { OutreachRouteError, useOutreachApi } from './use-outreach-api'\nimport { useOutreachEmailTemplates } from './use-outreach-crm'\nimport type { OutreachMailboxesResult } from './use-outreach-mailboxes'\nimport type { OutreachSettingsLoad } from './use-outreach-settings'\n\nexport interface OutreachSequenceEditorProps {\n orgId: string\n orgMount?: ConsolePluginOrgMount\n /** The organization document, for the consent group a test send's person picker searches (AGL-3325). */\n org?: Record<string, unknown> | null\n /** The stored sequence, or `null` for a new one. */\n sequence: OutreachSequence | null\n /** The organization's compliance settings: its countries, and the preview's footer. */\n settings: OutreachSettingsLoad\n /**\n * The organization's mailboxes, from the Mailboxes section's listener:\n * what the picker offers, and who the preview's emails are from.\n */\n mailboxes: OutreachMailboxesResult\n /** The Mailboxes section, where the picker sends a member to connect one. */\n mailboxesPath: string\n onSaved(sequence: OutreachSequence): void\n onCancel?(): void\n}\n\n/** The step a dotted issue path is about, and the field within it. */\nfunction stepIssueKey(path: string): { index: number; field: string } | null {\n const match = /^steps\\.(\\d+)(?:\\.(.+))?$/.exec(path)\n if (!match) return null\n const field = match[2] ?? 'step'\n return { index: Number(match[1]), field: field === 'id' ? 'step' : field }\n}\n\ninterface OutreachCountriesFieldProps {\n options: readonly string[]\n value: readonly string[]\n onChange(next: string[]): void\n issue?: string\n disabled: boolean\n}\n\n/**\n * The countries a sequence sends to, as chips in an Autocomplete.\n *\n * MEMOIZED, AND EVERY PROP IT TAKES IS STABLE WHILE THE COUNTRIES ARE\n * (AGL-3423). A multiple Autocomplete hands its input a new chip array as\n * `startAdornment` on every render, and MUI's `InputBase` copies that into\n * its `FormControl` from a passive effect — a state update after every\n * commit this field takes part in. React 19 counts a commit that leaves such\n * an update pending as a nested update, and keystrokes the browser delivers\n * back to back (a held key, fast typing on a busy page) commit one after\n * another with nothing in between to clear the count: fifty-one of them and\n * the next keystroke's own `setState` throws \"Maximum update depth exceeded\"\n * (minified error #185), which is what typing a step's body reported. Kept\n * out of the editor's other renders, the field commits only when the\n * countries, their options or their issue change.\n */\nconst OutreachCountriesField = memo(function OutreachCountriesField(\n props: OutreachCountriesFieldProps,\n) {\n return (\n <Autocomplete<string, true>\n multiple\n options={props.options}\n value={props.value as string[]}\n getOptionLabel={outreachCountryLabel}\n onChange={(_event, next) => props.onChange(next)}\n disabled={props.disabled}\n renderValue={(value, getItemProps) =>\n value.map((code, index) => {\n const { key, ...item } = getItemProps({ index })\n return (\n <Chip\n key={key}\n size=\"small\"\n label={outreachCountryLabel(code)}\n {...item}\n />\n )\n })\n }\n renderInput={(params) => (\n <TextField\n {...params}\n label=\"Countries\"\n error={Boolean(props.issue)}\n helperText={\n props.issue ??\n 'Among the countries your organization allows. Cold contacts are emailed only in the United States.'\n }\n />\n )}\n />\n )\n})\n\n/** Each step's issues by the field they are about, as its card reads them. */\ntype StepIssues = Partial<Record<string, string>>\n\n/**\n * Each step's issues, the SAME record for a step while what it holds reads\n * the same (AGL-3423), so a step a keystroke did not touch keeps its props.\n */\nfunction useStepIssues(\n issues: readonly OutreachSequenceIssue[],\n count: number,\n): StepIssues[] {\n const held = useRef<Array<{ key: string; value: StepIssues }>>([])\n return useMemo(() => {\n const found: Record<string, string>[] = Array.from(\n { length: count },\n () => ({}),\n )\n for (const issue of issues) {\n const key = stepIssueKey(issue.path)\n const record = key ? found[key.index] : undefined\n if (key && record && !record[key.field])\n record[key.field] = issue.message\n }\n held.current = found.map((value, index) => {\n const key = JSON.stringify(value)\n const before = held.current[index]\n return before?.key === key ? before : { key, value }\n })\n return held.current.map((entry) => entry.value)\n }, [issues, count])\n}\n\n/** A text field that redraws only when what it shows changes (AGL-3423). */\nconst MemoTextField = memo(TextField) as typeof TextField\n\n/*\n * The sections below are drawn from the one draft, and each redraws only\n * when what it shows changes (AGL-3423).\n */\nconst MemoMailboxPicker = memo(OutreachSequenceMailboxPicker)\nconst MemoRotationPicker = memo(OutreachSequenceRotationPicker)\n/** A stable empty rotation, so the picker's props hold still while there is none. */\nconst NO_ROTATION: readonly string[] = []\nconst MemoContainerPicker = memo(ContainerPicker)\nconst MemoSendWindowFields = memo(OutreachSendWindowFields)\nconst MemoSequencePreview = memo(OutreachSequencePreview)\n\ntype FieldChange = { target: { value: string } }\ntype SwitchChange = { target: { checked: boolean } }\ntype SequenceSettings = OutreachSequenceDraft['settings']\n\nconst NAME_SLOT_PROPS = {\n htmlInput: { maxLength: OUTREACH_SEQUENCE_NAME_MAX + 20 },\n}\nconst ADD_STEP_ROW = { flexWrap: 'wrap', rowGap: 1 } as const\nconst PREVIEW_COLUMN = {\n position: { md: 'sticky' },\n top: { md: 16 },\n} as const\n\nconst SequenceSiteField = memo(function SequenceSiteField(props: {\n hosts: ConsolePluginOrgMount['hosts']\n value: string\n issue?: string\n disabled: boolean\n onChange(event: FieldChange): void\n}) {\n const { hosts, value, issue } = props\n return (\n <TextField\n select\n label=\"Site\"\n value={hosts.some((host) => host.id === value) ? value : ''}\n onChange={props.onChange}\n disabled={props.disabled || !hosts.length}\n error={Boolean(issue)}\n helperText={issue ?? 'The site whose contacts this sequence emails.'}\n fullWidth\n >\n {hosts.map((host) => (\n <MenuItem key={host.id} value={host.id}>\n {host.name}\n </MenuItem>\n ))}\n </TextField>\n )\n})\n\n/** The sequence card's header actions: Cancel, and the save of the whole sequence. */\nconst SequenceSaveActions = memo(function SequenceSaveActions(props: {\n saving: boolean\n /** \"Save\" for a stored sequence, \"Create sequence\" for a new one. */\n saveLabel: string\n onCancel?(): void\n onSave(): void\n}) {\n return (\n <Stack direction=\"row\" spacing={1}>\n {props.onCancel ? (\n <Button\n size=\"small\"\n variant=\"text\"\n onClick={props.onCancel}\n disabled={props.saving}\n >\n Cancel\n </Button>\n ) : null}\n <Button\n size=\"small\"\n variant=\"contained\"\n onClick={props.onSave}\n disabled={props.saving}\n >\n {props.saving ? 'Saving…' : props.saveLabel}\n </Button>\n </Stack>\n )\n})\n\ninterface SequenceCardProps {\n orgId: string\n uid: string | null\n name: string\n hostId: string\n mailboxId: string\n /** The mailboxes it rotates through beside its own (AGL-3489). */\n mailboxIds: readonly string[]\n campaignIds: readonly string[]\n hosts: ConsolePluginOrgMount['hosts']\n mailboxes: OutreachMailboxesResult\n mailboxesPath: string\n campaignOptions: ContainerPickerProps['options']\n /** The organization has no campaigns at all. */\n noCampaigns: boolean\n nameIssue?: string\n hostIssue?: string\n mailboxIssue?: string\n rotationIssue?: string\n campaignsIssue?: string\n archived: boolean\n saving: boolean\n saveLabel: string\n onCancel?(): void\n onSave(): void\n onName(event: FieldChange): void\n onHost(event: FieldChange): void\n onMailbox(mailboxId: string): void\n onRotation(mailboxIds: string[]): void\n onCampaigns(campaignIds: string[]): void\n}\n\n/** The sequence's own card: its name, site, mailbox and campaigns. */\nconst SequenceCard = memo(function SequenceCard(props: SequenceCardProps) {\n const { archived } = props\n return (\n <CardDisplay\n header=\"Sequence\"\n help={pluginDocsHelp('sequences', { anchor: '#build-a-sequence' })}\n // The whole sequence (steps and sending rules included) saves\n // from its first card's header, where the console puts a card's\n // actions (AGL-3333).\n HeaderProps={{\n action: archived ? undefined : (\n <SequenceSaveActions\n saving={props.saving}\n saveLabel={props.saveLabel}\n onCancel={props.onCancel}\n onSave={props.onSave}\n />\n ),\n }}\n contentGutterX\n contentGutterY\n >\n <Stack spacing={2}>\n <MemoTextField\n label=\"Name\"\n value={props.name}\n onChange={props.onName}\n disabled={archived}\n error={Boolean(props.nameIssue)}\n helperText={props.nameIssue}\n slotProps={NAME_SLOT_PROPS}\n fullWidth\n />\n <SequenceSiteField\n hosts={props.hosts}\n value={props.hostId}\n issue={props.hostIssue}\n disabled={archived}\n onChange={props.onHost}\n />\n <MemoMailboxPicker\n orgId={props.orgId}\n uid={props.uid}\n mailboxes={props.mailboxes}\n mailboxesPath={props.mailboxesPath}\n value={props.mailboxId}\n onChange={props.onMailbox}\n error={props.mailboxIssue}\n disabled={archived}\n />\n <MemoRotationPicker\n orgId={props.orgId}\n uid={props.uid}\n mailboxes={props.mailboxes}\n mailboxId={props.mailboxId}\n value={props.mailboxIds}\n onChange={props.onRotation}\n error={props.rotationIssue}\n disabled={archived}\n />\n {/*\n The campaigns this sequence is part of (AGL-3254), picked the\n way a form's page picks them. Everyone enrolled joins them,\n and what the sequence produces is reported under them; it\n does not change who is enrolled or what is sent.\n */}\n <MemoContainerPicker\n kind=\"campaign\"\n options={props.campaignOptions}\n value={props.campaignIds}\n onChange={props.onCampaigns}\n label=\"Campaigns\"\n helperText={\n props.campaignsIssue ??\n 'The campaigns this sequence is part of. Everyone enrolled joins them, and its sends, replies, meetings and conversions count on their pages.'\n }\n disabled={archived}\n empty={props.noCampaigns}\n emptyText=\"There are no campaigns yet. Create one from Marketing to file this sequence under it.\"\n />\n </Stack>\n </CardDisplay>\n )\n})\n\ninterface SequenceStepItemProps\n extends Omit<\n OutreachStepCardProps,\n 'onChange' | 'onMove' | 'onRemove' | 'onSendTest'\n > {\n /** Whether the step offers a test send: an email in a sequence that is not archived. */\n canSendTest: boolean\n onStepChange(index: number, step: OutreachSequenceStep): void\n onStepMove(index: number, direction: -1 | 1): void\n onStepRemove(index: number): void\n onStepTest(index: number): void\n}\n\n/**\n * One step's card, bound to its position. Memoized, with handlers that keep\n * their identity, so a keystroke in one step leaves the others undrawn.\n */\nconst SequenceStepItem = memo(function SequenceStepItem(\n props: SequenceStepItemProps,\n) {\n const {\n index,\n canSendTest,\n onStepChange,\n onStepMove,\n onStepRemove,\n onStepTest,\n ...card\n } = props\n const onChange = useCallback(\n (step: OutreachSequenceStep) => onStepChange(index, step),\n [index, onStepChange],\n )\n const onMove = useCallback(\n (direction: -1 | 1) => onStepMove(index, direction),\n [index, onStepMove],\n )\n const onRemove = useCallback(\n () => onStepRemove(index),\n [index, onStepRemove],\n )\n const onSendTest = useCallback(() => onStepTest(index), [index, onStepTest])\n return (\n <OutreachStepCard\n {...card}\n index={index}\n onChange={onChange}\n onMove={onMove}\n onRemove={onRemove}\n onSendTest={canSendTest ? onSendTest : undefined}\n />\n )\n})\n\n/** Adds an email, or a task of a kind picked from its menu. */\nconst SequenceAddStep = memo(function SequenceAddStep(props: {\n emailDisabled: boolean\n taskDisabled: boolean\n onAddEmail(): void\n onAddTask(kind: OutreachTaskKind): void\n}) {\n const { onAddTask } = props\n const [taskAnchor, setTaskAnchor] = useState<HTMLElement | null>(null)\n return (\n <Stack direction=\"row\" spacing={1} sx={ADD_STEP_ROW}>\n <Button\n variant=\"outlined\"\n startIcon={<MdiIcon path={mdiPlus.path} fontSize=\"small\" />}\n disabled={props.emailDisabled}\n onClick={props.onAddEmail}\n >\n Add email\n </Button>\n <Button\n variant=\"outlined\"\n startIcon={<MdiIcon path={mdiPlus.path} fontSize=\"small\" />}\n disabled={props.taskDisabled}\n onClick={(event) => setTaskAnchor(event.currentTarget)}\n aria-haspopup=\"menu\"\n >\n Add task\n </Button>\n <Menu\n anchorEl={taskAnchor}\n open={Boolean(taskAnchor)}\n onClose={() => setTaskAnchor(null)}\n >\n {OUTREACH_TASK_KINDS.map((kind: OutreachTaskKind) => (\n <MenuItem\n key={kind}\n onClick={() => {\n setTaskAnchor(null)\n onAddTask(kind)\n }}\n >\n {OUTREACH_TASK_KIND_LABELS[kind]}\n </MenuItem>\n ))}\n </Menu>\n </Stack>\n )\n})\n\ninterface SequenceSendingCardProps {\n settings: SequenceSettings\n countryOptions: readonly string[]\n countriesIssue?: string\n daysIssue?: string\n hoursIssue?: string\n disabled: boolean\n onCountries(next: string[]): void\n onSettings(patch: Partial<SequenceSettings>): void\n}\n\n/** Who the sequence sends to, and when: its countries, switches and hours. */\nconst SequenceSendingCard = memo(function SequenceSendingCard(\n props: SequenceSendingCardProps,\n) {\n const { settings, disabled, onSettings } = props\n const setAllowCustomers = useCallback(\n (event: SwitchChange) =>\n onSettings({ allowCustomers: event.target.checked }),\n [onSettings],\n )\n const setTrackClicks = useCallback(\n (event: SwitchChange) => onSettings({ trackClicks: event.target.checked }),\n [onSettings],\n )\n const setCountOpens = useCallback(\n (event: SwitchChange) => onSettings({ countOpens: event.target.checked }),\n [onSettings],\n )\n const setListUnsubscribe = useCallback(\n (event: SwitchChange) =>\n onSettings({ listUnsubscribe: event.target.checked }),\n [onSettings],\n )\n const setWindow = useCallback(\n (window: SequenceSettings['window']) => onSettings({ window }),\n [onSettings],\n )\n return (\n <CardDisplay\n header=\"Who it sends to, and when\"\n help={pluginDocsHelp('sequences', {\n anchor: '#build-a-sequence',\n excerpt:\n 'A sequence sends only to the countries both it and your organization allow, and in its mailbox’s sending hours unless it has its own.',\n })}\n contentGutterX\n contentGutterY\n >\n <Stack spacing={2}>\n <OutreachCountriesField\n options={props.countryOptions}\n value={settings.allowedCountries}\n onChange={props.onCountries}\n issue={props.countriesIssue}\n disabled={disabled}\n />\n <FormControlLabel\n control={\n <Switch\n checked={settings.allowCustomers}\n onChange={setAllowCustomers}\n disabled={disabled}\n />\n }\n label=\"Include customers\"\n />\n {/*\n * Click tracking (AGL-3239), with its cost stated where it is\n * chosen rather than in a document nobody opens. Off by\n * default: it changes the link a cold recipient sees. The\n * emails stay plain text either way; opens are the separate\n * switch below.\n */}\n <Stack spacing={0}>\n <FormControlLabel\n control={\n <Switch\n checked={settings.trackClicks}\n onChange={setTrackClicks}\n disabled={disabled}\n />\n }\n label=\"Count link clicks\"\n />\n <Typography variant=\"caption\" color=\"text.secondary\">\n Links in these emails are replaced with links of ours that\n forward to the same page, so clicks can be counted. The\n recipient sees the replacement, not your address. The\n emails stay plain text.\n </Typography>\n </Stack>\n {/*\n * Open counting (AGL-3395), off by default, its cost stated\n * where it is chosen: an HTML copy with a tracking image is the\n * least one-to-one thing a sequence email can carry, so it is\n * for measuring a slice, not for every sequence.\n */}\n <Stack spacing={0}>\n <FormControlLabel\n control={\n <Switch\n checked={settings.countOpens}\n onChange={setCountOpens}\n disabled={disabled}\n />\n }\n label=\"Count opens\"\n />\n <Typography variant=\"caption\" color=\"text.secondary\">\n Each email also goes out as HTML — the same words — with a\n tiny tracking image, so opens can be counted. The plain-text\n version is unchanged. It makes the email look less like one\n written by hand, and some spam filters score HTML with a\n remote image against you, so turn it on to measure a slice\n of your sends rather than for every sequence. Gmail opens\n count; Apple Mail loads every image on arrival, so its loads\n are counted separately.\n </Typography>\n </Stack>\n {/*\n * The mail-client unsubscribe button (AGL-3296), off by\n * default: the header is what makes Apple Mail, Gmail and\n * Outlook present a one-to-one email as a mailing list. The\n * footer's \"reply 'no'\" line is the way out either way.\n */}\n <Stack spacing={0}>\n <FormControlLabel\n control={\n <Switch\n checked={settings.listUnsubscribe}\n onChange={setListUnsubscribe}\n disabled={disabled}\n />\n }\n label=\"Add a mail-client unsubscribe button\"\n />\n <Typography variant=\"caption\" color=\"text.secondary\">\n Adds the List-Unsubscribe header, so the recipient’s mail\n app shows its own Unsubscribe button. It’s the easiest way\n out for them, and fewer people mark you as spam when they\n have it, but mail apps then label the email as coming from\n a mailing list. Off, the footer’s “reply ‘no’” line is the\n way out, and it’s always there.\n </Typography>\n </Stack>\n <MemoSendWindowFields\n window={settings.window}\n onChange={setWindow}\n daysIssue={props.daysIssue}\n hoursIssue={props.hoursIssue}\n disabled={disabled}\n />\n </Stack>\n </CardDisplay>\n )\n})\n\n/**\n * The sequence editor (AGL-2980): the name, the site and mailbox, the steps,\n * who it sends to and when, beside a live preview of each email.\n *\n * Every issue the engine's validator finds is shown beside its field — the\n * same validator the save route refuses with — errors once a save was\n * attempted, warnings as soon as they appear. What only the server can\n * judge (whose mailbox, which countries the organization allows, what may\n * no longer change once people are enrolled) comes back from the save and\n * is shown in the same places.\n *\n * ## A keystroke redraws its own field (AGL-3423)\n *\n * The whole sequence is one draft, so every letter typed anywhere is a new\n * draft, and drawing the editor from it inline redrew every field of every\n * step, the settings and the preview with each one: 17 inputs and some 1,150\n * components for one letter in a three-step sequence. That cost is what lets\n * typed input queue, and queued keystrokes processed back to back are what\n * drove the countries chips into React's #185. The sequence card, each step,\n * the sending card and the preview are memoized and handed only what they\n * show, through handlers that keep their identity; the handlers that wrote\n * from the draft as drawn still do, through `drawn`. A letter now redraws the\n * field it lands in, and the preview when it shows that step's email.\n */\nexport function OutreachSequenceEditor(props: OutreachSequenceEditorProps) {\n const { orgId, orgMount, sequence, settings } = props\n const api = useOutreachApi(orgId)\n const { enqueueSnackbar } = useSnackbar()\n const { data: user } = useUser()\n const uid = user?.uid ?? null\n const mountedHosts = orgMount?.hosts\n const hosts = useMemo(() => mountedHosts ?? [], [mountedHosts])\n const allowedCountries = settings.settings?.allowedCountries\n const orgCountries = useMemo(\n () => allowedCountries ?? ['US'],\n [allowedCountries],\n )\n\n const [draft, setDraft] = useState<OutreachSequenceDraft>(() =>\n sequence\n ? outreachSequenceDraftOf(sequence)\n : emptyOutreachSequenceDraft({\n hostId: hosts.length === 1 ? hosts[0].id : '',\n allowedCountries: orgCountries,\n }),\n )\n const [attempted, setAttempted] = useState(false)\n const [serverIssues, setServerIssues] = useState<OutreachSequenceIssue[]>([])\n const [saving, setSaving] = useState(false)\n // The step whose test-send dialog is open (AGL-3325), by index.\n const [testing, setTesting] = useState<number | null>(null)\n // The draft as last drawn, which the handlers that build on it read.\n const drawn = useRef(draft)\n drawn.current = draft\n\n // A stored sequence the listener updated (a save, a status change) is the\n // new starting point.\n useEffect(() => {\n if (sequence) setDraft(outreachSequenceDraftOf(sequence))\n }, [sequence])\n // A new sequence starts on the organization's countries once they are read.\n const settingsCountries = settings.settings?.allowedCountries.join(',')\n useEffect(() => {\n if (!sequence && settingsCountries) {\n setDraft((previous) => ({\n ...previous,\n settings: {\n ...previous.settings,\n allowedCountries: settingsCountries.split(','),\n },\n }))\n }\n }, [sequence, settingsCountries])\n useEffect(() => {\n if (!sequence && !draft.hostId && hosts.length === 1)\n setDraft((previous) => ({ ...previous, hostId: hosts[0].id }))\n }, [sequence, draft.hostId, hosts])\n\n // A new sequence starts on the member's own mailbox when they have exactly\n // one that is sending.\n const ownSending = props.mailboxes.mailboxes.filter(\n (entry) => entry.connectedByUid === uid && entry.status === 'connected',\n )\n const onlyOwnMailbox = ownSending.length === 1 ? ownSending[0].id : ''\n useEffect(() => {\n if (!sequence && !draft.mailboxId && onlyOwnMailbox)\n setDraft((previous) => ({ ...previous, mailboxId: onlyOwnMailbox }))\n }, [sequence, draft.mailboxId, onlyOwnMailbox])\n\n const templates = useOutreachEmailTemplates(orgId, draft.hostId || null, uid)\n const mailbox =\n props.mailboxes.mailboxes.find((entry) => entry.id === draft.mailboxId) ??\n null\n const sender = useMemo(\n () =>\n mailbox\n ? { name: mailbox.displayName, email: mailbox.sendAs || mailbox.email }\n : null,\n [mailbox],\n )\n const archived = sequence?.status === 'archived'\n /*\n * The org's campaigns, for the picker (AGL-3254): read while the editor\n * is open. A sequence is the organization's record and so is a campaign,\n * so the choice is every campaign in the org, whichever site the\n * sequence sends as.\n */\n const campaigns = useOrgContainerOptions('campaign', orgId, { enabled: true })\n\n const issues = useMemo(() => {\n const judged = [\n ...validateOutreachSequence(draft),\n ...serverIssues,\n ] as OutreachSequenceIssue[]\n return judged.filter(\n (issue) =>\n issue.severity === 'warning' ||\n attempted ||\n serverIssues.includes(issue),\n )\n }, [draft, serverIssues, attempted])\n const issueAt = (path: string) =>\n issues.find((issue) => issue.path === path)?.message\n const stepIssues = useStepIssues(issues, draft.steps.length)\n const listIssue = issueAt('steps')\n const countriesIssue = issues.find((issue) =>\n issue.path.startsWith('settings.allowedCountries'),\n )?.message\n\n // An edit clears what the last save refused. The empty list stays the same\n // list, so an edit with nothing to clear does not change that state.\n const clearServerIssues = useCallback(\n () => setServerIssues((previous) => (previous.length ? [] : previous)),\n [],\n )\n const update = useCallback(\n (next: Partial<OutreachSequenceDraft>) => {\n clearServerIssues()\n setDraft((previous) => ({ ...previous, ...next }))\n },\n [clearServerIssues],\n )\n // Stable, for the memoized countries field: it reads the settings it\n // replaces from the draft it is given rather than from this render's.\n const setCountries = useCallback(\n (next: string[]) => {\n clearServerIssues()\n setDraft((previous) => ({\n ...previous,\n settings: { ...previous.settings, allowedCountries: next },\n }))\n },\n [clearServerIssues],\n )\n const setName = useCallback(\n (event: FieldChange) => update({ name: event.target.value }),\n [update],\n )\n const setHost = useCallback(\n (event: FieldChange) => update({ hostId: event.target.value }),\n [update],\n )\n const setMailbox = useCallback(\n (mailboxId: string) =>\n update({\n mailboxId,\n // The sequence's own mailbox is never also one it rotates through.\n mailboxIds: drawn.current.mailboxIds?.filter((id) => id !== mailboxId).length\n ? drawn.current.mailboxIds.filter((id) => id !== mailboxId)\n : undefined,\n }),\n [update],\n )\n const setRotation = useCallback(\n (mailboxIds: string[]) => update({ mailboxIds: mailboxIds.length ? mailboxIds : undefined }),\n [update],\n )\n const setCampaigns = useCallback(\n (campaignIds: string[]) => update({ campaignIds }),\n [update],\n )\n const setSettings = useCallback(\n (patch: Partial<SequenceSettings>) =>\n update({ settings: { ...drawn.current.settings, ...patch } }),\n [update],\n )\n const setStep = useCallback(\n (index: number, step: OutreachSequenceStep) =>\n update({\n steps: drawn.current.steps.map((entry, position) =>\n position === index ? step : entry,\n ),\n }),\n [update],\n )\n const moveStep = useCallback(\n (index: number, direction: -1 | 1) => {\n const steps = [...drawn.current.steps]\n const [moved] = steps.splice(index, 1)\n steps.splice(index + direction, 0, moved)\n update({ steps })\n },\n [update],\n )\n const removeStep = useCallback(\n (index: number) =>\n update({\n steps: drawn.current.steps.filter(\n (_entry, position) => position !== index,\n ),\n }),\n [update],\n )\n const addEmail = useCallback(\n () =>\n update({\n steps: [\n ...drawn.current.steps,\n newOutreachEmailStep(drawn.current.steps),\n ],\n }),\n [update],\n )\n const addTask = useCallback(\n (kind: OutreachTaskKind) =>\n update({\n steps: [\n ...drawn.current.steps,\n newOutreachTaskStep(drawn.current.steps, kind),\n ],\n }),\n [update],\n )\n const emailCount = draft.steps.filter((step) => step.kind === 'email').length\n const full = draft.steps.length >= OUTREACH_MAX_STEPS\n const firstEmail = draft.steps.findIndex((entry) => entry.kind === 'email')\n const threadSubject = (index: number) => {\n for (let position = index - 1; position >= 0; position -= 1) {\n const step = draft.steps[position]\n if (step.kind === 'email' && !isInThreadEmailStep(draft.steps, position))\n return step.subject\n }\n return ''\n }\n\n const save = async () => {\n setAttempted(true)\n if (\n validateOutreachSequence(draft).some(\n (issue) => issue.severity === 'error',\n )\n )\n return\n setSaving(true)\n try {\n const answer = await api.saveSequence(sequence?.id ?? null, draft)\n setServerIssues([])\n setAttempted(false)\n enqueueSnackbar(\n answer.created ? 'Sequence created.' : 'Sequence saved.',\n { variant: 'success' },\n )\n props.onSaved(answer.sequence)\n } catch (error) {\n if (error instanceof OutreachRouteError && error.issues.length) {\n setServerIssues(\n error.issues.filter(\n (issue): issue is OutreachSequenceIssue => 'path' in issue,\n ),\n )\n }\n enqueueSnackbar((error as Error).message, {\n variant: 'error',\n allowDuplicate: true,\n })\n } finally {\n setSaving(false)\n }\n }\n // The save as last drawn, behind a handler that keeps its identity.\n const drawnSave = useRef(save)\n drawnSave.current = save\n const onSave = useCallback(() => void drawnSave.current(), [])\n\n const siteName = hosts.find((host) => host.id === draft.hostId)?.name ?? ''\n const draftCountries = draft.settings.allowedCountries\n const countryOptions = useMemo(\n () => [...new Set([...orgCountries, ...draftCountries])],\n [orgCountries, draftCountries],\n )\n /*\n * A test sends the step as STORED (AGL-3325): the route reads the saved\n * sequence, so a new one has nothing to send yet and an edited one sends\n * its last save — said on the button and in the dialog rather than found\n * out in the inbox.\n */\n const unsaved =\n sequence !== null &&\n JSON.stringify(draft) !== JSON.stringify(outreachSequenceDraftOf(sequence))\n const sendTestDisabledReason = !sequence\n ? 'Create the sequence to send a test of it.'\n : !draft.mailboxId\n ? 'Choose a mailbox to send the test from.'\n : null\n\n return (\n <Grid container spacing={2}>\n <Grid size={{ xs: 12, md: 7 }}>\n <Stack spacing={2}>\n {archived ? (\n <Alert severity=\"info\">\n This sequence is archived, so it can’t be edited.\n </Alert>\n ) : null}\n <SequenceCard\n orgId={orgId}\n uid={uid}\n name={draft.name}\n hostId={draft.hostId}\n mailboxId={draft.mailboxId}\n mailboxIds={draft.mailboxIds ?? NO_ROTATION}\n campaignIds={draft.campaignIds}\n hosts={hosts}\n mailboxes={props.mailboxes}\n mailboxesPath={props.mailboxesPath}\n campaignOptions={campaigns.options}\n noCampaigns={campaigns.ready && !campaigns.options.length}\n nameIssue={issueAt('name')}\n hostIssue={issueAt('hostId')}\n mailboxIssue={issueAt('mailboxId')}\n rotationIssue={issueAt('mailboxIds')}\n campaignsIssue={issueAt('campaignIds')}\n archived={archived}\n saving={saving}\n saveLabel={sequence ? 'Save' : 'Create sequence'}\n onCancel={props.onCancel}\n onSave={onSave}\n onName={setName}\n onHost={setHost}\n onMailbox={setMailbox}\n onRotation={setRotation}\n onCampaigns={setCampaigns}\n />\n\n {listIssue ? <Alert severity=\"error\">{listIssue}</Alert> : null}\n {draft.steps.map((step, index) => {\n const inThread = isInThreadEmailStep(draft.steps, index)\n return (\n <SequenceStepItem\n key={step.id || `step-${index}`}\n step={step}\n index={index}\n count={draft.steps.length}\n firstEmail={firstEmail === index}\n inThread={inThread}\n // Read only by an email sent in the thread, so no other\n // step is redrawn as the subject it replies to is typed.\n threadSubject={inThread ? threadSubject(index) : ''}\n templates={templates.data}\n issues={stepIssues[index]}\n disabled={archived}\n canSendTest={step.kind === 'email' && !archived}\n sendTestDisabledReason={sendTestDisabledReason}\n onStepChange={setStep}\n onStepMove={moveStep}\n onStepRemove={removeStep}\n onStepTest={setTesting}\n />\n )\n })}\n <SequenceAddStep\n emailDisabled={\n archived || full || emailCount >= OUTREACH_MAX_EMAIL_STEPS\n }\n taskDisabled={archived || full}\n onAddEmail={addEmail}\n onAddTask={addTask}\n />\n <Typography variant=\"caption\" color=\"text.secondary\">\n {`Up to ${OUTREACH_MAX_STEPS} steps, ${OUTREACH_MAX_EMAIL_STEPS} of them emails.`}\n </Typography>\n\n <SequenceSendingCard\n settings={draft.settings}\n countryOptions={countryOptions}\n countriesIssue={countriesIssue}\n daysIssue={issueAt('settings.window.days')}\n hoursIssue={issueAt('settings.window')}\n disabled={archived}\n onCountries={setCountries}\n onSettings={setSettings}\n />\n\n </Stack>\n </Grid>\n {sequence && testing !== null ? (\n <OutreachStepTestDialog\n open\n onClose={() => setTesting(null)}\n orgId={orgId}\n sequence={sequence}\n stepIndex={testing}\n contactGroupId={\n sequence.hostId\n ? consentGroupForHost(props.org ?? null, sequence.hostId).groupId\n : ''\n }\n selfEmail={user?.email ?? null}\n unsaved={unsaved}\n api={api}\n />\n ) : null}\n <Grid size={{ xs: 12, md: 5 }}>\n <Box sx={PREVIEW_COLUMN}>\n <MemoSequencePreview\n steps={draft.steps}\n orgSettings={settings.settings}\n orgSettingsStatus={settings.status}\n templates={templates.data}\n sender={sender}\n siteName={siteName}\n />\n </Box>\n </Grid>\n </Grid>\n )\n}\nOutreachSequenceEditor.displayName = 'OutreachSequenceEditor'\n\nexport default OutreachSequenceEditor\n"],"names":["pluginDocsHelp","consentGroupForHost","mdiPlus","CardDisplay","MdiIcon","ContainerPicker","useSnackbar","useOrgContainerOptions","useUser","Alert","Autocomplete","Box","Button","Chip","FormControlLabel","Grid","Menu","MenuItem","Stack","Switch","TextField","Typography","memo","useCallback","useEffect","useMemo","useRef","useState","isInThreadEmailStep","OUTREACH_SEQUENCE_NAME_MAX","validateOutreachSequence","outreachCountryLabel","OUTREACH_MAX_EMAIL_STEPS","OUTREACH_MAX_STEPS","OUTREACH_TASK_KIND_LABELS","OUTREACH_TASK_KINDS","emptyOutreachSequenceDraft","newOutreachEmailStep","newOutreachTaskStep","outreachSequenceDraftOf","OutreachSendWindowFields","OutreachSequenceMailboxPicker","OutreachSequenceRotationPicker","OutreachSequencePreview","OutreachStepCard","OutreachStepTestDialog","OutreachRouteError","useOutreachApi","useOutreachEmailTemplates","stepIssueKey","path","match","exec","field","index","Number","OutreachCountriesField","props","multiple","options","value","getOptionLabel","onChange","_event","next","disabled","renderValue","getItemProps","map","code","key","item","size","label","renderInput","params","error","Boolean","issue","helperText","useStepIssues","issues","count","held","found","Array","from","length","record","undefined","message","current","JSON","stringify","before","entry","MemoTextField","MemoMailboxPicker","MemoRotationPicker","NO_ROTATION","MemoContainerPicker","MemoSendWindowFields","MemoSequencePreview","NAME_SLOT_PROPS","htmlInput","maxLength","ADD_STEP_ROW","flexWrap","rowGap","PREVIEW_COLUMN","position","md","top","SequenceSiteField","hosts","select","some","host","id","fullWidth","name","SequenceSaveActions","direction","spacing","onCancel","variant","onClick","saving","onSave","saveLabel","SequenceCard","archived","header","help","anchor","HeaderProps","action","contentGutterX","contentGutterY","onName","nameIssue","slotProps","hostId","hostIssue","onHost","orgId","uid","mailboxes","mailboxesPath","mailboxId","onMailbox","mailboxIssue","mailboxIds","onRotation","rotationIssue","kind","campaignOptions","campaignIds","onCampaigns","campaignsIssue","empty","noCampaigns","emptyText","SequenceStepItem","canSendTest","onStepChange","onStepMove","onStepRemove","onStepTest","card","step","onMove","onRemove","onSendTest","SequenceAddStep","onAddTask","taskAnchor","setTaskAnchor","sx","startIcon","fontSize","emailDisabled","onAddEmail","taskDisabled","event","currentTarget","aria-haspopup","anchorEl","open","onClose","SequenceSendingCard","settings","onSettings","setAllowCustomers","allowCustomers","target","checked","setTrackClicks","trackClicks","setCountOpens","countOpens","setListUnsubscribe","listUnsubscribe","setWindow","window","excerpt","countryOptions","allowedCountries","onCountries","countriesIssue","control","color","daysIssue","hoursIssue","OutreachSequenceEditor","draft","orgMount","sequence","api","enqueueSnackbar","data","user","mountedHosts","orgCountries","setDraft","attempted","setAttempted","serverIssues","setServerIssues","setSaving","testing","setTesting","drawn","settingsCountries","join","previous","split","ownSending","filter","connectedByUid","status","onlyOwnMailbox","templates","mailbox","find","sender","displayName","email","sendAs","campaigns","enabled","judged","severity","includes","issueAt","stepIssues","steps","listIssue","startsWith","clearServerIssues","update","setCountries","setName","setHost","setMailbox","setRotation","setCampaigns","setSettings","patch","setStep","moveStep","moved","splice","removeStep","_entry","addEmail","addTask","emailCount","full","firstEmail","findIndex","threadSubject","subject","save","answer","saveSequence","created","onSaved","allowDuplicate","drawnSave","siteName","draftCountries","Set","unsaved","sendTestDisabledReason","container","xs","ready","inThread","stepIndex","contactGroupId","org","groupId","selfEmail","orgSettings","orgSettingsStatus"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/outreach/src/lib/components/sequence-editor.tsx"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n'use client'\n\nimport { pluginDocsHelp, type ConsolePluginOrgMount } from '@aglyn/aglyn'\nimport { consentGroupForHost } from '@aglyn/aglyn/app-utils/consent-groups'\nimport { mdiPlus } from '@aglyn/shared-data-mdi'\nimport { CardDisplay, MdiIcon } from '@aglyn/shared-ui-jsx'\nimport ContainerPicker, {\n type ContainerPickerProps,\n} from '@aglyn/tenant-feature-instance/components/container-picker'\nimport { useSnackbar } from '@aglyn/shared-ui-snackstack'\nimport { useOrgContainerOptions, useUser } from '@aglyn/tenant-feature-instance'\nimport {\n Alert,\n Autocomplete,\n Box,\n Button,\n Chip,\n FormControlLabel,\n Grid,\n Menu,\n MenuItem,\n Stack,\n Switch,\n TextField,\n Typography,\n} from '@mui/material'\nimport { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react'\nimport {\n isInThreadEmailStep,\n OUTREACH_SEQUENCE_NAME_MAX,\n validateOutreachSequence,\n} from '../engine/sequence-validation'\nimport { outreachCountryLabel } from '../model/compliance-settings'\nimport {\n OUTREACH_MAX_EMAIL_STEPS,\n OUTREACH_MAX_STEPS,\n OUTREACH_TASK_KIND_LABELS,\n OUTREACH_TASK_KINDS,\n type OutreachSequence,\n type OutreachSequenceStep,\n type OutreachTaskKind,\n} from '../model/outreach.types'\nimport {\n emptyOutreachSequenceDraft,\n newOutreachEmailStep,\n newOutreachTaskStep,\n outreachSequenceDraftOf,\n type OutreachSequenceDraft,\n type OutreachSequenceIssue,\n} from '../model/sequence-draft'\nimport { OutreachSendWindowFields } from './send-window-fields'\nimport { OutreachSequenceMailboxPicker, OutreachSequenceRotationPicker } from './sequence-mailbox-picker'\nimport { OutreachSequencePreview } from './sequence-preview'\nimport {\n OutreachStepCard,\n type OutreachStepCardProps,\n} from './sequence-step-card'\nimport { OutreachStepTestDialog } from './step-test-dialog'\nimport { OutreachRouteError, useOutreachApi } from './use-outreach-api'\nimport { useOutreachEmailTemplates } from './use-outreach-crm'\nimport type { OutreachMailboxesResult } from './use-outreach-mailboxes'\nimport type { OutreachSettingsLoad } from './use-outreach-settings'\n\nexport interface OutreachSequenceEditorProps {\n orgId: string\n orgMount?: ConsolePluginOrgMount\n /** The organization document, for the consent group a test send's person picker searches (AGL-3325). */\n org?: Record<string, unknown> | null\n /** The stored sequence, or `null` for a new one. */\n sequence: OutreachSequence | null\n /** The organization's compliance settings: its countries, and the preview's footer. */\n settings: OutreachSettingsLoad\n /**\n * The organization's mailboxes, from the Mailboxes section's listener:\n * what the picker offers, and who the preview's emails are from.\n */\n mailboxes: OutreachMailboxesResult\n /** The Mailboxes section, where the picker sends a member to connect one. */\n mailboxesPath: string\n onSaved(sequence: OutreachSequence): void\n onCancel?(): void\n}\n\n/** The step a dotted issue path is about, and the field within it. */\nfunction stepIssueKey(path: string): { index: number; field: string } | null {\n const match = /^steps\\.(\\d+)(?:\\.(.+))?$/.exec(path)\n if (!match) return null\n const field = match[2] ?? 'step'\n return { index: Number(match[1]), field: field === 'id' ? 'step' : field }\n}\n\ninterface OutreachCountriesFieldProps {\n options: readonly string[]\n value: readonly string[]\n onChange(next: string[]): void\n issue?: string\n disabled: boolean\n}\n\n/**\n * The countries a sequence sends to, as chips in an Autocomplete.\n *\n * MEMOIZED, AND EVERY PROP IT TAKES IS STABLE WHILE THE COUNTRIES ARE\n * (AGL-3423). A multiple Autocomplete hands its input a new chip array as\n * `startAdornment` on every render, and MUI's `InputBase` copies that into\n * its `FormControl` from a passive effect — a state update after every\n * commit this field takes part in. React 19 counts a commit that leaves such\n * an update pending as a nested update, and keystrokes the browser delivers\n * back to back (a held key, fast typing on a busy page) commit one after\n * another with nothing in between to clear the count: fifty-one of them and\n * the next keystroke's own `setState` throws \"Maximum update depth exceeded\"\n * (minified error #185), which is what typing a step's body reported. Kept\n * out of the editor's other renders, the field commits only when the\n * countries, their options or their issue change.\n */\nconst OutreachCountriesField = memo(function OutreachCountriesField(\n props: OutreachCountriesFieldProps,\n) {\n return (\n <Autocomplete<string, true>\n multiple\n options={props.options}\n value={props.value as string[]}\n getOptionLabel={outreachCountryLabel}\n onChange={(_event, next) => props.onChange(next)}\n disabled={props.disabled}\n renderValue={(value, getItemProps) =>\n value.map((code, index) => {\n const { key, ...item } = getItemProps({ index })\n return (\n <Chip\n key={key}\n size=\"small\"\n label={outreachCountryLabel(code)}\n {...item}\n />\n )\n })\n }\n renderInput={(params) => (\n <TextField\n {...params}\n label=\"Countries\"\n error={Boolean(props.issue)}\n helperText={\n props.issue ??\n 'Among the countries your organization allows. Cold contacts are emailed only in the United States.'\n }\n />\n )}\n />\n )\n})\n\n/** Each step's issues by the field they are about, as its card reads them. */\ntype StepIssues = Partial<Record<string, string>>\n\n/**\n * Each step's issues, the SAME record for a step while what it holds reads\n * the same (AGL-3423), so a step a keystroke did not touch keeps its props.\n */\nfunction useStepIssues(\n issues: readonly OutreachSequenceIssue[],\n count: number,\n): StepIssues[] {\n const held = useRef<Array<{ key: string; value: StepIssues }>>([])\n return useMemo(() => {\n const found: Record<string, string>[] = Array.from(\n { length: count },\n () => ({}),\n )\n for (const issue of issues) {\n const key = stepIssueKey(issue.path)\n const record = key ? found[key.index] : undefined\n if (key && record && !record[key.field])\n record[key.field] = issue.message\n }\n held.current = found.map((value, index) => {\n const key = JSON.stringify(value)\n const before = held.current[index]\n return before?.key === key ? before : { key, value }\n })\n return held.current.map((entry) => entry.value)\n }, [issues, count])\n}\n\n/** A text field that redraws only when what it shows changes (AGL-3423). */\nconst MemoTextField = memo(TextField) as typeof TextField\n\n/*\n * The sections below are drawn from the one draft, and each redraws only\n * when what it shows changes (AGL-3423).\n */\nconst MemoMailboxPicker = memo(OutreachSequenceMailboxPicker)\nconst MemoRotationPicker = memo(OutreachSequenceRotationPicker)\n/** A stable empty rotation, so the picker's props hold still while there is none. */\nconst NO_ROTATION: readonly string[] = []\nconst MemoContainerPicker = memo(ContainerPicker)\nconst MemoSendWindowFields = memo(OutreachSendWindowFields)\nconst MemoSequencePreview = memo(OutreachSequencePreview)\n\ntype FieldChange = { target: { value: string } }\ntype SwitchChange = { target: { checked: boolean } }\ntype SequenceSettings = OutreachSequenceDraft['settings']\n\nconst NAME_SLOT_PROPS = {\n htmlInput: { maxLength: OUTREACH_SEQUENCE_NAME_MAX + 20 },\n}\nconst ADD_STEP_ROW = { flexWrap: 'wrap', rowGap: 1 } as const\nconst PREVIEW_COLUMN = {\n position: { md: 'sticky' },\n top: { md: 16 },\n} as const\n\nconst SequenceSiteField = memo(function SequenceSiteField(props: {\n hosts: ConsolePluginOrgMount['hosts']\n value: string\n issue?: string\n disabled: boolean\n onChange(event: FieldChange): void\n}) {\n const { hosts, value, issue } = props\n return (\n <TextField\n select\n label=\"Site\"\n value={hosts.some((host) => host.id === value) ? value : ''}\n onChange={props.onChange}\n disabled={props.disabled || !hosts.length}\n error={Boolean(issue)}\n helperText={issue ?? 'The site whose contacts this sequence emails.'}\n fullWidth\n >\n {hosts.map((host) => (\n <MenuItem key={host.id} value={host.id}>\n {host.name}\n </MenuItem>\n ))}\n </TextField>\n )\n})\n\n/** The sequence card's header actions: Cancel, and the save of the whole sequence. */\nconst SequenceSaveActions = memo(function SequenceSaveActions(props: {\n saving: boolean\n /** \"Save\" for a stored sequence, \"Create sequence\" for a new one. */\n saveLabel: string\n onCancel?(): void\n onSave(): void\n}) {\n return (\n <Stack direction=\"row\" spacing={1}>\n {props.onCancel ? (\n <Button\n size=\"small\"\n variant=\"text\"\n onClick={props.onCancel}\n disabled={props.saving}\n >\n Cancel\n </Button>\n ) : null}\n <Button\n size=\"small\"\n variant=\"contained\"\n onClick={props.onSave}\n disabled={props.saving}\n >\n {props.saving ? 'Saving…' : props.saveLabel}\n </Button>\n </Stack>\n )\n})\n\ninterface SequenceCardProps {\n orgId: string\n uid: string | null\n name: string\n hostId: string\n mailboxId: string\n /** The mailboxes it rotates through beside its own (AGL-3489). */\n mailboxIds: readonly string[]\n campaignIds: readonly string[]\n hosts: ConsolePluginOrgMount['hosts']\n mailboxes: OutreachMailboxesResult\n mailboxesPath: string\n campaignOptions: ContainerPickerProps['options']\n /** The organization has no campaigns at all. */\n noCampaigns: boolean\n nameIssue?: string\n hostIssue?: string\n mailboxIssue?: string\n rotationIssue?: string\n campaignsIssue?: string\n archived: boolean\n saving: boolean\n saveLabel: string\n onCancel?(): void\n onSave(): void\n onName(event: FieldChange): void\n onHost(event: FieldChange): void\n onMailbox(mailboxId: string): void\n onRotation(mailboxIds: string[]): void\n onCampaigns(campaignIds: string[]): void\n}\n\n/** The sequence's own card: its name, site, mailbox and campaigns. */\nconst SequenceCard = memo(function SequenceCard(props: SequenceCardProps) {\n const { archived } = props\n return (\n <CardDisplay\n header=\"Sequence\"\n help={pluginDocsHelp('sequences', { anchor: '#build-a-sequence' })}\n // The whole sequence (steps and sending rules included) saves\n // from its first card's header, where the console puts a card's\n // actions (AGL-3333).\n HeaderProps={{\n action: archived ? undefined : (\n <SequenceSaveActions\n saving={props.saving}\n saveLabel={props.saveLabel}\n onCancel={props.onCancel}\n onSave={props.onSave}\n />\n ),\n }}\n contentGutterX\n contentGutterY\n >\n <Stack spacing={2}>\n <MemoTextField\n label=\"Name\"\n value={props.name}\n onChange={props.onName}\n disabled={archived}\n error={Boolean(props.nameIssue)}\n helperText={props.nameIssue}\n slotProps={NAME_SLOT_PROPS}\n fullWidth\n />\n <SequenceSiteField\n hosts={props.hosts}\n value={props.hostId}\n issue={props.hostIssue}\n disabled={archived}\n onChange={props.onHost}\n />\n <MemoMailboxPicker\n orgId={props.orgId}\n uid={props.uid}\n mailboxes={props.mailboxes}\n mailboxesPath={props.mailboxesPath}\n value={props.mailboxId}\n onChange={props.onMailbox}\n error={props.mailboxIssue}\n disabled={archived}\n />\n <MemoRotationPicker\n orgId={props.orgId}\n uid={props.uid}\n mailboxes={props.mailboxes}\n mailboxId={props.mailboxId}\n value={props.mailboxIds}\n onChange={props.onRotation}\n error={props.rotationIssue}\n disabled={archived}\n />\n {/*\n The campaigns this sequence is part of (AGL-3254), picked the\n way a form's page picks them. Everyone enrolled joins them,\n and what the sequence produces is reported under them; it\n does not change who is enrolled or what is sent.\n */}\n <MemoContainerPicker\n kind=\"campaign\"\n options={props.campaignOptions}\n value={props.campaignIds}\n onChange={props.onCampaigns}\n label=\"Campaigns\"\n helperText={\n props.campaignsIssue ??\n 'The campaigns this sequence is part of. Everyone enrolled joins them, and its sends, replies, meetings and conversions count on their pages.'\n }\n disabled={archived}\n empty={props.noCampaigns}\n emptyText=\"There are no campaigns yet. Create one from Marketing to file this sequence under it.\"\n />\n </Stack>\n </CardDisplay>\n )\n})\n\ninterface SequenceStepItemProps\n extends Omit<\n OutreachStepCardProps,\n 'onChange' | 'onMove' | 'onRemove' | 'onSendTest'\n > {\n /** Whether the step offers a test send: an email in a sequence that is not archived. */\n canSendTest: boolean\n onStepChange(index: number, step: OutreachSequenceStep): void\n onStepMove(index: number, direction: -1 | 1): void\n onStepRemove(index: number): void\n onStepTest(index: number): void\n}\n\n/**\n * One step's card, bound to its position. Memoized, with handlers that keep\n * their identity, so a keystroke in one step leaves the others undrawn.\n */\nconst SequenceStepItem = memo(function SequenceStepItem(\n props: SequenceStepItemProps,\n) {\n const {\n index,\n canSendTest,\n onStepChange,\n onStepMove,\n onStepRemove,\n onStepTest,\n ...card\n } = props\n const onChange = useCallback(\n (step: OutreachSequenceStep) => onStepChange(index, step),\n [index, onStepChange],\n )\n const onMove = useCallback(\n (direction: -1 | 1) => onStepMove(index, direction),\n [index, onStepMove],\n )\n const onRemove = useCallback(\n () => onStepRemove(index),\n [index, onStepRemove],\n )\n const onSendTest = useCallback(() => onStepTest(index), [index, onStepTest])\n return (\n <OutreachStepCard\n {...card}\n index={index}\n onChange={onChange}\n onMove={onMove}\n onRemove={onRemove}\n onSendTest={canSendTest ? onSendTest : undefined}\n />\n )\n})\n\n/** Adds an email, or a task of a kind picked from its menu. */\nconst SequenceAddStep = memo(function SequenceAddStep(props: {\n emailDisabled: boolean\n taskDisabled: boolean\n onAddEmail(): void\n onAddTask(kind: OutreachTaskKind): void\n}) {\n const { onAddTask } = props\n const [taskAnchor, setTaskAnchor] = useState<HTMLElement | null>(null)\n return (\n <Stack direction=\"row\" spacing={1} sx={ADD_STEP_ROW}>\n <Button\n variant=\"outlined\"\n startIcon={<MdiIcon path={mdiPlus.path} fontSize=\"small\" />}\n disabled={props.emailDisabled}\n onClick={props.onAddEmail}\n >\n Add email\n </Button>\n <Button\n variant=\"outlined\"\n startIcon={<MdiIcon path={mdiPlus.path} fontSize=\"small\" />}\n disabled={props.taskDisabled}\n onClick={(event) => setTaskAnchor(event.currentTarget)}\n aria-haspopup=\"menu\"\n >\n Add task\n </Button>\n <Menu\n anchorEl={taskAnchor}\n open={Boolean(taskAnchor)}\n onClose={() => setTaskAnchor(null)}\n >\n {OUTREACH_TASK_KINDS.map((kind: OutreachTaskKind) => (\n <MenuItem\n key={kind}\n onClick={() => {\n setTaskAnchor(null)\n onAddTask(kind)\n }}\n >\n {OUTREACH_TASK_KIND_LABELS[kind]}\n </MenuItem>\n ))}\n </Menu>\n </Stack>\n )\n})\n\ninterface SequenceSendingCardProps {\n settings: SequenceSettings\n countryOptions: readonly string[]\n countriesIssue?: string\n daysIssue?: string\n hoursIssue?: string\n disabled: boolean\n onCountries(next: string[]): void\n onSettings(patch: Partial<SequenceSettings>): void\n}\n\n/** Who the sequence sends to, and when: its countries, switches and hours. */\nconst SequenceSendingCard = memo(function SequenceSendingCard(\n props: SequenceSendingCardProps,\n) {\n const { settings, disabled, onSettings } = props\n const setAllowCustomers = useCallback(\n (event: SwitchChange) =>\n onSettings({ allowCustomers: event.target.checked }),\n [onSettings],\n )\n const setTrackClicks = useCallback(\n (event: SwitchChange) => onSettings({ trackClicks: event.target.checked }),\n [onSettings],\n )\n const setCountOpens = useCallback(\n (event: SwitchChange) => onSettings({ countOpens: event.target.checked }),\n [onSettings],\n )\n const setListUnsubscribe = useCallback(\n (event: SwitchChange) =>\n onSettings({ listUnsubscribe: event.target.checked }),\n [onSettings],\n )\n const setWindow = useCallback(\n (window: SequenceSettings['window']) => onSettings({ window }),\n [onSettings],\n )\n return (\n <CardDisplay\n header=\"Who it sends to, and when\"\n help={pluginDocsHelp('sequences', { anchor: '#sequence-sending-settings' })}\n contentGutterX\n contentGutterY\n >\n <Stack spacing={2}>\n <OutreachCountriesField\n options={props.countryOptions}\n value={settings.allowedCountries}\n onChange={props.onCountries}\n issue={props.countriesIssue}\n disabled={disabled}\n />\n <FormControlLabel\n control={\n <Switch\n checked={settings.allowCustomers}\n onChange={setAllowCustomers}\n disabled={disabled}\n />\n }\n label=\"Include customers\"\n />\n {/*\n * Click tracking (AGL-3239), with its cost stated where it is\n * chosen rather than in a document nobody opens. Off by\n * default: it changes the link a cold recipient sees. The\n * emails stay plain text either way; opens are the separate\n * switch below.\n */}\n <Stack spacing={0}>\n <FormControlLabel\n control={\n <Switch\n checked={settings.trackClicks}\n onChange={setTrackClicks}\n disabled={disabled}\n />\n }\n label=\"Count link clicks\"\n />\n <Typography variant=\"caption\" color=\"text.secondary\">\n Links in these emails are replaced with links of ours that\n forward to the same page, so clicks can be counted. The\n recipient sees the replacement, not your address. The\n emails stay plain text.\n </Typography>\n </Stack>\n {/*\n * Open counting (AGL-3395), off by default, its cost stated\n * where it is chosen: an HTML copy with a tracking image is the\n * least one-to-one thing a sequence email can carry, so it is\n * for measuring a slice, not for every sequence.\n */}\n <Stack spacing={0}>\n <FormControlLabel\n control={\n <Switch\n checked={settings.countOpens}\n onChange={setCountOpens}\n disabled={disabled}\n />\n }\n label=\"Count opens\"\n />\n <Typography variant=\"caption\" color=\"text.secondary\">\n Each email also goes out as HTML — the same words — with a\n tiny tracking image, so opens can be counted. The plain-text\n version is unchanged. It makes the email look less like one\n written by hand, and some spam filters score HTML with a\n remote image against you, so turn it on to measure a slice\n of your sends rather than for every sequence. Gmail opens\n count; Apple Mail loads every image on arrival, so its loads\n are counted separately.\n </Typography>\n </Stack>\n {/*\n * The mail-client unsubscribe button (AGL-3296), off by\n * default: the header is what makes Apple Mail, Gmail and\n * Outlook present a one-to-one email as a mailing list. The\n * footer's \"reply 'no'\" line is the way out either way.\n */}\n <Stack spacing={0}>\n <FormControlLabel\n control={\n <Switch\n checked={settings.listUnsubscribe}\n onChange={setListUnsubscribe}\n disabled={disabled}\n />\n }\n label=\"Add a mail-client unsubscribe button\"\n />\n <Typography variant=\"caption\" color=\"text.secondary\">\n Adds the List-Unsubscribe header, so the recipient’s mail\n app shows its own Unsubscribe button. It’s the easiest way\n out for them, and fewer people mark you as spam when they\n have it, but mail apps then label the email as coming from\n a mailing list. Off, the footer’s “reply ‘no’” line is the\n way out, and it’s always there.\n </Typography>\n </Stack>\n <MemoSendWindowFields\n window={settings.window}\n onChange={setWindow}\n daysIssue={props.daysIssue}\n hoursIssue={props.hoursIssue}\n disabled={disabled}\n />\n </Stack>\n </CardDisplay>\n )\n})\n\n/**\n * The sequence editor (AGL-2980): the name, the site and mailbox, the steps,\n * who it sends to and when, beside a live preview of each email.\n *\n * Every issue the engine's validator finds is shown beside its field — the\n * same validator the save route refuses with — errors once a save was\n * attempted, warnings as soon as they appear. What only the server can\n * judge (whose mailbox, which countries the organization allows, what may\n * no longer change once people are enrolled) comes back from the save and\n * is shown in the same places.\n *\n * ## A keystroke redraws its own field (AGL-3423)\n *\n * The whole sequence is one draft, so every letter typed anywhere is a new\n * draft, and drawing the editor from it inline redrew every field of every\n * step, the settings and the preview with each one: 17 inputs and some 1,150\n * components for one letter in a three-step sequence. That cost is what lets\n * typed input queue, and queued keystrokes processed back to back are what\n * drove the countries chips into React's #185. The sequence card, each step,\n * the sending card and the preview are memoized and handed only what they\n * show, through handlers that keep their identity; the handlers that wrote\n * from the draft as drawn still do, through `drawn`. A letter now redraws the\n * field it lands in, and the preview when it shows that step's email.\n */\nexport function OutreachSequenceEditor(props: OutreachSequenceEditorProps) {\n const { orgId, orgMount, sequence, settings } = props\n const api = useOutreachApi(orgId)\n const { enqueueSnackbar } = useSnackbar()\n const { data: user } = useUser()\n const uid = user?.uid ?? null\n const mountedHosts = orgMount?.hosts\n const hosts = useMemo(() => mountedHosts ?? [], [mountedHosts])\n const allowedCountries = settings.settings?.allowedCountries\n const orgCountries = useMemo(\n () => allowedCountries ?? ['US'],\n [allowedCountries],\n )\n\n const [draft, setDraft] = useState<OutreachSequenceDraft>(() =>\n sequence\n ? outreachSequenceDraftOf(sequence)\n : emptyOutreachSequenceDraft({\n hostId: hosts.length === 1 ? hosts[0].id : '',\n allowedCountries: orgCountries,\n }),\n )\n const [attempted, setAttempted] = useState(false)\n const [serverIssues, setServerIssues] = useState<OutreachSequenceIssue[]>([])\n const [saving, setSaving] = useState(false)\n // The step whose test-send dialog is open (AGL-3325), by index.\n const [testing, setTesting] = useState<number | null>(null)\n // The draft as last drawn, which the handlers that build on it read.\n const drawn = useRef(draft)\n drawn.current = draft\n\n // A stored sequence the listener updated (a save, a status change) is the\n // new starting point.\n useEffect(() => {\n if (sequence) setDraft(outreachSequenceDraftOf(sequence))\n }, [sequence])\n // A new sequence starts on the organization's countries once they are read.\n const settingsCountries = settings.settings?.allowedCountries.join(',')\n useEffect(() => {\n if (!sequence && settingsCountries) {\n setDraft((previous) => ({\n ...previous,\n settings: {\n ...previous.settings,\n allowedCountries: settingsCountries.split(','),\n },\n }))\n }\n }, [sequence, settingsCountries])\n useEffect(() => {\n if (!sequence && !draft.hostId && hosts.length === 1)\n setDraft((previous) => ({ ...previous, hostId: hosts[0].id }))\n }, [sequence, draft.hostId, hosts])\n\n // A new sequence starts on the member's own mailbox when they have exactly\n // one that is sending.\n const ownSending = props.mailboxes.mailboxes.filter(\n (entry) => entry.connectedByUid === uid && entry.status === 'connected',\n )\n const onlyOwnMailbox = ownSending.length === 1 ? ownSending[0].id : ''\n useEffect(() => {\n if (!sequence && !draft.mailboxId && onlyOwnMailbox)\n setDraft((previous) => ({ ...previous, mailboxId: onlyOwnMailbox }))\n }, [sequence, draft.mailboxId, onlyOwnMailbox])\n\n const templates = useOutreachEmailTemplates(orgId, draft.hostId || null, uid)\n const mailbox =\n props.mailboxes.mailboxes.find((entry) => entry.id === draft.mailboxId) ??\n null\n const sender = useMemo(\n () =>\n mailbox\n ? { name: mailbox.displayName, email: mailbox.sendAs || mailbox.email }\n : null,\n [mailbox],\n )\n const archived = sequence?.status === 'archived'\n /*\n * The org's campaigns, for the picker (AGL-3254): read while the editor\n * is open. A sequence is the organization's record and so is a campaign,\n * so the choice is every campaign in the org, whichever site the\n * sequence sends as.\n */\n const campaigns = useOrgContainerOptions('campaign', orgId, { enabled: true })\n\n const issues = useMemo(() => {\n const judged = [\n ...validateOutreachSequence(draft),\n ...serverIssues,\n ] as OutreachSequenceIssue[]\n return judged.filter(\n (issue) =>\n issue.severity === 'warning' ||\n attempted ||\n serverIssues.includes(issue),\n )\n }, [draft, serverIssues, attempted])\n const issueAt = (path: string) =>\n issues.find((issue) => issue.path === path)?.message\n const stepIssues = useStepIssues(issues, draft.steps.length)\n const listIssue = issueAt('steps')\n const countriesIssue = issues.find((issue) =>\n issue.path.startsWith('settings.allowedCountries'),\n )?.message\n\n // An edit clears what the last save refused. The empty list stays the same\n // list, so an edit with nothing to clear does not change that state.\n const clearServerIssues = useCallback(\n () => setServerIssues((previous) => (previous.length ? [] : previous)),\n [],\n )\n const update = useCallback(\n (next: Partial<OutreachSequenceDraft>) => {\n clearServerIssues()\n setDraft((previous) => ({ ...previous, ...next }))\n },\n [clearServerIssues],\n )\n // Stable, for the memoized countries field: it reads the settings it\n // replaces from the draft it is given rather than from this render's.\n const setCountries = useCallback(\n (next: string[]) => {\n clearServerIssues()\n setDraft((previous) => ({\n ...previous,\n settings: { ...previous.settings, allowedCountries: next },\n }))\n },\n [clearServerIssues],\n )\n const setName = useCallback(\n (event: FieldChange) => update({ name: event.target.value }),\n [update],\n )\n const setHost = useCallback(\n (event: FieldChange) => update({ hostId: event.target.value }),\n [update],\n )\n const setMailbox = useCallback(\n (mailboxId: string) =>\n update({\n mailboxId,\n // The sequence's own mailbox is never also one it rotates through.\n mailboxIds: drawn.current.mailboxIds?.filter((id) => id !== mailboxId).length\n ? drawn.current.mailboxIds.filter((id) => id !== mailboxId)\n : undefined,\n }),\n [update],\n )\n const setRotation = useCallback(\n (mailboxIds: string[]) => update({ mailboxIds: mailboxIds.length ? mailboxIds : undefined }),\n [update],\n )\n const setCampaigns = useCallback(\n (campaignIds: string[]) => update({ campaignIds }),\n [update],\n )\n const setSettings = useCallback(\n (patch: Partial<SequenceSettings>) =>\n update({ settings: { ...drawn.current.settings, ...patch } }),\n [update],\n )\n const setStep = useCallback(\n (index: number, step: OutreachSequenceStep) =>\n update({\n steps: drawn.current.steps.map((entry, position) =>\n position === index ? step : entry,\n ),\n }),\n [update],\n )\n const moveStep = useCallback(\n (index: number, direction: -1 | 1) => {\n const steps = [...drawn.current.steps]\n const [moved] = steps.splice(index, 1)\n steps.splice(index + direction, 0, moved)\n update({ steps })\n },\n [update],\n )\n const removeStep = useCallback(\n (index: number) =>\n update({\n steps: drawn.current.steps.filter(\n (_entry, position) => position !== index,\n ),\n }),\n [update],\n )\n const addEmail = useCallback(\n () =>\n update({\n steps: [\n ...drawn.current.steps,\n newOutreachEmailStep(drawn.current.steps),\n ],\n }),\n [update],\n )\n const addTask = useCallback(\n (kind: OutreachTaskKind) =>\n update({\n steps: [\n ...drawn.current.steps,\n newOutreachTaskStep(drawn.current.steps, kind),\n ],\n }),\n [update],\n )\n const emailCount = draft.steps.filter((step) => step.kind === 'email').length\n const full = draft.steps.length >= OUTREACH_MAX_STEPS\n const firstEmail = draft.steps.findIndex((entry) => entry.kind === 'email')\n const threadSubject = (index: number) => {\n for (let position = index - 1; position >= 0; position -= 1) {\n const step = draft.steps[position]\n if (step.kind === 'email' && !isInThreadEmailStep(draft.steps, position))\n return step.subject\n }\n return ''\n }\n\n const save = async () => {\n setAttempted(true)\n if (\n validateOutreachSequence(draft).some(\n (issue) => issue.severity === 'error',\n )\n )\n return\n setSaving(true)\n try {\n const answer = await api.saveSequence(sequence?.id ?? null, draft)\n setServerIssues([])\n setAttempted(false)\n enqueueSnackbar(\n answer.created ? 'Sequence created.' : 'Sequence saved.',\n { variant: 'success' },\n )\n props.onSaved(answer.sequence)\n } catch (error) {\n if (error instanceof OutreachRouteError && error.issues.length) {\n setServerIssues(\n error.issues.filter(\n (issue): issue is OutreachSequenceIssue => 'path' in issue,\n ),\n )\n }\n enqueueSnackbar((error as Error).message, {\n variant: 'error',\n allowDuplicate: true,\n })\n } finally {\n setSaving(false)\n }\n }\n // The save as last drawn, behind a handler that keeps its identity.\n const drawnSave = useRef(save)\n drawnSave.current = save\n const onSave = useCallback(() => void drawnSave.current(), [])\n\n const siteName = hosts.find((host) => host.id === draft.hostId)?.name ?? ''\n const draftCountries = draft.settings.allowedCountries\n const countryOptions = useMemo(\n () => [...new Set([...orgCountries, ...draftCountries])],\n [orgCountries, draftCountries],\n )\n /*\n * A test sends the step as STORED (AGL-3325): the route reads the saved\n * sequence, so a new one has nothing to send yet and an edited one sends\n * its last save — said on the button and in the dialog rather than found\n * out in the inbox.\n */\n const unsaved =\n sequence !== null &&\n JSON.stringify(draft) !== JSON.stringify(outreachSequenceDraftOf(sequence))\n const sendTestDisabledReason = !sequence\n ? 'Create the sequence to send a test of it.'\n : !draft.mailboxId\n ? 'Choose a mailbox to send the test from.'\n : null\n\n return (\n <Grid container spacing={2}>\n <Grid size={{ xs: 12, md: 7 }}>\n <Stack spacing={2}>\n {archived ? (\n <Alert severity=\"info\">\n This sequence is archived, so it can’t be edited.\n </Alert>\n ) : null}\n <SequenceCard\n orgId={orgId}\n uid={uid}\n name={draft.name}\n hostId={draft.hostId}\n mailboxId={draft.mailboxId}\n mailboxIds={draft.mailboxIds ?? NO_ROTATION}\n campaignIds={draft.campaignIds}\n hosts={hosts}\n mailboxes={props.mailboxes}\n mailboxesPath={props.mailboxesPath}\n campaignOptions={campaigns.options}\n noCampaigns={campaigns.ready && !campaigns.options.length}\n nameIssue={issueAt('name')}\n hostIssue={issueAt('hostId')}\n mailboxIssue={issueAt('mailboxId')}\n rotationIssue={issueAt('mailboxIds')}\n campaignsIssue={issueAt('campaignIds')}\n archived={archived}\n saving={saving}\n saveLabel={sequence ? 'Save' : 'Create sequence'}\n onCancel={props.onCancel}\n onSave={onSave}\n onName={setName}\n onHost={setHost}\n onMailbox={setMailbox}\n onRotation={setRotation}\n onCampaigns={setCampaigns}\n />\n\n {listIssue ? <Alert severity=\"error\">{listIssue}</Alert> : null}\n {draft.steps.map((step, index) => {\n const inThread = isInThreadEmailStep(draft.steps, index)\n return (\n <SequenceStepItem\n key={step.id || `step-${index}`}\n step={step}\n index={index}\n count={draft.steps.length}\n firstEmail={firstEmail === index}\n inThread={inThread}\n // Read only by an email sent in the thread, so no other\n // step is redrawn as the subject it replies to is typed.\n threadSubject={inThread ? threadSubject(index) : ''}\n templates={templates.data}\n issues={stepIssues[index]}\n disabled={archived}\n canSendTest={step.kind === 'email' && !archived}\n sendTestDisabledReason={sendTestDisabledReason}\n onStepChange={setStep}\n onStepMove={moveStep}\n onStepRemove={removeStep}\n onStepTest={setTesting}\n />\n )\n })}\n <SequenceAddStep\n emailDisabled={\n archived || full || emailCount >= OUTREACH_MAX_EMAIL_STEPS\n }\n taskDisabled={archived || full}\n onAddEmail={addEmail}\n onAddTask={addTask}\n />\n <Typography variant=\"caption\" color=\"text.secondary\">\n {`Up to ${OUTREACH_MAX_STEPS} steps, ${OUTREACH_MAX_EMAIL_STEPS} of them emails.`}\n </Typography>\n\n <SequenceSendingCard\n settings={draft.settings}\n countryOptions={countryOptions}\n countriesIssue={countriesIssue}\n daysIssue={issueAt('settings.window.days')}\n hoursIssue={issueAt('settings.window')}\n disabled={archived}\n onCountries={setCountries}\n onSettings={setSettings}\n />\n\n </Stack>\n </Grid>\n {sequence && testing !== null ? (\n <OutreachStepTestDialog\n open\n onClose={() => setTesting(null)}\n orgId={orgId}\n sequence={sequence}\n stepIndex={testing}\n contactGroupId={\n sequence.hostId\n ? consentGroupForHost(props.org ?? null, sequence.hostId).groupId\n : ''\n }\n selfEmail={user?.email ?? null}\n unsaved={unsaved}\n api={api}\n />\n ) : null}\n <Grid size={{ xs: 12, md: 5 }}>\n <Box sx={PREVIEW_COLUMN}>\n <MemoSequencePreview\n steps={draft.steps}\n orgSettings={settings.settings}\n orgSettingsStatus={settings.status}\n templates={templates.data}\n sender={sender}\n siteName={siteName}\n />\n </Box>\n </Grid>\n </Grid>\n )\n}\nOutreachSequenceEditor.displayName = 'OutreachSequenceEditor'\n\nexport default OutreachSequenceEditor\n"],"names":["pluginDocsHelp","consentGroupForHost","mdiPlus","CardDisplay","MdiIcon","ContainerPicker","useSnackbar","useOrgContainerOptions","useUser","Alert","Autocomplete","Box","Button","Chip","FormControlLabel","Grid","Menu","MenuItem","Stack","Switch","TextField","Typography","memo","useCallback","useEffect","useMemo","useRef","useState","isInThreadEmailStep","OUTREACH_SEQUENCE_NAME_MAX","validateOutreachSequence","outreachCountryLabel","OUTREACH_MAX_EMAIL_STEPS","OUTREACH_MAX_STEPS","OUTREACH_TASK_KIND_LABELS","OUTREACH_TASK_KINDS","emptyOutreachSequenceDraft","newOutreachEmailStep","newOutreachTaskStep","outreachSequenceDraftOf","OutreachSendWindowFields","OutreachSequenceMailboxPicker","OutreachSequenceRotationPicker","OutreachSequencePreview","OutreachStepCard","OutreachStepTestDialog","OutreachRouteError","useOutreachApi","useOutreachEmailTemplates","stepIssueKey","path","match","exec","field","index","Number","OutreachCountriesField","props","multiple","options","value","getOptionLabel","onChange","_event","next","disabled","renderValue","getItemProps","map","code","key","item","size","label","renderInput","params","error","Boolean","issue","helperText","useStepIssues","issues","count","held","found","Array","from","length","record","undefined","message","current","JSON","stringify","before","entry","MemoTextField","MemoMailboxPicker","MemoRotationPicker","NO_ROTATION","MemoContainerPicker","MemoSendWindowFields","MemoSequencePreview","NAME_SLOT_PROPS","htmlInput","maxLength","ADD_STEP_ROW","flexWrap","rowGap","PREVIEW_COLUMN","position","md","top","SequenceSiteField","hosts","select","some","host","id","fullWidth","name","SequenceSaveActions","direction","spacing","onCancel","variant","onClick","saving","onSave","saveLabel","SequenceCard","archived","header","help","anchor","HeaderProps","action","contentGutterX","contentGutterY","onName","nameIssue","slotProps","hostId","hostIssue","onHost","orgId","uid","mailboxes","mailboxesPath","mailboxId","onMailbox","mailboxIssue","mailboxIds","onRotation","rotationIssue","kind","campaignOptions","campaignIds","onCampaigns","campaignsIssue","empty","noCampaigns","emptyText","SequenceStepItem","canSendTest","onStepChange","onStepMove","onStepRemove","onStepTest","card","step","onMove","onRemove","onSendTest","SequenceAddStep","onAddTask","taskAnchor","setTaskAnchor","sx","startIcon","fontSize","emailDisabled","onAddEmail","taskDisabled","event","currentTarget","aria-haspopup","anchorEl","open","onClose","SequenceSendingCard","settings","onSettings","setAllowCustomers","allowCustomers","target","checked","setTrackClicks","trackClicks","setCountOpens","countOpens","setListUnsubscribe","listUnsubscribe","setWindow","window","countryOptions","allowedCountries","onCountries","countriesIssue","control","color","daysIssue","hoursIssue","OutreachSequenceEditor","draft","orgMount","sequence","api","enqueueSnackbar","data","user","mountedHosts","orgCountries","setDraft","attempted","setAttempted","serverIssues","setServerIssues","setSaving","testing","setTesting","drawn","settingsCountries","join","previous","split","ownSending","filter","connectedByUid","status","onlyOwnMailbox","templates","mailbox","find","sender","displayName","email","sendAs","campaigns","enabled","judged","severity","includes","issueAt","stepIssues","steps","listIssue","startsWith","clearServerIssues","update","setCountries","setName","setHost","setMailbox","setRotation","setCampaigns","setSettings","patch","setStep","moveStep","moved","splice","removeStep","_entry","addEmail","addTask","emailCount","full","firstEmail","findIndex","threadSubject","subject","save","answer","saveSequence","created","onSaved","allowDuplicate","drawnSave","siteName","draftCountries","Set","unsaved","sendTestDisabledReason","container","xs","ready","inThread","stepIndex","contactGroupId","org","groupId","selfEmail","orgSettings","orgSettingsStatus"],"mappings":"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"}
@@ -86,7 +86,7 @@ import { OutreachLoading } from "./outreach-ui.js";
86
86
  header: "Preview",
87
87
  subheader: `As ${OUTREACH_SAMPLE_PERSON.name} of ${OUTREACH_SAMPLE_PERSON.companyName} would get it`,
88
88
  help: pluginDocsHelp('sequences', {
89
- anchor: '#build-a-sequence'
89
+ anchor: '#send-a-test'
90
90
  }),
91
91
  contentGutterX: true,
92
92
  contentGutterY: true,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../../libs/plugins/outreach/src/lib/components/sequence-preview.tsx"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n'use client'\n\nimport { pluginDocsHelp } from '@aglyn/aglyn'\nimport { crmMergeUnresolvedMessage } from '@aglyn/aglyn/app-utils/crm-email-templates'\nimport { CardDisplay } from '@aglyn/shared-ui-jsx'\nimport { useContentStable } from '@aglyn/shared-ui-jsx/hooks/use-content-stable'\nimport {\n Alert,\n Divider,\n MenuItem,\n Paper,\n Stack,\n TextField,\n Typography,\n} from '@mui/material'\nimport { memo, useMemo, useState } from 'react'\nimport type {\n OutreachComplianceSettingsDocument,\n OutreachSequenceStep,\n} from '../model/outreach.types'\nimport {\n OUTREACH_SAMPLE_PERSON,\n outreachSampleMergeContext,\n previewOutreachStep,\n} from '../model/step-preview'\nimport { OutreachLoading } from './outreach-ui'\nimport type { OutreachTemplateOption } from './use-outreach-crm'\nimport type { OutreachLoadStatus } from './use-outreach-data'\n\nexport interface OutreachSequencePreviewProps {\n steps: readonly OutreachSequenceStep[]\n /** The organization's footer fields; `null` until they are read. */\n orgSettings: OutreachComplianceSettingsDocument | null\n orgSettingsStatus: OutreachLoadStatus\n templates: readonly OutreachTemplateOption[]\n /** Who the email is from, as the mailbox says it. */\n sender: { name: string; email: string } | null\n siteName: string\n}\n\n/** One email the preview can show: its step's id, and the step's position. */\ninterface PreviewChoice {\n id: string\n index: number\n}\n\n/** Which email the preview shows, when the sequence has more than one. */\nconst PreviewEmailPicker = memo(function PreviewEmailPicker(props: {\n choices: readonly PreviewChoice[]\n value: number\n onChange(position: number): void\n}) {\n const { onChange } = props\n return (\n <TextField\n select\n size=\"small\"\n label=\"Email\"\n value={props.value}\n onChange={(event) => onChange(Number(event.target.value))}\n >\n {props.choices.map((entry, position) => (\n <MenuItem key={entry.id} value={position}>\n {`Email ${position + 1} · step ${entry.index + 1}`}\n </MenuItem>\n ))}\n </TextField>\n )\n})\n\n/**\n * The editor's live preview (AGL-2980): each email as it would reach a\n * sample contact, written by the engine's own composer as the rep types —\n * merge fields filled, the sample's personal line in place, and the real\n * footer from the organization's compliance settings at the end.\n */\nexport function OutreachSequencePreview(props: OutreachSequencePreviewProps) {\n const emails = props.steps\n .map((step, index) => ({ step, index }))\n .filter(({ step }) => step.kind === 'email')\n const [chosen, setChosen] = useState(0)\n const selected = emails[Math.min(chosen, emails.length - 1)]\n // Held by content: typing into a step leaves the emails to pick from as\n // they were, and the picker undrawn (AGL-3423).\n const choices = useContentStable(\n emails.map(({ step, index }) => ({ id: step.id, index })),\n )\n\n const result = useMemo(() => {\n if (!selected) return null\n const step = selected.step\n return previewOutreachStep({\n steps: props.steps,\n stepIndex: selected.index,\n orgSettings: props.orgSettings,\n merge: outreachSampleMergeContext({\n sender: props.sender,\n siteName: props.siteName,\n }),\n email: OUTREACH_SAMPLE_PERSON.email,\n personalLine: OUTREACH_SAMPLE_PERSON.personalLine,\n templateBody:\n step.kind === 'email' && step.templateId\n ? (props.templates.find((template) => template.id === step.templateId)\n ?.body ?? null)\n : null,\n })\n }, [\n selected,\n props.steps,\n props.orgSettings,\n props.sender,\n props.siteName,\n props.templates,\n ])\n\n return (\n <CardDisplay\n header=\"Preview\"\n subheader={`As ${OUTREACH_SAMPLE_PERSON.name} of ${OUTREACH_SAMPLE_PERSON.companyName} would get it`}\n help={pluginDocsHelp('sequences', { anchor: '#build-a-sequence' })}\n contentGutterX\n contentGutterY\n >\n {!selected ? (\n <Typography variant=\"body2\" color=\"text.secondary\">\n Add an email step to preview it.\n </Typography>\n ) : props.orgSettingsStatus === 'loading' ? (\n <OutreachLoading label=\"Loading your footer…\" />\n ) : props.orgSettingsStatus !== 'ready' ? (\n <Alert severity=\"info\">\n The preview needs your compliance settings, which couldn’t be read. It\n shows once they can be.\n </Alert>\n ) : (\n <Stack spacing={1.5}>\n {emails.length > 1 ? (\n <PreviewEmailPicker\n choices={choices}\n value={Math.min(chosen, emails.length - 1)}\n onChange={setChosen}\n />\n ) : null}\n {result?.email ? (\n <Paper\n variant=\"outlined\"\n sx={{ p: 1.5 }}\n aria-label=\"Email preview\"\n >\n <Stack spacing={1}>\n <Typography variant=\"body2\">\n <Typography\n component=\"span\"\n variant=\"body2\"\n color=\"text.secondary\"\n >\n Subject:{' '}\n </Typography>\n {result.email.subject}\n </Typography>\n <Divider />\n <Typography\n variant=\"body2\"\n sx={{ whiteSpace: 'pre-wrap', wordBreak: 'break-word' }}\n >\n {result.email.text}\n </Typography>\n </Stack>\n </Paper>\n ) : (\n <Alert severity=\"info\">\n {result?.error?.message ?? 'This email can’t be previewed yet.'}\n </Alert>\n )}\n {result?.email && result.unresolvedFields.length ? (\n <Typography variant=\"caption\" color=\"text.secondary\">\n {`${crmMergeUnresolvedMessage(result.unresolvedFields)}. They're sent empty.`}\n </Typography>\n ) : null}\n </Stack>\n )}\n </CardDisplay>\n )\n}\nOutreachSequencePreview.displayName = 'OutreachSequencePreview'\n\nexport default OutreachSequencePreview\n"],"names":["pluginDocsHelp","crmMergeUnresolvedMessage","CardDisplay","useContentStable","Alert","Divider","MenuItem","Paper","Stack","TextField","Typography","memo","useMemo","useState","OUTREACH_SAMPLE_PERSON","outreachSampleMergeContext","previewOutreachStep","OutreachLoading","PreviewEmailPicker","props","onChange","select","size","label","value","event","Number","target","choices","map","entry","position","index","id","OutreachSequencePreview","result","emails","steps","step","filter","kind","chosen","setChosen","selected","Math","min","length","stepIndex","orgSettings","merge","sender","siteName","email","personalLine","templateBody","templateId","templates","find","template","body","header","subheader","name","companyName","help","anchor","contentGutterX","contentGutterY","variant","color","orgSettingsStatus","severity","spacing","sx","p","aria-label","component","subject","whiteSpace","wordBreak","text","error","message","unresolvedFields","displayName"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/outreach/src/lib/components/sequence-preview.tsx"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n'use client'\n\nimport { pluginDocsHelp } from '@aglyn/aglyn'\nimport { crmMergeUnresolvedMessage } from '@aglyn/aglyn/app-utils/crm-email-templates'\nimport { CardDisplay } from '@aglyn/shared-ui-jsx'\nimport { useContentStable } from '@aglyn/shared-ui-jsx/hooks/use-content-stable'\nimport {\n Alert,\n Divider,\n MenuItem,\n Paper,\n Stack,\n TextField,\n Typography,\n} from '@mui/material'\nimport { memo, useMemo, useState } from 'react'\nimport type {\n OutreachComplianceSettingsDocument,\n OutreachSequenceStep,\n} from '../model/outreach.types'\nimport {\n OUTREACH_SAMPLE_PERSON,\n outreachSampleMergeContext,\n previewOutreachStep,\n} from '../model/step-preview'\nimport { OutreachLoading } from './outreach-ui'\nimport type { OutreachTemplateOption } from './use-outreach-crm'\nimport type { OutreachLoadStatus } from './use-outreach-data'\n\nexport interface OutreachSequencePreviewProps {\n steps: readonly OutreachSequenceStep[]\n /** The organization's footer fields; `null` until they are read. */\n orgSettings: OutreachComplianceSettingsDocument | null\n orgSettingsStatus: OutreachLoadStatus\n templates: readonly OutreachTemplateOption[]\n /** Who the email is from, as the mailbox says it. */\n sender: { name: string; email: string } | null\n siteName: string\n}\n\n/** One email the preview can show: its step's id, and the step's position. */\ninterface PreviewChoice {\n id: string\n index: number\n}\n\n/** Which email the preview shows, when the sequence has more than one. */\nconst PreviewEmailPicker = memo(function PreviewEmailPicker(props: {\n choices: readonly PreviewChoice[]\n value: number\n onChange(position: number): void\n}) {\n const { onChange } = props\n return (\n <TextField\n select\n size=\"small\"\n label=\"Email\"\n value={props.value}\n onChange={(event) => onChange(Number(event.target.value))}\n >\n {props.choices.map((entry, position) => (\n <MenuItem key={entry.id} value={position}>\n {`Email ${position + 1} · step ${entry.index + 1}`}\n </MenuItem>\n ))}\n </TextField>\n )\n})\n\n/**\n * The editor's live preview (AGL-2980): each email as it would reach a\n * sample contact, written by the engine's own composer as the rep types —\n * merge fields filled, the sample's personal line in place, and the real\n * footer from the organization's compliance settings at the end.\n */\nexport function OutreachSequencePreview(props: OutreachSequencePreviewProps) {\n const emails = props.steps\n .map((step, index) => ({ step, index }))\n .filter(({ step }) => step.kind === 'email')\n const [chosen, setChosen] = useState(0)\n const selected = emails[Math.min(chosen, emails.length - 1)]\n // Held by content: typing into a step leaves the emails to pick from as\n // they were, and the picker undrawn (AGL-3423).\n const choices = useContentStable(\n emails.map(({ step, index }) => ({ id: step.id, index })),\n )\n\n const result = useMemo(() => {\n if (!selected) return null\n const step = selected.step\n return previewOutreachStep({\n steps: props.steps,\n stepIndex: selected.index,\n orgSettings: props.orgSettings,\n merge: outreachSampleMergeContext({\n sender: props.sender,\n siteName: props.siteName,\n }),\n email: OUTREACH_SAMPLE_PERSON.email,\n personalLine: OUTREACH_SAMPLE_PERSON.personalLine,\n templateBody:\n step.kind === 'email' && step.templateId\n ? (props.templates.find((template) => template.id === step.templateId)\n ?.body ?? null)\n : null,\n })\n }, [\n selected,\n props.steps,\n props.orgSettings,\n props.sender,\n props.siteName,\n props.templates,\n ])\n\n return (\n <CardDisplay\n header=\"Preview\"\n subheader={`As ${OUTREACH_SAMPLE_PERSON.name} of ${OUTREACH_SAMPLE_PERSON.companyName} would get it`}\n help={pluginDocsHelp('sequences', { anchor: '#send-a-test' })}\n contentGutterX\n contentGutterY\n >\n {!selected ? (\n <Typography variant=\"body2\" color=\"text.secondary\">\n Add an email step to preview it.\n </Typography>\n ) : props.orgSettingsStatus === 'loading' ? (\n <OutreachLoading label=\"Loading your footer…\" />\n ) : props.orgSettingsStatus !== 'ready' ? (\n <Alert severity=\"info\">\n The preview needs your compliance settings, which couldn’t be read. It\n shows once they can be.\n </Alert>\n ) : (\n <Stack spacing={1.5}>\n {emails.length > 1 ? (\n <PreviewEmailPicker\n choices={choices}\n value={Math.min(chosen, emails.length - 1)}\n onChange={setChosen}\n />\n ) : null}\n {result?.email ? (\n <Paper\n variant=\"outlined\"\n sx={{ p: 1.5 }}\n aria-label=\"Email preview\"\n >\n <Stack spacing={1}>\n <Typography variant=\"body2\">\n <Typography\n component=\"span\"\n variant=\"body2\"\n color=\"text.secondary\"\n >\n Subject:{' '}\n </Typography>\n {result.email.subject}\n </Typography>\n <Divider />\n <Typography\n variant=\"body2\"\n sx={{ whiteSpace: 'pre-wrap', wordBreak: 'break-word' }}\n >\n {result.email.text}\n </Typography>\n </Stack>\n </Paper>\n ) : (\n <Alert severity=\"info\">\n {result?.error?.message ?? 'This email can’t be previewed yet.'}\n </Alert>\n )}\n {result?.email && result.unresolvedFields.length ? (\n <Typography variant=\"caption\" color=\"text.secondary\">\n {`${crmMergeUnresolvedMessage(result.unresolvedFields)}. They're sent empty.`}\n </Typography>\n ) : null}\n </Stack>\n )}\n </CardDisplay>\n )\n}\nOutreachSequencePreview.displayName = 'OutreachSequencePreview'\n\nexport default OutreachSequencePreview\n"],"names":["pluginDocsHelp","crmMergeUnresolvedMessage","CardDisplay","useContentStable","Alert","Divider","MenuItem","Paper","Stack","TextField","Typography","memo","useMemo","useState","OUTREACH_SAMPLE_PERSON","outreachSampleMergeContext","previewOutreachStep","OutreachLoading","PreviewEmailPicker","props","onChange","select","size","label","value","event","Number","target","choices","map","entry","position","index","id","OutreachSequencePreview","result","emails","steps","step","filter","kind","chosen","setChosen","selected","Math","min","length","stepIndex","orgSettings","merge","sender","siteName","email","personalLine","templateBody","templateId","templates","find","template","body","header","subheader","name","companyName","help","anchor","contentGutterX","contentGutterY","variant","color","orgSettingsStatus","severity","spacing","sx","p","aria-label","component","subject","whiteSpace","wordBreak","text","error","message","unresolvedFields","displayName"],"mappings":"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"}