@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,405 @@
|
|
|
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, Fragment as _Fragment } from "react/jsx-runtime";
|
|
19
|
+
import { contactDisplayName, contactMergePreview, nameSearchKey, normalizeContactEmail } from "@aglyn/aglyn";
|
|
20
|
+
import { useSnackbar } from "@aglyn/shared-ui-snackstack";
|
|
21
|
+
import { useFirestore } from "@aglyn/tenant-feature-instance";
|
|
22
|
+
import { ScrollTable } from "@aglyn/shared-ui-jsx/components/scroll-table.component";
|
|
23
|
+
import { Alert, Button, Dialog, DialogActions, DialogContent, DialogTitle, FormControl, FormControlLabel, FormLabel, List, ListItemButton, ListItemText, Radio, RadioGroup, Stack, TableBody, TableCell, TableHead, TableRow, TextField, Typography } from "@mui/material";
|
|
24
|
+
import { collection, endAt, getDocs, limit, orderBy, query, startAt, where } from "firebase/firestore";
|
|
25
|
+
import { useCallback, useEffect, useMemo, useState } from "react";
|
|
26
|
+
import { useCrmOrgMount } from "../hooks/use-crm-org-mount.js";
|
|
27
|
+
import { crmVisibleToClause } from "../hooks/use-crm-scope.js";
|
|
28
|
+
import { useCrmApi } from "./use-crm-api.js";
|
|
29
|
+
/** How many rows a search answers — a picker, not a list. */ const SEARCH_LIMIT = 8;
|
|
30
|
+
/** The high code point that closes a `nameLower` prefix range. */ const HIGH = '';
|
|
31
|
+
/**
|
|
32
|
+
* The dialog's open state, held by the page so two openers — the record's
|
|
33
|
+
* overflow menu and the likely-duplicates card — share one dialog.
|
|
34
|
+
*
|
|
35
|
+
* The menu opens it empty, to be searched, with the OTHER record surviving:
|
|
36
|
+
* "merge this into…" is what a reader means when they are on the record
|
|
37
|
+
* they want gone. The duplicates card opens it with the candidate already
|
|
38
|
+
* picked and THIS record surviving: the reader is on the record they keep,
|
|
39
|
+
* looking at the copies. Either way the dialog lets them switch.
|
|
40
|
+
*/ export function useContactMergeDialog() {
|
|
41
|
+
const [state, setState] = useState({
|
|
42
|
+
open: false,
|
|
43
|
+
other: null,
|
|
44
|
+
keep: 'other'
|
|
45
|
+
});
|
|
46
|
+
const open = useCallback((options = {})=>{
|
|
47
|
+
var _options_other, _options_keep;
|
|
48
|
+
return setState({
|
|
49
|
+
open: true,
|
|
50
|
+
other: (_options_other = options.other) != null ? _options_other : null,
|
|
51
|
+
keep: (_options_keep = options.keep) != null ? _options_keep : options.other ? 'current' : 'other'
|
|
52
|
+
});
|
|
53
|
+
}, []);
|
|
54
|
+
const close = useCallback(()=>setState((previous)=>_extends({}, previous, {
|
|
55
|
+
open: false
|
|
56
|
+
})), []);
|
|
57
|
+
return {
|
|
58
|
+
state,
|
|
59
|
+
open,
|
|
60
|
+
close
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
const label = (pick, groupId)=>{
|
|
64
|
+
var _pick_doc_email;
|
|
65
|
+
return contactDisplayName(pick.doc, groupId) || String((_pick_doc_email = pick.doc['email']) != null ? _pick_doc_email : pick.id);
|
|
66
|
+
};
|
|
67
|
+
/**
|
|
68
|
+
* MERGE TWO RECORDS FOR ONE PERSON (AGL-2625).
|
|
69
|
+
*
|
|
70
|
+
* Two steps in one dialog. First the OTHER record, found by address or by
|
|
71
|
+
* name among the contacts this viewer may list — the same two searches the
|
|
72
|
+
* company's contacts card runs, one read each, on ask. Then the two records
|
|
73
|
+
* side by side, field by field, with the value the surviving record will
|
|
74
|
+
* carry and where it came from — `contactMergePreview` is the same rule the
|
|
75
|
+
* server writes with, so what the reader is shown is what lands.
|
|
76
|
+
*
|
|
77
|
+
* The reader picks which record survives. The survivor keeps its address;
|
|
78
|
+
* the other record's address becomes an alternate on it, its deals, tasks,
|
|
79
|
+
* activities and leads move, and the document is deleted. The act is one
|
|
80
|
+
* server route, because it is one transaction over two documents and a
|
|
81
|
+
* repoint of rows a browser may not be able to list.
|
|
82
|
+
*/ export function ContactMergeDialog(props) {
|
|
83
|
+
var _current_doc_email, _other_doc_email;
|
|
84
|
+
const { open, onClose, hostId, current, scope, consentGroup, visibleTo, memberName, onMerged } = props;
|
|
85
|
+
const firestore = useFirestore();
|
|
86
|
+
const callCrm = useCrmApi(hostId);
|
|
87
|
+
const { enqueueSnackbar } = useSnackbar();
|
|
88
|
+
const groupId = consentGroup.groupId;
|
|
89
|
+
const orgMount = useCrmOrgMount();
|
|
90
|
+
// A site to run as, or the org to run as (AGL-2634): one of the two is
|
|
91
|
+
// what the route authorizes against, and with neither there is no door.
|
|
92
|
+
const canMerge = Boolean(hostId) || Boolean(orgMount);
|
|
93
|
+
const [other, setOther] = useState(props.other);
|
|
94
|
+
const [keep, setKeep] = useState(props.keep);
|
|
95
|
+
const [term, setTerm] = useState('');
|
|
96
|
+
const [searching, setSearching] = useState(false);
|
|
97
|
+
const [results, setResults] = useState(null);
|
|
98
|
+
const [busy, setBusy] = useState(false);
|
|
99
|
+
const [error, setError] = useState(null);
|
|
100
|
+
// Reset on every open to what the opener handed over.
|
|
101
|
+
useEffect(()=>{
|
|
102
|
+
if (!open) return;
|
|
103
|
+
setOther(props.other);
|
|
104
|
+
setKeep(props.keep);
|
|
105
|
+
setTerm('');
|
|
106
|
+
setResults(null);
|
|
107
|
+
setError(null);
|
|
108
|
+
setBusy(false);
|
|
109
|
+
}, [
|
|
110
|
+
open,
|
|
111
|
+
props.other,
|
|
112
|
+
props.keep
|
|
113
|
+
]);
|
|
114
|
+
const search = useCallback(async ()=>{
|
|
115
|
+
const raw = term.trim();
|
|
116
|
+
if (!raw || searching) return;
|
|
117
|
+
setSearching(true);
|
|
118
|
+
setError(null);
|
|
119
|
+
try {
|
|
120
|
+
const contactsRef = collection(firestore, scope[0], scope[1], 'contacts');
|
|
121
|
+
const scoped = crmVisibleToClause(visibleTo);
|
|
122
|
+
let found;
|
|
123
|
+
if (raw.includes('@')) {
|
|
124
|
+
const email = normalizeContactEmail(raw);
|
|
125
|
+
if (!email) {
|
|
126
|
+
setResults([]);
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
found = await getDocs(query(contactsRef, ...scoped, where('email', '==', email), limit(SEARCH_LIMIT)));
|
|
130
|
+
} else {
|
|
131
|
+
const key = nameSearchKey(raw);
|
|
132
|
+
found = await getDocs(query(contactsRef, ...scoped, orderBy('nameLower'), startAt(key), endAt(`${key}${HIGH}`), limit(SEARCH_LIMIT)));
|
|
133
|
+
}
|
|
134
|
+
setResults(found.docs.filter((snapshot)=>snapshot.id !== current.id).map((snapshot)=>({
|
|
135
|
+
id: snapshot.id,
|
|
136
|
+
doc: snapshot.data()
|
|
137
|
+
})));
|
|
138
|
+
} catch (searchError) {
|
|
139
|
+
console.error(searchError);
|
|
140
|
+
setResults(null);
|
|
141
|
+
setError('The search could not be run.');
|
|
142
|
+
} finally{
|
|
143
|
+
setSearching(false);
|
|
144
|
+
}
|
|
145
|
+
}, [
|
|
146
|
+
term,
|
|
147
|
+
searching,
|
|
148
|
+
firestore,
|
|
149
|
+
scope,
|
|
150
|
+
visibleTo,
|
|
151
|
+
current.id
|
|
152
|
+
]);
|
|
153
|
+
const survivor = keep === 'current' ? current : other;
|
|
154
|
+
const merged = keep === 'current' ? other : current;
|
|
155
|
+
const rows = useMemo(()=>survivor && merged ? contactMergePreview(survivor.doc, merged.doc, groupId, {
|
|
156
|
+
memberName
|
|
157
|
+
}) : [], [
|
|
158
|
+
survivor,
|
|
159
|
+
merged,
|
|
160
|
+
groupId,
|
|
161
|
+
memberName
|
|
162
|
+
]);
|
|
163
|
+
const submit = useCallback(async ()=>{
|
|
164
|
+
if (!survivor || !merged || busy || !canMerge) return;
|
|
165
|
+
setBusy(true);
|
|
166
|
+
setError(null);
|
|
167
|
+
try {
|
|
168
|
+
const { response, payload } = await callCrm('contacts-merge', {
|
|
169
|
+
survivorId: survivor.id,
|
|
170
|
+
mergedId: merged.id
|
|
171
|
+
});
|
|
172
|
+
if (!response.ok) {
|
|
173
|
+
var _payload_error;
|
|
174
|
+
setError(String((_payload_error = payload['error']) != null ? _payload_error : 'The contacts could not be merged.'));
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
enqueueSnackbar('Contacts merged', {
|
|
178
|
+
variant: 'success',
|
|
179
|
+
persist: false
|
|
180
|
+
});
|
|
181
|
+
onClose();
|
|
182
|
+
onMerged == null ? void 0 : onMerged(survivor.id);
|
|
183
|
+
} catch (submitError) {
|
|
184
|
+
console.error(submitError);
|
|
185
|
+
setError('The contacts could not be merged.');
|
|
186
|
+
} finally{
|
|
187
|
+
setBusy(false);
|
|
188
|
+
}
|
|
189
|
+
}, [
|
|
190
|
+
survivor,
|
|
191
|
+
merged,
|
|
192
|
+
busy,
|
|
193
|
+
canMerge,
|
|
194
|
+
callCrm,
|
|
195
|
+
enqueueSnackbar,
|
|
196
|
+
onClose,
|
|
197
|
+
onMerged
|
|
198
|
+
]);
|
|
199
|
+
const currentLabel = label(current, groupId);
|
|
200
|
+
const otherLabel = other ? label(other, groupId) : '';
|
|
201
|
+
return /*#__PURE__*/ _jsxs(Dialog, {
|
|
202
|
+
open: open,
|
|
203
|
+
onClose: busy ? undefined : onClose,
|
|
204
|
+
maxWidth: "md",
|
|
205
|
+
fullWidth: true,
|
|
206
|
+
children: [
|
|
207
|
+
/*#__PURE__*/ _jsx(DialogTitle, {
|
|
208
|
+
children: 'Merge contacts'
|
|
209
|
+
}),
|
|
210
|
+
/*#__PURE__*/ _jsx(DialogContent, {
|
|
211
|
+
children: /*#__PURE__*/ _jsxs(Stack, {
|
|
212
|
+
spacing: 2,
|
|
213
|
+
sx: {
|
|
214
|
+
pt: 1
|
|
215
|
+
},
|
|
216
|
+
children: [
|
|
217
|
+
!other ? /*#__PURE__*/ _jsxs(_Fragment, {
|
|
218
|
+
children: [
|
|
219
|
+
/*#__PURE__*/ _jsx(Typography, {
|
|
220
|
+
variant: "body2",
|
|
221
|
+
color: "text.secondary",
|
|
222
|
+
children: `Find the other record for ${currentLabel} — by email address, or by name.`
|
|
223
|
+
}),
|
|
224
|
+
/*#__PURE__*/ _jsxs(Stack, {
|
|
225
|
+
direction: "row",
|
|
226
|
+
spacing: 1,
|
|
227
|
+
sx: {
|
|
228
|
+
alignItems: 'flex-start'
|
|
229
|
+
},
|
|
230
|
+
children: [
|
|
231
|
+
/*#__PURE__*/ _jsx(TextField, {
|
|
232
|
+
label: "Email or name",
|
|
233
|
+
value: term,
|
|
234
|
+
onChange: (event)=>setTerm(event.target.value),
|
|
235
|
+
onKeyDown: (event)=>{
|
|
236
|
+
if (event.key === 'Enter') {
|
|
237
|
+
event.preventDefault();
|
|
238
|
+
void search();
|
|
239
|
+
}
|
|
240
|
+
},
|
|
241
|
+
size: "small",
|
|
242
|
+
fullWidth: true,
|
|
243
|
+
autoFocus: true
|
|
244
|
+
}),
|
|
245
|
+
/*#__PURE__*/ _jsx(Button, {
|
|
246
|
+
variant: "outlined",
|
|
247
|
+
onClick: ()=>void search(),
|
|
248
|
+
disabled: !term.trim() || searching,
|
|
249
|
+
children: searching ? 'Searching…' : 'Search'
|
|
250
|
+
})
|
|
251
|
+
]
|
|
252
|
+
}),
|
|
253
|
+
results ? results.length ? /*#__PURE__*/ _jsx(List, {
|
|
254
|
+
dense: true,
|
|
255
|
+
disablePadding: true,
|
|
256
|
+
"aria-label": "Matching contacts",
|
|
257
|
+
children: results.map((pick)=>{
|
|
258
|
+
var _pick_doc_email;
|
|
259
|
+
return /*#__PURE__*/ _jsx(ListItemButton, {
|
|
260
|
+
onClick: ()=>setOther(pick),
|
|
261
|
+
children: /*#__PURE__*/ _jsx(ListItemText, {
|
|
262
|
+
primary: label(pick, groupId),
|
|
263
|
+
secondary: String((_pick_doc_email = pick.doc['email']) != null ? _pick_doc_email : '')
|
|
264
|
+
})
|
|
265
|
+
}, pick.id);
|
|
266
|
+
})
|
|
267
|
+
}) : /*#__PURE__*/ _jsx(Typography, {
|
|
268
|
+
variant: "body2",
|
|
269
|
+
color: "text.secondary",
|
|
270
|
+
children: 'No other contact matches among the ones you can see.'
|
|
271
|
+
}) : null
|
|
272
|
+
]
|
|
273
|
+
}) : /*#__PURE__*/ _jsxs(_Fragment, {
|
|
274
|
+
children: [
|
|
275
|
+
/*#__PURE__*/ _jsxs(FormControl, {
|
|
276
|
+
children: [
|
|
277
|
+
/*#__PURE__*/ _jsx(FormLabel, {
|
|
278
|
+
id: "contact-merge-keep",
|
|
279
|
+
children: 'Keep'
|
|
280
|
+
}),
|
|
281
|
+
/*#__PURE__*/ _jsxs(RadioGroup, {
|
|
282
|
+
"aria-labelledby": "contact-merge-keep",
|
|
283
|
+
value: keep,
|
|
284
|
+
onChange: (event)=>setKeep(event.target.value),
|
|
285
|
+
children: [
|
|
286
|
+
/*#__PURE__*/ _jsx(FormControlLabel, {
|
|
287
|
+
value: "current",
|
|
288
|
+
control: /*#__PURE__*/ _jsx(Radio, {
|
|
289
|
+
size: "small"
|
|
290
|
+
}),
|
|
291
|
+
label: `${currentLabel} (${String((_current_doc_email = current.doc['email']) != null ? _current_doc_email : '')})`
|
|
292
|
+
}),
|
|
293
|
+
/*#__PURE__*/ _jsx(FormControlLabel, {
|
|
294
|
+
value: "other",
|
|
295
|
+
control: /*#__PURE__*/ _jsx(Radio, {
|
|
296
|
+
size: "small"
|
|
297
|
+
}),
|
|
298
|
+
label: `${otherLabel} (${String((_other_doc_email = other.doc['email']) != null ? _other_doc_email : '')})`
|
|
299
|
+
})
|
|
300
|
+
]
|
|
301
|
+
})
|
|
302
|
+
]
|
|
303
|
+
}),
|
|
304
|
+
/*#__PURE__*/ _jsx(Typography, {
|
|
305
|
+
variant: "body2",
|
|
306
|
+
color: "text.secondary",
|
|
307
|
+
children: 'The kept record keeps every value it has; empty fields fill from the ' + 'other record. Tags, filings and the timeline are combined, and the ' + "other record's deals, tasks, activities and leads move across. Its " + 'address becomes an alternate on the kept record, so a later capture ' + 'on it lands here — and the other record is deleted.'
|
|
308
|
+
}),
|
|
309
|
+
/*#__PURE__*/ _jsxs(ScrollTable, {
|
|
310
|
+
size: "small",
|
|
311
|
+
"aria-label": "What the merge keeps",
|
|
312
|
+
children: [
|
|
313
|
+
/*#__PURE__*/ _jsx(TableHead, {
|
|
314
|
+
children: /*#__PURE__*/ _jsxs(TableRow, {
|
|
315
|
+
children: [
|
|
316
|
+
/*#__PURE__*/ _jsx(TableCell, {
|
|
317
|
+
children: 'Field'
|
|
318
|
+
}),
|
|
319
|
+
/*#__PURE__*/ _jsx(TableCell, {
|
|
320
|
+
children: 'Kept'
|
|
321
|
+
}),
|
|
322
|
+
/*#__PURE__*/ _jsx(TableCell, {
|
|
323
|
+
children: 'Merged'
|
|
324
|
+
}),
|
|
325
|
+
/*#__PURE__*/ _jsx(TableCell, {
|
|
326
|
+
children: 'After'
|
|
327
|
+
})
|
|
328
|
+
]
|
|
329
|
+
})
|
|
330
|
+
}),
|
|
331
|
+
/*#__PURE__*/ _jsx(TableBody, {
|
|
332
|
+
children: rows.map((row)=>/*#__PURE__*/ _jsxs(TableRow, {
|
|
333
|
+
children: [
|
|
334
|
+
/*#__PURE__*/ _jsx(TableCell, {
|
|
335
|
+
component: "th",
|
|
336
|
+
scope: "row",
|
|
337
|
+
children: row.label
|
|
338
|
+
}),
|
|
339
|
+
/*#__PURE__*/ _jsx(TableCell, {
|
|
340
|
+
sx: {
|
|
341
|
+
whiteSpace: 'pre-wrap'
|
|
342
|
+
},
|
|
343
|
+
children: row.survivor
|
|
344
|
+
}),
|
|
345
|
+
/*#__PURE__*/ _jsx(TableCell, {
|
|
346
|
+
sx: {
|
|
347
|
+
whiteSpace: 'pre-wrap'
|
|
348
|
+
},
|
|
349
|
+
children: row.merged
|
|
350
|
+
}),
|
|
351
|
+
/*#__PURE__*/ _jsx(TableCell, {
|
|
352
|
+
sx: {
|
|
353
|
+
whiteSpace: 'pre-wrap',
|
|
354
|
+
fontWeight: row.from === 'merged' || row.from === 'both' ? 600 : undefined
|
|
355
|
+
},
|
|
356
|
+
children: row.result
|
|
357
|
+
})
|
|
358
|
+
]
|
|
359
|
+
}, row.key))
|
|
360
|
+
})
|
|
361
|
+
]
|
|
362
|
+
}),
|
|
363
|
+
!props.other ? /*#__PURE__*/ _jsx(Button, {
|
|
364
|
+
size: "small",
|
|
365
|
+
onClick: ()=>setOther(null),
|
|
366
|
+
sx: {
|
|
367
|
+
alignSelf: 'flex-start'
|
|
368
|
+
},
|
|
369
|
+
children: 'Pick a different contact'
|
|
370
|
+
}) : null
|
|
371
|
+
]
|
|
372
|
+
}),
|
|
373
|
+
error ? /*#__PURE__*/ _jsx(Alert, {
|
|
374
|
+
severity: "error",
|
|
375
|
+
children: error
|
|
376
|
+
}) : null,
|
|
377
|
+
!canMerge ? /*#__PURE__*/ _jsx(Alert, {
|
|
378
|
+
severity: "info",
|
|
379
|
+
children: 'No site has captured this contact, so there is no site to ' + 'merge it from. Open it from one of your sites instead.'
|
|
380
|
+
}) : null
|
|
381
|
+
]
|
|
382
|
+
})
|
|
383
|
+
}),
|
|
384
|
+
/*#__PURE__*/ _jsxs(DialogActions, {
|
|
385
|
+
children: [
|
|
386
|
+
/*#__PURE__*/ _jsx(Button, {
|
|
387
|
+
onClick: onClose,
|
|
388
|
+
disabled: busy,
|
|
389
|
+
children: 'Cancel'
|
|
390
|
+
}),
|
|
391
|
+
/*#__PURE__*/ _jsx(Button, {
|
|
392
|
+
variant: "contained",
|
|
393
|
+
onClick: ()=>void submit(),
|
|
394
|
+
disabled: !other || busy || !canMerge,
|
|
395
|
+
children: busy ? 'Merging…' : 'Merge'
|
|
396
|
+
})
|
|
397
|
+
]
|
|
398
|
+
})
|
|
399
|
+
]
|
|
400
|
+
});
|
|
401
|
+
}
|
|
402
|
+
ContactMergeDialog.displayName = 'ContactMergeDialog';
|
|
403
|
+
export default ContactMergeDialog;
|
|
404
|
+
|
|
405
|
+
//# sourceMappingURL=contact-merge-dialog.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/crm/src/lib/components/contact-merge-dialog.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 {\n type ConsentGroup,\n type ContactMergePreviewRow,\n contactDisplayName,\n contactMergePreview,\n nameSearchKey,\n normalizeContactEmail,\n} from '@aglyn/aglyn'\nimport { useSnackbar } from '@aglyn/shared-ui-snackstack'\nimport { useFirestore } from '@aglyn/tenant-feature-instance'\nimport { ScrollTable } from '@aglyn/shared-ui-jsx/components/scroll-table.component'\nimport {\n Alert,\n Button,\n Dialog,\n DialogActions,\n DialogContent,\n DialogTitle,\n FormControl,\n FormControlLabel,\n FormLabel,\n List,\n ListItemButton,\n ListItemText,\n Radio,\n RadioGroup,\n Stack,\n TableBody,\n TableCell,\n TableHead,\n TableRow,\n TextField,\n Typography,\n} from '@mui/material'\nimport {\n collection,\n endAt,\n getDocs,\n limit,\n orderBy,\n query,\n startAt,\n where,\n} from 'firebase/firestore'\nimport { useCallback, useEffect, useMemo, useState } from 'react'\nimport { useCrmOrgMount } from '../hooks/use-crm-org-mount'\nimport { crmVisibleToClause } from '../hooks/use-crm-scope'\nimport { useCrmApi } from './use-crm-api'\n\n/** One contact as the dialog holds it: its id and the document as read. */\nexport interface ContactPick {\n id: string\n doc: Record<string, unknown>\n}\n\n/** Which of the two records stays. */\nexport type ContactMergeKeep = 'current' | 'other'\n\n/** How many rows a search answers — a picker, not a list. */\nconst SEARCH_LIMIT = 8\n/** The high code point that closes a `nameLower` prefix range. */\nconst HIGH = ''\n\nexport interface ContactMergeDialogState {\n open: boolean\n /** The record to merge with, when the opener already knows it. */\n other: ContactPick | null\n keep: ContactMergeKeep\n}\n\n/**\n * The dialog's open state, held by the page so two openers — the record's\n * overflow menu and the likely-duplicates card — share one dialog.\n *\n * The menu opens it empty, to be searched, with the OTHER record surviving:\n * \"merge this into…\" is what a reader means when they are on the record\n * they want gone. The duplicates card opens it with the candidate already\n * picked and THIS record surviving: the reader is on the record they keep,\n * looking at the copies. Either way the dialog lets them switch.\n */\nexport function useContactMergeDialog() {\n const [state, setState] = useState<ContactMergeDialogState>({\n open: false,\n other: null,\n keep: 'other',\n })\n const open = useCallback(\n (options: { other?: ContactPick; keep?: ContactMergeKeep } = {}) =>\n setState({\n open: true,\n other: options.other ?? null,\n keep: options.keep ?? (options.other ? 'current' : 'other'),\n }),\n [],\n )\n const close = useCallback(\n () => setState((previous) => ({ ...previous, open: false })),\n [],\n )\n return { state, open, close }\n}\n\nexport interface ContactMergeDialogProps extends ContactMergeDialogState {\n onClose: () => void\n /**\n * The site the merge runs as — the route logs it on that site's feed. At\n * the organization level the record's own capturing site (AGL-2630), or\n * `null` for a row no site has captured: beneath the org hub's mount the\n * route's org variant merges it anyway (AGL-2634), and only a surface\n * mounted nowhere holds the button.\n */\n hostId: string | null\n /** The record whose page this is. */\n current: ContactPick\n /** `['orgs', orgId]` — where the contacts live. */\n scope: readonly [string, string]\n consentGroup: ConsentGroup\n /**\n * What this viewer may list — the search's `array-contains-any` — or\n * `null` at the organization level, where the search carries no clause\n * (AGL-2630).\n */\n visibleTo: readonly string[] | null\n /** The owner's name for a uid, for the preview. */\n memberName?: (uid: string) => string\n /** Told which record survived, once the server has merged. */\n onMerged?: (survivorId: string) => void\n}\n\nconst label = (pick: ContactPick, groupId: string) =>\n contactDisplayName(pick.doc, groupId) || String(pick.doc['email'] ?? pick.id)\n\n/**\n * MERGE TWO RECORDS FOR ONE PERSON (AGL-2625).\n *\n * Two steps in one dialog. First the OTHER record, found by address or by\n * name among the contacts this viewer may list — the same two searches the\n * company's contacts card runs, one read each, on ask. Then the two records\n * side by side, field by field, with the value the surviving record will\n * carry and where it came from — `contactMergePreview` is the same rule the\n * server writes with, so what the reader is shown is what lands.\n *\n * The reader picks which record survives. The survivor keeps its address;\n * the other record's address becomes an alternate on it, its deals, tasks,\n * activities and leads move, and the document is deleted. The act is one\n * server route, because it is one transaction over two documents and a\n * repoint of rows a browser may not be able to list.\n */\nexport function ContactMergeDialog(props: ContactMergeDialogProps) {\n const {\n open,\n onClose,\n hostId,\n current,\n scope,\n consentGroup,\n visibleTo,\n memberName,\n onMerged,\n } = props\n const firestore = useFirestore()\n const callCrm = useCrmApi(hostId)\n const { enqueueSnackbar } = useSnackbar()\n const groupId = consentGroup.groupId\n const orgMount = useCrmOrgMount()\n // A site to run as, or the org to run as (AGL-2634): one of the two is\n // what the route authorizes against, and with neither there is no door.\n const canMerge = Boolean(hostId) || Boolean(orgMount)\n\n const [other, setOther] = useState<ContactPick | null>(props.other)\n const [keep, setKeep] = useState<ContactMergeKeep>(props.keep)\n const [term, setTerm] = useState('')\n const [searching, setSearching] = useState(false)\n const [results, setResults] = useState<ContactPick[] | null>(null)\n const [busy, setBusy] = useState(false)\n const [error, setError] = useState<string | null>(null)\n\n // Reset on every open to what the opener handed over.\n useEffect(() => {\n if (!open) return\n setOther(props.other)\n setKeep(props.keep)\n setTerm('')\n setResults(null)\n setError(null)\n setBusy(false)\n }, [open, props.other, props.keep])\n\n const search = useCallback(async () => {\n const raw = term.trim()\n if (!raw || searching) return\n setSearching(true)\n setError(null)\n try {\n const contactsRef = collection(firestore, scope[0], scope[1], 'contacts')\n const scoped = crmVisibleToClause(visibleTo)\n let found\n if (raw.includes('@')) {\n const email = normalizeContactEmail(raw)\n if (!email) {\n setResults([])\n return\n }\n found = await getDocs(\n query(contactsRef, ...scoped, where('email', '==', email), limit(SEARCH_LIMIT)),\n )\n } else {\n const key = nameSearchKey(raw)\n found = await getDocs(\n query(\n contactsRef,\n ...scoped,\n orderBy('nameLower'),\n startAt(key),\n endAt(`${key}${HIGH}`),\n limit(SEARCH_LIMIT),\n ),\n )\n }\n setResults(\n found.docs\n .filter((snapshot) => snapshot.id !== current.id)\n .map((snapshot) => ({ id: snapshot.id, doc: snapshot.data() })),\n )\n } catch (searchError) {\n console.error(searchError)\n setResults(null)\n setError('The search could not be run.')\n } finally {\n setSearching(false)\n }\n }, [term, searching, firestore, scope, visibleTo, current.id])\n\n const survivor = keep === 'current' ? current : other\n const merged = keep === 'current' ? other : current\n const rows: ContactMergePreviewRow[] = useMemo(\n () =>\n survivor && merged\n ? contactMergePreview(survivor.doc, merged.doc, groupId, { memberName })\n : [],\n [survivor, merged, groupId, memberName],\n )\n\n const submit = useCallback(async () => {\n if (!survivor || !merged || busy || !canMerge) return\n setBusy(true)\n setError(null)\n try {\n const { response, payload } = await callCrm('contacts-merge', {\n survivorId: survivor.id,\n mergedId: merged.id,\n })\n if (!response.ok) {\n setError(String(payload['error'] ?? 'The contacts could not be merged.'))\n return\n }\n enqueueSnackbar('Contacts merged', { variant: 'success', persist: false })\n onClose()\n onMerged?.(survivor.id)\n } catch (submitError) {\n console.error(submitError)\n setError('The contacts could not be merged.')\n } finally {\n setBusy(false)\n }\n }, [survivor, merged, busy, canMerge, callCrm, enqueueSnackbar, onClose, onMerged])\n\n const currentLabel = label(current, groupId)\n const otherLabel = other ? label(other, groupId) : ''\n\n return (\n <Dialog open={open} onClose={busy ? undefined : onClose} maxWidth=\"md\" fullWidth>\n <DialogTitle>{'Merge contacts'}</DialogTitle>\n <DialogContent>\n <Stack spacing={2} sx={{ pt: 1 }}>\n {!other ? (\n <>\n <Typography variant=\"body2\" color=\"text.secondary\">\n {`Find the other record for ${currentLabel} — by email address, or by name.`}\n </Typography>\n <Stack direction=\"row\" spacing={1} sx={{ alignItems: 'flex-start' }}>\n <TextField\n label=\"Email or name\"\n value={term}\n onChange={(event) => setTerm(event.target.value)}\n onKeyDown={(event) => {\n if (event.key === 'Enter') {\n event.preventDefault()\n void search()\n }\n }}\n size=\"small\"\n fullWidth\n autoFocus\n />\n <Button\n variant=\"outlined\"\n onClick={() => void search()}\n disabled={!term.trim() || searching}\n >\n {searching ? 'Searching…' : 'Search'}\n </Button>\n </Stack>\n {results ? (\n results.length ? (\n <List dense disablePadding aria-label=\"Matching contacts\">\n {results.map((pick) => (\n <ListItemButton key={pick.id} onClick={() => setOther(pick)}>\n <ListItemText\n primary={label(pick, groupId)}\n secondary={String(pick.doc['email'] ?? '')}\n />\n </ListItemButton>\n ))}\n </List>\n ) : (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'No other contact matches among the ones you can see.'}\n </Typography>\n )\n ) : null}\n </>\n ) : (\n <>\n <FormControl>\n <FormLabel id=\"contact-merge-keep\">{'Keep'}</FormLabel>\n <RadioGroup\n aria-labelledby=\"contact-merge-keep\"\n value={keep}\n onChange={(event) => setKeep(event.target.value as ContactMergeKeep)}\n >\n <FormControlLabel\n value=\"current\"\n control={<Radio size=\"small\" />}\n label={`${currentLabel} (${String(current.doc['email'] ?? '')})`}\n />\n <FormControlLabel\n value=\"other\"\n control={<Radio size=\"small\" />}\n label={`${otherLabel} (${String(other.doc['email'] ?? '')})`}\n />\n </RadioGroup>\n </FormControl>\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'The kept record keeps every value it has; empty fields fill from the ' +\n 'other record. Tags, filings and the timeline are combined, and the ' +\n \"other record's deals, tasks, activities and leads move across. Its \" +\n 'address becomes an alternate on the kept record, so a later capture ' +\n 'on it lands here — and the other record is deleted.'}\n </Typography>\n <ScrollTable size=\"small\" aria-label=\"What the merge keeps\">\n <TableHead>\n <TableRow>\n <TableCell>{'Field'}</TableCell>\n <TableCell>{'Kept'}</TableCell>\n <TableCell>{'Merged'}</TableCell>\n <TableCell>{'After'}</TableCell>\n </TableRow>\n </TableHead>\n <TableBody>\n {rows.map((row) => (\n <TableRow key={row.key}>\n <TableCell component=\"th\" scope=\"row\">\n {row.label}\n </TableCell>\n <TableCell sx={{ whiteSpace: 'pre-wrap' }}>{row.survivor}</TableCell>\n <TableCell sx={{ whiteSpace: 'pre-wrap' }}>{row.merged}</TableCell>\n <TableCell\n sx={{\n whiteSpace: 'pre-wrap',\n fontWeight: row.from === 'merged' || row.from === 'both' ? 600 : undefined,\n }}\n >\n {row.result}\n </TableCell>\n </TableRow>\n ))}\n </TableBody>\n </ScrollTable>\n {!props.other ? (\n <Button size=\"small\" onClick={() => setOther(null)} sx={{ alignSelf: 'flex-start' }}>\n {'Pick a different contact'}\n </Button>\n ) : null}\n </>\n )}\n {error ? <Alert severity=\"error\">{error}</Alert> : null}\n {!canMerge ? (\n <Alert severity=\"info\">\n {'No site has captured this contact, so there is no site to ' +\n 'merge it from. Open it from one of your sites instead.'}\n </Alert>\n ) : null}\n </Stack>\n </DialogContent>\n <DialogActions>\n <Button onClick={onClose} disabled={busy}>\n {'Cancel'}\n </Button>\n <Button\n variant=\"contained\"\n onClick={() => void submit()}\n disabled={!other || busy || !canMerge}\n >\n {busy ? 'Merging…' : 'Merge'}\n </Button>\n </DialogActions>\n </Dialog>\n )\n}\nContactMergeDialog.displayName = 'ContactMergeDialog'\n\nexport default ContactMergeDialog\n"],"names":["contactDisplayName","contactMergePreview","nameSearchKey","normalizeContactEmail","useSnackbar","useFirestore","ScrollTable","Alert","Button","Dialog","DialogActions","DialogContent","DialogTitle","FormControl","FormControlLabel","FormLabel","List","ListItemButton","ListItemText","Radio","RadioGroup","Stack","TableBody","TableCell","TableHead","TableRow","TextField","Typography","collection","endAt","getDocs","limit","orderBy","query","startAt","where","useCallback","useEffect","useMemo","useState","useCrmOrgMount","crmVisibleToClause","useCrmApi","SEARCH_LIMIT","HIGH","useContactMergeDialog","state","setState","open","other","keep","options","close","previous","label","pick","groupId","doc","String","id","ContactMergeDialog","props","current","onClose","hostId","scope","consentGroup","visibleTo","memberName","onMerged","firestore","callCrm","enqueueSnackbar","orgMount","canMerge","Boolean","setOther","setKeep","term","setTerm","searching","setSearching","results","setResults","busy","setBusy","error","setError","search","raw","trim","contactsRef","scoped","found","includes","email","key","docs","filter","snapshot","map","data","searchError","console","survivor","merged","rows","submit","response","payload","survivorId","mergedId","ok","variant","persist","submitError","currentLabel","otherLabel","undefined","maxWidth","fullWidth","spacing","sx","pt","color","direction","alignItems","value","onChange","event","target","onKeyDown","preventDefault","size","autoFocus","onClick","disabled","length","dense","disablePadding","aria-label","primary","secondary","aria-labelledby","control","row","component","whiteSpace","fontWeight","from","result","alignSelf","severity","displayName"],"mappings":"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"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { type AglynOrgBilling, type ConsentGroup } from '@aglyn/aglyn';
|
|
2
|
+
import { type ContactRecord } from '../model/contact-record';
|
|
3
|
+
import type { OrgMembers } from './use-org-members';
|
|
4
|
+
export interface ContactPropertiesCardProps {
|
|
5
|
+
/** The site the record is read under, or `null` at the organization level. */
|
|
6
|
+
hostId: string | null;
|
|
7
|
+
/** The org document the shell passed, for the company picker's scope. */
|
|
8
|
+
org?: Partial<AglynOrgBilling> | null;
|
|
9
|
+
/** The row, flattened through the viewing group's facet. */
|
|
10
|
+
record: ContactRecord;
|
|
11
|
+
/** The controller whose facet the edits are saved into. */
|
|
12
|
+
consentGroup: ConsentGroup;
|
|
13
|
+
/**
|
|
14
|
+
* The listener's verdict on the row the drafts were seeded from, for the
|
|
15
|
+
* guard that refuses a save over an unconfirmed read.
|
|
16
|
+
*/
|
|
17
|
+
seed: {
|
|
18
|
+
status: 'loading' | 'success' | 'error';
|
|
19
|
+
fromCache: boolean;
|
|
20
|
+
};
|
|
21
|
+
/** The team, for the owner picker and the owner's name. */
|
|
22
|
+
members: OrgMembers;
|
|
23
|
+
/**
|
|
24
|
+
* The org's plan lacks the CRM (AGL-2788), which the shell mounts no CRM
|
|
25
|
+
* page for (AGL-2851). The owner, the lifecycle stage and the company
|
|
26
|
+
* show, locked, and are left out of a save; `crm/contact-update` refuses
|
|
27
|
+
* such a plan the rest of the profile, the tags and the notes too.
|
|
28
|
+
*/
|
|
29
|
+
suiteLocked?: boolean;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* THE RECORD ITSELF: every field a team keeps on a person, in one card with
|
|
33
|
+
* one Save (AGL-2596).
|
|
34
|
+
*
|
|
35
|
+
* ## One save, one request, one guard
|
|
36
|
+
*
|
|
37
|
+
* A field-at-a-time save would be nine requests and nine chances for the
|
|
38
|
+
* stale-seed guard to refuse one of them — so the card holds a draft of the
|
|
39
|
+
* whole profile and sends it once. The guard WRAPS the send: a row seeded
|
|
40
|
+
* from the cache or from a failed read is refused with the message the guard
|
|
41
|
+
* chooses, and what was typed stays in the fields, because a refusal that
|
|
42
|
+
* also emptied the form would read as a save that worked.
|
|
43
|
+
*
|
|
44
|
+
* ## The server writes the facet (AGL-2804)
|
|
45
|
+
*
|
|
46
|
+
* Every field here lives in THIS holder's facet, and the Firestore rules
|
|
47
|
+
* cannot tell one field of a facet from another, so the card writes nothing
|
|
48
|
+
* itself. The draft goes to `crm/contact-update`, which writes each field by
|
|
49
|
+
* dotted path into the holder's facet — never a nested object, which would
|
|
50
|
+
* take every other holder's records with it — clears a blank field rather
|
|
51
|
+
* than storing it empty, keeps the phone's and the company's search echoes
|
|
52
|
+
* at the top of the document, and refuses every field to a plan without
|
|
53
|
+
* the CRM. A refusal is shown in the route's own words.
|
|
54
|
+
*
|
|
55
|
+
* ## The stage goes to its own route
|
|
56
|
+
*
|
|
57
|
+
* The lifecycle stage is the one field an automation listens for:
|
|
58
|
+
* `contactStageChanged` (AGL-2605) is emitted by `crm/contact-stage` after it
|
|
59
|
+
* performs the write, and by nothing else. So when the stage the reader
|
|
60
|
+
* picked differs from the one the record holds, it is sent to that route
|
|
61
|
+
* once the rest of the profile has landed — the stage picked, or `null` for
|
|
62
|
+
* "Not placed yet", which clears it and announces nothing. A refusal from
|
|
63
|
+
* that route is reported on its own, with its sentence, after the fields that
|
|
64
|
+
* did save.
|
|
65
|
+
*
|
|
66
|
+
* ## The name is an override
|
|
67
|
+
*
|
|
68
|
+
* The canonical name is shared by every site holding the person, so this
|
|
69
|
+
* card never edits it. What it saves is this holder's own name for them,
|
|
70
|
+
* and the helper says what a blank falls back to, so nobody clears the
|
|
71
|
+
* field expecting the record to go nameless.
|
|
72
|
+
*
|
|
73
|
+
* ## Company is a record, with its name kept beside it
|
|
74
|
+
*
|
|
75
|
+
* The Company field is the picker (AGL-2613): the link is `companyId` in
|
|
76
|
+
* this holder's facet, mirrored into the top-level `companyIds` for the
|
|
77
|
+
* company page's query, and the company's contacts count moves with it —
|
|
78
|
+
* all planned by the route from the stored document, so this card never
|
|
79
|
+
* reasons about another holder's link. The name is sent too, from the picked
|
|
80
|
+
* company, because the list column and the global search read the name and
|
|
81
|
+
* not the id; a record that carries a name with no link — an import, a save
|
|
82
|
+
* from before the picker — keeps it as the label, and the picker offers it
|
|
83
|
+
* as the company to link or create.
|
|
84
|
+
*/
|
|
85
|
+
export declare function ContactPropertiesCard(props: ContactPropertiesCardProps): import("react").JSX.Element;
|
|
86
|
+
export declare namespace ContactPropertiesCard {
|
|
87
|
+
var displayName: string;
|
|
88
|
+
}
|
|
89
|
+
export default ContactPropertiesCard;
|