@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,161 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Aglyn LLC
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/ 'use client';
|
|
17
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
18
|
+
import * as Aglyn from "@aglyn/aglyn";
|
|
19
|
+
import { CardDisplay } from "@aglyn/shared-ui-jsx";
|
|
20
|
+
import { percent, Section } from "@aglyn/shared-ui-jsx/components/measured-figures.component";
|
|
21
|
+
import { Alert, Stack, Typography } from "@mui/material";
|
|
22
|
+
import { limit, orderBy, query } from "firebase/firestore";
|
|
23
|
+
import { useMemo } from "react";
|
|
24
|
+
import { useFirestore } from "@aglyn/tenant-feature-instance";
|
|
25
|
+
import { contactPrimaryGroup } from "../../model/contact-record.js";
|
|
26
|
+
import { ReportBreakdown } from "./report-breakdown.js";
|
|
27
|
+
import { plural } from "./report-format.js";
|
|
28
|
+
import { reportCacheKey, scopedCollection, visibleToClause } from "./report-scope.js";
|
|
29
|
+
import { useWindowRead } from "./use-aggregate-read.js";
|
|
30
|
+
/**
|
|
31
|
+
* How many contacts the source mix and the funnel are read from.
|
|
32
|
+
*
|
|
33
|
+
* These two charts need a FIELD off each contact — which facet sources it
|
|
34
|
+
* carries, which lifecycle stage — and Firestore aggregates cannot group by
|
|
35
|
+
* a map key, so the only way to draw them is to read documents. A thousand
|
|
36
|
+
* is the same bound the contacts list carries, and past it the card SAYS it
|
|
37
|
+
* is a sample rather than quietly drawing a thousand as if it were the org.
|
|
38
|
+
*/ const CONTACT_SAMPLE_CEILING = 1000;
|
|
39
|
+
/**
|
|
40
|
+
* Contacts by source, and the lifecycle funnel, from the newest thousand
|
|
41
|
+
* contacts (AGL-2604).
|
|
42
|
+
*
|
|
43
|
+
* Both are read through THIS group's facet, the way every other field on
|
|
44
|
+
* the contacts page is: a source is which capture surface this holder saw
|
|
45
|
+
* the person through, and a stage is where this business's sales team put
|
|
46
|
+
* them. Reading either off the top of the document would chart another
|
|
47
|
+
* holder's records — the disclosure the facet shape exists to end.
|
|
48
|
+
*
|
|
49
|
+
* Newest by `createdAt` rather than by `updatedAt`, so that the sample is
|
|
50
|
+
* "the last thousand people captured" — a population a reader can reason
|
|
51
|
+
* about — and not "the thousand most recently edited", which is whichever
|
|
52
|
+
* ones a bulk tag touched last.
|
|
53
|
+
*/ export function ContactsMixCard(props) {
|
|
54
|
+
const { report, totalContacts } = props;
|
|
55
|
+
const { scope, tokens, groupId, org, nowMs } = report;
|
|
56
|
+
const firestore = useFirestore();
|
|
57
|
+
const sample = useWindowRead(()=>query(scopedCollection(firestore, scope, 'contacts'), ...visibleToClause(tokens), orderBy('createdAt', 'desc'), limit(CONTACT_SAMPLE_CEILING + 1)), CONTACT_SAMPLE_CEILING, [
|
|
58
|
+
firestore,
|
|
59
|
+
scope,
|
|
60
|
+
tokens,
|
|
61
|
+
nowMs
|
|
62
|
+
], {
|
|
63
|
+
cacheKey: reportCacheKey(report, 'contacts:sample')
|
|
64
|
+
});
|
|
65
|
+
const status = sample.status;
|
|
66
|
+
const mix = useMemo(()=>{
|
|
67
|
+
// Through the viewing group's facet under a site; at the organization
|
|
68
|
+
// level (AGL-2630) through each person's own primary holder, so the mix
|
|
69
|
+
// is of the profiles the capturing sites keep.
|
|
70
|
+
const facets = sample.rows.map((row)=>Aglyn.readContactFacet(row, groupId != null ? groupId : contactPrimaryGroup(row, org).groupId));
|
|
71
|
+
// A person captured two ways counts under both sources: the chart asks
|
|
72
|
+
// "how many people came through each door", and a person who came
|
|
73
|
+
// through two did.
|
|
74
|
+
const sources = Aglyn.tally(facets.flatMap((facet)=>Object.keys(facet.sources).filter((source)=>facet.sources[source])), (source)=>source);
|
|
75
|
+
const stageCounts = {};
|
|
76
|
+
let unstaged = 0;
|
|
77
|
+
for (const facet of facets){
|
|
78
|
+
const stage = facet.lifecycleStage;
|
|
79
|
+
if (Aglyn.isContactLifecycleStage(stage)) {
|
|
80
|
+
var _stageCounts_stage;
|
|
81
|
+
stageCounts[stage] = ((_stageCounts_stage = stageCounts[stage]) != null ? _stageCounts_stage : 0) + 1;
|
|
82
|
+
} else {
|
|
83
|
+
unstaged += 1;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return {
|
|
87
|
+
sources,
|
|
88
|
+
funnel: Aglyn.funnelFromStages(stageCounts),
|
|
89
|
+
unstaged
|
|
90
|
+
};
|
|
91
|
+
}, [
|
|
92
|
+
sample,
|
|
93
|
+
groupId,
|
|
94
|
+
org
|
|
95
|
+
]);
|
|
96
|
+
// A sample only once the read has settled: while the window is empty
|
|
97
|
+
// every org "exceeds" zero rows.
|
|
98
|
+
const sampled = status === 'success' && (sample.truncated || totalContacts.value !== null && totalContacts.value > sample.rows.length);
|
|
99
|
+
return /*#__PURE__*/ _jsx(CardDisplay, {
|
|
100
|
+
header: 'Sources and lifecycle',
|
|
101
|
+
help: Aglyn.pluginDocsHelp('crmReports', {
|
|
102
|
+
anchor: '#sources-and-lifecycle',
|
|
103
|
+
excerpt: 'Which capture surfaces your contacts came through, and how many ' + 'have reached each lifecycle stage. Read from the newest thousand ' + 'contacts, through this site’s own view of each person.'
|
|
104
|
+
}),
|
|
105
|
+
contentGutterX: true,
|
|
106
|
+
contentGutterY: true,
|
|
107
|
+
children: /*#__PURE__*/ _jsxs(Stack, {
|
|
108
|
+
spacing: 2,
|
|
109
|
+
children: [
|
|
110
|
+
sampled ? /*#__PURE__*/ _jsx(Alert, {
|
|
111
|
+
severity: "info",
|
|
112
|
+
children: `Read from the newest ${sample.rows.length.toLocaleString()} contacts${totalContacts.value !== null ? ` of ${totalContacts.value.toLocaleString()}` : ''} — a sample, not the whole list.`
|
|
113
|
+
}) : null,
|
|
114
|
+
/*#__PURE__*/ _jsxs(Section, {
|
|
115
|
+
title: 'By source',
|
|
116
|
+
children: [
|
|
117
|
+
/*#__PURE__*/ _jsx(ReportBreakdown, {
|
|
118
|
+
rows: mix.sources.map((row)=>{
|
|
119
|
+
var _Aglyn_CONTACT_SOURCE_LABELS_row_key;
|
|
120
|
+
return {
|
|
121
|
+
key: row.key,
|
|
122
|
+
label: (_Aglyn_CONTACT_SOURCE_LABELS_row_key = Aglyn.CONTACT_SOURCE_LABELS[row.key]) != null ? _Aglyn_CONTACT_SOURCE_LABELS_row_key : row.key,
|
|
123
|
+
value: row.count
|
|
124
|
+
};
|
|
125
|
+
}),
|
|
126
|
+
emptyText: status === 'loading' ? 'Reading…' : 'No contacts to count yet.'
|
|
127
|
+
}),
|
|
128
|
+
mix.sources.length ? /*#__PURE__*/ _jsx(Typography, {
|
|
129
|
+
variant: "caption",
|
|
130
|
+
color: "text.secondary",
|
|
131
|
+
children: 'A person captured two ways counts under both.'
|
|
132
|
+
}) : null
|
|
133
|
+
]
|
|
134
|
+
}),
|
|
135
|
+
/*#__PURE__*/ _jsxs(Section, {
|
|
136
|
+
title: 'Lifecycle funnel',
|
|
137
|
+
children: [
|
|
138
|
+
/*#__PURE__*/ _jsx(ReportBreakdown, {
|
|
139
|
+
rows: mix.funnel.steps.map((step)=>({
|
|
140
|
+
key: step.stage,
|
|
141
|
+
label: step.label,
|
|
142
|
+
value: step.reached,
|
|
143
|
+
note: `${plural(step.count, 'person', 'people')} here now` + (step.conversion === null ? '' : ` · ${percent(step.conversion)} of the step before`)
|
|
144
|
+
})),
|
|
145
|
+
emptyText: status === 'loading' ? 'Reading…' : 'No contacts to place yet.'
|
|
146
|
+
}),
|
|
147
|
+
sample.rows.length ? /*#__PURE__*/ _jsx(Typography, {
|
|
148
|
+
variant: "caption",
|
|
149
|
+
color: "text.secondary",
|
|
150
|
+
children: `Each step counts everyone who reached it or went further. ${plural(mix.unstaged, 'contact')} with no stage yet · ${mix.funnel.other.toLocaleString()} marked other.`
|
|
151
|
+
}) : null
|
|
152
|
+
]
|
|
153
|
+
})
|
|
154
|
+
]
|
|
155
|
+
})
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
ContactsMixCard.displayName = 'ContactsMixCard';
|
|
159
|
+
export default ContactsMixCard;
|
|
160
|
+
|
|
161
|
+
//# sourceMappingURL=contacts-mix-card.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../../libs/plugins/crm/src/lib/components/reports/contacts-mix-card.tsx"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n'use client'\n\nimport * as Aglyn from '@aglyn/aglyn'\nimport { CardDisplay } from '@aglyn/shared-ui-jsx'\nimport {\n percent,\n Section,\n} from '@aglyn/shared-ui-jsx/components/measured-figures.component'\nimport { Alert, Stack, Typography } from '@mui/material'\nimport { limit, orderBy, query } from 'firebase/firestore'\nimport { useMemo } from 'react'\nimport { useFirestore } from '@aglyn/tenant-feature-instance'\nimport { contactPrimaryGroup } from '../../model/contact-record'\nimport { ReportBreakdown } from './report-breakdown'\nimport { plural } from './report-format'\nimport {\n type CrmReportScope,\n reportCacheKey,\n scopedCollection,\n visibleToClause,\n} from './report-scope'\nimport { type AggregateRead, useWindowRead } from './use-aggregate-read'\n\n/**\n * How many contacts the source mix and the funnel are read from.\n *\n * These two charts need a FIELD off each contact — which facet sources it\n * carries, which lifecycle stage — and Firestore aggregates cannot group by\n * a map key, so the only way to draw them is to read documents. A thousand\n * is the same bound the contacts list carries, and past it the card SAYS it\n * is a sample rather than quietly drawing a thousand as if it were the org.\n */\nconst CONTACT_SAMPLE_CEILING = 1000\n\nexport interface ContactsMixCardProps {\n report: CrmReportScope\n /** The section's count of every contact this reader may see — what decides whether the read is a sample. */\n totalContacts: AggregateRead<number>\n}\n\n/**\n * Contacts by source, and the lifecycle funnel, from the newest thousand\n * contacts (AGL-2604).\n *\n * Both are read through THIS group's facet, the way every other field on\n * the contacts page is: a source is which capture surface this holder saw\n * the person through, and a stage is where this business's sales team put\n * them. Reading either off the top of the document would chart another\n * holder's records — the disclosure the facet shape exists to end.\n *\n * Newest by `createdAt` rather than by `updatedAt`, so that the sample is\n * \"the last thousand people captured\" — a population a reader can reason\n * about — and not \"the thousand most recently edited\", which is whichever\n * ones a bulk tag touched last.\n */\nexport function ContactsMixCard(props: ContactsMixCardProps) {\n const { report, totalContacts } = props\n const { scope, tokens, groupId, org, nowMs } = report\n const firestore = useFirestore()\n\n const sample = useWindowRead<Record<string, unknown>>(\n () =>\n query(\n scopedCollection(firestore, scope, 'contacts'),\n ...visibleToClause(tokens),\n orderBy('createdAt', 'desc'),\n limit(CONTACT_SAMPLE_CEILING + 1),\n ),\n CONTACT_SAMPLE_CEILING,\n [firestore, scope, tokens, nowMs],\n { cacheKey: reportCacheKey(report, 'contacts:sample') },\n )\n const status = sample.status\n\n const mix = useMemo(() => {\n // Through the viewing group's facet under a site; at the organization\n // level (AGL-2630) through each person's own primary holder, so the mix\n // is of the profiles the capturing sites keep.\n const facets = sample.rows.map((row) =>\n Aglyn.readContactFacet(\n row,\n groupId ?? contactPrimaryGroup(row, org).groupId,\n ),\n )\n // A person captured two ways counts under both sources: the chart asks\n // \"how many people came through each door\", and a person who came\n // through two did.\n const sources = Aglyn.tally(\n facets.flatMap((facet) =>\n (Object.keys(facet.sources) as Aglyn.ContactSource[]).filter(\n (source) => facet.sources[source],\n ),\n ),\n (source) => source,\n )\n const stageCounts: Partial<Record<Aglyn.ContactLifecycleStage, number>> = {}\n let unstaged = 0\n for (const facet of facets) {\n const stage = facet.lifecycleStage\n if (Aglyn.isContactLifecycleStage(stage)) {\n stageCounts[stage] = (stageCounts[stage] ?? 0) + 1\n } else {\n unstaged += 1\n }\n }\n return { sources, funnel: Aglyn.funnelFromStages(stageCounts), unstaged }\n }, [sample, groupId, org])\n\n // A sample only once the read has settled: while the window is empty\n // every org \"exceeds\" zero rows.\n const sampled =\n status === 'success' &&\n (sample.truncated ||\n (totalContacts.value !== null && totalContacts.value > sample.rows.length))\n\n return (\n <CardDisplay\n header={'Sources and lifecycle'}\n help={Aglyn.pluginDocsHelp('crmReports', {\n anchor: '#sources-and-lifecycle',\n excerpt:\n 'Which capture surfaces your contacts came through, and how many ' +\n 'have reached each lifecycle stage. Read from the newest thousand ' +\n 'contacts, through this site’s own view of each person.',\n })}\n contentGutterX\n contentGutterY\n >\n <Stack spacing={2}>\n {sampled ? (\n <Alert severity=\"info\">\n {`Read from the newest ${sample.rows.length.toLocaleString()} contacts${\n totalContacts.value !== null\n ? ` of ${totalContacts.value.toLocaleString()}`\n : ''\n } — a sample, not the whole list.`}\n </Alert>\n ) : null}\n <Section title={'By source'}>\n <ReportBreakdown\n rows={mix.sources.map((row) => ({\n key: row.key,\n label:\n Aglyn.CONTACT_SOURCE_LABELS[row.key as Aglyn.ContactSource] ??\n row.key,\n value: row.count,\n }))}\n emptyText={\n status === 'loading' ? 'Reading…' : 'No contacts to count yet.'\n }\n />\n {mix.sources.length ? (\n <Typography variant=\"caption\" color=\"text.secondary\">\n {'A person captured two ways counts under both.'}\n </Typography>\n ) : null}\n </Section>\n <Section title={'Lifecycle funnel'}>\n <ReportBreakdown\n rows={mix.funnel.steps.map((step) => ({\n key: step.stage,\n label: step.label,\n value: step.reached,\n note:\n `${plural(step.count, 'person', 'people')} here now` +\n (step.conversion === null\n ? ''\n : ` · ${percent(step.conversion)} of the step before`),\n }))}\n emptyText={\n status === 'loading' ? 'Reading…' : 'No contacts to place yet.'\n }\n />\n {sample.rows.length ? (\n <Typography variant=\"caption\" color=\"text.secondary\">\n {`Each step counts everyone who reached it or went further. ${plural(\n mix.unstaged,\n 'contact',\n )} with no stage yet · ${mix.funnel.other.toLocaleString()} marked other.`}\n </Typography>\n ) : null}\n </Section>\n </Stack>\n </CardDisplay>\n )\n}\nContactsMixCard.displayName = 'ContactsMixCard'\n\nexport default ContactsMixCard\n"],"names":["Aglyn","CardDisplay","percent","Section","Alert","Stack","Typography","limit","orderBy","query","useMemo","useFirestore","contactPrimaryGroup","ReportBreakdown","plural","reportCacheKey","scopedCollection","visibleToClause","useWindowRead","CONTACT_SAMPLE_CEILING","ContactsMixCard","props","report","totalContacts","scope","tokens","groupId","org","nowMs","firestore","sample","cacheKey","status","mix","facets","rows","map","row","readContactFacet","sources","tally","flatMap","facet","Object","keys","filter","source","stageCounts","unstaged","stage","lifecycleStage","isContactLifecycleStage","funnel","funnelFromStages","sampled","truncated","value","length","header","help","pluginDocsHelp","anchor","excerpt","contentGutterX","contentGutterY","spacing","severity","toLocaleString","title","key","label","CONTACT_SOURCE_LABELS","count","emptyText","variant","color","steps","step","reached","note","conversion","other","displayName"],"mappings":"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"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { type CrmReportScope } from './report-scope';
|
|
2
|
+
import { type AggregateRead } from './use-aggregate-read';
|
|
3
|
+
export interface ContactsTrendCardProps {
|
|
4
|
+
report: CrmReportScope;
|
|
5
|
+
/** The section's one count of every contact this reader may see. */
|
|
6
|
+
totalContacts: AggregateRead<number>;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* New contacts over the period, against the period before, week by week
|
|
10
|
+
* (AGL-2604).
|
|
11
|
+
*
|
|
12
|
+
* ## Every number here is a server count
|
|
13
|
+
*
|
|
14
|
+
* One `getCountFromServer` per week of the period and one for the previous
|
|
15
|
+
* period — fourteen reads for ninety days, billed as index entries rather
|
|
16
|
+
* than documents — and NO document is downloaded to be counted. The period
|
|
17
|
+
* figure is the sum of its weeks rather than a fifteenth read, so the tile
|
|
18
|
+
* and the bars cannot disagree. The contacts list's head-count learned the
|
|
19
|
+
* same lesson (AGL-1706): a count taken from a capped listener saturates at
|
|
20
|
+
* the cap, and the org this page is for is the one with more contacts than
|
|
21
|
+
* any listener should carry.
|
|
22
|
+
*
|
|
23
|
+
* The range is on `createdAt`, the timestamp every contact writer stamps —
|
|
24
|
+
* the server upsert with `serverTimestamp()`, the console's add-by-hand with
|
|
25
|
+
* a `Date` — so "new" means first captured, not last touched.
|
|
26
|
+
*/
|
|
27
|
+
export declare function ContactsTrendCard(props: ContactsTrendCardProps): import("react").JSX.Element;
|
|
28
|
+
export declare namespace ContactsTrendCard {
|
|
29
|
+
var displayName: string;
|
|
30
|
+
}
|
|
31
|
+
export default ContactsTrendCard;
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Aglyn LLC
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/ 'use client';
|
|
17
|
+
import { _ as _extends } from "@swc/helpers/_/_extends";
|
|
18
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
19
|
+
import { deltaPercent, pluginDocsHelp, weekBuckets } from "@aglyn/aglyn";
|
|
20
|
+
import { CardDisplay } from "@aglyn/shared-ui-jsx";
|
|
21
|
+
import { Section } from "@aglyn/shared-ui-jsx/components/measured-figures.component";
|
|
22
|
+
import { Alert, Stack, Typography } from "@mui/material";
|
|
23
|
+
import { getCountFromServer, query, Timestamp, where } from "firebase/firestore";
|
|
24
|
+
import { useFirestore } from "@aglyn/tenant-feature-instance";
|
|
25
|
+
import { ReportBarChart } from "./report-bar-chart.js";
|
|
26
|
+
import { weekLabel } from "./report-format.js";
|
|
27
|
+
import { reportCacheKey, scopedCollection, visibleToClause } from "./report-scope.js";
|
|
28
|
+
import { ReportStatTile } from "./report-stat-tile.js";
|
|
29
|
+
import { useAggregateRead } from "./use-aggregate-read.js";
|
|
30
|
+
/**
|
|
31
|
+
* New contacts over the period, against the period before, week by week
|
|
32
|
+
* (AGL-2604).
|
|
33
|
+
*
|
|
34
|
+
* ## Every number here is a server count
|
|
35
|
+
*
|
|
36
|
+
* One `getCountFromServer` per week of the period and one for the previous
|
|
37
|
+
* period — fourteen reads for ninety days, billed as index entries rather
|
|
38
|
+
* than documents — and NO document is downloaded to be counted. The period
|
|
39
|
+
* figure is the sum of its weeks rather than a fifteenth read, so the tile
|
|
40
|
+
* and the bars cannot disagree. The contacts list's head-count learned the
|
|
41
|
+
* same lesson (AGL-1706): a count taken from a capped listener saturates at
|
|
42
|
+
* the cap, and the org this page is for is the one with more contacts than
|
|
43
|
+
* any listener should carry.
|
|
44
|
+
*
|
|
45
|
+
* The range is on `createdAt`, the timestamp every contact writer stamps —
|
|
46
|
+
* the server upsert with `serverTimestamp()`, the console's add-by-hand with
|
|
47
|
+
* a `Date` — so "new" means first captured, not last touched.
|
|
48
|
+
*/ export function ContactsTrendCard(props) {
|
|
49
|
+
var _ref, _ref1;
|
|
50
|
+
const { report, totalContacts } = props;
|
|
51
|
+
const { scope, tokens, range, routes } = report;
|
|
52
|
+
const firestore = useFirestore();
|
|
53
|
+
const trend = useAggregateRead(()=>{
|
|
54
|
+
const contacts = scopedCollection(firestore, scope, 'contacts');
|
|
55
|
+
const createdBetween = (from, to)=>getCountFromServer(query(contacts, ...visibleToClause(tokens), where('createdAt', '>=', Timestamp.fromMillis(from)), where('createdAt', '<', Timestamp.fromMillis(to)))).then((snapshot)=>snapshot.data().count);
|
|
56
|
+
const buckets = weekBuckets(range.from, range.to);
|
|
57
|
+
return Promise.all([
|
|
58
|
+
createdBetween(range.previousFrom, range.previousTo),
|
|
59
|
+
...buckets.map((bucket)=>createdBetween(bucket.start, bucket.end))
|
|
60
|
+
]).then(([previous, ...weekly])=>({
|
|
61
|
+
previous,
|
|
62
|
+
current: weekly.reduce((sum, count)=>sum + count, 0),
|
|
63
|
+
weekly: buckets.map((bucket, index)=>{
|
|
64
|
+
var _weekly_index;
|
|
65
|
+
return _extends({}, bucket, {
|
|
66
|
+
count: (_weekly_index = weekly[index]) != null ? _weekly_index : 0
|
|
67
|
+
});
|
|
68
|
+
})
|
|
69
|
+
}));
|
|
70
|
+
}, [
|
|
71
|
+
firestore,
|
|
72
|
+
scope,
|
|
73
|
+
tokens,
|
|
74
|
+
range
|
|
75
|
+
], {
|
|
76
|
+
cacheKey: reportCacheKey(report, 'contacts:trend')
|
|
77
|
+
});
|
|
78
|
+
const figures = trend.value;
|
|
79
|
+
return /*#__PURE__*/ _jsx(CardDisplay, {
|
|
80
|
+
header: 'Contacts',
|
|
81
|
+
help: pluginDocsHelp('crmReports', {
|
|
82
|
+
anchor: '#contacts',
|
|
83
|
+
excerpt: 'New contacts in the period against the period before it, week ' + 'by week, and how many contacts this site can see in all. Counted ' + 'on the server by when each contact was first captured.'
|
|
84
|
+
}),
|
|
85
|
+
contentGutterX: true,
|
|
86
|
+
contentGutterY: true,
|
|
87
|
+
children: /*#__PURE__*/ _jsxs(Stack, {
|
|
88
|
+
spacing: 2,
|
|
89
|
+
children: [
|
|
90
|
+
/*#__PURE__*/ _jsxs(Stack, {
|
|
91
|
+
direction: "row",
|
|
92
|
+
spacing: 3,
|
|
93
|
+
sx: {
|
|
94
|
+
flexWrap: 'wrap'
|
|
95
|
+
},
|
|
96
|
+
children: [
|
|
97
|
+
/*#__PURE__*/ _jsx(ReportStatTile, {
|
|
98
|
+
label: 'New contacts',
|
|
99
|
+
value: figures ? figures.current.toLocaleString() : null,
|
|
100
|
+
deltaPct: figures ? deltaPercent(figures.current, figures.previous) : null,
|
|
101
|
+
note: figures ? figures.previous ? `${figures.previous.toLocaleString()} in the previous period` : 'none in the previous period' : undefined,
|
|
102
|
+
href: routes.section('contacts')
|
|
103
|
+
}),
|
|
104
|
+
/*#__PURE__*/ _jsx(ReportStatTile, {
|
|
105
|
+
label: 'Total contacts',
|
|
106
|
+
value: totalContacts.value === null ? null : totalContacts.value.toLocaleString(),
|
|
107
|
+
note: 'visible to this site',
|
|
108
|
+
href: routes.section('contacts')
|
|
109
|
+
})
|
|
110
|
+
]
|
|
111
|
+
}),
|
|
112
|
+
trend.status === 'error' || totalContacts.status === 'error' ? /*#__PURE__*/ _jsx(Alert, {
|
|
113
|
+
severity: "warning",
|
|
114
|
+
children: 'The contact counts could not be read. The rest of the page is unaffected.'
|
|
115
|
+
}) : null,
|
|
116
|
+
/*#__PURE__*/ _jsxs(Section, {
|
|
117
|
+
title: 'New contacts per week',
|
|
118
|
+
children: [
|
|
119
|
+
/*#__PURE__*/ _jsx(ReportBarChart, {
|
|
120
|
+
labels: ((_ref = figures == null ? void 0 : figures.weekly) != null ? _ref : []).map((week)=>weekLabel(week.start)),
|
|
121
|
+
series: [
|
|
122
|
+
{
|
|
123
|
+
name: 'New contacts',
|
|
124
|
+
color: 'primary.main',
|
|
125
|
+
values: ((_ref1 = figures == null ? void 0 : figures.weekly) != null ? _ref1 : []).map((week)=>week.count)
|
|
126
|
+
}
|
|
127
|
+
],
|
|
128
|
+
emptyText: trend.status === 'loading' ? 'Counting…' : 'Nothing in this period.'
|
|
129
|
+
}),
|
|
130
|
+
/*#__PURE__*/ _jsx(Typography, {
|
|
131
|
+
variant: "caption",
|
|
132
|
+
color: "text.secondary",
|
|
133
|
+
children: 'Each bar is seven days from the start of the period; the last ' + 'may be shorter.'
|
|
134
|
+
})
|
|
135
|
+
]
|
|
136
|
+
})
|
|
137
|
+
]
|
|
138
|
+
})
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
ContactsTrendCard.displayName = 'ContactsTrendCard';
|
|
142
|
+
export default ContactsTrendCard;
|
|
143
|
+
|
|
144
|
+
//# sourceMappingURL=contacts-trend-card.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../../libs/plugins/crm/src/lib/components/reports/contacts-trend-card.tsx"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n'use client'\n\nimport { deltaPercent, pluginDocsHelp, weekBuckets } from '@aglyn/aglyn'\nimport { CardDisplay } from '@aglyn/shared-ui-jsx'\nimport { Section } from '@aglyn/shared-ui-jsx/components/measured-figures.component'\nimport { Alert, Stack, Typography } from '@mui/material'\nimport { getCountFromServer, query, Timestamp, where } from 'firebase/firestore'\nimport { useFirestore } from '@aglyn/tenant-feature-instance'\nimport { ReportBarChart } from './report-bar-chart'\nimport { weekLabel } from './report-format'\nimport {\n type CrmReportScope,\n reportCacheKey,\n scopedCollection,\n visibleToClause,\n} from './report-scope'\nimport { ReportStatTile } from './report-stat-tile'\nimport { type AggregateRead, useAggregateRead } from './use-aggregate-read'\n\nexport interface ContactsTrendCardProps {\n report: CrmReportScope\n /** The section's one count of every contact this reader may see. */\n totalContacts: AggregateRead<number>\n}\n\ninterface ContactsTrend {\n /** New contacts in the period — the sum of the weeks. */\n current: number\n /** New contacts in the period before it. */\n previous: number\n weekly: Array<{ start: number; end: number; count: number }>\n}\n\n/**\n * New contacts over the period, against the period before, week by week\n * (AGL-2604).\n *\n * ## Every number here is a server count\n *\n * One `getCountFromServer` per week of the period and one for the previous\n * period — fourteen reads for ninety days, billed as index entries rather\n * than documents — and NO document is downloaded to be counted. The period\n * figure is the sum of its weeks rather than a fifteenth read, so the tile\n * and the bars cannot disagree. The contacts list's head-count learned the\n * same lesson (AGL-1706): a count taken from a capped listener saturates at\n * the cap, and the org this page is for is the one with more contacts than\n * any listener should carry.\n *\n * The range is on `createdAt`, the timestamp every contact writer stamps —\n * the server upsert with `serverTimestamp()`, the console's add-by-hand with\n * a `Date` — so \"new\" means first captured, not last touched.\n */\nexport function ContactsTrendCard(props: ContactsTrendCardProps) {\n const { report, totalContacts } = props\n const { scope, tokens, range, routes } = report\n const firestore = useFirestore()\n\n const trend = useAggregateRead<ContactsTrend>(() => {\n const contacts = scopedCollection(firestore, scope, 'contacts')\n const createdBetween = (from: number, to: number) =>\n getCountFromServer(\n query(\n contacts,\n ...visibleToClause(tokens),\n where('createdAt', '>=', Timestamp.fromMillis(from)),\n where('createdAt', '<', Timestamp.fromMillis(to)),\n ),\n ).then((snapshot) => snapshot.data().count)\n const buckets = weekBuckets(range.from, range.to)\n return Promise.all([\n createdBetween(range.previousFrom, range.previousTo),\n ...buckets.map((bucket) => createdBetween(bucket.start, bucket.end)),\n ]).then(([previous, ...weekly]) => ({\n previous,\n current: weekly.reduce((sum, count) => sum + count, 0),\n weekly: buckets.map((bucket, index) => ({\n ...bucket,\n count: weekly[index] ?? 0,\n })),\n }))\n }, [firestore, scope, tokens, range], { cacheKey: reportCacheKey(report, 'contacts:trend') })\n\n const figures = trend.value\n return (\n <CardDisplay\n header={'Contacts'}\n help={pluginDocsHelp('crmReports', {\n anchor: '#contacts',\n excerpt:\n 'New contacts in the period against the period before it, week ' +\n 'by week, and how many contacts this site can see in all. Counted ' +\n 'on the server by when each contact was first captured.',\n })}\n contentGutterX\n contentGutterY\n >\n <Stack spacing={2}>\n <Stack direction=\"row\" spacing={3} sx={{ flexWrap: 'wrap' }}>\n <ReportStatTile\n label={'New contacts'}\n value={figures ? figures.current.toLocaleString() : null}\n deltaPct={figures ? deltaPercent(figures.current, figures.previous) : null}\n note={\n figures\n ? figures.previous\n ? `${figures.previous.toLocaleString()} in the previous period`\n : 'none in the previous period'\n : undefined\n }\n href={routes.section('contacts')}\n />\n <ReportStatTile\n label={'Total contacts'}\n value={\n totalContacts.value === null\n ? null\n : totalContacts.value.toLocaleString()\n }\n note={'visible to this site'}\n href={routes.section('contacts')}\n />\n </Stack>\n {trend.status === 'error' || totalContacts.status === 'error' ? (\n <Alert severity=\"warning\">\n {'The contact counts could not be read. The rest of the page is unaffected.'}\n </Alert>\n ) : null}\n <Section title={'New contacts per week'}>\n <ReportBarChart\n labels={(figures?.weekly ?? []).map((week) => weekLabel(week.start))}\n series={[\n {\n name: 'New contacts',\n color: 'primary.main',\n values: (figures?.weekly ?? []).map((week) => week.count),\n },\n ]}\n emptyText={\n trend.status === 'loading' ? 'Counting…' : 'Nothing in this period.'\n }\n />\n <Typography variant=\"caption\" color=\"text.secondary\">\n {'Each bar is seven days from the start of the period; the last ' +\n 'may be shorter.'}\n </Typography>\n </Section>\n </Stack>\n </CardDisplay>\n )\n}\nContactsTrendCard.displayName = 'ContactsTrendCard'\n\nexport default ContactsTrendCard\n"],"names":["deltaPercent","pluginDocsHelp","weekBuckets","CardDisplay","Section","Alert","Stack","Typography","getCountFromServer","query","Timestamp","where","useFirestore","ReportBarChart","weekLabel","reportCacheKey","scopedCollection","visibleToClause","ReportStatTile","useAggregateRead","ContactsTrendCard","props","report","totalContacts","scope","tokens","range","routes","firestore","trend","contacts","createdBetween","from","to","fromMillis","then","snapshot","data","count","buckets","Promise","all","previousFrom","previousTo","map","bucket","start","end","previous","weekly","current","reduce","sum","index","cacheKey","figures","value","header","help","anchor","excerpt","contentGutterX","contentGutterY","spacing","direction","sx","flexWrap","label","toLocaleString","deltaPct","note","undefined","href","section","status","severity","title","labels","week","series","name","color","values","emptyText","variant","displayName"],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { type CrmReportScope } from './report-scope';
|
|
2
|
+
export interface ForecastCardProps {
|
|
3
|
+
report: CrmReportScope;
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* Forecast by close month (AGL-2620): the open pipeline laid out by the
|
|
7
|
+
* month each deal is expected to close, for the next six, per pipeline,
|
|
8
|
+
* at face value and weighted by the stage.
|
|
9
|
+
*
|
|
10
|
+
* Not period-scoped, like the pipeline card and for the same reason: the
|
|
11
|
+
* forecast is what is open NOW, looked at forward. Deals with no expected
|
|
12
|
+
* close are their own row rather than a footnote — that row is the size
|
|
13
|
+
* of the pipeline nobody has scheduled, which is the number the picker
|
|
14
|
+
* of a close date most needs to see — and deals dated before this month
|
|
15
|
+
* (overdue) or past the sixth (later) are rows too, so the column adds up
|
|
16
|
+
* to the pipeline.
|
|
17
|
+
*/
|
|
18
|
+
export declare function ForecastCard(props: ForecastCardProps): import("react").JSX.Element;
|
|
19
|
+
export declare namespace ForecastCard {
|
|
20
|
+
var displayName: string;
|
|
21
|
+
}
|
|
22
|
+
export default ForecastCard;
|