@aglyn/plugins-outreach 1.0.0-beta.199 → 1.0.0-beta.201
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/do-not-contact-domains.js +60 -42
- package/src/lib/components/do-not-contact-domains.js.map +1 -1
- package/src/lib/components/enrollment-actions.d.ts +33 -0
- package/src/lib/components/enrollment-actions.js +174 -0
- package/src/lib/components/enrollment-actions.js.map +1 -0
- package/src/lib/components/enrollment-detail.d.ts +21 -0
- package/src/lib/components/enrollment-detail.js +870 -0
- package/src/lib/components/enrollment-detail.js.map +1 -0
- package/src/lib/components/enrollment-filter-params.d.ts +58 -0
- package/src/lib/components/enrollment-filter-params.js +98 -0
- package/src/lib/components/enrollment-filter-params.js.map +1 -0
- package/src/lib/components/enrollments-table.d.ts +25 -2
- package/src/lib/components/enrollments-table.js +303 -283
- package/src/lib/components/enrollments-table.js.map +1 -1
- package/src/lib/components/outreach-console-page.js +10 -0
- package/src/lib/components/outreach-console-page.js.map +1 -1
- package/src/lib/components/sequence-detail.d.ts +2 -0
- package/src/lib/components/sequence-detail.js +73 -11
- package/src/lib/components/sequence-detail.js.map +1 -1
- package/src/lib/components/sequence-report-card.d.ts +17 -0
- package/src/lib/components/sequence-report-card.js +63 -15
- package/src/lib/components/sequence-report-card.js.map +1 -1
- package/src/lib/components/sequences-section.d.ts +13 -1
- package/src/lib/components/sequences-section.js +108 -83
- package/src/lib/components/sequences-section.js.map +1 -1
- package/src/lib/components/use-outreach-api.d.ts +3 -1
- package/src/lib/components/use-outreach-api.js +6 -0
- package/src/lib/components/use-outreach-api.js.map +1 -1
- package/src/lib/components/use-outreach-data.d.ts +30 -25
- package/src/lib/components/use-outreach-data.js +93 -104
- package/src/lib/components/use-outreach-data.js.map +1 -1
- package/src/lib/components/use-outreach-enrollment.d.ts +18 -0
- package/src/lib/components/use-outreach-enrollment.js +133 -0
- package/src/lib/components/use-outreach-enrollment.js.map +1 -0
- package/src/lib/constants/api-routes.d.ts +2 -0
- package/src/lib/constants/api-routes.js +1 -0
- package/src/lib/constants/api-routes.js.map +1 -1
- package/src/lib/engine/gates.d.ts +4 -3
- package/src/lib/engine/gates.js.map +1 -1
- package/src/lib/engine/gateway-block.d.ts +4 -8
- package/src/lib/engine/gateway-block.js +6 -26
- package/src/lib/engine/gateway-block.js.map +1 -1
- package/src/lib/engine/mail-gateway.d.ts +18 -73
- package/src/lib/engine/mail-gateway.js +32 -206
- package/src/lib/engine/mail-gateway.js.map +1 -1
- package/src/lib/enrollment/enrollment-search.d.ts +32 -0
- package/src/lib/enrollment/enrollment-search.js +40 -0
- package/src/lib/enrollment/enrollment-search.js.map +1 -0
- package/src/lib/model/do-not-contact-domain-list-query.d.ts +32 -0
- package/src/lib/model/do-not-contact-domain-list-query.js +107 -0
- package/src/lib/model/do-not-contact-domain-list-query.js.map +1 -0
- package/src/lib/model/enrollment-engagement.d.ts +26 -2
- package/src/lib/model/enrollment-engagement.js +40 -3
- package/src/lib/model/enrollment-engagement.js.map +1 -1
- package/src/lib/model/enrollment-history.d.ts +40 -0
- package/src/lib/model/enrollment-history.js +95 -0
- package/src/lib/model/enrollment-history.js.map +1 -0
- package/src/lib/model/enrollment-list-query.d.ts +28 -0
- package/src/lib/model/enrollment-list-query.js +151 -0
- package/src/lib/model/enrollment-list-query.js.map +1 -0
- package/src/lib/model/enrollment-timeline.d.ts +78 -0
- package/src/lib/model/enrollment-timeline.js +430 -0
- package/src/lib/model/enrollment-timeline.js.map +1 -0
- package/src/lib/model/outreach-api.d.ts +24 -0
- package/src/lib/model/outreach-api.js.map +1 -1
- package/src/lib/model/outreach.types.d.ts +90 -29
- package/src/lib/model/outreach.types.js +33 -8
- package/src/lib/model/outreach.types.js.map +1 -1
- package/src/lib/model/sequence-list-query.d.ts +22 -0
- package/src/lib/model/sequence-list-query.js +99 -0
- package/src/lib/model/sequence-list-query.js.map +1 -0
- package/src/lib/routes/enroll-routes.js +34 -3
- package/src/lib/routes/enroll-routes.js.map +1 -1
- package/src/lib/routes/enrollment-routes.d.ts +10 -0
- package/src/lib/routes/enrollment-routes.js +82 -1
- package/src/lib/routes/enrollment-routes.js.map +1 -1
- package/src/lib/routes/register-routes.js +14 -4
- package/src/lib/routes/register-routes.js.map +1 -1
- package/src/lib/routes/route-deps.d.ts +3 -1
- package/src/lib/routes/route-deps.js.map +1 -1
- package/src/lib/routes/sequence-routes.js +6 -1
- package/src/lib/routes/sequence-routes.js.map +1 -1
- package/src/lib/runtime/click-events.d.ts +10 -5
- package/src/lib/runtime/click-events.js +45 -6
- package/src/lib/runtime/click-events.js.map +1 -1
- package/src/lib/runtime/gateway-ledger.d.ts +6 -0
- package/src/lib/runtime/gateway-ledger.js +9 -3
- package/src/lib/runtime/gateway-ledger.js.map +1 -1
- package/src/lib/runtime/host-suspension.d.ts +30 -0
- package/src/lib/runtime/host-suspension.js +35 -0
- package/src/lib/runtime/host-suspension.js.map +1 -0
- package/src/lib/runtime/person-erasure.d.ts +4 -1
- package/src/lib/runtime/person-erasure.js +14 -3
- package/src/lib/runtime/person-erasure.js.map +1 -1
- package/src/lib/runtime/platform-runtime-deps.js +34 -3
- package/src/lib/runtime/platform-runtime-deps.js.map +1 -1
- package/src/lib/runtime/runtime-deps.d.ts +27 -1
- package/src/lib/runtime/runtime-deps.js.map +1 -1
- package/src/lib/runtime/send-job.js +46 -6
- package/src/lib/runtime/send-job.js.map +1 -1
- package/src/lib/runtime/sync-job.js +4 -0
- package/src/lib/runtime/sync-job.js.map +1 -1
- package/src/lib/storage/do-not-contact-store.js +6 -1
- package/src/lib/storage/do-not-contact-store.js.map +1 -1
- package/src/lib/storage/domain-intel-store.d.ts +61 -43
- package/src/lib/storage/domain-intel-store.js +138 -226
- package/src/lib/storage/domain-intel-store.js.map +1 -1
|
@@ -14,22 +14,25 @@
|
|
|
14
14
|
* See the License for the specific language governing permissions and
|
|
15
15
|
* limitations under the License.
|
|
16
16
|
*/ 'use client';
|
|
17
|
-
import {
|
|
17
|
+
import { _ as _extends } from "@swc/helpers/_/_extends";
|
|
18
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
18
19
|
import EmptyStateComponent from "@aglyn/shared-ui-jsx/components/empty-state.component";
|
|
19
20
|
import ListFilterChips from "@aglyn/shared-ui-jsx/components/list-filter-chips.component";
|
|
21
|
+
import ListQueryNotices, { listQueryRefusals } from "@aglyn/shared-ui-jsx/components/list-query-notices.component";
|
|
20
22
|
import { ListPagination } from "@aglyn/shared-ui-jsx/components/list-pagination.component";
|
|
21
23
|
import { ListRowActions, ListTable, listActionsColumn } from "@aglyn/shared-ui-jsx/components/list-table.component";
|
|
22
24
|
import { hiddenFilterVisibility } from "@aglyn/shared-ui-jsx/const/list-filter";
|
|
23
|
-
import {
|
|
24
|
-
import { TABLE_PAGE_SIZE_DEFAULT } from "@aglyn/shared-ui-jsx/const/table-pagination";
|
|
25
|
+
import { listFilterGridColumns } from "@aglyn/shared-ui-jsx/const/list-grid-filter";
|
|
25
26
|
import { useListGridFilter } from "@aglyn/shared-ui-jsx/hooks/use-list-grid-filter";
|
|
26
|
-
import {
|
|
27
|
-
import {
|
|
28
|
-
import {
|
|
29
|
-
import {
|
|
30
|
-
import {
|
|
31
|
-
import {
|
|
27
|
+
import { Card, CardContent, Chip, Link, Stack, Tooltip, Typography, useMediaQuery, useTheme } from "@mui/material";
|
|
28
|
+
import { useMemo } from "react";
|
|
29
|
+
import { outreachClickCountLabel, outreachClickSummary } from "../model/enrollment-engagement.js";
|
|
30
|
+
import { OUTREACH_ENROLLMENT_CLICK_FIELDS, OUTREACH_ENROLLMENT_LIST_QUERY } from "../model/enrollment-list-query.js";
|
|
31
|
+
import { OUTREACH_ENROLLMENT_STATUSES, OUTREACH_STOP_REASONS, OUTREACH_TASK_KIND_LABELS } from "../model/outreach.types.js";
|
|
32
|
+
import { useOutreachEnrollmentActions } from "./enrollment-actions.js";
|
|
33
|
+
import { OUTREACH_CLICKED_FILTER_VALUE, OUTREACH_UNCLICKED_FILTER_VALUE } from "./enrollment-filter-params.js";
|
|
32
34
|
import { formatOutreachTime, OUTREACH_ENROLLMENT_STATUS_LABELS, OUTREACH_STOP_REASON_LABELS, OutreachEnrollmentStatusChip, OutreachLoading, OutreachLoadProblem } from "./outreach-ui.js";
|
|
35
|
+
import { useOutreachEnrollmentList } from "./use-outreach-data.js";
|
|
33
36
|
/** The step an enrollment is on, as a person reads it. */ export function outreachCurrentStepLabel(enrollment, steps) {
|
|
34
37
|
if (enrollment.status === 'finished' || enrollment.stepIndex >= steps.length) return 'All steps done';
|
|
35
38
|
const step = steps[enrollment.stepIndex];
|
|
@@ -46,63 +49,34 @@ import { formatOutreachTime, OUTREACH_ENROLLMENT_STATUS_LABELS, OUTREACH_STOP_RE
|
|
|
46
49
|
var _enrollment_lastSentAtMs, _enrollment_stoppedAtMs, _enrollment_createdAtMs;
|
|
47
50
|
return Math.max((_enrollment_lastSentAtMs = enrollment.lastSentAtMs) != null ? _enrollment_lastSentAtMs : 0, (_enrollment_stoppedAtMs = enrollment.stoppedAtMs) != null ? _enrollment_stoppedAtMs : 0, (_enrollment_createdAtMs = enrollment.createdAtMs) != null ? _enrollment_createdAtMs : 0);
|
|
48
51
|
}
|
|
49
|
-
/** What a member may do to an enrollment in the status it is in. */ function actionsFor(enrollment, steps) {
|
|
50
|
-
const actions = [];
|
|
51
|
-
// Rewrite the next email for this one person, while one is still to go.
|
|
52
|
-
if (outreachNextEmailStepIndex(enrollment, steps) !== null) actions.push('curate');
|
|
53
|
-
if (enrollment.status === 'active') actions.push('pause', 'stop');
|
|
54
|
-
if (enrollment.status === 'paused') actions.push('resume', 'stop');
|
|
55
|
-
if (enrollment.status !== 'opted_out') actions.push('do_not_contact');
|
|
56
|
-
return actions;
|
|
57
|
-
}
|
|
58
|
-
const ACTION_LABELS = {
|
|
59
|
-
curate: 'Curate next step',
|
|
60
|
-
pause: 'Pause',
|
|
61
|
-
resume: 'Resume',
|
|
62
|
-
stop: 'Stop',
|
|
63
|
-
do_not_contact: 'Mark do-not-contact'
|
|
64
|
-
};
|
|
65
52
|
/** Whether the step the enrollment is on goes out as this person's own copy (AGL-3324). */ export function outreachStepIsCurated(enrollment) {
|
|
66
53
|
var _enrollment_stepOverrides;
|
|
67
54
|
return Boolean((_enrollment_stepOverrides = enrollment.stepOverrides) == null ? void 0 : _enrollment_stepOverrides[String(enrollment.stepIndex)]);
|
|
68
55
|
}
|
|
69
|
-
/** What the snackbar says once an action lands. */ const DONE_LABELS = {
|
|
70
|
-
pause: 'Paused.',
|
|
71
|
-
resume: 'Resumed.',
|
|
72
|
-
stop: 'Stopped.'
|
|
73
|
-
};
|
|
74
|
-
/** The two actions that end something for good ask first. */ const CONFIRM = {
|
|
75
|
-
stop: {
|
|
76
|
-
title: 'Stop this enrollment?',
|
|
77
|
-
body: 'They won’t get any more steps from this sequence, and they can’t be enrolled in it again.',
|
|
78
|
-
label: 'Stop'
|
|
79
|
-
},
|
|
80
|
-
do_not_contact: {
|
|
81
|
-
title: 'Mark do-not-contact?',
|
|
82
|
-
body: 'The address goes on your organization’s do-not-contact list, which every sequence checks before ' + 'every send, and they are stopped in every sequence they are in.',
|
|
83
|
-
label: 'Mark do-not-contact'
|
|
84
|
-
}
|
|
85
|
-
};
|
|
86
56
|
/*
|
|
87
|
-
* What the enrollments grid's Filters panel offers (AGL-3317)
|
|
88
|
-
*
|
|
89
|
-
*
|
|
90
|
-
*
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
57
|
+
* What the enrollments grid's Filters panel offers (AGL-3317), each field on
|
|
58
|
+
* the table's Firestore query (AGL-3321, `OUTREACH_ENROLLMENT_LIST_QUERY`).
|
|
59
|
+
* Status, whether the person is a lead and the stop reason are picked; the
|
|
60
|
+
* address is typed whole. `target` and `email` are no column of their own,
|
|
61
|
+
* so they are hidden columns the panel can still reach; the search box
|
|
62
|
+
* reads the person's name and address.
|
|
63
|
+
*
|
|
64
|
+
* A sequence that counts clicks adds two more (AGL-3332), on the same query:
|
|
65
|
+
* whether the person clicked, and a destination they followed — matched
|
|
66
|
+
* whole against the destinations stored on the enrollment, never by a piece
|
|
67
|
+
* of its address, so "followed /pricing" does not also list the people who
|
|
68
|
+
* followed "/pricing/enterprise".
|
|
69
|
+
*/ const BASE_FILTER_FIELDS = OUTREACH_ENROLLMENT_LIST_QUERY.fields.filter((field)=>!OUTREACH_ENROLLMENT_CLICK_FIELDS.includes(field.column));
|
|
98
70
|
const ENROLLMENT_FILTER_HEADERS = {
|
|
99
71
|
status: 'Status',
|
|
100
72
|
target: 'Enrolled as',
|
|
101
|
-
|
|
73
|
+
stopReason: 'Stop reason',
|
|
102
74
|
email: 'Email',
|
|
103
|
-
|
|
75
|
+
enrolled: 'Enrolled',
|
|
76
|
+
clicked: 'Clicked',
|
|
77
|
+
link: 'Link followed'
|
|
104
78
|
};
|
|
105
|
-
const
|
|
79
|
+
const BASE_FILTER_OPTIONS = {
|
|
106
80
|
status: OUTREACH_ENROLLMENT_STATUSES.map((status)=>({
|
|
107
81
|
value: status,
|
|
108
82
|
label: OUTREACH_ENROLLMENT_STATUS_LABELS[status]
|
|
@@ -116,26 +90,82 @@ const ENROLLMENT_FILTER_OPTIONS = {
|
|
|
116
90
|
value: 'lead',
|
|
117
91
|
label: 'Lead'
|
|
118
92
|
}
|
|
119
|
-
]
|
|
93
|
+
],
|
|
94
|
+
stopReason: OUTREACH_STOP_REASONS.map((reason)=>({
|
|
95
|
+
value: reason,
|
|
96
|
+
label: OUTREACH_STOP_REASON_LABELS[reason]
|
|
97
|
+
}))
|
|
120
98
|
};
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
99
|
+
const CLICKED_OPTIONS = [
|
|
100
|
+
{
|
|
101
|
+
value: OUTREACH_CLICKED_FILTER_VALUE,
|
|
102
|
+
label: 'Yes'
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
value: OUTREACH_UNCLICKED_FILTER_VALUE,
|
|
106
|
+
label: 'No'
|
|
107
|
+
}
|
|
126
108
|
];
|
|
127
|
-
/**
|
|
128
|
-
'
|
|
129
|
-
'
|
|
130
|
-
|
|
109
|
+
/** Columns a reader can show from the column chooser, off until they do (AGL-3332). */ const CLICK_DETAIL_COLUMNS = [
|
|
110
|
+
'linksFollowed',
|
|
111
|
+
'lastClick',
|
|
112
|
+
'scannerClicks'
|
|
113
|
+
];
|
|
114
|
+
/** The table's grammar, with the click fields when the sequence counts clicks. */ function filterFieldsFor(trackClicks) {
|
|
115
|
+
return trackClicks ? OUTREACH_ENROLLMENT_LIST_QUERY.fields : BASE_FILTER_FIELDS;
|
|
116
|
+
}
|
|
117
|
+
/** What the grid's cells and its export read off one enrollment. */ function filterRow(enrollment, steps, clicks) {
|
|
118
|
+
return {
|
|
119
|
+
enrollment,
|
|
120
|
+
status: enrollment.status,
|
|
121
|
+
target: enrollment.target === 'lead' ? 'lead' : 'contact',
|
|
122
|
+
contactName: enrollment.contactName,
|
|
123
|
+
email: enrollment.email,
|
|
124
|
+
step: outreachCurrentStepLabel(enrollment, steps),
|
|
125
|
+
stopReason: outreachStopLabel(enrollment),
|
|
126
|
+
clicked: clicks.clicks > 0 ? OUTREACH_CLICKED_FILTER_VALUE : OUTREACH_UNCLICKED_FILTER_VALUE,
|
|
127
|
+
link: clicks.followed
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
/** The stop reason: its short label, with every word of it on hover and on the person's page. */ function StopReasonCell(props) {
|
|
131
|
+
var _OUTREACH_STOP_REASON_LABELS_enrollment_stopReason;
|
|
132
|
+
const { enrollment } = props;
|
|
133
|
+
if (!enrollment.stopReason) {
|
|
134
|
+
return /*#__PURE__*/ _jsx(Typography, {
|
|
135
|
+
variant: "body2",
|
|
136
|
+
color: "text.secondary",
|
|
137
|
+
children: "—"
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
const label = (_OUTREACH_STOP_REASON_LABELS_enrollment_stopReason = OUTREACH_STOP_REASON_LABELS[enrollment.stopReason]) != null ? _OUTREACH_STOP_REASON_LABELS_enrollment_stopReason : '';
|
|
141
|
+
const text = /*#__PURE__*/ _jsx(Typography, {
|
|
142
|
+
variant: "body2",
|
|
143
|
+
sx: _extends({
|
|
144
|
+
whiteSpace: 'normal',
|
|
145
|
+
lineHeight: 1.3
|
|
146
|
+
}, enrollment.stopDetail ? {
|
|
147
|
+
textDecoration: 'underline dotted',
|
|
148
|
+
textUnderlineOffset: 3,
|
|
149
|
+
cursor: 'help'
|
|
150
|
+
} : {}),
|
|
151
|
+
children: label
|
|
152
|
+
});
|
|
153
|
+
return enrollment.stopDetail ? /*#__PURE__*/ _jsx(Tooltip, {
|
|
154
|
+
title: outreachStopLabel(enrollment),
|
|
155
|
+
describeChild: true,
|
|
156
|
+
children: text
|
|
157
|
+
}) : text;
|
|
158
|
+
}
|
|
131
159
|
/** The table's columns; the person and the actions are drawn from the row's enrollment. */ function columns(rowActions, trackClicks) {
|
|
132
160
|
return [
|
|
133
161
|
{
|
|
134
162
|
field: 'person',
|
|
135
163
|
headerName: 'Person',
|
|
136
|
-
flex: 1,
|
|
137
|
-
minWidth:
|
|
164
|
+
flex: 1.2,
|
|
165
|
+
minWidth: 190,
|
|
138
166
|
sortable: false,
|
|
167
|
+
// What the export writes for a column that is drawn rather than read.
|
|
168
|
+
valueGetter: (_value, row)=>row.enrollment.contactName ? `${row.enrollment.contactName} <${row.enrollment.email}>` : row.enrollment.email,
|
|
139
169
|
renderCell: ({ row })=>/*#__PURE__*/ _jsxs(Stack, {
|
|
140
170
|
spacing: 0,
|
|
141
171
|
sx: {
|
|
@@ -176,7 +206,7 @@ const ENROLLMENT_FILTER_OPTIONS = {
|
|
|
176
206
|
{
|
|
177
207
|
field: 'status',
|
|
178
208
|
headerName: 'Status',
|
|
179
|
-
width:
|
|
209
|
+
width: 110,
|
|
180
210
|
renderCell: ({ row })=>/*#__PURE__*/ _jsx(OutreachEnrollmentStatusChip, {
|
|
181
211
|
status: row.status
|
|
182
212
|
})
|
|
@@ -212,158 +242,189 @@ const ENROLLMENT_FILTER_OPTIONS = {
|
|
|
212
242
|
{
|
|
213
243
|
field: 'nextSend',
|
|
214
244
|
headerName: 'Next send',
|
|
215
|
-
width:
|
|
245
|
+
width: 170,
|
|
216
246
|
sortable: false
|
|
217
247
|
},
|
|
218
248
|
{
|
|
219
249
|
field: 'lastActivity',
|
|
220
250
|
headerName: 'Last activity',
|
|
221
|
-
width:
|
|
251
|
+
width: 170,
|
|
222
252
|
sortable: false
|
|
223
253
|
},
|
|
224
254
|
...trackClicks ? [
|
|
225
255
|
{
|
|
226
256
|
field: 'clicks',
|
|
227
257
|
headerName: 'Clicks',
|
|
228
|
-
|
|
258
|
+
description: 'A person’s clicks, and how many different links they followed. Scanners are not counted.',
|
|
259
|
+
width: 110,
|
|
229
260
|
sortable: false,
|
|
230
|
-
renderCell: ({ row })
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
}) : null
|
|
256
|
-
]
|
|
257
|
-
});
|
|
258
|
-
}
|
|
261
|
+
renderCell: ({ row })=>/*#__PURE__*/ _jsx(Typography, {
|
|
262
|
+
variant: "body2",
|
|
263
|
+
color: row.clicks === '—' ? 'text.secondary' : undefined,
|
|
264
|
+
children: row.clicks
|
|
265
|
+
})
|
|
266
|
+
},
|
|
267
|
+
{
|
|
268
|
+
field: 'linksFollowed',
|
|
269
|
+
headerName: 'Links followed',
|
|
270
|
+
flex: 1,
|
|
271
|
+
minWidth: 220,
|
|
272
|
+
sortable: false
|
|
273
|
+
},
|
|
274
|
+
{
|
|
275
|
+
field: 'lastClick',
|
|
276
|
+
headerName: 'Last click',
|
|
277
|
+
width: 170,
|
|
278
|
+
sortable: false
|
|
279
|
+
},
|
|
280
|
+
{
|
|
281
|
+
field: 'scannerClicks',
|
|
282
|
+
headerName: 'Scanner clicks',
|
|
283
|
+
description: 'Clicks a security scanner made, which are not counted as the person’s.',
|
|
284
|
+
width: 130,
|
|
285
|
+
sortable: false
|
|
259
286
|
}
|
|
260
287
|
] : [],
|
|
261
288
|
{
|
|
262
289
|
field: 'stopReason',
|
|
263
290
|
headerName: 'Stop reason',
|
|
264
291
|
flex: 1,
|
|
265
|
-
minWidth: 170
|
|
292
|
+
minWidth: 170,
|
|
293
|
+
renderCell: ({ row })=>/*#__PURE__*/ _jsx(StopReasonCell, {
|
|
294
|
+
enrollment: row.enrollment
|
|
295
|
+
})
|
|
266
296
|
},
|
|
267
297
|
listActionsColumn((row)=>rowActions(row.enrollment), {
|
|
268
298
|
width: 72
|
|
269
299
|
})
|
|
270
300
|
];
|
|
271
301
|
}
|
|
302
|
+
/** A plain click on a link, which the page handles itself; any other is the browser's. */ const plainClick = (event)=>!event.defaultPrevented && event.button === 0 && !event.metaKey && !event.ctrlKey && !event.shiftKey && !event.altKey;
|
|
272
303
|
/**
|
|
273
304
|
* A sequence's enrollments (AGL-2980): who is in it, where each person
|
|
274
305
|
* stands, when their next step goes out in the mailbox's timezone, and the
|
|
275
306
|
* four things a member can do about it — pause, resume, stop, and mark
|
|
276
307
|
* do-not-contact. A table on wider screens, a list of cards on a phone.
|
|
308
|
+
*
|
|
309
|
+
* Each row opens the person's own page (AGL-3332), which holds everything
|
|
310
|
+
* else known about them: so a cell says one thing, whole, and the detail
|
|
311
|
+
* behind it is a click away rather than cut off at the column's edge.
|
|
277
312
|
*/ export function OutreachEnrollmentsTable(props) {
|
|
278
|
-
|
|
279
|
-
const { enrollments, steps, timeZone, api } = props;
|
|
313
|
+
const { steps, timeZone, api, onOpen, hrefFor } = props;
|
|
280
314
|
const trackClicks = props.trackClicks === true;
|
|
281
315
|
const theme = useTheme();
|
|
282
316
|
const narrow = useMediaQuery(theme.breakpoints.down('md'));
|
|
283
|
-
const
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
const
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
const gridFilter = useListGridFilter({
|
|
317
|
+
const actions = useOutreachEnrollmentActions({
|
|
318
|
+
api,
|
|
319
|
+
steps
|
|
320
|
+
});
|
|
321
|
+
const fields = useMemo(()=>filterFieldsFor(trackClicks), [
|
|
322
|
+
trackClicks
|
|
323
|
+
]);
|
|
324
|
+
const gridFilter = useListGridFilter(_extends({
|
|
291
325
|
selectFields: [
|
|
292
326
|
'status',
|
|
293
|
-
'target'
|
|
327
|
+
'target',
|
|
328
|
+
'stopReason',
|
|
329
|
+
'clicked',
|
|
330
|
+
'link'
|
|
294
331
|
]
|
|
295
|
-
}
|
|
296
|
-
|
|
332
|
+
}, props.clauses !== undefined ? {
|
|
333
|
+
clauses: props.clauses,
|
|
334
|
+
onChange: props.onClausesChange
|
|
335
|
+
} : {}));
|
|
336
|
+
const filtering = gridFilter.clauses.length > 0 || gridFilter.searchWords.some((word)=>word.trim());
|
|
297
337
|
/*
|
|
298
|
-
*
|
|
299
|
-
*
|
|
300
|
-
*
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
}).map((row)=>row.enrollment), // `searchKey` stands for the words, which are a new array each render.
|
|
315
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
316
|
-
[
|
|
317
|
-
loadedData,
|
|
318
|
-
steps,
|
|
319
|
-
gridFilter.clauses,
|
|
320
|
-
searchKey
|
|
321
|
-
]);
|
|
322
|
-
// A narrowed list starts again at its first page.
|
|
323
|
-
useEffect(()=>setPage(0), [
|
|
324
|
-
gridFilter.clauses,
|
|
325
|
-
searchKey
|
|
338
|
+
* One page of the sequence's enrollments, newest enrolled first, with
|
|
339
|
+
* every clause and the search word on the query (AGL-3321): a filter
|
|
340
|
+
* reaches the enrollment on page forty as surely as the one on page one,
|
|
341
|
+
* and nothing is matched over the rows that happen to be loaded. The
|
|
342
|
+
* click filters (AGL-3332) are on it too, answered by the `clicked` flag
|
|
343
|
+
* and the destinations the click route stores on each enrollment.
|
|
344
|
+
*/ const enrollments = useOutreachEnrollmentList(props.orgId, props.sequenceId, {
|
|
345
|
+
clauses: gridFilter.clauses,
|
|
346
|
+
search: gridFilter.searchWords
|
|
347
|
+
});
|
|
348
|
+
const loadedData = enrollments.rows;
|
|
349
|
+
const summaries = useMemo(()=>new Map(loadedData.map((enrollment)=>[
|
|
350
|
+
enrollment.id,
|
|
351
|
+
outreachClickSummary(enrollment.engagement)
|
|
352
|
+
])), [
|
|
353
|
+
loadedData
|
|
326
354
|
]);
|
|
327
|
-
const
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
const answer = await api.actOnEnrollment(enrollment.id, action, why);
|
|
331
|
-
const others = answer.stoppedOthers;
|
|
332
|
-
enqueueSnackbar(action === 'do_not_contact' ? `Marked do-not-contact${others ? `, and stopped in ${others} other ${others === 1 ? 'sequence' : 'sequences'}` : ''}.` : answer.changed ? DONE_LABELS[action] : 'Nothing to change.', {
|
|
333
|
-
variant: 'success'
|
|
334
|
-
});
|
|
335
|
-
} catch (error) {
|
|
336
|
-
enqueueSnackbar(error.message, {
|
|
337
|
-
variant: 'error',
|
|
338
|
-
allowDuplicate: true
|
|
339
|
-
});
|
|
340
|
-
} finally{
|
|
341
|
-
setBusy(null);
|
|
342
|
-
}
|
|
355
|
+
const clicksOf = (enrollment)=>{
|
|
356
|
+
var _summaries_get;
|
|
357
|
+
return (_summaries_get = summaries.get(enrollment.id)) != null ? _summaries_get : outreachClickSummary(enrollment.engagement);
|
|
343
358
|
};
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
359
|
+
/*
|
|
360
|
+
* The destinations the "Link followed" filter offers: the sequence's own
|
|
361
|
+
* rollup, and any a loaded person followed that it does not list — the
|
|
362
|
+
* rollup is capped, and a filter that could not name a destination a
|
|
363
|
+
* person followed would hide them from it.
|
|
364
|
+
*/ const linkOptions = useMemo(()=>{
|
|
365
|
+
var _props_linkOptions;
|
|
366
|
+
const options = new Map();
|
|
367
|
+
for (const option of (_props_linkOptions = props.linkOptions) != null ? _props_linkOptions : [])options.set(option.value, option.label);
|
|
368
|
+
for (const summary of summaries.values()){
|
|
369
|
+
for (const url of summary.followed)if (!options.has(url)) options.set(url, url);
|
|
355
370
|
}
|
|
356
|
-
|
|
357
|
-
|
|
371
|
+
return [
|
|
372
|
+
...options
|
|
373
|
+
].map(([value, label])=>({
|
|
374
|
+
value,
|
|
375
|
+
label
|
|
376
|
+
}));
|
|
377
|
+
}, [
|
|
378
|
+
props.linkOptions,
|
|
379
|
+
summaries
|
|
380
|
+
]);
|
|
381
|
+
const filterOptions = useMemo(()=>trackClicks ? _extends({}, BASE_FILTER_OPTIONS, {
|
|
382
|
+
clicked: CLICKED_OPTIONS,
|
|
383
|
+
link: linkOptions
|
|
384
|
+
}) : BASE_FILTER_OPTIONS, [
|
|
385
|
+
trackClicks,
|
|
386
|
+
linkOptions
|
|
387
|
+
]);
|
|
388
|
+
const hiddenColumns = useMemo(()=>_extends({}, hiddenFilterVisibility(fields, [
|
|
389
|
+
'status',
|
|
390
|
+
'stopReason'
|
|
391
|
+
]), trackClicks ? Object.fromEntries(CLICK_DETAIL_COLUMNS.map((column)=>[
|
|
392
|
+
column,
|
|
393
|
+
false
|
|
394
|
+
])) : {}), [
|
|
395
|
+
fields,
|
|
396
|
+
trackClicks
|
|
397
|
+
]);
|
|
398
|
+
/*
|
|
399
|
+
* A person who followed this destination before each click was recorded
|
|
400
|
+
* on its own, and another link after it, is known by their LAST link only
|
|
401
|
+
* — so a "Link followed" filter says it may miss them rather than
|
|
402
|
+
* implying the list is whole. Which people those are is exactly what the
|
|
403
|
+
* query cannot see, so the caveat stands whenever the filter does.
|
|
404
|
+
*/ const linkFilterMayMiss = trackClicks && gridFilter.clauses.some((clause)=>clause.field === 'link');
|
|
405
|
+
const chips = /*#__PURE__*/ _jsx(ListFilterChips, {
|
|
406
|
+
fields: fields,
|
|
407
|
+
headers: ENROLLMENT_FILTER_HEADERS,
|
|
408
|
+
clauses: gridFilter.clauses,
|
|
409
|
+
onChange: gridFilter.setClauses,
|
|
410
|
+
options: filterOptions
|
|
411
|
+
});
|
|
412
|
+
if (enrollments.status === 'loading' && !filtering) return /*#__PURE__*/ _jsx(OutreachLoading, {
|
|
358
413
|
label: "Loading enrollments…"
|
|
359
414
|
});
|
|
360
415
|
if (enrollments.status === 'error' || enrollments.status === 'refused') {
|
|
361
|
-
return /*#__PURE__*/
|
|
362
|
-
|
|
363
|
-
|
|
416
|
+
return /*#__PURE__*/ _jsxs(Stack, {
|
|
417
|
+
spacing: 1.5,
|
|
418
|
+
children: [
|
|
419
|
+
chips,
|
|
420
|
+
/*#__PURE__*/ _jsx(OutreachLoadProblem, {
|
|
421
|
+
status: enrollments.status,
|
|
422
|
+
what: "enrollments"
|
|
423
|
+
})
|
|
424
|
+
]
|
|
364
425
|
});
|
|
365
426
|
}
|
|
366
|
-
if (!enrollments.
|
|
427
|
+
if (enrollments.status === 'ready' && !enrollments.rows.length && !filtering && enrollments.page === 0) {
|
|
367
428
|
return /*#__PURE__*/ _jsx(Card, {
|
|
368
429
|
variant: "outlined",
|
|
369
430
|
children: /*#__PURE__*/ _jsx(EmptyStateComponent, {
|
|
@@ -375,15 +436,27 @@ const ENROLLMENT_FILTER_OPTIONS = {
|
|
|
375
436
|
}
|
|
376
437
|
const rowActions = (enrollment)=>/*#__PURE__*/ _jsx(ListRowActions, {
|
|
377
438
|
label: enrollment.contactName || enrollment.email,
|
|
378
|
-
items:
|
|
379
|
-
key: action,
|
|
380
|
-
label: ACTION_LABELS[action],
|
|
381
|
-
onClick: ()=>choose(enrollment, action),
|
|
382
|
-
destructive: action === 'stop' || action === 'do_not_contact',
|
|
383
|
-
disabled: busy === enrollment.id
|
|
384
|
-
}))
|
|
439
|
+
items: actions.menuItems(enrollment)
|
|
385
440
|
});
|
|
386
441
|
const nextSend = (enrollment)=>enrollment.status === 'active' || enrollment.status === 'paused' ? formatOutreachTime(enrollment.nextDueAtMs, timeZone) : '—';
|
|
442
|
+
const personName = (enrollment)=>{
|
|
443
|
+
const name = enrollment.contactName || enrollment.email;
|
|
444
|
+
if (!hrefFor) return /*#__PURE__*/ _jsx(Typography, {
|
|
445
|
+
variant: "body2",
|
|
446
|
+
children: name
|
|
447
|
+
});
|
|
448
|
+
return /*#__PURE__*/ _jsx(Link, {
|
|
449
|
+
href: hrefFor(enrollment),
|
|
450
|
+
variant: "body2",
|
|
451
|
+
underline: "hover",
|
|
452
|
+
onClick: (event)=>{
|
|
453
|
+
if (!onOpen || !plainClick(event)) return;
|
|
454
|
+
event.preventDefault();
|
|
455
|
+
onOpen(enrollment);
|
|
456
|
+
},
|
|
457
|
+
children: name
|
|
458
|
+
});
|
|
459
|
+
};
|
|
387
460
|
const person = (enrollment)=>/*#__PURE__*/ _jsxs(Stack, {
|
|
388
461
|
spacing: 0,
|
|
389
462
|
children: [
|
|
@@ -394,10 +467,7 @@ const ENROLLMENT_FILTER_OPTIONS = {
|
|
|
394
467
|
alignItems: 'center'
|
|
395
468
|
},
|
|
396
469
|
children: [
|
|
397
|
-
|
|
398
|
-
variant: "body2",
|
|
399
|
-
children: enrollment.contactName || enrollment.email
|
|
400
|
-
}),
|
|
470
|
+
personName(enrollment),
|
|
401
471
|
enrollment.target === 'lead' ? /*#__PURE__*/ _jsx(Chip, {
|
|
402
472
|
size: "small",
|
|
403
473
|
variant: "outlined",
|
|
@@ -412,27 +482,23 @@ const ENROLLMENT_FILTER_OPTIONS = {
|
|
|
412
482
|
}) : null
|
|
413
483
|
]
|
|
414
484
|
});
|
|
415
|
-
const
|
|
416
|
-
const pageRows = loaded.slice(page * pageSize, (page + 1) * pageSize);
|
|
417
|
-
const lastLoadedPage = Math.max(0, Math.ceil(loaded.length / pageSize) - 1);
|
|
418
|
-
/** Past the rows read so far, the next page reads another window first. */ const turnTo = (next)=>{
|
|
419
|
-
if ((next + 1) * pageSize > loaded.length && enrollments.hasMore) enrollments.showMore();
|
|
420
|
-
setPage(next);
|
|
421
|
-
};
|
|
485
|
+
const pageRows = enrollments.rows;
|
|
422
486
|
return /*#__PURE__*/ _jsxs(Stack, {
|
|
423
487
|
spacing: 1.5,
|
|
424
488
|
children: [
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
489
|
+
chips,
|
|
490
|
+
/*#__PURE__*/ _jsx(ListQueryNotices, {
|
|
491
|
+
refused: listQueryRefusals(enrollments.plan.refused, {
|
|
492
|
+
fields,
|
|
493
|
+
headers: ENROLLMENT_FILTER_HEADERS,
|
|
494
|
+
options: filterOptions
|
|
495
|
+
}),
|
|
496
|
+
notices: enrollments.plan.notices
|
|
431
497
|
}),
|
|
432
|
-
|
|
498
|
+
linkFilterMayMiss ? /*#__PURE__*/ _jsx(Typography, {
|
|
433
499
|
variant: "caption",
|
|
434
500
|
color: "text.secondary",
|
|
435
|
-
children:
|
|
501
|
+
children: "Clicks made before each one was recorded on its own kept only the person’s last link, so someone who followed this link and then another back then is not listed here."
|
|
436
502
|
}) : null,
|
|
437
503
|
narrow ? /*#__PURE__*/ _jsx(Stack, {
|
|
438
504
|
spacing: 1,
|
|
@@ -443,7 +509,9 @@ const ENROLLMENT_FILTER_OPTIONS = {
|
|
|
443
509
|
m: 0
|
|
444
510
|
},
|
|
445
511
|
"aria-label": "Enrollments",
|
|
446
|
-
children: pageRows.map((enrollment)
|
|
512
|
+
children: pageRows.map((enrollment)=>{
|
|
513
|
+
const clicks = clicksOf(enrollment);
|
|
514
|
+
return /*#__PURE__*/ _jsx(Card, {
|
|
447
515
|
variant: "outlined",
|
|
448
516
|
component: "li",
|
|
449
517
|
children: /*#__PURE__*/ _jsx(CardContent, {
|
|
@@ -495,10 +563,10 @@ const ENROLLMENT_FILTER_OPTIONS = {
|
|
|
495
563
|
color: "text.secondary",
|
|
496
564
|
children: `Next send: ${nextSend(enrollment)} · Last activity: ${formatOutreachTime(lastActivityMs(enrollment), timeZone)}`
|
|
497
565
|
}),
|
|
498
|
-
trackClicks &&
|
|
566
|
+
trackClicks && clicks.clicks ? /*#__PURE__*/ _jsx(Typography, {
|
|
499
567
|
variant: "body2",
|
|
500
568
|
color: "text.secondary",
|
|
501
|
-
children: `
|
|
569
|
+
children: `Clicks: ${outreachClickCountLabel(clicks)}`
|
|
502
570
|
}) : null,
|
|
503
571
|
outreachStopLabel(enrollment) ? /*#__PURE__*/ _jsx(Typography, {
|
|
504
572
|
variant: "body2",
|
|
@@ -508,104 +576,56 @@ const ENROLLMENT_FILTER_OPTIONS = {
|
|
|
508
576
|
]
|
|
509
577
|
})
|
|
510
578
|
})
|
|
511
|
-
}, enrollment.id)
|
|
579
|
+
}, enrollment.id);
|
|
580
|
+
})
|
|
512
581
|
}) : /*#__PURE__*/ _jsx(ListTable, {
|
|
513
582
|
"aria-label": "Enrollments",
|
|
514
|
-
columns: listFilterGridColumns(columns(rowActions, trackClicks),
|
|
583
|
+
columns: listFilterGridColumns(columns(rowActions, trackClicks), fields, filterOptions, ENROLLMENT_FILTER_HEADERS),
|
|
515
584
|
initialState: {
|
|
516
585
|
columns: {
|
|
517
|
-
columnVisibilityModel:
|
|
586
|
+
columnVisibilityModel: hiddenColumns
|
|
518
587
|
}
|
|
519
588
|
},
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
step: outreachCurrentStepLabel(enrollment, steps),
|
|
589
|
+
loading: enrollments.status === 'loading',
|
|
590
|
+
rows: pageRows.map((enrollment)=>{
|
|
591
|
+
var _enrollment_engagement;
|
|
592
|
+
const clicks = clicksOf(enrollment);
|
|
593
|
+
return _extends({
|
|
594
|
+
$id: enrollment.id
|
|
595
|
+
}, filterRow(enrollment, steps, clicks), {
|
|
528
596
|
nextSend: nextSend(enrollment),
|
|
529
597
|
lastActivity: formatOutreachTime(lastActivityMs(enrollment), timeZone),
|
|
598
|
+
// What the export writes; the cells draw these their own way.
|
|
599
|
+
clicks: outreachClickCountLabel(clicks),
|
|
600
|
+
linksFollowed: clicks.followed.join(' ') || '—',
|
|
601
|
+
lastClick: clicks.clicks ? formatOutreachTime((_enrollment_engagement = enrollment.engagement) == null ? void 0 : _enrollment_engagement.lastClickAtMs, timeZone) : '—',
|
|
602
|
+
scannerClicks: clicks.machineClicks ? String(clicks.machineClicks) : '—',
|
|
530
603
|
stopReason: outreachStopLabel(enrollment) || '—'
|
|
531
|
-
})
|
|
604
|
+
});
|
|
605
|
+
}),
|
|
606
|
+
onOpen: onOpen ? (_id, row)=>onOpen(row.enrollment) : undefined,
|
|
532
607
|
/*
|
|
533
|
-
* The panel and the search are the grid's;
|
|
534
|
-
*
|
|
608
|
+
* The panel and the search are the grid's; every clause and the
|
|
609
|
+
* search word are on the table's query (AGL-3321). The grid
|
|
610
|
+
* neither filters nor sorts the page it is handed: the query's
|
|
611
|
+
* one order, newest enrolled first, is the table's.
|
|
535
612
|
*/ filterMode: "server",
|
|
536
613
|
filterModel: gridFilter.filterModel,
|
|
537
614
|
onFilterModelChange: gridFilter.onFilterModelChange,
|
|
538
615
|
quickFilter: true,
|
|
616
|
+
disableColumnSorting: true,
|
|
539
617
|
noRowsLabel: "No enrollments match these filters",
|
|
540
618
|
hideFooter: true
|
|
541
619
|
}),
|
|
542
620
|
/*#__PURE__*/ _jsx(ListPagination, {
|
|
543
|
-
page: page,
|
|
544
|
-
pageSize: pageSize,
|
|
621
|
+
page: enrollments.page,
|
|
622
|
+
pageSize: enrollments.pageSize,
|
|
545
623
|
rowCount: pageRows.length,
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
onPageSizeChange: setPageSize
|
|
624
|
+
hasMore: enrollments.hasMore,
|
|
625
|
+
onPageChange: enrollments.setPage,
|
|
626
|
+
onPageSizeChange: enrollments.setPageSize
|
|
550
627
|
}),
|
|
551
|
-
|
|
552
|
-
enrollment: curating,
|
|
553
|
-
steps: steps,
|
|
554
|
-
api: api,
|
|
555
|
-
onClose: ()=>setCurating(null)
|
|
556
|
-
}),
|
|
557
|
-
/*#__PURE__*/ _jsx(Dialog, {
|
|
558
|
-
open: Boolean(confirming),
|
|
559
|
-
onClose: ()=>setConfirming(null),
|
|
560
|
-
fullWidth: true,
|
|
561
|
-
maxWidth: "xs",
|
|
562
|
-
children: confirming ? /*#__PURE__*/ _jsxs(_Fragment, {
|
|
563
|
-
children: [
|
|
564
|
-
/*#__PURE__*/ _jsx(DialogTitle, {
|
|
565
|
-
children: (_CONFIRM_confirming_action = CONFIRM[confirming.action]) == null ? void 0 : _CONFIRM_confirming_action.title
|
|
566
|
-
}),
|
|
567
|
-
/*#__PURE__*/ _jsx(DialogContent, {
|
|
568
|
-
children: /*#__PURE__*/ _jsxs(Stack, {
|
|
569
|
-
spacing: 2,
|
|
570
|
-
children: [
|
|
571
|
-
/*#__PURE__*/ _jsx(DialogContentText, {
|
|
572
|
-
children: (_CONFIRM_confirming_action1 = CONFIRM[confirming.action]) == null ? void 0 : _CONFIRM_confirming_action1.body
|
|
573
|
-
}),
|
|
574
|
-
/*#__PURE__*/ _jsx(TextField, {
|
|
575
|
-
label: "Why (optional)",
|
|
576
|
-
value: detail,
|
|
577
|
-
onChange: (event)=>setDetail(event.target.value),
|
|
578
|
-
fullWidth: true,
|
|
579
|
-
slotProps: {
|
|
580
|
-
htmlInput: {
|
|
581
|
-
maxLength: 200
|
|
582
|
-
}
|
|
583
|
-
}
|
|
584
|
-
})
|
|
585
|
-
]
|
|
586
|
-
})
|
|
587
|
-
}),
|
|
588
|
-
/*#__PURE__*/ _jsxs(DialogActions, {
|
|
589
|
-
children: [
|
|
590
|
-
/*#__PURE__*/ _jsx(Button, {
|
|
591
|
-
onClick: ()=>setConfirming(null),
|
|
592
|
-
children: "Cancel"
|
|
593
|
-
}),
|
|
594
|
-
/*#__PURE__*/ _jsx(Button, {
|
|
595
|
-
color: "error",
|
|
596
|
-
variant: "contained",
|
|
597
|
-
onClick: ()=>{
|
|
598
|
-
const { enrollment, action } = confirming;
|
|
599
|
-
setConfirming(null);
|
|
600
|
-
void act(enrollment, action, detail.trim() || undefined);
|
|
601
|
-
},
|
|
602
|
-
children: (_CONFIRM_confirming_action2 = CONFIRM[confirming.action]) == null ? void 0 : _CONFIRM_confirming_action2.label
|
|
603
|
-
})
|
|
604
|
-
]
|
|
605
|
-
})
|
|
606
|
-
]
|
|
607
|
-
}) : null
|
|
608
|
-
})
|
|
628
|
+
actions.dialogs
|
|
609
629
|
]
|
|
610
630
|
});
|
|
611
631
|
}
|