@aglyn/plugins-crm 1.0.0-beta.221 → 1.0.0-beta.222
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -1
- package/package.json +13 -13
- package/src/lib/components/activity-list.js +12 -5
- package/src/lib/components/activity-list.js.map +1 -1
- package/src/lib/components/companies-bulk-bar.d.ts +1 -4
- package/src/lib/components/companies-bulk-bar.js +7 -20
- package/src/lib/components/companies-bulk-bar.js.map +1 -1
- package/src/lib/components/companies-section.d.ts +3 -3
- package/src/lib/components/companies-section.js +149 -46
- package/src/lib/components/companies-section.js.map +1 -1
- package/src/lib/components/company-edit-drawer.js +281 -20
- package/src/lib/components/company-edit-drawer.js.map +1 -1
- package/src/lib/components/company-properties-card.js +99 -8
- package/src/lib/components/company-properties-card.js.map +1 -1
- package/src/lib/components/contact-detail-page.js +3 -1
- package/src/lib/components/contact-detail-page.js.map +1 -1
- package/src/lib/components/contact-merge-dialog.js +33 -10
- package/src/lib/components/contact-merge-dialog.js.map +1 -1
- package/src/lib/components/contact-properties-card.d.ts +0 -69
- package/src/lib/components/contact-properties-card.js +350 -60
- package/src/lib/components/contact-properties-card.js.map +1 -1
- package/src/lib/components/contact-reports-to-field.d.ts +46 -0
- package/src/lib/components/contact-reports-to-field.js +67 -0
- package/src/lib/components/contact-reports-to-field.js.map +1 -0
- package/src/lib/components/contacts-bulk-bar.d.ts +1 -8
- package/src/lib/components/contacts-bulk-bar.js +7 -19
- package/src/lib/components/contacts-bulk-bar.js.map +1 -1
- package/src/lib/components/contacts-section.js +46 -33
- package/src/lib/components/contacts-section.js.map +1 -1
- package/src/lib/components/crm-call-actions.d.ts +10 -0
- package/src/lib/components/crm-call-actions.js +26 -9
- package/src/lib/components/crm-call-actions.js.map +1 -1
- package/src/lib/components/crm-record-picker.d.ts +15 -0
- package/src/lib/components/crm-record-picker.js +16 -10
- package/src/lib/components/crm-record-picker.js.map +1 -1
- package/src/lib/components/crm-transfer-buttons.d.ts +54 -0
- package/src/lib/components/crm-transfer-buttons.js +167 -0
- package/src/lib/components/crm-transfer-buttons.js.map +1 -0
- package/src/lib/components/deal-contact-roles-card.d.ts +46 -0
- package/src/lib/components/deal-contact-roles-card.js +368 -0
- package/src/lib/components/deal-contact-roles-card.js.map +1 -0
- package/src/lib/components/deal-detail-page.d.ts +3 -2
- package/src/lib/components/deal-detail-page.js +25 -6
- package/src/lib/components/deal-detail-page.js.map +1 -1
- package/src/lib/components/deal-edit-drawer.d.ts +10 -0
- package/src/lib/components/deal-edit-drawer.js +219 -10
- package/src/lib/components/deal-edit-drawer.js.map +1 -1
- package/src/lib/components/deal-properties-card.d.ts +7 -0
- package/src/lib/components/deal-properties-card.js +34 -3
- package/src/lib/components/deal-properties-card.js.map +1 -1
- package/src/lib/components/deal-stage-card.d.ts +4 -0
- package/src/lib/components/deal-stage-card.js +10 -2
- package/src/lib/components/deal-stage-card.js.map +1 -1
- package/src/lib/components/deals-bulk-bar.d.ts +0 -3
- package/src/lib/components/deals-bulk-bar.js +7 -20
- package/src/lib/components/deals-bulk-bar.js.map +1 -1
- package/src/lib/components/deals-section.d.ts +3 -3
- package/src/lib/components/deals-section.js +123 -63
- package/src/lib/components/deals-section.js.map +1 -1
- package/src/lib/components/fields-section.js +31 -17
- package/src/lib/components/fields-section.js.map +1 -1
- package/src/lib/components/lead-convert-dialog.d.ts +4 -0
- package/src/lib/components/lead-convert-dialog.js +23 -1
- package/src/lib/components/lead-convert-dialog.js.map +1 -1
- package/src/lib/components/lead-detail-page.js +8 -2
- package/src/lib/components/lead-detail-page.js.map +1 -1
- package/src/lib/components/lead-profile-fields.d.ts +71 -0
- package/src/lib/components/lead-profile-fields.js +386 -0
- package/src/lib/components/lead-profile-fields.js.map +1 -0
- package/src/lib/components/lead-properties-card.d.ts +2 -1
- package/src/lib/components/lead-properties-card.js +85 -176
- package/src/lib/components/lead-properties-card.js.map +1 -1
- package/src/lib/components/lead-source-select.d.ts +4 -23
- package/src/lib/components/lead-source-select.js +9 -73
- package/src/lib/components/lead-source-select.js.map +1 -1
- package/src/lib/components/lead-status-chip.d.ts +9 -3
- package/src/lib/components/lead-status-chip.js +8 -4
- package/src/lib/components/lead-status-chip.js.map +1 -1
- package/src/lib/components/lead-status-options.d.ts +20 -0
- package/src/lib/components/lead-status-options.js +51 -0
- package/src/lib/components/lead-status-options.js.map +1 -0
- package/src/lib/components/lead-unqualify-dialog.d.ts +5 -0
- package/src/lib/components/lead-unqualify-dialog.js +50 -18
- package/src/lib/components/lead-unqualify-dialog.js.map +1 -1
- package/src/lib/components/leads-bulk-bar.d.ts +0 -3
- package/src/lib/components/leads-bulk-bar.js +29 -29
- package/src/lib/components/leads-bulk-bar.js.map +1 -1
- package/src/lib/components/leads-section.js +120 -68
- package/src/lib/components/leads-section.js.map +1 -1
- package/src/lib/components/linked-deals-card.d.ts +4 -0
- package/src/lib/components/linked-deals-card.js +47 -3
- package/src/lib/components/linked-deals-card.js.map +1 -1
- package/src/lib/components/log-activity-dialog.js +43 -3
- package/src/lib/components/log-activity-dialog.js.map +1 -1
- package/src/lib/components/new-contact-drawer.d.ts +8 -0
- package/src/lib/components/new-contact-drawer.js +108 -6
- package/src/lib/components/new-contact-drawer.js.map +1 -1
- package/src/lib/components/new-lead-drawer.d.ts +9 -2
- package/src/lib/components/new-lead-drawer.js +88 -121
- package/src/lib/components/new-lead-drawer.js.map +1 -1
- package/src/lib/components/picklist-select.d.ts +36 -0
- package/src/lib/components/picklist-select.js +114 -0
- package/src/lib/components/picklist-select.js.map +1 -0
- package/src/lib/components/picklist-values-card.d.ts +34 -0
- package/src/lib/components/{lead-source-values-card.js → picklist-values-card.js} +241 -58
- package/src/lib/components/picklist-values-card.js.map +1 -0
- package/src/lib/components/pipeline-stages-dialog.d.ts +7 -0
- package/src/lib/components/pipeline-stages-dialog.js +26 -4
- package/src/lib/components/pipeline-stages-dialog.js.map +1 -1
- package/src/lib/components/pipelines-dialog.js +15 -6
- package/src/lib/components/pipelines-dialog.js.map +1 -1
- package/src/lib/components/recent-activity-feed.js +20 -5
- package/src/lib/components/recent-activity-feed.js.map +1 -1
- package/src/lib/components/recipes-card.js +4 -2
- package/src/lib/components/recipes-card.js.map +1 -1
- package/src/lib/components/record-tasks-card.js +15 -8
- package/src/lib/components/record-tasks-card.js.map +1 -1
- package/src/lib/components/reports/forecast-card.d.ts +6 -0
- package/src/lib/components/reports/forecast-card.js +101 -3
- package/src/lib/components/reports/forecast-card.js.map +1 -1
- package/src/lib/components/reports/lead-funnel-card.d.ts +12 -0
- package/src/lib/components/reports/lead-funnel-card.js +9 -5
- package/src/lib/components/reports/lead-funnel-card.js.map +1 -1
- package/src/lib/components/reports/lead-source-card.d.ts +23 -0
- package/src/lib/components/reports/lead-source-card.js +318 -0
- package/src/lib/components/reports/lead-source-card.js.map +1 -0
- package/src/lib/components/reports/report-export.js +1 -1
- package/src/lib/components/reports/report-export.js.map +1 -1
- package/src/lib/components/reports-section.js +8 -0
- package/src/lib/components/reports-section.js.map +1 -1
- package/src/lib/components/sharing-rule-drawer.d.ts +5 -0
- package/src/lib/components/sharing-rule-drawer.js +108 -19
- package/src/lib/components/sharing-rule-drawer.js.map +1 -1
- package/src/lib/components/sharing-rules-card.js +11 -3
- package/src/lib/components/sharing-rules-card.js.map +1 -1
- package/src/lib/components/task-cells.d.ts +9 -1
- package/src/lib/components/task-cells.js +9 -4
- package/src/lib/components/task-cells.js.map +1 -1
- package/src/lib/components/task-edit-drawer.js +111 -43
- package/src/lib/components/task-edit-drawer.js.map +1 -1
- package/src/lib/components/tasks-bulk-bar.d.ts +0 -3
- package/src/lib/components/tasks-bulk-bar.js +7 -20
- package/src/lib/components/tasks-bulk-bar.js.map +1 -1
- package/src/lib/components/tasks-calendar.d.ts +3 -0
- package/src/lib/components/tasks-calendar.js +8 -1
- package/src/lib/components/tasks-calendar.js.map +1 -1
- package/src/lib/components/tasks-section.d.ts +3 -3
- package/src/lib/components/tasks-section.js +58 -43
- package/src/lib/components/tasks-section.js.map +1 -1
- package/src/lib/constants/api-routes.d.ts +2 -9
- package/src/lib/constants/api-routes.js +1 -7
- package/src/lib/constants/api-routes.js.map +1 -1
- package/src/lib/constants/bundle-common.d.ts +6 -0
- package/src/lib/constants/bundle-common.js +11 -0
- package/src/lib/constants/bundle-common.js.map +1 -1
- package/src/lib/constants/company-filters.d.ts +14 -0
- package/src/lib/constants/company-filters.js +51 -1
- package/src/lib/constants/company-filters.js.map +1 -1
- package/src/lib/constants/contact-filters.d.ts +2 -0
- package/src/lib/constants/contact-filters.js +18 -1
- package/src/lib/constants/contact-filters.js.map +1 -1
- package/src/lib/constants/deal-filters.d.ts +22 -1
- package/src/lib/constants/deal-filters.js +67 -4
- package/src/lib/constants/deal-filters.js.map +1 -1
- package/src/lib/declarations.console-server.d.ts +3 -0
- package/src/lib/declarations.console-server.js +35 -0
- package/src/lib/declarations.console-server.js.map +1 -1
- package/src/lib/declarations.d.ts +26 -0
- package/src/lib/declarations.js +35 -0
- package/src/lib/declarations.js.map +1 -0
- package/src/lib/declarations.server.d.ts +11 -0
- package/src/lib/declarations.server.js +92 -1
- package/src/lib/declarations.server.js.map +1 -1
- package/src/lib/hooks/use-company-picklists.d.ts +15 -0
- package/src/lib/hooks/use-company-picklists.js +55 -0
- package/src/lib/hooks/use-company-picklists.js.map +1 -0
- package/src/lib/hooks/use-crm-picklist.d.ts +25 -0
- package/src/lib/hooks/use-crm-picklist.js +53 -0
- package/src/lib/hooks/use-crm-picklist.js.map +1 -0
- package/src/lib/hooks/use-crm-record-names.d.ts +16 -0
- package/src/lib/hooks/use-crm-record-names.js +45 -19
- package/src/lib/hooks/use-crm-record-names.js.map +1 -1
- package/src/lib/hooks/use-crm-task-picklists.d.ts +11 -0
- package/src/lib/hooks/use-crm-task-picklists.js +45 -0
- package/src/lib/hooks/use-crm-task-picklists.js.map +1 -0
- package/src/lib/hooks/use-deals.d.ts +14 -0
- package/src/lib/hooks/use-deals.js +29 -0
- package/src/lib/hooks/use-deals.js.map +1 -1
- package/src/lib/hooks/use-lead-picklists.d.ts +14 -0
- package/src/lib/hooks/use-lead-picklists.js +46 -0
- package/src/lib/hooks/use-lead-picklists.js.map +1 -0
- package/src/lib/hooks/use-lead-source-picklist.d.ts +5 -19
- package/src/lib/hooks/use-lead-source-picklist.js +12 -22
- package/src/lib/hooks/use-lead-source-picklist.js.map +1 -1
- package/src/lib/hooks/use-lead-status-picklist.d.ts +9 -0
- package/src/lib/hooks/use-lead-status-picklist.js +40 -0
- package/src/lib/hooks/use-lead-status-picklist.js.map +1 -0
- package/src/lib/model/companies.d.ts +32 -3
- package/src/lib/model/companies.js +133 -16
- package/src/lib/model/companies.js.map +1 -1
- package/src/lib/model/contact-merge.d.ts +27 -3
- package/src/lib/model/contact-merge.js +81 -7
- package/src/lib/model/contact-merge.js.map +1 -1
- package/src/lib/model/contact-record.d.ts +17 -0
- package/src/lib/model/contact-record.js +15 -1
- package/src/lib/model/contact-record.js.map +1 -1
- package/src/lib/model/contact-update.d.ts +31 -2
- package/src/lib/model/contact-update.js +14 -0
- package/src/lib/model/contact-update.js.map +1 -1
- package/src/lib/model/crm-list-query.d.ts +5 -0
- package/src/lib/model/crm-list-query.js +8 -0
- package/src/lib/model/crm-list-query.js.map +1 -1
- package/src/lib/model/crm-recipes.d.ts +40 -0
- package/src/lib/model/crm-recipes.js +244 -0
- package/src/lib/model/crm-recipes.js.map +1 -0
- package/src/lib/model/crm-record-counts.d.ts +36 -0
- package/src/lib/model/crm-record-counts.js +54 -0
- package/src/lib/model/crm-record-counts.js.map +1 -0
- package/src/lib/model/crm-record-lists.d.ts +23 -0
- package/src/lib/model/crm-record-lists.js +161 -0
- package/src/lib/model/crm-record-lists.js.map +1 -0
- package/src/lib/model/crm-reports.d.ts +73 -3
- package/src/lib/model/crm-reports.js +120 -1
- package/src/lib/model/crm-reports.js.map +1 -1
- package/src/lib/model/crm-sharing.d.ts +21 -3
- package/src/lib/model/crm-sharing.js +27 -6
- package/src/lib/model/crm-sharing.js.map +1 -1
- package/src/lib/model/deal-board-model.d.ts +8 -2
- package/src/lib/model/deal-board-model.js +15 -2
- package/src/lib/model/deal-board-model.js.map +1 -1
- package/src/lib/model/deal-contact-roles.d.ts +45 -0
- package/src/lib/model/deal-contact-roles.js +73 -0
- package/src/lib/model/deal-contact-roles.js.map +1 -0
- package/src/lib/model/deal-form-model.d.ts +56 -0
- package/src/lib/model/deal-form-model.js +79 -7
- package/src/lib/model/deal-form-model.js.map +1 -1
- package/src/lib/model/download-text-file.d.ts +23 -0
- package/src/lib/model/download-text-file.js +34 -0
- package/src/lib/model/download-text-file.js.map +1 -0
- package/src/lib/model/lead-filters.d.ts +36 -2
- package/src/lib/model/lead-filters.js +123 -2
- package/src/lib/model/lead-filters.js.map +1 -1
- package/src/lib/model/lead-source-direction.d.ts +38 -0
- package/src/lib/model/lead-source-direction.js +52 -0
- package/src/lib/model/lead-source-direction.js.map +1 -0
- package/src/lib/model/picklist-values.d.ts +119 -0
- package/src/lib/model/picklist-values.js +256 -0
- package/src/lib/model/picklist-values.js.map +1 -0
- package/src/lib/model/record-facts-disclosed.d.ts +81 -0
- package/src/lib/model/record-facts-disclosed.js +281 -0
- package/src/lib/model/record-facts-disclosed.js.map +1 -0
- package/src/lib/model/record-facts.d.ts +215 -34
- package/src/lib/model/record-facts.js +307 -128
- package/src/lib/model/record-facts.js.map +1 -1
- package/src/lib/model/task-picklists.d.ts +52 -0
- package/src/lib/model/task-picklists.js +83 -0
- package/src/lib/model/task-picklists.js.map +1 -0
- package/src/lib/model/task-routes.d.ts +13 -0
- package/src/lib/model/task-routes.js +23 -4
- package/src/lib/model/task-routes.js.map +1 -1
- package/src/lib/plan-entitlements.js +6 -4
- package/src/lib/plan-entitlements.js.map +1 -1
- package/src/lib/plugin.js +17 -0
- package/src/lib/plugin.js.map +1 -1
- package/src/lib/server/api-v1/contacts.js +220 -14
- package/src/lib/server/api-v1/contacts.js.map +1 -1
- package/src/lib/server/api-v1/crm-activities.js +14 -1
- package/src/lib/server/api-v1/crm-activities.js.map +1 -1
- package/src/lib/server/api-v1/crm-companies.js +123 -14
- package/src/lib/server/api-v1/crm-companies.js.map +1 -1
- package/src/lib/server/api-v1/crm-deals.js +291 -26
- package/src/lib/server/api-v1/crm-deals.js.map +1 -1
- package/src/lib/server/api-v1/crm-leads.js +144 -38
- package/src/lib/server/api-v1/crm-leads.js.map +1 -1
- package/src/lib/server/api-v1/crm-pipelines.d.ts +6 -0
- package/src/lib/server/api-v1/crm-pipelines.js +8 -2
- package/src/lib/server/api-v1/crm-pipelines.js.map +1 -1
- package/src/lib/server/api-v1/crm-tasks.js +75 -33
- package/src/lib/server/api-v1/crm-tasks.js.map +1 -1
- package/src/lib/server/api-v1/openapi.d.ts +0 -11
- package/src/lib/server/api-v1/openapi.js +171 -16
- package/src/lib/server/api-v1/openapi.js.map +1 -1
- package/src/lib/server/assign-contact-owner.d.ts +162 -0
- package/src/lib/server/assign-contact-owner.js +340 -0
- package/src/lib/server/assign-contact-owner.js.map +1 -0
- package/src/lib/server/associate-company-by-domain.d.ts +70 -0
- package/src/lib/server/associate-company-by-domain.js +153 -0
- package/src/lib/server/associate-company-by-domain.js.map +1 -0
- package/src/lib/server/automation-steps.d.ts +139 -0
- package/src/lib/server/automation-steps.js +472 -0
- package/src/lib/server/automation-steps.js.map +1 -0
- package/src/lib/server/capture-contact.js +65 -21
- package/src/lib/server/capture-contact.js.map +1 -1
- package/src/lib/server/capture-host-contact.d.ts +104 -0
- package/src/lib/server/capture-host-contact.js +151 -0
- package/src/lib/server/capture-host-contact.js.map +1 -0
- package/src/lib/server/company-children.d.ts +25 -0
- package/src/lib/server/company-children.js +42 -0
- package/src/lib/server/company-children.js.map +1 -0
- package/src/lib/server/company-delete.d.ts +18 -0
- package/src/lib/server/company-delete.js +44 -21
- package/src/lib/server/company-delete.js.map +1 -1
- package/src/lib/server/contact-email-history.js +21 -19
- package/src/lib/server/contact-email-history.js.map +1 -1
- package/src/lib/server/contact-remove.js +27 -2
- package/src/lib/server/contact-remove.js.map +1 -1
- package/src/lib/server/contact-reports-to.d.ts +61 -0
- package/src/lib/server/contact-reports-to.js +114 -0
- package/src/lib/server/contact-reports-to.js.map +1 -0
- package/src/lib/server/contact-update.d.ts +42 -1
- package/src/lib/server/contact-update.js +204 -23
- package/src/lib/server/contact-update.js.map +1 -1
- package/src/lib/server/convert-host-lead.d.ts +46 -1
- package/src/lib/server/convert-host-lead.js +173 -15
- package/src/lib/server/convert-host-lead.js.map +1 -1
- package/src/lib/server/convert-open-lead.js +12 -5
- package/src/lib/server/convert-open-lead.js.map +1 -1
- package/src/lib/server/crm-record-indexes.d.ts +45 -0
- package/src/lib/server/crm-record-indexes.js +78 -0
- package/src/lib/server/crm-record-indexes.js.map +1 -0
- package/src/lib/server/crm-sharing.d.ts +9 -1
- package/src/lib/server/crm-sharing.js +23 -3
- package/src/lib/server/crm-sharing.js.map +1 -1
- package/src/lib/server/deal-contact-roles.d.ts +27 -0
- package/src/lib/server/deal-contact-roles.js +89 -0
- package/src/lib/server/deal-contact-roles.js.map +1 -0
- package/src/lib/server/lead-convert.d.ts +5 -0
- package/src/lib/server/lead-convert.js +19 -3
- package/src/lib/server/lead-convert.js.map +1 -1
- package/src/lib/server/lead-create.d.ts +17 -2
- package/src/lib/server/lead-create.js +46 -14
- package/src/lib/server/lead-create.js.map +1 -1
- package/src/lib/server/lead-nurturing.d.ts +6 -0
- package/src/lib/server/lead-nurturing.js +57 -20
- package/src/lib/server/lead-nurturing.js.map +1 -1
- package/src/lib/server/lead-picklists.d.ts +35 -0
- package/src/lib/server/lead-picklists.js +52 -0
- package/src/lib/server/lead-picklists.js.map +1 -0
- package/src/lib/server/lead-source-picklist.d.ts +1 -13
- package/src/lib/server/lead-source-picklist.js +6 -33
- package/src/lib/server/lead-source-picklist.js.map +1 -1
- package/src/lib/server/merge-contacts.js +22 -4
- package/src/lib/server/merge-contacts.js.map +1 -1
- package/src/lib/server/person-eraser.d.ts +53 -0
- package/src/lib/server/person-eraser.js +149 -0
- package/src/lib/server/person-eraser.js.map +1 -0
- package/src/lib/server/person-records.d.ts +69 -0
- package/src/lib/server/person-records.js +317 -0
- package/src/lib/server/person-records.js.map +1 -0
- package/src/lib/server/person-refund.d.ts +97 -0
- package/src/lib/server/person-refund.js +221 -0
- package/src/lib/server/person-refund.js.map +1 -0
- package/src/lib/server/picklist-values.d.ts +21 -0
- package/src/lib/server/picklist-values.js +308 -0
- package/src/lib/server/picklist-values.js.map +1 -0
- package/src/lib/server/read-picklist.d.ts +44 -0
- package/src/lib/server/read-picklist.js +65 -0
- package/src/lib/server/read-picklist.js.map +1 -0
- package/src/lib/server/recipe-routes.js +15 -7
- package/src/lib/server/recipe-routes.js.map +1 -1
- package/src/lib/server/record-email-state.js +7 -1
- package/src/lib/server/record-email-state.js.map +1 -1
- package/src/lib/server/record-facts.d.ts +3 -0
- package/src/lib/server/record-facts.js +233 -31
- package/src/lib/server/record-facts.js.map +1 -1
- package/src/lib/server/record-origin.d.ts +27 -0
- package/src/lib/server/record-origin.js +104 -0
- package/src/lib/server/record-origin.js.map +1 -0
- package/src/lib/server/record-timeline.js +15 -2
- package/src/lib/server/record-timeline.js.map +1 -1
- package/src/lib/server/suite-gate.js +4 -3
- package/src/lib/server/suite-gate.js.map +1 -1
- package/src/lib/server/task-routes.js +30 -16
- package/src/lib/server/task-routes.js.map +1 -1
- package/src/lib/server-deal-stage.d.ts +5 -1
- package/src/lib/server-deal-stage.js +10 -5
- package/src/lib/server-deal-stage.js.map +1 -1
- package/src/lib/server.d.ts +8 -3
- package/src/lib/server.js +47 -43
- package/src/lib/server.js.map +1 -1
- package/src/lib/testing/memory-firestore.d.ts +55 -0
- package/src/lib/testing/memory-firestore.js +335 -0
- package/src/lib/testing/memory-firestore.js.map +1 -0
- package/src/lib/testing/stand-in-email-send-index.d.ts +25 -0
- package/src/lib/testing/stand-in-email-send-index.js +49 -0
- package/src/lib/testing/stand-in-email-send-index.js.map +1 -0
- package/src/lib/transfer/activities.d.ts +30 -0
- package/src/lib/transfer/activities.js +132 -0
- package/src/lib/transfer/activities.js.map +1 -0
- package/src/lib/transfer/aliases.d.ts +22 -0
- package/src/lib/transfer/aliases.js +1342 -0
- package/src/lib/transfer/aliases.js.map +1 -0
- package/src/lib/transfer/common.d.ts +222 -0
- package/src/lib/transfer/common.js +832 -0
- package/src/lib/transfer/common.js.map +1 -0
- package/src/lib/transfer/companies.d.ts +43 -0
- package/src/lib/transfer/companies.js +549 -0
- package/src/lib/transfer/companies.js.map +1 -0
- package/src/lib/transfer/contacts.d.ts +31 -0
- package/src/lib/transfer/contacts.js +727 -0
- package/src/lib/transfer/contacts.js.map +1 -0
- package/src/lib/transfer/deals.d.ts +66 -0
- package/src/lib/transfer/deals.js +698 -0
- package/src/lib/transfer/deals.js.map +1 -0
- package/src/lib/transfer/email-templates-package.d.ts +40 -0
- package/src/lib/transfer/email-templates-package.js +76 -0
- package/src/lib/transfer/email-templates-package.js.map +1 -0
- package/src/lib/transfer/email-templates-package.server.d.ts +32 -0
- package/src/lib/transfer/email-templates-package.server.js +176 -0
- package/src/lib/transfer/email-templates-package.server.js.map +1 -0
- package/src/lib/transfer/fields.d.ts +102 -0
- package/src/lib/transfer/fields.js +1755 -0
- package/src/lib/transfer/fields.js.map +1 -0
- package/src/lib/transfer/leads.d.ts +30 -0
- package/src/lib/transfer/leads.js +582 -0
- package/src/lib/transfer/leads.js.map +1 -0
- package/src/lib/transfer/pipelines.d.ts +21 -0
- package/src/lib/transfer/pipelines.js +172 -0
- package/src/lib/transfer/pipelines.js.map +1 -0
- package/src/lib/transfer/register.d.ts +47 -0
- package/src/lib/transfer/register.js +277 -0
- package/src/lib/transfer/register.js.map +1 -0
- package/src/lib/transfer/tasks.d.ts +30 -0
- package/src/lib/transfer/tasks.js +418 -0
- package/src/lib/transfer/tasks.js.map +1 -0
- package/src/lib/transfer/ui.d.ts +20 -0
- package/src/lib/transfer/ui.js +42 -0
- package/src/lib/transfer/ui.js.map +1 -0
- package/src/lib/components/company-import-drawer.d.ts +0 -42
- package/src/lib/components/company-import-drawer.js +0 -99
- package/src/lib/components/company-import-drawer.js.map +0 -1
- package/src/lib/components/contact-import-drawer.d.ts +0 -46
- package/src/lib/components/contact-import-drawer.js +0 -149
- package/src/lib/components/contact-import-drawer.js.map +0 -1
- package/src/lib/components/crm-export-all-button.d.ts +0 -39
- package/src/lib/components/crm-export-all-button.js +0 -98
- package/src/lib/components/crm-export-all-button.js.map +0 -1
- package/src/lib/components/csv-import-drawer.d.ts +0 -139
- package/src/lib/components/csv-import-drawer.js +0 -757
- package/src/lib/components/csv-import-drawer.js.map +0 -1
- package/src/lib/components/deal-import-drawer.d.ts +0 -24
- package/src/lib/components/deal-import-drawer.js +0 -83
- package/src/lib/components/deal-import-drawer.js.map +0 -1
- package/src/lib/components/lead-import-drawer.d.ts +0 -27
- package/src/lib/components/lead-import-drawer.js +0 -118
- package/src/lib/components/lead-import-drawer.js.map +0 -1
- package/src/lib/components/lead-source-values-card.d.ts +0 -27
- package/src/lib/components/lead-source-values-card.js.map +0 -1
- package/src/lib/components/task-import-drawer.d.ts +0 -24
- package/src/lib/components/task-import-drawer.js +0 -82
- package/src/lib/components/task-import-drawer.js.map +0 -1
- package/src/lib/model/companies-csv.d.ts +0 -36
- package/src/lib/model/companies-csv.js +0 -38
- package/src/lib/model/companies-csv.js.map +0 -1
- package/src/lib/model/contacts-csv.d.ts +0 -54
- package/src/lib/model/contacts-csv.js +0 -67
- package/src/lib/model/contacts-csv.js.map +0 -1
- package/src/lib/model/crm-company-import.d.ts +0 -154
- package/src/lib/model/crm-company-import.js +0 -331
- package/src/lib/model/crm-company-import.js.map +0 -1
- package/src/lib/model/crm-csv.d.ts +0 -239
- package/src/lib/model/crm-csv.js +0 -467
- package/src/lib/model/crm-csv.js.map +0 -1
- package/src/lib/model/crm-deal-import.d.ts +0 -112
- package/src/lib/model/crm-deal-import.js +0 -263
- package/src/lib/model/crm-deal-import.js.map +0 -1
- package/src/lib/model/crm-import.d.ts +0 -250
- package/src/lib/model/crm-import.js +0 -467
- package/src/lib/model/crm-import.js.map +0 -1
- package/src/lib/model/crm-lead-import.d.ts +0 -138
- package/src/lib/model/crm-lead-import.js +0 -446
- package/src/lib/model/crm-lead-import.js.map +0 -1
- package/src/lib/model/crm-task-import.d.ts +0 -94
- package/src/lib/model/crm-task-import.js +0 -275
- package/src/lib/model/crm-task-import.js.map +0 -1
- package/src/lib/model/deals-csv.d.ts +0 -32
- package/src/lib/model/deals-csv.js +0 -36
- package/src/lib/model/deals-csv.js.map +0 -1
- package/src/lib/model/import-column-shapes.d.ts +0 -36
- package/src/lib/model/import-column-shapes.js +0 -76
- package/src/lib/model/import-column-shapes.js.map +0 -1
- package/src/lib/model/lead-source-values.d.ts +0 -82
- package/src/lib/model/lead-source-values.js +0 -149
- package/src/lib/model/lead-source-values.js.map +0 -1
- package/src/lib/model/leads-csv.d.ts +0 -40
- package/src/lib/model/leads-csv.js +0 -40
- package/src/lib/model/leads-csv.js.map +0 -1
- package/src/lib/model/tasks-csv.d.ts +0 -28
- package/src/lib/model/tasks-csv.js +0 -28
- package/src/lib/model/tasks-csv.js.map +0 -1
- package/src/lib/server/companies-import.d.ts +0 -57
- package/src/lib/server/companies-import.js +0 -242
- package/src/lib/server/companies-import.js.map +0 -1
- package/src/lib/server/contacts-import.d.ts +0 -109
- package/src/lib/server/contacts-import.js +0 -393
- package/src/lib/server/contacts-import.js.map +0 -1
- package/src/lib/server/deals-import.d.ts +0 -76
- package/src/lib/server/deals-import.js +0 -248
- package/src/lib/server/deals-import.js.map +0 -1
- package/src/lib/server/export-route.d.ts +0 -60
- package/src/lib/server/export-route.js +0 -447
- package/src/lib/server/export-route.js.map +0 -1
- package/src/lib/server/import-context.d.ts +0 -87
- package/src/lib/server/import-context.js +0 -182
- package/src/lib/server/import-context.js.map +0 -1
- package/src/lib/server/lead-source-values.d.ts +0 -50
- package/src/lib/server/lead-source-values.js +0 -191
- package/src/lib/server/lead-source-values.js.map +0 -1
- package/src/lib/server/leads-import.d.ts +0 -84
- package/src/lib/server/leads-import.js +0 -367
- package/src/lib/server/leads-import.js.map +0 -1
- package/src/lib/server/tasks-import.d.ts +0 -54
- package/src/lib/server/tasks-import.js +0 -160
- package/src/lib/server/tasks-import.js.map +0 -1
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
* limitations under the License.
|
|
16
16
|
*/ 'use client';
|
|
17
17
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
18
|
+
import { crmTaskPicklistLabels } from "@aglyn/aglyn";
|
|
18
19
|
import { mdiChevronLeft, mdiChevronRight } from "@aglyn/shared-data-mdi";
|
|
19
20
|
import { MdiIcon } from "@aglyn/shared-ui-jsx";
|
|
20
21
|
import { Box, Button, ButtonBase, IconButton, Stack, Typography } from "@mui/material";
|
|
@@ -45,7 +46,12 @@ import { bucketTasksByCalendarDay, CALENDAR_DAY_LABELS, CALENDAR_WEEK_DAYS, shif
|
|
|
45
46
|
* scheduling library for one surface is a dependency the whole console
|
|
46
47
|
* would carry.
|
|
47
48
|
*/ export function TasksCalendar(props) {
|
|
48
|
-
const { tasks, onOpen, truncated } = props;
|
|
49
|
+
const { tasks, onOpen, truncated, picklists } = props;
|
|
50
|
+
/** "Call Ada · Call · In Progress" — the entry's type and status on hover. */ const hoverText = (task)=>{
|
|
51
|
+
if (!picklists) return task.title;
|
|
52
|
+
const labels = crmTaskPicklistLabels(task, picklists);
|
|
53
|
+
return `${task.title} · ${labels.type} · ${labels.status}`;
|
|
54
|
+
};
|
|
49
55
|
/*
|
|
50
56
|
* The clock is read ONCE, at mount. A component that read `Date.now()`
|
|
51
57
|
* per render would move the today square under a reader who left the tab
|
|
@@ -173,6 +179,7 @@ import { bucketTasksByCalendarDay, CALENDAR_DAY_LABELS, CALENDAR_WEEK_DAYS, shif
|
|
|
173
179
|
children: [
|
|
174
180
|
shown.map((task)=>/*#__PURE__*/ _jsx(ButtonBase, {
|
|
175
181
|
onClick: ()=>onOpen(task),
|
|
182
|
+
title: hoverText(task),
|
|
176
183
|
sx: {
|
|
177
184
|
justifyContent: 'flex-start',
|
|
178
185
|
width: '100%',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../../libs/plugins/crm/src/lib/components/tasks-calendar.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 { mdiChevronLeft, mdiChevronRight } from '@aglyn/shared-data-mdi'\nimport { MdiIcon } from '@aglyn/shared-ui-jsx'\nimport { Box, Button, ButtonBase, IconButton, Stack, Typography } from '@mui/material'\nimport { useMemo, useState } from 'react'\nimport type { CrmTaskRow } from '../hooks/use-crm-tasks'\nimport {\n bucketTasksByCalendarDay,\n CALENDAR_DAY_LABELS,\n CALENDAR_WEEK_DAYS,\n shiftCalendarMonth,\n taskCalendarMonth,\n} from '../model/task-calendar'\n\n/** How many tasks a square lists before folding the rest into a count. */\nconst TASKS_PER_DAY = 3\n\nexport interface TasksCalendarProps {\n /** The window the list is holding — the calendar reads no more than it. */\n tasks: readonly CrmTaskRow[]\n /** Open one task's drawer, the same drawer a row opens. */\n onOpen: (task: CrmTaskRow) => void\n /** The list's window filled, so neither surface is showing everything. */\n truncated?: boolean\n}\n\n/**\n * A MONTH OF TASKS, BY DUE DATE (AGL-2662).\n *\n * The Tasks list answers \"what is on my plate\"; this answers \"what does\n * next week look like\", which a list ordered by due date can only imply.\n *\n * ## Drawn over the list's own window, and never over a second read\n *\n * The rows are the ones the section already holds. A calendar that fetched\n * its own month would be a second listener over the same collection, would\n * disagree with the list whenever the two windows differed, and would put\n * a read behind every page of the arrows. What it costs instead is honesty:\n * the grid can only place what the window carries, so the tasks due in\n * other months are counted under it rather than implied to be absent.\n *\n * ## Hand-built rather than a calendar dependency\n *\n * Seven columns of MUI boxes and the local-day arithmetic in\n * `task-calendar.ts`. The one calendar package already installed\n * (`@mui/x-date-pickers`) draws a date PICKER — a grid whose squares are\n * choices, not content — so it answers a different question, and a\n * scheduling library for one surface is a dependency the whole console\n * would carry.\n */\nexport function TasksCalendar(props: TasksCalendarProps) {\n const { tasks, onOpen, truncated } = props\n /*\n * The clock is read ONCE, at mount. A component that read `Date.now()`\n * per render would move the today square under a reader who left the tab\n * open across midnight, without any state having changed — and the grid\n * is a pure function of this, so what is drawn can be pinned.\n */\n const [nowMs] = useState(() => Date.now())\n const [anchorMs, setAnchorMs] = useState(() => nowMs)\n\n const month = useMemo(\n () => taskCalendarMonth(anchorMs, nowMs),\n [anchorMs, nowMs],\n )\n const buckets = useMemo(\n () => bucketTasksByCalendarDay(tasks, (task) => task.dueAtMs, month),\n [tasks, month],\n )\n const label = useMemo(\n () =>\n month.monthDate.toLocaleDateString(undefined, {\n month: 'long',\n year: 'numeric',\n }),\n [month],\n )\n\n return (\n <Stack spacing={1.5}>\n <Stack\n direction=\"row\"\n spacing={1}\n sx={{ alignItems: 'center', flexWrap: 'wrap', rowGap: 1 }}\n >\n <IconButton\n size=\"small\"\n aria-label=\"Previous month\"\n onClick={() => setAnchorMs((current) => shiftCalendarMonth(current, -1))}\n >\n <MdiIcon path={mdiChevronLeft.path} size={0.9} />\n </IconButton>\n <Typography variant=\"subtitle1\" sx={{ minWidth: 160, textAlign: 'center' }}>\n {label}\n </Typography>\n <IconButton\n size=\"small\"\n aria-label=\"Next month\"\n onClick={() => setAnchorMs((current) => shiftCalendarMonth(current, 1))}\n >\n <MdiIcon path={mdiChevronRight.path} size={0.9} />\n </IconButton>\n <Button size=\"small\" onClick={() => setAnchorMs(nowMs)}>\n {'Today'}\n </Button>\n </Stack>\n\n <Box sx={{ overflowX: 'auto' }}>\n <Box sx={{ minWidth: 640 }}>\n <Box\n sx={{\n display: 'grid',\n gridTemplateColumns: `repeat(${CALENDAR_WEEK_DAYS}, 1fr)`,\n gap: 0.5,\n mb: 0.5,\n }}\n >\n {CALENDAR_DAY_LABELS.map((day) => (\n <Typography\n key={day}\n variant=\"caption\"\n color=\"text.secondary\"\n sx={{ textAlign: 'center' }}\n >\n {day}\n </Typography>\n ))}\n </Box>\n <Box\n sx={{\n display: 'grid',\n gridTemplateColumns: `repeat(${CALENDAR_WEEK_DAYS}, 1fr)`,\n gap: 0.5,\n }}\n >\n {month.weeks.flat().map((day) => {\n const held = buckets.byDay.get(day.startMs) ?? []\n const shown = held.slice(0, TASKS_PER_DAY)\n const folded = held.length - shown.length\n return (\n <Box\n key={day.startMs}\n sx={{\n minHeight: 96,\n p: 0.75,\n borderRadius: 1,\n border: 1,\n borderColor: day.isToday ? 'primary.main' : 'divider',\n bgcolor: day.inMonth ? 'background.paper' : 'action.hover',\n }}\n >\n <Typography\n variant=\"caption\"\n sx={{\n display: 'block',\n mb: 0.5,\n fontWeight: day.isToday ? 'fontWeightBold' : undefined,\n color: day.inMonth ? 'text.primary' : 'text.disabled',\n }}\n >\n {day.date}\n </Typography>\n <Stack spacing={0.25}>\n {shown.map((task) => (\n <ButtonBase\n key={task.$id}\n onClick={() => onOpen(task)}\n sx={{\n justifyContent: 'flex-start',\n width: '100%',\n px: 0.5,\n py: 0.25,\n borderRadius: 0.5,\n bgcolor: 'action.selected',\n '&:hover': { bgcolor: 'action.focus' },\n }}\n >\n <Typography\n variant=\"caption\"\n noWrap\n sx={{\n width: '100%',\n textAlign: 'left',\n textDecoration:\n task.status === 'done' ? 'line-through' : undefined,\n color:\n task.status === 'done'\n ? 'text.secondary'\n : day.endMs <= nowMs\n ? 'error.main'\n : 'text.primary',\n }}\n >\n {task.title}\n </Typography>\n </ButtonBase>\n ))}\n {folded > 0 ? (\n <Typography variant=\"caption\" color=\"text.secondary\">\n {`+${folded} more`}\n </Typography>\n ) : null}\n </Stack>\n </Box>\n )\n })}\n </Box>\n </Box>\n </Box>\n\n {/*\n What the grid could not place. Said plainly, because a month with\n nothing on it reads as \"nothing is due\" and the honest reading here\n is often \"the window's tasks are somewhere else\".\n */}\n {buckets.undated.length || buckets.elsewhere.length || truncated ? (\n <Typography variant=\"caption\" color=\"text.secondary\">\n {[\n buckets.elsewhere.length\n ? `${buckets.elsewhere.length} due outside this month`\n : '',\n buckets.undated.length\n ? `${buckets.undated.length} with no due date`\n : '',\n truncated ? 'and the view is showing only its first page' : '',\n ]\n .filter(Boolean)\n .join(' · ')}\n </Typography>\n ) : null}\n </Stack>\n )\n}\nTasksCalendar.displayName = 'TasksCalendar'\n\nexport default TasksCalendar\n"],"names":["mdiChevronLeft","mdiChevronRight","MdiIcon","Box","Button","ButtonBase","IconButton","Stack","Typography","useMemo","useState","bucketTasksByCalendarDay","CALENDAR_DAY_LABELS","CALENDAR_WEEK_DAYS","shiftCalendarMonth","taskCalendarMonth","TASKS_PER_DAY","TasksCalendar","props","tasks","onOpen","truncated","nowMs","Date","now","anchorMs","setAnchorMs","month","buckets","task","dueAtMs","label","monthDate","toLocaleDateString","undefined","year","spacing","direction","sx","alignItems","flexWrap","rowGap","size","aria-label","onClick","current","path","variant","minWidth","textAlign","overflowX","display","gridTemplateColumns","gap","mb","map","day","color","weeks","flat","held","byDay","get","startMs","shown","slice","folded","length","minHeight","p","borderRadius","border","borderColor","isToday","bgcolor","inMonth","fontWeight","date","justifyContent","width","px","py","noWrap","textDecoration","status","endMs","title","$id","undated","elsewhere","filter","Boolean","join","displayName"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GACD;;AAEA,SAASA,cAAc,EAAEC,eAAe,QAAQ,yBAAwB;AACxE,SAASC,OAAO,QAAQ,uBAAsB;AAC9C,SAASC,GAAG,EAAEC,MAAM,EAAEC,UAAU,EAAEC,UAAU,EAAEC,KAAK,EAAEC,UAAU,QAAQ,gBAAe;AACtF,SAASC,OAAO,EAAEC,QAAQ,QAAQ,QAAO;AAEzC,SACEC,wBAAwB,EACxBC,mBAAmB,EACnBC,kBAAkB,EAClBC,kBAAkB,EAClBC,iBAAiB,QACZ,4BAAwB;AAE/B,wEAAwE,GACxE,MAAMC,gBAAgB;AAWtB;;;;;;;;;;;;;;;;;;;;;;;CAuBC,GACD,OAAO,SAASC,cAAcC,KAAyB;IACrD,MAAM,EAAEC,KAAK,EAAEC,MAAM,EAAEC,SAAS,EAAE,GAAGH;IACrC;;;;;GAKC,GACD,MAAM,CAACI,MAAM,GAAGZ,SAAS,IAAMa,KAAKC,GAAG;IACvC,MAAM,CAACC,UAAUC,YAAY,GAAGhB,SAAS,IAAMY;IAE/C,MAAMK,QAAQlB,QACZ,IAAMM,kBAAkBU,UAAUH,QAClC;QAACG;QAAUH;KAAM;IAEnB,MAAMM,UAAUnB,QACd,IAAME,yBAAyBQ,OAAO,CAACU,OAASA,KAAKC,OAAO,EAAEH,QAC9D;QAACR;QAAOQ;KAAM;IAEhB,MAAMI,QAAQtB,QACZ,IACEkB,MAAMK,SAAS,CAACC,kBAAkB,CAACC,WAAW;YAC5CP,OAAO;YACPQ,MAAM;QACR,IACF;QAACR;KAAM;IAGT,qBACE,MAACpB;QAAM6B,SAAS;;0BACd,MAAC7B;gBACC8B,WAAU;gBACVD,SAAS;gBACTE,IAAI;oBAAEC,YAAY;oBAAUC,UAAU;oBAAQC,QAAQ;gBAAE;;kCAExD,KAACnC;wBACCoC,MAAK;wBACLC,cAAW;wBACXC,SAAS,IAAMlB,YAAY,CAACmB,UAAY/B,mBAAmB+B,SAAS,CAAC;kCAErE,cAAA,KAAC3C;4BAAQ4C,MAAM9C,eAAe8C,IAAI;4BAAEJ,MAAM;;;kCAE5C,KAAClC;wBAAWuC,SAAQ;wBAAYT,IAAI;4BAAEU,UAAU;4BAAKC,WAAW;wBAAS;kCACtElB;;kCAEH,KAACzB;wBACCoC,MAAK;wBACLC,cAAW;wBACXC,SAAS,IAAMlB,YAAY,CAACmB,UAAY/B,mBAAmB+B,SAAS;kCAEpE,cAAA,KAAC3C;4BAAQ4C,MAAM7C,gBAAgB6C,IAAI;4BAAEJ,MAAM;;;kCAE7C,KAACtC;wBAAOsC,MAAK;wBAAQE,SAAS,IAAMlB,YAAYJ;kCAC7C;;;;0BAIL,KAACnB;gBAAImC,IAAI;oBAAEY,WAAW;gBAAO;0BAC3B,cAAA,MAAC/C;oBAAImC,IAAI;wBAAEU,UAAU;oBAAI;;sCACvB,KAAC7C;4BACCmC,IAAI;gCACFa,SAAS;gCACTC,qBAAqB,CAAC,OAAO,EAAEvC,mBAAmB,MAAM,CAAC;gCACzDwC,KAAK;gCACLC,IAAI;4BACN;sCAEC1C,oBAAoB2C,GAAG,CAAC,CAACC,oBACxB,KAAChD;oCAECuC,SAAQ;oCACRU,OAAM;oCACNnB,IAAI;wCAAEW,WAAW;oCAAS;8CAEzBO;mCALIA;;sCASX,KAACrD;4BACCmC,IAAI;gCACFa,SAAS;gCACTC,qBAAqB,CAAC,OAAO,EAAEvC,mBAAmB,MAAM,CAAC;gCACzDwC,KAAK;4BACP;sCAEC1B,MAAM+B,KAAK,CAACC,IAAI,GAAGJ,GAAG,CAAC,CAACC;oCACV5B;gCAAb,MAAMgC,QAAOhC,qBAAAA,QAAQiC,KAAK,CAACC,GAAG,CAACN,IAAIO,OAAO,aAA7BnC,qBAAkC,EAAE;gCACjD,MAAMoC,QAAQJ,KAAKK,KAAK,CAAC,GAAGjD;gCAC5B,MAAMkD,SAASN,KAAKO,MAAM,GAAGH,MAAMG,MAAM;gCACzC,qBACE,MAAChE;oCAECmC,IAAI;wCACF8B,WAAW;wCACXC,GAAG;wCACHC,cAAc;wCACdC,QAAQ;wCACRC,aAAahB,IAAIiB,OAAO,GAAG,iBAAiB;wCAC5CC,SAASlB,IAAImB,OAAO,GAAG,qBAAqB;oCAC9C;;sDAEA,KAACnE;4CACCuC,SAAQ;4CACRT,IAAI;gDACFa,SAAS;gDACTG,IAAI;gDACJsB,YAAYpB,IAAIiB,OAAO,GAAG,mBAAmBvC;gDAC7CuB,OAAOD,IAAImB,OAAO,GAAG,iBAAiB;4CACxC;sDAECnB,IAAIqB,IAAI;;sDAEX,MAACtE;4CAAM6B,SAAS;;gDACb4B,MAAMT,GAAG,CAAC,CAAC1B,qBACV,KAACxB;wDAECuC,SAAS,IAAMxB,OAAOS;wDACtBS,IAAI;4DACFwC,gBAAgB;4DAChBC,OAAO;4DACPC,IAAI;4DACJC,IAAI;4DACJX,cAAc;4DACdI,SAAS;4DACT,WAAW;gEAAEA,SAAS;4DAAe;wDACvC;kEAEA,cAAA,KAAClE;4DACCuC,SAAQ;4DACRmC,MAAM;4DACN5C,IAAI;gEACFyC,OAAO;gEACP9B,WAAW;gEACXkC,gBACEtD,KAAKuD,MAAM,KAAK,SAAS,iBAAiBlD;gEAC5CuB,OACE5B,KAAKuD,MAAM,KAAK,SACZ,mBACA5B,IAAI6B,KAAK,IAAI/D,QACX,eACA;4DACV;sEAECO,KAAKyD,KAAK;;uDA5BRzD,KAAK0D,GAAG;gDAgChBrB,SAAS,kBACR,KAAC1D;oDAAWuC,SAAQ;oDAAUU,OAAM;8DACjC,CAAC,CAAC,EAAES,OAAO,KAAK,CAAC;qDAElB;;;;mCA5DDV,IAAIO,OAAO;4BAgEtB;;;;;YAULnC,QAAQ4D,OAAO,CAACrB,MAAM,IAAIvC,QAAQ6D,SAAS,CAACtB,MAAM,IAAI9C,0BACrD,KAACb;gBAAWuC,SAAQ;gBAAUU,OAAM;0BACjC;oBACC7B,QAAQ6D,SAAS,CAACtB,MAAM,GACpB,GAAGvC,QAAQ6D,SAAS,CAACtB,MAAM,CAAC,uBAAuB,CAAC,GACpD;oBACJvC,QAAQ4D,OAAO,CAACrB,MAAM,GAClB,GAAGvC,QAAQ4D,OAAO,CAACrB,MAAM,CAAC,iBAAiB,CAAC,GAC5C;oBACJ9C,YAAY,gDAAgD;iBAC7D,CACEqE,MAAM,CAACC,SACPC,IAAI,CAAC;iBAER;;;AAGV;AACA3E,cAAc4E,WAAW,GAAG;AAE5B,eAAe5E,cAAa"}
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/crm/src/lib/components/tasks-calendar.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 { type CrmTaskPicklists, crmTaskPicklistLabels } from '@aglyn/aglyn'\nimport { mdiChevronLeft, mdiChevronRight } from '@aglyn/shared-data-mdi'\nimport { MdiIcon } from '@aglyn/shared-ui-jsx'\nimport { Box, Button, ButtonBase, IconButton, Stack, Typography } from '@mui/material'\nimport { useMemo, useState } from 'react'\nimport type { CrmTaskRow } from '../hooks/use-crm-tasks'\nimport {\n bucketTasksByCalendarDay,\n CALENDAR_DAY_LABELS,\n CALENDAR_WEEK_DAYS,\n shiftCalendarMonth,\n taskCalendarMonth,\n} from '../model/task-calendar'\n\n/** How many tasks a square lists before folding the rest into a count. */\nconst TASKS_PER_DAY = 3\n\nexport interface TasksCalendarProps {\n /** The window the list is holding — the calendar reads no more than it. */\n tasks: readonly CrmTaskRow[]\n /** Open one task's drawer, the same drawer a row opens. */\n onOpen: (task: CrmTaskRow) => void\n /** The list's window filled, so neither surface is showing everything. */\n truncated?: boolean\n /** The org's task lists, which name each entry's type and status on hover (AGL-3517). */\n picklists?: CrmTaskPicklists\n}\n\n/**\n * A MONTH OF TASKS, BY DUE DATE (AGL-2662).\n *\n * The Tasks list answers \"what is on my plate\"; this answers \"what does\n * next week look like\", which a list ordered by due date can only imply.\n *\n * ## Drawn over the list's own window, and never over a second read\n *\n * The rows are the ones the section already holds. A calendar that fetched\n * its own month would be a second listener over the same collection, would\n * disagree with the list whenever the two windows differed, and would put\n * a read behind every page of the arrows. What it costs instead is honesty:\n * the grid can only place what the window carries, so the tasks due in\n * other months are counted under it rather than implied to be absent.\n *\n * ## Hand-built rather than a calendar dependency\n *\n * Seven columns of MUI boxes and the local-day arithmetic in\n * `task-calendar.ts`. The one calendar package already installed\n * (`@mui/x-date-pickers`) draws a date PICKER — a grid whose squares are\n * choices, not content — so it answers a different question, and a\n * scheduling library for one surface is a dependency the whole console\n * would carry.\n */\nexport function TasksCalendar(props: TasksCalendarProps) {\n const { tasks, onOpen, truncated, picklists } = props\n /** \"Call Ada · Call · In Progress\" — the entry's type and status on hover. */\n const hoverText = (task: CrmTaskRow) => {\n if (!picklists) return task.title\n const labels = crmTaskPicklistLabels(task, picklists)\n return `${task.title} · ${labels.type} · ${labels.status}`\n }\n /*\n * The clock is read ONCE, at mount. A component that read `Date.now()`\n * per render would move the today square under a reader who left the tab\n * open across midnight, without any state having changed — and the grid\n * is a pure function of this, so what is drawn can be pinned.\n */\n const [nowMs] = useState(() => Date.now())\n const [anchorMs, setAnchorMs] = useState(() => nowMs)\n\n const month = useMemo(\n () => taskCalendarMonth(anchorMs, nowMs),\n [anchorMs, nowMs],\n )\n const buckets = useMemo(\n () => bucketTasksByCalendarDay(tasks, (task) => task.dueAtMs, month),\n [tasks, month],\n )\n const label = useMemo(\n () =>\n month.monthDate.toLocaleDateString(undefined, {\n month: 'long',\n year: 'numeric',\n }),\n [month],\n )\n\n return (\n <Stack spacing={1.5}>\n <Stack\n direction=\"row\"\n spacing={1}\n sx={{ alignItems: 'center', flexWrap: 'wrap', rowGap: 1 }}\n >\n <IconButton\n size=\"small\"\n aria-label=\"Previous month\"\n onClick={() => setAnchorMs((current) => shiftCalendarMonth(current, -1))}\n >\n <MdiIcon path={mdiChevronLeft.path} size={0.9} />\n </IconButton>\n <Typography variant=\"subtitle1\" sx={{ minWidth: 160, textAlign: 'center' }}>\n {label}\n </Typography>\n <IconButton\n size=\"small\"\n aria-label=\"Next month\"\n onClick={() => setAnchorMs((current) => shiftCalendarMonth(current, 1))}\n >\n <MdiIcon path={mdiChevronRight.path} size={0.9} />\n </IconButton>\n <Button size=\"small\" onClick={() => setAnchorMs(nowMs)}>\n {'Today'}\n </Button>\n </Stack>\n\n <Box sx={{ overflowX: 'auto' }}>\n <Box sx={{ minWidth: 640 }}>\n <Box\n sx={{\n display: 'grid',\n gridTemplateColumns: `repeat(${CALENDAR_WEEK_DAYS}, 1fr)`,\n gap: 0.5,\n mb: 0.5,\n }}\n >\n {CALENDAR_DAY_LABELS.map((day) => (\n <Typography\n key={day}\n variant=\"caption\"\n color=\"text.secondary\"\n sx={{ textAlign: 'center' }}\n >\n {day}\n </Typography>\n ))}\n </Box>\n <Box\n sx={{\n display: 'grid',\n gridTemplateColumns: `repeat(${CALENDAR_WEEK_DAYS}, 1fr)`,\n gap: 0.5,\n }}\n >\n {month.weeks.flat().map((day) => {\n const held = buckets.byDay.get(day.startMs) ?? []\n const shown = held.slice(0, TASKS_PER_DAY)\n const folded = held.length - shown.length\n return (\n <Box\n key={day.startMs}\n sx={{\n minHeight: 96,\n p: 0.75,\n borderRadius: 1,\n border: 1,\n borderColor: day.isToday ? 'primary.main' : 'divider',\n bgcolor: day.inMonth ? 'background.paper' : 'action.hover',\n }}\n >\n <Typography\n variant=\"caption\"\n sx={{\n display: 'block',\n mb: 0.5,\n fontWeight: day.isToday ? 'fontWeightBold' : undefined,\n color: day.inMonth ? 'text.primary' : 'text.disabled',\n }}\n >\n {day.date}\n </Typography>\n <Stack spacing={0.25}>\n {shown.map((task) => (\n <ButtonBase\n key={task.$id}\n onClick={() => onOpen(task)}\n title={hoverText(task)}\n sx={{\n justifyContent: 'flex-start',\n width: '100%',\n px: 0.5,\n py: 0.25,\n borderRadius: 0.5,\n bgcolor: 'action.selected',\n '&:hover': { bgcolor: 'action.focus' },\n }}\n >\n <Typography\n variant=\"caption\"\n noWrap\n sx={{\n width: '100%',\n textAlign: 'left',\n textDecoration:\n task.status === 'done' ? 'line-through' : undefined,\n color:\n task.status === 'done'\n ? 'text.secondary'\n : day.endMs <= nowMs\n ? 'error.main'\n : 'text.primary',\n }}\n >\n {task.title}\n </Typography>\n </ButtonBase>\n ))}\n {folded > 0 ? (\n <Typography variant=\"caption\" color=\"text.secondary\">\n {`+${folded} more`}\n </Typography>\n ) : null}\n </Stack>\n </Box>\n )\n })}\n </Box>\n </Box>\n </Box>\n\n {/*\n What the grid could not place. Said plainly, because a month with\n nothing on it reads as \"nothing is due\" and the honest reading here\n is often \"the window's tasks are somewhere else\".\n */}\n {buckets.undated.length || buckets.elsewhere.length || truncated ? (\n <Typography variant=\"caption\" color=\"text.secondary\">\n {[\n buckets.elsewhere.length\n ? `${buckets.elsewhere.length} due outside this month`\n : '',\n buckets.undated.length\n ? `${buckets.undated.length} with no due date`\n : '',\n truncated ? 'and the view is showing only its first page' : '',\n ]\n .filter(Boolean)\n .join(' · ')}\n </Typography>\n ) : null}\n </Stack>\n )\n}\nTasksCalendar.displayName = 'TasksCalendar'\n\nexport default TasksCalendar\n"],"names":["crmTaskPicklistLabels","mdiChevronLeft","mdiChevronRight","MdiIcon","Box","Button","ButtonBase","IconButton","Stack","Typography","useMemo","useState","bucketTasksByCalendarDay","CALENDAR_DAY_LABELS","CALENDAR_WEEK_DAYS","shiftCalendarMonth","taskCalendarMonth","TASKS_PER_DAY","TasksCalendar","props","tasks","onOpen","truncated","picklists","hoverText","task","title","labels","type","status","nowMs","Date","now","anchorMs","setAnchorMs","month","buckets","dueAtMs","label","monthDate","toLocaleDateString","undefined","year","spacing","direction","sx","alignItems","flexWrap","rowGap","size","aria-label","onClick","current","path","variant","minWidth","textAlign","overflowX","display","gridTemplateColumns","gap","mb","map","day","color","weeks","flat","held","byDay","get","startMs","shown","slice","folded","length","minHeight","p","borderRadius","border","borderColor","isToday","bgcolor","inMonth","fontWeight","date","justifyContent","width","px","py","noWrap","textDecoration","endMs","$id","undated","elsewhere","filter","Boolean","join","displayName"],"mappings":"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"}
|
|
@@ -16,9 +16,9 @@ import { type ConsolePluginPageProps } from '@aglyn/aglyn';
|
|
|
16
16
|
*
|
|
17
17
|
* The rows are selectable, and a selection raises `TasksBulkBar` over the
|
|
18
18
|
* list — Complete and Assign through their routes, the due date and the
|
|
19
|
-
* delete as batched writes (AGL-2621). Export
|
|
20
|
-
*
|
|
21
|
-
*
|
|
19
|
+
* delete as batched writes (AGL-2621). Import and Export open the console's
|
|
20
|
+
* wizard and dialog on `crm.tasks` (AGL-3528); the export reads the view's
|
|
21
|
+
* own query, and the bar opens it on the selection.
|
|
22
22
|
*/
|
|
23
23
|
export declare function TasksSection(props: ConsolePluginPageProps): import("react").JSX.Element;
|
|
24
24
|
export declare namespace TasksSection {
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
*/ 'use client';
|
|
17
17
|
import { _ as _extends } from "@swc/helpers/_/_extends";
|
|
18
18
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
19
|
-
import { CRM_COLLECTIONS,
|
|
19
|
+
import { CRM_COLLECTIONS, crmPicklistShownLabel, crmTaskPicklistLabels, crmTaskStatusWrite, pluginDocsHelp } from "@aglyn/aglyn";
|
|
20
20
|
import { CardDisplay } from "@aglyn/shared-ui-jsx";
|
|
21
21
|
import { ListTable } from "@aglyn/shared-ui-jsx/components/list-table.component";
|
|
22
22
|
import { useCrmSavedView } from "../hooks/use-crm-saved-view.js";
|
|
@@ -32,13 +32,12 @@ import { useCallback, useEffect, useMemo, useState } from "react";
|
|
|
32
32
|
import { useCrmRecordNames } from "../hooks/use-crm-record-names.js";
|
|
33
33
|
import { useCrmTaskList, useNowMs } from "../hooks/use-crm-tasks.js";
|
|
34
34
|
import { useOrgMemberDirectory } from "../hooks/use-org-member-directory.js";
|
|
35
|
-
import {
|
|
35
|
+
import { useCrmTaskPicklists } from "../hooks/use-crm-task-picklists.js";
|
|
36
36
|
import { crmRoutes } from "../model/crm-routes.js";
|
|
37
37
|
import { refreshCrmNextActivity } from "../model/next-activity-api.js";
|
|
38
38
|
import { completeCrmTask } from "../model/task-api.js";
|
|
39
39
|
import { crmTaskCallScope } from "../model/task-routes.js";
|
|
40
|
-
import {
|
|
41
|
-
import { CRM_TASK_KIND_LABELS, CRM_TASK_KINDS, CRM_TASK_PRIORITIES, CRM_TASK_PRIORITY_LABELS, CRM_TASK_VIEWS, TASK_LIST_QUERY_FIELDS } from "../model/task-views.js";
|
|
40
|
+
import { CRM_TASK_KINDS, CRM_TASK_PRIORITIES, CRM_TASK_VIEWS, TASK_LIST_QUERY_FIELDS } from "../model/task-views.js";
|
|
42
41
|
import { listFilterGridColumns } from "@aglyn/shared-ui-jsx/const/list-grid-filter";
|
|
43
42
|
import { ListPagination } from "@aglyn/shared-ui-jsx/components/list-pagination.component";
|
|
44
43
|
import { TABLE_PAGE_SIZE_DEFAULT } from "@aglyn/shared-ui-jsx/const/table-pagination";
|
|
@@ -49,7 +48,8 @@ import { CrmListActions, CrmListToolbar } from "./crm-list-toolbar.js";
|
|
|
49
48
|
import { TaskDueText, TaskKindCell, TaskPriorityChip, TaskRecordLink } from "./task-cells.js";
|
|
50
49
|
import TaskEditDrawer from "./task-edit-drawer.js";
|
|
51
50
|
import TasksCalendar from "./tasks-calendar.js";
|
|
52
|
-
import {
|
|
51
|
+
import { CrmExportButton, CrmImportButton } from "./crm-transfer-buttons.js";
|
|
52
|
+
import { CRM_TASKS_RESOURCE } from "../transfer/fields.js";
|
|
53
53
|
import TaskSnoozeMenu from "./task-snooze-menu.js";
|
|
54
54
|
import TasksBulkBar from "./tasks-bulk-bar.js";
|
|
55
55
|
/** What an empty view is headed, by view — "nothing overdue" is good news. */ /*
|
|
@@ -70,7 +70,7 @@ import TasksBulkBar from "./tasks-bulk-bar.js";
|
|
|
70
70
|
];
|
|
71
71
|
const TASK_FILTER_HEADERS = {
|
|
72
72
|
view: 'Show',
|
|
73
|
-
kind: '
|
|
73
|
+
kind: 'Type',
|
|
74
74
|
priority: 'Priority',
|
|
75
75
|
assigneeUid: 'Assignee'
|
|
76
76
|
};
|
|
@@ -116,9 +116,9 @@ const EMPTY_LABEL = {
|
|
|
116
116
|
*
|
|
117
117
|
* The rows are selectable, and a selection raises `TasksBulkBar` over the
|
|
118
118
|
* list — Complete and Assign through their routes, the due date and the
|
|
119
|
-
* delete as batched writes (AGL-2621). Export
|
|
120
|
-
*
|
|
121
|
-
*
|
|
119
|
+
* delete as batched writes (AGL-2621). Import and Export open the console's
|
|
120
|
+
* wizard and dialog on `crm.tasks` (AGL-3528); the export reads the view's
|
|
121
|
+
* own query, and the bar opens it on the selection.
|
|
122
122
|
*/ export function TasksSection(props) {
|
|
123
123
|
var _ref;
|
|
124
124
|
const { hostId, org, basePath = '' } = props;
|
|
@@ -194,25 +194,31 @@ const EMPTY_LABEL = {
|
|
|
194
194
|
});
|
|
195
195
|
const { tasks, status, fromCache, scope, orgId, readTokens } = list;
|
|
196
196
|
const directory = useOrgMemberDirectory(orgId);
|
|
197
|
-
const
|
|
197
|
+
const picklists = useCrmTaskPicklists(orgId);
|
|
198
|
+
/*
|
|
199
|
+
* Type and Priority filter on the MEANING the query holds (AGL-3517), so
|
|
200
|
+
* each option is a meaning, named by the org's label for it.
|
|
201
|
+
*/ const filterOptions = useMemo(()=>({
|
|
198
202
|
view: CRM_TASK_VIEWS.map((option)=>({
|
|
199
203
|
value: option.id,
|
|
200
204
|
label: option.label
|
|
201
205
|
})),
|
|
202
206
|
kind: CRM_TASK_KINDS.map((kind)=>({
|
|
203
207
|
value: kind,
|
|
204
|
-
label:
|
|
208
|
+
label: crmPicklistShownLabel(picklists.type, kind, null)
|
|
205
209
|
})),
|
|
206
210
|
priority: CRM_TASK_PRIORITIES.map((priority)=>({
|
|
207
211
|
value: priority,
|
|
208
|
-
label:
|
|
212
|
+
label: crmPicklistShownLabel(picklists.priority, priority, null)
|
|
209
213
|
})),
|
|
210
214
|
assigneeUid: directory.members.map((member)=>({
|
|
211
215
|
value: member.uid,
|
|
212
216
|
label: member.label
|
|
213
217
|
}))
|
|
214
218
|
}), [
|
|
215
|
-
directory.members
|
|
219
|
+
directory.members,
|
|
220
|
+
picklists.type,
|
|
221
|
+
picklists.priority
|
|
216
222
|
]);
|
|
217
223
|
// What the query could not hold, said above the list rather than matched in memory.
|
|
218
224
|
const refused = useMemo(()=>listQueryRefusals(list.plan.refused, {
|
|
@@ -264,21 +270,12 @@ const EMPTY_LABEL = {
|
|
|
264
270
|
list.plan,
|
|
265
271
|
list.page
|
|
266
272
|
]);
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
},
|
|
272
|
-
recordName: nameOf
|
|
273
|
+
// The view and its filters, for the export to read the same tasks the list does (AGL-3528).
|
|
274
|
+
const exportFilter = useMemo(()=>({
|
|
275
|
+
label: 'what the list shows',
|
|
276
|
+
plan: list.plan
|
|
273
277
|
}), [
|
|
274
|
-
|
|
275
|
-
nameOf
|
|
276
|
-
]);
|
|
277
|
-
const handleExport = useCallback(()=>{
|
|
278
|
-
downloadTextFile('tasks.csv', 'text/csv', tasksCsv(tasks, csvOptions));
|
|
279
|
-
}, [
|
|
280
|
-
tasks,
|
|
281
|
-
csvOptions
|
|
278
|
+
list.plan
|
|
282
279
|
]);
|
|
283
280
|
/*
|
|
284
281
|
* List or month (AGL-2662). A layout choice over the SAME rows and the
|
|
@@ -314,12 +311,11 @@ const EMPTY_LABEL = {
|
|
|
314
311
|
setBusyId(task.$id);
|
|
315
312
|
try {
|
|
316
313
|
if (task.status === 'done') {
|
|
317
|
-
await updateDoc(doc(firestore, scope[0], scope[1], CRM_COLLECTIONS.tasks, task.$id), {
|
|
318
|
-
status: 'open',
|
|
314
|
+
await updateDoc(doc(firestore, scope[0], scope[1], CRM_COLLECTIONS.tasks, task.$id), _extends({}, crmTaskStatusWrite(picklists.status, false), {
|
|
319
315
|
completedAtMs: null,
|
|
320
316
|
completedByUid: deleteField(),
|
|
321
317
|
updatedAt: serverTimestamp()
|
|
322
|
-
});
|
|
318
|
+
}));
|
|
323
319
|
enqueueSnackbar('Task reopened', {
|
|
324
320
|
variant: 'success'
|
|
325
321
|
});
|
|
@@ -354,7 +350,8 @@ const EMPTY_LABEL = {
|
|
|
354
350
|
user,
|
|
355
351
|
hostId,
|
|
356
352
|
orgId,
|
|
357
|
-
enqueueSnackbar
|
|
353
|
+
enqueueSnackbar,
|
|
354
|
+
picklists.status
|
|
358
355
|
]);
|
|
359
356
|
const columns = useMemo(()=>[
|
|
360
357
|
{
|
|
@@ -411,11 +408,12 @@ const EMPTY_LABEL = {
|
|
|
411
408
|
},
|
|
412
409
|
{
|
|
413
410
|
field: 'kind',
|
|
414
|
-
headerName: '
|
|
411
|
+
headerName: 'Type',
|
|
415
412
|
width: 120,
|
|
416
413
|
sortable: false,
|
|
417
414
|
renderCell: ({ row })=>/*#__PURE__*/ _jsx(TaskKindCell, {
|
|
418
|
-
kind: row.kind
|
|
415
|
+
kind: row.kind,
|
|
416
|
+
label: crmTaskPicklistLabels(row, picklists).type
|
|
419
417
|
})
|
|
420
418
|
},
|
|
421
419
|
{
|
|
@@ -424,7 +422,22 @@ const EMPTY_LABEL = {
|
|
|
424
422
|
width: 110,
|
|
425
423
|
sortable: false,
|
|
426
424
|
renderCell: ({ row })=>/*#__PURE__*/ _jsx(TaskPriorityChip, {
|
|
427
|
-
priority: row.priority
|
|
425
|
+
priority: row.priority,
|
|
426
|
+
label: crmTaskPicklistLabels(row, picklists).priority
|
|
427
|
+
})
|
|
428
|
+
},
|
|
429
|
+
{
|
|
430
|
+
// The org's status label (AGL-3517); the checkbox is the open/done half.
|
|
431
|
+
field: 'statusLabel',
|
|
432
|
+
headerName: 'Status',
|
|
433
|
+
width: 150,
|
|
434
|
+
sortable: false,
|
|
435
|
+
valueGetter: (_value, row)=>crmTaskPicklistLabels(row, picklists).status,
|
|
436
|
+
renderCell: ({ row })=>/*#__PURE__*/ _jsx(Typography, {
|
|
437
|
+
variant: "body2",
|
|
438
|
+
color: row.status === 'done' ? 'text.secondary' : undefined,
|
|
439
|
+
noWrap: true,
|
|
440
|
+
children: crmTaskPicklistLabels(row, picklists).status
|
|
428
441
|
})
|
|
429
442
|
},
|
|
430
443
|
{
|
|
@@ -492,7 +505,8 @@ const EMPTY_LABEL = {
|
|
|
492
505
|
directory,
|
|
493
506
|
routes,
|
|
494
507
|
nameOf,
|
|
495
|
-
scope
|
|
508
|
+
scope,
|
|
509
|
+
picklists
|
|
496
510
|
]);
|
|
497
511
|
/* The column and sort models are the view's (AGL-2617). */ const filterColumns = useMemo(()=>listFilterGridColumns(columns, TASK_FILTER_FIELDS, filterOptions, TASK_FILTER_HEADERS), [
|
|
498
512
|
columns,
|
|
@@ -513,14 +527,15 @@ const EMPTY_LABEL = {
|
|
|
513
527
|
// The record actions, top right and never clipped (AGL-3311).
|
|
514
528
|
action: /*#__PURE__*/ _jsxs(CrmListActions, {
|
|
515
529
|
children: [
|
|
516
|
-
/*#__PURE__*/ _jsx(
|
|
530
|
+
/*#__PURE__*/ _jsx(CrmImportButton, {
|
|
531
|
+
resource: CRM_TASKS_RESOURCE,
|
|
532
|
+
noun: "tasks",
|
|
517
533
|
hostId: hostId
|
|
518
534
|
}),
|
|
519
|
-
/*#__PURE__*/ _jsx(
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
children: 'Export CSV'
|
|
535
|
+
/*#__PURE__*/ _jsx(CrmExportButton, {
|
|
536
|
+
resource: CRM_TASKS_RESOURCE,
|
|
537
|
+
hostId: hostId,
|
|
538
|
+
filter: exportFilter
|
|
524
539
|
}),
|
|
525
540
|
/*#__PURE__*/ _jsx(Button, {
|
|
526
541
|
size: "small",
|
|
@@ -586,6 +601,7 @@ const EMPTY_LABEL = {
|
|
|
586
601
|
}) : /*#__PURE__*/ _jsx(_Fragment, {
|
|
587
602
|
children: layout === 'calendar' ? /*#__PURE__*/ _jsx(TasksCalendar, {
|
|
588
603
|
tasks: tasks,
|
|
604
|
+
picklists: picklists,
|
|
589
605
|
truncated: list.hasMore,
|
|
590
606
|
onOpen: (task)=>setDrawer({
|
|
591
607
|
open: true,
|
|
@@ -599,8 +615,7 @@ const EMPTY_LABEL = {
|
|
|
599
615
|
rows: tasks,
|
|
600
616
|
selected: selectedIds,
|
|
601
617
|
onSelectedChange: setSelectedIds,
|
|
602
|
-
directory: directory
|
|
603
|
-
csv: csvOptions
|
|
618
|
+
directory: directory
|
|
604
619
|
}),
|
|
605
620
|
/*#__PURE__*/ _jsx(CrmColumnOrderProvider, {
|
|
606
621
|
value: grid.columnOrder,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../../libs/plugins/crm/src/lib/components/tasks-section.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 ConsolePluginPageProps,\n CRM_COLLECTIONS,\n type CrmViewFilterClause,\n findOrgMember,\n pluginDocsHelp,\n} from '@aglyn/aglyn'\nimport { CardDisplay } from '@aglyn/shared-ui-jsx'\nimport { ListTable } from '@aglyn/shared-ui-jsx/components/list-table.component'\nimport { useCrmSavedView } from '../hooks/use-crm-saved-view'\nimport { useCrmScope } from '../hooks/use-crm-scope'\nimport { useCrmViewGrid } from '../hooks/use-crm-view-grid'\nimport { CRM_LIST_SLOTS, CrmColumnOrderProvider } from './crm-column-menu'\nimport CrmViewsControl from './crm-views-control'\nimport { useSnackbar } from '@aglyn/shared-ui-snackstack'\nimport { useFirestore, useUser } from '@aglyn/tenant-feature-instance'\nimport {\n Button,\n Checkbox,\n Stack,\n ToggleButton,\n ToggleButtonGroup,\n Typography,\n} from '@mui/material'\nimport type { GridColDef } from '@mui/x-data-grid'\nimport { deleteField, doc, serverTimestamp, updateDoc } from 'firebase/firestore'\nimport { useCallback, useEffect, useMemo, useState } from 'react'\nimport { useCrmRecordNames } from '../hooks/use-crm-record-names'\nimport { type CrmTaskRow, useCrmTaskList, useNowMs } from '../hooks/use-crm-tasks'\nimport { useOrgMemberDirectory } from '../hooks/use-org-member-directory'\nimport { downloadTextFile } from '../model/contacts-csv'\nimport { crmRoutes } from '../model/crm-routes'\nimport { refreshCrmNextActivity } from '../model/next-activity-api'\nimport { completeCrmTask } from '../model/task-api'\nimport { crmTaskCallScope } from '../model/task-routes'\nimport { type TaskCsvOptions, tasksCsv } from '../model/tasks-csv'\nimport {\n CRM_TASK_KIND_LABELS,\n CRM_TASK_KINDS,\n CRM_TASK_PRIORITIES,\n CRM_TASK_PRIORITY_LABELS,\n CRM_TASK_VIEWS,\n type CrmTaskView,\n TASK_LIST_QUERY_FIELDS,\n} from '../model/task-views'\nimport type { ListFilterField } from '@aglyn/shared-ui-jsx/const/list-filter'\nimport { listFilterGridColumns } from '@aglyn/shared-ui-jsx/const/list-grid-filter'\nimport { ListPagination } from '@aglyn/shared-ui-jsx/components/list-pagination.component'\nimport { TABLE_PAGE_SIZE_DEFAULT } from '@aglyn/shared-ui-jsx/const/table-pagination'\nimport ListQueryNotices, {\n listQueryRefusals,\n} from '@aglyn/shared-ui-jsx/components/list-query-notices.component'\nimport { useListGridFilter } from '@aglyn/shared-ui-jsx/hooks/use-list-grid-filter'\nimport ListFilterChips from '@aglyn/shared-ui-jsx/components/list-filter-chips.component'\nimport { CrmListActions, CrmListToolbar } from './crm-list-toolbar'\nimport {\n TaskDueText,\n TaskKindCell,\n TaskPriorityChip,\n TaskRecordLink,\n} from './task-cells'\nimport TaskEditDrawer from './task-edit-drawer'\nimport TasksCalendar from './tasks-calendar'\nimport { TaskImportButton } from './task-import-drawer'\nimport TaskSnoozeMenu from './task-snooze-menu'\nimport TasksBulkBar from './tasks-bulk-bar'\n\n/** What an empty view is headed, by view — \"nothing overdue\" is good news. */\n/*\n * What the tasks grid's panel offers (AGL-3313). `view` is the task view\n * the query's base answers — a hidden column, since it is no field of a\n * task — and Kind, Priority and Assignee are predicates on the same query\n * (AGL-3321).\n */\nconst TASK_FILTER_FIELDS: readonly ListFilterField[] = [\n { column: 'view', kind: 'exact', path: 'view', operators: ['equals'] },\n ...TASK_LIST_QUERY_FIELDS,\n]\nconst TASK_FILTER_HEADERS: Readonly<Record<string, string>> = {\n view: 'Show',\n kind: 'Kind',\n priority: 'Priority',\n assigneeUid: 'Assignee',\n}\n/** The filter-only `view` column never shows. */\nconst TASK_HIDDEN_COLUMNS: Readonly<Record<string, boolean>> = { view: false }\n/** How many tasks the month view reads: one page, sized for a month of work. */\nconst CALENDAR_PAGE_SIZE = 200\n/** No `view` clause is \"My tasks\", which the section opened on before views existed. */\nconst TASK_VIEW_DEFAULT: CrmViewFilterClause = { field: 'view', op: 'equals', value: 'mine' }\nconst EMPTY_LABEL: Record<CrmTaskView, string> = {\n mine: 'Nothing is assigned to you',\n overdue: 'Nothing is overdue',\n today: 'Nothing is due today',\n upcoming: 'Nothing is scheduled beyond today',\n open: 'No open tasks',\n done: 'No completed tasks yet',\n}\n\n/** The one sentence under it, by view. */\nconst EMPTY_COPY: Record<CrmTaskView, string> = {\n mine: 'Tasks you create are yours unless you hand them to someone.',\n overdue: 'Every dated task is on or ahead of schedule.',\n today: 'Nothing on your calendar day is owed to anyone in the CRM.',\n upcoming: 'A task with a due date past today would be listed here.',\n open: 'A task is a call, an email, a meeting or a to-do owed to a contact, a company or a deal.',\n done: 'Tasks ticked off on their record, or here, are kept for the history.',\n}\n\n/**\n * `/crm/tasks` — what the team owes the people in the CRM (AGL-2599).\n *\n * Six views over `orgs/{orgId}/crmTasks`, each a bounded listener on one of\n * the collection's indexes, chosen by a segmented control. A task hangs off\n * a contact, a company or a deal, but it is listed HERE because \"what is due\n * today\" is a question about the team's day and not about any one record;\n * the record pages carry their own `RecordTasksCard` for the other\n * direction.\n *\n * Completing goes through `crm/task-complete`, because completing fires the\n * `taskCompleted` host event and only the server can run a workflow.\n * Reopening is client-direct: undoing a tick has no side effect beyond the\n * document, and the rules gate it like any other CRM write.\n *\n * The rows are selectable, and a selection raises `TasksBulkBar` over the\n * list — Complete and Assign through their routes, the due date and the\n * delete as batched writes (AGL-2621). Export CSV beside the view control\n * writes the view through `tasksCsv()`, naming the assignee and the linked\n * records; the bar writes the same file over the selection.\n */\nexport function TasksSection(props: ConsolePluginPageProps) {\n const { hostId, org, basePath = '' } = props\n const orgRecord = org as Record<string, unknown> | undefined\n const firestore = useFirestore()\n const { data: user } = useUser()\n const { enqueueSnackbar } = useSnackbar()\n const nowMs = useNowMs()\n const routes = useMemo(() => crmRoutes(basePath), [basePath])\n // The viewing group a linked contact is named through, or `null` at the\n // organization level, where each is named through its own holder.\n const { consentGroup } = useCrmScope({ hostId, org: orgRecord })\n const groupId = consentGroup?.groupId ?? null\n\n /*\n * Which of the six task views is open is the saved VIEW'S (AGL-2617): a\n * saved view of tasks holds the task view beside the columns and the\n * sort, and the toggle below writes into it. Unset reads as \"My tasks\",\n * which is what the section opened on before views existed.\n */\n const views = useCrmSavedView({ section: 'tasks', hostId, org: orgRecord, basePath })\n const view: CrmTaskView = useMemo(() => {\n const value = views.state.filters.find((clause) => clause.field === 'view')?.value\n return CRM_TASK_VIEWS.some((option) => option.id === value)\n ? (value as CrmTaskView)\n : 'mine'\n }, [views.state.filters])\n /*\n * The grid's own Filters panel and quick search edit the view's clauses\n * (AGL-3313). \"Show\" is the task view the query's base answers — the\n * hidden `view` column, as the toggle stored it, with none meaning \"My\n * tasks\" — and Kind, Priority, Assignee and the search word are on the\n * same query (AGL-3321).\n */\n const clauses = useMemo(\n () =>\n views.state.filters.some((clause) => clause.field === 'view')\n ? views.state.filters\n : [TASK_VIEW_DEFAULT, ...views.state.filters],\n [views.state.filters],\n )\n const setClauses = useCallback(\n (next: CrmViewFilterClause[]) =>\n views.setFilters(\n next.filter(\n (clause) => !(clause.field === 'view' && clause.value === TASK_VIEW_DEFAULT.value),\n ),\n ),\n [views.setFilters],\n )\n const gridFilter = useListGridFilter({\n clauses,\n onChange: setClauses,\n selectFields: ['view', 'kind', 'priority', 'assigneeUid'],\n })\n const queryClauses = useMemo(\n () => clauses.filter((clause) => clause.field !== 'view'),\n [clauses],\n )\n const list = useCrmTaskList({\n hostId,\n org: orgRecord,\n view,\n uid: user?.uid,\n nowMs,\n clauses: queryClauses,\n search: gridFilter.searchWords,\n })\n const { tasks, status, fromCache, scope, orgId, readTokens } = list\n const directory = useOrgMemberDirectory(orgId)\n const filterOptions = useMemo(\n () => ({\n view: CRM_TASK_VIEWS.map((option) => ({ value: option.id, label: option.label })),\n kind: CRM_TASK_KINDS.map((kind) => ({ value: kind, label: CRM_TASK_KIND_LABELS[kind] })),\n priority: CRM_TASK_PRIORITIES.map((priority) => ({\n value: priority,\n label: CRM_TASK_PRIORITY_LABELS[priority],\n })),\n assigneeUid: directory.members.map((member) => ({\n value: member.uid,\n label: member.label,\n })),\n }),\n [directory.members],\n )\n // What the query could not hold, said above the list rather than matched in memory.\n const refused = useMemo(\n () =>\n listQueryRefusals(list.plan.refused, {\n fields: TASK_FILTER_FIELDS,\n headers: TASK_FILTER_HEADERS,\n options: filterOptions,\n }),\n [list.plan.refused, filterOptions],\n )\n const filtered = queryClauses.length > 0 || gridFilter.searchWords.some((word) => word.trim())\n\n /*\n * Every record a task names, not only the one its \"For\" cell shows: the\n * export writes the contact, the company and the deal each by name, and\n * a task that names two would otherwise carry an id in one column.\n */\n const linked = useMemo(\n () =>\n tasks.flatMap((task) => [\n ...(task.contactId ? [{ kind: 'contact' as const, id: task.contactId }] : []),\n ...(task.companyId ? [{ kind: 'company' as const, id: task.companyId }] : []),\n ...(task.dealId ? [{ kind: 'deal' as const, id: task.dealId }] : []),\n ]),\n [tasks],\n )\n const nameOf = useCrmRecordNames({ orgId, groupId, org: orgRecord, records: linked })\n\n const [selectedIds, setSelectedIds] = useState<string[]>([])\n // A view, a filter or a page is a different set of rows; a selection made\n // on the last one would be a count over rows no longer on screen.\n useEffect(() => setSelectedIds([]), [view, list.plan, list.page])\n const csvOptions: TaskCsvOptions = useMemo(\n () => ({\n assigneeEmail: (uid) => {\n const member = findOrgMember(directory.members, uid)\n return member?.email || member?.label || uid\n },\n recordName: nameOf,\n }),\n [directory.members, nameOf],\n )\n const handleExport = useCallback(() => {\n downloadTextFile('tasks.csv', 'text/csv', tasksCsv(tasks, csvOptions))\n }, [tasks, csvOptions])\n\n /*\n * List or month (AGL-2662). A layout choice over the SAME rows and the\n * same view — switching does not narrow anything and costs no read, so\n * it is a toggle rather than another saved view.\n */\n const [layout, setLayout] = useState<'list' | 'calendar'>('list')\n /*\n * The month draws one query page, so it asks for a month's worth: the\n * calendar's page is {@link CALENDAR_PAGE_SIZE} tasks of the same view and\n * filters, and it says when the view holds more. The list's own page size\n * comes back with the list.\n */\n const { setPage: setListPage, setPageSize: setListPageSize } = list\n useEffect(() => {\n setListPage(0)\n setListPageSize(layout === 'calendar' ? CALENDAR_PAGE_SIZE : TABLE_PAGE_SIZE_DEFAULT)\n }, [layout, setListPage, setListPageSize])\n const [drawer, setDrawer] = useState<{ open: boolean; task: CrmTaskRow | null }>({\n open: false,\n task: null,\n })\n const [busyId, setBusyId] = useState<string | null>(null)\n\n /*\n * Tick or untick. The two directions are two different writes on purpose\n * — see the module comment — and the row is disabled while either is in\n * flight so a double-click cannot complete a task and reopen it in the\n * same breath.\n */\n const toggleDone = useCallback(\n async (task: CrmTaskRow) => {\n if (!scope || busyId) return\n setBusyId(task.$id)\n try {\n if (task.status === 'done') {\n await updateDoc(\n doc(firestore, scope[0], scope[1], CRM_COLLECTIONS.tasks, task.$id),\n {\n status: 'open',\n completedAtMs: null,\n completedByUid: deleteField(),\n updatedAt: serverTimestamp(),\n },\n )\n enqueueSnackbar('Task reopened', { variant: 'success' })\n // A client-direct write: the records it names are told (AGL-2661).\n await refreshCrmNextActivity(user, crmTaskCallScope(hostId, orgId), [task])\n } else {\n // The route runs as the mounted site, which hears the event, or\n // at the organization level as the org — the org variant, which\n // emits on the task's own site, or nowhere for an org task.\n const callScope = crmTaskCallScope(hostId, orgId)\n if (!callScope) return\n await completeCrmTask(user, { ...callScope, taskId: task.$id })\n enqueueSnackbar('Task completed', { variant: 'success' })\n }\n } catch (cause) {\n enqueueSnackbar(\n cause instanceof Error ? cause.message : 'The task could not be updated.',\n { variant: 'warning' },\n )\n } finally {\n setBusyId(null)\n }\n },\n [scope, busyId, firestore, user, hostId, orgId, enqueueSnackbar],\n )\n\n const columns: GridColDef[] = useMemo(\n () => [\n {\n field: 'status',\n headerName: '',\n width: 56,\n sortable: false,\n filterable: false,\n renderCell: ({ row }: { row: CrmTaskRow }) => (\n <Checkbox\n size=\"small\"\n checked={row.status === 'done'}\n disabled={busyId === row.$id}\n onClick={(event) => {\n event.stopPropagation()\n void toggleDone(row)\n }}\n slotProps={{\n input: {\n 'aria-label':\n row.status === 'done'\n ? `Reopen \"${row.title}\"`\n : `Complete \"${row.title}\"`,\n },\n }}\n />\n ),\n },\n {\n field: 'title',\n headerName: 'Task',\n flex: 2,\n minWidth: 220,\n sortable: false,\n renderCell: ({ row }: { row: CrmTaskRow }) => (\n <Stack sx={{ justifyContent: 'center', height: '100%', minWidth: 0 }}>\n <Typography\n variant=\"body2\"\n noWrap\n sx={{\n textDecoration: row.status === 'done' ? 'line-through' : undefined,\n color: row.status === 'done' ? 'text.secondary' : undefined,\n }}\n >\n {row.title}\n </Typography>\n {row.notes ? (\n <Typography variant=\"caption\" color=\"text.secondary\" noWrap>\n {row.notes}\n </Typography>\n ) : null}\n </Stack>\n ),\n },\n {\n field: 'kind',\n headerName: 'Kind',\n width: 120,\n sortable: false,\n renderCell: ({ row }: { row: CrmTaskRow }) => <TaskKindCell kind={row.kind} />,\n },\n {\n field: 'priority',\n headerName: 'Priority',\n width: 110,\n sortable: false,\n renderCell: ({ row }: { row: CrmTaskRow }) => (\n <TaskPriorityChip priority={row.priority} />\n ),\n },\n {\n field: 'dueAtMs',\n headerName: 'Due',\n width: 260,\n sortable: false,\n renderCell: ({ row }: { row: CrmTaskRow }) => (\n <Stack direction=\"row\" spacing={0.5} sx={{ alignItems: 'center', height: '100%' }}>\n <TaskDueText task={row} nowMs={nowMs} />\n {row.status === 'done' || !scope ? null : (\n <TaskSnoozeMenu\n dueAtMs={row.dueAtMs}\n remindAtMs={row.remindAtMs}\n target={{\n write: {\n scope,\n taskId: row.$id,\n call: crmTaskCallScope(hostId, orgId),\n links: row,\n },\n }}\n disabled={busyId === row.$id}\n />\n )}\n </Stack>\n ),\n },\n {\n field: 'assigneeUid',\n headerName: 'Assignee',\n flex: 1,\n minWidth: 140,\n sortable: false,\n valueGetter: (_value: unknown, row: CrmTaskRow) =>\n directory.nameOf(row.assigneeUid),\n renderCell: ({ row }: { row: CrmTaskRow }) => (\n <Typography variant=\"body2\" color={row.assigneeUid ? undefined : 'text.secondary'}>\n {row.assigneeUid ? directory.nameOf(row.assigneeUid) : 'Unassigned'}\n </Typography>\n ),\n },\n {\n field: 'record',\n headerName: 'For',\n flex: 1,\n minWidth: 160,\n sortable: false,\n renderCell: ({ row }: { row: CrmTaskRow }) => (\n <TaskRecordLink task={row} routes={routes} nameOf={nameOf} />\n ),\n },\n ],\n [busyId, toggleDone, nowMs, directory, routes, nameOf, scope],\n )\n /* The column and sort models are the view's (AGL-2617). */\n const filterColumns = useMemo(\n () => listFilterGridColumns(columns, TASK_FILTER_FIELDS, filterOptions, TASK_FILTER_HEADERS),\n [columns, filterOptions],\n )\n const grid = useCrmViewGrid(views, filterColumns, TASK_HIDDEN_COLUMNS)\n\n return (\n <>\n <CardDisplay\n header={'Tasks'}\n help={pluginDocsHelp('crmTasks', {\n anchor: '#the-tasks-page',\n excerpt:\n 'Calls, emails, meetings and to-dos, each linked to the contact, ' +\n 'company or deal it is for. Overdue and today are read off the ' +\n 'due date as you look.',\n })}\n contentGutterX\n contentGutterY\n HeaderProps={{\n // The record actions, top right and never clipped (AGL-3311).\n action: (\n <CrmListActions>\n <TaskImportButton hostId={hostId} />\n <Button size=\"small\" onClick={handleExport} disabled={!tasks.length}>\n {'Export CSV'}\n </Button>\n <Button\n size=\"small\"\n variant=\"contained\"\n color=\"primary\"\n onClick={() => setDrawer({ open: true, task: null })}\n >\n {'New task'}\n </Button>\n </CrmListActions>\n ),\n }}\n >\n <Stack spacing={2}>\n {/*\n The saved view, and the clauses narrowing it as chips — \"Show\"\n among them — set in the grid's own Filters panel (AGL-3313).\n */}\n <CrmListToolbar label=\"Task filters\">\n <CrmViewsControl controller={views} allLabel=\"All tasks\" />\n <ListFilterChips\n fields={TASK_FILTER_FIELDS}\n headers={TASK_FILTER_HEADERS}\n clauses={clauses}\n onChange={setClauses}\n options={filterOptions}\n marksServed={false}\n />\n <ToggleButtonGroup\n exclusive\n size=\"small\"\n color=\"primary\"\n value={layout}\n onChange={(_event, next) => {\n if (next) setLayout(next as 'list' | 'calendar')\n }}\n aria-label=\"Task layout\"\n >\n <ToggleButton value=\"list\">{'List'}</ToggleButton>\n <ToggleButton value=\"calendar\">{'Calendar'}</ToggleButton>\n </ToggleButtonGroup>\n </CrmListToolbar>\n <ListQueryNotices refused={refused} notices={list.plan.notices} />\n {status === 'error' ? (\n <Typography variant=\"body2\" color=\"error\">\n {'The tasks could not be loaded. Reload to try again.'}\n </Typography>\n ) : (\n <>\n {/*\n The calendar draws the same rows, so there is no bulk bar\n over it: a selection is a list gesture, and a month grid\n offers nowhere to make one.\n */}\n {layout === 'calendar' ? (\n <TasksCalendar\n tasks={tasks}\n truncated={list.hasMore}\n onOpen={(task) => setDrawer({ open: true, task })}\n />\n ) : (\n <>\n <TasksBulkBar\n hostId={hostId}\n scope={scope}\n rows={tasks}\n selected={selectedIds}\n onSelectedChange={setSelectedIds}\n directory={directory}\n csv={csvOptions}\n />\n <CrmColumnOrderProvider value={grid.columnOrder}>\n <ListTable\n rows={tasks}\n columns={grid.columns}\n slots={CRM_LIST_SLOTS}\n selectable={{ selected: selectedIds, onChange: setSelectedIds }}\n loading={status === 'loading'}\n onOpen={(id) => {\n const found = tasks.find((row) => row.$id === id)\n if (found) setDrawer({ open: true, task: found })\n }}\n /*\n * The panel and the search are the grid's; the section\n * answers them, the view through the query (AGL-3313). An\n * empty view is said inside the grid rather than instead of\n * it, so its toolbar stays to choose another view.\n */\n noRowsLabel={filtered ? 'No tasks match these filters' : EMPTY_LABEL[view]}\n noRowsDescription={filtered ? undefined : EMPTY_COPY[view]}\n noRowsAction={\n filtered ? undefined : (\n <Button\n size=\"small\"\n variant=\"contained\"\n color=\"primary\"\n onClick={() => setDrawer({ open: true, task: null })}\n >\n {'New task'}\n </Button>\n )\n }\n filterMode=\"server\"\n filterModel={gridFilter.filterModel}\n onFilterModelChange={gridFilter.onFilterModelChange}\n quickFilter\n // The view orders the query (due soonest, or Done most\n // recently due), so the grid sorts nothing itself: a\n // sort over one page would reorder ten rows.\n sortingMode=\"server\"\n disableColumnSorting\n // Columns are the view's, controlled (AGL-2617).\n columnVisibilityModel={grid.columnVisibilityModel}\n onColumnVisibilityModelChange={grid.onColumnVisibilityModelChange}\n // Paged by the footer below, so the grid must not also slice.\n hideFooter\n />\n </CrmColumnOrderProvider>\n <ListPagination\n page={list.page}\n pageSize={list.pageSize}\n rowCount={tasks.length}\n hasMore={list.hasMore}\n onPageChange={list.setPage}\n onPageSizeChange={list.setPageSize}\n />\n </>\n )}\n </>\n )}\n </Stack>\n </CardDisplay>\n <TaskEditDrawer\n open={drawer.open}\n onClose={() => setDrawer((prev) => ({ ...prev, open: false }))}\n hostId={hostId}\n org={orgRecord}\n orgId={orgId}\n scope={scope}\n readTokens={readTokens}\n task={drawer.task}\n seed={{ fromCache, unreadable: status === 'error' }}\n />\n </>\n )\n}\nTasksSection.displayName = 'TasksSection'\n\nexport default TasksSection\n"],"names":["CRM_COLLECTIONS","findOrgMember","pluginDocsHelp","CardDisplay","ListTable","useCrmSavedView","useCrmScope","useCrmViewGrid","CRM_LIST_SLOTS","CrmColumnOrderProvider","CrmViewsControl","useSnackbar","useFirestore","useUser","Button","Checkbox","Stack","ToggleButton","ToggleButtonGroup","Typography","deleteField","doc","serverTimestamp","updateDoc","useCallback","useEffect","useMemo","useState","useCrmRecordNames","useCrmTaskList","useNowMs","useOrgMemberDirectory","downloadTextFile","crmRoutes","refreshCrmNextActivity","completeCrmTask","crmTaskCallScope","tasksCsv","CRM_TASK_KIND_LABELS","CRM_TASK_KINDS","CRM_TASK_PRIORITIES","CRM_TASK_PRIORITY_LABELS","CRM_TASK_VIEWS","TASK_LIST_QUERY_FIELDS","listFilterGridColumns","ListPagination","TABLE_PAGE_SIZE_DEFAULT","ListQueryNotices","listQueryRefusals","useListGridFilter","ListFilterChips","CrmListActions","CrmListToolbar","TaskDueText","TaskKindCell","TaskPriorityChip","TaskRecordLink","TaskEditDrawer","TasksCalendar","TaskImportButton","TaskSnoozeMenu","TasksBulkBar","TASK_FILTER_FIELDS","column","kind","path","operators","TASK_FILTER_HEADERS","view","priority","assigneeUid","TASK_HIDDEN_COLUMNS","CALENDAR_PAGE_SIZE","TASK_VIEW_DEFAULT","field","op","value","EMPTY_LABEL","mine","overdue","today","upcoming","open","done","EMPTY_COPY","TasksSection","props","hostId","org","basePath","orgRecord","firestore","data","user","enqueueSnackbar","nowMs","routes","consentGroup","groupId","views","section","state","filters","find","clause","some","option","id","clauses","setClauses","next","setFilters","filter","gridFilter","onChange","selectFields","queryClauses","list","uid","search","searchWords","tasks","status","fromCache","scope","orgId","readTokens","directory","filterOptions","map","label","members","member","refused","plan","fields","headers","options","filtered","length","word","trim","linked","flatMap","task","contactId","companyId","dealId","nameOf","records","selectedIds","setSelectedIds","page","csvOptions","assigneeEmail","email","recordName","handleExport","layout","setLayout","setPage","setListPage","setPageSize","setListPageSize","drawer","setDrawer","busyId","setBusyId","toggleDone","$id","completedAtMs","completedByUid","updatedAt","variant","callScope","taskId","cause","Error","message","columns","headerName","width","sortable","filterable","renderCell","row","size","checked","disabled","onClick","event","stopPropagation","slotProps","input","title","flex","minWidth","sx","justifyContent","height","noWrap","textDecoration","undefined","color","notes","direction","spacing","alignItems","dueAtMs","remindAtMs","target","write","call","links","valueGetter","_value","filterColumns","grid","header","help","anchor","excerpt","contentGutterX","contentGutterY","HeaderProps","action","controller","allLabel","marksServed","exclusive","_event","aria-label","notices","truncated","hasMore","onOpen","rows","selected","onSelectedChange","csv","columnOrder","slots","selectable","loading","found","noRowsLabel","noRowsDescription","noRowsAction","filterMode","filterModel","onFilterModelChange","quickFilter","sortingMode","disableColumnSorting","columnVisibilityModel","onColumnVisibilityModelChange","hideFooter","pageSize","rowCount","onPageChange","onPageSizeChange","onClose","prev","seed","unreadable","displayName"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/crm/src/lib/components/tasks-section.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 ConsolePluginPageProps,\n CRM_COLLECTIONS,\n crmPicklistShownLabel,\n crmTaskPicklistLabels,\n crmTaskStatusWrite,\n type CrmViewFilterClause,\n pluginDocsHelp,\n} from '@aglyn/aglyn'\nimport { CardDisplay } from '@aglyn/shared-ui-jsx'\nimport { ListTable } from '@aglyn/shared-ui-jsx/components/list-table.component'\nimport { useCrmSavedView } from '../hooks/use-crm-saved-view'\nimport { useCrmScope } from '../hooks/use-crm-scope'\nimport { useCrmViewGrid } from '../hooks/use-crm-view-grid'\nimport { CRM_LIST_SLOTS, CrmColumnOrderProvider } from './crm-column-menu'\nimport CrmViewsControl from './crm-views-control'\nimport { useSnackbar } from '@aglyn/shared-ui-snackstack'\nimport { useFirestore, useUser } from '@aglyn/tenant-feature-instance'\nimport {\n Button,\n Checkbox,\n Stack,\n ToggleButton,\n ToggleButtonGroup,\n Typography,\n} from '@mui/material'\nimport type { GridColDef } from '@mui/x-data-grid'\nimport { deleteField, doc, serverTimestamp, updateDoc } from 'firebase/firestore'\nimport { useCallback, useEffect, useMemo, useState } from 'react'\nimport { useCrmRecordNames } from '../hooks/use-crm-record-names'\nimport { type CrmTaskRow, useCrmTaskList, useNowMs } from '../hooks/use-crm-tasks'\nimport { useOrgMemberDirectory } from '../hooks/use-org-member-directory'\nimport { useCrmTaskPicklists } from '../hooks/use-crm-task-picklists'\nimport { crmRoutes } from '../model/crm-routes'\nimport { refreshCrmNextActivity } from '../model/next-activity-api'\nimport { completeCrmTask } from '../model/task-api'\nimport { crmTaskCallScope } from '../model/task-routes'\nimport {\n CRM_TASK_KINDS,\n CRM_TASK_PRIORITIES,\n CRM_TASK_VIEWS,\n type CrmTaskView,\n TASK_LIST_QUERY_FIELDS,\n} from '../model/task-views'\nimport type { ListFilterField } from '@aglyn/shared-ui-jsx/const/list-filter'\nimport { listFilterGridColumns } from '@aglyn/shared-ui-jsx/const/list-grid-filter'\nimport { ListPagination } from '@aglyn/shared-ui-jsx/components/list-pagination.component'\nimport { TABLE_PAGE_SIZE_DEFAULT } from '@aglyn/shared-ui-jsx/const/table-pagination'\nimport ListQueryNotices, {\n listQueryRefusals,\n} from '@aglyn/shared-ui-jsx/components/list-query-notices.component'\nimport { useListGridFilter } from '@aglyn/shared-ui-jsx/hooks/use-list-grid-filter'\nimport ListFilterChips from '@aglyn/shared-ui-jsx/components/list-filter-chips.component'\nimport { CrmListActions, CrmListToolbar } from './crm-list-toolbar'\nimport {\n TaskDueText,\n TaskKindCell,\n TaskPriorityChip,\n TaskRecordLink,\n} from './task-cells'\nimport TaskEditDrawer from './task-edit-drawer'\nimport TasksCalendar from './tasks-calendar'\nimport { CrmExportButton, CrmImportButton } from './crm-transfer-buttons'\nimport { CRM_TASKS_RESOURCE } from '../transfer/fields'\nimport TaskSnoozeMenu from './task-snooze-menu'\nimport TasksBulkBar from './tasks-bulk-bar'\n\n/** What an empty view is headed, by view — \"nothing overdue\" is good news. */\n/*\n * What the tasks grid's panel offers (AGL-3313). `view` is the task view\n * the query's base answers — a hidden column, since it is no field of a\n * task — and Kind, Priority and Assignee are predicates on the same query\n * (AGL-3321).\n */\nconst TASK_FILTER_FIELDS: readonly ListFilterField[] = [\n { column: 'view', kind: 'exact', path: 'view', operators: ['equals'] },\n ...TASK_LIST_QUERY_FIELDS,\n]\nconst TASK_FILTER_HEADERS: Readonly<Record<string, string>> = {\n view: 'Show',\n kind: 'Type',\n priority: 'Priority',\n assigneeUid: 'Assignee',\n}\n/** The filter-only `view` column never shows. */\nconst TASK_HIDDEN_COLUMNS: Readonly<Record<string, boolean>> = { view: false }\n/** How many tasks the month view reads: one page, sized for a month of work. */\nconst CALENDAR_PAGE_SIZE = 200\n/** No `view` clause is \"My tasks\", which the section opened on before views existed. */\nconst TASK_VIEW_DEFAULT: CrmViewFilterClause = { field: 'view', op: 'equals', value: 'mine' }\nconst EMPTY_LABEL: Record<CrmTaskView, string> = {\n mine: 'Nothing is assigned to you',\n overdue: 'Nothing is overdue',\n today: 'Nothing is due today',\n upcoming: 'Nothing is scheduled beyond today',\n open: 'No open tasks',\n done: 'No completed tasks yet',\n}\n\n/** The one sentence under it, by view. */\nconst EMPTY_COPY: Record<CrmTaskView, string> = {\n mine: 'Tasks you create are yours unless you hand them to someone.',\n overdue: 'Every dated task is on or ahead of schedule.',\n today: 'Nothing on your calendar day is owed to anyone in the CRM.',\n upcoming: 'A task with a due date past today would be listed here.',\n open: 'A task is a call, an email, a meeting or a to-do owed to a contact, a company or a deal.',\n done: 'Tasks ticked off on their record, or here, are kept for the history.',\n}\n\n/**\n * `/crm/tasks` — what the team owes the people in the CRM (AGL-2599).\n *\n * Six views over `orgs/{orgId}/crmTasks`, each a bounded listener on one of\n * the collection's indexes, chosen by a segmented control. A task hangs off\n * a contact, a company or a deal, but it is listed HERE because \"what is due\n * today\" is a question about the team's day and not about any one record;\n * the record pages carry their own `RecordTasksCard` for the other\n * direction.\n *\n * Completing goes through `crm/task-complete`, because completing fires the\n * `taskCompleted` host event and only the server can run a workflow.\n * Reopening is client-direct: undoing a tick has no side effect beyond the\n * document, and the rules gate it like any other CRM write.\n *\n * The rows are selectable, and a selection raises `TasksBulkBar` over the\n * list — Complete and Assign through their routes, the due date and the\n * delete as batched writes (AGL-2621). Import and Export open the console's\n * wizard and dialog on `crm.tasks` (AGL-3528); the export reads the view's\n * own query, and the bar opens it on the selection.\n */\nexport function TasksSection(props: ConsolePluginPageProps) {\n const { hostId, org, basePath = '' } = props\n const orgRecord = org as Record<string, unknown> | undefined\n const firestore = useFirestore()\n const { data: user } = useUser()\n const { enqueueSnackbar } = useSnackbar()\n const nowMs = useNowMs()\n const routes = useMemo(() => crmRoutes(basePath), [basePath])\n // The viewing group a linked contact is named through, or `null` at the\n // organization level, where each is named through its own holder.\n const { consentGroup } = useCrmScope({ hostId, org: orgRecord })\n const groupId = consentGroup?.groupId ?? null\n\n /*\n * Which of the six task views is open is the saved VIEW'S (AGL-2617): a\n * saved view of tasks holds the task view beside the columns and the\n * sort, and the toggle below writes into it. Unset reads as \"My tasks\",\n * which is what the section opened on before views existed.\n */\n const views = useCrmSavedView({ section: 'tasks', hostId, org: orgRecord, basePath })\n const view: CrmTaskView = useMemo(() => {\n const value = views.state.filters.find((clause) => clause.field === 'view')?.value\n return CRM_TASK_VIEWS.some((option) => option.id === value)\n ? (value as CrmTaskView)\n : 'mine'\n }, [views.state.filters])\n /*\n * The grid's own Filters panel and quick search edit the view's clauses\n * (AGL-3313). \"Show\" is the task view the query's base answers — the\n * hidden `view` column, as the toggle stored it, with none meaning \"My\n * tasks\" — and Kind, Priority, Assignee and the search word are on the\n * same query (AGL-3321).\n */\n const clauses = useMemo(\n () =>\n views.state.filters.some((clause) => clause.field === 'view')\n ? views.state.filters\n : [TASK_VIEW_DEFAULT, ...views.state.filters],\n [views.state.filters],\n )\n const setClauses = useCallback(\n (next: CrmViewFilterClause[]) =>\n views.setFilters(\n next.filter(\n (clause) => !(clause.field === 'view' && clause.value === TASK_VIEW_DEFAULT.value),\n ),\n ),\n [views.setFilters],\n )\n const gridFilter = useListGridFilter({\n clauses,\n onChange: setClauses,\n selectFields: ['view', 'kind', 'priority', 'assigneeUid'],\n })\n const queryClauses = useMemo(\n () => clauses.filter((clause) => clause.field !== 'view'),\n [clauses],\n )\n const list = useCrmTaskList({\n hostId,\n org: orgRecord,\n view,\n uid: user?.uid,\n nowMs,\n clauses: queryClauses,\n search: gridFilter.searchWords,\n })\n const { tasks, status, fromCache, scope, orgId, readTokens } = list\n const directory = useOrgMemberDirectory(orgId)\n const picklists = useCrmTaskPicklists(orgId)\n /*\n * Type and Priority filter on the MEANING the query holds (AGL-3517), so\n * each option is a meaning, named by the org's label for it.\n */\n const filterOptions = useMemo(\n () => ({\n view: CRM_TASK_VIEWS.map((option) => ({ value: option.id, label: option.label })),\n kind: CRM_TASK_KINDS.map((kind) => ({\n value: kind,\n label: crmPicklistShownLabel(picklists.type, kind, null),\n })),\n priority: CRM_TASK_PRIORITIES.map((priority) => ({\n value: priority,\n label: crmPicklistShownLabel(picklists.priority, priority, null),\n })),\n assigneeUid: directory.members.map((member) => ({\n value: member.uid,\n label: member.label,\n })),\n }),\n [directory.members, picklists.type, picklists.priority],\n )\n // What the query could not hold, said above the list rather than matched in memory.\n const refused = useMemo(\n () =>\n listQueryRefusals(list.plan.refused, {\n fields: TASK_FILTER_FIELDS,\n headers: TASK_FILTER_HEADERS,\n options: filterOptions,\n }),\n [list.plan.refused, filterOptions],\n )\n const filtered = queryClauses.length > 0 || gridFilter.searchWords.some((word) => word.trim())\n\n /*\n * Every record a task names, not only the one its \"For\" cell shows: the\n * export writes the contact, the company and the deal each by name, and\n * a task that names two would otherwise carry an id in one column.\n */\n const linked = useMemo(\n () =>\n tasks.flatMap((task) => [\n ...(task.contactId ? [{ kind: 'contact' as const, id: task.contactId }] : []),\n ...(task.companyId ? [{ kind: 'company' as const, id: task.companyId }] : []),\n ...(task.dealId ? [{ kind: 'deal' as const, id: task.dealId }] : []),\n ]),\n [tasks],\n )\n const nameOf = useCrmRecordNames({ orgId, groupId, org: orgRecord, records: linked })\n\n const [selectedIds, setSelectedIds] = useState<string[]>([])\n // A view, a filter or a page is a different set of rows; a selection made\n // on the last one would be a count over rows no longer on screen.\n useEffect(() => setSelectedIds([]), [view, list.plan, list.page])\n // The view and its filters, for the export to read the same tasks the list does (AGL-3528).\n const exportFilter = useMemo(() => ({ label: 'what the list shows', plan: list.plan }), [list.plan])\n\n /*\n * List or month (AGL-2662). A layout choice over the SAME rows and the\n * same view — switching does not narrow anything and costs no read, so\n * it is a toggle rather than another saved view.\n */\n const [layout, setLayout] = useState<'list' | 'calendar'>('list')\n /*\n * The month draws one query page, so it asks for a month's worth: the\n * calendar's page is {@link CALENDAR_PAGE_SIZE} tasks of the same view and\n * filters, and it says when the view holds more. The list's own page size\n * comes back with the list.\n */\n const { setPage: setListPage, setPageSize: setListPageSize } = list\n useEffect(() => {\n setListPage(0)\n setListPageSize(layout === 'calendar' ? CALENDAR_PAGE_SIZE : TABLE_PAGE_SIZE_DEFAULT)\n }, [layout, setListPage, setListPageSize])\n const [drawer, setDrawer] = useState<{ open: boolean; task: CrmTaskRow | null }>({\n open: false,\n task: null,\n })\n const [busyId, setBusyId] = useState<string | null>(null)\n\n /*\n * Tick or untick. The two directions are two different writes on purpose\n * — see the module comment — and the row is disabled while either is in\n * flight so a double-click cannot complete a task and reopen it in the\n * same breath.\n */\n const toggleDone = useCallback(\n async (task: CrmTaskRow) => {\n if (!scope || busyId) return\n setBusyId(task.$id)\n try {\n if (task.status === 'done') {\n await updateDoc(\n doc(firestore, scope[0], scope[1], CRM_COLLECTIONS.tasks, task.$id),\n {\n // Open again, with the label a new task starts with (AGL-3517).\n ...crmTaskStatusWrite(picklists.status, false),\n completedAtMs: null,\n completedByUid: deleteField(),\n updatedAt: serverTimestamp(),\n },\n )\n enqueueSnackbar('Task reopened', { variant: 'success' })\n // A client-direct write: the records it names are told (AGL-2661).\n await refreshCrmNextActivity(user, crmTaskCallScope(hostId, orgId), [task])\n } else {\n // The route runs as the mounted site, which hears the event, or\n // at the organization level as the org — the org variant, which\n // emits on the task's own site, or nowhere for an org task.\n const callScope = crmTaskCallScope(hostId, orgId)\n if (!callScope) return\n await completeCrmTask(user, { ...callScope, taskId: task.$id })\n enqueueSnackbar('Task completed', { variant: 'success' })\n }\n } catch (cause) {\n enqueueSnackbar(\n cause instanceof Error ? cause.message : 'The task could not be updated.',\n { variant: 'warning' },\n )\n } finally {\n setBusyId(null)\n }\n },\n [scope, busyId, firestore, user, hostId, orgId, enqueueSnackbar, picklists.status],\n )\n\n const columns: GridColDef[] = useMemo(\n () => [\n {\n field: 'status',\n headerName: '',\n width: 56,\n sortable: false,\n filterable: false,\n renderCell: ({ row }: { row: CrmTaskRow }) => (\n <Checkbox\n size=\"small\"\n checked={row.status === 'done'}\n disabled={busyId === row.$id}\n onClick={(event) => {\n event.stopPropagation()\n void toggleDone(row)\n }}\n slotProps={{\n input: {\n 'aria-label':\n row.status === 'done'\n ? `Reopen \"${row.title}\"`\n : `Complete \"${row.title}\"`,\n },\n }}\n />\n ),\n },\n {\n field: 'title',\n headerName: 'Task',\n flex: 2,\n minWidth: 220,\n sortable: false,\n renderCell: ({ row }: { row: CrmTaskRow }) => (\n <Stack sx={{ justifyContent: 'center', height: '100%', minWidth: 0 }}>\n <Typography\n variant=\"body2\"\n noWrap\n sx={{\n textDecoration: row.status === 'done' ? 'line-through' : undefined,\n color: row.status === 'done' ? 'text.secondary' : undefined,\n }}\n >\n {row.title}\n </Typography>\n {row.notes ? (\n <Typography variant=\"caption\" color=\"text.secondary\" noWrap>\n {row.notes}\n </Typography>\n ) : null}\n </Stack>\n ),\n },\n {\n field: 'kind',\n headerName: 'Type',\n width: 120,\n sortable: false,\n renderCell: ({ row }: { row: CrmTaskRow }) => (\n <TaskKindCell kind={row.kind} label={crmTaskPicklistLabels(row, picklists).type} />\n ),\n },\n {\n field: 'priority',\n headerName: 'Priority',\n width: 110,\n sortable: false,\n renderCell: ({ row }: { row: CrmTaskRow }) => (\n <TaskPriorityChip\n priority={row.priority}\n label={crmTaskPicklistLabels(row, picklists).priority}\n />\n ),\n },\n {\n // The org's status label (AGL-3517); the checkbox is the open/done half.\n field: 'statusLabel',\n headerName: 'Status',\n width: 150,\n sortable: false,\n valueGetter: (_value: unknown, row: CrmTaskRow) =>\n crmTaskPicklistLabels(row, picklists).status,\n renderCell: ({ row }: { row: CrmTaskRow }) => (\n <Typography\n variant=\"body2\"\n color={row.status === 'done' ? 'text.secondary' : undefined}\n noWrap\n >\n {crmTaskPicklistLabels(row, picklists).status}\n </Typography>\n ),\n },\n {\n field: 'dueAtMs',\n headerName: 'Due',\n width: 260,\n sortable: false,\n renderCell: ({ row }: { row: CrmTaskRow }) => (\n <Stack direction=\"row\" spacing={0.5} sx={{ alignItems: 'center', height: '100%' }}>\n <TaskDueText task={row} nowMs={nowMs} />\n {row.status === 'done' || !scope ? null : (\n <TaskSnoozeMenu\n dueAtMs={row.dueAtMs}\n remindAtMs={row.remindAtMs}\n target={{\n write: {\n scope,\n taskId: row.$id,\n call: crmTaskCallScope(hostId, orgId),\n links: row,\n },\n }}\n disabled={busyId === row.$id}\n />\n )}\n </Stack>\n ),\n },\n {\n field: 'assigneeUid',\n headerName: 'Assignee',\n flex: 1,\n minWidth: 140,\n sortable: false,\n valueGetter: (_value: unknown, row: CrmTaskRow) =>\n directory.nameOf(row.assigneeUid),\n renderCell: ({ row }: { row: CrmTaskRow }) => (\n <Typography variant=\"body2\" color={row.assigneeUid ? undefined : 'text.secondary'}>\n {row.assigneeUid ? directory.nameOf(row.assigneeUid) : 'Unassigned'}\n </Typography>\n ),\n },\n {\n field: 'record',\n headerName: 'For',\n flex: 1,\n minWidth: 160,\n sortable: false,\n renderCell: ({ row }: { row: CrmTaskRow }) => (\n <TaskRecordLink task={row} routes={routes} nameOf={nameOf} />\n ),\n },\n ],\n [busyId, toggleDone, nowMs, directory, routes, nameOf, scope, picklists],\n )\n /* The column and sort models are the view's (AGL-2617). */\n const filterColumns = useMemo(\n () => listFilterGridColumns(columns, TASK_FILTER_FIELDS, filterOptions, TASK_FILTER_HEADERS),\n [columns, filterOptions],\n )\n const grid = useCrmViewGrid(views, filterColumns, TASK_HIDDEN_COLUMNS)\n\n return (\n <>\n <CardDisplay\n header={'Tasks'}\n help={pluginDocsHelp('crmTasks', {\n anchor: '#the-tasks-page',\n excerpt:\n 'Calls, emails, meetings and to-dos, each linked to the contact, ' +\n 'company or deal it is for. Overdue and today are read off the ' +\n 'due date as you look.',\n })}\n contentGutterX\n contentGutterY\n HeaderProps={{\n // The record actions, top right and never clipped (AGL-3311).\n action: (\n <CrmListActions>\n <CrmImportButton resource={CRM_TASKS_RESOURCE} noun=\"tasks\" hostId={hostId} />\n <CrmExportButton resource={CRM_TASKS_RESOURCE} hostId={hostId} filter={exportFilter} />\n <Button\n size=\"small\"\n variant=\"contained\"\n color=\"primary\"\n onClick={() => setDrawer({ open: true, task: null })}\n >\n {'New task'}\n </Button>\n </CrmListActions>\n ),\n }}\n >\n <Stack spacing={2}>\n {/*\n The saved view, and the clauses narrowing it as chips — \"Show\"\n among them — set in the grid's own Filters panel (AGL-3313).\n */}\n <CrmListToolbar label=\"Task filters\">\n <CrmViewsControl controller={views} allLabel=\"All tasks\" />\n <ListFilterChips\n fields={TASK_FILTER_FIELDS}\n headers={TASK_FILTER_HEADERS}\n clauses={clauses}\n onChange={setClauses}\n options={filterOptions}\n marksServed={false}\n />\n <ToggleButtonGroup\n exclusive\n size=\"small\"\n color=\"primary\"\n value={layout}\n onChange={(_event, next) => {\n if (next) setLayout(next as 'list' | 'calendar')\n }}\n aria-label=\"Task layout\"\n >\n <ToggleButton value=\"list\">{'List'}</ToggleButton>\n <ToggleButton value=\"calendar\">{'Calendar'}</ToggleButton>\n </ToggleButtonGroup>\n </CrmListToolbar>\n <ListQueryNotices refused={refused} notices={list.plan.notices} />\n {status === 'error' ? (\n <Typography variant=\"body2\" color=\"error\">\n {'The tasks could not be loaded. Reload to try again.'}\n </Typography>\n ) : (\n <>\n {/*\n The calendar draws the same rows, so there is no bulk bar\n over it: a selection is a list gesture, and a month grid\n offers nowhere to make one.\n */}\n {layout === 'calendar' ? (\n <TasksCalendar\n tasks={tasks}\n picklists={picklists}\n truncated={list.hasMore}\n onOpen={(task) => setDrawer({ open: true, task })}\n />\n ) : (\n <>\n <TasksBulkBar\n hostId={hostId}\n scope={scope}\n rows={tasks}\n selected={selectedIds}\n onSelectedChange={setSelectedIds}\n directory={directory}\n />\n <CrmColumnOrderProvider value={grid.columnOrder}>\n <ListTable\n rows={tasks}\n columns={grid.columns}\n slots={CRM_LIST_SLOTS}\n selectable={{ selected: selectedIds, onChange: setSelectedIds }}\n loading={status === 'loading'}\n onOpen={(id) => {\n const found = tasks.find((row) => row.$id === id)\n if (found) setDrawer({ open: true, task: found })\n }}\n /*\n * The panel and the search are the grid's; the section\n * answers them, the view through the query (AGL-3313). An\n * empty view is said inside the grid rather than instead of\n * it, so its toolbar stays to choose another view.\n */\n noRowsLabel={filtered ? 'No tasks match these filters' : EMPTY_LABEL[view]}\n noRowsDescription={filtered ? undefined : EMPTY_COPY[view]}\n noRowsAction={\n filtered ? undefined : (\n <Button\n size=\"small\"\n variant=\"contained\"\n color=\"primary\"\n onClick={() => setDrawer({ open: true, task: null })}\n >\n {'New task'}\n </Button>\n )\n }\n filterMode=\"server\"\n filterModel={gridFilter.filterModel}\n onFilterModelChange={gridFilter.onFilterModelChange}\n quickFilter\n // The view orders the query (due soonest, or Done most\n // recently due), so the grid sorts nothing itself: a\n // sort over one page would reorder ten rows.\n sortingMode=\"server\"\n disableColumnSorting\n // Columns are the view's, controlled (AGL-2617).\n columnVisibilityModel={grid.columnVisibilityModel}\n onColumnVisibilityModelChange={grid.onColumnVisibilityModelChange}\n // Paged by the footer below, so the grid must not also slice.\n hideFooter\n />\n </CrmColumnOrderProvider>\n <ListPagination\n page={list.page}\n pageSize={list.pageSize}\n rowCount={tasks.length}\n hasMore={list.hasMore}\n onPageChange={list.setPage}\n onPageSizeChange={list.setPageSize}\n />\n </>\n )}\n </>\n )}\n </Stack>\n </CardDisplay>\n <TaskEditDrawer\n open={drawer.open}\n onClose={() => setDrawer((prev) => ({ ...prev, open: false }))}\n hostId={hostId}\n org={orgRecord}\n orgId={orgId}\n scope={scope}\n readTokens={readTokens}\n task={drawer.task}\n seed={{ fromCache, unreadable: status === 'error' }}\n />\n </>\n )\n}\nTasksSection.displayName = 'TasksSection'\n\nexport default TasksSection\n"],"names":["CRM_COLLECTIONS","crmPicklistShownLabel","crmTaskPicklistLabels","crmTaskStatusWrite","pluginDocsHelp","CardDisplay","ListTable","useCrmSavedView","useCrmScope","useCrmViewGrid","CRM_LIST_SLOTS","CrmColumnOrderProvider","CrmViewsControl","useSnackbar","useFirestore","useUser","Button","Checkbox","Stack","ToggleButton","ToggleButtonGroup","Typography","deleteField","doc","serverTimestamp","updateDoc","useCallback","useEffect","useMemo","useState","useCrmRecordNames","useCrmTaskList","useNowMs","useOrgMemberDirectory","useCrmTaskPicklists","crmRoutes","refreshCrmNextActivity","completeCrmTask","crmTaskCallScope","CRM_TASK_KINDS","CRM_TASK_PRIORITIES","CRM_TASK_VIEWS","TASK_LIST_QUERY_FIELDS","listFilterGridColumns","ListPagination","TABLE_PAGE_SIZE_DEFAULT","ListQueryNotices","listQueryRefusals","useListGridFilter","ListFilterChips","CrmListActions","CrmListToolbar","TaskDueText","TaskKindCell","TaskPriorityChip","TaskRecordLink","TaskEditDrawer","TasksCalendar","CrmExportButton","CrmImportButton","CRM_TASKS_RESOURCE","TaskSnoozeMenu","TasksBulkBar","TASK_FILTER_FIELDS","column","kind","path","operators","TASK_FILTER_HEADERS","view","priority","assigneeUid","TASK_HIDDEN_COLUMNS","CALENDAR_PAGE_SIZE","TASK_VIEW_DEFAULT","field","op","value","EMPTY_LABEL","mine","overdue","today","upcoming","open","done","EMPTY_COPY","TasksSection","props","hostId","org","basePath","orgRecord","firestore","data","user","enqueueSnackbar","nowMs","routes","consentGroup","groupId","views","section","state","filters","find","clause","some","option","id","clauses","setClauses","next","setFilters","filter","gridFilter","onChange","selectFields","queryClauses","list","uid","search","searchWords","tasks","status","fromCache","scope","orgId","readTokens","directory","picklists","filterOptions","map","label","type","members","member","refused","plan","fields","headers","options","filtered","length","word","trim","linked","flatMap","task","contactId","companyId","dealId","nameOf","records","selectedIds","setSelectedIds","page","exportFilter","layout","setLayout","setPage","setListPage","setPageSize","setListPageSize","drawer","setDrawer","busyId","setBusyId","toggleDone","$id","completedAtMs","completedByUid","updatedAt","variant","callScope","taskId","cause","Error","message","columns","headerName","width","sortable","filterable","renderCell","row","size","checked","disabled","onClick","event","stopPropagation","slotProps","input","title","flex","minWidth","sx","justifyContent","height","noWrap","textDecoration","undefined","color","notes","valueGetter","_value","direction","spacing","alignItems","dueAtMs","remindAtMs","target","write","call","links","filterColumns","grid","header","help","anchor","excerpt","contentGutterX","contentGutterY","HeaderProps","action","resource","noun","controller","allLabel","marksServed","exclusive","_event","aria-label","notices","truncated","hasMore","onOpen","rows","selected","onSelectedChange","columnOrder","slots","selectable","loading","found","noRowsLabel","noRowsDescription","noRowsAction","filterMode","filterModel","onFilterModelChange","quickFilter","sortingMode","disableColumnSorting","columnVisibilityModel","onColumnVisibilityModelChange","hideFooter","pageSize","rowCount","onPageChange","onPageSizeChange","onClose","prev","seed","unreadable","displayName"],"mappings":"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"}
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
* See the License for the specific language governing permissions and
|
|
15
15
|
* limitations under the License.
|
|
16
16
|
*/
|
|
17
|
-
import type { CrmActionRecipeId } from '
|
|
17
|
+
import type { CrmActionRecipeId } from '../model/crm-recipes';
|
|
18
18
|
/**
|
|
19
19
|
* The CRM plugin's console API routes, as the dispatcher keys them.
|
|
20
20
|
*
|
|
@@ -88,13 +88,6 @@ export declare const CRM_API_ROUTES: {
|
|
|
88
88
|
* `server/inbound-route.ts`.
|
|
89
89
|
*/
|
|
90
90
|
readonly inbound: "crm/inbound";
|
|
91
|
-
/**
|
|
92
|
-
* `GET` — one of the organization's CRM collections, or a site's leads,
|
|
93
|
-
* as a CSV streamed over every row (AGL-2662); the contacts and leads
|
|
94
|
-
* files are every workspace's (a portability route), see
|
|
95
|
-
* `server/export-route.ts`.
|
|
96
|
-
*/
|
|
97
|
-
readonly export: "crm/export";
|
|
98
91
|
};
|
|
99
92
|
/**
|
|
100
93
|
* One site's answer to `crm/recipe-status` (AGL-2639).
|
|
@@ -115,7 +108,7 @@ export interface CrmRecipeInstallRequest {
|
|
|
115
108
|
hostId: string;
|
|
116
109
|
orgId?: string;
|
|
117
110
|
recipeId: CrmActionRecipeId;
|
|
118
|
-
/** The site's form a recipe that `
|
|
111
|
+
/** The site's form a recipe that picks one (`picks: 'form'`) is keyed on. */
|
|
119
112
|
formId?: string;
|
|
120
113
|
}
|
|
121
114
|
/** What a successful `crm/recipe-install` answers with. */
|
|
@@ -72,13 +72,7 @@
|
|
|
72
72
|
* `POST` — the mail provider's signed notice of a message received at a
|
|
73
73
|
* capture address (AGL-2657); a machine's route, see
|
|
74
74
|
* `server/inbound-route.ts`.
|
|
75
|
-
*/ inbound: 'crm/inbound'
|
|
76
|
-
/**
|
|
77
|
-
* `GET` — one of the organization's CRM collections, or a site's leads,
|
|
78
|
-
* as a CSV streamed over every row (AGL-2662); the contacts and leads
|
|
79
|
-
* files are every workspace's (a portability route), see
|
|
80
|
-
* `server/export-route.ts`.
|
|
81
|
-
*/ export: 'crm/export'
|
|
75
|
+
*/ inbound: 'crm/inbound'
|
|
82
76
|
};
|
|
83
77
|
/**
|
|
84
78
|
* What an organization-level activity line may point at: the CRM's record
|