@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
@@ -51,6 +51,16 @@ export interface DealEditDrawerProps {
51
51
  * `contactChoicesFor` for why the contact search cannot be a query. Both
52
52
  * pickers copy the chosen NAME onto the deal beside the id, so a board of
53
53
  * cards can caption itself without a read per card.
54
+ *
55
+ * ## Salesforce's Opportunity fields (AGL-3516)
56
+ *
57
+ * Type and Lead source are the org's picklists, judged on save as every
58
+ * server door judges them (`judgeDealFormPicklists`) — a new deal with no
59
+ * Type takes the list's default. The probability is this deal's own
60
+ * override, blank for its stage's; the forecast category is one of the
61
+ * fixed set, "From the stage" storing the stage's. A stage move later
62
+ * stamps both afresh. The campaign is one of the campaigns the Campaigns
63
+ * picker of a lead offers at this level.
54
64
  */
55
65
  export declare function DealEditDrawer(props: DealEditDrawerProps): import("react").JSX.Element;
56
66
  export declare namespace DealEditDrawer {
@@ -17,7 +17,7 @@
17
17
  import { _ as _extends } from "@swc/helpers/_/_extends";
18
18
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
19
19
  import { createElement as _createElement } from "react";
20
- import { CRM_COLLECTIONS, CRM_RECORDS_BAND_FULL_MESSAGE, crmNewRecordListFields, dealHasLineItems, findOrgMember, nameSearchKey, crmMemberPickerLabel } from "@aglyn/aglyn";
20
+ import { CRM_COLLECTIONS, CRM_FORECAST_CATEGORIES, CRM_FORECAST_CATEGORY_LABELS, CRM_RECORDS_BAND_FULL_MESSAGE, crmNewRecordListFields, DEAL_NEXT_STEP_MAX, dealHasLineItems, dealStageById, dealStageForecastCategory, findOrgMember, nameSearchKey, crmMemberPickerLabel } from "@aglyn/aglyn";
21
21
  import { ICON_VARIANT_CLOSE } from "@aglyn/shared-data-enums";
22
22
  import { Container, MdiIcon, SrOnly } from "@aglyn/shared-ui-jsx";
23
23
  import { NavigationDrawerComponent } from "@aglyn/shared-ui-jsx/components/navigation-drawer.component";
@@ -28,16 +28,19 @@ import { addDoc, collection, deleteField, doc, endAt, getDocs, limit, orderBy, q
28
28
  import { useCallback, useEffect, useMemo, useState } from "react";
29
29
  import { useContactFieldDefinitions } from "../hooks/use-contact-field-definitions.js";
30
30
  import { useCrmActivityLogger } from "../hooks/use-crm-activity-logger.js";
31
+ import { useCrmCampaigns } from "../hooks/use-crm-campaigns.js";
32
+ import { useCrmPicklist } from "../hooks/use-crm-picklist.js";
31
33
  import { useCrmRecordsQuota } from "../hooks/use-crm-records-quota.js";
32
34
  import { crmScopeListable, crmVisibleToClause, useCrmScope } from "../hooks/use-crm-scope.js";
33
35
  import { useOrgMemberDirectory } from "../hooks/use-org-member-directory.js";
34
36
  import { contactPrimaryGroup } from "../model/contact-record.js";
35
37
  import { crmCustomDraftDocument, crmCustomDraftMissingRequired, crmCustomDraftValue, crmCustomDraftWrites } from "../model/crm-custom-draft.js";
36
38
  import { CrmCustomFieldControl } from "./crm-custom-field-control.js";
39
+ import { CrmPicklistSelect } from "./picklist-select.js";
37
40
  import { CrmSitePicker } from "./crm-site-picker.js";
38
- import { CRM_CLIENT_SEARCH_FIELDS, crmClientListFields } from "../model/crm-list-query.js";
41
+ import { CRM_CLIENT_SEARCH_FIELDS, CRM_DEAL_CONTACT_ROLE_LIST_FIELDS, crmClientListFields } from "../model/crm-list-query.js";
39
42
  import { DEAL_CURRENCIES, openStages } from "../model/deal-board-model.js";
40
- import { contactChoicesFor, DEAL_NOTES_MAX, DEAL_TITLE_MAX, dealDocumentFromForm, dealFormFromDoc, dealFormProblem, dealPatchFromForm, emptyDealForm } from "../model/deal-form-model.js";
43
+ import { contactChoicesFor, DEAL_NOTES_MAX, DEAL_TITLE_MAX, dealDocumentFromForm, dealFormFromDoc, dealFormProblem, dealPatchFromForm, emptyDealForm, judgeDealFormPicklists } from "../model/deal-form-model.js";
41
44
  import { useCrmSharingFollowUp } from "../hooks/use-crm-sharing.js";
42
45
  /**
43
46
  * How many recent contacts the picker matches against. The window is the
@@ -46,6 +49,13 @@ import { useCrmSharingFollowUp } from "../hooks/use-crm-sharing.js";
46
49
  * the match tests as a prefix of the email.
47
50
  */ const CONTACT_WINDOW = 300;
48
51
  /** Companies offered per keystroke; a longer list is a scroll, not a pick. */ const COMPANY_MATCHES = 8;
52
+ /** The list fields an edit restamps: the title's search words, the two picklist keys. */ const DEAL_CLIENT_LIST_FIELDS = [
53
+ ...CRM_CLIENT_SEARCH_FIELDS,
54
+ 'typeKey',
55
+ 'leadSourceKey',
56
+ // The arrays a deal's contact roles are found by (AGL-3521).
57
+ ...CRM_DEAL_CONTACT_ROLE_LIST_FIELDS
58
+ ];
49
59
  /**
50
60
  * The one form a deal is created and edited through (AGL-2598).
51
61
  *
@@ -73,8 +83,18 @@ import { useCrmSharingFollowUp } from "../hooks/use-crm-sharing.js";
73
83
  * `contactChoicesFor` for why the contact search cannot be a query. Both
74
84
  * pickers copy the chosen NAME onto the deal beside the id, so a board of
75
85
  * cards can caption itself without a read per card.
86
+ *
87
+ * ## Salesforce's Opportunity fields (AGL-3516)
88
+ *
89
+ * Type and Lead source are the org's picklists, judged on save as every
90
+ * server door judges them (`judgeDealFormPicklists`) — a new deal with no
91
+ * Type takes the list's default. The probability is this deal's own
92
+ * override, blank for its stage's; the forecast category is one of the
93
+ * fixed set, "From the stage" storing the stage's. A stage move later
94
+ * stamps both afresh. The campaign is one of the campaigns the Campaigns
95
+ * picker of a lead offers at this level.
76
96
  */ export function DealEditDrawer(props) {
77
- var _ref, _dealFormProblem;
97
+ var _ref, _dealFormProblem, _ref1, _ref2;
78
98
  var _contactChoices_find;
79
99
  const { open, onClose, hostId, org, deal, defaults, pipelines, defaultPipeline, unreadable = false, fromCache = false, onSaved } = props;
80
100
  const mode = deal ? 'edit' : 'create';
@@ -102,6 +122,15 @@ import { useCrmSharingFollowUp } from "../hooks/use-crm-sharing.js";
102
122
  * the reader has touched over what the deal stores — saved as the
103
123
  * difference (`crm-custom-draft`) in the same write as the fixed fields.
104
124
  */ const fields = useContactFieldDefinitions(open ? orgId : null, 'deal');
125
+ // The org's lists for the two picklist fields, and its campaigns (AGL-3516).
126
+ const typeList = useCrmPicklist('opportunityType', open ? orgId : null);
127
+ const leadSourceList = useCrmPicklist('leadSource', open ? orgId : null);
128
+ const campaigns = useCrmCampaigns({
129
+ hostId,
130
+ orgId
131
+ }, {
132
+ enabled: open
133
+ });
105
134
  const storedCustom = useMemo(()=>{
106
135
  var _ref;
107
136
  return (_ref = deal == null ? void 0 : deal.custom) != null ? _ref : {};
@@ -134,6 +163,32 @@ import { useCrmSharingFollowUp } from "../hooks/use-crm-sharing.js";
134
163
  pipeline
135
164
  ]);
136
165
  /*
166
+ * The stage the deal is in — the one picked on a new deal, the stored one
167
+ * on an edit, looked up in the deal's OWN pipeline and never the default's
168
+ * — whose probability and forecast category the blank fields stand for.
169
+ */ const currentStage = useMemo(()=>dealStageById(pipelines.find((entry)=>entry.$id === values.pipelineId), values.stageId), [
170
+ pipelines,
171
+ values.pipelineId,
172
+ values.stageId
173
+ ]);
174
+ const campaignOptions = useMemo(()=>{
175
+ const options = campaigns.options.map((option)=>({
176
+ value: option.value,
177
+ label: option.label
178
+ }));
179
+ // A campaign the deal names but the picker no longer offers stays itself.
180
+ return values.campaignId && !options.some((option)=>option.value === values.campaignId) ? [
181
+ ...options,
182
+ {
183
+ value: values.campaignId,
184
+ label: values.campaignId
185
+ }
186
+ ] : options;
187
+ }, [
188
+ campaigns.options,
189
+ values.campaignId
190
+ ]);
191
+ /*
137
192
  * THE CONTACT WINDOW: the newest contacts this viewer may see, read only
138
193
  * while the drawer is open. Scoped and ordered like the contacts list —
139
194
  * the same `(visibleTo, updatedAt DESC)` index — and bounded, because the
@@ -234,6 +289,21 @@ import { useCrmSharingFollowUp } from "../hooks/use-crm-sharing.js";
234
289
  });
235
290
  return;
236
291
  }
292
+ const judged = judgeDealFormPicklists(values, {
293
+ type: typeList.picklist,
294
+ leadSource: leadSourceList.picklist
295
+ }, {
296
+ current: deal != null ? deal : null,
297
+ created: !deal
298
+ });
299
+ if (judged.ok === false) {
300
+ enqueueSnackbar(judged.error, {
301
+ variant: 'warning',
302
+ persist: false
303
+ });
304
+ return;
305
+ }
306
+ const saved = judged.values;
237
307
  setBusy(true);
238
308
  try {
239
309
  const nowMs = Date.now();
@@ -243,13 +313,18 @@ import { useCrmSharingFollowUp } from "../hooks/use-crm-sharing.js";
243
313
  unreadable,
244
314
  fromCache
245
315
  }, async ()=>{
246
- const { set, clear } = dealPatchFromForm(values, nowMs, {
247
- amountDerived
316
+ const { set, clear } = dealPatchFromForm(saved, nowMs, {
317
+ amountDerived,
318
+ stage: currentStage,
319
+ current: deal
248
320
  });
249
321
  await updateDoc(doc(firestore, 'orgs', orgId, CRM_COLLECTIONS.deals, deal.$id), _extends({}, set, Object.fromEntries(clear.map((key)=>[
250
322
  key,
251
323
  deleteField()
252
- ])), crmCustomDraftWrites(storedCustom, custom), crmClientListFields('deals', deal, set, CRM_CLIENT_SEARCH_FIELDS)));
324
+ ])), crmCustomDraftWrites(storedCustom, custom), crmClientListFields('deals', deal, _extends({}, set, Object.fromEntries(clear.map((key)=>[
325
+ key,
326
+ null
327
+ ]))), DEAL_CLIENT_LIST_FIELDS)));
253
328
  });
254
329
  if (!verdict.ok) {
255
330
  enqueueSnackbar(verdict.message, {
@@ -271,13 +346,14 @@ import { useCrmSharingFollowUp } from "../hooks/use-crm-sharing.js";
271
346
  // again here because a callback can outlive the render that held it.
272
347
  if (!createHostId) return;
273
348
  const customDocument = crmCustomDraftDocument(custom);
274
- const record = _extends({}, dealDocumentFromForm(values, {
349
+ const record = _extends({}, dealDocumentFromForm(saved, {
275
350
  visibleTo: [
276
351
  ...createTokens
277
352
  ],
278
353
  hostId: createHostId,
279
354
  uid: user.uid,
280
- nowMs
355
+ nowMs,
356
+ stage: currentStage
281
357
  }), customDocument ? {
282
358
  custom: customDocument
283
359
  } : {});
@@ -329,7 +405,10 @@ import { useCrmSharingFollowUp } from "../hooks/use-crm-sharing.js";
329
405
  onSaved,
330
406
  onClose,
331
407
  storedCustom,
332
- custom
408
+ custom,
409
+ typeList.picklist,
410
+ leadSourceList.picklist,
411
+ currentStage
333
412
  ]);
334
413
  return /*#__PURE__*/ _jsx(NavigationDrawerComponent, {
335
414
  open: open,
@@ -500,6 +579,108 @@ import { useCrmSharingFollowUp } from "../hooks/use-crm-sharing.js";
500
579
  }
501
580
  }
502
581
  }),
582
+ /*#__PURE__*/ _jsxs(Stack, {
583
+ direction: "row",
584
+ spacing: 1,
585
+ children: [
586
+ /*#__PURE__*/ _jsx(CrmPicklistSelect, {
587
+ picklistId: "opportunityType",
588
+ picklist: typeList.picklist,
589
+ value: values.type,
590
+ stored: (_ref1 = deal == null ? void 0 : deal.type) != null ? _ref1 : '',
591
+ onChange: (type)=>update({
592
+ type
593
+ }),
594
+ disabled: busy
595
+ }),
596
+ /*#__PURE__*/ _jsx(CrmPicklistSelect, {
597
+ picklistId: "leadSource",
598
+ picklist: leadSourceList.picklist,
599
+ value: values.leadSource,
600
+ stored: (_ref2 = deal == null ? void 0 : deal.leadSource) != null ? _ref2 : '',
601
+ onChange: (leadSource)=>update({
602
+ leadSource
603
+ }),
604
+ disabled: busy
605
+ })
606
+ ]
607
+ }),
608
+ /*#__PURE__*/ _jsx(TextField, {
609
+ label: "Next step",
610
+ value: values.nextStep,
611
+ onChange: (event)=>update({
612
+ nextStep: event.target.value
613
+ }),
614
+ fullWidth: true,
615
+ slotProps: {
616
+ htmlInput: {
617
+ maxLength: DEAL_NEXT_STEP_MAX
618
+ }
619
+ }
620
+ }),
621
+ /*#__PURE__*/ _jsxs(Stack, {
622
+ direction: "row",
623
+ spacing: 1,
624
+ sx: {
625
+ alignItems: 'flex-start'
626
+ },
627
+ children: [
628
+ /*#__PURE__*/ _jsx(TextField, {
629
+ label: "Probability",
630
+ value: values.probability,
631
+ onChange: (event)=>update({
632
+ probability: event.target.value
633
+ }),
634
+ placeholder: currentStage ? String(currentStage.probability) : '',
635
+ helperText: currentStage ? `From stage: ${currentStage.probability}%` : 'Blank uses the stage’s',
636
+ sx: {
637
+ flex: 1
638
+ },
639
+ slotProps: {
640
+ htmlInput: {
641
+ inputMode: 'numeric',
642
+ 'aria-label': 'Probability'
643
+ },
644
+ input: {
645
+ endAdornment: '%'
646
+ },
647
+ inputLabel: {
648
+ shrink: true
649
+ }
650
+ }
651
+ }),
652
+ /*#__PURE__*/ _jsxs(TextField, {
653
+ select: true,
654
+ label: "Forecast category",
655
+ value: values.forecastCategory,
656
+ onChange: (event)=>update({
657
+ forecastCategory: event.target.value
658
+ }),
659
+ helperText: "A stage move sets it from the new stage.",
660
+ sx: {
661
+ flex: 1
662
+ },
663
+ slotProps: {
664
+ select: {
665
+ displayEmpty: true
666
+ },
667
+ inputLabel: {
668
+ shrink: true
669
+ }
670
+ },
671
+ children: [
672
+ /*#__PURE__*/ _jsx(MenuItem, {
673
+ value: "",
674
+ children: currentStage ? `From the stage (${CRM_FORECAST_CATEGORY_LABELS[dealStageForecastCategory(currentStage)]})` : 'From the stage'
675
+ }),
676
+ CRM_FORECAST_CATEGORIES.map((category)=>/*#__PURE__*/ _jsx(MenuItem, {
677
+ value: category,
678
+ children: CRM_FORECAST_CATEGORY_LABELS[category]
679
+ }, category))
680
+ ]
681
+ })
682
+ ]
683
+ }),
503
684
  /*#__PURE__*/ _jsxs(TextField, {
504
685
  select: true,
505
686
  label: "Owner",
@@ -597,6 +778,34 @@ import { useCrmSharingFollowUp } from "../hooks/use-crm-sharing.js";
597
778
  placeholder: "Company name"
598
779
  }))
599
780
  }),
