@aglyn/plugins-crm 1.0.0-beta.221 → 1.0.0-beta.223

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 (541) hide show
  1. package/README.md +2 -1
  2. package/package.json +13 -13
  3. package/src/lib/components/activity-list.js +12 -5
  4. package/src/lib/components/activity-list.js.map +1 -1
  5. package/src/lib/components/companies-bulk-bar.d.ts +1 -4
  6. package/src/lib/components/companies-bulk-bar.js +7 -20
  7. package/src/lib/components/companies-bulk-bar.js.map +1 -1
  8. package/src/lib/components/companies-section.d.ts +3 -3
  9. package/src/lib/components/companies-section.js +149 -46
  10. package/src/lib/components/companies-section.js.map +1 -1
  11. package/src/lib/components/company-edit-drawer.js +281 -20
  12. package/src/lib/components/company-edit-drawer.js.map +1 -1
  13. package/src/lib/components/company-properties-card.js +99 -8
  14. package/src/lib/components/company-properties-card.js.map +1 -1
  15. package/src/lib/components/contact-detail-page.js +3 -1
  16. package/src/lib/components/contact-detail-page.js.map +1 -1
  17. package/src/lib/components/contact-merge-dialog.js +33 -10
  18. package/src/lib/components/contact-merge-dialog.js.map +1 -1
  19. package/src/lib/components/contact-properties-card.d.ts +0 -69
  20. package/src/lib/components/contact-properties-card.js +350 -60
  21. package/src/lib/components/contact-properties-card.js.map +1 -1
  22. package/src/lib/components/contact-reports-to-field.d.ts +46 -0
  23. package/src/lib/components/contact-reports-to-field.js +67 -0
  24. package/src/lib/components/contact-reports-to-field.js.map +1 -0
  25. package/src/lib/components/contacts-bulk-bar.d.ts +1 -8
  26. package/src/lib/components/contacts-bulk-bar.js +7 -19
  27. package/src/lib/components/contacts-bulk-bar.js.map +1 -1
  28. package/src/lib/components/contacts-section.js +46 -33
  29. package/src/lib/components/contacts-section.js.map +1 -1
  30. package/src/lib/components/crm-call-actions.d.ts +10 -0
  31. package/src/lib/components/crm-call-actions.js +26 -9
  32. package/src/lib/components/crm-call-actions.js.map +1 -1
  33. package/src/lib/components/crm-next-activity-column.js +1 -1
  34. package/src/lib/components/crm-next-activity-column.js.map +1 -1
  35. package/src/lib/components/crm-record-picker.d.ts +15 -0
  36. package/src/lib/components/crm-record-picker.js +16 -10
  37. package/src/lib/components/crm-record-picker.js.map +1 -1
  38. package/src/lib/components/crm-transfer-buttons.d.ts +54 -0
  39. package/src/lib/components/crm-transfer-buttons.js +167 -0
  40. package/src/lib/components/crm-transfer-buttons.js.map +1 -0
  41. package/src/lib/components/deal-contact-roles-card.d.ts +46 -0
  42. package/src/lib/components/deal-contact-roles-card.js +368 -0
  43. package/src/lib/components/deal-contact-roles-card.js.map +1 -0
  44. package/src/lib/components/deal-detail-page.d.ts +3 -2
  45. package/src/lib/components/deal-detail-page.js +25 -6
  46. package/src/lib/components/deal-detail-page.js.map +1 -1
  47. package/src/lib/components/deal-edit-drawer.d.ts +10 -0
  48. package/src/lib/components/deal-edit-drawer.js +219 -10
  49. package/src/lib/components/deal-edit-drawer.js.map +1 -1
  50. package/src/lib/components/deal-properties-card.d.ts +7 -0
  51. package/src/lib/components/deal-properties-card.js +34 -3
  52. package/src/lib/components/deal-properties-card.js.map +1 -1
  53. package/src/lib/components/deal-stage-card.d.ts +4 -0
  54. package/src/lib/components/deal-stage-card.js +10 -2
  55. package/src/lib/components/deal-stage-card.js.map +1 -1
  56. package/src/lib/components/deals-bulk-bar.d.ts +0 -3
  57. package/src/lib/components/deals-bulk-bar.js +7 -20
  58. package/src/lib/components/deals-bulk-bar.js.map +1 -1
  59. package/src/lib/components/deals-section.d.ts +3 -3
  60. package/src/lib/components/deals-section.js +123 -63
  61. package/src/lib/components/deals-section.js.map +1 -1
  62. package/src/lib/components/fields-section.js +31 -17
  63. package/src/lib/components/fields-section.js.map +1 -1
  64. package/src/lib/components/lead-convert-dialog.d.ts +4 -0
  65. package/src/lib/components/lead-convert-dialog.js +23 -1
  66. package/src/lib/components/lead-convert-dialog.js.map +1 -1
  67. package/src/lib/components/lead-detail-page.js +8 -2
  68. package/src/lib/components/lead-detail-page.js.map +1 -1
  69. package/src/lib/components/lead-profile-fields.d.ts +71 -0
  70. package/src/lib/components/lead-profile-fields.js +386 -0
  71. package/src/lib/components/lead-profile-fields.js.map +1 -0
  72. package/src/lib/components/lead-properties-card.d.ts +2 -1
  73. package/src/lib/components/lead-properties-card.js +85 -176
  74. package/src/lib/components/lead-properties-card.js.map +1 -1
  75. package/src/lib/components/lead-source-select.d.ts +4 -23
  76. package/src/lib/components/lead-source-select.js +9 -73
  77. package/src/lib/components/lead-source-select.js.map +1 -1
  78. package/src/lib/components/lead-status-chip.d.ts +9 -3
  79. package/src/lib/components/lead-status-chip.js +8 -4
  80. package/src/lib/components/lead-status-chip.js.map +1 -1
  81. package/src/lib/components/lead-status-options.d.ts +20 -0
  82. package/src/lib/components/lead-status-options.js +51 -0
  83. package/src/lib/components/lead-status-options.js.map +1 -0
  84. package/src/lib/components/lead-unqualify-dialog.d.ts +5 -0
  85. package/src/lib/components/lead-unqualify-dialog.js +50 -18
  86. package/src/lib/components/lead-unqualify-dialog.js.map +1 -1
  87. package/src/lib/components/leads-bulk-bar.d.ts +0 -3
  88. package/src/lib/components/leads-bulk-bar.js +29 -29
  89. package/src/lib/components/leads-bulk-bar.js.map +1 -1
  90. package/src/lib/components/leads-section.js +120 -68
  91. package/src/lib/components/leads-section.js.map +1 -1
  92. package/src/lib/components/linked-deals-card.d.ts +4 -0
  93. package/src/lib/components/linked-deals-card.js +47 -3
  94. package/src/lib/components/linked-deals-card.js.map +1 -1
  95. package/src/lib/components/log-activity-dialog.js +43 -3
  96. package/src/lib/components/log-activity-dialog.js.map +1 -1
  97. package/src/lib/components/new-contact-drawer.d.ts +8 -0
  98. package/src/lib/components/new-contact-drawer.js +108 -6
  99. package/src/lib/components/new-contact-drawer.js.map +1 -1
  100. package/src/lib/components/new-lead-drawer.d.ts +9 -2
  101. package/src/lib/components/new-lead-drawer.js +88 -121
  102. package/src/lib/components/new-lead-drawer.js.map +1 -1
  103. package/src/lib/components/picklist-select.d.ts +36 -0
  104. package/src/lib/components/picklist-select.js +114 -0
  105. package/src/lib/components/picklist-select.js.map +1 -0
  106. package/src/lib/components/picklist-values-card.d.ts +34 -0
  107. package/src/lib/components/{lead-source-values-card.js → picklist-values-card.js} +241 -58
  108. package/src/lib/components/picklist-values-card.js.map +1 -0
  109. package/src/lib/components/pipeline-stages-dialog.d.ts +7 -0
  110. package/src/lib/components/pipeline-stages-dialog.js +26 -4
  111. package/src/lib/components/pipeline-stages-dialog.js.map +1 -1
  112. package/src/lib/components/pipelines-dialog.js +15 -6
  113. package/src/lib/components/pipelines-dialog.js.map +1 -1
  114. package/src/lib/components/recent-activity-feed.js +20 -5
  115. package/src/lib/components/recent-activity-feed.js.map +1 -1
  116. package/src/lib/components/recipes-card.js +4 -2
  117. package/src/lib/components/recipes-card.js.map +1 -1
  118. package/src/lib/components/record-tasks-card.js +15 -8
  119. package/src/lib/components/record-tasks-card.js.map +1 -1
  120. package/src/lib/components/reports/forecast-card.d.ts +6 -0
  121. package/src/lib/components/reports/forecast-card.js +101 -3
  122. package/src/lib/components/reports/forecast-card.js.map +1 -1
  123. package/src/lib/components/reports/lead-funnel-card.d.ts +12 -0
  124. package/src/lib/components/reports/lead-funnel-card.js +9 -5
  125. package/src/lib/components/reports/lead-funnel-card.js.map +1 -1
  126. package/src/lib/components/reports/lead-source-card.d.ts +23 -0
  127. package/src/lib/components/reports/lead-source-card.js +318 -0
  128. package/src/lib/components/reports/lead-source-card.js.map +1 -0
  129. package/src/lib/components/reports/pipeline-card.js +2 -1
  130. package/src/lib/components/reports/pipeline-card.js.map +1 -1
  131. package/src/lib/components/reports/report-export.js +1 -1
  132. package/src/lib/components/reports/report-export.js.map +1 -1
  133. package/src/lib/components/reports-section.js +8 -0
  134. package/src/lib/components/reports-section.js.map +1 -1
  135. package/src/lib/components/sharing-rule-drawer.d.ts +5 -0
  136. package/src/lib/components/sharing-rule-drawer.js +108 -19
  137. package/src/lib/components/sharing-rule-drawer.js.map +1 -1
  138. package/src/lib/components/sharing-rules-card.js +11 -3
  139. package/src/lib/components/sharing-rules-card.js.map +1 -1
  140. package/src/lib/components/task-cells.d.ts +9 -1
  141. package/src/lib/components/task-cells.js +9 -4
  142. package/src/lib/components/task-cells.js.map +1 -1
  143. package/src/lib/components/task-edit-drawer.js +111 -43
  144. package/src/lib/components/task-edit-drawer.js.map +1 -1
  145. package/src/lib/components/tasks-bulk-bar.d.ts +0 -3
  146. package/src/lib/components/tasks-bulk-bar.js +7 -20
  147. package/src/lib/components/tasks-bulk-bar.js.map +1 -1
  148. package/src/lib/components/tasks-calendar.d.ts +3 -0
  149. package/src/lib/components/tasks-calendar.js +8 -1
  150. package/src/lib/components/tasks-calendar.js.map +1 -1
  151. package/src/lib/components/tasks-section.d.ts +3 -3
  152. package/src/lib/components/tasks-section.js +58 -43
  153. package/src/lib/components/tasks-section.js.map +1 -1
  154. package/src/lib/constants/api-routes.d.ts +2 -9
  155. package/src/lib/constants/api-routes.js +1 -7
  156. package/src/lib/constants/api-routes.js.map +1 -1
  157. package/src/lib/constants/bundle-common.d.ts +6 -0
  158. package/src/lib/constants/bundle-common.js +11 -0
  159. package/src/lib/constants/bundle-common.js.map +1 -1
  160. package/src/lib/constants/company-filters.d.ts +14 -0
  161. package/src/lib/constants/company-filters.js +51 -1
  162. package/src/lib/constants/company-filters.js.map +1 -1
  163. package/src/lib/constants/contact-filters.d.ts +2 -0
  164. package/src/lib/constants/contact-filters.js +18 -1
  165. package/src/lib/constants/contact-filters.js.map +1 -1
  166. package/src/lib/constants/deal-filters.d.ts +22 -1
  167. package/src/lib/constants/deal-filters.js +67 -4
  168. package/src/lib/constants/deal-filters.js.map +1 -1
  169. package/src/lib/declarations.console-server.d.ts +3 -0
  170. package/src/lib/declarations.console-server.js +35 -0
  171. package/src/lib/declarations.console-server.js.map +1 -1
  172. package/src/lib/declarations.d.ts +26 -0
  173. package/src/lib/declarations.js +35 -0
  174. package/src/lib/declarations.js.map +1 -0
  175. package/src/lib/declarations.server.d.ts +11 -0
  176. package/src/lib/declarations.server.js +97 -1
  177. package/src/lib/declarations.server.js.map +1 -1
  178. package/src/lib/hooks/use-company-picklists.d.ts +15 -0
  179. package/src/lib/hooks/use-company-picklists.js +55 -0
  180. package/src/lib/hooks/use-company-picklists.js.map +1 -0
  181. package/src/lib/hooks/use-crm-picklist.d.ts +25 -0
  182. package/src/lib/hooks/use-crm-picklist.js +53 -0
  183. package/src/lib/hooks/use-crm-picklist.js.map +1 -0
  184. package/src/lib/hooks/use-crm-record-names.d.ts +16 -0
  185. package/src/lib/hooks/use-crm-record-names.js +45 -19
  186. package/src/lib/hooks/use-crm-record-names.js.map +1 -1
  187. package/src/lib/hooks/use-crm-task-picklists.d.ts +11 -0
  188. package/src/lib/hooks/use-crm-task-picklists.js +45 -0
  189. package/src/lib/hooks/use-crm-task-picklists.js.map +1 -0
  190. package/src/lib/hooks/use-deals.d.ts +14 -0
  191. package/src/lib/hooks/use-deals.js +29 -0
  192. package/src/lib/hooks/use-deals.js.map +1 -1
  193. package/src/lib/hooks/use-lead-picklists.d.ts +14 -0
  194. package/src/lib/hooks/use-lead-picklists.js +46 -0
  195. package/src/lib/hooks/use-lead-picklists.js.map +1 -0
  196. package/src/lib/hooks/use-lead-source-picklist.d.ts +5 -19
  197. package/src/lib/hooks/use-lead-source-picklist.js +12 -22
  198. package/src/lib/hooks/use-lead-source-picklist.js.map +1 -1
  199. package/src/lib/hooks/use-lead-status-picklist.d.ts +9 -0
  200. package/src/lib/hooks/use-lead-status-picklist.js +40 -0
  201. package/src/lib/hooks/use-lead-status-picklist.js.map +1 -0
  202. package/src/lib/model/companies.d.ts +32 -3
  203. package/src/lib/model/companies.js +133 -16
  204. package/src/lib/model/companies.js.map +1 -1
  205. package/src/lib/model/contact-merge.d.ts +27 -3
  206. package/src/lib/model/contact-merge.js +81 -7
  207. package/src/lib/model/contact-merge.js.map +1 -1
  208. package/src/lib/model/contact-record.d.ts +17 -0
  209. package/src/lib/model/contact-record.js +17 -2
  210. package/src/lib/model/contact-record.js.map +1 -1
  211. package/src/lib/model/contact-update.d.ts +31 -2
  212. package/src/lib/model/contact-update.js +14 -0
  213. package/src/lib/model/contact-update.js.map +1 -1
  214. package/src/lib/model/crm-list-query.d.ts +5 -0
  215. package/src/lib/model/crm-list-query.js +8 -0
  216. package/src/lib/model/crm-list-query.js.map +1 -1
  217. package/src/lib/model/crm-next-activity.d.ts +107 -0
  218. package/src/lib/model/crm-next-activity.js +140 -0
  219. package/src/lib/model/crm-next-activity.js.map +1 -0
  220. package/src/lib/model/crm-recipes.d.ts +40 -0
  221. package/src/lib/model/crm-recipes.js +259 -0
  222. package/src/lib/model/crm-recipes.js.map +1 -0
  223. package/src/lib/model/crm-record-counts.d.ts +36 -0
  224. package/src/lib/model/crm-record-counts.js +54 -0
  225. package/src/lib/model/crm-record-counts.js.map +1 -0
  226. package/src/lib/model/crm-record-lists.d.ts +23 -0
  227. package/src/lib/model/crm-record-lists.js +161 -0
  228. package/src/lib/model/crm-record-lists.js.map +1 -0
  229. package/src/lib/model/crm-reports.d.ts +73 -3
  230. package/src/lib/model/crm-reports.js +120 -1
  231. package/src/lib/model/crm-reports.js.map +1 -1
  232. package/src/lib/model/crm-sharing.d.ts +21 -3
  233. package/src/lib/model/crm-sharing.js +27 -6
  234. package/src/lib/model/crm-sharing.js.map +1 -1
  235. package/src/lib/model/crm-task-reminders.d.ts +152 -0
  236. package/src/lib/model/crm-task-reminders.js +161 -0
  237. package/src/lib/model/crm-task-reminders.js.map +1 -0
  238. package/src/lib/model/deal-board-model.d.ts +8 -2
  239. package/src/lib/model/deal-board-model.js +15 -2
  240. package/src/lib/model/deal-board-model.js.map +1 -1
  241. package/src/lib/model/deal-contact-roles.d.ts +45 -0
  242. package/src/lib/model/deal-contact-roles.js +73 -0
  243. package/src/lib/model/deal-contact-roles.js.map +1 -0
  244. package/src/lib/model/deal-form-model.d.ts +56 -0
  245. package/src/lib/model/deal-form-model.js +79 -7
  246. package/src/lib/model/deal-form-model.js.map +1 -1
  247. package/src/lib/model/download-text-file.d.ts +23 -0
  248. package/src/lib/model/download-text-file.js +34 -0
  249. package/src/lib/model/download-text-file.js.map +1 -0
  250. package/src/lib/model/lead-filters.d.ts +36 -2
  251. package/src/lib/model/lead-filters.js +123 -2
  252. package/src/lib/model/lead-filters.js.map +1 -1
  253. package/src/lib/model/lead-source-direction.d.ts +38 -0
  254. package/src/lib/model/lead-source-direction.js +52 -0
  255. package/src/lib/model/lead-source-direction.js.map +1 -0
  256. package/src/lib/model/next-activity.d.ts +1 -1
  257. package/src/lib/model/next-activity.js.map +1 -1
  258. package/src/lib/model/picklist-values.d.ts +119 -0
  259. package/src/lib/model/picklist-values.js +256 -0
  260. package/src/lib/model/picklist-values.js.map +1 -0
  261. package/src/lib/model/record-facts-disclosed.d.ts +81 -0
  262. package/src/lib/model/record-facts-disclosed.js +281 -0
  263. package/src/lib/model/record-facts-disclosed.js.map +1 -0
  264. package/src/lib/model/record-facts.d.ts +215 -34
  265. package/src/lib/model/record-facts.js +307 -128
  266. package/src/lib/model/record-facts.js.map +1 -1
  267. package/src/lib/model/task-picklists.d.ts +52 -0
  268. package/src/lib/model/task-picklists.js +83 -0
  269. package/src/lib/model/task-picklists.js.map +1 -0
  270. package/src/lib/model/task-routes.d.ts +13 -0
  271. package/src/lib/model/task-routes.js +23 -4
  272. package/src/lib/model/task-routes.js.map +1 -1
  273. package/src/lib/plan-entitlements.js +6 -4
  274. package/src/lib/plan-entitlements.js.map +1 -1
  275. package/src/lib/plugin.js +17 -0
  276. package/src/lib/plugin.js.map +1 -1
  277. package/src/lib/server/api-v1/contacts.js +220 -14
  278. package/src/lib/server/api-v1/contacts.js.map +1 -1
  279. package/src/lib/server/api-v1/crm-activities.js +14 -1
  280. package/src/lib/server/api-v1/crm-activities.js.map +1 -1
  281. package/src/lib/server/api-v1/crm-companies.js +123 -14
  282. package/src/lib/server/api-v1/crm-companies.js.map +1 -1
  283. package/src/lib/server/api-v1/crm-deals.js +291 -26
  284. package/src/lib/server/api-v1/crm-deals.js.map +1 -1
  285. package/src/lib/server/api-v1/crm-leads.js +144 -38
  286. package/src/lib/server/api-v1/crm-leads.js.map +1 -1
  287. package/src/lib/server/api-v1/crm-pipelines.d.ts +6 -0
  288. package/src/lib/server/api-v1/crm-pipelines.js +8 -2
  289. package/src/lib/server/api-v1/crm-pipelines.js.map +1 -1
  290. package/src/lib/server/api-v1/crm-tasks.js +78 -34
  291. package/src/lib/server/api-v1/crm-tasks.js.map +1 -1
  292. package/src/lib/server/api-v1/openapi.d.ts +0 -11
  293. package/src/lib/server/api-v1/openapi.js +171 -16
  294. package/src/lib/server/api-v1/openapi.js.map +1 -1
  295. package/src/lib/server/assign-contact-owner.d.ts +188 -0
  296. package/src/lib/server/assign-contact-owner.js +446 -0
  297. package/src/lib/server/assign-contact-owner.js.map +1 -0
  298. package/src/lib/server/associate-company-by-domain.d.ts +70 -0
  299. package/src/lib/server/associate-company-by-domain.js +153 -0
  300. package/src/lib/server/associate-company-by-domain.js.map +1 -0
  301. package/src/lib/server/automation-steps.d.ts +140 -0
  302. package/src/lib/server/automation-steps.js +669 -0
  303. package/src/lib/server/automation-steps.js.map +1 -0
  304. package/src/lib/server/capture-contact.d.ts +17 -0
  305. package/src/lib/server/capture-contact.js +95 -26
  306. package/src/lib/server/capture-contact.js.map +1 -1
  307. package/src/lib/server/capture-host-contact.d.ts +104 -0
  308. package/src/lib/server/capture-host-contact.js +151 -0
  309. package/src/lib/server/capture-host-contact.js.map +1 -0
  310. package/src/lib/server/company-children.d.ts +25 -0
  311. package/src/lib/server/company-children.js +42 -0
  312. package/src/lib/server/company-children.js.map +1 -0
  313. package/src/lib/server/company-delete.d.ts +18 -0
  314. package/src/lib/server/company-delete.js +44 -21
  315. package/src/lib/server/company-delete.js.map +1 -1
  316. package/src/lib/server/contact-email-history.js +21 -19
  317. package/src/lib/server/contact-email-history.js.map +1 -1
  318. package/src/lib/server/contact-remove.js +27 -2
  319. package/src/lib/server/contact-remove.js.map +1 -1
  320. package/src/lib/server/contact-reports-to.d.ts +61 -0
  321. package/src/lib/server/contact-reports-to.js +114 -0
  322. package/src/lib/server/contact-reports-to.js.map +1 -0
  323. package/src/lib/server/contact-update.d.ts +42 -1
  324. package/src/lib/server/contact-update.js +204 -23
  325. package/src/lib/server/contact-update.js.map +1 -1
  326. package/src/lib/server/convert-host-lead.d.ts +46 -1
  327. package/src/lib/server/convert-host-lead.js +173 -15
  328. package/src/lib/server/convert-host-lead.js.map +1 -1
  329. package/src/lib/server/convert-open-lead.js +12 -5
  330. package/src/lib/server/convert-open-lead.js.map +1 -1
  331. package/src/lib/server/crm-email-activity.d.ts +118 -0
  332. package/src/lib/server/crm-email-activity.js +148 -0
  333. package/src/lib/server/crm-email-activity.js.map +1 -0
  334. package/src/lib/server/crm-inbound-email.js +1 -1
  335. package/src/lib/server/crm-inbound-email.js.map +1 -1
  336. package/src/lib/server/crm-next-activity.d.ts +74 -0
  337. package/src/lib/server/crm-next-activity.js +194 -0
  338. package/src/lib/server/crm-next-activity.js.map +1 -0
  339. package/src/lib/server/crm-record-indexes.d.ts +45 -0
  340. package/src/lib/server/crm-record-indexes.js +78 -0
  341. package/src/lib/server/crm-record-indexes.js.map +1 -0
  342. package/src/lib/server/crm-sharing.d.ts +9 -1
  343. package/src/lib/server/crm-sharing.js +23 -3
  344. package/src/lib/server/crm-sharing.js.map +1 -1
  345. package/src/lib/server/deal-contact-roles.d.ts +27 -0
  346. package/src/lib/server/deal-contact-roles.js +89 -0
  347. package/src/lib/server/deal-contact-roles.js.map +1 -0
  348. package/src/lib/server/email-send.js +2 -1
  349. package/src/lib/server/email-send.js.map +1 -1
  350. package/src/lib/server/lead-convert.d.ts +5 -0
  351. package/src/lib/server/lead-convert.js +19 -3
  352. package/src/lib/server/lead-convert.js.map +1 -1
  353. package/src/lib/server/lead-create.d.ts +17 -2
  354. package/src/lib/server/lead-create.js +46 -14
  355. package/src/lib/server/lead-create.js.map +1 -1
  356. package/src/lib/server/lead-nurturing.d.ts +6 -0
  357. package/src/lib/server/lead-nurturing.js +57 -20
  358. package/src/lib/server/lead-nurturing.js.map +1 -1
  359. package/src/lib/server/lead-picklists.d.ts +35 -0
  360. package/src/lib/server/lead-picklists.js +52 -0
  361. package/src/lib/server/lead-picklists.js.map +1 -0
  362. package/src/lib/server/lead-source-picklist.d.ts +1 -13
  363. package/src/lib/server/lead-source-picklist.js +6 -33
  364. package/src/lib/server/lead-source-picklist.js.map +1 -1
  365. package/src/lib/server/merge-contacts.js +23 -5
  366. package/src/lib/server/merge-contacts.js.map +1 -1
  367. package/src/lib/server/next-activity-routes.js +2 -1
  368. package/src/lib/server/next-activity-routes.js.map +1 -1
  369. package/src/lib/server/person-eraser.d.ts +53 -0
  370. package/src/lib/server/person-eraser.js +149 -0
  371. package/src/lib/server/person-eraser.js.map +1 -0
  372. package/src/lib/server/person-records.d.ts +69 -0
  373. package/src/lib/server/person-records.js +317 -0
  374. package/src/lib/server/person-records.js.map +1 -0
  375. package/src/lib/server/person-refund.d.ts +97 -0
  376. package/src/lib/server/person-refund.js +221 -0
  377. package/src/lib/server/person-refund.js.map +1 -0
  378. package/src/lib/server/picklist-values.d.ts +21 -0
  379. package/src/lib/server/picklist-values.js +308 -0
  380. package/src/lib/server/picklist-values.js.map +1 -0
  381. package/src/lib/server/read-picklist.d.ts +44 -0
  382. package/src/lib/server/read-picklist.js +65 -0
  383. package/src/lib/server/read-picklist.js.map +1 -0
  384. package/src/lib/server/recipe-routes.js +22 -8
  385. package/src/lib/server/recipe-routes.js.map +1 -1
  386. package/src/lib/server/record-email-state.js +7 -1
  387. package/src/lib/server/record-email-state.js.map +1 -1
  388. package/src/lib/server/record-facts.d.ts +3 -0
  389. package/src/lib/server/record-facts.js +233 -31
  390. package/src/lib/server/record-facts.js.map +1 -1
  391. package/src/lib/server/record-origin.d.ts +27 -0
  392. package/src/lib/server/record-origin.js +104 -0
  393. package/src/lib/server/record-origin.js.map +1 -0
  394. package/src/lib/server/record-timeline.js +40 -3
  395. package/src/lib/server/record-timeline.js.map +1 -1
  396. package/src/lib/server/suite-gate.js +4 -3
  397. package/src/lib/server/suite-gate.js.map +1 -1
  398. package/src/lib/server/task-reminders-route.js +2 -1
  399. package/src/lib/server/task-reminders-route.js.map +1 -1
  400. package/src/lib/server/task-routes.js +33 -17
  401. package/src/lib/server/task-routes.js.map +1 -1
  402. package/src/lib/server-deal-stage.d.ts +5 -1
  403. package/src/lib/server-deal-stage.js +10 -5
  404. package/src/lib/server-deal-stage.js.map +1 -1
  405. package/src/lib/server.d.ts +8 -3
  406. package/src/lib/server.js +47 -43
  407. package/src/lib/server.js.map +1 -1
  408. package/src/lib/testing/memory-firestore.d.ts +55 -0
  409. package/src/lib/testing/memory-firestore.js +335 -0
  410. package/src/lib/testing/memory-firestore.js.map +1 -0
  411. package/src/lib/testing/stand-in-email-send-index.d.ts +25 -0
  412. package/src/lib/testing/stand-in-email-send-index.js +49 -0
  413. package/src/lib/testing/stand-in-email-send-index.js.map +1 -0
  414. package/src/lib/transfer/activities.d.ts +30 -0
  415. package/src/lib/transfer/activities.js +132 -0
  416. package/src/lib/transfer/activities.js.map +1 -0
  417. package/src/lib/transfer/aliases.d.ts +22 -0
  418. package/src/lib/transfer/aliases.js +1342 -0
  419. package/src/lib/transfer/aliases.js.map +1 -0
  420. package/src/lib/transfer/common.d.ts +222 -0
  421. package/src/lib/transfer/common.js +832 -0
  422. package/src/lib/transfer/common.js.map +1 -0
  423. package/src/lib/transfer/companies.d.ts +43 -0
  424. package/src/lib/transfer/companies.js +549 -0
  425. package/src/lib/transfer/companies.js.map +1 -0
  426. package/src/lib/transfer/contacts.d.ts +31 -0
  427. package/src/lib/transfer/contacts.js +727 -0
  428. package/src/lib/transfer/contacts.js.map +1 -0
  429. package/src/lib/transfer/deals.d.ts +66 -0
  430. package/src/lib/transfer/deals.js +698 -0
  431. package/src/lib/transfer/deals.js.map +1 -0
  432. package/src/lib/transfer/email-templates-package.d.ts +40 -0
  433. package/src/lib/transfer/email-templates-package.js +76 -0
  434. package/src/lib/transfer/email-templates-package.js.map +1 -0
  435. package/src/lib/transfer/email-templates-package.server.d.ts +32 -0
  436. package/src/lib/transfer/email-templates-package.server.js +176 -0
  437. package/src/lib/transfer/email-templates-package.server.js.map +1 -0
  438. package/src/lib/transfer/fields.d.ts +102 -0
  439. package/src/lib/transfer/fields.js +1755 -0
  440. package/src/lib/transfer/fields.js.map +1 -0
  441. package/src/lib/transfer/leads.d.ts +30 -0
  442. package/src/lib/transfer/leads.js +582 -0
  443. package/src/lib/transfer/leads.js.map +1 -0
  444. package/src/lib/transfer/pipelines.d.ts +21 -0
  445. package/src/lib/transfer/pipelines.js +172 -0
  446. package/src/lib/transfer/pipelines.js.map +1 -0
  447. package/src/lib/transfer/register.d.ts +47 -0
  448. package/src/lib/transfer/register.js +277 -0
  449. package/src/lib/transfer/register.js.map +1 -0
  450. package/src/lib/transfer/tasks.d.ts +30 -0
  451. package/src/lib/transfer/tasks.js +418 -0
  452. package/src/lib/transfer/tasks.js.map +1 -0
  453. package/src/lib/transfer/ui.d.ts +20 -0
  454. package/src/lib/transfer/ui.js +42 -0
  455. package/src/lib/transfer/ui.js.map +1 -0
  456. package/src/lib/components/company-import-drawer.d.ts +0 -42
  457. package/src/lib/components/company-import-drawer.js +0 -99
  458. package/src/lib/components/company-import-drawer.js.map +0 -1
  459. package/src/lib/components/contact-import-drawer.d.ts +0 -46
  460. package/src/lib/components/contact-import-drawer.js +0 -149
  461. package/src/lib/components/contact-import-drawer.js.map +0 -1
  462. package/src/lib/components/crm-export-all-button.d.ts +0 -39
  463. package/src/lib/components/crm-export-all-button.js +0 -98
  464. package/src/lib/components/crm-export-all-button.js.map +0 -1
  465. package/src/lib/components/csv-import-drawer.d.ts +0 -139
  466. package/src/lib/components/csv-import-drawer.js +0 -757
  467. package/src/lib/components/csv-import-drawer.js.map +0 -1
  468. package/src/lib/components/deal-import-drawer.d.ts +0 -24
  469. package/src/lib/components/deal-import-drawer.js +0 -83
  470. package/src/lib/components/deal-import-drawer.js.map +0 -1
  471. package/src/lib/components/lead-import-drawer.d.ts +0 -27
  472. package/src/lib/components/lead-import-drawer.js +0 -118
  473. package/src/lib/components/lead-import-drawer.js.map +0 -1
  474. package/src/lib/components/lead-source-values-card.d.ts +0 -27
  475. package/src/lib/components/lead-source-values-card.js.map +0 -1
  476. package/src/lib/components/task-import-drawer.d.ts +0 -24
  477. package/src/lib/components/task-import-drawer.js +0 -82
  478. package/src/lib/components/task-import-drawer.js.map +0 -1
  479. package/src/lib/model/companies-csv.d.ts +0 -36
  480. package/src/lib/model/companies-csv.js +0 -38
  481. package/src/lib/model/companies-csv.js.map +0 -1
  482. package/src/lib/model/contacts-csv.d.ts +0 -54
  483. package/src/lib/model/contacts-csv.js +0 -67
  484. package/src/lib/model/contacts-csv.js.map +0 -1
  485. package/src/lib/model/crm-company-import.d.ts +0 -154
  486. package/src/lib/model/crm-company-import.js +0 -331
  487. package/src/lib/model/crm-company-import.js.map +0 -1
  488. package/src/lib/model/crm-csv.d.ts +0 -239
  489. package/src/lib/model/crm-csv.js +0 -467
  490. package/src/lib/model/crm-csv.js.map +0 -1
  491. package/src/lib/model/crm-deal-import.d.ts +0 -112
  492. package/src/lib/model/crm-deal-import.js +0 -263
  493. package/src/lib/model/crm-deal-import.js.map +0 -1
  494. package/src/lib/model/crm-import.d.ts +0 -250
  495. package/src/lib/model/crm-import.js +0 -467
  496. package/src/lib/model/crm-import.js.map +0 -1
  497. package/src/lib/model/crm-lead-import.d.ts +0 -138
  498. package/src/lib/model/crm-lead-import.js +0 -446
  499. package/src/lib/model/crm-lead-import.js.map +0 -1
  500. package/src/lib/model/crm-task-import.d.ts +0 -94
  501. package/src/lib/model/crm-task-import.js +0 -275
  502. package/src/lib/model/crm-task-import.js.map +0 -1
  503. package/src/lib/model/deals-csv.d.ts +0 -32
  504. package/src/lib/model/deals-csv.js +0 -36
  505. package/src/lib/model/deals-csv.js.map +0 -1
  506. package/src/lib/model/import-column-shapes.d.ts +0 -36
  507. package/src/lib/model/import-column-shapes.js +0 -76
  508. package/src/lib/model/import-column-shapes.js.map +0 -1
  509. package/src/lib/model/lead-source-values.d.ts +0 -82
  510. package/src/lib/model/lead-source-values.js +0 -149
  511. package/src/lib/model/lead-source-values.js.map +0 -1
  512. package/src/lib/model/leads-csv.d.ts +0 -40
  513. package/src/lib/model/leads-csv.js +0 -40
  514. package/src/lib/model/leads-csv.js.map +0 -1
  515. package/src/lib/model/tasks-csv.d.ts +0 -28
  516. package/src/lib/model/tasks-csv.js +0 -28
  517. package/src/lib/model/tasks-csv.js.map +0 -1
  518. package/src/lib/server/companies-import.d.ts +0 -57
  519. package/src/lib/server/companies-import.js +0 -242
  520. package/src/lib/server/companies-import.js.map +0 -1
  521. package/src/lib/server/contacts-import.d.ts +0 -109
  522. package/src/lib/server/contacts-import.js +0 -393
  523. package/src/lib/server/contacts-import.js.map +0 -1
  524. package/src/lib/server/deals-import.d.ts +0 -76
  525. package/src/lib/server/deals-import.js +0 -248
  526. package/src/lib/server/deals-import.js.map +0 -1
  527. package/src/lib/server/export-route.d.ts +0 -60
  528. package/src/lib/server/export-route.js +0 -447
  529. package/src/lib/server/export-route.js.map +0 -1
  530. package/src/lib/server/import-context.d.ts +0 -87
  531. package/src/lib/server/import-context.js +0 -182
  532. package/src/lib/server/import-context.js.map +0 -1
  533. package/src/lib/server/lead-source-values.d.ts +0 -50
  534. package/src/lib/server/lead-source-values.js +0 -191
  535. package/src/lib/server/lead-source-values.js.map +0 -1
  536. package/src/lib/server/leads-import.d.ts +0 -84
  537. package/src/lib/server/leads-import.js +0 -367
  538. package/src/lib/server/leads-import.js.map +0 -1
  539. package/src/lib/server/tasks-import.d.ts +0 -54
  540. package/src/lib/server/tasks-import.js +0 -160
  541. package/src/lib/server/tasks-import.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../../libs/plugins/crm/src/lib/components/lead-properties-card.tsx"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n'use client'\n\nimport * as Aglyn from '@aglyn/aglyn'\nimport type {\n AglynOrgBilling,\n ConsentGroup,\n CrmLeadFields,\n CrmLeadProfilePatch,\n CrmLeadStatus,\n} from '@aglyn/aglyn'\nimport { mdiAccountCancelOutline } from '@aglyn/shared-data-mdi'\nimport { AppLink, CardDisplay, MdiIcon } from '@aglyn/shared-ui-jsx'\nimport type { RowActionsMenuItem } from '@aglyn/shared-ui-jsx/components/row-actions-menu.component'\nimport { useSnackbar } from '@aglyn/shared-ui-snackstack'\nimport {\n type FirestoreDocStatus,\n useFirestore,\n writeGuardedBySeed,\n} from '@aglyn/tenant-feature-instance'\nimport {\n Alert,\n Button,\n FormControl,\n InputLabel,\n MenuItem,\n Select,\n Stack,\n TextField,\n Tooltip,\n Typography,\n} from '@mui/material'\nimport { deleteField, doc, serverTimestamp, updateDoc } from 'firebase/firestore'\nimport { useEffect, useId, useMemo, useState } from 'react'\nimport { useContactFieldDefinitions } from '../hooks/use-contact-field-definitions'\nimport { useLeadSourcePicklist } from '../hooks/use-lead-source-picklist'\nimport {\n crmCustomDraftChanges,\n type CrmCustomDraft,\n crmCustomDraftMissingRequired,\n crmCustomDraftValue,\n crmCustomDraftWrites,\n} from '../model/crm-custom-draft'\nimport { CrmCustomFieldControl } from './crm-custom-field-control'\nimport { crmRoutes } from '../model/crm-routes'\nimport {\n addressDraftFrom,\n ContactAddressFields,\n type AddressDraft,\n} from './contact-address-fields'\nimport { CrmCallButton, CrmPhoneLink } from './crm-call-actions'\nimport { CrmEmailStateChip } from './crm-email-state-chip'\nimport { CrmEmailGatewayChip } from './crm-email-check'\nimport { CrmRecordChip, CrmRecordHeader } from './crm-record-header'\nimport { CrmSendEmailButton } from './crm-send-email-button'\nimport type { OrgMemberOptions } from '../hooks/use-org-member-options'\nimport { LeadOwnerSelect } from './lead-owner-select'\nimport { LeadSourceSelect } from './lead-source-select'\nimport { LeadStatusChip } from './lead-status-chip'\nimport { crmClientListFields, CRM_CLIENT_SEARCH_FIELDS } from '../model/crm-list-query'\nimport { useCrmSharingFollowUp } from '../hooks/use-crm-sharing'\n\n/** The Leads list's fields a profile save rewrites; the verdict key is the server's. */\nconst LEAD_CLIENT_LIST_FIELDS = [...CRM_CLIENT_SEARCH_FIELDS, 'leadSourceKey'] as const\n\nconst NOTES_MAX = Aglyn.CRM_LEAD_NOTES_MAX\nconst TEXT_MAX = Aglyn.CRM_LEAD_TEXT_MAX\n\n/** The profile as the form holds it: every field a string, the address a draft. */\ninterface ProfileDraft {\n company: string\n jobTitle: string\n phone: string\n website: string\n leadSource: string\n tags: string\n address: AddressDraft\n}\n\n/** The stored profile as a draft the fields can edit. */\nfunction profileDraftFrom(lead: Record<string, unknown> & CrmLeadFields): ProfileDraft {\n return {\n company: String(lead.company ?? ''),\n jobTitle: String(lead.jobTitle ?? ''),\n phone: String(lead.phone ?? lead['phone'] ?? ''),\n website: String(lead.website ?? ''),\n leadSource: String(lead.leadSource ?? ''),\n tags: (lead.tags ?? []).join(', '),\n address: addressDraftFrom(lead.address ?? null),\n }\n}\n\n/** The patch as the document takes it: a cleared field is deleted, not blanked. */\nfunction profileWrite(patch: CrmLeadProfilePatch): Record<string, unknown> {\n const write: Record<string, unknown> = {}\n for (const [key, value] of Object.entries(patch)) {\n if (value === undefined) continue\n write[key] = value === null ? deleteField() : value\n }\n return write\n}\n\n/**\n * Why Convert is refused while an erasure waits on the person — the same\n * sentence shape the overflow's items carry, so the two read as one state.\n */\nexport const CONVERT_PENDING_ERASURE_REASON = 'An erasure is pending for this person'\n\n/** A label over a value — the record page's one row shape. */\nfunction Fact(props: { label: string; children: React.ReactNode }) {\n return (\n <Stack spacing={0.25}>\n <Typography variant=\"caption\" color=\"text.secondary\">\n {props.label}\n </Typography>\n <Typography variant=\"body2\" component=\"div\">\n {props.children}\n </Typography>\n </Stack>\n )\n}\n\nexport interface LeadPropertiesCardProps {\n /**\n * The site this lead is acted on as — the mounted one, or at the\n * organization level the lead's own first capturing site (AGL-3278).\n * `null` for a lead no site has captured: the booking door, the call and\n * the email close, because each of them is one site's to offer.\n */\n hostId: string | null\n /**\n * The group the consent basis is read against (AGL-3278): the site's own\n * declared group, resolved by the page. Not `soloConsentGroup(hostId)`,\n * which is what this card used to spell and which cannot see a refusal\n * recorded against a sibling brand — three sites presenting as one sender\n * are one sender to the person unsubscribing from them.\n */\n consentGroup: ConsentGroup\n /**\n * The org the site belongs to, as the page already resolved it — the\n * custom lead fields are ORG-wide (AGL-3272), and a second lookup here\n * would be one more read per record page for an answer already in hand.\n */\n orgId: string | null\n leadId: string\n lead: Record<string, unknown> & CrmLeadFields\n leadStatus: FirestoreDocStatus\n /** The listener has not confirmed this document with the server yet. */\n fromCache: boolean\n basePath: string\n roster: OrgMemberOptions\n onConvert: () => void\n onUnqualify: () => void\n /**\n * Items the page adds to the overflow beside Unqualify — the privacy\n * erasure (AGL-2623) lives on the page, because it needs the workspace\n * role and the API, and this card owns the header it must appear in.\n */\n extraMenuItems?: RowActionsMenuItem[]\n /** What the page shows above the facts — the erasure-pending state. */\n banner?: React.ReactNode\n /**\n * Chips the page adds after the owner — the campaigns the lead is filed\n * under (AGL-3274), named from the containers the page reads once for\n * this header and the Campaigns card below it.\n */\n extraChips?: React.ReactNode\n /**\n * An erasure request is waiting on this person (AGL-2623). Convert stays\n * on the page but is refused with the reason, the way the overflow's items\n * are: a conversion filed now would reach the capture door only to be\n * refused there, and the lead itself goes when the request runs.\n */\n erasurePending?: boolean\n /**\n * The org the shell passed: the booking door reads whether the lead's site\n * runs Bookings and whether the plan is entitled to it (AGL-2660), and a\n * logged call reads the activity scope it belongs in (AGL-2661).\n */\n org?: Partial<AglynOrgBilling> | null\n}\n\n/**\n * What the team knows and decides about a lead: status, owner, notes, and\n * the identity and consent the capture recorded (AGL-2608).\n *\n * Two cards. The record's header carries the identity, the status and owner,\n * the consent the capture recorded and the record's actions. **Details**\n * under it carries the profile, the org's own lead fields under **More\n * fields**, and the notes — one card with one Save in its header, the way\n * Salesforce keeps a record's standard and custom fields in one Details\n * section.\n *\n * Status and owner are single-field client writes — the rules let a site\n * admin, editor or author update `hosts/{hostId}/leads`, and a one-field\n * `update` cannot roll anything else back. The details are drafts seeded\n * from the document, so their save goes through `writeGuardedBySeed`: a\n * draft edited over a cached read would otherwise overwrite a newer note or\n * profile with an older one.\n *\n * Converted leads are read-only here, but for the notes. Their status is the\n * conversion, and the header's actions become links to what the conversion\n * made.\n */\nexport function LeadPropertiesCard(props: LeadPropertiesCardProps) {\n const {\n hostId,\n consentGroup,\n orgId,\n leadId,\n lead,\n leadStatus,\n fromCache,\n basePath,\n roster,\n onConvert,\n onUnqualify,\n extraMenuItems = [],\n banner,\n extraChips,\n erasurePending = false,\n org,\n } = props\n const firestore = useFirestore()\n const { enqueueSnackbar } = useSnackbar()\n const routes = crmRoutes(basePath)\n // A client-direct write owes the org's sharing rules a re-evaluation (AGL-3336).\n const followUpSharing = useCrmSharingFollowUp(hostId, orgId)\n /*\n * Built at USE, not at render (AGL-3275). A lead is an org row, so the org\n * has to be known to address one — and `orgId` is null while the lookup\n * settles. Composing a ref from that null throws during render, which the\n * page shows as a 500 rather than as a card still loading.\n */\n const refFor = () => (orgId ? doc(firestore, 'orgs', orgId, 'leads', leadId) : null)\n const status = Aglyn.crmLeadStatus(lead)\n const converted = Boolean(lead.convertedContactId)\n const open = Aglyn.isCrmLeadOpen(lead) && !converted\n // The last verdict on the address (AGL-3245), as the platform stamped it.\n const emailState = Aglyn.readEmailState(lead)\n /** What a capture that took a number left on the document (AGL-2661). */\n const leadPhone = String(lead['phone'] ?? '').trim()\n\n const [notes, setNotes] = useState(String(lead.notes ?? ''))\n // The label's id, so the status combobox is named \"Status\" rather than\n // after the status it shows — see `LeadOwnerSelect`.\n const statusLabelId = useId()\n const [notesDirty, setNotesDirty] = useState(false)\n /*\n * THE LEAD'S OWN PROFILE (AGL-3231) — company, title, phone, website,\n * address, tags, lead source — edited in the Details card with the notes\n * and the custom fields, under one Save, the way the contact's Properties\n * card saves. Seeded from the document and guarded on save: a draft\n * edited over a cached read must not overwrite a newer profile with an\n * older one.\n */\n const [profile, setProfile] = useState<ProfileDraft>(() => profileDraftFrom(lead))\n const [profileDirty, setProfileDirty] = useState(false)\n const [saving, setSaving] = useState(false)\n const [profileErrors, setProfileErrors] = useState<Record<string, string>>({})\n useEffect(() => {\n if (!profileDirty) setProfile(profileDraftFrom(lead))\n // The draft follows the document until it is edited; the fields are\n // read one by one so a change to any of them reseeds.\n }, [\n profileDirty,\n lead.company,\n lead.jobTitle,\n lead.phone,\n lead.website,\n lead.leadSource,\n lead.tags,\n lead.address,\n ])\n /*\n * THE ORG'S OWN LEAD FIELDS (AGL-3272), edited under the same Save as\n * the profile: one button over one card, so a person filling a lead in\n * does not have to find two.\n *\n * The draft holds only the keys the reader touched, and Save writes the\n * difference as dotted paths — a `custom` map written whole would take\n * out every key this card did not show, which is what a retired field's\n * values and an integration's writes sit under.\n */\n const fields = useContactFieldDefinitions(orgId, 'lead')\n // The org's lead source values (AGL-3298), for the select below.\n const leadSources = useLeadSourcePicklist(orgId)\n const storedCustom = useMemo(() => lead.custom ?? {}, [lead.custom])\n const [custom, setCustom] = useState<CrmCustomDraft>({})\n\n const editProfile = <K extends keyof ProfileDraft>(key: K, value: ProfileDraft[K]) => {\n setProfile((current) => ({ ...current, [key]: value }))\n setProfileDirty(true)\n }\n // A newer note from the server replaces an UNEDITED draft; an edited one is\n // the reader's, and the guard on save decides whether it may land.\n useEffect(() => {\n if (!notesDirty) setNotes(String(lead.notes ?? ''))\n }, [lead.notes, notesDirty])\n\n /** One update of the lead, and whether it landed. */\n const write = async (fields: Record<string, unknown>, done: string): Promise<boolean> => {\n try {\n const ref = refFor()\n if (!ref) {\n enqueueSnackbar('Still loading this workspace — try again in a moment.', {\n variant: 'warning',\n persist: false,\n })\n return false\n }\n await updateDoc(ref, { ...fields, updatedAt: serverTimestamp() })\n followUpSharing('leads', [leadId])\n enqueueSnackbar(done, { variant: 'success', persist: false })\n return true\n } catch (error) {\n enqueueSnackbar(\n error instanceof Error ? error.message : 'The lead could not be updated.',\n { variant: 'error' },\n )\n return false\n }\n }\n\n /*\n * What Save is offered for: a profile field edited, a custom value that\n * differs from the stored map, or the notes. Touched-and-put-back does\n * not count for a custom value — the draft keeps the key either way, and\n * a Save that wrote nothing would still bump `updatedAt`.\n */\n const customChanged = crmCustomDraftChanges(storedCustom, custom).length > 0\n const dirty = profileDirty || customChanged || notesDirty\n\n /** Every draft back to what the document holds. */\n const discard = () => {\n setProfile(profileDraftFrom(lead))\n setProfileDirty(false)\n setProfileErrors({})\n setCustom({})\n setNotes(String(lead.notes ?? ''))\n setNotesDirty(false)\n }\n\n /*\n * The Details card's one Save: the profile and the custom values while\n * the lead is open, and the notes, in one update. A converted lead's\n * profile is the contact's now, so only its notes are written.\n */\n const saveDetails = async () => {\n const update: Record<string, unknown> = {}\n if (!converted && (profileDirty || customChanged)) {\n const { patch, errors } = Aglyn.normalizeCrmLeadProfile({\n company: profile.company,\n jobTitle: profile.jobTitle,\n phone: profile.phone,\n website: profile.website,\n leadSource: profile.leadSource,\n tags: profile.tags,\n address: profile.address,\n })\n setProfileErrors(errors)\n if (Object.keys(errors).length) return\n /*\n * A required field the reader CLEARED is refused; one the lead has\n * always lacked is not this save's to demand, or a field added after\n * the lead was captured would block every later edit to its company.\n */\n const missing = crmCustomDraftMissingRequired(\n fields.active,\n storedCustom,\n custom,\n 'edit',\n )\n if (missing.length) {\n enqueueSnackbar(`${missing.join(', ')} ${missing.length > 1 ? 'are' : 'is'} required.`, {\n variant: 'warning',\n })\n return\n }\n const profileFields = profileWrite(patch)\n Object.assign(\n update,\n profileFields,\n crmCustomDraftWrites(storedCustom, custom),\n // The company, title, tags and lead source are what the Leads list\n // searches and filters by (AGL-3321).\n crmClientListFields('leads', lead, profileFields, LEAD_CLIENT_LIST_FIELDS),\n )\n }\n if (notesDirty) update['notes'] = notes.trim().slice(0, NOTES_MAX)\n if (!Object.keys(update).length) return\n setSaving(true)\n let landed = false\n const verdict = await writeGuardedBySeed(\n { subject: 'lead', fromCache, unreadable: leadStatus === 'error' },\n async () => {\n landed = await write(update, 'Lead saved')\n },\n )\n setSaving(false)\n if (!verdict.ok) {\n enqueueSnackbar(verdict.message ?? 'The lead could not be saved.', {\n variant: 'warning',\n })\n return\n }\n if (!landed) return\n setProfileDirty(false)\n setNotesDirty(false)\n // The draft is spent: what it held is stored, and the controls read\n // the document again.\n setCustom({})\n }\n\n const consent = Aglyn.readMarketingBasis(lead, consentGroup)\n const consentLine =\n consent.basis === 'granted'\n ? `Opted in to marketing${\n consent.basisAtMs ? ` on ${new Date(consent.basisAtMs).toLocaleDateString()}` : ''\n }`\n : consent.basis === 'declined'\n ? 'Declined marketing'\n : 'No marketing consent recorded — this lead cannot be emailed marketing'\n\n return (\n <>\n <CrmRecordHeader\n kind=\"Lead\"\n title={String(lead['name'] || lead['email'] || leadId)}\n // The name is the heading; the address is the one line under it,\n // unless the address IS the name, in which case there is no second fact.\n subtitle={lead['name'] ? String(lead['email'] ?? '') : undefined}\n help={Aglyn.pluginDocsHelp('crmLeads', { anchor: '#working-a-lead-from-the-row' })}\n backHref={routes.section('leads')}\n backLabel=\"Back to leads\"\n // The booking door (AGL-2660), while the lead is still the record\n // being worked: once converted, the contact is where a meeting is\n // booked from, and the links below lead there.\n booking={converted ? undefined : { hostId, org, kind: 'lead', recordId: leadId }}\n actions={\n <>\n {/*\n Once converted, the lead's actions are the records the\n conversion made.\n */}\n {converted ? (\n <>\n <Button\n component={AppLink as any}\n {...({ componentVariant: 'naked', nativeButton: false } as any)}\n href={routes.contact(String(lead.convertedContactId))}\n size=\"small\"\n variant=\"outlined\"\n >\n {'Open contact'}\n </Button>\n {lead.companyId ? (\n <Button\n component={AppLink as any}\n {...({ componentVariant: 'naked', nativeButton: false } as any)}\n href={routes.company(lead.companyId)}\n size=\"small\"\n variant=\"outlined\"\n >\n {'Open company'}\n </Button>\n ) : null}\n {lead.dealId ? (\n <Button\n component={AppLink as any}\n {...({ componentVariant: 'naked', nativeButton: false } as any)}\n href={routes.deal(lead.dealId)}\n size=\"small\"\n variant=\"outlined\"\n >\n {'Open deal'}\n </Button>\n ) : null}\n </>\n ) : erasurePending ? (\n <Tooltip title={CONVERT_PENDING_ERASURE_REASON}>\n {/* A disabled button receives no pointer events, so the\n tooltip anchors on the span around it. */}\n <span>\n <Button size=\"small\" variant=\"contained\" disabled>\n {'Convert'}\n </Button>\n </span>\n </Tooltip>\n ) : (\n <Button size=\"small\" variant=\"contained\" onClick={onConvert}>\n {'Convert'}\n </Button>\n )}\n {/* Dial the number the capture carried, and log the call (AGL-2661). */}\n <CrmCallButton\n hostId={hostId}\n org={org}\n link={{ leadId }}\n phone={leadPhone}\n />\n <CrmSendEmailButton\n hostId={hostId}\n leadId={leadId}\n email={String(lead['email'] ?? '')}\n name={String(lead['name'] ?? '')}\n emailState={emailState}\n />\n </>\n }\n menuItems={[\n ...(open\n ? [\n {\n key: 'unqualify',\n label: 'Unqualify',\n icon: <MdiIcon path={mdiAccountCancelOutline.path} size={0.8} />,\n destructive: true,\n onClick: onUnqualify,\n } satisfies RowActionsMenuItem,\n ]\n : []),\n ...extraMenuItems,\n ]}\n chips={\n <>\n <LeadStatusChip lead={lead} />\n {/* The verdict on the address (AGL-3245), beside the status: a\n bounce does not move New or Working, but it is the first\n thing a person deciding whether to write must see. */}\n <CrmEmailStateChip state={emailState} />\n {/* The mail gateway in front of the address, and what it did\n with this site's mail this week (AGL-3328). */}\n <CrmEmailGatewayChip\n hostId={hostId}\n email={String(lead['email'] ?? '')}\n emailState={emailState}\n />\n <CrmRecordChip\n label=\"Owner\"\n value={lead.ownerUid ? roster.labelFor(lead.ownerUid) : undefined}\n />\n {extraChips}\n </>\n }\n >\n <Stack spacing={3}>\n {banner}\n {/*\n Only when the capture carried one (AGL-2661): the sign-up and\n booking doors write no phone, so a row for every lead would be a\n permanent blank. A form that captures one fills this.\n */}\n {leadPhone ? (\n <Fact label=\"Phone\">\n <CrmPhoneLink phone={leadPhone} />\n </Fact>\n ) : null}\n <Fact label=\"Marketing consent\">{consentLine}</Fact>\n <Stack direction={{ xs: 'column', md: 'row' }} spacing={2}>\n {converted ? (\n <Fact label=\"Status\">\n <Stack direction=\"row\" spacing={1} sx={{ alignItems: 'center' }}>\n <LeadStatusChip lead={lead} />\n <Typography variant=\"body2\" color=\"text.secondary\">\n {lead.convertedAtMs\n ? `Converted ${new Date(lead.convertedAtMs).toLocaleString()}`\n : 'Converted'}\n </Typography>\n </Stack>\n </Fact>\n ) : (\n <FormControl size=\"small\" sx={{ minWidth: 200 }}>\n <InputLabel id={statusLabelId}>{'Status'}</InputLabel>\n <Select\n labelId={statusLabelId}\n label=\"Status\"\n value={status === 'unqualified' ? 'unqualified' : status}\n onChange={(event) => {\n const next = String(event.target.value) as CrmLeadStatus\n if (next === 'unqualified') {\n onUnqualify()\n return\n }\n // Reopening drops the reason with the closed state: a lead\n // being worked again is not \"unqualified because …\".\n void write(\n {\n status: next,\n ...(status === 'unqualified' ? { unqualifiedReason: deleteField() } : {}),\n },\n 'Status updated',\n )\n }}\n >\n <MenuItem value=\"new\">{Aglyn.CRM_LEAD_STATUS_LABELS.new}</MenuItem>\n <MenuItem value=\"nurturing\">{Aglyn.CRM_LEAD_STATUS_LABELS.nurturing}</MenuItem>\n <MenuItem value=\"working\">{Aglyn.CRM_LEAD_STATUS_LABELS.working}</MenuItem>\n <MenuItem value=\"unqualified\">\n {`${Aglyn.CRM_LEAD_STATUS_LABELS.unqualified}…`}\n </MenuItem>\n </Select>\n </FormControl>\n )}\n <LeadOwnerSelect\n value={lead.ownerUid}\n roster={roster}\n fullWidth={false}\n onChange={(uid) =>\n void write({ ownerUid: uid || deleteField() }, uid ? 'Owner assigned' : 'Owner cleared')\n }\n />\n </Stack>\n {status === 'unqualified' && lead.unqualifiedReason ? (\n <Alert severity=\"info\">{`Unqualified: ${lead.unqualifiedReason}`}</Alert>\n ) : null}\n </Stack>\n </CrmRecordHeader>\n {/*\n The profile (AGL-3231), the org's own lead fields (AGL-3272) and the\n notes: what Salesforce keeps on a lead and hands to the contact and\n the account on convert. Read-only once converted — the contact is the\n record then, and the header's links lead there — but for the notes.\n */}\n <CardDisplay\n header={'Details'}\n help={Aglyn.pluginDocsHelp('crmLeads', { anchor: '#a-leads-page' })}\n contentGutterX\n contentGutterY\n HeaderProps={{\n action: (\n <Stack direction=\"row\" spacing={1}>\n {dirty ? (\n <Button size=\"small\" disabled={saving} onClick={discard}>\n {'Discard changes'}\n </Button>\n ) : null}\n <Button\n size=\"small\"\n variant=\"contained\"\n onClick={() => void saveDetails()}\n disabled={!dirty || saving}\n >\n {saving ? 'Saving…' : 'Save'}\n </Button>\n </Stack>\n ),\n }}\n >\n <Stack spacing={2}>\n <Stack direction={{ xs: 'column', md: 'row' }} spacing={2}>\n <TextField\n size=\"small\"\n label=\"Company\"\n value={profile.company}\n onChange={(event) => editProfile('company', event.target.value)}\n disabled={converted}\n slotProps={{ htmlInput: { maxLength: TEXT_MAX } }}\n fullWidth\n />\n <TextField\n size=\"small\"\n label=\"Job title\"\n value={profile.jobTitle}\n onChange={(event) => editProfile('jobTitle', event.target.value)}\n disabled={converted}\n slotProps={{ htmlInput: { maxLength: TEXT_MAX } }}\n fullWidth\n />\n </Stack>\n <Stack direction={{ xs: 'column', md: 'row' }} spacing={2}>\n <TextField\n size=\"small\"\n label=\"Phone\"\n value={profile.phone}\n onChange={(event) => editProfile('phone', event.target.value)}\n disabled={converted}\n error={Boolean(profileErrors['phone'])}\n helperText={profileErrors['phone'] || 'With the country code, like +1 512 555 0107'}\n fullWidth\n />\n <TextField\n size=\"small\"\n label=\"Website\"\n value={profile.website}\n onChange={(event) => editProfile('website', event.target.value)}\n disabled={converted}\n error={Boolean(profileErrors['website'])}\n helperText={profileErrors['website'] || 'Like acme.com'}\n fullWidth\n />\n </Stack>\n <Stack direction={{ xs: 'column', md: 'row' }} spacing={2}>\n {/* The org's own values (AGL-3298); the stored one stays shown when the list no longer offers it. */}\n <LeadSourceSelect\n picklist={leadSources.picklist}\n value={profile.leadSource}\n stored={String(lead.leadSource ?? '')}\n onChange={(label) => editProfile('leadSource', label)}\n disabled={converted}\n />\n <TextField\n size=\"small\"\n label=\"Tags\"\n value={profile.tags}\n onChange={(event) => editProfile('tags', event.target.value)}\n disabled={converted}\n helperText=\"Comma-separated\"\n fullWidth\n />\n </Stack>\n <Typography variant=\"caption\" color=\"text.secondary\">\n {'Address'}\n </Typography>\n <ContactAddressFields\n value={profile.address}\n onChange={(next) => editProfile('address', next)}\n disabled={converted}\n />\n {/*\n The org's own lead fields (AGL-3272), after the built-in ones\n because they describe the same record and save with it. Absent,\n not an empty box, while the org defines none.\n */}\n {fields.active.length ? (\n <>\n <Typography variant=\"subtitle2\">{'More fields'}</Typography>\n {fields.active.map((definition) => (\n <CrmCustomFieldControl\n key={definition.$id}\n definition={definition}\n value={crmCustomDraftValue(storedCustom, custom, definition.key)}\n onChange={(value) =>\n setCustom((current) => ({ ...current, [definition.key]: value }))\n }\n disabled={converted || saving}\n />\n ))}\n </>\n ) : null}\n <TextField\n size=\"small\"\n label=\"Notes\"\n value={notes}\n onChange={(event) => {\n setNotes(event.target.value)\n setNotesDirty(true)\n }}\n multiline\n minRows={3}\n fullWidth\n slotProps={{ htmlInput: { maxLength: NOTES_MAX } }}\n />\n </Stack>\n </CardDisplay>\n </>\n )\n}\nLeadPropertiesCard.displayName = 'LeadPropertiesCard'\n\nexport default LeadPropertiesCard\n"],"names":["Aglyn","mdiAccountCancelOutline","AppLink","CardDisplay","MdiIcon","useSnackbar","useFirestore","writeGuardedBySeed","Alert","Button","FormControl","InputLabel","MenuItem","Select","Stack","TextField","Tooltip","Typography","deleteField","doc","serverTimestamp","updateDoc","useEffect","useId","useMemo","useState","useContactFieldDefinitions","useLeadSourcePicklist","crmCustomDraftChanges","crmCustomDraftMissingRequired","crmCustomDraftValue","crmCustomDraftWrites","CrmCustomFieldControl","crmRoutes","addressDraftFrom","ContactAddressFields","CrmCallButton","CrmPhoneLink","CrmEmailStateChip","CrmEmailGatewayChip","CrmRecordChip","CrmRecordHeader","CrmSendEmailButton","LeadOwnerSelect","LeadSourceSelect","LeadStatusChip","crmClientListFields","CRM_CLIENT_SEARCH_FIELDS","useCrmSharingFollowUp","LEAD_CLIENT_LIST_FIELDS","NOTES_MAX","CRM_LEAD_NOTES_MAX","TEXT_MAX","CRM_LEAD_TEXT_MAX","profileDraftFrom","lead","company","String","jobTitle","phone","website","leadSource","tags","join","address","profileWrite","patch","write","key","value","Object","entries","undefined","CONVERT_PENDING_ERASURE_REASON","Fact","props","spacing","variant","color","label","component","children","LeadPropertiesCard","hostId","consentGroup","orgId","leadId","leadStatus","fromCache","basePath","roster","onConvert","onUnqualify","extraMenuItems","banner","extraChips","erasurePending","org","firestore","enqueueSnackbar","routes","followUpSharing","refFor","status","crmLeadStatus","converted","Boolean","convertedContactId","open","isCrmLeadOpen","emailState","readEmailState","leadPhone","trim","notes","setNotes","statusLabelId","notesDirty","setNotesDirty","profile","setProfile","profileDirty","setProfileDirty","saving","setSaving","profileErrors","setProfileErrors","fields","leadSources","storedCustom","custom","setCustom","editProfile","current","done","ref","persist","updatedAt","error","Error","message","customChanged","length","dirty","discard","saveDetails","update","errors","normalizeCrmLeadProfile","keys","missing","active","profileFields","assign","slice","landed","verdict","subject","unreadable","ok","consent","readMarketingBasis","consentLine","basis","basisAtMs","Date","toLocaleDateString","kind","title","subtitle","help","pluginDocsHelp","anchor","backHref","section","backLabel","booking","recordId","actions","componentVariant","nativeButton","href","contact","size","companyId","dealId","deal","span","disabled","onClick","link","email","name","menuItems","icon","path","destructive","chips","state","ownerUid","labelFor","direction","xs","md","sx","alignItems","convertedAtMs","toLocaleString","minWidth","id","labelId","onChange","event","next","target","unqualifiedReason","CRM_LEAD_STATUS_LABELS","new","nurturing","working","unqualified","fullWidth","uid","severity","header","contentGutterX","contentGutterY","HeaderProps","action","slotProps","htmlInput","maxLength","helperText","picklist","stored","map","definition","$id","multiline","minRows","displayName"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/crm/src/lib/components/lead-properties-card.tsx"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n'use client'\n\nimport * as Aglyn from '@aglyn/aglyn'\nimport type {\n AglynOrgBilling,\n ConsentGroup,\n CrmLeadFields,\n CrmLeadProfilePatch,\n} from '@aglyn/aglyn'\nimport { mdiAccountCancelOutline } from '@aglyn/shared-data-mdi'\nimport { AppLink, CardDisplay, MdiIcon } from '@aglyn/shared-ui-jsx'\nimport type { RowActionsMenuItem } from '@aglyn/shared-ui-jsx/components/row-actions-menu.component'\nimport { useSnackbar } from '@aglyn/shared-ui-snackstack'\nimport {\n type FirestoreDocStatus,\n useFirestore,\n writeGuardedBySeed,\n} from '@aglyn/tenant-feature-instance'\nimport {\n Alert,\n Button,\n FormControl,\n InputLabel,\n Select,\n Stack,\n TextField,\n Tooltip,\n Typography,\n} from '@mui/material'\nimport { deleteField, doc, serverTimestamp, updateDoc } from 'firebase/firestore'\nimport { useEffect, useId, useMemo, useState } from 'react'\nimport { useContactFieldDefinitions } from '../hooks/use-contact-field-definitions'\nimport { useLeadSourcePicklist } from '../hooks/use-lead-source-picklist'\nimport { useLeadStatusPicklist } from '../hooks/use-lead-status-picklist'\nimport { useLeadPicklists } from '../hooks/use-lead-picklists'\nimport {\n crmCustomDraftChanges,\n type CrmCustomDraft,\n crmCustomDraftMissingRequired,\n crmCustomDraftValue,\n crmCustomDraftWrites,\n} from '../model/crm-custom-draft'\nimport { CrmCustomFieldControl } from './crm-custom-field-control'\nimport { crmRoutes } from '../model/crm-routes'\nimport {\n LeadProfileFields,\n type LeadProfileDraft,\n leadProfileDraftBody,\n leadProfileDraftFrom,\n} from './lead-profile-fields'\nimport { CrmCallButton, CrmPhoneLink } from './crm-call-actions'\nimport { CrmEmailStateChip } from './crm-email-state-chip'\nimport { CrmEmailGatewayChip } from './crm-email-check'\nimport { CrmRecordChip, CrmRecordHeader } from './crm-record-header'\nimport { CrmSendEmailButton } from './crm-send-email-button'\nimport type { OrgMemberOptions } from '../hooks/use-org-member-options'\nimport { LeadOwnerSelect } from './lead-owner-select'\nimport { LeadStatusChip } from './lead-status-chip'\nimport { leadStatusChoices, leadStatusMenuItems } from './lead-status-options'\nimport { crmClientListFields, CRM_CLIENT_SEARCH_FIELDS } from '../model/crm-list-query'\nimport { useCrmSharingFollowUp } from '../hooks/use-crm-sharing'\n\n/** The Leads list's fields a profile save rewrites; the verdict key is the server's. */\nconst LEAD_CLIENT_LIST_FIELDS = [\n ...CRM_CLIENT_SEARCH_FIELDS,\n 'leadSourceKey',\n // Industry and Rating (AGL-3513).\n 'industryKey',\n 'ratingKey',\n] as const\n\nconst NOTES_MAX = Aglyn.CRM_LEAD_NOTES_MAX\n\n/** The patch as the document takes it: a cleared field is deleted, not blanked. */\nfunction profileWrite(patch: CrmLeadProfilePatch): Record<string, unknown> {\n const write: Record<string, unknown> = {}\n for (const [key, value] of Object.entries(patch)) {\n if (value === undefined) continue\n write[key] = value === null ? deleteField() : value\n }\n return write\n}\n\n/**\n * Why Convert is refused while an erasure waits on the person — the same\n * sentence shape the overflow's items carry, so the two read as one state.\n */\nexport const CONVERT_PENDING_ERASURE_REASON = 'An erasure is pending for this person'\n\n/** A label over a value — the record page's one row shape. */\nfunction Fact(props: { label: string; children: React.ReactNode }) {\n return (\n <Stack spacing={0.25}>\n <Typography variant=\"caption\" color=\"text.secondary\">\n {props.label}\n </Typography>\n <Typography variant=\"body2\" component=\"div\">\n {props.children}\n </Typography>\n </Stack>\n )\n}\n\nexport interface LeadPropertiesCardProps {\n /**\n * The site this lead is acted on as — the mounted one, or at the\n * organization level the lead's own first capturing site (AGL-3278).\n * `null` for a lead no site has captured: the booking door, the call and\n * the email close, because each of them is one site's to offer.\n */\n hostId: string | null\n /**\n * The group the consent basis is read against (AGL-3278): the site's own\n * declared group, resolved by the page. Not `soloConsentGroup(hostId)`,\n * which is what this card used to spell and which cannot see a refusal\n * recorded against a sibling brand — three sites presenting as one sender\n * are one sender to the person unsubscribing from them.\n */\n consentGroup: ConsentGroup\n /**\n * The org the site belongs to, as the page already resolved it — the\n * custom lead fields are ORG-wide (AGL-3272), and a second lookup here\n * would be one more read per record page for an answer already in hand.\n */\n orgId: string | null\n leadId: string\n lead: Record<string, unknown> & CrmLeadFields\n leadStatus: FirestoreDocStatus\n /** The listener has not confirmed this document with the server yet. */\n fromCache: boolean\n basePath: string\n roster: OrgMemberOptions\n onConvert: () => void\n /** Opens the Unqualify dialog — with the Unqualified value picked, when the status select named one. */\n onUnqualify: (statusLabel?: string) => void\n /**\n * Items the page adds to the overflow beside Unqualify — the privacy\n * erasure (AGL-2623) lives on the page, because it needs the workspace\n * role and the API, and this card owns the header it must appear in.\n */\n extraMenuItems?: RowActionsMenuItem[]\n /** What the page shows above the facts — the erasure-pending state. */\n banner?: React.ReactNode\n /**\n * Chips the page adds after the owner — the campaigns the lead is filed\n * under (AGL-3274), named from the containers the page reads once for\n * this header and the Campaigns card below it.\n */\n extraChips?: React.ReactNode\n /**\n * An erasure request is waiting on this person (AGL-2623). Convert stays\n * on the page but is refused with the reason, the way the overflow's items\n * are: a conversion filed now would reach the capture door only to be\n * refused there, and the lead itself goes when the request runs.\n */\n erasurePending?: boolean\n /**\n * The org the shell passed: the booking door reads whether the lead's site\n * runs Bookings and whether the plan is entitled to it (AGL-2660), and a\n * logged call reads the activity scope it belongs in (AGL-2661).\n */\n org?: Partial<AglynOrgBilling> | null\n}\n\n/**\n * What the team knows and decides about a lead: status, owner, notes, and\n * the identity and consent the capture recorded (AGL-2608).\n *\n * Two cards. The record's header carries the identity, the status and owner,\n * the consent the capture recorded and the record's actions. **Details**\n * under it carries the profile, the org's own lead fields under **More\n * fields**, and the notes — one card with one Save in its header, the way\n * Salesforce keeps a record's standard and custom fields in one Details\n * section.\n *\n * Status and owner are single-field client writes — the rules let a site\n * admin, editor or author update `hosts/{hostId}/leads`, and a one-field\n * `update` cannot roll anything else back. The details are drafts seeded\n * from the document, so their save goes through `writeGuardedBySeed`: a\n * draft edited over a cached read would otherwise overwrite a newer note or\n * profile with an older one.\n *\n * Converted leads are read-only here, but for the notes. Their status is the\n * conversion, and the header's actions become links to what the conversion\n * made.\n */\nexport function LeadPropertiesCard(props: LeadPropertiesCardProps) {\n const {\n hostId,\n consentGroup,\n orgId,\n leadId,\n lead,\n leadStatus,\n fromCache,\n basePath,\n roster,\n onConvert,\n onUnqualify,\n extraMenuItems = [],\n banner,\n extraChips,\n erasurePending = false,\n org,\n } = props\n const firestore = useFirestore()\n const { enqueueSnackbar } = useSnackbar()\n const routes = crmRoutes(basePath)\n // A client-direct write owes the org's sharing rules a re-evaluation (AGL-3336).\n const followUpSharing = useCrmSharingFollowUp(hostId, orgId)\n /*\n * Built at USE, not at render (AGL-3275). A lead is an org row, so the org\n * has to be known to address one — and `orgId` is null while the lookup\n * settles. Composing a ref from that null throws during render, which the\n * page shows as a 500 rather than as a card still loading.\n */\n const refFor = () => (orgId ? doc(firestore, 'orgs', orgId, 'leads', leadId) : null)\n const status = Aglyn.crmLeadStatus(lead)\n const converted = Boolean(lead.convertedContactId)\n const open = Aglyn.isCrmLeadOpen(lead) && !converted\n // The last verdict on the address (AGL-3245), as the platform stamped it.\n const emailState = Aglyn.readEmailState(lead)\n /** What a capture that took a number left on the document (AGL-2661). */\n const leadPhone = String(lead['phone'] ?? '').trim()\n const leadMobile = String(lead.mobilePhone ?? '').trim()\n // The person asked not to be phoned (AGL-3513): a hint on every dial control.\n const doNotCall = lead.doNotCall === true\n\n const [notes, setNotes] = useState(String(lead.notes ?? ''))\n // The label's id, so the status combobox is named \"Status\" rather than\n // after the status it shows — see `LeadOwnerSelect`.\n const statusLabelId = useId()\n const [notesDirty, setNotesDirty] = useState(false)\n /*\n * THE LEAD'S OWN PROFILE (AGL-3231, AGL-3513) — the name's parts,\n * company, title, the phones, website, address, tags, lead source,\n * industry, rating, size and revenue — edited in the Details card with\n * the notes and the custom fields, under one Save, the way the contact's\n * Properties card saves. Seeded from the document and guarded on save: a\n * draft edited over a cached read must not overwrite a newer profile\n * with an older one.\n */\n const [profile, setProfile] = useState<LeadProfileDraft>(() => leadProfileDraftFrom(lead))\n const [profileDirty, setProfileDirty] = useState(false)\n const [saving, setSaving] = useState(false)\n const [profileErrors, setProfileErrors] = useState<Record<string, string>>({})\n // The stored profile as one value, so a change to any of its fields reseeds.\n const profileSeed = JSON.stringify(Aglyn.CRM_LEAD_PROFILE_KEYS.map((key) => lead[key] ?? null))\n useEffect(() => {\n if (!profileDirty) setProfile(leadProfileDraftFrom(lead))\n // The draft follows the document until it is edited.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [profileDirty, profileSeed])\n /*\n * THE ORG'S OWN LEAD FIELDS (AGL-3272), edited under the same Save as\n * the profile: one button over one card, so a person filling a lead in\n * does not have to find two.\n *\n * The draft holds only the keys the reader touched, and Save writes the\n * difference as dotted paths — a `custom` map written whole would take\n * out every key this card did not show, which is what a retired field's\n * values and an integration's writes sit under.\n */\n const fields = useContactFieldDefinitions(orgId, 'lead')\n // The org's lead source values (AGL-3298), for the select below.\n const leadSources = useLeadSourcePicklist(orgId)\n // The org's lead status values (AGL-3512): the chip's words and the select's choices.\n const leadStatuses = useLeadStatusPicklist(orgId)\n // The org's Salutation, Industry and Rating lists (AGL-3513).\n const leadPicklists = useLeadPicklists(orgId)\n const statusChoices = useMemo(\n () => leadStatusChoices(leadStatuses.picklist, lead),\n [leadStatuses.picklist, lead],\n )\n const storedCustom = useMemo(() => lead.custom ?? {}, [lead.custom])\n const [custom, setCustom] = useState<CrmCustomDraft>({})\n\n const editProfile = <K extends keyof LeadProfileDraft>(key: K, value: LeadProfileDraft[K]) => {\n setProfile((current) => ({ ...current, [key]: value }))\n setProfileDirty(true)\n }\n // A newer note from the server replaces an UNEDITED draft; an edited one is\n // the reader's, and the guard on save decides whether it may land.\n useEffect(() => {\n if (!notesDirty) setNotes(String(lead.notes ?? ''))\n }, [lead.notes, notesDirty])\n\n /** One update of the lead, and whether it landed. */\n const write = async (fields: Record<string, unknown>, done: string): Promise<boolean> => {\n try {\n const ref = refFor()\n if (!ref) {\n enqueueSnackbar('Still loading this workspace — try again in a moment.', {\n variant: 'warning',\n persist: false,\n })\n return false\n }\n await updateDoc(ref, { ...fields, updatedAt: serverTimestamp() })\n followUpSharing('leads', [leadId])\n enqueueSnackbar(done, { variant: 'success', persist: false })\n return true\n } catch (error) {\n enqueueSnackbar(\n error instanceof Error ? error.message : 'The lead could not be updated.',\n { variant: 'error' },\n )\n return false\n }\n }\n\n /*\n * What Save is offered for: a profile field edited, a custom value that\n * differs from the stored map, or the notes. Touched-and-put-back does\n * not count for a custom value — the draft keeps the key either way, and\n * a Save that wrote nothing would still bump `updatedAt`.\n */\n const customChanged = crmCustomDraftChanges(storedCustom, custom).length > 0\n const dirty = profileDirty || customChanged || notesDirty\n\n /** Every draft back to what the document holds. */\n const discard = () => {\n setProfile(leadProfileDraftFrom(lead))\n setProfileDirty(false)\n setProfileErrors({})\n setCustom({})\n setNotes(String(lead.notes ?? ''))\n setNotesDirty(false)\n }\n\n /*\n * The Details card's one Save: the profile and the custom values while\n * the lead is open, and the notes, in one update. A converted lead's\n * profile is the contact's now, so only its notes are written.\n */\n const saveDetails = async () => {\n const update: Record<string, unknown> = {}\n if (!converted && (profileDirty || customChanged)) {\n const { body, revenueError } = leadProfileDraftBody(profile)\n const { patch, errors } = Aglyn.normalizeCrmLeadProfile(body)\n const shown: Record<string, string> = { ...errors }\n if (revenueError) shown['annualRevenueCents'] = revenueError\n setProfileErrors(shown)\n if (Object.keys(shown).length) return\n /*\n * A required field the reader CLEARED is refused; one the lead has\n * always lacked is not this save's to demand, or a field added after\n * the lead was captured would block every later edit to its company.\n */\n const missing = crmCustomDraftMissingRequired(\n fields.active,\n storedCustom,\n custom,\n 'edit',\n )\n if (missing.length) {\n enqueueSnackbar(`${missing.join(', ')} ${missing.length > 1 ? 'are' : 'is'} required.`, {\n variant: 'warning',\n })\n return\n }\n const profileFields = profileWrite(patch)\n // While a first or last name is set, the name is theirs (AGL-3513).\n const composed = Aglyn.crmLeadComposedName(lead, patch)\n if (composed && composed !== lead['name']) profileFields['name'] = composed\n Object.assign(\n update,\n profileFields,\n crmCustomDraftWrites(storedCustom, custom),\n // The company, title, tags and lead source are what the Leads list\n // searches and filters by (AGL-3321).\n crmClientListFields('leads', lead, profileFields, LEAD_CLIENT_LIST_FIELDS),\n )\n }\n if (notesDirty) update['notes'] = notes.trim().slice(0, NOTES_MAX)\n if (!Object.keys(update).length) return\n setSaving(true)\n let landed = false\n const verdict = await writeGuardedBySeed(\n { subject: 'lead', fromCache, unreadable: leadStatus === 'error' },\n async () => {\n landed = await write(update, 'Lead saved')\n },\n )\n setSaving(false)\n if (!verdict.ok) {\n enqueueSnackbar(verdict.message ?? 'The lead could not be saved.', {\n variant: 'warning',\n })\n return\n }\n if (!landed) return\n setProfileDirty(false)\n setNotesDirty(false)\n // The draft is spent: what it held is stored, and the controls read\n // the document again.\n setCustom({})\n }\n\n const consent = Aglyn.readMarketingBasis(lead, consentGroup)\n const consentLine =\n consent.basis === 'granted'\n ? `Opted in to marketing${\n consent.basisAtMs ? ` on ${new Date(consent.basisAtMs).toLocaleDateString()}` : ''\n }`\n : consent.basis === 'declined'\n ? 'Declined marketing'\n : 'No marketing consent recorded — this lead cannot be emailed marketing'\n\n return (\n <>\n <CrmRecordHeader\n kind=\"Lead\"\n title={String(lead['name'] || lead['email'] || leadId)}\n // The name is the heading; the address is the one line under it,\n // unless the address IS the name, in which case there is no second fact.\n subtitle={lead['name'] ? String(lead['email'] ?? '') : undefined}\n help={Aglyn.pluginDocsHelp('crmLeads', { anchor: '#working-a-lead-from-the-row' })}\n backHref={routes.section('leads')}\n backLabel=\"Back to leads\"\n // The booking door (AGL-2660), while the lead is still the record\n // being worked: once converted, the contact is where a meeting is\n // booked from, and the links below lead there.\n booking={converted ? undefined : { hostId, org, kind: 'lead', recordId: leadId }}\n actions={\n <>\n {/*\n Once converted, the lead's actions are the records the\n conversion made.\n */}\n {converted ? (\n <>\n <Button\n component={AppLink as any}\n {...({ componentVariant: 'naked', nativeButton: false } as any)}\n href={routes.contact(String(lead.convertedContactId))}\n size=\"small\"\n variant=\"outlined\"\n >\n {'Open contact'}\n </Button>\n {lead.companyId ? (\n <Button\n component={AppLink as any}\n {...({ componentVariant: 'naked', nativeButton: false } as any)}\n href={routes.company(lead.companyId)}\n size=\"small\"\n variant=\"outlined\"\n >\n {'Open company'}\n </Button>\n ) : null}\n {lead.dealId ? (\n <Button\n component={AppLink as any}\n {...({ componentVariant: 'naked', nativeButton: false } as any)}\n href={routes.deal(lead.dealId)}\n size=\"small\"\n variant=\"outlined\"\n >\n {'Open deal'}\n </Button>\n ) : null}\n </>\n ) : erasurePending ? (\n <Tooltip title={CONVERT_PENDING_ERASURE_REASON}>\n {/* A disabled button receives no pointer events, so the\n tooltip anchors on the span around it. */}\n <span>\n <Button size=\"small\" variant=\"contained\" disabled>\n {'Convert'}\n </Button>\n </span>\n </Tooltip>\n ) : (\n <Button size=\"small\" variant=\"contained\" onClick={onConvert}>\n {'Convert'}\n </Button>\n )}\n {/* Dial the number the capture carried, and log the call (AGL-2661). */}\n <CrmCallButton\n hostId={hostId}\n org={org}\n link={{ leadId }}\n phone={leadPhone || leadMobile}\n doNotCall={doNotCall}\n />\n <CrmSendEmailButton\n hostId={hostId}\n leadId={leadId}\n email={String(lead['email'] ?? '')}\n name={String(lead['name'] ?? '')}\n emailState={emailState}\n />\n </>\n }\n menuItems={[\n ...(open\n ? [\n {\n key: 'unqualify',\n label: 'Unqualify',\n icon: <MdiIcon path={mdiAccountCancelOutline.path} size={0.8} />,\n destructive: true,\n onClick: () => onUnqualify(),\n } satisfies RowActionsMenuItem,\n ]\n : []),\n ...extraMenuItems,\n ]}\n chips={\n <>\n <LeadStatusChip lead={lead} statuses={leadStatuses.picklist} />\n {/* The verdict on the address (AGL-3245), beside the status: a\n bounce does not move New or Working, but it is the first\n thing a person deciding whether to write must see. */}\n <CrmEmailStateChip state={emailState} />\n {/* The mail gateway in front of the address, and what it did\n with this site's mail this week (AGL-3328). */}\n <CrmEmailGatewayChip\n hostId={hostId}\n email={String(lead['email'] ?? '')}\n emailState={emailState}\n />\n <CrmRecordChip\n label=\"Owner\"\n value={lead.ownerUid ? roster.labelFor(lead.ownerUid) : undefined}\n />\n {extraChips}\n </>\n }\n >\n <Stack spacing={3}>\n {banner}\n {/*\n Only when the capture carried one (AGL-2661): the sign-up door\n writes no phone, and a booking only when its service asks for\n one (AGL-3493), so a row for every lead would often be a\n permanent blank. A form that captures one fills this.\n */}\n {leadPhone ? (\n <Fact label=\"Phone\">\n <CrmPhoneLink phone={leadPhone} doNotCall={doNotCall} />\n </Fact>\n ) : null}\n {leadMobile ? (\n <Fact label=\"Mobile phone\">\n <CrmPhoneLink phone={leadMobile} doNotCall={doNotCall} />\n </Fact>\n ) : null}\n <Fact label=\"Marketing consent\">{consentLine}</Fact>\n <Stack direction={{ xs: 'column', md: 'row' }} spacing={2}>\n {converted ? (\n <Fact label=\"Status\">\n <Stack direction=\"row\" spacing={1} sx={{ alignItems: 'center' }}>\n <LeadStatusChip lead={lead} statuses={leadStatuses.picklist} />\n <Typography variant=\"body2\" color=\"text.secondary\">\n {lead.convertedAtMs\n ? `Converted ${new Date(lead.convertedAtMs).toLocaleString()}`\n : 'Converted'}\n </Typography>\n </Stack>\n </Fact>\n ) : (\n <FormControl size=\"small\" sx={{ minWidth: 200 }}>\n <InputLabel id={statusLabelId}>{'Status'}</InputLabel>\n <Select\n labelId={statusLabelId}\n label=\"Status\"\n value={Aglyn.crmLeadStatusLabel(lead, leadStatuses.picklist)}\n onChange={(event) => {\n const choice = statusChoices.find((entry) => entry.label === event.target.value)\n if (!choice) return\n if (choice.status === 'unqualified') {\n onUnqualify(choice.label)\n return\n }\n // The meaning and the org's label for it, together\n // (AGL-3512). Reopening drops the reason with the closed\n // state: a lead being worked again is not \"unqualified\n // because …\".\n void write(\n {\n status: choice.status,\n statusLabel: choice.label,\n ...(status === 'unqualified' ? { unqualifiedReason: deleteField() } : {}),\n },\n 'Status updated',\n )\n }}\n >\n {leadStatusMenuItems(statusChoices)}\n </Select>\n </FormControl>\n )}\n <LeadOwnerSelect\n value={lead.ownerUid}\n roster={roster}\n fullWidth={false}\n onChange={(uid) =>\n void write({ ownerUid: uid || deleteField() }, uid ? 'Owner assigned' : 'Owner cleared')\n }\n />\n </Stack>\n {status === 'unqualified' && lead.unqualifiedReason ? (\n <Alert severity=\"info\">{`Unqualified: ${lead.unqualifiedReason}`}</Alert>\n ) : null}\n </Stack>\n </CrmRecordHeader>\n {/*\n The profile (AGL-3231), the org's own lead fields (AGL-3272) and the\n notes: what Salesforce keeps on a lead and hands to the contact and\n the account on convert. Read-only once converted — the contact is the\n record then, and the header's links lead there — but for the notes.\n */}\n <CardDisplay\n header={'Details'}\n help={Aglyn.pluginDocsHelp('crmLeads', { anchor: '#a-leads-page' })}\n contentGutterX\n contentGutterY\n HeaderProps={{\n action: (\n <Stack direction=\"row\" spacing={1}>\n {dirty ? (\n <Button size=\"small\" disabled={saving} onClick={discard}>\n {'Discard changes'}\n </Button>\n ) : null}\n <Button\n size=\"small\"\n variant=\"contained\"\n onClick={() => void saveDetails()}\n disabled={!dirty || saving}\n >\n {saving ? 'Saving…' : 'Save'}\n </Button>\n </Stack>\n ),\n }}\n >\n <Stack spacing={2}>\n <LeadProfileFields\n draft={profile}\n onChange={editProfile}\n errors={profileErrors}\n disabled={converted}\n leadSources={leadSources.picklist}\n lists={leadPicklists.lists}\n stored={lead}\n />\n {/*\n The org's own lead fields (AGL-3272), after the built-in ones\n because they describe the same record and save with it. Absent,\n not an empty box, while the org defines none.\n */}\n {fields.active.length ? (\n <>\n <Typography variant=\"subtitle2\">{'More fields'}</Typography>\n {fields.active.map((definition) => (\n <CrmCustomFieldControl\n key={definition.$id}\n definition={definition}\n value={crmCustomDraftValue(storedCustom, custom, definition.key)}\n onChange={(value) =>\n setCustom((current) => ({ ...current, [definition.key]: value }))\n }\n disabled={converted || saving}\n />\n ))}\n </>\n ) : null}\n <TextField\n size=\"small\"\n label=\"Notes\"\n value={notes}\n onChange={(event) => {\n setNotes(event.target.value)\n setNotesDirty(true)\n }}\n multiline\n minRows={3}\n fullWidth\n slotProps={{ htmlInput: { maxLength: NOTES_MAX } }}\n />\n </Stack>\n </CardDisplay>\n </>\n )\n}\nLeadPropertiesCard.displayName = 'LeadPropertiesCard'\n\nexport default LeadPropertiesCard\n"],"names":["Aglyn","mdiAccountCancelOutline","AppLink","CardDisplay","MdiIcon","useSnackbar","useFirestore","writeGuardedBySeed","Alert","Button","FormControl","InputLabel","Select","Stack","TextField","Tooltip","Typography","deleteField","doc","serverTimestamp","updateDoc","useEffect","useId","useMemo","useState","useContactFieldDefinitions","useLeadSourcePicklist","useLeadStatusPicklist","useLeadPicklists","crmCustomDraftChanges","crmCustomDraftMissingRequired","crmCustomDraftValue","crmCustomDraftWrites","CrmCustomFieldControl","crmRoutes","LeadProfileFields","leadProfileDraftBody","leadProfileDraftFrom","CrmCallButton","CrmPhoneLink","CrmEmailStateChip","CrmEmailGatewayChip","CrmRecordChip","CrmRecordHeader","CrmSendEmailButton","LeadOwnerSelect","LeadStatusChip","leadStatusChoices","leadStatusMenuItems","crmClientListFields","CRM_CLIENT_SEARCH_FIELDS","useCrmSharingFollowUp","LEAD_CLIENT_LIST_FIELDS","NOTES_MAX","CRM_LEAD_NOTES_MAX","profileWrite","patch","write","key","value","Object","entries","undefined","CONVERT_PENDING_ERASURE_REASON","Fact","props","spacing","variant","color","label","component","children","LeadPropertiesCard","lead","hostId","consentGroup","orgId","leadId","leadStatus","fromCache","basePath","roster","onConvert","onUnqualify","extraMenuItems","banner","extraChips","erasurePending","org","firestore","enqueueSnackbar","routes","followUpSharing","refFor","status","crmLeadStatus","converted","Boolean","convertedContactId","open","isCrmLeadOpen","emailState","readEmailState","leadPhone","String","trim","leadMobile","mobilePhone","doNotCall","notes","setNotes","statusLabelId","notesDirty","setNotesDirty","profile","setProfile","profileDirty","setProfileDirty","saving","setSaving","profileErrors","setProfileErrors","profileSeed","JSON","stringify","CRM_LEAD_PROFILE_KEYS","map","fields","leadSources","leadStatuses","leadPicklists","statusChoices","picklist","storedCustom","custom","setCustom","editProfile","current","done","ref","persist","updatedAt","error","Error","message","customChanged","length","dirty","discard","saveDetails","update","body","revenueError","errors","normalizeCrmLeadProfile","shown","keys","missing","active","join","profileFields","composed","crmLeadComposedName","assign","slice","landed","verdict","subject","unreadable","ok","consent","readMarketingBasis","consentLine","basis","basisAtMs","Date","toLocaleDateString","kind","title","subtitle","help","pluginDocsHelp","anchor","backHref","section","backLabel","booking","recordId","actions","componentVariant","nativeButton","href","contact","size","companyId","company","dealId","deal","span","disabled","onClick","link","phone","email","name","menuItems","icon","path","destructive","chips","statuses","state","ownerUid","labelFor","direction","xs","md","sx","alignItems","convertedAtMs","toLocaleString","minWidth","id","labelId","crmLeadStatusLabel","onChange","event","choice","find","entry","target","statusLabel","unqualifiedReason","fullWidth","uid","severity","header","contentGutterX","contentGutterY","HeaderProps","action","draft","lists","stored","definition","$id","multiline","minRows","slotProps","htmlInput","maxLength","displayName"],"mappings":"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"}
