@aglyn/plugins-crm 1.0.0-beta.143
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/LICENSE +201 -0
- package/README.md +7 -0
- package/package.json +57 -0
- package/src/index.d.ts +21 -0
- package/src/index.js +29 -0
- package/src/index.js.map +1 -0
- package/src/lib/components/activity-list.d.ts +98 -0
- package/src/lib/components/activity-list.js +321 -0
- package/src/lib/components/activity-list.js.map +1 -0
- package/src/lib/components/activity-queries.d.ts +117 -0
- package/src/lib/components/activity-queries.js +198 -0
- package/src/lib/components/activity-queries.js.map +1 -0
- package/src/lib/components/add-to-list-button.d.ts +25 -0
- package/src/lib/components/add-to-list-button.js +64 -0
- package/src/lib/components/add-to-list-button.js.map +1 -0
- package/src/lib/components/add-to-list-dialog.d.ts +24 -0
- package/src/lib/components/add-to-list-dialog.js +327 -0
- package/src/lib/components/add-to-list-dialog.js.map +1 -0
- package/src/lib/components/assignment-rule-drawer.d.ts +43 -0
- package/src/lib/components/assignment-rule-drawer.js +293 -0
- package/src/lib/components/assignment-rule-drawer.js.map +1 -0
- package/src/lib/components/companies-bulk-bar.d.ts +29 -0
- package/src/lib/components/companies-bulk-bar.js +274 -0
- package/src/lib/components/companies-bulk-bar.js.map +1 -0
- package/src/lib/components/companies-section.d.ts +54 -0
- package/src/lib/components/companies-section.js +522 -0
- package/src/lib/components/companies-section.js.map +1 -0
- package/src/lib/components/company-contacts-card.d.ts +49 -0
- package/src/lib/components/company-contacts-card.js +435 -0
- package/src/lib/components/company-contacts-card.js.map +1 -0
- package/src/lib/components/company-deals-card.d.ts +20 -0
- package/src/lib/components/company-deals-card.js +38 -0
- package/src/lib/components/company-deals-card.js.map +1 -0
- package/src/lib/components/company-detail-page.d.ts +20 -0
- package/src/lib/components/company-detail-page.js +165 -0
- package/src/lib/components/company-detail-page.js.map +1 -0
- package/src/lib/components/company-edit-drawer.d.ts +65 -0
- package/src/lib/components/company-edit-drawer.js +433 -0
- package/src/lib/components/company-edit-drawer.js.map +1 -0
- package/src/lib/components/company-import-drawer.d.ts +42 -0
- package/src/lib/components/company-import-drawer.js +99 -0
- package/src/lib/components/company-import-drawer.js.map +1 -0
- package/src/lib/components/company-picker.d.ts +127 -0
- package/src/lib/components/company-picker.js +323 -0
- package/src/lib/components/company-picker.js.map +1 -0
- package/src/lib/components/company-properties-card.d.ts +47 -0
- package/src/lib/components/company-properties-card.js +289 -0
- package/src/lib/components/company-properties-card.js.map +1 -0
- package/src/lib/components/contact-address-fields.d.ts +29 -0
- package/src/lib/components/contact-address-fields.js +149 -0
- package/src/lib/components/contact-address-fields.js.map +1 -0
- package/src/lib/components/contact-associations-card.d.ts +72 -0
- package/src/lib/components/contact-associations-card.js +296 -0
- package/src/lib/components/contact-associations-card.js.map +1 -0
- package/src/lib/components/contact-custom-columns.d.ts +38 -0
- package/src/lib/components/contact-custom-columns.js +102 -0
- package/src/lib/components/contact-custom-columns.js.map +1 -0
- package/src/lib/components/contact-custom-fields-card.d.ts +39 -0
- package/src/lib/components/contact-custom-fields-card.js +204 -0
- package/src/lib/components/contact-custom-fields-card.js.map +1 -0
- package/src/lib/components/contact-deals-card.d.ts +20 -0
- package/src/lib/components/contact-deals-card.js +38 -0
- package/src/lib/components/contact-deals-card.js.map +1 -0
- package/src/lib/components/contact-detail-page.d.ts +46 -0
- package/src/lib/components/contact-detail-page.js +535 -0
- package/src/lib/components/contact-detail-page.js.map +1 -0
- package/src/lib/components/contact-duplicates-card.d.ts +42 -0
- package/src/lib/components/contact-duplicates-card.js +167 -0
- package/src/lib/components/contact-duplicates-card.js.map +1 -0
- package/src/lib/components/contact-field-drawer.d.ts +64 -0
- package/src/lib/components/contact-field-drawer.js +251 -0
- package/src/lib/components/contact-field-drawer.js.map +1 -0
- package/src/lib/components/contact-import-drawer.d.ts +46 -0
- package/src/lib/components/contact-import-drawer.js +149 -0
- package/src/lib/components/contact-import-drawer.js.map +1 -0
- package/src/lib/components/contact-known-by-card.d.ts +39 -0
- package/src/lib/components/contact-known-by-card.js +142 -0
- package/src/lib/components/contact-known-by-card.js.map +1 -0
- package/src/lib/components/contact-list-columns.d.ts +53 -0
- package/src/lib/components/contact-list-columns.js +288 -0
- package/src/lib/components/contact-list-columns.js.map +1 -0
- package/src/lib/components/contact-merge-dialog.d.ts +79 -0
- package/src/lib/components/contact-merge-dialog.js +405 -0
- package/src/lib/components/contact-merge-dialog.js.map +1 -0
- package/src/lib/components/contact-properties-card.d.ts +89 -0
- package/src/lib/components/contact-properties-card.js +492 -0
- package/src/lib/components/contact-properties-card.js.map +1 -0
- package/src/lib/components/contact-timeline-card.d.ts +68 -0
- package/src/lib/components/contact-timeline-card.js +435 -0
- package/src/lib/components/contact-timeline-card.js.map +1 -0
- package/src/lib/components/contacts-bulk-bar.d.ts +91 -0
- package/src/lib/components/contacts-bulk-bar.js +493 -0
- package/src/lib/components/contacts-bulk-bar.js.map +1 -0
- package/src/lib/components/contacts-section.d.ts +26 -0
- package/src/lib/components/contacts-section.js +1025 -0
- package/src/lib/components/contacts-section.js.map +1 -0
- package/src/lib/components/copy-capture-address-button.d.ts +33 -0
- package/src/lib/components/copy-capture-address-button.js +60 -0
- package/src/lib/components/copy-capture-address-button.js.map +1 -0
- package/src/lib/components/crm-attribution-zone.d.ts +38 -0
- package/src/lib/components/crm-attribution-zone.js +36 -0
- package/src/lib/components/crm-attribution-zone.js.map +1 -0
- package/src/lib/components/crm-booking-zone.d.ts +61 -0
- package/src/lib/components/crm-booking-zone.js +50 -0
- package/src/lib/components/crm-booking-zone.js.map +1 -0
- package/src/lib/components/crm-bulk-bar-frame.d.ts +47 -0
- package/src/lib/components/crm-bulk-bar-frame.js +137 -0
- package/src/lib/components/crm-bulk-bar-frame.js.map +1 -0
- package/src/lib/components/crm-call-actions.d.ts +65 -0
- package/src/lib/components/crm-call-actions.js +110 -0
- package/src/lib/components/crm-call-actions.js.map +1 -0
- package/src/lib/components/crm-column-menu.d.ts +21 -0
- package/src/lib/components/crm-column-menu.js +103 -0
- package/src/lib/components/crm-column-menu.js.map +1 -0
- package/src/lib/components/crm-console-page.d.ts +19 -0
- package/src/lib/components/crm-console-page.js +151 -0
- package/src/lib/components/crm-console-page.js.map +1 -0
- package/src/lib/components/crm-console-sections.d.ts +52 -0
- package/src/lib/components/crm-console-sections.js +83 -0
- package/src/lib/components/crm-console-sections.js.map +1 -0
- package/src/lib/components/crm-custom-field-control.d.ts +26 -0
- package/src/lib/components/crm-custom-field-control.js +131 -0
- package/src/lib/components/crm-custom-field-control.js.map +1 -0
- package/src/lib/components/crm-email-template-tools.d.ts +69 -0
- package/src/lib/components/crm-email-template-tools.js +240 -0
- package/src/lib/components/crm-email-template-tools.js.map +1 -0
- package/src/lib/components/crm-export-all-button.d.ts +39 -0
- package/src/lib/components/crm-export-all-button.js +98 -0
- package/src/lib/components/crm-export-all-button.js.map +1 -0
- package/src/lib/components/crm-filter-bar.d.ts +53 -0
- package/src/lib/components/crm-filter-bar.js +294 -0
- package/src/lib/components/crm-filter-bar.js.map +1 -0
- package/src/lib/components/crm-glance-card.d.ts +54 -0
- package/src/lib/components/crm-glance-card.js +219 -0
- package/src/lib/components/crm-glance-card.js.map +1 -0
- package/src/lib/components/crm-next-activity-column.d.ts +35 -0
- package/src/lib/components/crm-next-activity-column.js +100 -0
- package/src/lib/components/crm-next-activity-column.js.map +1 -0
- package/src/lib/components/crm-record-header.d.ts +97 -0
- package/src/lib/components/crm-record-header.js +160 -0
- package/src/lib/components/crm-record-header.js.map +1 -0
- package/src/lib/components/crm-record-insights-zone.d.ts +50 -0
- package/src/lib/components/crm-record-insights-zone.js +169 -0
- package/src/lib/components/crm-record-insights-zone.js.map +1 -0
- package/src/lib/components/crm-record-picker.d.ts +42 -0
- package/src/lib/components/crm-record-picker.js +104 -0
- package/src/lib/components/crm-record-picker.js.map +1 -0
- package/src/lib/components/crm-send-email-button.d.ts +39 -0
- package/src/lib/components/crm-send-email-button.js +81 -0
- package/src/lib/components/crm-send-email-button.js.map +1 -0
- package/src/lib/components/crm-send-email-dialog.d.ts +61 -0
- package/src/lib/components/crm-send-email-dialog.js +851 -0
- package/src/lib/components/crm-send-email-dialog.js.map +1 -0
- package/src/lib/components/crm-site-picker.d.ts +61 -0
- package/src/lib/components/crm-site-picker.js +99 -0
- package/src/lib/components/crm-site-picker.js.map +1 -0
- package/src/lib/components/crm-suite-lock.d.ts +29 -0
- package/src/lib/components/crm-suite-lock.js +114 -0
- package/src/lib/components/crm-suite-lock.js.map +1 -0
- package/src/lib/components/crm-tasks-due-card.d.ts +42 -0
- package/src/lib/components/crm-tasks-due-card.js +225 -0
- package/src/lib/components/crm-tasks-due-card.js.map +1 -0
- package/src/lib/components/crm-views-control.d.ts +65 -0
- package/src/lib/components/crm-views-control.js +518 -0
- package/src/lib/components/crm-views-control.js.map +1 -0
- package/src/lib/components/csv-import-drawer.d.ts +132 -0
- package/src/lib/components/csv-import-drawer.js +746 -0
- package/src/lib/components/csv-import-drawer.js.map +1 -0
- package/src/lib/components/deal-board.d.ts +70 -0
- package/src/lib/components/deal-board.js +478 -0
- package/src/lib/components/deal-board.js.map +1 -0
- package/src/lib/components/deal-detail-page.d.ts +18 -0
- package/src/lib/components/deal-detail-page.js +323 -0
- package/src/lib/components/deal-detail-page.js.map +1 -0
- package/src/lib/components/deal-edit-drawer.d.ts +59 -0
- package/src/lib/components/deal-edit-drawer.js +640 -0
- package/src/lib/components/deal-edit-drawer.js.map +1 -0
- package/src/lib/components/deal-import-drawer.d.ts +24 -0
- package/src/lib/components/deal-import-drawer.js +83 -0
- package/src/lib/components/deal-import-drawer.js.map +1 -0
- package/src/lib/components/deal-products-card.d.ts +48 -0
- package/src/lib/components/deal-products-card.js +614 -0
- package/src/lib/components/deal-products-card.js.map +1 -0
- package/src/lib/components/deal-properties-card.d.ts +29 -0
- package/src/lib/components/deal-properties-card.js +144 -0
- package/src/lib/components/deal-properties-card.js.map +1 -0
- package/src/lib/components/deal-stage-card.d.ts +24 -0
- package/src/lib/components/deal-stage-card.js +199 -0
- package/src/lib/components/deal-stage-card.js.map +1 -0
- package/src/lib/components/deals-bulk-bar.d.ts +31 -0
- package/src/lib/components/deals-bulk-bar.js +340 -0
- package/src/lib/components/deals-bulk-bar.js.map +1 -0
- package/src/lib/components/deals-section.d.ts +49 -0
- package/src/lib/components/deals-section.js +767 -0
- package/src/lib/components/deals-section.js.map +1 -0
- package/src/lib/components/email-capture-card.d.ts +42 -0
- package/src/lib/components/email-capture-card.js +134 -0
- package/src/lib/components/email-capture-card.js.map +1 -0
- package/src/lib/components/email-template-drawer.d.ts +33 -0
- package/src/lib/components/email-template-drawer.js +209 -0
- package/src/lib/components/email-template-drawer.js.map +1 -0
- package/src/lib/components/email-templates-card.d.ts +33 -0
- package/src/lib/components/email-templates-card.js +370 -0
- package/src/lib/components/email-templates-card.js.map +1 -0
- package/src/lib/components/erase-person-action.d.ts +92 -0
- package/src/lib/components/erase-person-action.js +261 -0
- package/src/lib/components/erase-person-action.js.map +1 -0
- package/src/lib/components/fields-section.d.ts +37 -0
- package/src/lib/components/fields-section.js +641 -0
- package/src/lib/components/fields-section.js.map +1 -0
- package/src/lib/components/form-contact-fields-card.d.ts +46 -0
- package/src/lib/components/form-contact-fields-card.js +253 -0
- package/src/lib/components/form-contact-fields-card.js.map +1 -0
- package/src/lib/components/insert-link-at-caret.d.ts +28 -0
- package/src/lib/components/insert-link-at-caret.js +37 -0
- package/src/lib/components/insert-link-at-caret.js.map +1 -0
- package/src/lib/components/lead-convert-dialog.d.ts +32 -0
- package/src/lib/components/lead-convert-dialog.js +493 -0
- package/src/lib/components/lead-convert-dialog.js.map +1 -0
- package/src/lib/components/lead-detail-page.d.ts +16 -0
- package/src/lib/components/lead-detail-page.js +163 -0
- package/src/lib/components/lead-detail-page.js.map +1 -0
- package/src/lib/components/lead-history-card.d.ts +32 -0
- package/src/lib/components/lead-history-card.js +165 -0
- package/src/lib/components/lead-history-card.js.map +1 -0
- package/src/lib/components/lead-import-drawer.d.ts +24 -0
- package/src/lib/components/lead-import-drawer.js +95 -0
- package/src/lib/components/lead-import-drawer.js.map +1 -0
- package/src/lib/components/lead-owner-select.d.ts +35 -0
- package/src/lib/components/lead-owner-select.js +91 -0
- package/src/lib/components/lead-owner-select.js.map +1 -0
- package/src/lib/components/lead-properties-card.d.ts +61 -0
- package/src/lib/components/lead-properties-card.js +395 -0
- package/src/lib/components/lead-properties-card.js.map +1 -0
- package/src/lib/components/lead-status-chip.d.ts +12 -0
- package/src/lib/components/lead-status-chip.js +43 -0
- package/src/lib/components/lead-status-chip.js.map +1 -0
- package/src/lib/components/lead-surfaces-note.d.ts +126 -0
- package/src/lib/components/lead-surfaces-note.js +262 -0
- package/src/lib/components/lead-surfaces-note.js.map +1 -0
- package/src/lib/components/lead-unqualify-dialog.d.ts +24 -0
- package/src/lib/components/lead-unqualify-dialog.js +125 -0
- package/src/lib/components/lead-unqualify-dialog.js.map +1 -0
- package/src/lib/components/leads-bulk-bar.d.ts +58 -0
- package/src/lib/components/leads-bulk-bar.js +307 -0
- package/src/lib/components/leads-bulk-bar.js.map +1 -0
- package/src/lib/components/leads-section.d.ts +23 -0
- package/src/lib/components/leads-section.js +664 -0
- package/src/lib/components/leads-section.js.map +1 -0
- package/src/lib/components/linked-deals-card.d.ts +32 -0
- package/src/lib/components/linked-deals-card.js +163 -0
- package/src/lib/components/linked-deals-card.js.map +1 -0
- package/src/lib/components/log-activity-dialog.d.ts +60 -0
- package/src/lib/components/log-activity-dialog.js +368 -0
- package/src/lib/components/log-activity-dialog.js.map +1 -0
- package/src/lib/components/lost-reason-dialog.d.ts +26 -0
- package/src/lib/components/lost-reason-dialog.js +95 -0
- package/src/lib/components/lost-reason-dialog.js.map +1 -0
- package/src/lib/components/new-contact-drawer.d.ts +78 -0
- package/src/lib/components/new-contact-drawer.js +343 -0
- package/src/lib/components/new-contact-drawer.js.map +1 -0
- package/src/lib/components/org-lead-surfaces-note.d.ts +57 -0
- package/src/lib/components/org-lead-surfaces-note.js +172 -0
- package/src/lib/components/org-lead-surfaces-note.js.map +1 -0
- package/src/lib/components/owner-avatar.d.ts +18 -0
- package/src/lib/components/owner-avatar.js +61 -0
- package/src/lib/components/owner-avatar.js.map +1 -0
- package/src/lib/components/pipeline-stages-dialog.d.ts +43 -0
- package/src/lib/components/pipeline-stages-dialog.js +339 -0
- package/src/lib/components/pipeline-stages-dialog.js.map +1 -0
- package/src/lib/components/pipelines-dialog.d.ts +55 -0
- package/src/lib/components/pipelines-dialog.js +517 -0
- package/src/lib/components/pipelines-dialog.js.map +1 -0
- package/src/lib/components/recent-activity-feed.d.ts +39 -0
- package/src/lib/components/recent-activity-feed.js +103 -0
- package/src/lib/components/recent-activity-feed.js.map +1 -0
- package/src/lib/components/recipes-card.d.ts +39 -0
- package/src/lib/components/recipes-card.js +485 -0
- package/src/lib/components/recipes-card.js.map +1 -0
- package/src/lib/components/record-activity-card.d.ts +26 -0
- package/src/lib/components/record-activity-card.js +121 -0
- package/src/lib/components/record-activity-card.js.map +1 -0
- package/src/lib/components/record-files-card.d.ts +67 -0
- package/src/lib/components/record-files-card.js +290 -0
- package/src/lib/components/record-files-card.js.map +1 -0
- package/src/lib/components/record-tasks-card.d.ts +32 -0
- package/src/lib/components/record-tasks-card.js +306 -0
- package/src/lib/components/record-tasks-card.js.map +1 -0
- package/src/lib/components/reports/activity-card.d.ts +57 -0
- package/src/lib/components/reports/activity-card.js +281 -0
- package/src/lib/components/reports/activity-card.js.map +1 -0
- package/src/lib/components/reports/closed-deals-card.d.ts +20 -0
- package/src/lib/components/reports/closed-deals-card.js +194 -0
- package/src/lib/components/reports/closed-deals-card.js.map +1 -0
- package/src/lib/components/reports/contacts-mix-card.d.ts +27 -0
- package/src/lib/components/reports/contacts-mix-card.js +161 -0
- package/src/lib/components/reports/contacts-mix-card.js.map +1 -0
- package/src/lib/components/reports/contacts-trend-card.d.ts +31 -0
- package/src/lib/components/reports/contacts-trend-card.js +144 -0
- package/src/lib/components/reports/contacts-trend-card.js.map +1 -0
- package/src/lib/components/reports/forecast-card.d.ts +22 -0
- package/src/lib/components/reports/forecast-card.js +251 -0
- package/src/lib/components/reports/forecast-card.js.map +1 -0
- package/src/lib/components/reports/lead-counts.d.ts +32 -0
- package/src/lib/components/reports/lead-counts.js +44 -0
- package/src/lib/components/reports/lead-counts.js.map +1 -0
- package/src/lib/components/reports/lead-funnel-card.d.ts +38 -0
- package/src/lib/components/reports/lead-funnel-card.js +375 -0
- package/src/lib/components/reports/lead-funnel-card.js.map +1 -0
- package/src/lib/components/reports/pipeline-card.d.ts +19 -0
- package/src/lib/components/reports/pipeline-card.js +338 -0
- package/src/lib/components/reports/pipeline-card.js.map +1 -0
- package/src/lib/components/reports/report-bar-chart.d.ts +39 -0
- package/src/lib/components/reports/report-bar-chart.js +133 -0
- package/src/lib/components/reports/report-bar-chart.js.map +1 -0
- package/src/lib/components/reports/report-breakdown.d.ts +32 -0
- package/src/lib/components/reports/report-breakdown.js +105 -0
- package/src/lib/components/reports/report-breakdown.js.map +1 -0
- package/src/lib/components/reports/report-export.d.ts +37 -0
- package/src/lib/components/reports/report-export.js +66 -0
- package/src/lib/components/reports/report-export.js.map +1 -0
- package/src/lib/components/reports/report-format.d.ts +36 -0
- package/src/lib/components/reports/report-format.js +43 -0
- package/src/lib/components/reports/report-format.js.map +1 -0
- package/src/lib/components/reports/report-scope.d.ts +81 -0
- package/src/lib/components/reports/report-scope.js +58 -0
- package/src/lib/components/reports/report-scope.js.map +1 -0
- package/src/lib/components/reports/report-stat-tile.d.ts +47 -0
- package/src/lib/components/reports/report-stat-tile.js +96 -0
- package/src/lib/components/reports/report-stat-tile.js.map +1 -0
- package/src/lib/components/reports/source-conversion-card.d.ts +28 -0
- package/src/lib/components/reports/source-conversion-card.js +205 -0
- package/src/lib/components/reports/source-conversion-card.js.map +1 -0
- package/src/lib/components/reports/tasks-card.d.ts +26 -0
- package/src/lib/components/reports/tasks-card.js +279 -0
- package/src/lib/components/reports/tasks-card.js.map +1 -0
- package/src/lib/components/reports/use-aggregate-read.d.ts +99 -0
- package/src/lib/components/reports/use-aggregate-read.js +195 -0
- package/src/lib/components/reports/use-aggregate-read.js.map +1 -0
- package/src/lib/components/reports/won-lost-by-owner-card.d.ts +30 -0
- package/src/lib/components/reports/won-lost-by-owner-card.js +168 -0
- package/src/lib/components/reports/won-lost-by-owner-card.js.map +1 -0
- package/src/lib/components/reports-section.d.ts +42 -0
- package/src/lib/components/reports-section.js +308 -0
- package/src/lib/components/reports-section.js.map +1 -0
- package/src/lib/components/sending-addresses-card.d.ts +49 -0
- package/src/lib/components/sending-addresses-card.js +262 -0
- package/src/lib/components/sending-addresses-card.js.map +1 -0
- package/src/lib/components/settings-section.d.ts +151 -0
- package/src/lib/components/settings-section.js +783 -0
- package/src/lib/components/settings-section.js.map +1 -0
- package/src/lib/components/task-cells.d.ts +51 -0
- package/src/lib/components/task-cells.js +139 -0
- package/src/lib/components/task-cells.js.map +1 -0
- package/src/lib/components/task-edit-drawer.d.ts +53 -0
- package/src/lib/components/task-edit-drawer.js +483 -0
- package/src/lib/components/task-edit-drawer.js.map +1 -0
- package/src/lib/components/task-import-drawer.d.ts +24 -0
- package/src/lib/components/task-import-drawer.js +82 -0
- package/src/lib/components/task-import-drawer.js.map +1 -0
- package/src/lib/components/task-snooze-menu.d.ts +65 -0
- package/src/lib/components/task-snooze-menu.js +207 -0
- package/src/lib/components/task-snooze-menu.js.map +1 -0
- package/src/lib/components/tasks-bulk-bar.d.ts +25 -0
- package/src/lib/components/tasks-bulk-bar.js +348 -0
- package/src/lib/components/tasks-bulk-bar.js.map +1 -0
- package/src/lib/components/tasks-calendar.d.ts +38 -0
- package/src/lib/components/tasks-calendar.js +228 -0
- package/src/lib/components/tasks-calendar.js.map +1 -0
- package/src/lib/components/tasks-section.d.ts +27 -0
- package/src/lib/components/tasks-section.js +579 -0
- package/src/lib/components/tasks-section.js.map +1 -0
- package/src/lib/components/use-contact-campaign-emails.d.ts +32 -0
- package/src/lib/components/use-contact-campaign-emails.js +83 -0
- package/src/lib/components/use-contact-campaign-emails.js.map +1 -0
- package/src/lib/components/use-crm-api.d.ts +44 -0
- package/src/lib/components/use-crm-api.js +84 -0
- package/src/lib/components/use-crm-api.js.map +1 -0
- package/src/lib/components/use-crm-inbound-address.d.ts +60 -0
- package/src/lib/components/use-crm-inbound-address.js +124 -0
- package/src/lib/components/use-crm-inbound-address.js.map +1 -0
- package/src/lib/components/use-emails-hub-path.d.ts +24 -0
- package/src/lib/components/use-emails-hub-path.js +59 -0
- package/src/lib/components/use-emails-hub-path.js.map +1 -0
- package/src/lib/components/use-member-email-aliases.d.ts +54 -0
- package/src/lib/components/use-member-email-aliases.js +186 -0
- package/src/lib/components/use-member-email-aliases.js.map +1 -0
- package/src/lib/components/use-org-members.d.ts +40 -0
- package/src/lib/components/use-org-members.js +100 -0
- package/src/lib/components/use-org-members.js.map +1 -0
- package/src/lib/constants/api-routes.d.ts +109 -0
- package/src/lib/constants/api-routes.js +74 -0
- package/src/lib/constants/api-routes.js.map +1 -0
- package/src/lib/constants/bundle-common.d.ts +14 -0
- package/src/lib/constants/bundle-common.js +14 -0
- package/src/lib/constants/bundle-common.js.map +1 -0
- package/src/lib/constants/company-filters.d.ts +18 -0
- package/src/lib/constants/company-filters.js +51 -0
- package/src/lib/constants/company-filters.js.map +1 -0
- package/src/lib/constants/contact-filters.d.ts +38 -0
- package/src/lib/constants/contact-filters.js +294 -0
- package/src/lib/constants/contact-filters.js.map +1 -0
- package/src/lib/hooks/use-contact-field-definitions.d.ts +48 -0
- package/src/lib/hooks/use-contact-field-definitions.js +72 -0
- package/src/lib/hooks/use-contact-field-definitions.js.map +1 -0
- package/src/lib/hooks/use-contact-update.d.ts +25 -0
- package/src/lib/hooks/use-contact-update.js +80 -0
- package/src/lib/hooks/use-contact-update.js.map +1 -0
- package/src/lib/hooks/use-crm-activity-logger.d.ts +73 -0
- package/src/lib/hooks/use-crm-activity-logger.js +101 -0
- package/src/lib/hooks/use-crm-activity-logger.js.map +1 -0
- package/src/lib/hooks/use-crm-bulk-apply.d.ts +52 -0
- package/src/lib/hooks/use-crm-bulk-apply.js +112 -0
- package/src/lib/hooks/use-crm-bulk-apply.js.map +1 -0
- package/src/lib/hooks/use-crm-default-view.d.ts +24 -0
- package/src/lib/hooks/use-crm-default-view.js +64 -0
- package/src/lib/hooks/use-crm-default-view.js.map +1 -0
- package/src/lib/hooks/use-crm-email-templates.d.ts +59 -0
- package/src/lib/hooks/use-crm-email-templates.js +103 -0
- package/src/lib/hooks/use-crm-email-templates.js.map +1 -0
- package/src/lib/hooks/use-crm-hub-path.d.ts +29 -0
- package/src/lib/hooks/use-crm-hub-path.js +41 -0
- package/src/lib/hooks/use-crm-hub-path.js.map +1 -0
- package/src/lib/hooks/use-crm-org-mount.d.ts +97 -0
- package/src/lib/hooks/use-crm-org-mount.js +215 -0
- package/src/lib/hooks/use-crm-org-mount.js.map +1 -0
- package/src/lib/hooks/use-crm-record-names.d.ts +52 -0
- package/src/lib/hooks/use-crm-record-names.js +126 -0
- package/src/lib/hooks/use-crm-record-names.js.map +1 -0
- package/src/lib/hooks/use-crm-records-quota.d.ts +68 -0
- package/src/lib/hooks/use-crm-records-quota.js +118 -0
- package/src/lib/hooks/use-crm-records-quota.js.map +1 -0
- package/src/lib/hooks/use-crm-saved-view.d.ts +96 -0
- package/src/lib/hooks/use-crm-saved-view.js +329 -0
- package/src/lib/hooks/use-crm-saved-view.js.map +1 -0
- package/src/lib/hooks/use-crm-scope.d.ts +117 -0
- package/src/lib/hooks/use-crm-scope.js +147 -0
- package/src/lib/hooks/use-crm-scope.js.map +1 -0
- package/src/lib/hooks/use-crm-tasks.d.ts +85 -0
- package/src/lib/hooks/use-crm-tasks.js +153 -0
- package/src/lib/hooks/use-crm-tasks.js.map +1 -0
- package/src/lib/hooks/use-crm-view-grid.d.ts +55 -0
- package/src/lib/hooks/use-crm-view-grid.js +170 -0
- package/src/lib/hooks/use-crm-view-grid.js.map +1 -0
- package/src/lib/hooks/use-crm-views.d.ts +42 -0
- package/src/lib/hooks/use-crm-views.js +84 -0
- package/src/lib/hooks/use-crm-views.js.map +1 -0
- package/src/lib/hooks/use-deal-stage-api.d.ts +69 -0
- package/src/lib/hooks/use-deal-stage-api.js +78 -0
- package/src/lib/hooks/use-deal-stage-api.js.map +1 -0
- package/src/lib/hooks/use-deals.d.ts +47 -0
- package/src/lib/hooks/use-deals.js +105 -0
- package/src/lib/hooks/use-deals.js.map +1 -0
- package/src/lib/hooks/use-org-leads.d.ts +53 -0
- package/src/lib/hooks/use-org-leads.js +114 -0
- package/src/lib/hooks/use-org-leads.js.map +1 -0
- package/src/lib/hooks/use-org-member-directory.d.ts +36 -0
- package/src/lib/hooks/use-org-member-directory.js +116 -0
- package/src/lib/hooks/use-org-member-directory.js.map +1 -0
- package/src/lib/hooks/use-org-member-options.d.ts +38 -0
- package/src/lib/hooks/use-org-member-options.js +131 -0
- package/src/lib/hooks/use-org-member-options.js.map +1 -0
- package/src/lib/hooks/use-pipeline.d.ts +71 -0
- package/src/lib/hooks/use-pipeline.js +159 -0
- package/src/lib/hooks/use-pipeline.js.map +1 -0
- package/src/lib/model/companies-bulk-writes.d.ts +40 -0
- package/src/lib/model/companies-bulk-writes.js +103 -0
- package/src/lib/model/companies-bulk-writes.js.map +1 -0
- package/src/lib/model/companies-csv.d.ts +36 -0
- package/src/lib/model/companies-csv.js +38 -0
- package/src/lib/model/companies-csv.js.map +1 -0
- package/src/lib/model/companies.d.ts +99 -0
- package/src/lib/model/companies.js +168 -0
- package/src/lib/model/companies.js.map +1 -0
- package/src/lib/model/company-delete-route.d.ts +43 -0
- package/src/lib/model/company-delete-route.js +31 -0
- package/src/lib/model/company-delete-route.js.map +1 -0
- package/src/lib/model/company-delete.d.ts +42 -0
- package/src/lib/model/company-delete.js +52 -0
- package/src/lib/model/company-delete.js.map +1 -0
- package/src/lib/model/contact-duplicates.d.ts +58 -0
- package/src/lib/model/contact-duplicates.js +67 -0
- package/src/lib/model/contact-duplicates.js.map +1 -0
- package/src/lib/model/contact-record.d.ts +113 -0
- package/src/lib/model/contact-record.js +70 -0
- package/src/lib/model/contact-record.js.map +1 -0
- package/src/lib/model/contact-update.d.ts +93 -0
- package/src/lib/model/contact-update.js +50 -0
- package/src/lib/model/contact-update.js.map +1 -0
- package/src/lib/model/contacts-bulk-writes.d.ts +173 -0
- package/src/lib/model/contacts-bulk-writes.js +196 -0
- package/src/lib/model/contacts-bulk-writes.js.map +1 -0
- package/src/lib/model/contacts-csv.d.ts +54 -0
- package/src/lib/model/contacts-csv.js +67 -0
- package/src/lib/model/contacts-csv.js.map +1 -0
- package/src/lib/model/contacts-list-seed.d.ts +51 -0
- package/src/lib/model/contacts-list-seed.js +63 -0
- package/src/lib/model/contacts-list-seed.js.map +1 -0
- package/src/lib/model/crm-activity-report.d.ts +27 -0
- package/src/lib/model/crm-activity-report.js +56 -0
- package/src/lib/model/crm-activity-report.js.map +1 -0
- package/src/lib/model/crm-api.d.ts +49 -0
- package/src/lib/model/crm-api.js +47 -0
- package/src/lib/model/crm-api.js.map +1 -0
- package/src/lib/model/crm-bulk-writes.d.ts +147 -0
- package/src/lib/model/crm-bulk-writes.js +207 -0
- package/src/lib/model/crm-bulk-writes.js.map +1 -0
- package/src/lib/model/crm-company-import.d.ts +154 -0
- package/src/lib/model/crm-company-import.js +331 -0
- package/src/lib/model/crm-company-import.js.map +1 -0
- package/src/lib/model/crm-custom-draft.d.ts +62 -0
- package/src/lib/model/crm-custom-draft.js +67 -0
- package/src/lib/model/crm-custom-draft.js.map +1 -0
- package/src/lib/model/crm-deal-import.d.ts +112 -0
- package/src/lib/model/crm-deal-import.js +263 -0
- package/src/lib/model/crm-deal-import.js.map +1 -0
- package/src/lib/model/crm-import.d.ts +244 -0
- package/src/lib/model/crm-import.js +466 -0
- package/src/lib/model/crm-import.js.map +1 -0
- package/src/lib/model/crm-lead-import.d.ts +105 -0
- package/src/lib/model/crm-lead-import.js +255 -0
- package/src/lib/model/crm-lead-import.js.map +1 -0
- package/src/lib/model/crm-record-routes.d.ts +21 -0
- package/src/lib/model/crm-record-routes.js +70 -0
- package/src/lib/model/crm-record-routes.js.map +1 -0
- package/src/lib/model/crm-routes.d.ts +101 -0
- package/src/lib/model/crm-routes.js +92 -0
- package/src/lib/model/crm-routes.js.map +1 -0
- package/src/lib/model/crm-task-import.d.ts +94 -0
- package/src/lib/model/crm-task-import.js +275 -0
- package/src/lib/model/crm-task-import.js.map +1 -0
- package/src/lib/model/crm-view-param.d.ts +43 -0
- package/src/lib/model/crm-view-param.js +49 -0
- package/src/lib/model/crm-view-param.js.map +1 -0
- package/src/lib/model/deal-board-model.d.ts +241 -0
- package/src/lib/model/deal-board-model.js +439 -0
- package/src/lib/model/deal-board-model.js.map +1 -0
- package/src/lib/model/deal-form-model.d.ts +114 -0
- package/src/lib/model/deal-form-model.js +218 -0
- package/src/lib/model/deal-form-model.js.map +1 -0
- package/src/lib/model/deals-csv.d.ts +32 -0
- package/src/lib/model/deals-csv.js +37 -0
- package/src/lib/model/deals-csv.js.map +1 -0
- package/src/lib/model/import-column-shapes.d.ts +36 -0
- package/src/lib/model/import-column-shapes.js +76 -0
- package/src/lib/model/import-column-shapes.js.map +1 -0
- package/src/lib/model/lead-company-suggestion.d.ts +61 -0
- package/src/lib/model/lead-company-suggestion.js +65 -0
- package/src/lib/model/lead-company-suggestion.js.map +1 -0
- package/src/lib/model/lead-filters.d.ts +29 -0
- package/src/lib/model/lead-filters.js +39 -0
- package/src/lib/model/lead-filters.js.map +1 -0
- package/src/lib/model/lead-surfaces.d.ts +58 -0
- package/src/lib/model/lead-surfaces.js +67 -0
- package/src/lib/model/lead-surfaces.js.map +1 -0
- package/src/lib/model/leads-csv.d.ts +40 -0
- package/src/lib/model/leads-csv.js +40 -0
- package/src/lib/model/leads-csv.js.map +1 -0
- package/src/lib/model/next-activity-api.d.ts +31 -0
- package/src/lib/model/next-activity-api.js +57 -0
- package/src/lib/model/next-activity-api.js.map +1 -0
- package/src/lib/model/next-activity.d.ts +64 -0
- package/src/lib/model/next-activity.js +47 -0
- package/src/lib/model/next-activity.js.map +1 -0
- package/src/lib/model/person-key-web.d.ts +43 -0
- package/src/lib/model/person-key-web.js +52 -0
- package/src/lib/model/person-key-web.js.map +1 -0
- package/src/lib/model/record-facts.d.ts +282 -0
- package/src/lib/model/record-facts.js +434 -0
- package/src/lib/model/record-facts.js.map +1 -0
- package/src/lib/model/task-api.d.ts +28 -0
- package/src/lib/model/task-api.js +57 -0
- package/src/lib/model/task-api.js.map +1 -0
- package/src/lib/model/task-calendar.d.ts +108 -0
- package/src/lib/model/task-calendar.js +139 -0
- package/src/lib/model/task-calendar.js.map +1 -0
- package/src/lib/model/task-routes.d.ts +177 -0
- package/src/lib/model/task-routes.js +197 -0
- package/src/lib/model/task-routes.js.map +1 -0
- package/src/lib/model/task-scope.d.ts +45 -0
- package/src/lib/model/task-scope.js +51 -0
- package/src/lib/model/task-scope.js.map +1 -0
- package/src/lib/model/task-views.d.ts +149 -0
- package/src/lib/model/task-views.js +286 -0
- package/src/lib/model/task-views.js.map +1 -0
- package/src/lib/model/tasks-csv.d.ts +28 -0
- package/src/lib/model/tasks-csv.js +28 -0
- package/src/lib/model/tasks-csv.js.map +1 -0
- package/src/lib/plugin.d.ts +32 -0
- package/src/lib/plugin.js +208 -0
- package/src/lib/plugin.js.map +1 -0
- package/src/lib/server/companies-import.d.ts +57 -0
- package/src/lib/server/companies-import.js +242 -0
- package/src/lib/server/companies-import.js.map +1 -0
- package/src/lib/server/company-delete.d.ts +59 -0
- package/src/lib/server/company-delete.js +146 -0
- package/src/lib/server/company-delete.js.map +1 -0
- package/src/lib/server/contact-email-history.d.ts +82 -0
- package/src/lib/server/contact-email-history.js +264 -0
- package/src/lib/server/contact-email-history.js.map +1 -0
- package/src/lib/server/contact-profile.d.ts +41 -0
- package/src/lib/server/contact-profile.js +45 -0
- package/src/lib/server/contact-profile.js.map +1 -0
- package/src/lib/server/contact-update.d.ts +92 -0
- package/src/lib/server/contact-update.js +512 -0
- package/src/lib/server/contact-update.js.map +1 -0
- package/src/lib/server/contacts-import.d.ts +73 -0
- package/src/lib/server/contacts-import.js +263 -0
- package/src/lib/server/contacts-import.js.map +1 -0
- package/src/lib/server/contacts-merge.d.ts +86 -0
- package/src/lib/server/contacts-merge.js +206 -0
- package/src/lib/server/contacts-merge.js.map +1 -0
- package/src/lib/server/deals-import.d.ts +76 -0
- package/src/lib/server/deals-import.js +246 -0
- package/src/lib/server/deals-import.js.map +1 -0
- package/src/lib/server/email-send.d.ts +119 -0
- package/src/lib/server/email-send.js +667 -0
- package/src/lib/server/email-send.js.map +1 -0
- package/src/lib/server/email-template-duplicate.d.ts +19 -0
- package/src/lib/server/email-template-duplicate.js +206 -0
- package/src/lib/server/email-template-duplicate.js.map +1 -0
- package/src/lib/server/erase-person.d.ts +108 -0
- package/src/lib/server/erase-person.js +309 -0
- package/src/lib/server/erase-person.js.map +1 -0
- package/src/lib/server/import-context.d.ts +85 -0
- package/src/lib/server/import-context.js +181 -0
- package/src/lib/server/import-context.js.map +1 -0
- package/src/lib/server/inbound-address.d.ts +61 -0
- package/src/lib/server/inbound-address.js +188 -0
- package/src/lib/server/inbound-address.js.map +1 -0
- package/src/lib/server/lead-convert.d.ts +78 -0
- package/src/lib/server/lead-convert.js +250 -0
- package/src/lib/server/lead-convert.js.map +1 -0
- package/src/lib/server/leads-import.d.ts +84 -0
- package/src/lib/server/leads-import.js +261 -0
- package/src/lib/server/leads-import.js.map +1 -0
- package/src/lib/server/next-activity-routes.d.ts +33 -0
- package/src/lib/server/next-activity-routes.js +110 -0
- package/src/lib/server/next-activity-routes.js.map +1 -0
- package/src/lib/server/org-activity.d.ts +61 -0
- package/src/lib/server/org-activity.js +120 -0
- package/src/lib/server/org-activity.js.map +1 -0
- package/src/lib/server/org-caller.d.ts +110 -0
- package/src/lib/server/org-caller.js +154 -0
- package/src/lib/server/org-caller.js.map +1 -0
- package/src/lib/server/recipe-routes.d.ts +75 -0
- package/src/lib/server/recipe-routes.js +442 -0
- package/src/lib/server/recipe-routes.js.map +1 -0
- package/src/lib/server/record-facts.d.ts +65 -0
- package/src/lib/server/record-facts.js +337 -0
- package/src/lib/server/record-facts.js.map +1 -0
- package/src/lib/server/record-timeline.d.ts +51 -0
- package/src/lib/server/record-timeline.js +215 -0
- package/src/lib/server/record-timeline.js.map +1 -0
- package/src/lib/server/suite-gate.d.ts +42 -0
- package/src/lib/server/suite-gate.js +87 -0
- package/src/lib/server/suite-gate.js.map +1 -0
- package/src/lib/server/task-routes.d.ts +132 -0
- package/src/lib/server/task-routes.js +699 -0
- package/src/lib/server/task-routes.js.map +1 -0
- package/src/lib/server/tasks-import.d.ts +54 -0
- package/src/lib/server/tasks-import.js +157 -0
- package/src/lib/server/tasks-import.js.map +1 -0
- package/src/lib/server-deal-stage.d.ts +88 -0
- package/src/lib/server-deal-stage.js +316 -0
- package/src/lib/server-deal-stage.js.map +1 -0
- package/src/lib/server.d.ts +149 -0
- package/src/lib/server.js +615 -0
- package/src/lib/server.js.map +1 -0
|
@@ -0,0 +1,434 @@
|
|
|
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
|
+
*/ import { CONTACT_LIFECYCLE_STAGE_LABELS, CONTACT_SOURCE_LABELS, CRM_ACTIVITY_KIND_LABELS, CRM_EMAIL_DELIVERY_STATE_LABELS, CRM_LEAD_STATUS_LABELS, CRM_TASK_KIND_LABELS, contactDisplayName, crmLeadStatus, customImportTarget, dealStageById, fieldDefinitionObject, interactionsForGroup, isContactLifecycleStage, isCrmEmailDeliveryState, readContactFacet } from "@aglyn/aglyn/server";
|
|
17
|
+
import { COMPANY_IMPORT_FIELD_LABELS, COMPANY_IMPORT_FIELDS } from "./crm-company-import.js";
|
|
18
|
+
import { CONTACT_IMPORT_FIELD_LABELS, CONTACT_IMPORT_FIELDS } from "./crm-import.js";
|
|
19
|
+
import { DEAL_IMPORT_FIELD_LABELS, DEAL_IMPORT_FIELDS } from "./crm-deal-import.js";
|
|
20
|
+
import { LEAD_IMPORT_FIELD_LABELS, LEAD_IMPORT_FIELDS } from "./crm-lead-import.js";
|
|
21
|
+
/**
|
|
22
|
+
* WHAT THE CRM TELLS ANOTHER PLUGIN ABOUT ONE OF ITS RECORDS (AGL-2917).
|
|
23
|
+
*
|
|
24
|
+
* The facts a reader on the core's record-facts seam reports: one contact,
|
|
25
|
+
* company, deal or lead as a person on the team sees it, and the fields a
|
|
26
|
+
* spreadsheet import may fill. The server half reads the documents and
|
|
27
|
+
* applies who may see them (`server/record-facts.ts`); this half decides
|
|
28
|
+
* which of their fields leave the CRM at all, so the list below is the whole
|
|
29
|
+
* of what a caller — an assistant summarizing a record, an automation
|
|
30
|
+
* deciding on one — can pass on.
|
|
31
|
+
*
|
|
32
|
+
* ## What never leaves
|
|
33
|
+
*
|
|
34
|
+
* No email address, phone number or postal address of anyone; no marketing
|
|
35
|
+
* consent; no custom field VALUE; no team member's name or id; no document
|
|
36
|
+
* id of any record; no file; no order or payment detail beyond a count. A
|
|
37
|
+
* logged email carries its subject and a cut of its body, never the address
|
|
38
|
+
* it went to or came from. An import catalog carries field keys, labels and
|
|
39
|
+
* types, never a row of the file.
|
|
40
|
+
*
|
|
41
|
+
* Every text a person wrote into a record — a name, a job title, a tag, notes,
|
|
42
|
+
* a logged activity, a capture's summary, a task's or a deal's title, a
|
|
43
|
+
* reason — is reported as written, except that an email address or a phone
|
|
44
|
+
* number inside it is replaced by a placeholder first ({@link crmFactProse}):
|
|
45
|
+
* an import that put an address in the name column leaves no address behind.
|
|
46
|
+
* What the workspace configured — pipeline, stage and field names — and a
|
|
47
|
+
* company's domain are reported as they are. A postal address typed into a
|
|
48
|
+
* note is not recognized and leaves as typed.
|
|
49
|
+
*
|
|
50
|
+
* ## Stable bytes
|
|
51
|
+
*
|
|
52
|
+
* Every builder writes its keys in one order, dates as UTC calendar days and
|
|
53
|
+
* money as a currency code and a fixed-point amount, so the same records read
|
|
54
|
+
* twice report the same facts — a caller may key a cache on them, and one
|
|
55
|
+
* that does sees a change exactly when something it was told has changed.
|
|
56
|
+
*/ /** The records a reader is registered for, by the seam's resource name. */ export const CRM_RECORD_FACTS_RESOURCES = {
|
|
57
|
+
contact: 'crm.contact',
|
|
58
|
+
company: 'crm.company',
|
|
59
|
+
deal: 'crm.deal',
|
|
60
|
+
lead: 'crm.lead'
|
|
61
|
+
};
|
|
62
|
+
/** The import catalogs, read by collection name as the record id. */ export const CRM_IMPORT_FACTS_RESOURCE = 'crm.import';
|
|
63
|
+
export const CRM_IMPORT_FACTS_COLLECTIONS = [
|
|
64
|
+
'contacts',
|
|
65
|
+
'companies',
|
|
66
|
+
'deals',
|
|
67
|
+
'leads'
|
|
68
|
+
];
|
|
69
|
+
export function isCrmImportFactsCollection(value) {
|
|
70
|
+
return typeof value === 'string' && CRM_IMPORT_FACTS_COLLECTIONS.includes(value);
|
|
71
|
+
}
|
|
72
|
+
/** Newest timeline entries reported for a record. */ export const CRM_FACTS_TIMELINE_MAX = 12;
|
|
73
|
+
/** Open tasks reported for a record. */ export const CRM_FACTS_TASKS_MAX = 8;
|
|
74
|
+
/** Deals reported for a contact or a company. */ export const CRM_FACTS_DEALS_MAX = 5;
|
|
75
|
+
/** Tags reported for a record. */ export const CRM_FACTS_TAGS_MAX = 10;
|
|
76
|
+
/** How much of a logged activity's text, or a platform capture's summary, is reported. */ export const CRM_FACTS_TEXT_MAX = 280;
|
|
77
|
+
/** How much of a record's notes is reported. */ export const CRM_FACTS_NOTES_MAX = 600;
|
|
78
|
+
/** How long a name, a title or a subject may run. */ export const CRM_FACTS_LABEL_MAX = 120;
|
|
79
|
+
/** Custom fields an import catalog reports. */ export const CRM_FACTS_CUSTOM_FIELDS_MAX = 40;
|
|
80
|
+
const DAY_MS = 86400000;
|
|
81
|
+
/** A value as trimmed, single-spaced text of at most `max` characters. */ export function crmFactText(value, max) {
|
|
82
|
+
if (typeof value !== 'string') return '';
|
|
83
|
+
const text = value.replace(/\s+/g, ' ').trim();
|
|
84
|
+
return text.length > max ? `${text.slice(0, max - 1).trimEnd()}…` : text;
|
|
85
|
+
}
|
|
86
|
+
/** Epoch millis, a `Date` or a stored timestamp, as epoch millis; `null` for anything else. */ export function crmFactMillis(value) {
|
|
87
|
+
if (typeof value === 'number') return Number.isFinite(value) && value > 0 ? value : null;
|
|
88
|
+
if (value instanceof Date) return Number.isFinite(value.getTime()) ? value.getTime() : null;
|
|
89
|
+
const toMillis = value == null ? void 0 : value.toMillis;
|
|
90
|
+
if (typeof toMillis === 'function') {
|
|
91
|
+
const millis = toMillis.call(value);
|
|
92
|
+
return Number.isFinite(millis) ? millis : null;
|
|
93
|
+
}
|
|
94
|
+
return null;
|
|
95
|
+
}
|
|
96
|
+
/** A UTC calendar day, `YYYY-MM-DD`, or `null`. */ export function crmFactDay(value) {
|
|
97
|
+
const millis = crmFactMillis(value);
|
|
98
|
+
return millis === null ? null : new Date(millis).toISOString().slice(0, 10);
|
|
99
|
+
}
|
|
100
|
+
/** An amount as a currency code and a fixed-point figure: `USD 1250.00`. */ export function crmFactMoney(cents, currency) {
|
|
101
|
+
if (typeof cents !== 'number' || !Number.isFinite(cents)) return null;
|
|
102
|
+
const code = (typeof currency === 'string' && /^[a-z]{3}$/i.test(currency) ? currency : 'usd').toUpperCase();
|
|
103
|
+
return `${code} ${(cents / 100).toFixed(2)}`;
|
|
104
|
+
}
|
|
105
|
+
/** An email address written inside free text. */ const EMAIL_IN_PROSE = /[\w.+-]+@[\w-]+(?:\.[\w-]+)+/g;
|
|
106
|
+
/** A run of digits and the separators a phone number is written with. */ const DIGIT_RUN_IN_PROSE = /\+?\(?\d[\d\s().-]{7,}\d/g;
|
|
107
|
+
/** Calendar days, which a run of digits may be and a phone number is not. */ const DAYS_ONLY = /^\d{4}-\d{2}-\d{2}(?:\s+\d{4}-\d{2}-\d{2})*$/;
|
|
108
|
+
export const CRM_FACTS_EMAIL_PLACEHOLDER = '[email address]';
|
|
109
|
+
export const CRM_FACTS_PHONE_PLACEHOLDER = '[phone number]';
|
|
110
|
+
/**
|
|
111
|
+
* Free text the team wrote, as {@link crmFactText} reports it, with every
|
|
112
|
+
* email address, and every run of ten digits or more that is not a list of
|
|
113
|
+
* days, replaced by a placeholder. The fields that hold an address or a number
|
|
114
|
+
* are never reported, and this keeps one typed into a note from leaving
|
|
115
|
+
* either. Replaced before the cut, so a cut never halves an address into
|
|
116
|
+
* something unrecognized.
|
|
117
|
+
*/ export function crmFactProse(value, max) {
|
|
118
|
+
if (typeof value !== 'string') return '';
|
|
119
|
+
const scrubbed = value.replace(EMAIL_IN_PROSE, CRM_FACTS_EMAIL_PLACEHOLDER).replace(DIGIT_RUN_IN_PROSE, (run)=>DAYS_ONLY.test(run.trim()) || run.replace(/\D/g, '').length < 10 ? run : CRM_FACTS_PHONE_PLACEHOLDER);
|
|
120
|
+
return crmFactText(scrubbed, max);
|
|
121
|
+
}
|
|
122
|
+
function tagsOf(value) {
|
|
123
|
+
return Array.isArray(value) ? value.map((tag)=>crmFactProse(tag, 40)).filter(Boolean).slice(0, CRM_FACTS_TAGS_MAX) : [];
|
|
124
|
+
}
|
|
125
|
+
/** A logged activity as a timeline entry. */ export function crmActivityFact(activity) {
|
|
126
|
+
var _activity_subject;
|
|
127
|
+
const on = crmFactDay(activity.atMs);
|
|
128
|
+
if (!on) return null;
|
|
129
|
+
const kind = activity.kind && CRM_ACTIVITY_KIND_LABELS[activity.kind] ? activity.kind : 'other';
|
|
130
|
+
const fact = {
|
|
131
|
+
on,
|
|
132
|
+
kind: CRM_ACTIVITY_KIND_LABELS[kind]
|
|
133
|
+
};
|
|
134
|
+
if (kind === 'email' && (activity.direction === 'outbound' || activity.direction === 'inbound')) {
|
|
135
|
+
fact.direction = activity.direction;
|
|
136
|
+
}
|
|
137
|
+
const subject = crmFactProse((_activity_subject = activity.subject) != null ? _activity_subject : activity.threadSubject, CRM_FACTS_LABEL_MAX);
|
|
138
|
+
if (subject) fact.subject = subject;
|
|
139
|
+
const text = crmFactProse(activity.body, CRM_FACTS_TEXT_MAX);
|
|
140
|
+
if (text) fact.text = text;
|
|
141
|
+
const outcome = crmFactProse(activity.outcome, CRM_FACTS_LABEL_MAX);
|
|
142
|
+
if (outcome) fact.outcome = outcome;
|
|
143
|
+
if (kind === 'email' && isCrmEmailDeliveryState(activity.deliveryState)) {
|
|
144
|
+
fact.delivery = CRM_EMAIL_DELIVERY_STATE_LABELS[activity.deliveryState];
|
|
145
|
+
}
|
|
146
|
+
return fact;
|
|
147
|
+
}
|
|
148
|
+
/** A capture the platform recorded on a contact, as a timeline entry. */ export function crmInteractionFact(interaction) {
|
|
149
|
+
const on = crmFactDay(interaction.atMs);
|
|
150
|
+
if (!on) return null;
|
|
151
|
+
const kind = interaction.type && CONTACT_SOURCE_LABELS[interaction.type] ? CONTACT_SOURCE_LABELS[interaction.type] : 'Capture';
|
|
152
|
+
const text = crmFactProse(interaction.summary, CRM_FACTS_TEXT_MAX);
|
|
153
|
+
return text ? {
|
|
154
|
+
on,
|
|
155
|
+
kind,
|
|
156
|
+
text
|
|
157
|
+
} : {
|
|
158
|
+
on,
|
|
159
|
+
kind
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Timeline entries newest first, at most {@link CRM_FACTS_TIMELINE_MAX}. A
|
|
164
|
+
* tie keeps the order the entries arrived in, so the same reads report the
|
|
165
|
+
* same list.
|
|
166
|
+
*/ export function crmTimelineFacts(entries) {
|
|
167
|
+
return entries.map((entry, index)=>{
|
|
168
|
+
var _crmFactMillis;
|
|
169
|
+
return {
|
|
170
|
+
at: (_crmFactMillis = crmFactMillis(entry.atMs)) != null ? _crmFactMillis : 0,
|
|
171
|
+
index,
|
|
172
|
+
fact: entry.fact
|
|
173
|
+
};
|
|
174
|
+
}).filter((entry)=>entry.fact !== null).sort((a, b)=>b.at - a.at || a.index - b.index).slice(0, CRM_FACTS_TIMELINE_MAX).map((entry)=>entry.fact);
|
|
175
|
+
}
|
|
176
|
+
/** The open tasks among `tasks`, soonest due first, undated last. */ export function crmOpenTaskFacts(tasks, nowMs) {
|
|
177
|
+
return tasks.filter((task)=>task.status !== 'done' && crmFactText(task.title, CRM_FACTS_LABEL_MAX)).map((task, index)=>({
|
|
178
|
+
task,
|
|
179
|
+
index,
|
|
180
|
+
due: crmFactMillis(task.dueAtMs)
|
|
181
|
+
})).sort((a, b)=>{
|
|
182
|
+
var _a_due, _b_due;
|
|
183
|
+
return ((_a_due = a.due) != null ? _a_due : Number.POSITIVE_INFINITY) - ((_b_due = b.due) != null ? _b_due : Number.POSITIVE_INFINITY) || a.index - b.index;
|
|
184
|
+
}).slice(0, CRM_FACTS_TASKS_MAX).map(({ task, due })=>({
|
|
185
|
+
title: crmFactProse(task.title, CRM_FACTS_LABEL_MAX),
|
|
186
|
+
kind: task.kind && CRM_TASK_KIND_LABELS[task.kind] ? CRM_TASK_KIND_LABELS[task.kind] : 'To-do',
|
|
187
|
+
priority: task.priority === 'high' || task.priority === 'low' ? task.priority : 'normal',
|
|
188
|
+
due: due === null ? null : crmFactDay(due),
|
|
189
|
+
// Overdue by the UTC day: a task due today is not overdue until tomorrow.
|
|
190
|
+
overdue: due !== null && Math.floor(due / DAY_MS) < Math.floor(nowMs / DAY_MS)
|
|
191
|
+
}));
|
|
192
|
+
}
|
|
193
|
+
/** One deal, with its stage named by the pipeline it is in. */ export function crmDealFact(deal, pipeline) {
|
|
194
|
+
var _deal_stageId;
|
|
195
|
+
const stage = dealStageById(pipeline != null ? pipeline : undefined, String((_deal_stageId = deal.stageId) != null ? _deal_stageId : ''));
|
|
196
|
+
return {
|
|
197
|
+
title: crmFactProse(deal.title, CRM_FACTS_LABEL_MAX),
|
|
198
|
+
stage: crmFactText(stage == null ? void 0 : stage.name, CRM_FACTS_LABEL_MAX),
|
|
199
|
+
status: deal.status === 'won' || deal.status === 'lost' ? deal.status : 'open',
|
|
200
|
+
amount: crmFactMoney(deal.amountCents, deal.currency),
|
|
201
|
+
expectedClose: crmFactDay(deal.expectedCloseAtMs)
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
/** Deals, open ones first, then most recently updated. */ export function crmDealFacts(deals, pipelines) {
|
|
205
|
+
return deals.map((deal, index)=>{
|
|
206
|
+
var _crmFactMillis;
|
|
207
|
+
return {
|
|
208
|
+
deal,
|
|
209
|
+
index,
|
|
210
|
+
updated: (_crmFactMillis = crmFactMillis(deal.updatedAt)) != null ? _crmFactMillis : 0
|
|
211
|
+
};
|
|
212
|
+
}).sort((a, b)=>Number(a.deal.status !== 'open') - Number(b.deal.status !== 'open') || b.updated - a.updated || a.index - b.index).slice(0, CRM_FACTS_DEALS_MAX).map(({ deal })=>{
|
|
213
|
+
var _deal_pipelineId;
|
|
214
|
+
return crmDealFact(deal, pipelines.get(String((_deal_pipelineId = deal.pipelineId) != null ? _deal_pipelineId : '')));
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
export function contactFacts(input) {
|
|
218
|
+
var _facet_sources;
|
|
219
|
+
const { row, group } = input;
|
|
220
|
+
const facet = readContactFacet(row, group.groupId);
|
|
221
|
+
const sources = Object.entries((_facet_sources = facet.sources) != null ? _facet_sources : {}).filter(([, on])=>on === true).map(([source])=>{
|
|
222
|
+
var _CONTACT_SOURCE_LABELS_source;
|
|
223
|
+
return (_CONTACT_SOURCE_LABELS_source = CONTACT_SOURCE_LABELS[source]) != null ? _CONTACT_SOURCE_LABELS_source : '';
|
|
224
|
+
}).filter(Boolean);
|
|
225
|
+
const interactions = interactionsForGroup(facet.interactions, group.hostIds);
|
|
226
|
+
return {
|
|
227
|
+
record: 'contact',
|
|
228
|
+
name: crmFactProse(contactDisplayName(row, group.groupId), CRM_FACTS_LABEL_MAX),
|
|
229
|
+
jobTitle: crmFactProse(facet.jobTitle, CRM_FACTS_LABEL_MAX),
|
|
230
|
+
company: crmFactProse(facet.companyName, CRM_FACTS_LABEL_MAX),
|
|
231
|
+
lifecycleStage: isContactLifecycleStage(facet.lifecycleStage) ? CONTACT_LIFECYCLE_STAGE_LABELS[facet.lifecycleStage] : '',
|
|
232
|
+
tags: tagsOf(facet.tags),
|
|
233
|
+
sources: [
|
|
234
|
+
...new Set(sources)
|
|
235
|
+
].sort(),
|
|
236
|
+
orders: typeof facet.ordersCount === 'number' && facet.ordersCount > 0 ? Math.floor(facet.ordersCount) : 0,
|
|
237
|
+
lastPurchase: crmFactDay(facet.lastPurchaseAtMs),
|
|
238
|
+
since: crmFactDay(row['createdAt']),
|
|
239
|
+
lastEmailEngagement: crmFactDay(facet.lastEmailEngagementAtMs),
|
|
240
|
+
notes: crmFactProse(facet.notes, CRM_FACTS_NOTES_MAX),
|
|
241
|
+
timeline: crmTimelineFacts([
|
|
242
|
+
...input.activities.map((activity)=>({
|
|
243
|
+
atMs: activity.atMs,
|
|
244
|
+
fact: crmActivityFact(activity)
|
|
245
|
+
})),
|
|
246
|
+
...interactions.map((interaction)=>({
|
|
247
|
+
atMs: interaction.atMs,
|
|
248
|
+
fact: crmInteractionFact(interaction)
|
|
249
|
+
}))
|
|
250
|
+
]),
|
|
251
|
+
openTasks: crmOpenTaskFacts(input.tasks, input.nowMs),
|
|
252
|
+
deals: crmDealFacts(input.deals, input.pipelines)
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
export function companyFacts(input) {
|
|
256
|
+
const { company } = input;
|
|
257
|
+
return {
|
|
258
|
+
record: 'company',
|
|
259
|
+
name: crmFactProse(company.name, CRM_FACTS_LABEL_MAX),
|
|
260
|
+
domain: crmFactText(company.domain, CRM_FACTS_LABEL_MAX),
|
|
261
|
+
industry: crmFactProse(company.industry, CRM_FACTS_LABEL_MAX),
|
|
262
|
+
tags: tagsOf(company.tags),
|
|
263
|
+
people: typeof company.contactsCount === 'number' && company.contactsCount > 0 ? Math.floor(company.contactsCount) : 0,
|
|
264
|
+
since: crmFactDay(company.createdAt),
|
|
265
|
+
notes: crmFactProse(company.notes, CRM_FACTS_NOTES_MAX),
|
|
266
|
+
timeline: crmTimelineFacts(input.activities.map((activity)=>({
|
|
267
|
+
atMs: activity.atMs,
|
|
268
|
+
fact: crmActivityFact(activity)
|
|
269
|
+
}))),
|
|
270
|
+
openTasks: crmOpenTaskFacts(input.tasks, input.nowMs),
|
|
271
|
+
deals: crmDealFacts(input.deals, input.pipelines)
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
export function dealFacts(input) {
|
|
275
|
+
var _ref, _deal_stageId;
|
|
276
|
+
const { deal, pipeline } = input;
|
|
277
|
+
const summary = crmDealFact(deal, pipeline);
|
|
278
|
+
const stages = [
|
|
279
|
+
...(_ref = pipeline == null ? void 0 : pipeline.stages) != null ? _ref : []
|
|
280
|
+
].sort((a, b)=>{
|
|
281
|
+
var _a_order, _b_order;
|
|
282
|
+
return Number((_a_order = a.order) != null ? _a_order : 0) - Number((_b_order = b.order) != null ? _b_order : 0);
|
|
283
|
+
}).map((stage)=>({
|
|
284
|
+
id: String(stage.id),
|
|
285
|
+
name: crmFactText(stage.name, CRM_FACTS_LABEL_MAX),
|
|
286
|
+
kind: stage.kind === 'won' || stage.kind === 'lost' ? stage.kind : 'open'
|
|
287
|
+
}));
|
|
288
|
+
return {
|
|
289
|
+
record: 'deal',
|
|
290
|
+
title: summary.title,
|
|
291
|
+
pipeline: crmFactText(pipeline == null ? void 0 : pipeline.name, CRM_FACTS_LABEL_MAX),
|
|
292
|
+
stages,
|
|
293
|
+
stageId: String((_deal_stageId = deal.stageId) != null ? _deal_stageId : ''),
|
|
294
|
+
stage: summary.stage,
|
|
295
|
+
status: summary.status,
|
|
296
|
+
amount: summary.amount,
|
|
297
|
+
expectedClose: summary.expectedClose,
|
|
298
|
+
inStageSince: crmFactDay(deal.stageChangedAtMs),
|
|
299
|
+
lostReason: crmFactProse(deal.lostReason, CRM_FACTS_LABEL_MAX),
|
|
300
|
+
contact: crmFactProse(deal.contactName, CRM_FACTS_LABEL_MAX),
|
|
301
|
+
company: crmFactProse(deal.companyName, CRM_FACTS_LABEL_MAX),
|
|
302
|
+
products: Array.isArray(deal.lineItems) ? deal.lineItems.length : 0,
|
|
303
|
+
since: crmFactDay(deal.createdAt),
|
|
304
|
+
notes: crmFactProse(deal.notes, CRM_FACTS_NOTES_MAX),
|
|
305
|
+
timeline: crmTimelineFacts(input.activities.map((activity)=>({
|
|
306
|
+
atMs: activity.atMs,
|
|
307
|
+
fact: crmActivityFact(activity)
|
|
308
|
+
}))),
|
|
309
|
+
openTasks: crmOpenTaskFacts(input.tasks, input.nowMs)
|
|
310
|
+
};
|
|
311
|
+
}
|
|
312
|
+
/** What a lead's capture surfaces are called, the lead history card's words. */ function leadSourceFact(source) {
|
|
313
|
+
if (source === 'signup') return 'Sign-up';
|
|
314
|
+
if (source === 'booking') return 'Booking';
|
|
315
|
+
if (source === 'import') return CONTACT_SOURCE_LABELS.import;
|
|
316
|
+
if (source === 'form' || source.startsWith('form:')) return CONTACT_SOURCE_LABELS.form;
|
|
317
|
+
return 'Other';
|
|
318
|
+
}
|
|
319
|
+
export function leadFacts(input) {
|
|
320
|
+
const { lead } = input;
|
|
321
|
+
const rawSources = Array.isArray(lead['sources']) ? lead['sources'] : typeof lead['source'] === 'string' ? [
|
|
322
|
+
lead['source']
|
|
323
|
+
] : [];
|
|
324
|
+
const captures = Number(lead['submissionCount']);
|
|
325
|
+
return {
|
|
326
|
+
record: 'lead',
|
|
327
|
+
name: crmFactProse(lead['name'], CRM_FACTS_LABEL_MAX),
|
|
328
|
+
status: CRM_LEAD_STATUS_LABELS[crmLeadStatus(lead)],
|
|
329
|
+
sources: [
|
|
330
|
+
...new Set(rawSources.map((source)=>leadSourceFact(String(source))))
|
|
331
|
+
].sort(),
|
|
332
|
+
captures: Number.isFinite(captures) && captures > 0 ? Math.floor(captures) : 0,
|
|
333
|
+
firstSeen: crmFactDay(lead['firstSeenAtMs']),
|
|
334
|
+
lastSeen: crmFactDay(lead['lastSeenAtMs']),
|
|
335
|
+
assigned: typeof lead['ownerUid'] === 'string' && lead['ownerUid'] !== '',
|
|
336
|
+
converted: typeof lead['convertedContactId'] === 'string' && lead['convertedContactId'] !== '',
|
|
337
|
+
unqualifiedReason: crmFactProse(lead['unqualifiedReason'], CRM_FACTS_LABEL_MAX),
|
|
338
|
+
notes: crmFactProse(lead['notes'], CRM_FACTS_NOTES_MAX),
|
|
339
|
+
timeline: crmTimelineFacts(input.activities.map((activity)=>({
|
|
340
|
+
atMs: activity.atMs,
|
|
341
|
+
fact: crmActivityFact(activity)
|
|
342
|
+
})))
|
|
343
|
+
};
|
|
344
|
+
}
|
|
345
|
+
/** The standard fields of each import, with the type a column must hold for each. */ const STANDARD_IMPORT_FIELDS = {
|
|
346
|
+
contacts: {
|
|
347
|
+
keys: CONTACT_IMPORT_FIELDS,
|
|
348
|
+
labels: CONTACT_IMPORT_FIELD_LABELS,
|
|
349
|
+
required: 'email',
|
|
350
|
+
types: {
|
|
351
|
+
email: 'email',
|
|
352
|
+
phone: 'phone',
|
|
353
|
+
ownerEmail: 'email',
|
|
354
|
+
marketingConsent: 'yes-no'
|
|
355
|
+
}
|
|
356
|
+
},
|
|
357
|
+
companies: {
|
|
358
|
+
keys: COMPANY_IMPORT_FIELDS,
|
|
359
|
+
labels: COMPANY_IMPORT_FIELD_LABELS,
|
|
360
|
+
required: 'name',
|
|
361
|
+
types: {
|
|
362
|
+
phone: 'phone',
|
|
363
|
+
ownerEmail: 'email',
|
|
364
|
+
website: 'url'
|
|
365
|
+
}
|
|
366
|
+
},
|
|
367
|
+
deals: {
|
|
368
|
+
keys: DEAL_IMPORT_FIELDS,
|
|
369
|
+
labels: DEAL_IMPORT_FIELD_LABELS,
|
|
370
|
+
required: 'title',
|
|
371
|
+
types: {
|
|
372
|
+
amount: 'number',
|
|
373
|
+
ownerEmail: 'email',
|
|
374
|
+
expectedClose: 'date'
|
|
375
|
+
}
|
|
376
|
+
},
|
|
377
|
+
leads: {
|
|
378
|
+
keys: LEAD_IMPORT_FIELDS,
|
|
379
|
+
labels: LEAD_IMPORT_FIELD_LABELS,
|
|
380
|
+
required: 'email',
|
|
381
|
+
types: {
|
|
382
|
+
email: 'email',
|
|
383
|
+
ownerEmail: 'email'
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
};
|
|
387
|
+
/** The object a collection's custom fields describe; leads and deals import none. */ const CUSTOM_FIELD_OBJECT = {
|
|
388
|
+
contacts: 'contact',
|
|
389
|
+
companies: 'company'
|
|
390
|
+
};
|
|
391
|
+
const CUSTOM_FIELD_TYPES = {
|
|
392
|
+
number: 'number',
|
|
393
|
+
date: 'date',
|
|
394
|
+
checkbox: 'yes-no',
|
|
395
|
+
url: 'url'
|
|
396
|
+
};
|
|
397
|
+
/**
|
|
398
|
+
* The fields an import of `collection` may fill: the standard ones in the
|
|
399
|
+
* mapping menu's order, then the org's active custom fields for the record
|
|
400
|
+
* the collection holds, in their own order.
|
|
401
|
+
*/ export function importFacts(collection, customFields) {
|
|
402
|
+
const standard = STANDARD_IMPORT_FIELDS[collection];
|
|
403
|
+
const object = CUSTOM_FIELD_OBJECT[collection];
|
|
404
|
+
const custom = object ? customFields.filter((field)=>field.key && !field.retiredAt && fieldDefinitionObject(field) === object).sort((a, b)=>{
|
|
405
|
+
var _a_order, _b_order;
|
|
406
|
+
return Number((_a_order = a.order) != null ? _a_order : 0) - Number((_b_order = b.order) != null ? _b_order : 0) || String(a.key).localeCompare(String(b.key));
|
|
407
|
+
}).slice(0, CRM_FACTS_CUSTOM_FIELDS_MAX).map((field)=>{
|
|
408
|
+
var _CUSTOM_FIELD_TYPES_String;
|
|
409
|
+
return {
|
|
410
|
+
key: customImportTarget(String(field.key)),
|
|
411
|
+
label: crmFactText(field.label, CRM_FACTS_LABEL_MAX) || String(field.key),
|
|
412
|
+
type: (_CUSTOM_FIELD_TYPES_String = CUSTOM_FIELD_TYPES[String(field.type)]) != null ? _CUSTOM_FIELD_TYPES_String : 'text',
|
|
413
|
+
required: false
|
|
414
|
+
};
|
|
415
|
+
}) : [];
|
|
416
|
+
return {
|
|
417
|
+
record: 'import',
|
|
418
|
+
collection,
|
|
419
|
+
fields: [
|
|
420
|
+
...standard.keys.map((key)=>{
|
|
421
|
+
var _standard_labels_key, _standard_types_key;
|
|
422
|
+
return {
|
|
423
|
+
key,
|
|
424
|
+
label: (_standard_labels_key = standard.labels[key]) != null ? _standard_labels_key : key,
|
|
425
|
+
type: (_standard_types_key = standard.types[key]) != null ? _standard_types_key : 'text',
|
|
426
|
+
required: key === standard.required
|
|
427
|
+
};
|
|
428
|
+
}),
|
|
429
|
+
...custom
|
|
430
|
+
]
|
|
431
|
+
};
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
//# sourceMappingURL=record-facts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/crm/src/lib/model/record-facts.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 {\n CONTACT_LIFECYCLE_STAGE_LABELS,\n CONTACT_SOURCE_LABELS,\n CRM_ACTIVITY_KIND_LABELS,\n CRM_EMAIL_DELIVERY_STATE_LABELS,\n CRM_LEAD_STATUS_LABELS,\n CRM_TASK_KIND_LABELS,\n contactDisplayName,\n crmLeadStatus,\n customImportTarget,\n dealStageById,\n fieldDefinitionObject,\n interactionsForGroup,\n isContactLifecycleStage,\n isCrmEmailDeliveryState,\n readContactFacet,\n type ConsentGroup,\n type ContactFieldDefinition,\n type ContactInteraction,\n type CrmActivity,\n type CrmCompany,\n type CrmDeal,\n type CrmFieldObject,\n type CrmPipeline,\n type CrmTask,\n} from '@aglyn/aglyn/server'\nimport {\n COMPANY_IMPORT_FIELD_LABELS,\n COMPANY_IMPORT_FIELDS,\n} from './crm-company-import'\nimport {\n CONTACT_IMPORT_FIELD_LABELS,\n CONTACT_IMPORT_FIELDS,\n} from './crm-import'\nimport { DEAL_IMPORT_FIELD_LABELS, DEAL_IMPORT_FIELDS } from './crm-deal-import'\nimport { LEAD_IMPORT_FIELD_LABELS, LEAD_IMPORT_FIELDS } from './crm-lead-import'\n\n/**\n * WHAT THE CRM TELLS ANOTHER PLUGIN ABOUT ONE OF ITS RECORDS (AGL-2917).\n *\n * The facts a reader on the core's record-facts seam reports: one contact,\n * company, deal or lead as a person on the team sees it, and the fields a\n * spreadsheet import may fill. The server half reads the documents and\n * applies who may see them (`server/record-facts.ts`); this half decides\n * which of their fields leave the CRM at all, so the list below is the whole\n * of what a caller — an assistant summarizing a record, an automation\n * deciding on one — can pass on.\n *\n * ## What never leaves\n *\n * No email address, phone number or postal address of anyone; no marketing\n * consent; no custom field VALUE; no team member's name or id; no document\n * id of any record; no file; no order or payment detail beyond a count. A\n * logged email carries its subject and a cut of its body, never the address\n * it went to or came from. An import catalog carries field keys, labels and\n * types, never a row of the file.\n *\n * Every text a person wrote into a record — a name, a job title, a tag, notes,\n * a logged activity, a capture's summary, a task's or a deal's title, a\n * reason — is reported as written, except that an email address or a phone\n * number inside it is replaced by a placeholder first ({@link crmFactProse}):\n * an import that put an address in the name column leaves no address behind.\n * What the workspace configured — pipeline, stage and field names — and a\n * company's domain are reported as they are. A postal address typed into a\n * note is not recognized and leaves as typed.\n *\n * ## Stable bytes\n *\n * Every builder writes its keys in one order, dates as UTC calendar days and\n * money as a currency code and a fixed-point amount, so the same records read\n * twice report the same facts — a caller may key a cache on them, and one\n * that does sees a change exactly when something it was told has changed.\n */\n\n/** The records a reader is registered for, by the seam's resource name. */\nexport const CRM_RECORD_FACTS_RESOURCES = {\n contact: 'crm.contact',\n company: 'crm.company',\n deal: 'crm.deal',\n lead: 'crm.lead',\n} as const\n\nexport type CrmRecordFactsKind = keyof typeof CRM_RECORD_FACTS_RESOURCES\n\n/** The import catalogs, read by collection name as the record id. */\nexport const CRM_IMPORT_FACTS_RESOURCE = 'crm.import'\n\nexport const CRM_IMPORT_FACTS_COLLECTIONS = ['contacts', 'companies', 'deals', 'leads'] as const\n\nexport type CrmImportFactsCollection = (typeof CRM_IMPORT_FACTS_COLLECTIONS)[number]\n\nexport function isCrmImportFactsCollection(value: unknown): value is CrmImportFactsCollection {\n return typeof value === 'string' && (CRM_IMPORT_FACTS_COLLECTIONS as readonly string[]).includes(value)\n}\n\n/** Newest timeline entries reported for a record. */\nexport const CRM_FACTS_TIMELINE_MAX = 12\n/** Open tasks reported for a record. */\nexport const CRM_FACTS_TASKS_MAX = 8\n/** Deals reported for a contact or a company. */\nexport const CRM_FACTS_DEALS_MAX = 5\n/** Tags reported for a record. */\nexport const CRM_FACTS_TAGS_MAX = 10\n/** How much of a logged activity's text, or a platform capture's summary, is reported. */\nexport const CRM_FACTS_TEXT_MAX = 280\n/** How much of a record's notes is reported. */\nexport const CRM_FACTS_NOTES_MAX = 600\n/** How long a name, a title or a subject may run. */\nexport const CRM_FACTS_LABEL_MAX = 120\n/** Custom fields an import catalog reports. */\nexport const CRM_FACTS_CUSTOM_FIELDS_MAX = 40\n\n/** One thing that happened, as a record's timeline reports it. */\nexport interface CrmTimelineFact {\n /** The UTC day it happened, `YYYY-MM-DD`. */\n on: string\n /** What happened: a logged kind (Call, Email) or the capture it came through (Form, Booking). */\n kind: string\n /** `outbound` or `inbound` for an email; absent otherwise. */\n direction?: string\n subject?: string\n text?: string\n outcome?: string\n /** How far a sent email got: Sent, Delivered, Opened, Clicked, Bounced, Complained. */\n delivery?: string\n}\n\n/** One task still to do. */\nexport interface CrmTaskFact {\n title: string\n kind: string\n priority: string\n /** The UTC day it is due, or `null` for a task with no due date. */\n due: string | null\n overdue: boolean\n}\n\n/** One deal, as a contact's or a company's facts report it. */\nexport interface CrmDealFact {\n title: string\n stage: string\n status: string\n amount: string | null\n expectedClose: string | null\n}\n\nexport interface CrmContactFacts {\n record: 'contact'\n name: string\n jobTitle: string\n company: string\n lifecycleStage: string\n tags: string[]\n /** The captures that met the person: Form, Booking, Customer. */\n sources: string[]\n orders: number\n lastPurchase: string | null\n since: string | null\n lastEmailEngagement: string | null\n notes: string\n timeline: CrmTimelineFact[]\n openTasks: CrmTaskFact[]\n deals: CrmDealFact[]\n}\n\nexport interface CrmCompanyFacts {\n record: 'company'\n name: string\n domain: string\n industry: string\n tags: string[]\n people: number\n since: string | null\n notes: string\n timeline: CrmTimelineFact[]\n openTasks: CrmTaskFact[]\n deals: CrmDealFact[]\n}\n\n/** One stage of a deal's pipeline, in order. */\nexport interface CrmStageFact {\n id: string\n name: string\n kind: 'open' | 'won' | 'lost'\n}\n\nexport interface CrmDealFacts {\n record: 'deal'\n title: string\n pipeline: string\n stages: CrmStageFact[]\n stageId: string\n stage: string\n status: string\n amount: string | null\n expectedClose: string | null\n inStageSince: string | null\n lostReason: string\n /** The name of the person the deal is with, as the deal copied it. */\n contact: string\n company: string\n products: number\n since: string | null\n notes: string\n timeline: CrmTimelineFact[]\n openTasks: CrmTaskFact[]\n}\n\nexport interface CrmLeadFacts {\n record: 'lead'\n name: string\n status: string\n /** Where the lead was captured: Form, Booking, Sign-up, Import. */\n sources: string[]\n captures: number\n firstSeen: string | null\n lastSeen: string | null\n assigned: boolean\n converted: boolean\n unqualifiedReason: string\n notes: string\n timeline: CrmTimelineFact[]\n}\n\nexport type CrmRecordFacts = CrmContactFacts | CrmCompanyFacts | CrmDealFacts | CrmLeadFacts\n\n/** What a column of a file may hold, as an import field expects it. */\nexport type CrmImportFieldType = 'email' | 'phone' | 'number' | 'date' | 'yes-no' | 'url' | 'text'\n\n/** One field an import may fill. */\nexport interface CrmImportFieldFact {\n /** The mapping target: a standard field's key, or `custom:<key>`. */\n key: string\n label: string\n type: CrmImportFieldType\n required: boolean\n}\n\nexport interface CrmImportFacts {\n record: 'import'\n collection: CrmImportFactsCollection\n fields: CrmImportFieldFact[]\n}\n\nconst DAY_MS = 86_400_000\n\n/** A value as trimmed, single-spaced text of at most `max` characters. */\nexport function crmFactText(value: unknown, max: number): string {\n if (typeof value !== 'string') return ''\n const text = value.replace(/\\s+/g, ' ').trim()\n return text.length > max ? `${text.slice(0, max - 1).trimEnd()}…` : text\n}\n\n/** Epoch millis, a `Date` or a stored timestamp, as epoch millis; `null` for anything else. */\nexport function crmFactMillis(value: unknown): number | null {\n if (typeof value === 'number') return Number.isFinite(value) && value > 0 ? value : null\n if (value instanceof Date) return Number.isFinite(value.getTime()) ? value.getTime() : null\n const toMillis = (value as { toMillis?: () => number } | null | undefined)?.toMillis\n if (typeof toMillis === 'function') {\n const millis = toMillis.call(value)\n return Number.isFinite(millis) ? millis : null\n }\n return null\n}\n\n/** A UTC calendar day, `YYYY-MM-DD`, or `null`. */\nexport function crmFactDay(value: unknown): string | null {\n const millis = crmFactMillis(value)\n return millis === null ? null : new Date(millis).toISOString().slice(0, 10)\n}\n\n/** An amount as a currency code and a fixed-point figure: `USD 1250.00`. */\nexport function crmFactMoney(cents: unknown, currency: unknown): string | null {\n if (typeof cents !== 'number' || !Number.isFinite(cents)) return null\n const code = (typeof currency === 'string' && /^[a-z]{3}$/i.test(currency) ? currency : 'usd').toUpperCase()\n return `${code} ${(cents / 100).toFixed(2)}`\n}\n\n/** An email address written inside free text. */\nconst EMAIL_IN_PROSE = /[\\w.+-]+@[\\w-]+(?:\\.[\\w-]+)+/g\n/** A run of digits and the separators a phone number is written with. */\nconst DIGIT_RUN_IN_PROSE = /\\+?\\(?\\d[\\d\\s().-]{7,}\\d/g\n/** Calendar days, which a run of digits may be and a phone number is not. */\nconst DAYS_ONLY = /^\\d{4}-\\d{2}-\\d{2}(?:\\s+\\d{4}-\\d{2}-\\d{2})*$/\n\nexport const CRM_FACTS_EMAIL_PLACEHOLDER = '[email address]'\nexport const CRM_FACTS_PHONE_PLACEHOLDER = '[phone number]'\n\n/**\n * Free text the team wrote, as {@link crmFactText} reports it, with every\n * email address, and every run of ten digits or more that is not a list of\n * days, replaced by a placeholder. The fields that hold an address or a number\n * are never reported, and this keeps one typed into a note from leaving\n * either. Replaced before the cut, so a cut never halves an address into\n * something unrecognized.\n */\nexport function crmFactProse(value: unknown, max: number): string {\n if (typeof value !== 'string') return ''\n const scrubbed = value\n .replace(EMAIL_IN_PROSE, CRM_FACTS_EMAIL_PLACEHOLDER)\n .replace(DIGIT_RUN_IN_PROSE, (run) =>\n DAYS_ONLY.test(run.trim()) || run.replace(/\\D/g, '').length < 10 ? run : CRM_FACTS_PHONE_PLACEHOLDER,\n )\n return crmFactText(scrubbed, max)\n}\n\nfunction tagsOf(value: unknown): string[] {\n return Array.isArray(value)\n ? value\n .map((tag) => crmFactProse(tag, 40))\n .filter(Boolean)\n .slice(0, CRM_FACTS_TAGS_MAX)\n : []\n}\n\n/** A logged activity as a timeline entry. */\nexport function crmActivityFact(activity: Partial<CrmActivity>): CrmTimelineFact | null {\n const on = crmFactDay(activity.atMs)\n if (!on) return null\n const kind = activity.kind && CRM_ACTIVITY_KIND_LABELS[activity.kind] ? activity.kind : 'other'\n const fact: CrmTimelineFact = { on, kind: CRM_ACTIVITY_KIND_LABELS[kind] }\n if (kind === 'email' && (activity.direction === 'outbound' || activity.direction === 'inbound')) {\n fact.direction = activity.direction\n }\n const subject = crmFactProse(activity.subject ?? activity.threadSubject, CRM_FACTS_LABEL_MAX)\n if (subject) fact.subject = subject\n const text = crmFactProse(activity.body, CRM_FACTS_TEXT_MAX)\n if (text) fact.text = text\n const outcome = crmFactProse(activity.outcome, CRM_FACTS_LABEL_MAX)\n if (outcome) fact.outcome = outcome\n if (kind === 'email' && isCrmEmailDeliveryState(activity.deliveryState)) {\n fact.delivery = CRM_EMAIL_DELIVERY_STATE_LABELS[activity.deliveryState]\n }\n return fact\n}\n\n/** A capture the platform recorded on a contact, as a timeline entry. */\nexport function crmInteractionFact(interaction: Partial<ContactInteraction>): CrmTimelineFact | null {\n const on = crmFactDay(interaction.atMs)\n if (!on) return null\n const kind =\n interaction.type && CONTACT_SOURCE_LABELS[interaction.type] ? CONTACT_SOURCE_LABELS[interaction.type] : 'Capture'\n const text = crmFactProse(interaction.summary, CRM_FACTS_TEXT_MAX)\n return text ? { on, kind, text } : { on, kind }\n}\n\n/**\n * Timeline entries newest first, at most {@link CRM_FACTS_TIMELINE_MAX}. A\n * tie keeps the order the entries arrived in, so the same reads report the\n * same list.\n */\nexport function crmTimelineFacts(\n entries: ReadonlyArray<{ atMs: unknown; fact: CrmTimelineFact | null }>,\n): CrmTimelineFact[] {\n return entries\n .map((entry, index) => ({ at: crmFactMillis(entry.atMs) ?? 0, index, fact: entry.fact }))\n .filter((entry): entry is { at: number; index: number; fact: CrmTimelineFact } => entry.fact !== null)\n .sort((a, b) => b.at - a.at || a.index - b.index)\n .slice(0, CRM_FACTS_TIMELINE_MAX)\n .map((entry) => entry.fact)\n}\n\n/** The open tasks among `tasks`, soonest due first, undated last. */\nexport function crmOpenTaskFacts(tasks: ReadonlyArray<Partial<CrmTask>>, nowMs: number): CrmTaskFact[] {\n return tasks\n .filter((task) => task.status !== 'done' && crmFactText(task.title, CRM_FACTS_LABEL_MAX))\n .map((task, index) => ({ task, index, due: crmFactMillis(task.dueAtMs) }))\n .sort((a, b) => (a.due ?? Number.POSITIVE_INFINITY) - (b.due ?? Number.POSITIVE_INFINITY) || a.index - b.index)\n .slice(0, CRM_FACTS_TASKS_MAX)\n .map(({ task, due }) => ({\n title: crmFactProse(task.title, CRM_FACTS_LABEL_MAX),\n kind: task.kind && CRM_TASK_KIND_LABELS[task.kind] ? CRM_TASK_KIND_LABELS[task.kind] : 'To-do',\n priority: task.priority === 'high' || task.priority === 'low' ? task.priority : 'normal',\n due: due === null ? null : crmFactDay(due),\n // Overdue by the UTC day: a task due today is not overdue until tomorrow.\n overdue: due !== null && Math.floor(due / DAY_MS) < Math.floor(nowMs / DAY_MS),\n }))\n}\n\n/** One deal, with its stage named by the pipeline it is in. */\nexport function crmDealFact(deal: Partial<CrmDeal>, pipeline: CrmPipeline | null | undefined): CrmDealFact {\n const stage = dealStageById(pipeline ?? undefined, String(deal.stageId ?? ''))\n return {\n title: crmFactProse(deal.title, CRM_FACTS_LABEL_MAX),\n stage: crmFactText(stage?.name, CRM_FACTS_LABEL_MAX),\n status: deal.status === 'won' || deal.status === 'lost' ? deal.status : 'open',\n amount: crmFactMoney(deal.amountCents, deal.currency),\n expectedClose: crmFactDay(deal.expectedCloseAtMs),\n }\n}\n\n/** Deals, open ones first, then most recently updated. */\nexport function crmDealFacts(\n deals: ReadonlyArray<Partial<CrmDeal>>,\n pipelines: ReadonlyMap<string, CrmPipeline>,\n): CrmDealFact[] {\n return deals\n .map((deal, index) => ({ deal, index, updated: crmFactMillis(deal.updatedAt) ?? 0 }))\n .sort(\n (a, b) =>\n Number(a.deal.status !== 'open') - Number(b.deal.status !== 'open') ||\n b.updated - a.updated ||\n a.index - b.index,\n )\n .slice(0, CRM_FACTS_DEALS_MAX)\n .map(({ deal }) => crmDealFact(deal, pipelines.get(String(deal.pipelineId ?? ''))))\n}\n\nexport interface ContactFactsInput {\n row: Record<string, unknown>\n /** The holder whose facet the person is read through. */\n group: ConsentGroup\n activities: ReadonlyArray<Partial<CrmActivity>>\n tasks: ReadonlyArray<Partial<CrmTask>>\n deals: ReadonlyArray<Partial<CrmDeal>>\n pipelines: ReadonlyMap<string, CrmPipeline>\n nowMs: number\n}\n\nexport function contactFacts(input: ContactFactsInput): CrmContactFacts {\n const { row, group } = input\n const facet = readContactFacet(row, group.groupId)\n const sources = Object.entries(facet.sources ?? {})\n .filter(([, on]) => on === true)\n .map(([source]) => CONTACT_SOURCE_LABELS[source as keyof typeof CONTACT_SOURCE_LABELS] ?? '')\n .filter(Boolean)\n const interactions = interactionsForGroup(facet.interactions, group.hostIds)\n return {\n record: 'contact',\n name: crmFactProse(contactDisplayName(row, group.groupId), CRM_FACTS_LABEL_MAX),\n jobTitle: crmFactProse(facet.jobTitle, CRM_FACTS_LABEL_MAX),\n company: crmFactProse(facet.companyName, CRM_FACTS_LABEL_MAX),\n lifecycleStage: isContactLifecycleStage(facet.lifecycleStage)\n ? CONTACT_LIFECYCLE_STAGE_LABELS[facet.lifecycleStage]\n : '',\n tags: tagsOf(facet.tags),\n sources: [...new Set(sources)].sort(),\n orders: typeof facet.ordersCount === 'number' && facet.ordersCount > 0 ? Math.floor(facet.ordersCount) : 0,\n lastPurchase: crmFactDay(facet.lastPurchaseAtMs),\n since: crmFactDay(row['createdAt']),\n lastEmailEngagement: crmFactDay(facet.lastEmailEngagementAtMs),\n notes: crmFactProse(facet.notes, CRM_FACTS_NOTES_MAX),\n timeline: crmTimelineFacts([\n ...input.activities.map((activity) => ({ atMs: activity.atMs, fact: crmActivityFact(activity) })),\n ...interactions.map((interaction) => ({ atMs: interaction.atMs, fact: crmInteractionFact(interaction) })),\n ]),\n openTasks: crmOpenTaskFacts(input.tasks, input.nowMs),\n deals: crmDealFacts(input.deals, input.pipelines),\n }\n}\n\nexport interface CompanyFactsInput {\n company: Partial<CrmCompany>\n activities: ReadonlyArray<Partial<CrmActivity>>\n tasks: ReadonlyArray<Partial<CrmTask>>\n deals: ReadonlyArray<Partial<CrmDeal>>\n pipelines: ReadonlyMap<string, CrmPipeline>\n nowMs: number\n}\n\nexport function companyFacts(input: CompanyFactsInput): CrmCompanyFacts {\n const { company } = input\n return {\n record: 'company',\n name: crmFactProse(company.name, CRM_FACTS_LABEL_MAX),\n domain: crmFactText(company.domain, CRM_FACTS_LABEL_MAX),\n industry: crmFactProse(company.industry, CRM_FACTS_LABEL_MAX),\n tags: tagsOf(company.tags),\n people:\n typeof company.contactsCount === 'number' && company.contactsCount > 0\n ? Math.floor(company.contactsCount)\n : 0,\n since: crmFactDay(company.createdAt),\n notes: crmFactProse(company.notes, CRM_FACTS_NOTES_MAX),\n timeline: crmTimelineFacts(\n input.activities.map((activity) => ({ atMs: activity.atMs, fact: crmActivityFact(activity) })),\n ),\n openTasks: crmOpenTaskFacts(input.tasks, input.nowMs),\n deals: crmDealFacts(input.deals, input.pipelines),\n }\n}\n\nexport interface DealFactsInput {\n deal: Partial<CrmDeal> & { contactName?: unknown; companyName?: unknown }\n pipeline: CrmPipeline | null\n activities: ReadonlyArray<Partial<CrmActivity>>\n tasks: ReadonlyArray<Partial<CrmTask>>\n nowMs: number\n}\n\nexport function dealFacts(input: DealFactsInput): CrmDealFacts {\n const { deal, pipeline } = input\n const summary = crmDealFact(deal, pipeline)\n const stages = [...(pipeline?.stages ?? [])]\n .sort((a, b) => Number(a.order ?? 0) - Number(b.order ?? 0))\n .map((stage) => ({\n id: String(stage.id),\n name: crmFactText(stage.name, CRM_FACTS_LABEL_MAX),\n kind: stage.kind === 'won' || stage.kind === 'lost' ? stage.kind : ('open' as const),\n }))\n return {\n record: 'deal',\n title: summary.title,\n pipeline: crmFactText(pipeline?.name, CRM_FACTS_LABEL_MAX),\n stages,\n stageId: String(deal.stageId ?? ''),\n stage: summary.stage,\n status: summary.status,\n amount: summary.amount,\n expectedClose: summary.expectedClose,\n inStageSince: crmFactDay(deal.stageChangedAtMs),\n lostReason: crmFactProse(deal.lostReason, CRM_FACTS_LABEL_MAX),\n contact: crmFactProse(deal.contactName, CRM_FACTS_LABEL_MAX),\n company: crmFactProse(deal.companyName, CRM_FACTS_LABEL_MAX),\n products: Array.isArray(deal.lineItems) ? deal.lineItems.length : 0,\n since: crmFactDay(deal.createdAt),\n notes: crmFactProse(deal.notes, CRM_FACTS_NOTES_MAX),\n timeline: crmTimelineFacts(\n input.activities.map((activity) => ({ atMs: activity.atMs, fact: crmActivityFact(activity) })),\n ),\n openTasks: crmOpenTaskFacts(input.tasks, input.nowMs),\n }\n}\n\n/** What a lead's capture surfaces are called, the lead history card's words. */\nfunction leadSourceFact(source: string): string {\n if (source === 'signup') return 'Sign-up'\n if (source === 'booking') return 'Booking'\n if (source === 'import') return CONTACT_SOURCE_LABELS.import\n if (source === 'form' || source.startsWith('form:')) return CONTACT_SOURCE_LABELS.form\n return 'Other'\n}\n\nexport interface LeadFactsInput {\n lead: Record<string, unknown>\n activities: ReadonlyArray<Partial<CrmActivity>>\n}\n\nexport function leadFacts(input: LeadFactsInput): CrmLeadFacts {\n const { lead } = input\n const rawSources = Array.isArray(lead['sources'])\n ? lead['sources']\n : typeof lead['source'] === 'string'\n ? [lead['source']]\n : []\n const captures = Number(lead['submissionCount'])\n return {\n record: 'lead',\n name: crmFactProse(lead['name'], CRM_FACTS_LABEL_MAX),\n status: CRM_LEAD_STATUS_LABELS[crmLeadStatus(lead as { status?: never })],\n sources: [...new Set(rawSources.map((source) => leadSourceFact(String(source))))].sort(),\n captures: Number.isFinite(captures) && captures > 0 ? Math.floor(captures) : 0,\n firstSeen: crmFactDay(lead['firstSeenAtMs']),\n lastSeen: crmFactDay(lead['lastSeenAtMs']),\n assigned: typeof lead['ownerUid'] === 'string' && lead['ownerUid'] !== '',\n converted: typeof lead['convertedContactId'] === 'string' && lead['convertedContactId'] !== '',\n unqualifiedReason: crmFactProse(lead['unqualifiedReason'], CRM_FACTS_LABEL_MAX),\n notes: crmFactProse(lead['notes'], CRM_FACTS_NOTES_MAX),\n timeline: crmTimelineFacts(\n input.activities.map((activity) => ({ atMs: activity.atMs, fact: crmActivityFact(activity) })),\n ),\n }\n}\n\n/** The standard fields of each import, with the type a column must hold for each. */\nconst STANDARD_IMPORT_FIELDS: Record<\n CrmImportFactsCollection,\n { keys: readonly string[]; labels: Record<string, string>; required: string; types: Record<string, CrmImportFieldType> }\n> = {\n contacts: {\n keys: CONTACT_IMPORT_FIELDS,\n labels: CONTACT_IMPORT_FIELD_LABELS,\n required: 'email',\n types: { email: 'email', phone: 'phone', ownerEmail: 'email', marketingConsent: 'yes-no' },\n },\n companies: {\n keys: COMPANY_IMPORT_FIELDS,\n labels: COMPANY_IMPORT_FIELD_LABELS,\n required: 'name',\n types: { phone: 'phone', ownerEmail: 'email', website: 'url' },\n },\n deals: {\n keys: DEAL_IMPORT_FIELDS,\n labels: DEAL_IMPORT_FIELD_LABELS,\n required: 'title',\n types: { amount: 'number', ownerEmail: 'email', expectedClose: 'date' },\n },\n leads: {\n keys: LEAD_IMPORT_FIELDS,\n labels: LEAD_IMPORT_FIELD_LABELS,\n required: 'email',\n types: { email: 'email', ownerEmail: 'email' },\n },\n}\n\n/** The object a collection's custom fields describe; leads and deals import none. */\nconst CUSTOM_FIELD_OBJECT: Partial<Record<CrmImportFactsCollection, CrmFieldObject>> = {\n contacts: 'contact',\n companies: 'company',\n}\n\nconst CUSTOM_FIELD_TYPES: Record<string, CrmImportFieldType> = {\n number: 'number',\n date: 'date',\n checkbox: 'yes-no',\n url: 'url',\n}\n\n/**\n * The fields an import of `collection` may fill: the standard ones in the\n * mapping menu's order, then the org's active custom fields for the record\n * the collection holds, in their own order.\n */\nexport function importFacts(\n collection: CrmImportFactsCollection,\n customFields: ReadonlyArray<Partial<ContactFieldDefinition>>,\n): CrmImportFacts {\n const standard = STANDARD_IMPORT_FIELDS[collection]\n const object = CUSTOM_FIELD_OBJECT[collection]\n const custom = object\n ? customFields\n .filter((field) => field.key && !field.retiredAt && fieldDefinitionObject(field as ContactFieldDefinition) === object)\n .sort((a, b) => Number(a.order ?? 0) - Number(b.order ?? 0) || String(a.key).localeCompare(String(b.key)))\n .slice(0, CRM_FACTS_CUSTOM_FIELDS_MAX)\n .map((field) => ({\n key: customImportTarget(String(field.key)),\n label: crmFactText(field.label, CRM_FACTS_LABEL_MAX) || String(field.key),\n type: CUSTOM_FIELD_TYPES[String(field.type)] ?? ('text' as const),\n required: false,\n }))\n : []\n return {\n record: 'import',\n collection,\n fields: [\n ...standard.keys.map((key) => ({\n key,\n label: standard.labels[key] ?? key,\n type: standard.types[key] ?? ('text' as const),\n required: key === standard.required,\n })),\n ...custom,\n ],\n }\n}\n"],"names":["CONTACT_LIFECYCLE_STAGE_LABELS","CONTACT_SOURCE_LABELS","CRM_ACTIVITY_KIND_LABELS","CRM_EMAIL_DELIVERY_STATE_LABELS","CRM_LEAD_STATUS_LABELS","CRM_TASK_KIND_LABELS","contactDisplayName","crmLeadStatus","customImportTarget","dealStageById","fieldDefinitionObject","interactionsForGroup","isContactLifecycleStage","isCrmEmailDeliveryState","readContactFacet","COMPANY_IMPORT_FIELD_LABELS","COMPANY_IMPORT_FIELDS","CONTACT_IMPORT_FIELD_LABELS","CONTACT_IMPORT_FIELDS","DEAL_IMPORT_FIELD_LABELS","DEAL_IMPORT_FIELDS","LEAD_IMPORT_FIELD_LABELS","LEAD_IMPORT_FIELDS","CRM_RECORD_FACTS_RESOURCES","contact","company","deal","lead","CRM_IMPORT_FACTS_RESOURCE","CRM_IMPORT_FACTS_COLLECTIONS","isCrmImportFactsCollection","value","includes","CRM_FACTS_TIMELINE_MAX","CRM_FACTS_TASKS_MAX","CRM_FACTS_DEALS_MAX","CRM_FACTS_TAGS_MAX","CRM_FACTS_TEXT_MAX","CRM_FACTS_NOTES_MAX","CRM_FACTS_LABEL_MAX","CRM_FACTS_CUSTOM_FIELDS_MAX","DAY_MS","crmFactText","max","text","replace","trim","length","slice","trimEnd","crmFactMillis","Number","isFinite","Date","getTime","toMillis","millis","call","crmFactDay","toISOString","crmFactMoney","cents","currency","code","test","toUpperCase","toFixed","EMAIL_IN_PROSE","DIGIT_RUN_IN_PROSE","DAYS_ONLY","CRM_FACTS_EMAIL_PLACEHOLDER","CRM_FACTS_PHONE_PLACEHOLDER","crmFactProse","scrubbed","run","tagsOf","Array","isArray","map","tag","filter","Boolean","crmActivityFact","activity","on","atMs","kind","fact","direction","subject","threadSubject","body","outcome","deliveryState","delivery","crmInteractionFact","interaction","type","summary","crmTimelineFacts","entries","entry","index","at","sort","a","b","crmOpenTaskFacts","tasks","nowMs","task","status","title","due","dueAtMs","POSITIVE_INFINITY","priority","overdue","Math","floor","crmDealFact","pipeline","stage","undefined","String","stageId","name","amount","amountCents","expectedClose","expectedCloseAtMs","crmDealFacts","deals","pipelines","updated","updatedAt","get","pipelineId","contactFacts","input","facet","row","group","groupId","sources","Object","source","interactions","hostIds","record","jobTitle","companyName","lifecycleStage","tags","Set","orders","ordersCount","lastPurchase","lastPurchaseAtMs","since","lastEmailEngagement","lastEmailEngagementAtMs","notes","timeline","activities","openTasks","companyFacts","domain","industry","people","contactsCount","createdAt","dealFacts","stages","order","id","inStageSince","stageChangedAtMs","lostReason","contactName","products","lineItems","leadSourceFact","import","startsWith","form","leadFacts","rawSources","captures","firstSeen","lastSeen","assigned","converted","unqualifiedReason","STANDARD_IMPORT_FIELDS","contacts","keys","labels","required","types","email","phone","ownerEmail","marketingConsent","companies","website","leads","CUSTOM_FIELD_OBJECT","CUSTOM_FIELD_TYPES","number","date","checkbox","url","importFacts","collection","customFields","standard","object","custom","field","key","retiredAt","localeCompare","label","fields"],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
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
|
+
*/
|
|
17
|
+
import { type MaybeTokenSource } from '@aglyn/shared-util-http/authorized-token';
|
|
18
|
+
import { type CrmTaskCompleteRequest, type CrmTaskCompleteResponse, type CrmTaskSaveRequest, type CrmTaskSaveResponse, type CrmTasksCompleteRequest, type CrmTasksCompleteResponse, type CrmTasksSaveRequest, type CrmTasksSaveResponse } from './task-routes';
|
|
19
|
+
export declare function saveCrmTask(user: MaybeTokenSource, request: CrmTaskSaveRequest): Promise<CrmTaskSaveResponse>;
|
|
20
|
+
export declare function completeCrmTask(user: MaybeTokenSource, request: CrmTaskCompleteRequest): Promise<CrmTaskCompleteResponse>;
|
|
21
|
+
/**
|
|
22
|
+
* The organization hub's batch forms (AGL-2637): one request per bulk
|
|
23
|
+
* action, answered per task. A refused TASK is a row in `results`, not a
|
|
24
|
+
* thrown error — only a refused REQUEST (no session, no reach, a body the
|
|
25
|
+
* route would not read) throws.
|
|
26
|
+
*/
|
|
27
|
+
export declare function completeCrmTasks(user: MaybeTokenSource, request: CrmTasksCompleteRequest): Promise<CrmTasksCompleteResponse>;
|
|
28
|
+
export declare function saveCrmTasks(user: MaybeTokenSource, request: CrmTasksSaveRequest): Promise<CrmTasksSaveResponse>;
|
|
@@ -0,0 +1,57 @@
|
|
|
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
|
+
*/ import { authorizedFetch } from "@aglyn/shared-util-http/authorized-token";
|
|
17
|
+
import { CRM_TASK_ROUTES, crmTaskRouteUrl } from "./task-routes.js";
|
|
18
|
+
/**
|
|
19
|
+
* The browser's side of the two task routes (AGL-2599).
|
|
20
|
+
*
|
|
21
|
+
* Both go through `authorizedFetch`, so a signed-out caller is answered with
|
|
22
|
+
* the reason rather than a request that leaves without credentials. A
|
|
23
|
+
* refused response becomes a thrown `Error` carrying the route's own
|
|
24
|
+
* sentence, which is what the drawer and the checkbox put in the snackbar.
|
|
25
|
+
*/ async function post(user, route, body) {
|
|
26
|
+
const response = await authorizedFetch(user, crmTaskRouteUrl(route), {
|
|
27
|
+
method: 'POST',
|
|
28
|
+
headers: {
|
|
29
|
+
'Content-Type': 'application/json'
|
|
30
|
+
},
|
|
31
|
+
body: JSON.stringify(body)
|
|
32
|
+
});
|
|
33
|
+
const payload = await response.json().catch(()=>({}));
|
|
34
|
+
if (!response.ok) {
|
|
35
|
+
throw new Error((payload == null ? void 0 : payload.error) || `The request was refused (${response.status}).`);
|
|
36
|
+
}
|
|
37
|
+
return payload;
|
|
38
|
+
}
|
|
39
|
+
export function saveCrmTask(user, request) {
|
|
40
|
+
return post(user, CRM_TASK_ROUTES.save, request);
|
|
41
|
+
}
|
|
42
|
+
export function completeCrmTask(user, request) {
|
|
43
|
+
return post(user, CRM_TASK_ROUTES.complete, request);
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* The organization hub's batch forms (AGL-2637): one request per bulk
|
|
47
|
+
* action, answered per task. A refused TASK is a row in `results`, not a
|
|
48
|
+
* thrown error — only a refused REQUEST (no session, no reach, a body the
|
|
49
|
+
* route would not read) throws.
|
|
50
|
+
*/ export function completeCrmTasks(user, request) {
|
|
51
|
+
return post(user, CRM_TASK_ROUTES.complete, request);
|
|
52
|
+
}
|
|
53
|
+
export function saveCrmTasks(user, request) {
|
|
54
|
+
return post(user, CRM_TASK_ROUTES.save, request);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
//# sourceMappingURL=task-api.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/crm/src/lib/model/task-api.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 {\n authorizedFetch,\n type MaybeTokenSource,\n} from '@aglyn/shared-util-http/authorized-token'\nimport {\n CRM_TASK_ROUTES,\n type CrmTaskCompleteRequest,\n type CrmTaskCompleteResponse,\n type CrmTaskSaveRequest,\n type CrmTaskSaveResponse,\n type CrmTasksCompleteRequest,\n type CrmTasksCompleteResponse,\n type CrmTasksSaveRequest,\n type CrmTasksSaveResponse,\n crmTaskRouteUrl,\n} from './task-routes'\n\n/**\n * The browser's side of the two task routes (AGL-2599).\n *\n * Both go through `authorizedFetch`, so a signed-out caller is answered with\n * the reason rather than a request that leaves without credentials. A\n * refused response becomes a thrown `Error` carrying the route's own\n * sentence, which is what the drawer and the checkbox put in the snackbar.\n */\nasync function post<T>(\n user: MaybeTokenSource,\n route: (typeof CRM_TASK_ROUTES)[keyof typeof CRM_TASK_ROUTES],\n body: unknown,\n): Promise<T> {\n const response = await authorizedFetch(user, crmTaskRouteUrl(route), {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(body),\n })\n const payload = (await response.json().catch(() => ({}))) as {\n error?: string\n }\n if (!response.ok) {\n throw new Error(\n payload?.error || `The request was refused (${response.status}).`,\n )\n }\n return payload as T\n}\n\nexport function saveCrmTask(\n user: MaybeTokenSource,\n request: CrmTaskSaveRequest,\n): Promise<CrmTaskSaveResponse> {\n return post<CrmTaskSaveResponse>(user, CRM_TASK_ROUTES.save, request)\n}\n\nexport function completeCrmTask(\n user: MaybeTokenSource,\n request: CrmTaskCompleteRequest,\n): Promise<CrmTaskCompleteResponse> {\n return post<CrmTaskCompleteResponse>(user, CRM_TASK_ROUTES.complete, request)\n}\n\n/**\n * The organization hub's batch forms (AGL-2637): one request per bulk\n * action, answered per task. A refused TASK is a row in `results`, not a\n * thrown error — only a refused REQUEST (no session, no reach, a body the\n * route would not read) throws.\n */\nexport function completeCrmTasks(\n user: MaybeTokenSource,\n request: CrmTasksCompleteRequest,\n): Promise<CrmTasksCompleteResponse> {\n return post<CrmTasksCompleteResponse>(user, CRM_TASK_ROUTES.complete, request)\n}\n\nexport function saveCrmTasks(\n user: MaybeTokenSource,\n request: CrmTasksSaveRequest,\n): Promise<CrmTasksSaveResponse> {\n return post<CrmTasksSaveResponse>(user, CRM_TASK_ROUTES.save, request)\n}\n"],"names":["authorizedFetch","CRM_TASK_ROUTES","crmTaskRouteUrl","post","user","route","body","response","method","headers","JSON","stringify","payload","json","catch","ok","Error","error","status","saveCrmTask","request","save","completeCrmTask","complete","completeCrmTasks","saveCrmTasks"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAED,SACEA,eAAe,QAEV,2CAA0C;AACjD,SACEC,eAAe,EASfC,eAAe,QACV,mBAAe;AAEtB;;;;;;;CAOC,GACD,eAAeC,KACbC,IAAsB,EACtBC,KAA6D,EAC7DC,IAAa;IAEb,MAAMC,WAAW,MAAMP,gBAAgBI,MAAMF,gBAAgBG,QAAQ;QACnEG,QAAQ;QACRC,SAAS;YAAE,gBAAgB;QAAmB;QAC9CH,MAAMI,KAAKC,SAAS,CAACL;IACvB;IACA,MAAMM,UAAW,MAAML,SAASM,IAAI,GAAGC,KAAK,CAAC,IAAO,CAAA,CAAC,CAAA;IAGrD,IAAI,CAACP,SAASQ,EAAE,EAAE;QAChB,MAAM,IAAIC,MACRJ,CAAAA,2BAAAA,QAASK,KAAK,KAAI,CAAC,yBAAyB,EAAEV,SAASW,MAAM,CAAC,EAAE,CAAC;IAErE;IACA,OAAON;AACT;AAEA,OAAO,SAASO,YACdf,IAAsB,EACtBgB,OAA2B;IAE3B,OAAOjB,KAA0BC,MAAMH,gBAAgBoB,IAAI,EAAED;AAC/D;AAEA,OAAO,SAASE,gBACdlB,IAAsB,EACtBgB,OAA+B;IAE/B,OAAOjB,KAA8BC,MAAMH,gBAAgBsB,QAAQ,EAAEH;AACvE;AAEA;;;;;CAKC,GACD,OAAO,SAASI,iBACdpB,IAAsB,EACtBgB,OAAgC;IAEhC,OAAOjB,KAA+BC,MAAMH,gBAAgBsB,QAAQ,EAAEH;AACxE;AAEA,OAAO,SAASK,aACdrB,IAAsB,EACtBgB,OAA4B;IAE5B,OAAOjB,KAA2BC,MAAMH,gBAAgBoB,IAAI,EAAED;AAChE"}
|