781
+ /*#__PURE__*/ _jsxs(TextField, {
782
+ select: true,
783
+ label: "Campaign",
784
+ value: values.campaignId,
785
+ onChange: (event)=>update({
786
+ campaignId: event.target.value
787
+ }),
788
+ fullWidth: true,
789
+ helperText: campaigns.ready && !campaignOptions.length ? 'There are no campaigns yet. Create one from Marketing.' : 'The campaign this deal is attributed to.',
790
+ slotProps: {
791
+ select: {
792
+ displayEmpty: true
793
+ },
794
+ inputLabel: {
795
+ shrink: true
796
+ }
797
+ },
798
+ children: [
799
+ /*#__PURE__*/ _jsx(MenuItem, {
800
+ value: "",
801
+ children: 'None'
802
+ }),
803
+ campaignOptions.map((option)=>/*#__PURE__*/ _jsx(MenuItem, {
804
+ value: option.value,
805
+ children: option.label
806
+ }, option.value))
807
+ ]
808
+ }),
600
809
  /*#__PURE__*/ _jsx(TextField, {
601
810
  label: "Notes",
602
811
  value: values.notes,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../../libs/plugins/crm/src/lib/components/deal-edit-drawer.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_COLLECTIONS,\n CRM_RECORDS_BAND_FULL_MESSAGE,\n crmNewRecordListFields,\n dealHasLineItems,\n findOrgMember,\n nameSearchKey,\n crmMemberPickerLabel,\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 { useSnackbar } from '@aglyn/shared-ui-snackstack'\nimport {\n useFirestore,\n useFirestoreCollection,\n useUser,\n writeGuardedBySeed,\n} from '@aglyn/tenant-feature-instance'\nimport {\n Alert,\n Autocomplete,\n Button,\n IconButton,\n MenuItem,\n Stack,\n TextField,\n Typography,\n} from '@mui/material'\nimport {\n addDoc,\n collection,\n deleteField,\n doc,\n endAt,\n getDocs,\n limit,\n orderBy,\n query,\n startAt,\n updateDoc,\n where,\n} from 'firebase/firestore'\nimport { useCallback, useEffect, useMemo, useState } from 'react'\nimport { useContactFieldDefinitions } from '../hooks/use-contact-field-definitions'\nimport { useCrmActivityLogger } from '../hooks/use-crm-activity-logger'\nimport { useCrmRecordsQuota } from '../hooks/use-crm-records-quota'\nimport {\n type CrmOrgDoc,\n crmScopeListable,\n crmVisibleToClause,\n useCrmScope,\n} from '../hooks/use-crm-scope'\nimport { useOrgMemberDirectory } from '../hooks/use-org-member-directory'\nimport { contactPrimaryGroup } from '../model/contact-record'\nimport {\n type CrmCustomDraft,\n crmCustomDraftDocument,\n crmCustomDraftMissingRequired,\n crmCustomDraftValue,\n crmCustomDraftWrites,\n} from '../model/crm-custom-draft'\nimport { CrmCustomFieldControl } from './crm-custom-field-control'\nimport { CrmSitePicker } from './crm-site-picker'\nimport { CRM_CLIENT_SEARCH_FIELDS, crmClientListFields } from '../model/crm-list-query'\nimport {\n DEAL_CURRENCIES,\n type DealDoc,\n openStages,\n type PipelineDoc,\n} from '../model/deal-board-model'\nimport {\n type ContactChoice,\n contactChoicesFor,\n DEAL_NOTES_MAX,\n DEAL_TITLE_MAX,\n dealDocumentFromForm,\n dealFormFromDoc,\n dealFormProblem,\n type DealFormValues,\n dealPatchFromForm,\n emptyDealForm,\n} from '../model/deal-form-model'\nimport { useCrmSharingFollowUp } from '../hooks/use-crm-sharing'\n\n/**\n * How many recent contacts the picker matches against. The window is the\n * ask — it is read when the drawer opens, not when the section does — and\n * a person outside it is still linkable by pasting their address, which\n * the match tests as a prefix of the email.\n */\nconst CONTACT_WINDOW = 300\n\n/** Companies offered per keystroke; a longer list is a scroll, not a pick. */\nconst COMPANY_MATCHES = 8\n\n/** A company as the picker offers it. */\ninterface CompanyChoice {\n id: string\n name: string\n}\n\nexport interface DealEditDrawerProps {\n open: boolean\n onClose: () => void\n /**\n * The site the drawer is opened under, or `null` at the organization\n * level (AGL-2630), where a NEW deal asks which site captures it and an\n * edit keeps the deal's own.\n */\n hostId: string | null\n org: CrmOrgDoc\n /** The deal being edited; absent for a new one. */\n deal?: DealDoc | null\n /** Links and values a new deal opens with — a contact's page passes itself. */\n defaults?: Partial<DealFormValues>\n pipelines: PipelineDoc[]\n /** Where a new deal lands when nobody picks a pipeline. */\n defaultPipeline: PipelineDoc | null\n /** The listener's verdict on the row being edited, for the stale-seed guard. */\n unreadable?: boolean\n fromCache?: boolean\n /** After a save, with the id of the deal written. */\n onSaved?: (dealId: string, mode: 'create' | 'edit') => void\n}\n\n/**\n * The one form a deal is created and edited through (AGL-2598).\n *\n * ## What it writes, and what it does not\n *\n * Client-direct against the rules, like a contact's notes: the title, the\n * amount and its currency, the expected close, the owner, the linked\n * contact and company, and the notes. The stage and the status are shown on\n * a new deal — it has to start somewhere — and never on an existing one,\n * because a stage change is the moment an automation listens for and only\n * the server route can emit that event. A drawer that wrote `stageId`\n * directly would move a deal without anybody hearing it.\n *\n * Nor the amount of a deal that has line items (AGL-2620): it is their\n * sum, the products card on the deal's page owns it, and the field here\n * is read-only with a caption saying so. The pipeline picker on a new\n * deal lists every ACTIVE pipeline (`pipelines`) and opens on the one the\n * caller was looking at.\n *\n * ## The pickers\n *\n * The owner is picked from the org's roster, the company by a server-side\n * prefix on `nameLower` (indexed with the scope), and the contact from a\n * bounded window of the newest contacts matched in memory — see\n * `contactChoicesFor` for why the contact search cannot be a query. Both\n * pickers copy the chosen NAME onto the deal beside the id, so a board of\n * cards can caption itself without a read per card.\n */\nexport function DealEditDrawer(props: DealEditDrawerProps) {\n const {\n open,\n onClose,\n hostId,\n org,\n deal,\n defaults,\n pipelines,\n defaultPipeline,\n unreadable = false,\n fromCache = false,\n onSaved,\n } = props\n const mode: 'create' | 'edit' = deal ? 'edit' : 'create'\n const firestore = useFirestore()\n const { enqueueSnackbar } = useSnackbar()\n const { data: user } = useUser()\n const { orgId, consentGroup, visibleTo, createHostId, createTokens } =\n useCrmScope({ hostId, org })\n // A client-direct write owes the org's sharing rules a re-evaluation (AGL-3336).\n const followUpSharing = useCrmSharingFollowUp(hostId, orgId)\n // The feed the act is logged in is the level it was PERFORMED at\n // (AGL-2738): this site's under a site, the organization's at the org\n // hub. `createHostId` is where the deal is STAMPED, which at the hub is a\n // site the reader picked and may hold no role on — a different question\n // from where the line belongs, and a gate the record write never faced.\n const logActivity = useCrmActivityLogger(hostId)\n const roster = useOrgMemberDirectory(open ? orgId : null)\n\n const [values, setValues] = useState<DealFormValues>(() =>\n emptyDealForm(defaultPipeline, defaults),\n )\n const owner = findOrgMember(roster.members, values.ownerUid)\n const [busy, setBusy] = useState(false)\n /*\n * THE CUSTOM FIELDS (AGL-2661): the org's deal definitions, and the keys\n * the reader has touched over what the deal stores — saved as the\n * difference (`crm-custom-draft`) in the same write as the fixed fields.\n */\n const fields = useContactFieldDefinitions(open ? orgId : null, 'deal')\n const storedCustom = useMemo(() => deal?.custom ?? {}, [deal?.custom])\n const [custom, setCustom] = useState<CrmCustomDraft>({})\n\n // Re-seeded on every open: an existing deal's stored values, or a blank\n // form aimed at the default pipeline with whatever the opener preselected.\n useEffect(() => {\n if (!open) return\n setValues(deal ? dealFormFromDoc(deal) : emptyDealForm(defaultPipeline, defaults))\n setCustom({})\n }, [open, deal, defaultPipeline, defaults])\n\n const update = useCallback(\n (patch: Partial<DealFormValues>) =>\n setValues((current) => ({ ...current, ...patch })),\n [],\n )\n\n const pipeline = useMemo(\n () =>\n pipelines.find((entry) => entry.$id === values.pipelineId) ??\n defaultPipeline,\n [pipelines, values.pipelineId, defaultPipeline],\n )\n const stages = useMemo(() => openStages(pipeline), [pipeline])\n\n /*\n * THE CONTACT WINDOW: the newest contacts this viewer may see, read only\n * while the drawer is open. Scoped and ordered like the contacts list —\n * the same `(visibleTo, updatedAt DESC)` index — and bounded, because the\n * picker's job is to find one person, not to list the audience.\n */\n const { data: contactRows } = useFirestoreCollection<Record<string, unknown>>(\n () =>\n open && orgId && crmScopeListable(visibleTo)\n ? query(\n collection(firestore, 'orgs', orgId, 'contacts'),\n ...crmVisibleToClause(visibleTo),\n orderBy('updatedAt', 'desc'),\n limit(CONTACT_WINDOW),\n )\n : null,\n [firestore, open, orgId, visibleTo],\n { idField: '$id' },\n )\n const [contactQuery, setContactQuery] = useState('')\n // Named through the viewing group under a site; at the organization level\n // through each person's own primary holder.\n const contactChoices = useMemo(\n () =>\n contactChoicesFor(\n contactQuery,\n contactRows ?? [],\n consentGroup?.groupId ??\n ((row) => contactPrimaryGroup(row, org as Record<string, unknown>).groupId),\n ),\n [contactQuery, contactRows, consentGroup, org],\n )\n const contactValue: ContactChoice | null = values.contactId\n ? {\n id: values.contactId,\n name: values.contactName,\n email:\n contactChoices.find((choice) => choice.id === values.contactId)?.email ?? '',\n }\n : null\n\n /*\n * THE COMPANY SEARCH: a prefix on `nameLower` with the scope, which the\n * companies collection indexes. Debounced so a name typed at speed is one\n * query rather than one per letter.\n */\n const [companyQuery, setCompanyQuery] = useState('')\n const [companyChoices, setCompanyChoices] = useState<CompanyChoice[]>([])\n useEffect(() => {\n if (!open || !orgId || !crmScopeListable(visibleTo)) return\n const key = nameSearchKey(companyQuery)\n let active = true\n const timer = setTimeout(() => {\n void getDocs(\n query(\n collection(firestore, 'orgs', orgId, CRM_COLLECTIONS.companies),\n ...crmVisibleToClause(visibleTo),\n orderBy('nameLower'),\n ...(key ? [startAt(key), endAt(`${key}\\uf8ff`)] : []),\n limit(COMPANY_MATCHES),\n ),\n )\n .then((snapshot) => {\n if (!active) return\n setCompanyChoices(\n snapshot.docs.map((entry) => ({\n id: entry.id,\n name: String(entry.get('name') ?? ''),\n })),\n )\n })\n .catch(() => {\n if (active) setCompanyChoices([])\n })\n }, 200)\n return () => {\n active = false\n clearTimeout(timer)\n }\n }, [firestore, open, orgId, visibleTo, companyQuery])\n const companyValue: CompanyChoice | null = values.companyId\n ? { id: values.companyId, name: values.companyName }\n : null\n\n const customMissing = crmCustomDraftMissingRequired(fields.active, storedCustom, custom, mode)\n const problem =\n dealFormProblem(values, mode) ??\n (customMissing.length ? `${customMissing.join(', ')} is required.` : null)\n const amountDerived = Boolean(deal && dealHasLineItems(deal))\n\n /*\n * THE RECORDS BAND (AGL-2611), read only while a CREATE is open: a deal\n * is a record of the band the contacts list is banded by, and on an org\n * at a full hard band this drawer refuses the way `upsertHostContact`\n * refuses a capture — same number, same sentence. Memoized, because the\n * tuple is an effect dependency and a fresh one per render would re-read\n * the three aggregates on every keystroke.\n */\n const recordsScope = useMemo(\n () => (open && mode === 'create' && orgId ? (['orgs', orgId] as const) : null),\n [open, mode, orgId],\n )\n const records = useCrmRecordsQuota(recordsScope, org)\n const bandFull = mode === 'create' && records.ready && !records.quota.allowed\n\n const handleSave = useCallback(async () => {\n if (problem || !orgId || !user?.uid) return\n if (bandFull) {\n enqueueSnackbar(CRM_RECORDS_BAND_FULL_MESSAGE, { variant: 'warning', persist: false })\n return\n }\n setBusy(true)\n try {\n const nowMs = Date.now()\n if (deal) {\n const verdict = await writeGuardedBySeed(\n { subject: 'deal', unreadable, fromCache },\n async () => {\n const { set, clear } = dealPatchFromForm(values, nowMs, { amountDerived })\n await updateDoc(\n doc(firestore, 'orgs', orgId, CRM_COLLECTIONS.deals, deal.$id),\n {\n ...set,\n ...Object.fromEntries(clear.map((key) => [key, deleteField()])),\n // The custom keys that changed, merged into the stored map.\n ...crmCustomDraftWrites(storedCustom, custom),\n // The title is what the Deals table searches (AGL-3321),\n // from the listener's row with the edit over it.\n ...crmClientListFields(\n 'deals',\n deal as unknown as Record<string, unknown>,\n set,\n CRM_CLIENT_SEARCH_FIELDS,\n ),\n },\n )\n },\n )\n if (!verdict.ok) {\n enqueueSnackbar(verdict.message, { variant: 'warning', persist: false })\n return\n }\n followUpSharing('deals', [deal.$id])\n enqueueSnackbar('Deal saved', { variant: 'success', persist: false })\n onSaved?.(deal.$id, 'edit')\n } else {\n // Held by the button until the capturing site is known; checked\n // again here because a callback can outlive the render that held it.\n if (!createHostId) return\n const customDocument = crmCustomDraftDocument(custom)\n const record: Record<string, unknown> = {\n ...dealDocumentFromForm(values, {\n visibleTo: [...createTokens],\n hostId: createHostId,\n uid: user.uid,\n nowMs,\n }),\n ...(customDocument ? { custom: customDocument } : {}),\n }\n const created = await addDoc(\n collection(firestore, 'orgs', orgId, CRM_COLLECTIONS.deals),\n // What the Deals table searches and filters by (AGL-3321), and\n // nothing scheduled against a deal that did not exist.\n { ...record, ...crmNewRecordListFields('deals', record) },\n )\n // Setup → Activity shows CRM work (AGL-2622): the deal is org data,\n // but the act happened in this site's console and belongs in its\n // feed. Creation only — an edit is a save the card reports.\n followUpSharing('deals', [created.id])\n logActivity('Added deal', { type: 'deal', id: created.id, name: values.title })\n enqueueSnackbar('Deal created', { variant: 'success', persist: false })\n onSaved?.(created.id, 'create')\n }\n onClose()\n } catch (error) {\n console.error(error)\n enqueueSnackbar('An error has occurred', {\n variant: 'error',\n allowDuplicate: true,\n })\n } finally {\n setBusy(false)\n }\n }, [\n problem,\n bandFull,\n orgId,\n followUpSharing,\n user,\n deal,\n values,\n unreadable,\n fromCache,\n firestore,\n createTokens,\n createHostId,\n logActivity,\n enqueueSnackbar,\n onSaved,\n onClose,\n storedCustom,\n custom,\n ])\n\n return (\n <NavigationDrawerComponent\n open={open}\n anchor=\"right\"\n variant=\"temporary\"\n onClose={busy ? undefined : onClose}\n AppBarProps={{ color: 'surface' }}\n appBarLeft={\n <>\n <IconButton color=\"inherit\" edge=\"start\" onClick={onClose} sx={{ mr: 2 }}>\n <MdiIcon path={ICON_VARIANT_CLOSE.path} />\n <SrOnly>close drawer</SrOnly>\n </IconButton>\n <Typography variant=\"h6\" component=\"div\">\n {deal ? 'Edit deal' : 'New deal'}\n </Typography>\n </>\n }\n appBarRight={\n <Button variant=\"outlined\" color=\"inherit\" onClick={onClose} disabled={busy}>\n {'Cancel'}\n </Button>\n }\n >\n <Container gutterY>\n <Stack spacing={2} sx={{ width: { xs: '100%', sm: 420 } }}>\n {/*\n First, because the scope of everything below follows from it: at\n the organization level a new deal names the site that captures\n it. Nothing under a site, and nothing on an edit — a deal keeps\n the site it was made on (AGL-2630).\n */}\n {mode === 'create' ? (\n <CrmSitePicker\n hostId={hostId}\n disabled={busy}\n helperText=\"The site this deal belongs to — it decides which of your sites may see it.\"\n />\n ) : null}\n <TextField\n label=\"Title\"\n value={values.title}\n onChange={(event) => update({ title: event.target.value })}\n autoFocus\n fullWidth\n slotProps={{ htmlInput: { maxLength: DEAL_TITLE_MAX } }}\n />\n {mode === 'create' ? (\n <Stack direction=\"row\" spacing={1}>\n <TextField\n select\n label=\"Pipeline\"\n value={pipelines.some((entry) => entry.$id === values.pipelineId) ? values.pipelineId : ''}\n onChange={(event) => {\n const next = pipelines.find(\n (entry) => entry.$id === event.target.value,\n )\n update({\n pipelineId: event.target.value,\n stageId: openStages(next)[0]?.id ?? '',\n })\n }}\n sx={{ flex: 1 }}\n >\n {pipelines.map((entry) => (\n <MenuItem key={entry.$id} value={entry.$id}>\n {entry.name}\n </MenuItem>\n ))}\n </TextField>\n <TextField\n select\n label=\"Stage\"\n value={stages.some((stage) => stage.id === values.stageId) ? values.stageId : ''}\n onChange={(event) => update({ stageId: event.target.value })}\n sx={{ flex: 1 }}\n >\n {stages.map((stage) => (\n <MenuItem key={stage.id} value={stage.id}>\n {stage.name}\n </MenuItem>\n ))}\n </TextField>\n </Stack>\n ) : null}\n <Stack direction=\"row\" spacing={1} sx={{ alignItems: 'flex-start' }}>\n <TextField\n label=\"Amount\"\n value={values.amount}\n onChange={(event) => update({ amount: event.target.value })}\n placeholder=\"0.00\"\n sx={{ flex: 1 }}\n helperText={\n amountDerived\n ? \"The sum of the deal's line items — edit them on the Products card.\"\n : undefined\n }\n slotProps={{\n htmlInput: { inputMode: 'decimal', readOnly: amountDerived },\n }}\n />\n <TextField\n select\n label=\"Currency\"\n value={values.currency}\n onChange={(event) => update({ currency: event.target.value })}\n disabled={amountDerived}\n sx={{ width: 120 }}\n >\n {DEAL_CURRENCIES.map((code) => (\n <MenuItem key={code} value={code}>\n {code.toUpperCase()}\n </MenuItem>\n ))}\n </TextField>\n </Stack>\n <TextField\n type=\"date\"\n label=\"Expected close\"\n value={values.expectedClose}\n onChange={(event) => update({ expectedClose: event.target.value })}\n fullWidth\n slotProps={{ inputLabel: { shrink: true } }}\n />\n <TextField\n select\n label=\"Owner\"\n // The stored owner resolved to a member — by uid, or by an\n // address the roster has — so the picker highlights the person\n // and a save writes their uid.\n value={owner ? owner.uid : values.ownerUid ? '__keep' : ''}\n onChange={(event) =>\n update({\n ownerUid: event.target.value === '__keep' ? values.ownerUid : event.target.value,\n })\n }\n fullWidth\n helperText={\n !roster.loading && !roster.members.length\n ? 'The roster could not be read; the owner stays as stored.'\n : undefined\n }\n >\n <MenuItem value=\"\">{'Nobody yet'}</MenuItem>\n {values.ownerUid && !owner ? (\n // The stored owner is not on the roster the route returned —\n // a member who left, or a roster that failed to load. Shown by\n // uid so the field is never blank while the deal has an owner.\n <MenuItem value=\"__keep\">{values.ownerUid}</MenuItem>\n ) : null}\n {roster.members.map((member) => (\n <MenuItem key={member.uid} value={member.uid}>\n {crmMemberPickerLabel(member)}\n </MenuItem>\n ))}\n </TextField>\n <Autocomplete<ContactChoice, false, false, false>\n options={contactChoices}\n value={contactValue}\n inputValue={contactQuery}\n onInputChange={(_event, next, reason) => {\n if (reason !== 'reset') setContactQuery(next)\n }}\n onChange={(_event, picked) =>\n update({\n contactId: picked?.id ?? '',\n contactName: picked ? picked.name || picked.email : '',\n })\n }\n getOptionLabel={(choice) => choice.name || choice.email}\n isOptionEqualToValue={(option, value) => option.id === value.id}\n // Matching is `contactChoicesFor`'s — the list's grammar over the\n // window — and never MUI's own substring filter over labels.\n filterOptions={(options) => options}\n renderOption={(optionProps, choice) => (\n <li {...optionProps} key={choice.id}>\n <Stack sx={{ lineHeight: 1.25 }}>\n <Typography variant=\"body2\">{choice.name || choice.email}</Typography>\n {choice.name ? (\n <Typography variant=\"caption\" color=\"text.secondary\">\n {choice.email}\n </Typography>\n ) : null}\n </Stack>\n </li>\n )}\n noOptionsText=\"No recent contact matches\"\n renderInput={(params) => (\n <TextField\n {...params}\n label=\"Contact\"\n placeholder=\"Name or email\"\n helperText=\"Searches your most recent contacts by name or email.\"\n />\n )}\n />\n <Autocomplete<CompanyChoice, false, false, false>\n options={companyChoices}\n value={companyValue}\n inputValue={companyQuery}\n onInputChange={(_event, next, reason) => {\n if (reason !== 'reset') setCompanyQuery(next)\n }}\n onChange={(_event, picked) =>\n update({\n companyId: picked?.id ?? '',\n companyName: picked?.name ?? '',\n })\n }\n getOptionLabel={(choice) => choice.name}\n isOptionEqualToValue={(option, value) => option.id === value.id}\n filterOptions={(options) => options}\n noOptionsText=\"No company matches\"\n renderInput={(params) => (\n <TextField {...params} label=\"Company\" placeholder=\"Company name\" />\n )}\n />\n <TextField\n label=\"Notes\"\n value={values.notes}\n onChange={(event) => update({ notes: event.target.value })}\n multiline\n minRows={3}\n fullWidth\n slotProps={{ htmlInput: { maxLength: DEAL_NOTES_MAX } }}\n />\n {fields.active.length ? (\n <>\n <Typography variant=\"subtitle2\">{'Custom 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={busy}\n />\n ))}\n </>\n ) : null}\n {bandFull ? (\n <Alert severity=\"warning\">{CRM_RECORDS_BAND_FULL_MESSAGE}</Alert>\n ) : null}\n {problem && values.title ? <Alert severity=\"warning\">{problem}</Alert> : null}\n <Button\n variant=\"contained\"\n disabled={\n busy ||\n Boolean(problem) ||\n !orgId ||\n bandFull ||\n // A new deal waits for its capturing site.\n (mode === 'create' && !createHostId)\n }\n onClick={() => void handleSave()}\n >\n {deal ? 'Save deal' : 'Create deal'}\n </Button>\n </Stack>\n </Container>\n </NavigationDrawerComponent>\n )\n}\nDealEditDrawer.displayName = 'DealEditDrawer'\n\nexport default DealEditDrawer\n"],"names":["CRM_COLLECTIONS","CRM_RECORDS_BAND_FULL_MESSAGE","crmNewRecordListFields","dealHasLineItems","findOrgMember","nameSearchKey","crmMemberPickerLabel","ICON_VARIANT_CLOSE","Container","MdiIcon","SrOnly","NavigationDrawerComponent","useSnackbar","useFirestore","useFirestoreCollection","useUser","writeGuardedBySeed","Alert","Autocomplete","Button","IconButton","MenuItem","Stack","TextField","Typography","addDoc","collection","deleteField","doc","endAt","getDocs","limit","orderBy","query","startAt","updateDoc","useCallback","useEffect","useMemo","useState","useContactFieldDefinitions","useCrmActivityLogger","useCrmRecordsQuota","crmScopeListable","crmVisibleToClause","useCrmScope","useOrgMemberDirectory","contactPrimaryGroup","crmCustomDraftDocument","crmCustomDraftMissingRequired","crmCustomDraftValue","crmCustomDraftWrites","CrmCustomFieldControl","CrmSitePicker","CRM_CLIENT_SEARCH_FIELDS","crmClientListFields","DEAL_CURRENCIES","openStages","contactChoicesFor","DEAL_NOTES_MAX","DEAL_TITLE_MAX","dealDocumentFromForm","dealFormFromDoc","dealFormProblem","dealPatchFromForm","emptyDealForm","useCrmSharingFollowUp","CONTACT_WINDOW","COMPANY_MATCHES","DealEditDrawer","props","contactChoices","open","onClose","hostId","org","deal","defaults","pipelines","defaultPipeline","unreadable","fromCache","onSaved","mode","firestore","enqueueSnackbar","data","user","orgId","consentGroup","visibleTo","createHostId","createTokens","followUpSharing","logActivity","roster","values","setValues","owner","members","ownerUid","busy","setBusy","fields","storedCustom","custom","setCustom","update","patch","current","pipeline","find","entry","$id","pipelineId","stages","contactRows","idField","contactQuery","setContactQuery","groupId","row","contactValue","contactId","id","name","contactName","email","choice","companyQuery","setCompanyQuery","companyChoices","setCompanyChoices","key","active","timer","setTimeout","companies","then","snapshot","docs","map","String","get","catch","clearTimeout","companyValue","companyId","companyName","customMissing","problem","length","join","amountDerived","Boolean","recordsScope","records","bandFull","ready","quota","allowed","handleSave","uid","variant","persist","nowMs","Date","now","verdict","subject","set","clear","deals","Object","fromEntries","ok","message","customDocument","record","created","type","title","error","console","allowDuplicate","anchor","undefined","AppBarProps","color","appBarLeft","edge","onClick","sx","mr","path","component","appBarRight","disabled","gutterY","spacing","width","xs","sm","helperText","label","value","onChange","event","target","autoFocus","fullWidth","slotProps","htmlInput","maxLength","direction","select","some","next","stageId","flex","stage","alignItems","amount","placeholder","inputMode","readOnly","currency","code","toUpperCase","expectedClose","inputLabel","shrink","loading","member","options","inputValue","onInputChange","_event","reason","picked","getOptionLabel","isOptionEqualToValue","option","filterOptions","renderOption","optionProps","li","lineHeight","noOptionsText","renderInput","params","notes","multiline","minRows","definition","severity","displayName"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/crm/src/lib/components/deal-edit-drawer.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_COLLECTIONS,\n CRM_FORECAST_CATEGORIES,\n CRM_FORECAST_CATEGORY_LABELS,\n CRM_RECORDS_BAND_FULL_MESSAGE,\n type CrmForecastCategory,\n crmNewRecordListFields,\n DEAL_NEXT_STEP_MAX,\n dealHasLineItems,\n dealStageById,\n dealStageForecastCategory,\n findOrgMember,\n nameSearchKey,\n crmMemberPickerLabel,\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 { useSnackbar } from '@aglyn/shared-ui-snackstack'\nimport {\n useFirestore,\n useFirestoreCollection,\n useUser,\n writeGuardedBySeed,\n} from '@aglyn/tenant-feature-instance'\nimport {\n Alert,\n Autocomplete,\n Button,\n IconButton,\n MenuItem,\n Stack,\n TextField,\n Typography,\n} from '@mui/material'\nimport {\n addDoc,\n collection,\n deleteField,\n doc,\n endAt,\n getDocs,\n limit,\n orderBy,\n query,\n startAt,\n updateDoc,\n where,\n} from 'firebase/firestore'\nimport { useCallback, useEffect, useMemo, useState } from 'react'\nimport { useContactFieldDefinitions } from '../hooks/use-contact-field-definitions'\nimport { useCrmActivityLogger } from '../hooks/use-crm-activity-logger'\nimport { useCrmCampaigns } from '../hooks/use-crm-campaigns'\nimport { useCrmPicklist } from '../hooks/use-crm-picklist'\nimport { useCrmRecordsQuota } from '../hooks/use-crm-records-quota'\nimport {\n type CrmOrgDoc,\n crmScopeListable,\n crmVisibleToClause,\n useCrmScope,\n} from '../hooks/use-crm-scope'\nimport { useOrgMemberDirectory } from '../hooks/use-org-member-directory'\nimport { contactPrimaryGroup } from '../model/contact-record'\nimport {\n type CrmCustomDraft,\n crmCustomDraftDocument,\n crmCustomDraftMissingRequired,\n crmCustomDraftValue,\n crmCustomDraftWrites,\n} from '../model/crm-custom-draft'\nimport { CrmCustomFieldControl } from './crm-custom-field-control'\nimport { CrmPicklistSelect } from './picklist-select'\nimport { CrmSitePicker } from './crm-site-picker'\nimport {\n CRM_CLIENT_SEARCH_FIELDS,\n CRM_DEAL_CONTACT_ROLE_LIST_FIELDS,\n crmClientListFields,\n} from '../model/crm-list-query'\nimport {\n DEAL_CURRENCIES,\n type DealDoc,\n openStages,\n type PipelineDoc,\n} from '../model/deal-board-model'\nimport {\n type ContactChoice,\n contactChoicesFor,\n DEAL_NOTES_MAX,\n DEAL_TITLE_MAX,\n dealDocumentFromForm,\n dealFormFromDoc,\n dealFormProblem,\n type DealFormValues,\n dealPatchFromForm,\n emptyDealForm,\n judgeDealFormPicklists,\n} from '../model/deal-form-model'\nimport { useCrmSharingFollowUp } from '../hooks/use-crm-sharing'\n\n/**\n * How many recent contacts the picker matches against. The window is the\n * ask — it is read when the drawer opens, not when the section does — and\n * a person outside it is still linkable by pasting their address, which\n * the match tests as a prefix of the email.\n */\nconst CONTACT_WINDOW = 300\n\n/** Companies offered per keystroke; a longer list is a scroll, not a pick. */\nconst COMPANY_MATCHES = 8\n\n/** The list fields an edit restamps: the title's search words, the two picklist keys. */\nconst DEAL_CLIENT_LIST_FIELDS = [\n ...CRM_CLIENT_SEARCH_FIELDS,\n 'typeKey',\n 'leadSourceKey',\n // The arrays a deal's contact roles are found by (AGL-3521).\n ...CRM_DEAL_CONTACT_ROLE_LIST_FIELDS,\n] as const\n\n/** A company as the picker offers it. */\ninterface CompanyChoice {\n id: string\n name: string\n}\n\nexport interface DealEditDrawerProps {\n open: boolean\n onClose: () => void\n /**\n * The site the drawer is opened under, or `null` at the organization\n * level (AGL-2630), where a NEW deal asks which site captures it and an\n * edit keeps the deal's own.\n */\n hostId: string | null\n org: CrmOrgDoc\n /** The deal being edited; absent for a new one. */\n deal?: DealDoc | null\n /** Links and values a new deal opens with — a contact's page passes itself. */\n defaults?: Partial<DealFormValues>\n pipelines: PipelineDoc[]\n /** Where a new deal lands when nobody picks a pipeline. */\n defaultPipeline: PipelineDoc | null\n /** The listener's verdict on the row being edited, for the stale-seed guard. */\n unreadable?: boolean\n fromCache?: boolean\n /** After a save, with the id of the deal written. */\n onSaved?: (dealId: string, mode: 'create' | 'edit') => void\n}\n\n/**\n * The one form a deal is created and edited through (AGL-2598).\n *\n * ## What it writes, and what it does not\n *\n * Client-direct against the rules, like a contact's notes: the title, the\n * amount and its currency, the expected close, the owner, the linked\n * contact and company, and the notes. The stage and the status are shown on\n * a new deal — it has to start somewhere — and never on an existing one,\n * because a stage change is the moment an automation listens for and only\n * the server route can emit that event. A drawer that wrote `stageId`\n * directly would move a deal without anybody hearing it.\n *\n * Nor the amount of a deal that has line items (AGL-2620): it is their\n * sum, the products card on the deal's page owns it, and the field here\n * is read-only with a caption saying so. The pipeline picker on a new\n * deal lists every ACTIVE pipeline (`pipelines`) and opens on the one the\n * caller was looking at.\n *\n * ## The pickers\n *\n * The owner is picked from the org's roster, the company by a server-side\n * prefix on `nameLower` (indexed with the scope), and the contact from a\n * bounded window of the newest contacts matched in memory — see\n * `contactChoicesFor` for why the contact search cannot be a query. Both\n * pickers copy the chosen NAME onto the deal beside the id, so a board of\n * cards can caption itself without a read per card.\n *\n * ## Salesforce's Opportunity fields (AGL-3516)\n *\n * Type and Lead source are the org's picklists, judged on save as every\n * server door judges them (`judgeDealFormPicklists`) — a new deal with no\n * Type takes the list's default. The probability is this deal's own\n * override, blank for its stage's; the forecast category is one of the\n * fixed set, \"From the stage\" storing the stage's. A stage move later\n * stamps both afresh. The campaign is one of the campaigns the Campaigns\n * picker of a lead offers at this level.\n */\nexport function DealEditDrawer(props: DealEditDrawerProps) {\n const {\n open,\n onClose,\n hostId,\n org,\n deal,\n defaults,\n pipelines,\n defaultPipeline,\n unreadable = false,\n fromCache = false,\n onSaved,\n } = props\n const mode: 'create' | 'edit' = deal ? 'edit' : 'create'\n const firestore = useFirestore()\n const { enqueueSnackbar } = useSnackbar()\n const { data: user } = useUser()\n const { orgId, consentGroup, visibleTo, createHostId, createTokens } =\n useCrmScope({ hostId, org })\n // A client-direct write owes the org's sharing rules a re-evaluation (AGL-3336).\n const followUpSharing = useCrmSharingFollowUp(hostId, orgId)\n // The feed the act is logged in is the level it was PERFORMED at\n // (AGL-2738): this site's under a site, the organization's at the org\n // hub. `createHostId` is where the deal is STAMPED, which at the hub is a\n // site the reader picked and may hold no role on — a different question\n // from where the line belongs, and a gate the record write never faced.\n const logActivity = useCrmActivityLogger(hostId)\n const roster = useOrgMemberDirectory(open ? orgId : null)\n\n const [values, setValues] = useState<DealFormValues>(() =>\n emptyDealForm(defaultPipeline, defaults),\n )\n const owner = findOrgMember(roster.members, values.ownerUid)\n const [busy, setBusy] = useState(false)\n /*\n * THE CUSTOM FIELDS (AGL-2661): the org's deal definitions, and the keys\n * the reader has touched over what the deal stores — saved as the\n * difference (`crm-custom-draft`) in the same write as the fixed fields.\n */\n const fields = useContactFieldDefinitions(open ? orgId : null, 'deal')\n // The org's lists for the two picklist fields, and its campaigns (AGL-3516).\n const typeList = useCrmPicklist('opportunityType', open ? orgId : null)\n const leadSourceList = useCrmPicklist('leadSource', open ? orgId : null)\n const campaigns = useCrmCampaigns({ hostId, orgId }, { enabled: open })\n const storedCustom = useMemo(() => deal?.custom ?? {}, [deal?.custom])\n const [custom, setCustom] = useState<CrmCustomDraft>({})\n\n // Re-seeded on every open: an existing deal's stored values, or a blank\n // form aimed at the default pipeline with whatever the opener preselected.\n useEffect(() => {\n if (!open) return\n setValues(deal ? dealFormFromDoc(deal) : emptyDealForm(defaultPipeline, defaults))\n setCustom({})\n }, [open, deal, defaultPipeline, defaults])\n\n const update = useCallback(\n (patch: Partial<DealFormValues>) =>\n setValues((current) => ({ ...current, ...patch })),\n [],\n )\n\n const pipeline = useMemo(\n () =>\n pipelines.find((entry) => entry.$id === values.pipelineId) ??\n defaultPipeline,\n [pipelines, values.pipelineId, defaultPipeline],\n )\n const stages = useMemo(() => openStages(pipeline), [pipeline])\n /*\n * The stage the deal is in — the one picked on a new deal, the stored one\n * on an edit, looked up in the deal's OWN pipeline and never the default's\n * — whose probability and forecast category the blank fields stand for.\n */\n const currentStage = useMemo(\n () =>\n dealStageById(\n pipelines.find((entry) => entry.$id === values.pipelineId),\n values.stageId,\n ),\n [pipelines, values.pipelineId, values.stageId],\n )\n const campaignOptions = useMemo(() => {\n const options = campaigns.options.map((option) => ({ value: option.value, label: option.label }))\n // A campaign the deal names but the picker no longer offers stays itself.\n return values.campaignId && !options.some((option) => option.value === values.campaignId)\n ? [...options, { value: values.campaignId, label: values.campaignId }]\n : options\n }, [campaigns.options, values.campaignId])\n\n /*\n * THE CONTACT WINDOW: the newest contacts this viewer may see, read only\n * while the drawer is open. Scoped and ordered like the contacts list —\n * the same `(visibleTo, updatedAt DESC)` index — and bounded, because the\n * picker's job is to find one person, not to list the audience.\n */\n const { data: contactRows } = useFirestoreCollection<Record<string, unknown>>(\n () =>\n open && orgId && crmScopeListable(visibleTo)\n ? query(\n collection(firestore, 'orgs', orgId, 'contacts'),\n ...crmVisibleToClause(visibleTo),\n orderBy('updatedAt', 'desc'),\n limit(CONTACT_WINDOW),\n )\n : null,\n [firestore, open, orgId, visibleTo],\n { idField: '$id' },\n )\n const [contactQuery, setContactQuery] = useState('')\n // Named through the viewing group under a site; at the organization level\n // through each person's own primary holder.\n const contactChoices = useMemo(\n () =>\n contactChoicesFor(\n contactQuery,\n contactRows ?? [],\n consentGroup?.groupId ??\n ((row) => contactPrimaryGroup(row, org as Record<string, unknown>).groupId),\n ),\n [contactQuery, contactRows, consentGroup, org],\n )\n const contactValue: ContactChoice | null = values.contactId\n ? {\n id: values.contactId,\n name: values.contactName,\n email:\n contactChoices.find((choice) => choice.id === values.contactId)?.email ?? '',\n }\n : null\n\n /*\n * THE COMPANY SEARCH: a prefix on `nameLower` with the scope, which the\n * companies collection indexes. Debounced so a name typed at speed is one\n * query rather than one per letter.\n */\n const [companyQuery, setCompanyQuery] = useState('')\n const [companyChoices, setCompanyChoices] = useState<CompanyChoice[]>([])\n useEffect(() => {\n if (!open || !orgId || !crmScopeListable(visibleTo)) return\n const key = nameSearchKey(companyQuery)\n let active = true\n const timer = setTimeout(() => {\n void getDocs(\n query(\n collection(firestore, 'orgs', orgId, CRM_COLLECTIONS.companies),\n ...crmVisibleToClause(visibleTo),\n orderBy('nameLower'),\n ...(key ? [startAt(key), endAt(`${key}\\uf8ff`)] : []),\n limit(COMPANY_MATCHES),\n ),\n )\n .then((snapshot) => {\n if (!active) return\n setCompanyChoices(\n snapshot.docs.map((entry) => ({\n id: entry.id,\n name: String(entry.get('name') ?? ''),\n })),\n )\n })\n .catch(() => {\n if (active) setCompanyChoices([])\n })\n }, 200)\n return () => {\n active = false\n clearTimeout(timer)\n }\n }, [firestore, open, orgId, visibleTo, companyQuery])\n const companyValue: CompanyChoice | null = values.companyId\n ? { id: values.companyId, name: values.companyName }\n : null\n\n const customMissing = crmCustomDraftMissingRequired(fields.active, storedCustom, custom, mode)\n const problem =\n dealFormProblem(values, mode) ??\n (customMissing.length ? `${customMissing.join(', ')} is required.` : null)\n const amountDerived = Boolean(deal && dealHasLineItems(deal))\n\n /*\n * THE RECORDS BAND (AGL-2611), read only while a CREATE is open: a deal\n * is a record of the band the contacts list is banded by, and on an org\n * at a full hard band this drawer refuses the way `upsertHostContact`\n * refuses a capture — same number, same sentence. Memoized, because the\n * tuple is an effect dependency and a fresh one per render would re-read\n * the three aggregates on every keystroke.\n */\n const recordsScope = useMemo(\n () => (open && mode === 'create' && orgId ? (['orgs', orgId] as const) : null),\n [open, mode, orgId],\n )\n const records = useCrmRecordsQuota(recordsScope, org)\n const bandFull = mode === 'create' && records.ready && !records.quota.allowed\n\n const handleSave = useCallback(async () => {\n if (problem || !orgId || !user?.uid) return\n if (bandFull) {\n enqueueSnackbar(CRM_RECORDS_BAND_FULL_MESSAGE, { variant: 'warning', persist: false })\n return\n }\n const judged = judgeDealFormPicklists(\n values,\n { type: typeList.picklist, leadSource: leadSourceList.picklist },\n { current: deal ?? null, created: !deal },\n )\n if (judged.ok === false) {\n enqueueSnackbar(judged.error, { variant: 'warning', persist: false })\n return\n }\n const saved = judged.values\n setBusy(true)\n try {\n const nowMs = Date.now()\n if (deal) {\n const verdict = await writeGuardedBySeed(\n { subject: 'deal', unreadable, fromCache },\n async () => {\n const { set, clear } = dealPatchFromForm(saved, nowMs, {\n amountDerived,\n stage: currentStage,\n current: deal,\n })\n await updateDoc(\n doc(firestore, 'orgs', orgId, CRM_COLLECTIONS.deals, deal.$id),\n {\n ...set,\n ...Object.fromEntries(clear.map((key) => [key, deleteField()])),\n // The custom keys that changed, merged into the stored map.\n ...crmCustomDraftWrites(storedCustom, custom),\n // The title is what the Deals table searches (AGL-3321), and\n // the Type and Lead source what it filters by (AGL-3516),\n // from the listener's row with the edit over it.\n ...crmClientListFields(\n 'deals',\n deal as unknown as Record<string, unknown>,\n { ...set, ...Object.fromEntries(clear.map((key) => [key, null])) },\n DEAL_CLIENT_LIST_FIELDS,\n ),\n },\n )\n },\n )\n if (!verdict.ok) {\n enqueueSnackbar(verdict.message, { variant: 'warning', persist: false })\n return\n }\n followUpSharing('deals', [deal.$id])\n enqueueSnackbar('Deal saved', { variant: 'success', persist: false })\n onSaved?.(deal.$id, 'edit')\n } else {\n // Held by the button until the capturing site is known; checked\n // again here because a callback can outlive the render that held it.\n if (!createHostId) return\n const customDocument = crmCustomDraftDocument(custom)\n const record: Record<string, unknown> = {\n ...dealDocumentFromForm(saved, {\n visibleTo: [...createTokens],\n hostId: createHostId,\n uid: user.uid,\n nowMs,\n stage: currentStage,\n }),\n ...(customDocument ? { custom: customDocument } : {}),\n }\n const created = await addDoc(\n collection(firestore, 'orgs', orgId, CRM_COLLECTIONS.deals),\n // What the Deals table searches and filters by (AGL-3321), and\n // nothing scheduled against a deal that did not exist.\n { ...record, ...crmNewRecordListFields('deals', record) },\n )\n // Setup → Activity shows CRM work (AGL-2622): the deal is org data,\n // but the act happened in this site's console and belongs in its\n // feed. Creation only — an edit is a save the card reports.\n followUpSharing('deals', [created.id])\n logActivity('Added deal', { type: 'deal', id: created.id, name: values.title })\n enqueueSnackbar('Deal created', { variant: 'success', persist: false })\n onSaved?.(created.id, 'create')\n }\n onClose()\n } catch (error) {\n console.error(error)\n enqueueSnackbar('An error has occurred', {\n variant: 'error',\n allowDuplicate: true,\n })\n } finally {\n setBusy(false)\n }\n }, [\n problem,\n bandFull,\n orgId,\n followUpSharing,\n user,\n deal,\n values,\n unreadable,\n fromCache,\n firestore,\n createTokens,\n createHostId,\n logActivity,\n enqueueSnackbar,\n onSaved,\n onClose,\n storedCustom,\n custom,\n typeList.picklist,\n leadSourceList.picklist,\n currentStage,\n ])\n\n return (\n <NavigationDrawerComponent\n open={open}\n anchor=\"right\"\n variant=\"temporary\"\n onClose={busy ? undefined : onClose}\n AppBarProps={{ color: 'surface' }}\n appBarLeft={\n <>\n <IconButton color=\"inherit\" edge=\"start\" onClick={onClose} sx={{ mr: 2 }}>\n <MdiIcon path={ICON_VARIANT_CLOSE.path} />\n <SrOnly>close drawer</SrOnly>\n </IconButton>\n <Typography variant=\"h6\" component=\"div\">\n {deal ? 'Edit deal' : 'New deal'}\n </Typography>\n </>\n }\n appBarRight={\n <Button variant=\"outlined\" color=\"inherit\" onClick={onClose} disabled={busy}>\n {'Cancel'}\n </Button>\n }\n >\n <Container gutterY>\n <Stack spacing={2} sx={{ width: { xs: '100%', sm: 420 } }}>\n {/*\n First, because the scope of everything below follows from it: at\n the organization level a new deal names the site that captures\n it. Nothing under a site, and nothing on an edit — a deal keeps\n the site it was made on (AGL-2630).\n */}\n {mode === 'create' ? (\n <CrmSitePicker\n hostId={hostId}\n disabled={busy}\n helperText=\"The site this deal belongs to — it decides which of your sites may see it.\"\n />\n ) : null}\n <TextField\n label=\"Title\"\n value={values.title}\n onChange={(event) => update({ title: event.target.value })}\n autoFocus\n fullWidth\n slotProps={{ htmlInput: { maxLength: DEAL_TITLE_MAX } }}\n />\n {mode === 'create' ? (\n <Stack direction=\"row\" spacing={1}>\n <TextField\n select\n label=\"Pipeline\"\n value={pipelines.some((entry) => entry.$id === values.pipelineId) ? values.pipelineId : ''}\n onChange={(event) => {\n const next = pipelines.find(\n (entry) => entry.$id === event.target.value,\n )\n update({\n pipelineId: event.target.value,\n stageId: openStages(next)[0]?.id ?? '',\n })\n }}\n sx={{ flex: 1 }}\n >\n {pipelines.map((entry) => (\n <MenuItem key={entry.$id} value={entry.$id}>\n {entry.name}\n </MenuItem>\n ))}\n </TextField>\n <TextField\n select\n label=\"Stage\"\n value={stages.some((stage) => stage.id === values.stageId) ? values.stageId : ''}\n onChange={(event) => update({ stageId: event.target.value })}\n sx={{ flex: 1 }}\n >\n {stages.map((stage) => (\n <MenuItem key={stage.id} value={stage.id}>\n {stage.name}\n </MenuItem>\n ))}\n </TextField>\n </Stack>\n ) : null}\n <Stack direction=\"row\" spacing={1} sx={{ alignItems: 'flex-start' }}>\n <TextField\n label=\"Amount\"\n value={values.amount}\n onChange={(event) => update({ amount: event.target.value })}\n placeholder=\"0.00\"\n sx={{ flex: 1 }}\n helperText={\n amountDerived\n ? \"The sum of the deal's line items — edit them on the Products card.\"\n : undefined\n }\n slotProps={{\n htmlInput: { inputMode: 'decimal', readOnly: amountDerived },\n }}\n />\n <TextField\n select\n label=\"Currency\"\n value={values.currency}\n onChange={(event) => update({ currency: event.target.value })}\n disabled={amountDerived}\n sx={{ width: 120 }}\n >\n {DEAL_CURRENCIES.map((code) => (\n <MenuItem key={code} value={code}>\n {code.toUpperCase()}\n </MenuItem>\n ))}\n </TextField>\n </Stack>\n <TextField\n type=\"date\"\n label=\"Expected close\"\n value={values.expectedClose}\n onChange={(event) => update({ expectedClose: event.target.value })}\n fullWidth\n slotProps={{ inputLabel: { shrink: true } }}\n />\n <Stack direction=\"row\" spacing={1}>\n <CrmPicklistSelect\n picklistId=\"opportunityType\"\n picklist={typeList.picklist}\n value={values.type}\n stored={deal?.type ?? ''}\n onChange={(type) => update({ type })}\n disabled={busy}\n />\n <CrmPicklistSelect\n picklistId=\"leadSource\"\n picklist={leadSourceList.picklist}\n value={values.leadSource}\n stored={deal?.leadSource ?? ''}\n onChange={(leadSource) => update({ leadSource })}\n disabled={busy}\n />\n </Stack>\n <TextField\n label=\"Next step\"\n value={values.nextStep}\n onChange={(event) => update({ nextStep: event.target.value })}\n fullWidth\n slotProps={{ htmlInput: { maxLength: DEAL_NEXT_STEP_MAX } }}\n />\n <Stack direction=\"row\" spacing={1} sx={{ alignItems: 'flex-start' }}>\n <TextField\n label=\"Probability\"\n value={values.probability}\n onChange={(event) => update({ probability: event.target.value })}\n placeholder={currentStage ? String(currentStage.probability) : ''}\n helperText={\n currentStage\n ? `From stage: ${currentStage.probability}%`\n : 'Blank uses the stage’s'\n }\n sx={{ flex: 1 }}\n slotProps={{\n htmlInput: { inputMode: 'numeric', 'aria-label': 'Probability' },\n input: { endAdornment: '%' },\n inputLabel: { shrink: true },\n }}\n />\n <TextField\n select\n label=\"Forecast category\"\n value={values.forecastCategory}\n onChange={(event) =>\n update({ forecastCategory: event.target.value as '' | CrmForecastCategory })\n }\n helperText=\"A stage move sets it from the new stage.\"\n sx={{ flex: 1 }}\n slotProps={{ select: { displayEmpty: true }, inputLabel: { shrink: true } }}\n >\n <MenuItem value=\"\">\n {currentStage\n ? `From the stage (${CRM_FORECAST_CATEGORY_LABELS[dealStageForecastCategory(currentStage)]})`\n : 'From the stage'}\n </MenuItem>\n {CRM_FORECAST_CATEGORIES.map((category) => (\n <MenuItem key={category} value={category}>\n {CRM_FORECAST_CATEGORY_LABELS[category]}\n </MenuItem>\n ))}\n </TextField>\n </Stack>\n <TextField\n select\n label=\"Owner\"\n // The stored owner resolved to a member — by uid, or by an\n // address the roster has — so the picker highlights the person\n // and a save writes their uid.\n value={owner ? owner.uid : values.ownerUid ? '__keep' : ''}\n onChange={(event) =>\n update({\n ownerUid: event.target.value === '__keep' ? values.ownerUid : event.target.value,\n })\n }\n fullWidth\n helperText={\n !roster.loading && !roster.members.length\n ? 'The roster could not be read; the owner stays as stored.'\n : undefined\n }\n >\n <MenuItem value=\"\">{'Nobody yet'}</MenuItem>\n {values.ownerUid && !owner ? (\n // The stored owner is not on the roster the route returned —\n // a member who left, or a roster that failed to load. Shown by\n // uid so the field is never blank while the deal has an owner.\n <MenuItem value=\"__keep\">{values.ownerUid}</MenuItem>\n ) : null}\n {roster.members.map((member) => (\n <MenuItem key={member.uid} value={member.uid}>\n {crmMemberPickerLabel(member)}\n </MenuItem>\n ))}\n </TextField>\n <Autocomplete<ContactChoice, false, false, false>\n options={contactChoices}\n value={contactValue}\n inputValue={contactQuery}\n onInputChange={(_event, next, reason) => {\n if (reason !== 'reset') setContactQuery(next)\n }}\n onChange={(_event, picked) =>\n update({\n contactId: picked?.id ?? '',\n contactName: picked ? picked.name || picked.email : '',\n })\n }\n getOptionLabel={(choice) => choice.name || choice.email}\n isOptionEqualToValue={(option, value) => option.id === value.id}\n // Matching is `contactChoicesFor`'s — the list's grammar over the\n // window — and never MUI's own substring filter over labels.\n filterOptions={(options) => options}\n renderOption={(optionProps, choice) => (\n <li {...optionProps} key={choice.id}>\n <Stack sx={{ lineHeight: 1.25 }}>\n <Typography variant=\"body2\">{choice.name || choice.email}</Typography>\n {choice.name ? (\n <Typography variant=\"caption\" color=\"text.secondary\">\n {choice.email}\n </Typography>\n ) : null}\n </Stack>\n </li>\n )}\n noOptionsText=\"No recent contact matches\"\n renderInput={(params) => (\n <TextField\n {...params}\n label=\"Contact\"\n placeholder=\"Name or email\"\n helperText=\"Searches your most recent contacts by name or email.\"\n />\n )}\n />\n <Autocomplete<CompanyChoice, false, false, false>\n options={companyChoices}\n value={companyValue}\n inputValue={companyQuery}\n onInputChange={(_event, next, reason) => {\n if (reason !== 'reset') setCompanyQuery(next)\n }}\n onChange={(_event, picked) =>\n update({\n companyId: picked?.id ?? '',\n companyName: picked?.name ?? '',\n })\n }\n getOptionLabel={(choice) => choice.name}\n isOptionEqualToValue={(option, value) => option.id === value.id}\n filterOptions={(options) => options}\n noOptionsText=\"No company matches\"\n renderInput={(params) => (\n <TextField {...params} label=\"Company\" placeholder=\"Company name\" />\n )}\n />\n <TextField\n select\n label=\"Campaign\"\n value={values.campaignId}\n onChange={(event) => update({ campaignId: event.target.value })}\n fullWidth\n helperText={\n campaigns.ready && !campaignOptions.length\n ? 'There are no campaigns yet. Create one from Marketing.'\n : 'The campaign this deal is attributed to.'\n }\n slotProps={{ select: { displayEmpty: true }, inputLabel: { shrink: true } }}\n >\n <MenuItem value=\"\">{'None'}</MenuItem>\n {campaignOptions.map((option) => (\n <MenuItem key={option.value} value={option.value}>\n {option.label}\n </MenuItem>\n ))}\n </TextField>\n <TextField\n label=\"Notes\"\n value={values.notes}\n onChange={(event) => update({ notes: event.target.value })}\n multiline\n minRows={3}\n fullWidth\n slotProps={{ htmlInput: { maxLength: DEAL_NOTES_MAX } }}\n />\n {fields.active.length ? (\n <>\n <Typography variant=\"subtitle2\">{'Custom 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={busy}\n />\n ))}\n </>\n ) : null}\n {bandFull ? (\n <Alert severity=\"warning\">{CRM_RECORDS_BAND_FULL_MESSAGE}</Alert>\n ) : null}\n {problem && values.title ? <Alert severity=\"warning\">{problem}</Alert> : null}\n <Button\n variant=\"contained\"\n disabled={\n busy ||\n Boolean(problem) ||\n !orgId ||\n bandFull ||\n // A new deal waits for its capturing site.\n (mode === 'create' && !createHostId)\n }\n onClick={() => void handleSave()}\n >\n {deal ? 'Save deal' : 'Create deal'}\n </Button>\n </Stack>\n </Container>\n </NavigationDrawerComponent>\n )\n}\nDealEditDrawer.displayName = 'DealEditDrawer'\n\nexport default DealEditDrawer\n"],"names":["CRM_COLLECTIONS","CRM_FORECAST_CATEGORIES","CRM_FORECAST_CATEGORY_LABELS","CRM_RECORDS_BAND_FULL_MESSAGE","crmNewRecordListFields","DEAL_NEXT_STEP_MAX","dealHasLineItems","dealStageById","dealStageForecastCategory","findOrgMember","nameSearchKey","crmMemberPickerLabel","ICON_VARIANT_CLOSE","Container","MdiIcon","SrOnly","NavigationDrawerComponent","useSnackbar","useFirestore","useFirestoreCollection","useUser","writeGuardedBySeed","Alert","Autocomplete","Button","IconButton","MenuItem","Stack","TextField","Typography","addDoc","collection","deleteField","doc","endAt","getDocs","limit","orderBy","query","startAt","updateDoc","useCallback","useEffect","useMemo","useState","useContactFieldDefinitions","useCrmActivityLogger","useCrmCampaigns","useCrmPicklist","useCrmRecordsQuota","crmScopeListable","crmVisibleToClause","useCrmScope","useOrgMemberDirectory","contactPrimaryGroup","crmCustomDraftDocument","crmCustomDraftMissingRequired","crmCustomDraftValue","crmCustomDraftWrites","CrmCustomFieldControl","CrmPicklistSelect","CrmSitePicker","CRM_CLIENT_SEARCH_FIELDS","CRM_DEAL_CONTACT_ROLE_LIST_FIELDS","crmClientListFields","DEAL_CURRENCIES","openStages","contactChoicesFor","DEAL_NOTES_MAX","DEAL_TITLE_MAX","dealDocumentFromForm","dealFormFromDoc","dealFormProblem","dealPatchFromForm","emptyDealForm","judgeDealFormPicklists","useCrmSharingFollowUp","CONTACT_WINDOW","COMPANY_MATCHES","DEAL_CLIENT_LIST_FIELDS","DealEditDrawer","props","contactChoices","open","onClose","hostId","org","deal","defaults","pipelines","defaultPipeline","unreadable","fromCache","onSaved","mode","firestore","enqueueSnackbar","data","user","orgId","consentGroup","visibleTo","createHostId","createTokens","followUpSharing","logActivity","roster","values","setValues","owner","members","ownerUid","busy","setBusy","fields","typeList","leadSourceList","campaigns","enabled","storedCustom","custom","setCustom","update","patch","current","pipeline","find","entry","$id","pipelineId","stages","currentStage","stageId","campaignOptions","options","map","option","value","label","campaignId","some","contactRows","idField","contactQuery","setContactQuery","groupId","row","contactValue","contactId","id","name","contactName","email","choice","companyQuery","setCompanyQuery","companyChoices","setCompanyChoices","key","active","timer","setTimeout","companies","then","snapshot","docs","String","get","catch","clearTimeout","companyValue","companyId","companyName","customMissing","problem","length","join","amountDerived","Boolean","recordsScope","records","bandFull","ready","quota","allowed","handleSave","uid","variant","persist","judged","type","picklist","leadSource","created","ok","error","saved","nowMs","Date","now","verdict","subject","set","clear","stage","deals","Object","fromEntries","message","customDocument","record","title","console","allowDuplicate","anchor","undefined","AppBarProps","color","appBarLeft","edge","onClick","sx","mr","path","component","appBarRight","disabled","gutterY","spacing","width","xs","sm","helperText","onChange","event","target","autoFocus","fullWidth","slotProps","htmlInput","maxLength","direction","select","next","flex","alignItems","amount","placeholder","inputMode","readOnly","currency","code","toUpperCase","expectedClose","inputLabel","shrink","picklistId","stored","nextStep","probability","input","endAdornment","forecastCategory","displayEmpty","category","loading","member","inputValue","onInputChange","_event","reason","picked","getOptionLabel","isOptionEqualToValue","filterOptions","renderOption","optionProps","li","lineHeight","noOptionsText","renderInput","params","notes","multiline","minRows","definition","severity","displayName"],"mappings":"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"}
@@ -12,6 +12,8 @@ export interface DealPropertiesCardProps {
12
12
  * once for every card on it.
13
13
  */
14
14
  customFields?: readonly ContactFieldDefinition[];
15
+ /** The deal's campaign by name, resolved by the page; absent when it names none. */
16
+ campaignName?: string;
15
17
  }
16
18
  /**
17
19
  * What the deal is worth and who it is with (AGL-2598).
@@ -21,6 +23,11 @@ export interface DealPropertiesCardProps {
21
23
  * a stored figure would go stale the moment they did. The contact and the
22
24
  * company are links into their own pages — the id is the link; the name on
23
25
  * the deal is a caption that may lag a rename.
26
+ *
27
+ * Salesforce's Opportunity fields (AGL-3516) follow: the Type, the Lead
28
+ * source, the Next step, the probability — the deal's own override, with
29
+ * its stage's beside it, or the stage's — the forecast category and the
30
+ * campaign. Edit changes them; a stage move re-stamps the last two.
24
31
  */
25
32
  export declare function DealPropertiesCard(props: DealPropertiesCardProps): import("react").JSX.Element;
26
33
  export declare namespace DealPropertiesCard {