@aglyn/plugins-crm 1.0.0-beta.143

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (669) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +7 -0
  3. package/package.json +57 -0
  4. package/src/index.d.ts +21 -0
  5. package/src/index.js +29 -0
  6. package/src/index.js.map +1 -0
  7. package/src/lib/components/activity-list.d.ts +98 -0
  8. package/src/lib/components/activity-list.js +321 -0
  9. package/src/lib/components/activity-list.js.map +1 -0
  10. package/src/lib/components/activity-queries.d.ts +117 -0
  11. package/src/lib/components/activity-queries.js +198 -0
  12. package/src/lib/components/activity-queries.js.map +1 -0
  13. package/src/lib/components/add-to-list-button.d.ts +25 -0
  14. package/src/lib/components/add-to-list-button.js +64 -0
  15. package/src/lib/components/add-to-list-button.js.map +1 -0
  16. package/src/lib/components/add-to-list-dialog.d.ts +24 -0
  17. package/src/lib/components/add-to-list-dialog.js +327 -0
  18. package/src/lib/components/add-to-list-dialog.js.map +1 -0
  19. package/src/lib/components/assignment-rule-drawer.d.ts +43 -0
  20. package/src/lib/components/assignment-rule-drawer.js +293 -0
  21. package/src/lib/components/assignment-rule-drawer.js.map +1 -0
  22. package/src/lib/components/companies-bulk-bar.d.ts +29 -0
  23. package/src/lib/components/companies-bulk-bar.js +274 -0
  24. package/src/lib/components/companies-bulk-bar.js.map +1 -0
  25. package/src/lib/components/companies-section.d.ts +54 -0
  26. package/src/lib/components/companies-section.js +522 -0
  27. package/src/lib/components/companies-section.js.map +1 -0
  28. package/src/lib/components/company-contacts-card.d.ts +49 -0
  29. package/src/lib/components/company-contacts-card.js +435 -0
  30. package/src/lib/components/company-contacts-card.js.map +1 -0
  31. package/src/lib/components/company-deals-card.d.ts +20 -0
  32. package/src/lib/components/company-deals-card.js +38 -0
  33. package/src/lib/components/company-deals-card.js.map +1 -0
  34. package/src/lib/components/company-detail-page.d.ts +20 -0
  35. package/src/lib/components/company-detail-page.js +165 -0
  36. package/src/lib/components/company-detail-page.js.map +1 -0
  37. package/src/lib/components/company-edit-drawer.d.ts +65 -0
  38. package/src/lib/components/company-edit-drawer.js +433 -0
  39. package/src/lib/components/company-edit-drawer.js.map +1 -0
  40. package/src/lib/components/company-import-drawer.d.ts +42 -0
  41. package/src/lib/components/company-import-drawer.js +99 -0
  42. package/src/lib/components/company-import-drawer.js.map +1 -0
  43. package/src/lib/components/company-picker.d.ts +127 -0
  44. package/src/lib/components/company-picker.js +323 -0
  45. package/src/lib/components/company-picker.js.map +1 -0
  46. package/src/lib/components/company-properties-card.d.ts +47 -0
  47. package/src/lib/components/company-properties-card.js +289 -0
  48. package/src/lib/components/company-properties-card.js.map +1 -0
  49. package/src/lib/components/contact-address-fields.d.ts +29 -0
  50. package/src/lib/components/contact-address-fields.js +149 -0
  51. package/src/lib/components/contact-address-fields.js.map +1 -0
  52. package/src/lib/components/contact-associations-card.d.ts +72 -0
  53. package/src/lib/components/contact-associations-card.js +296 -0
  54. package/src/lib/components/contact-associations-card.js.map +1 -0
  55. package/src/lib/components/contact-custom-columns.d.ts +38 -0
  56. package/src/lib/components/contact-custom-columns.js +102 -0
  57. package/src/lib/components/contact-custom-columns.js.map +1 -0
  58. package/src/lib/components/contact-custom-fields-card.d.ts +39 -0
  59. package/src/lib/components/contact-custom-fields-card.js +204 -0
  60. package/src/lib/components/contact-custom-fields-card.js.map +1 -0
  61. package/src/lib/components/contact-deals-card.d.ts +20 -0
  62. package/src/lib/components/contact-deals-card.js +38 -0
  63. package/src/lib/components/contact-deals-card.js.map +1 -0
  64. package/src/lib/components/contact-detail-page.d.ts +46 -0
  65. package/src/lib/components/contact-detail-page.js +535 -0
  66. package/src/lib/components/contact-detail-page.js.map +1 -0
  67. package/src/lib/components/contact-duplicates-card.d.ts +42 -0
  68. package/src/lib/components/contact-duplicates-card.js +167 -0
  69. package/src/lib/components/contact-duplicates-card.js.map +1 -0
  70. package/src/lib/components/contact-field-drawer.d.ts +64 -0
  71. package/src/lib/components/contact-field-drawer.js +251 -0
  72. package/src/lib/components/contact-field-drawer.js.map +1 -0
  73. package/src/lib/components/contact-import-drawer.d.ts +46 -0
  74. package/src/lib/components/contact-import-drawer.js +149 -0
  75. package/src/lib/components/contact-import-drawer.js.map +1 -0
  76. package/src/lib/components/contact-known-by-card.d.ts +39 -0
  77. package/src/lib/components/contact-known-by-card.js +142 -0
  78. package/src/lib/components/contact-known-by-card.js.map +1 -0
  79. package/src/lib/components/contact-list-columns.d.ts +53 -0
  80. package/src/lib/components/contact-list-columns.js +288 -0
  81. package/src/lib/components/contact-list-columns.js.map +1 -0
  82. package/src/lib/components/contact-merge-dialog.d.ts +79 -0
  83. package/src/lib/components/contact-merge-dialog.js +405 -0
  84. package/src/lib/components/contact-merge-dialog.js.map +1 -0
  85. package/src/lib/components/contact-properties-card.d.ts +89 -0
  86. package/src/lib/components/contact-properties-card.js +492 -0
  87. package/src/lib/components/contact-properties-card.js.map +1 -0
  88. package/src/lib/components/contact-timeline-card.d.ts +68 -0
  89. package/src/lib/components/contact-timeline-card.js +435 -0
  90. package/src/lib/components/contact-timeline-card.js.map +1 -0
  91. package/src/lib/components/contacts-bulk-bar.d.ts +91 -0
  92. package/src/lib/components/contacts-bulk-bar.js +493 -0
  93. package/src/lib/components/contacts-bulk-bar.js.map +1 -0
  94. package/src/lib/components/contacts-section.d.ts +26 -0
  95. package/src/lib/components/contacts-section.js +1025 -0
  96. package/src/lib/components/contacts-section.js.map +1 -0
  97. package/src/lib/components/copy-capture-address-button.d.ts +33 -0
  98. package/src/lib/components/copy-capture-address-button.js +60 -0
  99. package/src/lib/components/copy-capture-address-button.js.map +1 -0
  100. package/src/lib/components/crm-attribution-zone.d.ts +38 -0
  101. package/src/lib/components/crm-attribution-zone.js +36 -0
  102. package/src/lib/components/crm-attribution-zone.js.map +1 -0
  103. package/src/lib/components/crm-booking-zone.d.ts +61 -0
  104. package/src/lib/components/crm-booking-zone.js +50 -0
  105. package/src/lib/components/crm-booking-zone.js.map +1 -0
  106. package/src/lib/components/crm-bulk-bar-frame.d.ts +47 -0
  107. package/src/lib/components/crm-bulk-bar-frame.js +137 -0
  108. package/src/lib/components/crm-bulk-bar-frame.js.map +1 -0
  109. package/src/lib/components/crm-call-actions.d.ts +65 -0
  110. package/src/lib/components/crm-call-actions.js +110 -0
  111. package/src/lib/components/crm-call-actions.js.map +1 -0
  112. package/src/lib/components/crm-column-menu.d.ts +21 -0
  113. package/src/lib/components/crm-column-menu.js +103 -0
  114. package/src/lib/components/crm-column-menu.js.map +1 -0
  115. package/src/lib/components/crm-console-page.d.ts +19 -0
  116. package/src/lib/components/crm-console-page.js +151 -0
  117. package/src/lib/components/crm-console-page.js.map +1 -0
  118. package/src/lib/components/crm-console-sections.d.ts +52 -0
  119. package/src/lib/components/crm-console-sections.js +83 -0
  120. package/src/lib/components/crm-console-sections.js.map +1 -0
  121. package/src/lib/components/crm-custom-field-control.d.ts +26 -0
  122. package/src/lib/components/crm-custom-field-control.js +131 -0
  123. package/src/lib/components/crm-custom-field-control.js.map +1 -0
  124. package/src/lib/components/crm-email-template-tools.d.ts +69 -0
  125. package/src/lib/components/crm-email-template-tools.js +240 -0
  126. package/src/lib/components/crm-email-template-tools.js.map +1 -0
  127. package/src/lib/components/crm-export-all-button.d.ts +39 -0
  128. package/src/lib/components/crm-export-all-button.js +98 -0
  129. package/src/lib/components/crm-export-all-button.js.map +1 -0
  130. package/src/lib/components/crm-filter-bar.d.ts +53 -0
  131. package/src/lib/components/crm-filter-bar.js +294 -0
  132. package/src/lib/components/crm-filter-bar.js.map +1 -0
  133. package/src/lib/components/crm-glance-card.d.ts +54 -0
  134. package/src/lib/components/crm-glance-card.js +219 -0
  135. package/src/lib/components/crm-glance-card.js.map +1 -0
  136. package/src/lib/components/crm-next-activity-column.d.ts +35 -0
  137. package/src/lib/components/crm-next-activity-column.js +100 -0
  138. package/src/lib/components/crm-next-activity-column.js.map +1 -0
  139. package/src/lib/components/crm-record-header.d.ts +97 -0
  140. package/src/lib/components/crm-record-header.js +160 -0
  141. package/src/lib/components/crm-record-header.js.map +1 -0
  142. package/src/lib/components/crm-record-insights-zone.d.ts +50 -0
  143. package/src/lib/components/crm-record-insights-zone.js +169 -0
  144. package/src/lib/components/crm-record-insights-zone.js.map +1 -0
  145. package/src/lib/components/crm-record-picker.d.ts +42 -0
  146. package/src/lib/components/crm-record-picker.js +104 -0
  147. package/src/lib/components/crm-record-picker.js.map +1 -0
  148. package/src/lib/components/crm-send-email-button.d.ts +39 -0
  149. package/src/lib/components/crm-send-email-button.js +81 -0
  150. package/src/lib/components/crm-send-email-button.js.map +1 -0
  151. package/src/lib/components/crm-send-email-dialog.d.ts +61 -0
  152. package/src/lib/components/crm-send-email-dialog.js +851 -0
  153. package/src/lib/components/crm-send-email-dialog.js.map +1 -0
  154. package/src/lib/components/crm-site-picker.d.ts +61 -0
  155. package/src/lib/components/crm-site-picker.js +99 -0
  156. package/src/lib/components/crm-site-picker.js.map +1 -0
  157. package/src/lib/components/crm-suite-lock.d.ts +29 -0
  158. package/src/lib/components/crm-suite-lock.js +114 -0
  159. package/src/lib/components/crm-suite-lock.js.map +1 -0
  160. package/src/lib/components/crm-tasks-due-card.d.ts +42 -0
  161. package/src/lib/components/crm-tasks-due-card.js +225 -0
  162. package/src/lib/components/crm-tasks-due-card.js.map +1 -0
  163. package/src/lib/components/crm-views-control.d.ts +65 -0
  164. package/src/lib/components/crm-views-control.js +518 -0
  165. package/src/lib/components/crm-views-control.js.map +1 -0
  166. package/src/lib/components/csv-import-drawer.d.ts +132 -0
  167. package/src/lib/components/csv-import-drawer.js +746 -0
  168. package/src/lib/components/csv-import-drawer.js.map +1 -0
  169. package/src/lib/components/deal-board.d.ts +70 -0
  170. package/src/lib/components/deal-board.js +478 -0
  171. package/src/lib/components/deal-board.js.map +1 -0
  172. package/src/lib/components/deal-detail-page.d.ts +18 -0
  173. package/src/lib/components/deal-detail-page.js +323 -0
  174. package/src/lib/components/deal-detail-page.js.map +1 -0
  175. package/src/lib/components/deal-edit-drawer.d.ts +59 -0
  176. package/src/lib/components/deal-edit-drawer.js +640 -0
  177. package/src/lib/components/deal-edit-drawer.js.map +1 -0
  178. package/src/lib/components/deal-import-drawer.d.ts +24 -0
  179. package/src/lib/components/deal-import-drawer.js +83 -0
  180. package/src/lib/components/deal-import-drawer.js.map +1 -0
  181. package/src/lib/components/deal-products-card.d.ts +48 -0
  182. package/src/lib/components/deal-products-card.js +614 -0
  183. package/src/lib/components/deal-products-card.js.map +1 -0
  184. package/src/lib/components/deal-properties-card.d.ts +29 -0
  185. package/src/lib/components/deal-properties-card.js +144 -0
  186. package/src/lib/components/deal-properties-card.js.map +1 -0
  187. package/src/lib/components/deal-stage-card.d.ts +24 -0
  188. package/src/lib/components/deal-stage-card.js +199 -0
  189. package/src/lib/components/deal-stage-card.js.map +1 -0
  190. package/src/lib/components/deals-bulk-bar.d.ts +31 -0
  191. package/src/lib/components/deals-bulk-bar.js +340 -0
  192. package/src/lib/components/deals-bulk-bar.js.map +1 -0
  193. package/src/lib/components/deals-section.d.ts +49 -0
  194. package/src/lib/components/deals-section.js +767 -0
  195. package/src/lib/components/deals-section.js.map +1 -0
  196. package/src/lib/components/email-capture-card.d.ts +42 -0
  197. package/src/lib/components/email-capture-card.js +134 -0
  198. package/src/lib/components/email-capture-card.js.map +1 -0
  199. package/src/lib/components/email-template-drawer.d.ts +33 -0
  200. package/src/lib/components/email-template-drawer.js +209 -0
  201. package/src/lib/components/email-template-drawer.js.map +1 -0
  202. package/src/lib/components/email-templates-card.d.ts +33 -0
  203. package/src/lib/components/email-templates-card.js +370 -0
  204. package/src/lib/components/email-templates-card.js.map +1 -0
  205. package/src/lib/components/erase-person-action.d.ts +92 -0
  206. package/src/lib/components/erase-person-action.js +261 -0
  207. package/src/lib/components/erase-person-action.js.map +1 -0
  208. package/src/lib/components/fields-section.d.ts +37 -0
  209. package/src/lib/components/fields-section.js +641 -0
  210. package/src/lib/components/fields-section.js.map +1 -0
  211. package/src/lib/components/form-contact-fields-card.d.ts +46 -0
  212. package/src/lib/components/form-contact-fields-card.js +253 -0
  213. package/src/lib/components/form-contact-fields-card.js.map +1 -0
  214. package/src/lib/components/insert-link-at-caret.d.ts +28 -0
  215. package/src/lib/components/insert-link-at-caret.js +37 -0
  216. package/src/lib/components/insert-link-at-caret.js.map +1 -0
  217. package/src/lib/components/lead-convert-dialog.d.ts +32 -0
  218. package/src/lib/components/lead-convert-dialog.js +493 -0
  219. package/src/lib/components/lead-convert-dialog.js.map +1 -0
  220. package/src/lib/components/lead-detail-page.d.ts +16 -0
  221. package/src/lib/components/lead-detail-page.js +163 -0
  222. package/src/lib/components/lead-detail-page.js.map +1 -0
  223. package/src/lib/components/lead-history-card.d.ts +32 -0
  224. package/src/lib/components/lead-history-card.js +165 -0
  225. package/src/lib/components/lead-history-card.js.map +1 -0
  226. package/src/lib/components/lead-import-drawer.d.ts +24 -0
  227. package/src/lib/components/lead-import-drawer.js +95 -0
  228. package/src/lib/components/lead-import-drawer.js.map +1 -0
  229. package/src/lib/components/lead-owner-select.d.ts +35 -0
  230. package/src/lib/components/lead-owner-select.js +91 -0
  231. package/src/lib/components/lead-owner-select.js.map +1 -0
  232. package/src/lib/components/lead-properties-card.d.ts +61 -0
  233. package/src/lib/components/lead-properties-card.js +395 -0
  234. package/src/lib/components/lead-properties-card.js.map +1 -0
  235. package/src/lib/components/lead-status-chip.d.ts +12 -0
  236. package/src/lib/components/lead-status-chip.js +43 -0
  237. package/src/lib/components/lead-status-chip.js.map +1 -0
  238. package/src/lib/components/lead-surfaces-note.d.ts +126 -0
  239. package/src/lib/components/lead-surfaces-note.js +262 -0
  240. package/src/lib/components/lead-surfaces-note.js.map +1 -0
  241. package/src/lib/components/lead-unqualify-dialog.d.ts +24 -0
  242. package/src/lib/components/lead-unqualify-dialog.js +125 -0
  243. package/src/lib/components/lead-unqualify-dialog.js.map +1 -0
  244. package/src/lib/components/leads-bulk-bar.d.ts +58 -0
  245. package/src/lib/components/leads-bulk-bar.js +307 -0
  246. package/src/lib/components/leads-bulk-bar.js.map +1 -0
  247. package/src/lib/components/leads-section.d.ts +23 -0
  248. package/src/lib/components/leads-section.js +664 -0
  249. package/src/lib/components/leads-section.js.map +1 -0
  250. package/src/lib/components/linked-deals-card.d.ts +32 -0
  251. package/src/lib/components/linked-deals-card.js +163 -0
  252. package/src/lib/components/linked-deals-card.js.map +1 -0
  253. package/src/lib/components/log-activity-dialog.d.ts +60 -0
  254. package/src/lib/components/log-activity-dialog.js +368 -0
  255. package/src/lib/components/log-activity-dialog.js.map +1 -0
  256. package/src/lib/components/lost-reason-dialog.d.ts +26 -0
  257. package/src/lib/components/lost-reason-dialog.js +95 -0
  258. package/src/lib/components/lost-reason-dialog.js.map +1 -0
  259. package/src/lib/components/new-contact-drawer.d.ts +78 -0
  260. package/src/lib/components/new-contact-drawer.js +343 -0
  261. package/src/lib/components/new-contact-drawer.js.map +1 -0
  262. package/src/lib/components/org-lead-surfaces-note.d.ts +57 -0
  263. package/src/lib/components/org-lead-surfaces-note.js +172 -0
  264. package/src/lib/components/org-lead-surfaces-note.js.map +1 -0
  265. package/src/lib/components/owner-avatar.d.ts +18 -0
  266. package/src/lib/components/owner-avatar.js +61 -0
  267. package/src/lib/components/owner-avatar.js.map +1 -0
  268. package/src/lib/components/pipeline-stages-dialog.d.ts +43 -0
  269. package/src/lib/components/pipeline-stages-dialog.js +339 -0
  270. package/src/lib/components/pipeline-stages-dialog.js.map +1 -0
  271. package/src/lib/components/pipelines-dialog.d.ts +55 -0
  272. package/src/lib/components/pipelines-dialog.js +517 -0
  273. package/src/lib/components/pipelines-dialog.js.map +1 -0
  274. package/src/lib/components/recent-activity-feed.d.ts +39 -0
  275. package/src/lib/components/recent-activity-feed.js +103 -0
  276. package/src/lib/components/recent-activity-feed.js.map +1 -0
  277. package/src/lib/components/recipes-card.d.ts +39 -0
  278. package/src/lib/components/recipes-card.js +485 -0
  279. package/src/lib/components/recipes-card.js.map +1 -0
  280. package/src/lib/components/record-activity-card.d.ts +26 -0
  281. package/src/lib/components/record-activity-card.js +121 -0
  282. package/src/lib/components/record-activity-card.js.map +1 -0
  283. package/src/lib/components/record-files-card.d.ts +67 -0
  284. package/src/lib/components/record-files-card.js +290 -0
  285. package/src/lib/components/record-files-card.js.map +1 -0
  286. package/src/lib/components/record-tasks-card.d.ts +32 -0
  287. package/src/lib/components/record-tasks-card.js +306 -0
  288. package/src/lib/components/record-tasks-card.js.map +1 -0
  289. package/src/lib/components/reports/activity-card.d.ts +57 -0
  290. package/src/lib/components/reports/activity-card.js +281 -0
  291. package/src/lib/components/reports/activity-card.js.map +1 -0
  292. package/src/lib/components/reports/closed-deals-card.d.ts +20 -0
  293. package/src/lib/components/reports/closed-deals-card.js +194 -0
  294. package/src/lib/components/reports/closed-deals-card.js.map +1 -0
  295. package/src/lib/components/reports/contacts-mix-card.d.ts +27 -0
  296. package/src/lib/components/reports/contacts-mix-card.js +161 -0
  297. package/src/lib/components/reports/contacts-mix-card.js.map +1 -0
  298. package/src/lib/components/reports/contacts-trend-card.d.ts +31 -0
  299. package/src/lib/components/reports/contacts-trend-card.js +144 -0
  300. package/src/lib/components/reports/contacts-trend-card.js.map +1 -0
  301. package/src/lib/components/reports/forecast-card.d.ts +22 -0
  302. package/src/lib/components/reports/forecast-card.js +251 -0
  303. package/src/lib/components/reports/forecast-card.js.map +1 -0
  304. package/src/lib/components/reports/lead-counts.d.ts +32 -0
  305. package/src/lib/components/reports/lead-counts.js +44 -0
  306. package/src/lib/components/reports/lead-counts.js.map +1 -0
  307. package/src/lib/components/reports/lead-funnel-card.d.ts +38 -0
  308. package/src/lib/components/reports/lead-funnel-card.js +375 -0
  309. package/src/lib/components/reports/lead-funnel-card.js.map +1 -0
  310. package/src/lib/components/reports/pipeline-card.d.ts +19 -0
  311. package/src/lib/components/reports/pipeline-card.js +338 -0
  312. package/src/lib/components/reports/pipeline-card.js.map +1 -0
  313. package/src/lib/components/reports/report-bar-chart.d.ts +39 -0
  314. package/src/lib/components/reports/report-bar-chart.js +133 -0
  315. package/src/lib/components/reports/report-bar-chart.js.map +1 -0
  316. package/src/lib/components/reports/report-breakdown.d.ts +32 -0
  317. package/src/lib/components/reports/report-breakdown.js +105 -0
  318. package/src/lib/components/reports/report-breakdown.js.map +1 -0
  319. package/src/lib/components/reports/report-export.d.ts +37 -0
  320. package/src/lib/components/reports/report-export.js +66 -0
  321. package/src/lib/components/reports/report-export.js.map +1 -0
  322. package/src/lib/components/reports/report-format.d.ts +36 -0
  323. package/src/lib/components/reports/report-format.js +43 -0
  324. package/src/lib/components/reports/report-format.js.map +1 -0
  325. package/src/lib/components/reports/report-scope.d.ts +81 -0
  326. package/src/lib/components/reports/report-scope.js +58 -0
  327. package/src/lib/components/reports/report-scope.js.map +1 -0
  328. package/src/lib/components/reports/report-stat-tile.d.ts +47 -0
  329. package/src/lib/components/reports/report-stat-tile.js +96 -0
  330. package/src/lib/components/reports/report-stat-tile.js.map +1 -0
  331. package/src/lib/components/reports/source-conversion-card.d.ts +28 -0
  332. package/src/lib/components/reports/source-conversion-card.js +205 -0
  333. package/src/lib/components/reports/source-conversion-card.js.map +1 -0
  334. package/src/lib/components/reports/tasks-card.d.ts +26 -0
  335. package/src/lib/components/reports/tasks-card.js +279 -0
  336. package/src/lib/components/reports/tasks-card.js.map +1 -0
  337. package/src/lib/components/reports/use-aggregate-read.d.ts +99 -0
  338. package/src/lib/components/reports/use-aggregate-read.js +195 -0
  339. package/src/lib/components/reports/use-aggregate-read.js.map +1 -0
  340. package/src/lib/components/reports/won-lost-by-owner-card.d.ts +30 -0
  341. package/src/lib/components/reports/won-lost-by-owner-card.js +168 -0
  342. package/src/lib/components/reports/won-lost-by-owner-card.js.map +1 -0
  343. package/src/lib/components/reports-section.d.ts +42 -0
  344. package/src/lib/components/reports-section.js +308 -0
  345. package/src/lib/components/reports-section.js.map +1 -0
  346. package/src/lib/components/sending-addresses-card.d.ts +49 -0
  347. package/src/lib/components/sending-addresses-card.js +262 -0
  348. package/src/lib/components/sending-addresses-card.js.map +1 -0
  349. package/src/lib/components/settings-section.d.ts +151 -0
  350. package/src/lib/components/settings-section.js +783 -0
  351. package/src/lib/components/settings-section.js.map +1 -0
  352. package/src/lib/components/task-cells.d.ts +51 -0
  353. package/src/lib/components/task-cells.js +139 -0
  354. package/src/lib/components/task-cells.js.map +1 -0
  355. package/src/lib/components/task-edit-drawer.d.ts +53 -0
  356. package/src/lib/components/task-edit-drawer.js +483 -0
  357. package/src/lib/components/task-edit-drawer.js.map +1 -0
  358. package/src/lib/components/task-import-drawer.d.ts +24 -0
  359. package/src/lib/components/task-import-drawer.js +82 -0
  360. package/src/lib/components/task-import-drawer.js.map +1 -0
  361. package/src/lib/components/task-snooze-menu.d.ts +65 -0
  362. package/src/lib/components/task-snooze-menu.js +207 -0
  363. package/src/lib/components/task-snooze-menu.js.map +1 -0
  364. package/src/lib/components/tasks-bulk-bar.d.ts +25 -0
  365. package/src/lib/components/tasks-bulk-bar.js +348 -0
  366. package/src/lib/components/tasks-bulk-bar.js.map +1 -0
  367. package/src/lib/components/tasks-calendar.d.ts +38 -0
  368. package/src/lib/components/tasks-calendar.js +228 -0
  369. package/src/lib/components/tasks-calendar.js.map +1 -0
  370. package/src/lib/components/tasks-section.d.ts +27 -0
  371. package/src/lib/components/tasks-section.js +579 -0
  372. package/src/lib/components/tasks-section.js.map +1 -0
  373. package/src/lib/components/use-contact-campaign-emails.d.ts +32 -0
  374. package/src/lib/components/use-contact-campaign-emails.js +83 -0
  375. package/src/lib/components/use-contact-campaign-emails.js.map +1 -0
  376. package/src/lib/components/use-crm-api.d.ts +44 -0
  377. package/src/lib/components/use-crm-api.js +84 -0
  378. package/src/lib/components/use-crm-api.js.map +1 -0
  379. package/src/lib/components/use-crm-inbound-address.d.ts +60 -0
  380. package/src/lib/components/use-crm-inbound-address.js +124 -0
  381. package/src/lib/components/use-crm-inbound-address.js.map +1 -0
  382. package/src/lib/components/use-emails-hub-path.d.ts +24 -0
  383. package/src/lib/components/use-emails-hub-path.js +59 -0
  384. package/src/lib/components/use-emails-hub-path.js.map +1 -0
  385. package/src/lib/components/use-member-email-aliases.d.ts +54 -0
  386. package/src/lib/components/use-member-email-aliases.js +186 -0
  387. package/src/lib/components/use-member-email-aliases.js.map +1 -0
  388. package/src/lib/components/use-org-members.d.ts +40 -0
  389. package/src/lib/components/use-org-members.js +100 -0
  390. package/src/lib/components/use-org-members.js.map +1 -0
  391. package/src/lib/constants/api-routes.d.ts +109 -0
  392. package/src/lib/constants/api-routes.js +74 -0
  393. package/src/lib/constants/api-routes.js.map +1 -0
  394. package/src/lib/constants/bundle-common.d.ts +14 -0
  395. package/src/lib/constants/bundle-common.js +14 -0
  396. package/src/lib/constants/bundle-common.js.map +1 -0
  397. package/src/lib/constants/company-filters.d.ts +18 -0
  398. package/src/lib/constants/company-filters.js +51 -0
  399. package/src/lib/constants/company-filters.js.map +1 -0
  400. package/src/lib/constants/contact-filters.d.ts +38 -0
  401. package/src/lib/constants/contact-filters.js +294 -0
  402. package/src/lib/constants/contact-filters.js.map +1 -0
  403. package/src/lib/hooks/use-contact-field-definitions.d.ts +48 -0
  404. package/src/lib/hooks/use-contact-field-definitions.js +72 -0
  405. package/src/lib/hooks/use-contact-field-definitions.js.map +1 -0
  406. package/src/lib/hooks/use-contact-update.d.ts +25 -0
  407. package/src/lib/hooks/use-contact-update.js +80 -0
  408. package/src/lib/hooks/use-contact-update.js.map +1 -0
  409. package/src/lib/hooks/use-crm-activity-logger.d.ts +73 -0
  410. package/src/lib/hooks/use-crm-activity-logger.js +101 -0
  411. package/src/lib/hooks/use-crm-activity-logger.js.map +1 -0
  412. package/src/lib/hooks/use-crm-bulk-apply.d.ts +52 -0
  413. package/src/lib/hooks/use-crm-bulk-apply.js +112 -0
  414. package/src/lib/hooks/use-crm-bulk-apply.js.map +1 -0
  415. package/src/lib/hooks/use-crm-default-view.d.ts +24 -0
  416. package/src/lib/hooks/use-crm-default-view.js +64 -0
  417. package/src/lib/hooks/use-crm-default-view.js.map +1 -0
  418. package/src/lib/hooks/use-crm-email-templates.d.ts +59 -0
  419. package/src/lib/hooks/use-crm-email-templates.js +103 -0
  420. package/src/lib/hooks/use-crm-email-templates.js.map +1 -0
  421. package/src/lib/hooks/use-crm-hub-path.d.ts +29 -0
  422. package/src/lib/hooks/use-crm-hub-path.js +41 -0
  423. package/src/lib/hooks/use-crm-hub-path.js.map +1 -0
  424. package/src/lib/hooks/use-crm-org-mount.d.ts +97 -0
  425. package/src/lib/hooks/use-crm-org-mount.js +215 -0
  426. package/src/lib/hooks/use-crm-org-mount.js.map +1 -0
  427. package/src/lib/hooks/use-crm-record-names.d.ts +52 -0
  428. package/src/lib/hooks/use-crm-record-names.js +126 -0
  429. package/src/lib/hooks/use-crm-record-names.js.map +1 -0
  430. package/src/lib/hooks/use-crm-records-quota.d.ts +68 -0
  431. package/src/lib/hooks/use-crm-records-quota.js +118 -0
  432. package/src/lib/hooks/use-crm-records-quota.js.map +1 -0
  433. package/src/lib/hooks/use-crm-saved-view.d.ts +96 -0
  434. package/src/lib/hooks/use-crm-saved-view.js +329 -0
  435. package/src/lib/hooks/use-crm-saved-view.js.map +1 -0
  436. package/src/lib/hooks/use-crm-scope.d.ts +117 -0
  437. package/src/lib/hooks/use-crm-scope.js +147 -0
  438. package/src/lib/hooks/use-crm-scope.js.map +1 -0
  439. package/src/lib/hooks/use-crm-tasks.d.ts +85 -0
  440. package/src/lib/hooks/use-crm-tasks.js +153 -0
  441. package/src/lib/hooks/use-crm-tasks.js.map +1 -0
  442. package/src/lib/hooks/use-crm-view-grid.d.ts +55 -0
  443. package/src/lib/hooks/use-crm-view-grid.js +170 -0
  444. package/src/lib/hooks/use-crm-view-grid.js.map +1 -0
  445. package/src/lib/hooks/use-crm-views.d.ts +42 -0
  446. package/src/lib/hooks/use-crm-views.js +84 -0
  447. package/src/lib/hooks/use-crm-views.js.map +1 -0
  448. package/src/lib/hooks/use-deal-stage-api.d.ts +69 -0
  449. package/src/lib/hooks/use-deal-stage-api.js +78 -0
  450. package/src/lib/hooks/use-deal-stage-api.js.map +1 -0
  451. package/src/lib/hooks/use-deals.d.ts +47 -0
  452. package/src/lib/hooks/use-deals.js +105 -0
  453. package/src/lib/hooks/use-deals.js.map +1 -0
  454. package/src/lib/hooks/use-org-leads.d.ts +53 -0
  455. package/src/lib/hooks/use-org-leads.js +114 -0
  456. package/src/lib/hooks/use-org-leads.js.map +1 -0
  457. package/src/lib/hooks/use-org-member-directory.d.ts +36 -0
  458. package/src/lib/hooks/use-org-member-directory.js +116 -0
  459. package/src/lib/hooks/use-org-member-directory.js.map +1 -0
  460. package/src/lib/hooks/use-org-member-options.d.ts +38 -0
  461. package/src/lib/hooks/use-org-member-options.js +131 -0
  462. package/src/lib/hooks/use-org-member-options.js.map +1 -0
  463. package/src/lib/hooks/use-pipeline.d.ts +71 -0
  464. package/src/lib/hooks/use-pipeline.js +159 -0
  465. package/src/lib/hooks/use-pipeline.js.map +1 -0
  466. package/src/lib/model/companies-bulk-writes.d.ts +40 -0
  467. package/src/lib/model/companies-bulk-writes.js +103 -0
  468. package/src/lib/model/companies-bulk-writes.js.map +1 -0
  469. package/src/lib/model/companies-csv.d.ts +36 -0
  470. package/src/lib/model/companies-csv.js +38 -0
  471. package/src/lib/model/companies-csv.js.map +1 -0
  472. package/src/lib/model/companies.d.ts +99 -0
  473. package/src/lib/model/companies.js +168 -0
  474. package/src/lib/model/companies.js.map +1 -0
  475. package/src/lib/model/company-delete-route.d.ts +43 -0
  476. package/src/lib/model/company-delete-route.js +31 -0
  477. package/src/lib/model/company-delete-route.js.map +1 -0
  478. package/src/lib/model/company-delete.d.ts +42 -0
  479. package/src/lib/model/company-delete.js +52 -0
  480. package/src/lib/model/company-delete.js.map +1 -0
  481. package/src/lib/model/contact-duplicates.d.ts +58 -0
  482. package/src/lib/model/contact-duplicates.js +67 -0
  483. package/src/lib/model/contact-duplicates.js.map +1 -0
  484. package/src/lib/model/contact-record.d.ts +113 -0
  485. package/src/lib/model/contact-record.js +70 -0
  486. package/src/lib/model/contact-record.js.map +1 -0
  487. package/src/lib/model/contact-update.d.ts +93 -0
  488. package/src/lib/model/contact-update.js +50 -0
  489. package/src/lib/model/contact-update.js.map +1 -0
  490. package/src/lib/model/contacts-bulk-writes.d.ts +173 -0
  491. package/src/lib/model/contacts-bulk-writes.js +196 -0
  492. package/src/lib/model/contacts-bulk-writes.js.map +1 -0
  493. package/src/lib/model/contacts-csv.d.ts +54 -0
  494. package/src/lib/model/contacts-csv.js +67 -0
  495. package/src/lib/model/contacts-csv.js.map +1 -0
  496. package/src/lib/model/contacts-list-seed.d.ts +51 -0
  497. package/src/lib/model/contacts-list-seed.js +63 -0
  498. package/src/lib/model/contacts-list-seed.js.map +1 -0
  499. package/src/lib/model/crm-activity-report.d.ts +27 -0
  500. package/src/lib/model/crm-activity-report.js +56 -0
  501. package/src/lib/model/crm-activity-report.js.map +1 -0
  502. package/src/lib/model/crm-api.d.ts +49 -0
  503. package/src/lib/model/crm-api.js +47 -0
  504. package/src/lib/model/crm-api.js.map +1 -0
  505. package/src/lib/model/crm-bulk-writes.d.ts +147 -0
  506. package/src/lib/model/crm-bulk-writes.js +207 -0
  507. package/src/lib/model/crm-bulk-writes.js.map +1 -0
  508. package/src/lib/model/crm-company-import.d.ts +154 -0
  509. package/src/lib/model/crm-company-import.js +331 -0
  510. package/src/lib/model/crm-company-import.js.map +1 -0
  511. package/src/lib/model/crm-custom-draft.d.ts +62 -0
  512. package/src/lib/model/crm-custom-draft.js +67 -0
  513. package/src/lib/model/crm-custom-draft.js.map +1 -0
  514. package/src/lib/model/crm-deal-import.d.ts +112 -0
  515. package/src/lib/model/crm-deal-import.js +263 -0
  516. package/src/lib/model/crm-deal-import.js.map +1 -0
  517. package/src/lib/model/crm-import.d.ts +244 -0
  518. package/src/lib/model/crm-import.js +466 -0
  519. package/src/lib/model/crm-import.js.map +1 -0
  520. package/src/lib/model/crm-lead-import.d.ts +105 -0
  521. package/src/lib/model/crm-lead-import.js +255 -0
  522. package/src/lib/model/crm-lead-import.js.map +1 -0
  523. package/src/lib/model/crm-record-routes.d.ts +21 -0
  524. package/src/lib/model/crm-record-routes.js +70 -0
  525. package/src/lib/model/crm-record-routes.js.map +1 -0
  526. package/src/lib/model/crm-routes.d.ts +101 -0
  527. package/src/lib/model/crm-routes.js +92 -0
  528. package/src/lib/model/crm-routes.js.map +1 -0
  529. package/src/lib/model/crm-task-import.d.ts +94 -0
  530. package/src/lib/model/crm-task-import.js +275 -0
  531. package/src/lib/model/crm-task-import.js.map +1 -0
  532. package/src/lib/model/crm-view-param.d.ts +43 -0
  533. package/src/lib/model/crm-view-param.js +49 -0
  534. package/src/lib/model/crm-view-param.js.map +1 -0
  535. package/src/lib/model/deal-board-model.d.ts +241 -0
  536. package/src/lib/model/deal-board-model.js +439 -0
  537. package/src/lib/model/deal-board-model.js.map +1 -0
  538. package/src/lib/model/deal-form-model.d.ts +114 -0
  539. package/src/lib/model/deal-form-model.js +218 -0
  540. package/src/lib/model/deal-form-model.js.map +1 -0
  541. package/src/lib/model/deals-csv.d.ts +32 -0
  542. package/src/lib/model/deals-csv.js +37 -0
  543. package/src/lib/model/deals-csv.js.map +1 -0
  544. package/src/lib/model/import-column-shapes.d.ts +36 -0
  545. package/src/lib/model/import-column-shapes.js +76 -0
  546. package/src/lib/model/import-column-shapes.js.map +1 -0
  547. package/src/lib/model/lead-company-suggestion.d.ts +61 -0
  548. package/src/lib/model/lead-company-suggestion.js +65 -0
  549. package/src/lib/model/lead-company-suggestion.js.map +1 -0
  550. package/src/lib/model/lead-filters.d.ts +29 -0
  551. package/src/lib/model/lead-filters.js +39 -0
  552. package/src/lib/model/lead-filters.js.map +1 -0
  553. package/src/lib/model/lead-surfaces.d.ts +58 -0
  554. package/src/lib/model/lead-surfaces.js +67 -0
  555. package/src/lib/model/lead-surfaces.js.map +1 -0
  556. package/src/lib/model/leads-csv.d.ts +40 -0
  557. package/src/lib/model/leads-csv.js +40 -0
  558. package/src/lib/model/leads-csv.js.map +1 -0
  559. package/src/lib/model/next-activity-api.d.ts +31 -0
  560. package/src/lib/model/next-activity-api.js +57 -0
  561. package/src/lib/model/next-activity-api.js.map +1 -0
  562. package/src/lib/model/next-activity.d.ts +64 -0
  563. package/src/lib/model/next-activity.js +47 -0
  564. package/src/lib/model/next-activity.js.map +1 -0
  565. package/src/lib/model/person-key-web.d.ts +43 -0
  566. package/src/lib/model/person-key-web.js +52 -0
  567. package/src/lib/model/person-key-web.js.map +1 -0
  568. package/src/lib/model/record-facts.d.ts +282 -0
  569. package/src/lib/model/record-facts.js +434 -0
  570. package/src/lib/model/record-facts.js.map +1 -0
  571. package/src/lib/model/task-api.d.ts +28 -0
  572. package/src/lib/model/task-api.js +57 -0
  573. package/src/lib/model/task-api.js.map +1 -0
  574. package/src/lib/model/task-calendar.d.ts +108 -0
  575. package/src/lib/model/task-calendar.js +139 -0
  576. package/src/lib/model/task-calendar.js.map +1 -0
  577. package/src/lib/model/task-routes.d.ts +177 -0
  578. package/src/lib/model/task-routes.js +197 -0
  579. package/src/lib/model/task-routes.js.map +1 -0
  580. package/src/lib/model/task-scope.d.ts +45 -0
  581. package/src/lib/model/task-scope.js +51 -0
  582. package/src/lib/model/task-scope.js.map +1 -0
  583. package/src/lib/model/task-views.d.ts +149 -0
  584. package/src/lib/model/task-views.js +286 -0
  585. package/src/lib/model/task-views.js.map +1 -0
  586. package/src/lib/model/tasks-csv.d.ts +28 -0
  587. package/src/lib/model/tasks-csv.js +28 -0
  588. package/src/lib/model/tasks-csv.js.map +1 -0
  589. package/src/lib/plugin.d.ts +32 -0
  590. package/src/lib/plugin.js +208 -0
  591. package/src/lib/plugin.js.map +1 -0
  592. package/src/lib/server/companies-import.d.ts +57 -0
  593. package/src/lib/server/companies-import.js +242 -0
  594. package/src/lib/server/companies-import.js.map +1 -0
  595. package/src/lib/server/company-delete.d.ts +59 -0
  596. package/src/lib/server/company-delete.js +146 -0
  597. package/src/lib/server/company-delete.js.map +1 -0
  598. package/src/lib/server/contact-email-history.d.ts +82 -0
  599. package/src/lib/server/contact-email-history.js +264 -0
  600. package/src/lib/server/contact-email-history.js.map +1 -0
  601. package/src/lib/server/contact-profile.d.ts +41 -0
  602. package/src/lib/server/contact-profile.js +45 -0
  603. package/src/lib/server/contact-profile.js.map +1 -0
  604. package/src/lib/server/contact-update.d.ts +92 -0
  605. package/src/lib/server/contact-update.js +512 -0
  606. package/src/lib/server/contact-update.js.map +1 -0
  607. package/src/lib/server/contacts-import.d.ts +73 -0
  608. package/src/lib/server/contacts-import.js +263 -0
  609. package/src/lib/server/contacts-import.js.map +1 -0
  610. package/src/lib/server/contacts-merge.d.ts +86 -0
  611. package/src/lib/server/contacts-merge.js +206 -0
  612. package/src/lib/server/contacts-merge.js.map +1 -0
  613. package/src/lib/server/deals-import.d.ts +76 -0
  614. package/src/lib/server/deals-import.js +246 -0
  615. package/src/lib/server/deals-import.js.map +1 -0
  616. package/src/lib/server/email-send.d.ts +119 -0
  617. package/src/lib/server/email-send.js +667 -0
  618. package/src/lib/server/email-send.js.map +1 -0
  619. package/src/lib/server/email-template-duplicate.d.ts +19 -0
  620. package/src/lib/server/email-template-duplicate.js +206 -0
  621. package/src/lib/server/email-template-duplicate.js.map +1 -0
  622. package/src/lib/server/erase-person.d.ts +108 -0
  623. package/src/lib/server/erase-person.js +309 -0
  624. package/src/lib/server/erase-person.js.map +1 -0
  625. package/src/lib/server/import-context.d.ts +85 -0
  626. package/src/lib/server/import-context.js +181 -0
  627. package/src/lib/server/import-context.js.map +1 -0
  628. package/src/lib/server/inbound-address.d.ts +61 -0
  629. package/src/lib/server/inbound-address.js +188 -0
  630. package/src/lib/server/inbound-address.js.map +1 -0
  631. package/src/lib/server/lead-convert.d.ts +78 -0
  632. package/src/lib/server/lead-convert.js +250 -0
  633. package/src/lib/server/lead-convert.js.map +1 -0
  634. package/src/lib/server/leads-import.d.ts +84 -0
  635. package/src/lib/server/leads-import.js +261 -0
  636. package/src/lib/server/leads-import.js.map +1 -0
  637. package/src/lib/server/next-activity-routes.d.ts +33 -0
  638. package/src/lib/server/next-activity-routes.js +110 -0
  639. package/src/lib/server/next-activity-routes.js.map +1 -0
  640. package/src/lib/server/org-activity.d.ts +61 -0
  641. package/src/lib/server/org-activity.js +120 -0
  642. package/src/lib/server/org-activity.js.map +1 -0
  643. package/src/lib/server/org-caller.d.ts +110 -0
  644. package/src/lib/server/org-caller.js +154 -0
  645. package/src/lib/server/org-caller.js.map +1 -0
  646. package/src/lib/server/recipe-routes.d.ts +75 -0
  647. package/src/lib/server/recipe-routes.js +442 -0
  648. package/src/lib/server/recipe-routes.js.map +1 -0
  649. package/src/lib/server/record-facts.d.ts +65 -0
  650. package/src/lib/server/record-facts.js +337 -0
  651. package/src/lib/server/record-facts.js.map +1 -0
  652. package/src/lib/server/record-timeline.d.ts +51 -0
  653. package/src/lib/server/record-timeline.js +215 -0
  654. package/src/lib/server/record-timeline.js.map +1 -0
  655. package/src/lib/server/suite-gate.d.ts +42 -0
  656. package/src/lib/server/suite-gate.js +87 -0
  657. package/src/lib/server/suite-gate.js.map +1 -0
  658. package/src/lib/server/task-routes.d.ts +132 -0
  659. package/src/lib/server/task-routes.js +699 -0
  660. package/src/lib/server/task-routes.js.map +1 -0
  661. package/src/lib/server/tasks-import.d.ts +54 -0
  662. package/src/lib/server/tasks-import.js +157 -0
  663. package/src/lib/server/tasks-import.js.map +1 -0
  664. package/src/lib/server-deal-stage.d.ts +88 -0
  665. package/src/lib/server-deal-stage.js +316 -0
  666. package/src/lib/server-deal-stage.js.map +1 -0
  667. package/src/lib/server.d.ts +149 -0
  668. package/src/lib/server.js +615 -0
  669. package/src/lib/server.js.map +1 -0
