@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,7 +1,7 @@
1
1
  'use client';
2
2
  import { _ as _extends } from "@swc/helpers/_/_extends";
3
3
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
4
- import { CRM_LEAD_STATUS_LABELS, CRM_LEAD_TEXT_MAX, containerMembershipValue, crmPicklistDefaultLabel, normalizeCrmLeadTags, normalizeContactEmail, normalizeCrmLeadProfile } from "@aglyn/aglyn";
4
+ import { CRM_LEAD_TEXT_MAX, crmLeadStatusLabelFor, crmLeadStatusOptions, containerMembershipValue, crmLeadComposedName, crmPicklistDefaultLabel, normalizeContactEmail, normalizeCrmLeadProfile } from "@aglyn/aglyn";
5
5
  import { ICON_VARIANT_CLOSE } from "@aglyn/shared-data-enums";
6
6
  import { Container, MdiIcon, SrOnly } from "@aglyn/shared-ui-jsx";
7
7
  import { NavigationDrawerComponent } from "@aglyn/shared-ui-jsx/components/navigation-drawer.component";
@@ -11,13 +11,18 @@ import { useEffect, useState } from "react";
11
11
  import { useContactFieldDefinitions } from "../hooks/use-contact-field-definitions.js";
12
12
  import { useCrmCampaigns } from "../hooks/use-crm-campaigns.js";
13
13
  import { useCrmScope } from "../hooks/use-crm-scope.js";
14
- import { ContactAddressFields, EMPTY_ADDRESS } from "./contact-address-fields.js";
14
+ import { EMPTY_LEAD_PROFILE_DRAFT, leadDraftComposedName, LeadProfileFields, leadProfileDraftBody } from "./lead-profile-fields.js";
15
15
  import { CrmSitePicker } from "./crm-site-picker.js";
16
16
  import { CrmCustomFieldControl } from "./crm-custom-field-control.js";
17
17
  import { crmCustomDraftDocument, crmCustomDraftMissingRequired } from "../model/crm-custom-draft.js";
18
18
  import { LeadOwnerSelect } from "./lead-owner-select.js";
19
- import { LeadSourceSelect } from "./lead-source-select.js";
20
19
  import { useLeadSourcePicklist } from "../hooks/use-lead-source-picklist.js";
20
+ import { useLeadPicklists } from "../hooks/use-lead-picklists.js";
21
+ import { useLeadStatusPicklist } from "../hooks/use-lead-status-picklist.js";
22
+ /** The meanings a lead is entered in by hand: New or Working (AGL-3231). */ const NEW_LEAD_STATUSES = [
23
+ 'new',
24
+ 'working'
25
+ ];
21
26
  const NOTES_MAX = 4000;
