@aglyn/plugins-crm 1.0.0-beta.231 → 1.0.0-beta.232

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/package.json +14 -14
  2. package/src/lib/components/activity-timeline.js +1 -0
  3. package/src/lib/components/activity-timeline.js.map +1 -1
  4. package/src/lib/components/assignment-rule-drawer.js +1 -0
  5. package/src/lib/components/assignment-rule-drawer.js.map +1 -1
  6. package/src/lib/components/contact-associations-card.js +1 -0
  7. package/src/lib/components/contact-associations-card.js.map +1 -1
  8. package/src/lib/components/contact-duplicates-card.js +1 -0
  9. package/src/lib/components/contact-duplicates-card.js.map +1 -1
  10. package/src/lib/components/contact-field-drawer.js +1 -0
  11. package/src/lib/components/contact-field-drawer.js.map +1 -1
  12. package/src/lib/components/contact-known-by-card.js +1 -0
  13. package/src/lib/components/contact-known-by-card.js.map +1 -1
  14. package/src/lib/components/contact-timeline-card.js +1 -0
  15. package/src/lib/components/contact-timeline-card.js.map +1 -1
  16. package/src/lib/components/crm-glance-card.js +1 -0
  17. package/src/lib/components/crm-glance-card.js.map +1 -1
  18. package/src/lib/components/crm-record-header.js +2 -0
  19. package/src/lib/components/crm-record-header.js.map +1 -1
  20. package/src/lib/components/deals-section.js +1 -0
  21. package/src/lib/components/deals-section.js.map +1 -1
  22. package/src/lib/components/fields-section.js +4 -0
  23. package/src/lib/components/fields-section.js.map +1 -1
  24. package/src/lib/components/lead-history-card.js +1 -0
  25. package/src/lib/components/lead-history-card.js.map +1 -1
  26. package/src/lib/components/lead-surfaces-note.js +1 -0
  27. package/src/lib/components/lead-surfaces-note.js.map +1 -1
  28. package/src/lib/components/linked-deals-card.js +1 -0
  29. package/src/lib/components/linked-deals-card.js.map +1 -1
  30. package/src/lib/components/picklist-values-card.js +1 -0
  31. package/src/lib/components/picklist-values-card.js.map +1 -1
  32. package/src/lib/components/recipes-card.js +1 -0
  33. package/src/lib/components/recipes-card.js.map +1 -1
  34. package/src/lib/components/reports/activity-card.js +1 -0
  35. package/src/lib/components/reports/activity-card.js.map +1 -1
  36. package/src/lib/components/reports/closed-deals-card.js +1 -0
  37. package/src/lib/components/reports/closed-deals-card.js.map +1 -1
  38. package/src/lib/components/reports/contacts-trend-card.js +1 -0
  39. package/src/lib/components/reports/contacts-trend-card.js.map +1 -1
  40. package/src/lib/components/reports/lead-funnel-card.js +1 -0
  41. package/src/lib/components/reports/lead-funnel-card.js.map +1 -1
  42. package/src/lib/components/reports/lead-source-card.js +1 -0
  43. package/src/lib/components/reports/lead-source-card.js.map +1 -1
  44. package/src/lib/components/reports/pipeline-card.js +1 -0
  45. package/src/lib/components/reports/pipeline-card.js.map +1 -1
  46. package/src/lib/components/reports/source-conversion-card.js +1 -0
  47. package/src/lib/components/reports/source-conversion-card.js.map +1 -1
  48. package/src/lib/components/reports/tasks-card.js +1 -0
  49. package/src/lib/components/reports/tasks-card.js.map +1 -1
  50. package/src/lib/components/reports-section.js +2 -0
  51. package/src/lib/components/reports-section.js.map +1 -1
  52. package/src/lib/components/tasks-calendar.js +1 -0
  53. package/src/lib/components/tasks-calendar.js.map +1 -1
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../../libs/plugins/crm/src/lib/components/deals-section.tsx"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n'use client'\n\nimport {\n type ConsolePluginPageProps,\n type CrmDealStatus,\n type CrmPicklist,\n CRM_COLLECTIONS,\n crmPicklistRank,\n dealStageById,\n ORG_SCOPE_TOKEN,\n pluginDocsHelp,\n} from '@aglyn/aglyn'\nimport {\n mdiCogOutline,\n mdiPlus,\n mdiTableLarge,\n mdiViewColumnOutline,\n} from '@aglyn/shared-data-mdi'\nimport { CardDisplay, MdiIcon } from '@aglyn/shared-ui-jsx'\nimport { ListPagination } from '@aglyn/shared-ui-jsx/components/list-pagination.component'\nimport { ListTable } from '@aglyn/shared-ui-jsx/components/list-table.component'\nimport ListQueryNotices from '@aglyn/shared-ui-jsx/components/list-query-notices.component'\nimport { useCrmSavedView } from '../hooks/use-crm-saved-view'\nimport { useCrmViewGrid } from '../hooks/use-crm-view-grid'\nimport { CrmListActions, CrmListToolbar } from './crm-list-toolbar'\nimport { CRM_LIST_SLOTS, CrmColumnOrderProvider } from './crm-column-menu'\nimport {\n CRM_NEXT_ACTIVITY_FILTER_FIELD,\n CRM_NEXT_ACTIVITY_FILTER_HEADER,\n nextActivityColumn,\n} from './crm-next-activity-column'\nimport {\n DEAL_FILTER_CODECS,\n DEAL_LIST_DECLARATION,\n DEAL_LIST_FILTER_FIELDS,\n DEAL_PICKLIST_FILTER_NONE,\n DEAL_PREFIX_SEARCH,\n dealPipelineBase,\n dealQueryClause,\n} from '../constants/deal-filters'\nimport { useCrmFoldsScope, useCrmListQuery } from '../hooks/use-crm-list-query'\nimport { useCrmPicklist } from '../hooks/use-crm-picklist'\nimport { crmAskClauses, crmQueryRefusals } from '../model/crm-list-query'\nimport ListFilterChips from '@aglyn/shared-ui-jsx/components/list-filter-chips.component'\nimport {\n type ListFilterOption,\n listFilterGridColumns,\n} from '@aglyn/shared-ui-jsx/const/list-grid-filter'\nimport { useListGridFilter } from '@aglyn/shared-ui-jsx/hooks/use-list-grid-filter'\nimport CrmViewsControl from './crm-views-control'\nimport EmptyStateComponent from '@aglyn/shared-ui-jsx/components/empty-state.component'\nimport { useSnackbar } from '@aglyn/shared-ui-snackstack'\nimport {\n Alert,\n Button,\n Chip,\n CircularProgress,\n MenuItem,\n Stack,\n TextField,\n ToggleButton,\n ToggleButtonGroup,\n Typography,\n} from '@mui/material'\nimport type { GridColDef } from '@mui/x-data-grid'\nimport { useRouter } from 'next/navigation'\nimport { useCallback, useEffect, useMemo, useState } from 'react'\nimport { useContactFieldDefinitions } from '../hooks/use-contact-field-definitions'\nimport { useCrmScope } from '../hooks/use-crm-scope'\nimport { useDealStageApi } from '../hooks/use-deal-stage-api'\nimport {\n BOARD_CLOSED_LIMIT,\n BOARD_OPEN_LIMIT,\n useDealsByStatus,\n} from '../hooks/use-deals'\nimport { useOrgMemberDirectory } from '../hooks/use-org-member-directory'\nimport { usePipeline } from '../hooks/use-pipeline'\nimport { crmRoutes } from '../model/crm-routes'\nimport {\n boardSummary,\n DEAL_STATUS_LABELS,\n type DealDoc,\n formatAmountByCurrency,\n formatMoney,\n} from '../model/deal-board-model'\nimport { customFieldColumns } from './contact-custom-columns'\nimport { DealBoard } from './deal-board'\nimport { DealEditDrawer } from './deal-edit-drawer'\nimport { CrmExportButton, CrmImportButton } from './crm-transfer-buttons'\nimport { CRM_DEALS_RESOURCE } from '../transfer/fields'\nimport DealsBulkBar from './deals-bulk-bar'\nimport { LostReasonDialog } from './lost-reason-dialog'\nimport { OwnerAvatar } from './owner-avatar'\nimport { PipelinesDialog } from './pipelines-dialog'\n\ntype View = 'board' | 'table'\ntype StatusFilter = CrmDealStatus | 'all'\n\n/** What the deals table's panel offers: the status, \"No next activity\", the Type and the Lead source. */\nconst DEAL_GRID_FILTER_FIELDS = DEAL_LIST_FILTER_FIELDS\nconst DEAL_GRID_FILTER_HEADERS: Readonly<Record<string, string>> = {\n status: 'Status',\n [CRM_NEXT_ACTIVITY_FILTER_FIELD.column]: CRM_NEXT_ACTIVITY_FILTER_HEADER,\n type: 'Type',\n leadSource: 'Lead source',\n}\nconst DEAL_STATUS_FILTER_OPTIONS = (['open', 'won', 'lost'] as const).map((value) => ({\n value,\n label: DEAL_STATUS_LABELS[value],\n}))\n\n/** Salesforce's Type and Lead source columns are offered, not shown, until a view turns them on (AGL-3516). */\nconst DEAL_HIDDEN_COLUMNS: Readonly<Record<string, boolean>> = { type: false, leadSource: false }\n\n/** A picklist's choices for its filter: every value the org keeps, inactive ones marked, then \"none\". */\nfunction picklistFilterOptions(picklist: CrmPicklist, none: string): ListFilterOption[] {\n return [\n ...picklist.values.map((value) => ({\n value: value.label,\n label: value.active ? value.label : `${value.label} (inactive)`,\n })),\n { value: DEAL_PICKLIST_FILTER_NONE, label: none },\n ]\n}\n\n\n/** What a pipeline made at the organization level is stamped with — the org's own token. */\nconst ORG_PIPELINE_TOKENS: readonly string[] = [ORG_SCOPE_TOKEN]\n\n/**\n * `/crm/deals` — the pipeline (AGL-2598).\n *\n * ## Two views of one pipeline\n *\n * The BOARD is one pipeline's open deals, one column per open stage, read\n * in one bounded listener over `(visibleTo, pipelineId, status, updatedAt)`\n * and sorted into columns here — a listener per column would be five\n * subscriptions for one board. The TABLE is the same pipeline's deals,\n * paged by a query that carries its status, \"No next activity\" and search\n * word (AGL-3321); it is where the closed history is found. The three figures above both come from the board's read, so\n * they describe what is in play whichever view is showing.\n *\n * ## Which pipeline\n *\n * The switcher in the header (AGL-2620) picks among the ACTIVE pipelines\n * and opens on the default; the board, the table, the figures and the New\n * deal drawer all follow it. It is section state rather than a route: a\n * pipeline is a lens on the section, and a saved view that names one\n * composes with it. **Pipelines** opens the dialog that creates, renames,\n * defaults, archives and — through it — edits the stages of each.\n *\n * ## Every move goes through the route\n *\n * A drag, a card's \"Move to\", \"Mark won\" and \"Mark lost\" all end in\n * `useDealStageApi`, never a Firestore write: the stage is the fact the\n * automations listen for, and only the server emits the event. The section\n * marks the card pending while the request runs and lets the listener land\n * it — see `DealBoard` for why a move is not applied optimistically.\n *\n * ## Creation is a button\n *\n * \"New deal\" opens a drawer; there is no form above the list. The drawer\n * writes client-direct against the rules, stamped with this console's scope.\n *\n * ## The table selects and exports (AGL-2621)\n *\n * The table's rows are selectable, and a selection raises `DealsBulkBar`\n * over it — whose stage moves go through the same `useDealStageApi` as a\n * drag. Import and Export open the console's import wizard and export\n * dialog on `crm.deals` (AGL-3528): the export over the selection, the\n * list's own query, or every deal.\n */\nexport function DealsSection(props: ConsolePluginPageProps) {\n const { hostId, org, basePath } = props\n const routes = crmRoutes(basePath ?? '')\n const router = useRouter()\n const { enqueueSnackbar } = useSnackbar()\n const scope = useCrmScope({ hostId, org })\n const pipelineState = usePipeline(scope.orgId, {\n hostId,\n org: (org ?? null) as Record<string, unknown> | null,\n })\n const { activePipelines } = pipelineState\n const [pipelineId, setPipelineId] = useState<string | null>(null)\n // The chosen pipeline while it is still active; else the default. A\n // pipeline archived from another tab falls back rather than leaving the\n // board on a pipeline the picker no longer lists.\n const pipeline =\n (pipelineId ? activePipelines.find((entry) => entry.$id === pipelineId) : null) ??\n pipelineState.pipeline\n const roster = useOrgMemberDirectory(scope.orgId)\n const api = useDealStageApi(hostId)\n const nowMs = useMemo(() => Date.now(), [])\n // The org's deal fields, for the table's optional columns (AGL-2661).\n const dealFields = useContactFieldDefinitions(scope.orgId, 'deal')\n // Salesforce's Type and Lead source lists, for their columns and filters (AGL-3516).\n const typeList = useCrmPicklist('opportunityType', scope.orgId)\n const leadSourceList = useCrmPicklist('leadSource', scope.orgId)\n\n const [view, setView] = useState<View>('board')\n const [closedExpanded, setClosedExpanded] = useState(false)\n /*\n * The table's status filter is the saved VIEW'S (AGL-2617): a view of\n * deals is a view of the table, and it holds the status beside the\n * columns and the sort. Opening one shows the table, because the board\n * has no columns to arrange and answers to the pipeline's stages alone.\n */\n const views = useCrmSavedView({\n section: 'deals',\n hostId,\n org,\n basePath: basePath ?? '',\n })\n const statusFilter: StatusFilter = useMemo(() => {\n const value = views.state.filters.find((clause) => clause.field === 'status')?.value\n return value === 'open' || value === 'won' || value === 'lost' ? value : 'all'\n }, [views.state.filters])\n // Every clause is the query's, the status and \"No next activity\" alike.\n const viewFilters = views.state.filters\n useEffect(() => {\n if (views.currentId) setView('table')\n }, [views.currentId])\n\n // The board's read stays on in the table view too: it is what the summary\n // above both views is computed from, and it is already bounded.\n const open = useDealsByStatus(\n scope.orgId,\n scope.visibleTo,\n pipeline?.$id ?? null,\n 'open',\n BOARD_OPEN_LIMIT,\n )\n const closedPipelineId =\n view === 'board' && closedExpanded ? (pipeline?.$id ?? null) : null\n const won = useDealsByStatus(scope.orgId, scope.visibleTo, closedPipelineId, 'won', BOARD_CLOSED_LIMIT)\n const lost = useDealsByStatus(scope.orgId, scope.visibleTo, closedPipelineId, 'lost', BOARD_CLOSED_LIMIT)\n /*\n * THE TABLE (AGL-3321): the pipeline's deals, every clause and the search\n * word on one query — the search reads the title's word prefixes every\n * deal writer stamps, so a deal on page four is found by any word of its\n * title — paged by that query, and read only while the table is showing.\n */\n const [searchWords, setSearchWords] = useState<string[]>([])\n const searching = searchWords.some((word) => word.trim())\n const searchKey = searchWords.join(' ')\n const foldsScope = useCrmFoldsScope(scope.orgId, scope.visibleTo)\n const pipelineBase = useMemo(() => dealPipelineBase(pipeline?.$id ?? null), [pipeline?.$id])\n // Each stored clause asked through the field its writer keeps — a Type\n // or a Lead source by its key (AGL-3516).\n const asked = useMemo(() => crmAskClauses(viewFilters, dealQueryClause), [viewFilters])\n const paged = useCrmListQuery<DealDoc>({\n scope: scope.scope,\n collection: CRM_COLLECTIONS.deals,\n visibleTo: scope.visibleTo,\n foldsScope,\n declaration: DEAL_LIST_DECLARATION,\n clauses: asked.clauses,\n search: searchWords,\n base: pipelineBase,\n prefixSearch: DEAL_PREFIX_SEARCH,\n enabled: view === 'table' && Boolean(pipeline),\n })\n\n const summary = useMemo(() => boardSummary(open.data, pipeline), [open.data, pipeline])\n\n /*\n * MOVES IN FLIGHT. A card in this set is dimmed and cannot be dragged\n * again until the route answers; the listener is what moves it.\n */\n const [moving, setMoving] = useState<ReadonlySet<string>>(() => new Set())\n const track = useCallback(\n async (deal: DealDoc, request: () => Promise<unknown>, done: string) => {\n setMoving((current) => new Set(current).add(deal.$id))\n try {\n await request()\n enqueueSnackbar(done, { variant: 'success', persist: false })\n return true\n } catch (error) {\n enqueueSnackbar(\n error instanceof Error ? error.message : 'The deal could not be moved.',\n { variant: 'warning', allowDuplicate: true },\n )\n return false\n } finally {\n setMoving((current) => {\n const next = new Set(current)\n next.delete(deal.$id)\n return next\n })\n }\n },\n [enqueueSnackbar],\n )\n const handleMove = useCallback(\n (deal: DealDoc, stageId: string) => {\n const stage = dealStageById(pipeline, stageId)\n void track(\n deal,\n () => api.moveToStage(deal, stageId),\n `Moved to ${stage?.name ?? 'stage'}`,\n )\n },\n [api, pipeline, track],\n )\n const handleWon = useCallback(\n (deal: DealDoc) => void track(deal, () => api.markWon(deal), 'Deal won'),\n [api, track],\n )\n const [losing, setLosing] = useState<DealDoc | null>(null)\n const handleLost = useCallback((deal: DealDoc) => setLosing(deal), [])\n const confirmLost = useCallback(\n (reason: string) => {\n const deal = losing\n if (!deal) return\n setLosing(null)\n void track(deal, () => api.markLost(deal, reason), 'Deal marked lost')\n },\n [api, losing, track],\n )\n\n const openDeal = useCallback(\n (deal: DealDoc) => router.push(routes.deal(deal.$id)),\n [router, routes],\n )\n\n const [creating, setCreating] = useState(false)\n const [managingPipelines, setManagingPipelines] = useState(false)\n\n const [selectedIds, setSelectedIds] = useState<string[]>([])\n // A page or a status is a different set of rows; a selection made on\n // the last one would be a count over rows no longer on screen.\n useEffect(() => setSelectedIds([]), [paged.plan, paged.page])\n // The list's filter, when one narrows it, for the export to read the same\n // records the list does (AGL-3528).\n const exportFilter = useMemo(\n () => (paged.plan.served.length || paged.plan.searched ? { label: 'what the list shows', plan: paged.plan } : null),\n [paged.plan],\n )\n\n const columns: GridColDef[] = useMemo(\n () => [\n {\n field: 'title',\n headerName: 'Deal',\n flex: 1.6,\n minWidth: 220,\n renderCell: ({ row }: { row: DealDoc }) => {\n const withWhom = [row.contactName, row.companyName].filter(Boolean).join(' · ')\n return (\n <Stack sx={{ justifyContent: 'center', lineHeight: 1.25 }}>\n <Typography variant=\"body2\" sx={{ lineHeight: 1.25 }}>\n {row.title || 'Untitled deal'}\n </Typography>\n {withWhom ? (\n <Typography variant=\"caption\" color=\"text.secondary\" noWrap sx={{ lineHeight: 1.25 }}>\n {withWhom}\n </Typography>\n ) : null}\n </Stack>\n )\n },\n },\n {\n field: 'stageId',\n headerName: 'Stage',\n flex: 0.9,\n minWidth: 140,\n valueGetter: (_value: unknown, row: DealDoc) =>\n dealStageById(pipelineState.pipelineById(row.pipelineId), row.stageId)?.name ??\n row.stageId,\n },\n {\n field: 'amountCents',\n headerName: 'Amount',\n flex: 0.8,\n minWidth: 120,\n align: 'right',\n headerAlign: 'right',\n valueGetter: (_value: unknown, row: DealDoc) => row.amountCents ?? null,\n renderCell: ({ row }: { row: DealDoc }) =>\n typeof row.amountCents === 'number' ? formatMoney(row.amountCents, row.currency) : '—',\n },\n {\n field: 'ownerUid',\n headerName: 'Owner',\n flex: 0.9,\n minWidth: 140,\n valueGetter: (_value: unknown, row: DealDoc) => roster.nameOf(row.ownerUid),\n renderCell: ({ row }: { row: DealDoc }) => {\n const label = roster.nameOf(row.ownerUid)\n return label ? (\n <Stack direction=\"row\" spacing={1} sx={{ alignItems: 'center' }}>\n <OwnerAvatar label={label} size={22} />\n <Typography variant=\"body2\" noWrap>\n {label}\n </Typography>\n </Stack>\n ) : (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'—'}\n </Typography>\n )\n },\n },\n {\n field: 'expectedCloseAtMs',\n headerName: 'Expected close',\n flex: 0.8,\n minWidth: 130,\n type: 'date',\n valueGetter: (_value: unknown, row: DealDoc) =>\n typeof row.expectedCloseAtMs === 'number' ? new Date(row.expectedCloseAtMs) : null,\n renderCell: ({ row }: { row: DealDoc }) =>\n typeof row.expectedCloseAtMs === 'number'\n ? new Date(row.expectedCloseAtMs).toLocaleDateString()\n : '—',\n },\n {\n field: 'status',\n headerName: 'Status',\n flex: 0.6,\n minWidth: 100,\n renderCell: ({ row }: { row: DealDoc }) => (\n <Chip\n size=\"small\"\n label={DEAL_STATUS_LABELS[row.status] ?? row.status}\n color={row.status === 'won' ? 'success' : row.status === 'lost' ? 'default' : 'primary'}\n variant={row.status === 'open' ? 'outlined' : 'filled'}\n />\n ),\n },\n // When the earliest open task against the deal is due (AGL-2661).\n nextActivityColumn(nowMs),\n // Salesforce's Type and Lead source, optional, in their lists' order (AGL-3516).\n picklistColumn('type', 'Type', typeList.picklist),\n picklistColumn('leadSource', 'Lead source', leadSourceList.picklist),\n // The org's deal fields as optional columns (AGL-2661).\n ...customFieldColumns(dealFields.active),\n ],\n [pipelineState, roster, dealFields.active, nowMs, typeList.picklist, leadSourceList.picklist],\n )\n /** The table's rows: the query's page. */\n const tableRows = paged.rows\n /*\n * The table's column and sort models are the view's (AGL-2617); its\n * filters are the grid's own panel over the view's clauses (AGL-3313),\n * every one of them asked of the query (AGL-3321).\n */\n /*\n * The choices each select column offers. A stored clause naming a value\n * no longer listed stays a choice, so the panel can show it and clear it.\n */\n const filterOptions = useMemo<Record<string, ListFilterOption[]>>(() => {\n const stale = (field: string, known: readonly { value: string }[]) =>\n viewFilters\n .filter((clause) => clause.field === field && clause.op !== 'isEmpty')\n .flatMap((clause) => clause.value.split(','))\n .map((value) => value.trim())\n .filter((value) => value && !known.some((option) => option.value === value))\n .map((value) => ({ value, label: value }))\n const types = picklistFilterOptions(typeList.picklist, 'No type')\n const sources = picklistFilterOptions(leadSourceList.picklist, 'No lead source')\n return {\n status: DEAL_STATUS_FILTER_OPTIONS,\n type: [...types, ...stale('type', types)],\n leadSource: [...sources, ...stale('leadSource', sources)],\n }\n }, [viewFilters, typeList.picklist, leadSourceList.picklist])\n const filterColumns = useMemo(\n () => listFilterGridColumns(columns, DEAL_GRID_FILTER_FIELDS, filterOptions, DEAL_GRID_FILTER_HEADERS),\n [columns, filterOptions],\n )\n const grid = useCrmViewGrid(views, filterColumns, DEAL_HIDDEN_COLUMNS)\n const gridFilter = useListGridFilter({\n clauses: viewFilters,\n onChange: views.setFilters,\n selectFields: ['status', 'type', 'leadSource'],\n codecs: DEAL_FILTER_CODECS,\n search: { words: searchWords, onChange: setSearchWords },\n })\n // What the query could not hold, named by the clause the reader set.\n const refused = useMemo(\n () =>\n crmQueryRefusals(paged.plan, asked, {\n fields: DEAL_GRID_FILTER_FIELDS,\n headers: DEAL_GRID_FILTER_HEADERS,\n options: filterOptions,\n }),\n [paged.plan, asked, filterOptions],\n )\n\n const noOrg = scope.ready && !scope.orgId\n const pipelineLoading =\n !noOrg && (pipelineState.status === 'loading' || pipelineState.seeding || (!pipeline && pipelineState.status !== 'error'))\n\n return (\n <>\n <CardDisplay\n header={'Deals'}\n help={pluginDocsHelp('deals', { anchor: '#the-board-and-the-table' })}\n contentGutterX\n contentGutterY\n HeaderProps={{\n // The record actions, top right and never clipped (AGL-3311).\n action: (\n <CrmListActions>\n <CrmImportButton resource={CRM_DEALS_RESOURCE} noun=\"deals\" hostId={hostId} mappingZone=\"deals\" />\n <CrmExportButton resource={CRM_DEALS_RESOURCE} hostId={hostId} filter={exportFilter} />\n <Button\n size=\"small\"\n startIcon={<MdiIcon path={mdiCogOutline.path} size={0.8} />}\n disabled={!scope.orgId || pipelineState.status === 'loading'}\n onClick={() => setManagingPipelines(true)}\n >\n {'Pipelines'}\n </Button>\n <Button\n size=\"small\"\n variant=\"contained\"\n startIcon={<MdiIcon path={mdiPlus.path} size={0.8} />}\n disabled={!pipeline || !scope.orgId}\n onClick={() => setCreating(true)}\n >\n {'New deal'}\n </Button>\n </CrmListActions>\n ),\n }}\n >\n <Stack spacing={2}>\n <Stack\n direction=\"row\"\n spacing={3}\n sx={{ alignItems: 'flex-end', flexWrap: 'wrap', rowGap: 1 }}\n >\n <Figure label=\"Open deals\" value={summary.openCount.toLocaleString()} />\n <Figure label=\"Pipeline value\" value={formatAmountByCurrency(summary.valueByCurrency)} />\n <Figure label=\"Weighted value\" value={formatAmountByCurrency(summary.weightedByCurrency)} />\n <Stack sx={{ flex: 1 }} />\n {/* Which pipeline the board and table show, above them rather than under (AGL-3311). */}\n {activePipelines.length > 1 ? (\n <TextField\n select\n size=\"small\"\n label=\"Pipeline\"\n value={pipeline?.$id ?? ''}\n onChange={(event) => setPipelineId(event.target.value)}\n sx={{ minWidth: 160 }}\n slotProps={{ select: { 'aria-label': 'Pipeline' } }}\n >\n {activePipelines.map((entry) => (\n <MenuItem key={entry.$id} value={entry.$id}>\n {entry.name}\n </MenuItem>\n ))}\n </TextField>\n ) : null}\n <ToggleButtonGroup\n exclusive\n size=\"small\"\n color=\"primary\"\n value={view}\n onChange={(_event, next) => {\n if (next) setView(next as View)\n }}\n aria-label=\"View\"\n >\n <ToggleButton value=\"board\" aria-label=\"Board\">\n <MdiIcon path={mdiViewColumnOutline.path} size={0.8} />\n <Typography variant=\"button\" sx={{ ml: 0.5 }}>\n {'Board'}\n </Typography>\n </ToggleButton>\n <ToggleButton value=\"table\" aria-label=\"Table\">\n <MdiIcon path={mdiTableLarge.path} size={0.8} />\n <Typography variant=\"button\" sx={{ ml: 0.5 }}>\n {'Table'}\n </Typography>\n </ToggleButton>\n </ToggleButtonGroup>\n </Stack>\n\n {noOrg ? (\n <Alert severity=\"info\">\n {'This site has no organization, so it has no pipeline.'}\n </Alert>\n ) : pipelineState.status === 'error' ? (\n <Alert severity=\"warning\">\n {'The pipeline could not be read. Deals need the \"Manage data\" permission.'}\n </Alert>\n ) : pipelineLoading ? (\n <Stack direction=\"row\" spacing={1} sx={{ alignItems: 'center' }}>\n <CircularProgress size={18} />\n <Typography variant=\"body2\" color=\"text.secondary\">\n {pipelineState.seeding ? 'Setting up your Sales pipeline…' : 'Loading the pipeline…'}\n </Typography>\n </Stack>\n ) : view === 'board' && pipeline ? (\n <>\n {open.status === 'success' && open.data.length === 0 ? (\n <EmptyStateComponent\n compact\n label={'No open deals yet'}\n description={'A deal is a sale in progress, moved across the stages below as it advances.'}\n action={\n <Button\n size=\"small\"\n variant=\"contained\"\n startIcon={<MdiIcon path={mdiPlus.path} size={0.8} />}\n disabled={!pipeline || !scope.orgId}\n onClick={() => setCreating(true)}\n >\n {'New deal'}\n </Button>\n }\n />\n ) : null}\n <DealBoard\n pipeline={pipeline}\n deals={open.data}\n won={closedExpanded && won.status !== 'loading' ? won.data : null}\n lost={closedExpanded && lost.status !== 'loading' ? lost.data : null}\n closedExpanded={closedExpanded}\n onToggleClosed={() => setClosedExpanded((current) => !current)}\n labelFor={roster.nameOf}\n moving={moving}\n onOpen={openDeal}\n onMove={handleMove}\n onWon={handleWon}\n onLost={handleLost}\n nowMs={nowMs}\n />\n </>\n ) : (\n <Stack spacing={1.5}>\n {/*\n The view this table is showing, and the clauses narrowing it\n as chips (AGL-2617, AGL-3313). Status and \"No next activity\"\n are set in the grid's own Filters panel.\n */}\n <CrmListToolbar label=\"Deal filters\">\n <CrmViewsControl controller={views} allLabel=\"All deals\" />\n <ListFilterChips\n fields={DEAL_GRID_FILTER_FIELDS}\n headers={DEAL_GRID_FILTER_HEADERS}\n clauses={viewFilters}\n onChange={views.setFilters}\n options={filterOptions}\n marksServed={false}\n />\n </CrmListToolbar>\n <ListQueryNotices refused={refused} notices={paged.plan.notices} />\n <>\n <DealsBulkBar\n hostId={hostId}\n scope={scope.scope}\n rows={tableRows}\n selected={selectedIds}\n onSelectedChange={setSelectedIds}\n pipelineById={pipelineState.pipelineById}\n roster={roster}\n api={api}\n />\n <CrmColumnOrderProvider value={grid.columnOrder}>\n <ListTable\n rows={tableRows}\n columns={grid.columns}\n slots={CRM_LIST_SLOTS}\n selectable={{ selected: selectedIds, onChange: setSelectedIds }}\n onOpen={(_id, row) => openDeal(row as DealDoc)}\n // The panel and the search are the query's (AGL-3321).\n filterMode=\"server\"\n filterModel={gridFilter.filterModel}\n onFilterModelChange={gridFilter.onFilterModelChange}\n quickFilter\n loading={paged.status === 'loading'}\n // An empty table is said inside the grid, so its toolbar\n // stays to change the status that emptied it.\n noRowsLabel={\n searching\n ? `No deals match “${searchKey.trim()}”`\n : statusFilter === 'all'\n ? 'No deals yet'\n : `No ${statusFilter} deals`\n }\n noRowsDescription={\n statusFilter === 'all' && !searching\n ? 'A deal is a sale in progress, moved across the pipeline as it advances.'\n : undefined\n }\n noRowsAction={\n statusFilter === 'all' && !searching ? (\n <Button\n size=\"small\"\n variant=\"contained\"\n startIcon={<MdiIcon path={mdiPlus.path} size={0.8} />}\n disabled={!pipeline || !scope.orgId}\n onClick={() => setCreating(true)}\n >\n {'New deal'}\n </Button>\n ) : undefined\n }\n // Columns and sort are the view's, controlled (AGL-2617).\n columnVisibilityModel={grid.columnVisibilityModel}\n onColumnVisibilityModelChange={grid.onColumnVisibilityModelChange}\n sortModel={grid.sortModel}\n onSortModelChange={grid.onSortModelChange}\n hideFooter\n />\n </CrmColumnOrderProvider>\n <ListPagination\n page={paged.page}\n pageSize={paged.pageSize}\n rowCount={paged.rows.length}\n hasMore={paged.hasMore}\n onPageChange={paged.setPage}\n onPageSizeChange={paged.setPageSize}\n />\n </>\n </Stack>\n )}\n </Stack>\n </CardDisplay>\n <DealEditDrawer\n open={creating}\n onClose={() => setCreating(false)}\n hostId={hostId}\n org={org}\n pipelines={activePipelines}\n defaultPipeline={pipeline}\n />\n <PipelinesDialog\n open={managingPipelines}\n onClose={() => setManagingPipelines(false)}\n orgId={scope.orgId ?? ''}\n // A pipeline made here is stamped the way the seeded default is\n // (`usePipeline`): the site's own tokens under a site; at the\n // organization level the org token, with the picked site as its\n // provenance (AGL-2630).\n hostId={scope.createHostId}\n pipelines={pipelineState.pipelines}\n fromCache={pipelineState.fromCache}\n unreadable={pipelineState.status === 'error'}\n visibleToTokens={scope.visibleTo}\n createTokens={scope.level === 'site' ? scope.createTokens : ORG_PIPELINE_TOKENS}\n />\n <LostReasonDialog\n open={Boolean(losing)}\n dealTitle={losing?.title ?? ''}\n onClose={() => setLosing(null)}\n onConfirm={confirmLost}\n />\n </>\n )\n}\nDealsSection.displayName = 'DealsSection'\n\n/** An optional column of a picklist field: its label, sorted in the list's order. */\nfunction picklistColumn(field: 'type' | 'leadSource', headerName: string, picklist: CrmPicklist): GridColDef {\n return {\n field,\n headerName,\n flex: 0.8,\n minWidth: 130,\n valueGetter: (_value: unknown, row: DealDoc) => String(row[field] ?? ''),\n sortComparator: (a: string, b: string) =>\n crmPicklistRank(picklist, a) - crmPicklistRank(picklist, b) || a.localeCompare(b),\n }\n}\n\nfunction Figure(props: { label: string; value: string }) {\n return (\n <Stack sx={{ lineHeight: 1.2 }}>\n <Typography variant=\"caption\" color=\"text.secondary\">\n {props.label}\n </Typography>\n <Typography variant=\"h6\" component=\"span\">\n {props.value}\n </Typography>\n </Stack>\n )\n}\nFigure.displayName = 'Figure'\n\nexport default DealsSection\n"],"names":["CRM_COLLECTIONS","crmPicklistRank","dealStageById","ORG_SCOPE_TOKEN","pluginDocsHelp","mdiCogOutline","mdiPlus","mdiTableLarge","mdiViewColumnOutline","CardDisplay","MdiIcon","ListPagination","ListTable","ListQueryNotices","useCrmSavedView","useCrmViewGrid","CrmListActions","CrmListToolbar","CRM_LIST_SLOTS","CrmColumnOrderProvider","CRM_NEXT_ACTIVITY_FILTER_FIELD","CRM_NEXT_ACTIVITY_FILTER_HEADER","nextActivityColumn","DEAL_FILTER_CODECS","DEAL_LIST_DECLARATION","DEAL_LIST_FILTER_FIELDS","DEAL_PICKLIST_FILTER_NONE","DEAL_PREFIX_SEARCH","dealPipelineBase","dealQueryClause","useCrmFoldsScope","useCrmListQuery","useCrmPicklist","crmAskClauses","crmQueryRefusals","ListFilterChips","listFilterGridColumns","useListGridFilter","CrmViewsControl","EmptyStateComponent","useSnackbar","Alert","Button","Chip","CircularProgress","MenuItem","Stack","TextField","ToggleButton","ToggleButtonGroup","Typography","useRouter","useCallback","useEffect","useMemo","useState","useContactFieldDefinitions","useCrmScope","useDealStageApi","BOARD_CLOSED_LIMIT","BOARD_OPEN_LIMIT","useDealsByStatus","useOrgMemberDirectory","usePipeline","crmRoutes","boardSummary","DEAL_STATUS_LABELS","formatAmountByCurrency","formatMoney","customFieldColumns","DealBoard","DealEditDrawer","CrmExportButton","CrmImportButton","CRM_DEALS_RESOURCE","DealsBulkBar","LostReasonDialog","OwnerAvatar","PipelinesDialog","DEAL_GRID_FILTER_FIELDS","DEAL_GRID_FILTER_HEADERS","status","column","type","leadSource","DEAL_STATUS_FILTER_OPTIONS","map","value","label","DEAL_HIDDEN_COLUMNS","picklistFilterOptions","picklist","none","values","active","ORG_PIPELINE_TOKENS","DealsSection","props","pipelineId","scope","hostId","org","basePath","routes","router","enqueueSnackbar","pipelineState","orgId","activePipelines","setPipelineId","pipeline","find","entry","$id","roster","api","nowMs","Date","now","dealFields","typeList","leadSourceList","view","setView","closedExpanded","setClosedExpanded","views","section","statusFilter","state","filters","clause","field","viewFilters","currentId","open","visibleTo","closedPipelineId","won","lost","searchWords","setSearchWords","searching","some","word","trim","searchKey","join","foldsScope","pipelineBase","asked","paged","collection","deals","declaration","clauses","search","base","prefixSearch","enabled","Boolean","summary","data","moving","setMoving","Set","track","deal","request","done","current","add","variant","persist","error","Error","message","allowDuplicate","next","delete","handleMove","stageId","stage","moveToStage","name","handleWon","markWon","losing","setLosing","handleLost","confirmLost","reason","markLost","openDeal","push","creating","setCreating","managingPipelines","setManagingPipelines","selectedIds","setSelectedIds","plan","page","exportFilter","served","length","searched","columns","headerName","flex","minWidth","renderCell","row","withWhom","contactName","companyName","filter","sx","justifyContent","lineHeight","title","color","noWrap","valueGetter","_value","pipelineById","align","headerAlign","amountCents","currency","nameOf","ownerUid","direction","spacing","alignItems","size","expectedCloseAtMs","toLocaleDateString","picklistColumn","tableRows","rows","filterOptions","stale","known","op","flatMap","split","option","types","sources","filterColumns","grid","gridFilter","onChange","setFilters","selectFields","codecs","words","refused","fields","headers","options","noOrg","ready","pipelineLoading","seeding","header","help","anchor","contentGutterX","contentGutterY","HeaderProps","action","resource","noun","mappingZone","startIcon","path","disabled","onClick","flexWrap","rowGap","Figure","openCount","toLocaleString","valueByCurrency","weightedByCurrency","select","event","target","slotProps","exclusive","_event","aria-label","ml","severity","compact","description","onToggleClosed","labelFor","onOpen","onMove","onWon","onLost","controller","allLabel","marksServed","notices","selected","onSelectedChange","columnOrder","slots","selectable","_id","filterMode","filterModel","onFilterModelChange","quickFilter","loading","noRowsLabel","noRowsDescription","undefined","noRowsAction","columnVisibilityModel","onColumnVisibilityModelChange","sortModel","onSortModelChange","hideFooter","pageSize","rowCount","hasMore","onPageChange","setPage","onPageSizeChange","setPageSize","onClose","pipelines","defaultPipeline","createHostId","fromCache","unreadable","visibleToTokens","createTokens","level","dealTitle","onConfirm","displayName","String","sortComparator","a","b","localeCompare","component"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/crm/src/lib/components/deals-section.tsx"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n'use client'\n\nimport {\n type ConsolePluginPageProps,\n type CrmDealStatus,\n type CrmPicklist,\n CRM_COLLECTIONS,\n crmPicklistRank,\n dealStageById,\n ORG_SCOPE_TOKEN,\n pluginDocsHelp,\n} from '@aglyn/aglyn'\nimport {\n mdiCogOutline,\n mdiPlus,\n mdiTableLarge,\n mdiViewColumnOutline,\n} from '@aglyn/shared-data-mdi'\nimport { CardDisplay, MdiIcon } from '@aglyn/shared-ui-jsx'\nimport { ListPagination } from '@aglyn/shared-ui-jsx/components/list-pagination.component'\nimport { ListTable } from '@aglyn/shared-ui-jsx/components/list-table.component'\nimport ListQueryNotices from '@aglyn/shared-ui-jsx/components/list-query-notices.component'\nimport { useCrmSavedView } from '../hooks/use-crm-saved-view'\nimport { useCrmViewGrid } from '../hooks/use-crm-view-grid'\nimport { CrmListActions, CrmListToolbar } from './crm-list-toolbar'\nimport { CRM_LIST_SLOTS, CrmColumnOrderProvider } from './crm-column-menu'\nimport {\n CRM_NEXT_ACTIVITY_FILTER_FIELD,\n CRM_NEXT_ACTIVITY_FILTER_HEADER,\n nextActivityColumn,\n} from './crm-next-activity-column'\nimport {\n DEAL_FILTER_CODECS,\n DEAL_LIST_DECLARATION,\n DEAL_LIST_FILTER_FIELDS,\n DEAL_PICKLIST_FILTER_NONE,\n DEAL_PREFIX_SEARCH,\n dealPipelineBase,\n dealQueryClause,\n} from '../constants/deal-filters'\nimport { useCrmFoldsScope, useCrmListQuery } from '../hooks/use-crm-list-query'\nimport { useCrmPicklist } from '../hooks/use-crm-picklist'\nimport { crmAskClauses, crmQueryRefusals } from '../model/crm-list-query'\nimport ListFilterChips from '@aglyn/shared-ui-jsx/components/list-filter-chips.component'\nimport {\n type ListFilterOption,\n listFilterGridColumns,\n} from '@aglyn/shared-ui-jsx/const/list-grid-filter'\nimport { useListGridFilter } from '@aglyn/shared-ui-jsx/hooks/use-list-grid-filter'\nimport CrmViewsControl from './crm-views-control'\nimport EmptyStateComponent from '@aglyn/shared-ui-jsx/components/empty-state.component'\nimport { useSnackbar } from '@aglyn/shared-ui-snackstack'\nimport {\n Alert,\n Button,\n Chip,\n CircularProgress,\n MenuItem,\n Stack,\n TextField,\n ToggleButton,\n ToggleButtonGroup,\n Typography,\n} from '@mui/material'\nimport type { GridColDef } from '@mui/x-data-grid'\nimport { useRouter } from 'next/navigation'\nimport { useCallback, useEffect, useMemo, useState } from 'react'\nimport { useContactFieldDefinitions } from '../hooks/use-contact-field-definitions'\nimport { useCrmScope } from '../hooks/use-crm-scope'\nimport { useDealStageApi } from '../hooks/use-deal-stage-api'\nimport {\n BOARD_CLOSED_LIMIT,\n BOARD_OPEN_LIMIT,\n useDealsByStatus,\n} from '../hooks/use-deals'\nimport { useOrgMemberDirectory } from '../hooks/use-org-member-directory'\nimport { usePipeline } from '../hooks/use-pipeline'\nimport { crmRoutes } from '../model/crm-routes'\nimport {\n boardSummary,\n DEAL_STATUS_LABELS,\n type DealDoc,\n formatAmountByCurrency,\n formatMoney,\n} from '../model/deal-board-model'\nimport { customFieldColumns } from './contact-custom-columns'\nimport { DealBoard } from './deal-board'\nimport { DealEditDrawer } from './deal-edit-drawer'\nimport { CrmExportButton, CrmImportButton } from './crm-transfer-buttons'\nimport { CRM_DEALS_RESOURCE } from '../transfer/fields'\nimport DealsBulkBar from './deals-bulk-bar'\nimport { LostReasonDialog } from './lost-reason-dialog'\nimport { OwnerAvatar } from './owner-avatar'\nimport { PipelinesDialog } from './pipelines-dialog'\n\ntype View = 'board' | 'table'\ntype StatusFilter = CrmDealStatus | 'all'\n\n/** What the deals table's panel offers: the status, \"No next activity\", the Type and the Lead source. */\nconst DEAL_GRID_FILTER_FIELDS = DEAL_LIST_FILTER_FIELDS\nconst DEAL_GRID_FILTER_HEADERS: Readonly<Record<string, string>> = {\n status: 'Status',\n [CRM_NEXT_ACTIVITY_FILTER_FIELD.column]: CRM_NEXT_ACTIVITY_FILTER_HEADER,\n type: 'Type',\n leadSource: 'Lead source',\n}\nconst DEAL_STATUS_FILTER_OPTIONS = (['open', 'won', 'lost'] as const).map((value) => ({\n value,\n label: DEAL_STATUS_LABELS[value],\n}))\n\n/** Salesforce's Type and Lead source columns are offered, not shown, until a view turns them on (AGL-3516). */\nconst DEAL_HIDDEN_COLUMNS: Readonly<Record<string, boolean>> = { type: false, leadSource: false }\n\n/** A picklist's choices for its filter: every value the org keeps, inactive ones marked, then \"none\". */\nfunction picklistFilterOptions(picklist: CrmPicklist, none: string): ListFilterOption[] {\n return [\n ...picklist.values.map((value) => ({\n value: value.label,\n label: value.active ? value.label : `${value.label} (inactive)`,\n })),\n { value: DEAL_PICKLIST_FILTER_NONE, label: none },\n ]\n}\n\n\n/** What a pipeline made at the organization level is stamped with — the org's own token. */\nconst ORG_PIPELINE_TOKENS: readonly string[] = [ORG_SCOPE_TOKEN]\n\n/**\n * `/crm/deals` — the pipeline (AGL-2598).\n *\n * ## Two views of one pipeline\n *\n * The BOARD is one pipeline's open deals, one column per open stage, read\n * in one bounded listener over `(visibleTo, pipelineId, status, updatedAt)`\n * and sorted into columns here — a listener per column would be five\n * subscriptions for one board. The TABLE is the same pipeline's deals,\n * paged by a query that carries its status, \"No next activity\" and search\n * word (AGL-3321); it is where the closed history is found. The three figures above both come from the board's read, so\n * they describe what is in play whichever view is showing.\n *\n * ## Which pipeline\n *\n * The switcher in the header (AGL-2620) picks among the ACTIVE pipelines\n * and opens on the default; the board, the table, the figures and the New\n * deal drawer all follow it. It is section state rather than a route: a\n * pipeline is a lens on the section, and a saved view that names one\n * composes with it. **Pipelines** opens the dialog that creates, renames,\n * defaults, archives and — through it — edits the stages of each.\n *\n * ## Every move goes through the route\n *\n * A drag, a card's \"Move to\", \"Mark won\" and \"Mark lost\" all end in\n * `useDealStageApi`, never a Firestore write: the stage is the fact the\n * automations listen for, and only the server emits the event. The section\n * marks the card pending while the request runs and lets the listener land\n * it — see `DealBoard` for why a move is not applied optimistically.\n *\n * ## Creation is a button\n *\n * \"New deal\" opens a drawer; there is no form above the list. The drawer\n * writes client-direct against the rules, stamped with this console's scope.\n *\n * ## The table selects and exports (AGL-2621)\n *\n * The table's rows are selectable, and a selection raises `DealsBulkBar`\n * over it — whose stage moves go through the same `useDealStageApi` as a\n * drag. Import and Export open the console's import wizard and export\n * dialog on `crm.deals` (AGL-3528): the export over the selection, the\n * list's own query, or every deal.\n */\nexport function DealsSection(props: ConsolePluginPageProps) {\n const { hostId, org, basePath } = props\n const routes = crmRoutes(basePath ?? '')\n const router = useRouter()\n const { enqueueSnackbar } = useSnackbar()\n const scope = useCrmScope({ hostId, org })\n const pipelineState = usePipeline(scope.orgId, {\n hostId,\n org: (org ?? null) as Record<string, unknown> | null,\n })\n const { activePipelines } = pipelineState\n const [pipelineId, setPipelineId] = useState<string | null>(null)\n // The chosen pipeline while it is still active; else the default. A\n // pipeline archived from another tab falls back rather than leaving the\n // board on a pipeline the picker no longer lists.\n const pipeline =\n (pipelineId ? activePipelines.find((entry) => entry.$id === pipelineId) : null) ??\n pipelineState.pipeline\n const roster = useOrgMemberDirectory(scope.orgId)\n const api = useDealStageApi(hostId)\n const nowMs = useMemo(() => Date.now(), [])\n // The org's deal fields, for the table's optional columns (AGL-2661).\n const dealFields = useContactFieldDefinitions(scope.orgId, 'deal')\n // Salesforce's Type and Lead source lists, for their columns and filters (AGL-3516).\n const typeList = useCrmPicklist('opportunityType', scope.orgId)\n const leadSourceList = useCrmPicklist('leadSource', scope.orgId)\n\n const [view, setView] = useState<View>('board')\n const [closedExpanded, setClosedExpanded] = useState(false)\n /*\n * The table's status filter is the saved VIEW'S (AGL-2617): a view of\n * deals is a view of the table, and it holds the status beside the\n * columns and the sort. Opening one shows the table, because the board\n * has no columns to arrange and answers to the pipeline's stages alone.\n */\n const views = useCrmSavedView({\n section: 'deals',\n hostId,\n org,\n basePath: basePath ?? '',\n })\n const statusFilter: StatusFilter = useMemo(() => {\n const value = views.state.filters.find((clause) => clause.field === 'status')?.value\n return value === 'open' || value === 'won' || value === 'lost' ? value : 'all'\n }, [views.state.filters])\n // Every clause is the query's, the status and \"No next activity\" alike.\n const viewFilters = views.state.filters\n useEffect(() => {\n if (views.currentId) setView('table')\n }, [views.currentId])\n\n // The board's read stays on in the table view too: it is what the summary\n // above both views is computed from, and it is already bounded.\n const open = useDealsByStatus(\n scope.orgId,\n scope.visibleTo,\n pipeline?.$id ?? null,\n 'open',\n BOARD_OPEN_LIMIT,\n )\n const closedPipelineId =\n view === 'board' && closedExpanded ? (pipeline?.$id ?? null) : null\n const won = useDealsByStatus(scope.orgId, scope.visibleTo, closedPipelineId, 'won', BOARD_CLOSED_LIMIT)\n const lost = useDealsByStatus(scope.orgId, scope.visibleTo, closedPipelineId, 'lost', BOARD_CLOSED_LIMIT)\n /*\n * THE TABLE (AGL-3321): the pipeline's deals, every clause and the search\n * word on one query — the search reads the title's word prefixes every\n * deal writer stamps, so a deal on page four is found by any word of its\n * title — paged by that query, and read only while the table is showing.\n */\n const [searchWords, setSearchWords] = useState<string[]>([])\n const searching = searchWords.some((word) => word.trim())\n const searchKey = searchWords.join(' ')\n const foldsScope = useCrmFoldsScope(scope.orgId, scope.visibleTo)\n const pipelineBase = useMemo(() => dealPipelineBase(pipeline?.$id ?? null), [pipeline?.$id])\n // Each stored clause asked through the field its writer keeps — a Type\n // or a Lead source by its key (AGL-3516).\n const asked = useMemo(() => crmAskClauses(viewFilters, dealQueryClause), [viewFilters])\n const paged = useCrmListQuery<DealDoc>({\n scope: scope.scope,\n collection: CRM_COLLECTIONS.deals,\n visibleTo: scope.visibleTo,\n foldsScope,\n declaration: DEAL_LIST_DECLARATION,\n clauses: asked.clauses,\n search: searchWords,\n base: pipelineBase,\n prefixSearch: DEAL_PREFIX_SEARCH,\n enabled: view === 'table' && Boolean(pipeline),\n })\n\n const summary = useMemo(() => boardSummary(open.data, pipeline), [open.data, pipeline])\n\n /*\n * MOVES IN FLIGHT. A card in this set is dimmed and cannot be dragged\n * again until the route answers; the listener is what moves it.\n */\n const [moving, setMoving] = useState<ReadonlySet<string>>(() => new Set())\n const track = useCallback(\n async (deal: DealDoc, request: () => Promise<unknown>, done: string) => {\n setMoving((current) => new Set(current).add(deal.$id))\n try {\n await request()\n enqueueSnackbar(done, { variant: 'success', persist: false })\n return true\n } catch (error) {\n enqueueSnackbar(\n error instanceof Error ? error.message : 'The deal could not be moved.',\n { variant: 'warning', allowDuplicate: true },\n )\n return false\n } finally {\n setMoving((current) => {\n const next = new Set(current)\n next.delete(deal.$id)\n return next\n })\n }\n },\n [enqueueSnackbar],\n )\n const handleMove = useCallback(\n (deal: DealDoc, stageId: string) => {\n const stage = dealStageById(pipeline, stageId)\n void track(\n deal,\n () => api.moveToStage(deal, stageId),\n `Moved to ${stage?.name ?? 'stage'}`,\n )\n },\n [api, pipeline, track],\n )\n const handleWon = useCallback(\n (deal: DealDoc) => void track(deal, () => api.markWon(deal), 'Deal won'),\n [api, track],\n )\n const [losing, setLosing] = useState<DealDoc | null>(null)\n const handleLost = useCallback((deal: DealDoc) => setLosing(deal), [])\n const confirmLost = useCallback(\n (reason: string) => {\n const deal = losing\n if (!deal) return\n setLosing(null)\n void track(deal, () => api.markLost(deal, reason), 'Deal marked lost')\n },\n [api, losing, track],\n )\n\n const openDeal = useCallback(\n (deal: DealDoc) => router.push(routes.deal(deal.$id)),\n [router, routes],\n )\n\n const [creating, setCreating] = useState(false)\n const [managingPipelines, setManagingPipelines] = useState(false)\n\n const [selectedIds, setSelectedIds] = useState<string[]>([])\n // A page or a status is a different set of rows; a selection made on\n // the last one would be a count over rows no longer on screen.\n useEffect(() => setSelectedIds([]), [paged.plan, paged.page])\n // The list's filter, when one narrows it, for the export to read the same\n // records the list does (AGL-3528).\n const exportFilter = useMemo(\n () => (paged.plan.served.length || paged.plan.searched ? { label: 'what the list shows', plan: paged.plan } : null),\n [paged.plan],\n )\n\n const columns: GridColDef[] = useMemo(\n () => [\n {\n field: 'title',\n headerName: 'Deal',\n flex: 1.6,\n minWidth: 220,\n renderCell: ({ row }: { row: DealDoc }) => {\n const withWhom = [row.contactName, row.companyName].filter(Boolean).join(' · ')\n return (\n <Stack sx={{ justifyContent: 'center', lineHeight: 1.25 }}>\n <Typography variant=\"body2\" sx={{ lineHeight: 1.25 }}>\n {row.title || 'Untitled deal'}\n </Typography>\n {withWhom ? (\n <Typography variant=\"caption\" color=\"text.secondary\" noWrap sx={{ lineHeight: 1.25 }}>\n {withWhom}\n </Typography>\n ) : null}\n </Stack>\n )\n },\n },\n {\n field: 'stageId',\n headerName: 'Stage',\n flex: 0.9,\n minWidth: 140,\n valueGetter: (_value: unknown, row: DealDoc) =>\n dealStageById(pipelineState.pipelineById(row.pipelineId), row.stageId)?.name ??\n row.stageId,\n },\n {\n field: 'amountCents',\n headerName: 'Amount',\n flex: 0.8,\n minWidth: 120,\n align: 'right',\n headerAlign: 'right',\n valueGetter: (_value: unknown, row: DealDoc) => row.amountCents ?? null,\n renderCell: ({ row }: { row: DealDoc }) =>\n typeof row.amountCents === 'number' ? formatMoney(row.amountCents, row.currency) : '—',\n },\n {\n field: 'ownerUid',\n headerName: 'Owner',\n flex: 0.9,\n minWidth: 140,\n valueGetter: (_value: unknown, row: DealDoc) => roster.nameOf(row.ownerUid),\n renderCell: ({ row }: { row: DealDoc }) => {\n const label = roster.nameOf(row.ownerUid)\n return label ? (\n <Stack direction=\"row\" spacing={1} sx={{ alignItems: 'center' }}>\n <OwnerAvatar label={label} size={22} />\n <Typography variant=\"body2\" noWrap>\n {label}\n </Typography>\n </Stack>\n ) : (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'—'}\n </Typography>\n )\n },\n },\n {\n field: 'expectedCloseAtMs',\n headerName: 'Expected close',\n flex: 0.8,\n minWidth: 130,\n type: 'date',\n valueGetter: (_value: unknown, row: DealDoc) =>\n typeof row.expectedCloseAtMs === 'number' ? new Date(row.expectedCloseAtMs) : null,\n renderCell: ({ row }: { row: DealDoc }) =>\n typeof row.expectedCloseAtMs === 'number'\n ? new Date(row.expectedCloseAtMs).toLocaleDateString()\n : '—',\n },\n {\n field: 'status',\n headerName: 'Status',\n flex: 0.6,\n minWidth: 100,\n renderCell: ({ row }: { row: DealDoc }) => (\n <Chip\n size=\"small\"\n label={DEAL_STATUS_LABELS[row.status] ?? row.status}\n color={row.status === 'won' ? 'success' : row.status === 'lost' ? 'default' : 'primary'}\n variant={row.status === 'open' ? 'outlined' : 'filled'}\n />\n ),\n },\n // When the earliest open task against the deal is due (AGL-2661).\n nextActivityColumn(nowMs),\n // Salesforce's Type and Lead source, optional, in their lists' order (AGL-3516).\n picklistColumn('type', 'Type', typeList.picklist),\n picklistColumn('leadSource', 'Lead source', leadSourceList.picklist),\n // The org's deal fields as optional columns (AGL-2661).\n ...customFieldColumns(dealFields.active),\n ],\n [pipelineState, roster, dealFields.active, nowMs, typeList.picklist, leadSourceList.picklist],\n )\n /** The table's rows: the query's page. */\n const tableRows = paged.rows\n /*\n * The table's column and sort models are the view's (AGL-2617); its\n * filters are the grid's own panel over the view's clauses (AGL-3313),\n * every one of them asked of the query (AGL-3321).\n */\n /*\n * The choices each select column offers. A stored clause naming a value\n * no longer listed stays a choice, so the panel can show it and clear it.\n */\n const filterOptions = useMemo<Record<string, ListFilterOption[]>>(() => {\n const stale = (field: string, known: readonly { value: string }[]) =>\n viewFilters\n .filter((clause) => clause.field === field && clause.op !== 'isEmpty')\n .flatMap((clause) => clause.value.split(','))\n .map((value) => value.trim())\n .filter((value) => value && !known.some((option) => option.value === value))\n .map((value) => ({ value, label: value }))\n const types = picklistFilterOptions(typeList.picklist, 'No type')\n const sources = picklistFilterOptions(leadSourceList.picklist, 'No lead source')\n return {\n status: DEAL_STATUS_FILTER_OPTIONS,\n type: [...types, ...stale('type', types)],\n leadSource: [...sources, ...stale('leadSource', sources)],\n }\n }, [viewFilters, typeList.picklist, leadSourceList.picklist])\n const filterColumns = useMemo(\n () => listFilterGridColumns(columns, DEAL_GRID_FILTER_FIELDS, filterOptions, DEAL_GRID_FILTER_HEADERS),\n [columns, filterOptions],\n )\n const grid = useCrmViewGrid(views, filterColumns, DEAL_HIDDEN_COLUMNS)\n const gridFilter = useListGridFilter({\n clauses: viewFilters,\n onChange: views.setFilters,\n selectFields: ['status', 'type', 'leadSource'],\n codecs: DEAL_FILTER_CODECS,\n search: { words: searchWords, onChange: setSearchWords },\n })\n // What the query could not hold, named by the clause the reader set.\n const refused = useMemo(\n () =>\n crmQueryRefusals(paged.plan, asked, {\n fields: DEAL_GRID_FILTER_FIELDS,\n headers: DEAL_GRID_FILTER_HEADERS,\n options: filterOptions,\n }),\n [paged.plan, asked, filterOptions],\n )\n\n const noOrg = scope.ready && !scope.orgId\n const pipelineLoading =\n !noOrg && (pipelineState.status === 'loading' || pipelineState.seeding || (!pipeline && pipelineState.status !== 'error'))\n\n return (\n <>\n <CardDisplay\n header={'Deals'}\n help={pluginDocsHelp('deals', { anchor: '#the-board-and-the-table' })}\n contentGutterX\n contentGutterY\n HeaderProps={{\n // The record actions, top right and never clipped (AGL-3311).\n action: (\n <CrmListActions>\n <CrmImportButton resource={CRM_DEALS_RESOURCE} noun=\"deals\" hostId={hostId} mappingZone=\"deals\" />\n <CrmExportButton resource={CRM_DEALS_RESOURCE} hostId={hostId} filter={exportFilter} />\n <Button\n size=\"small\"\n startIcon={<MdiIcon path={mdiCogOutline.path} size={0.8} />}\n disabled={!scope.orgId || pipelineState.status === 'loading'}\n onClick={() => setManagingPipelines(true)}\n >\n {'Pipelines'}\n </Button>\n <Button\n size=\"small\"\n variant=\"contained\"\n startIcon={<MdiIcon path={mdiPlus.path} size={0.8} />}\n disabled={!pipeline || !scope.orgId}\n onClick={() => setCreating(true)}\n >\n {'New deal'}\n </Button>\n </CrmListActions>\n ),\n }}\n >\n <Stack spacing={2}>\n <Stack\n useFlexGap\n direction=\"row\"\n spacing={3}\n sx={{ alignItems: 'flex-end', flexWrap: 'wrap', rowGap: 1 }}\n >\n <Figure label=\"Open deals\" value={summary.openCount.toLocaleString()} />\n <Figure label=\"Pipeline value\" value={formatAmountByCurrency(summary.valueByCurrency)} />\n <Figure label=\"Weighted value\" value={formatAmountByCurrency(summary.weightedByCurrency)} />\n <Stack sx={{ flex: 1 }} />\n {/* Which pipeline the board and table show, above them rather than under (AGL-3311). */}\n {activePipelines.length > 1 ? (\n <TextField\n select\n size=\"small\"\n label=\"Pipeline\"\n value={pipeline?.$id ?? ''}\n onChange={(event) => setPipelineId(event.target.value)}\n sx={{ minWidth: 160 }}\n slotProps={{ select: { 'aria-label': 'Pipeline' } }}\n >\n {activePipelines.map((entry) => (\n <MenuItem key={entry.$id} value={entry.$id}>\n {entry.name}\n </MenuItem>\n ))}\n </TextField>\n ) : null}\n <ToggleButtonGroup\n exclusive\n size=\"small\"\n color=\"primary\"\n value={view}\n onChange={(_event, next) => {\n if (next) setView(next as View)\n }}\n aria-label=\"View\"\n >\n <ToggleButton value=\"board\" aria-label=\"Board\">\n <MdiIcon path={mdiViewColumnOutline.path} size={0.8} />\n <Typography variant=\"button\" sx={{ ml: 0.5 }}>\n {'Board'}\n </Typography>\n </ToggleButton>\n <ToggleButton value=\"table\" aria-label=\"Table\">\n <MdiIcon path={mdiTableLarge.path} size={0.8} />\n <Typography variant=\"button\" sx={{ ml: 0.5 }}>\n {'Table'}\n </Typography>\n </ToggleButton>\n </ToggleButtonGroup>\n </Stack>\n\n {noOrg ? (\n <Alert severity=\"info\">\n {'This site has no organization, so it has no pipeline.'}\n </Alert>\n ) : pipelineState.status === 'error' ? (\n <Alert severity=\"warning\">\n {'The pipeline could not be read. Deals need the \"Manage data\" permission.'}\n </Alert>\n ) : pipelineLoading ? (\n <Stack direction=\"row\" spacing={1} sx={{ alignItems: 'center' }}>\n <CircularProgress size={18} />\n <Typography variant=\"body2\" color=\"text.secondary\">\n {pipelineState.seeding ? 'Setting up your Sales pipeline…' : 'Loading the pipeline…'}\n </Typography>\n </Stack>\n ) : view === 'board' && pipeline ? (\n <>\n {open.status === 'success' && open.data.length === 0 ? (\n <EmptyStateComponent\n compact\n label={'No open deals yet'}\n description={'A deal is a sale in progress, moved across the stages below as it advances.'}\n action={\n <Button\n size=\"small\"\n variant=\"contained\"\n startIcon={<MdiIcon path={mdiPlus.path} size={0.8} />}\n disabled={!pipeline || !scope.orgId}\n onClick={() => setCreating(true)}\n >\n {'New deal'}\n </Button>\n }\n />\n ) : null}\n <DealBoard\n pipeline={pipeline}\n deals={open.data}\n won={closedExpanded && won.status !== 'loading' ? won.data : null}\n lost={closedExpanded && lost.status !== 'loading' ? lost.data : null}\n closedExpanded={closedExpanded}\n onToggleClosed={() => setClosedExpanded((current) => !current)}\n labelFor={roster.nameOf}\n moving={moving}\n onOpen={openDeal}\n onMove={handleMove}\n onWon={handleWon}\n onLost={handleLost}\n nowMs={nowMs}\n />\n </>\n ) : (\n <Stack spacing={1.5}>\n {/*\n The view this table is showing, and the clauses narrowing it\n as chips (AGL-2617, AGL-3313). Status and \"No next activity\"\n are set in the grid's own Filters panel.\n */}\n <CrmListToolbar label=\"Deal filters\">\n <CrmViewsControl controller={views} allLabel=\"All deals\" />\n <ListFilterChips\n fields={DEAL_GRID_FILTER_FIELDS}\n headers={DEAL_GRID_FILTER_HEADERS}\n clauses={viewFilters}\n onChange={views.setFilters}\n options={filterOptions}\n marksServed={false}\n />\n </CrmListToolbar>\n <ListQueryNotices refused={refused} notices={paged.plan.notices} />\n <>\n <DealsBulkBar\n hostId={hostId}\n scope={scope.scope}\n rows={tableRows}\n selected={selectedIds}\n onSelectedChange={setSelectedIds}\n pipelineById={pipelineState.pipelineById}\n roster={roster}\n api={api}\n />\n <CrmColumnOrderProvider value={grid.columnOrder}>\n <ListTable\n rows={tableRows}\n columns={grid.columns}\n slots={CRM_LIST_SLOTS}\n selectable={{ selected: selectedIds, onChange: setSelectedIds }}\n onOpen={(_id, row) => openDeal(row as DealDoc)}\n // The panel and the search are the query's (AGL-3321).\n filterMode=\"server\"\n filterModel={gridFilter.filterModel}\n onFilterModelChange={gridFilter.onFilterModelChange}\n quickFilter\n loading={paged.status === 'loading'}\n // An empty table is said inside the grid, so its toolbar\n // stays to change the status that emptied it.\n noRowsLabel={\n searching\n ? `No deals match “${searchKey.trim()}”`\n : statusFilter === 'all'\n ? 'No deals yet'\n : `No ${statusFilter} deals`\n }\n noRowsDescription={\n statusFilter === 'all' && !searching\n ? 'A deal is a sale in progress, moved across the pipeline as it advances.'\n : undefined\n }\n noRowsAction={\n statusFilter === 'all' && !searching ? (\n <Button\n size=\"small\"\n variant=\"contained\"\n startIcon={<MdiIcon path={mdiPlus.path} size={0.8} />}\n disabled={!pipeline || !scope.orgId}\n onClick={() => setCreating(true)}\n >\n {'New deal'}\n </Button>\n ) : undefined\n }\n // Columns and sort are the view's, controlled (AGL-2617).\n columnVisibilityModel={grid.columnVisibilityModel}\n onColumnVisibilityModelChange={grid.onColumnVisibilityModelChange}\n sortModel={grid.sortModel}\n onSortModelChange={grid.onSortModelChange}\n hideFooter\n />\n </CrmColumnOrderProvider>\n <ListPagination\n page={paged.page}\n pageSize={paged.pageSize}\n rowCount={paged.rows.length}\n hasMore={paged.hasMore}\n onPageChange={paged.setPage}\n onPageSizeChange={paged.setPageSize}\n />\n </>\n </Stack>\n )}\n </Stack>\n </CardDisplay>\n <DealEditDrawer\n open={creating}\n onClose={() => setCreating(false)}\n hostId={hostId}\n org={org}\n pipelines={activePipelines}\n defaultPipeline={pipeline}\n />\n <PipelinesDialog\n open={managingPipelines}\n onClose={() => setManagingPipelines(false)}\n orgId={scope.orgId ?? ''}\n // A pipeline made here is stamped the way the seeded default is\n // (`usePipeline`): the site's own tokens under a site; at the\n // organization level the org token, with the picked site as its\n // provenance (AGL-2630).\n hostId={scope.createHostId}\n pipelines={pipelineState.pipelines}\n fromCache={pipelineState.fromCache}\n unreadable={pipelineState.status === 'error'}\n visibleToTokens={scope.visibleTo}\n createTokens={scope.level === 'site' ? scope.createTokens : ORG_PIPELINE_TOKENS}\n />\n <LostReasonDialog\n open={Boolean(losing)}\n dealTitle={losing?.title ?? ''}\n onClose={() => setLosing(null)}\n onConfirm={confirmLost}\n />\n </>\n )\n}\nDealsSection.displayName = 'DealsSection'\n\n/** An optional column of a picklist field: its label, sorted in the list's order. */\nfunction picklistColumn(field: 'type' | 'leadSource', headerName: string, picklist: CrmPicklist): GridColDef {\n return {\n field,\n headerName,\n flex: 0.8,\n minWidth: 130,\n valueGetter: (_value: unknown, row: DealDoc) => String(row[field] ?? ''),\n sortComparator: (a: string, b: string) =>\n crmPicklistRank(picklist, a) - crmPicklistRank(picklist, b) || a.localeCompare(b),\n }\n}\n\nfunction Figure(props: { label: string; value: string }) {\n return (\n <Stack sx={{ lineHeight: 1.2 }}>\n <Typography variant=\"caption\" color=\"text.secondary\">\n {props.label}\n </Typography>\n <Typography variant=\"h6\" component=\"span\">\n {props.value}\n </Typography>\n </Stack>\n )\n}\nFigure.displayName = 'Figure'\n\nexport default DealsSection\n"],"names":["CRM_COLLECTIONS","crmPicklistRank","dealStageById","ORG_SCOPE_TOKEN","pluginDocsHelp","mdiCogOutline","mdiPlus","mdiTableLarge","mdiViewColumnOutline","CardDisplay","MdiIcon","ListPagination","ListTable","ListQueryNotices","useCrmSavedView","useCrmViewGrid","CrmListActions","CrmListToolbar","CRM_LIST_SLOTS","CrmColumnOrderProvider","CRM_NEXT_ACTIVITY_FILTER_FIELD","CRM_NEXT_ACTIVITY_FILTER_HEADER","nextActivityColumn","DEAL_FILTER_CODECS","DEAL_LIST_DECLARATION","DEAL_LIST_FILTER_FIELDS","DEAL_PICKLIST_FILTER_NONE","DEAL_PREFIX_SEARCH","dealPipelineBase","dealQueryClause","useCrmFoldsScope","useCrmListQuery","useCrmPicklist","crmAskClauses","crmQueryRefusals","ListFilterChips","listFilterGridColumns","useListGridFilter","CrmViewsControl","EmptyStateComponent","useSnackbar","Alert","Button","Chip","CircularProgress","MenuItem","Stack","TextField","ToggleButton","ToggleButtonGroup","Typography","useRouter","useCallback","useEffect","useMemo","useState","useContactFieldDefinitions","useCrmScope","useDealStageApi","BOARD_CLOSED_LIMIT","BOARD_OPEN_LIMIT","useDealsByStatus","useOrgMemberDirectory","usePipeline","crmRoutes","boardSummary","DEAL_STATUS_LABELS","formatAmountByCurrency","formatMoney","customFieldColumns","DealBoard","DealEditDrawer","CrmExportButton","CrmImportButton","CRM_DEALS_RESOURCE","DealsBulkBar","LostReasonDialog","OwnerAvatar","PipelinesDialog","DEAL_GRID_FILTER_FIELDS","DEAL_GRID_FILTER_HEADERS","status","column","type","leadSource","DEAL_STATUS_FILTER_OPTIONS","map","value","label","DEAL_HIDDEN_COLUMNS","picklistFilterOptions","picklist","none","values","active","ORG_PIPELINE_TOKENS","DealsSection","props","pipelineId","scope","hostId","org","basePath","routes","router","enqueueSnackbar","pipelineState","orgId","activePipelines","setPipelineId","pipeline","find","entry","$id","roster","api","nowMs","Date","now","dealFields","typeList","leadSourceList","view","setView","closedExpanded","setClosedExpanded","views","section","statusFilter","state","filters","clause","field","viewFilters","currentId","open","visibleTo","closedPipelineId","won","lost","searchWords","setSearchWords","searching","some","word","trim","searchKey","join","foldsScope","pipelineBase","asked","paged","collection","deals","declaration","clauses","search","base","prefixSearch","enabled","Boolean","summary","data","moving","setMoving","Set","track","deal","request","done","current","add","variant","persist","error","Error","message","allowDuplicate","next","delete","handleMove","stageId","stage","moveToStage","name","handleWon","markWon","losing","setLosing","handleLost","confirmLost","reason","markLost","openDeal","push","creating","setCreating","managingPipelines","setManagingPipelines","selectedIds","setSelectedIds","plan","page","exportFilter","served","length","searched","columns","headerName","flex","minWidth","renderCell","row","withWhom","contactName","companyName","filter","sx","justifyContent","lineHeight","title","color","noWrap","valueGetter","_value","pipelineById","align","headerAlign","amountCents","currency","nameOf","ownerUid","direction","spacing","alignItems","size","expectedCloseAtMs","toLocaleDateString","picklistColumn","tableRows","rows","filterOptions","stale","known","op","flatMap","split","option","types","sources","filterColumns","grid","gridFilter","onChange","setFilters","selectFields","codecs","words","refused","fields","headers","options","noOrg","ready","pipelineLoading","seeding","header","help","anchor","contentGutterX","contentGutterY","HeaderProps","action","resource","noun","mappingZone","startIcon","path","disabled","onClick","useFlexGap","flexWrap","rowGap","Figure","openCount","toLocaleString","valueByCurrency","weightedByCurrency","select","event","target","slotProps","exclusive","_event","aria-label","ml","severity","compact","description","onToggleClosed","labelFor","onOpen","onMove","onWon","onLost","controller","allLabel","marksServed","notices","selected","onSelectedChange","columnOrder","slots","selectable","_id","filterMode","filterModel","onFilterModelChange","quickFilter","loading","noRowsLabel","noRowsDescription","undefined","noRowsAction","columnVisibilityModel","onColumnVisibilityModelChange","sortModel","onSortModelChange","hideFooter","pageSize","rowCount","hasMore","onPageChange","setPage","onPageSizeChange","setPageSize","onClose","pipelines","defaultPipeline","createHostId","fromCache","unreadable","visibleToTokens","createTokens","level","dealTitle","onConfirm","displayName","String","sortComparator","a","b","localeCompare","component"],"mappings":"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"}
@@ -256,6 +256,7 @@ const typeLabel = (type)=>{
256
256
  flex: 1,
257
257
  minWidth: 180,
258
258
  renderCell: ({ row })=>/*#__PURE__*/ _jsxs(Stack, {
259
+ useFlexGap: true,
259
260
  direction: "row",
260
261
  spacing: 1,
261
262
  sx: {
@@ -815,6 +816,9 @@ FieldsTable.displayName = 'FieldsTable';
815
816
  if (isCrmPicklistObject(next)) setTab(next);
816
817
  },
817
818
  "aria-label": "Fields by record",
819
+ variant: "scrollable",
820
+ scrollButtons: "auto",
821
+ allowScrollButtonsMobile: true,
818
822
  children: CRM_PICKLIST_OBJECTS.map((entry)=>/*#__PURE__*/ _jsx(Tab, {
819
823
  value: entry,
820
824
  label: CRM_PICKLIST_OBJECT_LABELS[entry]
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../../libs/plugins/crm/src/lib/components/fields-section.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 { CrmExportButton } from './crm-transfer-buttons'\nimport { CRM_FIELDS_RESOURCE } from '../transfer/fields'\nimport {\n CONTACT_FIELD_TYPE_LABELS,\n CONTACT_FIELD_TYPES,\n CONTACT_FIELDS_MAX_PER_ORG,\n type ConsolePluginPageProps,\n createResourceUid,\n CRM_COLLECTIONS,\n crmFieldListFields,\n type CrmFieldObject,\n CRM_PICKLIST_OBJECT_LABELS,\n CRM_PICKLIST_OBJECTS,\n type CrmPicklistId,\n type CrmPicklistObject,\n crmPicklistDefinitionsFor,\n isCrmPicklistObject,\n newResourceScopeFields,\n ORG_SCOPE_TOKEN,\n pluginDocsHelp,\n} from '@aglyn/aglyn'\nimport EmptyStateComponent from '@aglyn/shared-ui-jsx/components/empty-state.component'\nimport ListFilterChips from '@aglyn/shared-ui-jsx/components/list-filter-chips.component'\nimport ListQueryNotices, {\n listQueryRefusals,\n} from '@aglyn/shared-ui-jsx/components/list-query-notices.component'\nimport {\n ListRowActions,\n ListTable,\n listActionsColumn,\n} from '@aglyn/shared-ui-jsx/components/list-table.component'\nimport {\n mdiArchiveArrowUpOutline,\n mdiArchiveOutline,\n mdiArrowDown,\n mdiArrowUp,\n mdiDeleteOutline,\n mdiPencilOutline,\n} from '@aglyn/shared-data-mdi'\nimport {\n CardDisplay,\n MdiIcon,\n SrOnly,\n useConfirmationContext,\n} from '@aglyn/shared-ui-jsx'\nimport type { RowActionsMenuItem } from '@aglyn/shared-ui-jsx/components/row-actions-menu.component'\nimport {\n type ListFilterOption,\n listFilterGridColumns,\n} from '@aglyn/shared-ui-jsx/const/list-grid-filter'\nimport { planListQuery } from '@aglyn/shared-ui-jsx/const/list-query-plan'\nimport { useListGridFilter } from '@aglyn/shared-ui-jsx/hooks/use-list-grid-filter'\nimport { nameSearchNormalizers } from '@aglyn/aglyn/app-utils/name-search'\nimport { useSnackbar } from '@aglyn/shared-ui-snackstack'\nimport { ceilingedWindow } from '@aglyn/tenant-feature-instance/hooks/host-collection-queries'\nimport { listQueryConstraints } from '@aglyn/tenant-feature-instance/hooks/use-list-query'\nimport {\n useFirestore,\n useFirestoreCollection,\n useUser,\n writeGuardedBySeed,\n} from '@aglyn/tenant-feature-instance'\nimport {\n Button,\n Chip,\n IconButton,\n Stack,\n Tab,\n Tabs,\n Tooltip,\n Typography,\n} from '@mui/material'\nimport type { GridColDef, GridSortModel } from '@mui/x-data-grid'\nimport {\n collection,\n deleteDoc,\n doc,\n limit,\n query,\n setDoc,\n updateDoc,\n writeBatch,\n} from 'firebase/firestore'\nimport { useCallback, useMemo, useState } from 'react'\nimport {\n type ContactFieldDefinitionDoc,\n useContactFieldDefinitions,\n} from '../hooks/use-contact-field-definitions'\nimport { useCrmScope } from '../hooks/use-crm-scope'\nimport { CRM_FIELD_LIST_QUERY, crmFieldListBase } from '../constants/field-list-query'\nimport ContactFieldDrawer, { type ContactFieldDraft } from './contact-field-drawer'\nimport { PicklistValuesCard } from './picklist-values-card'\nimport { recomputeAllCrmNextActivity } from '../model/next-activity-api'\nimport { crmTaskCallScope } from '../model/task-routes'\n\nexport type ContactsFieldsSectionProps = Pick<ConsolePluginPageProps, 'hostId' | 'org'>\n\n/** What each tab says the fields are for, above its list. */\nconst OBJECT_INTRO: Record<CrmFieldObject, string> = {\n contact:\n 'The custom fields on a contact — text, number, date, choice, ' +\n 'checkbox or link. They show on every contact, as columns on the ' +\n 'list, and a form field can save into one.',\n company:\n 'The custom fields on a company. They show on every company’s page ' +\n 'and its edit form, as columns on the companies list, and a CSV ' +\n 'import can fill them.',\n deal:\n 'The custom fields on a deal. They show on every deal’s page and ' +\n 'its edit form, and as columns on the deals table.',\n lead:\n 'The custom fields on a lead. They show on every lead’s page and the ' +\n 'New lead drawer, and as columns on the leads list. They stay on the ' +\n 'lead when it converts — a contact’s fields are its own.',\n}\n\n/**\n * The Tasks tab's intro (AGL-3517): a task has standard picklists and no\n * custom fields, so the tab is its picklist cards alone.\n */\nconst TASKS_INTRO =\n 'A task’s standard picklists — its Status, Priority and Type, and the ' +\n 'subjects its title suggests. Status, Priority and Type each mean one of ' +\n 'the CRM’s own values, which reminders, due dates and automations read; ' +\n 'the labels are your organization’s. Tasks have no custom fields.'\n\n/** The noun each tab's empty state and captions use. */\nconst OBJECT_NOUN: Record<CrmFieldObject, string> = {\n contact: 'contact',\n company: 'company',\n deal: 'deal',\n lead: 'lead',\n}\n\n/** One definition as the list table draws it. */\ninterface FieldRow {\n $id: string\n label: string\n key: string\n type: string\n /** `true` or `false`, the value the Required filter picks. */\n required: 'true' | 'false'\n /** Where the stored order puts it, from zero. */\n position: number\n definition: ContactFieldDefinitionDoc\n}\n\n/** What the grid's Filters panel offers: the type and whether it is required, on the query. */\nconst FIELD_FILTER_FIELDS = CRM_FIELD_LIST_QUERY.fields\nconst FIELD_FILTER_HEADERS: Readonly<Record<string, string>> = {\n type: 'Type',\n required: 'Required',\n}\nconst FIELD_FILTER_OPTIONS: Readonly<Record<string, readonly ListFilterOption[]>> = {\n type: CONTACT_FIELD_TYPES.map((type) => ({\n value: type,\n label: CONTACT_FIELD_TYPE_LABELS[type],\n })),\n required: [\n { value: 'true', label: 'Required' },\n { value: 'false', label: 'Optional' },\n ],\n}\n\n/** Why the arrows are off while the list is not in its stored order. */\nexport const FIELD_REORDER_LOCKED_REASON = 'Clear sorting and filters to reorder'\n\nconst typeLabel = (type: unknown) =>\n CONTACT_FIELD_TYPE_LABELS[type as keyof typeof CONTACT_FIELD_TYPE_LABELS] ?? String(type ?? '')\n\ninterface FieldsTableProps {\n /** The organization whose definitions these are; `null` reads nothing. */\n orgId: string | null\n /** The tab: which record the definitions describe. */\n object: CrmFieldObject\n /** One tab's definitions, in the stored order. */\n definitions: readonly ContactFieldDefinitionDoc[]\n /** A field being written; every arrow waits for it. */\n busyId: string\n onMove: (definition: ContactFieldDefinitionDoc, direction: -1 | 1) => void\n rowActions: (definition: ContactFieldDefinitionDoc) => RowActionsMenuItem[]\n}\n\n/**\n * One tab's field definitions in the console's list table (AGL-3335): the\n * toolbar's columns, filters, export and search, sorting by Field, Key and\n * Type, and the shared footer.\n *\n * ## Order is data, not a sort\n *\n * The stored `order` is where each field appears on every record and form,\n * so the arrows that move it are kept, and are live only while the table\n * shows that order: no sort, no filter and no search. Under any of them the\n * row above a field on screen is not the field above it in the stored\n * order, and a move would land somewhere the reader cannot see; the arrows\n * say so rather than disappear.\n *\n * The panel and the search are asked of Firestore (AGL-3321): a clause or\n * a search word reads the tab's definitions that match it\n * (`CRM_FIELD_LIST_QUERY`), and never narrows the rows already on screen.\n * That answer is every match, at most `CONTACT_FIELDS_MAX_PER_ORG`, so the\n * grid sorts and pages it whole; a read that reaches the ceiling says so.\n */\nfunction FieldsTable(props: FieldsTableProps) {\n const { orgId, object, definitions, busyId, onMove, rowActions } = props\n const firestore = useFirestore()\n const gridFilter = useListGridFilter({ selectFields: ['type', 'required'] })\n const [sortModel, setSortModel] = useState<GridSortModel>([])\n const searching = gridFilter.searchWords.some((word) => word.trim() !== '')\n const reorderLocked =\n sortModel.length > 0 || gridFilter.clauses.length > 0 || searching\n\n const narrowed = gridFilter.clauses.length > 0 || searching\n const plan = useMemo(\n () =>\n planListQuery(\n CRM_FIELD_LIST_QUERY,\n {\n clauses: gridFilter.clauses,\n search: gridFilter.searchWords,\n base: crmFieldListBase(object),\n },\n nameSearchNormalizers,\n ),\n // The words are a new array each render; their text is their identity.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [object, gridFilter.clauses, gridFilter.searchWords.join(' ')],\n )\n const planKey = JSON.stringify({ filters: plan.filters, orderBy: plan.orderBy })\n /*\n * Read only while something narrows the tab. Unnarrowed, the table is the\n * shared definitions read every CRM surface already holds, in its stored\n * order — the same fields, with no second read.\n */\n const matched = useFirestoreCollection<ContactFieldDefinitionDoc>(\n () =>\n narrowed && orgId\n ? query(\n collection(firestore, 'orgs', orgId, CRM_COLLECTIONS.contactFields),\n ...listQueryConstraints(plan),\n limit(CONTACT_FIELDS_MAX_PER_ORG + 1),\n )\n : null,\n [firestore, orgId, narrowed, planKey],\n { idField: '$id' },\n )\n const answer = useMemo(\n () => ceilingedWindow(matched.data, CONTACT_FIELDS_MAX_PER_ORG),\n [matched.data],\n )\n const positions = useMemo(\n () => new Map(definitions.map((definition, position) => [definition.$id, position])),\n [definitions],\n )\n const rows = useMemo<FieldRow[]>(() => {\n const shown = narrowed\n ? [...answer.rows].sort(\n (a, b) =>\n (positions.get(a.$id) ?? Number.MAX_SAFE_INTEGER) -\n (positions.get(b.$id) ?? Number.MAX_SAFE_INTEGER),\n )\n : definitions\n return shown.map((definition) => ({\n $id: definition.$id,\n label: definition.label,\n key: definition.key,\n type: definition.type,\n required: definition.required ? 'true' : 'false',\n position: positions.get(definition.$id) ?? 0,\n definition,\n }))\n }, [narrowed, answer.rows, definitions, positions])\n const refused = useMemo(\n () =>\n listQueryRefusals(plan.refused, {\n fields: FIELD_FILTER_FIELDS,\n headers: FIELD_FILTER_HEADERS,\n options: FIELD_FILTER_OPTIONS,\n }),\n [plan.refused],\n )\n\n const columns = useMemo<GridColDef[]>(\n () =>\n listFilterGridColumns(\n [\n {\n field: 'position',\n headerName: 'Order',\n width: 132,\n sortable: false,\n filterable: false,\n hideable: false,\n disableColumnMenu: true,\n renderCell: ({ row }: { row: FieldRow }) => {\n const arrows = (\n <Stack direction=\"row\" spacing={0} sx={{ alignItems: 'center' }}>\n <Typography\n variant=\"body2\"\n color=\"text.secondary\"\n sx={{ minWidth: 24, textAlign: 'right', mr: 0.5 }}\n >\n {row.position + 1}\n </Typography>\n <IconButton\n size=\"small\"\n disabled={reorderLocked || row.position === 0 || Boolean(busyId)}\n onClick={() => onMove(row.definition, -1)}\n >\n <MdiIcon path={mdiArrowUp.path} size={0.7} />\n <SrOnly>{`Move ${row.label} up`}</SrOnly>\n </IconButton>\n <IconButton\n size=\"small\"\n disabled={\n reorderLocked || row.position === definitions.length - 1 || Boolean(busyId)\n }\n onClick={() => onMove(row.definition, 1)}\n >\n <MdiIcon path={mdiArrowDown.path} size={0.7} />\n <SrOnly>{`Move ${row.label} down`}</SrOnly>\n </IconButton>\n </Stack>\n )\n return reorderLocked ? (\n <Tooltip title={FIELD_REORDER_LOCKED_REASON}>\n {/* A disabled button emits no events; the span carries the tooltip. */}\n <span>{arrows}</span>\n </Tooltip>\n ) : (\n arrows\n )\n },\n },\n {\n field: 'label',\n headerName: 'Field',\n flex: 1,\n minWidth: 180,\n renderCell: ({ row }: { row: FieldRow }) => (\n <Stack\n direction=\"row\"\n spacing={1}\n sx={{ flexWrap: 'wrap', alignItems: 'center' }}\n >\n <Typography variant=\"body2\">{row.label}</Typography>\n {row.definition.retiredAt ? (\n <Chip size=\"small\" variant=\"outlined\" color=\"warning\" label=\"Retired\" />\n ) : null}\n </Stack>\n ),\n },\n {\n field: 'key',\n headerName: 'Key',\n flex: 1,\n minWidth: 160,\n renderCell: ({ row }: { row: FieldRow }) => (\n <Typography\n variant=\"body2\"\n color=\"text.secondary\"\n sx={{ fontFamily: 'monospace' }}\n >\n {row.key}\n </Typography>\n ),\n },\n {\n field: 'type',\n headerName: 'Type',\n width: 170,\n // By what the type reads as, not by its stored key.\n sortComparator: (a: unknown, b: unknown) =>\n typeLabel(a).localeCompare(typeLabel(b)),\n renderCell: ({ row }: { row: FieldRow }) => (\n <Typography variant=\"body2\">\n {typeLabel(row.type)}\n {row.definition.type === 'select' && row.definition.options?.length\n ? ` · ${row.definition.options.length} choices`\n : ''}\n </Typography>\n ),\n },\n {\n field: 'required',\n headerName: 'Required',\n width: 120,\n sortable: false,\n renderCell: ({ row }: { row: FieldRow }) => (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {row.required === 'true' ? 'Yes' : '—'}\n </Typography>\n ),\n },\n listActionsColumn(\n (row: FieldRow) => (\n <ListRowActions label={row.label} items={rowActions(row.definition)} />\n ),\n { width: 72 },\n ),\n ],\n FIELD_FILTER_FIELDS,\n FIELD_FILTER_OPTIONS,\n FIELD_FILTER_HEADERS,\n ),\n [reorderLocked, busyId, onMove, rowActions, definitions.length],\n )\n\n return (\n <Stack spacing={1}>\n <ListFilterChips\n fields={FIELD_FILTER_FIELDS}\n headers={FIELD_FILTER_HEADERS}\n clauses={gridFilter.clauses}\n onChange={gridFilter.setClauses}\n options={FIELD_FILTER_OPTIONS}\n marksServed={false}\n />\n <ListQueryNotices refused={refused} notices={plan.notices} />\n {narrowed && answer.truncated ? (\n <Typography variant=\"caption\" color=\"text.secondary\">\n {`Showing the first ${CONTACT_FIELDS_MAX_PER_ORG} matching fields.`}\n </Typography>\n ) : null}\n <ListTable\n aria-label=\"Fields\"\n rows={rows}\n loading={narrowed && matched.status === 'loading'}\n columns={columns}\n sortModel={sortModel}\n onSortModelChange={setSortModel}\n // Firestore narrowed the rows above; the grid only draws them.\n filterMode=\"server\"\n filterModel={gridFilter.filterModel}\n onFilterModelChange={gridFilter.onFilterModelChange}\n quickFilter\n noRowsLabel=\"No fields match these filters\"\n getRowClassName={({ row }: { row: FieldRow }) =>\n row.definition.retiredAt ? 'field-retired' : ''\n }\n sx={{ '& .field-retired': { opacity: 0.6 } }}\n />\n </Stack>\n )\n}\nFieldsTable.displayName = 'FieldsTable'\n\n/**\n * `/crm/fields` — the custom fields a holder keeps on a person (AGL-2601),\n * since AGL-2661 on a company and a deal too, and since AGL-3272 on a lead:\n * one tab each, and every CRM record describable in the org's own words.\n *\n * Definitions live in `orgs/{orgId}/contactFields`, one document per field,\n * and the VALUES live under each contact facet's `custom` keyed by the\n * definition's `key`. That split decides everything this section does:\n *\n * - A field is RETIRED, not deleted, while values may exist under it. A\n * retired field leaves every form and every column, but an export can\n * still read what was written, and a restore brings it back intact.\n * Delete is offered only on a retired field, because retiring is the step\n * where the author had to look at what they were losing.\n * - The KEY never changes. It is the map key every value sits under; a\n * rename is a new field and a retire.\n * - Order is a stored `order` on each document, moved with the arrows here,\n * and every reader sorts by it — the profile card, the columns, an export.\n * The list table sorts, filters and searches a tab too (AGL-3335), and\n * the arrows wait while it does — see `FieldsTable`.\n *\n * ## What is NOT on this page\n *\n * How many contacts carry a value under each field. That count is a read of\n * every contact document in the org — the expensive-read shape this codebase\n * has a standing rule against — and it would be paid on every visit to a\n * settings page. The list says so rather than showing a number it cannot\n * afford to keep true.\n *\n * Definitions are ORG-WIDE (`visibleTo: ['org']`): a field is a fact about\n * how this business describes people, and every site in the org files\n * people into the same address book. `hostId` records which site defined it.\n */\nexport function ContactsFieldsSection(props: ContactsFieldsSectionProps) {\n const { hostId, org } = props\n const firestore = useFirestore()\n const { enqueueSnackbar } = useSnackbar()\n const { confirm } = useConfirmationContext()\n // The org root from the one scope hook (AGL-2614), which also answers at\n // the organization level (AGL-2630). A definition is org-wide either way;\n // the defining site it records is the mounted one, or the picked one, or\n // none for a field defined over the whole org before any pick.\n const { scope, ready: scopeReady, createHostId } = useCrmScope({ hostId, org })\n const orgId = scope?.[1] ?? null\n /*\n * ONE TAB PER OBJECT (AGL-2661). The list, the drawer and every write\n * below are about the tab's object: the hook narrows the org's one\n * definition list to it, a new field is stamped with it, and the drawer\n * refuses a key only against the keys THIS object already uses — a\n * company and a contact may both define `region`.\n */\n const [tab, setTab] = useState<CrmPicklistObject>('contact')\n // The Tasks tab has no custom fields (AGL-3517): no read, no New field.\n const tasksTab = tab === 'task'\n const object: CrmFieldObject = tab === 'task' ? 'contact' : tab\n const { definitions, ready, fromCache } = useContactFieldDefinitions(\n tasksTab ? null : orgId,\n object,\n )\n const noun = OBJECT_NOUN[object]\n\n /*\n * MAINTENANCE: recompute every record's next activity (AGL-2661). The\n * figure is kept by every task write, so this is for the records written\n * before it existed and for whatever a write that could not reach the\n * route left behind. A console action rather than a script, because the\n * person who notices a stale column is the person who should be able to\n * fix it.\n */\n const { data: user } = useUser()\n const [recomputing, setRecomputing] = useState(false)\n const recomputeNextActivity = useCallback(async () => {\n const callScope = crmTaskCallScope(hostId, orgId)\n if (!callScope || recomputing) return\n const confirmed = await confirm({\n title: 'Recompute next activity?',\n description:\n 'Every contact, company and deal in this organization gets its ' +\n '\"Next activity\" recomputed from its open tasks. Safe to run any time; ' +\n 'it only rewrites a figure the task list already implies.',\n confirmationText: 'Recompute',\n })\n .then(() => true)\n .catch(() => false)\n if (!confirmed) return\n setRecomputing(true)\n try {\n const result = await recomputeAllCrmNextActivity(user, callScope)\n enqueueSnackbar(\n `Next activity recomputed: ${result.records.toLocaleString()} record${result.records === 1 ? '' : 's'} ` +\n `from ${(result.tasks ?? 0).toLocaleString()} open task${result.tasks === 1 ? '' : 's'}` +\n (result.truncated\n ? ' — the first batch of open tasks only; nothing stale was cleared'\n : ''),\n { variant: 'success' },\n )\n } catch (cause) {\n enqueueSnackbar(\n cause instanceof Error ? cause.message : 'The next activity could not be recomputed.',\n { variant: 'warning' },\n )\n } finally {\n setRecomputing(false)\n }\n }, [hostId, orgId, recomputing, confirm, user, enqueueSnackbar])\n\n const [drawerOpen, setDrawerOpen] = useState(false)\n const [editing, setEditing] = useState<ContactFieldDefinitionDoc | null>(null)\n const [busyId, setBusyId] = useState('')\n\n const fieldRef = useCallback(\n (id: string) => {\n if (!scope) throw new Error('a contact field needs an organization')\n return doc(firestore, scope[0], scope[1], CRM_COLLECTIONS.contactFields, id)\n },\n [firestore, scope],\n )\n\n const openCreate = useCallback(() => {\n setEditing(null)\n setDrawerOpen(true)\n }, [])\n const openEdit = useCallback((definition: ContactFieldDefinitionDoc) => {\n setEditing(definition)\n setDrawerOpen(true)\n }, [])\n\n /**\n * Create, or save the editable half of an existing field.\n *\n * On create the document carries everything a reader expects: the key,\n * an `order` past every existing one so it lands last, an explicit\n * `retiredAt: null` so a `where('retiredAt', '==', null)` can find it, the\n * defining site, and the org-wide scope stamp the rules require. On edit\n * only the label, the choices and the required flag move — the key and\n * the type are the drawer's disabled inputs, and this writer does not\n * take them either.\n */\n const handleSubmit = useCallback(\n async (draft: ContactFieldDraft) => {\n if (!scope) return\n const now = new Date()\n if (editing) {\n const verdict = await writeGuardedBySeed(\n { subject: 'field', fromCache },\n async () => {\n await updateDoc(fieldRef(editing.$id), {\n label: draft.label,\n ...(editing.type === 'select' ? { options: draft.options } : {}),\n // The Fields table's query fields (AGL-3335), from the new name —\n // and a definition written before them gains them here.\n ...crmFieldListFields({ ...editing, label: draft.label, required: draft.required }),\n updatedAt: now,\n })\n },\n )\n if (!verdict.ok) {\n return void enqueueSnackbar(verdict.message, {\n variant: 'warning',\n persist: false,\n })\n }\n enqueueSnackbar('Field saved', { variant: 'success', persist: false })\n } else {\n const order =\n definitions.reduce(\n (highest, definition) => Math.max(highest, Number(definition.order) || 0),\n -1,\n ) + 1\n await setDoc(\n doc(\n collection(firestore, scope[0], scope[1], CRM_COLLECTIONS.contactFields),\n createResourceUid(),\n ),\n {\n key: draft.key,\n label: draft.label,\n type: draft.type,\n ...(draft.type === 'select' ? { options: draft.options } : {}),\n required: draft.required,\n order,\n retiredAt: null,\n // Which record the field describes — the tab it was made on —\n // with the Fields table's query fields (AGL-3335).\n ...crmFieldListFields({ key: draft.key, label: draft.label, required: draft.required, object }),\n hostId: createHostId,\n ...newResourceScopeFields([ORG_SCOPE_TOKEN]),\n createdAt: now,\n updatedAt: now,\n },\n )\n enqueueSnackbar(`Field \"${draft.label}\" added`, {\n variant: 'success',\n persist: false,\n })\n }\n setDrawerOpen(false)\n setEditing(null)\n },\n [scope, editing, fromCache, fieldRef, enqueueSnackbar, definitions, firestore, createHostId, object],\n )\n\n /**\n * Move a field one place up or down.\n *\n * Writes `order` as the POSITION for every row whose stored order is not\n * already its position, in one batch. Swapping two numbers would be enough\n * on a list whose orders are already distinct, and wrong on one where they\n * are not — every field created before this section existed carries the\n * same `order`, and a swap of two equal numbers moves nothing. Renumbering\n * what is out of place makes the first move on such a list also the one\n * that normalizes it, at the cost of a batch that is at most the list.\n */\n const move = useCallback(\n async (definition: ContactFieldDefinitionDoc, direction: -1 | 1) => {\n if (!scope || busyId) return\n const index = definitions.findIndex((entry) => entry.$id === definition.$id)\n const target = index + direction\n if (index < 0 || target < 0 || target >= definitions.length) return\n const next = [...definitions]\n next[index] = definitions[target]\n next[target] = definitions[index]\n setBusyId(definition.$id)\n try {\n const verdict = await writeGuardedBySeed(\n { subject: 'field order', fromCache },\n async () => {\n const batch = writeBatch(firestore)\n const now = new Date()\n next.forEach((entry, position) => {\n if (entry.order === position) return\n batch.update(fieldRef(entry.$id), { order: position, updatedAt: now })\n })\n await batch.commit()\n },\n )\n if (!verdict.ok) {\n enqueueSnackbar(verdict.message, { variant: 'warning', persist: false })\n }\n } catch (error) {\n console.error(error)\n enqueueSnackbar('An error has occurred', { variant: 'error', allowDuplicate: true })\n } finally {\n setBusyId('')\n }\n },\n [scope, busyId, definitions, fromCache, firestore, fieldRef, enqueueSnackbar],\n )\n\n /**\n * Retire a field, or bring one back.\n *\n * Retiring is asked about because it takes a control off every contact\n * form and a column off the list; restoring is not, because it puts a\n * choice back and is undone by retiring again. Neither touches a value.\n */\n const toggleRetired = useCallback(\n async (definition: ContactFieldDefinitionDoc) => {\n if (!scope || busyId) return\n if (!definition.retiredAt) {\n const accepted = await confirm({\n title: `Retire “${definition.label}”?`,\n description:\n `It leaves every ${noun} form, column and form-field mapping. ` +\n 'Values already saved under it are kept and still export, and ' +\n 'you can restore the field at any time.',\n confirmationText: 'Retire',\n })\n // `confirm` resolves with no value and REJECTS on cancel, so gating\n // on the resolved value alone would always fall through.\n .then(() => true)\n .catch(() => false)\n if (!accepted) return\n }\n setBusyId(definition.$id)\n try {\n await updateDoc(fieldRef(definition.$id), {\n retiredAt: definition.retiredAt ? null : Date.now(),\n updatedAt: new Date(),\n })\n enqueueSnackbar(definition.retiredAt ? 'Field restored' : 'Field retired', {\n variant: 'success',\n persist: false,\n })\n } catch (error) {\n console.error(error)\n enqueueSnackbar('An error has occurred', { variant: 'error', allowDuplicate: true })\n } finally {\n setBusyId('')\n }\n },\n [scope, busyId, confirm, fieldRef, enqueueSnackbar, noun],\n )\n\n /**\n * Delete a RETIRED field's definition.\n *\n * The values under its key are not touched — they sit on contact documents\n * this page does not read — so what is destroyed is the ability to show\n * them anywhere. The dialog says exactly that, and the key stays taken for\n * as long as the list can see it, which after this write it cannot; a new\n * field with the same key would read the orphaned values back as its own.\n */\n const handleDelete = useCallback(\n async (definition: ContactFieldDefinitionDoc) => {\n if (!scope || busyId || !definition.retiredAt) return\n const accepted = await confirm({\n title: `Delete “${definition.label}”?`,\n description:\n 'The definition is removed for good. Values saved under its key ' +\n `(${definition.key}) stay on the ${noun}s that carry them but ` +\n 'nothing will show them again — and a new field created with the ' +\n 'same key would read them as its own.',\n confirmationText: 'Delete field',\n confirmationButtonProps: { color: 'error' },\n })\n .then(() => true)\n .catch(() => false)\n if (!accepted) return\n setBusyId(definition.$id)\n try {\n await deleteDoc(fieldRef(definition.$id))\n enqueueSnackbar('Field deleted', { variant: 'success', persist: false })\n } catch (error) {\n console.error(error)\n enqueueSnackbar('An error has occurred', { variant: 'error', allowDuplicate: true })\n } finally {\n setBusyId('')\n }\n },\n [scope, busyId, confirm, fieldRef, enqueueSnackbar, noun],\n )\n\n /*\n * Stable across renders, as the table's columns are built from them: a\n * fresh function each render would rebuild every column on every render.\n */\n const rowActions = useCallback(\n (definition: ContactFieldDefinitionDoc): RowActionsMenuItem[] => [\n {\n key: 'edit',\n label: 'Edit field',\n icon: <MdiIcon path={mdiPencilOutline.path} size={0.8} />,\n onClick: () => openEdit(definition),\n },\n {\n key: 'retire',\n label: definition.retiredAt ? 'Restore' : 'Retire',\n icon: (\n <MdiIcon\n path={definition.retiredAt ? mdiArchiveArrowUpOutline.path : mdiArchiveOutline.path}\n size={0.8}\n />\n ),\n destructive: !definition.retiredAt,\n disabled: Boolean(busyId),\n disabledReason: busyId ? 'Another field is being saved' : undefined,\n onClick: () => void toggleRetired(definition),\n },\n ...(definition.retiredAt\n ? [\n {\n key: 'delete',\n label: 'Delete',\n icon: <MdiIcon path={mdiDeleteOutline.path} size={0.8} />,\n destructive: true,\n disabled: Boolean(busyId),\n disabledReason: busyId ? 'Another field is being saved' : undefined,\n onClick: () => void handleDelete(definition),\n } satisfies RowActionsMenuItem,\n ]\n : []),\n ],\n [openEdit, toggleRetired, handleDelete, busyId],\n )\n const onMove = useCallback(\n (definition: ContactFieldDefinitionDoc, direction: -1 | 1) =>\n void move(definition, direction),\n [move],\n )\n\n return (\n <CardDisplay\n header={'Fields'}\n help={pluginDocsHelp('contactFields', { anchor: '#define-a-field' })}\n contentGutterX\n contentGutterY\n contentBordered=\"all\"\n HeaderProps={{\n action: scope ? (\n <Stack direction=\"row\" spacing={1} sx={{ alignItems: 'center' }}>\n {/* Every custom field, as a file (AGL-3528). */}\n <CrmExportButton resource={CRM_FIELDS_RESOURCE} hostId={hostId ?? null} />\n <Button size=\"small\" onClick={() => void recomputeNextActivity()} disabled={recomputing}>\n {recomputing ? 'Recomputing…' : 'Recompute next activity'}\n </Button>\n {tasksTab ? null : (\n <Button variant=\"contained\" onClick={openCreate}>\n {'New field'}\n </Button>\n )}\n </Stack>\n ) : null,\n }}\n >\n <Stack spacing={2}>\n <Tabs\n value={tab}\n onChange={(_event, next) => {\n if (isCrmPicklistObject(next)) setTab(next)\n }}\n aria-label=\"Fields by record\"\n >\n {CRM_PICKLIST_OBJECTS.map((entry) => (\n <Tab key={entry} value={entry} label={CRM_PICKLIST_OBJECT_LABELS[entry]} />\n ))}\n </Tabs>\n <Typography variant=\"body2\" color=\"text.secondary\">\n {`${tasksTab ? TASKS_INTRO : OBJECT_INTRO[object]} Fields are shared across every site in this ` +\n 'organization, like the records themselves.'}\n </Typography>\n {tasksTab ? null : scopeReady && !scope ? (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {`This site has no organization, so it has no ${noun} fields.`}\n </Typography>\n ) : !ready ? null : definitions.length === 0 ? (\n <EmptyStateComponent\n label={`No custom ${noun} fields yet`}\n description={`A field you define here is kept on every ${noun} and shows on its page.`}\n action={\n scope ? (\n <Button variant=\"contained\" onClick={openCreate}>\n {'New field'}\n </Button>\n ) : undefined\n }\n />\n ) : (\n /*\n Keyed by the tab, so a sort, a filter or a search made on one\n record's fields does not follow the reader onto another's.\n */\n <FieldsTable\n key={object}\n orgId={orgId}\n object={object}\n definitions={definitions}\n busyId={busyId}\n onMove={onMove}\n rowActions={rowActions}\n />\n )}\n {definitions.length && !tasksTab ? (\n <Typography variant=\"caption\" color=\"text.secondary\">\n {`How many ${noun}s carry a value under each field is not ` +\n `counted — that would read every ${noun} in the organization ` +\n 'each time this page opened.'}\n </Typography>\n ) : null}\n {/*\n The tab's standard picklists (AGL-3298, AGL-3510) — standard fields\n whose CHOICES are the org's, Salesforce's picklist value sets — one\n card each, beside the custom fields of the same record.\n */}\n {scope\n ? crmPicklistDefinitionsFor(tab).map((definition) => (\n <PicklistValuesCard\n key={definition.id}\n picklistId={definition.id as CrmPicklistId}\n hostId={hostId}\n orgId={orgId}\n createHostId={createHostId}\n />\n ))\n : null}\n </Stack>\n <ContactFieldDrawer\n open={drawerOpen}\n onClose={() => setDrawerOpen(false)}\n definition={editing}\n object={object}\n takenKeys={definitions.map((definition) => definition.key)}\n onSubmit={handleSubmit}\n />\n </CardDisplay>\n )\n}\nContactsFieldsSection.displayName = 'ContactsFieldsSection'\n\nexport default ContactsFieldsSection\n"],"names":["CrmExportButton","CRM_FIELDS_RESOURCE","CONTACT_FIELD_TYPE_LABELS","CONTACT_FIELD_TYPES","CONTACT_FIELDS_MAX_PER_ORG","createResourceUid","CRM_COLLECTIONS","crmFieldListFields","CRM_PICKLIST_OBJECT_LABELS","CRM_PICKLIST_OBJECTS","crmPicklistDefinitionsFor","isCrmPicklistObject","newResourceScopeFields","ORG_SCOPE_TOKEN","pluginDocsHelp","EmptyStateComponent","ListFilterChips","ListQueryNotices","listQueryRefusals","ListRowActions","ListTable","listActionsColumn","mdiArchiveArrowUpOutline","mdiArchiveOutline","mdiArrowDown","mdiArrowUp","mdiDeleteOutline","mdiPencilOutline","CardDisplay","MdiIcon","SrOnly","useConfirmationContext","listFilterGridColumns","planListQuery","useListGridFilter","nameSearchNormalizers","useSnackbar","ceilingedWindow","listQueryConstraints","useFirestore","useFirestoreCollection","useUser","writeGuardedBySeed","Button","Chip","IconButton","Stack","Tab","Tabs","Tooltip","Typography","collection","deleteDoc","doc","limit","query","setDoc","updateDoc","writeBatch","useCallback","useMemo","useState","useContactFieldDefinitions","useCrmScope","CRM_FIELD_LIST_QUERY","crmFieldListBase","ContactFieldDrawer","PicklistValuesCard","recomputeAllCrmNextActivity","crmTaskCallScope","OBJECT_INTRO","contact","company","deal","lead","TASKS_INTRO","OBJECT_NOUN","FIELD_FILTER_FIELDS","fields","FIELD_FILTER_HEADERS","type","required","FIELD_FILTER_OPTIONS","map","value","label","FIELD_REORDER_LOCKED_REASON","typeLabel","String","FieldsTable","props","orgId","object","definitions","busyId","onMove","rowActions","firestore","gridFilter","selectFields","sortModel","setSortModel","searching","searchWords","some","word","trim","reorderLocked","length","clauses","narrowed","plan","search","base","join","planKey","JSON","stringify","filters","orderBy","matched","contactFields","idField","answer","data","positions","Map","definition","position","$id","rows","shown","sort","a","b","get","Number","MAX_SAFE_INTEGER","key","refused","headers","options","columns","field","headerName","width","sortable","filterable","hideable","disableColumnMenu","renderCell","row","arrows","direction","spacing","sx","alignItems","variant","color","minWidth","textAlign","mr","size","disabled","Boolean","onClick","path","title","span","flex","flexWrap","retiredAt","fontFamily","sortComparator","localeCompare","items","onChange","setClauses","marksServed","notices","truncated","aria-label","loading","status","onSortModelChange","filterMode","filterModel","onFilterModelChange","quickFilter","noRowsLabel","getRowClassName","opacity","displayName","ContactsFieldsSection","hostId","org","enqueueSnackbar","confirm","scope","ready","scopeReady","createHostId","tab","setTab","tasksTab","fromCache","noun","user","recomputing","setRecomputing","recomputeNextActivity","callScope","confirmed","description","confirmationText","then","catch","result","records","toLocaleString","tasks","cause","Error","message","drawerOpen","setDrawerOpen","editing","setEditing","setBusyId","fieldRef","id","openCreate","openEdit","handleSubmit","draft","now","Date","verdict","subject","updatedAt","ok","persist","order","reduce","highest","Math","max","createdAt","move","index","findIndex","entry","target","next","batch","forEach","update","commit","error","console","allowDuplicate","toggleRetired","accepted","handleDelete","confirmationButtonProps","icon","destructive","disabledReason","undefined","header","help","anchor","contentGutterX","contentGutterY","contentBordered","HeaderProps","action","resource","_event","picklistId","open","onClose","takenKeys","onSubmit"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/crm/src/lib/components/fields-section.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 { CrmExportButton } from './crm-transfer-buttons'\nimport { CRM_FIELDS_RESOURCE } from '../transfer/fields'\nimport {\n CONTACT_FIELD_TYPE_LABELS,\n CONTACT_FIELD_TYPES,\n CONTACT_FIELDS_MAX_PER_ORG,\n type ConsolePluginPageProps,\n createResourceUid,\n CRM_COLLECTIONS,\n crmFieldListFields,\n type CrmFieldObject,\n CRM_PICKLIST_OBJECT_LABELS,\n CRM_PICKLIST_OBJECTS,\n type CrmPicklistId,\n type CrmPicklistObject,\n crmPicklistDefinitionsFor,\n isCrmPicklistObject,\n newResourceScopeFields,\n ORG_SCOPE_TOKEN,\n pluginDocsHelp,\n} from '@aglyn/aglyn'\nimport EmptyStateComponent from '@aglyn/shared-ui-jsx/components/empty-state.component'\nimport ListFilterChips from '@aglyn/shared-ui-jsx/components/list-filter-chips.component'\nimport ListQueryNotices, {\n listQueryRefusals,\n} from '@aglyn/shared-ui-jsx/components/list-query-notices.component'\nimport {\n ListRowActions,\n ListTable,\n listActionsColumn,\n} from '@aglyn/shared-ui-jsx/components/list-table.component'\nimport {\n mdiArchiveArrowUpOutline,\n mdiArchiveOutline,\n mdiArrowDown,\n mdiArrowUp,\n mdiDeleteOutline,\n mdiPencilOutline,\n} from '@aglyn/shared-data-mdi'\nimport {\n CardDisplay,\n MdiIcon,\n SrOnly,\n useConfirmationContext,\n} from '@aglyn/shared-ui-jsx'\nimport type { RowActionsMenuItem } from '@aglyn/shared-ui-jsx/components/row-actions-menu.component'\nimport {\n type ListFilterOption,\n listFilterGridColumns,\n} from '@aglyn/shared-ui-jsx/const/list-grid-filter'\nimport { planListQuery } from '@aglyn/shared-ui-jsx/const/list-query-plan'\nimport { useListGridFilter } from '@aglyn/shared-ui-jsx/hooks/use-list-grid-filter'\nimport { nameSearchNormalizers } from '@aglyn/aglyn/app-utils/name-search'\nimport { useSnackbar } from '@aglyn/shared-ui-snackstack'\nimport { ceilingedWindow } from '@aglyn/tenant-feature-instance/hooks/host-collection-queries'\nimport { listQueryConstraints } from '@aglyn/tenant-feature-instance/hooks/use-list-query'\nimport {\n useFirestore,\n useFirestoreCollection,\n useUser,\n writeGuardedBySeed,\n} from '@aglyn/tenant-feature-instance'\nimport {\n Button,\n Chip,\n IconButton,\n Stack,\n Tab,\n Tabs,\n Tooltip,\n Typography,\n} from '@mui/material'\nimport type { GridColDef, GridSortModel } from '@mui/x-data-grid'\nimport {\n collection,\n deleteDoc,\n doc,\n limit,\n query,\n setDoc,\n updateDoc,\n writeBatch,\n} from 'firebase/firestore'\nimport { useCallback, useMemo, useState } from 'react'\nimport {\n type ContactFieldDefinitionDoc,\n useContactFieldDefinitions,\n} from '../hooks/use-contact-field-definitions'\nimport { useCrmScope } from '../hooks/use-crm-scope'\nimport { CRM_FIELD_LIST_QUERY, crmFieldListBase } from '../constants/field-list-query'\nimport ContactFieldDrawer, { type ContactFieldDraft } from './contact-field-drawer'\nimport { PicklistValuesCard } from './picklist-values-card'\nimport { recomputeAllCrmNextActivity } from '../model/next-activity-api'\nimport { crmTaskCallScope } from '../model/task-routes'\n\nexport type ContactsFieldsSectionProps = Pick<ConsolePluginPageProps, 'hostId' | 'org'>\n\n/** What each tab says the fields are for, above its list. */\nconst OBJECT_INTRO: Record<CrmFieldObject, string> = {\n contact:\n 'The custom fields on a contact — text, number, date, choice, ' +\n 'checkbox or link. They show on every contact, as columns on the ' +\n 'list, and a form field can save into one.',\n company:\n 'The custom fields on a company. They show on every company’s page ' +\n 'and its edit form, as columns on the companies list, and a CSV ' +\n 'import can fill them.',\n deal:\n 'The custom fields on a deal. They show on every deal’s page and ' +\n 'its edit form, and as columns on the deals table.',\n lead:\n 'The custom fields on a lead. They show on every lead’s page and the ' +\n 'New lead drawer, and as columns on the leads list. They stay on the ' +\n 'lead when it converts — a contact’s fields are its own.',\n}\n\n/**\n * The Tasks tab's intro (AGL-3517): a task has standard picklists and no\n * custom fields, so the tab is its picklist cards alone.\n */\nconst TASKS_INTRO =\n 'A task’s standard picklists — its Status, Priority and Type, and the ' +\n 'subjects its title suggests. Status, Priority and Type each mean one of ' +\n 'the CRM’s own values, which reminders, due dates and automations read; ' +\n 'the labels are your organization’s. Tasks have no custom fields.'\n\n/** The noun each tab's empty state and captions use. */\nconst OBJECT_NOUN: Record<CrmFieldObject, string> = {\n contact: 'contact',\n company: 'company',\n deal: 'deal',\n lead: 'lead',\n}\n\n/** One definition as the list table draws it. */\ninterface FieldRow {\n $id: string\n label: string\n key: string\n type: string\n /** `true` or `false`, the value the Required filter picks. */\n required: 'true' | 'false'\n /** Where the stored order puts it, from zero. */\n position: number\n definition: ContactFieldDefinitionDoc\n}\n\n/** What the grid's Filters panel offers: the type and whether it is required, on the query. */\nconst FIELD_FILTER_FIELDS = CRM_FIELD_LIST_QUERY.fields\nconst FIELD_FILTER_HEADERS: Readonly<Record<string, string>> = {\n type: 'Type',\n required: 'Required',\n}\nconst FIELD_FILTER_OPTIONS: Readonly<Record<string, readonly ListFilterOption[]>> = {\n type: CONTACT_FIELD_TYPES.map((type) => ({\n value: type,\n label: CONTACT_FIELD_TYPE_LABELS[type],\n })),\n required: [\n { value: 'true', label: 'Required' },\n { value: 'false', label: 'Optional' },\n ],\n}\n\n/** Why the arrows are off while the list is not in its stored order. */\nexport const FIELD_REORDER_LOCKED_REASON = 'Clear sorting and filters to reorder'\n\nconst typeLabel = (type: unknown) =>\n CONTACT_FIELD_TYPE_LABELS[type as keyof typeof CONTACT_FIELD_TYPE_LABELS] ?? String(type ?? '')\n\ninterface FieldsTableProps {\n /** The organization whose definitions these are; `null` reads nothing. */\n orgId: string | null\n /** The tab: which record the definitions describe. */\n object: CrmFieldObject\n /** One tab's definitions, in the stored order. */\n definitions: readonly ContactFieldDefinitionDoc[]\n /** A field being written; every arrow waits for it. */\n busyId: string\n onMove: (definition: ContactFieldDefinitionDoc, direction: -1 | 1) => void\n rowActions: (definition: ContactFieldDefinitionDoc) => RowActionsMenuItem[]\n}\n\n/**\n * One tab's field definitions in the console's list table (AGL-3335): the\n * toolbar's columns, filters, export and search, sorting by Field, Key and\n * Type, and the shared footer.\n *\n * ## Order is data, not a sort\n *\n * The stored `order` is where each field appears on every record and form,\n * so the arrows that move it are kept, and are live only while the table\n * shows that order: no sort, no filter and no search. Under any of them the\n * row above a field on screen is not the field above it in the stored\n * order, and a move would land somewhere the reader cannot see; the arrows\n * say so rather than disappear.\n *\n * The panel and the search are asked of Firestore (AGL-3321): a clause or\n * a search word reads the tab's definitions that match it\n * (`CRM_FIELD_LIST_QUERY`), and never narrows the rows already on screen.\n * That answer is every match, at most `CONTACT_FIELDS_MAX_PER_ORG`, so the\n * grid sorts and pages it whole; a read that reaches the ceiling says so.\n */\nfunction FieldsTable(props: FieldsTableProps) {\n const { orgId, object, definitions, busyId, onMove, rowActions } = props\n const firestore = useFirestore()\n const gridFilter = useListGridFilter({ selectFields: ['type', 'required'] })\n const [sortModel, setSortModel] = useState<GridSortModel>([])\n const searching = gridFilter.searchWords.some((word) => word.trim() !== '')\n const reorderLocked =\n sortModel.length > 0 || gridFilter.clauses.length > 0 || searching\n\n const narrowed = gridFilter.clauses.length > 0 || searching\n const plan = useMemo(\n () =>\n planListQuery(\n CRM_FIELD_LIST_QUERY,\n {\n clauses: gridFilter.clauses,\n search: gridFilter.searchWords,\n base: crmFieldListBase(object),\n },\n nameSearchNormalizers,\n ),\n // The words are a new array each render; their text is their identity.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [object, gridFilter.clauses, gridFilter.searchWords.join(' ')],\n )\n const planKey = JSON.stringify({ filters: plan.filters, orderBy: plan.orderBy })\n /*\n * Read only while something narrows the tab. Unnarrowed, the table is the\n * shared definitions read every CRM surface already holds, in its stored\n * order — the same fields, with no second read.\n */\n const matched = useFirestoreCollection<ContactFieldDefinitionDoc>(\n () =>\n narrowed && orgId\n ? query(\n collection(firestore, 'orgs', orgId, CRM_COLLECTIONS.contactFields),\n ...listQueryConstraints(plan),\n limit(CONTACT_FIELDS_MAX_PER_ORG + 1),\n )\n : null,\n [firestore, orgId, narrowed, planKey],\n { idField: '$id' },\n )\n const answer = useMemo(\n () => ceilingedWindow(matched.data, CONTACT_FIELDS_MAX_PER_ORG),\n [matched.data],\n )\n const positions = useMemo(\n () => new Map(definitions.map((definition, position) => [definition.$id, position])),\n [definitions],\n )\n const rows = useMemo<FieldRow[]>(() => {\n const shown = narrowed\n ? [...answer.rows].sort(\n (a, b) =>\n (positions.get(a.$id) ?? Number.MAX_SAFE_INTEGER) -\n (positions.get(b.$id) ?? Number.MAX_SAFE_INTEGER),\n )\n : definitions\n return shown.map((definition) => ({\n $id: definition.$id,\n label: definition.label,\n key: definition.key,\n type: definition.type,\n required: definition.required ? 'true' : 'false',\n position: positions.get(definition.$id) ?? 0,\n definition,\n }))\n }, [narrowed, answer.rows, definitions, positions])\n const refused = useMemo(\n () =>\n listQueryRefusals(plan.refused, {\n fields: FIELD_FILTER_FIELDS,\n headers: FIELD_FILTER_HEADERS,\n options: FIELD_FILTER_OPTIONS,\n }),\n [plan.refused],\n )\n\n const columns = useMemo<GridColDef[]>(\n () =>\n listFilterGridColumns(\n [\n {\n field: 'position',\n headerName: 'Order',\n width: 132,\n sortable: false,\n filterable: false,\n hideable: false,\n disableColumnMenu: true,\n renderCell: ({ row }: { row: FieldRow }) => {\n const arrows = (\n <Stack direction=\"row\" spacing={0} sx={{ alignItems: 'center' }}>\n <Typography\n variant=\"body2\"\n color=\"text.secondary\"\n sx={{ minWidth: 24, textAlign: 'right', mr: 0.5 }}\n >\n {row.position + 1}\n </Typography>\n <IconButton\n size=\"small\"\n disabled={reorderLocked || row.position === 0 || Boolean(busyId)}\n onClick={() => onMove(row.definition, -1)}\n >\n <MdiIcon path={mdiArrowUp.path} size={0.7} />\n <SrOnly>{`Move ${row.label} up`}</SrOnly>\n </IconButton>\n <IconButton\n size=\"small\"\n disabled={\n reorderLocked || row.position === definitions.length - 1 || Boolean(busyId)\n }\n onClick={() => onMove(row.definition, 1)}\n >\n <MdiIcon path={mdiArrowDown.path} size={0.7} />\n <SrOnly>{`Move ${row.label} down`}</SrOnly>\n </IconButton>\n </Stack>\n )\n return reorderLocked ? (\n <Tooltip title={FIELD_REORDER_LOCKED_REASON}>\n {/* A disabled button emits no events; the span carries the tooltip. */}\n <span>{arrows}</span>\n </Tooltip>\n ) : (\n arrows\n )\n },\n },\n {\n field: 'label',\n headerName: 'Field',\n flex: 1,\n minWidth: 180,\n renderCell: ({ row }: { row: FieldRow }) => (\n <Stack\n useFlexGap\n direction=\"row\"\n spacing={1}\n sx={{ flexWrap: 'wrap', alignItems: 'center' }}\n >\n <Typography variant=\"body2\">{row.label}</Typography>\n {row.definition.retiredAt ? (\n <Chip size=\"small\" variant=\"outlined\" color=\"warning\" label=\"Retired\" />\n ) : null}\n </Stack>\n ),\n },\n {\n field: 'key',\n headerName: 'Key',\n flex: 1,\n minWidth: 160,\n renderCell: ({ row }: { row: FieldRow }) => (\n <Typography\n variant=\"body2\"\n color=\"text.secondary\"\n sx={{ fontFamily: 'monospace' }}\n >\n {row.key}\n </Typography>\n ),\n },\n {\n field: 'type',\n headerName: 'Type',\n width: 170,\n // By what the type reads as, not by its stored key.\n sortComparator: (a: unknown, b: unknown) =>\n typeLabel(a).localeCompare(typeLabel(b)),\n renderCell: ({ row }: { row: FieldRow }) => (\n <Typography variant=\"body2\">\n {typeLabel(row.type)}\n {row.definition.type === 'select' && row.definition.options?.length\n ? ` · ${row.definition.options.length} choices`\n : ''}\n </Typography>\n ),\n },\n {\n field: 'required',\n headerName: 'Required',\n width: 120,\n sortable: false,\n renderCell: ({ row }: { row: FieldRow }) => (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {row.required === 'true' ? 'Yes' : '—'}\n </Typography>\n ),\n },\n listActionsColumn(\n (row: FieldRow) => (\n <ListRowActions label={row.label} items={rowActions(row.definition)} />\n ),\n { width: 72 },\n ),\n ],\n FIELD_FILTER_FIELDS,\n FIELD_FILTER_OPTIONS,\n FIELD_FILTER_HEADERS,\n ),\n [reorderLocked, busyId, onMove, rowActions, definitions.length],\n )\n\n return (\n <Stack spacing={1}>\n <ListFilterChips\n fields={FIELD_FILTER_FIELDS}\n headers={FIELD_FILTER_HEADERS}\n clauses={gridFilter.clauses}\n onChange={gridFilter.setClauses}\n options={FIELD_FILTER_OPTIONS}\n marksServed={false}\n />\n <ListQueryNotices refused={refused} notices={plan.notices} />\n {narrowed && answer.truncated ? (\n <Typography variant=\"caption\" color=\"text.secondary\">\n {`Showing the first ${CONTACT_FIELDS_MAX_PER_ORG} matching fields.`}\n </Typography>\n ) : null}\n <ListTable\n aria-label=\"Fields\"\n rows={rows}\n loading={narrowed && matched.status === 'loading'}\n columns={columns}\n sortModel={sortModel}\n onSortModelChange={setSortModel}\n // Firestore narrowed the rows above; the grid only draws them.\n filterMode=\"server\"\n filterModel={gridFilter.filterModel}\n onFilterModelChange={gridFilter.onFilterModelChange}\n quickFilter\n noRowsLabel=\"No fields match these filters\"\n getRowClassName={({ row }: { row: FieldRow }) =>\n row.definition.retiredAt ? 'field-retired' : ''\n }\n sx={{ '& .field-retired': { opacity: 0.6 } }}\n />\n </Stack>\n )\n}\nFieldsTable.displayName = 'FieldsTable'\n\n/**\n * `/crm/fields` — the custom fields a holder keeps on a person (AGL-2601),\n * since AGL-2661 on a company and a deal too, and since AGL-3272 on a lead:\n * one tab each, and every CRM record describable in the org's own words.\n *\n * Definitions live in `orgs/{orgId}/contactFields`, one document per field,\n * and the VALUES live under each contact facet's `custom` keyed by the\n * definition's `key`. That split decides everything this section does:\n *\n * - A field is RETIRED, not deleted, while values may exist under it. A\n * retired field leaves every form and every column, but an export can\n * still read what was written, and a restore brings it back intact.\n * Delete is offered only on a retired field, because retiring is the step\n * where the author had to look at what they were losing.\n * - The KEY never changes. It is the map key every value sits under; a\n * rename is a new field and a retire.\n * - Order is a stored `order` on each document, moved with the arrows here,\n * and every reader sorts by it — the profile card, the columns, an export.\n * The list table sorts, filters and searches a tab too (AGL-3335), and\n * the arrows wait while it does — see `FieldsTable`.\n *\n * ## What is NOT on this page\n *\n * How many contacts carry a value under each field. That count is a read of\n * every contact document in the org — the expensive-read shape this codebase\n * has a standing rule against — and it would be paid on every visit to a\n * settings page. The list says so rather than showing a number it cannot\n * afford to keep true.\n *\n * Definitions are ORG-WIDE (`visibleTo: ['org']`): a field is a fact about\n * how this business describes people, and every site in the org files\n * people into the same address book. `hostId` records which site defined it.\n */\nexport function ContactsFieldsSection(props: ContactsFieldsSectionProps) {\n const { hostId, org } = props\n const firestore = useFirestore()\n const { enqueueSnackbar } = useSnackbar()\n const { confirm } = useConfirmationContext()\n // The org root from the one scope hook (AGL-2614), which also answers at\n // the organization level (AGL-2630). A definition is org-wide either way;\n // the defining site it records is the mounted one, or the picked one, or\n // none for a field defined over the whole org before any pick.\n const { scope, ready: scopeReady, createHostId } = useCrmScope({ hostId, org })\n const orgId = scope?.[1] ?? null\n /*\n * ONE TAB PER OBJECT (AGL-2661). The list, the drawer and every write\n * below are about the tab's object: the hook narrows the org's one\n * definition list to it, a new field is stamped with it, and the drawer\n * refuses a key only against the keys THIS object already uses — a\n * company and a contact may both define `region`.\n */\n const [tab, setTab] = useState<CrmPicklistObject>('contact')\n // The Tasks tab has no custom fields (AGL-3517): no read, no New field.\n const tasksTab = tab === 'task'\n const object: CrmFieldObject = tab === 'task' ? 'contact' : tab\n const { definitions, ready, fromCache } = useContactFieldDefinitions(\n tasksTab ? null : orgId,\n object,\n )\n const noun = OBJECT_NOUN[object]\n\n /*\n * MAINTENANCE: recompute every record's next activity (AGL-2661). The\n * figure is kept by every task write, so this is for the records written\n * before it existed and for whatever a write that could not reach the\n * route left behind. A console action rather than a script, because the\n * person who notices a stale column is the person who should be able to\n * fix it.\n */\n const { data: user } = useUser()\n const [recomputing, setRecomputing] = useState(false)\n const recomputeNextActivity = useCallback(async () => {\n const callScope = crmTaskCallScope(hostId, orgId)\n if (!callScope || recomputing) return\n const confirmed = await confirm({\n title: 'Recompute next activity?',\n description:\n 'Every contact, company and deal in this organization gets its ' +\n '\"Next activity\" recomputed from its open tasks. Safe to run any time; ' +\n 'it only rewrites a figure the task list already implies.',\n confirmationText: 'Recompute',\n })\n .then(() => true)\n .catch(() => false)\n if (!confirmed) return\n setRecomputing(true)\n try {\n const result = await recomputeAllCrmNextActivity(user, callScope)\n enqueueSnackbar(\n `Next activity recomputed: ${result.records.toLocaleString()} record${result.records === 1 ? '' : 's'} ` +\n `from ${(result.tasks ?? 0).toLocaleString()} open task${result.tasks === 1 ? '' : 's'}` +\n (result.truncated\n ? ' — the first batch of open tasks only; nothing stale was cleared'\n : ''),\n { variant: 'success' },\n )\n } catch (cause) {\n enqueueSnackbar(\n cause instanceof Error ? cause.message : 'The next activity could not be recomputed.',\n { variant: 'warning' },\n )\n } finally {\n setRecomputing(false)\n }\n }, [hostId, orgId, recomputing, confirm, user, enqueueSnackbar])\n\n const [drawerOpen, setDrawerOpen] = useState(false)\n const [editing, setEditing] = useState<ContactFieldDefinitionDoc | null>(null)\n const [busyId, setBusyId] = useState('')\n\n const fieldRef = useCallback(\n (id: string) => {\n if (!scope) throw new Error('a contact field needs an organization')\n return doc(firestore, scope[0], scope[1], CRM_COLLECTIONS.contactFields, id)\n },\n [firestore, scope],\n )\n\n const openCreate = useCallback(() => {\n setEditing(null)\n setDrawerOpen(true)\n }, [])\n const openEdit = useCallback((definition: ContactFieldDefinitionDoc) => {\n setEditing(definition)\n setDrawerOpen(true)\n }, [])\n\n /**\n * Create, or save the editable half of an existing field.\n *\n * On create the document carries everything a reader expects: the key,\n * an `order` past every existing one so it lands last, an explicit\n * `retiredAt: null` so a `where('retiredAt', '==', null)` can find it, the\n * defining site, and the org-wide scope stamp the rules require. On edit\n * only the label, the choices and the required flag move — the key and\n * the type are the drawer's disabled inputs, and this writer does not\n * take them either.\n */\n const handleSubmit = useCallback(\n async (draft: ContactFieldDraft) => {\n if (!scope) return\n const now = new Date()\n if (editing) {\n const verdict = await writeGuardedBySeed(\n { subject: 'field', fromCache },\n async () => {\n await updateDoc(fieldRef(editing.$id), {\n label: draft.label,\n ...(editing.type === 'select' ? { options: draft.options } : {}),\n // The Fields table's query fields (AGL-3335), from the new name —\n // and a definition written before them gains them here.\n ...crmFieldListFields({ ...editing, label: draft.label, required: draft.required }),\n updatedAt: now,\n })\n },\n )\n if (!verdict.ok) {\n return void enqueueSnackbar(verdict.message, {\n variant: 'warning',\n persist: false,\n })\n }\n enqueueSnackbar('Field saved', { variant: 'success', persist: false })\n } else {\n const order =\n definitions.reduce(\n (highest, definition) => Math.max(highest, Number(definition.order) || 0),\n -1,\n ) + 1\n await setDoc(\n doc(\n collection(firestore, scope[0], scope[1], CRM_COLLECTIONS.contactFields),\n createResourceUid(),\n ),\n {\n key: draft.key,\n label: draft.label,\n type: draft.type,\n ...(draft.type === 'select' ? { options: draft.options } : {}),\n required: draft.required,\n order,\n retiredAt: null,\n // Which record the field describes — the tab it was made on —\n // with the Fields table's query fields (AGL-3335).\n ...crmFieldListFields({ key: draft.key, label: draft.label, required: draft.required, object }),\n hostId: createHostId,\n ...newResourceScopeFields([ORG_SCOPE_TOKEN]),\n createdAt: now,\n updatedAt: now,\n },\n )\n enqueueSnackbar(`Field \"${draft.label}\" added`, {\n variant: 'success',\n persist: false,\n })\n }\n setDrawerOpen(false)\n setEditing(null)\n },\n [scope, editing, fromCache, fieldRef, enqueueSnackbar, definitions, firestore, createHostId, object],\n )\n\n /**\n * Move a field one place up or down.\n *\n * Writes `order` as the POSITION for every row whose stored order is not\n * already its position, in one batch. Swapping two numbers would be enough\n * on a list whose orders are already distinct, and wrong on one where they\n * are not — every field created before this section existed carries the\n * same `order`, and a swap of two equal numbers moves nothing. Renumbering\n * what is out of place makes the first move on such a list also the one\n * that normalizes it, at the cost of a batch that is at most the list.\n */\n const move = useCallback(\n async (definition: ContactFieldDefinitionDoc, direction: -1 | 1) => {\n if (!scope || busyId) return\n const index = definitions.findIndex((entry) => entry.$id === definition.$id)\n const target = index + direction\n if (index < 0 || target < 0 || target >= definitions.length) return\n const next = [...definitions]\n next[index] = definitions[target]\n next[target] = definitions[index]\n setBusyId(definition.$id)\n try {\n const verdict = await writeGuardedBySeed(\n { subject: 'field order', fromCache },\n async () => {\n const batch = writeBatch(firestore)\n const now = new Date()\n next.forEach((entry, position) => {\n if (entry.order === position) return\n batch.update(fieldRef(entry.$id), { order: position, updatedAt: now })\n })\n await batch.commit()\n },\n )\n if (!verdict.ok) {\n enqueueSnackbar(verdict.message, { variant: 'warning', persist: false })\n }\n } catch (error) {\n console.error(error)\n enqueueSnackbar('An error has occurred', { variant: 'error', allowDuplicate: true })\n } finally {\n setBusyId('')\n }\n },\n [scope, busyId, definitions, fromCache, firestore, fieldRef, enqueueSnackbar],\n )\n\n /**\n * Retire a field, or bring one back.\n *\n * Retiring is asked about because it takes a control off every contact\n * form and a column off the list; restoring is not, because it puts a\n * choice back and is undone by retiring again. Neither touches a value.\n */\n const toggleRetired = useCallback(\n async (definition: ContactFieldDefinitionDoc) => {\n if (!scope || busyId) return\n if (!definition.retiredAt) {\n const accepted = await confirm({\n title: `Retire “${definition.label}”?`,\n description:\n `It leaves every ${noun} form, column and form-field mapping. ` +\n 'Values already saved under it are kept and still export, and ' +\n 'you can restore the field at any time.',\n confirmationText: 'Retire',\n })\n // `confirm` resolves with no value and REJECTS on cancel, so gating\n // on the resolved value alone would always fall through.\n .then(() => true)\n .catch(() => false)\n if (!accepted) return\n }\n setBusyId(definition.$id)\n try {\n await updateDoc(fieldRef(definition.$id), {\n retiredAt: definition.retiredAt ? null : Date.now(),\n updatedAt: new Date(),\n })\n enqueueSnackbar(definition.retiredAt ? 'Field restored' : 'Field retired', {\n variant: 'success',\n persist: false,\n })\n } catch (error) {\n console.error(error)\n enqueueSnackbar('An error has occurred', { variant: 'error', allowDuplicate: true })\n } finally {\n setBusyId('')\n }\n },\n [scope, busyId, confirm, fieldRef, enqueueSnackbar, noun],\n )\n\n /**\n * Delete a RETIRED field's definition.\n *\n * The values under its key are not touched — they sit on contact documents\n * this page does not read — so what is destroyed is the ability to show\n * them anywhere. The dialog says exactly that, and the key stays taken for\n * as long as the list can see it, which after this write it cannot; a new\n * field with the same key would read the orphaned values back as its own.\n */\n const handleDelete = useCallback(\n async (definition: ContactFieldDefinitionDoc) => {\n if (!scope || busyId || !definition.retiredAt) return\n const accepted = await confirm({\n title: `Delete “${definition.label}”?`,\n description:\n 'The definition is removed for good. Values saved under its key ' +\n `(${definition.key}) stay on the ${noun}s that carry them but ` +\n 'nothing will show them again — and a new field created with the ' +\n 'same key would read them as its own.',\n confirmationText: 'Delete field',\n confirmationButtonProps: { color: 'error' },\n })\n .then(() => true)\n .catch(() => false)\n if (!accepted) return\n setBusyId(definition.$id)\n try {\n await deleteDoc(fieldRef(definition.$id))\n enqueueSnackbar('Field deleted', { variant: 'success', persist: false })\n } catch (error) {\n console.error(error)\n enqueueSnackbar('An error has occurred', { variant: 'error', allowDuplicate: true })\n } finally {\n setBusyId('')\n }\n },\n [scope, busyId, confirm, fieldRef, enqueueSnackbar, noun],\n )\n\n /*\n * Stable across renders, as the table's columns are built from them: a\n * fresh function each render would rebuild every column on every render.\n */\n const rowActions = useCallback(\n (definition: ContactFieldDefinitionDoc): RowActionsMenuItem[] => [\n {\n key: 'edit',\n label: 'Edit field',\n icon: <MdiIcon path={mdiPencilOutline.path} size={0.8} />,\n onClick: () => openEdit(definition),\n },\n {\n key: 'retire',\n label: definition.retiredAt ? 'Restore' : 'Retire',\n icon: (\n <MdiIcon\n path={definition.retiredAt ? mdiArchiveArrowUpOutline.path : mdiArchiveOutline.path}\n size={0.8}\n />\n ),\n destructive: !definition.retiredAt,\n disabled: Boolean(busyId),\n disabledReason: busyId ? 'Another field is being saved' : undefined,\n onClick: () => void toggleRetired(definition),\n },\n ...(definition.retiredAt\n ? [\n {\n key: 'delete',\n label: 'Delete',\n icon: <MdiIcon path={mdiDeleteOutline.path} size={0.8} />,\n destructive: true,\n disabled: Boolean(busyId),\n disabledReason: busyId ? 'Another field is being saved' : undefined,\n onClick: () => void handleDelete(definition),\n } satisfies RowActionsMenuItem,\n ]\n : []),\n ],\n [openEdit, toggleRetired, handleDelete, busyId],\n )\n const onMove = useCallback(\n (definition: ContactFieldDefinitionDoc, direction: -1 | 1) =>\n void move(definition, direction),\n [move],\n )\n\n return (\n <CardDisplay\n header={'Fields'}\n help={pluginDocsHelp('contactFields', { anchor: '#define-a-field' })}\n contentGutterX\n contentGutterY\n contentBordered=\"all\"\n HeaderProps={{\n action: scope ? (\n <Stack direction=\"row\" spacing={1} sx={{ alignItems: 'center' }}>\n {/* Every custom field, as a file (AGL-3528). */}\n <CrmExportButton resource={CRM_FIELDS_RESOURCE} hostId={hostId ?? null} />\n <Button size=\"small\" onClick={() => void recomputeNextActivity()} disabled={recomputing}>\n {recomputing ? 'Recomputing…' : 'Recompute next activity'}\n </Button>\n {tasksTab ? null : (\n <Button variant=\"contained\" onClick={openCreate}>\n {'New field'}\n </Button>\n )}\n </Stack>\n ) : null,\n }}\n >\n <Stack spacing={2}>\n <Tabs\n value={tab}\n onChange={(_event, next) => {\n if (isCrmPicklistObject(next)) setTab(next)\n }}\n aria-label=\"Fields by record\"\n variant=\"scrollable\"\n scrollButtons=\"auto\"\n allowScrollButtonsMobile\n >\n {CRM_PICKLIST_OBJECTS.map((entry) => (\n <Tab key={entry} value={entry} label={CRM_PICKLIST_OBJECT_LABELS[entry]} />\n ))}\n </Tabs>\n <Typography variant=\"body2\" color=\"text.secondary\">\n {`${tasksTab ? TASKS_INTRO : OBJECT_INTRO[object]} Fields are shared across every site in this ` +\n 'organization, like the records themselves.'}\n </Typography>\n {tasksTab ? null : scopeReady && !scope ? (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {`This site has no organization, so it has no ${noun} fields.`}\n </Typography>\n ) : !ready ? null : definitions.length === 0 ? (\n <EmptyStateComponent\n label={`No custom ${noun} fields yet`}\n description={`A field you define here is kept on every ${noun} and shows on its page.`}\n action={\n scope ? (\n <Button variant=\"contained\" onClick={openCreate}>\n {'New field'}\n </Button>\n ) : undefined\n }\n />\n ) : (\n /*\n Keyed by the tab, so a sort, a filter or a search made on one\n record's fields does not follow the reader onto another's.\n */\n <FieldsTable\n key={object}\n orgId={orgId}\n object={object}\n definitions={definitions}\n busyId={busyId}\n onMove={onMove}\n rowActions={rowActions}\n />\n )}\n {definitions.length && !tasksTab ? (\n <Typography variant=\"caption\" color=\"text.secondary\">\n {`How many ${noun}s carry a value under each field is not ` +\n `counted — that would read every ${noun} in the organization ` +\n 'each time this page opened.'}\n </Typography>\n ) : null}\n {/*\n The tab's standard picklists (AGL-3298, AGL-3510) — standard fields\n whose CHOICES are the org's, Salesforce's picklist value sets — one\n card each, beside the custom fields of the same record.\n */}\n {scope\n ? crmPicklistDefinitionsFor(tab).map((definition) => (\n <PicklistValuesCard\n key={definition.id}\n picklistId={definition.id as CrmPicklistId}\n hostId={hostId}\n orgId={orgId}\n createHostId={createHostId}\n />\n ))\n : null}\n </Stack>\n <ContactFieldDrawer\n open={drawerOpen}\n onClose={() => setDrawerOpen(false)}\n definition={editing}\n object={object}\n takenKeys={definitions.map((definition) => definition.key)}\n onSubmit={handleSubmit}\n />\n </CardDisplay>\n )\n}\nContactsFieldsSection.displayName = 'ContactsFieldsSection'\n\nexport default ContactsFieldsSection\n"],"names":["CrmExportButton","CRM_FIELDS_RESOURCE","CONTACT_FIELD_TYPE_LABELS","CONTACT_FIELD_TYPES","CONTACT_FIELDS_MAX_PER_ORG","createResourceUid","CRM_COLLECTIONS","crmFieldListFields","CRM_PICKLIST_OBJECT_LABELS","CRM_PICKLIST_OBJECTS","crmPicklistDefinitionsFor","isCrmPicklistObject","newResourceScopeFields","ORG_SCOPE_TOKEN","pluginDocsHelp","EmptyStateComponent","ListFilterChips","ListQueryNotices","listQueryRefusals","ListRowActions","ListTable","listActionsColumn","mdiArchiveArrowUpOutline","mdiArchiveOutline","mdiArrowDown","mdiArrowUp","mdiDeleteOutline","mdiPencilOutline","CardDisplay","MdiIcon","SrOnly","useConfirmationContext","listFilterGridColumns","planListQuery","useListGridFilter","nameSearchNormalizers","useSnackbar","ceilingedWindow","listQueryConstraints","useFirestore","useFirestoreCollection","useUser","writeGuardedBySeed","Button","Chip","IconButton","Stack","Tab","Tabs","Tooltip","Typography","collection","deleteDoc","doc","limit","query","setDoc","updateDoc","writeBatch","useCallback","useMemo","useState","useContactFieldDefinitions","useCrmScope","CRM_FIELD_LIST_QUERY","crmFieldListBase","ContactFieldDrawer","PicklistValuesCard","recomputeAllCrmNextActivity","crmTaskCallScope","OBJECT_INTRO","contact","company","deal","lead","TASKS_INTRO","OBJECT_NOUN","FIELD_FILTER_FIELDS","fields","FIELD_FILTER_HEADERS","type","required","FIELD_FILTER_OPTIONS","map","value","label","FIELD_REORDER_LOCKED_REASON","typeLabel","String","FieldsTable","props","orgId","object","definitions","busyId","onMove","rowActions","firestore","gridFilter","selectFields","sortModel","setSortModel","searching","searchWords","some","word","trim","reorderLocked","length","clauses","narrowed","plan","search","base","join","planKey","JSON","stringify","filters","orderBy","matched","contactFields","idField","answer","data","positions","Map","definition","position","$id","rows","shown","sort","a","b","get","Number","MAX_SAFE_INTEGER","key","refused","headers","options","columns","field","headerName","width","sortable","filterable","hideable","disableColumnMenu","renderCell","row","arrows","direction","spacing","sx","alignItems","variant","color","minWidth","textAlign","mr","size","disabled","Boolean","onClick","path","title","span","flex","useFlexGap","flexWrap","retiredAt","fontFamily","sortComparator","localeCompare","items","onChange","setClauses","marksServed","notices","truncated","aria-label","loading","status","onSortModelChange","filterMode","filterModel","onFilterModelChange","quickFilter","noRowsLabel","getRowClassName","opacity","displayName","ContactsFieldsSection","hostId","org","enqueueSnackbar","confirm","scope","ready","scopeReady","createHostId","tab","setTab","tasksTab","fromCache","noun","user","recomputing","setRecomputing","recomputeNextActivity","callScope","confirmed","description","confirmationText","then","catch","result","records","toLocaleString","tasks","cause","Error","message","drawerOpen","setDrawerOpen","editing","setEditing","setBusyId","fieldRef","id","openCreate","openEdit","handleSubmit","draft","now","Date","verdict","subject","updatedAt","ok","persist","order","reduce","highest","Math","max","createdAt","move","index","findIndex","entry","target","next","batch","forEach","update","commit","error","console","allowDuplicate","toggleRetired","accepted","handleDelete","confirmationButtonProps","icon","destructive","disabledReason","undefined","header","help","anchor","contentGutterX","contentGutterY","contentBordered","HeaderProps","action","resource","_event","scrollButtons","allowScrollButtonsMobile","picklistId","open","onClose","takenKeys","onSubmit"],"mappings":"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"}