@@ -1,27 +1,8 @@
1
- import { type CrmPicklist } from '@aglyn/aglyn';
2
- export interface LeadSourceSelectProps {
3
- picklist: CrmPicklist;
4
- /** The label the record holds, or `''` for none. */
5
- value: string;
6
- onChange: (label: string) => void;
7
- /**
8
- * What the record held when the form opened. Kept in the menu while the
9
- * list no longer offers it — deactivated, or written before the list
10
- * existed — so the select shows what is stored until somebody changes it.
11
- */
12
- stored?: string;
13
- disabled?: boolean;
14
- helperText?: string;
15
- error?: boolean;
16
- }
1
+ import { type CrmPicklistSelectProps } from './picklist-select';
2
+ export type LeadSourceSelectProps = Omit<CrmPicklistSelectProps, 'picklistId'>;
17
3
  /**
18
- * The Lead source select (AGL-3298): the org's active values in the order
19
- * the Fields page keeps them, a "None" to clear, and the record's own value
20
- * when the list would not otherwise show it — marked, and selectable only
21
- * as what it already is.
22
- *
23
- * MUI's select `TextField`, the control every CRM form in this plugin uses
24
- * for a fixed choice, so it sizes, labels and disables like its neighbors.
4
+ * The Lead source select (AGL-3298) — {@link CrmPicklistSelect} for the
5
+ * lead source, its values under Inbound and Outbound.
25
6
  */
