@aglyn/plugins-crm 1.0.0-beta.221 → 1.0.0-beta.222
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-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/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 +92 -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 +15 -1
- 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-recipes.d.ts +40 -0
- package/src/lib/model/crm-recipes.js +244 -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/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/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 +75 -33
- 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 +162 -0
- package/src/lib/server/assign-contact-owner.js +340 -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 +139 -0
- package/src/lib/server/automation-steps.js +472 -0
- package/src/lib/server/automation-steps.js.map +1 -0
- package/src/lib/server/capture-contact.js +65 -21
- 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-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/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 +22 -4
- package/src/lib/server/merge-contacts.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 +15 -7
- 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 +15 -2
- 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-routes.js +30 -16
- 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
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/crm/src/lib/hooks/use-crm-picklist.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n'use client'\n\nimport {\n CRM_COLLECTIONS,\n type CrmPicklist,\n type CrmPicklistDefinition,\n type CrmPicklistId,\n crmPicklistDefinition,\n effectiveCrmPicklist,\n normalizeCrmPicklist,\n} from '@aglyn/aglyn'\nimport { useFirestore, useFirestoreDoc } from '@aglyn/tenant-feature-instance'\nimport { doc } from 'firebase/firestore'\nimport { useMemo } from 'react'\n\nexport interface CrmPicklistResult {\n /** The field the list belongs to — its standard values, groups and targets. */\n definition: CrmPicklistDefinition\n /** The list every picker offers — the org's own values with every standard value. */\n picklist: CrmPicklist\n /** The org has written its own list; false while it reads the standard values alone. */\n stored: boolean\n /** The server has answered, so the list is the org's and not a placeholder. */\n ready: boolean\n /** The document has not been confirmed by the server — `writeGuardedBySeed`'s input. */\n fromCache: boolean\n}\n\n/**\n * An org's values for one of the CRM's standard picklists (AGL-3510), for\n * every surface that offers or manages them: a record's select, a create\n * drawer, a list's filter and the Fields page.\n *\n * One document listen, shared by the Firestore SDK across every mount that\n * asks for the same org and picklist, so a page with the list and a drawer\n * open pays for it once. `orgId` null issues no read and answers the\n * standard values, unready.\n */\nexport function useCrmPicklist(\n id: CrmPicklistId,\n orgId: string | null | undefined,\n): CrmPicklistResult {\n const firestore = useFirestore()\n const { data, status, fromCache } = useFirestoreDoc<Record<string, unknown>>(\n () => (orgId ? doc(firestore, 'orgs', orgId, CRM_COLLECTIONS.picklists, id) : null),\n [firestore, orgId, id],\n )\n return useMemo(\n () => ({\n definition: crmPicklistDefinition(id) as CrmPicklistDefinition,\n picklist: effectiveCrmPicklist(id, data),\n stored: normalizeCrmPicklist(data) !== null,\n ready: Boolean(orgId) && status !== 'loading',\n fromCache,\n }),\n [id, data, orgId, status, fromCache],\n )\n}\n\nexport default useCrmPicklist\n"],"names":["CRM_COLLECTIONS","crmPicklistDefinition","effectiveCrmPicklist","normalizeCrmPicklist","useFirestore","useFirestoreDoc","doc","useMemo","useCrmPicklist","id","orgId","firestore","data","status","fromCache","picklists","definition","picklist","stored","ready","Boolean"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GACD;AAEA,SACEA,eAAe,EAIfC,qBAAqB,EACrBC,oBAAoB,EACpBC,oBAAoB,QACf,eAAc;AACrB,SAASC,YAAY,EAAEC,eAAe,QAAQ,iCAAgC;AAC9E,SAASC,GAAG,QAAQ,qBAAoB;AACxC,SAASC,OAAO,QAAQ,QAAO;AAe/B;;;;;;;;;CASC,GACD,OAAO,SAASC,eACdC,EAAiB,EACjBC,KAAgC;IAEhC,MAAMC,YAAYP;IAClB,MAAM,EAAEQ,IAAI,EAAEC,MAAM,EAAEC,SAAS,EAAE,GAAGT,gBAClC,IAAOK,QAAQJ,IAAIK,WAAW,QAAQD,OAAOV,gBAAgBe,SAAS,EAAEN,MAAM,MAC9E;QAACE;QAAWD;QAAOD;KAAG;IAExB,OAAOF,QACL,IAAO,CAAA;YACLS,YAAYf,sBAAsBQ;YAClCQ,UAAUf,qBAAqBO,IAAIG;YACnCM,QAAQf,qBAAqBS,UAAU;YACvCO,OAAOC,QAAQV,UAAUG,WAAW;YACpCC;QACF,CAAA,GACA;QAACL;QAAIG;QAAMF;QAAOG;QAAQC;KAAU;AAExC;AAEA,eAAeN,eAAc"}
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
* See the License for the specific language governing permissions and
|
|
15
15
|
* limitations under the License.
|
|
16
16
|
*/
|
|
17
|
+
import { type Firestore } from 'firebase/firestore';
|
|
17
18
|
export type CrmRecordKind = 'contact' | 'company' | 'deal';
|
|
18
19
|
/** The collection each kind of record lives in, under `orgs/{orgId}/`. */
|
|
19
20
|
export declare const CRM_RECORD_COLLECTIONS: Record<CrmRecordKind, string>;
|
|
@@ -28,6 +29,21 @@ export declare const CRM_RECORD_COLLECTIONS: Record<CrmRecordKind, string>;
|
|
|
28
29
|
export declare function crmRecordName(kind: CrmRecordKind, data: Record<string, unknown> | undefined, groupId: string): string;
|
|
29
30
|
/** Test seam: forget everything, so a spec's fixtures are what get read. */
|
|
30
31
|
export declare function resetCrmRecordNameCache(): void;
|
|
32
|
+
/**
|
|
33
|
+
* The names of `records`, read now — for a one-off like a file export,
|
|
34
|
+
* which needs every name at once rather than a listener's re-render
|
|
35
|
+
* (AGL-3521). Shares {@link useCrmRecordNames}' cache, and answers the same
|
|
36
|
+
* lookup: `undefined` for a record that could not be named.
|
|
37
|
+
*/
|
|
38
|
+
export declare function readCrmRecordNames(firestore: Firestore, options: {
|
|
39
|
+
orgId: string;
|
|
40
|
+
groupId: string | null;
|
|
41
|
+
org?: Record<string, unknown> | null;
|
|
42
|
+
records: ReadonlyArray<{
|
|
43
|
+
kind: CrmRecordKind;
|
|
44
|
+
id: string;
|
|
45
|
+
}>;
|
|
46
|
+
}): Promise<(kind: CrmRecordKind, id: string) => string | undefined>;
|
|
31
47
|
/**
|
|
32
48
|
* The names of the records a list of tasks points at, resolved once each.
|
|
33
49
|
*
|
|
@@ -62,6 +62,45 @@ const cacheKey = (orgId, kind, id)=>`${orgId}/${CRM_RECORD_COLLECTIONS[kind]}/${
|
|
|
62
62
|
nameCache.clear();
|
|
63
63
|
pending.clear();
|
|
64
64
|
}
|
|
65
|
+
/**
|
|
66
|
+
* The reads that fill the cache for `records` not already in it — each
|
|
67
|
+
* record read once however many callers ask at the same time.
|
|
68
|
+
*/ function startNameReads(firestore, orgId, groupId, org, records) {
|
|
69
|
+
const reads = [];
|
|
70
|
+
for (const { kind, id } of records){
|
|
71
|
+
if (!id) continue;
|
|
72
|
+
const key = cacheKey(orgId, kind, id);
|
|
73
|
+
if (nameCache.has(key)) continue;
|
|
74
|
+
let read = pending.get(key);
|
|
75
|
+
if (!read) {
|
|
76
|
+
read = getDoc(doc(firestore, 'orgs', orgId, CRM_RECORD_COLLECTIONS[kind], id)).then((snapshot)=>{
|
|
77
|
+
const data = snapshot.exists() ? snapshot.data() : undefined;
|
|
78
|
+
nameCache.set(key, data ? crmRecordName(kind, data, groupId != null ? groupId : contactPrimaryGroup(data, org).groupId) : null);
|
|
79
|
+
}).catch(()=>{
|
|
80
|
+
// A refused or failed read is not cached: the cell keeps showing
|
|
81
|
+
// the id, and the next mount tries again.
|
|
82
|
+
}).finally(()=>{
|
|
83
|
+
pending.delete(key);
|
|
84
|
+
});
|
|
85
|
+
pending.set(key, read);
|
|
86
|
+
}
|
|
87
|
+
reads.push(read);
|
|
88
|
+
}
|
|
89
|
+
return reads;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* The names of `records`, read now — for a one-off like a file export,
|
|
93
|
+
* which needs every name at once rather than a listener's re-render
|
|
94
|
+
* (AGL-3521). Shares {@link useCrmRecordNames}' cache, and answers the same
|
|
95
|
+
* lookup: `undefined` for a record that could not be named.
|
|
96
|
+
*/ export async function readCrmRecordNames(firestore, options) {
|
|
97
|
+
const { orgId, groupId, org, records } = options;
|
|
98
|
+
await Promise.all(startNameReads(firestore, orgId, groupId, org, records));
|
|
99
|
+
return (kind, id)=>{
|
|
100
|
+
var _nameCache_get;
|
|
101
|
+
return (_nameCache_get = nameCache.get(cacheKey(orgId, kind, id))) != null ? _nameCache_get : undefined;
|
|
102
|
+
};
|
|
103
|
+
}
|
|
65
104
|
/**
|
|
66
105
|
* The names of the records a list of tasks points at, resolved once each.
|
|
67
106
|
*
|
|
@@ -81,26 +120,13 @@ const cacheKey = (orgId, kind, id)=>`${orgId}/${CRM_RECORD_COLLECTIONS[kind]}/${
|
|
|
81
120
|
useEffect(()=>{
|
|
82
121
|
if (!orgId || !wanted) return;
|
|
83
122
|
let active = true;
|
|
84
|
-
const reads =
|
|
85
|
-
for (const entry of wanted.split('\n')){
|
|
123
|
+
const reads = startNameReads(firestore, orgId, groupId, org, wanted.split('\n').map((entry)=>{
|
|
86
124
|
const [kind, id] = entry.split(':');
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
const data = snapshot.exists() ? snapshot.data() : undefined;
|
|
93
|
-
nameCache.set(key, data ? crmRecordName(kind, data, groupId != null ? groupId : contactPrimaryGroup(data, org).groupId) : null);
|
|
94
|
-
}).catch(()=>{
|
|
95
|
-
// A refused or failed read is not cached: the cell keeps showing
|
|
96
|
-
// the id, and the next mount tries again.
|
|
97
|
-
}).finally(()=>{
|
|
98
|
-
pending.delete(key);
|
|
99
|
-
});
|
|
100
|
-
pending.set(key, read);
|
|
101
|
-
}
|
|
102
|
-
reads.push(read);
|
|
103
|
-
}
|
|
125
|
+
return {
|
|
126
|
+
kind,
|
|
127
|
+
id
|
|
128
|
+
};
|
|
129
|
+
}));
|
|
104
130
|
if (!reads.length) return;
|
|
105
131
|
void Promise.all(reads).then(()=>{
|
|
106
132
|
if (active) setResolved((count)=>count + 1);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../../libs/plugins/crm/src/lib/hooks/use-crm-record-names.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { contactDisplayName, CRM_COLLECTIONS } from '@aglyn/aglyn'\nimport { useFirestore } from '@aglyn/tenant-feature-instance'\nimport { doc, getDoc } from 'firebase/firestore'\nimport { useCallback, useEffect, useState } from 'react'\nimport { contactPrimaryGroup } from '../model/contact-record'\n\nexport type CrmRecordKind = 'contact' | 'company' | 'deal'\n\n/** The collection each kind of record lives in, under `orgs/{orgId}/`. */\nexport const CRM_RECORD_COLLECTIONS: Record<CrmRecordKind, string> = {\n contact: 'contacts',\n company: CRM_COLLECTIONS.companies,\n deal: CRM_COLLECTIONS.deals,\n}\n\n/**\n * What a record is CALLED, from its document.\n *\n * A contact's name is read through the viewing group's facet, the way the\n * people list reads it, so one business renaming a person does not change\n * what an unrelated business's task list shows; the email stands in for a\n * contact nobody has named. A company has a name and a deal a title.\n */\nexport function crmRecordName(\n kind: CrmRecordKind,\n data: Record<string, unknown> | undefined,\n groupId: string,\n): string {\n if (!data) return ''\n switch (kind) {\n case 'contact':\n return contactDisplayName(data, groupId) || String(data['email'] ?? '')\n case 'company':\n return String(data['name'] ?? '')\n case 'deal':\n return String(data['title'] ?? '')\n }\n}\n\n/**\n * Names already read, keyed by `orgId/collection/id`, shared by every\n * mount for the life of the page.\n *\n * A task list names the same handful of records over and over — five tasks\n * about one deal are five rows and one name — and a person moves between the\n * tasks section, a contact's page and the dashboard without the records\n * changing underneath them. `null` records a document that does not exist,\n * so a task pointing at a deleted record costs one read rather than one per\n * render. A rename is picked up on the next page load, which is the right\n * staleness for a label beside a link to the record itself.\n */\nconst nameCache = new Map<string, string | null>()\nconst pending = new Map<string, Promise<void>>()\n\nconst cacheKey = (orgId: string, kind: CrmRecordKind, id: string) =>\n `${orgId}/${CRM_RECORD_COLLECTIONS[kind]}/${id}`\n\n/** Test seam: forget everything, so a spec's fixtures are what get read. */\nexport function resetCrmRecordNameCache(): void {\n nameCache.clear()\n pending.clear()\n}\n\n/**\n * The names of the records a list of tasks points at, resolved once each.\n *\n * Returns a lookup rather than a map so the caller does not have to know the\n * cache's key shape. An unresolved record answers `undefined` — the cell\n * renders the link with the id until the name lands, which is one render\n * later on a warm cache and one round trip on a cold one.\n */\nexport function useCrmRecordNames(options: {\n orgId: string | null | undefined\n /**\n * The viewing group a contact is named through, or `null` at the\n * organization level (AGL-2630), where each contact is named through its\n * own primary holder, resolved from {@link org}.\n */\n groupId: string | null\n org?: Record<string, unknown> | null\n records: ReadonlyArray<{ kind: CrmRecordKind; id: string }>\n}): (kind: CrmRecordKind, id: string) => string | undefined {\n const { orgId, groupId, org, records } = options\n const firestore = useFirestore()\n // A counter rather than a copy of the cache: the cache is the source of\n // truth and this only exists to re-render when it grows.\n const [, setResolved] = useState(0)\n\n // The pairs as one string, so the effect runs when the SET changes and not\n // when the caller builds a new array of the same pairs on every render.\n const wanted = records\n .map((record) => `${record.kind}:${record.id}`)\n .filter((entry, index, all) => all.indexOf(entry) === index)\n .sort()\n .join('\\n')\n\n useEffect(() => {\n if (!orgId || !wanted) return\n let active = true\n const reads: Promise<void>[] = []\n for (const entry of wanted.split('\\n')) {\n const [kind, id] = entry.split(':') as [CrmRecordKind, string]\n const key = cacheKey(orgId, kind, id)\n if (nameCache.has(key)) continue\n let read = pending.get(key)\n if (!read) {\n read = getDoc(\n doc(firestore, 'orgs', orgId, CRM_RECORD_COLLECTIONS[kind], id),\n )\n .then((snapshot) => {\n const data = snapshot.exists()\n ? (snapshot.data() as Record<string, unknown>)\n : undefined\n nameCache.set(\n key,\n data\n ? crmRecordName(\n kind,\n data,\n groupId ?? contactPrimaryGroup(data, org).groupId,\n )\n : null,\n )\n })\n .catch(() => {\n // A refused or failed read is not cached: the cell keeps showing\n // the id, and the next mount tries again.\n })\n .finally(() => {\n pending.delete(key)\n })\n pending.set(key, read)\n }\n reads.push(read)\n }\n if (!reads.length) return\n void Promise.all(reads).then(() => {\n if (active) setResolved((count) => count + 1)\n })\n return () => {\n active = false\n }\n }, [firestore, orgId, groupId, wanted])\n\n return useCallback(\n (kind: CrmRecordKind, id: string) => {\n if (!orgId) return undefined\n const hit = nameCache.get(cacheKey(orgId, kind, id))\n return hit === null ? undefined : hit\n },\n [orgId],\n )\n}\n"],"names":["contactDisplayName","CRM_COLLECTIONS","useFirestore","doc","getDoc","useCallback","useEffect","useState","contactPrimaryGroup","CRM_RECORD_COLLECTIONS","contact","company","companies","deal","deals","crmRecordName","kind","data","groupId","String","nameCache","Map","pending","cacheKey","orgId","id","resetCrmRecordNameCache","clear","useCrmRecordNames","options","org","records","firestore","setResolved","wanted","map","record","filter","entry","index","all","indexOf","sort","join","active","reads","split","key","has","read","get","then","snapshot","exists","undefined","set","catch","finally","delete","push","length","Promise","count","hit"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/crm/src/lib/hooks/use-crm-record-names.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { contactDisplayName, CRM_COLLECTIONS } from '@aglyn/aglyn'\nimport { useFirestore } from '@aglyn/tenant-feature-instance'\nimport { doc, type Firestore, getDoc } from 'firebase/firestore'\nimport { useCallback, useEffect, useState } from 'react'\nimport { contactPrimaryGroup } from '../model/contact-record'\n\nexport type CrmRecordKind = 'contact' | 'company' | 'deal'\n\n/** The collection each kind of record lives in, under `orgs/{orgId}/`. */\nexport const CRM_RECORD_COLLECTIONS: Record<CrmRecordKind, string> = {\n contact: 'contacts',\n company: CRM_COLLECTIONS.companies,\n deal: CRM_COLLECTIONS.deals,\n}\n\n/**\n * What a record is CALLED, from its document.\n *\n * A contact's name is read through the viewing group's facet, the way the\n * people list reads it, so one business renaming a person does not change\n * what an unrelated business's task list shows; the email stands in for a\n * contact nobody has named. A company has a name and a deal a title.\n */\nexport function crmRecordName(\n kind: CrmRecordKind,\n data: Record<string, unknown> | undefined,\n groupId: string,\n): string {\n if (!data) return ''\n switch (kind) {\n case 'contact':\n return contactDisplayName(data, groupId) || String(data['email'] ?? '')\n case 'company':\n return String(data['name'] ?? '')\n case 'deal':\n return String(data['title'] ?? '')\n }\n}\n\n/**\n * Names already read, keyed by `orgId/collection/id`, shared by every\n * mount for the life of the page.\n *\n * A task list names the same handful of records over and over — five tasks\n * about one deal are five rows and one name — and a person moves between the\n * tasks section, a contact's page and the dashboard without the records\n * changing underneath them. `null` records a document that does not exist,\n * so a task pointing at a deleted record costs one read rather than one per\n * render. A rename is picked up on the next page load, which is the right\n * staleness for a label beside a link to the record itself.\n */\nconst nameCache = new Map<string, string | null>()\nconst pending = new Map<string, Promise<void>>()\n\nconst cacheKey = (orgId: string, kind: CrmRecordKind, id: string) =>\n `${orgId}/${CRM_RECORD_COLLECTIONS[kind]}/${id}`\n\n/** Test seam: forget everything, so a spec's fixtures are what get read. */\nexport function resetCrmRecordNameCache(): void {\n nameCache.clear()\n pending.clear()\n}\n\n/**\n * The reads that fill the cache for `records` not already in it — each\n * record read once however many callers ask at the same time.\n */\nfunction startNameReads(\n firestore: Firestore,\n orgId: string,\n groupId: string | null,\n org: Record<string, unknown> | null | undefined,\n records: ReadonlyArray<{ kind: CrmRecordKind; id: string }>,\n): Promise<void>[] {\n const reads: Promise<void>[] = []\n for (const { kind, id } of records) {\n if (!id) continue\n const key = cacheKey(orgId, kind, id)\n if (nameCache.has(key)) continue\n let read = pending.get(key)\n if (!read) {\n read = getDoc(doc(firestore, 'orgs', orgId, CRM_RECORD_COLLECTIONS[kind], id))\n .then((snapshot) => {\n const data = snapshot.exists() ? (snapshot.data() as Record<string, unknown>) : undefined\n nameCache.set(\n key,\n data ? crmRecordName(kind, data, groupId ?? contactPrimaryGroup(data, org).groupId) : null,\n )\n })\n .catch(() => {\n // A refused or failed read is not cached: the cell keeps showing\n // the id, and the next mount tries again.\n })\n .finally(() => {\n pending.delete(key)\n })\n pending.set(key, read)\n }\n reads.push(read)\n }\n return reads\n}\n\n/**\n * The names of `records`, read now — for a one-off like a file export,\n * which needs every name at once rather than a listener's re-render\n * (AGL-3521). Shares {@link useCrmRecordNames}' cache, and answers the same\n * lookup: `undefined` for a record that could not be named.\n */\nexport async function readCrmRecordNames(\n firestore: Firestore,\n options: {\n orgId: string\n groupId: string | null\n org?: Record<string, unknown> | null\n records: ReadonlyArray<{ kind: CrmRecordKind; id: string }>\n },\n): Promise<(kind: CrmRecordKind, id: string) => string | undefined> {\n const { orgId, groupId, org, records } = options\n await Promise.all(startNameReads(firestore, orgId, groupId, org, records))\n return (kind, id) => nameCache.get(cacheKey(orgId, kind, id)) ?? undefined\n}\n\n/**\n * The names of the records a list of tasks points at, resolved once each.\n *\n * Returns a lookup rather than a map so the caller does not have to know the\n * cache's key shape. An unresolved record answers `undefined` — the cell\n * renders the link with the id until the name lands, which is one render\n * later on a warm cache and one round trip on a cold one.\n */\nexport function useCrmRecordNames(options: {\n orgId: string | null | undefined\n /**\n * The viewing group a contact is named through, or `null` at the\n * organization level (AGL-2630), where each contact is named through its\n * own primary holder, resolved from {@link org}.\n */\n groupId: string | null\n org?: Record<string, unknown> | null\n records: ReadonlyArray<{ kind: CrmRecordKind; id: string }>\n}): (kind: CrmRecordKind, id: string) => string | undefined {\n const { orgId, groupId, org, records } = options\n const firestore = useFirestore()\n // A counter rather than a copy of the cache: the cache is the source of\n // truth and this only exists to re-render when it grows.\n const [, setResolved] = useState(0)\n\n // The pairs as one string, so the effect runs when the SET changes and not\n // when the caller builds a new array of the same pairs on every render.\n const wanted = records\n .map((record) => `${record.kind}:${record.id}`)\n .filter((entry, index, all) => all.indexOf(entry) === index)\n .sort()\n .join('\\n')\n\n useEffect(() => {\n if (!orgId || !wanted) return\n let active = true\n const reads = startNameReads(\n firestore,\n orgId,\n groupId,\n org,\n wanted.split('\\n').map((entry) => {\n const [kind, id] = entry.split(':') as [CrmRecordKind, string]\n return { kind, id }\n }),\n )\n if (!reads.length) return\n void Promise.all(reads).then(() => {\n if (active) setResolved((count) => count + 1)\n })\n return () => {\n active = false\n }\n }, [firestore, orgId, groupId, wanted])\n\n return useCallback(\n (kind: CrmRecordKind, id: string) => {\n if (!orgId) return undefined\n const hit = nameCache.get(cacheKey(orgId, kind, id))\n return hit === null ? undefined : hit\n },\n [orgId],\n )\n}\n"],"names":["contactDisplayName","CRM_COLLECTIONS","useFirestore","doc","getDoc","useCallback","useEffect","useState","contactPrimaryGroup","CRM_RECORD_COLLECTIONS","contact","company","companies","deal","deals","crmRecordName","kind","data","groupId","String","nameCache","Map","pending","cacheKey","orgId","id","resetCrmRecordNameCache","clear","startNameReads","firestore","org","records","reads","key","has","read","get","then","snapshot","exists","undefined","set","catch","finally","delete","push","readCrmRecordNames","options","Promise","all","useCrmRecordNames","setResolved","wanted","map","record","filter","entry","index","indexOf","sort","join","active","split","length","count","hit"],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type CrmTaskPicklists } from '@aglyn/aglyn';
|
|
2
|
+
/**
|
|
3
|
+
* An org's Status, Priority and Type lists for tasks (AGL-3517), for every
|
|
4
|
+
* surface that shows or writes a task's labels. Three document listens,
|
|
5
|
+
* shared by the Firestore SDK with every other mount asking for the same
|
|
6
|
+
* lists; `orgId` null reads nothing and answers the standard values.
|
|
7
|
+
*/
|
|
8
|
+
export declare function useCrmTaskPicklists(orgId: string | null | undefined): CrmTaskPicklists & {
|
|
9
|
+
ready: boolean;
|
|
10
|
+
};
|
|
11
|
+
export default useCrmTaskPicklists;
|
|
@@ -0,0 +1,45 @@
|
|
|
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 { CRM_TASK_PICKLIST_IDS } from "@aglyn/aglyn";
|
|
18
|
+
import { useMemo } from "react";
|
|
19
|
+
import { useCrmPicklist } from "./use-crm-picklist.js";
|
|
20
|
+
/**
|
|
21
|
+
* An org's Status, Priority and Type lists for tasks (AGL-3517), for every
|
|
22
|
+
* surface that shows or writes a task's labels. Three document listens,
|
|
23
|
+
* shared by the Firestore SDK with every other mount asking for the same
|
|
24
|
+
* lists; `orgId` null reads nothing and answers the standard values.
|
|
25
|
+
*/ export function useCrmTaskPicklists(orgId) {
|
|
26
|
+
const status = useCrmPicklist(CRM_TASK_PICKLIST_IDS.status, orgId);
|
|
27
|
+
const priority = useCrmPicklist(CRM_TASK_PICKLIST_IDS.priority, orgId);
|
|
28
|
+
const type = useCrmPicklist(CRM_TASK_PICKLIST_IDS.type, orgId);
|
|
29
|
+
return useMemo(()=>({
|
|
30
|
+
status: status.picklist,
|
|
31
|
+
priority: priority.picklist,
|
|
32
|
+
type: type.picklist,
|
|
33
|
+
ready: status.ready && priority.ready && type.ready
|
|
34
|
+
}), [
|
|
35
|
+
status.picklist,
|
|
36
|
+
status.ready,
|
|
37
|
+
priority.picklist,
|
|
38
|
+
priority.ready,
|
|
39
|
+
type.picklist,
|
|
40
|
+
type.ready
|
|
41
|
+
]);
|
|
42
|
+
}
|
|
43
|
+
export default useCrmTaskPicklists;
|
|
44
|
+
|
|
45
|
+
//# sourceMappingURL=use-crm-task-picklists.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/crm/src/lib/hooks/use-crm-task-picklists.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n'use client'\n\nimport { CRM_TASK_PICKLIST_IDS, type CrmTaskPicklists } from '@aglyn/aglyn'\nimport { useMemo } from 'react'\nimport { useCrmPicklist } from './use-crm-picklist'\n\n/**\n * An org's Status, Priority and Type lists for tasks (AGL-3517), for every\n * surface that shows or writes a task's labels. Three document listens,\n * shared by the Firestore SDK with every other mount asking for the same\n * lists; `orgId` null reads nothing and answers the standard values.\n */\nexport function useCrmTaskPicklists(orgId: string | null | undefined): CrmTaskPicklists & {\n ready: boolean\n} {\n const status = useCrmPicklist(CRM_TASK_PICKLIST_IDS.status, orgId)\n const priority = useCrmPicklist(CRM_TASK_PICKLIST_IDS.priority, orgId)\n const type = useCrmPicklist(CRM_TASK_PICKLIST_IDS.type, orgId)\n return useMemo(\n () => ({\n status: status.picklist,\n priority: priority.picklist,\n type: type.picklist,\n ready: status.ready && priority.ready && type.ready,\n }),\n [status.picklist, status.ready, priority.picklist, priority.ready, type.picklist, type.ready],\n )\n}\n\nexport default useCrmTaskPicklists\n"],"names":["CRM_TASK_PICKLIST_IDS","useMemo","useCrmPicklist","useCrmTaskPicklists","orgId","status","priority","type","picklist","ready"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GACD;AAEA,SAASA,qBAAqB,QAA+B,eAAc;AAC3E,SAASC,OAAO,QAAQ,QAAO;AAC/B,SAASC,cAAc,QAAQ,wBAAoB;AAEnD;;;;;CAKC,GACD,OAAO,SAASC,oBAAoBC,KAAgC;IAGlE,MAAMC,SAASH,eAAeF,sBAAsBK,MAAM,EAAED;IAC5D,MAAME,WAAWJ,eAAeF,sBAAsBM,QAAQ,EAAEF;IAChE,MAAMG,OAAOL,eAAeF,sBAAsBO,IAAI,EAAEH;IACxD,OAAOH,QACL,IAAO,CAAA;YACLI,QAAQA,OAAOG,QAAQ;YACvBF,UAAUA,SAASE,QAAQ;YAC3BD,MAAMA,KAAKC,QAAQ;YACnBC,OAAOJ,OAAOI,KAAK,IAAIH,SAASG,KAAK,IAAIF,KAAKE,KAAK;QACrD,CAAA,GACA;QAACJ,OAAOG,QAAQ;QAAEH,OAAOI,KAAK;QAAEH,SAASE,QAAQ;QAAEF,SAASG,KAAK;QAAEF,KAAKC,QAAQ;QAAED,KAAKE,KAAK;KAAC;AAEjG;AAEA,eAAeN,oBAAmB"}
|
|
@@ -32,5 +32,19 @@ export declare function useLinkedDeals(orgId: string | null, readTokens: readonl
|
|
|
32
32
|
} | {
|
|
33
33
|
companyId: string;
|
|
34
34
|
}): import("@aglyn/tenant-feature-instance").UseFirestoreCollectionResult<DealDoc>;
|
|
35
|
+
/**
|
|
36
|
+
* The deals a contact is on in ANY role (AGL-3521), for the contact's page
|
|
37
|
+
* beside the deals that name them as `contactId`.
|
|
38
|
+
*
|
|
39
|
+
* At the organization level, `contactRoleContactIds array-contains`. Under
|
|
40
|
+
* a site the scope and the contact are one clause —
|
|
41
|
+
* `scopedContactRoleContactIds array-contains-any` over `token~contactId`
|
|
42
|
+
* — because a query holds one array clause and the scope clause is one;
|
|
43
|
+
* that is a query the rules prove only for an org-wide member
|
|
44
|
+
* (`foldsScope`). A member whose reach is some sites asks nothing here, and
|
|
45
|
+
* reads the deals that name the contact as their Primary.
|
|
46
|
+
* `(contactRoleContactIds | scopedContactRoleContactIds, updatedAt DESC)`.
|
|
47
|
+
*/
|
|
48
|
+
export declare function useContactRoleDeals(orgId: string | null, readTokens: readonly string[] | null, foldsScope: boolean, contactId: string | null): import("@aglyn/tenant-feature-instance").UseFirestoreCollectionResult<DealDoc>;
|
|
35
49
|
/** One deal, live. `undefined` while loading, and after a delete. */
|
|
36
50
|
export declare function useDeal(orgId: string | null, dealId: string): import("@aglyn/tenant-feature-instance").UseFirestoreDocResult<DealDoc>;
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
* limitations under the License.
|
|
16
16
|
*/ 'use client';
|
|
17
17
|
import { CRM_COLLECTIONS } from "@aglyn/aglyn";
|
|
18
|
+
import { SCOPED_SEARCH_JOIN } from "@aglyn/aglyn/app-utils/name-search";
|
|
18
19
|
import { useFirestore, useFirestoreCollection, useFirestoreDoc } from "@aglyn/tenant-feature-instance";
|
|
19
20
|
import { collection, doc, limit, orderBy, query, where } from "firebase/firestore";
|
|
20
21
|
import { crmScopeListable, crmVisibleToClause } from "./use-crm-scope.js";
|
|
@@ -66,6 +67,34 @@ import { crmScopeListable, crmVisibleToClause } from "./use-crm-scope.js";
|
|
|
66
67
|
idField: '$id'
|
|
67
68
|
});
|
|
68
69
|
}
|
|
70
|
+
/**
|
|
71
|
+
* The deals a contact is on in ANY role (AGL-3521), for the contact's page
|
|
72
|
+
* beside the deals that name them as `contactId`.
|
|
73
|
+
*
|
|
74
|
+
* At the organization level, `contactRoleContactIds array-contains`. Under
|
|
75
|
+
* a site the scope and the contact are one clause —
|
|
76
|
+
* `scopedContactRoleContactIds array-contains-any` over `token~contactId`
|
|
77
|
+
* — because a query holds one array clause and the scope clause is one;
|
|
78
|
+
* that is a query the rules prove only for an org-wide member
|
|
79
|
+
* (`foldsScope`). A member whose reach is some sites asks nothing here, and
|
|
80
|
+
* reads the deals that name the contact as their Primary.
|
|
81
|
+
* `(contactRoleContactIds | scopedContactRoleContactIds, updatedAt DESC)`.
|
|
82
|
+
*/ export function useContactRoleDeals(orgId, readTokens, foldsScope, contactId) {
|
|
83
|
+
const firestore = useFirestore();
|
|
84
|
+
const scoped = readTokens ? readTokens.slice(0, 30).map((token)=>`${token}${SCOPED_SEARCH_JOIN}${contactId}`) : null;
|
|
85
|
+
const key = scoped ? scoped.join('\n') : '';
|
|
86
|
+
return useFirestoreCollection(()=>orgId && contactId && (readTokens === null || foldsScope && (scoped == null ? void 0 : scoped.length)) ? query(collection(firestore, 'orgs', orgId, CRM_COLLECTIONS.deals), scoped ? where('scopedContactRoleContactIds', 'array-contains-any', scoped) : where('contactRoleContactIds', 'array-contains', contactId), orderBy('updatedAt', 'desc'), limit(LINKED_DEALS_LIMIT)) : null, // `key` stands for `scoped`, whose array is rebuilt on every render.
|
|
87
|
+
[
|
|
88
|
+
firestore,
|
|
89
|
+
orgId,
|
|
90
|
+
key,
|
|
91
|
+
foldsScope,
|
|
92
|
+
contactId,
|
|
93
|
+
readTokens === null
|
|
94
|
+
], {
|
|
95
|
+
idField: '$id'
|
|
96
|
+
});
|
|
97
|
+
}
|
|
69
98
|
/** One deal, live. `undefined` while loading, and after a delete. */ export function useDeal(orgId, dealId) {
|
|
70
99
|
const firestore = useFirestore();
|
|
71
100
|
return useFirestoreDoc(()=>orgId && dealId ? doc(firestore, 'orgs', orgId, CRM_COLLECTIONS.deals, dealId) : null, [
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../../libs/plugins/crm/src/lib/hooks/use-deals.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n'use client'\n\nimport { CRM_COLLECTIONS, type CrmDealStatus } from '@aglyn/aglyn'\nimport {\n useFirestore,\n useFirestoreCollection,\n useFirestoreDoc,\n} from '@aglyn/tenant-feature-instance'\nimport {\n collection,\n doc,\n limit,\n orderBy,\n query,\n where,\n} from 'firebase/firestore'\nimport type { DealDoc } from '../model/deal-board-model'\nimport { crmScopeListable, crmVisibleToClause } from './use-crm-scope'\n\n/**\n * The most open cards one pipeline draws. A board past this is a board\n * nobody reads column by column; the table is paged by its query\n * (`DEAL_LIST_DECLARATION`) and reaches the rest.\n */\nexport const BOARD_OPEN_LIMIT = 500\n\n/** Closed deals shown per closed column when it is expanded. */\nexport const BOARD_CLOSED_LIMIT = 50\n\n/** Deals listed on a contact's or a company's page. */\nexport const LINKED_DEALS_LIMIT = 25\n\n/**\n * The deals of one status in one pipeline, newest activity first (AGL-2598).\n *\n * Every query here carries the viewer's scope tokens and an `orderBy`, and\n * each shape sits on an index the foundation declared:\n * `(visibleTo, pipelineId, status, updatedAt DESC)`. Passing `null` for the\n * pipeline or an EMPTY token list issues nothing, which is how a column\n * stays quiet until the pipeline has loaded and a collapsed Won column\n * costs no read. A `null` token list is the ORGANIZATION level (AGL-2630):\n * the clause is dropped and the query rides the `(pipelineId, status,\n * updatedAt DESC)` twin of that index.\n */\nexport function useDealsByStatus(\n orgId: string | null,\n readTokens: readonly string[] | null,\n pipelineId: string | null,\n status: CrmDealStatus,\n max: number,\n) {\n const firestore = useFirestore()\n return useFirestoreCollection<DealDoc>(\n () =>\n orgId && pipelineId && crmScopeListable(readTokens)\n ? query(\n collection(firestore, 'orgs', orgId, CRM_COLLECTIONS.deals),\n ...crmVisibleToClause(readTokens),\n where('pipelineId', '==', pipelineId),\n where('status', '==', status),\n orderBy('updatedAt', 'desc'),\n limit(max),\n )\n : null,\n [firestore, orgId, readTokens, pipelineId, status, max],\n { idField: '$id' },\n )\n}\n\n/**\n * The deals that name one contact or one company, for the card on that\n * record's page. `(visibleTo, contactId|companyId, updatedAt DESC)`.\n */\nexport function useLinkedDeals(\n orgId: string | null,\n readTokens: readonly string[] | null,\n link: { contactId: string } | { companyId: string },\n) {\n const firestore = useFirestore()\n const field = 'contactId' in link ? 'contactId' : 'companyId'\n const id = 'contactId' in link ? link.contactId : link.companyId\n return useFirestoreCollection<DealDoc>(\n () =>\n orgId && id && crmScopeListable(readTokens)\n ? query(\n collection(firestore, 'orgs', orgId, CRM_COLLECTIONS.deals),\n ...crmVisibleToClause(readTokens),\n where(field, '==', id),\n orderBy('updatedAt', 'desc'),\n limit(LINKED_DEALS_LIMIT),\n )\n : null,\n [firestore, orgId, readTokens, field, id],\n { idField: '$id' },\n )\n}\n\n/** One deal, live. `undefined` while loading, and after a delete. */\nexport function useDeal(orgId: string | null, dealId: string) {\n const firestore = useFirestore()\n return useFirestoreDoc<DealDoc>(\n () =>\n orgId && dealId\n ? doc(firestore, 'orgs', orgId, CRM_COLLECTIONS.deals, dealId)\n : null,\n [firestore, orgId, dealId],\n { idField: '$id' },\n )\n}\n"],"names":["CRM_COLLECTIONS","useFirestore","useFirestoreCollection","useFirestoreDoc","collection","doc","limit","orderBy","query","where","crmScopeListable","crmVisibleToClause","BOARD_OPEN_LIMIT","BOARD_CLOSED_LIMIT","LINKED_DEALS_LIMIT","useDealsByStatus","orgId","readTokens","pipelineId","status","max","firestore","deals","idField","useLinkedDeals","link","field","id","contactId","companyId","useDeal","dealId"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GACD;AAEA,SAASA,eAAe,QAA4B,eAAc;AAClE,SACEC,YAAY,EACZC,sBAAsB,EACtBC,eAAe,QACV,iCAAgC;AACvC,SACEC,UAAU,EACVC,GAAG,EACHC,KAAK,EACLC,OAAO,EACPC,KAAK,EACLC,KAAK,QACA,qBAAoB;AAE3B,SAASC,gBAAgB,EAAEC,kBAAkB,QAAQ,qBAAiB;AAEtE;;;;CAIC,GACD,OAAO,MAAMC,mBAAmB,IAAG;AAEnC,8DAA8D,GAC9D,OAAO,MAAMC,qBAAqB,GAAE;AAEpC,qDAAqD,GACrD,OAAO,MAAMC,qBAAqB,GAAE;AAEpC;;;;;;;;;;;CAWC,GACD,OAAO,SAASC,iBACdC,KAAoB,EACpBC,UAAoC,EACpCC,UAAyB,EACzBC,MAAqB,EACrBC,GAAW;IAEX,MAAMC,YAAYpB;IAClB,OAAOC,uBACL,IACEc,SAASE,cAAcR,iBAAiBO,cACpCT,MACEJ,WAAWiB,WAAW,QAAQL,
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/crm/src/lib/hooks/use-deals.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n'use client'\n\nimport { CRM_COLLECTIONS, type CrmDealStatus } from '@aglyn/aglyn'\nimport { SCOPED_SEARCH_JOIN } from '@aglyn/aglyn/app-utils/name-search'\nimport {\n useFirestore,\n useFirestoreCollection,\n useFirestoreDoc,\n} from '@aglyn/tenant-feature-instance'\nimport {\n collection,\n doc,\n limit,\n orderBy,\n query,\n where,\n} from 'firebase/firestore'\nimport type { DealDoc } from '../model/deal-board-model'\nimport { crmScopeListable, crmVisibleToClause } from './use-crm-scope'\n\n/**\n * The most open cards one pipeline draws. A board past this is a board\n * nobody reads column by column; the table is paged by its query\n * (`DEAL_LIST_DECLARATION`) and reaches the rest.\n */\nexport const BOARD_OPEN_LIMIT = 500\n\n/** Closed deals shown per closed column when it is expanded. */\nexport const BOARD_CLOSED_LIMIT = 50\n\n/** Deals listed on a contact's or a company's page. */\nexport const LINKED_DEALS_LIMIT = 25\n\n/**\n * The deals of one status in one pipeline, newest activity first (AGL-2598).\n *\n * Every query here carries the viewer's scope tokens and an `orderBy`, and\n * each shape sits on an index the foundation declared:\n * `(visibleTo, pipelineId, status, updatedAt DESC)`. Passing `null` for the\n * pipeline or an EMPTY token list issues nothing, which is how a column\n * stays quiet until the pipeline has loaded and a collapsed Won column\n * costs no read. A `null` token list is the ORGANIZATION level (AGL-2630):\n * the clause is dropped and the query rides the `(pipelineId, status,\n * updatedAt DESC)` twin of that index.\n */\nexport function useDealsByStatus(\n orgId: string | null,\n readTokens: readonly string[] | null,\n pipelineId: string | null,\n status: CrmDealStatus,\n max: number,\n) {\n const firestore = useFirestore()\n return useFirestoreCollection<DealDoc>(\n () =>\n orgId && pipelineId && crmScopeListable(readTokens)\n ? query(\n collection(firestore, 'orgs', orgId, CRM_COLLECTIONS.deals),\n ...crmVisibleToClause(readTokens),\n where('pipelineId', '==', pipelineId),\n where('status', '==', status),\n orderBy('updatedAt', 'desc'),\n limit(max),\n )\n : null,\n [firestore, orgId, readTokens, pipelineId, status, max],\n { idField: '$id' },\n )\n}\n\n/**\n * The deals that name one contact or one company, for the card on that\n * record's page. `(visibleTo, contactId|companyId, updatedAt DESC)`.\n */\nexport function useLinkedDeals(\n orgId: string | null,\n readTokens: readonly string[] | null,\n link: { contactId: string } | { companyId: string },\n) {\n const firestore = useFirestore()\n const field = 'contactId' in link ? 'contactId' : 'companyId'\n const id = 'contactId' in link ? link.contactId : link.companyId\n return useFirestoreCollection<DealDoc>(\n () =>\n orgId && id && crmScopeListable(readTokens)\n ? query(\n collection(firestore, 'orgs', orgId, CRM_COLLECTIONS.deals),\n ...crmVisibleToClause(readTokens),\n where(field, '==', id),\n orderBy('updatedAt', 'desc'),\n limit(LINKED_DEALS_LIMIT),\n )\n : null,\n [firestore, orgId, readTokens, field, id],\n { idField: '$id' },\n )\n}\n\n/**\n * The deals a contact is on in ANY role (AGL-3521), for the contact's page\n * beside the deals that name them as `contactId`.\n *\n * At the organization level, `contactRoleContactIds array-contains`. Under\n * a site the scope and the contact are one clause —\n * `scopedContactRoleContactIds array-contains-any` over `token~contactId`\n * — because a query holds one array clause and the scope clause is one;\n * that is a query the rules prove only for an org-wide member\n * (`foldsScope`). A member whose reach is some sites asks nothing here, and\n * reads the deals that name the contact as their Primary.\n * `(contactRoleContactIds | scopedContactRoleContactIds, updatedAt DESC)`.\n */\nexport function useContactRoleDeals(\n orgId: string | null,\n readTokens: readonly string[] | null,\n foldsScope: boolean,\n contactId: string | null,\n) {\n const firestore = useFirestore()\n const scoped = readTokens\n ? readTokens.slice(0, 30).map((token) => `${token}${SCOPED_SEARCH_JOIN}${contactId}`)\n : null\n const key = scoped ? scoped.join('\\n') : ''\n return useFirestoreCollection<DealDoc>(\n () =>\n orgId && contactId && (readTokens === null || (foldsScope && scoped?.length))\n ? query(\n collection(firestore, 'orgs', orgId, CRM_COLLECTIONS.deals),\n scoped\n ? where('scopedContactRoleContactIds', 'array-contains-any', scoped)\n : where('contactRoleContactIds', 'array-contains', contactId),\n orderBy('updatedAt', 'desc'),\n limit(LINKED_DEALS_LIMIT),\n )\n : null,\n // `key` stands for `scoped`, whose array is rebuilt on every render.\n [firestore, orgId, key, foldsScope, contactId, readTokens === null],\n { idField: '$id' },\n )\n}\n\n/** One deal, live. `undefined` while loading, and after a delete. */\nexport function useDeal(orgId: string | null, dealId: string) {\n const firestore = useFirestore()\n return useFirestoreDoc<DealDoc>(\n () =>\n orgId && dealId\n ? doc(firestore, 'orgs', orgId, CRM_COLLECTIONS.deals, dealId)\n : null,\n [firestore, orgId, dealId],\n { idField: '$id' },\n )\n}\n"],"names":["CRM_COLLECTIONS","SCOPED_SEARCH_JOIN","useFirestore","useFirestoreCollection","useFirestoreDoc","collection","doc","limit","orderBy","query","where","crmScopeListable","crmVisibleToClause","BOARD_OPEN_LIMIT","BOARD_CLOSED_LIMIT","LINKED_DEALS_LIMIT","useDealsByStatus","orgId","readTokens","pipelineId","status","max","firestore","deals","idField","useLinkedDeals","link","field","id","contactId","companyId","useContactRoleDeals","foldsScope","scoped","slice","map","token","key","join","length","useDeal","dealId"],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { CrmPicklist, CrmPicklistId } from '@aglyn/aglyn';
|
|
2
|
+
export interface LeadPicklistsResult {
|
|
3
|
+
/** Each list a lead field beside the lead source holds a value of, by picklist id. */
|
|
4
|
+
lists: Readonly<Partial<Record<CrmPicklistId, CrmPicklist>>>;
|
|
5
|
+
/** Every list has answered from the server. */
|
|
6
|
+
ready: boolean;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* The org's lists behind a lead's Salutation, Industry and Rating
|
|
10
|
+
* (AGL-3513) — the contact's and the company's own lists, one document
|
|
11
|
+
* listen each, shared with every other mount asking for the same list.
|
|
12
|
+
*/
|
|
13
|
+
export declare function useLeadPicklists(orgId: string | null | undefined): LeadPicklistsResult;
|
|
14
|
+
export default useLeadPicklists;
|
|
@@ -0,0 +1,46 @@
|
|
|
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 { useMemo } from "react";
|
|
18
|
+
import { useCrmPicklist } from "./use-crm-picklist.js";
|
|
19
|
+
/**
|
|
20
|
+
* The org's lists behind a lead's Salutation, Industry and Rating
|
|
21
|
+
* (AGL-3513) — the contact's and the company's own lists, one document
|
|
22
|
+
* listen each, shared with every other mount asking for the same list.
|
|
23
|
+
*/ export function useLeadPicklists(orgId) {
|
|
24
|
+
const salutation = useCrmPicklist('salutation', orgId);
|
|
25
|
+
const industry = useCrmPicklist('industry', orgId);
|
|
26
|
+
const rating = useCrmPicklist('rating', orgId);
|
|
27
|
+
return useMemo(()=>({
|
|
28
|
+
lists: {
|
|
29
|
+
salutation: salutation.picklist,
|
|
30
|
+
industry: industry.picklist,
|
|
31
|
+
rating: rating.picklist
|
|
32
|
+
},
|
|
33
|
+
ready: [
|
|
34
|
+
salutation,
|
|
35
|
+
industry,
|
|
36
|
+
rating
|
|
37
|
+
].every((list)=>list.ready)
|
|
38
|
+
}), [
|
|
39
|
+
salutation,
|
|
40
|
+
industry,
|
|
41
|
+
rating
|
|
42
|
+
]);
|
|
43
|
+
}
|
|
44
|
+
export default useLeadPicklists;
|
|
45
|
+
|
|
46
|
+
//# sourceMappingURL=use-lead-picklists.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/crm/src/lib/hooks/use-lead-picklists.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n'use client'\n\nimport type { CrmPicklist, CrmPicklistId } from '@aglyn/aglyn'\nimport { useMemo } from 'react'\nimport { useCrmPicklist } from './use-crm-picklist'\n\nexport interface LeadPicklistsResult {\n /** Each list a lead field beside the lead source holds a value of, by picklist id. */\n lists: Readonly<Partial<Record<CrmPicklistId, CrmPicklist>>>\n /** Every list has answered from the server. */\n ready: boolean\n}\n\n/**\n * The org's lists behind a lead's Salutation, Industry and Rating\n * (AGL-3513) — the contact's and the company's own lists, one document\n * listen each, shared with every other mount asking for the same list.\n */\nexport function useLeadPicklists(orgId: string | null | undefined): LeadPicklistsResult {\n const salutation = useCrmPicklist('salutation', orgId)\n const industry = useCrmPicklist('industry', orgId)\n const rating = useCrmPicklist('rating', orgId)\n return useMemo(\n () => ({\n lists: {\n salutation: salutation.picklist,\n industry: industry.picklist,\n rating: rating.picklist,\n },\n ready: [salutation, industry, rating].every((list) => list.ready),\n }),\n [salutation, industry, rating],\n )\n}\n\nexport default useLeadPicklists\n"],"names":["useMemo","useCrmPicklist","useLeadPicklists","orgId","salutation","industry","rating","lists","picklist","ready","every","list"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GACD;AAGA,SAASA,OAAO,QAAQ,QAAO;AAC/B,SAASC,cAAc,QAAQ,wBAAoB;AASnD;;;;CAIC,GACD,OAAO,SAASC,iBAAiBC,KAAgC;IAC/D,MAAMC,aAAaH,eAAe,cAAcE;IAChD,MAAME,WAAWJ,eAAe,YAAYE;IAC5C,MAAMG,SAASL,eAAe,UAAUE;IACxC,OAAOH,QACL,IAAO,CAAA;YACLO,OAAO;gBACLH,YAAYA,WAAWI,QAAQ;gBAC/BH,UAAUA,SAASG,QAAQ;gBAC3BF,QAAQA,OAAOE,QAAQ;YACzB;YACAC,OAAO;gBAACL;gBAAYC;gBAAUC;aAAO,CAACI,KAAK,CAAC,CAACC,OAASA,KAAKF,KAAK;QAClE,CAAA,GACA;QAACL;QAAYC;QAAUC;KAAO;AAElC;AAEA,eAAeJ,iBAAgB"}
|
|
@@ -1,23 +1,9 @@
|
|
|
1
|
-
import { type
|
|
2
|
-
export
|
|
3
|
-
/** The list every picker offers — the org's own, or the starter set. */
|
|
4
|
-
picklist: CrmPicklist;
|
|
5
|
-
/** The org has written its own list; false while it reads the starter set. */
|
|
6
|
-
stored: boolean;
|
|
7
|
-
/** The server has answered, so the list is the org's and not a placeholder. */
|
|
8
|
-
ready: boolean;
|
|
9
|
-
/** The document has not been confirmed by the server — `writeGuardedBySeed`'s input. */
|
|
10
|
-
fromCache: boolean;
|
|
11
|
-
}
|
|
1
|
+
import { type CrmPicklistResult } from './use-crm-picklist';
|
|
2
|
+
export type LeadSourcePicklistResult = Omit<CrmPicklistResult, 'definition'>;
|
|
12
3
|
/**
|
|
13
|
-
* The org's lead source values (AGL-3298)
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
* One document listen, shared by the Firestore SDK across every mount that
|
|
18
|
-
* asks for the same org, so a page with the list and a drawer open pays
|
|
19
|
-
* for it once. `orgId` null issues no read and answers the starter set,
|
|
20
|
-
* unready.
|
|
4
|
+
* The org's lead source values (AGL-3298) — {@link useCrmPicklist} for the
|
|
5
|
+
* lead source: the lead page's select, the New lead drawer, the contact's
|
|
6
|
+
* card, the leads list's filter and the import drawer.
|
|
21
7
|
*/
|
|
22
8
|
export declare function useLeadSourcePicklist(orgId: string | null | undefined): LeadSourcePicklistResult;
|
|
23
9
|
export default useLeadSourcePicklist;
|
|
@@ -14,34 +14,24 @@
|
|
|
14
14
|
* See the License for the specific language governing permissions and
|
|
15
15
|
* limitations under the License.
|
|
16
16
|
*/ 'use client';
|
|
17
|
-
import {
|
|
18
|
-
import { useFirestore, useFirestoreDoc } from "@aglyn/tenant-feature-instance";
|
|
19
|
-
import { doc } from "firebase/firestore";
|
|
17
|
+
import { CRM_LEAD_SOURCE_PICKLIST } from "@aglyn/aglyn";
|
|
20
18
|
import { useMemo } from "react";
|
|
19
|
+
import { useCrmPicklist } from "./use-crm-picklist.js";
|
|
21
20
|
/**
|
|
22
|
-
* The org's lead source values (AGL-3298)
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
* One document listen, shared by the Firestore SDK across every mount that
|
|
27
|
-
* asks for the same org, so a page with the list and a drawer open pays
|
|
28
|
-
* for it once. `orgId` null issues no read and answers the starter set,
|
|
29
|
-
* unready.
|
|
21
|
+
* The org's lead source values (AGL-3298) — {@link useCrmPicklist} for the
|
|
22
|
+
* lead source: the lead page's select, the New lead drawer, the contact's
|
|
23
|
+
* card, the leads list's filter and the import drawer.
|
|
30
24
|
*/ export function useLeadSourcePicklist(orgId) {
|
|
31
|
-
const
|
|
32
|
-
const { data, status, fromCache } = useFirestoreDoc(()=>orgId ? doc(firestore, 'orgs', orgId, CRM_COLLECTIONS.picklists, CRM_LEAD_SOURCE_PICKLIST) : null, [
|
|
33
|
-
firestore,
|
|
34
|
-
orgId
|
|
35
|
-
]);
|
|
25
|
+
const { picklist, stored, ready, fromCache } = useCrmPicklist(CRM_LEAD_SOURCE_PICKLIST, orgId);
|
|
36
26
|
return useMemo(()=>({
|
|
37
|
-
picklist
|
|
38
|
-
stored
|
|
39
|
-
ready
|
|
27
|
+
picklist,
|
|
28
|
+
stored,
|
|
29
|
+
ready,
|
|
40
30
|
fromCache
|
|
41
31
|
}), [
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
32
|
+
picklist,
|
|
33
|
+
stored,
|
|
34
|
+
ready,
|
|
45
35
|
fromCache
|
|
46
36
|
]);
|
|
47
37
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../../libs/plugins/crm/src/lib/hooks/use-lead-source-picklist.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n'use client'\n\nimport {
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/crm/src/lib/hooks/use-lead-source-picklist.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n'use client'\n\nimport { CRM_LEAD_SOURCE_PICKLIST } from '@aglyn/aglyn'\nimport { useMemo } from 'react'\nimport { type CrmPicklistResult, useCrmPicklist } from './use-crm-picklist'\n\nexport type LeadSourcePicklistResult = Omit<CrmPicklistResult, 'definition'>\n\n/**\n * The org's lead source values (AGL-3298) — {@link useCrmPicklist} for the\n * lead source: the lead page's select, the New lead drawer, the contact's\n * card, the leads list's filter and the import drawer.\n */\nexport function useLeadSourcePicklist(orgId: string | null | undefined): LeadSourcePicklistResult {\n const { picklist, stored, ready, fromCache } = useCrmPicklist(CRM_LEAD_SOURCE_PICKLIST, orgId)\n return useMemo(() => ({ picklist, stored, ready, fromCache }), [picklist, stored, ready, fromCache])\n}\n\nexport default useLeadSourcePicklist\n"],"names":["CRM_LEAD_SOURCE_PICKLIST","useMemo","useCrmPicklist","useLeadSourcePicklist","orgId","picklist","stored","ready","fromCache"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GACD;AAEA,SAASA,wBAAwB,QAAQ,eAAc;AACvD,SAASC,OAAO,QAAQ,QAAO;AAC/B,SAAiCC,cAAc,QAAQ,wBAAoB;AAI3E;;;;CAIC,GACD,OAAO,SAASC,sBAAsBC,KAAgC;IACpE,MAAM,EAAEC,QAAQ,EAAEC,MAAM,EAAEC,KAAK,EAAEC,SAAS,EAAE,GAAGN,eAAeF,0BAA0BI;IACxF,OAAOH,QAAQ,IAAO,CAAA;YAAEI;YAAUC;YAAQC;YAAOC;QAAU,CAAA,GAAI;QAACH;QAAUC;QAAQC;QAAOC;KAAU;AACrG;AAEA,eAAeL,sBAAqB"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type CrmPicklistResult } from './use-crm-picklist';
|
|
2
|
+
export type LeadStatusPicklistResult = Omit<CrmPicklistResult, 'definition'>;
|
|
3
|
+
/**
|
|
4
|
+
* The org's lead status values (AGL-3512) — {@link useCrmPicklist} for the
|
|
5
|
+
* lead status: every chip, select and filter that shows a lead's status by
|
|
6
|
+
* the label the org gave its meaning. One shared document listen.
|
|
7
|
+
*/
|
|
8
|
+
export declare function useLeadStatusPicklist(orgId: string | null | undefined): LeadStatusPicklistResult;
|
|
9
|
+
export default useLeadStatusPicklist;
|
|
@@ -0,0 +1,40 @@
|
|
|
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 { CRM_LEAD_STATUS_PICKLIST } from "@aglyn/aglyn";
|
|
18
|
+
import { useMemo } from "react";
|
|
19
|
+
import { useCrmPicklist } from "./use-crm-picklist.js";
|
|
20
|
+
/**
|
|
21
|
+
* The org's lead status values (AGL-3512) — {@link useCrmPicklist} for the
|
|
22
|
+
* lead status: every chip, select and filter that shows a lead's status by
|
|
23
|
+
* the label the org gave its meaning. One shared document listen.
|
|
24
|
+
*/ export function useLeadStatusPicklist(orgId) {
|
|
25
|
+
const { picklist, stored, ready, fromCache } = useCrmPicklist(CRM_LEAD_STATUS_PICKLIST, orgId);
|
|
26
|
+
return useMemo(()=>({
|
|
27
|
+
picklist,
|
|
28
|
+
stored,
|
|
29
|
+
ready,
|
|
30
|
+
fromCache
|
|
31
|
+
}), [
|
|
32
|
+
picklist,
|
|
33
|
+
stored,
|
|
34
|
+
ready,
|
|
35
|
+
fromCache
|
|
36
|
+
]);
|
|
37
|
+
}
|
|
38
|
+
export default useLeadStatusPicklist;
|
|
39
|
+
|
|
40
|
+
//# sourceMappingURL=use-lead-status-picklist.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/crm/src/lib/hooks/use-lead-status-picklist.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n'use client'\n\nimport { CRM_LEAD_STATUS_PICKLIST } from '@aglyn/aglyn'\nimport { useMemo } from 'react'\nimport { type CrmPicklistResult, useCrmPicklist } from './use-crm-picklist'\n\nexport type LeadStatusPicklistResult = Omit<CrmPicklistResult, 'definition'>\n\n/**\n * The org's lead status values (AGL-3512) — {@link useCrmPicklist} for the\n * lead status: every chip, select and filter that shows a lead's status by\n * the label the org gave its meaning. One shared document listen.\n */\nexport function useLeadStatusPicklist(orgId: string | null | undefined): LeadStatusPicklistResult {\n const { picklist, stored, ready, fromCache } = useCrmPicklist(CRM_LEAD_STATUS_PICKLIST, orgId)\n return useMemo(() => ({ picklist, stored, ready, fromCache }), [picklist, stored, ready, fromCache])\n}\n\nexport default useLeadStatusPicklist\n"],"names":["CRM_LEAD_STATUS_PICKLIST","useMemo","useCrmPicklist","useLeadStatusPicklist","orgId","picklist","stored","ready","fromCache"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GACD;AAEA,SAASA,wBAAwB,QAAQ,eAAc;AACvD,SAASC,OAAO,QAAQ,QAAO;AAC/B,SAAiCC,cAAc,QAAQ,wBAAoB;AAI3E;;;;CAIC,GACD,OAAO,SAASC,sBAAsBC,KAAgC;IACpE,MAAM,EAAEC,QAAQ,EAAEC,MAAM,EAAEC,KAAK,EAAEC,SAAS,EAAE,GAAGN,eAAeF,0BAA0BI;IACxF,OAAOH,QAAQ,IAAO,CAAA;YAAEI;YAAUC;YAAQC;YAAOC;QAAU,CAAA,GAAI;QAACH;QAAUC;QAAQC;QAAOC;KAAU;AACrG;AAEA,eAAeL,sBAAqB"}
|