@@ -0,0 +1,281 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Aglyn LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */ 'use client';
17
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
18
+ import * as Aglyn from "@aglyn/aglyn";
19
+ import { CardDisplay } from "@aglyn/shared-ui-jsx";
20
+ import { Section } from "@aglyn/shared-ui-jsx/components/measured-figures.component";
21
+ import { ScrollTable } from "@aglyn/shared-ui-jsx/components/scroll-table.component";
22
+ import { Alert, Stack, TableBody, TableCell, TableHead, TableRow, Typography } from "@mui/material";
23
+ import { getCountFromServer, limit, orderBy, query, where } from "firebase/firestore";
24
+ import { useMemo } from "react";
25
+ import { useFirestore } from "@aglyn/tenant-feature-instance";
26
+ import { useOrgMemberOptions } from "../../hooks/use-org-member-options.js";
27
+ import { ReportExport } from "./report-export.js";
28
+ import { reportFilename } from "./report-format.js";
29
+ import { reportCacheKey, scopedCollection, visibleToClause } from "./report-scope.js";
30
+ import { ReportStatTile } from "./report-stat-tile.js";
31
+ import { useAggregateRead, useWindowRead } from "./use-aggregate-read.js";
32
+ /**
33
+ * How many activities and how many completed tasks the leaderboard is
34
+ * grouped from.
35
+ *
36
+ * The tiles are server counts and never meet these bounds; the table needs
37
+ * each activity's kind and author and each task's completer, so it reads
38
+ * the period's newest thousand of each and says when there were more —
39
+ * the contacts list's bound, and the one every window on this page shares.
40
+ */ const ACTIVITY_CEILING = 1000;
41
+ const TASK_DONE_CEILING = 1000;
42
+ /** The table's columns, which are also the CSV's. */ const COLUMNS = [
43
+ 'Teammate',
44
+ ...Aglyn.CRM_ACTIVITY_KINDS.map((kind)=>Aglyn.CRM_ACTIVITY_KIND_LABELS[kind]),
45
+ 'Activities',
46
+ 'Tasks done'
47
+ ];
48
+ /**
49
+ * Activity by teammate (AGL-2624): the calls, emails, meetings and notes
50
+ * each member logged in the period, and the tasks they ticked off,
51
+ * busiest first.
52
+ *
53
+ * ## Two windows, two indexes, one table
54
+ *
55
+ * Activities are counted within the period on `atMs`; completed tasks are
56
+ * counted the same way on `completedAtMs`, under `status == 'done'`. Each
57
+ * count is also drawn as a window, newest first, for the leaderboard.
58
+ *
59
+ * ## Why that is four indexes and not one
60
+ *
61
+ * The counts and the windows do not share an index, and neither do the two
62
+ * audiences.
63
+ *
64
+ * A COUNT here names no `orderBy`. Firestore then orders implicitly by the
65
+ * range field, ASCENDING, so a count wants `completedAtMs` ascending — while
66
+ * the window beside it asks for `desc` explicitly and wants the descending
67
+ * one. A composite index serves one direction or its exact reverse, never
68
+ * both, so declaring only the direction the window reads leaves the count
69
+ * with nothing: `FAILED_PRECONDITION`, one column of dashes, and a card that
70
+ * otherwise looks fine.
71
+ *
72
+ * Then the visibility clause doubles it. `visibleToClause` contributes
73
+ * nothing when the reader's tokens are null, which is every organization-level
74
+ * read, so the shape arriving at Firestore has no leading array field — a
75
+ * different index, not a prefix of the one with it. `(visibleTo, status,
76
+ * completedAtMs)` serves a site and `(status, completedAtMs)` the org above
77
+ * it; one without the other is a card that works for exactly one audience.
78
+ *
79
+ * The two reads are independent so that a missing task index degrades ONE
80
+ * column to a dash and a notice rather than the whole card: the activities
81
+ * were read, and the leaderboard draws them.
82
+ *
83
+ * A task ordered by `completedAtMs` is a task the complete route stamped;
84
+ * a task marked done some other way, without the stamp, is not in the
85
+ * window and the caption says what the column is grouped from.
86
+ *
87
+ * ## Names
88
+ *
89
+ * Every activity carries the name it was signed with, for the reason
90
+ * `CrmActivity.byName` gives — a scoped reader cannot resolve a colleague's
91
+ * uid. The roster is read too, through the members route any member may
92
+ * ask, and wins when it knows the uid, so a renamed teammate reads by
93
+ * their current name; the signed name covers a uid the roster no longer
94
+ * has, and the uid itself covers the rest.
95
+ */ export function ActivityCard(props) {
96
+ const { report } = props;
97
+ const { scope, tokens, range, period, routes } = report;
98
+ const firestore = useFirestore();
99
+ const roster = useOrgMemberOptions(scope[1]);
100
+ const activitiesBetween = (from, to)=>query(scopedCollection(firestore, scope, Aglyn.CRM_COLLECTIONS.activities), ...visibleToClause(tokens), where('atMs', '>=', from), where('atMs', '<', to));
101
+ const tasksDoneBetween = (from, to)=>query(scopedCollection(firestore, scope, Aglyn.CRM_COLLECTIONS.tasks), ...visibleToClause(tokens), where('status', '==', 'done'), where('completedAtMs', '>=', from), where('completedAtMs', '<', to));
102
+ const countOf = (target)=>getCountFromServer(target).then((snapshot)=>snapshot.data().count);
103
+ const activityCounts = useAggregateRead(()=>Promise.all([
104
+ countOf(activitiesBetween(range.from, range.to)),
105
+ countOf(activitiesBetween(range.previousFrom, range.previousTo))
106
+ ]).then(([current, previous])=>({
107
+ current,
108
+ previous
109
+ })), [
110
+ firestore,
111
+ scope,
112
+ tokens,
113
+ range
114
+ ], {
115
+ cacheKey: reportCacheKey(report, 'activity:counts')
116
+ });
117
+ const taskCounts = useAggregateRead(()=>Promise.all([
118
+ countOf(tasksDoneBetween(range.from, range.to)),
119
+ countOf(tasksDoneBetween(range.previousFrom, range.previousTo))
120
+ ]).then(([current, previous])=>({
121
+ current,
122
+ previous
123
+ })), [
124
+ firestore,
125
+ scope,
126
+ tokens,
127
+ range
128
+ ], {
129
+ cacheKey: reportCacheKey(report, 'activity:tasks-counts')
130
+ });
131
+ const activityWindow = useWindowRead(()=>query(activitiesBetween(range.from, range.to), orderBy('atMs', 'desc'), limit(ACTIVITY_CEILING + 1)), ACTIVITY_CEILING, [
132
+ firestore,
133
+ scope,
134
+ tokens,
135
+ range
136
+ ], {
137
+ cacheKey: reportCacheKey(report, 'activity:window')
138
+ });
139
+ const taskWindow = useWindowRead(()=>query(tasksDoneBetween(range.from, range.to), orderBy('completedAtMs', 'desc'), limit(TASK_DONE_CEILING + 1)), TASK_DONE_CEILING, [
140
+ firestore,
141
+ scope,
142
+ tokens,
143
+ range
144
+ ], {
145
+ cacheKey: reportCacheKey(report, 'activity:tasks-window')
146
+ });
147
+ const rows = useMemo(()=>Aglyn.activityLeaderboard(activityWindow.rows, taskWindow.rows), [
148
+ activityWindow,
149
+ taskWindow
150
+ ]);
151
+ const nameOf = (row)=>{
152
+ var _ref, _ref1;
153
+ var _Aglyn_findOrgMember;
154
+ if (!row.uid) return 'No teammate';
155
+ return (_ref = (_ref1 = (_Aglyn_findOrgMember = Aglyn.findOrgMember(roster.options, row.uid)) == null ? void 0 : _Aglyn_findOrgMember.label) != null ? _ref1 : row.name) != null ? _ref : row.uid;
156
+ };
157
+ const teammates = rows.filter((row)=>row.uid).length;
158
+ const activitiesRead = activityWindow.status === 'success';
159
+ const tasksRead = taskWindow.status === 'success';
160
+ const settled = activityWindow.status !== 'loading' && taskWindow.status !== 'loading';
161
+ const caption = [
162
+ activityWindow.truncated ? `Grouped from the ${ACTIVITY_CEILING.toLocaleString()} most recent activities in the period` : null,
163
+ taskWindow.truncated ? `the ${TASK_DONE_CEILING.toLocaleString()} most recently completed tasks` : null
164
+ ].filter(Boolean).join(' and ');
165
+ const activityFigures = activityCounts.value;
166
+ const taskFigures = taskCounts.value;
167
+ return /*#__PURE__*/ _jsx(CardDisplay, {
168
+ header: 'Activity by teammate',
169
+ help: Aglyn.pluginDocsHelp('crmReports', {
170
+ anchor: '#activity-by-teammate',
171
+ excerpt: 'The calls, emails, meetings and notes each teammate logged in ' + 'the period, and the tasks they completed, busiest first. ' + 'Grouped from the period’s newest thousand of each.'
172
+ }),
173
+ contentGutterX: true,
174
+ contentGutterY: true,
175
+ children: /*#__PURE__*/ _jsxs(Stack, {
176
+ spacing: 2,
177
+ children: [
178
+ /*#__PURE__*/ _jsxs(Stack, {
179
+ direction: "row",
180
+ spacing: 3,
181
+ sx: {
182
+ flexWrap: 'wrap'
183
+ },
184
+ children: [
185
+ /*#__PURE__*/ _jsx(ReportStatTile, {
186
+ label: 'Activities logged',
187
+ value: activityFigures ? activityFigures.current.toLocaleString() : null,
188
+ deltaPct: activityFigures ? Aglyn.deltaPercent(activityFigures.current, activityFigures.previous) : null,
189
+ note: 'counted on the server',
190
+ href: routes.section('contacts')
191
+ }),
192
+ /*#__PURE__*/ _jsx(ReportStatTile, {
193
+ label: 'Tasks completed',
194
+ value: taskFigures ? taskFigures.current.toLocaleString() : null,
195
+ deltaPct: taskFigures ? Aglyn.deltaPercent(taskFigures.current, taskFigures.previous) : null,
196
+ note: 'ticked off in the period',
197
+ href: routes.section('tasks')
198
+ }),
199
+ /*#__PURE__*/ _jsx(ReportStatTile, {
200
+ label: 'Teammates active',
201
+ value: settled ? teammates.toLocaleString() : null,
202
+ note: 'logged or completed something'
203
+ })
204
+ ]
205
+ }),
206
+ activityCounts.status === 'error' || activityWindow.status === 'error' ? /*#__PURE__*/ _jsx(Alert, {
207
+ severity: "warning",
208
+ children: 'The activities could not be read.'
209
+ }) : null,
210
+ taskCounts.status === 'error' || taskWindow.status === 'error' ? /*#__PURE__*/ _jsx(Alert, {
211
+ severity: "warning",
212
+ children: 'The completed-task counts could not be read; the Tasks done column is left blank.'
213
+ }) : null,
214
+ /*#__PURE__*/ _jsxs(Section, {
215
+ title: 'Who did what',
216
+ children: [
217
+ rows.length ? /*#__PURE__*/ _jsxs(ScrollTable, {
218
+ size: "small",
219
+ children: [
220
+ /*#__PURE__*/ _jsx(TableHead, {
221
+ children: /*#__PURE__*/ _jsx(TableRow, {
222
+ children: COLUMNS.map((column, index)=>/*#__PURE__*/ _jsx(TableCell, {
223
+ align: index ? 'right' : 'left',
224
+ children: column
225
+ }, column))
226
+ })
227
+ }),
228
+ /*#__PURE__*/ _jsx(TableBody, {
229
+ children: rows.map((row)=>/*#__PURE__*/ _jsxs(TableRow, {
230
+ children: [
231
+ /*#__PURE__*/ _jsx(TableCell, {
232
+ children: nameOf(row)
233
+ }),
234
+ Aglyn.CRM_ACTIVITY_KINDS.map((kind)=>/*#__PURE__*/ _jsx(TableCell, {
235
+ align: "right",
236
+ children: row.kinds[kind].toLocaleString()
237
+ }, kind)),
238
+ /*#__PURE__*/ _jsx(TableCell, {
239
+ align: "right",
240
+ children: row.activities.toLocaleString()
241
+ }),
242
+ /*#__PURE__*/ _jsx(TableCell, {
243
+ align: "right",
244
+ children: tasksRead ? row.tasksDone.toLocaleString() : '—'
245
+ })
246
+ ]
247
+ }, row.uid || '$nobody'))
248
+ })
249
+ ]
250
+ }) : /*#__PURE__*/ _jsx(Typography, {
251
+ variant: "body2",
252
+ color: "text.secondary",
253
+ children: settled ? 'Nothing logged or completed in this period.' : 'Reading…'
254
+ }),
255
+ rows.some((row)=>!row.uid) ? /*#__PURE__*/ _jsx(Typography, {
256
+ variant: "caption",
257
+ color: "text.secondary",
258
+ children: 'No teammate — activities an automation logged, and tasks completed with nobody assigned.'
259
+ }) : null,
260
+ /*#__PURE__*/ _jsx(ReportExport, {
261
+ filename: reportFilename('activity', period),
262
+ columns: COLUMNS,
263
+ rows: ()=>rows.map((row)=>[
264
+ nameOf(row),
265
+ ...Aglyn.CRM_ACTIVITY_KINDS.map((kind)=>row.kinds[kind]),
266
+ row.activities,
267
+ tasksRead ? row.tasksDone : ''
268
+ ]),
269
+ disabled: !activitiesRead || !rows.length,
270
+ caption: caption ? `${caption}; the tiles are counted on the server.` : undefined
271
+ })
272
+ ]
273
+ })
274
+ ]
275
+ })
276
+ });
277
+ }
278
+ ActivityCard.displayName = 'ActivityCard';
279
+ export default ActivityCard;
280
+
281
+ //# sourceMappingURL=activity-card.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../../libs/plugins/crm/src/lib/components/reports/activity-card.tsx"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n'use client'\n\nimport * as Aglyn from '@aglyn/aglyn'\nimport { CardDisplay } from '@aglyn/shared-ui-jsx'\nimport { Section } from '@aglyn/shared-ui-jsx/components/measured-figures.component'\nimport { ScrollTable } from '@aglyn/shared-ui-jsx/components/scroll-table.component'\nimport {\n Alert,\n Stack,\n TableBody,\n TableCell,\n TableHead,\n TableRow,\n Typography,\n} from '@mui/material'\nimport {\n getCountFromServer,\n limit,\n orderBy,\n query,\n where,\n} from 'firebase/firestore'\nimport { useMemo } from 'react'\nimport { useFirestore } from '@aglyn/tenant-feature-instance'\nimport { useOrgMemberOptions } from '../../hooks/use-org-member-options'\nimport { ReportExport } from './report-export'\nimport { reportFilename } from './report-format'\nimport {\n type CrmReportScope,\n reportCacheKey,\n scopedCollection,\n visibleToClause,\n} from './report-scope'\nimport { ReportStatTile } from './report-stat-tile'\nimport { useAggregateRead, useWindowRead } from './use-aggregate-read'\n\n/**\n * How many activities and how many completed tasks the leaderboard is\n * grouped from.\n *\n * The tiles are server counts and never meet these bounds; the table needs\n * each activity's kind and author and each task's completer, so it reads\n * the period's newest thousand of each and says when there were more —\n * the contacts list's bound, and the one every window on this page shares.\n */\nconst ACTIVITY_CEILING = 1000\nconst TASK_DONE_CEILING = 1000\n\ntype ActivityRow = Aglyn.CrmActivityRow\ntype TaskRow = Aglyn.CrmTask & { $id: string }\n\n/** The table's columns, which are also the CSV's. */\nconst COLUMNS = [\n 'Teammate',\n ...Aglyn.CRM_ACTIVITY_KINDS.map((kind) => Aglyn.CRM_ACTIVITY_KIND_LABELS[kind]),\n 'Activities',\n 'Tasks done',\n] as const\n\nexport interface ActivityCardProps {\n report: CrmReportScope\n}\n\n/**\n * Activity by teammate (AGL-2624): the calls, emails, meetings and notes\n * each member logged in the period, and the tasks they ticked off,\n * busiest first.\n *\n * ## Two windows, two indexes, one table\n *\n * Activities are counted within the period on `atMs`; completed tasks are\n * counted the same way on `completedAtMs`, under `status == 'done'`. Each\n * count is also drawn as a window, newest first, for the leaderboard.\n *\n * ## Why that is four indexes and not one\n *\n * The counts and the windows do not share an index, and neither do the two\n * audiences.\n *\n * A COUNT here names no `orderBy`. Firestore then orders implicitly by the\n * range field, ASCENDING, so a count wants `completedAtMs` ascending — while\n * the window beside it asks for `desc` explicitly and wants the descending\n * one. A composite index serves one direction or its exact reverse, never\n * both, so declaring only the direction the window reads leaves the count\n * with nothing: `FAILED_PRECONDITION`, one column of dashes, and a card that\n * otherwise looks fine.\n *\n * Then the visibility clause doubles it. `visibleToClause` contributes\n * nothing when the reader's tokens are null, which is every organization-level\n * read, so the shape arriving at Firestore has no leading array field — a\n * different index, not a prefix of the one with it. `(visibleTo, status,\n * completedAtMs)` serves a site and `(status, completedAtMs)` the org above\n * it; one without the other is a card that works for exactly one audience.\n *\n * The two reads are independent so that a missing task index degrades ONE\n * column to a dash and a notice rather than the whole card: the activities\n * were read, and the leaderboard draws them.\n *\n * A task ordered by `completedAtMs` is a task the complete route stamped;\n * a task marked done some other way, without the stamp, is not in the\n * window and the caption says what the column is grouped from.\n *\n * ## Names\n *\n * Every activity carries the name it was signed with, for the reason\n * `CrmActivity.byName` gives — a scoped reader cannot resolve a colleague's\n * uid. The roster is read too, through the members route any member may\n * ask, and wins when it knows the uid, so a renamed teammate reads by\n * their current name; the signed name covers a uid the roster no longer\n * has, and the uid itself covers the rest.\n */\nexport function ActivityCard(props: ActivityCardProps) {\n const { report } = props\n const { scope, tokens, range, period, routes } = report\n const firestore = useFirestore()\n const roster = useOrgMemberOptions(scope[1])\n\n const activitiesBetween = (from: number, to: number) =>\n query(\n scopedCollection(firestore, scope, Aglyn.CRM_COLLECTIONS.activities),\n ...visibleToClause(tokens),\n where('atMs', '>=', from),\n where('atMs', '<', to),\n )\n const tasksDoneBetween = (from: number, to: number) =>\n query(\n scopedCollection(firestore, scope, Aglyn.CRM_COLLECTIONS.tasks),\n ...visibleToClause(tokens),\n where('status', '==', 'done'),\n where('completedAtMs', '>=', from),\n where('completedAtMs', '<', to),\n )\n const countOf = (target: ReturnType<typeof query>) =>\n getCountFromServer(target).then((snapshot) => snapshot.data().count)\n\n const activityCounts = useAggregateRead(\n () =>\n Promise.all([\n countOf(activitiesBetween(range.from, range.to)),\n countOf(activitiesBetween(range.previousFrom, range.previousTo)),\n ]).then(([current, previous]) => ({ current, previous })),\n [firestore, scope, tokens, range],\n { cacheKey: reportCacheKey(report, 'activity:counts') },\n )\n const taskCounts = useAggregateRead(\n () =>\n Promise.all([\n countOf(tasksDoneBetween(range.from, range.to)),\n countOf(tasksDoneBetween(range.previousFrom, range.previousTo)),\n ]).then(([current, previous]) => ({ current, previous })),\n [firestore, scope, tokens, range],\n { cacheKey: reportCacheKey(report, 'activity:tasks-counts') },\n )\n\n const activityWindow = useWindowRead<ActivityRow>(\n () =>\n query(\n activitiesBetween(range.from, range.to),\n orderBy('atMs', 'desc'),\n limit(ACTIVITY_CEILING + 1),\n ),\n ACTIVITY_CEILING,\n [firestore, scope, tokens, range],\n { cacheKey: reportCacheKey(report, 'activity:window') },\n )\n const taskWindow = useWindowRead<TaskRow>(\n () =>\n query(\n tasksDoneBetween(range.from, range.to),\n orderBy('completedAtMs', 'desc'),\n limit(TASK_DONE_CEILING + 1),\n ),\n TASK_DONE_CEILING,\n [firestore, scope, tokens, range],\n { cacheKey: reportCacheKey(report, 'activity:tasks-window') },\n )\n\n const rows = useMemo(\n () => Aglyn.activityLeaderboard(activityWindow.rows, taskWindow.rows),\n [activityWindow, taskWindow],\n )\n const nameOf = (row: Aglyn.ActivityLeaderboardRow): string => {\n if (!row.uid) return 'No teammate'\n return Aglyn.findOrgMember(roster.options, row.uid)?.label ?? row.name ?? row.uid\n }\n const teammates = rows.filter((row) => row.uid).length\n\n const activitiesRead = activityWindow.status === 'success'\n const tasksRead = taskWindow.status === 'success'\n const settled = activityWindow.status !== 'loading' && taskWindow.status !== 'loading'\n const caption = [\n activityWindow.truncated\n ? `Grouped from the ${ACTIVITY_CEILING.toLocaleString()} most recent activities in the period`\n : null,\n taskWindow.truncated\n ? `the ${TASK_DONE_CEILING.toLocaleString()} most recently completed tasks`\n : null,\n ]\n .filter(Boolean)\n .join(' and ')\n const activityFigures = activityCounts.value\n const taskFigures = taskCounts.value\n\n return (\n <CardDisplay\n header={'Activity by teammate'}\n help={Aglyn.pluginDocsHelp('crmReports', {\n anchor: '#activity-by-teammate',\n excerpt:\n 'The calls, emails, meetings and notes each teammate logged in ' +\n 'the period, and the tasks they completed, busiest first. ' +\n 'Grouped from the period’s newest thousand of each.',\n })}\n contentGutterX\n contentGutterY\n >\n <Stack spacing={2}>\n <Stack direction=\"row\" spacing={3} sx={{ flexWrap: 'wrap' }}>\n <ReportStatTile\n label={'Activities logged'}\n value={activityFigures ? activityFigures.current.toLocaleString() : null}\n deltaPct={\n activityFigures\n ? Aglyn.deltaPercent(activityFigures.current, activityFigures.previous)\n : null\n }\n note={'counted on the server'}\n href={routes.section('contacts')}\n />\n <ReportStatTile\n label={'Tasks completed'}\n value={taskFigures ? taskFigures.current.toLocaleString() : null}\n deltaPct={\n taskFigures\n ? Aglyn.deltaPercent(taskFigures.current, taskFigures.previous)\n : null\n }\n note={'ticked off in the period'}\n href={routes.section('tasks')}\n />\n <ReportStatTile\n label={'Teammates active'}\n value={settled ? teammates.toLocaleString() : null}\n note={'logged or completed something'}\n />\n </Stack>\n {activityCounts.status === 'error' || activityWindow.status === 'error' ? (\n <Alert severity=\"warning\">{'The activities could not be read.'}</Alert>\n ) : null}\n {taskCounts.status === 'error' || taskWindow.status === 'error' ? (\n <Alert severity=\"warning\">\n {'The completed-task counts could not be read; the Tasks done column is left blank.'}\n </Alert>\n ) : null}\n <Section title={'Who did what'}>\n {rows.length ? (\n <ScrollTable size=\"small\">\n <TableHead>\n <TableRow>\n {COLUMNS.map((column, index) => (\n <TableCell key={column} align={index ? 'right' : 'left'}>\n {column}\n </TableCell>\n ))}\n </TableRow>\n </TableHead>\n <TableBody>\n {rows.map((row) => (\n <TableRow key={row.uid || '$nobody'}>\n <TableCell>{nameOf(row)}</TableCell>\n {Aglyn.CRM_ACTIVITY_KINDS.map((kind) => (\n <TableCell key={kind} align=\"right\">\n {row.kinds[kind].toLocaleString()}\n </TableCell>\n ))}\n <TableCell align=\"right\">{row.activities.toLocaleString()}</TableCell>\n <TableCell align=\"right\">\n {tasksRead ? row.tasksDone.toLocaleString() : '—'}\n </TableCell>\n </TableRow>\n ))}\n </TableBody>\n </ScrollTable>\n ) : (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {settled ? 'Nothing logged or completed in this period.' : 'Reading…'}\n </Typography>\n )}\n {rows.some((row) => !row.uid) ? (\n <Typography variant=\"caption\" color=\"text.secondary\">\n {'No teammate — activities an automation logged, and tasks completed with nobody assigned.'}\n </Typography>\n ) : null}\n <ReportExport\n filename={reportFilename('activity', period)}\n columns={COLUMNS}\n rows={() =>\n rows.map((row) => [\n nameOf(row),\n ...Aglyn.CRM_ACTIVITY_KINDS.map((kind) => row.kinds[kind]),\n row.activities,\n tasksRead ? row.tasksDone : '',\n ])\n }\n disabled={!activitiesRead || !rows.length}\n caption={caption ? `${caption}; the tiles are counted on the server.` : undefined}\n />\n </Section>\n </Stack>\n </CardDisplay>\n )\n}\nActivityCard.displayName = 'ActivityCard'\n\nexport default ActivityCard\n"],"names":["Aglyn","CardDisplay","Section","ScrollTable","Alert","Stack","TableBody","TableCell","TableHead","TableRow","Typography","getCountFromServer","limit","orderBy","query","where","useMemo","useFirestore","useOrgMemberOptions","ReportExport","reportFilename","reportCacheKey","scopedCollection","visibleToClause","ReportStatTile","useAggregateRead","useWindowRead","ACTIVITY_CEILING","TASK_DONE_CEILING","COLUMNS","CRM_ACTIVITY_KINDS","map","kind","CRM_ACTIVITY_KIND_LABELS","ActivityCard","props","report","scope","tokens","range","period","routes","firestore","roster","activitiesBetween","from","to","CRM_COLLECTIONS","activities","tasksDoneBetween","tasks","countOf","target","then","snapshot","data","count","activityCounts","Promise","all","previousFrom","previousTo","current","previous","cacheKey","taskCounts","activityWindow","taskWindow","rows","activityLeaderboard","nameOf","row","uid","findOrgMember","options","label","name","teammates","filter","length","activitiesRead","status","tasksRead","settled","caption","truncated","toLocaleString","Boolean","join","activityFigures","value","taskFigures","header","help","pluginDocsHelp","anchor","excerpt","contentGutterX","contentGutterY","spacing","direction","sx","flexWrap","deltaPct","deltaPercent","note","href","section","severity","title","size","column","index","align","kinds","tasksDone","variant","color","some","filename","columns","disabled","undefined","displayName"],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ import { type CrmReportScope } from './report-scope';
2
+ export interface ClosedDealsCardProps {
3
+ report: CrmReportScope;
4
+ }
5
+ /**
6
+ * Deals won and lost in the period, and the win rate over what closed
7
+ * (AGL-2604).
8
+ *
9
+ * Won and lost are TWO queries rather than one over `status in [won,
10
+ * lost]`: each is an equality the `(visibleTo, status, closedAtMs)` index
11
+ * serves directly, and a card that drew one series from a merged read
12
+ * would have to split it again by hand. The range is on `closedAtMs`, the
13
+ * moment the deal was closed — not `updatedAt`, which a note added last
14
+ * week would move.
15
+ */
16
+ export declare function ClosedDealsCard(props: ClosedDealsCardProps): import("react").JSX.Element;
17
+ export declare namespace ClosedDealsCard {
18
+ var displayName: string;
19
+ }
20
+ export default ClosedDealsCard;
@@ -0,0 +1,194 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Aglyn LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */ 'use client';
17
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
18
+ import * as Aglyn from "@aglyn/aglyn";
19
+ import { money } from "@aglyn/shared-ui-email-campaigns/components/report-figures";
20
+ import { CardDisplay } from "@aglyn/shared-ui-jsx";
21
+ import { measuredRate, percent, Section } from "@aglyn/shared-ui-jsx/components/measured-figures.component";
22
+ import { Alert, Stack, Typography } from "@mui/material";
23
+ import { count, getAggregateFromServer, getCountFromServer, limit, orderBy, query, sum, where } from "firebase/firestore";
24
+ import { useMemo } from "react";
25
+ import { useFirestore } from "@aglyn/tenant-feature-instance";
26
+ import { ReportBarChart } from "./report-bar-chart.js";
27
+ import { weekLabel } from "./report-format.js";
28
+ import { reportCacheKey, scopedCollection, visibleToClause } from "./report-scope.js";
29
+ import { ReportStatTile } from "./report-stat-tile.js";
30
+ import { useAggregateRead, useWindowRead } from "./use-aggregate-read.js";
31
+ /**
32
+ * How many closed deals of each outcome the weekly chart reads.
33
+ *
34
+ * The tiles are server aggregates and never meet this bound; the chart
35
+ * needs each deal's `closedAtMs` to place it in a week, so it reads them,
36
+ * most recent first, and says when the period held more.
37
+ */ const CLOSED_DEAL_CEILING = 500;
38
+ /**
39
+ * Deals won and lost in the period, and the win rate over what closed
40
+ * (AGL-2604).
41
+ *
42
+ * Won and lost are TWO queries rather than one over `status in [won,
43
+ * lost]`: each is an equality the `(visibleTo, status, closedAtMs)` index
44
+ * serves directly, and a card that drew one series from a merged read
45
+ * would have to split it again by hand. The range is on `closedAtMs`, the
46
+ * moment the deal was closed — not `updatedAt`, which a note added last
47
+ * week would move.
48
+ */ export function ClosedDealsCard(props) {
49
+ const { report } = props;
50
+ const { scope, tokens, range, routes } = report;
51
+ const firestore = useFirestore();
52
+ const closedInPeriod = (status)=>query(scopedCollection(firestore, scope, 'deals'), ...visibleToClause(tokens), where('status', '==', status), where('closedAtMs', '>=', range.from), where('closedAtMs', '<', range.to));
53
+ const closed = useAggregateRead(()=>Promise.all([
54
+ getAggregateFromServer(closedInPeriod('won'), {
55
+ count: count(),
56
+ amountCents: sum('amountCents')
57
+ }).then((snapshot)=>{
58
+ var _snapshot_data_count, _snapshot_data_amountCents;
59
+ return {
60
+ count: Number((_snapshot_data_count = snapshot.data().count) != null ? _snapshot_data_count : 0),
61
+ amountCents: Number((_snapshot_data_amountCents = snapshot.data().amountCents) != null ? _snapshot_data_amountCents : 0)
62
+ };
63
+ }),
64
+ getCountFromServer(closedInPeriod('lost')).then((snapshot)=>snapshot.data().count)
65
+ ]).then(([won, lost])=>({
66
+ won,
67
+ lost
68
+ })), [
69
+ firestore,
70
+ scope,
71
+ tokens,
72
+ range
73
+ ], {
74
+ cacheKey: reportCacheKey(report, 'closed:totals')
75
+ });
76
+ const wonWindow = useWindowRead(()=>query(closedInPeriod('won'), orderBy('closedAtMs', 'desc'), limit(CLOSED_DEAL_CEILING + 1)), CLOSED_DEAL_CEILING, [
77
+ firestore,
78
+ scope,
79
+ tokens,
80
+ range
81
+ ], {
82
+ cacheKey: reportCacheKey(report, 'closed:won')
83
+ });
84
+ const lostWindow = useWindowRead(()=>query(closedInPeriod('lost'), orderBy('closedAtMs', 'desc'), limit(CLOSED_DEAL_CEILING + 1)), CLOSED_DEAL_CEILING, [
85
+ firestore,
86
+ scope,
87
+ tokens,
88
+ range
89
+ ], {
90
+ cacheKey: reportCacheKey(report, 'closed:lost')
91
+ });
92
+ const wonStatus = wonWindow.status;
93
+ const lostStatus = lostWindow.status;
94
+ const chart = useMemo(()=>{
95
+ const wonWeeks = Aglyn.bucketByWeek(wonWindow.rows, (deal)=>deal.closedAtMs, range.from, range.to);
96
+ const lostWeeks = Aglyn.bucketByWeek(lostWindow.rows, (deal)=>deal.closedAtMs, range.from, range.to);
97
+ return {
98
+ labels: wonWeeks.map((week)=>weekLabel(week.start)),
99
+ won: wonWeeks.map((week)=>week.items.length),
100
+ wonCents: wonWeeks.map((week)=>week.items.reduce((total, deal)=>{
101
+ var _deal_amountCents;
102
+ return total + Math.max(0, Number((_deal_amountCents = deal.amountCents) != null ? _deal_amountCents : 0));
103
+ }, 0)),
104
+ lost: lostWeeks.map((week)=>week.items.length),
105
+ currency: Aglyn.currencyOfDeals(wonWindow.rows).currency
106
+ };
107
+ }, [
108
+ wonWindow,
109
+ lostWindow,
110
+ range
111
+ ]);
112
+ const figures = closed.value;
113
+ const winRate = figures ? measuredRate(figures.won.count, figures.won.count + figures.lost, 'closed') : null;
114
+ const chartRead = wonStatus === 'success' && lostStatus === 'success';
115
+ return /*#__PURE__*/ _jsx(CardDisplay, {
116
+ header: 'Won and lost',
117
+ help: Aglyn.pluginDocsHelp('crmReports', {
118
+ anchor: '#won-and-lost',
119
+ excerpt: 'Deals closed in the period, by outcome and by week, with the ' + 'value of what was won and the win rate over everything that ' + 'closed. Placed by the moment each deal was closed.'
120
+ }),
121
+ contentGutterX: true,
122
+ contentGutterY: true,
123
+ children: /*#__PURE__*/ _jsxs(Stack, {
124
+ spacing: 2,
125
+ children: [
126
+ /*#__PURE__*/ _jsxs(Stack, {
127
+ direction: "row",
128
+ spacing: 3,
129
+ sx: {
130
+ flexWrap: 'wrap'
131
+ },
132
+ children: [
133
+ /*#__PURE__*/ _jsx(ReportStatTile, {
134
+ label: 'Won',
135
+ value: figures ? figures.won.count.toLocaleString() : null,
136
+ note: figures ? `${money(figures.won.amountCents, chart.currency)} closed won` : undefined,
137
+ href: routes.section('deals')
138
+ }),
139
+ /*#__PURE__*/ _jsx(ReportStatTile, {
140
+ label: 'Lost',
141
+ value: figures ? figures.lost.toLocaleString() : null,
142
+ note: 'in the period',
143
+ riseIsGood: false,
144
+ href: routes.section('deals')
145
+ }),
146
+ /*#__PURE__*/ _jsx(ReportStatTile, {
147
+ label: 'Win rate',
148
+ value: winRate ? percent(winRate.value) : null,
149
+ note: winRate ? `${winRate.numerator.toLocaleString()} of ${winRate.denominator.toLocaleString()} ${winRate.denominatorLabel}` : figures ? 'nothing closed in the period' : undefined
150
+ })
151
+ ]
152
+ }),
153
+ closed.status === 'error' ? /*#__PURE__*/ _jsx(Alert, {
154
+ severity: "warning",
155
+ children: 'The closed-deal totals could not be read.'
156
+ }) : null,
157
+ /*#__PURE__*/ _jsxs(Section, {
158
+ title: 'Won vs lost per week',
159
+ children: [
160
+ /*#__PURE__*/ _jsx(ReportBarChart, {
161
+ labels: chart.labels,
162
+ series: [
163
+ {
164
+ name: 'Won',
165
+ color: 'success.main',
166
+ values: chart.won
167
+ },
168
+ {
169
+ name: 'Lost',
170
+ color: 'error.main',
171
+ values: chart.lost
172
+ }
173
+ ],
174
+ format: (value, seriesIndex, barIndex)=>{
175
+ var _chart_wonCents_barIndex;
176
+ return seriesIndex === 0 ? `Won: ${value.toLocaleString()} · ${money((_chart_wonCents_barIndex = chart.wonCents[barIndex]) != null ? _chart_wonCents_barIndex : 0, chart.currency)}` : `Lost: ${value.toLocaleString()}`;
177
+ },
178
+ emptyText: chartRead ? 'Nothing closed in this period.' : 'Reading…'
179
+ }),
180
+ wonWindow.truncated || lostWindow.truncated ? /*#__PURE__*/ _jsx(Typography, {
181
+ variant: "caption",
182
+ color: "text.secondary",
183
+ children: `The chart places the ${CLOSED_DEAL_CEILING} most recently closed of each outcome; the tiles are counted on the server.`
184
+ }) : null
185
+ ]
186
+ })
187
+ ]
188
+ })
189
+ });
190
+ }
191
+ ClosedDealsCard.displayName = 'ClosedDealsCard';
192
+ export default ClosedDealsCard;
193
+
194
+ //# sourceMappingURL=closed-deals-card.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../../libs/plugins/crm/src/lib/components/reports/closed-deals-card.tsx"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n'use client'\n\nimport * as Aglyn from '@aglyn/aglyn'\nimport { money } from '@aglyn/shared-ui-email-campaigns/components/report-figures'\nimport { CardDisplay } from '@aglyn/shared-ui-jsx'\nimport {\n measuredRate,\n percent,\n Section,\n} from '@aglyn/shared-ui-jsx/components/measured-figures.component'\nimport { Alert, Stack, Typography } from '@mui/material'\nimport {\n count,\n getAggregateFromServer,\n getCountFromServer,\n limit,\n orderBy,\n query,\n sum,\n where,\n} from 'firebase/firestore'\nimport { useMemo } from 'react'\nimport { useFirestore } from '@aglyn/tenant-feature-instance'\nimport { ReportBarChart } from './report-bar-chart'\nimport { weekLabel } from './report-format'\nimport {\n type CrmReportScope,\n reportCacheKey,\n scopedCollection,\n visibleToClause,\n} from './report-scope'\nimport { ReportStatTile } from './report-stat-tile'\nimport { useAggregateRead, useWindowRead } from './use-aggregate-read'\n\n/**\n * How many closed deals of each outcome the weekly chart reads.\n *\n * The tiles are server aggregates and never meet this bound; the chart\n * needs each deal's `closedAtMs` to place it in a week, so it reads them,\n * most recent first, and says when the period held more.\n */\nconst CLOSED_DEAL_CEILING = 500\n\ntype DealRow = Aglyn.CrmDeal & { $id: string }\n\nexport interface ClosedDealsCardProps {\n report: CrmReportScope\n}\n\n/**\n * Deals won and lost in the period, and the win rate over what closed\n * (AGL-2604).\n *\n * Won and lost are TWO queries rather than one over `status in [won,\n * lost]`: each is an equality the `(visibleTo, status, closedAtMs)` index\n * serves directly, and a card that drew one series from a merged read\n * would have to split it again by hand. The range is on `closedAtMs`, the\n * moment the deal was closed — not `updatedAt`, which a note added last\n * week would move.\n */\nexport function ClosedDealsCard(props: ClosedDealsCardProps) {\n const { report } = props\n const { scope, tokens, range, routes } = report\n const firestore = useFirestore()\n\n const closedInPeriod = (status: Aglyn.CrmDealStatus) =>\n query(\n scopedCollection(firestore, scope, 'deals'),\n ...visibleToClause(tokens),\n where('status', '==', status),\n where('closedAtMs', '>=', range.from),\n where('closedAtMs', '<', range.to),\n )\n\n const closed = useAggregateRead(\n () =>\n Promise.all([\n getAggregateFromServer(closedInPeriod('won'), {\n count: count(),\n amountCents: sum('amountCents'),\n }).then((snapshot) => ({\n count: Number(snapshot.data().count ?? 0),\n amountCents: Number(snapshot.data().amountCents ?? 0),\n })),\n getCountFromServer(closedInPeriod('lost')).then(\n (snapshot) => snapshot.data().count,\n ),\n ]).then(([won, lost]) => ({ won, lost })),\n [firestore, scope, tokens, range],\n { cacheKey: reportCacheKey(report, 'closed:totals') },\n )\n\n const wonWindow = useWindowRead<DealRow>(\n () =>\n query(\n closedInPeriod('won'),\n orderBy('closedAtMs', 'desc'),\n limit(CLOSED_DEAL_CEILING + 1),\n ),\n CLOSED_DEAL_CEILING,\n [firestore, scope, tokens, range],\n { cacheKey: reportCacheKey(report, 'closed:won') },\n )\n const lostWindow = useWindowRead<DealRow>(\n () =>\n query(\n closedInPeriod('lost'),\n orderBy('closedAtMs', 'desc'),\n limit(CLOSED_DEAL_CEILING + 1),\n ),\n CLOSED_DEAL_CEILING,\n [firestore, scope, tokens, range],\n { cacheKey: reportCacheKey(report, 'closed:lost') },\n )\n const wonStatus = wonWindow.status\n const lostStatus = lostWindow.status\n\n const chart = useMemo(() => {\n const wonWeeks = Aglyn.bucketByWeek(\n wonWindow.rows,\n (deal) => deal.closedAtMs,\n range.from,\n range.to,\n )\n const lostWeeks = Aglyn.bucketByWeek(\n lostWindow.rows,\n (deal) => deal.closedAtMs,\n range.from,\n range.to,\n )\n return {\n labels: wonWeeks.map((week) => weekLabel(week.start)),\n won: wonWeeks.map((week) => week.items.length),\n wonCents: wonWeeks.map((week) =>\n week.items.reduce(\n (total, deal) => total + Math.max(0, Number(deal.amountCents ?? 0)),\n 0,\n ),\n ),\n lost: lostWeeks.map((week) => week.items.length),\n currency: Aglyn.currencyOfDeals(wonWindow.rows).currency,\n }\n }, [wonWindow, lostWindow, range])\n\n const figures = closed.value\n const winRate = figures\n ? measuredRate(figures.won.count, figures.won.count + figures.lost, 'closed')\n : null\n const chartRead = wonStatus === 'success' && lostStatus === 'success'\n\n return (\n <CardDisplay\n header={'Won and lost'}\n help={Aglyn.pluginDocsHelp('crmReports', {\n anchor: '#won-and-lost',\n excerpt:\n 'Deals closed in the period, by outcome and by week, with the ' +\n 'value of what was won and the win rate over everything that ' +\n 'closed. Placed by the moment each deal was closed.',\n })}\n contentGutterX\n contentGutterY\n >\n <Stack spacing={2}>\n <Stack direction=\"row\" spacing={3} sx={{ flexWrap: 'wrap' }}>\n <ReportStatTile\n label={'Won'}\n value={figures ? figures.won.count.toLocaleString() : null}\n note={\n figures\n ? `${money(figures.won.amountCents, chart.currency)} closed won`\n : undefined\n }\n href={routes.section('deals')}\n />\n <ReportStatTile\n label={'Lost'}\n value={figures ? figures.lost.toLocaleString() : null}\n note={'in the period'}\n riseIsGood={false}\n href={routes.section('deals')}\n />\n <ReportStatTile\n label={'Win rate'}\n value={winRate ? percent(winRate.value) : null}\n note={\n winRate\n ? `${winRate.numerator.toLocaleString()} of ${winRate.denominator.toLocaleString()} ${winRate.denominatorLabel}`\n : figures\n ? 'nothing closed in the period'\n : undefined\n }\n />\n </Stack>\n {closed.status === 'error' ? (\n <Alert severity=\"warning\">\n {'The closed-deal totals could not be read.'}\n </Alert>\n ) : null}\n <Section title={'Won vs lost per week'}>\n <ReportBarChart\n labels={chart.labels}\n series={[\n { name: 'Won', color: 'success.main', values: chart.won },\n { name: 'Lost', color: 'error.main', values: chart.lost },\n ]}\n format={(value, seriesIndex, barIndex) =>\n seriesIndex === 0\n ? `Won: ${value.toLocaleString()} · ${money(chart.wonCents[barIndex] ?? 0, chart.currency)}`\n : `Lost: ${value.toLocaleString()}`\n }\n emptyText={chartRead ? 'Nothing closed in this period.' : 'Reading…'}\n />\n {wonWindow.truncated || lostWindow.truncated ? (\n <Typography variant=\"caption\" color=\"text.secondary\">\n {`The chart places the ${CLOSED_DEAL_CEILING} most recently closed of each outcome; the tiles are counted on the server.`}\n </Typography>\n ) : null}\n </Section>\n </Stack>\n </CardDisplay>\n )\n}\nClosedDealsCard.displayName = 'ClosedDealsCard'\n\nexport default ClosedDealsCard\n"],"names":["Aglyn","money","CardDisplay","measuredRate","percent","Section","Alert","Stack","Typography","count","getAggregateFromServer","getCountFromServer","limit","orderBy","query","sum","where","useMemo","useFirestore","ReportBarChart","weekLabel","reportCacheKey","scopedCollection","visibleToClause","ReportStatTile","useAggregateRead","useWindowRead","CLOSED_DEAL_CEILING","ClosedDealsCard","props","report","scope","tokens","range","routes","firestore","closedInPeriod","status","from","to","closed","Promise","all","amountCents","then","snapshot","Number","data","won","lost","cacheKey","wonWindow","lostWindow","wonStatus","lostStatus","chart","wonWeeks","bucketByWeek","rows","deal","closedAtMs","lostWeeks","labels","map","week","start","items","length","wonCents","reduce","total","Math","max","currency","currencyOfDeals","figures","value","winRate","chartRead","header","help","pluginDocsHelp","anchor","excerpt","contentGutterX","contentGutterY","spacing","direction","sx","flexWrap","label","toLocaleString","note","undefined","href","section","riseIsGood","numerator","denominator","denominatorLabel","severity","title","series","name","color","values","format","seriesIndex","barIndex","emptyText","truncated","variant","displayName"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GACD;;AAEA,YAAYA,WAAW,eAAc;AACrC,SAASC,KAAK,QAAQ,6DAA4D;AAClF,SAASC,WAAW,QAAQ,uBAAsB;AAClD,SACEC,YAAY,EACZC,OAAO,EACPC,OAAO,QACF,6DAA4D;AACnE,SAASC,KAAK,EAAEC,KAAK,EAAEC,UAAU,QAAQ,gBAAe;AACxD,SACEC,KAAK,EACLC,sBAAsB,EACtBC,kBAAkB,EAClBC,KAAK,EACLC,OAAO,EACPC,KAAK,EACLC,GAAG,EACHC,KAAK,QACA,qBAAoB;AAC3B,SAASC,OAAO,QAAQ,QAAO;AAC/B,SAASC,YAAY,QAAQ,iCAAgC;AAC7D,SAASC,cAAc,QAAQ,wBAAoB;AACnD,SAASC,SAAS,QAAQ,qBAAiB;AAC3C,SAEEC,cAAc,EACdC,gBAAgB,EAChBC,eAAe,QACV,oBAAgB;AACvB,SAASC,cAAc,QAAQ,wBAAoB;AACnD,SAASC,gBAAgB,EAAEC,aAAa,QAAQ,0BAAsB;AAEtE;;;;;;CAMC,GACD,MAAMC,sBAAsB;AAQ5B;;;;;;;;;;CAUC,GACD,OAAO,SAASC,gBAAgBC,KAA2B;IACzD,MAAM,EAAEC,MAAM,EAAE,GAAGD;IACnB,MAAM,EAAEE,KAAK,EAAEC,MAAM,EAAEC,KAAK,EAAEC,MAAM,EAAE,GAAGJ;IACzC,MAAMK,YAAYjB;IAElB,MAAMkB,iBAAiB,CAACC,SACtBvB,MACEQ,iBAAiBa,WAAWJ,OAAO,aAChCR,gBAAgBS,SACnBhB,MAAM,UAAU,MAAMqB,SACtBrB,MAAM,cAAc,MAAMiB,MAAMK,IAAI,GACpCtB,MAAM,cAAc,KAAKiB,MAAMM,EAAE;IAGrC,MAAMC,SAASf,iBACb,IACEgB,QAAQC,GAAG,CAAC;YACVhC,uBAAuB0B,eAAe,QAAQ;gBAC5C3B,OAAOA;gBACPkC,aAAa5B,IAAI;YACnB,GAAG6B,IAAI,CAAC,CAACC;oBACOA,sBACMA;uBAFC;oBACrBpC,OAAOqC,QAAOD,uBAAAA,SAASE,IAAI,GAAGtC,KAAK,YAArBoC,uBAAyB;oBACvCF,aAAaG,QAAOD,6BAAAA,SAASE,IAAI,GAAGJ,WAAW,YAA3BE,6BAA+B;gBACrD;;YACAlC,mBAAmByB,eAAe,SAASQ,IAAI,CAC7C,CAACC,WAAaA,SAASE,IAAI,GAAGtC,KAAK;SAEtC,EAAEmC,IAAI,CAAC,CAAC,CAACI,KAAKC,KAAK,GAAM,CAAA;gBAAED;gBAAKC;YAAK,CAAA,IACxC;QAACd;QAAWJ;QAAOC;QAAQC;KAAM,EACjC;QAAEiB,UAAU7B,eAAeS,QAAQ;IAAiB;IAGtD,MAAMqB,YAAYzB,cAChB,IACEZ,MACEsB,eAAe,QACfvB,QAAQ,cAAc,SACtBD,MAAMe,sBAAsB,KAEhCA,qBACA;QAACQ;QAAWJ;QAAOC;QAAQC;KAAM,EACjC;QAAEiB,UAAU7B,eAAeS,QAAQ;IAAc;IAEnD,MAAMsB,aAAa1B,cACjB,IACEZ,MACEsB,eAAe,SACfvB,QAAQ,cAAc,SACtBD,MAAMe,sBAAsB,KAEhCA,qBACA;QAACQ;QAAWJ;QAAOC;QAAQC;KAAM,EACjC;QAAEiB,UAAU7B,eAAeS,QAAQ;IAAe;IAEpD,MAAMuB,YAAYF,UAAUd,MAAM;IAClC,MAAMiB,aAAaF,WAAWf,MAAM;IAEpC,MAAMkB,QAAQtC,QAAQ;QACpB,MAAMuC,WAAWxD,MAAMyD,YAAY,CACjCN,UAAUO,IAAI,EACd,CAACC,OAASA,KAAKC,UAAU,EACzB3B,MAAMK,IAAI,EACVL,MAAMM,EAAE;QAEV,MAAMsB,YAAY7D,MAAMyD,YAAY,CAClCL,WAAWM,IAAI,EACf,CAACC,OAASA,KAAKC,UAAU,EACzB3B,MAAMK,IAAI,EACVL,MAAMM,EAAE;QAEV,OAAO;YACLuB,QAAQN,SAASO,GAAG,CAAC,CAACC,OAAS5C,UAAU4C,KAAKC,KAAK;YACnDjB,KAAKQ,SAASO,GAAG,CAAC,CAACC,OAASA,KAAKE,KAAK,CAACC,MAAM;YAC7CC,UAAUZ,SAASO,GAAG,CAAC,CAACC,OACtBA,KAAKE,KAAK,CAACG,MAAM,CACf,CAACC,OAAOX;wBAAoCA;2BAA3BW,QAAQC,KAAKC,GAAG,CAAC,GAAG1B,QAAOa,oBAAAA,KAAKhB,WAAW,YAAhBgB,oBAAoB;mBAChE;YAGJV,MAAMY,UAAUE,GAAG,CAAC,CAACC,OAASA,KAAKE,KAAK,CAACC,MAAM;YAC/CM,UAAUzE,MAAM0E,eAAe,CAACvB,UAAUO,IAAI,EAAEe,QAAQ;QAC1D;IACF,GAAG;QAACtB;QAAWC;QAAYnB;KAAM;IAEjC,MAAM0C,UAAUnC,OAAOoC,KAAK;IAC5B,MAAMC,UAAUF,UACZxE,aAAawE,QAAQ3B,GAAG,CAACvC,KAAK,EAAEkE,QAAQ3B,GAAG,CAACvC,KAAK,GAAGkE,QAAQ1B,IAAI,EAAE,YAClE;IACJ,MAAM6B,YAAYzB,cAAc,aAAaC,eAAe;IAE5D,qBACE,KAACpD;QACC6E,QAAQ;QACRC,MAAMhF,MAAMiF,cAAc,CAAC,cAAc;YACvCC,QAAQ;YACRC,SACE,kEACA,iEACA;QACJ;QACAC,cAAc;QACdC,cAAc;kBAEd,cAAA,MAAC9E;YAAM+E,SAAS;;8BACd,MAAC/E;oBAAMgF,WAAU;oBAAMD,SAAS;oBAAGE,IAAI;wBAAEC,UAAU;oBAAO;;sCACxD,KAACjE;4BACCkE,OAAO;4BACPd,OAAOD,UAAUA,QAAQ3B,GAAG,CAACvC,KAAK,CAACkF,cAAc,KAAK;4BACtDC,MACEjB,UACI,GAAG1E,MAAM0E,QAAQ3B,GAAG,CAACL,WAAW,EAAEY,MAAMkB,QAAQ,EAAE,WAAW,CAAC,GAC9DoB;4BAENC,MAAM5D,OAAO6D,OAAO,CAAC;;sCAEvB,KAACvE;4BACCkE,OAAO;4BACPd,OAAOD,UAAUA,QAAQ1B,IAAI,CAAC0C,cAAc,KAAK;4BACjDC,MAAM;4BACNI,YAAY;4BACZF,MAAM5D,OAAO6D,OAAO,CAAC;;sCAEvB,KAACvE;4BACCkE,OAAO;4BACPd,OAAOC,UAAUzE,QAAQyE,QAAQD,KAAK,IAAI;4BAC1CgB,MACEf,UACI,GAAGA,QAAQoB,SAAS,CAACN,cAAc,GAAG,IAAI,EAAEd,QAAQqB,WAAW,CAACP,cAAc,GAAG,CAAC,EAAEd,QAAQsB,gBAAgB,EAAE,GAC9GxB,UACE,iCACAkB;;;;gBAIXrD,OAAOH,MAAM,KAAK,wBACjB,KAAC/B;oBAAM8F,UAAS;8BACb;qBAED;8BACJ,MAAC/F;oBAAQgG,OAAO;;sCACd,KAAClF;4BACC2C,QAAQP,MAAMO,MAAM;4BACpBwC,QAAQ;gCACN;oCAAEC,MAAM;oCAAOC,OAAO;oCAAgBC,QAAQlD,MAAMP,GAAG;gCAAC;gCACxD;oCAAEuD,MAAM;oCAAQC,OAAO;oCAAcC,QAAQlD,MAAMN,IAAI;gCAAC;6BACzD;4BACDyD,QAAQ,CAAC9B,OAAO+B,aAAaC;oCAEmBrD;uCAD9CoD,gBAAgB,IACZ,CAAC,KAAK,EAAE/B,MAAMe,cAAc,GAAG,GAAG,EAAE1F,OAAMsD,2BAAAA,MAAMa,QAAQ,CAACwC,SAAS,YAAxBrD,2BAA4B,GAAGA,MAAMkB,QAAQ,GAAG,GAC1F,CAAC,MAAM,EAAEG,MAAMe,cAAc,IAAI;;4BAEvCkB,WAAW/B,YAAY,mCAAmC;;wBAE3D3B,UAAU2D,SAAS,IAAI1D,WAAW0D,SAAS,iBAC1C,KAACtG;4BAAWuG,SAAQ;4BAAUP,OAAM;sCACjC,CAAC,qBAAqB,EAAE7E,oBAAoB,2EAA2E,CAAC;6BAEzH;;;;;;AAKd;AACAC,gBAAgBoF,WAAW,GAAG;AAE9B,eAAepF,gBAAe"}
@@ -0,0 +1,27 @@
1
+ import { type CrmReportScope } from './report-scope';
2
+ import { type AggregateRead } from './use-aggregate-read';
3
+ export interface ContactsMixCardProps {
4
+ report: CrmReportScope;
5
+ /** The section's count of every contact this reader may see — what decides whether the read is a sample. */
6
+ totalContacts: AggregateRead<number>;
7
+ }
8
+ /**
9
+ * Contacts by source, and the lifecycle funnel, from the newest thousand
10
+ * contacts (AGL-2604).
11
+ *
12
+ * Both are read through THIS group's facet, the way every other field on
13
+ * the contacts page is: a source is which capture surface this holder saw
14
+ * the person through, and a stage is where this business's sales team put
15
+ * them. Reading either off the top of the document would chart another
16
+ * holder's records — the disclosure the facet shape exists to end.
17
+ *
18
+ * Newest by `createdAt` rather than by `updatedAt`, so that the sample is
19
+ * "the last thousand people captured" — a population a reader can reason
20
+ * about — and not "the thousand most recently edited", which is whichever
21
+ * ones a bulk tag touched last.
22
+ */
23
+ export declare function ContactsMixCard(props: ContactsMixCardProps): import("react").JSX.Element;
24
+ export declare namespace ContactsMixCard {
25
+ var displayName: string;
26
+ }
27
+ export default ContactsMixCard;