@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,99 @@
1
+ import { type DocumentData, type Query } from 'firebase/firestore';
2
+ import { type DependencyList } from 'react';
3
+ export type AggregateReadStatus = 'loading' | 'success' | 'error';
4
+ /**
5
+ * A server aggregate as a card renders it: the value once it has arrived,
6
+ * and `null` until then or when the server refused.
7
+ *
8
+ * `null` and not 0 for the same reason `Figure` draws a dash for it — "the
9
+ * count has not arrived" and "the count is zero" are different facts and a
10
+ * tile that showed 0 for the first would be read as the second.
11
+ */
12
+ export interface AggregateRead<T> {
13
+ value: T | null;
14
+ status: AggregateReadStatus;
15
+ }
16
+ export interface AggregateReadOptions {
17
+ /**
18
+ * Remember the answer under this key for {@link AGGREGATE_READ_TTL_MS},
19
+ * so the same question asked again — the section reopened, a card
20
+ * remounted — is answered from memory rather than from the server. Omit
21
+ * it and every change of `deps` reads.
22
+ */
23
+ cacheKey?: string;
24
+ ttlMs?: number;
25
+ }
26
+ /**
27
+ * How long a report answer is trusted (AGL-2614).
28
+ *
29
+ * A report is a snapshot, not a listener: nothing on the page moves while
30
+ * it is open, and the reader who closes it and opens it again a moment
31
+ * later is asking the same question. Sixty seconds is long enough to cover
32
+ * that round trip and short enough that a deal closed over lunch is on the
33
+ * page after it. The Refresh control is the way to ask sooner.
34
+ */
35
+ export declare const AGGREGATE_READ_TTL_MS = 60000;
36
+ /**
37
+ * Forgets every answer whose key starts with `prefix` — the section's
38
+ * Refresh, which names its own scope so a refresh of one org's reports
39
+ * does not throw away another's.
40
+ */
41
+ export declare function invalidateAggregateReads(prefix: string): void;
42
+ /** Test seam: forget everything. */
43
+ export declare function resetAggregateReadCache(): void;
44
+ /**
45
+ * One server-side read, run once per change of `deps` and never per render,
46
+ * and — when keyed — once per {@link AGGREGATE_READ_TTL_MS} rather than once
47
+ * per mount.
48
+ *
49
+ * The CRM reports are built from `getCountFromServer`,
50
+ * `getAggregateFromServer` and bounded `getDocs` windows — a count is a
51
+ * count, not the length of a capped listener — and each of those is a
52
+ * promise rather than a subscription, so it needs the effect-with-an-active-
53
+ * flag the contacts list already writes for its head-count. This is that
54
+ * effect, once, so that five cards do not carry five copies of it and one of
55
+ * them forgets the flag and sets state on an unmounted card.
56
+ *
57
+ * ## Why the answers are remembered
58
+ *
59
+ * The section reads up to 3,500 documents to draw its windows — the newest
60
+ * thousand contacts, a thousand open deals, a thousand open tasks, five
61
+ * hundred closed deals of each outcome — and it read them again every time
62
+ * the reader arrived, including the arrival ten seconds after they left to
63
+ * check a deal the report named. A report is a snapshot; the second arrival
64
+ * is the same question. A keyed read is answered from memory while its
65
+ * answer is fresh, and the key names the scope and the period so a different
66
+ * org, a different site group or a different period is a different question.
67
+ * Refusals are never remembered: a dash the server drew once should not be
68
+ * drawn from memory for a minute after the rules change.
69
+ *
70
+ * `read` returning `null` means "not yet" — the org scope has not resolved,
71
+ * the tokens are not known — and leaves the read pending rather than
72
+ * counting against nothing. The latest `read` is always the one invoked, via
73
+ * a ref, so the caller can close over fresh props without listing every one
74
+ * of them in `deps`; what `deps` names is WHEN to read again.
75
+ */
76
+ export declare function useAggregateRead<T>(read: () => Promise<T> | null, deps: DependencyList, options?: AggregateReadOptions): AggregateRead<T>;
77
+ /** A bounded window of documents as a card draws it, and whether the bound bit. */
78
+ export interface WindowRead<T> {
79
+ /** At most `ceiling` rows — the probe row is never among them. */
80
+ rows: T[];
81
+ /** The collection holds MORE than the ceiling. A fact from the probe, not a guess. */
82
+ truncated: boolean;
83
+ status: AggregateReadStatus;
84
+ }
85
+ /**
86
+ * A bounded window, read once and remembered — the report's replacement
87
+ * for a live listener over the same query.
88
+ *
89
+ * The cards used to hold their windows open as `onSnapshot` listeners,
90
+ * which is the right shape for a list somebody edits and the wrong one for
91
+ * a report: the listener re-delivered the whole window on every mount, and
92
+ * a snapshot that updates under the reader while they compare it to the
93
+ * tile above it is a page that contradicts itself. `getDocs` answers once,
94
+ * `ceilingedWindow` drops the probe row the caller over-fetched by, and the
95
+ * answer is remembered under `cacheKey` like every other report read.
96
+ *
97
+ * `build` returning `null` means "not yet", the way `read` does above.
98
+ */
99
+ export declare function useWindowRead<T extends DocumentData>(build: () => Query | null, ceiling: number, deps: DependencyList, options?: AggregateReadOptions): WindowRead<T>;
@@ -0,0 +1,195 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Aglyn LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */ 'use client';
17
+ import { _ as _extends } from "@swc/helpers/_/_extends";
18
+ import { ceilingedWindow } from "@aglyn/tenant-feature-instance/hooks/host-collection-queries";
19
+ import { getDocs } from "firebase/firestore";
20
+ import { useEffect, useMemo, useRef, useState } from "react";
21
+ /**
22
+ * How long a report answer is trusted (AGL-2614).
23
+ *
24
+ * A report is a snapshot, not a listener: nothing on the page moves while
25
+ * it is open, and the reader who closes it and opens it again a moment
26
+ * later is asking the same question. Sixty seconds is long enough to cover
27
+ * that round trip and short enough that a deal closed over lunch is on the
28
+ * page after it. The Refresh control is the way to ask sooner.
29
+ */ export const AGGREGATE_READ_TTL_MS = 60000;
30
+ /**
31
+ * The answers, for the life of the page load. Module state rather than
32
+ * React state because the point is to outlive the card that asked: the
33
+ * section unmounts when the reader leaves it, and everything a component
34
+ * held goes with it.
35
+ */ const cache = new Map();
36
+ /**
37
+ * The reads still in the air, by key (AGL-2620). Two cards that mount
38
+ * together and ask the same question — the pipeline card and the forecast
39
+ * card both want the open-deal window — would each miss the empty cache
40
+ * and each read a thousand documents; the second joins the first's
41
+ * promise instead. An entry lives only until its promise settles, so a
42
+ * refusal is neither remembered nor re-joined.
43
+ */ const inflight = new Map();
44
+ /** A fresh cached answer under `key`, or undefined. Expired entries are dropped on the way. */ function readCache(key, nowMs) {
45
+ const entry = cache.get(key);
46
+ if (!entry) return undefined;
47
+ if (entry.expiresAt <= nowMs) {
48
+ cache.delete(key);
49
+ return undefined;
50
+ }
51
+ return entry;
52
+ }
53
+ /**
54
+ * Forgets every answer whose key starts with `prefix` — the section's
55
+ * Refresh, which names its own scope so a refresh of one org's reports
56
+ * does not throw away another's.
57
+ */ export function invalidateAggregateReads(prefix) {
58
+ for (const key of [
59
+ ...cache.keys()
60
+ ]){
61
+ if (key.startsWith(prefix)) cache.delete(key);
62
+ }
63
+ }
64
+ /** Test seam: forget everything. */ export function resetAggregateReadCache() {
65
+ cache.clear();
66
+ inflight.clear();
67
+ }
68
+ /**
69
+ * One server-side read, run once per change of `deps` and never per render,
70
+ * and — when keyed — once per {@link AGGREGATE_READ_TTL_MS} rather than once
71
+ * per mount.
72
+ *
73
+ * The CRM reports are built from `getCountFromServer`,
74
+ * `getAggregateFromServer` and bounded `getDocs` windows — a count is a
75
+ * count, not the length of a capped listener — and each of those is a
76
+ * promise rather than a subscription, so it needs the effect-with-an-active-
77
+ * flag the contacts list already writes for its head-count. This is that
78
+ * effect, once, so that five cards do not carry five copies of it and one of
79
+ * them forgets the flag and sets state on an unmounted card.
80
+ *
81
+ * ## Why the answers are remembered
82
+ *
83
+ * The section reads up to 3,500 documents to draw its windows — the newest
84
+ * thousand contacts, a thousand open deals, a thousand open tasks, five
85
+ * hundred closed deals of each outcome — and it read them again every time
86
+ * the reader arrived, including the arrival ten seconds after they left to
87
+ * check a deal the report named. A report is a snapshot; the second arrival
88
+ * is the same question. A keyed read is answered from memory while its
89
+ * answer is fresh, and the key names the scope and the period so a different
90
+ * org, a different site group or a different period is a different question.
91
+ * Refusals are never remembered: a dash the server drew once should not be
92
+ * drawn from memory for a minute after the rules change.
93
+ *
94
+ * `read` returning `null` means "not yet" — the org scope has not resolved,
95
+ * the tokens are not known — and leaves the read pending rather than
96
+ * counting against nothing. The latest `read` is always the one invoked, via
97
+ * a ref, so the caller can close over fresh props without listing every one
98
+ * of them in `deps`; what `deps` names is WHEN to read again.
99
+ */ export function useAggregateRead(read, deps, options = {}) {
100
+ const { cacheKey, ttlMs = AGGREGATE_READ_TTL_MS } = options;
101
+ const [state, setState] = useState({
102
+ value: null,
103
+ status: 'loading'
104
+ });
105
+ const readRef = useRef(read);
106
+ readRef.current = read;
107
+ useEffect(()=>{
108
+ const remembered = cacheKey ? readCache(cacheKey, Date.now()) : undefined;
109
+ if (remembered) {
110
+ setState({
111
+ value: remembered.value,
112
+ status: 'success'
113
+ });
114
+ return undefined;
115
+ }
116
+ const joined = cacheKey ? inflight.get(cacheKey) : undefined;
117
+ const pending = joined != null ? joined : readRef.current();
118
+ setState({
119
+ value: null,
120
+ status: 'loading'
121
+ });
122
+ if (!pending) return undefined;
123
+ if (cacheKey && !joined) {
124
+ inflight.set(cacheKey, pending);
125
+ pending.finally(()=>{
126
+ if (inflight.get(cacheKey) === pending) inflight.delete(cacheKey);
127
+ }).catch(()=>undefined);
128
+ }
129
+ let active = true;
130
+ pending.then((value)=>{
131
+ if (cacheKey) cache.set(cacheKey, {
132
+ value,
133
+ expiresAt: Date.now() + ttlMs
134
+ });
135
+ if (active) setState({
136
+ value,
137
+ status: 'success'
138
+ });
139
+ }).catch(()=>{
140
+ // Denied or failed: the tile draws its dash. Nothing here substitutes
141
+ // a zero, because a zero is a measurement and this is the absence of
142
+ // one.
143
+ if (active) setState({
144
+ value: null,
145
+ status: 'error'
146
+ });
147
+ });
148
+ return ()=>{
149
+ active = false;
150
+ };
151
+ // `deps` is the caller's dependency list, forwarded the way
152
+ // `useFirestoreCollection` forwards its own; the key changes with them.
153
+ // eslint-disable-next-line react-hooks/exhaustive-deps
154
+ }, [
155
+ ...deps,
156
+ cacheKey
157
+ ]);
158
+ return state;
159
+ }
160
+ /**
161
+ * A bounded window, read once and remembered — the report's replacement
162
+ * for a live listener over the same query.
163
+ *
164
+ * The cards used to hold their windows open as `onSnapshot` listeners,
165
+ * which is the right shape for a list somebody edits and the wrong one for
166
+ * a report: the listener re-delivered the whole window on every mount, and
167
+ * a snapshot that updates under the reader while they compare it to the
168
+ * tile above it is a page that contradicts itself. `getDocs` answers once,
169
+ * `ceilingedWindow` drops the probe row the caller over-fetched by, and the
170
+ * answer is remembered under `cacheKey` like every other report read.
171
+ *
172
+ * `build` returning `null` means "not yet", the way `read` does above.
173
+ */ export function useWindowRead(build, ceiling, deps, options = {}) {
174
+ const buildRef = useRef(build);
175
+ buildRef.current = build;
176
+ const read = useAggregateRead(()=>{
177
+ const query = buildRef.current();
178
+ return query ? getDocs(query).then((snapshot)=>ceilingedWindow(snapshot.docs.map((document)=>_extends({}, document.data(), {
179
+ $id: document.id
180
+ })), ceiling)) : null;
181
+ }, deps, options);
182
+ return useMemo(()=>{
183
+ var _ref, _ref1;
184
+ var _read_value, _read_value1;
185
+ return {
186
+ rows: (_ref = (_read_value = read.value) == null ? void 0 : _read_value.rows) != null ? _ref : [],
187
+ truncated: (_ref1 = (_read_value1 = read.value) == null ? void 0 : _read_value1.truncated) != null ? _ref1 : false,
188
+ status: read.status
189
+ };
190
+ }, [
191
+ read
192
+ ]);
193
+ }
194
+
195
+ //# sourceMappingURL=use-aggregate-read.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../../libs/plugins/crm/src/lib/components/reports/use-aggregate-read.ts"],"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 { ceilingedWindow } from '@aglyn/tenant-feature-instance/hooks/host-collection-queries'\nimport { type DocumentData, getDocs, type Query } from 'firebase/firestore'\nimport { type DependencyList, useEffect, useMemo, useRef, useState } from 'react'\n\nexport type AggregateReadStatus = 'loading' | 'success' | 'error'\n\n/**\n * A server aggregate as a card renders it: the value once it has arrived,\n * and `null` until then or when the server refused.\n *\n * `null` and not 0 for the same reason `Figure` draws a dash for it — \"the\n * count has not arrived\" and \"the count is zero\" are different facts and a\n * tile that showed 0 for the first would be read as the second.\n */\nexport interface AggregateRead<T> {\n value: T | null\n status: AggregateReadStatus\n}\n\nexport interface AggregateReadOptions {\n /**\n * Remember the answer under this key for {@link AGGREGATE_READ_TTL_MS},\n * so the same question asked again — the section reopened, a card\n * remounted — is answered from memory rather than from the server. Omit\n * it and every change of `deps` reads.\n */\n cacheKey?: string\n ttlMs?: number\n}\n\n/**\n * How long a report answer is trusted (AGL-2614).\n *\n * A report is a snapshot, not a listener: nothing on the page moves while\n * it is open, and the reader who closes it and opens it again a moment\n * later is asking the same question. Sixty seconds is long enough to cover\n * that round trip and short enough that a deal closed over lunch is on the\n * page after it. The Refresh control is the way to ask sooner.\n */\nexport const AGGREGATE_READ_TTL_MS = 60_000\n\ninterface CacheEntry {\n value: unknown\n expiresAt: number\n}\n\n/**\n * The answers, for the life of the page load. Module state rather than\n * React state because the point is to outlive the card that asked: the\n * section unmounts when the reader leaves it, and everything a component\n * held goes with it.\n */\nconst cache = new Map<string, CacheEntry>()\n\n/**\n * The reads still in the air, by key (AGL-2620). Two cards that mount\n * together and ask the same question — the pipeline card and the forecast\n * card both want the open-deal window — would each miss the empty cache\n * and each read a thousand documents; the second joins the first's\n * promise instead. An entry lives only until its promise settles, so a\n * refusal is neither remembered nor re-joined.\n */\nconst inflight = new Map<string, Promise<unknown>>()\n\n/** A fresh cached answer under `key`, or undefined. Expired entries are dropped on the way. */\nfunction readCache(key: string, nowMs: number): CacheEntry | undefined {\n const entry = cache.get(key)\n if (!entry) return undefined\n if (entry.expiresAt <= nowMs) {\n cache.delete(key)\n return undefined\n }\n return entry\n}\n\n/**\n * Forgets every answer whose key starts with `prefix` — the section's\n * Refresh, which names its own scope so a refresh of one org's reports\n * does not throw away another's.\n */\nexport function invalidateAggregateReads(prefix: string): void {\n for (const key of [...cache.keys()]) {\n if (key.startsWith(prefix)) cache.delete(key)\n }\n}\n\n/** Test seam: forget everything. */\nexport function resetAggregateReadCache(): void {\n cache.clear()\n inflight.clear()\n}\n\n/**\n * One server-side read, run once per change of `deps` and never per render,\n * and — when keyed — once per {@link AGGREGATE_READ_TTL_MS} rather than once\n * per mount.\n *\n * The CRM reports are built from `getCountFromServer`,\n * `getAggregateFromServer` and bounded `getDocs` windows — a count is a\n * count, not the length of a capped listener — and each of those is a\n * promise rather than a subscription, so it needs the effect-with-an-active-\n * flag the contacts list already writes for its head-count. This is that\n * effect, once, so that five cards do not carry five copies of it and one of\n * them forgets the flag and sets state on an unmounted card.\n *\n * ## Why the answers are remembered\n *\n * The section reads up to 3,500 documents to draw its windows — the newest\n * thousand contacts, a thousand open deals, a thousand open tasks, five\n * hundred closed deals of each outcome — and it read them again every time\n * the reader arrived, including the arrival ten seconds after they left to\n * check a deal the report named. A report is a snapshot; the second arrival\n * is the same question. A keyed read is answered from memory while its\n * answer is fresh, and the key names the scope and the period so a different\n * org, a different site group or a different period is a different question.\n * Refusals are never remembered: a dash the server drew once should not be\n * drawn from memory for a minute after the rules change.\n *\n * `read` returning `null` means \"not yet\" — the org scope has not resolved,\n * the tokens are not known — and leaves the read pending rather than\n * counting against nothing. The latest `read` is always the one invoked, via\n * a ref, so the caller can close over fresh props without listing every one\n * of them in `deps`; what `deps` names is WHEN to read again.\n */\nexport function useAggregateRead<T>(\n read: () => Promise<T> | null,\n deps: DependencyList,\n options: AggregateReadOptions = {},\n): AggregateRead<T> {\n const { cacheKey, ttlMs = AGGREGATE_READ_TTL_MS } = options\n const [state, setState] = useState<AggregateRead<T>>({\n value: null,\n status: 'loading',\n })\n const readRef = useRef(read)\n readRef.current = read\n\n useEffect(() => {\n const remembered = cacheKey ? readCache(cacheKey, Date.now()) : undefined\n if (remembered) {\n setState({ value: remembered.value as T, status: 'success' })\n return undefined\n }\n const joined = cacheKey ? (inflight.get(cacheKey) as Promise<T> | undefined) : undefined\n const pending = joined ?? readRef.current()\n setState({ value: null, status: 'loading' })\n if (!pending) return undefined\n if (cacheKey && !joined) {\n inflight.set(cacheKey, pending)\n pending.finally(() => {\n if (inflight.get(cacheKey) === pending) inflight.delete(cacheKey)\n }).catch(() => undefined)\n }\n let active = true\n pending\n .then((value) => {\n if (cacheKey) cache.set(cacheKey, { value, expiresAt: Date.now() + ttlMs })\n if (active) setState({ value, status: 'success' })\n })\n .catch(() => {\n // Denied or failed: the tile draws its dash. Nothing here substitutes\n // a zero, because a zero is a measurement and this is the absence of\n // one.\n if (active) setState({ value: null, status: 'error' })\n })\n return () => {\n active = false\n }\n // `deps` is the caller's dependency list, forwarded the way\n // `useFirestoreCollection` forwards its own; the key changes with them.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [...deps, cacheKey])\n\n return state\n}\n\n/** A bounded window of documents as a card draws it, and whether the bound bit. */\nexport interface WindowRead<T> {\n /** At most `ceiling` rows — the probe row is never among them. */\n rows: T[]\n /** The collection holds MORE than the ceiling. A fact from the probe, not a guess. */\n truncated: boolean\n status: AggregateReadStatus\n}\n\n/**\n * A bounded window, read once and remembered — the report's replacement\n * for a live listener over the same query.\n *\n * The cards used to hold their windows open as `onSnapshot` listeners,\n * which is the right shape for a list somebody edits and the wrong one for\n * a report: the listener re-delivered the whole window on every mount, and\n * a snapshot that updates under the reader while they compare it to the\n * tile above it is a page that contradicts itself. `getDocs` answers once,\n * `ceilingedWindow` drops the probe row the caller over-fetched by, and the\n * answer is remembered under `cacheKey` like every other report read.\n *\n * `build` returning `null` means \"not yet\", the way `read` does above.\n */\nexport function useWindowRead<T extends DocumentData>(\n build: () => Query | null,\n ceiling: number,\n deps: DependencyList,\n options: AggregateReadOptions = {},\n): WindowRead<T> {\n const buildRef = useRef(build)\n buildRef.current = build\n const read = useAggregateRead<{ rows: T[]; truncated: boolean }>(\n () => {\n const query = buildRef.current()\n return query\n ? getDocs(query).then((snapshot) =>\n ceilingedWindow(\n snapshot.docs.map(\n (document) => ({ ...document.data(), $id: document.id }) as unknown as T,\n ),\n ceiling,\n ),\n )\n : null\n },\n deps,\n options,\n )\n return useMemo(\n () => ({\n rows: read.value?.rows ?? [],\n truncated: read.value?.truncated ?? false,\n status: read.status,\n }),\n [read],\n )\n}\n"],"names":["ceilingedWindow","getDocs","useEffect","useMemo","useRef","useState","AGGREGATE_READ_TTL_MS","cache","Map","inflight","readCache","key","nowMs","entry","get","undefined","expiresAt","delete","invalidateAggregateReads","prefix","keys","startsWith","resetAggregateReadCache","clear","useAggregateRead","read","deps","options","cacheKey","ttlMs","state","setState","value","status","readRef","current","remembered","Date","now","joined","pending","set","finally","catch","active","then","useWindowRead","build","ceiling","buildRef","query","snapshot","docs","map","document","data","$id","id","rows","truncated"],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ import { type CrmReportScope } from './report-scope';
2
+ export interface WonLostByOwnerCardProps {
3
+ report: CrmReportScope;
4
+ }
5
+ /**
6
+ * Who closed what (AGL-2662): the period's wins and losses, by the person
7
+ * who owned the deal at the close.
8
+ *
9
+ * ## It costs no read
10
+ *
11
+ * The two windows are the SAME queries the Won and lost card builds, under
12
+ * the same cache keys — `closed:won` and `closed:lost` — so
13
+ * `useAggregateRead` either answers this card from the remembered window or
14
+ * joins the other card's in-flight promise. Two cards, one pair of reads.
15
+ * A key of its own here would have doubled the most expensive read on the
16
+ * page to ask a different question of the same rows.
17
+ *
18
+ * ## Why the rows can under-report a very busy period
19
+ *
20
+ * The window is bounded, and the bound is on the deals rather than on the
21
+ * owners — so a period with more than {@link CLOSED_DEAL_CEILING} closes of
22
+ * an outcome is tallied over the most recent of them, and the caption says
23
+ * so. A server-side group-by would need one aggregate per owner, and the
24
+ * owner list is not known before the read.
25
+ */
26
+ export declare function WonLostByOwnerCard(props: WonLostByOwnerCardProps): import("react").JSX.Element;
27
+ export declare namespace WonLostByOwnerCard {
28
+ var displayName: string;
29
+ }
30
+ export default WonLostByOwnerCard;
@@ -0,0 +1,168 @@
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 { percent } from "@aglyn/shared-ui-jsx/components/measured-figures.component";
22
+ import { Alert, Stack, Typography } from "@mui/material";
23
+ import { 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 { ReportBreakdown } from "./report-breakdown.js";
28
+ import { reportCacheKey, scopedCollection, visibleToClause } from "./report-scope.js";
29
+ import { useWindowRead } from "./use-aggregate-read.js";
30
+ /**
31
+ * The same ceiling the Won and lost card reads its chart under, spelled
32
+ * from one constant so the two cards share the read rather than each
33
+ * paying for its own.
34
+ */ const CLOSED_DEAL_CEILING = 500;
35
+ /** How many owners the breakdown draws before folding the rest into one row. */ const OWNER_ROW_CEILING = 8;
36
+ /**
37
+ * Who closed what (AGL-2662): the period's wins and losses, by the person
38
+ * who owned the deal at the close.
39
+ *
40
+ * ## It costs no read
41
+ *
42
+ * The two windows are the SAME queries the Won and lost card builds, under
43
+ * the same cache keys — `closed:won` and `closed:lost` — so
44
+ * `useAggregateRead` either answers this card from the remembered window or
45
+ * joins the other card's in-flight promise. Two cards, one pair of reads.
46
+ * A key of its own here would have doubled the most expensive read on the
47
+ * page to ask a different question of the same rows.
48
+ *
49
+ * ## Why the rows can under-report a very busy period
50
+ *
51
+ * The window is bounded, and the bound is on the deals rather than on the
52
+ * owners — so a period with more than {@link CLOSED_DEAL_CEILING} closes of
53
+ * an outcome is tallied over the most recent of them, and the caption says
54
+ * so. A server-side group-by would need one aggregate per owner, and the
55
+ * owner list is not known before the read.
56
+ */ export function WonLostByOwnerCard(props) {
57
+ const { report } = props;
58
+ const { scope, tokens, range } = report;
59
+ const firestore = useFirestore();
60
+ // The roster resolves a uid into the name the team reads; a uid it no
61
+ // longer carries — somebody who has left — is named by its own id rather
62
+ // than dropped, because their closed deals still happened.
63
+ const roster = useOrgMemberOptions(scope[1]);
64
+ const closedInPeriod = (status)=>query(scopedCollection(firestore, scope, 'deals'), ...visibleToClause(tokens), where('status', '==', status), where('closedAtMs', '>=', range.from), where('closedAtMs', '<', range.to), orderBy('closedAtMs', 'desc'), limit(CLOSED_DEAL_CEILING + 1));
65
+ const wonWindow = useWindowRead(()=>closedInPeriod('won'), CLOSED_DEAL_CEILING, [
66
+ firestore,
67
+ scope,
68
+ tokens,
69
+ range
70
+ ], {
71
+ cacheKey: reportCacheKey(report, 'closed:won')
72
+ });
73
+ const lostWindow = useWindowRead(()=>closedInPeriod('lost'), CLOSED_DEAL_CEILING, [
74
+ firestore,
75
+ scope,
76
+ tokens,
77
+ range
78
+ ], {
79
+ cacheKey: reportCacheKey(report, 'closed:lost')
80
+ });
81
+ const owners = useMemo(()=>Aglyn.wonLostByOwner(wonWindow.rows, lostWindow.rows), [
82
+ wonWindow.rows,
83
+ lostWindow.rows
84
+ ]);
85
+ const currency = useMemo(()=>Aglyn.currencyOfDeals(wonWindow.rows).currency, [
86
+ wonWindow.rows
87
+ ]);
88
+ const read = wonWindow.status === 'success' && lostWindow.status === 'success';
89
+ const failed = wonWindow.status === 'error' || lostWindow.status === 'error';
90
+ const rows = useMemo(()=>{
91
+ const named = (uid)=>{
92
+ var _ref;
93
+ var _Aglyn_findOrgMember;
94
+ return uid ? (_ref = (_Aglyn_findOrgMember = Aglyn.findOrgMember(roster.options, uid)) == null ? void 0 : _Aglyn_findOrgMember.label) != null ? _ref : uid : 'Unassigned';
95
+ };
96
+ const shown = owners.slice(0, OWNER_ROW_CEILING);
97
+ const folded = owners.slice(OWNER_ROW_CEILING);
98
+ const rest = folded.reduce((total, owner)=>({
99
+ won: total.won + owner.won,
100
+ lost: total.lost + owner.lost,
101
+ wonAmountCents: total.wonAmountCents + owner.wonAmountCents
102
+ }), {
103
+ won: 0,
104
+ lost: 0,
105
+ wonAmountCents: 0
106
+ });
107
+ return [
108
+ ...shown.map((owner)=>({
109
+ key: owner.uid || 'unassigned',
110
+ label: named(owner.uid),
111
+ value: owner.won,
112
+ display: `${owner.won.toLocaleString()} won`,
113
+ note: `${owner.lost.toLocaleString()} lost · ` + `${owner.winRate === null ? 'no rate' : `${percent(owner.winRate)} win rate`} · ` + `${money(owner.wonAmountCents, currency)}`,
114
+ color: 'success.main'
115
+ })),
116
+ ...folded.length ? [
117
+ {
118
+ key: '$rest',
119
+ label: `${folded.length} more`,
120
+ value: rest.won,
121
+ display: `${rest.won.toLocaleString()} won`,
122
+ note: `${rest.lost.toLocaleString()} lost · ${money(rest.wonAmountCents, currency)}`,
123
+ color: 'success.main'
124
+ }
125
+ ] : []
126
+ ];
127
+ }, [
128
+ owners,
129
+ roster.options,
130
+ currency
131
+ ]);
132
+ return /*#__PURE__*/ _jsx(CardDisplay, {
133
+ header: 'Won and lost by owner',
134
+ help: Aglyn.pluginDocsHelp('crmReports', {
135
+ anchor: '#won-and-lost-by-owner',
136
+ excerpt: 'Closed deals grouped by the person who owned them at the close, ' + 'ranked by how much closed rather than by win rate, with the deals ' + 'nobody owned kept as a row of their own.'
137
+ }),
138
+ contentGutterX: true,
139
+ contentGutterY: true,
140
+ children: /*#__PURE__*/ _jsxs(Stack, {
141
+ spacing: 1.5,
142
+ children: [
143
+ failed ? /*#__PURE__*/ _jsx(Alert, {
144
+ severity: "warning",
145
+ children: 'The closed deals could not be read, so this is not an empty period.'
146
+ }) : null,
147
+ /*#__PURE__*/ _jsx(ReportBreakdown, {
148
+ rows: rows,
149
+ emptyText: read ? 'Nothing closed in this period.' : 'Reading…'
150
+ }),
151
+ wonWindow.truncated || lostWindow.truncated ? /*#__PURE__*/ _jsx(Typography, {
152
+ variant: "caption",
153
+ color: "text.secondary",
154
+ children: `Counted over the ${CLOSED_DEAL_CEILING} most recently closed of each outcome; this period held more.`
155
+ }) : null,
156
+ /*#__PURE__*/ _jsx(Typography, {
157
+ variant: "caption",
158
+ color: "text.secondary",
159
+ children: 'Credited to whoever owned the deal when it closed, not to whoever created it.'
160
+ })
161
+ ]
162
+ })
163
+ });
164
+ }
165
+ WonLostByOwnerCard.displayName = 'WonLostByOwnerCard';
166
+ export default WonLostByOwnerCard;
167
+
168
+ //# sourceMappingURL=won-lost-by-owner-card.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../../libs/plugins/crm/src/lib/components/reports/won-lost-by-owner-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 { percent } from '@aglyn/shared-ui-jsx/components/measured-figures.component'\nimport { Alert, Stack, Typography } from '@mui/material'\nimport { limit, orderBy, query, where } from 'firebase/firestore'\nimport { useMemo } from 'react'\nimport { useFirestore } from '@aglyn/tenant-feature-instance'\nimport { useOrgMemberOptions } from '../../hooks/use-org-member-options'\nimport { ReportBreakdown } from './report-breakdown'\nimport {\n type CrmReportScope,\n reportCacheKey,\n scopedCollection,\n visibleToClause,\n} from './report-scope'\nimport { useWindowRead } from './use-aggregate-read'\n\n/**\n * The same ceiling the Won and lost card reads its chart under, spelled\n * from one constant so the two cards share the read rather than each\n * paying for its own.\n */\nconst CLOSED_DEAL_CEILING = 500\n\n/** How many owners the breakdown draws before folding the rest into one row. */\nconst OWNER_ROW_CEILING = 8\n\ntype DealRow = Aglyn.CrmDeal & { $id: string }\n\nexport interface WonLostByOwnerCardProps {\n report: CrmReportScope\n}\n\n/**\n * Who closed what (AGL-2662): the period's wins and losses, by the person\n * who owned the deal at the close.\n *\n * ## It costs no read\n *\n * The two windows are the SAME queries the Won and lost card builds, under\n * the same cache keys — `closed:won` and `closed:lost` — so\n * `useAggregateRead` either answers this card from the remembered window or\n * joins the other card's in-flight promise. Two cards, one pair of reads.\n * A key of its own here would have doubled the most expensive read on the\n * page to ask a different question of the same rows.\n *\n * ## Why the rows can under-report a very busy period\n *\n * The window is bounded, and the bound is on the deals rather than on the\n * owners — so a period with more than {@link CLOSED_DEAL_CEILING} closes of\n * an outcome is tallied over the most recent of them, and the caption says\n * so. A server-side group-by would need one aggregate per owner, and the\n * owner list is not known before the read.\n */\nexport function WonLostByOwnerCard(props: WonLostByOwnerCardProps) {\n const { report } = props\n const { scope, tokens, range } = report\n const firestore = useFirestore()\n // The roster resolves a uid into the name the team reads; a uid it no\n // longer carries — somebody who has left — is named by its own id rather\n // than dropped, because their closed deals still happened.\n const roster = useOrgMemberOptions(scope[1])\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 orderBy('closedAtMs', 'desc'),\n limit(CLOSED_DEAL_CEILING + 1),\n )\n\n const wonWindow = useWindowRead<DealRow>(\n () => closedInPeriod('won'),\n CLOSED_DEAL_CEILING,\n [firestore, scope, tokens, range],\n { cacheKey: reportCacheKey(report, 'closed:won') },\n )\n const lostWindow = useWindowRead<DealRow>(\n () => closedInPeriod('lost'),\n CLOSED_DEAL_CEILING,\n [firestore, scope, tokens, range],\n { cacheKey: reportCacheKey(report, 'closed:lost') },\n )\n\n const owners = useMemo(\n () => Aglyn.wonLostByOwner(wonWindow.rows, lostWindow.rows),\n [wonWindow.rows, lostWindow.rows],\n )\n const currency = useMemo(\n () => Aglyn.currencyOfDeals(wonWindow.rows).currency,\n [wonWindow.rows],\n )\n\n const read = wonWindow.status === 'success' && lostWindow.status === 'success'\n const failed = wonWindow.status === 'error' || lostWindow.status === 'error'\n\n const rows = useMemo(() => {\n const named = (uid: string) =>\n uid\n ? (Aglyn.findOrgMember(roster.options, uid)?.label ?? uid)\n : 'Unassigned'\n const shown = owners.slice(0, OWNER_ROW_CEILING)\n const folded = owners.slice(OWNER_ROW_CEILING)\n const rest = folded.reduce(\n (total, owner) => ({\n won: total.won + owner.won,\n lost: total.lost + owner.lost,\n wonAmountCents: total.wonAmountCents + owner.wonAmountCents,\n }),\n { won: 0, lost: 0, wonAmountCents: 0 },\n )\n return [\n ...shown.map((owner) => ({\n key: owner.uid || 'unassigned',\n label: named(owner.uid),\n value: owner.won,\n display: `${owner.won.toLocaleString()} won`,\n note:\n `${owner.lost.toLocaleString()} lost · ` +\n `${owner.winRate === null ? 'no rate' : `${percent(owner.winRate)} win rate`} · ` +\n `${money(owner.wonAmountCents, currency)}`,\n color: 'success.main',\n })),\n ...(folded.length\n ? [\n {\n key: '$rest',\n label: `${folded.length} more`,\n value: rest.won,\n display: `${rest.won.toLocaleString()} won`,\n note: `${rest.lost.toLocaleString()} lost · ${money(rest.wonAmountCents, currency)}`,\n color: 'success.main',\n },\n ]\n : []),\n ]\n }, [owners, roster.options, currency])\n\n return (\n <CardDisplay\n header={'Won and lost by owner'}\n help={Aglyn.pluginDocsHelp('crmReports', {\n anchor: '#won-and-lost-by-owner',\n excerpt:\n 'Closed deals grouped by the person who owned them at the close, ' +\n 'ranked by how much closed rather than by win rate, with the deals ' +\n 'nobody owned kept as a row of their own.',\n })}\n contentGutterX\n contentGutterY\n >\n <Stack spacing={1.5}>\n {failed ? (\n <Alert severity=\"warning\">\n {'The closed deals could not be read, so this is not an empty period.'}\n </Alert>\n ) : null}\n <ReportBreakdown\n rows={rows}\n emptyText={read ? 'Nothing closed in this period.' : 'Reading…'}\n />\n {wonWindow.truncated || lostWindow.truncated ? (\n <Typography variant=\"caption\" color=\"text.secondary\">\n {`Counted over the ${CLOSED_DEAL_CEILING} most recently closed of each outcome; this period held more.`}\n </Typography>\n ) : null}\n <Typography variant=\"caption\" color=\"text.secondary\">\n {'Credited to whoever owned the deal when it closed, not to whoever created it.'}\n </Typography>\n </Stack>\n </CardDisplay>\n )\n}\nWonLostByOwnerCard.displayName = 'WonLostByOwnerCard'\n\nexport default WonLostByOwnerCard\n"],"names":["Aglyn","money","CardDisplay","percent","Alert","Stack","Typography","limit","orderBy","query","where","useMemo","useFirestore","useOrgMemberOptions","ReportBreakdown","reportCacheKey","scopedCollection","visibleToClause","useWindowRead","CLOSED_DEAL_CEILING","OWNER_ROW_CEILING","WonLostByOwnerCard","props","report","scope","tokens","range","firestore","roster","closedInPeriod","status","from","to","wonWindow","cacheKey","lostWindow","owners","wonLostByOwner","rows","currency","currencyOfDeals","read","failed","named","uid","findOrgMember","options","label","shown","slice","folded","rest","reduce","total","owner","won","lost","wonAmountCents","map","key","value","display","toLocaleString","note","winRate","color","length","header","help","pluginDocsHelp","anchor","excerpt","contentGutterX","contentGutterY","spacing","severity","emptyText","truncated","variant","displayName"],"mappings":"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"}
@@ -0,0 +1,42 @@
1
+ import type { ConsolePluginPageProps } from '@aglyn/aglyn';
2
+ /**
3
+ * `/crm/reports` — the CRM in aggregate (AGL-2604, AGL-2624).
4
+ *
5
+ * Nine cards, each reading its own collection: contacts over time, contacts
6
+ * by source and stage, which sources convert, this site's lead funnel, the
7
+ * open pipeline, what closed, who logged what, the forecast by close month
8
+ * (AGL-2620, over the pipeline card's own window), and the task load. This
9
+ * section resolves what they share and hands it down — see `CrmReportScope`
10
+ * — so that every card counts the same reader's records over the same
11
+ * clock. The lead funnel is the one card handed the site as well: leads live
12
+ * under the host, not the org.
13
+ *
14
+ * ## The period is a control, and the reads follow it
15
+ *
16
+ * Nothing on this page reads a year on mount. The picker names the period,
17
+ * the period sizes every read (one count per week of it, the deals closed
18
+ * within it), and the default is thirty days. The three cards that are
19
+ * stocks rather than flows — the open pipeline, its forecast, the open
20
+ * tasks — ignore the period because "what is open" has no period.
21
+ *
22
+ * ## Scoped like the list
23
+ *
24
+ * Every query carries `visibleTo array-contains-any` over the group's
25
+ * tokens, the predicate the rules evaluate, so a report can never count a
26
+ * record its reader could not open — and the total here is the reader's
27
+ * total, not the org's billable audience, which is the head-count the
28
+ * contacts list keeps for the quota.
29
+ *
30
+ * ## Read once a minute, not once an arrival
31
+ *
32
+ * Every read on this page is keyed by the scope and the period and kept
33
+ * for `AGGREGATE_READ_TTL_MS` — see `useAggregateRead` — so leaving to open
34
+ * a deal the report named and coming straight back costs nothing. Refresh
35
+ * forgets this reader's answers for this org and anchors the period again,
36
+ * which is what makes every card ask afresh.
37
+ */
38
+ export declare function ContactsReportsSection(props: ConsolePluginPageProps): import("react").JSX.Element;
39
+ export declare namespace ContactsReportsSection {
40
+ var displayName: string;
41
+ }
42
+ export default ContactsReportsSection;