@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,126 @@
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
+ */ import { contactDisplayName, CRM_COLLECTIONS } from "@aglyn/aglyn";
17
+ import { useFirestore } from "@aglyn/tenant-feature-instance";
18
+ import { doc, getDoc } from "firebase/firestore";
19
+ import { useCallback, useEffect, useState } from "react";
20
+ import { contactPrimaryGroup } from "../model/contact-record.js";
21
+ /** The collection each kind of record lives in, under `orgs/{orgId}/`. */ export const CRM_RECORD_COLLECTIONS = {
22
+ contact: 'contacts',
23
+ company: CRM_COLLECTIONS.companies,
24
+ deal: CRM_COLLECTIONS.deals
25
+ };
26
+ /**
27
+ * What a record is CALLED, from its document.
28
+ *
29
+ * A contact's name is read through the viewing group's facet, the way the
30
+ * people list reads it, so one business renaming a person does not change
31
+ * what an unrelated business's task list shows; the email stands in for a
32
+ * contact nobody has named. A company has a name and a deal a title.
33
+ */ export function crmRecordName(kind, data, groupId) {
34
+ if (!data) return '';
35
+ switch(kind){
36
+ case 'contact':
37
+ var _data_email;
38
+ return contactDisplayName(data, groupId) || String((_data_email = data['email']) != null ? _data_email : '');
39
+ case 'company':
40
+ var _data_name;
41
+ return String((_data_name = data['name']) != null ? _data_name : '');
42
+ case 'deal':
43
+ var _data_title;
44
+ return String((_data_title = data['title']) != null ? _data_title : '');
45
+ }
46
+ }
47
+ /**
48
+ * Names already read, keyed by `orgId/collection/id`, shared by every
49
+ * mount for the life of the page.
50
+ *
51
+ * A task list names the same handful of records over and over — five tasks
52
+ * about one deal are five rows and one name — and a person moves between the
53
+ * tasks section, a contact's page and the dashboard without the records
54
+ * changing underneath them. `null` records a document that does not exist,
55
+ * so a task pointing at a deleted record costs one read rather than one per
56
+ * render. A rename is picked up on the next page load, which is the right
57
+ * staleness for a label beside a link to the record itself.
58
+ */ const nameCache = new Map();
59
+ const pending = new Map();
60
+ const cacheKey = (orgId, kind, id)=>`${orgId}/${CRM_RECORD_COLLECTIONS[kind]}/${id}`;
61
+ /** Test seam: forget everything, so a spec's fixtures are what get read. */ export function resetCrmRecordNameCache() {
62
+ nameCache.clear();
63
+ pending.clear();
64
+ }
65
+ /**
66
+ * The names of the records a list of tasks points at, resolved once each.
67
+ *
68
+ * Returns a lookup rather than a map so the caller does not have to know the
69
+ * cache's key shape. An unresolved record answers `undefined` — the cell
70
+ * renders the link with the id until the name lands, which is one render
71
+ * later on a warm cache and one round trip on a cold one.
72
+ */ export function useCrmRecordNames(options) {
73
+ const { orgId, groupId, org, records } = options;
74
+ const firestore = useFirestore();
75
+ // A counter rather than a copy of the cache: the cache is the source of
76
+ // truth and this only exists to re-render when it grows.
77
+ const [, setResolved] = useState(0);
78
+ // The pairs as one string, so the effect runs when the SET changes and not
79
+ // when the caller builds a new array of the same pairs on every render.
80
+ const wanted = records.map((record)=>`${record.kind}:${record.id}`).filter((entry, index, all)=>all.indexOf(entry) === index).sort().join('\n');
81
+ useEffect(()=>{
82
+ if (!orgId || !wanted) return;
83
+ let active = true;
84
+ const reads = [];
85
+ for (const entry of wanted.split('\n')){
86
+ const [kind, id] = entry.split(':');
87
+ const key = cacheKey(orgId, kind, id);
88
+ if (nameCache.has(key)) continue;
89
+ let read = pending.get(key);
90
+ if (!read) {
91
+ read = getDoc(doc(firestore, 'orgs', orgId, CRM_RECORD_COLLECTIONS[kind], id)).then((snapshot)=>{
92
+ const data = snapshot.exists() ? snapshot.data() : undefined;
93
+ nameCache.set(key, data ? crmRecordName(kind, data, groupId != null ? groupId : contactPrimaryGroup(data, org).groupId) : null);
94
+ }).catch(()=>{
95
+ // A refused or failed read is not cached: the cell keeps showing
96
+ // the id, and the next mount tries again.
97
+ }).finally(()=>{
98
+ pending.delete(key);
99
+ });
100
+ pending.set(key, read);
101
+ }
102
+ reads.push(read);
103
+ }
104
+ if (!reads.length) return;
105
+ void Promise.all(reads).then(()=>{
106
+ if (active) setResolved((count)=>count + 1);
107
+ });
108
+ return ()=>{
109
+ active = false;
110
+ };
111
+ }, [
112
+ firestore,
113
+ orgId,
114
+ groupId,
115
+ wanted
116
+ ]);
117
+ return useCallback((kind, id)=>{
118
+ if (!orgId) return undefined;
119
+ const hit = nameCache.get(cacheKey(orgId, kind, id));
120
+ return hit === null ? undefined : hit;
121
+ }, [
122
+ orgId
123
+ ]);
124
+ }
125
+
126
+ //# sourceMappingURL=use-crm-record-names.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/crm/src/lib/hooks/use-crm-record-names.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\nimport { contactDisplayName, CRM_COLLECTIONS } from '@aglyn/aglyn'\nimport { useFirestore } from '@aglyn/tenant-feature-instance'\nimport { doc, getDoc } from 'firebase/firestore'\nimport { useCallback, useEffect, useState } from 'react'\nimport { contactPrimaryGroup } from '../model/contact-record'\n\nexport type CrmRecordKind = 'contact' | 'company' | 'deal'\n\n/** The collection each kind of record lives in, under `orgs/{orgId}/`. */\nexport const CRM_RECORD_COLLECTIONS: Record<CrmRecordKind, string> = {\n contact: 'contacts',\n company: CRM_COLLECTIONS.companies,\n deal: CRM_COLLECTIONS.deals,\n}\n\n/**\n * What a record is CALLED, from its document.\n *\n * A contact's name is read through the viewing group's facet, the way the\n * people list reads it, so one business renaming a person does not change\n * what an unrelated business's task list shows; the email stands in for a\n * contact nobody has named. A company has a name and a deal a title.\n */\nexport function crmRecordName(\n kind: CrmRecordKind,\n data: Record<string, unknown> | undefined,\n groupId: string,\n): string {\n if (!data) return ''\n switch (kind) {\n case 'contact':\n return contactDisplayName(data, groupId) || String(data['email'] ?? '')\n case 'company':\n return String(data['name'] ?? '')\n case 'deal':\n return String(data['title'] ?? '')\n }\n}\n\n/**\n * Names already read, keyed by `orgId/collection/id`, shared by every\n * mount for the life of the page.\n *\n * A task list names the same handful of records over and over — five tasks\n * about one deal are five rows and one name — and a person moves between the\n * tasks section, a contact's page and the dashboard without the records\n * changing underneath them. `null` records a document that does not exist,\n * so a task pointing at a deleted record costs one read rather than one per\n * render. A rename is picked up on the next page load, which is the right\n * staleness for a label beside a link to the record itself.\n */\nconst nameCache = new Map<string, string | null>()\nconst pending = new Map<string, Promise<void>>()\n\nconst cacheKey = (orgId: string, kind: CrmRecordKind, id: string) =>\n `${orgId}/${CRM_RECORD_COLLECTIONS[kind]}/${id}`\n\n/** Test seam: forget everything, so a spec's fixtures are what get read. */\nexport function resetCrmRecordNameCache(): void {\n nameCache.clear()\n pending.clear()\n}\n\n/**\n * The names of the records a list of tasks points at, resolved once each.\n *\n * Returns a lookup rather than a map so the caller does not have to know the\n * cache's key shape. An unresolved record answers `undefined` — the cell\n * renders the link with the id until the name lands, which is one render\n * later on a warm cache and one round trip on a cold one.\n */\nexport function useCrmRecordNames(options: {\n orgId: string | null | undefined\n /**\n * The viewing group a contact is named through, or `null` at the\n * organization level (AGL-2630), where each contact is named through its\n * own primary holder, resolved from {@link org}.\n */\n groupId: string | null\n org?: Record<string, unknown> | null\n records: ReadonlyArray<{ kind: CrmRecordKind; id: string }>\n}): (kind: CrmRecordKind, id: string) => string | undefined {\n const { orgId, groupId, org, records } = options\n const firestore = useFirestore()\n // A counter rather than a copy of the cache: the cache is the source of\n // truth and this only exists to re-render when it grows.\n const [, setResolved] = useState(0)\n\n // The pairs as one string, so the effect runs when the SET changes and not\n // when the caller builds a new array of the same pairs on every render.\n const wanted = records\n .map((record) => `${record.kind}:${record.id}`)\n .filter((entry, index, all) => all.indexOf(entry) === index)\n .sort()\n .join('\\n')\n\n useEffect(() => {\n if (!orgId || !wanted) return\n let active = true\n const reads: Promise<void>[] = []\n for (const entry of wanted.split('\\n')) {\n const [kind, id] = entry.split(':') as [CrmRecordKind, string]\n const key = cacheKey(orgId, kind, id)\n if (nameCache.has(key)) continue\n let read = pending.get(key)\n if (!read) {\n read = getDoc(\n doc(firestore, 'orgs', orgId, CRM_RECORD_COLLECTIONS[kind], id),\n )\n .then((snapshot) => {\n const data = snapshot.exists()\n ? (snapshot.data() as Record<string, unknown>)\n : undefined\n nameCache.set(\n key,\n data\n ? crmRecordName(\n kind,\n data,\n groupId ?? contactPrimaryGroup(data, org).groupId,\n )\n : null,\n )\n })\n .catch(() => {\n // A refused or failed read is not cached: the cell keeps showing\n // the id, and the next mount tries again.\n })\n .finally(() => {\n pending.delete(key)\n })\n pending.set(key, read)\n }\n reads.push(read)\n }\n if (!reads.length) return\n void Promise.all(reads).then(() => {\n if (active) setResolved((count) => count + 1)\n })\n return () => {\n active = false\n }\n }, [firestore, orgId, groupId, wanted])\n\n return useCallback(\n (kind: CrmRecordKind, id: string) => {\n if (!orgId) return undefined\n const hit = nameCache.get(cacheKey(orgId, kind, id))\n return hit === null ? undefined : hit\n },\n [orgId],\n )\n}\n"],"names":["contactDisplayName","CRM_COLLECTIONS","useFirestore","doc","getDoc","useCallback","useEffect","useState","contactPrimaryGroup","CRM_RECORD_COLLECTIONS","contact","company","companies","deal","deals","crmRecordName","kind","data","groupId","String","nameCache","Map","pending","cacheKey","orgId","id","resetCrmRecordNameCache","clear","useCrmRecordNames","options","org","records","firestore","setResolved","wanted","map","record","filter","entry","index","all","indexOf","sort","join","active","reads","split","key","has","read","get","then","snapshot","exists","undefined","set","catch","finally","delete","push","length","Promise","count","hit"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAED,SAASA,kBAAkB,EAAEC,eAAe,QAAQ,eAAc;AAClE,SAASC,YAAY,QAAQ,iCAAgC;AAC7D,SAASC,GAAG,EAAEC,MAAM,QAAQ,qBAAoB;AAChD,SAASC,WAAW,EAAEC,SAAS,EAAEC,QAAQ,QAAQ,QAAO;AACxD,SAASC,mBAAmB,QAAQ,6BAAyB;AAI7D,wEAAwE,GACxE,OAAO,MAAMC,yBAAwD;IACnEC,SAAS;IACTC,SAASV,gBAAgBW,SAAS;IAClCC,MAAMZ,gBAAgBa,KAAK;AAC7B,EAAC;AAED;;;;;;;CAOC,GACD,OAAO,SAASC,cACdC,IAAmB,EACnBC,IAAyC,EACzCC,OAAe;IAEf,IAAI,CAACD,MAAM,OAAO;IAClB,OAAQD;QACN,KAAK;gBACgDC;YAAnD,OAAOjB,mBAAmBiB,MAAMC,YAAYC,QAAOF,cAAAA,IAAI,CAAC,QAAQ,YAAbA,cAAiB;QACtE,KAAK;gBACWA;YAAd,OAAOE,QAAOF,aAAAA,IAAI,CAAC,OAAO,YAAZA,aAAgB;QAChC,KAAK;gBACWA;YAAd,OAAOE,QAAOF,cAAAA,IAAI,CAAC,QAAQ,YAAbA,cAAiB;IACnC;AACF;AAEA;;;;;;;;;;;CAWC,GACD,MAAMG,YAAY,IAAIC;AACtB,MAAMC,UAAU,IAAID;AAEpB,MAAME,WAAW,CAACC,OAAeR,MAAqBS,KACpD,GAAGD,MAAM,CAAC,EAAEf,sBAAsB,CAACO,KAAK,CAAC,CAAC,EAAES,IAAI;AAElD,0EAA0E,GAC1E,OAAO,SAASC;IACdN,UAAUO,KAAK;IACfL,QAAQK,KAAK;AACf;AAEA;;;;;;;CAOC,GACD,OAAO,SAASC,kBAAkBC,OAUjC;IACC,MAAM,EAAEL,KAAK,EAAEN,OAAO,EAAEY,GAAG,EAAEC,OAAO,EAAE,GAAGF;IACzC,MAAMG,YAAY9B;IAClB,wEAAwE;IACxE,yDAAyD;IACzD,MAAM,GAAG+B,YAAY,GAAG1B,SAAS;IAEjC,2EAA2E;IAC3E,wEAAwE;IACxE,MAAM2B,SAASH,QACZI,GAAG,CAAC,CAACC,SAAW,GAAGA,OAAOpB,IAAI,CAAC,CAAC,EAAEoB,OAAOX,EAAE,EAAE,EAC7CY,MAAM,CAAC,CAACC,OAAOC,OAAOC,MAAQA,IAAIC,OAAO,CAACH,WAAWC,OACrDG,IAAI,GACJC,IAAI,CAAC;IAERrC,UAAU;QACR,IAAI,CAACkB,SAAS,CAACU,QAAQ;QACvB,IAAIU,SAAS;QACb,MAAMC,QAAyB,EAAE;QACjC,KAAK,MAAMP,SAASJ,OAAOY,KAAK,CAAC,MAAO;YACtC,MAAM,CAAC9B,MAAMS,GAAG,GAAGa,MAAMQ,KAAK,CAAC;YAC/B,MAAMC,MAAMxB,SAASC,OAAOR,MAAMS;YAClC,IAAIL,UAAU4B,GAAG,CAACD,MAAM;YACxB,IAAIE,OAAO3B,QAAQ4B,GAAG,CAACH;YACvB,IAAI,CAACE,MAAM;gBACTA,OAAO7C,OACLD,IAAI6B,WAAW,QAAQR,OAAOf,sBAAsB,CAACO,KAAK,EAAES,KAE3D0B,IAAI,CAAC,CAACC;oBACL,MAAMnC,OAAOmC,SAASC,MAAM,KACvBD,SAASnC,IAAI,KACdqC;oBACJlC,UAAUmC,GAAG,CACXR,KACA9B,OACIF,cACEC,MACAC,MACAC,kBAAAA,UAAWV,oBAAoBS,MAAMa,KAAKZ,OAAO,IAEnD;gBAER,GACCsC,KAAK,CAAC;gBACL,iEAAiE;gBACjE,0CAA0C;gBAC5C,GACCC,OAAO,CAAC;oBACPnC,QAAQoC,MAAM,CAACX;gBACjB;gBACFzB,QAAQiC,GAAG,CAACR,KAAKE;YACnB;YACAJ,MAAMc,IAAI,CAACV;QACb;QACA,IAAI,CAACJ,MAAMe,MAAM,EAAE;QACnB,KAAKC,QAAQrB,GAAG,CAACK,OAAOM,IAAI,CAAC;YAC3B,IAAIP,QAAQX,YAAY,CAAC6B,QAAUA,QAAQ;QAC7C;QACA,OAAO;YACLlB,SAAS;QACX;IACF,GAAG;QAACZ;QAAWR;QAAON;QAASgB;KAAO;IAEtC,OAAO7B,YACL,CAACW,MAAqBS;QACpB,IAAI,CAACD,OAAO,OAAO8B;QACnB,MAAMS,MAAM3C,UAAU8B,GAAG,CAAC3B,SAASC,OAAOR,MAAMS;QAChD,OAAOsC,QAAQ,OAAOT,YAAYS;IACpC,GACA;QAACvC;KAAM;AAEX"}
@@ -0,0 +1,68 @@
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
+ */
17
+ import { type AglynOrgBilling, type CrmRecordsQuotaResult } from '@aglyn/aglyn';
18
+ import { type Firestore } from 'firebase/firestore';
19
+ /**
20
+ * The band's verdict, measured ONCE and now — for a write that happens on
21
+ * a click rather than inside a drawer that stays open (AGL-2644).
22
+ *
23
+ * The company picker's "Create …" row lives on every contact page and in
24
+ * the bulk bar, mounted long before anyone types a new name, so a hook that
25
+ * read the three aggregates on mount would charge every page view for a
26
+ * create that mostly never comes. This is the same three reads and the same
27
+ * fallback as {@link useCrmRecordsQuota}, taken at the moment they decide
28
+ * something. A read that failed counts as nothing, which is the permissive
29
+ * direction: an org is refused only by a hard band that was measured full.
30
+ */
31
+ export declare function readCrmRecordsQuota(firestore: Firestore, scope: readonly ['orgs', string], org: Partial<AglynOrgBilling> | null | undefined): Promise<CrmRecordsQuotaResult>;
32
+ export interface CrmRecordsQuotaState {
33
+ /** The contacts aggregate, or `null` while pending or denied. */
34
+ contactsCount: number | null;
35
+ companiesCount: number | null;
36
+ dealsCount: number | null;
37
+ /**
38
+ * The three summed, with an unanswered one counted as its fallback — a
39
+ * LOWER bound until `ready`, never an overstatement, so no alert this
40
+ * number gates can fire on a count larger than the truth.
41
+ */
42
+ crmRecordsCount: number;
43
+ /** The band's verdict on `crmRecordsCount`. */
44
+ quota: CrmRecordsQuotaResult;
45
+ /** All three aggregates have answered. */
46
+ ready: boolean;
47
+ }
48
+ /**
49
+ * The CRM records band as the browser can measure it (AGL-2611): one
50
+ * server-side aggregate per counted collection, read once per mount, summed,
51
+ * and handed to `checkCrmRecordsQuota` — the client twin of the server's
52
+ * `countCrmRecords`, for the surfaces that write client-direct.
53
+ *
54
+ * The contacts list has always read its head-count this way (AGL-1706): the
55
+ * listener is `limit(1000)` and must never answer "how many". What the band
56
+ * widening adds is the two collections beside it, so the list's alert and
57
+ * the company and deal drawers refuse on the same number the rollup bills.
58
+ *
59
+ * `scope` may be `null` to read nothing — a drawer that is closed, or a
60
+ * drawer editing an existing record, has no create to gate and pays for no
61
+ * aggregate. A denied read stays `null` and falls back: the alert on a full
62
+ * hard band must not be cleared by a count that could not be taken, and a
63
+ * defaulted 0 would do exactly that.
64
+ */
65
+ export declare function useCrmRecordsQuota(scope: readonly ['orgs', string] | null | undefined, org: Partial<AglynOrgBilling> | null | undefined, options?: {
66
+ contactsFallback?: number | null;
67
+ }): CrmRecordsQuotaState;
68
+ export default useCrmRecordsQuota;
@@ -0,0 +1,118 @@
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 { checkCrmRecordsQuota, CRM_RECORD_COLLECTIONS } from "@aglyn/aglyn";
19
+ import { useFirestore } from "@aglyn/tenant-feature-instance";
20
+ import { collection, getCountFromServer } from "firebase/firestore";
21
+ import { useEffect, useMemo, useState } from "react";
22
+ /**
23
+ * One aggregate for one counted collection, or `null` when the read was
24
+ * denied or unavailable — the fallback rule every reader of the band
25
+ * shares, so a count that could not be taken stands in as nothing rather
26
+ * than as a zero that clears an alert.
27
+ */ async function countCrmCollection(firestore, scope, name) {
28
+ try {
29
+ const snapshot = await getCountFromServer(collection(firestore, scope[0], scope[1], name));
30
+ return snapshot.data().count;
31
+ } catch (unused) {
32
+ return null;
33
+ }
34
+ }
35
+ /**
36
+ * The band's verdict, measured ONCE and now — for a write that happens on
37
+ * a click rather than inside a drawer that stays open (AGL-2644).
38
+ *
39
+ * The company picker's "Create …" row lives on every contact page and in
40
+ * the bulk bar, mounted long before anyone types a new name, so a hook that
41
+ * read the three aggregates on mount would charge every page view for a
42
+ * create that mostly never comes. This is the same three reads and the same
43
+ * fallback as {@link useCrmRecordsQuota}, taken at the moment they decide
44
+ * something. A read that failed counts as nothing, which is the permissive
45
+ * direction: an org is refused only by a hard band that was measured full.
46
+ */ export async function readCrmRecordsQuota(firestore, scope, org) {
47
+ const counts = await Promise.all(CRM_RECORD_COLLECTIONS.map((name)=>countCrmCollection(firestore, scope, name)));
48
+ const crmRecordsCount = counts.reduce((sum, count)=>sum + (count != null ? count : 0), 0);
49
+ return checkCrmRecordsQuota(org, crmRecordsCount);
50
+ }
51
+ /**
52
+ * The CRM records band as the browser can measure it (AGL-2611): one
53
+ * server-side aggregate per counted collection, read once per mount, summed,
54
+ * and handed to `checkCrmRecordsQuota` — the client twin of the server's
55
+ * `countCrmRecords`, for the surfaces that write client-direct.
56
+ *
57
+ * The contacts list has always read its head-count this way (AGL-1706): the
58
+ * listener is `limit(1000)` and must never answer "how many". What the band
59
+ * widening adds is the two collections beside it, so the list's alert and
60
+ * the company and deal drawers refuse on the same number the rollup bills.
61
+ *
62
+ * `scope` may be `null` to read nothing — a drawer that is closed, or a
63
+ * drawer editing an existing record, has no create to gate and pays for no
64
+ * aggregate. A denied read stays `null` and falls back: the alert on a full
65
+ * hard band must not be cleared by a count that could not be taken, and a
66
+ * defaulted 0 would do exactly that.
67
+ */ export function useCrmRecordsQuota(scope, org, options = {}) {
68
+ const firestore = useFirestore();
69
+ const { contactsFallback = null } = options;
70
+ const [counts, setCounts] = useState({});
71
+ /*
72
+ * Every state write below is IDENTITY-PRESERVING when nothing changed —
73
+ * the same answer to the same read hands back the same object — so the
74
+ * effect reaches a steady state even under a caller whose `scope` tuple
75
+ * is not referentially stable. A reset that minted a fresh `{}` per run
76
+ * would re-render, re-fire on the fresh tuple, reset again, and never
77
+ * settle: a read per render at best, a hung surface at worst.
78
+ */ useEffect(()=>{
79
+ if (!scope) return;
80
+ let active = true;
81
+ const record = (name, value)=>setCounts((current)=>name in current && current[name] === value ? current : _extends({}, current, {
82
+ [name]: value
83
+ }));
84
+ for (const name of CRM_RECORD_COLLECTIONS){
85
+ void countCrmCollection(firestore, scope, name).then((count)=>{
86
+ if (active) record(name, count);
87
+ });
88
+ }
89
+ return ()=>{
90
+ active = false;
91
+ };
92
+ }, [
93
+ firestore,
94
+ scope
95
+ ]);
96
+ return useMemo(()=>{
97
+ var _counts_contacts, _counts_companies, _counts_deals, _ref;
98
+ const contactsCount = (_counts_contacts = counts['contacts']) != null ? _counts_contacts : null;
99
+ const companiesCount = (_counts_companies = counts['companies']) != null ? _counts_companies : null;
100
+ const dealsCount = (_counts_deals = counts['deals']) != null ? _counts_deals : null;
101
+ const crmRecordsCount = ((_ref = contactsCount != null ? contactsCount : contactsFallback) != null ? _ref : 0) + (companiesCount != null ? companiesCount : 0) + (dealsCount != null ? dealsCount : 0);
102
+ return {
103
+ contactsCount,
104
+ companiesCount,
105
+ dealsCount,
106
+ crmRecordsCount,
107
+ quota: checkCrmRecordsQuota(org, crmRecordsCount),
108
+ ready: CRM_RECORD_COLLECTIONS.every((name)=>name in counts)
109
+ };
110
+ }, [
111
+ counts,
112
+ contactsFallback,
113
+ org
114
+ ]);
115
+ }
116
+ export default useCrmRecordsQuota;
117
+
118
+ //# sourceMappingURL=use-crm-records-quota.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/crm/src/lib/hooks/use-crm-records-quota.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\n'use client'\n\nimport {\n type AglynOrgBilling,\n checkCrmRecordsQuota,\n CRM_RECORD_COLLECTIONS,\n type CrmRecordsQuotaResult,\n} from '@aglyn/aglyn'\nimport { useFirestore } from '@aglyn/tenant-feature-instance'\nimport { collection, type Firestore, getCountFromServer } from 'firebase/firestore'\nimport { useEffect, useMemo, useState } from 'react'\n\n/**\n * One aggregate for one counted collection, or `null` when the read was\n * denied or unavailable — the fallback rule every reader of the band\n * shares, so a count that could not be taken stands in as nothing rather\n * than as a zero that clears an alert.\n */\nasync function countCrmCollection(\n firestore: Firestore,\n scope: readonly ['orgs', string],\n name: string,\n): Promise<number | null> {\n try {\n const snapshot = await getCountFromServer(\n collection(firestore, scope[0], scope[1], name),\n )\n return snapshot.data().count\n } catch {\n return null\n }\n}\n\n/**\n * The band's verdict, measured ONCE and now — for a write that happens on\n * a click rather than inside a drawer that stays open (AGL-2644).\n *\n * The company picker's \"Create …\" row lives on every contact page and in\n * the bulk bar, mounted long before anyone types a new name, so a hook that\n * read the three aggregates on mount would charge every page view for a\n * create that mostly never comes. This is the same three reads and the same\n * fallback as {@link useCrmRecordsQuota}, taken at the moment they decide\n * something. A read that failed counts as nothing, which is the permissive\n * direction: an org is refused only by a hard band that was measured full.\n */\nexport async function readCrmRecordsQuota(\n firestore: Firestore,\n scope: readonly ['orgs', string],\n org: Partial<AglynOrgBilling> | null | undefined,\n): Promise<CrmRecordsQuotaResult> {\n const counts = await Promise.all(\n CRM_RECORD_COLLECTIONS.map((name) => countCrmCollection(firestore, scope, name)),\n )\n const crmRecordsCount = counts.reduce<number>((sum, count) => sum + (count ?? 0), 0)\n return checkCrmRecordsQuota(org, crmRecordsCount)\n}\n\nexport interface CrmRecordsQuotaState {\n /** The contacts aggregate, or `null` while pending or denied. */\n contactsCount: number | null\n companiesCount: number | null\n dealsCount: number | null\n /**\n * The three summed, with an unanswered one counted as its fallback — a\n * LOWER bound until `ready`, never an overstatement, so no alert this\n * number gates can fire on a count larger than the truth.\n */\n crmRecordsCount: number\n /** The band's verdict on `crmRecordsCount`. */\n quota: CrmRecordsQuotaResult\n /** All three aggregates have answered. */\n ready: boolean\n}\n\n/**\n * The CRM records band as the browser can measure it (AGL-2611): one\n * server-side aggregate per counted collection, read once per mount, summed,\n * and handed to `checkCrmRecordsQuota` — the client twin of the server's\n * `countCrmRecords`, for the surfaces that write client-direct.\n *\n * The contacts list has always read its head-count this way (AGL-1706): the\n * listener is `limit(1000)` and must never answer \"how many\". What the band\n * widening adds is the two collections beside it, so the list's alert and\n * the company and deal drawers refuse on the same number the rollup bills.\n *\n * `scope` may be `null` to read nothing — a drawer that is closed, or a\n * drawer editing an existing record, has no create to gate and pays for no\n * aggregate. A denied read stays `null` and falls back: the alert on a full\n * hard band must not be cleared by a count that could not be taken, and a\n * defaulted 0 would do exactly that.\n */\nexport function useCrmRecordsQuota(\n scope: readonly ['orgs', string] | null | undefined,\n org: Partial<AglynOrgBilling> | null | undefined,\n options: { contactsFallback?: number | null } = {},\n): CrmRecordsQuotaState {\n const firestore = useFirestore()\n const { contactsFallback = null } = options\n const [counts, setCounts] = useState<Record<string, number | null>>({})\n\n /*\n * Every state write below is IDENTITY-PRESERVING when nothing changed —\n * the same answer to the same read hands back the same object — so the\n * effect reaches a steady state even under a caller whose `scope` tuple\n * is not referentially stable. A reset that minted a fresh `{}` per run\n * would re-render, re-fire on the fresh tuple, reset again, and never\n * settle: a read per render at best, a hung surface at worst.\n */\n useEffect(() => {\n if (!scope) return\n let active = true\n const record = (name: string, value: number | null) =>\n setCounts((current) =>\n name in current && current[name] === value\n ? current\n : { ...current, [name]: value },\n )\n for (const name of CRM_RECORD_COLLECTIONS) {\n void countCrmCollection(firestore, scope, name).then((count) => {\n if (active) record(name, count)\n })\n }\n return () => {\n active = false\n }\n }, [firestore, scope])\n\n return useMemo(() => {\n const contactsCount = counts['contacts'] ?? null\n const companiesCount = counts['companies'] ?? null\n const dealsCount = counts['deals'] ?? null\n const crmRecordsCount =\n (contactsCount ?? contactsFallback ?? 0) +\n (companiesCount ?? 0) +\n (dealsCount ?? 0)\n return {\n contactsCount,\n companiesCount,\n dealsCount,\n crmRecordsCount,\n quota: checkCrmRecordsQuota(org, crmRecordsCount),\n ready: CRM_RECORD_COLLECTIONS.every((name) => name in counts),\n }\n }, [counts, contactsFallback, org])\n}\n\nexport default useCrmRecordsQuota\n"],"names":["checkCrmRecordsQuota","CRM_RECORD_COLLECTIONS","useFirestore","collection","getCountFromServer","useEffect","useMemo","useState","countCrmCollection","firestore","scope","name","snapshot","data","count","readCrmRecordsQuota","org","counts","Promise","all","map","crmRecordsCount","reduce","sum","useCrmRecordsQuota","options","contactsFallback","setCounts","active","record","value","current","then","contactsCount","companiesCount","dealsCount","quota","ready","every"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAED;;AAEA,SAEEA,oBAAoB,EACpBC,sBAAsB,QAEjB,eAAc;AACrB,SAASC,YAAY,QAAQ,iCAAgC;AAC7D,SAASC,UAAU,EAAkBC,kBAAkB,QAAQ,qBAAoB;AACnF,SAASC,SAAS,EAAEC,OAAO,EAAEC,QAAQ,QAAQ,QAAO;AAEpD;;;;;CAKC,GACD,eAAeC,mBACbC,SAAoB,EACpBC,KAAgC,EAChCC,IAAY;IAEZ,IAAI;QACF,MAAMC,WAAW,MAAMR,mBACrBD,WAAWM,WAAWC,KAAK,CAAC,EAAE,EAAEA,KAAK,CAAC,EAAE,EAAEC;QAE5C,OAAOC,SAASC,IAAI,GAAGC,KAAK;IAC9B,EAAE,eAAM;QACN,OAAO;IACT;AACF;AAEA;;;;;;;;;;;CAWC,GACD,OAAO,eAAeC,oBACpBN,SAAoB,EACpBC,KAAgC,EAChCM,GAAgD;IAEhD,MAAMC,SAAS,MAAMC,QAAQC,GAAG,CAC9BlB,uBAAuBmB,GAAG,CAAC,CAACT,OAASH,mBAAmBC,WAAWC,OAAOC;IAE5E,MAAMU,kBAAkBJ,OAAOK,MAAM,CAAS,CAACC,KAAKT,QAAUS,OAAOT,gBAAAA,QAAS,IAAI;IAClF,OAAOd,qBAAqBgB,KAAKK;AACnC;AAmBA;;;;;;;;;;;;;;;;CAgBC,GACD,OAAO,SAASG,mBACdd,KAAmD,EACnDM,GAAgD,EAChDS,UAAgD,CAAC,CAAC;IAElD,MAAMhB,YAAYP;IAClB,MAAM,EAAEwB,mBAAmB,IAAI,EAAE,GAAGD;IACpC,MAAM,CAACR,QAAQU,UAAU,GAAGpB,SAAwC,CAAC;IAErE;;;;;;;GAOC,GACDF,UAAU;QACR,IAAI,CAACK,OAAO;QACZ,IAAIkB,SAAS;QACb,MAAMC,SAAS,CAAClB,MAAcmB,QAC5BH,UAAU,CAACI,UACTpB,QAAQoB,WAAWA,OAAO,CAACpB,KAAK,KAAKmB,QACjCC,UACA,aAAKA;oBAAS,CAACpB,KAAK,EAAEmB;;QAE9B,KAAK,MAAMnB,QAAQV,uBAAwB;YACzC,KAAKO,mBAAmBC,WAAWC,OAAOC,MAAMqB,IAAI,CAAC,CAAClB;gBACpD,IAAIc,QAAQC,OAAOlB,MAAMG;YAC3B;QACF;QACA,OAAO;YACLc,SAAS;QACX;IACF,GAAG;QAACnB;QAAWC;KAAM;IAErB,OAAOJ,QAAQ;YACSW,kBACCA,mBACJA,eAEhBgB;QAJH,MAAMA,iBAAgBhB,mBAAAA,MAAM,CAAC,WAAW,YAAlBA,mBAAsB;QAC5C,MAAMiB,kBAAiBjB,oBAAAA,MAAM,CAAC,YAAY,YAAnBA,oBAAuB;QAC9C,MAAMkB,cAAalB,gBAAAA,MAAM,CAAC,QAAQ,YAAfA,gBAAmB;QACtC,MAAMI,kBACJ,EAACY,OAAAA,wBAAAA,gBAAiBP,4BAAjBO,OAAqC,MACrCC,yBAAAA,iBAAkB,MAClBC,qBAAAA,aAAc;QACjB,OAAO;YACLF;YACAC;YACAC;YACAd;YACAe,OAAOpC,qBAAqBgB,KAAKK;YACjCgB,OAAOpC,uBAAuBqC,KAAK,CAAC,CAAC3B,OAASA,QAAQM;QACxD;IACF,GAAG;QAACA;QAAQS;QAAkBV;KAAI;AACpC;AAEA,eAAeQ,mBAAkB"}
@@ -0,0 +1,96 @@
1
+ import { type CrmViewFilterClause, type CrmViewSection, type CrmViewSort, type CrmViewState } from '@aglyn/aglyn';
2
+ import { type CrmOrgDoc } from './use-crm-scope';
3
+ import { type CrmSavedViewRow } from './use-crm-views';
4
+ /**
5
+ * The address value that means "no view, whatever my default is".
6
+ *
7
+ * Without it, choosing the plain list would clear the key and the default
8
+ * would reapply on the next render — the reader could never leave their
9
+ * own default. Written only when a default exists to be overridden, so an
10
+ * address stays clean for a reader who never set one.
11
+ */
12
+ export declare const CRM_VIEW_NONE = "all";
13
+ /** What a section holds of its saved views, and can do with them. */
14
+ export interface CrmSavedViewController {
15
+ section: CrmViewSection;
16
+ /** Mine and shared, by name. */
17
+ views: CrmSavedViewRow[];
18
+ /** Whether the listing has settled — a missing view is not missing until it has. */
19
+ ready: boolean;
20
+ /** The view the list is showing, when the address or the default names a listed one. */
21
+ current: CrmSavedViewRow | null;
22
+ /** The id the address names, listed or not. */
23
+ currentId: string | null;
24
+ /** The address names a view the listing does not carry. */
25
+ missing: boolean;
26
+ /** The list's working state: what the reader has narrowed, shown and sorted. */
27
+ state: CrmViewState;
28
+ setFilters: (filters: CrmViewFilterClause[]) => void;
29
+ setColumns: (columns: string[]) => void;
30
+ setSort: (sort: CrmViewSort | null) => void;
31
+ /** The working state differs from the view it started from. */
32
+ dirty: boolean;
33
+ /** The reader may change or remove the current view — its creator, or an org-wide member. */
34
+ canEdit: boolean;
35
+ uid: string | null;
36
+ /** Open a view by id, or the plain list with `null`. */
37
+ select: (viewId: string | null) => void;
38
+ /** Back to the view's saved state, or the plain list's. */
39
+ reset: () => void;
40
+ save: () => Promise<void>;
41
+ /** Creates, opens, and answers with the new id. */
42
+ saveAs: (name: string, shared: boolean) => Promise<string | null>;
43
+ rename: (name: string) => Promise<void>;
44
+ setShared: (shared: boolean) => Promise<void>;
45
+ remove: () => Promise<void>;
46
+ defaultViewId: string | null;
47
+ isDefault: boolean;
48
+ setDefault: (viewId: string | null) => Promise<void>;
49
+ /** A write is in flight. */
50
+ busy: boolean;
51
+ }
52
+ /**
53
+ * One section's saved views, resolved against its address (AGL-2617).
54
+ *
55
+ * The controller behind the views control on every CRM list. It owns three
56
+ * things the list used to keep in loose state and lose on reload: which
57
+ * view is open, what the reader has changed since, and how that gets back
58
+ * to the document.
59
+ *
60
+ * ## The address is the truth about which view is open
61
+ *
62
+ * `?view=<id>` names the view; choosing one navigates. So a view is a link,
63
+ * Back returns to the one before it, and a reload lands where the reader
64
+ * was. When the address names nothing, the reader's default for this
65
+ * section (their own profile's) opens instead — unless the list was opened
66
+ * FOR something, a form's captures or one address, in which case the plain
67
+ * list shows what it was asked for and nothing narrows it further.
68
+ *
69
+ * ## The seed is kept, first
70
+ *
71
+ * A Contacts address that carries a seed and a view means both: the seed's
72
+ * clause leads the view's, so the query serves the seed (it reaches the
73
+ * whole collection, as it did before views existed) and the view narrows
74
+ * the window. That is why `initial` folds into every baseline rather than
75
+ * being a starting state the view replaces.
76
+ *
77
+ * ## A view's state is applied once per view
78
+ *
79
+ * When the address names a view, its stored filters, columns and sort
80
+ * become the working state the moment the listing carries it — once. A
81
+ * later change to the document does not overwrite what the reader is in
82
+ * the middle of; a change the reader makes is theirs until they save it or
83
+ * reset. The default applies only onto an untouched plain list, so a reader
84
+ * who started narrowing before their profile arrived keeps what they typed.
85
+ */
86
+ export declare function useCrmSavedView(options: {
87
+ section: CrmViewSection;
88
+ /** The site the list is read under, or `null` at the organization level. */
89
+ hostId: string | null;
90
+ org?: CrmOrgDoc;
91
+ /** The CRM hub path the section hangs beneath — what the address is built from. */
92
+ basePath: string;
93
+ /** What the list was opened for: clauses every baseline keeps in front. */
94
+ initial?: Partial<CrmViewState>;
95
+ }): CrmSavedViewController;
96
+ export default useCrmSavedView;