@aglyn/plugins-crm 1.0.0-beta.178 → 1.0.0-beta.179
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/contact-detail-page.js +1 -0
- package/src/lib/components/contact-detail-page.js.map +1 -1
- package/src/lib/components/contact-properties-card.d.ts +6 -0
- package/src/lib/components/contact-properties-card.js +25 -2
- package/src/lib/components/contact-properties-card.js.map +1 -1
- package/src/lib/components/csv-import-drawer.d.ts +7 -0
- package/src/lib/components/csv-import-drawer.js +7 -0
- package/src/lib/components/csv-import-drawer.js.map +1 -1
- package/src/lib/components/fields-section.js +6 -0
- package/src/lib/components/fields-section.js.map +1 -1
- package/src/lib/components/lead-import-drawer.d.ts +3 -0
- package/src/lib/components/lead-import-drawer.js +29 -6
- package/src/lib/components/lead-import-drawer.js.map +1 -1
- package/src/lib/components/lead-properties-card.js +10 -12
- package/src/lib/components/lead-properties-card.js.map +1 -1
- package/src/lib/components/lead-source-select.d.ts +30 -0
- package/src/lib/components/lead-source-select.js +96 -0
- package/src/lib/components/lead-source-select.js.map +1 -0
- package/src/lib/components/lead-source-values-card.d.ts +27 -0
- package/src/lib/components/lead-source-values-card.js +606 -0
- package/src/lib/components/lead-source-values-card.js.map +1 -0
- package/src/lib/components/leads-section.js +100 -4
- package/src/lib/components/leads-section.js.map +1 -1
- package/src/lib/components/new-lead-drawer.js +27 -11
- package/src/lib/components/new-lead-drawer.js.map +1 -1
- package/src/lib/hooks/use-lead-source-picklist.d.ts +23 -0
- package/src/lib/hooks/use-lead-source-picklist.js +50 -0
- package/src/lib/hooks/use-lead-source-picklist.js.map +1 -0
- package/src/lib/model/contact-record.d.ts +2 -0
- package/src/lib/model/contact-record.js +2 -1
- package/src/lib/model/contact-record.js.map +1 -1
- package/src/lib/model/contact-update.d.ts +6 -0
- package/src/lib/model/contact-update.js +1 -0
- package/src/lib/model/contact-update.js.map +1 -1
- package/src/lib/model/crm-lead-import.d.ts +10 -2
- package/src/lib/model/crm-lead-import.js +19 -1
- package/src/lib/model/crm-lead-import.js.map +1 -1
- package/src/lib/model/lead-filters.d.ts +13 -0
- package/src/lib/model/lead-filters.js +17 -1
- package/src/lib/model/lead-filters.js.map +1 -1
- package/src/lib/model/lead-source-values.d.ts +82 -0
- package/src/lib/model/lead-source-values.js +149 -0
- package/src/lib/model/lead-source-values.js.map +1 -0
- package/src/lib/server/contact-update.js +25 -2
- package/src/lib/server/contact-update.js.map +1 -1
- package/src/lib/server/lead-create.js +19 -0
- package/src/lib/server/lead-create.js.map +1 -1
- package/src/lib/server/lead-source-picklist.d.ts +42 -0
- package/src/lib/server/lead-source-picklist.js +52 -0
- package/src/lib/server/lead-source-picklist.js.map +1 -0
- package/src/lib/server/lead-source-values.d.ts +50 -0
- package/src/lib/server/lead-source-values.js +187 -0
- package/src/lib/server/lead-source-values.js.map +1 -0
- package/src/lib/server/leads-import.js +31 -2
- package/src/lib/server/leads-import.js.map +1 -1
- package/src/lib/server.js +5 -0
- package/src/lib/server.js.map +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/crm/src/lib/components/lead-source-values-card.tsx"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n'use client'\n\nimport {\n CRM_COLLECTIONS,\n CRM_LEAD_SOURCE_PICKLIST,\n CRM_LEAD_TEXT_MAX,\n type CrmPicklist,\n type CrmPicklistValue,\n crmPicklistActiveValues,\n newResourceScopeFields,\n ORG_SCOPE_TOKEN,\n} from '@aglyn/aglyn'\nimport {\n mdiArrowDown,\n mdiArrowUp,\n mdiDeleteOutline,\n mdiDragVertical,\n mdiEyeOffOutline,\n mdiEyeOutline,\n mdiPencilOutline,\n mdiStarOutline,\n} from '@aglyn/shared-data-mdi'\nimport { MdiIcon, SrOnly } from '@aglyn/shared-ui-jsx'\nimport RowActionsMenu, {\n type RowActionsMenuItem,\n} from '@aglyn/shared-ui-jsx/components/row-actions-menu.component'\nimport { ScrollTable } from '@aglyn/shared-ui-jsx/components/scroll-table.component'\nimport { useSnackbar } from '@aglyn/shared-ui-snackstack'\nimport { authorizedFetch } from '@aglyn/shared-util-http/authorized-token'\nimport {\n useFirestore,\n useUser,\n writeGuardedBySeed,\n} from '@aglyn/tenant-feature-instance'\nimport {\n Button,\n Chip,\n Dialog,\n DialogActions,\n DialogContent,\n DialogContentText,\n DialogTitle,\n IconButton,\n MenuItem,\n Stack,\n TableBody,\n TableCell,\n TableHead,\n TableRow,\n TextField,\n Typography,\n} from '@mui/material'\nimport { doc, serverTimestamp, setDoc } from 'firebase/firestore'\nimport { useCallback, useState } from 'react'\nimport { useLeadSourcePicklist } from '../hooks/use-lead-source-picklist'\nimport {\n addPicklistValue,\n crmLeadSourceValuesRouteUrl,\n type LeadSourceValuesRequest,\n type LeadSourceValuesResponse,\n movePicklistValue,\n setPicklistDefault,\n setPicklistValueActive,\n sortPicklistValues,\n} from '../model/lead-source-values'\nimport { crmTaskCallScope } from '../model/task-routes'\n\nexport interface LeadSourceValuesCardProps {\n /** The mounted site, or `null` at the organization level. */\n hostId: string | null\n /** The org whose list this is; `null` while it settles. */\n orgId: string | null\n /** The site a newly written list records as its definer — the Fields page's own. */\n createHostId: string | null\n}\n\n/** The add and rename dialog's state: which value, if any, is being renamed. */\ntype NameDialog = { mode: 'add' } | { mode: 'rename'; value: CrmPicklistValue } | null\n\n/**\n * THE LEAD SOURCE VALUES (AGL-3298) — Salesforce's Lead Source picklist,\n * managed where the org's lead fields are.\n *\n * Every move that touches only the LIST — add, reorder by drag or arrows,\n * sort A–Z, activate, deactivate, default — is one client write of the\n * whole document, guarded against a cached read like every seeded save on\n * the Fields page. The two that change RECORDS — rename, and delete with a\n * replacement — go to `crm/lead-source-values`, which rewrites the list and\n * every lead and contact holding the old label together; see that route.\n *\n * An org that has never edited its list reads the starter set, and the\n * first move here writes it down as the org's own.\n */\nexport function LeadSourceValuesCard(props: LeadSourceValuesCardProps) {\n const { hostId, orgId, createHostId } = props\n const firestore = useFirestore()\n const { data: user } = useUser()\n const { enqueueSnackbar } = useSnackbar()\n const { picklist, stored, ready, fromCache } = useLeadSourcePicklist(orgId)\n const [busy, setBusy] = useState(false)\n const [nameDialog, setNameDialog] = useState<NameDialog>(null)\n const [draftName, setDraftName] = useState('')\n const [nameError, setNameError] = useState('')\n const [deleting, setDeleting] = useState<CrmPicklistValue | null>(null)\n const [replaceWith, setReplaceWith] = useState('')\n const [dragFrom, setDragFrom] = useState<number | null>(null)\n\n /** Write the whole list — the list-only moves above. */\n const save = useCallback(\n async (next: CrmPicklist, done: string) => {\n if (!orgId || busy) return\n setBusy(true)\n try {\n const verdict = await writeGuardedBySeed({ subject: 'lead source list', fromCache }, () =>\n setDoc(\n doc(firestore, 'orgs', orgId, CRM_COLLECTIONS.picklists, CRM_LEAD_SOURCE_PICKLIST),\n {\n values: next.values,\n defaultValueId: next.defaultValueId,\n updatedAt: serverTimestamp(),\n // The org-wide stamp the rules require of a new CRM document,\n // the same one a field definition carries.\n ...(stored\n ? {}\n : {\n hostId: createHostId,\n createdAt: serverTimestamp(),\n ...newResourceScopeFields([ORG_SCOPE_TOKEN]),\n }),\n },\n { merge: true },\n ),\n )\n if (!verdict.ok) {\n enqueueSnackbar(verdict.message, { variant: 'warning', persist: false })\n return\n }\n enqueueSnackbar(done, { variant: 'success', persist: false })\n } catch (error) {\n console.error(error)\n enqueueSnackbar('The lead sources could not be saved.', { variant: 'error', allowDuplicate: true })\n } finally {\n setBusy(false)\n }\n },\n [orgId, busy, fromCache, firestore, stored, createHostId, enqueueSnackbar],\n )\n\n /** A rename or a delete — the moves that change records too. */\n const post = useCallback(\n async (request: LeadSourceValuesRequest): Promise<LeadSourceValuesResponse | null> => {\n const scope = crmTaskCallScope(hostId, orgId)\n if (!scope || busy) return null\n setBusy(true)\n try {\n const response = await authorizedFetch(user, crmLeadSourceValuesRouteUrl(), {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ ...request, ...scope }),\n })\n const payload = (await response.json().catch(() => ({}))) as { error?: string }\n if (!response.ok) {\n enqueueSnackbar(payload.error || 'The lead sources could not be saved.', {\n variant: 'warning',\n persist: false,\n })\n return null\n }\n return payload as LeadSourceValuesResponse\n } catch (error) {\n console.error(error)\n enqueueSnackbar('The lead sources could not be saved.', { variant: 'error', allowDuplicate: true })\n return null\n } finally {\n setBusy(false)\n }\n },\n [hostId, orgId, busy, user, enqueueSnackbar],\n )\n\n const moved = (result: LeadSourceValuesResponse) => {\n const records = result.leads + result.contacts\n return records\n ? ` — ${result.leads.toLocaleString()} lead${result.leads === 1 ? '' : 's'} and ` +\n `${result.contacts.toLocaleString()} contact${result.contacts === 1 ? '' : 's'} updated`\n : ''\n }\n\n const openAdd = () => {\n setDraftName('')\n setNameError('')\n setNameDialog({ mode: 'add' })\n }\n const openRename = (value: CrmPicklistValue) => {\n setDraftName(value.label)\n setNameError('')\n setNameDialog({ mode: 'rename', value })\n }\n\n const submitName = async () => {\n if (!nameDialog) return\n if (nameDialog.mode === 'add') {\n const move = addPicklistValue(picklist, draftName)\n if (move.ok === false) return void setNameError(move.error)\n setNameDialog(null)\n await save(move.picklist, `“${draftName.trim()}” added`)\n return\n }\n const result = await post({ action: 'rename', valueId: nameDialog.value.id, label: draftName })\n if (!result) return\n setNameDialog(null)\n enqueueSnackbar(`Renamed${moved(result)}`, { variant: 'success', persist: false })\n }\n\n const openDelete = (value: CrmPicklistValue) => {\n setReplaceWith('')\n setDeleting(value)\n }\n const submitDelete = async () => {\n if (!deleting) return\n const result = await post({\n action: 'delete',\n valueId: deleting.id,\n replaceWith: replaceWith || null,\n })\n if (!result) return\n setDeleting(null)\n enqueueSnackbar(`“${deleting.label}” deleted${moved(result)}`, {\n variant: 'success',\n persist: false,\n })\n }\n\n const move = (from: number, to: number) =>\n void save(movePicklistValue(picklist, from, to), 'Order saved')\n\n const rowActions = (value: CrmPicklistValue): RowActionsMenuItem[] => {\n const isDefault = picklist.defaultValueId === value.id\n return [\n {\n key: 'rename',\n label: 'Rename',\n icon: <MdiIcon path={mdiPencilOutline.path} size={0.8} />,\n disabled: busy,\n onClick: () => openRename(value),\n },\n {\n key: 'default',\n label: isDefault ? 'Clear default' : 'Make default',\n icon: <MdiIcon path={mdiStarOutline.path} size={0.8} />,\n disabled: busy || (!isDefault && !value.active),\n disabledReason: !value.active ? 'An inactive value cannot be the default' : undefined,\n onClick: () =>\n void save(\n setPicklistDefault(picklist, isDefault ? null : value.id),\n isDefault ? 'Default cleared' : `New leads start as “${value.label}”`,\n ),\n },\n {\n key: 'active',\n label: value.active ? 'Deactivate' : 'Activate',\n icon: (\n <MdiIcon path={value.active ? mdiEyeOffOutline.path : mdiEyeOutline.path} size={0.8} />\n ),\n disabled: busy,\n onClick: () =>\n void save(\n setPicklistValueActive(picklist, value.id, !value.active),\n value.active ? `“${value.label}” deactivated` : `“${value.label}” activated`,\n ),\n },\n {\n key: 'delete',\n label: 'Delete…',\n icon: <MdiIcon path={mdiDeleteOutline.path} size={0.8} />,\n destructive: true,\n disabled: busy,\n onClick: () => openDelete(value),\n },\n ]\n }\n\n const replacements = crmPicklistActiveValues(picklist).filter(\n (value) => value.id !== deleting?.id,\n )\n\n return (\n <Stack spacing={1.5}>\n <Stack\n direction={{ xs: 'column', sm: 'row' }}\n spacing={1}\n sx={{ justifyContent: 'space-between', alignItems: { sm: 'center' } }}\n >\n <Stack spacing={0.25}>\n <Typography variant=\"subtitle1\">{'Lead source values'}</Typography>\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'The choices in every lead’s Lead source select, in this order. ' +\n 'An import or an API write naming anything else is refused. ' +\n 'A deactivated value stays on the records that hold it.'}\n </Typography>\n </Stack>\n {orgId ? (\n <Stack direction=\"row\" spacing={1} sx={{ flexShrink: 0 }}>\n <Button\n size=\"small\"\n disabled={busy || picklist.values.length < 2}\n onClick={() => void save(sortPicklistValues(picklist), 'Sorted A–Z')}\n >\n {'Sort A–Z'}\n </Button>\n <Button size=\"small\" variant=\"outlined\" disabled={busy} onClick={openAdd}>\n {'Add value'}\n </Button>\n </Stack>\n ) : null}\n </Stack>\n {!ready ? null : (\n <ScrollTable size=\"small\" aria-label=\"Lead source values\">\n <TableHead>\n <TableRow>\n <TableCell sx={{ width: 120 }}>{'Order'}</TableCell>\n <TableCell>{'Value'}</TableCell>\n <TableCell>{'Status'}</TableCell>\n <TableCell align=\"right\" />\n </TableRow>\n </TableHead>\n <TableBody>\n {picklist.values.length === 0 ? (\n <TableRow>\n <TableCell colSpan={4}>\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'No values yet. Add one, and every lead can be given it.'}\n </Typography>\n </TableCell>\n </TableRow>\n ) : null}\n {picklist.values.map((value, index) => (\n <TableRow\n key={value.id}\n hover\n // Native drag and drop for a pointer; the arrows beside the\n // handle are the same move for a keyboard or a touch screen.\n draggable={!busy}\n onDragStart={(event) => {\n setDragFrom(index)\n event.dataTransfer.effectAllowed = 'move'\n }}\n onDragOver={(event) => {\n if (dragFrom === null) return\n event.preventDefault()\n event.dataTransfer.dropEffect = 'move'\n }}\n onDrop={(event) => {\n event.preventDefault()\n if (dragFrom !== null && dragFrom !== index) move(dragFrom, index)\n setDragFrom(null)\n }}\n onDragEnd={() => setDragFrom(null)}\n sx={{\n ...(value.active ? {} : { opacity: 0.6 }),\n ...(dragFrom === index ? { outline: 1, outlineColor: 'primary.main' } : {}),\n }}\n >\n <TableCell>\n <Stack direction=\"row\" spacing={0} sx={{ alignItems: 'center' }}>\n <MdiIcon\n path={mdiDragVertical.path}\n size={0.8}\n style={{ cursor: busy ? 'default' : 'grab' }}\n aria-hidden\n />\n <IconButton\n size=\"small\"\n disabled={index === 0 || busy}\n onClick={() => move(index, index - 1)}\n >\n <MdiIcon path={mdiArrowUp.path} size={0.7} />\n <SrOnly>{`Move ${value.label} up`}</SrOnly>\n </IconButton>\n <IconButton\n size=\"small\"\n disabled={index === picklist.values.length - 1 || busy}\n onClick={() => move(index, index + 1)}\n >\n <MdiIcon path={mdiArrowDown.path} size={0.7} />\n <SrOnly>{`Move ${value.label} down`}</SrOnly>\n </IconButton>\n </Stack>\n </TableCell>\n <TableCell>\n <Typography variant=\"body2\">{value.label}</Typography>\n </TableCell>\n <TableCell>\n <Stack direction=\"row\" spacing={1} sx={{ flexWrap: 'wrap', alignItems: 'center' }}>\n {value.active ? null : (\n <Chip size=\"small\" variant=\"outlined\" color=\"warning\" label=\"Inactive\" />\n )}\n {picklist.defaultValueId === value.id ? (\n <Chip size=\"small\" variant=\"outlined\" color=\"primary\" label=\"Default\" />\n ) : null}\n {value.active && picklist.defaultValueId !== value.id ? (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'Active'}\n </Typography>\n ) : null}\n </Stack>\n </TableCell>\n <TableCell align=\"right\" sx={{ width: 56 }}>\n <RowActionsMenu label={value.label} items={rowActions(value)} />\n </TableCell>\n </TableRow>\n ))}\n </TableBody>\n </ScrollTable>\n )}\n {ready && !stored ? (\n <Typography variant=\"caption\" color=\"text.secondary\">\n {'This is the starter list. Your first change here makes it your organization’s own.'}\n </Typography>\n ) : null}\n\n <Dialog open={nameDialog !== null} onClose={() => setNameDialog(null)} fullWidth maxWidth=\"xs\">\n <DialogTitle>\n {nameDialog?.mode === 'rename' ? `Rename “${nameDialog.value.label}”` : 'Add a lead source'}\n </DialogTitle>\n <DialogContent>\n <Stack spacing={1.5} sx={{ pt: 1 }}>\n {nameDialog?.mode === 'rename' ? (\n <DialogContentText variant=\"body2\">\n {'Every lead and contact holding this value is updated to the new name.'}\n </DialogContentText>\n ) : null}\n <TextField\n size=\"small\"\n label=\"Value\"\n value={draftName}\n onChange={(event) => {\n setDraftName(event.target.value)\n setNameError('')\n }}\n onKeyDown={(event) => {\n if (event.key === 'Enter') void submitName()\n }}\n error={Boolean(nameError)}\n helperText={nameError || ' '}\n slotProps={{ htmlInput: { maxLength: CRM_LEAD_TEXT_MAX } }}\n autoFocus\n fullWidth\n />\n </Stack>\n </DialogContent>\n <DialogActions>\n <Button onClick={() => setNameDialog(null)}>{'Cancel'}</Button>\n <Button\n variant=\"contained\"\n disabled={busy || !draftName.trim()}\n onClick={() => void submitName()}\n >\n {nameDialog?.mode === 'rename' ? 'Rename' : 'Add'}\n </Button>\n </DialogActions>\n </Dialog>\n\n <Dialog open={deleting !== null} onClose={() => setDeleting(null)} fullWidth maxWidth=\"xs\">\n <DialogTitle>{`Delete “${deleting?.label ?? ''}”?`}</DialogTitle>\n <DialogContent>\n <Stack spacing={1.5} sx={{ pt: 1 }}>\n <DialogContentText variant=\"body2\">\n {'The value leaves the list for good. Leads and contacts that hold it ' +\n 'are moved to the value you pick here, or cleared. To keep it on ' +\n 'those records instead, deactivate it.'}\n </DialogContentText>\n <TextField\n select\n size=\"small\"\n label=\"Replace it on existing records with\"\n value={replaceWith}\n onChange={(event) => setReplaceWith(String(event.target.value))}\n fullWidth\n slotProps={{ select: { displayEmpty: true }, inputLabel: { shrink: true } }}\n >\n <MenuItem value=\"\">{'None — clear it'}</MenuItem>\n {replacements.map((value) => (\n <MenuItem key={value.id} value={value.label}>\n {value.label}\n </MenuItem>\n ))}\n </TextField>\n </Stack>\n </DialogContent>\n <DialogActions>\n <Button onClick={() => setDeleting(null)}>{'Cancel'}</Button>\n <Button\n variant=\"contained\"\n color=\"error\"\n disabled={busy}\n onClick={() => void submitDelete()}\n >\n {'Delete value'}\n </Button>\n </DialogActions>\n </Dialog>\n </Stack>\n )\n}\nLeadSourceValuesCard.displayName = 'LeadSourceValuesCard'\n\nexport default LeadSourceValuesCard\n"],"names":["CRM_COLLECTIONS","CRM_LEAD_SOURCE_PICKLIST","CRM_LEAD_TEXT_MAX","crmPicklistActiveValues","newResourceScopeFields","ORG_SCOPE_TOKEN","mdiArrowDown","mdiArrowUp","mdiDeleteOutline","mdiDragVertical","mdiEyeOffOutline","mdiEyeOutline","mdiPencilOutline","mdiStarOutline","MdiIcon","SrOnly","RowActionsMenu","ScrollTable","useSnackbar","authorizedFetch","useFirestore","useUser","writeGuardedBySeed","Button","Chip","Dialog","DialogActions","DialogContent","DialogContentText","DialogTitle","IconButton","MenuItem","Stack","TableBody","TableCell","TableHead","TableRow","TextField","Typography","doc","serverTimestamp","setDoc","useCallback","useState","useLeadSourcePicklist","addPicklistValue","crmLeadSourceValuesRouteUrl","movePicklistValue","setPicklistDefault","setPicklistValueActive","sortPicklistValues","crmTaskCallScope","LeadSourceValuesCard","props","hostId","orgId","createHostId","firestore","data","user","enqueueSnackbar","picklist","stored","ready","fromCache","busy","setBusy","nameDialog","setNameDialog","draftName","setDraftName","nameError","setNameError","deleting","setDeleting","replaceWith","setReplaceWith","dragFrom","setDragFrom","save","next","done","verdict","subject","picklists","values","defaultValueId","updatedAt","createdAt","merge","ok","message","variant","persist","error","console","allowDuplicate","post","request","scope","response","method","headers","body","JSON","stringify","payload","json","catch","moved","result","records","leads","contacts","toLocaleString","openAdd","mode","openRename","value","label","submitName","move","trim","action","valueId","id","openDelete","submitDelete","from","to","rowActions","isDefault","key","icon","path","size","disabled","onClick","active","disabledReason","undefined","destructive","replacements","filter","spacing","direction","xs","sm","sx","justifyContent","alignItems","color","flexShrink","length","aria-label","width","align","colSpan","map","index","hover","draggable","onDragStart","event","dataTransfer","effectAllowed","onDragOver","preventDefault","dropEffect","onDrop","onDragEnd","opacity","outline","outlineColor","style","cursor","aria-hidden","flexWrap","items","open","onClose","fullWidth","maxWidth","pt","onChange","target","onKeyDown","Boolean","helperText","slotProps","htmlInput","maxLength","autoFocus","select","String","displayEmpty","inputLabel","shrink","displayName"],"mappings":"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"}
|
|
@@ -44,7 +44,8 @@ import { useRouter } from "next/navigation";
|
|
|
44
44
|
import { useCallback, useEffect, useId, useMemo, useState } from "react";
|
|
45
45
|
import { downloadTextFile } from "../model/contacts-csv.js";
|
|
46
46
|
import { crmRoutes } from "../model/crm-routes.js";
|
|
47
|
-
import { LEAD_FILTER_LABELS, LEAD_EMAIL_FILTER_LABELS, LEAD_EMAIL_FILTERS, LEAD_FILTERS, leadMatchesCampaignFilter, leadMatchesEmailFilter, leadMatchesFilter, leadMatchesSearch } from "../model/lead-filters.js";
|
|
47
|
+
import { LEAD_FILTER_LABELS, LEAD_EMAIL_FILTER_LABELS, LEAD_EMAIL_FILTERS, LEAD_FILTERS, leadMatchesCampaignFilter, leadMatchesEmailFilter, leadMatchesFilter, leadMatchesLeadSourceFilter, leadMatchesSearch, LEAD_SOURCE_FILTER_NONE } from "../model/lead-filters.js";
|
|
48
|
+
import { useLeadSourcePicklist } from "../hooks/use-lead-source-picklist.js";
|
|
48
49
|
import { leadsCsv } from "../model/leads-csv.js";
|
|
49
50
|
import { LeadConvertDialog } from "./lead-convert-dialog.js";
|
|
50
51
|
import { leadSourceLabel, leadSources, leadTimeLabel } from "./lead-history-card.js";
|
|
@@ -111,6 +112,9 @@ import OrgLeadSurfacesNote from "./org-lead-surfaces-note.js";
|
|
|
111
112
|
const roster = useOrgMemberOptions(orgId);
|
|
112
113
|
// The org's lead fields, for the optional columns below (AGL-3272).
|
|
113
114
|
const leadFields = useContactFieldDefinitions(orgId, 'lead');
|
|
115
|
+
// The org's lead source values (AGL-3298): the filter's menu and the
|
|
116
|
+
// column's sort order.
|
|
117
|
+
const leadSourceList = useLeadSourcePicklist(orgId);
|
|
114
118
|
const routes = crmRoutes(basePath != null ? basePath : '');
|
|
115
119
|
/*
|
|
116
120
|
* Under a site: the ORG collection, narrowed to what this site may see
|
|
@@ -235,6 +239,37 @@ import OrgLeadSurfacesNote from "./org-lead-surfaces-note.js";
|
|
|
235
239
|
views.setFilters,
|
|
236
240
|
views.state.filters
|
|
237
241
|
]);
|
|
242
|
+
/*
|
|
243
|
+
* The `Lead source` filter (AGL-3298) is the view's too: an `equals`
|
|
244
|
+
* clause naming the label records store, or an `isEmpty` one for the
|
|
245
|
+
* leads that hold none.
|
|
246
|
+
*/ const leadSourceFilter = useMemo(()=>{
|
|
247
|
+
var _clause_value;
|
|
248
|
+
const clause = views.state.filters.find((entry)=>entry.field === 'leadSource');
|
|
249
|
+
if (!clause) return '';
|
|
250
|
+
return clause.op === 'isEmpty' ? LEAD_SOURCE_FILTER_NONE : String((_clause_value = clause.value) != null ? _clause_value : '');
|
|
251
|
+
}, [
|
|
252
|
+
views.state.filters
|
|
253
|
+
]);
|
|
254
|
+
const setLeadSourceFilter = useCallback((next)=>views.setFilters([
|
|
255
|
+
...views.state.filters.filter((clause)=>clause.field !== 'leadSource'),
|
|
256
|
+
...next === LEAD_SOURCE_FILTER_NONE ? [
|
|
257
|
+
{
|
|
258
|
+
field: 'leadSource',
|
|
259
|
+
op: 'isEmpty',
|
|
260
|
+
value: ''
|
|
261
|
+
}
|
|
262
|
+
] : next ? [
|
|
263
|
+
{
|
|
264
|
+
field: 'leadSource',
|
|
265
|
+
op: 'equals',
|
|
266
|
+
value: next
|
|
267
|
+
}
|
|
268
|
+
] : []
|
|
269
|
+
]), [
|
|
270
|
+
views.setFilters,
|
|
271
|
+
views.state.filters
|
|
272
|
+
]);
|
|
238
273
|
const campaigns = useCrmCampaigns({
|
|
239
274
|
hostId,
|
|
240
275
|
orgId
|
|
@@ -253,6 +288,7 @@ import OrgLeadSurfacesNote from "./org-lead-surfaces-note.js";
|
|
|
253
288
|
const filterLabelId = useId();
|
|
254
289
|
const emailFilterLabelId = useId();
|
|
255
290
|
const campaignFilterLabelId = useId();
|
|
291
|
+
const leadSourceFilterLabelId = useId();
|
|
256
292
|
/*
|
|
257
293
|
* The search box is the SECTION'S, not the grid's (AGL-3246). The grid's
|
|
258
294
|
* quick filter runs over the rows the grid holds, and the grid holds one
|
|
@@ -262,11 +298,12 @@ import OrgLeadSurfacesNote from "./org-lead-surfaces-note.js";
|
|
|
262
298
|
* before the footer's count and the page slice, over the fields a person
|
|
263
299
|
* types to find a lead: name, email, company, title and tags.
|
|
264
300
|
*/ const [search, setSearch] = useState('');
|
|
265
|
-
const rows = useMemo(()=>window.filter((lead)=>leadMatchesFilter(lead, filter) && leadMatchesEmailFilter(lead, emailFilter) && leadMatchesCampaignFilter(lead, campaignFilter) && leadMatchesSearch(lead, search)), [
|
|
301
|
+
const rows = useMemo(()=>window.filter((lead)=>leadMatchesFilter(lead, filter) && leadMatchesEmailFilter(lead, emailFilter) && leadMatchesCampaignFilter(lead, campaignFilter) && leadMatchesLeadSourceFilter(lead, leadSourceFilter) && leadMatchesSearch(lead, search)), [
|
|
266
302
|
window,
|
|
267
303
|
filter,
|
|
268
304
|
emailFilter,
|
|
269
305
|
campaignFilter,
|
|
306
|
+
leadSourceFilter,
|
|
270
307
|
search
|
|
271
308
|
]);
|
|
272
309
|
const [page, setPage] = useState(0);
|
|
@@ -280,6 +317,7 @@ import OrgLeadSurfacesNote from "./org-lead-surfaces-note.js";
|
|
|
280
317
|
filter,
|
|
281
318
|
emailFilter,
|
|
282
319
|
campaignFilter,
|
|
320
|
+
leadSourceFilter,
|
|
283
321
|
search
|
|
284
322
|
]);
|
|
285
323
|
const pageRows = useMemo(()=>rows.slice(page * pageSize, (page + 1) * pageSize), [
|
|
@@ -297,6 +335,7 @@ import OrgLeadSurfacesNote from "./org-lead-surfaces-note.js";
|
|
|
297
335
|
filter,
|
|
298
336
|
emailFilter,
|
|
299
337
|
campaignFilter,
|
|
338
|
+
leadSourceFilter,
|
|
300
339
|
search
|
|
301
340
|
]);
|
|
302
341
|
// How the file names the owner and, at the org level, the site.
|
|
@@ -547,6 +586,22 @@ import OrgLeadSurfacesNote from "./org-lead-surfaces-note.js";
|
|
|
547
586
|
minWidth: 140,
|
|
548
587
|
valueGetter: (_value, row)=>leadSources(row).map(leadSourceLabel).join(', ')
|
|
549
588
|
},
|
|
589
|
+
/*
|
|
590
|
+
* Salesforce's Lead Source (AGL-3298), beside the surfaces that
|
|
591
|
+
* captured the person. Sorted in the order the org keeps its values,
|
|
592
|
+
* as a picklist sorts, with a value the list does not hold after
|
|
593
|
+
* every listed one and a lead with none last.
|
|
594
|
+
*/ {
|
|
595
|
+
field: 'leadSource',
|
|
596
|
+
headerName: 'Lead source',
|
|
597
|
+
flex: 1,
|
|
598
|
+
minWidth: 150,
|
|
599
|
+
valueGetter: (_value, row)=>{
|
|
600
|
+
var _row_leadSource;
|
|
601
|
+
return String((_row_leadSource = row.leadSource) != null ? _row_leadSource : '');
|
|
602
|
+
},
|
|
603
|
+
sortComparator: (a, b)=>Aglyn.crmPicklistRank(leadSourceList.picklist, a) - Aglyn.crmPicklistRank(leadSourceList.picklist, b) || String(a != null ? a : '').localeCompare(String(b != null ? b : ''))
|
|
604
|
+
},
|
|
550
605
|
{
|
|
551
606
|
field: 'tags',
|
|
552
607
|
headerName: 'Tags',
|
|
@@ -660,7 +715,8 @@ import OrgLeadSurfacesNote from "./org-lead-surfaces-note.js";
|
|
|
660
715
|
hostId,
|
|
661
716
|
mount,
|
|
662
717
|
campaignName,
|
|
663
|
-
leadFields.active
|
|
718
|
+
leadFields.active,
|
|
719
|
+
leadSourceList.picklist
|
|
664
720
|
]);
|
|
665
721
|
/* The column and sort models are the view's (AGL-2617). */ const grid = useCrmViewGrid(views, columns);
|
|
666
722
|
return /*#__PURE__*/ _jsxs(_Fragment, {
|
|
@@ -760,6 +816,45 @@ import OrgLeadSurfacesNote from "./org-lead-surfaces-note.js";
|
|
|
760
816
|
})
|
|
761
817
|
]
|
|
762
818
|
}),
|
|
819
|
+
/*#__PURE__*/ _jsxs(FormControl, {
|
|
820
|
+
size: "small",
|
|
821
|
+
sx: {
|
|
822
|
+
minWidth: 180
|
|
823
|
+
},
|
|
824
|
+
children: [
|
|
825
|
+
/*#__PURE__*/ _jsx(InputLabel, {
|
|
826
|
+
id: leadSourceFilterLabelId,
|
|
827
|
+
shrink: true,
|
|
828
|
+
children: 'Lead source'
|
|
829
|
+
}),
|
|
830
|
+
/*#__PURE__*/ _jsxs(Select, {
|
|
831
|
+
labelId: leadSourceFilterLabelId,
|
|
832
|
+
label: "Lead source",
|
|
833
|
+
notched: true,
|
|
834
|
+
value: leadSourceFilter,
|
|
835
|
+
onChange: (event)=>setLeadSourceFilter(String(event.target.value)),
|
|
836
|
+
displayEmpty: true,
|
|
837
|
+
children: [
|
|
838
|
+
/*#__PURE__*/ _jsx(MenuItem, {
|
|
839
|
+
value: "",
|
|
840
|
+
children: 'Any lead source'
|
|
841
|
+
}),
|
|
842
|
+
leadSourceList.picklist.values.map((value)=>/*#__PURE__*/ _jsx(MenuItem, {
|
|
843
|
+
value: value.label,
|
|
844
|
+
children: value.active ? value.label : `${value.label} (inactive)`
|
|
845
|
+
}, value.id)),
|
|
846
|
+
/*#__PURE__*/ _jsx(MenuItem, {
|
|
847
|
+
value: LEAD_SOURCE_FILTER_NONE,
|
|
848
|
+
children: 'No lead source'
|
|
849
|
+
}),
|
|
850
|
+
leadSourceFilter && leadSourceFilter !== LEAD_SOURCE_FILTER_NONE && !Aglyn.crmPicklistValueByLabel(leadSourceList.picklist, leadSourceFilter) ? /*#__PURE__*/ _jsx(MenuItem, {
|
|
851
|
+
value: leadSourceFilter,
|
|
852
|
+
children: leadSourceFilter
|
|
853
|
+
}) : null
|
|
854
|
+
]
|
|
855
|
+
})
|
|
856
|
+
]
|
|
857
|
+
}),
|
|
763
858
|
/*#__PURE__*/ _jsx(TextField, {
|
|
764
859
|
size: "small",
|
|
765
860
|
value: search,
|
|
@@ -785,7 +880,8 @@ import OrgLeadSurfacesNote from "./org-lead-surfaces-note.js";
|
|
|
785
880
|
}
|
|
786
881
|
}),
|
|
787
882
|
/*#__PURE__*/ _jsx(LeadImportButton, {
|
|
788
|
-
hostId: hostId
|
|
883
|
+
hostId: hostId,
|
|
884
|
+
orgId: orgId
|
|
789
885
|
}),
|
|
790
886
|
/*#__PURE__*/ _jsx(Button, {
|
|
791
887
|
size: "small",
|