@aglyn/plugins-crm 1.0.0-beta.221 → 1.0.0-beta.223
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -1
- package/package.json +13 -13
- package/src/lib/components/activity-list.js +12 -5
- package/src/lib/components/activity-list.js.map +1 -1
- package/src/lib/components/companies-bulk-bar.d.ts +1 -4
- package/src/lib/components/companies-bulk-bar.js +7 -20
- package/src/lib/components/companies-bulk-bar.js.map +1 -1
- package/src/lib/components/companies-section.d.ts +3 -3
- package/src/lib/components/companies-section.js +149 -46
- package/src/lib/components/companies-section.js.map +1 -1
- package/src/lib/components/company-edit-drawer.js +281 -20
- package/src/lib/components/company-edit-drawer.js.map +1 -1
- package/src/lib/components/company-properties-card.js +99 -8
- package/src/lib/components/company-properties-card.js.map +1 -1
- package/src/lib/components/contact-detail-page.js +3 -1
- package/src/lib/components/contact-detail-page.js.map +1 -1
- package/src/lib/components/contact-merge-dialog.js +33 -10
- package/src/lib/components/contact-merge-dialog.js.map +1 -1
- package/src/lib/components/contact-properties-card.d.ts +0 -69
- package/src/lib/components/contact-properties-card.js +350 -60
- package/src/lib/components/contact-properties-card.js.map +1 -1
- package/src/lib/components/contact-reports-to-field.d.ts +46 -0
- package/src/lib/components/contact-reports-to-field.js +67 -0
- package/src/lib/components/contact-reports-to-field.js.map +1 -0
- package/src/lib/components/contacts-bulk-bar.d.ts +1 -8
- package/src/lib/components/contacts-bulk-bar.js +7 -19
- package/src/lib/components/contacts-bulk-bar.js.map +1 -1
- package/src/lib/components/contacts-section.js +46 -33
- package/src/lib/components/contacts-section.js.map +1 -1
- package/src/lib/components/crm-call-actions.d.ts +10 -0
- package/src/lib/components/crm-call-actions.js +26 -9
- package/src/lib/components/crm-call-actions.js.map +1 -1
- package/src/lib/components/crm-next-activity-column.js +1 -1
- package/src/lib/components/crm-next-activity-column.js.map +1 -1
- package/src/lib/components/crm-record-picker.d.ts +15 -0
- package/src/lib/components/crm-record-picker.js +16 -10
- package/src/lib/components/crm-record-picker.js.map +1 -1
- package/src/lib/components/crm-transfer-buttons.d.ts +54 -0
- package/src/lib/components/crm-transfer-buttons.js +167 -0
- package/src/lib/components/crm-transfer-buttons.js.map +1 -0
- package/src/lib/components/deal-contact-roles-card.d.ts +46 -0
- package/src/lib/components/deal-contact-roles-card.js +368 -0
- package/src/lib/components/deal-contact-roles-card.js.map +1 -0
- package/src/lib/components/deal-detail-page.d.ts +3 -2
- package/src/lib/components/deal-detail-page.js +25 -6
- package/src/lib/components/deal-detail-page.js.map +1 -1
- package/src/lib/components/deal-edit-drawer.d.ts +10 -0
- package/src/lib/components/deal-edit-drawer.js +219 -10
- package/src/lib/components/deal-edit-drawer.js.map +1 -1
- package/src/lib/components/deal-properties-card.d.ts +7 -0
- package/src/lib/components/deal-properties-card.js +34 -3
- package/src/lib/components/deal-properties-card.js.map +1 -1
- package/src/lib/components/deal-stage-card.d.ts +4 -0
- package/src/lib/components/deal-stage-card.js +10 -2
- package/src/lib/components/deal-stage-card.js.map +1 -1
- package/src/lib/components/deals-bulk-bar.d.ts +0 -3
- package/src/lib/components/deals-bulk-bar.js +7 -20
- package/src/lib/components/deals-bulk-bar.js.map +1 -1
- package/src/lib/components/deals-section.d.ts +3 -3
- package/src/lib/components/deals-section.js +123 -63
- package/src/lib/components/deals-section.js.map +1 -1
- package/src/lib/components/fields-section.js +31 -17
- package/src/lib/components/fields-section.js.map +1 -1
- package/src/lib/components/lead-convert-dialog.d.ts +4 -0
- package/src/lib/components/lead-convert-dialog.js +23 -1
- package/src/lib/components/lead-convert-dialog.js.map +1 -1
- package/src/lib/components/lead-detail-page.js +8 -2
- package/src/lib/components/lead-detail-page.js.map +1 -1
- package/src/lib/components/lead-profile-fields.d.ts +71 -0
- package/src/lib/components/lead-profile-fields.js +386 -0
- package/src/lib/components/lead-profile-fields.js.map +1 -0
- package/src/lib/components/lead-properties-card.d.ts +2 -1
- package/src/lib/components/lead-properties-card.js +85 -176
- package/src/lib/components/lead-properties-card.js.map +1 -1
- package/src/lib/components/lead-source-select.d.ts +4 -23
- package/src/lib/components/lead-source-select.js +9 -73
- package/src/lib/components/lead-source-select.js.map +1 -1
- package/src/lib/components/lead-status-chip.d.ts +9 -3
- package/src/lib/components/lead-status-chip.js +8 -4
- package/src/lib/components/lead-status-chip.js.map +1 -1
- package/src/lib/components/lead-status-options.d.ts +20 -0
- package/src/lib/components/lead-status-options.js +51 -0
- package/src/lib/components/lead-status-options.js.map +1 -0
- package/src/lib/components/lead-unqualify-dialog.d.ts +5 -0
- package/src/lib/components/lead-unqualify-dialog.js +50 -18
- package/src/lib/components/lead-unqualify-dialog.js.map +1 -1
- package/src/lib/components/leads-bulk-bar.d.ts +0 -3
- package/src/lib/components/leads-bulk-bar.js +29 -29
- package/src/lib/components/leads-bulk-bar.js.map +1 -1
- package/src/lib/components/leads-section.js +120 -68
- package/src/lib/components/leads-section.js.map +1 -1
- package/src/lib/components/linked-deals-card.d.ts +4 -0
- package/src/lib/components/linked-deals-card.js +47 -3
- package/src/lib/components/linked-deals-card.js.map +1 -1
- package/src/lib/components/log-activity-dialog.js +43 -3
- package/src/lib/components/log-activity-dialog.js.map +1 -1
- package/src/lib/components/new-contact-drawer.d.ts +8 -0
- package/src/lib/components/new-contact-drawer.js +108 -6
- package/src/lib/components/new-contact-drawer.js.map +1 -1
- package/src/lib/components/new-lead-drawer.d.ts +9 -2
- package/src/lib/components/new-lead-drawer.js +88 -121
- package/src/lib/components/new-lead-drawer.js.map +1 -1
- package/src/lib/components/picklist-select.d.ts +36 -0
- package/src/lib/components/picklist-select.js +114 -0
- package/src/lib/components/picklist-select.js.map +1 -0
- package/src/lib/components/picklist-values-card.d.ts +34 -0
- package/src/lib/components/{lead-source-values-card.js → picklist-values-card.js} +241 -58
- package/src/lib/components/picklist-values-card.js.map +1 -0
- package/src/lib/components/pipeline-stages-dialog.d.ts +7 -0
- package/src/lib/components/pipeline-stages-dialog.js +26 -4
- package/src/lib/components/pipeline-stages-dialog.js.map +1 -1
- package/src/lib/components/pipelines-dialog.js +15 -6
- package/src/lib/components/pipelines-dialog.js.map +1 -1
- package/src/lib/components/recent-activity-feed.js +20 -5
- package/src/lib/components/recent-activity-feed.js.map +1 -1
- package/src/lib/components/recipes-card.js +4 -2
- package/src/lib/components/recipes-card.js.map +1 -1
- package/src/lib/components/record-tasks-card.js +15 -8
- package/src/lib/components/record-tasks-card.js.map +1 -1
- package/src/lib/components/reports/forecast-card.d.ts +6 -0
- package/src/lib/components/reports/forecast-card.js +101 -3
- package/src/lib/components/reports/forecast-card.js.map +1 -1
- package/src/lib/components/reports/lead-funnel-card.d.ts +12 -0
- package/src/lib/components/reports/lead-funnel-card.js +9 -5
- package/src/lib/components/reports/lead-funnel-card.js.map +1 -1
- package/src/lib/components/reports/lead-source-card.d.ts +23 -0
- package/src/lib/components/reports/lead-source-card.js +318 -0
- package/src/lib/components/reports/lead-source-card.js.map +1 -0
- package/src/lib/components/reports/pipeline-card.js +2 -1
- package/src/lib/components/reports/pipeline-card.js.map +1 -1
- package/src/lib/components/reports/report-export.js +1 -1
- package/src/lib/components/reports/report-export.js.map +1 -1
- package/src/lib/components/reports-section.js +8 -0
- package/src/lib/components/reports-section.js.map +1 -1
- package/src/lib/components/sharing-rule-drawer.d.ts +5 -0
- package/src/lib/components/sharing-rule-drawer.js +108 -19
- package/src/lib/components/sharing-rule-drawer.js.map +1 -1
- package/src/lib/components/sharing-rules-card.js +11 -3
- package/src/lib/components/sharing-rules-card.js.map +1 -1
- package/src/lib/components/task-cells.d.ts +9 -1
- package/src/lib/components/task-cells.js +9 -4
- package/src/lib/components/task-cells.js.map +1 -1
- package/src/lib/components/task-edit-drawer.js +111 -43
- package/src/lib/components/task-edit-drawer.js.map +1 -1
- package/src/lib/components/tasks-bulk-bar.d.ts +0 -3
- package/src/lib/components/tasks-bulk-bar.js +7 -20
- package/src/lib/components/tasks-bulk-bar.js.map +1 -1
- package/src/lib/components/tasks-calendar.d.ts +3 -0
- package/src/lib/components/tasks-calendar.js +8 -1
- package/src/lib/components/tasks-calendar.js.map +1 -1
- package/src/lib/components/tasks-section.d.ts +3 -3
- package/src/lib/components/tasks-section.js +58 -43
- package/src/lib/components/tasks-section.js.map +1 -1
- package/src/lib/constants/api-routes.d.ts +2 -9
- package/src/lib/constants/api-routes.js +1 -7
- package/src/lib/constants/api-routes.js.map +1 -1
- package/src/lib/constants/bundle-common.d.ts +6 -0
- package/src/lib/constants/bundle-common.js +11 -0
- package/src/lib/constants/bundle-common.js.map +1 -1
- package/src/lib/constants/company-filters.d.ts +14 -0
- package/src/lib/constants/company-filters.js +51 -1
- package/src/lib/constants/company-filters.js.map +1 -1
- package/src/lib/constants/contact-filters.d.ts +2 -0
- package/src/lib/constants/contact-filters.js +18 -1
- package/src/lib/constants/contact-filters.js.map +1 -1
- package/src/lib/constants/deal-filters.d.ts +22 -1
- package/src/lib/constants/deal-filters.js +67 -4
- package/src/lib/constants/deal-filters.js.map +1 -1
- package/src/lib/declarations.console-server.d.ts +3 -0
- package/src/lib/declarations.console-server.js +35 -0
- package/src/lib/declarations.console-server.js.map +1 -1
- package/src/lib/declarations.d.ts +26 -0
- package/src/lib/declarations.js +35 -0
- package/src/lib/declarations.js.map +1 -0
- package/src/lib/declarations.server.d.ts +11 -0
- package/src/lib/declarations.server.js +97 -1
- package/src/lib/declarations.server.js.map +1 -1
- package/src/lib/hooks/use-company-picklists.d.ts +15 -0
- package/src/lib/hooks/use-company-picklists.js +55 -0
- package/src/lib/hooks/use-company-picklists.js.map +1 -0
- package/src/lib/hooks/use-crm-picklist.d.ts +25 -0
- package/src/lib/hooks/use-crm-picklist.js +53 -0
- package/src/lib/hooks/use-crm-picklist.js.map +1 -0
- package/src/lib/hooks/use-crm-record-names.d.ts +16 -0
- package/src/lib/hooks/use-crm-record-names.js +45 -19
- package/src/lib/hooks/use-crm-record-names.js.map +1 -1
- package/src/lib/hooks/use-crm-task-picklists.d.ts +11 -0
- package/src/lib/hooks/use-crm-task-picklists.js +45 -0
- package/src/lib/hooks/use-crm-task-picklists.js.map +1 -0
- package/src/lib/hooks/use-deals.d.ts +14 -0
- package/src/lib/hooks/use-deals.js +29 -0
- package/src/lib/hooks/use-deals.js.map +1 -1
- package/src/lib/hooks/use-lead-picklists.d.ts +14 -0
- package/src/lib/hooks/use-lead-picklists.js +46 -0
- package/src/lib/hooks/use-lead-picklists.js.map +1 -0
- package/src/lib/hooks/use-lead-source-picklist.d.ts +5 -19
- package/src/lib/hooks/use-lead-source-picklist.js +12 -22
- package/src/lib/hooks/use-lead-source-picklist.js.map +1 -1
- package/src/lib/hooks/use-lead-status-picklist.d.ts +9 -0
- package/src/lib/hooks/use-lead-status-picklist.js +40 -0
- package/src/lib/hooks/use-lead-status-picklist.js.map +1 -0
- package/src/lib/model/companies.d.ts +32 -3
- package/src/lib/model/companies.js +133 -16
- package/src/lib/model/companies.js.map +1 -1
- package/src/lib/model/contact-merge.d.ts +27 -3
- package/src/lib/model/contact-merge.js +81 -7
- package/src/lib/model/contact-merge.js.map +1 -1
- package/src/lib/model/contact-record.d.ts +17 -0
- package/src/lib/model/contact-record.js +17 -2
- package/src/lib/model/contact-record.js.map +1 -1
- package/src/lib/model/contact-update.d.ts +31 -2
- package/src/lib/model/contact-update.js +14 -0
- package/src/lib/model/contact-update.js.map +1 -1
- package/src/lib/model/crm-list-query.d.ts +5 -0
- package/src/lib/model/crm-list-query.js +8 -0
- package/src/lib/model/crm-list-query.js.map +1 -1
- package/src/lib/model/crm-next-activity.d.ts +107 -0
- package/src/lib/model/crm-next-activity.js +140 -0
- package/src/lib/model/crm-next-activity.js.map +1 -0
- package/src/lib/model/crm-recipes.d.ts +40 -0
- package/src/lib/model/crm-recipes.js +259 -0
- package/src/lib/model/crm-recipes.js.map +1 -0
- package/src/lib/model/crm-record-counts.d.ts +36 -0
- package/src/lib/model/crm-record-counts.js +54 -0
- package/src/lib/model/crm-record-counts.js.map +1 -0
- package/src/lib/model/crm-record-lists.d.ts +23 -0
- package/src/lib/model/crm-record-lists.js +161 -0
- package/src/lib/model/crm-record-lists.js.map +1 -0
- package/src/lib/model/crm-reports.d.ts +73 -3
- package/src/lib/model/crm-reports.js +120 -1
- package/src/lib/model/crm-reports.js.map +1 -1
- package/src/lib/model/crm-sharing.d.ts +21 -3
- package/src/lib/model/crm-sharing.js +27 -6
- package/src/lib/model/crm-sharing.js.map +1 -1
- package/src/lib/model/crm-task-reminders.d.ts +152 -0
- package/src/lib/model/crm-task-reminders.js +161 -0
- package/src/lib/model/crm-task-reminders.js.map +1 -0
- package/src/lib/model/deal-board-model.d.ts +8 -2
- package/src/lib/model/deal-board-model.js +15 -2
- package/src/lib/model/deal-board-model.js.map +1 -1
- package/src/lib/model/deal-contact-roles.d.ts +45 -0
- package/src/lib/model/deal-contact-roles.js +73 -0
- package/src/lib/model/deal-contact-roles.js.map +1 -0
- package/src/lib/model/deal-form-model.d.ts +56 -0
- package/src/lib/model/deal-form-model.js +79 -7
- package/src/lib/model/deal-form-model.js.map +1 -1
- package/src/lib/model/download-text-file.d.ts +23 -0
- package/src/lib/model/download-text-file.js +34 -0
- package/src/lib/model/download-text-file.js.map +1 -0
- package/src/lib/model/lead-filters.d.ts +36 -2
- package/src/lib/model/lead-filters.js +123 -2
- package/src/lib/model/lead-filters.js.map +1 -1
- package/src/lib/model/lead-source-direction.d.ts +38 -0
- package/src/lib/model/lead-source-direction.js +52 -0
- package/src/lib/model/lead-source-direction.js.map +1 -0
- package/src/lib/model/next-activity.d.ts +1 -1
- package/src/lib/model/next-activity.js.map +1 -1
- package/src/lib/model/picklist-values.d.ts +119 -0
- package/src/lib/model/picklist-values.js +256 -0
- package/src/lib/model/picklist-values.js.map +1 -0
- package/src/lib/model/record-facts-disclosed.d.ts +81 -0
- package/src/lib/model/record-facts-disclosed.js +281 -0
- package/src/lib/model/record-facts-disclosed.js.map +1 -0
- package/src/lib/model/record-facts.d.ts +215 -34
- package/src/lib/model/record-facts.js +307 -128
- package/src/lib/model/record-facts.js.map +1 -1
- package/src/lib/model/task-picklists.d.ts +52 -0
- package/src/lib/model/task-picklists.js +83 -0
- package/src/lib/model/task-picklists.js.map +1 -0
- package/src/lib/model/task-routes.d.ts +13 -0
- package/src/lib/model/task-routes.js +23 -4
- package/src/lib/model/task-routes.js.map +1 -1
- package/src/lib/plan-entitlements.js +6 -4
- package/src/lib/plan-entitlements.js.map +1 -1
- package/src/lib/plugin.js +17 -0
- package/src/lib/plugin.js.map +1 -1
- package/src/lib/server/api-v1/contacts.js +220 -14
- package/src/lib/server/api-v1/contacts.js.map +1 -1
- package/src/lib/server/api-v1/crm-activities.js +14 -1
- package/src/lib/server/api-v1/crm-activities.js.map +1 -1
- package/src/lib/server/api-v1/crm-companies.js +123 -14
- package/src/lib/server/api-v1/crm-companies.js.map +1 -1
- package/src/lib/server/api-v1/crm-deals.js +291 -26
- package/src/lib/server/api-v1/crm-deals.js.map +1 -1
- package/src/lib/server/api-v1/crm-leads.js +144 -38
- package/src/lib/server/api-v1/crm-leads.js.map +1 -1
- package/src/lib/server/api-v1/crm-pipelines.d.ts +6 -0
- package/src/lib/server/api-v1/crm-pipelines.js +8 -2
- package/src/lib/server/api-v1/crm-pipelines.js.map +1 -1
- package/src/lib/server/api-v1/crm-tasks.js +78 -34
- package/src/lib/server/api-v1/crm-tasks.js.map +1 -1
- package/src/lib/server/api-v1/openapi.d.ts +0 -11
- package/src/lib/server/api-v1/openapi.js +171 -16
- package/src/lib/server/api-v1/openapi.js.map +1 -1
- package/src/lib/server/assign-contact-owner.d.ts +188 -0
- package/src/lib/server/assign-contact-owner.js +446 -0
- package/src/lib/server/assign-contact-owner.js.map +1 -0
- package/src/lib/server/associate-company-by-domain.d.ts +70 -0
- package/src/lib/server/associate-company-by-domain.js +153 -0
- package/src/lib/server/associate-company-by-domain.js.map +1 -0
- package/src/lib/server/automation-steps.d.ts +140 -0
- package/src/lib/server/automation-steps.js +669 -0
- package/src/lib/server/automation-steps.js.map +1 -0
- package/src/lib/server/capture-contact.d.ts +17 -0
- package/src/lib/server/capture-contact.js +95 -26
- package/src/lib/server/capture-contact.js.map +1 -1
- package/src/lib/server/capture-host-contact.d.ts +104 -0
- package/src/lib/server/capture-host-contact.js +151 -0
- package/src/lib/server/capture-host-contact.js.map +1 -0
- package/src/lib/server/company-children.d.ts +25 -0
- package/src/lib/server/company-children.js +42 -0
- package/src/lib/server/company-children.js.map +1 -0
- package/src/lib/server/company-delete.d.ts +18 -0
- package/src/lib/server/company-delete.js +44 -21
- package/src/lib/server/company-delete.js.map +1 -1
- package/src/lib/server/contact-email-history.js +21 -19
- package/src/lib/server/contact-email-history.js.map +1 -1
- package/src/lib/server/contact-remove.js +27 -2
- package/src/lib/server/contact-remove.js.map +1 -1
- package/src/lib/server/contact-reports-to.d.ts +61 -0
- package/src/lib/server/contact-reports-to.js +114 -0
- package/src/lib/server/contact-reports-to.js.map +1 -0
- package/src/lib/server/contact-update.d.ts +42 -1
- package/src/lib/server/contact-update.js +204 -23
- package/src/lib/server/contact-update.js.map +1 -1
- package/src/lib/server/convert-host-lead.d.ts +46 -1
- package/src/lib/server/convert-host-lead.js +173 -15
- package/src/lib/server/convert-host-lead.js.map +1 -1
- package/src/lib/server/convert-open-lead.js +12 -5
- package/src/lib/server/convert-open-lead.js.map +1 -1
- package/src/lib/server/crm-email-activity.d.ts +118 -0
- package/src/lib/server/crm-email-activity.js +148 -0
- package/src/lib/server/crm-email-activity.js.map +1 -0
- package/src/lib/server/crm-inbound-email.js +1 -1
- package/src/lib/server/crm-inbound-email.js.map +1 -1
- package/src/lib/server/crm-next-activity.d.ts +74 -0
- package/src/lib/server/crm-next-activity.js +194 -0
- package/src/lib/server/crm-next-activity.js.map +1 -0
- package/src/lib/server/crm-record-indexes.d.ts +45 -0
- package/src/lib/server/crm-record-indexes.js +78 -0
- package/src/lib/server/crm-record-indexes.js.map +1 -0
- package/src/lib/server/crm-sharing.d.ts +9 -1
- package/src/lib/server/crm-sharing.js +23 -3
- package/src/lib/server/crm-sharing.js.map +1 -1
- package/src/lib/server/deal-contact-roles.d.ts +27 -0
- package/src/lib/server/deal-contact-roles.js +89 -0
- package/src/lib/server/deal-contact-roles.js.map +1 -0
- package/src/lib/server/email-send.js +2 -1
- package/src/lib/server/email-send.js.map +1 -1
- package/src/lib/server/lead-convert.d.ts +5 -0
- package/src/lib/server/lead-convert.js +19 -3
- package/src/lib/server/lead-convert.js.map +1 -1
- package/src/lib/server/lead-create.d.ts +17 -2
- package/src/lib/server/lead-create.js +46 -14
- package/src/lib/server/lead-create.js.map +1 -1
- package/src/lib/server/lead-nurturing.d.ts +6 -0
- package/src/lib/server/lead-nurturing.js +57 -20
- package/src/lib/server/lead-nurturing.js.map +1 -1
- package/src/lib/server/lead-picklists.d.ts +35 -0
- package/src/lib/server/lead-picklists.js +52 -0
- package/src/lib/server/lead-picklists.js.map +1 -0
- package/src/lib/server/lead-source-picklist.d.ts +1 -13
- package/src/lib/server/lead-source-picklist.js +6 -33
- package/src/lib/server/lead-source-picklist.js.map +1 -1
- package/src/lib/server/merge-contacts.js +23 -5
- package/src/lib/server/merge-contacts.js.map +1 -1
- package/src/lib/server/next-activity-routes.js +2 -1
- package/src/lib/server/next-activity-routes.js.map +1 -1
- package/src/lib/server/person-eraser.d.ts +53 -0
- package/src/lib/server/person-eraser.js +149 -0
- package/src/lib/server/person-eraser.js.map +1 -0
- package/src/lib/server/person-records.d.ts +69 -0
- package/src/lib/server/person-records.js +317 -0
- package/src/lib/server/person-records.js.map +1 -0
- package/src/lib/server/person-refund.d.ts +97 -0
- package/src/lib/server/person-refund.js +221 -0
- package/src/lib/server/person-refund.js.map +1 -0
- package/src/lib/server/picklist-values.d.ts +21 -0
- package/src/lib/server/picklist-values.js +308 -0
- package/src/lib/server/picklist-values.js.map +1 -0
- package/src/lib/server/read-picklist.d.ts +44 -0
- package/src/lib/server/read-picklist.js +65 -0
- package/src/lib/server/read-picklist.js.map +1 -0
- package/src/lib/server/recipe-routes.js +22 -8
- package/src/lib/server/recipe-routes.js.map +1 -1
- package/src/lib/server/record-email-state.js +7 -1
- package/src/lib/server/record-email-state.js.map +1 -1
- package/src/lib/server/record-facts.d.ts +3 -0
- package/src/lib/server/record-facts.js +233 -31
- package/src/lib/server/record-facts.js.map +1 -1
- package/src/lib/server/record-origin.d.ts +27 -0
- package/src/lib/server/record-origin.js +104 -0
- package/src/lib/server/record-origin.js.map +1 -0
- package/src/lib/server/record-timeline.js +40 -3
- package/src/lib/server/record-timeline.js.map +1 -1
- package/src/lib/server/suite-gate.js +4 -3
- package/src/lib/server/suite-gate.js.map +1 -1
- package/src/lib/server/task-reminders-route.js +2 -1
- package/src/lib/server/task-reminders-route.js.map +1 -1
- package/src/lib/server/task-routes.js +33 -17
- package/src/lib/server/task-routes.js.map +1 -1
- package/src/lib/server-deal-stage.d.ts +5 -1
- package/src/lib/server-deal-stage.js +10 -5
- package/src/lib/server-deal-stage.js.map +1 -1
- package/src/lib/server.d.ts +8 -3
- package/src/lib/server.js +47 -43
- package/src/lib/server.js.map +1 -1
- package/src/lib/testing/memory-firestore.d.ts +55 -0
- package/src/lib/testing/memory-firestore.js +335 -0
- package/src/lib/testing/memory-firestore.js.map +1 -0
- package/src/lib/testing/stand-in-email-send-index.d.ts +25 -0
- package/src/lib/testing/stand-in-email-send-index.js +49 -0
- package/src/lib/testing/stand-in-email-send-index.js.map +1 -0
- package/src/lib/transfer/activities.d.ts +30 -0
- package/src/lib/transfer/activities.js +132 -0
- package/src/lib/transfer/activities.js.map +1 -0
- package/src/lib/transfer/aliases.d.ts +22 -0
- package/src/lib/transfer/aliases.js +1342 -0
- package/src/lib/transfer/aliases.js.map +1 -0
- package/src/lib/transfer/common.d.ts +222 -0
- package/src/lib/transfer/common.js +832 -0
- package/src/lib/transfer/common.js.map +1 -0
- package/src/lib/transfer/companies.d.ts +43 -0
- package/src/lib/transfer/companies.js +549 -0
- package/src/lib/transfer/companies.js.map +1 -0
- package/src/lib/transfer/contacts.d.ts +31 -0
- package/src/lib/transfer/contacts.js +727 -0
- package/src/lib/transfer/contacts.js.map +1 -0
- package/src/lib/transfer/deals.d.ts +66 -0
- package/src/lib/transfer/deals.js +698 -0
- package/src/lib/transfer/deals.js.map +1 -0
- package/src/lib/transfer/email-templates-package.d.ts +40 -0
- package/src/lib/transfer/email-templates-package.js +76 -0
- package/src/lib/transfer/email-templates-package.js.map +1 -0
- package/src/lib/transfer/email-templates-package.server.d.ts +32 -0
- package/src/lib/transfer/email-templates-package.server.js +176 -0
- package/src/lib/transfer/email-templates-package.server.js.map +1 -0
- package/src/lib/transfer/fields.d.ts +102 -0
- package/src/lib/transfer/fields.js +1755 -0
- package/src/lib/transfer/fields.js.map +1 -0
- package/src/lib/transfer/leads.d.ts +30 -0
- package/src/lib/transfer/leads.js +582 -0
- package/src/lib/transfer/leads.js.map +1 -0
- package/src/lib/transfer/pipelines.d.ts +21 -0
- package/src/lib/transfer/pipelines.js +172 -0
- package/src/lib/transfer/pipelines.js.map +1 -0
- package/src/lib/transfer/register.d.ts +47 -0
- package/src/lib/transfer/register.js +277 -0
- package/src/lib/transfer/register.js.map +1 -0
- package/src/lib/transfer/tasks.d.ts +30 -0
- package/src/lib/transfer/tasks.js +418 -0
- package/src/lib/transfer/tasks.js.map +1 -0
- package/src/lib/transfer/ui.d.ts +20 -0
- package/src/lib/transfer/ui.js +42 -0
- package/src/lib/transfer/ui.js.map +1 -0
- package/src/lib/components/company-import-drawer.d.ts +0 -42
- package/src/lib/components/company-import-drawer.js +0 -99
- package/src/lib/components/company-import-drawer.js.map +0 -1
- package/src/lib/components/contact-import-drawer.d.ts +0 -46
- package/src/lib/components/contact-import-drawer.js +0 -149
- package/src/lib/components/contact-import-drawer.js.map +0 -1
- package/src/lib/components/crm-export-all-button.d.ts +0 -39
- package/src/lib/components/crm-export-all-button.js +0 -98
- package/src/lib/components/crm-export-all-button.js.map +0 -1
- package/src/lib/components/csv-import-drawer.d.ts +0 -139
- package/src/lib/components/csv-import-drawer.js +0 -757
- package/src/lib/components/csv-import-drawer.js.map +0 -1
- package/src/lib/components/deal-import-drawer.d.ts +0 -24
- package/src/lib/components/deal-import-drawer.js +0 -83
- package/src/lib/components/deal-import-drawer.js.map +0 -1
- package/src/lib/components/lead-import-drawer.d.ts +0 -27
- package/src/lib/components/lead-import-drawer.js +0 -118
- package/src/lib/components/lead-import-drawer.js.map +0 -1
- package/src/lib/components/lead-source-values-card.d.ts +0 -27
- package/src/lib/components/lead-source-values-card.js.map +0 -1
- package/src/lib/components/task-import-drawer.d.ts +0 -24
- package/src/lib/components/task-import-drawer.js +0 -82
- package/src/lib/components/task-import-drawer.js.map +0 -1
- package/src/lib/model/companies-csv.d.ts +0 -36
- package/src/lib/model/companies-csv.js +0 -38
- package/src/lib/model/companies-csv.js.map +0 -1
- package/src/lib/model/contacts-csv.d.ts +0 -54
- package/src/lib/model/contacts-csv.js +0 -67
- package/src/lib/model/contacts-csv.js.map +0 -1
- package/src/lib/model/crm-company-import.d.ts +0 -154
- package/src/lib/model/crm-company-import.js +0 -331
- package/src/lib/model/crm-company-import.js.map +0 -1
- package/src/lib/model/crm-csv.d.ts +0 -239
- package/src/lib/model/crm-csv.js +0 -467
- package/src/lib/model/crm-csv.js.map +0 -1
- package/src/lib/model/crm-deal-import.d.ts +0 -112
- package/src/lib/model/crm-deal-import.js +0 -263
- package/src/lib/model/crm-deal-import.js.map +0 -1
- package/src/lib/model/crm-import.d.ts +0 -250
- package/src/lib/model/crm-import.js +0 -467
- package/src/lib/model/crm-import.js.map +0 -1
- package/src/lib/model/crm-lead-import.d.ts +0 -138
- package/src/lib/model/crm-lead-import.js +0 -446
- package/src/lib/model/crm-lead-import.js.map +0 -1
- package/src/lib/model/crm-task-import.d.ts +0 -94
- package/src/lib/model/crm-task-import.js +0 -275
- package/src/lib/model/crm-task-import.js.map +0 -1
- package/src/lib/model/deals-csv.d.ts +0 -32
- package/src/lib/model/deals-csv.js +0 -36
- package/src/lib/model/deals-csv.js.map +0 -1
- package/src/lib/model/import-column-shapes.d.ts +0 -36
- package/src/lib/model/import-column-shapes.js +0 -76
- package/src/lib/model/import-column-shapes.js.map +0 -1
- package/src/lib/model/lead-source-values.d.ts +0 -82
- package/src/lib/model/lead-source-values.js +0 -149
- package/src/lib/model/lead-source-values.js.map +0 -1
- package/src/lib/model/leads-csv.d.ts +0 -40
- package/src/lib/model/leads-csv.js +0 -40
- package/src/lib/model/leads-csv.js.map +0 -1
- package/src/lib/model/tasks-csv.d.ts +0 -28
- package/src/lib/model/tasks-csv.js +0 -28
- package/src/lib/model/tasks-csv.js.map +0 -1
- package/src/lib/server/companies-import.d.ts +0 -57
- package/src/lib/server/companies-import.js +0 -242
- package/src/lib/server/companies-import.js.map +0 -1
- package/src/lib/server/contacts-import.d.ts +0 -109
- package/src/lib/server/contacts-import.js +0 -393
- package/src/lib/server/contacts-import.js.map +0 -1
- package/src/lib/server/deals-import.d.ts +0 -76
- package/src/lib/server/deals-import.js +0 -248
- package/src/lib/server/deals-import.js.map +0 -1
- package/src/lib/server/export-route.d.ts +0 -60
- package/src/lib/server/export-route.js +0 -447
- package/src/lib/server/export-route.js.map +0 -1
- package/src/lib/server/import-context.d.ts +0 -87
- package/src/lib/server/import-context.js +0 -182
- package/src/lib/server/import-context.js.map +0 -1
- package/src/lib/server/lead-source-values.d.ts +0 -50
- package/src/lib/server/lead-source-values.js +0 -191
- package/src/lib/server/lead-source-values.js.map +0 -1
- package/src/lib/server/leads-import.d.ts +0 -84
- package/src/lib/server/leads-import.js +0 -367
- package/src/lib/server/leads-import.js.map +0 -1
- package/src/lib/server/tasks-import.d.ts +0 -54
- package/src/lib/server/tasks-import.js +0 -160
- package/src/lib/server/tasks-import.js.map +0 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { _ as _extends } from "@swc/helpers/_/_extends";
|
|
3
3
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
4
|
-
import {
|
|
4
|
+
import { CRM_LEAD_TEXT_MAX, crmLeadStatusLabelFor, crmLeadStatusOptions, containerMembershipValue, crmLeadComposedName, crmPicklistDefaultLabel, normalizeContactEmail, normalizeCrmLeadProfile } from "@aglyn/aglyn";
|
|
5
5
|
import { ICON_VARIANT_CLOSE } from "@aglyn/shared-data-enums";
|
|
6
6
|
import { Container, MdiIcon, SrOnly } from "@aglyn/shared-ui-jsx";
|
|
7
7
|
import { NavigationDrawerComponent } from "@aglyn/shared-ui-jsx/components/navigation-drawer.component";
|
|
@@ -11,13 +11,18 @@ import { useEffect, useState } from "react";
|
|
|
11
11
|
import { useContactFieldDefinitions } from "../hooks/use-contact-field-definitions.js";
|
|
12
12
|
import { useCrmCampaigns } from "../hooks/use-crm-campaigns.js";
|
|
13
13
|
import { useCrmScope } from "../hooks/use-crm-scope.js";
|
|
14
|
-
import {
|
|
14
|
+
import { EMPTY_LEAD_PROFILE_DRAFT, leadDraftComposedName, LeadProfileFields, leadProfileDraftBody } from "./lead-profile-fields.js";
|
|
15
15
|
import { CrmSitePicker } from "./crm-site-picker.js";
|
|
16
16
|
import { CrmCustomFieldControl } from "./crm-custom-field-control.js";
|
|
17
17
|
import { crmCustomDraftDocument, crmCustomDraftMissingRequired } from "../model/crm-custom-draft.js";
|
|
18
18
|
import { LeadOwnerSelect } from "./lead-owner-select.js";
|
|
19
|
-
import { LeadSourceSelect } from "./lead-source-select.js";
|
|
20
19
|
import { useLeadSourcePicklist } from "../hooks/use-lead-source-picklist.js";
|
|
20
|
+
import { useLeadPicklists } from "../hooks/use-lead-picklists.js";
|
|
21
|
+
import { useLeadStatusPicklist } from "../hooks/use-lead-status-picklist.js";
|
|
22
|
+
/** The meanings a lead is entered in by hand: New or Working (AGL-3231). */ const NEW_LEAD_STATUSES = [
|
|
23
|
+
'new',
|
|
24
|
+
'working'
|
|
25
|
+
];
|
|
21
26
|
const NOTES_MAX = 4000;
|
|
22
27
|
/**
|
|
23
28
|
* ADDING ONE LEAD BY HAND, IN A DRAWER (AGL-3231).
|
|
@@ -48,11 +53,16 @@ const NOTES_MAX = 4000;
|
|
|
48
53
|
});
|
|
49
54
|
const [email, setEmail] = useState('');
|
|
50
55
|
const [name, setName] = useState('');
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
const [
|
|
56
|
+
/*
|
|
57
|
+
* THE PROFILE (AGL-3231, AGL-3513), one draft the fields edit — the
|
|
58
|
+
* lead's page edits the same draft with the same fields.
|
|
59
|
+
*/ const [profile, setProfile] = useState(EMPTY_LEAD_PROFILE_DRAFT);
|
|
60
|
+
const [profileErrors, setProfileErrors] = useState({});
|
|
61
|
+
const editProfile = (key, value)=>setProfile((current)=>_extends({}, current, {
|
|
62
|
+
[key]: value
|
|
63
|
+
}));
|
|
64
|
+
// The org's Salutation, Industry and Rating lists (AGL-3513).
|
|
65
|
+
const leadPicklists = useLeadPicklists(open ? orgId != null ? orgId : null : null);
|
|
56
66
|
/*
|
|
57
67
|
* THE ORG'S LEAD SOURCES (AGL-3298), and its default for a new record.
|
|
58
68
|
* The default is filled in once the list has answered and only until the
|
|
@@ -62,17 +72,23 @@ const NOTES_MAX = 4000;
|
|
|
62
72
|
const [leadSourceTouched, setLeadSourceTouched] = useState(false);
|
|
63
73
|
const defaultLeadSource = (_crmPicklistDefaultLabel = crmPicklistDefaultLabel(leadSources.picklist)) != null ? _crmPicklistDefaultLabel : '';
|
|
64
74
|
useEffect(()=>{
|
|
65
|
-
if (open && !leadSourceTouched)
|
|
75
|
+
if (open && !leadSourceTouched) {
|
|
76
|
+
setProfile((current)=>_extends({}, current, {
|
|
77
|
+
leadSource: defaultLeadSource
|
|
78
|
+
}));
|
|
79
|
+
}
|
|
66
80
|
}, [
|
|
67
81
|
open,
|
|
68
82
|
leadSourceTouched,
|
|
69
83
|
defaultLeadSource
|
|
70
84
|
]);
|
|
71
|
-
|
|
85
|
+
// The org's New and Working values (AGL-3512); a new lead starts as New's.
|
|
86
|
+
const leadStatuses = useLeadStatusPicklist(orgId != null ? orgId : null);
|
|
87
|
+
const statusChoices = crmLeadStatusOptions(leadStatuses.picklist, NEW_LEAD_STATUSES);
|
|
88
|
+
const [status, setStatus] = useState('');
|
|
89
|
+
const shownStatus = statusChoices.some((choice)=>choice.label === status) ? status : crmLeadStatusLabelFor(leadStatuses.picklist, 'new');
|
|
72
90
|
const [ownerUid, setOwnerUid] = useState('');
|
|
73
|
-
const [tags, setTags] = useState('');
|
|
74
91
|
const [campaignIds, setCampaignIds] = useState([]);
|
|
75
|
-
const [address, setAddress] = useState(EMPTY_ADDRESS);
|
|
76
92
|
const [notes, setNotes] = useState('');
|
|
77
93
|
/*
|
|
78
94
|
* The org's own lead fields (AGL-3272). A CREATE holds only a draft —
|
|
@@ -82,8 +98,6 @@ const NOTES_MAX = 4000;
|
|
|
82
98
|
const [custom, setCustom] = useState({});
|
|
83
99
|
const [customError, setCustomError] = useState('');
|
|
84
100
|
const [emailError, setEmailError] = useState('');
|
|
85
|
-
const [phoneError, setPhoneError] = useState('');
|
|
86
|
-
const [websiteError, setWebsiteError] = useState('');
|
|
87
101
|
/*
|
|
88
102
|
* The campaigns, for the picker (AGL-3254): read while the drawer is
|
|
89
103
|
* open. Under a site, the ones placed on it; at the organization level,
|
|
@@ -101,63 +115,73 @@ const NOTES_MAX = 4000;
|
|
|
101
115
|
if (!open) return;
|
|
102
116
|
setEmail('');
|
|
103
117
|
setName('');
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
setPhone('');
|
|
107
|
-
setWebsite('');
|
|
108
|
-
setLeadSource('');
|
|
118
|
+
setProfile(EMPTY_LEAD_PROFILE_DRAFT);
|
|
119
|
+
setProfileErrors({});
|
|
109
120
|
setLeadSourceTouched(false);
|
|
110
|
-
setStatus('
|
|
121
|
+
setStatus('');
|
|
111
122
|
setOwnerUid('');
|
|
112
|
-
setTags('');
|
|
113
123
|
setCampaignIds([]);
|
|
114
|
-
setAddress(EMPTY_ADDRESS);
|
|
115
124
|
setNotes('');
|
|
116
125
|
setCustom({});
|
|
117
126
|
setCustomError('');
|
|
118
127
|
setEmailError('');
|
|
119
|
-
setPhoneError('');
|
|
120
|
-
setWebsiteError('');
|
|
121
128
|
}, [
|
|
122
129
|
open
|
|
123
130
|
]);
|
|
124
131
|
const handleSubmit = ()=>{
|
|
125
|
-
var
|
|
132
|
+
var _crmLeadComposedName, _patch_company, _patch_jobTitle, _patch_phone, _patch_website, _patch_leadSource, _patch_tags, _patch_address;
|
|
126
133
|
const normalizedEmail = normalizeContactEmail(email);
|
|
127
|
-
const {
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
website,
|
|
132
|
-
leadSource,
|
|
133
|
-
address,
|
|
134
|
-
tags: normalizeCrmLeadTags(tags)
|
|
135
|
-
});
|
|
134
|
+
const { body, revenueError } = leadProfileDraftBody(profile);
|
|
135
|
+
const { patch, errors } = normalizeCrmLeadProfile(body);
|
|
136
|
+
const shown = _extends({}, errors);
|
|
137
|
+
if (revenueError) shown['annualRevenueCents'] = revenueError;
|
|
136
138
|
// Every required lead field counts on a create: the record is being
|
|
137
139
|
// made whole, and nothing has been written to come back and fill.
|
|
138
140
|
const missing = crmCustomDraftMissingRequired(fields.active, {}, custom, 'create');
|
|
139
141
|
setEmailError(normalizedEmail ? '' : 'Enter a valid email address.');
|
|
140
|
-
|
|
141
|
-
setWebsiteError((_errors_website = errors.website) != null ? _errors_website : '');
|
|
142
|
+
setProfileErrors(shown);
|
|
142
143
|
setCustomError(missing.length ? `${missing.join(', ')} ${missing.length > 1 ? 'are' : 'is'} required.` : '');
|
|
143
|
-
if (!normalizedEmail ||
|
|
144
|
+
if (!normalizedEmail || Object.keys(shown).length || missing.length) return;
|
|
145
|
+
// Only what was filled: a create has nothing to clear.
|
|
146
|
+
const standard = {};
|
|
147
|
+
for (const key of [
|
|
148
|
+
'salutation',
|
|
149
|
+
'firstName',
|
|
150
|
+
'lastName',
|
|
151
|
+
'mobilePhone',
|
|
152
|
+
'fax',
|
|
153
|
+
'doNotCall',
|
|
154
|
+
'industry',
|
|
155
|
+
'rating',
|
|
156
|
+
'annualRevenueCents',
|
|
157
|
+
'currency',
|
|
158
|
+
'numberOfEmployees'
|
|
159
|
+
]){
|
|
160
|
+
const value = patch[key];
|
|
161
|
+
if (value !== null && value !== undefined) Object.assign(standard, {
|
|
162
|
+
[key]: value
|
|
163
|
+
});
|
|
164
|
+
}
|
|
144
165
|
onSubmit({
|
|
145
166
|
email: normalizedEmail,
|
|
146
|
-
name
|
|
167
|
+
// While a first or last name is typed, the name is theirs (AGL-3513).
|
|
168
|
+
name: (_crmLeadComposedName = crmLeadComposedName(null, patch)) != null ? _crmLeadComposedName : name.trim().replace(/\s+/g, ' ').slice(0, CRM_LEAD_TEXT_MAX),
|
|
147
169
|
company: (_patch_company = patch.company) != null ? _patch_company : '',
|
|
148
170
|
jobTitle: (_patch_jobTitle = patch.jobTitle) != null ? _patch_jobTitle : '',
|
|
149
171
|
phone: (_patch_phone = patch.phone) != null ? _patch_phone : '',
|
|
150
172
|
website: (_patch_website = patch.website) != null ? _patch_website : '',
|
|
151
173
|
leadSource: (_patch_leadSource = patch.leadSource) != null ? _patch_leadSource : '',
|
|
152
|
-
status,
|
|
174
|
+
status: shownStatus,
|
|
153
175
|
ownerUid,
|
|
154
176
|
tags: (_patch_tags = patch.tags) != null ? _patch_tags : [],
|
|
155
177
|
campaignIds: containerMembershipValue(campaignIds),
|
|
156
178
|
address: (_patch_address = patch.address) != null ? _patch_address : null,
|
|
157
179
|
notes: notes.trim().slice(0, NOTES_MAX),
|
|
158
|
-
custom: crmCustomDraftDocument(custom)
|
|
180
|
+
custom: crmCustomDraftDocument(custom),
|
|
181
|
+
standard
|
|
159
182
|
});
|
|
160
183
|
};
|
|
184
|
+
const composedName = leadDraftComposedName(profile);
|
|
161
185
|
return /*#__PURE__*/ _jsx(NavigationDrawerComponent, {
|
|
162
186
|
open: open,
|
|
163
187
|
anchor: "right",
|
|
@@ -234,67 +258,33 @@ const NOTES_MAX = 4000;
|
|
|
234
258
|
/*#__PURE__*/ _jsx(TextField, {
|
|
235
259
|
size: "small",
|
|
236
260
|
label: "Name",
|
|
237
|
-
value: name,
|
|
261
|
+
value: composedName || name,
|
|
238
262
|
onChange: (event)=>setName(event.target.value),
|
|
239
263
|
slotProps: {
|
|
240
264
|
htmlInput: {
|
|
241
265
|
maxLength: CRM_LEAD_TEXT_MAX
|
|
266
|
+
},
|
|
267
|
+
input: {
|
|
268
|
+
readOnly: Boolean(composedName)
|
|
242
269
|
}
|
|
243
270
|
},
|
|
271
|
+
helperText: composedName ? 'Made of the first and last name.' : 'Or the whole name in one field.',
|
|
244
272
|
fullWidth: true
|
|
245
273
|
}),
|
|
246
|
-
/*#__PURE__*/ _jsx(
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
helperText: "As text — converting the lead is what makes it a company record.",
|
|
252
|
-
slotProps: {
|
|
253
|
-
htmlInput: {
|
|
254
|
-
maxLength: CRM_LEAD_TEXT_MAX
|
|
255
|
-
}
|
|
256
|
-
},
|
|
257
|
-
fullWidth: true
|
|
258
|
-
}),
|
|
259
|
-
/*#__PURE__*/ _jsx(TextField, {
|
|
260
|
-
size: "small",
|
|
261
|
-
label: "Job title",
|
|
262
|
-
value: jobTitle,
|
|
263
|
-
onChange: (event)=>setJobTitle(event.target.value),
|
|
264
|
-
slotProps: {
|
|
265
|
-
htmlInput: {
|
|
266
|
-
maxLength: CRM_LEAD_TEXT_MAX
|
|
267
|
-
}
|
|
268
|
-
},
|
|
269
|
-
fullWidth: true
|
|
270
|
-
}),
|
|
271
|
-
/*#__PURE__*/ _jsx(TextField, {
|
|
272
|
-
size: "small",
|
|
273
|
-
label: "Phone",
|
|
274
|
-
value: phone,
|
|
275
|
-
onChange: (event)=>setPhone(event.target.value),
|
|
276
|
-
error: Boolean(phoneError),
|
|
277
|
-
helperText: phoneError || 'With the country code, like +1 512 555 0107',
|
|
278
|
-
fullWidth: true
|
|
279
|
-
}),
|
|
280
|
-
/*#__PURE__*/ _jsx(TextField, {
|
|
281
|
-
size: "small",
|
|
282
|
-
label: "Website",
|
|
283
|
-
value: website,
|
|
284
|
-
onChange: (event)=>setWebsite(event.target.value),
|
|
285
|
-
error: Boolean(websiteError),
|
|
286
|
-
helperText: websiteError || 'Like acme.com',
|
|
287
|
-
fullWidth: true
|
|
288
|
-
}),
|
|
289
|
-
/*#__PURE__*/ _jsx(LeadSourceSelect, {
|
|
290
|
-
picklist: leadSources.picklist,
|
|
291
|
-
value: leadSource,
|
|
292
|
-
onChange: (label)=>{
|
|
293
|
-
setLeadSource(label);
|
|
294
|
-
setLeadSourceTouched(true);
|
|
274
|
+
/*#__PURE__*/ _jsx(LeadProfileFields, {
|
|
275
|
+
draft: profile,
|
|
276
|
+
onChange: (key, value)=>{
|
|
277
|
+
if (key === 'leadSource') setLeadSourceTouched(true);
|
|
278
|
+
editProfile(key, value);
|
|
295
279
|
},
|
|
280
|
+
errors: profileErrors,
|
|
296
281
|
disabled: Boolean(busy),
|
|
297
|
-
|
|
282
|
+
leadSources: leadSources.picklist,
|
|
283
|
+
lists: leadPicklists.lists,
|
|
284
|
+
helperTexts: {
|
|
285
|
+
company: 'As text — converting the lead is what makes it a company record.',
|
|
286
|
+
leadSource: 'Where this lead came from. The choices are kept under CRM › Fields › Leads.'
|
|
287
|
+
}
|
|
298
288
|
}),
|
|
299
289
|
/*#__PURE__*/ _jsxs(Stack, {
|
|
300
290
|
direction: {
|
|
@@ -303,23 +293,17 @@ const NOTES_MAX = 4000;
|
|
|
303
293
|
},
|
|
304
294
|
spacing: 2,
|
|
305
295
|
children: [
|
|
306
|
-
/*#__PURE__*/
|
|
296
|
+
/*#__PURE__*/ _jsx(TextField, {
|
|
307
297
|
select: true,
|
|
308
298
|
size: "small",
|
|
309
299
|
label: "Status",
|
|
310
|
-
value:
|
|
311
|
-
onChange: (event)=>setStatus(event.target.value),
|
|
300
|
+
value: statusChoices.some((choice)=>choice.label === shownStatus) ? shownStatus : '',
|
|
301
|
+
onChange: (event)=>setStatus(String(event.target.value)),
|
|
312
302
|
fullWidth: true,
|
|
313
|
-
children:
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
}),
|
|
318
|
-
/*#__PURE__*/ _jsx(MenuItem, {
|
|
319
|
-
value: "working",
|
|
320
|
-
children: CRM_LEAD_STATUS_LABELS.working
|
|
321
|
-
})
|
|
322
|
-
]
|
|
303
|
+
children: statusChoices.map((choice)=>/*#__PURE__*/ _jsx(MenuItem, {
|
|
304
|
+
value: choice.label,
|
|
305
|
+
children: choice.label
|
|
306
|
+
}, choice.label))
|
|
323
307
|
}),
|
|
324
308
|
/*#__PURE__*/ _jsx(LeadOwnerSelect, {
|
|
325
309
|
value: ownerUid,
|
|
@@ -328,15 +312,6 @@ const NOTES_MAX = 4000;
|
|
|
328
312
|
})
|
|
329
313
|
]
|
|
330
314
|
}),
|
|
331
|
-
/*#__PURE__*/ _jsx(TextField, {
|
|
332
|
-
size: "small",
|
|
333
|
-
label: "Tags",
|
|
334
|
-
placeholder: "icp2, a-list",
|
|
335
|
-
helperText: "Comma-separated",
|
|
336
|
-
value: tags,
|
|
337
|
-
onChange: (event)=>setTags(event.target.value),
|
|
338
|
-
fullWidth: true
|
|
339
|
-
}),
|
|
340
315
|
/*#__PURE__*/ _jsx(ContainerPicker, {
|
|
341
316
|
kind: "campaign",
|
|
342
317
|
options: campaigns.options,
|
|
@@ -347,14 +322,6 @@ const NOTES_MAX = 4000;
|
|
|
347
322
|
empty: campaigns.ready && !campaigns.options.length,
|
|
348
323
|
emptyText: hostId ? 'This site has no campaigns yet. Create one from Marketing to file leads under it.' : 'There are no campaigns yet. Create one from Marketing to file leads under it.'
|
|
349
324
|
}),
|
|
350
|
-
/*#__PURE__*/ _jsx(Typography, {
|
|
351
|
-
variant: "subtitle2",
|
|
352
|
-
children: 'Address'
|
|
353
|
-
}),
|
|
354
|
-
/*#__PURE__*/ _jsx(ContactAddressFields, {
|
|
355
|
-
value: address,
|
|
356
|
-
onChange: setAddress
|
|
357
|
-
}),
|
|
358
325
|
fields.active.length ? /*#__PURE__*/ _jsxs(_Fragment, {
|
|
359
326
|
children: [
|
|
360
327
|
/*#__PURE__*/ _jsx(Typography, {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../../libs/plugins/crm/src/lib/components/new-lead-drawer.tsx"],"sourcesContent":["'use client'\n\nimport {\n CRM_LEAD_STATUS_LABELS,\n CRM_LEAD_TEXT_MAX,\n type CrmCustomValue,\n type CrmLeadStatus,\n containerMembershipValue,\n crmPicklistDefaultLabel,\n normalizeCrmLeadTags,\n normalizeContactEmail,\n normalizeCrmLeadProfile,\n type AglynPostalAddress,\n} from '@aglyn/aglyn'\nimport { ICON_VARIANT_CLOSE } from '@aglyn/shared-data-enums'\nimport { Container, MdiIcon, SrOnly } from '@aglyn/shared-ui-jsx'\nimport { NavigationDrawerComponent } from '@aglyn/shared-ui-jsx/components/navigation-drawer.component'\nimport {\n Alert,\n Button,\n IconButton,\n MenuItem,\n Stack,\n TextField,\n Typography,\n} from '@mui/material'\nimport ContainerPicker from '@aglyn/tenant-feature-instance/components/container-picker'\nimport { useEffect, useState } from 'react'\nimport { useContactFieldDefinitions } from '../hooks/use-contact-field-definitions'\nimport { useCrmCampaigns } from '../hooks/use-crm-campaigns'\nimport { useCrmScope } from '../hooks/use-crm-scope'\nimport type { OrgMemberOptions } from '../hooks/use-org-member-options'\nimport {\n ContactAddressFields,\n EMPTY_ADDRESS,\n type AddressDraft,\n} from './contact-address-fields'\nimport { CrmSitePicker } from './crm-site-picker'\nimport { CrmCustomFieldControl } from './crm-custom-field-control'\nimport {\n type CrmCustomDraft,\n crmCustomDraftDocument,\n crmCustomDraftMissingRequired,\n} from '../model/crm-custom-draft'\nimport { LeadOwnerSelect } from './lead-owner-select'\nimport { LeadSourceSelect } from './lead-source-select'\nimport { useLeadSourcePicklist } from '../hooks/use-lead-source-picklist'\n\n/** What the drawer hands back — already normalized where the route would. */\nexport interface NewLeadValues {\n email: string\n name: string\n company: string\n jobTitle: string\n phone: string\n website: string\n leadSource: string\n status: Extract<CrmLeadStatus, 'new' | 'working'>\n ownerUid: string\n tags: string[]\n /** The site's campaigns to file the lead under (AGL-3254), by id. */\n campaignIds: string[]\n address: AglynPostalAddress | null\n notes: string\n /**\n * The org's custom lead fields (AGL-3272), keyed by each definition's\n * `key`. Absent when the org has defined none, or none was filled — the\n * route stores a `custom` map only when there is one.\n */\n custom?: Record<string, CrmCustomValue>\n}\n\nexport interface NewLeadDrawerProps {\n open: boolean\n onClose: () => void\n /**\n * The site the lead is filed under — a lead is private to one site by\n * path. `null` at the organization level, where the drawer asks which\n * site with a picker and holds its submit until one is named.\n */\n hostId: string | null\n org?: Record<string, unknown> | null\n /** The request is in flight — the form holds still and the button says so. */\n busy?: boolean\n /** What the route answered when it refused, shown above the form. */\n error?: string | null\n /** The team, for the owner picker. */\n roster: OrgMemberOptions\n /**\n * The org the custom lead fields belong to (AGL-3272), as the list\n * already resolved it. `null` while it is in flight — the drawer then\n * shows the standard fields and no custom ones, which is what an org\n * with none defined shows anyway.\n */\n orgId?: string | null\n onSubmit: (values: NewLeadValues) => void\n}\n\nconst NOTES_MAX = 4000\n\n/**\n * ADDING ONE LEAD BY HAND, IN A DRAWER (AGL-3231).\n *\n * Salesforce's New Lead, on the Leads list: a person the team has heard of\n * and not yet qualified, entered with what is known — the address, the\n * name, the company as text, a title, a phone, a website, an address, tags\n * and where they came from. It makes a lead and nothing else: no contact,\n * no company record. Those are the conversion's to create once the lead is\n * real, which is what keeps one person from sitting in two lists.\n *\n * A drawer and not a form above the list, for the reason every list in this\n * console gives. The two fields a person can mistype in a way the record\n * cannot hold — the email and the phone, and the website beside them — are\n * checked before the request leaves, with the same normalizer the route\n * runs, so the refusal lands under the field. Everything else is the\n * route's to decide: whether the site already holds the address (it\n * updates that lead), whether the plan carries the suite, whether the site\n * is at the platform ceiling.\n */\nexport function NewLeadDrawer(props: NewLeadDrawerProps) {\n const { open, onClose, hostId, org, busy, error, roster, orgId, onSubmit } = props\n // The site the route files the lead under: the mounted site, or at the\n // organization level the picked one. `null` until it is known.\n const { createHostId } = useCrmScope({ hostId, org: org as never })\n\n const [email, setEmail] = useState('')\n const [name, setName] = useState('')\n const [company, setCompany] = useState('')\n const [jobTitle, setJobTitle] = useState('')\n const [phone, setPhone] = useState('')\n const [website, setWebsite] = useState('')\n const [leadSource, setLeadSource] = useState('')\n /*\n * THE ORG'S LEAD SOURCES (AGL-3298), and its default for a new record.\n * The default is filled in once the list has answered and only until the\n * person picks something themselves — \"None\" included — so a list that\n * arrives after the drawer opened does not overwrite a choice.\n */\n const leadSources = useLeadSourcePicklist(orgId ?? null)\n const [leadSourceTouched, setLeadSourceTouched] = useState(false)\n const defaultLeadSource = crmPicklistDefaultLabel(leadSources.picklist) ?? ''\n useEffect(() => {\n if (open && !leadSourceTouched) setLeadSource(defaultLeadSource)\n }, [open, leadSourceTouched, defaultLeadSource])\n const [status, setStatus] = useState<NewLeadValues['status']>('new')\n const [ownerUid, setOwnerUid] = useState('')\n const [tags, setTags] = useState('')\n const [campaignIds, setCampaignIds] = useState<string[]>([])\n const [address, setAddress] = useState<AddressDraft>(EMPTY_ADDRESS)\n const [notes, setNotes] = useState('')\n /*\n * The org's own lead fields (AGL-3272). A CREATE holds only a draft —\n * there is no stored map to diff against — and `crmCustomDraftDocument`\n * turns it into the `custom` the route stores, or nothing.\n */\n const fields = useContactFieldDefinitions(orgId ?? null, 'lead')\n const [custom, setCustom] = useState<CrmCustomDraft>({})\n const [customError, setCustomError] = useState('')\n const [emailError, setEmailError] = useState('')\n const [phoneError, setPhoneError] = useState('')\n const [websiteError, setWebsiteError] = useState('')\n /*\n * The campaigns, for the picker (AGL-3254): read while the drawer is\n * open. Under a site, the ones placed on it; at the organization level,\n * every campaign in the org — the lead is the org's record whichever\n * site it is captured by, so the site picked above does not narrow them.\n */\n const campaigns = useCrmCampaigns({ hostId, orgId }, { enabled: open })\n\n // A fresh form on every opening: a person typed and then abandoned must\n // not reappear half-filled the next time somebody reaches for New lead.\n useEffect(() => {\n if (!open) return\n setEmail('')\n setName('')\n setCompany('')\n setJobTitle('')\n setPhone('')\n setWebsite('')\n setLeadSource('')\n setLeadSourceTouched(false)\n setStatus('new')\n setOwnerUid('')\n setTags('')\n setCampaignIds([])\n setAddress(EMPTY_ADDRESS)\n setNotes('')\n setCustom({})\n setCustomError('')\n setEmailError('')\n setPhoneError('')\n setWebsiteError('')\n }, [open])\n\n const handleSubmit = () => {\n const normalizedEmail = normalizeContactEmail(email)\n const { patch, errors } = normalizeCrmLeadProfile({\n company,\n jobTitle,\n phone,\n website,\n leadSource,\n address,\n tags: normalizeCrmLeadTags(tags),\n })\n // Every required lead field counts on a create: the record is being\n // made whole, and nothing has been written to come back and fill.\n const missing = crmCustomDraftMissingRequired(fields.active, {}, custom, 'create')\n setEmailError(normalizedEmail ? '' : 'Enter a valid email address.')\n setPhoneError(errors.phone ?? '')\n setWebsiteError(errors.website ?? '')\n setCustomError(\n missing.length\n ? `${missing.join(', ')} ${missing.length > 1 ? 'are' : 'is'} required.`\n : '',\n )\n if (!normalizedEmail || errors.phone || errors.website || missing.length) return\n onSubmit({\n email: normalizedEmail,\n name: name.trim().replace(/\\s+/g, ' ').slice(0, CRM_LEAD_TEXT_MAX),\n company: patch.company ?? '',\n jobTitle: patch.jobTitle ?? '',\n phone: patch.phone ?? '',\n website: patch.website ?? '',\n leadSource: patch.leadSource ?? '',\n status,\n ownerUid,\n tags: patch.tags ?? [],\n campaignIds: containerMembershipValue(campaignIds),\n address: patch.address ?? null,\n notes: notes.trim().slice(0, NOTES_MAX),\n custom: crmCustomDraftDocument(custom),\n })\n }\n\n return (\n <NavigationDrawerComponent\n open={open}\n anchor=\"right\"\n variant=\"temporary\"\n onClose={onClose}\n AppBarProps={{ color: 'surface' }}\n sx={{ '& .MuiDrawer-paper': { width: { xs: '100%', sm: 480 } } }}\n appBarLeft={\n <>\n <IconButton\n color=\"inherit\"\n edge=\"start\"\n onClick={onClose}\n sx={{ mr: 2 }}\n >\n <MdiIcon path={ICON_VARIANT_CLOSE.path} />\n <SrOnly>close drawer</SrOnly>\n </IconButton>\n <Typography variant=\"h6\" component=\"div\">\n {'New lead'}\n </Typography>\n </>\n }\n appBarRight={\n <Button variant=\"outlined\" color=\"inherit\" onClick={onClose}>\n {'Cancel'}\n </Button>\n }\n >\n <Container gutterY>\n <Stack spacing={2}>\n {error ? <Alert severity=\"warning\">{error}</Alert> : null}\n {/* First, because the lead is filed under the answer. Renders nothing under a site. */}\n <CrmSitePicker\n hostId={hostId}\n disabled={Boolean(busy)}\n helperText=\"The site this lead is filed under — a lead is private to one site.\"\n />\n <TextField\n size=\"small\"\n label=\"Email\"\n type=\"email\"\n value={email}\n onChange={(event) => setEmail(event.target.value)}\n error={Boolean(emailError)}\n helperText={\n emailError ||\n 'The one field that is required — a site holds one lead per address.'\n }\n required\n fullWidth\n autoFocus\n />\n <TextField\n size=\"small\"\n label=\"Name\"\n value={name}\n onChange={(event) => setName(event.target.value)}\n slotProps={{ htmlInput: { maxLength: CRM_LEAD_TEXT_MAX } }}\n fullWidth\n />\n <TextField\n size=\"small\"\n label=\"Company\"\n value={company}\n onChange={(event) => setCompany(event.target.value)}\n helperText=\"As text — converting the lead is what makes it a company record.\"\n slotProps={{ htmlInput: { maxLength: CRM_LEAD_TEXT_MAX } }}\n fullWidth\n />\n <TextField\n size=\"small\"\n label=\"Job title\"\n value={jobTitle}\n onChange={(event) => setJobTitle(event.target.value)}\n slotProps={{ htmlInput: { maxLength: CRM_LEAD_TEXT_MAX } }}\n fullWidth\n />\n <TextField\n size=\"small\"\n label=\"Phone\"\n value={phone}\n onChange={(event) => setPhone(event.target.value)}\n error={Boolean(phoneError)}\n helperText={\n phoneError || 'With the country code, like +1 512 555 0107'\n }\n fullWidth\n />\n <TextField\n size=\"small\"\n label=\"Website\"\n value={website}\n onChange={(event) => setWebsite(event.target.value)}\n error={Boolean(websiteError)}\n helperText={websiteError || 'Like acme.com'}\n fullWidth\n />\n <LeadSourceSelect\n picklist={leadSources.picklist}\n value={leadSource}\n onChange={(label) => {\n setLeadSource(label)\n setLeadSourceTouched(true)\n }}\n disabled={Boolean(busy)}\n helperText=\"Where this lead came from. The choices are kept under CRM › Fields › Leads.\"\n />\n <Stack direction={{ xs: 'column', sm: 'row' }} spacing={2}>\n <TextField\n select\n size=\"small\"\n label=\"Status\"\n value={status}\n onChange={(event) =>\n setStatus(event.target.value as NewLeadValues['status'])\n }\n fullWidth\n >\n <MenuItem value=\"new\">{CRM_LEAD_STATUS_LABELS.new}</MenuItem>\n <MenuItem value=\"working\">\n {CRM_LEAD_STATUS_LABELS.working}\n </MenuItem>\n </TextField>\n <LeadOwnerSelect\n value={ownerUid}\n onChange={setOwnerUid}\n roster={roster}\n />\n </Stack>\n <TextField\n size=\"small\"\n label=\"Tags\"\n placeholder=\"icp2, a-list\"\n helperText=\"Comma-separated\"\n value={tags}\n onChange={(event) => setTags(event.target.value)}\n fullWidth\n />\n {/*\n The campaigns to file the lead under (AGL-3254), picked the way a\n form's page picks them. Grouping, not consent: it decides which\n campaign pages list the lead, never whether anything mails them.\n */}\n <ContainerPicker\n kind=\"campaign\"\n options={campaigns.options}\n value={campaignIds}\n onChange={setCampaignIds}\n helperText=\"The campaigns this lead is part of. It does not decide who a campaign mails.\"\n disabled={Boolean(busy)}\n empty={campaigns.ready && !campaigns.options.length}\n emptyText={\n hostId\n ? 'This site has no campaigns yet. Create one from Marketing to file leads under it.'\n : 'There are no campaigns yet. Create one from Marketing to file leads under it.'\n }\n />\n <Typography variant=\"subtitle2\">{'Address'}</Typography>\n <ContactAddressFields value={address} onChange={setAddress} />\n {/* The org's own lead fields (AGL-3272), the same controls the\n lead's page edits them with. */}\n {fields.active.length ? (\n <>\n <Typography variant=\"subtitle2\">{'Custom fields'}</Typography>\n {customError ? <Alert severity=\"warning\">{customError}</Alert> : null}\n {fields.active.map((definition) => (\n <CrmCustomFieldControl\n key={definition.$id}\n definition={definition}\n value={custom[definition.key]}\n onChange={(value) =>\n setCustom((current) => ({ ...current, [definition.key]: value }))\n }\n disabled={Boolean(busy)}\n />\n ))}\n </>\n ) : null}\n <TextField\n size=\"small\"\n label=\"Notes\"\n value={notes}\n onChange={(event) => setNotes(event.target.value)}\n multiline\n minRows={2}\n slotProps={{ htmlInput: { maxLength: NOTES_MAX } }}\n fullWidth\n />\n <Button\n variant=\"contained\"\n color=\"primary\"\n // Held until the site is known: the route files the lead under it.\n disabled={Boolean(busy) || !createHostId}\n onClick={handleSubmit}\n >\n {busy ? 'Adding…' : 'Add lead'}\n </Button>\n </Stack>\n </Container>\n </NavigationDrawerComponent>\n )\n}\n\nexport default NewLeadDrawer\n"],"names":["CRM_LEAD_STATUS_LABELS","CRM_LEAD_TEXT_MAX","containerMembershipValue","crmPicklistDefaultLabel","normalizeCrmLeadTags","normalizeContactEmail","normalizeCrmLeadProfile","ICON_VARIANT_CLOSE","Container","MdiIcon","SrOnly","NavigationDrawerComponent","Alert","Button","IconButton","MenuItem","Stack","TextField","Typography","ContainerPicker","useEffect","useState","useContactFieldDefinitions","useCrmCampaigns","useCrmScope","ContactAddressFields","EMPTY_ADDRESS","CrmSitePicker","CrmCustomFieldControl","crmCustomDraftDocument","crmCustomDraftMissingRequired","LeadOwnerSelect","LeadSourceSelect","useLeadSourcePicklist","NOTES_MAX","NewLeadDrawer","props","open","onClose","hostId","org","busy","error","roster","orgId","onSubmit","createHostId","email","setEmail","name","setName","company","setCompany","jobTitle","setJobTitle","phone","setPhone","website","setWebsite","leadSource","setLeadSource","leadSources","leadSourceTouched","setLeadSourceTouched","defaultLeadSource","picklist","status","setStatus","ownerUid","setOwnerUid","tags","setTags","campaignIds","setCampaignIds","address","setAddress","notes","setNotes","fields","custom","setCustom","customError","setCustomError","emailError","setEmailError","phoneError","setPhoneError","websiteError","setWebsiteError","campaigns","enabled","handleSubmit","errors","patch","normalizedEmail","missing","active","length","join","trim","replace","slice","anchor","variant","AppBarProps","color","sx","width","xs","sm","appBarLeft","edge","onClick","mr","path","component","appBarRight","gutterY","spacing","severity","disabled","Boolean","helperText","size","label","type","value","onChange","event","target","required","fullWidth","autoFocus","slotProps","htmlInput","maxLength","direction","select","new","working","placeholder","kind","options","empty","ready","emptyText","map","definition","key","current","$id","multiline","minRows"],"mappings":"AAAA;;;AAEA,SACEA,sBAAsB,EACtBC,iBAAiB,EAGjBC,wBAAwB,EACxBC,uBAAuB,EACvBC,oBAAoB,EACpBC,qBAAqB,EACrBC,uBAAuB,QAElB,eAAc;AACrB,SAASC,kBAAkB,QAAQ,2BAA0B;AAC7D,SAASC,SAAS,EAAEC,OAAO,EAAEC,MAAM,QAAQ,uBAAsB;AACjE,SAASC,yBAAyB,QAAQ,8DAA6D;AACvG,SACEC,KAAK,EACLC,MAAM,EACNC,UAAU,EACVC,QAAQ,EACRC,KAAK,EACLC,SAAS,EACTC,UAAU,QACL,gBAAe;AACtB,OAAOC,qBAAqB,6DAA4D;AACxF,SAASC,SAAS,EAAEC,QAAQ,QAAQ,QAAO;AAC3C,SAASC,0BAA0B,QAAQ,4CAAwC;AACnF,SAASC,eAAe,QAAQ,gCAA4B;AAC5D,SAASC,WAAW,QAAQ,4BAAwB;AAEpD,SACEC,oBAAoB,EACpBC,aAAa,QAER,8BAA0B;AACjC,SAASC,aAAa,QAAQ,uBAAmB;AACjD,SAASC,qBAAqB,QAAQ,gCAA4B;AAClE,SAEEC,sBAAsB,EACtBC,6BAA6B,QACxB,+BAA2B;AAClC,SAASC,eAAe,QAAQ,yBAAqB;AACrD,SAASC,gBAAgB,QAAQ,0BAAsB;AACvD,SAASC,qBAAqB,QAAQ,uCAAmC;AAoDzE,MAAMC,YAAY;AAElB;;;;;;;;;;;;;;;;;;CAkBC,GACD,OAAO,SAASC,cAAcC,KAAyB;QAqB3BjC;IApB1B,MAAM,EAAEkC,IAAI,EAAEC,OAAO,EAAEC,MAAM,EAAEC,GAAG,EAAEC,IAAI,EAAEC,KAAK,EAAEC,MAAM,EAAEC,KAAK,EAAEC,QAAQ,EAAE,GAAGT;IAC7E,uEAAuE;IACvE,+DAA+D;IAC/D,MAAM,EAAEU,YAAY,EAAE,GAAGtB,YAAY;QAAEe;QAAQC,KAAKA;IAAa;IAEjE,MAAM,CAACO,OAAOC,SAAS,GAAG3B,SAAS;IACnC,MAAM,CAAC4B,MAAMC,QAAQ,GAAG7B,SAAS;IACjC,MAAM,CAAC8B,SAASC,WAAW,GAAG/B,SAAS;IACvC,MAAM,CAACgC,UAAUC,YAAY,GAAGjC,SAAS;IACzC,MAAM,CAACkC,OAAOC,SAAS,GAAGnC,SAAS;IACnC,MAAM,CAACoC,SAASC,WAAW,GAAGrC,SAAS;IACvC,MAAM,CAACsC,YAAYC,cAAc,GAAGvC,SAAS;IAC7C;;;;;GAKC,GACD,MAAMwC,cAAc5B,sBAAsBW,gBAAAA,QAAS;IACnD,MAAM,CAACkB,mBAAmBC,qBAAqB,GAAG1C,SAAS;IAC3D,MAAM2C,qBAAoB7D,2BAAAA,wBAAwB0D,YAAYI,QAAQ,aAA5C9D,2BAAiD;IAC3EiB,UAAU;QACR,IAAIiB,QAAQ,CAACyB,mBAAmBF,cAAcI;IAChD,GAAG;QAAC3B;QAAMyB;QAAmBE;KAAkB;IAC/C,MAAM,CAACE,QAAQC,UAAU,GAAG9C,SAAkC;IAC9D,MAAM,CAAC+C,UAAUC,YAAY,GAAGhD,SAAS;IACzC,MAAM,CAACiD,MAAMC,QAAQ,GAAGlD,SAAS;IACjC,MAAM,CAACmD,aAAaC,eAAe,GAAGpD,SAAmB,EAAE;IAC3D,MAAM,CAACqD,SAASC,WAAW,GAAGtD,SAAuBK;IACrD,MAAM,CAACkD,OAAOC,SAAS,GAAGxD,SAAS;IACnC;;;;GAIC,GACD,MAAMyD,SAASxD,2BAA2BsB,gBAAAA,QAAS,MAAM;IACzD,MAAM,CAACmC,QAAQC,UAAU,GAAG3D,SAAyB,CAAC;IACtD,MAAM,CAAC4D,aAAaC,eAAe,GAAG7D,SAAS;IAC/C,MAAM,CAAC8D,YAAYC,cAAc,GAAG/D,SAAS;IAC7C,MAAM,CAACgE,YAAYC,cAAc,GAAGjE,SAAS;IAC7C,MAAM,CAACkE,cAAcC,gBAAgB,GAAGnE,SAAS;IACjD;;;;;GAKC,GACD,MAAMoE,YAAYlE,gBAAgB;QAAEgB;QAAQK;IAAM,GAAG;QAAE8C,SAASrD;IAAK;IAErE,wEAAwE;IACxE,wEAAwE;IACxEjB,UAAU;QACR,IAAI,CAACiB,MAAM;QACXW,SAAS;QACTE,QAAQ;QACRE,WAAW;QACXE,YAAY;QACZE,SAAS;QACTE,WAAW;QACXE,cAAc;QACdG,qBAAqB;QACrBI,UAAU;QACVE,YAAY;QACZE,QAAQ;QACRE,eAAe,EAAE;QACjBE,WAAWjD;QACXmD,SAAS;QACTG,UAAU,CAAC;QACXE,eAAe;QACfE,cAAc;QACdE,cAAc;QACdE,gBAAgB;IAClB,GAAG;QAACnD;KAAK;IAET,MAAMsD,eAAe;YAeLC,eACEA,iBAULC,gBACCA,iBACHA,cACEA,gBACGA,mBAGNA,aAEGA;QAlCX,MAAMC,kBAAkBzF,sBAAsB0C;QAC9C,MAAM,EAAE8C,KAAK,EAAED,MAAM,EAAE,GAAGtF,wBAAwB;YAChD6C;YACAE;YACAE;YACAE;YACAE;YACAe;YACAJ,MAAMlE,qBAAqBkE;QAC7B;QACA,oEAAoE;QACpE,kEAAkE;QAClE,MAAMyB,UAAUjE,8BAA8BgD,OAAOkB,MAAM,EAAE,CAAC,GAAGjB,QAAQ;QACzEK,cAAcU,kBAAkB,KAAK;QACrCR,eAAcM,gBAAAA,OAAOrC,KAAK,YAAZqC,gBAAgB;QAC9BJ,iBAAgBI,kBAAAA,OAAOnC,OAAO,YAAdmC,kBAAkB;QAClCV,eACEa,QAAQE,MAAM,GACV,GAAGF,QAAQG,IAAI,CAAC,MAAM,CAAC,EAAEH,QAAQE,MAAM,GAAG,IAAI,QAAQ,KAAK,UAAU,CAAC,GACtE;QAEN,IAAI,CAACH,mBAAmBF,OAAOrC,KAAK,IAAIqC,OAAOnC,OAAO,IAAIsC,QAAQE,MAAM,EAAE;QAC1EpD,SAAS;YACPE,OAAO+C;YACP7C,MAAMA,KAAKkD,IAAI,GAAGC,OAAO,CAAC,QAAQ,KAAKC,KAAK,CAAC,GAAGpG;YAChDkD,OAAO,GAAE0C,iBAAAA,MAAM1C,OAAO,YAAb0C,iBAAiB;YAC1BxC,QAAQ,GAAEwC,kBAAAA,MAAMxC,QAAQ,YAAdwC,kBAAkB;YAC5BtC,KAAK,GAAEsC,eAAAA,MAAMtC,KAAK,YAAXsC,eAAe;YACtBpC,OAAO,GAAEoC,iBAAAA,MAAMpC,OAAO,YAAboC,iBAAiB;YAC1BlC,UAAU,GAAEkC,oBAAAA,MAAMlC,UAAU,YAAhBkC,oBAAoB;YAChC3B;YACAE;YACAE,IAAI,GAAEuB,cAAAA,MAAMvB,IAAI,YAAVuB,cAAc,EAAE;YACtBrB,aAAatE,yBAAyBsE;YACtCE,OAAO,GAAEmB,iBAAAA,MAAMnB,OAAO,YAAbmB,iBAAiB;YAC1BjB,OAAOA,MAAMuB,IAAI,GAAGE,KAAK,CAAC,GAAGnE;YAC7B6C,QAAQlD,uBAAuBkD;QACjC;IACF;IAEA,qBACE,KAACpE;QACC0B,MAAMA;QACNiE,QAAO;QACPC,SAAQ;QACRjE,SAASA;QACTkE,aAAa;YAAEC,OAAO;QAAU;QAChCC,IAAI;YAAE,sBAAsB;gBAAEC,OAAO;oBAAEC,IAAI;oBAAQC,IAAI;gBAAI;YAAE;QAAE;QAC/DC,0BACE;;8BACE,MAAChG;oBACC2F,OAAM;oBACNM,MAAK;oBACLC,SAAS1E;oBACToE,IAAI;wBAAEO,IAAI;oBAAE;;sCAEZ,KAACxG;4BAAQyG,MAAM3G,mBAAmB2G,IAAI;;sCACtC,KAACxG;sCAAO;;;;8BAEV,KAACQ;oBAAWqF,SAAQ;oBAAKY,WAAU;8BAChC;;;;QAIPC,2BACE,KAACvG;YAAO0F,SAAQ;YAAWE,OAAM;YAAUO,SAAS1E;sBACjD;;kBAIL,cAAA,KAAC9B;YAAU6G,OAAO;sBAChB,cAAA,MAACrG;gBAAMsG,SAAS;;oBACb5E,sBAAQ,KAAC9B;wBAAM2G,UAAS;kCAAW7E;yBAAiB;kCAErD,KAACf;wBACCY,QAAQA;wBACRiF,UAAUC,QAAQhF;wBAClBiF,YAAW;;kCAEb,KAACzG;wBACC0G,MAAK;wBACLC,OAAM;wBACNC,MAAK;wBACLC,OAAO/E;wBACPgF,UAAU,CAACC,QAAUhF,SAASgF,MAAMC,MAAM,CAACH,KAAK;wBAChDpF,OAAO+E,QAAQtC;wBACfuC,YACEvC,cACA;wBAEF+C,QAAQ;wBACRC,SAAS;wBACTC,SAAS;;kCAEX,KAACnH;wBACC0G,MAAK;wBACLC,OAAM;wBACNE,OAAO7E;wBACP8E,UAAU,CAACC,QAAU9E,QAAQ8E,MAAMC,MAAM,CAACH,KAAK;wBAC/CO,WAAW;4BAAEC,WAAW;gCAAEC,WAAWtI;4BAAkB;wBAAE;wBACzDkI,SAAS;;kCAEX,KAAClH;wBACC0G,MAAK;wBACLC,OAAM;wBACNE,OAAO3E;wBACP4E,UAAU,CAACC,QAAU5E,WAAW4E,MAAMC,MAAM,CAACH,KAAK;wBAClDJ,YAAW;wBACXW,WAAW;4BAAEC,WAAW;gCAAEC,WAAWtI;4BAAkB;wBAAE;wBACzDkI,SAAS;;kCAEX,KAAClH;wBACC0G,MAAK;wBACLC,OAAM;wBACNE,OAAOzE;wBACP0E,UAAU,CAACC,QAAU1E,YAAY0E,MAAMC,MAAM,CAACH,KAAK;wBACnDO,WAAW;4BAAEC,WAAW;gCAAEC,WAAWtI;4BAAkB;wBAAE;wBACzDkI,SAAS;;kCAEX,KAAClH;wBACC0G,MAAK;wBACLC,OAAM;wBACNE,OAAOvE;wBACPwE,UAAU,CAACC,QAAUxE,SAASwE,MAAMC,MAAM,CAACH,KAAK;wBAChDpF,OAAO+E,QAAQpC;wBACfqC,YACErC,cAAc;wBAEhB8C,SAAS;;kCAEX,KAAClH;wBACC0G,MAAK;wBACLC,OAAM;wBACNE,OAAOrE;wBACPsE,UAAU,CAACC,QAAUtE,WAAWsE,MAAMC,MAAM,CAACH,KAAK;wBAClDpF,OAAO+E,QAAQlC;wBACfmC,YAAYnC,gBAAgB;wBAC5B4C,SAAS;;kCAEX,KAACnG;wBACCiC,UAAUJ,YAAYI,QAAQ;wBAC9B6D,OAAOnE;wBACPoE,UAAU,CAACH;4BACThE,cAAcgE;4BACd7D,qBAAqB;wBACvB;wBACAyD,UAAUC,QAAQhF;wBAClBiF,YAAW;;kCAEb,MAAC1G;wBAAMwH,WAAW;4BAAE5B,IAAI;4BAAUC,IAAI;wBAAM;wBAAGS,SAAS;;0CACtD,MAACrG;gCACCwH,MAAM;gCACNd,MAAK;gCACLC,OAAM;gCACNE,OAAO5D;gCACP6D,UAAU,CAACC,QACT7D,UAAU6D,MAAMC,MAAM,CAACH,KAAK;gCAE9BK,SAAS;;kDAET,KAACpH;wCAAS+G,OAAM;kDAAO9H,uBAAuB0I,GAAG;;kDACjD,KAAC3H;wCAAS+G,OAAM;kDACb9H,uBAAuB2I,OAAO;;;;0CAGnC,KAAC5G;gCACC+F,OAAO1D;gCACP2D,UAAU1D;gCACV1B,QAAQA;;;;kCAGZ,KAAC1B;wBACC0G,MAAK;wBACLC,OAAM;wBACNgB,aAAY;wBACZlB,YAAW;wBACXI,OAAOxD;wBACPyD,UAAU,CAACC,QAAUzD,QAAQyD,MAAMC,MAAM,CAACH,KAAK;wBAC/CK,SAAS;;kCAOX,KAAChH;wBACC0H,MAAK;wBACLC,SAASrD,UAAUqD,OAAO;wBAC1BhB,OAAOtD;wBACPuD,UAAUtD;wBACViD,YAAW;wBACXF,UAAUC,QAAQhF;wBAClBsG,OAAOtD,UAAUuD,KAAK,IAAI,CAACvD,UAAUqD,OAAO,CAAC7C,MAAM;wBACnDgD,WACE1G,SACI,sFACA;;kCAGR,KAACrB;wBAAWqF,SAAQ;kCAAa;;kCACjC,KAAC9E;wBAAqBqG,OAAOpD;wBAASqD,UAAUpD;;oBAG/CG,OAAOkB,MAAM,CAACC,MAAM,iBACnB;;0CACE,KAAC/E;gCAAWqF,SAAQ;0CAAa;;4BAChCtB,4BAAc,KAACrE;gCAAM2G,UAAS;0CAAWtC;iCAAuB;4BAChEH,OAAOkB,MAAM,CAACkD,GAAG,CAAC,CAACC,2BAClB,KAACvH;oCAECuH,YAAYA;oCACZrB,OAAO/C,MAAM,CAACoE,WAAWC,GAAG,CAAC;oCAC7BrB,UAAU,CAACD,QACT9C,UAAU,CAACqE,UAAa,aAAKA;gDAAS,CAACF,WAAWC,GAAG,CAAC,EAAEtB;;oCAE1DN,UAAUC,QAAQhF;mCANb0G,WAAWG,GAAG;;yBAUvB;kCACJ,KAACrI;wBACC0G,MAAK;wBACLC,OAAM;wBACNE,OAAOlD;wBACPmD,UAAU,CAACC,QAAUnD,SAASmD,MAAMC,MAAM,CAACH,KAAK;wBAChDyB,SAAS;wBACTC,SAAS;wBACTnB,WAAW;4BAAEC,WAAW;gCAAEC,WAAWrG;4BAAU;wBAAE;wBACjDiG,SAAS;;kCAEX,KAACtH;wBACC0F,SAAQ;wBACRE,OAAM;wBACN,mEAAmE;wBACnEe,UAAUC,QAAQhF,SAAS,CAACK;wBAC5BkE,SAASrB;kCAERlD,OAAO,YAAY;;;;;;AAMhC;AAEA,eAAeN,cAAa"}
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/crm/src/lib/components/new-lead-drawer.tsx"],"sourcesContent":["'use client'\n\nimport {\n CRM_LEAD_TEXT_MAX,\n type CrmCustomValue,\n type CrmLeadStatus,\n crmLeadStatusLabelFor,\n crmLeadStatusOptions,\n containerMembershipValue,\n crmLeadComposedName,\n type CrmLeadProfilePatch,\n crmPicklistDefaultLabel,\n normalizeContactEmail,\n normalizeCrmLeadProfile,\n type AglynPostalAddress,\n} from '@aglyn/aglyn'\nimport { ICON_VARIANT_CLOSE } from '@aglyn/shared-data-enums'\nimport { Container, MdiIcon, SrOnly } from '@aglyn/shared-ui-jsx'\nimport { NavigationDrawerComponent } from '@aglyn/shared-ui-jsx/components/navigation-drawer.component'\nimport {\n Alert,\n Button,\n IconButton,\n MenuItem,\n Stack,\n TextField,\n Typography,\n} from '@mui/material'\nimport ContainerPicker from '@aglyn/tenant-feature-instance/components/container-picker'\nimport { useEffect, useState } from 'react'\nimport { useContactFieldDefinitions } from '../hooks/use-contact-field-definitions'\nimport { useCrmCampaigns } from '../hooks/use-crm-campaigns'\nimport { useCrmScope } from '../hooks/use-crm-scope'\nimport type { OrgMemberOptions } from '../hooks/use-org-member-options'\nimport {\n EMPTY_LEAD_PROFILE_DRAFT,\n leadDraftComposedName,\n LeadProfileFields,\n type LeadProfileDraft,\n leadProfileDraftBody,\n} from './lead-profile-fields'\nimport { CrmSitePicker } from './crm-site-picker'\nimport { CrmCustomFieldControl } from './crm-custom-field-control'\nimport {\n type CrmCustomDraft,\n crmCustomDraftDocument,\n crmCustomDraftMissingRequired,\n} from '../model/crm-custom-draft'\nimport { LeadOwnerSelect } from './lead-owner-select'\nimport { useLeadSourcePicklist } from '../hooks/use-lead-source-picklist'\nimport { useLeadPicklists } from '../hooks/use-lead-picklists'\nimport { useLeadStatusPicklist } from '../hooks/use-lead-status-picklist'\n\n/** The meanings a lead is entered in by hand: New or Working (AGL-3231). */\nconst NEW_LEAD_STATUSES: readonly CrmLeadStatus[] = ['new', 'working']\n\n/** What the drawer hands back — already normalized where the route would. */\nexport interface NewLeadValues {\n email: string\n name: string\n company: string\n jobTitle: string\n phone: string\n website: string\n leadSource: string\n /** One of the org's New or Working values, by its label (AGL-3512). */\n status: string\n ownerUid: string\n tags: string[]\n /** The site's campaigns to file the lead under (AGL-3254), by id. */\n campaignIds: string[]\n address: AglynPostalAddress | null\n notes: string\n /**\n * The org's custom lead fields (AGL-3272), keyed by each definition's\n * `key`. Absent when the org has defined none, or none was filled — the\n * route stores a `custom` map only when there is one.\n */\n custom?: Record<string, CrmCustomValue>\n /**\n * Salesforce's standard lead fields (AGL-3513) — salutation, the name's\n * parts, mobile, fax, do not call, industry, rating, size and revenue —\n * normalized as the route stores them, only the ones that were filled.\n */\n standard: Pick<\n CrmLeadProfilePatch,\n | 'salutation'\n | 'firstName'\n | 'lastName'\n | 'mobilePhone'\n | 'fax'\n | 'doNotCall'\n | 'industry'\n | 'rating'\n | 'annualRevenueCents'\n | 'currency'\n | 'numberOfEmployees'\n >\n}\n\nexport interface NewLeadDrawerProps {\n open: boolean\n onClose: () => void\n /**\n * The site the lead is filed under — a lead is private to one site by\n * path. `null` at the organization level, where the drawer asks which\n * site with a picker and holds its submit until one is named.\n */\n hostId: string | null\n org?: Record<string, unknown> | null\n /** The request is in flight — the form holds still and the button says so. */\n busy?: boolean\n /** What the route answered when it refused, shown above the form. */\n error?: string | null\n /** The team, for the owner picker. */\n roster: OrgMemberOptions\n /**\n * The org the custom lead fields belong to (AGL-3272), as the list\n * already resolved it. `null` while it is in flight — the drawer then\n * shows the standard fields and no custom ones, which is what an org\n * with none defined shows anyway.\n */\n orgId?: string | null\n onSubmit: (values: NewLeadValues) => void\n}\n\nconst NOTES_MAX = 4000\n\n/**\n * ADDING ONE LEAD BY HAND, IN A DRAWER (AGL-3231).\n *\n * Salesforce's New Lead, on the Leads list: a person the team has heard of\n * and not yet qualified, entered with what is known — the address, the\n * name, the company as text, a title, a phone, a website, an address, tags\n * and where they came from. It makes a lead and nothing else: no contact,\n * no company record. Those are the conversion's to create once the lead is\n * real, which is what keeps one person from sitting in two lists.\n *\n * A drawer and not a form above the list, for the reason every list in this\n * console gives. The two fields a person can mistype in a way the record\n * cannot hold — the email and the phone, and the website beside them — are\n * checked before the request leaves, with the same normalizer the route\n * runs, so the refusal lands under the field. Everything else is the\n * route's to decide: whether the site already holds the address (it\n * updates that lead), whether the plan carries the suite, whether the site\n * is at the platform ceiling.\n */\nexport function NewLeadDrawer(props: NewLeadDrawerProps) {\n const { open, onClose, hostId, org, busy, error, roster, orgId, onSubmit } = props\n // The site the route files the lead under: the mounted site, or at the\n // organization level the picked one. `null` until it is known.\n const { createHostId } = useCrmScope({ hostId, org: org as never })\n\n const [email, setEmail] = useState('')\n const [name, setName] = useState('')\n /*\n * THE PROFILE (AGL-3231, AGL-3513), one draft the fields edit — the\n * lead's page edits the same draft with the same fields.\n */\n const [profile, setProfile] = useState<LeadProfileDraft>(EMPTY_LEAD_PROFILE_DRAFT)\n const [profileErrors, setProfileErrors] = useState<Record<string, string>>({})\n const editProfile = <K extends keyof LeadProfileDraft>(key: K, value: LeadProfileDraft[K]) =>\n setProfile((current) => ({ ...current, [key]: value }))\n // The org's Salutation, Industry and Rating lists (AGL-3513).\n const leadPicklists = useLeadPicklists(open ? (orgId ?? null) : null)\n /*\n * THE ORG'S LEAD SOURCES (AGL-3298), and its default for a new record.\n * The default is filled in once the list has answered and only until the\n * person picks something themselves — \"None\" included — so a list that\n * arrives after the drawer opened does not overwrite a choice.\n */\n const leadSources = useLeadSourcePicklist(orgId ?? null)\n const [leadSourceTouched, setLeadSourceTouched] = useState(false)\n const defaultLeadSource = crmPicklistDefaultLabel(leadSources.picklist) ?? ''\n useEffect(() => {\n if (open && !leadSourceTouched) {\n setProfile((current) => ({ ...current, leadSource: defaultLeadSource }))\n }\n }, [open, leadSourceTouched, defaultLeadSource])\n // The org's New and Working values (AGL-3512); a new lead starts as New's.\n const leadStatuses = useLeadStatusPicklist(orgId ?? null)\n const statusChoices = crmLeadStatusOptions(leadStatuses.picklist, NEW_LEAD_STATUSES)\n const [status, setStatus] = useState('')\n const shownStatus = statusChoices.some((choice) => choice.label === status)\n ? status\n : crmLeadStatusLabelFor(leadStatuses.picklist, 'new')\n const [ownerUid, setOwnerUid] = useState('')\n const [campaignIds, setCampaignIds] = useState<string[]>([])\n const [notes, setNotes] = useState('')\n /*\n * The org's own lead fields (AGL-3272). A CREATE holds only a draft —\n * there is no stored map to diff against — and `crmCustomDraftDocument`\n * turns it into the `custom` the route stores, or nothing.\n */\n const fields = useContactFieldDefinitions(orgId ?? null, 'lead')\n const [custom, setCustom] = useState<CrmCustomDraft>({})\n const [customError, setCustomError] = useState('')\n const [emailError, setEmailError] = useState('')\n /*\n * The campaigns, for the picker (AGL-3254): read while the drawer is\n * open. Under a site, the ones placed on it; at the organization level,\n * every campaign in the org — the lead is the org's record whichever\n * site it is captured by, so the site picked above does not narrow them.\n */\n const campaigns = useCrmCampaigns({ hostId, orgId }, { enabled: open })\n\n // A fresh form on every opening: a person typed and then abandoned must\n // not reappear half-filled the next time somebody reaches for New lead.\n useEffect(() => {\n if (!open) return\n setEmail('')\n setName('')\n setProfile(EMPTY_LEAD_PROFILE_DRAFT)\n setProfileErrors({})\n setLeadSourceTouched(false)\n setStatus('')\n setOwnerUid('')\n setCampaignIds([])\n setNotes('')\n setCustom({})\n setCustomError('')\n setEmailError('')\n }, [open])\n\n const handleSubmit = () => {\n const normalizedEmail = normalizeContactEmail(email)\n const { body, revenueError } = leadProfileDraftBody(profile)\n const { patch, errors } = normalizeCrmLeadProfile(body)\n const shown: Record<string, string> = { ...errors }\n if (revenueError) shown['annualRevenueCents'] = revenueError\n // Every required lead field counts on a create: the record is being\n // made whole, and nothing has been written to come back and fill.\n const missing = crmCustomDraftMissingRequired(fields.active, {}, custom, 'create')\n setEmailError(normalizedEmail ? '' : 'Enter a valid email address.')\n setProfileErrors(shown)\n setCustomError(\n missing.length\n ? `${missing.join(', ')} ${missing.length > 1 ? 'are' : 'is'} required.`\n : '',\n )\n if (!normalizedEmail || Object.keys(shown).length || missing.length) return\n // Only what was filled: a create has nothing to clear.\n const standard: NewLeadValues['standard'] = {}\n for (const key of [\n 'salutation',\n 'firstName',\n 'lastName',\n 'mobilePhone',\n 'fax',\n 'doNotCall',\n 'industry',\n 'rating',\n 'annualRevenueCents',\n 'currency',\n 'numberOfEmployees',\n ] as const) {\n const value = patch[key]\n if (value !== null && value !== undefined) Object.assign(standard, { [key]: value })\n }\n onSubmit({\n email: normalizedEmail,\n // While a first or last name is typed, the name is theirs (AGL-3513).\n name:\n crmLeadComposedName(null, patch) ??\n name.trim().replace(/\\s+/g, ' ').slice(0, CRM_LEAD_TEXT_MAX),\n company: patch.company ?? '',\n jobTitle: patch.jobTitle ?? '',\n phone: patch.phone ?? '',\n website: patch.website ?? '',\n leadSource: patch.leadSource ?? '',\n status: shownStatus,\n ownerUid,\n tags: patch.tags ?? [],\n campaignIds: containerMembershipValue(campaignIds),\n address: patch.address ?? null,\n notes: notes.trim().slice(0, NOTES_MAX),\n custom: crmCustomDraftDocument(custom),\n standard,\n })\n }\n\n const composedName = leadDraftComposedName(profile)\n\n return (\n <NavigationDrawerComponent\n open={open}\n anchor=\"right\"\n variant=\"temporary\"\n onClose={onClose}\n AppBarProps={{ color: 'surface' }}\n sx={{ '& .MuiDrawer-paper': { width: { xs: '100%', sm: 480 } } }}\n appBarLeft={\n <>\n <IconButton\n color=\"inherit\"\n edge=\"start\"\n onClick={onClose}\n sx={{ mr: 2 }}\n >\n <MdiIcon path={ICON_VARIANT_CLOSE.path} />\n <SrOnly>close drawer</SrOnly>\n </IconButton>\n <Typography variant=\"h6\" component=\"div\">\n {'New lead'}\n </Typography>\n </>\n }\n appBarRight={\n <Button variant=\"outlined\" color=\"inherit\" onClick={onClose}>\n {'Cancel'}\n </Button>\n }\n >\n <Container gutterY>\n <Stack spacing={2}>\n {error ? <Alert severity=\"warning\">{error}</Alert> : null}\n {/* First, because the lead is filed under the answer. Renders nothing under a site. */}\n <CrmSitePicker\n hostId={hostId}\n disabled={Boolean(busy)}\n helperText=\"The site this lead is filed under — a lead is private to one site.\"\n />\n <TextField\n size=\"small\"\n label=\"Email\"\n type=\"email\"\n value={email}\n onChange={(event) => setEmail(event.target.value)}\n error={Boolean(emailError)}\n helperText={\n emailError ||\n 'The one field that is required — a site holds one lead per address.'\n }\n required\n fullWidth\n autoFocus\n />\n <TextField\n size=\"small\"\n label=\"Name\"\n value={composedName || name}\n onChange={(event) => setName(event.target.value)}\n slotProps={{\n htmlInput: { maxLength: CRM_LEAD_TEXT_MAX },\n input: { readOnly: Boolean(composedName) },\n }}\n helperText={\n composedName ? 'Made of the first and last name.' : 'Or the whole name in one field.'\n }\n fullWidth\n />\n <LeadProfileFields\n draft={profile}\n onChange={(key, value) => {\n if (key === 'leadSource') setLeadSourceTouched(true)\n editProfile(key, value)\n }}\n errors={profileErrors}\n disabled={Boolean(busy)}\n leadSources={leadSources.picklist}\n lists={leadPicklists.lists}\n helperTexts={{\n company: 'As text — converting the lead is what makes it a company record.',\n leadSource:\n 'Where this lead came from. The choices are kept under CRM › Fields › Leads.',\n }}\n />\n <Stack direction={{ xs: 'column', sm: 'row' }} spacing={2}>\n <TextField\n select\n size=\"small\"\n label=\"Status\"\n value={statusChoices.some((choice) => choice.label === shownStatus) ? shownStatus : ''}\n onChange={(event) => setStatus(String(event.target.value))}\n fullWidth\n >\n {statusChoices.map((choice) => (\n <MenuItem key={choice.label} value={choice.label}>\n {choice.label}\n </MenuItem>\n ))}\n </TextField>\n <LeadOwnerSelect\n value={ownerUid}\n onChange={setOwnerUid}\n roster={roster}\n />\n </Stack>\n {/*\n The campaigns to file the lead under (AGL-3254), picked the way a\n form's page picks them. Grouping, not consent: it decides which\n campaign pages list the lead, never whether anything mails them.\n */}\n <ContainerPicker\n kind=\"campaign\"\n options={campaigns.options}\n value={campaignIds}\n onChange={setCampaignIds}\n helperText=\"The campaigns this lead is part of. It does not decide who a campaign mails.\"\n disabled={Boolean(busy)}\n empty={campaigns.ready && !campaigns.options.length}\n emptyText={\n hostId\n ? 'This site has no campaigns yet. Create one from Marketing to file leads under it.'\n : 'There are no campaigns yet. Create one from Marketing to file leads under it.'\n }\n />\n {/* The org's own lead fields (AGL-3272), the same controls the\n lead's page edits them with. */}\n {fields.active.length ? (\n <>\n <Typography variant=\"subtitle2\">{'Custom fields'}</Typography>\n {customError ? <Alert severity=\"warning\">{customError}</Alert> : null}\n {fields.active.map((definition) => (\n <CrmCustomFieldControl\n key={definition.$id}\n definition={definition}\n value={custom[definition.key]}\n onChange={(value) =>\n setCustom((current) => ({ ...current, [definition.key]: value }))\n }\n disabled={Boolean(busy)}\n />\n ))}\n </>\n ) : null}\n <TextField\n size=\"small\"\n label=\"Notes\"\n value={notes}\n onChange={(event) => setNotes(event.target.value)}\n multiline\n minRows={2}\n slotProps={{ htmlInput: { maxLength: NOTES_MAX } }}\n fullWidth\n />\n <Button\n variant=\"contained\"\n color=\"primary\"\n // Held until the site is known: the route files the lead under it.\n disabled={Boolean(busy) || !createHostId}\n onClick={handleSubmit}\n >\n {busy ? 'Adding…' : 'Add lead'}\n </Button>\n </Stack>\n </Container>\n </NavigationDrawerComponent>\n )\n}\n\nexport default NewLeadDrawer\n"],"names":["CRM_LEAD_TEXT_MAX","crmLeadStatusLabelFor","crmLeadStatusOptions","containerMembershipValue","crmLeadComposedName","crmPicklistDefaultLabel","normalizeContactEmail","normalizeCrmLeadProfile","ICON_VARIANT_CLOSE","Container","MdiIcon","SrOnly","NavigationDrawerComponent","Alert","Button","IconButton","MenuItem","Stack","TextField","Typography","ContainerPicker","useEffect","useState","useContactFieldDefinitions","useCrmCampaigns","useCrmScope","EMPTY_LEAD_PROFILE_DRAFT","leadDraftComposedName","LeadProfileFields","leadProfileDraftBody","CrmSitePicker","CrmCustomFieldControl","crmCustomDraftDocument","crmCustomDraftMissingRequired","LeadOwnerSelect","useLeadSourcePicklist","useLeadPicklists","useLeadStatusPicklist","NEW_LEAD_STATUSES","NOTES_MAX","NewLeadDrawer","props","open","onClose","hostId","org","busy","error","roster","orgId","onSubmit","createHostId","email","setEmail","name","setName","profile","setProfile","profileErrors","setProfileErrors","editProfile","key","value","current","leadPicklists","leadSources","leadSourceTouched","setLeadSourceTouched","defaultLeadSource","picklist","leadSource","leadStatuses","statusChoices","status","setStatus","shownStatus","some","choice","label","ownerUid","setOwnerUid","campaignIds","setCampaignIds","notes","setNotes","fields","custom","setCustom","customError","setCustomError","emailError","setEmailError","campaigns","enabled","handleSubmit","patch","normalizedEmail","body","revenueError","errors","shown","missing","active","length","join","Object","keys","standard","undefined","assign","trim","replace","slice","company","jobTitle","phone","website","tags","address","composedName","anchor","variant","AppBarProps","color","sx","width","xs","sm","appBarLeft","edge","onClick","mr","path","component","appBarRight","gutterY","spacing","severity","disabled","Boolean","helperText","size","type","onChange","event","target","required","fullWidth","autoFocus","slotProps","htmlInput","maxLength","input","readOnly","draft","lists","helperTexts","direction","select","String","map","kind","options","empty","ready","emptyText","definition","$id","multiline","minRows"],"mappings":"AAAA;;;AAEA,SACEA,iBAAiB,EAGjBC,qBAAqB,EACrBC,oBAAoB,EACpBC,wBAAwB,EACxBC,mBAAmB,EAEnBC,uBAAuB,EACvBC,qBAAqB,EACrBC,uBAAuB,QAElB,eAAc;AACrB,SAASC,kBAAkB,QAAQ,2BAA0B;AAC7D,SAASC,SAAS,EAAEC,OAAO,EAAEC,MAAM,QAAQ,uBAAsB;AACjE,SAASC,yBAAyB,QAAQ,8DAA6D;AACvG,SACEC,KAAK,EACLC,MAAM,EACNC,UAAU,EACVC,QAAQ,EACRC,KAAK,EACLC,SAAS,EACTC,UAAU,QACL,gBAAe;AACtB,OAAOC,qBAAqB,6DAA4D;AACxF,SAASC,SAAS,EAAEC,QAAQ,QAAQ,QAAO;AAC3C,SAASC,0BAA0B,QAAQ,4CAAwC;AACnF,SAASC,eAAe,QAAQ,gCAA4B;AAC5D,SAASC,WAAW,QAAQ,4BAAwB;AAEpD,SACEC,wBAAwB,EACxBC,qBAAqB,EACrBC,iBAAiB,EAEjBC,oBAAoB,QACf,2BAAuB;AAC9B,SAASC,aAAa,QAAQ,uBAAmB;AACjD,SAASC,qBAAqB,QAAQ,gCAA4B;AAClE,SAEEC,sBAAsB,EACtBC,6BAA6B,QACxB,+BAA2B;AAClC,SAASC,eAAe,QAAQ,yBAAqB;AACrD,SAASC,qBAAqB,QAAQ,uCAAmC;AACzE,SAASC,gBAAgB,QAAQ,iCAA6B;AAC9D,SAASC,qBAAqB,QAAQ,uCAAmC;AAEzE,0EAA0E,GAC1E,MAAMC,oBAA8C;IAAC;IAAO;CAAU;AAwEtE,MAAMC,YAAY;AAElB;;;;;;;;;;;;;;;;;;CAkBC,GACD,OAAO,SAASC,cAAcC,KAAyB;QA0B3BpC;IAzB1B,MAAM,EAAEqC,IAAI,EAAEC,OAAO,EAAEC,MAAM,EAAEC,GAAG,EAAEC,IAAI,EAAEC,KAAK,EAAEC,MAAM,EAAEC,KAAK,EAAEC,QAAQ,EAAE,GAAGT;IAC7E,uEAAuE;IACvE,+DAA+D;IAC/D,MAAM,EAAEU,YAAY,EAAE,GAAG1B,YAAY;QAAEmB;QAAQC,KAAKA;IAAa;IAEjE,MAAM,CAACO,OAAOC,SAAS,GAAG/B,SAAS;IACnC,MAAM,CAACgC,MAAMC,QAAQ,GAAGjC,SAAS;IACjC;;;GAGC,GACD,MAAM,CAACkC,SAASC,WAAW,GAAGnC,SAA2BI;IACzD,MAAM,CAACgC,eAAeC,iBAAiB,GAAGrC,SAAiC,CAAC;IAC5E,MAAMsC,cAAc,CAAmCC,KAAQC,QAC7DL,WAAW,CAACM,UAAa,aAAKA;gBAAS,CAACF,IAAI,EAAEC;;IAChD,8DAA8D;IAC9D,MAAME,gBAAgB5B,iBAAiBM,OAAQO,gBAAAA,QAAS,OAAQ;IAChE;;;;;GAKC,GACD,MAAMgB,cAAc9B,sBAAsBc,gBAAAA,QAAS;IACnD,MAAM,CAACiB,mBAAmBC,qBAAqB,GAAG7C,SAAS;IAC3D,MAAM8C,qBAAoB/D,2BAAAA,wBAAwB4D,YAAYI,QAAQ,aAA5ChE,2BAAiD;IAC3EgB,UAAU;QACR,IAAIqB,QAAQ,CAACwB,mBAAmB;YAC9BT,WAAW,CAACM,UAAa,aAAKA;oBAASO,YAAYF;;QACrD;IACF,GAAG;QAAC1B;QAAMwB;QAAmBE;KAAkB;IAC/C,2EAA2E;IAC3E,MAAMG,eAAelC,sBAAsBY,gBAAAA,QAAS;IACpD,MAAMuB,gBAAgBtE,qBAAqBqE,aAAaF,QAAQ,EAAE/B;IAClE,MAAM,CAACmC,QAAQC,UAAU,GAAGpD,SAAS;IACrC,MAAMqD,cAAcH,cAAcI,IAAI,CAAC,CAACC,SAAWA,OAAOC,KAAK,KAAKL,UAChEA,SACAxE,sBAAsBsE,aAAaF,QAAQ,EAAE;IACjD,MAAM,CAACU,UAAUC,YAAY,GAAG1D,SAAS;IACzC,MAAM,CAAC2D,aAAaC,eAAe,GAAG5D,SAAmB,EAAE;IAC3D,MAAM,CAAC6D,OAAOC,SAAS,GAAG9D,SAAS;IACnC;;;;GAIC,GACD,MAAM+D,SAAS9D,2BAA2B0B,gBAAAA,QAAS,MAAM;IACzD,MAAM,CAACqC,QAAQC,UAAU,GAAGjE,SAAyB,CAAC;IACtD,MAAM,CAACkE,aAAaC,eAAe,GAAGnE,SAAS;IAC/C,MAAM,CAACoE,YAAYC,cAAc,GAAGrE,SAAS;IAC7C;;;;;GAKC,GACD,MAAMsE,YAAYpE,gBAAgB;QAAEoB;QAAQK;IAAM,GAAG;QAAE4C,SAASnD;IAAK;IAErE,wEAAwE;IACxE,wEAAwE;IACxErB,UAAU;QACR,IAAI,CAACqB,MAAM;QACXW,SAAS;QACTE,QAAQ;QACRE,WAAW/B;QACXiC,iBAAiB,CAAC;QAClBQ,qBAAqB;QACrBO,UAAU;QACVM,YAAY;QACZE,eAAe,EAAE;QACjBE,SAAS;QACTG,UAAU,CAAC;QACXE,eAAe;QACfE,cAAc;IAChB,GAAG;QAACjD;KAAK;IAET,MAAMoD,eAAe;YAuCf1F,sBAEO2F,gBACCA,iBACHA,cACEA,gBACGA,mBAGNA,aAEGA;QAjDX,MAAMC,kBAAkB1F,sBAAsB8C;QAC9C,MAAM,EAAE6C,IAAI,EAAEC,YAAY,EAAE,GAAGrE,qBAAqB2B;QACpD,MAAM,EAAEuC,KAAK,EAAEI,MAAM,EAAE,GAAG5F,wBAAwB0F;QAClD,MAAMG,QAAgC,aAAKD;QAC3C,IAAID,cAAcE,KAAK,CAAC,qBAAqB,GAAGF;QAChD,oEAAoE;QACpE,kEAAkE;QAClE,MAAMG,UAAUpE,8BAA8BoD,OAAOiB,MAAM,EAAE,CAAC,GAAGhB,QAAQ;QACzEK,cAAcK,kBAAkB,KAAK;QACrCrC,iBAAiByC;QACjBX,eACEY,QAAQE,MAAM,GACV,GAAGF,QAAQG,IAAI,CAAC,MAAM,CAAC,EAAEH,QAAQE,MAAM,GAAG,IAAI,QAAQ,KAAK,UAAU,CAAC,GACtE;QAEN,IAAI,CAACP,mBAAmBS,OAAOC,IAAI,CAACN,OAAOG,MAAM,IAAIF,QAAQE,MAAM,EAAE;QACrE,uDAAuD;QACvD,MAAMI,WAAsC,CAAC;QAC7C,KAAK,MAAM9C,OAAO;YAChB;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;SACD,CAAW;YACV,MAAMC,QAAQiC,KAAK,CAAClC,IAAI;YACxB,IAAIC,UAAU,QAAQA,UAAU8C,WAAWH,OAAOI,MAAM,CAACF,UAAU;gBAAE,CAAC9C,IAAI,EAAEC;YAAM;QACpF;QACAZ,SAAS;YACPE,OAAO4C;YACP,sEAAsE;YACtE1C,IAAI,GACFlD,uBAAAA,oBAAoB,MAAM2F,kBAA1B3F,uBACAkD,KAAKwD,IAAI,GAAGC,OAAO,CAAC,QAAQ,KAAKC,KAAK,CAAC,GAAGhH;YAC5CiH,OAAO,GAAElB,iBAAAA,MAAMkB,OAAO,YAAblB,iBAAiB;YAC1BmB,QAAQ,GAAEnB,kBAAAA,MAAMmB,QAAQ,YAAdnB,kBAAkB;YAC5BoB,KAAK,GAAEpB,eAAAA,MAAMoB,KAAK,YAAXpB,eAAe;YACtBqB,OAAO,GAAErB,iBAAAA,MAAMqB,OAAO,YAAbrB,iBAAiB;YAC1BzB,UAAU,GAAEyB,oBAAAA,MAAMzB,UAAU,YAAhByB,oBAAoB;YAChCtB,QAAQE;YACRI;YACAsC,IAAI,GAAEtB,cAAAA,MAAMsB,IAAI,YAAVtB,cAAc,EAAE;YACtBd,aAAa9E,yBAAyB8E;YACtCqC,OAAO,GAAEvB,iBAAAA,MAAMuB,OAAO,YAAbvB,iBAAiB;YAC1BZ,OAAOA,MAAM2B,IAAI,GAAGE,KAAK,CAAC,GAAGzE;YAC7B+C,QAAQtD,uBAAuBsD;YAC/BqB;QACF;IACF;IAEA,MAAMY,eAAe5F,sBAAsB6B;IAE3C,qBACE,KAAC5C;QACC8B,MAAMA;QACN8E,QAAO;QACPC,SAAQ;QACR9E,SAASA;QACT+E,aAAa;YAAEC,OAAO;QAAU;QAChCC,IAAI;YAAE,sBAAsB;gBAAEC,OAAO;oBAAEC,IAAI;oBAAQC,IAAI;gBAAI;YAAE;QAAE;QAC/DC,0BACE;;8BACE,MAACjH;oBACC4G,OAAM;oBACNM,MAAK;oBACLC,SAASvF;oBACTiF,IAAI;wBAAEO,IAAI;oBAAE;;sCAEZ,KAACzH;4BAAQ0H,MAAM5H,mBAAmB4H,IAAI;;sCACtC,KAACzH;sCAAO;;;;8BAEV,KAACQ;oBAAWsG,SAAQ;oBAAKY,WAAU;8BAChC;;;;QAIPC,2BACE,KAACxH;YAAO2G,SAAQ;YAAWE,OAAM;YAAUO,SAASvF;sBACjD;;kBAIL,cAAA,KAAClC;YAAU8H,OAAO;sBAChB,cAAA,MAACtH;gBAAMuH,SAAS;;oBACbzF,sBAAQ,KAAClC;wBAAM4H,UAAS;kCAAW1F;yBAAiB;kCAErD,KAACjB;wBACCc,QAAQA;wBACR8F,UAAUC,QAAQ7F;wBAClB8F,YAAW;;kCAEb,KAAC1H;wBACC2H,MAAK;wBACL/D,OAAM;wBACNgE,MAAK;wBACLhF,OAAOV;wBACP2F,UAAU,CAACC,QAAU3F,SAAS2F,MAAMC,MAAM,CAACnF,KAAK;wBAChDf,OAAO4F,QAAQjD;wBACfkD,YACElD,cACA;wBAEFwD,QAAQ;wBACRC,SAAS;wBACTC,SAAS;;kCAEX,KAAClI;wBACC2H,MAAK;wBACL/D,OAAM;wBACNhB,OAAOyD,gBAAgBjE;wBACvByF,UAAU,CAACC,QAAUzF,QAAQyF,MAAMC,MAAM,CAACnF,KAAK;wBAC/CuF,WAAW;4BACTC,WAAW;gCAAEC,WAAWvJ;4BAAkB;4BAC1CwJ,OAAO;gCAAEC,UAAUd,QAAQpB;4BAAc;wBAC3C;wBACAqB,YACErB,eAAe,qCAAqC;wBAEtD4B,SAAS;;kCAEX,KAACvH;wBACC8H,OAAOlG;wBACPuF,UAAU,CAAClF,KAAKC;4BACd,IAAID,QAAQ,cAAcM,qBAAqB;4BAC/CP,YAAYC,KAAKC;wBACnB;wBACAqC,QAAQzC;wBACRgF,UAAUC,QAAQ7F;wBAClBmB,aAAaA,YAAYI,QAAQ;wBACjCsF,OAAO3F,cAAc2F,KAAK;wBAC1BC,aAAa;4BACX3C,SAAS;4BACT3C,YACE;wBACJ;;kCAEF,MAACrD;wBAAM4I,WAAW;4BAAE/B,IAAI;4BAAUC,IAAI;wBAAM;wBAAGS,SAAS;;0CACtD,KAACtH;gCACC4I,MAAM;gCACNjB,MAAK;gCACL/D,OAAM;gCACNhB,OAAOU,cAAcI,IAAI,CAAC,CAACC,SAAWA,OAAOC,KAAK,KAAKH,eAAeA,cAAc;gCACpFoE,UAAU,CAACC,QAAUtE,UAAUqF,OAAOf,MAAMC,MAAM,CAACnF,KAAK;gCACxDqF,SAAS;0CAER3E,cAAcwF,GAAG,CAAC,CAACnF,uBAClB,KAAC7D;wCAA4B8C,OAAOe,OAAOC,KAAK;kDAC7CD,OAAOC,KAAK;uCADAD,OAAOC,KAAK;;0CAK/B,KAAC5C;gCACC4B,OAAOiB;gCACPgE,UAAU/D;gCACVhC,QAAQA;;;;kCAQZ,KAAC5B;wBACC6I,MAAK;wBACLC,SAAStE,UAAUsE,OAAO;wBAC1BpG,OAAOmB;wBACP8D,UAAU7D;wBACV0D,YAAW;wBACXF,UAAUC,QAAQ7F;wBAClBqH,OAAOvE,UAAUwE,KAAK,IAAI,CAACxE,UAAUsE,OAAO,CAAC3D,MAAM;wBACnD8D,WACEzH,SACI,sFACA;;oBAKPyC,OAAOiB,MAAM,CAACC,MAAM,iBACnB;;0CACE,KAACpF;gCAAWsG,SAAQ;0CAAa;;4BAChCjC,4BAAc,KAAC3E;gCAAM4H,UAAS;0CAAWjD;iCAAuB;4BAChEH,OAAOiB,MAAM,CAAC0D,GAAG,CAAC,CAACM,2BAClB,KAACvI;oCAECuI,YAAYA;oCACZxG,OAAOwB,MAAM,CAACgF,WAAWzG,GAAG,CAAC;oCAC7BkF,UAAU,CAACjF,QACTyB,UAAU,CAACxB,UAAa,aAAKA;gDAAS,CAACuG,WAAWzG,GAAG,CAAC,EAAEC;;oCAE1D4E,UAAUC,QAAQ7F;mCANbwH,WAAWC,GAAG;;yBAUvB;kCACJ,KAACrJ;wBACC2H,MAAK;wBACL/D,OAAM;wBACNhB,OAAOqB;wBACP4D,UAAU,CAACC,QAAU5D,SAAS4D,MAAMC,MAAM,CAACnF,KAAK;wBAChD0G,SAAS;wBACTC,SAAS;wBACTpB,WAAW;4BAAEC,WAAW;gCAAEC,WAAWhH;4BAAU;wBAAE;wBACjD4G,SAAS;;kCAEX,KAACrI;wBACC2G,SAAQ;wBACRE,OAAM;wBACN,mEAAmE;wBACnEe,UAAUC,QAAQ7F,SAAS,CAACK;wBAC5B+E,SAASpC;kCAERhD,OAAO,YAAY;;;;;;AAMhC;AAEA,eAAeN,cAAa"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { type CrmPicklist, type CrmPicklistId } from '@aglyn/aglyn';
|
|
2
|
+
export interface CrmPicklistSelectProps {
|
|
3
|
+
/** Which of the CRM's standard picklists the field is. */
|
|
4
|
+
picklistId: CrmPicklistId;
|
|
5
|
+
picklist: CrmPicklist;
|
|
6
|
+
/** The label the record holds, or `''` for none. */
|
|
7
|
+
value: string;
|
|
8
|
+
onChange: (label: string) => void;
|
|
9
|
+
/**
|
|
10
|
+
* What the record held when the form opened. Kept in the menu while the
|
|
11
|
+
* list no longer offers it — deactivated, or written before the list
|
|
12
|
+
* held it — so the select shows what is stored until somebody changes it.
|
|
13
|
+
*/
|
|
14
|
+
stored?: string;
|
|
15
|
+
disabled?: boolean;
|
|
16
|
+
helperText?: string;
|
|
17
|
+
error?: boolean;
|
|
18
|
+
/** The field's label, when a record names it otherwise than the list does. */
|
|
19
|
+
label?: string;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* A standard picklist's select (AGL-3298, AGL-3510): the org's active
|
|
23
|
+
* values in the order the Fields page keeps them, a "None" to clear, and
|
|
24
|
+
* the record's own value when the list would not otherwise show it —
|
|
25
|
+
* marked, and selectable only as what it already is. A definition with
|
|
26
|
+
* groups lists its values under a heading per group, in the definition's
|
|
27
|
+
* order, with ungrouped values last.
|
|
28
|
+
*
|
|
29
|
+
* MUI's select `TextField`, the control every CRM form in this plugin uses
|
|
30
|
+
* for a fixed choice, so it sizes, labels and disables like its neighbors.
|
|
31
|
+
*/
|
|
32
|
+
export declare function CrmPicklistSelect(props: CrmPicklistSelectProps): import("react").JSX.Element;
|
|
33
|
+
export declare namespace CrmPicklistSelect {
|
|
34
|
+
var displayName: string;
|
|
35
|
+
}
|
|
36
|
+
export default CrmPicklistSelect;
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Aglyn LLC
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/ 'use client';
|
|
17
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
18
|
+
import { crmPicklistDefinition, crmPicklistOptions, groupPicklistOptions } from "@aglyn/aglyn";
|
|
19
|
+
import { ListItemText, ListSubheader, MenuItem, TextField } from "@mui/material";
|
|
20
|
+
import { useMemo } from "react";
|
|
21
|
+
/** How a kept value that the list does not offer reads in the menu and the field. */ function optionText(option) {
|
|
22
|
+
if (option.inactive) return `${option.label} (inactive)`;
|
|
23
|
+
if (option.unlisted) return `${option.label} (not in the list)`;
|
|
24
|
+
return option.label;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* A standard picklist's select (AGL-3298, AGL-3510): the org's active
|
|
28
|
+
* values in the order the Fields page keeps them, a "None" to clear, and
|
|
29
|
+
* the record's own value when the list would not otherwise show it —
|
|
30
|
+
* marked, and selectable only as what it already is. A definition with
|
|
31
|
+
* groups lists its values under a heading per group, in the definition's
|
|
32
|
+
* order, with ungrouped values last.
|
|
33
|
+
*
|
|
34
|
+
* MUI's select `TextField`, the control every CRM form in this plugin uses
|
|
35
|
+
* for a fixed choice, so it sizes, labels and disables like its neighbors.
|
|
36
|
+
*/ export function CrmPicklistSelect(props) {
|
|
37
|
+
var _ref, _ref1;
|
|
38
|
+
const { picklistId, picklist, value, onChange, stored, disabled, helperText, error, label } = props;
|
|
39
|
+
const definition = crmPicklistDefinition(picklistId);
|
|
40
|
+
const options = useMemo(()=>crmPicklistOptions(picklist, stored || value), [
|
|
41
|
+
picklist,
|
|
42
|
+
stored,
|
|
43
|
+
value
|
|
44
|
+
]);
|
|
45
|
+
const selected = options.find((option)=>option.label === value);
|
|
46
|
+
const item = (option)=>/*#__PURE__*/ _jsx(MenuItem, {
|
|
47
|
+
value: option.label,
|
|
48
|
+
// A kept value is shown so the record reads true, not offered as a
|
|
49
|
+
// choice for a record that does not hold it already.
|
|
50
|
+
disabled: (option.inactive || option.unlisted) && option.label !== (stored || value),
|
|
51
|
+
children: /*#__PURE__*/ _jsx(ListItemText, {
|
|
52
|
+
primary: optionText(option),
|
|
53
|
+
slotProps: option.inactive || option.unlisted ? {
|
|
54
|
+
primary: {
|
|
55
|
+
color: 'text.secondary'
|
|
56
|
+
}
|
|
57
|
+
} : undefined
|
|
58
|
+
})
|
|
59
|
+
}, option.label);
|
|
60
|
+
// The menu's children flat — a Select reads its options from its direct
|
|
61
|
+
// children, so the headings sit between them rather than around them.
|
|
62
|
+
const groups = (_ref = definition == null ? void 0 : definition.groups) != null ? _ref : [];
|
|
63
|
+
const items = groups.length ? groupPicklistOptions(options, groups).flatMap((section)=>{
|
|
64
|
+
var _ref, _ref1;
|
|
65
|
+
var _section_group, _section_group1;
|
|
66
|
+
return [
|
|
67
|
+
/*#__PURE__*/ _jsx(ListSubheader, {
|
|
68
|
+
children: (_ref = (_section_group = section.group) == null ? void 0 : _section_group.label) != null ? _ref : 'No group'
|
|
69
|
+
}, `group:${(_ref1 = (_section_group1 = section.group) == null ? void 0 : _section_group1.id) != null ? _ref1 : ''}`),
|
|
70
|
+
...section.options.map(item)
|
|
71
|
+
];
|
|
72
|
+
}) : options.map(item);
|
|
73
|
+
return /*#__PURE__*/ _jsxs(TextField, {
|
|
74
|
+
select: true,
|
|
75
|
+
size: "small",
|
|
76
|
+
label: (_ref1 = label != null ? label : definition == null ? void 0 : definition.label) != null ? _ref1 : 'Value',
|
|
77
|
+
value: selected ? value : '',
|
|
78
|
+
onChange: (event)=>onChange(String(event.target.value)),
|
|
79
|
+
disabled: disabled,
|
|
80
|
+
helperText: helperText,
|
|
81
|
+
error: error,
|
|
82
|
+
fullWidth: true,
|
|
83
|
+
slotProps: {
|
|
84
|
+
select: {
|
|
85
|
+
displayEmpty: true,
|
|
86
|
+
renderValue: (current)=>{
|
|
87
|
+
const option = options.find((entry)=>entry.label === current);
|
|
88
|
+
return option ? optionText(option) : 'None';
|
|
89
|
+
}
|
|
90
|
+
},
|
|
91
|
+
inputLabel: {
|
|
92
|
+
shrink: true
|
|
93
|
+
}
|
|
94
|
+
},
|
|
95
|
+
children: [
|
|
96
|
+
/*#__PURE__*/ _jsx(MenuItem, {
|
|
97
|
+
value: "",
|
|
98
|
+
children: /*#__PURE__*/ _jsx(ListItemText, {
|
|
99
|
+
primary: "None",
|
|
100
|
+
slotProps: {
|
|
101
|
+
primary: {
|
|
102
|
+
color: 'text.secondary'
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
})
|
|
106
|
+
}),
|
|
107
|
+
items
|
|
108
|
+
]
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
CrmPicklistSelect.displayName = 'CrmPicklistSelect';
|
|
112
|
+
export default CrmPicklistSelect;
|
|
113
|
+
|
|
114
|
+
//# sourceMappingURL=picklist-select.js.map
|