@aglyn/plugins-crm 1.0.0-beta.182 → 1.0.0-beta.184
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 +13 -13
- package/src/lib/components/companies-section.js +97 -54
- package/src/lib/components/companies-section.js.map +1 -1
- package/src/lib/components/contacts-section.js +51 -19
- package/src/lib/components/contacts-section.js.map +1 -1
- package/src/lib/components/crm-filter-bar.d.ts +34 -32
- package/src/lib/components/crm-filter-bar.js +34 -235
- package/src/lib/components/crm-filter-bar.js.map +1 -1
- package/src/lib/components/crm-next-activity-column.d.ts +13 -21
- package/src/lib/components/crm-next-activity-column.js +21 -32
- package/src/lib/components/crm-next-activity-column.js.map +1 -1
- package/src/lib/components/deals-section.js +65 -54
- package/src/lib/components/deals-section.js.map +1 -1
- package/src/lib/components/leads-section.js +106 -286
- package/src/lib/components/leads-section.js.map +1 -1
- package/src/lib/components/tasks-section.js +139 -34
- package/src/lib/components/tasks-section.js.map +1 -1
- package/src/lib/hooks/use-crm-grid-filter.d.ts +77 -0
- package/src/lib/hooks/use-crm-grid-filter.js +143 -0
- package/src/lib/hooks/use-crm-grid-filter.js.map +1 -0
- package/src/lib/model/crm-grid-filter.d.ts +64 -0
- package/src/lib/model/crm-grid-filter.js +144 -0
- package/src/lib/model/crm-grid-filter.js.map +1 -0
- package/src/lib/model/lead-filters.d.ts +42 -0
- package/src/lib/model/lead-filters.js +182 -9
- package/src/lib/model/lead-filters.js.map +1 -1
- package/src/lib/server/email-send.js +4 -2
- package/src/lib/server/email-send.js.map +1 -1
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
import { _ as _extends } from "@swc/helpers/_/_extends";
|
|
18
18
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
19
19
|
import * as Aglyn from "@aglyn/aglyn";
|
|
20
|
-
import { mdiAccountArrowRight, mdiAccountCancelOutline, mdiAccountConvertOutline, mdiAccountTieOutline
|
|
20
|
+
import { mdiAccountArrowRight, mdiAccountCancelOutline, mdiAccountConvertOutline, mdiAccountTieOutline } from "@aglyn/shared-data-mdi";
|
|
21
21
|
import { CardDisplay, MdiIcon } from "@aglyn/shared-ui-jsx";
|
|
22
22
|
import { ListPagination } from "@aglyn/shared-ui-jsx/components/list-pagination.component";
|
|
23
23
|
import { ListTable } from "@aglyn/shared-ui-jsx/components/list-table.component";
|
|
@@ -39,13 +39,16 @@ import { TABLE_PAGE_SIZE_DEFAULT } from "@aglyn/shared-ui-jsx/const/table-pagina
|
|
|
39
39
|
import EmptyStateComponent from "@aglyn/shared-ui-jsx/components/empty-state.component";
|
|
40
40
|
import { useSnackbar } from "@aglyn/shared-ui-snackstack";
|
|
41
41
|
import { useFirestore, useFirestoreCollection } from "@aglyn/tenant-feature-instance";
|
|
42
|
-
import { Alert, Box, Button, Dialog, DialogActions, DialogContent, DialogTitle,
|
|
42
|
+
import { Alert, Box, Button, Dialog, DialogActions, DialogContent, DialogTitle, MenuItem, Select, Stack, Typography } from "@mui/material";
|
|
43
43
|
import { collection, deleteField, doc, limit, orderBy, query, serverTimestamp, updateDoc, where } from "firebase/firestore";
|
|
44
44
|
import { useRouter } from "next/navigation";
|
|
45
|
-
import { useCallback, useEffect,
|
|
45
|
+
import { useCallback, useEffect, useMemo, useState } from "react";
|
|
46
46
|
import { downloadTextFile } from "../model/contacts-csv.js";
|
|
47
47
|
import { crmRoutes } from "../model/crm-routes.js";
|
|
48
|
-
import {
|
|
48
|
+
import { LEAD_EMAIL_FILTER_OPTIONS, LEAD_FILTER_CODECS, LEAD_LIST_FILTER_FIELDS, LEAD_LIST_FILTER_HEADERS, LEAD_SOURCE_FILTER_NONE, LEAD_STATUS_FILTER_OPTIONS, leadClausesForGrid, leadClausesToStore, leadMatchesClauses, leadMatchesSearch } from "../model/lead-filters.js";
|
|
49
|
+
import { crmFilterColumns } from "../model/crm-grid-filter.js";
|
|
50
|
+
import { useCrmGridFilter } from "../hooks/use-crm-grid-filter.js";
|
|
51
|
+
import CrmFilterBar from "./crm-filter-bar.js";
|
|
49
52
|
import { useLeadSourcePicklist } from "../hooks/use-lead-source-picklist.js";
|
|
50
53
|
import { leadsCsv } from "../model/leads-csv.js";
|
|
51
54
|
import { LeadConvertDialog } from "./lead-convert-dialog.js";
|
|
@@ -160,117 +163,33 @@ import OrgLeadSurfacesNote from "./org-lead-surfaces-note.js";
|
|
|
160
163
|
leadDocs
|
|
161
164
|
]);
|
|
162
165
|
/*
|
|
163
|
-
*
|
|
164
|
-
*
|
|
165
|
-
*
|
|
166
|
-
*
|
|
166
|
+
* What the list is narrowed by is the saved VIEW'S (AGL-2617), and the
|
|
167
|
+
* grid's own Filters panel and quick search edit it (AGL-3313): Status,
|
|
168
|
+
* Email, Owner, Lead source and Campaign are select columns of the grid.
|
|
169
|
+
* The clauses keep the shape the old dropdowns stored — see
|
|
170
|
+
* `leadClausesForGrid` — so no saved view of leads loses its filter.
|
|
167
171
|
*/ const views = useCrmSavedView({
|
|
168
172
|
section: 'leads',
|
|
169
173
|
hostId,
|
|
170
174
|
org: props.org,
|
|
171
175
|
basePath: basePath != null ? basePath : ''
|
|
172
176
|
});
|
|
173
|
-
const
|
|
174
|
-
var _views_state_filters_find;
|
|
175
|
-
const value = (_views_state_filters_find = views.state.filters.find((clause)=>clause.field === 'status')) == null ? void 0 : _views_state_filters_find.value;
|
|
176
|
-
return LEAD_FILTERS.includes(value != null ? value : '') ? value : 'open';
|
|
177
|
-
}, [
|
|
177
|
+
const clauses = useMemo(()=>leadClausesForGrid(views.state.filters), [
|
|
178
178
|
views.state.filters
|
|
179
179
|
]);
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
* clause beside the status one. Each setter keeps the other's clause:
|
|
183
|
-
* narrowing to bounced leads does not reopen the unqualified ones.
|
|
184
|
-
*/ const emailFilter = useMemo(()=>{
|
|
185
|
-
var _views_state_filters_find;
|
|
186
|
-
const value = (_views_state_filters_find = views.state.filters.find((clause)=>clause.field === 'emailState')) == null ? void 0 : _views_state_filters_find.value;
|
|
187
|
-
return LEAD_EMAIL_FILTERS.includes(value != null ? value : '') ? value : 'any';
|
|
188
|
-
}, [
|
|
189
|
-
views.state.filters
|
|
190
|
-
]);
|
|
191
|
-
const setFilter = useCallback((next)=>views.setFilters([
|
|
192
|
-
...views.state.filters.filter((clause)=>clause.field !== 'status'),
|
|
193
|
-
...next === 'open' ? [] : [
|
|
194
|
-
{
|
|
195
|
-
field: 'status',
|
|
196
|
-
op: 'equals',
|
|
197
|
-
value: next
|
|
198
|
-
}
|
|
199
|
-
]
|
|
200
|
-
]), [
|
|
201
|
-
views.setFilters,
|
|
202
|
-
views.state.filters
|
|
203
|
-
]);
|
|
204
|
-
const setEmailFilter = useCallback((next)=>views.setFilters([
|
|
205
|
-
...views.state.filters.filter((clause)=>clause.field !== 'emailState'),
|
|
206
|
-
...next === 'any' ? [] : [
|
|
207
|
-
{
|
|
208
|
-
field: 'emailState',
|
|
209
|
-
op: 'equals',
|
|
210
|
-
value: next
|
|
211
|
-
}
|
|
212
|
-
]
|
|
213
|
-
]), [
|
|
214
|
-
views.setFilters,
|
|
215
|
-
views.state.filters
|
|
216
|
-
]);
|
|
217
|
-
/*
|
|
218
|
-
* The `Campaign` filter (AGL-3254) is the view's too, as a `campaignIds`
|
|
219
|
-
* clause: the id of one of the org's campaign containers, resolved to its
|
|
220
|
-
* name from the containers themselves — ids only in storage, so a renamed
|
|
221
|
-
* campaign keeps its leads. Under a site the choice is the campaigns
|
|
222
|
-
* placed on it; at the organization level, every campaign in the org.
|
|
223
|
-
*/ const campaignFilter = useMemo(()=>{
|
|
224
|
-
var _ref;
|
|
225
|
-
var _views_state_filters_find;
|
|
226
|
-
return (_ref = (_views_state_filters_find = views.state.filters.find((clause)=>clause.field === 'campaignIds')) == null ? void 0 : _views_state_filters_find.value) != null ? _ref : '';
|
|
227
|
-
}, [
|
|
228
|
-
views.state.filters
|
|
229
|
-
]);
|
|
230
|
-
const setCampaignFilter = useCallback((next)=>views.setFilters([
|
|
231
|
-
...views.state.filters.filter((clause)=>clause.field !== 'campaignIds'),
|
|
232
|
-
...next ? [
|
|
233
|
-
{
|
|
234
|
-
field: 'campaignIds',
|
|
235
|
-
op: 'contains',
|
|
236
|
-
value: next
|
|
237
|
-
}
|
|
238
|
-
] : []
|
|
239
|
-
]), [
|
|
240
|
-
views.setFilters,
|
|
241
|
-
views.state.filters
|
|
242
|
-
]);
|
|
243
|
-
/*
|
|
244
|
-
* The `Lead source` filter (AGL-3298) is the view's too: an `equals`
|
|
245
|
-
* clause naming the label records store, or an `isEmpty` one for the
|
|
246
|
-
* leads that hold none.
|
|
247
|
-
*/ const leadSourceFilter = useMemo(()=>{
|
|
248
|
-
var _clause_value;
|
|
249
|
-
const clause = views.state.filters.find((entry)=>entry.field === 'leadSource');
|
|
250
|
-
if (!clause) return '';
|
|
251
|
-
return clause.op === 'isEmpty' ? LEAD_SOURCE_FILTER_NONE : String((_clause_value = clause.value) != null ? _clause_value : '');
|
|
252
|
-
}, [
|
|
253
|
-
views.state.filters
|
|
254
|
-
]);
|
|
255
|
-
const setLeadSourceFilter = useCallback((next)=>views.setFilters([
|
|
256
|
-
...views.state.filters.filter((clause)=>clause.field !== 'leadSource'),
|
|
257
|
-
...next === LEAD_SOURCE_FILTER_NONE ? [
|
|
258
|
-
{
|
|
259
|
-
field: 'leadSource',
|
|
260
|
-
op: 'isEmpty',
|
|
261
|
-
value: ''
|
|
262
|
-
}
|
|
263
|
-
] : next ? [
|
|
264
|
-
{
|
|
265
|
-
field: 'leadSource',
|
|
266
|
-
op: 'equals',
|
|
267
|
-
value: next
|
|
268
|
-
}
|
|
269
|
-
] : []
|
|
270
|
-
]), [
|
|
271
|
-
views.setFilters,
|
|
272
|
-
views.state.filters
|
|
180
|
+
const setClauses = useCallback((next)=>views.setFilters(leadClausesToStore(next)), [
|
|
181
|
+
views.setFilters
|
|
273
182
|
]);
|
|
183
|
+
const gridFilter = useCrmGridFilter({
|
|
184
|
+
clauses,
|
|
185
|
+
onChange: setClauses,
|
|
186
|
+
selectFields: [
|
|
187
|
+
'status',
|
|
188
|
+
'emailState',
|
|
189
|
+
'ownerUid'
|
|
190
|
+
],
|
|
191
|
+
codecs: LEAD_FILTER_CODECS
|
|
192
|
+
});
|
|
274
193
|
const campaigns = useCrmCampaigns({
|
|
275
194
|
hostId,
|
|
276
195
|
orgId
|
|
@@ -284,28 +203,62 @@ import OrgLeadSurfacesNote from "./org-lead-surfaces-note.js";
|
|
|
284
203
|
}, [
|
|
285
204
|
campaigns.options
|
|
286
205
|
]);
|
|
287
|
-
// The label's id, so the filter's combobox is named "Show" rather than
|
|
288
|
-
// after the option it shows — see `LeadOwnerSelect`.
|
|
289
|
-
const filterLabelId = useId();
|
|
290
|
-
const emailFilterLabelId = useId();
|
|
291
|
-
const campaignFilterLabelId = useId();
|
|
292
|
-
const leadSourceFilterLabelId = useId();
|
|
293
206
|
/*
|
|
294
|
-
* The
|
|
295
|
-
*
|
|
296
|
-
*
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
207
|
+
* The choices each select column offers. A stored clause naming a value
|
|
208
|
+
* no longer listed — a retired campaign, a lead source since removed —
|
|
209
|
+
* stays a choice, so the panel can show it and clear it.
|
|
210
|
+
*/ const filterOptions = useMemo(()=>{
|
|
211
|
+
const stale = (field, known)=>clauses.filter((clause)=>clause.field === field && clause.op !== 'isEmpty').flatMap((clause)=>clause.value.split(',')).map((value)=>value.trim()).filter((value)=>value && !known.some((option)=>option.value === value)).map((value)=>({
|
|
212
|
+
value,
|
|
213
|
+
label: value
|
|
214
|
+
}));
|
|
215
|
+
const campaignOptions = campaigns.options.map((option)=>({
|
|
216
|
+
value: option.value,
|
|
217
|
+
label: option.label
|
|
218
|
+
}));
|
|
219
|
+
// Salesforce's Lead Source (AGL-3298): every value the org keeps, inactive ones marked.
|
|
220
|
+
const sourceOptions = [
|
|
221
|
+
...leadSourceList.picklist.values.map((value)=>({
|
|
222
|
+
value: value.label,
|
|
223
|
+
label: value.active ? value.label : `${value.label} (inactive)`
|
|
224
|
+
})),
|
|
225
|
+
{
|
|
226
|
+
value: LEAD_SOURCE_FILTER_NONE,
|
|
227
|
+
label: 'No lead source'
|
|
228
|
+
}
|
|
229
|
+
];
|
|
230
|
+
return {
|
|
231
|
+
status: LEAD_STATUS_FILTER_OPTIONS,
|
|
232
|
+
emailState: LEAD_EMAIL_FILTER_OPTIONS,
|
|
233
|
+
ownerUid: roster.options.map((option)=>({
|
|
234
|
+
value: option.uid,
|
|
235
|
+
label: Aglyn.crmMemberPickerLabel(option)
|
|
236
|
+
})),
|
|
237
|
+
campaignIds: [
|
|
238
|
+
...campaignOptions,
|
|
239
|
+
...stale('campaignIds', campaignOptions)
|
|
240
|
+
],
|
|
241
|
+
leadSource: [
|
|
242
|
+
...sourceOptions,
|
|
243
|
+
...stale('leadSource', sourceOptions)
|
|
244
|
+
]
|
|
245
|
+
};
|
|
246
|
+
}, [
|
|
247
|
+
clauses,
|
|
248
|
+
campaigns.options,
|
|
249
|
+
leadSourceList.picklist,
|
|
250
|
+
roster.options
|
|
251
|
+
]);
|
|
252
|
+
/*
|
|
253
|
+
* Every clause and the search narrow the whole loaded WINDOW here, before
|
|
254
|
+
* the footer's count and the page slice (AGL-3246). The grid holds one
|
|
255
|
+
* page of it, so a filter or a quick search the grid ran itself would
|
|
256
|
+
* answer "no match" for a lead on page three.
|
|
257
|
+
*/ const searchKey = gridFilter.searchWords.join(' ');
|
|
258
|
+
const rows = useMemo(()=>window.filter((lead)=>leadMatchesClauses(lead, clauses) && leadMatchesSearch(lead, searchKey)), [
|
|
303
259
|
window,
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
campaignFilter,
|
|
307
|
-
leadSourceFilter,
|
|
308
|
-
search
|
|
260
|
+
clauses,
|
|
261
|
+
searchKey
|
|
309
262
|
]);
|
|
310
263
|
const [page, setPage] = useState(0);
|
|
311
264
|
const [pageSize, setPageSize] = useState(TABLE_PAGE_SIZE_DEFAULT);
|
|
@@ -315,11 +268,8 @@ import OrgLeadSurfacesNote from "./org-lead-surfaces-note.js";
|
|
|
315
268
|
useEffect(()=>{
|
|
316
269
|
setPage(0);
|
|
317
270
|
}, [
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
campaignFilter,
|
|
321
|
-
leadSourceFilter,
|
|
322
|
-
search
|
|
271
|
+
views.state.filters,
|
|
272
|
+
searchKey
|
|
323
273
|
]);
|
|
324
274
|
const pageRows = useMemo(()=>rows.slice(page * pageSize, (page + 1) * pageSize), [
|
|
325
275
|
rows,
|
|
@@ -333,11 +283,8 @@ import OrgLeadSurfacesNote from "./org-lead-surfaces-note.js";
|
|
|
333
283
|
* rows no longer listed.
|
|
334
284
|
*/ const [selectedIds, setSelectedIds] = useState([]);
|
|
335
285
|
useEffect(()=>setSelectedIds([]), [
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
campaignFilter,
|
|
339
|
-
leadSourceFilter,
|
|
340
|
-
search
|
|
286
|
+
views.state.filters,
|
|
287
|
+
searchKey
|
|
341
288
|
]);
|
|
342
289
|
// How the file names the owner and, at the org level, the site.
|
|
343
290
|
const csvOptions = useMemo(()=>_extends({
|
|
@@ -719,7 +666,14 @@ import OrgLeadSurfacesNote from "./org-lead-surfaces-note.js";
|
|
|
719
666
|
leadFields.active,
|
|
720
667
|
leadSourceList.picklist
|
|
721
668
|
]);
|
|
722
|
-
/*
|
|
669
|
+
/*
|
|
670
|
+
* The column and sort models are the view's (AGL-2617); the filterable
|
|
671
|
+
* columns are the declared fields, as selects over their choices (AGL-3313).
|
|
672
|
+
*/ const filterColumns = useMemo(()=>crmFilterColumns(columns, LEAD_LIST_FILTER_FIELDS, filterOptions, LEAD_LIST_FILTER_HEADERS), [
|
|
673
|
+
columns,
|
|
674
|
+
filterOptions
|
|
675
|
+
]);
|
|
676
|
+
const grid = useCrmViewGrid(views, filterColumns);
|
|
723
677
|
return /*#__PURE__*/ _jsxs(_Fragment, {
|
|
724
678
|
children: [
|
|
725
679
|
/*#__PURE__*/ _jsx(CardDisplay, {
|
|
@@ -765,157 +719,19 @@ import OrgLeadSurfacesNote from "./org-lead-surfaces-note.js";
|
|
|
765
719
|
controller: views,
|
|
766
720
|
allLabel: "All leads"
|
|
767
721
|
}),
|
|
768
|
-
/*#__PURE__*/
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
id: filterLabelId,
|
|
776
|
-
children: 'Show'
|
|
777
|
-
}),
|
|
778
|
-
/*#__PURE__*/ _jsx(Select, {
|
|
779
|
-
labelId: filterLabelId,
|
|
780
|
-
label: "Show",
|
|
781
|
-
value: filter,
|
|
782
|
-
onChange: (event)=>setFilter(event.target.value),
|
|
783
|
-
children: LEAD_FILTERS.map((option)=>/*#__PURE__*/ _jsx(MenuItem, {
|
|
784
|
-
value: option,
|
|
785
|
-
children: LEAD_FILTER_LABELS[option]
|
|
786
|
-
}, option))
|
|
787
|
-
})
|
|
788
|
-
]
|
|
789
|
-
}),
|
|
790
|
-
/*#__PURE__*/ _jsxs(FormControl, {
|
|
791
|
-
size: "small",
|
|
792
|
-
sx: {
|
|
793
|
-
minWidth: 160
|
|
794
|
-
},
|
|
795
|
-
children: [
|
|
796
|
-
/*#__PURE__*/ _jsx(InputLabel, {
|
|
797
|
-
id: emailFilterLabelId,
|
|
798
|
-
children: 'Email'
|
|
799
|
-
}),
|
|
800
|
-
/*#__PURE__*/ _jsx(Select, {
|
|
801
|
-
labelId: emailFilterLabelId,
|
|
802
|
-
label: "Email",
|
|
803
|
-
value: emailFilter,
|
|
804
|
-
onChange: (event)=>setEmailFilter(event.target.value),
|
|
805
|
-
children: LEAD_EMAIL_FILTERS.map((option)=>/*#__PURE__*/ _jsx(MenuItem, {
|
|
806
|
-
value: option,
|
|
807
|
-
children: LEAD_EMAIL_FILTER_LABELS[option]
|
|
808
|
-
}, option))
|
|
809
|
-
})
|
|
810
|
-
]
|
|
811
|
-
}),
|
|
812
|
-
/*#__PURE__*/ _jsxs(FormControl, {
|
|
813
|
-
size: "small",
|
|
814
|
-
sx: {
|
|
815
|
-
minWidth: 180
|
|
816
|
-
},
|
|
817
|
-
children: [
|
|
818
|
-
/*#__PURE__*/ _jsx(InputLabel, {
|
|
819
|
-
id: campaignFilterLabelId,
|
|
820
|
-
shrink: true,
|
|
821
|
-
children: 'Campaign'
|
|
822
|
-
}),
|
|
823
|
-
/*#__PURE__*/ _jsxs(Select, {
|
|
824
|
-
labelId: campaignFilterLabelId,
|
|
825
|
-
label: "Campaign",
|
|
826
|
-
notched: true,
|
|
827
|
-
value: campaignFilter,
|
|
828
|
-
onChange: (event)=>setCampaignFilter(String(event.target.value)),
|
|
829
|
-
displayEmpty: true,
|
|
830
|
-
children: [
|
|
831
|
-
/*#__PURE__*/ _jsx(MenuItem, {
|
|
832
|
-
value: "",
|
|
833
|
-
children: 'Any campaign'
|
|
834
|
-
}),
|
|
835
|
-
campaigns.options.map((option)=>/*#__PURE__*/ _jsx(MenuItem, {
|
|
836
|
-
value: option.value,
|
|
837
|
-
children: option.label
|
|
838
|
-
}, option.value)),
|
|
839
|
-
campaignFilter && !campaigns.options.some((option)=>option.value === campaignFilter) ? /*#__PURE__*/ _jsx(MenuItem, {
|
|
840
|
-
value: campaignFilter,
|
|
841
|
-
children: campaignFilter
|
|
842
|
-
}) : null
|
|
843
|
-
]
|
|
844
|
-
})
|
|
845
|
-
]
|
|
846
|
-
}),
|
|
847
|
-
/*#__PURE__*/ _jsxs(FormControl, {
|
|
848
|
-
size: "small",
|
|
849
|
-
sx: {
|
|
850
|
-
minWidth: 180
|
|
851
|
-
},
|
|
852
|
-
children: [
|
|
853
|
-
/*#__PURE__*/ _jsx(InputLabel, {
|
|
854
|
-
id: leadSourceFilterLabelId,
|
|
855
|
-
shrink: true,
|
|
856
|
-
children: 'Lead source'
|
|
857
|
-
}),
|
|
858
|
-
/*#__PURE__*/ _jsxs(Select, {
|
|
859
|
-
labelId: leadSourceFilterLabelId,
|
|
860
|
-
label: "Lead source",
|
|
861
|
-
notched: true,
|
|
862
|
-
value: leadSourceFilter,
|
|
863
|
-
onChange: (event)=>setLeadSourceFilter(String(event.target.value)),
|
|
864
|
-
displayEmpty: true,
|
|
865
|
-
children: [
|
|
866
|
-
/*#__PURE__*/ _jsx(MenuItem, {
|
|
867
|
-
value: "",
|
|
868
|
-
children: 'Any lead source'
|
|
869
|
-
}),
|
|
870
|
-
leadSourceList.picklist.values.map((value)=>/*#__PURE__*/ _jsx(MenuItem, {
|
|
871
|
-
value: value.label,
|
|
872
|
-
children: value.active ? value.label : `${value.label} (inactive)`
|
|
873
|
-
}, value.id)),
|
|
874
|
-
/*#__PURE__*/ _jsx(MenuItem, {
|
|
875
|
-
value: LEAD_SOURCE_FILTER_NONE,
|
|
876
|
-
children: 'No lead source'
|
|
877
|
-
}),
|
|
878
|
-
leadSourceFilter && leadSourceFilter !== LEAD_SOURCE_FILTER_NONE && !Aglyn.crmPicklistValueByLabel(leadSourceList.picklist, leadSourceFilter) ? /*#__PURE__*/ _jsx(MenuItem, {
|
|
879
|
-
value: leadSourceFilter,
|
|
880
|
-
children: leadSourceFilter
|
|
881
|
-
}) : null
|
|
882
|
-
]
|
|
883
|
-
})
|
|
884
|
-
]
|
|
885
|
-
}),
|
|
886
|
-
/*#__PURE__*/ _jsx(TextField, {
|
|
887
|
-
size: "small",
|
|
888
|
-
value: search,
|
|
889
|
-
onChange: (event)=>setSearch(event.target.value),
|
|
890
|
-
placeholder: "Search leads",
|
|
891
|
-
slotProps: {
|
|
892
|
-
input: {
|
|
893
|
-
startAdornment: /*#__PURE__*/ _jsx(InputAdornment, {
|
|
894
|
-
position: "start",
|
|
895
|
-
children: /*#__PURE__*/ _jsx(MdiIcon, {
|
|
896
|
-
path: mdiMagnify.path,
|
|
897
|
-
size: 0.8
|
|
898
|
-
})
|
|
899
|
-
})
|
|
900
|
-
},
|
|
901
|
-
htmlInput: {
|
|
902
|
-
'aria-label': 'Search leads',
|
|
903
|
-
type: 'search'
|
|
904
|
-
}
|
|
905
|
-
},
|
|
906
|
-
sx: {
|
|
907
|
-
minWidth: 200
|
|
908
|
-
}
|
|
722
|
+
/*#__PURE__*/ _jsx(CrmFilterBar, {
|
|
723
|
+
fields: LEAD_LIST_FILTER_FIELDS,
|
|
724
|
+
headers: LEAD_LIST_FILTER_HEADERS,
|
|
725
|
+
clauses: clauses,
|
|
726
|
+
onChange: setClauses,
|
|
727
|
+
options: filterOptions,
|
|
728
|
+
marksServed: false
|
|
909
729
|
})
|
|
910
730
|
]
|
|
911
731
|
}),
|
|
912
732
|
status === 'success' && window.length === 0 ? /*#__PURE__*/ _jsx(EmptyStateComponent, {
|
|
913
733
|
label: 'No leads yet',
|
|
914
734
|
description: 'Bookings and lead-routed forms on your site become leads on their own — or add one with New lead, or bring a list in with Import CSV.'
|
|
915
|
-
}) : status === 'success' && rows.length === 0 ? /*#__PURE__*/ _jsx(Typography, {
|
|
916
|
-
variant: "body2",
|
|
917
|
-
color: "text.secondary",
|
|
918
|
-
children: `No ${LEAD_FILTER_LABELS[filter].toLowerCase()} leads` + (search.trim() ? ` match “${search.trim()}”` : '') + ` among the ${window.length.toLocaleString()} most recently seen.`
|
|
919
735
|
}) : /*#__PURE__*/ _jsxs(_Fragment, {
|
|
920
736
|
children: [
|
|
921
737
|
/*#__PURE__*/ _jsx(LeadsBulkBar, {
|
|
@@ -945,9 +761,13 @@ import OrgLeadSurfacesNote from "./org-lead-surfaces-note.js";
|
|
|
945
761
|
onColumnVisibilityModelChange: grid.onColumnVisibilityModelChange,
|
|
946
762
|
sortModel: grid.sortModel,
|
|
947
763
|
onSortModelChange: grid.onSortModelChange,
|
|
948
|
-
// The
|
|
949
|
-
//
|
|
950
|
-
|
|
764
|
+
// The panel and the search are the grid's; the section
|
|
765
|
+
// answers both over the whole window (AGL-3313).
|
|
766
|
+
filterMode: "server",
|
|
767
|
+
filterModel: gridFilter.filterModel,
|
|
768
|
+
onFilterModelChange: gridFilter.onFilterModelChange,
|
|
769
|
+
quickFilter: true,
|
|
770
|
+
noRowsLabel: `No leads match among the ${window.length.toLocaleString()} most recently seen`,
|
|
951
771
|
// Paged by the footer below, so the grid must not also slice.
|
|
952
772
|
hideFooter: true
|
|
953
773
|
})
|
|
@@ -964,7 +784,7 @@ import OrgLeadSurfacesNote from "./org-lead-surfaces-note.js";
|
|
|
964
784
|
}),
|
|
965
785
|
truncated ? /*#__PURE__*/ _jsx(Alert, {
|
|
966
786
|
severity: "info",
|
|
967
|
-
children: `Showing the ${LEADS_WINDOW.toLocaleString()} most recently seen ` + 'leads. The
|
|
787
|
+
children: `Showing the ${LEADS_WINDOW.toLocaleString()} most recently seen ` + 'leads. The filters and the search narrow these ' + `${LEADS_WINDOW.toLocaleString()} only; older leads are still ` + 'listed in the Inbox and reached by campaign audiences.'
|
|
968
788
|
}) : null
|
|
969
789
|
]
|
|
970
790
|
})
|