@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 @@
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/crm/src/lib/components/recipes-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 {\n type AglynOrgBilling,\n checkEntitlement,\n CRM_ACTION_RECIPES,\n type CrmActionRecipe,\n type CrmActionRecipeId,\n planLabelGrantingFeature,\n pluginDocsHelp,\n} from '@aglyn/aglyn'\nimport { AppLink, CardDisplay, SrOnly } from '@aglyn/shared-ui-jsx'\nimport { ScrollTable } from '@aglyn/shared-ui-jsx/components/scroll-table.component'\nimport { useSnackbar } from '@aglyn/shared-ui-snackstack'\nimport {\n ceilingedWindow,\n collectionCeiling,\n useFirestore,\n useFirestoreCollection,\n} from '@aglyn/tenant-feature-instance'\nimport {\n Alert,\n Button,\n Drawer,\n MenuItem,\n Stack,\n TableBody,\n TableCell,\n TableHead,\n TableRow,\n TextField,\n Typography,\n} from '@mui/material'\nimport { collection } from 'firebase/firestore'\nimport { Fragment, useCallback, useEffect, useMemo, useState } from 'react'\nimport type {\n CrmRecipeInstallResult,\n CrmRecipeSiteStatus,\n} from '../constants/api-routes'\nimport { type CrmOrgMount, useCrmOrgMount } from '../hooks/use-crm-org-mount'\nimport { useCrmApi } from './use-crm-api'\n\n/** How many of a site's forms the picker offers before it says it stopped. */\nconst FORM_OPTION_CEILING = 100\n\n/**\n * The site's Automation → Actions page — where an installed action lives\n * and is edited — or `null` for a site whose subdomain the mount could not\n * answer, which is named and not linked.\n */\nfunction siteActionsHref(mount: CrmOrgMount, hostId: string): string | null {\n const subdomain = mount.siteSubdomain(hostId)\n return subdomain\n ? `${mount.hostsPath}/${encodeURIComponent(subdomain)}/automation/actions`\n : null\n}\n\n/**\n * Where a site stands with one recipe, read off the stamps the status route\n * answered. `maybe` is the third answer and the honest one: the site\n * carries actions saved before the stamp existed, any of which could have\n * started from the recipe, so the card neither lists the site as carrying\n * it nor offers the install as if to a blank site. `unread` is the answer\n * before the route has answered, or for a site it did not name.\n */\ntype SiteStanding = 'installed' | 'maybe' | 'clear' | 'unread'\n\nfunction standingOf(\n status: ReadonlyMap<string, CrmRecipeSiteStatus> | null,\n hostId: string,\n recipeId: CrmActionRecipeId,\n): SiteStanding {\n const site = status?.get(hostId)\n if (!site) return 'unread'\n if (site.installed.includes(recipeId)) return 'installed'\n return site.unstamped > 0 ? 'maybe' : 'clear'\n}\n\n/**\n * The stamps of every site of the org, read once the site list is known\n * and again after each install, so the card reports what the documents\n * say rather than what it last did.\n */\nfunction useRecipeStatus(mount: CrmOrgMount | null) {\n const api = useCrmApi(null)\n const [sites, setSites] = useState<Map<string, CrmRecipeSiteStatus> | null>(null)\n const [error, setError] = useState<string | null>(null)\n const refresh = useCallback(async () => {\n try {\n const { response, payload } = await api('recipe-status', {})\n if (!response.ok) {\n setError(payload?.error ?? 'Which sites carry a recipe could not be read.')\n return\n }\n const answered = (payload.sites ?? []) as CrmRecipeSiteStatus[]\n setSites(new Map(answered.map((site) => [site.hostId, site])))\n setError(null)\n } catch (caught) {\n console.error(caught)\n setError('Which sites carry a recipe could not be read.')\n }\n }, [api])\n const hostsReady = Boolean(mount?.hostsReady)\n useEffect(() => {\n if (hostsReady) void refresh()\n }, [hostsReady, refresh])\n return { sites, error, refresh }\n}\n\n/** A site's name, linked into its Actions page when the link is known. */\nfunction SiteLink(props: { mount: CrmOrgMount; hostId: string }) {\n const { mount, hostId } = props\n const href = siteActionsHref(mount, hostId)\n const name = mount.siteName(hostId)\n return href ? <AppLink href={href}>{name}</AppLink> : <>{name}</>\n}\nSiteLink.displayName = 'SiteLink'\n\n/** One recipe's \"Installed on\" cell: the sites that carry it, and the ones that may. */\nfunction InstalledOn(props: {\n mount: CrmOrgMount\n recipe: CrmActionRecipe\n status: ReadonlyMap<string, CrmRecipeSiteStatus> | null\n}) {\n const { mount, recipe, status } = props\n if (!status) {\n return (\n <Typography variant=\"caption\" color=\"text.secondary\">\n {'Reading…'}\n </Typography>\n )\n }\n const installed = mount.hosts.filter(\n (host) => standingOf(status, host.id, recipe.id) === 'installed',\n )\n const maybe = mount.hosts.filter(\n (host) => standingOf(status, host.id, recipe.id) === 'maybe',\n )\n return (\n <Stack spacing={0.5}>\n <Typography variant=\"body2\">\n {installed.length === 0\n ? 'Not installed on any site yet.'\n : installed.map((host, index) => (\n <Fragment key={host.id}>\n {index > 0 ? ', ' : null}\n <SiteLink mount={mount} hostId={host.id} />\n </Fragment>\n ))}\n </Typography>\n {maybe.length > 0 ? (\n <Typography variant=\"caption\" color=\"text.secondary\">\n {`May already have it: ${maybe.map((host) => host.name).join(', ')} — ` +\n 'actions there were saved before recipes were tracked.'}\n </Typography>\n ) : null}\n </Stack>\n )\n}\nInstalledOn.displayName = 'InstalledOn'\n\ninterface RecipeInstallFormProps {\n recipe: CrmActionRecipe\n mount: CrmOrgMount\n status: ReadonlyMap<string, CrmRecipeSiteStatus> | null\n onClose: () => void\n onInstalled: (result: CrmRecipeInstallResult, hostId: string) => void\n}\n\n/**\n * The install drawer's body: pick the site, pick the form a recipe that\n * needs one is keyed on, confirm. Mounted fresh on every opening — the\n * Drawer unmounts it when closed — so the picks start over each time from\n * the session's site, when that site does not already carry the recipe.\n *\n * The forms are read from the picked site only once a site is picked and\n * only for a recipe that needs one, so a reader installing the other three\n * pays no read. Live forms only: an archived form collects nothing, and a\n * recipe keyed on it would never fire.\n */\nfunction RecipeInstallForm(props: RecipeInstallFormProps) {\n const { recipe, mount, status, onClose, onInstalled } = props\n const firestore = useFirestore()\n const api = useCrmApi(null)\n const needsForm = recipe.needs === 'form'\n const [hostId, setHostId] = useState(() => {\n const pick = mount.createHostId\n return pick && standingOf(status, pick, recipe.id) !== 'installed' ? pick : ''\n })\n const [formId, setFormId] = useState('')\n const [busy, setBusy] = useState(false)\n const [error, setError] = useState<string | null>(null)\n\n const { data: formRead, status: formsStatus } = useFirestoreCollection<any>(\n () =>\n needsForm && hostId\n ? collectionCeiling(\n collection(firestore, 'hosts', hostId, 'forms'),\n FORM_OPTION_CEILING,\n )\n : null,\n [firestore, needsForm, hostId],\n { idField: '$id' },\n )\n const { rows: formDocs, truncated: formsTruncated } = ceilingedWindow<any>(\n formRead,\n FORM_OPTION_CEILING,\n )\n const formOptions = useMemo(\n () =>\n (formDocs ?? [])\n .filter((form: any) => !form.archivedAt)\n .map((form: any) => ({\n id: form.$id as string,\n name: (String(form.displayName ?? '').trim() || form.$id) as string,\n }))\n .sort((a: { name: string }, b: { name: string }) =>\n a.name.localeCompare(b.name),\n ),\n [formDocs],\n )\n const formsLoading = needsForm && Boolean(hostId) && formsStatus === 'loading'\n\n const canInstall =\n Boolean(hostId) && (!needsForm || Boolean(formId)) && !busy && !formsLoading\n\n const handleInstall = async () => {\n if (!canInstall) return\n setBusy(true)\n setError(null)\n try {\n const { response, payload } = await api('recipe-install', {\n hostId,\n recipeId: recipe.id,\n ...(formId ? { formId } : {}),\n })\n if (!response.ok) {\n setError(payload?.error ?? 'The recipe could not be installed.')\n return\n }\n onInstalled(payload as CrmRecipeInstallResult, hostId)\n } catch (caught) {\n console.error(caught)\n setError('The recipe could not be installed.')\n } finally {\n setBusy(false)\n }\n }\n\n const siteSuffix = (id: string) => {\n const standing = standingOf(status, id, recipe.id)\n if (standing === 'installed') return ' — installed'\n if (standing === 'maybe') return ' — may already have it'\n return ''\n }\n\n return (\n <Stack spacing={2} sx={{ width: 380, p: 3 }}>\n <Typography variant=\"h6\">{`Install “${recipe.title}”`}</Typography>\n <Typography variant=\"body2\" color=\"text.secondary\">\n {recipe.description}\n </Typography>\n <TextField\n select\n size=\"small\"\n label=\"Site\"\n value={hostId}\n onChange={(event) => {\n setHostId(event.target.value)\n setFormId('')\n setError(null)\n }}\n disabled={busy}\n helperText={\n mount.hosts.length === 0\n ? 'This organization has no sites yet.'\n : 'The action is written into this site’s Automation → Actions.'\n }\n fullWidth\n >\n {mount.hosts.map((host) => (\n <MenuItem\n key={host.id}\n value={host.id}\n disabled={standingOf(status, host.id, recipe.id) === 'installed'}\n >\n {`${host.name}${siteSuffix(host.id)}`}\n </MenuItem>\n ))}\n </TextField>\n {needsForm ? (\n <TextField\n select\n size=\"small\"\n label=\"Form\"\n value={formId}\n onChange={(event) => setFormId(event.target.value)}\n disabled={!hostId || busy || formsLoading}\n helperText={\n !hostId\n ? 'Pick the site first; the recipe is keyed on one of its forms.'\n : formsLoading\n ? 'Loading the site’s forms…'\n : formOptions.length === 0\n ? 'This site has no live forms.'\n : formsTruncated\n ? `Showing the first ${FORM_OPTION_CEILING} forms.`\n : 'Contacts this form makes are tagged with its name.'\n }\n fullWidth\n >\n {formOptions.map((form) => (\n <MenuItem key={form.id} value={form.id}>\n {form.name}\n </MenuItem>\n ))}\n </TextField>\n ) : null}\n <Typography variant=\"caption\" color=\"text.secondary\">\n {'The action is created enabled, exactly as the recipe defines it. ' +\n 'Change anything afterwards from the site’s Automation → Actions page.'}\n </Typography>\n {error ? (\n <Typography variant=\"body2\" color=\"error\">\n {error}\n </Typography>\n ) : null}\n <Stack direction=\"row\" spacing={1}>\n <Button\n variant=\"contained\"\n color=\"primary\"\n disabled={!canInstall}\n onClick={() => void handleInstall()}\n >\n {busy ? 'Installing…' : 'Install'}\n </Button>\n <Button onClick={onClose} disabled={busy}>\n {'Cancel'}\n </Button>\n </Stack>\n </Stack>\n )\n}\nRecipeInstallForm.displayName = 'RecipeInstallForm'\n\nexport interface RecipesCardProps {\n org?: Partial<AglynOrgBilling> | null\n}\n\n/**\n * \"Recipes\" — the CRM's ready-made automations, installed on a site from\n * the organization (AGL-2639).\n *\n * ## Why this card exists at the org level and nowhere else\n *\n * Automation is a site feature: a site's Actions page has a Recipes menu\n * that opens the editor prefilled, and the person saves what they see.\n * The org hub mounts over every site with no editor of its own, so it had\n * no recipes at all, and an org running five sites installed \"Welcome a\n * new lead\" five times by hand. This card is the org's door: every recipe,\n * the sites that already carry it, and Install, which writes the action\n * into the site the reader picks through the server — the server stamps\n * the recipe, refuses a site outside the org, and refuses a second copy.\n * Under a site the section does not mount it; the site's own menu is the\n * right door there.\n *\n * ## \"Installed on\" reads the stamp, and says when it cannot\n *\n * The status route answers, per site, the recipes a live action is stamped\n * with and how many live actions carry no stamp. A site with any of the\n * latter is named as one that MAY already have the recipe rather than\n * listed as clear: those actions were saved before the stamp existed and\n * the card cannot tell a hand-built welcome from an installed one.\n *\n * ## Creation opens a drawer\n *\n * Install is a button per row; the picks — the site, and for Tag by form\n * one of that site's forms — live in a drawer, never above the list.\n */\nexport function RecipesCard(props: RecipesCardProps) {\n const { org } = props\n const mount = useCrmOrgMount()\n const { enqueueSnackbar } = useSnackbar()\n const status = useRecipeStatus(mount)\n const refreshStatus = status.refresh\n const [installing, setInstalling] = useState<CrmActionRecipe | null>(null)\n const [lastInstall, setLastInstall] = useState<{\n hostId: string\n name: string\n } | null>(null)\n\n const entitled = checkEntitlement(org, 'actions')\n const canInstall = Boolean(mount?.hostsReady) && entitled\n\n const handleInstalled = useCallback(\n (result: CrmRecipeInstallResult, hostId: string) => {\n setInstalling(null)\n setLastInstall({ hostId, name: result.name })\n enqueueSnackbar(\n `Installed “${result.name}” on ${mount?.siteName(hostId) ?? hostId}`,\n { variant: 'success', persist: false },\n )\n void refreshStatus()\n },\n [enqueueSnackbar, mount, refreshStatus],\n )\n\n // Mounted by the section only beneath the org hub's provider; the hooks\n // above run either way, so the render order never depends on the mount.\n if (!mount) return null\n\n const lastInstallHref = lastInstall ? siteActionsHref(mount, lastInstall.hostId) : null\n return (\n <CardDisplay\n header={'Recipes'}\n help={pluginDocsHelp('crmSettings', { anchor: '#recipes' })}\n contentGutterX\n contentGutterY\n contentBordered=\"all\"\n >\n <Stack spacing={2}>\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'Ready-made automations for the CRM. Install one on a site and the ' +\n 'action is written into that site’s Automation → Actions as the ' +\n 'recipe defines it, where it can be edited like any other action.'}\n </Typography>\n {lastInstall ? (\n <Alert\n severity=\"success\"\n onClose={() => setLastInstall(null)}\n action={\n lastInstallHref ? (\n // A link dressed as a button: the anchor carries its own\n // href, so it keeps the link role a navigation door has.\n <Button\n component={AppLink as any}\n {...({\n componentVariant: 'naked',\n nativeButton: false,\n } as any)}\n href={lastInstallHref}\n size=\"small\"\n color=\"inherit\"\n >\n {'Open Automation → Actions'}\n </Button>\n ) : undefined\n }\n >\n {`Installed “${lastInstall.name}” on ${mount.siteName(lastInstall.hostId)}.`}\n </Alert>\n ) : null}\n {status.error ? (\n <Typography variant=\"caption\" color=\"error\">\n {status.error}\n </Typography>\n ) : null}\n <ScrollTable size=\"small\">\n <TableHead>\n <TableRow>\n <TableCell>{'Recipe'}</TableCell>\n <TableCell>{'Installed on'}</TableCell>\n <TableCell align=\"right\" />\n </TableRow>\n </TableHead>\n <TableBody>\n {CRM_ACTION_RECIPES.map((recipe) => (\n <TableRow key={recipe.id} hover>\n <TableCell sx={{ maxWidth: 360 }}>\n <Typography variant=\"body2\">{recipe.title}</Typography>\n <Typography variant=\"caption\" color=\"text.secondary\">\n {recipe.description}\n </Typography>\n </TableCell>\n <TableCell>\n <InstalledOn mount={mount} recipe={recipe} status={status.sites} />\n </TableCell>\n <TableCell align=\"right\" sx={{ width: 120 }}>\n <Button\n size=\"small\"\n variant=\"outlined\"\n disabled={!canInstall}\n onClick={() => setInstalling(recipe)}\n >\n {'Install'}\n <SrOnly>{` ${recipe.title}`}</SrOnly>\n </Button>\n </TableCell>\n </TableRow>\n ))}\n </TableBody>\n </ScrollTable>\n {!entitled ? (\n <Typography variant=\"caption\" color=\"text.secondary\">\n {`The actions builder requires the ${planLabelGrantingFeature('actions') ?? 'Pro'} ` +\n 'plan — see Billing to upgrade.'}\n </Typography>\n ) : null}\n {mount.hostsReady && mount.hosts.length === 0 ? (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'This organization has no sites yet, so there is nowhere to install a recipe.'}\n </Typography>\n ) : null}\n </Stack>\n <Drawer anchor=\"right\" open={Boolean(installing)} onClose={() => setInstalling(null)}>\n {installing ? (\n <RecipeInstallForm\n recipe={installing}\n mount={mount}\n status={status.sites}\n onClose={() => setInstalling(null)}\n onInstalled={handleInstalled}\n />\n ) : null}\n </Drawer>\n </CardDisplay>\n )\n}\nRecipesCard.displayName = 'RecipesCard'\n\nexport default RecipesCard\n"],"names":["checkEntitlement","CRM_ACTION_RECIPES","planLabelGrantingFeature","pluginDocsHelp","AppLink","CardDisplay","SrOnly","ScrollTable","useSnackbar","ceilingedWindow","collectionCeiling","useFirestore","useFirestoreCollection","Alert","Button","Drawer","MenuItem","Stack","TableBody","TableCell","TableHead","TableRow","TextField","Typography","collection","Fragment","useCallback","useEffect","useMemo","useState","useCrmOrgMount","useCrmApi","FORM_OPTION_CEILING","siteActionsHref","mount","hostId","subdomain","siteSubdomain","hostsPath","encodeURIComponent","standingOf","status","recipeId","site","get","installed","includes","unstamped","useRecipeStatus","api","sites","setSites","error","setError","refresh","payload","response","ok","answered","Map","map","caught","console","hostsReady","Boolean","SiteLink","props","href","name","siteName","displayName","InstalledOn","recipe","variant","color","hosts","filter","host","id","maybe","spacing","length","index","join","RecipeInstallForm","onClose","onInstalled","firestore","needsForm","needs","setHostId","pick","createHostId","formId","setFormId","busy","setBusy","data","formRead","formsStatus","idField","rows","formDocs","truncated","formsTruncated","formOptions","form","archivedAt","$id","String","trim","sort","a","b","localeCompare","formsLoading","canInstall","handleInstall","siteSuffix","standing","sx","width","p","title","description","select","size","label","value","onChange","event","target","disabled","helperText","fullWidth","direction","onClick","RecipesCard","org","enqueueSnackbar","refreshStatus","installing","setInstalling","lastInstall","setLastInstall","entitled","handleInstalled","result","persist","lastInstallHref","header","help","anchor","contentGutterX","contentGutterY","contentBordered","severity","action","component","componentVariant","nativeButton","undefined","align","hover","maxWidth","open"],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ import { type ActivityRecordLink, type CrmOrg } from './activity-queries';
2
+ export type RecordActivityCardProps = ActivityRecordLink & {
3
+ /** The site the record is read under, or `null` at the organization level. */
4
+ hostId: string | null;
5
+ org: CrmOrg;
6
+ };
7
+ /**
8
+ * The activity log of one record — a contact, a company, a deal or a lead
9
+ * (AGL-2615) — with the button that adds to it (AGL-2600).
10
+ *
11
+ * One card for all four record pages, because the log is the same thing on
12
+ * each of them: what people did about this record, newest first, bounded to
13
+ * a page of a hundred with a foot that asks for the next hundred. Which
14
+ * record is decided by whichever of the four ids the page passes, and that
15
+ * id is what the dialog files a new activity against — the page fixes it,
16
+ * the reader does not pick it.
17
+ *
18
+ * The contact's page does NOT use this card. A person has a second history
19
+ * the platform captured on the row itself, and the two belong in one
20
+ * stream; see `contact-timeline-card.tsx`, which is this card's superset.
21
+ */
22
+ export declare function RecordActivityCard(props: RecordActivityCardProps): import("react").JSX.Element;
23
+ export declare namespace RecordActivityCard {
24
+ var displayName: string;
25
+ }
26
+ export default RecordActivityCard;
@@ -0,0 +1,121 @@
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, Fragment as _Fragment } from "react/jsx-runtime";
18
+ import { pluginDocsHelp } from "@aglyn/aglyn";
19
+ import { CardDisplay } from "@aglyn/shared-ui-jsx";
20
+ import { Button, Typography } from "@mui/material";
21
+ import { useCallback, useMemo, useState } from "react";
22
+ import { ActivityList } from "./activity-list.js";
23
+ import { useActivityScope, useActivityWindow } from "./activity-queries.js";
24
+ import { LogActivityDialog } from "./log-activity-dialog.js";
25
+ /**
26
+ * The activity log of one record — a contact, a company, a deal or a lead
27
+ * (AGL-2615) — with the button that adds to it (AGL-2600).
28
+ *
29
+ * One card for all four record pages, because the log is the same thing on
30
+ * each of them: what people did about this record, newest first, bounded to
31
+ * a page of a hundred with a foot that asks for the next hundred. Which
32
+ * record is decided by whichever of the four ids the page passes, and that
33
+ * id is what the dialog files a new activity against — the page fixes it,
34
+ * the reader does not pick it.
35
+ *
36
+ * The contact's page does NOT use this card. A person has a second history
37
+ * the platform captured on the row itself, and the two belong in one
38
+ * stream; see `contact-timeline-card.tsx`, which is this card's superset.
39
+ */ export function RecordActivityCard(props) {
40
+ const { hostId, org, contactId, companyId, dealId, leadId } = props;
41
+ const scope = useActivityScope(hostId, org);
42
+ /*
43
+ * Memoized because the link is a listener dependency by value inside
44
+ * `useActivityWindow` and the dialog's prop by reference: a fresh object
45
+ * each render would be harmless to the query, which reads the ids, and
46
+ * noisy for anything that compares the object.
47
+ */ const link = useMemo(()=>({
48
+ contactId,
49
+ companyId,
50
+ dealId,
51
+ leadId
52
+ }), [
53
+ contactId,
54
+ companyId,
55
+ dealId,
56
+ leadId
57
+ ]);
58
+ const activities = useActivityWindow(scope, link);
59
+ const [dialogOpen, setDialogOpen] = useState(false);
60
+ const [editing, setEditing] = useState(null);
61
+ const openNew = useCallback(()=>{
62
+ setEditing(null);
63
+ setDialogOpen(true);
64
+ }, []);
65
+ const openEdit = useCallback((activity)=>{
66
+ setEditing(activity);
67
+ setDialogOpen(true);
68
+ }, []);
69
+ const close = useCallback(()=>setDialogOpen(false), []);
70
+ return /*#__PURE__*/ _jsxs(_Fragment, {
71
+ children: [
72
+ /*#__PURE__*/ _jsx(CardDisplay, {
73
+ header: 'Activity',
74
+ help: pluginDocsHelp('contactActivities', {
75
+ anchor: '#logging-an-activity'
76
+ }),
77
+ actions: /*#__PURE__*/ _jsx(Button, {
78
+ size: "small",
79
+ variant: "contained",
80
+ color: "primary",
81
+ onClick: openNew,
82
+ disabled: !activities.ready,
83
+ children: 'Log activity'
84
+ }),
85
+ contentGutterX: true,
86
+ contentGutterY: true,
87
+ children: activities.status === 'error' ? /*#__PURE__*/ _jsx(Typography, {
88
+ variant: "body2",
89
+ color: "error",
90
+ children: 'The activity log could not be loaded.'
91
+ }) : /*#__PURE__*/ _jsx(ActivityList, {
92
+ rows: activities.rows,
93
+ scope: scope,
94
+ onEdit: openEdit,
95
+ hasMore: activities.hasMore,
96
+ onShowMore: activities.showMore,
97
+ emptyText: "A call, an email, a meeting or a note about this record goes here.",
98
+ emptyAction: /*#__PURE__*/ _jsx(Button, {
99
+ size: "small",
100
+ variant: "contained",
101
+ color: "primary",
102
+ onClick: openNew,
103
+ disabled: !activities.ready,
104
+ children: 'Log activity'
105
+ })
106
+ })
107
+ }),
108
+ /*#__PURE__*/ _jsx(LogActivityDialog, {
109
+ open: dialogOpen,
110
+ onClose: close,
111
+ scope: scope,
112
+ link: link,
113
+ activity: editing
114
+ })
115
+ ]
116
+ });
117
+ }
118
+ RecordActivityCard.displayName = 'RecordActivityCard';
119
+ export default RecordActivityCard;
120
+
121
+ //# sourceMappingURL=record-activity-card.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/crm/src/lib/components/record-activity-card.tsx"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n'use client'\n\nimport type { CrmActivityRow } from '@aglyn/aglyn'\nimport { pluginDocsHelp } from '@aglyn/aglyn'\nimport { CardDisplay } from '@aglyn/shared-ui-jsx'\nimport { Button, Typography } from '@mui/material'\nimport { useCallback, useMemo, useState } from 'react'\nimport { ActivityList } from './activity-list'\nimport {\n type ActivityRecordLink,\n type CrmOrg,\n useActivityScope,\n useActivityWindow,\n} from './activity-queries'\nimport { LogActivityDialog } from './log-activity-dialog'\n\nexport type RecordActivityCardProps = ActivityRecordLink & {\n /** The site the record is read under, or `null` at the organization level. */\n hostId: string | null\n org: CrmOrg\n}\n\n/**\n * The activity log of one record — a contact, a company, a deal or a lead\n * (AGL-2615) — with the button that adds to it (AGL-2600).\n *\n * One card for all four record pages, because the log is the same thing on\n * each of them: what people did about this record, newest first, bounded to\n * a page of a hundred with a foot that asks for the next hundred. Which\n * record is decided by whichever of the four ids the page passes, and that\n * id is what the dialog files a new activity against — the page fixes it,\n * the reader does not pick it.\n *\n * The contact's page does NOT use this card. A person has a second history\n * the platform captured on the row itself, and the two belong in one\n * stream; see `contact-timeline-card.tsx`, which is this card's superset.\n */\nexport function RecordActivityCard(props: RecordActivityCardProps) {\n const { hostId, org, contactId, companyId, dealId, leadId } = props\n const scope = useActivityScope(hostId, org)\n /*\n * Memoized because the link is a listener dependency by value inside\n * `useActivityWindow` and the dialog's prop by reference: a fresh object\n * each render would be harmless to the query, which reads the ids, and\n * noisy for anything that compares the object.\n */\n const link = useMemo<ActivityRecordLink>(\n () => ({ contactId, companyId, dealId, leadId }),\n [contactId, companyId, dealId, leadId],\n )\n const activities = useActivityWindow(scope, link)\n const [dialogOpen, setDialogOpen] = useState(false)\n const [editing, setEditing] = useState<CrmActivityRow | null>(null)\n const openNew = useCallback(() => {\n setEditing(null)\n setDialogOpen(true)\n }, [])\n const openEdit = useCallback((activity: CrmActivityRow) => {\n setEditing(activity)\n setDialogOpen(true)\n }, [])\n const close = useCallback(() => setDialogOpen(false), [])\n\n return (\n <>\n <CardDisplay\n header={'Activity'}\n help={pluginDocsHelp('contactActivities', { anchor: '#logging-an-activity' })}\n actions={\n <Button\n size=\"small\"\n variant=\"contained\"\n color=\"primary\"\n onClick={openNew}\n disabled={!activities.ready}\n >\n {'Log activity'}\n </Button>\n }\n contentGutterX\n contentGutterY\n >\n {activities.status === 'error' ? (\n <Typography variant=\"body2\" color=\"error\">\n {'The activity log could not be loaded.'}\n </Typography>\n ) : (\n <ActivityList\n rows={activities.rows}\n scope={scope}\n onEdit={openEdit}\n hasMore={activities.hasMore}\n onShowMore={activities.showMore}\n emptyText=\"A call, an email, a meeting or a note about this record goes here.\"\n emptyAction={\n <Button\n size=\"small\"\n variant=\"contained\"\n color=\"primary\"\n onClick={openNew}\n disabled={!activities.ready}\n >\n {'Log activity'}\n </Button>\n }\n />\n )}\n </CardDisplay>\n <LogActivityDialog\n open={dialogOpen}\n onClose={close}\n scope={scope}\n link={link}\n activity={editing}\n />\n </>\n )\n}\nRecordActivityCard.displayName = 'RecordActivityCard'\n\nexport default RecordActivityCard\n"],"names":["pluginDocsHelp","CardDisplay","Button","Typography","useCallback","useMemo","useState","ActivityList","useActivityScope","useActivityWindow","LogActivityDialog","RecordActivityCard","props","hostId","org","contactId","companyId","dealId","leadId","scope","link","activities","dialogOpen","setDialogOpen","editing","setEditing","openNew","openEdit","activity","close","header","help","anchor","actions","size","variant","color","onClick","disabled","ready","contentGutterX","contentGutterY","status","rows","onEdit","hasMore","onShowMore","showMore","emptyText","emptyAction","open","onClose","displayName"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GACD;;AAGA,SAASA,cAAc,QAAQ,eAAc;AAC7C,SAASC,WAAW,QAAQ,uBAAsB;AAClD,SAASC,MAAM,EAAEC,UAAU,QAAQ,gBAAe;AAClD,SAASC,WAAW,EAAEC,OAAO,EAAEC,QAAQ,QAAQ,QAAO;AACtD,SAASC,YAAY,QAAQ,qBAAiB;AAC9C,SAGEC,gBAAgB,EAChBC,iBAAiB,QACZ,wBAAoB;AAC3B,SAASC,iBAAiB,QAAQ,2BAAuB;AAQzD;;;;;;;;;;;;;;CAcC,GACD,OAAO,SAASC,mBAAmBC,KAA8B;IAC/D,MAAM,EAAEC,MAAM,EAAEC,GAAG,EAAEC,SAAS,EAAEC,SAAS,EAAEC,MAAM,EAAEC,MAAM,EAAE,GAAGN;IAC9D,MAAMO,QAAQX,iBAAiBK,QAAQC;IACvC;;;;;GAKC,GACD,MAAMM,OAAOf,QACX,IAAO,CAAA;YAAEU;YAAWC;YAAWC;YAAQC;QAAO,CAAA,GAC9C;QAACH;QAAWC;QAAWC;QAAQC;KAAO;IAExC,MAAMG,aAAaZ,kBAAkBU,OAAOC;IAC5C,MAAM,CAACE,YAAYC,cAAc,GAAGjB,SAAS;IAC7C,MAAM,CAACkB,SAASC,WAAW,GAAGnB,SAAgC;IAC9D,MAAMoB,UAAUtB,YAAY;QAC1BqB,WAAW;QACXF,cAAc;IAChB,GAAG,EAAE;IACL,MAAMI,WAAWvB,YAAY,CAACwB;QAC5BH,WAAWG;QACXL,cAAc;IAChB,GAAG,EAAE;IACL,MAAMM,QAAQzB,YAAY,IAAMmB,cAAc,QAAQ,EAAE;IAExD,qBACE;;0BACE,KAACtB;gBACC6B,QAAQ;gBACRC,MAAM/B,eAAe,qBAAqB;oBAAEgC,QAAQ;gBAAuB;gBAC3EC,uBACE,KAAC/B;oBACCgC,MAAK;oBACLC,SAAQ;oBACRC,OAAM;oBACNC,SAASX;oBACTY,UAAU,CAACjB,WAAWkB,KAAK;8BAE1B;;gBAGLC,cAAc;gBACdC,cAAc;0BAEbpB,WAAWqB,MAAM,KAAK,wBACrB,KAACvC;oBAAWgC,SAAQ;oBAAQC,OAAM;8BAC/B;mCAGH,KAAC7B;oBACCoC,MAAMtB,WAAWsB,IAAI;oBACrBxB,OAAOA;oBACPyB,QAAQjB;oBACRkB,SAASxB,WAAWwB,OAAO;oBAC3BC,YAAYzB,WAAW0B,QAAQ;oBAC/BC,WAAU;oBACVC,2BACE,KAAC/C;wBACCgC,MAAK;wBACLC,SAAQ;wBACRC,OAAM;wBACNC,SAASX;wBACTY,UAAU,CAACjB,WAAWkB,KAAK;kCAE1B;;;;0BAMX,KAAC7B;gBACCwC,MAAM5B;gBACN6B,SAAStB;gBACTV,OAAOA;gBACPC,MAAMA;gBACNQ,UAAUJ;;;;AAIlB;AACAb,mBAAmByC,WAAW,GAAG;AAEjC,eAAezC,mBAAkB"}
@@ -0,0 +1,67 @@
1
+ export interface RecordFilesCardProps {
2
+ /** `['orgs', orgId]`, or `null` while the org is unresolved. */
3
+ scope: readonly [string, string] | null;
4
+ /** The collection the record lives in under the org root. */
5
+ collection: string;
6
+ /** The record's document id. */
7
+ recordId: string;
8
+ /**
9
+ * The holder whose facet the field belongs to, for a CONTACT.
10
+ *
11
+ * A contact's fields live per holder — an agency running two client brands
12
+ * has one contact document between them, and a contract one client filed
13
+ * is not the other's to see — so the field is a facet's, and a facet is the
14
+ * server's to write (AGL-2804): a contact's files are saved through
15
+ * `crm/contact-update`, which writes the holder's facet and refuses a plan
16
+ * without the CRM. `null` for a company or a deal, whose fields are
17
+ * the organization's, sit at the top of the document and are written here.
18
+ */
19
+ facetGroupId?: string | null;
20
+ /**
21
+ * The site a contact's files are saved as: the mounted site, or `null` at
22
+ * the organization level, where the route writes each contact through its
23
+ * own holder. Read only for a contact.
24
+ */
25
+ hostId?: string | null;
26
+ /** The ids the record currently carries. */
27
+ mediaIds: readonly string[] | undefined;
28
+ /**
29
+ * The manual page this card's help opens — each record kind documents its
30
+ * own Files section, and a card that pointed all three at one page would
31
+ * send a company's reader to a page about people.
32
+ */
33
+ topic: 'contactRecord' | 'companies' | 'deals';
34
+ }
35
+ /**
36
+ * FILES ON A RECORD (AGL-2662): the organization's library, attached.
37
+ *
38
+ * ## Ids, not URLs
39
+ *
40
+ * The field stores media DOCUMENT ids and resolves them to the CDN at read
41
+ * time. A stored URL names an object's current location and dies on a folder
42
+ * move; it also pins a private asset to a raw storage link rather than the
43
+ * signed door that checks who is asking. `media-ref.ts` already made this
44
+ * choice for every placement on a page, and this is the same choice for a
45
+ * record.
46
+ *
47
+ * ## The picker is the console's, reached through the bridge
48
+ *
49
+ * The media library is coupled to the org and session context and lives in
50
+ * the console app, which a plugin may not import — so this asks for one
51
+ * through `MediaPickerContext`, the same door the commerce product editor
52
+ * uses. Where no provider is mounted the card says so rather than offering a
53
+ * button that does nothing.
54
+ *
55
+ * ## One read per attached file, and only for the files attached
56
+ *
57
+ * A name and a type are on the media document, not in the id, so each
58
+ * attachment costs one `getDoc` — bounded by {@link CRM_MEDIA_IDS_MAX} and
59
+ * paid only on a record that actually carries files. A file the library no
60
+ * longer holds is still listed, by its id and as missing: an attachment that
61
+ * silently vanished is worse than one that says it is gone.
62
+ */
63
+ export declare function RecordFilesCard(props: RecordFilesCardProps): import("react").JSX.Element;
64
+ export declare namespace RecordFilesCard {
65
+ var displayName: string;
66
+ }
67
+ export default RecordFilesCard;
@@ -0,0 +1,290 @@
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 { CRM_MEDIA_IDS_FIELD, CRM_MEDIA_IDS_MAX, formatMediaRef, normalizeCrmMediaIds, pluginDocsHelp, resolveMediaSrc, useMediaPicker } from "@aglyn/aglyn";
19
+ import { mdiClose, mdiFileOutline, mdiPaperclip } from "@aglyn/shared-data-mdi";
20
+ import { CardDisplay, MdiIcon } from "@aglyn/shared-ui-jsx";
21
+ import { Alert, Box, Button, IconButton, Link, Stack, Typography } from "@mui/material";
22
+ import { doc, getDoc, serverTimestamp, updateDoc } from "firebase/firestore";
23
+ import { useSnackbar } from "notistack";
24
+ import { useCallback, useEffect, useMemo, useState } from "react";
25
+ import { useFirestore } from "@aglyn/tenant-feature-instance";
26
+ import { useContactUpdate } from "../hooks/use-contact-update.js";
27
+ /**
28
+ * FILES ON A RECORD (AGL-2662): the organization's library, attached.
29
+ *
30
+ * ## Ids, not URLs
31
+ *
32
+ * The field stores media DOCUMENT ids and resolves them to the CDN at read
33
+ * time. A stored URL names an object's current location and dies on a folder
34
+ * move; it also pins a private asset to a raw storage link rather than the
35
+ * signed door that checks who is asking. `media-ref.ts` already made this
36
+ * choice for every placement on a page, and this is the same choice for a
37
+ * record.
38
+ *
39
+ * ## The picker is the console's, reached through the bridge
40
+ *
41
+ * The media library is coupled to the org and session context and lives in
42
+ * the console app, which a plugin may not import — so this asks for one
43
+ * through `MediaPickerContext`, the same door the commerce product editor
44
+ * uses. Where no provider is mounted the card says so rather than offering a
45
+ * button that does nothing.
46
+ *
47
+ * ## One read per attached file, and only for the files attached
48
+ *
49
+ * A name and a type are on the media document, not in the id, so each
50
+ * attachment costs one `getDoc` — bounded by {@link CRM_MEDIA_IDS_MAX} and
51
+ * paid only on a record that actually carries files. A file the library no
52
+ * longer holds is still listed, by its id and as missing: an attachment that
53
+ * silently vanished is worse than one that says it is gone.
54
+ */ export function RecordFilesCard(props) {
55
+ var _ref;
56
+ const { scope, collection, recordId, facetGroupId, hostId, mediaIds, topic } = props;
57
+ const firestore = useFirestore();
58
+ const { pickMedia } = useMediaPicker();
59
+ const { enqueueSnackbar } = useSnackbar();
60
+ const contactUpdate = useContactUpdate(hostId != null ? hostId : null);
61
+ const [busy, setBusy] = useState(false);
62
+ const [files, setFiles] = useState(null);
63
+ const ids = useMemo(()=>normalizeCrmMediaIds(mediaIds), [
64
+ mediaIds
65
+ ]);
66
+ const key = ids.join('\n');
67
+ const orgId = (_ref = scope == null ? void 0 : scope[1]) != null ? _ref : '';
68
+ useEffect(()=>{
69
+ if (!orgId) return undefined;
70
+ const wanted = key ? key.split('\n') : [];
71
+ if (!wanted.length) {
72
+ setFiles([]);
73
+ return undefined;
74
+ }
75
+ let live = true;
76
+ void Promise.all(wanted.map(async (mediaId)=>{
77
+ try {
78
+ var _snapshot_data, _data_fileName, _data_contentType, _data_alt, _formatMediaRef;
79
+ const snapshot = await getDoc(doc(firestore, 'orgs', orgId, 'media', mediaId));
80
+ const data = (_snapshot_data = snapshot.data()) != null ? _snapshot_data : {};
81
+ return {
82
+ mediaId,
83
+ fileName: String((_data_fileName = data['fileName']) != null ? _data_fileName : ''),
84
+ contentType: String((_data_contentType = data['contentType']) != null ? _data_contentType : ''),
85
+ alt: String((_data_alt = data['alt']) != null ? _data_alt : ''),
86
+ src: resolveMediaSrc((_formatMediaRef = formatMediaRef(`org:${orgId}`, mediaId)) != null ? _formatMediaRef : undefined)
87
+ };
88
+ } catch (unused) {
89
+ // A file the reader may not see, or one that is gone. Listed and
90
+ // named as unreadable rather than dropped — an attachment that
91
+ // silently disappears reads as one that was never made.
92
+ return {
93
+ mediaId,
94
+ fileName: '',
95
+ contentType: '',
96
+ alt: ''
97
+ };
98
+ }
99
+ })).then((resolved)=>{
100
+ if (live) setFiles(resolved);
101
+ });
102
+ return ()=>{
103
+ live = false;
104
+ };
105
+ }, [
106
+ firestore,
107
+ orgId,
108
+ key
109
+ ]);
110
+ const write = useCallback(async (next)=>{
111
+ if (!scope) return;
112
+ if (facetGroupId) {
113
+ await contactUpdate.updateOne(recordId, {
114
+ mediaIds: next
115
+ });
116
+ return;
117
+ }
118
+ await updateDoc(doc(firestore, scope[0], scope[1], collection, recordId), {
119
+ [CRM_MEDIA_IDS_FIELD]: next,
120
+ updatedAt: serverTimestamp()
121
+ });
122
+ }, [
123
+ firestore,
124
+ scope,
125
+ collection,
126
+ recordId,
127
+ facetGroupId,
128
+ contactUpdate
129
+ ]);
130
+ const handleAttach = useCallback(async ()=>{
131
+ if (!pickMedia || busy) return;
132
+ const picked = await pickMedia();
133
+ if (!(picked == null ? void 0 : picked.mediaId)) return;
134
+ if (ids.includes(picked.mediaId)) {
135
+ enqueueSnackbar('That file is already attached', {
136
+ variant: 'info'
137
+ });
138
+ return;
139
+ }
140
+ if (ids.length >= CRM_MEDIA_IDS_MAX) {
141
+ enqueueSnackbar(`A record holds at most ${CRM_MEDIA_IDS_MAX} files — remove one first.`, {
142
+ variant: 'warning'
143
+ });
144
+ return;
145
+ }
146
+ setBusy(true);
147
+ try {
148
+ await write(normalizeCrmMediaIds([
149
+ ...ids,
150
+ picked.mediaId
151
+ ]));
152
+ } catch (unused) {
153
+ enqueueSnackbar('The file could not be attached', {
154
+ variant: 'error'
155
+ });
156
+ } finally{
157
+ setBusy(false);
158
+ }
159
+ }, [
160
+ pickMedia,
161
+ busy,
162
+ ids,
163
+ write,
164
+ enqueueSnackbar
165
+ ]);
166
+ const handleRemove = useCallback(async (mediaId)=>{
167
+ if (busy) return;
168
+ setBusy(true);
169
+ try {
170
+ await write(ids.filter((id)=>id !== mediaId));
171
+ } catch (unused) {
172
+ enqueueSnackbar('The file could not be removed', {
173
+ variant: 'error'
174
+ });
175
+ } finally{
176
+ setBusy(false);
177
+ }
178
+ }, [
179
+ busy,
180
+ ids,
181
+ write,
182
+ enqueueSnackbar
183
+ ]);
184
+ return /*#__PURE__*/ _jsx(CardDisplay, {
185
+ header: 'Files',
186
+ help: pluginDocsHelp(topic, {
187
+ anchor: '#files',
188
+ excerpt: 'Files from the organization library attached to this record. ' + 'Stored by id, so a file moved between folders keeps its ' + 'attachment and a private one is still served through the signed ' + 'door.'
189
+ }),
190
+ contentGutterX: true,
191
+ contentGutterY: true,
192
+ HeaderProps: {
193
+ action: /*#__PURE__*/ _jsx(Button, {
194
+ size: "small",
195
+ startIcon: /*#__PURE__*/ _jsx(MdiIcon, {
196
+ path: mdiPaperclip.path,
197
+ size: 0.8
198
+ }),
199
+ disabled: !scope || !pickMedia || busy,
200
+ onClick: ()=>void handleAttach(),
201
+ children: 'Attach…'
202
+ })
203
+ },
204
+ children: /*#__PURE__*/ _jsxs(Stack, {
205
+ spacing: 1,
206
+ children: [
207
+ !pickMedia ? /*#__PURE__*/ _jsx(Alert, {
208
+ severity: "info",
209
+ children: 'The media library is not available on this surface.'
210
+ }) : null,
211
+ files === null ? /*#__PURE__*/ _jsx(Typography, {
212
+ variant: "body2",
213
+ color: "text.secondary",
214
+ children: 'Reading…'
215
+ }) : files.length === 0 ? /*#__PURE__*/ _jsx(Typography, {
216
+ variant: "body2",
217
+ color: "text.secondary",
218
+ children: 'No files attached.'
219
+ }) : files.map((file)=>/*#__PURE__*/ _jsxs(Stack, {
220
+ direction: "row",
221
+ spacing: 1.5,
222
+ sx: {
223
+ alignItems: 'center'
224
+ },
225
+ children: [
226
+ file.src && file.contentType.startsWith('image/') ? /*#__PURE__*/ _jsx(Box, {
227
+ component: "img",
228
+ src: file.src,
229
+ alt: file.alt || file.fileName,
230
+ sx: {
231
+ width: 40,
232
+ height: 40,
233
+ objectFit: 'cover',
234
+ borderRadius: 1,
235
+ border: 1,
236
+ borderColor: 'divider'
237
+ }
238
+ }) : /*#__PURE__*/ _jsx(MdiIcon, {
239
+ path: mdiFileOutline.path,
240
+ size: 1,
241
+ sx: {
242
+ color: 'text.disabled'
243
+ }
244
+ }),
245
+ /*#__PURE__*/ _jsxs(Stack, {
246
+ sx: {
247
+ flex: 1,
248
+ minWidth: 0
249
+ },
250
+ children: [
251
+ file.src ? /*#__PURE__*/ _jsx(Link, {
252
+ href: file.src,
253
+ target: "_blank",
254
+ rel: "noreferrer",
255
+ variant: "body2",
256
+ noWrap: true,
257
+ children: file.fileName || file.mediaId
258
+ }) : /*#__PURE__*/ _jsx(Typography, {
259
+ variant: "body2",
260
+ noWrap: true,
261
+ children: file.fileName || file.mediaId
262
+ }),
263
+ /*#__PURE__*/ _jsx(Typography, {
264
+ variant: "caption",
265
+ color: "text.secondary",
266
+ noWrap: true,
267
+ children: file.fileName ? file.contentType || 'Unknown type' : 'This file is no longer in the library, or you cannot see it'
268
+ })
269
+ ]
270
+ }),
271
+ /*#__PURE__*/ _jsx(IconButton, {
272
+ size: "small",
273
+ "aria-label": `Remove ${file.fileName || file.mediaId}`,
274
+ disabled: busy || !scope,
275
+ onClick: ()=>void handleRemove(file.mediaId),
276
+ children: /*#__PURE__*/ _jsx(MdiIcon, {
277
+ path: mdiClose.path,
278
+ size: 0.8
279
+ })
280
+ })
281
+ ]
282
+ }, file.mediaId))
283
+ ]
284
+ })
285
+ });
286
+ }
287
+ RecordFilesCard.displayName = 'RecordFilesCard';
288
+ export default RecordFilesCard;
289
+
290
+ //# sourceMappingURL=record-files-card.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/crm/src/lib/components/record-files-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 {\n CRM_MEDIA_IDS_FIELD,\n CRM_MEDIA_IDS_MAX,\n formatMediaRef,\n normalizeCrmMediaIds,\n pluginDocsHelp,\n resolveMediaSrc,\n useMediaPicker,\n} from '@aglyn/aglyn'\nimport { mdiClose, mdiFileOutline, mdiPaperclip } from '@aglyn/shared-data-mdi'\nimport { CardDisplay, MdiIcon } from '@aglyn/shared-ui-jsx'\nimport {\n Alert,\n Box,\n Button,\n IconButton,\n Link,\n Stack,\n Typography,\n} from '@mui/material'\nimport { doc, getDoc, serverTimestamp, updateDoc } from 'firebase/firestore'\nimport { useSnackbar } from 'notistack'\nimport { useCallback, useEffect, useMemo, useState } from 'react'\nimport { useFirestore } from '@aglyn/tenant-feature-instance'\nimport { useContactUpdate } from '../hooks/use-contact-update'\n\n/** What one attached file is known by once its media document has been read. */\ninterface AttachedFile {\n mediaId: string\n fileName: string\n contentType: string\n alt: string\n /** The CDN URL the id resolves to, or undefined when it cannot be built. */\n src?: string\n}\n\nexport interface RecordFilesCardProps {\n /** `['orgs', orgId]`, or `null` while the org is unresolved. */\n scope: readonly [string, string] | null\n /** The collection the record lives in under the org root. */\n collection: string\n /** The record's document id. */\n recordId: string\n /**\n * The holder whose facet the field belongs to, for a CONTACT.\n *\n * A contact's fields live per holder — an agency running two client brands\n * has one contact document between them, and a contract one client filed\n * is not the other's to see — so the field is a facet's, and a facet is the\n * server's to write (AGL-2804): a contact's files are saved through\n * `crm/contact-update`, which writes the holder's facet and refuses a plan\n * without the CRM. `null` for a company or a deal, whose fields are\n * the organization's, sit at the top of the document and are written here.\n */\n facetGroupId?: string | null\n /**\n * The site a contact's files are saved as: the mounted site, or `null` at\n * the organization level, where the route writes each contact through its\n * own holder. Read only for a contact.\n */\n hostId?: string | null\n /** The ids the record currently carries. */\n mediaIds: readonly string[] | undefined\n /**\n * The manual page this card's help opens — each record kind documents its\n * own Files section, and a card that pointed all three at one page would\n * send a company's reader to a page about people.\n */\n topic: 'contactRecord' | 'companies' | 'deals'\n}\n\n/**\n * FILES ON A RECORD (AGL-2662): the organization's library, attached.\n *\n * ## Ids, not URLs\n *\n * The field stores media DOCUMENT ids and resolves them to the CDN at read\n * time. A stored URL names an object's current location and dies on a folder\n * move; it also pins a private asset to a raw storage link rather than the\n * signed door that checks who is asking. `media-ref.ts` already made this\n * choice for every placement on a page, and this is the same choice for a\n * record.\n *\n * ## The picker is the console's, reached through the bridge\n *\n * The media library is coupled to the org and session context and lives in\n * the console app, which a plugin may not import — so this asks for one\n * through `MediaPickerContext`, the same door the commerce product editor\n * uses. Where no provider is mounted the card says so rather than offering a\n * button that does nothing.\n *\n * ## One read per attached file, and only for the files attached\n *\n * A name and a type are on the media document, not in the id, so each\n * attachment costs one `getDoc` — bounded by {@link CRM_MEDIA_IDS_MAX} and\n * paid only on a record that actually carries files. A file the library no\n * longer holds is still listed, by its id and as missing: an attachment that\n * silently vanished is worse than one that says it is gone.\n */\nexport function RecordFilesCard(props: RecordFilesCardProps) {\n const { scope, collection, recordId, facetGroupId, hostId, mediaIds, topic } = props\n const firestore = useFirestore()\n const { pickMedia } = useMediaPicker()\n const { enqueueSnackbar } = useSnackbar()\n const contactUpdate = useContactUpdate(hostId ?? null)\n const [busy, setBusy] = useState(false)\n const [files, setFiles] = useState<AttachedFile[] | null>(null)\n\n const ids = useMemo(() => normalizeCrmMediaIds(mediaIds), [mediaIds])\n const key = ids.join('\\n')\n const orgId = scope?.[1] ?? ''\n\n useEffect(() => {\n if (!orgId) return undefined\n const wanted = key ? key.split('\\n') : []\n if (!wanted.length) {\n setFiles([])\n return undefined\n }\n let live = true\n void Promise.all(\n wanted.map(async (mediaId) => {\n try {\n const snapshot = await getDoc(\n doc(firestore, 'orgs', orgId, 'media', mediaId),\n )\n const data = (snapshot.data() ?? {}) as Record<string, unknown>\n return {\n mediaId,\n fileName: String(data['fileName'] ?? ''),\n contentType: String(data['contentType'] ?? ''),\n alt: String(data['alt'] ?? ''),\n src: resolveMediaSrc(\n formatMediaRef(`org:${orgId}`, mediaId) ?? undefined,\n ),\n }\n } catch {\n // A file the reader may not see, or one that is gone. Listed and\n // named as unreadable rather than dropped — an attachment that\n // silently disappears reads as one that was never made.\n return { mediaId, fileName: '', contentType: '', alt: '' }\n }\n }),\n ).then((resolved) => {\n if (live) setFiles(resolved)\n })\n return () => {\n live = false\n }\n }, [firestore, orgId, key])\n\n const write = useCallback(\n async (next: string[]) => {\n if (!scope) return\n if (facetGroupId) {\n await contactUpdate.updateOne(recordId, { mediaIds: next })\n return\n }\n await updateDoc(doc(firestore, scope[0], scope[1], collection, recordId), {\n [CRM_MEDIA_IDS_FIELD]: next,\n updatedAt: serverTimestamp(),\n })\n },\n [firestore, scope, collection, recordId, facetGroupId, contactUpdate],\n )\n\n const handleAttach = useCallback(async () => {\n if (!pickMedia || busy) return\n const picked = await pickMedia()\n if (!picked?.mediaId) return\n if (ids.includes(picked.mediaId)) {\n enqueueSnackbar('That file is already attached', { variant: 'info' })\n return\n }\n if (ids.length >= CRM_MEDIA_IDS_MAX) {\n enqueueSnackbar(\n `A record holds at most ${CRM_MEDIA_IDS_MAX} files — remove one first.`,\n { variant: 'warning' },\n )\n return\n }\n setBusy(true)\n try {\n await write(normalizeCrmMediaIds([...ids, picked.mediaId]))\n } catch {\n enqueueSnackbar('The file could not be attached', { variant: 'error' })\n } finally {\n setBusy(false)\n }\n }, [pickMedia, busy, ids, write, enqueueSnackbar])\n\n const handleRemove = useCallback(\n async (mediaId: string) => {\n if (busy) return\n setBusy(true)\n try {\n await write(ids.filter((id) => id !== mediaId))\n } catch {\n enqueueSnackbar('The file could not be removed', { variant: 'error' })\n } finally {\n setBusy(false)\n }\n },\n [busy, ids, write, enqueueSnackbar],\n )\n\n return (\n <CardDisplay\n header={'Files'}\n help={pluginDocsHelp(topic, {\n anchor: '#files',\n excerpt:\n 'Files from the organization library attached to this record. ' +\n 'Stored by id, so a file moved between folders keeps its ' +\n 'attachment and a private one is still served through the signed ' +\n 'door.',\n })}\n contentGutterX\n contentGutterY\n HeaderProps={{\n action: (\n <Button\n size=\"small\"\n startIcon={<MdiIcon path={mdiPaperclip.path} size={0.8} />}\n disabled={!scope || !pickMedia || busy}\n onClick={() => void handleAttach()}\n >\n {'Attach…'}\n </Button>\n ),\n }}\n >\n <Stack spacing={1}>\n {!pickMedia ? (\n <Alert severity=\"info\">\n {'The media library is not available on this surface.'}\n </Alert>\n ) : null}\n {files === null ? (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'Reading…'}\n </Typography>\n ) : files.length === 0 ? (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'No files attached.'}\n </Typography>\n ) : (\n files.map((file) => (\n <Stack\n key={file.mediaId}\n direction=\"row\"\n spacing={1.5}\n sx={{ alignItems: 'center' }}\n >\n {file.src && file.contentType.startsWith('image/') ? (\n <Box\n component=\"img\"\n src={file.src}\n alt={file.alt || file.fileName}\n sx={{\n width: 40,\n height: 40,\n objectFit: 'cover',\n borderRadius: 1,\n border: 1,\n borderColor: 'divider',\n }}\n />\n ) : (\n <MdiIcon\n path={mdiFileOutline.path}\n size={1}\n sx={{ color: 'text.disabled' }}\n />\n )}\n <Stack sx={{ flex: 1, minWidth: 0 }}>\n {file.src ? (\n <Link\n href={file.src}\n target=\"_blank\"\n rel=\"noreferrer\"\n variant=\"body2\"\n noWrap\n >\n {file.fileName || file.mediaId}\n </Link>\n ) : (\n <Typography variant=\"body2\" noWrap>\n {file.fileName || file.mediaId}\n </Typography>\n )}\n <Typography variant=\"caption\" color=\"text.secondary\" noWrap>\n {file.fileName\n ? file.contentType || 'Unknown type'\n : 'This file is no longer in the library, or you cannot see it'}\n </Typography>\n </Stack>\n <IconButton\n size=\"small\"\n aria-label={`Remove ${file.fileName || file.mediaId}`}\n disabled={busy || !scope}\n onClick={() => void handleRemove(file.mediaId)}\n >\n <MdiIcon path={mdiClose.path} size={0.8} />\n </IconButton>\n </Stack>\n ))\n )}\n </Stack>\n </CardDisplay>\n )\n}\nRecordFilesCard.displayName = 'RecordFilesCard'\n\nexport default RecordFilesCard\n"],"names":["CRM_MEDIA_IDS_FIELD","CRM_MEDIA_IDS_MAX","formatMediaRef","normalizeCrmMediaIds","pluginDocsHelp","resolveMediaSrc","useMediaPicker","mdiClose","mdiFileOutline","mdiPaperclip","CardDisplay","MdiIcon","Alert","Box","Button","IconButton","Link","Stack","Typography","doc","getDoc","serverTimestamp","updateDoc","useSnackbar","useCallback","useEffect","useMemo","useState","useFirestore","useContactUpdate","RecordFilesCard","props","scope","collection","recordId","facetGroupId","hostId","mediaIds","topic","firestore","pickMedia","enqueueSnackbar","contactUpdate","busy","setBusy","files","setFiles","ids","key","join","orgId","undefined","wanted","split","length","live","Promise","all","map","mediaId","snapshot","data","fileName","String","contentType","alt","src","then","resolved","write","next","updateOne","updatedAt","handleAttach","picked","includes","variant","handleRemove","filter","id","header","help","anchor","excerpt","contentGutterX","contentGutterY","HeaderProps","action","size","startIcon","path","disabled","onClick","spacing","severity","color","file","direction","sx","alignItems","startsWith","component","width","height","objectFit","borderRadius","border","borderColor","flex","minWidth","href","target","rel","noWrap","aria-label","displayName"],"mappings":"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"}