26
7
  export declare function LeadSourceSelect(props: LeadSourceSelectProps): import("react").JSX.Element;
27
8
  export declare namespace LeadSourceSelect {
@@ -14,81 +14,17 @@
14
14
  * See the License for the specific language governing permissions and
15
15
  * limitations under the License.
16
16
  */ 'use client';
17
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
18
- import { crmPicklistOptions } from "@aglyn/aglyn";
19
- import { ListItemText, MenuItem, TextField } from "@mui/material";
20
- import { useMemo } from "react";
21
- /** How a kept value that the list does not offer reads in the menu and the field. */ function optionText(label, inactive, unlisted) {
22
- if (inactive) return `${label} (inactive)`;
23
- if (unlisted) return `${label} (not in the list)`;
24
- return label;
25
- }
17
+ import { _ as _extends } from "@swc/helpers/_/_extends";
18
+ import { jsx as _jsx } from "react/jsx-runtime";
19
+ import { CRM_LEAD_SOURCE_PICKLIST } from "@aglyn/aglyn";
20
+ import { CrmPicklistSelect } from "./picklist-select.js";
26
21
  /**
27
- * The Lead source select (AGL-3298): the org's active values in the order
28
- * the Fields page keeps them, a "None" to clear, and the record's own value
29
- * when the list would not otherwise show it — marked, and selectable only
30
- * as what it already is.
31
- *
32
- * MUI's select `TextField`, the control every CRM form in this plugin uses
33
- * for a fixed choice, so it sizes, labels and disables like its neighbors.
22
+ * The Lead source select (AGL-3298) — {@link CrmPicklistSelect} for the
23
+ * lead source, its values under Inbound and Outbound.
34
24
  */ export function LeadSourceSelect(props) {
35
- const { picklist, value, onChange, stored, disabled, helperText, error } = props;
36
- const options = useMemo(()=>crmPicklistOptions(picklist, stored || value), [
37
- picklist,
38
- stored,
39
- value
40
- ]);
41
- const selected = options.find((option)=>option.label === value);
42
- return /*#__PURE__*/ _jsxs(TextField, {
43
- select: true,
44
- size: "small",
45
- label: "Lead source",
46
- value: selected ? value : '',
47
- onChange: (event)=>onChange(String(event.target.value)),
48
- disabled: disabled,
49
- helperText: helperText,
50
- error: error,
51
- fullWidth: true,
52
- slotProps: {
53
- select: {
54
- displayEmpty: true,
55
- renderValue: (current)=>{
56
- const option = options.find((entry)=>entry.label === current);
57
- return option ? optionText(option.label, option.inactive, option.unlisted) : 'None';
58
- }
59
- },
60
- inputLabel: {
61
- shrink: true
62
- }
63
- },
64
- children: [
65
- /*#__PURE__*/ _jsx(MenuItem, {
66
- value: "",
67
- children: /*#__PURE__*/ _jsx(ListItemText, {
68
- primary: "None",
69
- slotProps: {
70
- primary: {
71
- color: 'text.secondary'
72
- }
73
- }
74
- })
75
- }),
76
- options.map((option)=>/*#__PURE__*/ _jsx(MenuItem, {
77
- value: option.label,
78
- // A kept value is shown so the record reads true, not offered as a
79
- // choice for a record that does not hold it already.
80
- disabled: (option.inactive || option.unlisted) && option.label !== (stored || value),
81
- children: /*#__PURE__*/ _jsx(ListItemText, {
82
- primary: optionText(option.label, option.inactive, option.unlisted),
83
- slotProps: option.inactive || option.unlisted ? {
84
- primary: {
85
- color: 'text.secondary'
86
- }
87
- } : undefined
88
- })
89
- }, option.label))
90
- ]
91
- });
25
+ return /*#__PURE__*/ _jsx(CrmPicklistSelect, _extends({
26
+ picklistId: CRM_LEAD_SOURCE_PICKLIST
27
+ }, props));
92
28
  }
93
29
  LeadSourceSelect.displayName = 'LeadSourceSelect';
94
30
  export default LeadSourceSelect;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../../libs/plugins/crm/src/lib/components/lead-source-select.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 CrmPicklist, crmPicklistOptions } from '@aglyn/aglyn'\nimport { ListItemText, MenuItem, TextField } from '@mui/material'\nimport { useMemo } from 'react'\n\nexport interface LeadSourceSelectProps {\n picklist: CrmPicklist\n /** The label the record holds, or `''` for none. */\n value: string\n onChange: (label: string) => void\n /**\n * What the record held when the form opened. Kept in the menu while the\n * list no longer offers it — deactivated, or written before the list\n * existed — so the select shows what is stored until somebody changes it.\n */\n stored?: string\n disabled?: boolean\n helperText?: string\n error?: boolean\n}\n\n/** How a kept value that the list does not offer reads in the menu and the field. */\nfunction optionText(label: string, inactive: boolean, unlisted: boolean): string {\n if (inactive) return `${label} (inactive)`\n if (unlisted) return `${label} (not in the list)`\n return label\n}\n\n/**\n * The Lead source select (AGL-3298): the org's active values in the order\n * the Fields page keeps them, a \"None\" to clear, and the record's own value\n * when the list would not otherwise show it — marked, and selectable only\n * as what it already is.\n *\n * MUI's select `TextField`, the control every CRM form in this plugin uses\n * for a fixed choice, so it sizes, labels and disables like its neighbors.\n */\nexport function LeadSourceSelect(props: LeadSourceSelectProps) {\n const { picklist, value, onChange, stored, disabled, helperText, error } = props\n const options = useMemo(\n () => crmPicklistOptions(picklist, stored || value),\n [picklist, stored, value],\n )\n const selected = options.find((option) => option.label === value)\n return (\n <TextField\n select\n size=\"small\"\n label=\"Lead source\"\n value={selected ? value : ''}\n onChange={(event) => onChange(String(event.target.value))}\n disabled={disabled}\n helperText={helperText}\n error={error}\n fullWidth\n slotProps={{\n select: {\n displayEmpty: true,\n renderValue: (current) => {\n const option = options.find((entry) => entry.label === current)\n return option ? optionText(option.label, option.inactive, option.unlisted) : 'None'\n },\n },\n inputLabel: { shrink: true },\n }}\n >\n <MenuItem value=\"\">\n <ListItemText primary=\"None\" slotProps={{ primary: { color: 'text.secondary' } }} />\n </MenuItem>\n {options.map((option) => (\n <MenuItem\n key={option.label}\n value={option.label}\n // A kept value is shown so the record reads true, not offered as a\n // choice for a record that does not hold it already.\n disabled={(option.inactive || option.unlisted) && option.label !== (stored || value)}\n >\n <ListItemText\n primary={optionText(option.label, option.inactive, option.unlisted)}\n slotProps={\n option.inactive || option.unlisted\n ? { primary: { color: 'text.secondary' } }\n : undefined\n }\n />\n </MenuItem>\n ))}\n </TextField>\n )\n}\nLeadSourceSelect.displayName = 'LeadSourceSelect'\n\nexport default LeadSourceSelect\n"],"names":["crmPicklistOptions","ListItemText","MenuItem","TextField","useMemo","optionText","label","inactive","unlisted","LeadSourceSelect","props","picklist","value","onChange","stored","disabled","helperText","error","options","selected","find","option","select","size","event","String","target","fullWidth","slotProps","displayEmpty","renderValue","current","entry","inputLabel","shrink","primary","color","map","undefined","displayName"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GACD;;AAEA,SAA2BA,kBAAkB,QAAQ,eAAc;AACnE,SAASC,YAAY,EAAEC,QAAQ,EAAEC,SAAS,QAAQ,gBAAe;AACjE,SAASC,OAAO,QAAQ,QAAO;AAkB/B,mFAAmF,GACnF,SAASC,WAAWC,KAAa,EAAEC,QAAiB,EAAEC,QAAiB;IACrE,IAAID,UAAU,OAAO,GAAGD,MAAM,WAAW,CAAC;IAC1C,IAAIE,UAAU,OAAO,GAAGF,MAAM,kBAAkB,CAAC;IACjD,OAAOA;AACT;AAEA;;;;;;;;CAQC,GACD,OAAO,SAASG,iBAAiBC,KAA4B;IAC3D,MAAM,EAAEC,QAAQ,EAAEC,KAAK,EAAEC,QAAQ,EAAEC,MAAM,EAAEC,QAAQ,EAAEC,UAAU,EAAEC,KAAK,EAAE,GAAGP;IAC3E,MAAMQ,UAAUd,QACd,IAAMJ,mBAAmBW,UAAUG,UAAUF,QAC7C;QAACD;QAAUG;QAAQF;KAAM;IAE3B,MAAMO,WAAWD,QAAQE,IAAI,CAAC,CAACC,SAAWA,OAAOf,KAAK,KAAKM;IAC3D,qBACE,MAACT;QACCmB,MAAM;QACNC,MAAK;QACLjB,OAAM;QACNM,OAAOO,WAAWP,QAAQ;QAC1BC,UAAU,CAACW,QAAUX,SAASY,OAAOD,MAAME,MAAM,CAACd,KAAK;QACvDG,UAAUA;QACVC,YAAYA;QACZC,OAAOA;QACPU,SAAS;QACTC,WAAW;YACTN,QAAQ;gBACNO,cAAc;gBACdC,aAAa,CAACC;oBACZ,MAAMV,SAASH,QAAQE,IAAI,CAAC,CAACY,QAAUA,MAAM1B,KAAK,KAAKyB;oBACvD,OAAOV,SAAShB,WAAWgB,OAAOf,KAAK,EAAEe,OAAOd,QAAQ,EAAEc,OAAOb,QAAQ,IAAI;gBAC/E;YACF;YACAyB,YAAY;gBAAEC,QAAQ;YAAK;QAC7B;;0BAEA,KAAChC;gBAASU,OAAM;0BACd,cAAA,KAACX;oBAAakC,SAAQ;oBAAOP,WAAW;wBAAEO,SAAS;4BAAEC,OAAO;wBAAiB;oBAAE;;;YAEhFlB,QAAQmB,GAAG,CAAC,CAAChB,uBACZ,KAACnB;oBAECU,OAAOS,OAAOf,KAAK;oBACnB,mEAAmE;oBACnE,qDAAqD;oBACrDS,UAAU,AAACM,CAAAA,OAAOd,QAAQ,IAAIc,OAAOb,QAAQ,AAAD,KAAMa,OAAOf,KAAK,KAAMQ,CAAAA,UAAUF,KAAI;8BAElF,cAAA,KAACX;wBACCkC,SAAS9B,WAAWgB,OAAOf,KAAK,EAAEe,OAAOd,QAAQ,EAAEc,OAAOb,QAAQ;wBAClEoB,WACEP,OAAOd,QAAQ,IAAIc,OAAOb,QAAQ,GAC9B;4BAAE2B,SAAS;gCAAEC,OAAO;4BAAiB;wBAAE,IACvCE;;mBAXHjB,OAAOf,KAAK;;;AAkB3B;AACAG,iBAAiB8B,WAAW,GAAG;AAE/B,eAAe9B,iBAAgB"}
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/crm/src/lib/components/lead-source-select.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 { CRM_LEAD_SOURCE_PICKLIST } from '@aglyn/aglyn'\nimport { CrmPicklistSelect, type CrmPicklistSelectProps } from './picklist-select'\n\nexport type LeadSourceSelectProps = Omit<CrmPicklistSelectProps, 'picklistId'>\n\n/**\n * The Lead source select (AGL-3298) — {@link CrmPicklistSelect} for the\n * lead source, its values under Inbound and Outbound.\n */\nexport function LeadSourceSelect(props: LeadSourceSelectProps) {\n return <CrmPicklistSelect picklistId={CRM_LEAD_SOURCE_PICKLIST} {...props} />\n}\nLeadSourceSelect.displayName = 'LeadSourceSelect'\n\nexport default LeadSourceSelect\n"],"names":["CRM_LEAD_SOURCE_PICKLIST","CrmPicklistSelect","LeadSourceSelect","props","picklistId","displayName"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GACD;;;AAEA,SAASA,wBAAwB,QAAQ,eAAc;AACvD,SAASC,iBAAiB,QAAqC,uBAAmB;AAIlF;;;CAGC,GACD,OAAO,SAASC,iBAAiBC,KAA4B;IAC3D,qBAAO,KAACF;QAAkBG,YAAYJ;OAA8BG;AACtE;AACAD,iBAAiBG,WAAW,GAAG;AAE/B,eAAeH,iBAAgB"}
@@ -1,10 +1,16 @@
1
- import { type CrmLeadFields } from '@aglyn/aglyn';
1
+ import { type CrmLeadFields, type CrmPicklist } from '@aglyn/aglyn';
2
2
  import { type ChipProps } from '@mui/material';
3
3
  export interface LeadStatusChipProps {
4
- lead: Pick<CrmLeadFields, 'status'> | null | undefined;
4
+ lead: Pick<CrmLeadFields, 'status' | 'statusLabel'> | null | undefined;
5
+ /** The org's Lead status list, whose labels the chip reads (AGL-3512); the standard ones without it. */
6
+ statuses?: CrmPicklist;
5
7
  size?: ChipProps['size'];
6
8
  }
7
- /** A lead's status as a chip (AGL-2608). An absent status reads as New. */
9
+ /**
10
+ * A lead's status as a chip (AGL-2608). An absent status reads as New. The
11
+ * color is the MEANING's and the words are the org's label for the value
12
+ * the lead holds (AGL-3512).
13
+ */
8
14
  export declare function LeadStatusChip(props: LeadStatusChipProps): import("react").JSX.Element;
9
15
  export declare namespace LeadStatusChip {
10
16
  var displayName: string;
@@ -15,7 +15,7 @@
15
15
  * limitations under the License.
16
16
  */ 'use client';
17
17
  import { jsx as _jsx } from "react/jsx-runtime";
18
- import { CRM_LEAD_STATUS_LABELS, crmLeadStatus } from "@aglyn/aglyn";
18
+ import { crmLeadStatus, crmLeadStatusLabel } from "@aglyn/aglyn";
19
19
  import { Chip } from "@mui/material";
20
20
  /**
21
21
  * One palette key per status, so the list and the record page paint the same
@@ -29,12 +29,16 @@ import { Chip } from "@mui/material";
29
29
  qualified: 'success',
30
30
  unqualified: 'default'
31
31
  };
32
- /** A lead's status as a chip (AGL-2608). An absent status reads as New. */ export function LeadStatusChip(props) {
33
- const { lead, size = 'small' } = props;
32
+ /**
33
+ * A lead's status as a chip (AGL-2608). An absent status reads as New. The
34
+ * color is the MEANING's and the words are the org's label for the value
35
+ * the lead holds (AGL-3512).
36
+ */ export function LeadStatusChip(props) {
37
+ const { lead, statuses, size = 'small' } = props;
34
38
  const status = crmLeadStatus(lead);
35
39
  return /*#__PURE__*/ _jsx(Chip, {
36
40
  size: size,
37
- label: CRM_LEAD_STATUS_LABELS[status],
41
+ label: crmLeadStatusLabel(lead, statuses),
38
42
  color: STATUS_COLOR[status],
39
43
  variant: status === 'unqualified' ? 'outlined' : 'filled'
40
44
  });
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../../libs/plugins/crm/src/lib/components/lead-status-chip.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_LEAD_STATUS_LABELS,\n type CrmLeadFields,\n type CrmLeadStatus,\n crmLeadStatus,\n} from '@aglyn/aglyn'\nimport { Chip, type ChipProps } from '@mui/material'\n\n/**\n * One palette key per status, so the list and the record page paint the same\n * state the same way. `qualified` is the converted state and reads as the\n * success it is; `nurturing` — automation is reaching it, no person yet —\n * takes its own hue between New and Working; `unqualified` is outlined and neutral — closed, not wrong.\n */\nconst STATUS_COLOR: Record<CrmLeadStatus, ChipProps['color']> = {\n new: 'info',\n nurturing: 'secondary',\n working: 'primary',\n qualified: 'success',\n unqualified: 'default',\n}\n\nexport interface LeadStatusChipProps {\n lead: Pick<CrmLeadFields, 'status'> | null | undefined\n size?: ChipProps['size']\n}\n\n/** A lead's status as a chip (AGL-2608). An absent status reads as New. */\nexport function LeadStatusChip(props: LeadStatusChipProps) {\n const { lead, size = 'small' } = props\n const status = crmLeadStatus(lead)\n return (\n <Chip\n size={size}\n label={CRM_LEAD_STATUS_LABELS[status]}\n color={STATUS_COLOR[status]}\n variant={status === 'unqualified' ? 'outlined' : 'filled'}\n />\n )\n}\nLeadStatusChip.displayName = 'LeadStatusChip'\n\nexport default LeadStatusChip\n"],"names":["CRM_LEAD_STATUS_LABELS","crmLeadStatus","Chip","STATUS_COLOR","new","nurturing","working","qualified","unqualified","LeadStatusChip","props","lead","size","status","label","color","variant","displayName"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GACD;;AAEA,SACEA,sBAAsB,EAGtBC,aAAa,QACR,eAAc;AACrB,SAASC,IAAI,QAAwB,gBAAe;AAEpD;;;;;CAKC,GACD,MAAMC,eAA0D;IAC9DC,KAAK;IACLC,WAAW;IACXC,SAAS;IACTC,WAAW;IACXC,aAAa;AACf;AAOA,yEAAyE,GACzE,OAAO,SAASC,eAAeC,KAA0B;IACvD,MAAM,EAAEC,IAAI,EAAEC,OAAO,OAAO,EAAE,GAAGF;IACjC,MAAMG,SAASZ,cAAcU;IAC7B,qBACE,KAACT;QACCU,MAAMA;QACNE,OAAOd,sBAAsB,CAACa,OAAO;QACrCE,OAAOZ,YAAY,CAACU,OAAO;QAC3BG,SAASH,WAAW,gBAAgB,aAAa;;AAGvD;AACAJ,eAAeQ,WAAW,GAAG;AAE7B,eAAeR,eAAc"}
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/crm/src/lib/components/lead-status-chip.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 CrmLeadFields,\n type CrmLeadStatus,\n type CrmPicklist,\n crmLeadStatus,\n crmLeadStatusLabel,\n} from '@aglyn/aglyn'\nimport { Chip, type ChipProps } from '@mui/material'\n\n/**\n * One palette key per status, so the list and the record page paint the same\n * state the same way. `qualified` is the converted state and reads as the\n * success it is; `nurturing` — automation is reaching it, no person yet —\n * takes its own hue between New and Working; `unqualified` is outlined and neutral — closed, not wrong.\n */\nconst STATUS_COLOR: Record<CrmLeadStatus, ChipProps['color']> = {\n new: 'info',\n nurturing: 'secondary',\n working: 'primary',\n qualified: 'success',\n unqualified: 'default',\n}\n\nexport interface LeadStatusChipProps {\n lead: Pick<CrmLeadFields, 'status' | 'statusLabel'> | null | undefined\n /** The org's Lead status list, whose labels the chip reads (AGL-3512); the standard ones without it. */\n statuses?: CrmPicklist\n size?: ChipProps['size']\n}\n\n/**\n * A lead's status as a chip (AGL-2608). An absent status reads as New. The\n * color is the MEANING's and the words are the org's label for the value\n * the lead holds (AGL-3512).\n */\nexport function LeadStatusChip(props: LeadStatusChipProps) {\n const { lead, statuses, size = 'small' } = props\n const status = crmLeadStatus(lead)\n return (\n <Chip\n size={size}\n label={crmLeadStatusLabel(lead, statuses)}\n color={STATUS_COLOR[status]}\n variant={status === 'unqualified' ? 'outlined' : 'filled'}\n />\n )\n}\nLeadStatusChip.displayName = 'LeadStatusChip'\n\nexport default LeadStatusChip\n"],"names":["crmLeadStatus","crmLeadStatusLabel","Chip","STATUS_COLOR","new","nurturing","working","qualified","unqualified","LeadStatusChip","props","lead","statuses","size","status","label","color","variant","displayName"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GACD;;AAEA,SAIEA,aAAa,EACbC,kBAAkB,QACb,eAAc;AACrB,SAASC,IAAI,QAAwB,gBAAe;AAEpD;;;;;CAKC,GACD,MAAMC,eAA0D;IAC9DC,KAAK;IACLC,WAAW;IACXC,SAAS;IACTC,WAAW;IACXC,aAAa;AACf;AASA;;;;CAIC,GACD,OAAO,SAASC,eAAeC,KAA0B;IACvD,MAAM,EAAEC,IAAI,EAAEC,QAAQ,EAAEC,OAAO,OAAO,EAAE,GAAGH;IAC3C,MAAMI,SAASd,cAAcW;IAC7B,qBACE,KAACT;QACCW,MAAMA;QACNE,OAAOd,mBAAmBU,MAAMC;QAChCI,OAAOb,YAAY,CAACW,OAAO;QAC3BG,SAASH,WAAW,gBAAgB,aAAa;;AAGvD;AACAL,eAAeS,WAAW,GAAG;AAE7B,eAAeT,eAAc"}
@@ -0,0 +1,20 @@
1
+ import { type CrmLeadFields, type CrmLeadStatus, type CrmPicklist } from '@aglyn/aglyn';
2
+ /**
3
+ * The meanings a person sets by hand from a lead's status select: every one
4
+ * but Qualified, which only a conversion sets (AGL-2608, AGL-3512).
5
+ */
6
+ export declare const LEAD_STATUS_HAND_SET: readonly CrmLeadStatus[];
7
+ /** One choice of a lead status select: the org's label, and the meaning it sets. */
8
+ export interface LeadStatusChoice {
9
+ label: string;
10
+ status: CrmLeadStatus;
11
+ inactive: boolean;
12
+ }
13
+ /** What a lead status select offers a lead: the org's active values of the hand-set meanings, and its own. */
14
+ export declare function leadStatusChoices(picklist: CrmPicklist, lead: Pick<CrmLeadFields, 'status' | 'statusLabel'>): LeadStatusChoice[];
15
+ /**
16
+ * The select's items, by label (AGL-3512). An Unqualified value ends in "…"
17
+ * because it opens the dialog that asks why; the lead's own value, when the
18
+ * list no longer offers it, is shown and not offered.
19
+ */
20
+ export declare function leadStatusMenuItems(choices: readonly LeadStatusChoice[]): import("react").JSX.Element[];
@@ -0,0 +1,51 @@
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 } from "react/jsx-runtime";
18
+ import { crmLeadStatusOptions } from "@aglyn/aglyn";
19
+ import { ListItemText, MenuItem } from "@mui/material";
20
+ /**
21
+ * The meanings a person sets by hand from a lead's status select: every one
22
+ * but Qualified, which only a conversion sets (AGL-2608, AGL-3512).
23
+ */ export const LEAD_STATUS_HAND_SET = [
24
+ 'new',
25
+ 'nurturing',
26
+ 'working',
27
+ 'unqualified'
28
+ ];
29
+ /** What a lead status select offers a lead: the org's active values of the hand-set meanings, and its own. */ export function leadStatusChoices(picklist, lead) {
30
+ return crmLeadStatusOptions(picklist, LEAD_STATUS_HAND_SET, lead);
31
+ }
32
+ /**
33
+ * The select's items, by label (AGL-3512). An Unqualified value ends in "…"
34
+ * because it opens the dialog that asks why; the lead's own value, when the
35
+ * list no longer offers it, is shown and not offered.
36
+ */ export function leadStatusMenuItems(choices) {
37
+ return choices.map((choice)=>/*#__PURE__*/ _jsx(MenuItem, {
38
+ value: choice.label,
39
+ disabled: choice.inactive,
40
+ children: /*#__PURE__*/ _jsx(ListItemText, {
41
+ primary: choice.status === 'unqualified' ? `${choice.label}…` : choice.label,
42
+ slotProps: choice.inactive ? {
43
+ primary: {
44
+ color: 'text.secondary'
45
+ }
46
+ } : undefined
47
+ })
48
+ }, choice.label));
49
+ }
50
+
51
+ //# sourceMappingURL=lead-status-options.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/crm/src/lib/components/lead-status-options.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 CrmLeadFields,\n type CrmLeadStatus,\n type CrmPicklist,\n crmLeadStatusOptions,\n} from '@aglyn/aglyn'\nimport { ListItemText, MenuItem } from '@mui/material'\n\n/**\n * The meanings a person sets by hand from a lead's status select: every one\n * but Qualified, which only a conversion sets (AGL-2608, AGL-3512).\n */\nexport const LEAD_STATUS_HAND_SET: readonly CrmLeadStatus[] = [\n 'new',\n 'nurturing',\n 'working',\n 'unqualified',\n]\n\n/** One choice of a lead status select: the org's label, and the meaning it sets. */\nexport interface LeadStatusChoice {\n label: string\n status: CrmLeadStatus\n inactive: boolean\n}\n\n/** What a lead status select offers a lead: the org's active values of the hand-set meanings, and its own. */\nexport function leadStatusChoices(\n picklist: CrmPicklist,\n lead: Pick<CrmLeadFields, 'status' | 'statusLabel'>,\n): LeadStatusChoice[] {\n return crmLeadStatusOptions(picklist, LEAD_STATUS_HAND_SET, lead)\n}\n\n/**\n * The select's items, by label (AGL-3512). An Unqualified value ends in \"…\"\n * because it opens the dialog that asks why; the lead's own value, when the\n * list no longer offers it, is shown and not offered.\n */\nexport function leadStatusMenuItems(choices: readonly LeadStatusChoice[]) {\n return choices.map((choice) => (\n <MenuItem key={choice.label} value={choice.label} disabled={choice.inactive}>\n <ListItemText\n primary={choice.status === 'unqualified' ? `${choice.label}…` : choice.label}\n slotProps={choice.inactive ? { primary: { color: 'text.secondary' } } : undefined}\n />\n </MenuItem>\n ))\n}\n"],"names":["crmLeadStatusOptions","ListItemText","MenuItem","LEAD_STATUS_HAND_SET","leadStatusChoices","picklist","lead","leadStatusMenuItems","choices","map","choice","value","label","disabled","inactive","primary","status","slotProps","color","undefined"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GACD;;AAEA,SAIEA,oBAAoB,QACf,eAAc;AACrB,SAASC,YAAY,EAAEC,QAAQ,QAAQ,gBAAe;AAEtD;;;CAGC,GACD,OAAO,MAAMC,uBAAiD;IAC5D;IACA;IACA;IACA;CACD,CAAA;AASD,4GAA4G,GAC5G,OAAO,SAASC,kBACdC,QAAqB,EACrBC,IAAmD;IAEnD,OAAON,qBAAqBK,UAAUF,sBAAsBG;AAC9D;AAEA;;;;CAIC,GACD,OAAO,SAASC,oBAAoBC,OAAoC;IACtE,OAAOA,QAAQC,GAAG,CAAC,CAACC,uBAClB,KAACR;YAA4BS,OAAOD,OAAOE,KAAK;YAAEC,UAAUH,OAAOI,QAAQ;sBACzE,cAAA,KAACb;gBACCc,SAASL,OAAOM,MAAM,KAAK,gBAAgB,GAAGN,OAAOE,KAAK,CAAC,CAAC,CAAC,GAAGF,OAAOE,KAAK;gBAC5EK,WAAWP,OAAOI,QAAQ,GAAG;oBAAEC,SAAS;wBAAEG,OAAO;oBAAiB;gBAAE,IAAIC;;WAH7DT,OAAOE,KAAK;AAO/B"}
@@ -12,6 +12,11 @@ export interface LeadUnqualifyDialogProps {
12
12
  leadId: string;
13
13
  /** How the lead reads in the title — its name, else its address. */
14
14
  leadLabel: string;
15
+ /**
16
+ * The Unqualified value the lead is closed as, when the reader already
17
+ * picked one (AGL-3512); the meaning's default label otherwise.
18
+ */
19
+ statusLabel?: string | null;
15
20
  }
16
21
  /**
17
22
  * Close a lead without converting it, with the reason why (AGL-2608).