22
27
  /**
23
28
  * ADDING ONE LEAD BY HAND, IN A DRAWER (AGL-3231).
@@ -48,11 +53,16 @@ const NOTES_MAX = 4000;
48
53
  });
49
54
  const [email, setEmail] = useState('');
50
55
  const [name, setName] = useState('');
51
- const [company, setCompany] = useState('');
52
- const [jobTitle, setJobTitle] = useState('');
53
- const [phone, setPhone] = useState('');
54
- const [website, setWebsite] = useState('');
55
- const [leadSource, setLeadSource] = useState('');
56
+ /*
57
+ * THE PROFILE (AGL-3231, AGL-3513), one draft the fields edit — the
58
+ * lead's page edits the same draft with the same fields.
59
+ */ const [profile, setProfile] = useState(EMPTY_LEAD_PROFILE_DRAFT);
60
+ const [profileErrors, setProfileErrors] = useState({});
61
+ const editProfile = (key, value)=>setProfile((current)=>_extends({}, current, {
62
+ [key]: value
63
+ }));
64
+ // The org's Salutation, Industry and Rating lists (AGL-3513).
65
+ const leadPicklists = useLeadPicklists(open ? orgId != null ? orgId : null : null);
56
66
  /*
57
67
  * THE ORG'S LEAD SOURCES (AGL-3298), and its default for a new record.
58
68
  * The default is filled in once the list has answered and only until the
@@ -62,17 +72,23 @@ const NOTES_MAX = 4000;
62
72
  const [leadSourceTouched, setLeadSourceTouched] = useState(false);
63
73
  const defaultLeadSource = (_crmPicklistDefaultLabel = crmPicklistDefaultLabel(leadSources.picklist)) != null ? _crmPicklistDefaultLabel : '';
64
74
  useEffect(()=>{
65
- if (open && !leadSourceTouched) setLeadSource(defaultLeadSource);
75
+ if (open && !leadSourceTouched) {
76
+ setProfile((current)=>_extends({}, current, {
77
+ leadSource: defaultLeadSource
78
+ }));
79
+ }
66
80
  }, [
67
81
  open,
68
82
  leadSourceTouched,
69
83
  defaultLeadSource
70
84
  ]);
71
- const [status, setStatus] = useState('new');
85
+ // The org's New and Working values (AGL-3512); a new lead starts as New's.
86
+ const leadStatuses = useLeadStatusPicklist(orgId != null ? orgId : null);
87
+ const statusChoices = crmLeadStatusOptions(leadStatuses.picklist, NEW_LEAD_STATUSES);
88
+ const [status, setStatus] = useState('');
89
+ const shownStatus = statusChoices.some((choice)=>choice.label === status) ? status : crmLeadStatusLabelFor(leadStatuses.picklist, 'new');
72
90
  const [ownerUid, setOwnerUid] = useState('');
73
- const [tags, setTags] = useState('');
74
91
  const [campaignIds, setCampaignIds] = useState([]);
75
- const [address, setAddress] = useState(EMPTY_ADDRESS);
76
92
  const [notes, setNotes] = useState('');
77
93
  /*
78
94
  * The org's own lead fields (AGL-3272). A CREATE holds only a draft —
@@ -82,8 +98,6 @@ const NOTES_MAX = 4000;
82
98
  const [custom, setCustom] = useState({});
83
99
  const [customError, setCustomError] = useState('');
84
100
  const [emailError, setEmailError] = useState('');
85
- const [phoneError, setPhoneError] = useState('');
86
- const [websiteError, setWebsiteError] = useState('');
87
101
  /*
88
102
  * The campaigns, for the picker (AGL-3254): read while the drawer is
89
103
  * open. Under a site, the ones placed on it; at the organization level,
@@ -101,63 +115,73 @@ const NOTES_MAX = 4000;
101
115
  if (!open) return;
102
116
  setEmail('');
103
117
  setName('');
104
- setCompany('');
105
- setJobTitle('');
106
- setPhone('');
107
- setWebsite('');
108
- setLeadSource('');
118
+ setProfile(EMPTY_LEAD_PROFILE_DRAFT);
119
+ setProfileErrors({});
109
120
  setLeadSourceTouched(false);
110
- setStatus('new');
121
+ setStatus('');
111
122
  setOwnerUid('');
112
- setTags('');
113
123
  setCampaignIds([]);
114
- setAddress(EMPTY_ADDRESS);
115
124
  setNotes('');
116
125
  setCustom({});
117
126
  setCustomError('');
118
127
  setEmailError('');
119
- setPhoneError('');
120
- setWebsiteError('');
121
128
  }, [
122
129
  open
123
130
  ]);
124
131
  const handleSubmit = ()=>{
125
- var _errors_phone, _errors_website, _patch_company, _patch_jobTitle, _patch_phone, _patch_website, _patch_leadSource, _patch_tags, _patch_address;
132
+ var _crmLeadComposedName, _patch_company, _patch_jobTitle, _patch_phone, _patch_website, _patch_leadSource, _patch_tags, _patch_address;
126
133
  const normalizedEmail = normalizeContactEmail(email);
127
- const { patch, errors } = normalizeCrmLeadProfile({
128
- company,
129
- jobTitle,
130
- phone,
131
- website,
132
- leadSource,
133
- address,
134
- tags: normalizeCrmLeadTags(tags)
135
- });
134
+ const { body, revenueError } = leadProfileDraftBody(profile);
135
+ const { patch, errors } = normalizeCrmLeadProfile(body);
136
+ const shown = _extends({}, errors);
137
+ if (revenueError) shown['annualRevenueCents'] = revenueError;
136
138
  // Every required lead field counts on a create: the record is being
137
139
  // made whole, and nothing has been written to come back and fill.
138
140
  const missing = crmCustomDraftMissingRequired(fields.active, {}, custom, 'create');
139
141
  setEmailError(normalizedEmail ? '' : 'Enter a valid email address.');
140
- setPhoneError((_errors_phone = errors.phone) != null ? _errors_phone : '');
141
- setWebsiteError((_errors_website = errors.website) != null ? _errors_website : '');
142
+ setProfileErrors(shown);
142
143
  setCustomError(missing.length ? `${missing.join(', ')} ${missing.length > 1 ? 'are' : 'is'} required.` : '');
143
- if (!normalizedEmail || errors.phone || errors.website || missing.length) return;
144
+ if (!normalizedEmail || Object.keys(shown).length || missing.length) return;
145
+ // Only what was filled: a create has nothing to clear.
146
+ const standard = {};
147
+ for (const key of [
148
+ 'salutation',
149
+ 'firstName',
150
+ 'lastName',
151
+ 'mobilePhone',
152
+ 'fax',
153
+ 'doNotCall',
154
+ 'industry',
155
+ 'rating',
156
+ 'annualRevenueCents',
157
+ 'currency',
158
+ 'numberOfEmployees'
159
+ ]){
160
+ const value = patch[key];
161
+ if (value !== null && value !== undefined) Object.assign(standard, {
162
+ [key]: value
163
+ });
164
+ }
144
165
  onSubmit({
145
166
  email: normalizedEmail,
146
- name: name.trim().replace(/\s+/g, ' ').slice(0, CRM_LEAD_TEXT_MAX),
167
+ // While a first or last name is typed, the name is theirs (AGL-3513).
168
+ name: (_crmLeadComposedName = crmLeadComposedName(null, patch)) != null ? _crmLeadComposedName : name.trim().replace(/\s+/g, ' ').slice(0, CRM_LEAD_TEXT_MAX),
147
169
  company: (_patch_company = patch.company) != null ? _patch_company : '',
148
170
  jobTitle: (_patch_jobTitle = patch.jobTitle) != null ? _patch_jobTitle : '',
149
171
  phone: (_patch_phone = patch.phone) != null ? _patch_phone : '',
150
172
  website: (_patch_website = patch.website) != null ? _patch_website : '',
151
173
  leadSource: (_patch_leadSource = patch.leadSource) != null ? _patch_leadSource : '',
152
- status,
174
+ status: shownStatus,
153
175
  ownerUid,
154
176
  tags: (_patch_tags = patch.tags) != null ? _patch_tags : [],
155
177
  campaignIds: containerMembershipValue(campaignIds),
156
178
  address: (_patch_address = patch.address) != null ? _patch_address : null,
157
179
  notes: notes.trim().slice(0, NOTES_MAX),
158
- custom: crmCustomDraftDocument(custom)
180
+ custom: crmCustomDraftDocument(custom),
181
+ standard
159
182
  });
160
183
  };
184
+ const composedName = leadDraftComposedName(profile);
161
185
  return /*#__PURE__*/ _jsx(NavigationDrawerComponent, {
162
186
  open: open,
163
187
  anchor: "right",
@@ -234,67 +258,33 @@ const NOTES_MAX = 4000;
234
258
  /*#__PURE__*/ _jsx(TextField, {
235
259
  size: "small",
236
260
  label: "Name",
237
- value: name,
261
+ value: composedName || name,
238
262
  onChange: (event)=>setName(event.target.value),
239
263
  slotProps: {
240
264
  htmlInput: {
241
265
  maxLength: CRM_LEAD_TEXT_MAX
266
+ },
267
+ input: {
268
+ readOnly: Boolean(composedName)
242
269
  }
243
270
  },
271
+ helperText: composedName ? 'Made of the first and last name.' : 'Or the whole name in one field.',
244
272
  fullWidth: true
245
273
  }),
246
- /*#__PURE__*/ _jsx(TextField, {
247
- size: "small",
248
- label: "Company",
249
- value: company,
250
- onChange: (event)=>setCompany(event.target.value),
251
- helperText: "As text — converting the lead is what makes it a company record.",
252
- slotProps: {
253
- htmlInput: {
254
- maxLength: CRM_LEAD_TEXT_MAX
255
- }
256
- },
257
- fullWidth: true
258
- }),
259
- /*#__PURE__*/ _jsx(TextField, {
260
- size: "small",
261
- label: "Job title",
262
- value: jobTitle,
263
- onChange: (event)=>setJobTitle(event.target.value),
264
- slotProps: {
265
- htmlInput: {
266
- maxLength: CRM_LEAD_TEXT_MAX
267
- }
268
- },
269
- fullWidth: true
270
- }),
271
- /*#__PURE__*/ _jsx(TextField, {
272
- size: "small",
273
- label: "Phone",
274
- value: phone,
275
- onChange: (event)=>setPhone(event.target.value),
276
- error: Boolean(phoneError),
277
- helperText: phoneError || 'With the country code, like +1 512 555 0107',
278
- fullWidth: true
279
- }),
280
- /*#__PURE__*/ _jsx(TextField, {
281
- size: "small",
282
- label: "Website",
283
- value: website,
284
- onChange: (event)=>setWebsite(event.target.value),
285
- error: Boolean(websiteError),
286
- helperText: websiteError || 'Like acme.com',
287
- fullWidth: true
288
- }),
289
- /*#__PURE__*/ _jsx(LeadSourceSelect, {
290
- picklist: leadSources.picklist,
291
- value: leadSource,
292
- onChange: (label)=>{
293
- setLeadSource(label);
294
- setLeadSourceTouched(true);
274
+ /*#__PURE__*/ _jsx(LeadProfileFields, {
275
+ draft: profile,
276
+ onChange: (key, value)=>{
277
+ if (key === 'leadSource') setLeadSourceTouched(true);
278
+ editProfile(key, value);
295
279
  },
280
+ errors: profileErrors,
296
281
  disabled: Boolean(busy),
297
- helperText: "Where this lead came from. The choices are kept under CRM › Fields › Leads."
282
+ leadSources: leadSources.picklist,
283
+ lists: leadPicklists.lists,
284
+ helperTexts: {
285
+ company: 'As text — converting the lead is what makes it a company record.',
286
+ leadSource: 'Where this lead came from. The choices are kept under CRM › Fields › Leads.'
287
+ }
298
288
  }),
299
289
  /*#__PURE__*/ _jsxs(Stack, {
300
290
  direction: {
@@ -303,23 +293,17 @@ const NOTES_MAX = 4000;
303
293
  },
304
294
  spacing: 2,
305
295
  children: [
306
- /*#__PURE__*/ _jsxs(TextField, {
296
+ /*#__PURE__*/ _jsx(TextField, {
307
297
  select: true,
308
298
  size: "small",
309
299
  label: "Status",
310
- value: status,
311
- onChange: (event)=>setStatus(event.target.value),
300
+ value: statusChoices.some((choice)=>choice.label === shownStatus) ? shownStatus : '',
301
+ onChange: (event)=>setStatus(String(event.target.value)),
312
302
  fullWidth: true,
313
- children: [
314
- /*#__PURE__*/ _jsx(MenuItem, {
315
- value: "new",
316
- children: CRM_LEAD_STATUS_LABELS.new
317
- }),
318
- /*#__PURE__*/ _jsx(MenuItem, {
319
- value: "working",
320
- children: CRM_LEAD_STATUS_LABELS.working
321
- })
322
- ]
303
+ children: statusChoices.map((choice)=>/*#__PURE__*/ _jsx(MenuItem, {
304
+ value: choice.label,
305
+ children: choice.label
306
+ }, choice.label))
323
307
  }),
324
308
  /*#__PURE__*/ _jsx(LeadOwnerSelect, {
325
309
  value: ownerUid,
@@ -328,15 +312,6 @@ const NOTES_MAX = 4000;
328
312
  })
329
313
  ]
330
314
  }),
331
- /*#__PURE__*/ _jsx(TextField, {
332
- size: "small",
333
- label: "Tags",
334
- placeholder: "icp2, a-list",
335
- helperText: "Comma-separated",
336
- value: tags,
337
- onChange: (event)=>setTags(event.target.value),
338
- fullWidth: true
339
- }),
340
315
  /*#__PURE__*/ _jsx(ContainerPicker, {
341
316
  kind: "campaign",
342
317
  options: campaigns.options,
@@ -347,14 +322,6 @@ const NOTES_MAX = 4000;
347
322
  empty: campaigns.ready && !campaigns.options.length,
348
323
  emptyText: hostId ? 'This site has no campaigns yet. Create one from Marketing to file leads under it.' : 'There are no campaigns yet. Create one from Marketing to file leads under it.'
349
324
  }),
350
- /*#__PURE__*/ _jsx(Typography, {
351
- variant: "subtitle2",
352
- children: 'Address'
353
- }),
354
- /*#__PURE__*/ _jsx(ContactAddressFields, {
355
- value: address,
356
- onChange: setAddress
357
- }),
358
325
  fields.active.length ? /*#__PURE__*/ _jsxs(_Fragment, {
359
326
  children: [
360
327
  /*#__PURE__*/ _jsx(Typography, {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../../libs/plugins/crm/src/lib/components/new-lead-drawer.tsx"],"sourcesContent":["'use client'\n\nimport {\n CRM_LEAD_STATUS_LABELS,\n CRM_LEAD_TEXT_MAX,\n type CrmCustomValue,\n type CrmLeadStatus,\n containerMembershipValue,\n crmPicklistDefaultLabel,\n normalizeCrmLeadTags,\n normalizeContactEmail,\n normalizeCrmLeadProfile,\n type AglynPostalAddress,\n} from '@aglyn/aglyn'\nimport { ICON_VARIANT_CLOSE } from '@aglyn/shared-data-enums'\nimport { Container, MdiIcon, SrOnly } from '@aglyn/shared-ui-jsx'\nimport { NavigationDrawerComponent } from '@aglyn/shared-ui-jsx/components/navigation-drawer.component'\nimport {\n Alert,\n Button,\n IconButton,\n MenuItem,\n Stack,\n TextField,\n Typography,\n} from '@mui/material'\nimport ContainerPicker from '@aglyn/tenant-feature-instance/components/container-picker'\nimport { useEffect, useState } from 'react'\nimport { useContactFieldDefinitions } from '../hooks/use-contact-field-definitions'\nimport { useCrmCampaigns } from '../hooks/use-crm-campaigns'\nimport { useCrmScope } from '../hooks/use-crm-scope'\nimport type { OrgMemberOptions } from '../hooks/use-org-member-options'\nimport {\n ContactAddressFields,\n EMPTY_ADDRESS,\n type AddressDraft,\n} from './contact-address-fields'\nimport { CrmSitePicker } from './crm-site-picker'\nimport { CrmCustomFieldControl } from './crm-custom-field-control'\nimport {\n type CrmCustomDraft,\n crmCustomDraftDocument,\n crmCustomDraftMissingRequired,\n} from '../model/crm-custom-draft'\nimport { LeadOwnerSelect } from './lead-owner-select'\nimport { LeadSourceSelect } from './lead-source-select'\nimport { useLeadSourcePicklist } from '../hooks/use-lead-source-picklist'\n\n/** What the drawer hands back — already normalized where the route would. */\nexport interface NewLeadValues {\n email: string\n name: string\n company: string\n jobTitle: string\n phone: string\n website: string\n leadSource: string\n status: Extract<CrmLeadStatus, 'new' | 'working'>\n ownerUid: string\n tags: string[]\n /** The site's campaigns to file the lead under (AGL-3254), by id. */\n campaignIds: string[]\n address: AglynPostalAddress | null\n notes: string\n /**\n * The org's custom lead fields (AGL-3272), keyed by each definition's\n * `key`. Absent when the org has defined none, or none was filled — the\n * route stores a `custom` map only when there is one.\n */\n custom?: Record<string, CrmCustomValue>\n}\n\nexport interface NewLeadDrawerProps {\n open: boolean\n onClose: () => void\n /**\n * The site the lead is filed under — a lead is private to one site by\n * path. `null` at the organization level, where the drawer asks which\n * site with a picker and holds its submit until one is named.\n */\n hostId: string | null\n org?: Record<string, unknown> | null\n /** The request is in flight — the form holds still and the button says so. */\n busy?: boolean\n /** What the route answered when it refused, shown above the form. */\n error?: string | null\n /** The team, for the owner picker. */\n roster: OrgMemberOptions\n /**\n * The org the custom lead fields belong to (AGL-3272), as the list\n * already resolved it. `null` while it is in flight — the drawer then\n * shows the standard fields and no custom ones, which is what an org\n * with none defined shows anyway.\n */\n orgId?: string | null\n onSubmit: (values: NewLeadValues) => void\n}\n\nconst NOTES_MAX = 4000\n\n/**\n * ADDING ONE LEAD BY HAND, IN A DRAWER (AGL-3231).\n *\n * Salesforce's New Lead, on the Leads list: a person the team has heard of\n * and not yet qualified, entered with what is known — the address, the\n * name, the company as text, a title, a phone, a website, an address, tags\n * and where they came from. It makes a lead and nothing else: no contact,\n * no company record. Those are the conversion's to create once the lead is\n * real, which is what keeps one person from sitting in two lists.\n *\n * A drawer and not a form above the list, for the reason every list in this\n * console gives. The two fields a person can mistype in a way the record\n * cannot hold — the email and the phone, and the website beside them — are\n * checked before the request leaves, with the same normalizer the route\n * runs, so the refusal lands under the field. Everything else is the\n * route's to decide: whether the site already holds the address (it\n * updates that lead), whether the plan carries the suite, whether the site\n * is at the platform ceiling.\n */\nexport function NewLeadDrawer(props: NewLeadDrawerProps) {\n const { open, onClose, hostId, org, busy, error, roster, orgId, onSubmit } = props\n // The site the route files the lead under: the mounted site, or at the\n // organization level the picked one. `null` until it is known.\n const { createHostId } = useCrmScope({ hostId, org: org as never })\n\n const [email, setEmail] = useState('')\n const [name, setName] = useState('')\n const [company, setCompany] = useState('')\n const [jobTitle, setJobTitle] = useState('')\n const [phone, setPhone] = useState('')\n const [website, setWebsite] = useState('')\n const [leadSource, setLeadSource] = useState('')\n /*\n * THE ORG'S LEAD SOURCES (AGL-3298), and its default for a new record.\n * The default is filled in once the list has answered and only until the\n * person picks something themselves — \"None\" included — so a list that\n * arrives after the drawer opened does not overwrite a choice.\n */\n const leadSources = useLeadSourcePicklist(orgId ?? null)\n const [leadSourceTouched, setLeadSourceTouched] = useState(false)\n const defaultLeadSource = crmPicklistDefaultLabel(leadSources.picklist) ?? ''\n useEffect(() => {\n if (open && !leadSourceTouched) setLeadSource(defaultLeadSource)\n }, [open, leadSourceTouched, defaultLeadSource])\n const [status, setStatus] = useState<NewLeadValues['status']>('new')\n const [ownerUid, setOwnerUid] = useState('')\n const [tags, setTags] = useState('')\n const [campaignIds, setCampaignIds] = useState<string[]>([])\n const [address, setAddress] = useState<AddressDraft>(EMPTY_ADDRESS)\n const [notes, setNotes] = useState('')\n /*\n * The org's own lead fields (AGL-3272). A CREATE holds only a draft —\n * there is no stored map to diff against — and `crmCustomDraftDocument`\n * turns it into the `custom` the route stores, or nothing.\n */\n const fields = useContactFieldDefinitions(orgId ?? null, 'lead')\n const [custom, setCustom] = useState<CrmCustomDraft>({})\n const [customError, setCustomError] = useState('')\n const [emailError, setEmailError] = useState('')\n const [phoneError, setPhoneError] = useState('')\n const [websiteError, setWebsiteError] = useState('')\n /*\n * The campaigns, for the picker (AGL-3254): read while the drawer is\n * open. Under a site, the ones placed on it; at the organization level,\n * every campaign in the org — the lead is the org's record whichever\n * site it is captured by, so the site picked above does not narrow them.\n */\n const campaigns = useCrmCampaigns({ hostId, orgId }, { enabled: open })\n\n // A fresh form on every opening: a person typed and then abandoned must\n // not reappear half-filled the next time somebody reaches for New lead.\n useEffect(() => {\n if (!open) return\n setEmail('')\n setName('')\n setCompany('')\n setJobTitle('')\n setPhone('')\n setWebsite('')\n setLeadSource('')\n setLeadSourceTouched(false)\n setStatus('new')\n setOwnerUid('')\n setTags('')\n setCampaignIds([])\n setAddress(EMPTY_ADDRESS)\n setNotes('')\n setCustom({})\n setCustomError('')\n setEmailError('')\n setPhoneError('')\n setWebsiteError('')\n }, [open])\n\n const handleSubmit = () => {\n const normalizedEmail = normalizeContactEmail(email)\n const { patch, errors } = normalizeCrmLeadProfile({\n company,\n jobTitle,\n phone,\n website,\n leadSource,\n address,\n tags: normalizeCrmLeadTags(tags),\n })\n // Every required lead field counts on a create: the record is being\n // made whole, and nothing has been written to come back and fill.\n const missing = crmCustomDraftMissingRequired(fields.active, {}, custom, 'create')\n setEmailError(normalizedEmail ? '' : 'Enter a valid email address.')\n setPhoneError(errors.phone ?? '')\n setWebsiteError(errors.website ?? '')\n setCustomError(\n missing.length\n ? `${missing.join(', ')} ${missing.length > 1 ? 'are' : 'is'} required.`\n : '',\n )\n if (!normalizedEmail || errors.phone || errors.website || missing.length) return\n onSubmit({\n email: normalizedEmail,\n name: name.trim().replace(/\\s+/g, ' ').slice(0, CRM_LEAD_TEXT_MAX),\n company: patch.company ?? '',\n jobTitle: patch.jobTitle ?? '',\n phone: patch.phone ?? '',\n website: patch.website ?? '',\n leadSource: patch.leadSource ?? '',\n status,\n ownerUid,\n tags: patch.tags ?? [],\n campaignIds: containerMembershipValue(campaignIds),\n address: patch.address ?? null,\n notes: notes.trim().slice(0, NOTES_MAX),\n custom: crmCustomDraftDocument(custom),\n })\n }\n\n return (\n <NavigationDrawerComponent\n open={open}\n anchor=\"right\"\n variant=\"temporary\"\n onClose={onClose}\n AppBarProps={{ color: 'surface' }}\n sx={{ '& .MuiDrawer-paper': { width: { xs: '100%', sm: 480 } } }}\n appBarLeft={\n <>\n <IconButton\n color=\"inherit\"\n edge=\"start\"\n onClick={onClose}\n sx={{ mr: 2 }}\n >\n <MdiIcon path={ICON_VARIANT_CLOSE.path} />\n <SrOnly>close drawer</SrOnly>\n </IconButton>\n <Typography variant=\"h6\" component=\"div\">\n {'New lead'}\n </Typography>\n </>\n }\n appBarRight={\n <Button variant=\"outlined\" color=\"inherit\" onClick={onClose}>\n {'Cancel'}\n </Button>\n }\n >\n <Container gutterY>\n <Stack spacing={2}>\n {error ? <Alert severity=\"warning\">{error}</Alert> : null}\n {/* First, because the lead is filed under the answer. Renders nothing under a site. */}\n <CrmSitePicker\n hostId={hostId}\n disabled={Boolean(busy)}\n helperText=\"The site this lead is filed under — a lead is private to one site.\"\n />\n <TextField\n size=\"small\"\n label=\"Email\"\n type=\"email\"\n value={email}\n onChange={(event) => setEmail(event.target.value)}\n error={Boolean(emailError)}\n helperText={\n emailError ||\n 'The one field that is required — a site holds one lead per address.'\n }\n required\n fullWidth\n autoFocus\n />\n <TextField\n size=\"small\"\n label=\"Name\"\n value={name}\n onChange={(event) => setName(event.target.value)}\n slotProps={{ htmlInput: { maxLength: CRM_LEAD_TEXT_MAX } }}\n fullWidth\n />\n <TextField\n size=\"small\"\n label=\"Company\"\n value={company}\n onChange={(event) => setCompany(event.target.value)}\n helperText=\"As text — converting the lead is what makes it a company record.\"\n slotProps={{ htmlInput: { maxLength: CRM_LEAD_TEXT_MAX } }}\n fullWidth\n />\n <TextField\n size=\"small\"\n label=\"Job title\"\n value={jobTitle}\n onChange={(event) => setJobTitle(event.target.value)}\n slotProps={{ htmlInput: { maxLength: CRM_LEAD_TEXT_MAX } }}\n fullWidth\n />\n <TextField\n size=\"small\"\n label=\"Phone\"\n value={phone}\n onChange={(event) => setPhone(event.target.value)}\n error={Boolean(phoneError)}\n helperText={\n phoneError || 'With the country code, like +1 512 555 0107'\n }\n fullWidth\n />\n <TextField\n size=\"small\"\n label=\"Website\"\n value={website}\n onChange={(event) => setWebsite(event.target.value)}\n error={Boolean(websiteError)}\n helperText={websiteError || 'Like acme.com'}\n fullWidth\n />\n <LeadSourceSelect\n picklist={leadSources.picklist}\n value={leadSource}\n onChange={(label) => {\n setLeadSource(label)\n setLeadSourceTouched(true)\n }}\n disabled={Boolean(busy)}\n helperText=\"Where this lead came from. The choices are kept under CRM › Fields › Leads.\"\n />\n <Stack direction={{ xs: 'column', sm: 'row' }} spacing={2}>\n <TextField\n select\n size=\"small\"\n label=\"Status\"\n value={status}\n onChange={(event) =>\n setStatus(event.target.value as NewLeadValues['status'])\n }\n fullWidth\n >\n <MenuItem value=\"new\">{CRM_LEAD_STATUS_LABELS.new}</MenuItem>\n <MenuItem value=\"working\">\n {CRM_LEAD_STATUS_LABELS.working}\n </MenuItem>\n </TextField>\n <LeadOwnerSelect\n value={ownerUid}\n onChange={setOwnerUid}\n roster={roster}\n />\n </Stack>\n <TextField\n size=\"small\"\n label=\"Tags\"\n placeholder=\"icp2, a-list\"\n helperText=\"Comma-separated\"\n value={tags}\n onChange={(event) => setTags(event.target.value)}\n fullWidth\n />\n {/*\n The campaigns to file the lead under (AGL-3254), picked the way a\n form's page picks them. Grouping, not consent: it decides which\n campaign pages list the lead, never whether anything mails them.\n */}\n <ContainerPicker\n kind=\"campaign\"\n options={campaigns.options}\n value={campaignIds}\n onChange={setCampaignIds}\n helperText=\"The campaigns this lead is part of. It does not decide who a campaign mails.\"\n disabled={Boolean(busy)}\n empty={campaigns.ready && !campaigns.options.length}\n emptyText={\n hostId\n ? 'This site has no campaigns yet. Create one from Marketing to file leads under it.'\n : 'There are no campaigns yet. Create one from Marketing to file leads under it.'\n }\n />\n <Typography variant=\"subtitle2\">{'Address'}</Typography>\n <ContactAddressFields value={address} onChange={setAddress} />\n {/* The org's own lead fields (AGL-3272), the same controls the\n lead's page edits them with. */}\n {fields.active.length ? (\n <>\n <Typography variant=\"subtitle2\">{'Custom fields'}</Typography>\n {customError ? <Alert severity=\"warning\">{customError}</Alert> : null}\n {fields.active.map((definition) => (\n <CrmCustomFieldControl\n key={definition.$id}\n definition={definition}\n value={custom[definition.key]}\n onChange={(value) =>\n setCustom((current) => ({ ...current, [definition.key]: value }))\n }\n disabled={Boolean(busy)}\n />\n ))}\n </>\n ) : null}\n <TextField\n size=\"small\"\n label=\"Notes\"\n value={notes}\n onChange={(event) => setNotes(event.target.value)}\n multiline\n minRows={2}\n slotProps={{ htmlInput: { maxLength: NOTES_MAX } }}\n fullWidth\n />\n <Button\n variant=\"contained\"\n color=\"primary\"\n // Held until the site is known: the route files the lead under it.\n disabled={Boolean(busy) || !createHostId}\n onClick={handleSubmit}\n >\n {busy ? 'Adding…' : 'Add lead'}\n </Button>\n </Stack>\n </Container>\n </NavigationDrawerComponent>\n )\n}\n\nexport default NewLeadDrawer\n"],"names":["CRM_LEAD_STATUS_LABELS","CRM_LEAD_TEXT_MAX","containerMembershipValue","crmPicklistDefaultLabel","normalizeCrmLeadTags","normalizeContactEmail","normalizeCrmLeadProfile","ICON_VARIANT_CLOSE","Container","MdiIcon","SrOnly","NavigationDrawerComponent","Alert","Button","IconButton","MenuItem","Stack","TextField","Typography","ContainerPicker","useEffect","useState","useContactFieldDefinitions","useCrmCampaigns","useCrmScope","ContactAddressFields","EMPTY_ADDRESS","CrmSitePicker","CrmCustomFieldControl","crmCustomDraftDocument","crmCustomDraftMissingRequired","LeadOwnerSelect","LeadSourceSelect","useLeadSourcePicklist","NOTES_MAX","NewLeadDrawer","props","open","onClose","hostId","org","busy","error","roster","orgId","onSubmit","createHostId","email","setEmail","name","setName","company","setCompany","jobTitle","setJobTitle","phone","setPhone","website","setWebsite","leadSource","setLeadSource","leadSources","leadSourceTouched","setLeadSourceTouched","defaultLeadSource","picklist","status","setStatus","ownerUid","setOwnerUid","tags","setTags","campaignIds","setCampaignIds","address","setAddress","notes","setNotes","fields","custom","setCustom","customError","setCustomError","emailError","setEmailError","phoneError","setPhoneError","websiteError","setWebsiteError","campaigns","enabled","handleSubmit","errors","patch","normalizedEmail","missing","active","length","join","trim","replace","slice","anchor","variant","AppBarProps","color","sx","width","xs","sm","appBarLeft","edge","onClick","mr","path","component","appBarRight","gutterY","spacing","severity","disabled","Boolean","helperText","size","label","type","value","onChange","event","target","required","fullWidth","autoFocus","slotProps","htmlInput","maxLength","direction","select","new","working","placeholder","kind","options","empty","ready","emptyText","map","definition","key","current","$id","multiline","minRows"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/crm/src/lib/components/new-lead-drawer.tsx"],"sourcesContent":["'use client'\n\nimport {\n CRM_LEAD_TEXT_MAX,\n type CrmCustomValue,\n type CrmLeadStatus,\n crmLeadStatusLabelFor,\n crmLeadStatusOptions,\n containerMembershipValue,\n crmLeadComposedName,\n type CrmLeadProfilePatch,\n crmPicklistDefaultLabel,\n normalizeContactEmail,\n normalizeCrmLeadProfile,\n type AglynPostalAddress,\n} from '@aglyn/aglyn'\nimport { ICON_VARIANT_CLOSE } from '@aglyn/shared-data-enums'\nimport { Container, MdiIcon, SrOnly } from '@aglyn/shared-ui-jsx'\nimport { NavigationDrawerComponent } from '@aglyn/shared-ui-jsx/components/navigation-drawer.component'\nimport {\n Alert,\n Button,\n IconButton,\n MenuItem,\n Stack,\n TextField,\n Typography,\n} from '@mui/material'\nimport ContainerPicker from '@aglyn/tenant-feature-instance/components/container-picker'\nimport { useEffect, useState } from 'react'\nimport { useContactFieldDefinitions } from '../hooks/use-contact-field-definitions'\nimport { useCrmCampaigns } from '../hooks/use-crm-campaigns'\nimport { useCrmScope } from '../hooks/use-crm-scope'\nimport type { OrgMemberOptions } from '../hooks/use-org-member-options'\nimport {\n EMPTY_LEAD_PROFILE_DRAFT,\n leadDraftComposedName,\n LeadProfileFields,\n type LeadProfileDraft,\n leadProfileDraftBody,\n} from './lead-profile-fields'\nimport { CrmSitePicker } from './crm-site-picker'\nimport { CrmCustomFieldControl } from './crm-custom-field-control'\nimport {\n type CrmCustomDraft,\n crmCustomDraftDocument,\n crmCustomDraftMissingRequired,\n} from '../model/crm-custom-draft'\nimport { LeadOwnerSelect } from './lead-owner-select'\nimport { useLeadSourcePicklist } from '../hooks/use-lead-source-picklist'\nimport { useLeadPicklists } from '../hooks/use-lead-picklists'\nimport { useLeadStatusPicklist } from '../hooks/use-lead-status-picklist'\n\n/** The meanings a lead is entered in by hand: New or Working (AGL-3231). */\nconst NEW_LEAD_STATUSES: readonly CrmLeadStatus[] = ['new', 'working']\n\n/** What the drawer hands back — already normalized where the route would. */\nexport interface NewLeadValues {\n email: string\n name: string\n company: string\n jobTitle: string\n phone: string\n website: string\n leadSource: string\n /** One of the org's New or Working values, by its label (AGL-3512). */\n status: string\n ownerUid: string\n tags: string[]\n /** The site's campaigns to file the lead under (AGL-3254), by id. */\n campaignIds: string[]\n address: AglynPostalAddress | null\n notes: string\n /**\n * The org's custom lead fields (AGL-3272), keyed by each definition's\n * `key`. Absent when the org has defined none, or none was filled — the\n * route stores a `custom` map only when there is one.\n */\n custom?: Record<string, CrmCustomValue>\n /**\n * Salesforce's standard lead fields (AGL-3513) — salutation, the name's\n * parts, mobile, fax, do not call, industry, rating, size and revenue —\n * normalized as the route stores them, only the ones that were filled.\n */\n standard: Pick<\n CrmLeadProfilePatch,\n | 'salutation'\n | 'firstName'\n | 'lastName'\n | 'mobilePhone'\n | 'fax'\n | 'doNotCall'\n | 'industry'\n | 'rating'\n | 'annualRevenueCents'\n | 'currency'\n | 'numberOfEmployees'\n >\n}\n\nexport interface NewLeadDrawerProps {\n open: boolean\n onClose: () => void\n /**\n * The site the lead is filed under — a lead is private to one site by\n * path. `null` at the organization level, where the drawer asks which\n * site with a picker and holds its submit until one is named.\n */\n hostId: string | null\n org?: Record<string, unknown> | null\n /** The request is in flight — the form holds still and the button says so. */\n busy?: boolean\n /** What the route answered when it refused, shown above the form. */\n error?: string | null\n /** The team, for the owner picker. */\n roster: OrgMemberOptions\n /**\n * The org the custom lead fields belong to (AGL-3272), as the list\n * already resolved it. `null` while it is in flight — the drawer then\n * shows the standard fields and no custom ones, which is what an org\n * with none defined shows anyway.\n */\n orgId?: string | null\n onSubmit: (values: NewLeadValues) => void\n}\n\nconst NOTES_MAX = 4000\n\n/**\n * ADDING ONE LEAD BY HAND, IN A DRAWER (AGL-3231).\n *\n * Salesforce's New Lead, on the Leads list: a person the team has heard of\n * and not yet qualified, entered with what is known — the address, the\n * name, the company as text, a title, a phone, a website, an address, tags\n * and where they came from. It makes a lead and nothing else: no contact,\n * no company record. Those are the conversion's to create once the lead is\n * real, which is what keeps one person from sitting in two lists.\n *\n * A drawer and not a form above the list, for the reason every list in this\n * console gives. The two fields a person can mistype in a way the record\n * cannot hold — the email and the phone, and the website beside them — are\n * checked before the request leaves, with the same normalizer the route\n * runs, so the refusal lands under the field. Everything else is the\n * route's to decide: whether the site already holds the address (it\n * updates that lead), whether the plan carries the suite, whether the site\n * is at the platform ceiling.\n */\nexport function NewLeadDrawer(props: NewLeadDrawerProps) {\n const { open, onClose, hostId, org, busy, error, roster, orgId, onSubmit } = props\n // The site the route files the lead under: the mounted site, or at the\n // organization level the picked one. `null` until it is known.\n const { createHostId } = useCrmScope({ hostId, org: org as never })\n\n const [email, setEmail] = useState('')\n const [name, setName] = useState('')\n /*\n * THE PROFILE (AGL-3231, AGL-3513), one draft the fields edit — the\n * lead's page edits the same draft with the same fields.\n */\n const [profile, setProfile] = useState<LeadProfileDraft>(EMPTY_LEAD_PROFILE_DRAFT)\n const [profileErrors, setProfileErrors] = useState<Record<string, string>>({})\n const editProfile = <K extends keyof LeadProfileDraft>(key: K, value: LeadProfileDraft[K]) =>\n setProfile((current) => ({ ...current, [key]: value }))\n // The org's Salutation, Industry and Rating lists (AGL-3513).\n const leadPicklists = useLeadPicklists(open ? (orgId ?? null) : null)\n /*\n * THE ORG'S LEAD SOURCES (AGL-3298), and its default for a new record.\n * The default is filled in once the list has answered and only until the\n * person picks something themselves — \"None\" included — so a list that\n * arrives after the drawer opened does not overwrite a choice.\n */\n const leadSources = useLeadSourcePicklist(orgId ?? null)\n const [leadSourceTouched, setLeadSourceTouched] = useState(false)\n const defaultLeadSource = crmPicklistDefaultLabel(leadSources.picklist) ?? ''\n useEffect(() => {\n if (open && !leadSourceTouched) {\n setProfile((current) => ({ ...current, leadSource: defaultLeadSource }))\n }\n }, [open, leadSourceTouched, defaultLeadSource])\n // The org's New and Working values (AGL-3512); a new lead starts as New's.\n const leadStatuses = useLeadStatusPicklist(orgId ?? null)\n const statusChoices = crmLeadStatusOptions(leadStatuses.picklist, NEW_LEAD_STATUSES)\n const [status, setStatus] = useState('')\n const shownStatus = statusChoices.some((choice) => choice.label === status)\n ? status\n : crmLeadStatusLabelFor(leadStatuses.picklist, 'new')\n const [ownerUid, setOwnerUid] = useState('')\n const [campaignIds, setCampaignIds] = useState<string[]>([])\n const [notes, setNotes] = useState('')\n /*\n * The org's own lead fields (AGL-3272). A CREATE holds only a draft —\n * there is no stored map to diff against — and `crmCustomDraftDocument`\n * turns it into the `custom` the route stores, or nothing.\n */\n const fields = useContactFieldDefinitions(orgId ?? null, 'lead')\n const [custom, setCustom] = useState<CrmCustomDraft>({})\n const [customError, setCustomError] = useState('')\n const [emailError, setEmailError] = useState('')\n /*\n * The campaigns, for the picker (AGL-3254): read while the drawer is\n * open. Under a site, the ones placed on it; at the organization level,\n * every campaign in the org — the lead is the org's record whichever\n * site it is captured by, so the site picked above does not narrow them.\n */\n const campaigns = useCrmCampaigns({ hostId, orgId }, { enabled: open })\n\n // A fresh form on every opening: a person typed and then abandoned must\n // not reappear half-filled the next time somebody reaches for New lead.\n useEffect(() => {\n if (!open) return\n setEmail('')\n setName('')\n setProfile(EMPTY_LEAD_PROFILE_DRAFT)\n setProfileErrors({})\n setLeadSourceTouched(false)\n setStatus('')\n setOwnerUid('')\n setCampaignIds([])\n setNotes('')\n setCustom({})\n setCustomError('')\n setEmailError('')\n }, [open])\n\n const handleSubmit = () => {\n const normalizedEmail = normalizeContactEmail(email)\n const { body, revenueError } = leadProfileDraftBody(profile)\n const { patch, errors } = normalizeCrmLeadProfile(body)\n const shown: Record<string, string> = { ...errors }\n if (revenueError) shown['annualRevenueCents'] = revenueError\n // Every required lead field counts on a create: the record is being\n // made whole, and nothing has been written to come back and fill.\n const missing = crmCustomDraftMissingRequired(fields.active, {}, custom, 'create')\n setEmailError(normalizedEmail ? '' : 'Enter a valid email address.')\n setProfileErrors(shown)\n setCustomError(\n missing.length\n ? `${missing.join(', ')} ${missing.length > 1 ? 'are' : 'is'} required.`\n : '',\n )\n if (!normalizedEmail || Object.keys(shown).length || missing.length) return\n // Only what was filled: a create has nothing to clear.\n const standard: NewLeadValues['standard'] = {}\n for (const key of [\n 'salutation',\n 'firstName',\n 'lastName',\n 'mobilePhone',\n 'fax',\n 'doNotCall',\n 'industry',\n 'rating',\n 'annualRevenueCents',\n 'currency',\n 'numberOfEmployees',\n ] as const) {\n const value = patch[key]\n if (value !== null && value !== undefined) Object.assign(standard, { [key]: value })\n }\n onSubmit({\n email: normalizedEmail,\n // While a first or last name is typed, the name is theirs (AGL-3513).\n name:\n crmLeadComposedName(null, patch) ??\n name.trim().replace(/\\s+/g, ' ').slice(0, CRM_LEAD_TEXT_MAX),\n company: patch.company ?? '',\n jobTitle: patch.jobTitle ?? '',\n phone: patch.phone ?? '',\n website: patch.website ?? '',\n leadSource: patch.leadSource ?? '',\n status: shownStatus,\n ownerUid,\n tags: patch.tags ?? [],\n campaignIds: containerMembershipValue(campaignIds),\n address: patch.address ?? null,\n notes: notes.trim().slice(0, NOTES_MAX),\n custom: crmCustomDraftDocument(custom),\n standard,\n })\n }\n\n const composedName = leadDraftComposedName(profile)\n\n return (\n <NavigationDrawerComponent\n open={open}\n anchor=\"right\"\n variant=\"temporary\"\n onClose={onClose}\n AppBarProps={{ color: 'surface' }}\n sx={{ '& .MuiDrawer-paper': { width: { xs: '100%', sm: 480 } } }}\n appBarLeft={\n <>\n <IconButton\n color=\"inherit\"\n edge=\"start\"\n onClick={onClose}\n sx={{ mr: 2 }}\n >\n <MdiIcon path={ICON_VARIANT_CLOSE.path} />\n <SrOnly>close drawer</SrOnly>\n </IconButton>\n <Typography variant=\"h6\" component=\"div\">\n {'New lead'}\n </Typography>\n </>\n }\n appBarRight={\n <Button variant=\"outlined\" color=\"inherit\" onClick={onClose}>\n {'Cancel'}\n </Button>\n }\n >\n <Container gutterY>\n <Stack spacing={2}>\n {error ? <Alert severity=\"warning\">{error}</Alert> : null}\n {/* First, because the lead is filed under the answer. Renders nothing under a site. */}\n <CrmSitePicker\n hostId={hostId}\n disabled={Boolean(busy)}\n helperText=\"The site this lead is filed under — a lead is private to one site.\"\n />\n <TextField\n size=\"small\"\n label=\"Email\"\n type=\"email\"\n value={email}\n onChange={(event) => setEmail(event.target.value)}\n error={Boolean(emailError)}\n helperText={\n emailError ||\n 'The one field that is required — a site holds one lead per address.'\n }\n required\n fullWidth\n autoFocus\n />\n <TextField\n size=\"small\"\n label=\"Name\"\n value={composedName || name}\n onChange={(event) => setName(event.target.value)}\n slotProps={{\n htmlInput: { maxLength: CRM_LEAD_TEXT_MAX },\n input: { readOnly: Boolean(composedName) },\n }}\n helperText={\n composedName ? 'Made of the first and last name.' : 'Or the whole name in one field.'\n }\n fullWidth\n />\n <LeadProfileFields\n draft={profile}\n onChange={(key, value) => {\n if (key === 'leadSource') setLeadSourceTouched(true)\n editProfile(key, value)\n }}\n errors={profileErrors}\n disabled={Boolean(busy)}\n leadSources={leadSources.picklist}\n lists={leadPicklists.lists}\n helperTexts={{\n company: 'As text — converting the lead is what makes it a company record.',\n leadSource:\n 'Where this lead came from. The choices are kept under CRM › Fields › Leads.',\n }}\n />\n <Stack direction={{ xs: 'column', sm: 'row' }} spacing={2}>\n <TextField\n select\n size=\"small\"\n label=\"Status\"\n value={statusChoices.some((choice) => choice.label === shownStatus) ? shownStatus : ''}\n onChange={(event) => setStatus(String(event.target.value))}\n fullWidth\n >\n {statusChoices.map((choice) => (\n <MenuItem key={choice.label} value={choice.label}>\n {choice.label}\n </MenuItem>\n ))}\n </TextField>\n <LeadOwnerSelect\n value={ownerUid}\n onChange={setOwnerUid}\n roster={roster}\n />\n </Stack>\n {/*\n The campaigns to file the lead under (AGL-3254), picked the way a\n form's page picks them. Grouping, not consent: it decides which\n campaign pages list the lead, never whether anything mails them.\n */}\n <ContainerPicker\n kind=\"campaign\"\n options={campaigns.options}\n value={campaignIds}\n onChange={setCampaignIds}\n helperText=\"The campaigns this lead is part of. It does not decide who a campaign mails.\"\n disabled={Boolean(busy)}\n empty={campaigns.ready && !campaigns.options.length}\n emptyText={\n hostId\n ? 'This site has no campaigns yet. Create one from Marketing to file leads under it.'\n : 'There are no campaigns yet. Create one from Marketing to file leads under it.'\n }\n />\n {/* The org's own lead fields (AGL-3272), the same controls the\n lead's page edits them with. */}\n {fields.active.length ? (\n <>\n <Typography variant=\"subtitle2\">{'Custom fields'}</Typography>\n {customError ? <Alert severity=\"warning\">{customError}</Alert> : null}\n {fields.active.map((definition) => (\n <CrmCustomFieldControl\n key={definition.$id}\n definition={definition}\n value={custom[definition.key]}\n onChange={(value) =>\n setCustom((current) => ({ ...current, [definition.key]: value }))\n }\n disabled={Boolean(busy)}\n />\n ))}\n </>\n ) : null}\n <TextField\n size=\"small\"\n label=\"Notes\"\n value={notes}\n onChange={(event) => setNotes(event.target.value)}\n multiline\n minRows={2}\n slotProps={{ htmlInput: { maxLength: NOTES_MAX } }}\n fullWidth\n />\n <Button\n variant=\"contained\"\n color=\"primary\"\n // Held until the site is known: the route files the lead under it.\n disabled={Boolean(busy) || !createHostId}\n onClick={handleSubmit}\n >\n {busy ? 'Adding…' : 'Add lead'}\n </Button>\n </Stack>\n </Container>\n </NavigationDrawerComponent>\n )\n}\n\nexport default NewLeadDrawer\n"],"names":["CRM_LEAD_TEXT_MAX","crmLeadStatusLabelFor","crmLeadStatusOptions","containerMembershipValue","crmLeadComposedName","crmPicklistDefaultLabel","normalizeContactEmail","normalizeCrmLeadProfile","ICON_VARIANT_CLOSE","Container","MdiIcon","SrOnly","NavigationDrawerComponent","Alert","Button","IconButton","MenuItem","Stack","TextField","Typography","ContainerPicker","useEffect","useState","useContactFieldDefinitions","useCrmCampaigns","useCrmScope","EMPTY_LEAD_PROFILE_DRAFT","leadDraftComposedName","LeadProfileFields","leadProfileDraftBody","CrmSitePicker","CrmCustomFieldControl","crmCustomDraftDocument","crmCustomDraftMissingRequired","LeadOwnerSelect","useLeadSourcePicklist","useLeadPicklists","useLeadStatusPicklist","NEW_LEAD_STATUSES","NOTES_MAX","NewLeadDrawer","props","open","onClose","hostId","org","busy","error","roster","orgId","onSubmit","createHostId","email","setEmail","name","setName","profile","setProfile","profileErrors","setProfileErrors","editProfile","key","value","current","leadPicklists","leadSources","leadSourceTouched","setLeadSourceTouched","defaultLeadSource","picklist","leadSource","leadStatuses","statusChoices","status","setStatus","shownStatus","some","choice","label","ownerUid","setOwnerUid","campaignIds","setCampaignIds","notes","setNotes","fields","custom","setCustom","customError","setCustomError","emailError","setEmailError","campaigns","enabled","handleSubmit","patch","normalizedEmail","body","revenueError","errors","shown","missing","active","length","join","Object","keys","standard","undefined","assign","trim","replace","slice","company","jobTitle","phone","website","tags","address","composedName","anchor","variant","AppBarProps","color","sx","width","xs","sm","appBarLeft","edge","onClick","mr","path","component","appBarRight","gutterY","spacing","severity","disabled","Boolean","helperText","size","type","onChange","event","target","required","fullWidth","autoFocus","slotProps","htmlInput","maxLength","input","readOnly","draft","lists","helperTexts","direction","select","String","map","kind","options","empty","ready","emptyText","definition","$id","multiline","minRows"],"mappings":"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"}
@@ -0,0 +1,36 @@
1
+ import { type CrmPicklist, type CrmPicklistId } from '@aglyn/aglyn';
2
+ export interface CrmPicklistSelectProps {
3
+ /** Which of the CRM's standard picklists the field is. */
4
+ picklistId: CrmPicklistId;
5
+ picklist: CrmPicklist;
6
+ /** The label the record holds, or `''` for none. */
7
+ value: string;
8
+ onChange: (label: string) => void;
9
+ /**
10
+ * What the record held when the form opened. Kept in the menu while the
11
+ * list no longer offers it — deactivated, or written before the list
12
+ * held it — so the select shows what is stored until somebody changes it.
13
+ */
14
+ stored?: string;
15
+ disabled?: boolean;
16
+ helperText?: string;
17
+ error?: boolean;
18
+ /** The field's label, when a record names it otherwise than the list does. */
19
+ label?: string;
20
+ }
21
+ /**
22
+ * A standard picklist's select (AGL-3298, AGL-3510): the org's active
23
+ * values in the order the Fields page keeps them, a "None" to clear, and
24
+ * the record's own value when the list would not otherwise show it —
25
+ * marked, and selectable only as what it already is. A definition with
26
+ * groups lists its values under a heading per group, in the definition's
27
+ * order, with ungrouped values last.
28
+ *
29
+ * MUI's select `TextField`, the control every CRM form in this plugin uses
30
+ * for a fixed choice, so it sizes, labels and disables like its neighbors.
31
+ */
32
+ export declare function CrmPicklistSelect(props: CrmPicklistSelectProps): import("react").JSX.Element;
33
+ export declare namespace CrmPicklistSelect {
34
+ var displayName: string;
35
+ }
36
+ export default CrmPicklistSelect;
@@ -0,0 +1,114 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Aglyn LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */ 'use client';
17
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
18
+ import { crmPicklistDefinition, crmPicklistOptions, groupPicklistOptions } from "@aglyn/aglyn";
19
+ import { ListItemText, ListSubheader, 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(option) {
22
+ if (option.inactive) return `${option.label} (inactive)`;
23
+ if (option.unlisted) return `${option.label} (not in the list)`;
24
+ return option.label;
25
+ }
26
+ /**
27
+ * A standard picklist's select (AGL-3298, AGL-3510): the org's active
28
+ * values in the order the Fields page keeps them, a "None" to clear, and
29
+ * the record's own value when the list would not otherwise show it —
30
+ * marked, and selectable only as what it already is. A definition with
31
+ * groups lists its values under a heading per group, in the definition's
32
+ * order, with ungrouped values last.
33
+ *
34
+ * MUI's select `TextField`, the control every CRM form in this plugin uses
35
+ * for a fixed choice, so it sizes, labels and disables like its neighbors.
36
+ */ export function CrmPicklistSelect(props) {
37
+ var _ref, _ref1;
38
+ const { picklistId, picklist, value, onChange, stored, disabled, helperText, error, label } = props;
39
+ const definition = crmPicklistDefinition(picklistId);
40
+ const options = useMemo(()=>crmPicklistOptions(picklist, stored || value), [
41
+ picklist,
42
+ stored,
43
+ value
44
+ ]);
45
+ const selected = options.find((option)=>option.label === value);
46
+ const item = (option)=>/*#__PURE__*/ _jsx(MenuItem, {
47
+ value: option.label,
48
+ // A kept value is shown so the record reads true, not offered as a
49
+ // choice for a record that does not hold it already.
50
+ disabled: (option.inactive || option.unlisted) && option.label !== (stored || value),
51
+ children: /*#__PURE__*/ _jsx(ListItemText, {
52
+ primary: optionText(option),
53
+ slotProps: option.inactive || option.unlisted ? {
54
+ primary: {
55
+ color: 'text.secondary'
56
+ }
57
+ } : undefined
58
+ })
59
+ }, option.label);
60
+ // The menu's children flat — a Select reads its options from its direct
61
+ // children, so the headings sit between them rather than around them.
62
+ const groups = (_ref = definition == null ? void 0 : definition.groups) != null ? _ref : [];
63
+ const items = groups.length ? groupPicklistOptions(options, groups).flatMap((section)=>{
64
+ var _ref, _ref1;
65
+ var _section_group, _section_group1;
66
+ return [
67
+ /*#__PURE__*/ _jsx(ListSubheader, {
68
+ children: (_ref = (_section_group = section.group) == null ? void 0 : _section_group.label) != null ? _ref : 'No group'
69
+ }, `group:${(_ref1 = (_section_group1 = section.group) == null ? void 0 : _section_group1.id) != null ? _ref1 : ''}`),
70
+ ...section.options.map(item)
71
+ ];
72
+ }) : options.map(item);
73
+ return /*#__PURE__*/ _jsxs(TextField, {
74
+ select: true,
75
+ size: "small",
76
+ label: (_ref1 = label != null ? label : definition == null ? void 0 : definition.label) != null ? _ref1 : 'Value',
77
+ value: selected ? value : '',
78
+ onChange: (event)=>onChange(String(event.target.value)),
79
+ disabled: disabled,
80
+ helperText: helperText,
81
+ error: error,
82
+ fullWidth: true,
83
+ slotProps: {
84
+ select: {
85
+ displayEmpty: true,
86
+ renderValue: (current)=>{
87
+ const option = options.find((entry)=>entry.label === current);
88
+ return option ? optionText(option) : 'None';
89
+ }
90
+ },
91
+ inputLabel: {
92
+ shrink: true
93
+ }
94
+ },
95
+ children: [
96
+ /*#__PURE__*/ _jsx(MenuItem, {
97
+ value: "",
98
+ children: /*#__PURE__*/ _jsx(ListItemText, {
99
+ primary: "None",
100
+ slotProps: {
101
+ primary: {
102
+ color: 'text.secondary'
103
+ }
104
+ }
105
+ })
106
+ }),
107
+ items
108
+ ]
109
+ });
110
+ }
111
+ CrmPicklistSelect.displayName = 'CrmPicklistSelect';
112
+ export default CrmPicklistSelect;
113
+
114
+ //# sourceMappingURL=picklist-select.js.map