@aglyn/plugins-outreach 1.0.0-beta.231 → 1.0.0-beta.232
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 +14 -14
- package/src/lib/components/curated-step-editor.js +1 -0
- package/src/lib/components/curated-step-editor.js.map +1 -1
- package/src/lib/components/enroll-dialog.js +6 -0
- package/src/lib/components/enroll-dialog.js.map +1 -1
- package/src/lib/components/enrollment-detail.js +3 -0
- package/src/lib/components/enrollment-detail.js.map +1 -1
- package/src/lib/components/enrollments-table.js +1 -0
- package/src/lib/components/enrollments-table.js.map +1 -1
- package/src/lib/components/link-domains-card.js +2 -0
- package/src/lib/components/link-domains-card.js.map +1 -1
- package/src/lib/components/mailboxes-section.js +1 -0
- package/src/lib/components/mailboxes-section.js.map +1 -1
- package/src/lib/components/sequence-detail.js +1 -0
- package/src/lib/components/sequence-detail.js.map +1 -1
- package/src/lib/components/sequence-report-card.js +1 -0
- package/src/lib/components/sequence-report-card.js.map +1 -1
- package/src/lib/components/sequences-section.js +1 -0
- package/src/lib/components/sequences-section.js.map +1 -1
|
@@ -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 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 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 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","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-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 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../../libs/plugins/outreach/src/lib/components/enrollments-table.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 EmptyStateComponent from '@aglyn/shared-ui-jsx/components/empty-state.component'\nimport ListFilterChips from '@aglyn/shared-ui-jsx/components/list-filter-chips.component'\nimport ListQueryNotices, {\n listQueryRefusals,\n} from '@aglyn/shared-ui-jsx/components/list-query-notices.component'\nimport { ListPagination } from '@aglyn/shared-ui-jsx/components/list-pagination.component'\nimport {\n ListRowActions,\n ListTable,\n listActionsColumn,\n type ListTableProps,\n} from '@aglyn/shared-ui-jsx/components/list-table.component'\nimport { hiddenFilterVisibility, type ListFilterField } from '@aglyn/shared-ui-jsx/const/list-filter'\nimport {\n listFilterGridColumns,\n type ListFilterClause,\n type ListFilterOption,\n} from '@aglyn/shared-ui-jsx/const/list-grid-filter'\nimport { useListGridFilter } from '@aglyn/shared-ui-jsx/hooks/use-list-grid-filter'\nimport {\n Card,\n CardContent,\n Chip,\n Link,\n Stack,\n Tooltip,\n Typography,\n useMediaQuery,\n useTheme,\n} from '@mui/material'\nimport { type MouseEvent, type ReactNode, useMemo } from 'react'\nimport {\n outreachClickCountLabel,\n outreachClickSummary,\n outreachMachineOpenLabel,\n outreachOpenCountLabel,\n outreachOpenSummary,\n type OutreachClickSummary,\n type OutreachOpenSummary,\n} from '../model/enrollment-engagement'\nimport {\n OUTREACH_ENROLLMENT_CLICK_FIELDS,\n OUTREACH_ENROLLMENT_LIST_QUERY,\n} from '../model/enrollment-list-query'\nimport {\n OUTREACH_ENROLLMENT_STATUSES,\n OUTREACH_STOP_REASONS,\n OUTREACH_TASK_KIND_LABELS,\n type OutreachEnrollment,\n type OutreachMailbox,\n type OutreachSequence,\n type OutreachSequenceStep,\n} from '../model/outreach.types'\nimport { outreachNextSendState, type OutreachNextSendState } from '../engine/next-send'\nimport { useOutreachEnrollmentActions } from './enrollment-actions'\nimport { OUTREACH_CLICKED_FILTER_VALUE, OUTREACH_UNCLICKED_FILTER_VALUE } from './enrollment-filter-params'\nimport {\n OutreachNextSend,\n outreachNextSendDetail,\n outreachNextSendLabel,\n useOutreachNowMs,\n} from './next-send'\nimport {\n formatOutreachTime,\n OUTREACH_ENROLLMENT_STATUS_LABELS,\n OUTREACH_STOP_REASON_LABELS,\n OutreachEnrollmentStatusChip,\n OutreachLoading,\n OutreachLoadProblem,\n} from './outreach-ui'\nimport type { OutreachApi } from './use-outreach-api'\nimport { useOutreachEnrollmentList } from './use-outreach-data'\n\nexport interface OutreachEnrollmentsTableProps {\n /** The organization, whose enrollments the table asks for. */\n orgId: string\n /** The sequence whose people these are: every page is narrowed to it. */\n sequenceId: string\n steps: readonly OutreachSequenceStep[]\n /**\n * Whether this sequence counts link clicks (AGL-3239). The Clicks column\n * is shown only when it does: a column of dashes for a sequence that\n * measures nothing reads as \"nobody clicked\", which is a different claim\n * and a false one.\n */\n trackClicks?: boolean\n /**\n * Whether this sequence counts opens, or once did (AGL-3488). The Opens\n * column is shown only then, for the reason the Clicks column is: a\n * column of dashes where nothing was measured reads as \"nobody opened\".\n */\n countOpens?: boolean\n /** The mailbox's IANA zone, which next sends are read in; `null` for the reader's own. */\n timeZone: string | null\n /**\n * The sequence's mailbox, whose pacing a due enrollment waits on\n * (AGL-3366): `undefined` while the mailboxes load, `null` when it has none.\n */\n mailbox?: OutreachMailbox | null\n /** The sequence, whose status and window a due enrollment waits on too. */\n sequence?: Pick<OutreachSequence, 'status' | 'steps' | 'settings'> | null\n api: OutreachApi\n /** Shown in the empty state when the sequence takes people. */\n enrollAction?: ReactNode\n /**\n * Opens one person's page (AGL-3332): a row's click, Enter on a focused\n * row, or the name on a phone's card. The row's menu never opens it.\n */\n onOpen?: (enrollment: OutreachEnrollment) => void\n /** The person's page, for the name on a phone's card, which is a real link. */\n hrefFor?: (enrollment: OutreachEnrollment) => string\n /**\n * The clauses the table is narrowed by, when the page holds them — so the\n * Results card's \"Clicked\" and \"Links followed\" can set one (AGL-3332).\n * Omitted, the table holds its own.\n */\n clauses?: readonly ListFilterClause[]\n onClausesChange?: (clauses: ListFilterClause[]) => void\n /** Destinations the sequence's links went to, for the \"Link followed\" filter's choices. */\n linkOptions?: readonly ListFilterOption[]\n}\n\n/** The step an enrollment is on, as a person reads it. */\nexport function outreachCurrentStepLabel(\n enrollment: Pick<OutreachEnrollment, 'status' | 'stepIndex'>,\n steps: readonly OutreachSequenceStep[],\n): string {\n if (enrollment.status === 'finished' || enrollment.stepIndex >= steps.length)\n return 'All steps done'\n const step = steps[enrollment.stepIndex]\n const kind =\n step?.kind === 'email'\n ? 'Email'\n : step?.kind === 'task'\n ? OUTREACH_TASK_KIND_LABELS[step.taskKind]\n : 'Step'\n return `Step ${enrollment.stepIndex + 1} of ${steps.length} · ${kind}`\n}\n\n/** Why an enrollment stopped, as the table says it; `''` while it runs. */\nexport function outreachStopLabel(\n enrollment: Pick<OutreachEnrollment, 'stopReason' | 'stopDetail'>,\n): string {\n if (!enrollment.stopReason) return ''\n const reason = OUTREACH_STOP_REASON_LABELS[enrollment.stopReason] ?? ''\n return enrollment.stopDetail ? `${reason} — ${enrollment.stopDetail}` : reason\n}\n\n/** The last thing that happened: a send, a stop, or the enrollment itself. */\nfunction lastActivityMs(enrollment: OutreachEnrollment): number {\n return Math.max(\n enrollment.lastSentAtMs ?? 0,\n enrollment.stoppedAtMs ?? 0,\n enrollment.createdAtMs ?? 0,\n )\n}\n\n/** Whether the step the enrollment is on goes out as this person's own copy (AGL-3324). */\nexport function outreachStepIsCurated(\n enrollment: Pick<OutreachEnrollment, 'stepIndex' | 'stepOverrides'>,\n): boolean {\n return Boolean(enrollment.stepOverrides?.[String(enrollment.stepIndex)])\n}\n\n/*\n * What the enrollments grid's Filters panel offers (AGL-3317), each field on\n * the table's Firestore query (AGL-3321, `OUTREACH_ENROLLMENT_LIST_QUERY`).\n * Status, whether the person is a lead and the stop reason are picked; the\n * address is typed whole. `target` and `email` are no column of their own,\n * so they are hidden columns the panel can still reach; the search box\n * reads the person's name and address.\n *\n * A sequence that counts clicks adds two more (AGL-3332), on the same query:\n * whether the person clicked, and a destination they followed — matched\n * whole against the destinations stored on the enrollment, never by a piece\n * of its address, so \"followed /pricing\" does not also list the people who\n * followed \"/pricing/enterprise\".\n */\nconst BASE_FILTER_FIELDS = OUTREACH_ENROLLMENT_LIST_QUERY.fields.filter(\n (field) => !(OUTREACH_ENROLLMENT_CLICK_FIELDS as readonly string[]).includes(field.column),\n)\nconst ENROLLMENT_FILTER_HEADERS: Readonly<Record<string, string>> = {\n status: 'Status',\n target: 'Enrolled as',\n stopReason: 'Stop reason',\n email: 'Email',\n enrolled: 'Enrolled',\n clicked: 'Clicked',\n link: 'Link followed',\n}\nconst BASE_FILTER_OPTIONS: Record<string, readonly ListFilterOption[]> = {\n status: OUTREACH_ENROLLMENT_STATUSES.map((status) => ({\n value: status,\n label: OUTREACH_ENROLLMENT_STATUS_LABELS[status],\n })),\n target: [\n { value: 'contact', label: 'Contact' },\n { value: 'lead', label: 'Lead' },\n ],\n stopReason: OUTREACH_STOP_REASONS.map((reason) => ({\n value: reason,\n label: OUTREACH_STOP_REASON_LABELS[reason],\n })),\n}\nconst CLICKED_OPTIONS: readonly ListFilterOption[] = [\n { value: OUTREACH_CLICKED_FILTER_VALUE, label: 'Yes' },\n { value: OUTREACH_UNCLICKED_FILTER_VALUE, label: 'No' },\n]\n/** Columns a reader can show from the column chooser, off until they do (AGL-3332). */\nconst CLICK_DETAIL_COLUMNS = ['linksFollowed', 'lastClick', 'scannerClicks'] as const\n/** The opens column a reader can show from the column chooser, off until they do. */\nconst OPEN_DETAIL_COLUMNS = ['lastOpen'] as const\n\n/** The table's grammar, with the click fields when the sequence counts clicks. */\nfunction filterFieldsFor(trackClicks: boolean): readonly ListFilterField[] {\n return trackClicks ? OUTREACH_ENROLLMENT_LIST_QUERY.fields : BASE_FILTER_FIELDS\n}\n\n/** What the grid's cells and its export read off one enrollment. */\nfunction filterRow(\n enrollment: OutreachEnrollment,\n steps: readonly OutreachSequenceStep[],\n clicks: OutreachClickSummary,\n) {\n return {\n enrollment,\n status: enrollment.status,\n target: enrollment.target === 'lead' ? 'lead' : 'contact',\n contactName: enrollment.contactName,\n email: enrollment.email,\n step: outreachCurrentStepLabel(enrollment, steps),\n stopReason: outreachStopLabel(enrollment),\n clicked: clicks.clicks > 0 ? OUTREACH_CLICKED_FILTER_VALUE : OUTREACH_UNCLICKED_FILTER_VALUE,\n link: clicks.followed,\n }\n}\n\n/** The stop reason: its short label, with every word of it on hover and on the person's page. */\nfunction StopReasonCell(props: { enrollment: OutreachEnrollment }) {\n const { enrollment } = props\n if (!enrollment.stopReason) {\n return (\n <Typography variant=\"body2\" color=\"text.secondary\">\n —\n </Typography>\n )\n }\n const label = OUTREACH_STOP_REASON_LABELS[enrollment.stopReason] ?? ''\n const text = (\n <Typography\n variant=\"body2\"\n sx={{\n whiteSpace: 'normal',\n lineHeight: 1.3,\n ...(enrollment.stopDetail\n ? { textDecoration: 'underline dotted', textUnderlineOffset: 3, cursor: 'help' }\n : {}),\n }}\n >\n {label}\n </Typography>\n )\n return enrollment.stopDetail ? (\n <Tooltip title={outreachStopLabel(enrollment)} describeChild>\n {text}\n </Tooltip>\n ) : (\n text\n )\n}\n\n/**\n * The Opens cell (AGL-3488): the person's opens, and under them the fetches\n * a machine made — counted apart and never in the person's number, as\n * scanner clicks are never in their clicks.\n */\nfunction OpensCell(props: { opens: OutreachOpenSummary }) {\n const { opens } = props\n const machines = outreachMachineOpenLabel(opens)\n return (\n <Stack spacing={0} sx={{ justifyContent: 'center', height: '100%' }}>\n <Typography variant=\"body2\" color={opens.opens ? undefined : 'text.secondary'}>\n {opens.opens ? String(opens.opens) : '—'}\n </Typography>\n {machines ? (\n <Tooltip\n title=\"Fetches of the tracking image by a mail provider’s proxy or a security scanner. They aren’t counted as the person’s opens.\"\n describeChild\n >\n <Typography\n variant=\"caption\"\n color=\"text.secondary\"\n noWrap\n sx={{ textDecoration: 'underline dotted', textUnderlineOffset: 3, cursor: 'help' }}\n >\n {machines}\n </Typography>\n </Tooltip>\n ) : null}\n </Stack>\n )\n}\n\n/** The table's columns; the person and the actions are drawn from the row's enrollment. */\nfunction columns(\n rowActions: (enrollment: OutreachEnrollment) => ReactNode,\n trackClicks: boolean,\n countOpens: boolean,\n timeZone: string | null,\n): NonNullable<ListTableProps['columns']> {\n return [\n {\n field: 'person',\n headerName: 'Person',\n flex: 1.2,\n minWidth: 190,\n sortable: false,\n // What the export writes for a column that is drawn rather than read.\n valueGetter: (_value: unknown, row: { enrollment: OutreachEnrollment }) =>\n row.enrollment.contactName\n ? `${row.enrollment.contactName} <${row.enrollment.email}>`\n : row.enrollment.email,\n renderCell: ({ row }) => (\n <Stack\n spacing={0}\n sx={{ justifyContent: 'center', height: '100%', minWidth: 0 }}\n >\n <Stack direction=\"row\" spacing={0.75} sx={{ alignItems: 'center', minWidth: 0 }}>\n <Typography variant=\"body2\" noWrap>\n {row.enrollment.contactName || row.enrollment.email}\n </Typography>\n {row.enrollment.target === 'lead' ? (\n <Chip size=\"small\" variant=\"outlined\" label=\"Lead\" />\n ) : null}\n </Stack>\n {row.enrollment.contactName ? (\n <Typography variant=\"caption\" color=\"text.secondary\" noWrap>\n {row.enrollment.email}\n </Typography>\n ) : null}\n </Stack>\n ),\n },\n {\n field: 'status',\n headerName: 'Status',\n width: 110,\n renderCell: ({ row }) => (\n <OutreachEnrollmentStatusChip status={row.status} />\n ),\n },\n {\n field: 'step',\n headerName: 'Current step',\n flex: 1,\n minWidth: 170,\n renderCell: ({ row }) => (\n <Stack direction=\"row\" spacing={0.75} sx={{ alignItems: 'center', height: '100%', minWidth: 0 }}>\n <Typography variant=\"body2\" noWrap>\n {row.step}\n </Typography>\n {outreachStepIsCurated(row.enrollment) ? (\n <Chip size=\"small\" variant=\"outlined\" color=\"success\" label=\"Curated\" />\n ) : null}\n </Stack>\n ),\n },\n {\n field: 'nextSend',\n headerName: 'Next send',\n width: 190,\n sortable: false,\n renderCell: ({ row }: { row: { nextSendState: OutreachNextSendState } }) => (\n <Stack sx={{ justifyContent: 'center', height: '100%' }}>\n <OutreachNextSend state={row.nextSendState} timeZone={timeZone} />\n </Stack>\n ),\n },\n {\n field: 'lastActivity',\n headerName: 'Last activity',\n width: 170,\n sortable: false,\n },\n ...(countOpens\n ? [\n {\n field: 'opens',\n headerName: 'Opens',\n description:\n 'A person’s opens of the emails. Fetches by mail proxies and security scanners are shown under them and not counted.',\n width: 130,\n sortable: false,\n renderCell: ({ row }: { row: { openSummary: OutreachOpenSummary } }) => (\n <OpensCell opens={row.openSummary} />\n ),\n },\n { field: 'lastOpen', headerName: 'Last open', width: 170, sortable: false },\n ]\n : []),\n ...(trackClicks\n ? [\n {\n field: 'clicks',\n headerName: 'Clicks',\n description: 'A person’s clicks, and how many different links they followed. Scanners are not counted.',\n width: 110,\n sortable: false,\n renderCell: ({ row }: { row: { clicks: string } }) => (\n <Typography variant=\"body2\" color={row.clicks === '—' ? 'text.secondary' : undefined}>\n {row.clicks}\n </Typography>\n ),\n },\n {\n field: 'linksFollowed',\n headerName: 'Links followed',\n flex: 1,\n minWidth: 220,\n sortable: false,\n },\n { field: 'lastClick', headerName: 'Last click', width: 170, sortable: false },\n {\n field: 'scannerClicks',\n headerName: 'Scanner clicks',\n description: 'Clicks a security scanner made, which are not counted as the person’s.',\n width: 130,\n sortable: false,\n },\n ]\n : []),\n {\n field: 'stopReason',\n headerName: 'Stop reason',\n flex: 1,\n minWidth: 170,\n renderCell: ({ row }) => <StopReasonCell enrollment={row.enrollment} />,\n },\n listActionsColumn((row) => rowActions(row.enrollment), { width: 72 }),\n ]\n}\n\n/** A plain click on a link, which the page handles itself; any other is the browser's. */\nconst plainClick = (event: MouseEvent) =>\n !event.defaultPrevented &&\n event.button === 0 &&\n !event.metaKey &&\n !event.ctrlKey &&\n !event.shiftKey &&\n !event.altKey\n\n/**\n * A sequence's enrollments (AGL-2980): who is in it, where each person\n * stands, when their next step goes out in the mailbox's timezone, and the\n * four things a member can do about it — pause, resume, stop, and mark\n * do-not-contact. A table on wider screens, a list of cards on a phone.\n *\n * Each row opens the person's own page (AGL-3332), which holds everything\n * else known about them: so a cell says one thing, whole, and the detail\n * behind it is a click away rather than cut off at the column's edge.\n */\nexport function OutreachEnrollmentsTable(props: OutreachEnrollmentsTableProps) {\n const { steps, timeZone, api, onOpen, hrefFor } = props\n const trackClicks = props.trackClicks === true\n const countOpens = props.countOpens === true\n const nowMs = useOutreachNowMs()\n const theme = useTheme()\n const narrow = useMediaQuery(theme.breakpoints.down('md'))\n const actions = useOutreachEnrollmentActions({ api, steps })\n const fields = useMemo(() => filterFieldsFor(trackClicks), [trackClicks])\n const gridFilter = useListGridFilter({\n selectFields: ['status', 'target', 'stopReason', 'clicked', 'link'],\n ...(props.clauses !== undefined\n ? { clauses: props.clauses, onChange: props.onClausesChange }\n : {}),\n })\n const filtering =\n gridFilter.clauses.length > 0 || gridFilter.searchWords.some((word) => word.trim())\n /*\n * One page of the sequence's enrollments, newest enrolled first, with\n * every clause and the search word on the query (AGL-3321): a filter\n * reaches the enrollment on page forty as surely as the one on page one,\n * and nothing is matched over the rows that happen to be loaded. The\n * click filters (AGL-3332) are on it too, answered by the `clicked` flag\n * and the destinations the click route stores on each enrollment.\n */\n const enrollments = useOutreachEnrollmentList(props.orgId, props.sequenceId, {\n clauses: gridFilter.clauses,\n search: gridFilter.searchWords,\n })\n const loadedData = enrollments.rows\n const summaries = useMemo(\n () =>\n new Map(\n loadedData.map((enrollment) => [enrollment.id, outreachClickSummary(enrollment.engagement)]),\n ),\n [loadedData],\n )\n const clicksOf = (enrollment: OutreachEnrollment) =>\n summaries.get(enrollment.id) ?? outreachClickSummary(enrollment.engagement)\n\n /*\n * The destinations the \"Link followed\" filter offers: the sequence's own\n * rollup, and any a loaded person followed that it does not list — the\n * rollup is capped, and a filter that could not name a destination a\n * person followed would hide them from it.\n */\n const linkOptions = useMemo(() => {\n const options = new Map<string, string>()\n for (const option of props.linkOptions ?? []) options.set(option.value, option.label)\n for (const summary of summaries.values()) {\n for (const url of summary.followed) if (!options.has(url)) options.set(url, url)\n }\n return [...options].map(([value, label]) => ({ value, label }))\n }, [props.linkOptions, summaries])\n const filterOptions = useMemo(\n () =>\n trackClicks\n ? { ...BASE_FILTER_OPTIONS, clicked: CLICKED_OPTIONS, link: linkOptions }\n : BASE_FILTER_OPTIONS,\n [trackClicks, linkOptions],\n )\n const hiddenColumns = useMemo(\n () => ({\n ...hiddenFilterVisibility(fields, ['status', 'stopReason']),\n ...(trackClicks\n ? Object.fromEntries(CLICK_DETAIL_COLUMNS.map((column) => [column, false]))\n : {}),\n ...(countOpens\n ? Object.fromEntries(OPEN_DETAIL_COLUMNS.map((column) => [column, false]))\n : {}),\n }),\n [fields, trackClicks, countOpens],\n )\n /*\n * A person who followed this destination before each click was recorded\n * on its own, and another link after it, is known by their LAST link only\n * — so a \"Link followed\" filter says it may miss them rather than\n * implying the list is whole. Which people those are is exactly what the\n * query cannot see, so the caveat stands whenever the filter does.\n */\n const linkFilterMayMiss =\n trackClicks && gridFilter.clauses.some((clause) => clause.field === 'link')\n\n const chips = (\n <ListFilterChips\n fields={fields}\n headers={ENROLLMENT_FILTER_HEADERS}\n clauses={gridFilter.clauses}\n onChange={gridFilter.setClauses}\n options={filterOptions}\n />\n )\n if (enrollments.status === 'loading' && !filtering)\n return <OutreachLoading label=\"Loading enrollments…\" />\n if (enrollments.status === 'error' || enrollments.status === 'refused') {\n return (\n <Stack spacing={1.5}>\n {chips}\n <OutreachLoadProblem status={enrollments.status} what=\"enrollments\" />\n </Stack>\n )\n }\n if (\n enrollments.status === 'ready' &&\n !enrollments.rows.length &&\n !filtering &&\n enrollments.page === 0\n ) {\n return (\n <Card variant=\"outlined\">\n <EmptyStateComponent\n label=\"Nobody is enrolled yet\"\n description=\"People you enroll show here, with where each of them is in the sequence.\"\n action={props.enrollAction}\n />\n </Card>\n )\n }\n\n const rowActions = (enrollment: OutreachEnrollment) => (\n <ListRowActions\n label={enrollment.contactName || enrollment.email}\n items={actions.menuItems(enrollment)}\n />\n )\n /*\n * A next send whose time has come says it is queued, and why, rather than\n * showing a time already past (AGL-3366): the mailbox sends its share of\n * the day each run, follow-ups first, so a first email can wait its turn\n * for an hour or more without anything having failed.\n */\n const nextSendState = (enrollment: OutreachEnrollment) =>\n outreachNextSendState({\n enrollment,\n sequence: props.sequence ?? null,\n mailbox: props.mailbox,\n nowMs,\n })\n const personName = (enrollment: OutreachEnrollment) => {\n const name = enrollment.contactName || enrollment.email\n if (!hrefFor) return <Typography variant=\"body2\">{name}</Typography>\n return (\n <Link\n href={hrefFor(enrollment)}\n variant=\"body2\"\n underline=\"hover\"\n onClick={(event) => {\n if (!onOpen || !plainClick(event)) return\n event.preventDefault()\n onOpen(enrollment)\n }}\n >\n {name}\n </Link>\n )\n }\n const person = (enrollment: OutreachEnrollment) => (\n <Stack spacing={0}>\n <Stack direction=\"row\" spacing={0.75} sx={{ alignItems: 'center' }}>\n {personName(enrollment)}\n {enrollment.target === 'lead' ? (\n <Chip size=\"small\" variant=\"outlined\" label=\"Lead\" />\n ) : null}\n </Stack>\n {enrollment.contactName ? (\n <Typography variant=\"caption\" color=\"text.secondary\">\n {enrollment.email}\n </Typography>\n ) : null}\n </Stack>\n )\n\n const pageRows = enrollments.rows\n\n return (\n <Stack spacing={1.5}>\n {chips}\n <ListQueryNotices\n refused={listQueryRefusals(enrollments.plan.refused, {\n fields,\n headers: ENROLLMENT_FILTER_HEADERS,\n options: filterOptions,\n })}\n notices={enrollments.plan.notices}\n />\n {linkFilterMayMiss ? (\n <Typography variant=\"caption\" color=\"text.secondary\">\n Clicks made before each one was recorded on its own kept only the person’s last link, so\n someone who followed this link and then another back then is not listed here.\n </Typography>\n ) : null}\n {narrow ? (\n <Stack\n spacing={1}\n component=\"ul\"\n sx={{ listStyle: 'none', p: 0, m: 0 }}\n aria-label=\"Enrollments\"\n >\n {pageRows.map((enrollment) => {\n const clicks = clicksOf(enrollment)\n const opens = outreachOpenSummary(enrollment.engagement)\n return (\n <Card key={enrollment.id} variant=\"outlined\" component=\"li\">\n <CardContent>\n <Stack spacing={1}>\n <Stack\n direction=\"row\"\n spacing={1}\n sx={{ alignItems: 'flex-start' }}\n >\n <Stack sx={{ flexGrow: 1, minWidth: 0 }}>\n {person(enrollment)}\n </Stack>\n <OutreachEnrollmentStatusChip status={enrollment.status} />\n {rowActions(enrollment)}\n </Stack>\n <Stack direction=\"row\" spacing={0.75} sx={{ alignItems: 'center' }}>\n <Typography variant=\"body2\" color=\"text.secondary\">\n {outreachCurrentStepLabel(enrollment, steps)}\n </Typography>\n {outreachStepIsCurated(enrollment) ? (\n <Chip size=\"small\" variant=\"outlined\" color=\"success\" label=\"Curated\" />\n ) : null}\n </Stack>\n <Stack\n direction=\"row\"\n spacing={0.5}\n sx={{ alignItems: 'baseline', flexWrap: 'wrap', color: 'text.secondary' }}\n >\n <Typography variant=\"body2\">Next send:</Typography>\n <OutreachNextSend state={nextSendState(enrollment)} timeZone={timeZone} />\n <Typography variant=\"body2\">\n {`· Last activity: ${formatOutreachTime(lastActivityMs(enrollment), timeZone)}`}\n </Typography>\n </Stack>\n {countOpens && (opens.opens || opens.machineOpens) ? (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {`Opens: ${outreachOpenCountLabel(opens)}`}\n </Typography>\n ) : null}\n {trackClicks && clicks.clicks ? (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {`Clicks: ${outreachClickCountLabel(clicks)}`}\n </Typography>\n ) : null}\n {outreachStopLabel(enrollment) ? (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {outreachStopLabel(enrollment)}\n </Typography>\n ) : null}\n </Stack>\n </CardContent>\n </Card>\n )\n })}\n </Stack>\n ) : (\n <ListTable\n aria-label=\"Enrollments\"\n columns={listFilterGridColumns(\n columns(rowActions, trackClicks, countOpens, timeZone),\n fields,\n filterOptions,\n ENROLLMENT_FILTER_HEADERS,\n )}\n initialState={{ columns: { columnVisibilityModel: hiddenColumns } }}\n loading={enrollments.status === 'loading'}\n rows={pageRows.map((enrollment) => {\n const clicks = clicksOf(enrollment)\n const opens = outreachOpenSummary(enrollment.engagement)\n const next = nextSendState(enrollment)\n return {\n $id: enrollment.id,\n ...filterRow(enrollment, steps, clicks),\n nextSendState: next,\n // What the export writes: the label, and for a queued send, why.\n nextSend: [outreachNextSendLabel(next, timeZone), outreachNextSendDetail(next, timeZone)]\n .filter(Boolean)\n .join(' — '),\n lastActivity: formatOutreachTime(\n lastActivityMs(enrollment),\n timeZone,\n ),\n // What the export writes; the cells draw these their own way.\n openSummary: opens,\n opens: outreachOpenCountLabel(opens),\n lastOpen: opens.opens ? formatOutreachTime(opens.lastOpenAtMs, timeZone) : '—',\n clicks: outreachClickCountLabel(clicks),\n linksFollowed: clicks.followed.join(' ') || '—',\n lastClick: clicks.clicks\n ? formatOutreachTime(enrollment.engagement?.lastClickAtMs, timeZone)\n : '—',\n scannerClicks: clicks.machineClicks ? String(clicks.machineClicks) : '—',\n stopReason: outreachStopLabel(enrollment) || '—',\n }\n })}\n onOpen={\n onOpen\n ? (_id, row: { enrollment: OutreachEnrollment }) => onOpen(row.enrollment)\n : undefined\n }\n /*\n * The panel and the search are the grid's; every clause and the\n * search word are on the table's query (AGL-3321). The grid\n * neither filters nor sorts the page it is handed: the query's\n * one order, newest enrolled first, is the table's.\n */\n filterMode=\"server\"\n filterModel={gridFilter.filterModel}\n onFilterModelChange={gridFilter.onFilterModelChange}\n quickFilter\n disableColumnSorting\n noRowsLabel=\"No enrollments match these filters\"\n hideFooter\n />\n )}\n <ListPagination\n page={enrollments.page}\n pageSize={enrollments.pageSize}\n rowCount={pageRows.length}\n hasMore={enrollments.hasMore}\n onPageChange={enrollments.setPage}\n onPageSizeChange={enrollments.setPageSize}\n />\n {actions.dialogs}\n </Stack>\n )\n}\nOutreachEnrollmentsTable.displayName = 'OutreachEnrollmentsTable'\n\nexport default OutreachEnrollmentsTable\n"],"names":["EmptyStateComponent","ListFilterChips","ListQueryNotices","listQueryRefusals","ListPagination","ListRowActions","ListTable","listActionsColumn","hiddenFilterVisibility","listFilterGridColumns","useListGridFilter","Card","CardContent","Chip","Link","Stack","Tooltip","Typography","useMediaQuery","useTheme","useMemo","outreachClickCountLabel","outreachClickSummary","outreachMachineOpenLabel","outreachOpenCountLabel","outreachOpenSummary","OUTREACH_ENROLLMENT_CLICK_FIELDS","OUTREACH_ENROLLMENT_LIST_QUERY","OUTREACH_ENROLLMENT_STATUSES","OUTREACH_STOP_REASONS","OUTREACH_TASK_KIND_LABELS","outreachNextSendState","useOutreachEnrollmentActions","OUTREACH_CLICKED_FILTER_VALUE","OUTREACH_UNCLICKED_FILTER_VALUE","OutreachNextSend","outreachNextSendDetail","outreachNextSendLabel","useOutreachNowMs","formatOutreachTime","OUTREACH_ENROLLMENT_STATUS_LABELS","OUTREACH_STOP_REASON_LABELS","OutreachEnrollmentStatusChip","OutreachLoading","OutreachLoadProblem","useOutreachEnrollmentList","outreachCurrentStepLabel","enrollment","steps","status","stepIndex","length","step","kind","taskKind","outreachStopLabel","stopReason","reason","stopDetail","lastActivityMs","Math","max","lastSentAtMs","stoppedAtMs","createdAtMs","outreachStepIsCurated","Boolean","stepOverrides","String","BASE_FILTER_FIELDS","fields","filter","field","includes","column","ENROLLMENT_FILTER_HEADERS","target","email","enrolled","clicked","link","BASE_FILTER_OPTIONS","map","value","label","CLICKED_OPTIONS","CLICK_DETAIL_COLUMNS","OPEN_DETAIL_COLUMNS","filterFieldsFor","trackClicks","filterRow","clicks","contactName","followed","StopReasonCell","props","variant","color","text","sx","whiteSpace","lineHeight","textDecoration","textUnderlineOffset","cursor","title","describeChild","OpensCell","opens","machines","spacing","justifyContent","height","undefined","noWrap","columns","rowActions","countOpens","timeZone","headerName","flex","minWidth","sortable","valueGetter","_value","row","renderCell","direction","alignItems","size","width","state","nextSendState","description","openSummary","plainClick","event","defaultPrevented","button","metaKey","ctrlKey","shiftKey","altKey","OutreachEnrollmentsTable","api","onOpen","hrefFor","nowMs","theme","narrow","breakpoints","down","actions","gridFilter","selectFields","clauses","onChange","onClausesChange","filtering","searchWords","some","word","trim","enrollments","orgId","sequenceId","search","loadedData","rows","summaries","Map","id","engagement","clicksOf","get","linkOptions","options","option","set","summary","values","url","has","filterOptions","hiddenColumns","Object","fromEntries","linkFilterMayMiss","clause","chips","headers","setClauses","what","page","action","enrollAction","items","menuItems","sequence","mailbox","personName","name","href","underline","onClick","preventDefault","person","pageRows","refused","plan","notices","component","listStyle","p","m","aria-label","flexGrow","flexWrap","machineOpens","initialState","columnVisibilityModel","loading","next","$id","nextSend","join","lastActivity","lastOpen","lastOpenAtMs","linksFollowed","lastClick","lastClickAtMs","scannerClicks","machineClicks","_id","filterMode","filterModel","onFilterModelChange","quickFilter","disableColumnSorting","noRowsLabel","hideFooter","pageSize","rowCount","hasMore","onPageChange","setPage","onPageSizeChange","setPageSize","dialogs","displayName"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/outreach/src/lib/components/enrollments-table.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 EmptyStateComponent from '@aglyn/shared-ui-jsx/components/empty-state.component'\nimport ListFilterChips from '@aglyn/shared-ui-jsx/components/list-filter-chips.component'\nimport ListQueryNotices, {\n listQueryRefusals,\n} from '@aglyn/shared-ui-jsx/components/list-query-notices.component'\nimport { ListPagination } from '@aglyn/shared-ui-jsx/components/list-pagination.component'\nimport {\n ListRowActions,\n ListTable,\n listActionsColumn,\n type ListTableProps,\n} from '@aglyn/shared-ui-jsx/components/list-table.component'\nimport { hiddenFilterVisibility, type ListFilterField } from '@aglyn/shared-ui-jsx/const/list-filter'\nimport {\n listFilterGridColumns,\n type ListFilterClause,\n type ListFilterOption,\n} from '@aglyn/shared-ui-jsx/const/list-grid-filter'\nimport { useListGridFilter } from '@aglyn/shared-ui-jsx/hooks/use-list-grid-filter'\nimport {\n Card,\n CardContent,\n Chip,\n Link,\n Stack,\n Tooltip,\n Typography,\n useMediaQuery,\n useTheme,\n} from '@mui/material'\nimport { type MouseEvent, type ReactNode, useMemo } from 'react'\nimport {\n outreachClickCountLabel,\n outreachClickSummary,\n outreachMachineOpenLabel,\n outreachOpenCountLabel,\n outreachOpenSummary,\n type OutreachClickSummary,\n type OutreachOpenSummary,\n} from '../model/enrollment-engagement'\nimport {\n OUTREACH_ENROLLMENT_CLICK_FIELDS,\n OUTREACH_ENROLLMENT_LIST_QUERY,\n} from '../model/enrollment-list-query'\nimport {\n OUTREACH_ENROLLMENT_STATUSES,\n OUTREACH_STOP_REASONS,\n OUTREACH_TASK_KIND_LABELS,\n type OutreachEnrollment,\n type OutreachMailbox,\n type OutreachSequence,\n type OutreachSequenceStep,\n} from '../model/outreach.types'\nimport { outreachNextSendState, type OutreachNextSendState } from '../engine/next-send'\nimport { useOutreachEnrollmentActions } from './enrollment-actions'\nimport { OUTREACH_CLICKED_FILTER_VALUE, OUTREACH_UNCLICKED_FILTER_VALUE } from './enrollment-filter-params'\nimport {\n OutreachNextSend,\n outreachNextSendDetail,\n outreachNextSendLabel,\n useOutreachNowMs,\n} from './next-send'\nimport {\n formatOutreachTime,\n OUTREACH_ENROLLMENT_STATUS_LABELS,\n OUTREACH_STOP_REASON_LABELS,\n OutreachEnrollmentStatusChip,\n OutreachLoading,\n OutreachLoadProblem,\n} from './outreach-ui'\nimport type { OutreachApi } from './use-outreach-api'\nimport { useOutreachEnrollmentList } from './use-outreach-data'\n\nexport interface OutreachEnrollmentsTableProps {\n /** The organization, whose enrollments the table asks for. */\n orgId: string\n /** The sequence whose people these are: every page is narrowed to it. */\n sequenceId: string\n steps: readonly OutreachSequenceStep[]\n /**\n * Whether this sequence counts link clicks (AGL-3239). The Clicks column\n * is shown only when it does: a column of dashes for a sequence that\n * measures nothing reads as \"nobody clicked\", which is a different claim\n * and a false one.\n */\n trackClicks?: boolean\n /**\n * Whether this sequence counts opens, or once did (AGL-3488). The Opens\n * column is shown only then, for the reason the Clicks column is: a\n * column of dashes where nothing was measured reads as \"nobody opened\".\n */\n countOpens?: boolean\n /** The mailbox's IANA zone, which next sends are read in; `null` for the reader's own. */\n timeZone: string | null\n /**\n * The sequence's mailbox, whose pacing a due enrollment waits on\n * (AGL-3366): `undefined` while the mailboxes load, `null` when it has none.\n */\n mailbox?: OutreachMailbox | null\n /** The sequence, whose status and window a due enrollment waits on too. */\n sequence?: Pick<OutreachSequence, 'status' | 'steps' | 'settings'> | null\n api: OutreachApi\n /** Shown in the empty state when the sequence takes people. */\n enrollAction?: ReactNode\n /**\n * Opens one person's page (AGL-3332): a row's click, Enter on a focused\n * row, or the name on a phone's card. The row's menu never opens it.\n */\n onOpen?: (enrollment: OutreachEnrollment) => void\n /** The person's page, for the name on a phone's card, which is a real link. */\n hrefFor?: (enrollment: OutreachEnrollment) => string\n /**\n * The clauses the table is narrowed by, when the page holds them — so the\n * Results card's \"Clicked\" and \"Links followed\" can set one (AGL-3332).\n * Omitted, the table holds its own.\n */\n clauses?: readonly ListFilterClause[]\n onClausesChange?: (clauses: ListFilterClause[]) => void\n /** Destinations the sequence's links went to, for the \"Link followed\" filter's choices. */\n linkOptions?: readonly ListFilterOption[]\n}\n\n/** The step an enrollment is on, as a person reads it. */\nexport function outreachCurrentStepLabel(\n enrollment: Pick<OutreachEnrollment, 'status' | 'stepIndex'>,\n steps: readonly OutreachSequenceStep[],\n): string {\n if (enrollment.status === 'finished' || enrollment.stepIndex >= steps.length)\n return 'All steps done'\n const step = steps[enrollment.stepIndex]\n const kind =\n step?.kind === 'email'\n ? 'Email'\n : step?.kind === 'task'\n ? OUTREACH_TASK_KIND_LABELS[step.taskKind]\n : 'Step'\n return `Step ${enrollment.stepIndex + 1} of ${steps.length} · ${kind}`\n}\n\n/** Why an enrollment stopped, as the table says it; `''` while it runs. */\nexport function outreachStopLabel(\n enrollment: Pick<OutreachEnrollment, 'stopReason' | 'stopDetail'>,\n): string {\n if (!enrollment.stopReason) return ''\n const reason = OUTREACH_STOP_REASON_LABELS[enrollment.stopReason] ?? ''\n return enrollment.stopDetail ? `${reason} — ${enrollment.stopDetail}` : reason\n}\n\n/** The last thing that happened: a send, a stop, or the enrollment itself. */\nfunction lastActivityMs(enrollment: OutreachEnrollment): number {\n return Math.max(\n enrollment.lastSentAtMs ?? 0,\n enrollment.stoppedAtMs ?? 0,\n enrollment.createdAtMs ?? 0,\n )\n}\n\n/** Whether the step the enrollment is on goes out as this person's own copy (AGL-3324). */\nexport function outreachStepIsCurated(\n enrollment: Pick<OutreachEnrollment, 'stepIndex' | 'stepOverrides'>,\n): boolean {\n return Boolean(enrollment.stepOverrides?.[String(enrollment.stepIndex)])\n}\n\n/*\n * What the enrollments grid's Filters panel offers (AGL-3317), each field on\n * the table's Firestore query (AGL-3321, `OUTREACH_ENROLLMENT_LIST_QUERY`).\n * Status, whether the person is a lead and the stop reason are picked; the\n * address is typed whole. `target` and `email` are no column of their own,\n * so they are hidden columns the panel can still reach; the search box\n * reads the person's name and address.\n *\n * A sequence that counts clicks adds two more (AGL-3332), on the same query:\n * whether the person clicked, and a destination they followed — matched\n * whole against the destinations stored on the enrollment, never by a piece\n * of its address, so \"followed /pricing\" does not also list the people who\n * followed \"/pricing/enterprise\".\n */\nconst BASE_FILTER_FIELDS = OUTREACH_ENROLLMENT_LIST_QUERY.fields.filter(\n (field) => !(OUTREACH_ENROLLMENT_CLICK_FIELDS as readonly string[]).includes(field.column),\n)\nconst ENROLLMENT_FILTER_HEADERS: Readonly<Record<string, string>> = {\n status: 'Status',\n target: 'Enrolled as',\n stopReason: 'Stop reason',\n email: 'Email',\n enrolled: 'Enrolled',\n clicked: 'Clicked',\n link: 'Link followed',\n}\nconst BASE_FILTER_OPTIONS: Record<string, readonly ListFilterOption[]> = {\n status: OUTREACH_ENROLLMENT_STATUSES.map((status) => ({\n value: status,\n label: OUTREACH_ENROLLMENT_STATUS_LABELS[status],\n })),\n target: [\n { value: 'contact', label: 'Contact' },\n { value: 'lead', label: 'Lead' },\n ],\n stopReason: OUTREACH_STOP_REASONS.map((reason) => ({\n value: reason,\n label: OUTREACH_STOP_REASON_LABELS[reason],\n })),\n}\nconst CLICKED_OPTIONS: readonly ListFilterOption[] = [\n { value: OUTREACH_CLICKED_FILTER_VALUE, label: 'Yes' },\n { value: OUTREACH_UNCLICKED_FILTER_VALUE, label: 'No' },\n]\n/** Columns a reader can show from the column chooser, off until they do (AGL-3332). */\nconst CLICK_DETAIL_COLUMNS = ['linksFollowed', 'lastClick', 'scannerClicks'] as const\n/** The opens column a reader can show from the column chooser, off until they do. */\nconst OPEN_DETAIL_COLUMNS = ['lastOpen'] as const\n\n/** The table's grammar, with the click fields when the sequence counts clicks. */\nfunction filterFieldsFor(trackClicks: boolean): readonly ListFilterField[] {\n return trackClicks ? OUTREACH_ENROLLMENT_LIST_QUERY.fields : BASE_FILTER_FIELDS\n}\n\n/** What the grid's cells and its export read off one enrollment. */\nfunction filterRow(\n enrollment: OutreachEnrollment,\n steps: readonly OutreachSequenceStep[],\n clicks: OutreachClickSummary,\n) {\n return {\n enrollment,\n status: enrollment.status,\n target: enrollment.target === 'lead' ? 'lead' : 'contact',\n contactName: enrollment.contactName,\n email: enrollment.email,\n step: outreachCurrentStepLabel(enrollment, steps),\n stopReason: outreachStopLabel(enrollment),\n clicked: clicks.clicks > 0 ? OUTREACH_CLICKED_FILTER_VALUE : OUTREACH_UNCLICKED_FILTER_VALUE,\n link: clicks.followed,\n }\n}\n\n/** The stop reason: its short label, with every word of it on hover and on the person's page. */\nfunction StopReasonCell(props: { enrollment: OutreachEnrollment }) {\n const { enrollment } = props\n if (!enrollment.stopReason) {\n return (\n <Typography variant=\"body2\" color=\"text.secondary\">\n —\n </Typography>\n )\n }\n const label = OUTREACH_STOP_REASON_LABELS[enrollment.stopReason] ?? ''\n const text = (\n <Typography\n variant=\"body2\"\n sx={{\n whiteSpace: 'normal',\n lineHeight: 1.3,\n ...(enrollment.stopDetail\n ? { textDecoration: 'underline dotted', textUnderlineOffset: 3, cursor: 'help' }\n : {}),\n }}\n >\n {label}\n </Typography>\n )\n return enrollment.stopDetail ? (\n <Tooltip title={outreachStopLabel(enrollment)} describeChild>\n {text}\n </Tooltip>\n ) : (\n text\n )\n}\n\n/**\n * The Opens cell (AGL-3488): the person's opens, and under them the fetches\n * a machine made — counted apart and never in the person's number, as\n * scanner clicks are never in their clicks.\n */\nfunction OpensCell(props: { opens: OutreachOpenSummary }) {\n const { opens } = props\n const machines = outreachMachineOpenLabel(opens)\n return (\n <Stack spacing={0} sx={{ justifyContent: 'center', height: '100%' }}>\n <Typography variant=\"body2\" color={opens.opens ? undefined : 'text.secondary'}>\n {opens.opens ? String(opens.opens) : '—'}\n </Typography>\n {machines ? (\n <Tooltip\n title=\"Fetches of the tracking image by a mail provider’s proxy or a security scanner. They aren’t counted as the person’s opens.\"\n describeChild\n >\n <Typography\n variant=\"caption\"\n color=\"text.secondary\"\n noWrap\n sx={{ textDecoration: 'underline dotted', textUnderlineOffset: 3, cursor: 'help' }}\n >\n {machines}\n </Typography>\n </Tooltip>\n ) : null}\n </Stack>\n )\n}\n\n/** The table's columns; the person and the actions are drawn from the row's enrollment. */\nfunction columns(\n rowActions: (enrollment: OutreachEnrollment) => ReactNode,\n trackClicks: boolean,\n countOpens: boolean,\n timeZone: string | null,\n): NonNullable<ListTableProps['columns']> {\n return [\n {\n field: 'person',\n headerName: 'Person',\n flex: 1.2,\n minWidth: 190,\n sortable: false,\n // What the export writes for a column that is drawn rather than read.\n valueGetter: (_value: unknown, row: { enrollment: OutreachEnrollment }) =>\n row.enrollment.contactName\n ? `${row.enrollment.contactName} <${row.enrollment.email}>`\n : row.enrollment.email,\n renderCell: ({ row }) => (\n <Stack\n spacing={0}\n sx={{ justifyContent: 'center', height: '100%', minWidth: 0 }}\n >\n <Stack direction=\"row\" spacing={0.75} sx={{ alignItems: 'center', minWidth: 0 }}>\n <Typography variant=\"body2\" noWrap>\n {row.enrollment.contactName || row.enrollment.email}\n </Typography>\n {row.enrollment.target === 'lead' ? (\n <Chip size=\"small\" variant=\"outlined\" label=\"Lead\" />\n ) : null}\n </Stack>\n {row.enrollment.contactName ? (\n <Typography variant=\"caption\" color=\"text.secondary\" noWrap>\n {row.enrollment.email}\n </Typography>\n ) : null}\n </Stack>\n ),\n },\n {\n field: 'status',\n headerName: 'Status',\n width: 110,\n renderCell: ({ row }) => (\n <OutreachEnrollmentStatusChip status={row.status} />\n ),\n },\n {\n field: 'step',\n headerName: 'Current step',\n flex: 1,\n minWidth: 170,\n renderCell: ({ row }) => (\n <Stack direction=\"row\" spacing={0.75} sx={{ alignItems: 'center', height: '100%', minWidth: 0 }}>\n <Typography variant=\"body2\" noWrap>\n {row.step}\n </Typography>\n {outreachStepIsCurated(row.enrollment) ? (\n <Chip size=\"small\" variant=\"outlined\" color=\"success\" label=\"Curated\" />\n ) : null}\n </Stack>\n ),\n },\n {\n field: 'nextSend',\n headerName: 'Next send',\n width: 190,\n sortable: false,\n renderCell: ({ row }: { row: { nextSendState: OutreachNextSendState } }) => (\n <Stack sx={{ justifyContent: 'center', height: '100%' }}>\n <OutreachNextSend state={row.nextSendState} timeZone={timeZone} />\n </Stack>\n ),\n },\n {\n field: 'lastActivity',\n headerName: 'Last activity',\n width: 170,\n sortable: false,\n },\n ...(countOpens\n ? [\n {\n field: 'opens',\n headerName: 'Opens',\n description:\n 'A person’s opens of the emails. Fetches by mail proxies and security scanners are shown under them and not counted.',\n width: 130,\n sortable: false,\n renderCell: ({ row }: { row: { openSummary: OutreachOpenSummary } }) => (\n <OpensCell opens={row.openSummary} />\n ),\n },\n { field: 'lastOpen', headerName: 'Last open', width: 170, sortable: false },\n ]\n : []),\n ...(trackClicks\n ? [\n {\n field: 'clicks',\n headerName: 'Clicks',\n description: 'A person’s clicks, and how many different links they followed. Scanners are not counted.',\n width: 110,\n sortable: false,\n renderCell: ({ row }: { row: { clicks: string } }) => (\n <Typography variant=\"body2\" color={row.clicks === '—' ? 'text.secondary' : undefined}>\n {row.clicks}\n </Typography>\n ),\n },\n {\n field: 'linksFollowed',\n headerName: 'Links followed',\n flex: 1,\n minWidth: 220,\n sortable: false,\n },\n { field: 'lastClick', headerName: 'Last click', width: 170, sortable: false },\n {\n field: 'scannerClicks',\n headerName: 'Scanner clicks',\n description: 'Clicks a security scanner made, which are not counted as the person’s.',\n width: 130,\n sortable: false,\n },\n ]\n : []),\n {\n field: 'stopReason',\n headerName: 'Stop reason',\n flex: 1,\n minWidth: 170,\n renderCell: ({ row }) => <StopReasonCell enrollment={row.enrollment} />,\n },\n listActionsColumn((row) => rowActions(row.enrollment), { width: 72 }),\n ]\n}\n\n/** A plain click on a link, which the page handles itself; any other is the browser's. */\nconst plainClick = (event: MouseEvent) =>\n !event.defaultPrevented &&\n event.button === 0 &&\n !event.metaKey &&\n !event.ctrlKey &&\n !event.shiftKey &&\n !event.altKey\n\n/**\n * A sequence's enrollments (AGL-2980): who is in it, where each person\n * stands, when their next step goes out in the mailbox's timezone, and the\n * four things a member can do about it — pause, resume, stop, and mark\n * do-not-contact. A table on wider screens, a list of cards on a phone.\n *\n * Each row opens the person's own page (AGL-3332), which holds everything\n * else known about them: so a cell says one thing, whole, and the detail\n * behind it is a click away rather than cut off at the column's edge.\n */\nexport function OutreachEnrollmentsTable(props: OutreachEnrollmentsTableProps) {\n const { steps, timeZone, api, onOpen, hrefFor } = props\n const trackClicks = props.trackClicks === true\n const countOpens = props.countOpens === true\n const nowMs = useOutreachNowMs()\n const theme = useTheme()\n const narrow = useMediaQuery(theme.breakpoints.down('md'))\n const actions = useOutreachEnrollmentActions({ api, steps })\n const fields = useMemo(() => filterFieldsFor(trackClicks), [trackClicks])\n const gridFilter = useListGridFilter({\n selectFields: ['status', 'target', 'stopReason', 'clicked', 'link'],\n ...(props.clauses !== undefined\n ? { clauses: props.clauses, onChange: props.onClausesChange }\n : {}),\n })\n const filtering =\n gridFilter.clauses.length > 0 || gridFilter.searchWords.some((word) => word.trim())\n /*\n * One page of the sequence's enrollments, newest enrolled first, with\n * every clause and the search word on the query (AGL-3321): a filter\n * reaches the enrollment on page forty as surely as the one on page one,\n * and nothing is matched over the rows that happen to be loaded. The\n * click filters (AGL-3332) are on it too, answered by the `clicked` flag\n * and the destinations the click route stores on each enrollment.\n */\n const enrollments = useOutreachEnrollmentList(props.orgId, props.sequenceId, {\n clauses: gridFilter.clauses,\n search: gridFilter.searchWords,\n })\n const loadedData = enrollments.rows\n const summaries = useMemo(\n () =>\n new Map(\n loadedData.map((enrollment) => [enrollment.id, outreachClickSummary(enrollment.engagement)]),\n ),\n [loadedData],\n )\n const clicksOf = (enrollment: OutreachEnrollment) =>\n summaries.get(enrollment.id) ?? outreachClickSummary(enrollment.engagement)\n\n /*\n * The destinations the \"Link followed\" filter offers: the sequence's own\n * rollup, and any a loaded person followed that it does not list — the\n * rollup is capped, and a filter that could not name a destination a\n * person followed would hide them from it.\n */\n const linkOptions = useMemo(() => {\n const options = new Map<string, string>()\n for (const option of props.linkOptions ?? []) options.set(option.value, option.label)\n for (const summary of summaries.values()) {\n for (const url of summary.followed) if (!options.has(url)) options.set(url, url)\n }\n return [...options].map(([value, label]) => ({ value, label }))\n }, [props.linkOptions, summaries])\n const filterOptions = useMemo(\n () =>\n trackClicks\n ? { ...BASE_FILTER_OPTIONS, clicked: CLICKED_OPTIONS, link: linkOptions }\n : BASE_FILTER_OPTIONS,\n [trackClicks, linkOptions],\n )\n const hiddenColumns = useMemo(\n () => ({\n ...hiddenFilterVisibility(fields, ['status', 'stopReason']),\n ...(trackClicks\n ? Object.fromEntries(CLICK_DETAIL_COLUMNS.map((column) => [column, false]))\n : {}),\n ...(countOpens\n ? Object.fromEntries(OPEN_DETAIL_COLUMNS.map((column) => [column, false]))\n : {}),\n }),\n [fields, trackClicks, countOpens],\n )\n /*\n * A person who followed this destination before each click was recorded\n * on its own, and another link after it, is known by their LAST link only\n * — so a \"Link followed\" filter says it may miss them rather than\n * implying the list is whole. Which people those are is exactly what the\n * query cannot see, so the caveat stands whenever the filter does.\n */\n const linkFilterMayMiss =\n trackClicks && gridFilter.clauses.some((clause) => clause.field === 'link')\n\n const chips = (\n <ListFilterChips\n fields={fields}\n headers={ENROLLMENT_FILTER_HEADERS}\n clauses={gridFilter.clauses}\n onChange={gridFilter.setClauses}\n options={filterOptions}\n />\n )\n if (enrollments.status === 'loading' && !filtering)\n return <OutreachLoading label=\"Loading enrollments…\" />\n if (enrollments.status === 'error' || enrollments.status === 'refused') {\n return (\n <Stack spacing={1.5}>\n {chips}\n <OutreachLoadProblem status={enrollments.status} what=\"enrollments\" />\n </Stack>\n )\n }\n if (\n enrollments.status === 'ready' &&\n !enrollments.rows.length &&\n !filtering &&\n enrollments.page === 0\n ) {\n return (\n <Card variant=\"outlined\">\n <EmptyStateComponent\n label=\"Nobody is enrolled yet\"\n description=\"People you enroll show here, with where each of them is in the sequence.\"\n action={props.enrollAction}\n />\n </Card>\n )\n }\n\n const rowActions = (enrollment: OutreachEnrollment) => (\n <ListRowActions\n label={enrollment.contactName || enrollment.email}\n items={actions.menuItems(enrollment)}\n />\n )\n /*\n * A next send whose time has come says it is queued, and why, rather than\n * showing a time already past (AGL-3366): the mailbox sends its share of\n * the day each run, follow-ups first, so a first email can wait its turn\n * for an hour or more without anything having failed.\n */\n const nextSendState = (enrollment: OutreachEnrollment) =>\n outreachNextSendState({\n enrollment,\n sequence: props.sequence ?? null,\n mailbox: props.mailbox,\n nowMs,\n })\n const personName = (enrollment: OutreachEnrollment) => {\n const name = enrollment.contactName || enrollment.email\n if (!hrefFor) return <Typography variant=\"body2\">{name}</Typography>\n return (\n <Link\n href={hrefFor(enrollment)}\n variant=\"body2\"\n underline=\"hover\"\n onClick={(event) => {\n if (!onOpen || !plainClick(event)) return\n event.preventDefault()\n onOpen(enrollment)\n }}\n >\n {name}\n </Link>\n )\n }\n const person = (enrollment: OutreachEnrollment) => (\n <Stack spacing={0}>\n <Stack direction=\"row\" spacing={0.75} sx={{ alignItems: 'center' }}>\n {personName(enrollment)}\n {enrollment.target === 'lead' ? (\n <Chip size=\"small\" variant=\"outlined\" label=\"Lead\" />\n ) : null}\n </Stack>\n {enrollment.contactName ? (\n <Typography variant=\"caption\" color=\"text.secondary\">\n {enrollment.email}\n </Typography>\n ) : null}\n </Stack>\n )\n\n const pageRows = enrollments.rows\n\n return (\n <Stack spacing={1.5}>\n {chips}\n <ListQueryNotices\n refused={listQueryRefusals(enrollments.plan.refused, {\n fields,\n headers: ENROLLMENT_FILTER_HEADERS,\n options: filterOptions,\n })}\n notices={enrollments.plan.notices}\n />\n {linkFilterMayMiss ? (\n <Typography variant=\"caption\" color=\"text.secondary\">\n Clicks made before each one was recorded on its own kept only the person’s last link, so\n someone who followed this link and then another back then is not listed here.\n </Typography>\n ) : null}\n {narrow ? (\n <Stack\n spacing={1}\n component=\"ul\"\n sx={{ listStyle: 'none', p: 0, m: 0 }}\n aria-label=\"Enrollments\"\n >\n {pageRows.map((enrollment) => {\n const clicks = clicksOf(enrollment)\n const opens = outreachOpenSummary(enrollment.engagement)\n return (\n <Card key={enrollment.id} variant=\"outlined\" component=\"li\">\n <CardContent>\n <Stack spacing={1}>\n <Stack\n direction=\"row\"\n spacing={1}\n sx={{ alignItems: 'flex-start' }}\n >\n <Stack sx={{ flexGrow: 1, minWidth: 0 }}>\n {person(enrollment)}\n </Stack>\n <OutreachEnrollmentStatusChip status={enrollment.status} />\n {rowActions(enrollment)}\n </Stack>\n <Stack direction=\"row\" spacing={0.75} sx={{ alignItems: 'center' }}>\n <Typography variant=\"body2\" color=\"text.secondary\">\n {outreachCurrentStepLabel(enrollment, steps)}\n </Typography>\n {outreachStepIsCurated(enrollment) ? (\n <Chip size=\"small\" variant=\"outlined\" color=\"success\" label=\"Curated\" />\n ) : null}\n </Stack>\n <Stack\n useFlexGap\n direction=\"row\"\n spacing={0.5}\n sx={{ alignItems: 'baseline', flexWrap: 'wrap', color: 'text.secondary' }}\n >\n <Typography variant=\"body2\">Next send:</Typography>\n <OutreachNextSend state={nextSendState(enrollment)} timeZone={timeZone} />\n <Typography variant=\"body2\">\n {`· Last activity: ${formatOutreachTime(lastActivityMs(enrollment), timeZone)}`}\n </Typography>\n </Stack>\n {countOpens && (opens.opens || opens.machineOpens) ? (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {`Opens: ${outreachOpenCountLabel(opens)}`}\n </Typography>\n ) : null}\n {trackClicks && clicks.clicks ? (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {`Clicks: ${outreachClickCountLabel(clicks)}`}\n </Typography>\n ) : null}\n {outreachStopLabel(enrollment) ? (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {outreachStopLabel(enrollment)}\n </Typography>\n ) : null}\n </Stack>\n </CardContent>\n </Card>\n )\n })}\n </Stack>\n ) : (\n <ListTable\n aria-label=\"Enrollments\"\n columns={listFilterGridColumns(\n columns(rowActions, trackClicks, countOpens, timeZone),\n fields,\n filterOptions,\n ENROLLMENT_FILTER_HEADERS,\n )}\n initialState={{ columns: { columnVisibilityModel: hiddenColumns } }}\n loading={enrollments.status === 'loading'}\n rows={pageRows.map((enrollment) => {\n const clicks = clicksOf(enrollment)\n const opens = outreachOpenSummary(enrollment.engagement)\n const next = nextSendState(enrollment)\n return {\n $id: enrollment.id,\n ...filterRow(enrollment, steps, clicks),\n nextSendState: next,\n // What the export writes: the label, and for a queued send, why.\n nextSend: [outreachNextSendLabel(next, timeZone), outreachNextSendDetail(next, timeZone)]\n .filter(Boolean)\n .join(' — '),\n lastActivity: formatOutreachTime(\n lastActivityMs(enrollment),\n timeZone,\n ),\n // What the export writes; the cells draw these their own way.\n openSummary: opens,\n opens: outreachOpenCountLabel(opens),\n lastOpen: opens.opens ? formatOutreachTime(opens.lastOpenAtMs, timeZone) : '—',\n clicks: outreachClickCountLabel(clicks),\n linksFollowed: clicks.followed.join(' ') || '—',\n lastClick: clicks.clicks\n ? formatOutreachTime(enrollment.engagement?.lastClickAtMs, timeZone)\n : '—',\n scannerClicks: clicks.machineClicks ? String(clicks.machineClicks) : '—',\n stopReason: outreachStopLabel(enrollment) || '—',\n }\n })}\n onOpen={\n onOpen\n ? (_id, row: { enrollment: OutreachEnrollment }) => onOpen(row.enrollment)\n : undefined\n }\n /*\n * The panel and the search are the grid's; every clause and the\n * search word are on the table's query (AGL-3321). The grid\n * neither filters nor sorts the page it is handed: the query's\n * one order, newest enrolled first, is the table's.\n */\n filterMode=\"server\"\n filterModel={gridFilter.filterModel}\n onFilterModelChange={gridFilter.onFilterModelChange}\n quickFilter\n disableColumnSorting\n noRowsLabel=\"No enrollments match these filters\"\n hideFooter\n />\n )}\n <ListPagination\n page={enrollments.page}\n pageSize={enrollments.pageSize}\n rowCount={pageRows.length}\n hasMore={enrollments.hasMore}\n onPageChange={enrollments.setPage}\n onPageSizeChange={enrollments.setPageSize}\n />\n {actions.dialogs}\n </Stack>\n )\n}\nOutreachEnrollmentsTable.displayName = 'OutreachEnrollmentsTable'\n\nexport default OutreachEnrollmentsTable\n"],"names":["EmptyStateComponent","ListFilterChips","ListQueryNotices","listQueryRefusals","ListPagination","ListRowActions","ListTable","listActionsColumn","hiddenFilterVisibility","listFilterGridColumns","useListGridFilter","Card","CardContent","Chip","Link","Stack","Tooltip","Typography","useMediaQuery","useTheme","useMemo","outreachClickCountLabel","outreachClickSummary","outreachMachineOpenLabel","outreachOpenCountLabel","outreachOpenSummary","OUTREACH_ENROLLMENT_CLICK_FIELDS","OUTREACH_ENROLLMENT_LIST_QUERY","OUTREACH_ENROLLMENT_STATUSES","OUTREACH_STOP_REASONS","OUTREACH_TASK_KIND_LABELS","outreachNextSendState","useOutreachEnrollmentActions","OUTREACH_CLICKED_FILTER_VALUE","OUTREACH_UNCLICKED_FILTER_VALUE","OutreachNextSend","outreachNextSendDetail","outreachNextSendLabel","useOutreachNowMs","formatOutreachTime","OUTREACH_ENROLLMENT_STATUS_LABELS","OUTREACH_STOP_REASON_LABELS","OutreachEnrollmentStatusChip","OutreachLoading","OutreachLoadProblem","useOutreachEnrollmentList","outreachCurrentStepLabel","enrollment","steps","status","stepIndex","length","step","kind","taskKind","outreachStopLabel","stopReason","reason","stopDetail","lastActivityMs","Math","max","lastSentAtMs","stoppedAtMs","createdAtMs","outreachStepIsCurated","Boolean","stepOverrides","String","BASE_FILTER_FIELDS","fields","filter","field","includes","column","ENROLLMENT_FILTER_HEADERS","target","email","enrolled","clicked","link","BASE_FILTER_OPTIONS","map","value","label","CLICKED_OPTIONS","CLICK_DETAIL_COLUMNS","OPEN_DETAIL_COLUMNS","filterFieldsFor","trackClicks","filterRow","clicks","contactName","followed","StopReasonCell","props","variant","color","text","sx","whiteSpace","lineHeight","textDecoration","textUnderlineOffset","cursor","title","describeChild","OpensCell","opens","machines","spacing","justifyContent","height","undefined","noWrap","columns","rowActions","countOpens","timeZone","headerName","flex","minWidth","sortable","valueGetter","_value","row","renderCell","direction","alignItems","size","width","state","nextSendState","description","openSummary","plainClick","event","defaultPrevented","button","metaKey","ctrlKey","shiftKey","altKey","OutreachEnrollmentsTable","api","onOpen","hrefFor","nowMs","theme","narrow","breakpoints","down","actions","gridFilter","selectFields","clauses","onChange","onClausesChange","filtering","searchWords","some","word","trim","enrollments","orgId","sequenceId","search","loadedData","rows","summaries","Map","id","engagement","clicksOf","get","linkOptions","options","option","set","summary","values","url","has","filterOptions","hiddenColumns","Object","fromEntries","linkFilterMayMiss","clause","chips","headers","setClauses","what","page","action","enrollAction","items","menuItems","sequence","mailbox","personName","name","href","underline","onClick","preventDefault","person","pageRows","refused","plan","notices","component","listStyle","p","m","aria-label","flexGrow","useFlexGap","flexWrap","machineOpens","initialState","columnVisibilityModel","loading","next","$id","nextSend","join","lastActivity","lastOpen","lastOpenAtMs","linksFollowed","lastClick","lastClickAtMs","scannerClicks","machineClicks","_id","filterMode","filterModel","onFilterModelChange","quickFilter","disableColumnSorting","noRowsLabel","hideFooter","pageSize","rowCount","hasMore","onPageChange","setPage","onPageSizeChange","setPageSize","dialogs","displayName"],"mappings":"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"}
|