@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,338 @@
|
|
|
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 { money } from "@aglyn/shared-ui-email-campaigns/components/report-figures";
|
|
20
|
+
import { AppLink, CardDisplay } from "@aglyn/shared-ui-jsx";
|
|
21
|
+
import { Section } from "@aglyn/shared-ui-jsx/components/measured-figures.component";
|
|
22
|
+
import { ScrollTable } from "@aglyn/shared-ui-jsx/components/scroll-table.component";
|
|
23
|
+
import { Alert, Stack, TableBody, TableCell, TableHead, TableRow, Typography } from "@mui/material";
|
|
24
|
+
import { count, getAggregateFromServer, limit, orderBy, query, sum, where } from "firebase/firestore";
|
|
25
|
+
import { useMemo } from "react";
|
|
26
|
+
import { useFirestore } from "@aglyn/tenant-feature-instance";
|
|
27
|
+
import { collectionCeiling } from "@aglyn/tenant-feature-instance/hooks/host-collection-queries";
|
|
28
|
+
import { ReportBreakdown } from "./report-breakdown.js";
|
|
29
|
+
import { ReportExport } from "./report-export.js";
|
|
30
|
+
import { plural, reportFilename, shortDate } from "./report-format.js";
|
|
31
|
+
import { reportCacheKey, scopedCollection, visibleToClause } from "./report-scope.js";
|
|
32
|
+
import { ReportStatTile } from "./report-stat-tile.js";
|
|
33
|
+
import { useAggregateRead, useWindowRead } from "./use-aggregate-read.js";
|
|
34
|
+
/**
|
|
35
|
+
* How many open deals the by-stage chart, the forecast and the top-deals
|
|
36
|
+
* table are read from.
|
|
37
|
+
*
|
|
38
|
+
* The count and the face value of the pipeline are server aggregates and
|
|
39
|
+
* never meet this bound. The forecast cannot be: it weights each deal by
|
|
40
|
+
* ITS stage's odds, which is a join the server will not do, so it reads the
|
|
41
|
+
* deals and says so when there were more than this.
|
|
42
|
+
*/ const OPEN_DEAL_CEILING = 1000;
|
|
43
|
+
/** More pipelines than this is a shape nobody has asked for; the probe says if it happens. */ const PIPELINE_CEILING = 20;
|
|
44
|
+
const TOP_DEALS = 10;
|
|
45
|
+
/** The top-deals table's columns, which are also the CSV's — the amount split from its currency there. */ const TOP_DEAL_COLUMNS = [
|
|
46
|
+
'Deal',
|
|
47
|
+
'Stage',
|
|
48
|
+
'Expected close',
|
|
49
|
+
'Amount',
|
|
50
|
+
'Currency'
|
|
51
|
+
];
|
|
52
|
+
/**
|
|
53
|
+
* The open pipeline: how many deals, what they add up to, what they are
|
|
54
|
+
* worth at their stage odds, where they sit, and the largest of them
|
|
55
|
+
* (AGL-2604).
|
|
56
|
+
*
|
|
57
|
+
* Not period-scoped, deliberately. A pipeline is a stock, not a flow — what
|
|
58
|
+
* is open NOW — and a "pipeline over the last 30 days" would be a report on
|
|
59
|
+
* deals created in a window, which is a different question with a different
|
|
60
|
+
* answer. The period picker governs the cards that measure flows.
|
|
61
|
+
*/ export function PipelineCard(props) {
|
|
62
|
+
const { report } = props;
|
|
63
|
+
const { scope, tokens, routes, nowMs } = report;
|
|
64
|
+
const firestore = useFirestore();
|
|
65
|
+
const open = useAggregateRead(()=>getAggregateFromServer(query(scopedCollection(firestore, scope, 'deals'), ...visibleToClause(tokens), where('status', '==', 'open')), {
|
|
66
|
+
count: count(),
|
|
67
|
+
amountCents: sum('amountCents')
|
|
68
|
+
}).then((snapshot)=>{
|
|
69
|
+
var _snapshot_data_count, _snapshot_data_amountCents;
|
|
70
|
+
return {
|
|
71
|
+
count: Number((_snapshot_data_count = snapshot.data().count) != null ? _snapshot_data_count : 0),
|
|
72
|
+
amountCents: Number((_snapshot_data_amountCents = snapshot.data().amountCents) != null ? _snapshot_data_amountCents : 0)
|
|
73
|
+
};
|
|
74
|
+
}), [
|
|
75
|
+
firestore,
|
|
76
|
+
scope,
|
|
77
|
+
tokens,
|
|
78
|
+
nowMs
|
|
79
|
+
], {
|
|
80
|
+
cacheKey: reportCacheKey(report, 'pipeline:open')
|
|
81
|
+
});
|
|
82
|
+
/**
|
|
83
|
+
* The open deals, most recently updated first — the order the
|
|
84
|
+
* `(visibleTo, status, updatedAt)` index the deals list already uses can
|
|
85
|
+
* serve, so the report adds no index for this read.
|
|
86
|
+
*/ const dealWindow = useWindowRead(()=>query(scopedCollection(firestore, scope, 'deals'), ...visibleToClause(tokens), where('status', '==', 'open'), orderBy('updatedAt', 'desc'), limit(OPEN_DEAL_CEILING + 1)), OPEN_DEAL_CEILING, [
|
|
87
|
+
firestore,
|
|
88
|
+
scope,
|
|
89
|
+
tokens,
|
|
90
|
+
nowMs
|
|
91
|
+
], {
|
|
92
|
+
cacheKey: reportCacheKey(report, 'pipeline:deals')
|
|
93
|
+
});
|
|
94
|
+
const pipelineWindow = useWindowRead(()=>collectionCeiling(query(scopedCollection(firestore, scope, 'pipelines'), ...visibleToClause(tokens)), PIPELINE_CEILING), PIPELINE_CEILING, [
|
|
95
|
+
firestore,
|
|
96
|
+
scope,
|
|
97
|
+
tokens,
|
|
98
|
+
nowMs
|
|
99
|
+
], {
|
|
100
|
+
cacheKey: reportCacheKey(report, 'pipeline:pipelines')
|
|
101
|
+
});
|
|
102
|
+
const dealsStatus = dealWindow.status;
|
|
103
|
+
const summary = useMemo(()=>{
|
|
104
|
+
const byPipeline = new Map();
|
|
105
|
+
for (const deal of dealWindow.rows){
|
|
106
|
+
var _deal_pipelineId, _byPipeline_get;
|
|
107
|
+
const key = (_deal_pipelineId = deal.pipelineId) != null ? _deal_pipelineId : '';
|
|
108
|
+
const list = (_byPipeline_get = byPipeline.get(key)) != null ? _byPipeline_get : [];
|
|
109
|
+
list.push(deal);
|
|
110
|
+
byPipeline.set(key, list);
|
|
111
|
+
}
|
|
112
|
+
// Every active pipeline is charted even with nothing open; an archived
|
|
113
|
+
// one only while a deal still sits open in it — the forecast card's
|
|
114
|
+
// rule, so the two cards name the same pipelines.
|
|
115
|
+
const pipelines = pipelineWindow.rows.filter((pipeline)=>!Aglyn.isPipelineArchived(pipeline) || byPipeline.has(pipeline.$id)).map((pipeline)=>{
|
|
116
|
+
var _byPipeline_get;
|
|
117
|
+
return {
|
|
118
|
+
pipeline,
|
|
119
|
+
totals: Aglyn.pipelineTotals((_byPipeline_get = byPipeline.get(pipeline.$id)) != null ? _byPipeline_get : [], pipeline)
|
|
120
|
+
};
|
|
121
|
+
});
|
|
122
|
+
const known = new Set(pipelineWindow.rows.map((pipeline)=>pipeline.$id));
|
|
123
|
+
const orphans = dealWindow.rows.filter((deal)=>{
|
|
124
|
+
var _deal_pipelineId;
|
|
125
|
+
return !known.has((_deal_pipelineId = deal.pipelineId) != null ? _deal_pipelineId : '');
|
|
126
|
+
});
|
|
127
|
+
const stageName = (deal)=>{
|
|
128
|
+
var _ref;
|
|
129
|
+
var _Aglyn_dealStageById;
|
|
130
|
+
return (_ref = (_Aglyn_dealStageById = Aglyn.dealStageById(pipelineWindow.rows.find((pipeline)=>pipeline.$id === deal.pipelineId), deal.stageId)) == null ? void 0 : _Aglyn_dealStageById.name) != null ? _ref : deal.stageId;
|
|
131
|
+
};
|
|
132
|
+
const top = [
|
|
133
|
+
...dealWindow.rows
|
|
134
|
+
].sort((a, b)=>{
|
|
135
|
+
var _b_amountCents, _a_amountCents;
|
|
136
|
+
return Number((_b_amountCents = b.amountCents) != null ? _b_amountCents : 0) - Number((_a_amountCents = a.amountCents) != null ? _a_amountCents : 0);
|
|
137
|
+
}).slice(0, TOP_DEALS);
|
|
138
|
+
return {
|
|
139
|
+
pipelines,
|
|
140
|
+
orphanTotals: Aglyn.pipelineTotals(orphans, null),
|
|
141
|
+
weightedCents: pipelines.reduce((total, entry)=>total + entry.totals.weightedCents, 0),
|
|
142
|
+
top,
|
|
143
|
+
stageName,
|
|
144
|
+
currency: Aglyn.currencyOfDeals(dealWindow.rows)
|
|
145
|
+
};
|
|
146
|
+
}, [
|
|
147
|
+
dealWindow,
|
|
148
|
+
pipelineWindow
|
|
149
|
+
]);
|
|
150
|
+
// Open deals with nothing scheduled (AGL-2661), off the same window.
|
|
151
|
+
const stuck = useMemo(()=>Aglyn.stuckDeals(dealWindow.rows), [
|
|
152
|
+
dealWindow.rows
|
|
153
|
+
]);
|
|
154
|
+
const currency = summary.currency.currency;
|
|
155
|
+
const dealsRead = dealsStatus === 'success';
|
|
156
|
+
return /*#__PURE__*/ _jsx(CardDisplay, {
|
|
157
|
+
header: 'Pipeline',
|
|
158
|
+
help: Aglyn.pluginDocsHelp('crmReports', {
|
|
159
|
+
anchor: '#pipeline',
|
|
160
|
+
excerpt: 'Every open deal: how many, what they add up to, and what they ' + 'are worth once each is weighted by the odds of its stage. Not ' + 'tied to the period — a pipeline is what is open now.'
|
|
161
|
+
}),
|
|
162
|
+
contentGutterX: true,
|
|
163
|
+
contentGutterY: true,
|
|
164
|
+
children: /*#__PURE__*/ _jsxs(Stack, {
|
|
165
|
+
spacing: 2,
|
|
166
|
+
children: [
|
|
167
|
+
/*#__PURE__*/ _jsxs(Stack, {
|
|
168
|
+
direction: "row",
|
|
169
|
+
spacing: 3,
|
|
170
|
+
sx: {
|
|
171
|
+
flexWrap: 'wrap'
|
|
172
|
+
},
|
|
173
|
+
children: [
|
|
174
|
+
/*#__PURE__*/ _jsx(ReportStatTile, {
|
|
175
|
+
label: 'Open deals',
|
|
176
|
+
value: open.value ? open.value.count.toLocaleString() : null,
|
|
177
|
+
note: 'counted on the server',
|
|
178
|
+
href: routes.section('deals')
|
|
179
|
+
}),
|
|
180
|
+
/*#__PURE__*/ _jsx(ReportStatTile, {
|
|
181
|
+
label: 'Pipeline value',
|
|
182
|
+
value: open.value ? money(open.value.amountCents, currency) : null,
|
|
183
|
+
note: 'face value of every open deal',
|
|
184
|
+
href: routes.section('deals')
|
|
185
|
+
}),
|
|
186
|
+
/*#__PURE__*/ _jsx(ReportStatTile, {
|
|
187
|
+
label: 'Weighted forecast',
|
|
188
|
+
value: dealsRead ? money(summary.weightedCents, currency) : null,
|
|
189
|
+
note: dealWindow.truncated ? `from the ${OPEN_DEAL_CEILING.toLocaleString()} most recently updated` : 'each deal at its stage odds'
|
|
190
|
+
}),
|
|
191
|
+
/*#__PURE__*/ _jsx(ReportStatTile, {
|
|
192
|
+
label: 'Stuck deals',
|
|
193
|
+
value: dealsRead ? stuck.count.toLocaleString() : null,
|
|
194
|
+
note: 'open, with no next activity',
|
|
195
|
+
riseIsGood: false,
|
|
196
|
+
color: stuck.count > 0 ? 'warning.main' : undefined,
|
|
197
|
+
href: routes.section('deals')
|
|
198
|
+
})
|
|
199
|
+
]
|
|
200
|
+
}),
|
|
201
|
+
open.status === 'error' ? /*#__PURE__*/ _jsx(Alert, {
|
|
202
|
+
severity: "warning",
|
|
203
|
+
children: 'The deal totals could not be read.'
|
|
204
|
+
}) : null,
|
|
205
|
+
summary.currency.mixed ? /*#__PURE__*/ _jsx(Typography, {
|
|
206
|
+
variant: "caption",
|
|
207
|
+
color: "text.secondary",
|
|
208
|
+
children: `Deals are in more than one currency; the totals add them as numbers and show ${currency.toUpperCase()}, the most common.`
|
|
209
|
+
}) : null,
|
|
210
|
+
dealsRead && !summary.pipelines.length && !dealWindow.rows.length ? /*#__PURE__*/ _jsx(Typography, {
|
|
211
|
+
variant: "body2",
|
|
212
|
+
color: "text.secondary",
|
|
213
|
+
children: 'No open deals yet.'
|
|
214
|
+
}) : null,
|
|
215
|
+
summary.pipelines.map(({ pipeline, totals })=>/*#__PURE__*/ _jsx(Section, {
|
|
216
|
+
title: pipeline.name || 'Pipeline',
|
|
217
|
+
children: /*#__PURE__*/ _jsx(ReportBreakdown, {
|
|
218
|
+
rows: [
|
|
219
|
+
...totals.stages.map((row)=>({
|
|
220
|
+
key: row.stage.id,
|
|
221
|
+
label: row.stage.name,
|
|
222
|
+
value: row.amountCents,
|
|
223
|
+
display: money(row.amountCents, currency),
|
|
224
|
+
note: `${plural(row.count, 'deal')} · ${money(row.weightedCents, currency)} weighted`
|
|
225
|
+
})),
|
|
226
|
+
...totals.unplaced.count ? [
|
|
227
|
+
{
|
|
228
|
+
key: '$unplaced',
|
|
229
|
+
label: 'Stage no longer in this pipeline',
|
|
230
|
+
value: totals.unplaced.amountCents,
|
|
231
|
+
display: money(totals.unplaced.amountCents, currency),
|
|
232
|
+
note: `${plural(totals.unplaced.count, 'deal')} · not forecast`,
|
|
233
|
+
color: 'warning.main'
|
|
234
|
+
}
|
|
235
|
+
] : []
|
|
236
|
+
],
|
|
237
|
+
emptyText: 'This pipeline has no open stages.'
|
|
238
|
+
})
|
|
239
|
+
}, pipeline.$id)),
|
|
240
|
+
summary.orphanTotals.count ? /*#__PURE__*/ _jsx(Section, {
|
|
241
|
+
title: 'Deals in no pipeline',
|
|
242
|
+
children: /*#__PURE__*/ _jsx(ReportBreakdown, {
|
|
243
|
+
rows: [
|
|
244
|
+
{
|
|
245
|
+
key: '$orphans',
|
|
246
|
+
label: 'No pipeline',
|
|
247
|
+
value: summary.orphanTotals.amountCents,
|
|
248
|
+
display: money(summary.orphanTotals.amountCents, currency),
|
|
249
|
+
note: `${plural(summary.orphanTotals.count, 'deal')} · not forecast`,
|
|
250
|
+
color: 'warning.main'
|
|
251
|
+
}
|
|
252
|
+
],
|
|
253
|
+
emptyText: ''
|
|
254
|
+
})
|
|
255
|
+
}) : null,
|
|
256
|
+
pipelineWindow.truncated ? /*#__PURE__*/ _jsx(Typography, {
|
|
257
|
+
variant: "caption",
|
|
258
|
+
color: "text.secondary",
|
|
259
|
+
children: `Only the first ${PIPELINE_CEILING} pipelines are charted.`
|
|
260
|
+
}) : null,
|
|
261
|
+
summary.top.length ? /*#__PURE__*/ _jsxs(Section, {
|
|
262
|
+
title: 'Top open deals',
|
|
263
|
+
children: [
|
|
264
|
+
/*#__PURE__*/ _jsxs(ScrollTable, {
|
|
265
|
+
size: "small",
|
|
266
|
+
children: [
|
|
267
|
+
/*#__PURE__*/ _jsx(TableHead, {
|
|
268
|
+
children: /*#__PURE__*/ _jsxs(TableRow, {
|
|
269
|
+
children: [
|
|
270
|
+
/*#__PURE__*/ _jsx(TableCell, {
|
|
271
|
+
children: 'Deal'
|
|
272
|
+
}),
|
|
273
|
+
/*#__PURE__*/ _jsx(TableCell, {
|
|
274
|
+
children: 'Stage'
|
|
275
|
+
}),
|
|
276
|
+
/*#__PURE__*/ _jsx(TableCell, {
|
|
277
|
+
children: 'Expected close'
|
|
278
|
+
}),
|
|
279
|
+
/*#__PURE__*/ _jsx(TableCell, {
|
|
280
|
+
align: "right",
|
|
281
|
+
children: 'Amount'
|
|
282
|
+
})
|
|
283
|
+
]
|
|
284
|
+
})
|
|
285
|
+
}),
|
|
286
|
+
/*#__PURE__*/ _jsx(TableBody, {
|
|
287
|
+
children: summary.top.map((deal)=>{
|
|
288
|
+
var _deal_amountCents;
|
|
289
|
+
return /*#__PURE__*/ _jsxs(TableRow, {
|
|
290
|
+
children: [
|
|
291
|
+
/*#__PURE__*/ _jsx(TableCell, {
|
|
292
|
+
children: /*#__PURE__*/ _jsx(AppLink, {
|
|
293
|
+
href: routes.deal(deal.$id),
|
|
294
|
+
children: deal.title || deal.$id
|
|
295
|
+
})
|
|
296
|
+
}),
|
|
297
|
+
/*#__PURE__*/ _jsx(TableCell, {
|
|
298
|
+
children: summary.stageName(deal)
|
|
299
|
+
}),
|
|
300
|
+
/*#__PURE__*/ _jsx(TableCell, {
|
|
301
|
+
children: shortDate(deal.expectedCloseAtMs)
|
|
302
|
+
}),
|
|
303
|
+
/*#__PURE__*/ _jsx(TableCell, {
|
|
304
|
+
align: "right",
|
|
305
|
+
children: money(Number((_deal_amountCents = deal.amountCents) != null ? _deal_amountCents : 0), String(deal.currency || currency))
|
|
306
|
+
})
|
|
307
|
+
]
|
|
308
|
+
}, deal.$id);
|
|
309
|
+
})
|
|
310
|
+
})
|
|
311
|
+
]
|
|
312
|
+
}),
|
|
313
|
+
/*#__PURE__*/ _jsx(ReportExport, {
|
|
314
|
+
filename: reportFilename('top-open-deals'),
|
|
315
|
+
columns: TOP_DEAL_COLUMNS,
|
|
316
|
+
rows: ()=>summary.top.map((deal)=>{
|
|
317
|
+
var _deal_amountCents;
|
|
318
|
+
return [
|
|
319
|
+
deal.title || deal.$id,
|
|
320
|
+
summary.stageName(deal),
|
|
321
|
+
typeof deal.expectedCloseAtMs === 'number' && deal.expectedCloseAtMs > 0 ? new Date(deal.expectedCloseAtMs).toISOString().slice(0, 10) : '',
|
|
322
|
+
(Number((_deal_amountCents = deal.amountCents) != null ? _deal_amountCents : 0) / 100).toFixed(2),
|
|
323
|
+
String(deal.currency || currency).toUpperCase()
|
|
324
|
+
];
|
|
325
|
+
}),
|
|
326
|
+
disabled: !dealsRead,
|
|
327
|
+
caption: dealWindow.truncated ? `Ranked within the ${OPEN_DEAL_CEILING.toLocaleString()} most recently updated open deals.` : undefined
|
|
328
|
+
})
|
|
329
|
+
]
|
|
330
|
+
}) : null
|
|
331
|
+
]
|
|
332
|
+
})
|
|
333
|
+
});
|
|
334
|
+
}
|
|
335
|
+
PipelineCard.displayName = 'PipelineCard';
|
|
336
|
+
export default PipelineCard;
|
|
337
|
+
|
|
338
|
+
//# sourceMappingURL=pipeline-card.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../../libs/plugins/crm/src/lib/components/reports/pipeline-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 { money } from '@aglyn/shared-ui-email-campaigns/components/report-figures'\nimport { AppLink, CardDisplay } from '@aglyn/shared-ui-jsx'\nimport { Section } from '@aglyn/shared-ui-jsx/components/measured-figures.component'\nimport { ScrollTable } from '@aglyn/shared-ui-jsx/components/scroll-table.component'\nimport {\n Alert,\n Stack,\n TableBody,\n TableCell,\n TableHead,\n TableRow,\n Typography,\n} from '@mui/material'\nimport {\n count,\n getAggregateFromServer,\n limit,\n orderBy,\n query,\n sum,\n where,\n} from 'firebase/firestore'\nimport { useMemo } from 'react'\nimport { useFirestore } from '@aglyn/tenant-feature-instance'\nimport { collectionCeiling } from '@aglyn/tenant-feature-instance/hooks/host-collection-queries'\nimport { ReportBreakdown } from './report-breakdown'\nimport { ReportExport } from './report-export'\nimport { plural, reportFilename, shortDate } from './report-format'\nimport {\n type CrmReportScope,\n reportCacheKey,\n scopedCollection,\n visibleToClause,\n} from './report-scope'\nimport { ReportStatTile } from './report-stat-tile'\nimport { useAggregateRead, useWindowRead } from './use-aggregate-read'\n\n/**\n * How many open deals the by-stage chart, the forecast and the top-deals\n * table are read from.\n *\n * The count and the face value of the pipeline are server aggregates and\n * never meet this bound. The forecast cannot be: it weights each deal by\n * ITS stage's odds, which is a join the server will not do, so it reads the\n * deals and says so when there were more than this.\n */\nconst OPEN_DEAL_CEILING = 1000\n/** More pipelines than this is a shape nobody has asked for; the probe says if it happens. */\nconst PIPELINE_CEILING = 20\nconst TOP_DEALS = 10\n\n/** The top-deals table's columns, which are also the CSV's — the amount split from its currency there. */\nconst TOP_DEAL_COLUMNS = ['Deal', 'Stage', 'Expected close', 'Amount', 'Currency'] as const\n\ntype DealRow = Aglyn.CrmDeal & { $id: string }\ntype PipelineRow = Aglyn.CrmPipeline & { $id: string }\n\nexport interface PipelineCardProps {\n report: CrmReportScope\n}\n\n/**\n * The open pipeline: how many deals, what they add up to, what they are\n * worth at their stage odds, where they sit, and the largest of them\n * (AGL-2604).\n *\n * Not period-scoped, deliberately. A pipeline is a stock, not a flow — what\n * is open NOW — and a \"pipeline over the last 30 days\" would be a report on\n * deals created in a window, which is a different question with a different\n * answer. The period picker governs the cards that measure flows.\n */\nexport function PipelineCard(props: PipelineCardProps) {\n const { report } = props\n const { scope, tokens, routes, nowMs } = report\n const firestore = useFirestore()\n\n const open = useAggregateRead(\n () =>\n getAggregateFromServer(\n query(\n scopedCollection(firestore, scope, 'deals'),\n ...visibleToClause(tokens),\n where('status', '==', 'open'),\n ),\n { count: count(), amountCents: sum('amountCents') },\n ).then((snapshot) => ({\n count: Number(snapshot.data().count ?? 0),\n amountCents: Number(snapshot.data().amountCents ?? 0),\n })),\n [firestore, scope, tokens, nowMs],\n { cacheKey: reportCacheKey(report, 'pipeline:open') },\n )\n\n /**\n * The open deals, most recently updated first — the order the\n * `(visibleTo, status, updatedAt)` index the deals list already uses can\n * serve, so the report adds no index for this read.\n */\n const dealWindow = useWindowRead<DealRow>(\n () =>\n query(\n scopedCollection(firestore, scope, 'deals'),\n ...visibleToClause(tokens),\n where('status', '==', 'open'),\n orderBy('updatedAt', 'desc'),\n limit(OPEN_DEAL_CEILING + 1),\n ),\n OPEN_DEAL_CEILING,\n [firestore, scope, tokens, nowMs],\n { cacheKey: reportCacheKey(report, 'pipeline:deals') },\n )\n const pipelineWindow = useWindowRead<PipelineRow>(\n () =>\n collectionCeiling(\n query(\n scopedCollection(firestore, scope, 'pipelines'),\n ...visibleToClause(tokens),\n ),\n PIPELINE_CEILING,\n ),\n PIPELINE_CEILING,\n [firestore, scope, tokens, nowMs],\n { cacheKey: reportCacheKey(report, 'pipeline:pipelines') },\n )\n const dealsStatus = dealWindow.status\n\n const summary = useMemo(() => {\n const byPipeline = new Map<string, DealRow[]>()\n for (const deal of dealWindow.rows) {\n const key = deal.pipelineId ?? ''\n const list = byPipeline.get(key) ?? []\n list.push(deal)\n byPipeline.set(key, list)\n }\n // Every active pipeline is charted even with nothing open; an archived\n // one only while a deal still sits open in it — the forecast card's\n // rule, so the two cards name the same pipelines.\n const pipelines = pipelineWindow.rows\n .filter((pipeline) => !Aglyn.isPipelineArchived(pipeline) || byPipeline.has(pipeline.$id))\n .map((pipeline) => ({\n pipeline,\n totals: Aglyn.pipelineTotals(byPipeline.get(pipeline.$id) ?? [], pipeline),\n }))\n const known = new Set(pipelineWindow.rows.map((pipeline) => pipeline.$id))\n const orphans = dealWindow.rows.filter(\n (deal) => !known.has(deal.pipelineId ?? ''),\n )\n const stageName = (deal: DealRow): string =>\n Aglyn.dealStageById(\n pipelineWindow.rows.find((pipeline) => pipeline.$id === deal.pipelineId),\n deal.stageId,\n )?.name ?? deal.stageId\n const top = [...dealWindow.rows]\n .sort(\n (a, b) => Number(b.amountCents ?? 0) - Number(a.amountCents ?? 0),\n )\n .slice(0, TOP_DEALS)\n return {\n pipelines,\n orphanTotals: Aglyn.pipelineTotals(orphans, null),\n weightedCents: pipelines.reduce(\n (total, entry) => total + entry.totals.weightedCents,\n 0,\n ),\n top,\n stageName,\n currency: Aglyn.currencyOfDeals(dealWindow.rows),\n }\n }, [dealWindow, pipelineWindow])\n // Open deals with nothing scheduled (AGL-2661), off the same window.\n const stuck = useMemo(() => Aglyn.stuckDeals(dealWindow.rows), [dealWindow.rows])\n\n const currency = summary.currency.currency\n const dealsRead = dealsStatus === 'success'\n\n return (\n <CardDisplay\n header={'Pipeline'}\n help={Aglyn.pluginDocsHelp('crmReports', {\n anchor: '#pipeline',\n excerpt:\n 'Every open deal: how many, what they add up to, and what they ' +\n 'are worth once each is weighted by the odds of its stage. Not ' +\n 'tied to the period — a pipeline is what is open now.',\n })}\n contentGutterX\n contentGutterY\n >\n <Stack spacing={2}>\n <Stack direction=\"row\" spacing={3} sx={{ flexWrap: 'wrap' }}>\n <ReportStatTile\n label={'Open deals'}\n value={open.value ? open.value.count.toLocaleString() : null}\n note={'counted on the server'}\n href={routes.section('deals')}\n />\n <ReportStatTile\n label={'Pipeline value'}\n value={open.value ? money(open.value.amountCents, currency) : null}\n note={'face value of every open deal'}\n href={routes.section('deals')}\n />\n <ReportStatTile\n label={'Weighted forecast'}\n value={dealsRead ? money(summary.weightedCents, currency) : null}\n note={\n dealWindow.truncated\n ? `from the ${OPEN_DEAL_CEILING.toLocaleString()} most recently updated`\n : 'each deal at its stage odds'\n }\n />\n {/*\n Open deals with no open task against them (AGL-2661): the ones\n nobody has a next step for. Painted as a warning above zero,\n because a deal with nothing planned is a deal going nowhere; the\n tile opens the deals list, whose \"No next activity\" chip lists\n them.\n */}\n <ReportStatTile\n label={'Stuck deals'}\n value={dealsRead ? stuck.count.toLocaleString() : null}\n note={'open, with no next activity'}\n riseIsGood={false}\n color={stuck.count > 0 ? 'warning.main' : undefined}\n href={routes.section('deals')}\n />\n </Stack>\n {open.status === 'error' ? (\n <Alert severity=\"warning\">\n {'The deal totals could not be read.'}\n </Alert>\n ) : null}\n {summary.currency.mixed ? (\n <Typography variant=\"caption\" color=\"text.secondary\">\n {`Deals are in more than one currency; the totals add them as numbers and show ${currency.toUpperCase()}, the most common.`}\n </Typography>\n ) : null}\n {dealsRead && !summary.pipelines.length && !dealWindow.rows.length ? (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'No open deals yet.'}\n </Typography>\n ) : null}\n {summary.pipelines.map(({ pipeline, totals }) => (\n <Section key={pipeline.$id} title={pipeline.name || 'Pipeline'}>\n <ReportBreakdown\n rows={[\n ...totals.stages.map((row) => ({\n key: row.stage.id,\n label: row.stage.name,\n value: row.amountCents,\n display: money(row.amountCents, currency),\n note: `${plural(row.count, 'deal')} · ${money(row.weightedCents, currency)} weighted`,\n })),\n ...(totals.unplaced.count\n ? [\n {\n key: '$unplaced',\n label: 'Stage no longer in this pipeline',\n value: totals.unplaced.amountCents,\n display: money(totals.unplaced.amountCents, currency),\n note: `${plural(totals.unplaced.count, 'deal')} · not forecast`,\n color: 'warning.main',\n },\n ]\n : []),\n ]}\n emptyText={'This pipeline has no open stages.'}\n />\n </Section>\n ))}\n {summary.orphanTotals.count ? (\n <Section title={'Deals in no pipeline'}>\n <ReportBreakdown\n rows={[\n {\n key: '$orphans',\n label: 'No pipeline',\n value: summary.orphanTotals.amountCents,\n display: money(summary.orphanTotals.amountCents, currency),\n note: `${plural(summary.orphanTotals.count, 'deal')} · not forecast`,\n color: 'warning.main',\n },\n ]}\n emptyText={''}\n />\n </Section>\n ) : null}\n {pipelineWindow.truncated ? (\n <Typography variant=\"caption\" color=\"text.secondary\">\n {`Only the first ${PIPELINE_CEILING} pipelines are charted.`}\n </Typography>\n ) : null}\n {summary.top.length ? (\n <Section title={'Top open deals'}>\n <ScrollTable size=\"small\">\n <TableHead>\n <TableRow>\n <TableCell>{'Deal'}</TableCell>\n <TableCell>{'Stage'}</TableCell>\n <TableCell>{'Expected close'}</TableCell>\n <TableCell align=\"right\">{'Amount'}</TableCell>\n </TableRow>\n </TableHead>\n <TableBody>\n {summary.top.map((deal) => (\n <TableRow key={deal.$id}>\n <TableCell>\n <AppLink href={routes.deal(deal.$id)}>\n {deal.title || deal.$id}\n </AppLink>\n </TableCell>\n <TableCell>{summary.stageName(deal)}</TableCell>\n <TableCell>{shortDate(deal.expectedCloseAtMs)}</TableCell>\n <TableCell align=\"right\">\n {money(\n Number(deal.amountCents ?? 0),\n String(deal.currency || currency),\n )}\n </TableCell>\n </TableRow>\n ))}\n </TableBody>\n </ScrollTable>\n <ReportExport\n filename={reportFilename('top-open-deals')}\n columns={TOP_DEAL_COLUMNS}\n rows={() =>\n summary.top.map((deal) => [\n deal.title || deal.$id,\n summary.stageName(deal),\n typeof deal.expectedCloseAtMs === 'number' && deal.expectedCloseAtMs > 0\n ? new Date(deal.expectedCloseAtMs).toISOString().slice(0, 10)\n : '',\n (Number(deal.amountCents ?? 0) / 100).toFixed(2),\n String(deal.currency || currency).toUpperCase(),\n ])\n }\n disabled={!dealsRead}\n caption={\n dealWindow.truncated\n ? `Ranked within the ${OPEN_DEAL_CEILING.toLocaleString()} most recently updated open deals.`\n : undefined\n }\n />\n </Section>\n ) : null}\n </Stack>\n </CardDisplay>\n )\n}\nPipelineCard.displayName = 'PipelineCard'\n\nexport default PipelineCard\n"],"names":["Aglyn","money","AppLink","CardDisplay","Section","ScrollTable","Alert","Stack","TableBody","TableCell","TableHead","TableRow","Typography","count","getAggregateFromServer","limit","orderBy","query","sum","where","useMemo","useFirestore","collectionCeiling","ReportBreakdown","ReportExport","plural","reportFilename","shortDate","reportCacheKey","scopedCollection","visibleToClause","ReportStatTile","useAggregateRead","useWindowRead","OPEN_DEAL_CEILING","PIPELINE_CEILING","TOP_DEALS","TOP_DEAL_COLUMNS","PipelineCard","props","report","scope","tokens","routes","nowMs","firestore","open","amountCents","then","snapshot","Number","data","cacheKey","dealWindow","pipelineWindow","dealsStatus","status","summary","byPipeline","Map","deal","rows","key","pipelineId","list","get","push","set","pipelines","filter","pipeline","isPipelineArchived","has","$id","map","totals","pipelineTotals","known","Set","orphans","stageName","dealStageById","find","stageId","name","top","sort","a","b","slice","orphanTotals","weightedCents","reduce","total","entry","currency","currencyOfDeals","stuck","stuckDeals","dealsRead","header","help","pluginDocsHelp","anchor","excerpt","contentGutterX","contentGutterY","spacing","direction","sx","flexWrap","label","value","toLocaleString","note","href","section","truncated","riseIsGood","color","undefined","severity","mixed","variant","toUpperCase","length","title","stages","row","stage","id","display","unplaced","emptyText","size","align","expectedCloseAtMs","String","filename","columns","Date","toISOString","toFixed","disabled","caption","displayName"],"mappings":"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"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
export interface ReportBarSeries {
|
|
2
|
+
/** What the legend and the tooltip call it. */
|
|
3
|
+
name: string;
|
|
4
|
+
/** A theme palette path — `primary.main`, `success.main` — never a literal. */
|
|
5
|
+
color: string;
|
|
6
|
+
/** One value per label, in label order. */
|
|
7
|
+
values: number[];
|
|
8
|
+
}
|
|
9
|
+
export interface ReportBarChartProps {
|
|
10
|
+
/** One label per bar group, under the bars. */
|
|
11
|
+
labels: string[];
|
|
12
|
+
series: ReportBarSeries[];
|
|
13
|
+
/** The tooltip for one bar; defaults to the value and the series name. */
|
|
14
|
+
format?: (value: number, seriesIndex: number, barIndex: number) => string;
|
|
15
|
+
/** Bar area height in pixels. */
|
|
16
|
+
height?: number;
|
|
17
|
+
/** What to say when there are no bars at all. */
|
|
18
|
+
emptyText?: string;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Bars over a set of labels, drawn the way the commerce analytics card
|
|
22
|
+
* draws its fourteen days: a row of flex boxes whose heights are a share of
|
|
23
|
+
* the tallest, painted from the theme's palette, with the value in the
|
|
24
|
+
* bar's title. No chart library — the console has never carried one, and a
|
|
25
|
+
* dependency pulled in to draw a dozen bars is a dependency every console
|
|
26
|
+
* page pays for.
|
|
27
|
+
*
|
|
28
|
+
* Every bar is present even when its value is zero, drawn faint and
|
|
29
|
+
* short rather than left out: a week with no new contacts is a fact the
|
|
30
|
+
* chart is there to show, and a missing bar is read as a missing week.
|
|
31
|
+
* Several series draw side by side inside each group, so "won" and "lost"
|
|
32
|
+
* for the same week sit next to each other rather than stacking into a total
|
|
33
|
+
* nobody asked for.
|
|
34
|
+
*/
|
|
35
|
+
export declare function ReportBarChart(props: ReportBarChartProps): import("react").JSX.Element;
|
|
36
|
+
export declare namespace ReportBarChart {
|
|
37
|
+
var displayName: string;
|
|
38
|
+
}
|
|
39
|
+
export default ReportBarChart;
|
|
@@ -0,0 +1,133 @@
|
|
|
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 { Box, Stack, Typography } from "@mui/material";
|
|
19
|
+
/**
|
|
20
|
+
* Bars over a set of labels, drawn the way the commerce analytics card
|
|
21
|
+
* draws its fourteen days: a row of flex boxes whose heights are a share of
|
|
22
|
+
* the tallest, painted from the theme's palette, with the value in the
|
|
23
|
+
* bar's title. No chart library — the console has never carried one, and a
|
|
24
|
+
* dependency pulled in to draw a dozen bars is a dependency every console
|
|
25
|
+
* page pays for.
|
|
26
|
+
*
|
|
27
|
+
* Every bar is present even when its value is zero, drawn faint and
|
|
28
|
+
* short rather than left out: a week with no new contacts is a fact the
|
|
29
|
+
* chart is there to show, and a missing bar is read as a missing week.
|
|
30
|
+
* Several series draw side by side inside each group, so "won" and "lost"
|
|
31
|
+
* for the same week sit next to each other rather than stacking into a total
|
|
32
|
+
* nobody asked for.
|
|
33
|
+
*/ export function ReportBarChart(props) {
|
|
34
|
+
const { labels, series, format = (value, seriesIndex)=>{
|
|
35
|
+
var _ref;
|
|
36
|
+
var _series_seriesIndex;
|
|
37
|
+
return `${(_ref = (_series_seriesIndex = series[seriesIndex]) == null ? void 0 : _series_seriesIndex.name) != null ? _ref : ''}: ${value.toLocaleString()}`;
|
|
38
|
+
}, height = 96, emptyText = 'Nothing in this period.' } = props;
|
|
39
|
+
if (!labels.length || !series.length) {
|
|
40
|
+
return /*#__PURE__*/ _jsx(Typography, {
|
|
41
|
+
variant: "body2",
|
|
42
|
+
color: "text.secondary",
|
|
43
|
+
children: emptyText
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
const max = Math.max(1, ...series.flatMap((one)=>one.values));
|
|
47
|
+
return /*#__PURE__*/ _jsxs(Stack, {
|
|
48
|
+
spacing: 0.5,
|
|
49
|
+
children: [
|
|
50
|
+
/*#__PURE__*/ _jsx(Box, {
|
|
51
|
+
role: "img",
|
|
52
|
+
"aria-label": series.map((one)=>one.name).join(' and '),
|
|
53
|
+
sx: {
|
|
54
|
+
display: 'flex',
|
|
55
|
+
gap: 0.75,
|
|
56
|
+
alignItems: 'flex-end',
|
|
57
|
+
height
|
|
58
|
+
},
|
|
59
|
+
children: labels.map((label, barIndex)=>/*#__PURE__*/ _jsx(Box, {
|
|
60
|
+
sx: {
|
|
61
|
+
flex: 1,
|
|
62
|
+
minWidth: 0,
|
|
63
|
+
height: '100%',
|
|
64
|
+
display: 'flex',
|
|
65
|
+
gap: 0.25,
|
|
66
|
+
alignItems: 'flex-end'
|
|
67
|
+
},
|
|
68
|
+
children: series.map((one, seriesIndex)=>{
|
|
69
|
+
var _one_values_barIndex;
|
|
70
|
+
const value = (_one_values_barIndex = one.values[barIndex]) != null ? _one_values_barIndex : 0;
|
|
71
|
+
return /*#__PURE__*/ _jsx(Box, {
|
|
72
|
+
title: `${format(value, seriesIndex, barIndex)} · ${label}`,
|
|
73
|
+
sx: {
|
|
74
|
+
flex: 1,
|
|
75
|
+
bgcolor: one.color,
|
|
76
|
+
opacity: value ? 0.9 : 0.25,
|
|
77
|
+
borderRadius: 0.5,
|
|
78
|
+
height: `${Math.max(4, Math.round(value / max * 100))}%`
|
|
79
|
+
}
|
|
80
|
+
}, one.name);
|
|
81
|
+
})
|
|
82
|
+
}, label + barIndex))
|
|
83
|
+
}),
|
|
84
|
+
/*#__PURE__*/ _jsx(Box, {
|
|
85
|
+
sx: {
|
|
86
|
+
display: 'flex',
|
|
87
|
+
gap: 0.75
|
|
88
|
+
},
|
|
89
|
+
children: labels.map((label, index)=>/*#__PURE__*/ _jsx(Typography, {
|
|
90
|
+
variant: "caption",
|
|
91
|
+
color: "text.secondary",
|
|
92
|
+
noWrap: true,
|
|
93
|
+
sx: {
|
|
94
|
+
flex: 1,
|
|
95
|
+
minWidth: 0,
|
|
96
|
+
textAlign: 'center'
|
|
97
|
+
},
|
|
98
|
+
children: label
|
|
99
|
+
}, label + index))
|
|
100
|
+
}),
|
|
101
|
+
series.length > 1 ? /*#__PURE__*/ _jsx(Stack, {
|
|
102
|
+
direction: "row",
|
|
103
|
+
spacing: 2,
|
|
104
|
+
children: series.map((one)=>/*#__PURE__*/ _jsxs(Stack, {
|
|
105
|
+
direction: "row",
|
|
106
|
+
spacing: 0.5,
|
|
107
|
+
sx: {
|
|
108
|
+
alignItems: 'center'
|
|
109
|
+
},
|
|
110
|
+
children: [
|
|
111
|
+
/*#__PURE__*/ _jsx(Box, {
|
|
112
|
+
sx: {
|
|
113
|
+
width: 10,
|
|
114
|
+
height: 10,
|
|
115
|
+
borderRadius: 0.5,
|
|
116
|
+
bgcolor: one.color
|
|
117
|
+
}
|
|
118
|
+
}),
|
|
119
|
+
/*#__PURE__*/ _jsx(Typography, {
|
|
120
|
+
variant: "caption",
|
|
121
|
+
color: "text.secondary",
|
|
122
|
+
children: one.name
|
|
123
|
+
})
|
|
124
|
+
]
|
|
125
|
+
}, one.name))
|
|
126
|
+
}) : null
|
|
127
|
+
]
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
ReportBarChart.displayName = 'ReportBarChart';
|
|
131
|
+
export default ReportBarChart;
|
|
132
|
+
|
|
133
|
+
//# sourceMappingURL=report-bar-chart.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../../libs/plugins/crm/src/lib/components/reports/report-bar-chart.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 { Box, Stack, Typography } from '@mui/material'\n\nexport interface ReportBarSeries {\n /** What the legend and the tooltip call it. */\n name: string\n /** A theme palette path — `primary.main`, `success.main` — never a literal. */\n color: string\n /** One value per label, in label order. */\n values: number[]\n}\n\nexport interface ReportBarChartProps {\n /** One label per bar group, under the bars. */\n labels: string[]\n series: ReportBarSeries[]\n /** The tooltip for one bar; defaults to the value and the series name. */\n format?: (value: number, seriesIndex: number, barIndex: number) => string\n /** Bar area height in pixels. */\n height?: number\n /** What to say when there are no bars at all. */\n emptyText?: string\n}\n\n/**\n * Bars over a set of labels, drawn the way the commerce analytics card\n * draws its fourteen days: a row of flex boxes whose heights are a share of\n * the tallest, painted from the theme's palette, with the value in the\n * bar's title. No chart library — the console has never carried one, and a\n * dependency pulled in to draw a dozen bars is a dependency every console\n * page pays for.\n *\n * Every bar is present even when its value is zero, drawn faint and\n * short rather than left out: a week with no new contacts is a fact the\n * chart is there to show, and a missing bar is read as a missing week.\n * Several series draw side by side inside each group, so \"won\" and \"lost\"\n * for the same week sit next to each other rather than stacking into a total\n * nobody asked for.\n */\nexport function ReportBarChart(props: ReportBarChartProps) {\n const {\n labels,\n series,\n format = (value, seriesIndex) =>\n `${series[seriesIndex]?.name ?? ''}: ${value.toLocaleString()}`,\n height = 96,\n emptyText = 'Nothing in this period.',\n } = props\n if (!labels.length || !series.length) {\n return (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {emptyText}\n </Typography>\n )\n }\n const max = Math.max(1, ...series.flatMap((one) => one.values))\n return (\n <Stack spacing={0.5}>\n <Box\n role=\"img\"\n aria-label={series.map((one) => one.name).join(' and ')}\n sx={{ display: 'flex', gap: 0.75, alignItems: 'flex-end', height }}\n >\n {labels.map((label, barIndex) => (\n <Box\n key={label + barIndex}\n sx={{\n flex: 1,\n minWidth: 0,\n height: '100%',\n display: 'flex',\n gap: 0.25,\n alignItems: 'flex-end',\n }}\n >\n {series.map((one, seriesIndex) => {\n const value = one.values[barIndex] ?? 0\n return (\n <Box\n key={one.name}\n title={`${format(value, seriesIndex, barIndex)} · ${label}`}\n sx={{\n flex: 1,\n bgcolor: one.color,\n opacity: value ? 0.9 : 0.25,\n borderRadius: 0.5,\n height: `${Math.max(4, Math.round((value / max) * 100))}%`,\n }}\n />\n )\n })}\n </Box>\n ))}\n </Box>\n <Box sx={{ display: 'flex', gap: 0.75 }}>\n {labels.map((label, index) => (\n <Typography\n key={label + index}\n variant=\"caption\"\n color=\"text.secondary\"\n noWrap\n sx={{ flex: 1, minWidth: 0, textAlign: 'center' }}\n >\n {label}\n </Typography>\n ))}\n </Box>\n {series.length > 1 ? (\n <Stack direction=\"row\" spacing={2}>\n {series.map((one) => (\n <Stack\n key={one.name}\n direction=\"row\"\n spacing={0.5}\n sx={{ alignItems: 'center' }}\n >\n <Box\n sx={{\n width: 10,\n height: 10,\n borderRadius: 0.5,\n bgcolor: one.color,\n }}\n />\n <Typography variant=\"caption\" color=\"text.secondary\">\n {one.name}\n </Typography>\n </Stack>\n ))}\n </Stack>\n ) : null}\n </Stack>\n )\n}\nReportBarChart.displayName = 'ReportBarChart'\n\nexport default ReportBarChart\n"],"names":["Box","Stack","Typography","ReportBarChart","props","labels","series","format","value","seriesIndex","name","toLocaleString","height","emptyText","length","variant","color","max","Math","flatMap","one","values","spacing","role","aria-label","map","join","sx","display","gap","alignItems","label","barIndex","flex","minWidth","title","bgcolor","opacity","borderRadius","round","index","noWrap","textAlign","direction","width","displayName"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GACD;;AAEA,SAASA,GAAG,EAAEC,KAAK,EAAEC,UAAU,QAAQ,gBAAe;AAuBtD;;;;;;;;;;;;;;CAcC,GACD,OAAO,SAASC,eAAeC,KAA0B;IACvD,MAAM,EACJC,MAAM,EACNC,MAAM,EACNC,SAAS,CAACC,OAAOC;;YACZH;eAAH,YAAGA,sBAAAA,MAAM,CAACG,YAAY,qBAAnBH,oBAAqBI,IAAI,mBAAI,GAAG,EAAE,EAAEF,MAAMG,cAAc,IAAI;KAAA,EACjEC,SAAS,EAAE,EACXC,YAAY,yBAAyB,EACtC,GAAGT;IACJ,IAAI,CAACC,OAAOS,MAAM,IAAI,CAACR,OAAOQ,MAAM,EAAE;QACpC,qBACE,KAACZ;YAAWa,SAAQ;YAAQC,OAAM;sBAC/BH;;IAGP;IACA,MAAMI,MAAMC,KAAKD,GAAG,CAAC,MAAMX,OAAOa,OAAO,CAAC,CAACC,MAAQA,IAAIC,MAAM;IAC7D,qBACE,MAACpB;QAAMqB,SAAS;;0BACd,KAACtB;gBACCuB,MAAK;gBACLC,cAAYlB,OAAOmB,GAAG,CAAC,CAACL,MAAQA,IAAIV,IAAI,EAAEgB,IAAI,CAAC;gBAC/CC,IAAI;oBAAEC,SAAS;oBAAQC,KAAK;oBAAMC,YAAY;oBAAYlB;gBAAO;0BAEhEP,OAAOoB,GAAG,CAAC,CAACM,OAAOC,yBAClB,KAAChC;wBAEC2B,IAAI;4BACFM,MAAM;4BACNC,UAAU;4BACVtB,QAAQ;4BACRgB,SAAS;4BACTC,KAAK;4BACLC,YAAY;wBACd;kCAECxB,OAAOmB,GAAG,CAAC,CAACL,KAAKX;gCACFW;4BAAd,MAAMZ,SAAQY,uBAAAA,IAAIC,MAAM,CAACW,SAAS,YAApBZ,uBAAwB;4BACtC,qBACE,KAACpB;gCAECmC,OAAO,GAAG5B,OAAOC,OAAOC,aAAauB,UAAU,GAAG,EAAED,OAAO;gCAC3DJ,IAAI;oCACFM,MAAM;oCACNG,SAAShB,IAAIJ,KAAK;oCAClBqB,SAAS7B,QAAQ,MAAM;oCACvB8B,cAAc;oCACd1B,QAAQ,GAAGM,KAAKD,GAAG,CAAC,GAAGC,KAAKqB,KAAK,CAAC,AAAC/B,QAAQS,MAAO,MAAM,CAAC,CAAC;gCAC5D;+BARKG,IAAIV,IAAI;wBAWnB;uBAzBKqB,QAAQC;;0BA6BnB,KAAChC;gBAAI2B,IAAI;oBAAEC,SAAS;oBAAQC,KAAK;gBAAK;0BACnCxB,OAAOoB,GAAG,CAAC,CAACM,OAAOS,sBAClB,KAACtC;wBAECa,SAAQ;wBACRC,OAAM;wBACNyB,MAAM;wBACNd,IAAI;4BAAEM,MAAM;4BAAGC,UAAU;4BAAGQ,WAAW;wBAAS;kCAE/CX;uBANIA,QAAQS;;YAUlBlC,OAAOQ,MAAM,GAAG,kBACf,KAACb;gBAAM0C,WAAU;gBAAMrB,SAAS;0BAC7BhB,OAAOmB,GAAG,CAAC,CAACL,oBACX,MAACnB;wBAEC0C,WAAU;wBACVrB,SAAS;wBACTK,IAAI;4BAAEG,YAAY;wBAAS;;0CAE3B,KAAC9B;gCACC2B,IAAI;oCACFiB,OAAO;oCACPhC,QAAQ;oCACR0B,cAAc;oCACdF,SAAShB,IAAIJ,KAAK;gCACpB;;0CAEF,KAACd;gCAAWa,SAAQ;gCAAUC,OAAM;0CACjCI,IAAIV,IAAI;;;uBAdNU,IAAIV,IAAI;iBAmBjB;;;AAGV;AACAP,eAAe0C,WAAW,GAAG;AAE7B,eAAe1C,eAAc"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export interface ReportBreakdownRow {
|
|
2
|
+
key: string;
|
|
3
|
+
label: string;
|
|
4
|
+
/** What the bar's length is a share of the largest of. */
|
|
5
|
+
value: number;
|
|
6
|
+
/** The figure on the right; the value itself when omitted. */
|
|
7
|
+
display?: string;
|
|
8
|
+
/** A line under the label — a count, a rate with its denominator. */
|
|
9
|
+
note?: string;
|
|
10
|
+
/** A theme palette path; `primary.main` when omitted. */
|
|
11
|
+
color?: string;
|
|
12
|
+
}
|
|
13
|
+
export interface ReportBreakdownProps {
|
|
14
|
+
rows: ReportBreakdownRow[];
|
|
15
|
+
emptyText: string;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* One horizontal bar per category — contacts by source, deals by stage,
|
|
19
|
+
* the lifecycle funnel — each labeled, each with its figure at the end of
|
|
20
|
+
* the row.
|
|
21
|
+
*
|
|
22
|
+
* Horizontal rather than the vertical bars of the trend chart because the
|
|
23
|
+
* categories have NAMES, and a name under a thin vertical bar truncates
|
|
24
|
+
* while a name beside a horizontal one reads. The bar is a share of the
|
|
25
|
+
* largest row, not of the total, so a funnel's top step is always the full
|
|
26
|
+
* width and every step below it is visibly a fraction of the one above.
|
|
27
|
+
*/
|
|
28
|
+
export declare function ReportBreakdown(props: ReportBreakdownProps): import("react").JSX.Element;
|
|
29
|
+
export declare namespace ReportBreakdown {
|
|
30
|
+
var displayName: string;
|
|
31
|
+
}
|
|
32
|
+
export default ReportBreakdown;
|