@open-mercato/core 0.5.1-develop.2663.2c29774b5b → 0.5.1-develop.2681.c559bb2bc3

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 (687) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/dist/generated/entities/action_log/index.js +8 -0
  3. package/dist/generated/entities/action_log/index.js.map +2 -2
  4. package/dist/generated/entities/customer_company_billing/index.js +23 -0
  5. package/dist/generated/entities/customer_company_billing/index.js.map +7 -0
  6. package/dist/generated/entities/customer_deal/index.js +8 -0
  7. package/dist/generated/entities/customer_deal/index.js.map +2 -2
  8. package/dist/generated/entities/customer_deal_stage_transition/index.js +31 -0
  9. package/dist/generated/entities/customer_deal_stage_transition/index.js.map +7 -0
  10. package/dist/generated/entities/customer_dictionary_kind_setting/index.js +21 -0
  11. package/dist/generated/entities/customer_dictionary_kind_setting/index.js.map +7 -0
  12. package/dist/generated/entities/customer_entity/index.js +8 -0
  13. package/dist/generated/entities/customer_entity/index.js.map +2 -2
  14. package/dist/generated/entities/customer_entity_role/index.js +23 -0
  15. package/dist/generated/entities/customer_entity_role/index.js.map +7 -0
  16. package/dist/generated/entities/customer_interaction/index.js +23 -1
  17. package/dist/generated/entities/customer_interaction/index.js.map +2 -2
  18. package/dist/generated/entities/customer_label/index.js +19 -0
  19. package/dist/generated/entities/customer_label/index.js.map +7 -0
  20. package/dist/generated/entities/customer_label_assignment/index.js +17 -0
  21. package/dist/generated/entities/customer_label_assignment/index.js.map +7 -0
  22. package/dist/generated/entities/customer_person_company_link/index.js +21 -0
  23. package/dist/generated/entities/customer_person_company_link/index.js.map +7 -0
  24. package/dist/generated/entities/customer_person_company_role/index.js +17 -0
  25. package/dist/generated/entities/customer_person_company_role/index.js.map +7 -0
  26. package/dist/generated/entities/dictionary_entry/index.js +4 -0
  27. package/dist/generated/entities/dictionary_entry/index.js.map +2 -2
  28. package/dist/generated/entities.ids.generated.js +9 -1
  29. package/dist/generated/entities.ids.generated.js.map +2 -2
  30. package/dist/generated/entity-fields-registry.js +116 -1
  31. package/dist/generated/entity-fields-registry.js.map +2 -2
  32. package/dist/modules/attachments/api/route.js +46 -8
  33. package/dist/modules/attachments/api/route.js.map +2 -2
  34. package/dist/modules/audit_logs/api/audit-logs/actions/export/route.js +208 -0
  35. package/dist/modules/audit_logs/api/audit-logs/actions/export/route.js.map +7 -0
  36. package/dist/modules/audit_logs/api/audit-logs/actions/route.js +52 -6
  37. package/dist/modules/audit_logs/api/audit-logs/actions/route.js.map +2 -2
  38. package/dist/modules/audit_logs/cli.js +62 -0
  39. package/dist/modules/audit_logs/cli.js.map +7 -0
  40. package/dist/modules/audit_logs/data/entities.js +21 -1
  41. package/dist/modules/audit_logs/data/entities.js.map +2 -2
  42. package/dist/modules/audit_logs/data/validators.js +9 -1
  43. package/dist/modules/audit_logs/data/validators.js.map +2 -2
  44. package/dist/modules/audit_logs/lib/changeRows.js +34 -0
  45. package/dist/modules/audit_logs/lib/changeRows.js.map +7 -0
  46. package/dist/modules/audit_logs/lib/display-helpers.js +2 -20
  47. package/dist/modules/audit_logs/lib/display-helpers.js.map +3 -3
  48. package/dist/modules/audit_logs/lib/projections.js +58 -0
  49. package/dist/modules/audit_logs/lib/projections.js.map +7 -0
  50. package/dist/modules/audit_logs/migrations/Migration20260412160533.js +21 -0
  51. package/dist/modules/audit_logs/migrations/Migration20260412160533.js.map +7 -0
  52. package/dist/modules/audit_logs/services/actionLogService.js +313 -79
  53. package/dist/modules/audit_logs/services/actionLogService.js.map +2 -2
  54. package/dist/modules/customers/acl.js +3 -1
  55. package/dist/modules/customers/acl.js.map +2 -2
  56. package/dist/modules/customers/api/activities/route.js +4 -0
  57. package/dist/modules/customers/api/activities/route.js.map +2 -2
  58. package/dist/modules/customers/api/assignable-staff/route.js +208 -0
  59. package/dist/modules/customers/api/assignable-staff/route.js.map +7 -0
  60. package/dist/modules/customers/api/companies/[id]/people/route.js +205 -0
  61. package/dist/modules/customers/api/companies/[id]/people/route.js.map +7 -0
  62. package/dist/modules/customers/api/companies/[id]/roles/route.js +22 -0
  63. package/dist/modules/customers/api/companies/[id]/roles/route.js.map +7 -0
  64. package/dist/modules/customers/api/companies/[id]/route.js +374 -32
  65. package/dist/modules/customers/api/companies/[id]/route.js.map +2 -2
  66. package/dist/modules/customers/api/companies/route.js +82 -7
  67. package/dist/modules/customers/api/companies/route.js.map +2 -2
  68. package/dist/modules/customers/api/deals/[id]/companies/route.js +172 -0
  69. package/dist/modules/customers/api/deals/[id]/companies/route.js.map +7 -0
  70. package/dist/modules/customers/api/deals/[id]/people/route.js +156 -0
  71. package/dist/modules/customers/api/deals/[id]/people/route.js.map +7 -0
  72. package/dist/modules/customers/api/deals/[id]/route.js +459 -53
  73. package/dist/modules/customers/api/deals/[id]/route.js.map +2 -2
  74. package/dist/modules/customers/api/deals/[id]/stats/route.js +195 -0
  75. package/dist/modules/customers/api/deals/[id]/stats/route.js.map +7 -0
  76. package/dist/modules/customers/api/deals/route.js +20 -10
  77. package/dist/modules/customers/api/deals/route.js.map +3 -3
  78. package/dist/modules/customers/api/dictionaries/[kind]/[id]/route.js +105 -4
  79. package/dist/modules/customers/api/dictionaries/[kind]/[id]/route.js.map +2 -2
  80. package/dist/modules/customers/api/dictionaries/[kind]/route.js +118 -42
  81. package/dist/modules/customers/api/dictionaries/[kind]/route.js.map +2 -2
  82. package/dist/modules/customers/api/dictionaries/context.js +30 -6
  83. package/dist/modules/customers/api/dictionaries/context.js.map +2 -2
  84. package/dist/modules/customers/api/dictionaries/kind-settings/route.js +207 -0
  85. package/dist/modules/customers/api/dictionaries/kind-settings/route.js.map +7 -0
  86. package/dist/modules/customers/api/entity-roles-factory.js +471 -0
  87. package/dist/modules/customers/api/entity-roles-factory.js.map +7 -0
  88. package/dist/modules/customers/api/interactions/conflicts/route.js +158 -0
  89. package/dist/modules/customers/api/interactions/conflicts/route.js.map +7 -0
  90. package/dist/modules/customers/api/interactions/counts/route.js +92 -0
  91. package/dist/modules/customers/api/interactions/counts/route.js.map +7 -0
  92. package/dist/modules/customers/api/interactions/route.js +83 -4
  93. package/dist/modules/customers/api/interactions/route.js.map +2 -2
  94. package/dist/modules/customers/api/labels/assign/route.js +189 -0
  95. package/dist/modules/customers/api/labels/assign/route.js.map +7 -0
  96. package/dist/modules/customers/api/labels/auth.js +17 -0
  97. package/dist/modules/customers/api/labels/auth.js.map +7 -0
  98. package/dist/modules/customers/api/labels/route.js +281 -0
  99. package/dist/modules/customers/api/labels/route.js.map +7 -0
  100. package/dist/modules/customers/api/labels/table-errors.js +38 -0
  101. package/dist/modules/customers/api/labels/table-errors.js.map +7 -0
  102. package/dist/modules/customers/api/labels/unassign/route.js +184 -0
  103. package/dist/modules/customers/api/labels/unassign/route.js.map +7 -0
  104. package/dist/modules/customers/api/people/[id]/companies/[linkId]/route.js +292 -0
  105. package/dist/modules/customers/api/people/[id]/companies/[linkId]/route.js.map +7 -0
  106. package/dist/modules/customers/api/people/[id]/companies/context.js +66 -0
  107. package/dist/modules/customers/api/people/[id]/companies/context.js.map +7 -0
  108. package/dist/modules/customers/api/people/[id]/companies/enriched/route.js +334 -0
  109. package/dist/modules/customers/api/people/[id]/companies/enriched/route.js.map +7 -0
  110. package/dist/modules/customers/api/people/[id]/companies/route.js +205 -0
  111. package/dist/modules/customers/api/people/[id]/companies/route.js.map +7 -0
  112. package/dist/modules/customers/api/people/[id]/roles/route.js +22 -0
  113. package/dist/modules/customers/api/people/[id]/roles/route.js.map +7 -0
  114. package/dist/modules/customers/api/people/[id]/route.js +134 -21
  115. package/dist/modules/customers/api/people/[id]/route.js.map +2 -2
  116. package/dist/modules/customers/api/people/route.js +122 -23
  117. package/dist/modules/customers/api/people/route.js.map +2 -2
  118. package/dist/modules/customers/api/todos/route.js +4 -0
  119. package/dist/modules/customers/api/todos/route.js.map +2 -2
  120. package/dist/modules/customers/api/utils.js +22 -0
  121. package/dist/modules/customers/api/utils.js.map +2 -2
  122. package/dist/modules/customers/backend/config/customers/page.js +2 -6
  123. package/dist/modules/customers/backend/config/customers/page.js.map +2 -2
  124. package/dist/modules/customers/backend/customers/companies/page.js +37 -26
  125. package/dist/modules/customers/backend/customers/companies/page.js.map +2 -2
  126. package/dist/modules/customers/backend/customers/companies-v2/[id]/page.js +265 -262
  127. package/dist/modules/customers/backend/customers/companies-v2/[id]/page.js.map +3 -3
  128. package/dist/modules/customers/backend/customers/deals/[id]/hooks/formatters.js +23 -0
  129. package/dist/modules/customers/backend/customers/deals/[id]/hooks/formatters.js.map +7 -0
  130. package/dist/modules/customers/backend/customers/deals/[id]/hooks/types.js +1 -0
  131. package/dist/modules/customers/backend/customers/deals/[id]/hooks/types.js.map +7 -0
  132. package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealActivities.js +43 -0
  133. package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealActivities.js.map +7 -0
  134. package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealAssociations.js +264 -0
  135. package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealAssociations.js.map +7 -0
  136. package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealClosure.js +88 -0
  137. package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealClosure.js.map +7 -0
  138. package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealData.js +41 -0
  139. package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealData.js.map +7 -0
  140. package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealFormHandlers.js +66 -0
  141. package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealFormHandlers.js.map +7 -0
  142. package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealInjectedTabs.js +39 -0
  143. package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealInjectedTabs.js.map +7 -0
  144. package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealMutationContext.js +49 -0
  145. package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealMutationContext.js.map +7 -0
  146. package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealPipeline.js +43 -0
  147. package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealPipeline.js.map +7 -0
  148. package/dist/modules/customers/backend/customers/deals/[id]/hooks/useScheduleDialog.js +28 -0
  149. package/dist/modules/customers/backend/customers/deals/[id]/hooks/useScheduleDialog.js.map +7 -0
  150. package/dist/modules/customers/backend/customers/deals/[id]/page.js +556 -503
  151. package/dist/modules/customers/backend/customers/deals/[id]/page.js.map +3 -3
  152. package/dist/modules/customers/backend/customers/deals/page.js +66 -21
  153. package/dist/modules/customers/backend/customers/deals/page.js.map +2 -2
  154. package/dist/modules/customers/backend/customers/people/page.js +36 -28
  155. package/dist/modules/customers/backend/customers/people/page.js.map +2 -2
  156. package/dist/modules/customers/backend/customers/people-v2/[id]/page.js +318 -203
  157. package/dist/modules/customers/backend/customers/people-v2/[id]/page.js.map +3 -3
  158. package/dist/modules/customers/cli.js +105 -13
  159. package/dist/modules/customers/cli.js.map +2 -2
  160. package/dist/modules/customers/commands/activities.js +6 -0
  161. package/dist/modules/customers/commands/activities.js.map +2 -2
  162. package/dist/modules/customers/commands/deals.js +315 -107
  163. package/dist/modules/customers/commands/deals.js.map +2 -2
  164. package/dist/modules/customers/commands/dictionaries.js +166 -32
  165. package/dist/modules/customers/commands/dictionaries.js.map +2 -2
  166. package/dist/modules/customers/commands/dictionaryKindSettings.js +208 -0
  167. package/dist/modules/customers/commands/dictionaryKindSettings.js.map +7 -0
  168. package/dist/modules/customers/commands/entity-roles.js +415 -0
  169. package/dist/modules/customers/commands/entity-roles.js.map +7 -0
  170. package/dist/modules/customers/commands/index.js +4 -0
  171. package/dist/modules/customers/commands/index.js.map +2 -2
  172. package/dist/modules/customers/commands/interactions.js +108 -21
  173. package/dist/modules/customers/commands/interactions.js.map +2 -2
  174. package/dist/modules/customers/commands/labels.js +539 -0
  175. package/dist/modules/customers/commands/labels.js.map +7 -0
  176. package/dist/modules/customers/commands/people.js +560 -463
  177. package/dist/modules/customers/commands/people.js.map +3 -3
  178. package/dist/modules/customers/commands/personCompanyLinks.js +568 -0
  179. package/dist/modules/customers/commands/personCompanyLinks.js.map +7 -0
  180. package/dist/modules/customers/commands/shared.js +12 -4
  181. package/dist/modules/customers/commands/shared.js.map +2 -2
  182. package/dist/modules/customers/commands/todos.js +10 -1
  183. package/dist/modules/customers/commands/todos.js.map +2 -2
  184. package/dist/modules/customers/components/AddressEditor.js +1 -1
  185. package/dist/modules/customers/components/AddressEditor.js.map +2 -2
  186. package/dist/modules/customers/components/CustomersConfigurationSections.js +31 -0
  187. package/dist/modules/customers/components/CustomersConfigurationSections.js.map +7 -0
  188. package/dist/modules/customers/components/DictionarySettings.js +37 -2
  189. package/dist/modules/customers/components/DictionarySettings.js.map +2 -2
  190. package/dist/modules/customers/components/detail/ActiveDealCard.js +121 -0
  191. package/dist/modules/customers/components/detail/ActiveDealCard.js.map +7 -0
  192. package/dist/modules/customers/components/detail/ActivitiesSection.js +222 -331
  193. package/dist/modules/customers/components/detail/ActivitiesSection.js.map +3 -3
  194. package/dist/modules/customers/components/detail/ActivityAiActions.js +36 -0
  195. package/dist/modules/customers/components/detail/ActivityAiActions.js.map +7 -0
  196. package/dist/modules/customers/components/detail/ActivityCard.js +126 -0
  197. package/dist/modules/customers/components/detail/ActivityCard.js.map +7 -0
  198. package/dist/modules/customers/components/detail/ActivityHistorySection.js +340 -0
  199. package/dist/modules/customers/components/detail/ActivityHistorySection.js.map +7 -0
  200. package/dist/modules/customers/components/detail/ActivityLogTab.js +56 -0
  201. package/dist/modules/customers/components/detail/ActivityLogTab.js.map +7 -0
  202. package/dist/modules/customers/components/detail/ActivityTimeline.js +108 -0
  203. package/dist/modules/customers/components/detail/ActivityTimeline.js.map +7 -0
  204. package/dist/modules/customers/components/detail/ActivityTimelineFilters.js +139 -0
  205. package/dist/modules/customers/components/detail/ActivityTimelineFilters.js.map +7 -0
  206. package/dist/modules/customers/components/detail/ActivityTypeSelector.js +42 -0
  207. package/dist/modules/customers/components/detail/ActivityTypeSelector.js.map +7 -0
  208. package/dist/modules/customers/components/detail/AiActionChips.js +38 -0
  209. package/dist/modules/customers/components/detail/AiActionChips.js.map +7 -0
  210. package/dist/modules/customers/components/detail/AssignRoleDialog.js +534 -0
  211. package/dist/modules/customers/components/detail/AssignRoleDialog.js.map +7 -0
  212. package/dist/modules/customers/components/detail/ChangelogEntryRow.js +79 -0
  213. package/dist/modules/customers/components/detail/ChangelogEntryRow.js.map +7 -0
  214. package/dist/modules/customers/components/detail/ChangelogFilters.js +176 -0
  215. package/dist/modules/customers/components/detail/ChangelogFilters.js.map +7 -0
  216. package/dist/modules/customers/components/detail/ChangelogKpiCards.js +88 -0
  217. package/dist/modules/customers/components/detail/ChangelogKpiCards.js.map +7 -0
  218. package/dist/modules/customers/components/detail/ChangelogTab.js +470 -0
  219. package/dist/modules/customers/components/detail/ChangelogTab.js.map +7 -0
  220. package/dist/modules/customers/components/detail/ComingSoonPlaceholder.js +16 -0
  221. package/dist/modules/customers/components/detail/ComingSoonPlaceholder.js.map +7 -0
  222. package/dist/modules/customers/components/detail/CompanyCard.js +283 -0
  223. package/dist/modules/customers/components/detail/CompanyCard.js.map +7 -0
  224. package/dist/modules/customers/components/detail/CompanyDashboardTab.js +133 -0
  225. package/dist/modules/customers/components/detail/CompanyDashboardTab.js.map +7 -0
  226. package/dist/modules/customers/components/detail/CompanyDetailHeader.js +191 -0
  227. package/dist/modules/customers/components/detail/CompanyDetailHeader.js.map +7 -0
  228. package/dist/modules/customers/components/detail/CompanyDetailTabs.js +123 -0
  229. package/dist/modules/customers/components/detail/CompanyDetailTabs.js.map +7 -0
  230. package/dist/modules/customers/components/detail/CompanyKpiBar.js +174 -0
  231. package/dist/modules/customers/components/detail/CompanyKpiBar.js.map +7 -0
  232. package/dist/modules/customers/components/detail/CompanyPeopleSection.js +514 -230
  233. package/dist/modules/customers/components/detail/CompanyPeopleSection.js.map +2 -2
  234. package/dist/modules/customers/components/detail/CompanyTagsDialog.js +22 -0
  235. package/dist/modules/customers/components/detail/CompanyTagsDialog.js.map +7 -0
  236. package/dist/modules/customers/components/detail/ConfirmDealLostDialog.js +159 -0
  237. package/dist/modules/customers/components/detail/ConfirmDealLostDialog.js.map +7 -0
  238. package/dist/modules/customers/components/detail/CreatePersonDialog.js +135 -0
  239. package/dist/modules/customers/components/detail/CreatePersonDialog.js.map +7 -0
  240. package/dist/modules/customers/components/detail/DealClosureActionBar.js +59 -0
  241. package/dist/modules/customers/components/detail/DealClosureActionBar.js.map +7 -0
  242. package/dist/modules/customers/components/detail/DealDetailHeader.js +237 -0
  243. package/dist/modules/customers/components/detail/DealDetailHeader.js.map +7 -0
  244. package/dist/modules/customers/components/detail/DealDetailTabs.js +109 -0
  245. package/dist/modules/customers/components/detail/DealDetailTabs.js.map +7 -0
  246. package/dist/modules/customers/components/detail/DealForm.js +219 -92
  247. package/dist/modules/customers/components/detail/DealForm.js.map +2 -2
  248. package/dist/modules/customers/components/detail/DealLinkedEntitiesTab.js +295 -0
  249. package/dist/modules/customers/components/detail/DealLinkedEntitiesTab.js.map +7 -0
  250. package/dist/modules/customers/components/detail/DealLostSummaryDialog.js +107 -0
  251. package/dist/modules/customers/components/detail/DealLostSummaryDialog.js.map +7 -0
  252. package/dist/modules/customers/components/detail/DealWonPopup.js +113 -0
  253. package/dist/modules/customers/components/detail/DealWonPopup.js.map +7 -0
  254. package/dist/modules/customers/components/detail/DealsSection.js +206 -193
  255. package/dist/modules/customers/components/detail/DealsSection.js.map +2 -2
  256. package/dist/modules/customers/components/detail/DecisionMakersFooter.js +39 -0
  257. package/dist/modules/customers/components/detail/DecisionMakersFooter.js.map +7 -0
  258. package/dist/modules/customers/components/detail/EntityTagsDialog.js +1096 -0
  259. package/dist/modules/customers/components/detail/EntityTagsDialog.js.map +7 -0
  260. package/dist/modules/customers/components/detail/InlineActivityComposer.js +197 -0
  261. package/dist/modules/customers/components/detail/InlineActivityComposer.js.map +7 -0
  262. package/dist/modules/customers/components/detail/ManageTagsDialog.js +1091 -0
  263. package/dist/modules/customers/components/detail/ManageTagsDialog.js.map +7 -0
  264. package/dist/modules/customers/components/detail/MiniWeekCalendar.js +272 -0
  265. package/dist/modules/customers/components/detail/MiniWeekCalendar.js.map +7 -0
  266. package/dist/modules/customers/components/detail/MobilePersonDetail.js +106 -0
  267. package/dist/modules/customers/components/detail/MobilePersonDetail.js.map +7 -0
  268. package/dist/modules/customers/components/detail/NextStepCard.js +72 -0
  269. package/dist/modules/customers/components/detail/NextStepCard.js.map +7 -0
  270. package/dist/modules/customers/components/detail/PersonCard.js +192 -0
  271. package/dist/modules/customers/components/detail/PersonCard.js.map +7 -0
  272. package/dist/modules/customers/components/detail/PersonCompaniesSection.js +345 -0
  273. package/dist/modules/customers/components/detail/PersonCompaniesSection.js.map +7 -0
  274. package/dist/modules/customers/components/detail/PersonDetailHeader.js +220 -0
  275. package/dist/modules/customers/components/detail/PersonDetailHeader.js.map +7 -0
  276. package/dist/modules/customers/components/detail/PersonDetailTabs.js +122 -0
  277. package/dist/modules/customers/components/detail/PersonDetailTabs.js.map +7 -0
  278. package/dist/modules/customers/components/detail/PersonTagsDialog.js +24 -0
  279. package/dist/modules/customers/components/detail/PersonTagsDialog.js.map +7 -0
  280. package/dist/modules/customers/components/detail/PipelineStepper.js +191 -0
  281. package/dist/modules/customers/components/detail/PipelineStepper.js.map +7 -0
  282. package/dist/modules/customers/components/detail/PlannedActivitiesSection.js +222 -0
  283. package/dist/modules/customers/components/detail/PlannedActivitiesSection.js.map +7 -0
  284. package/dist/modules/customers/components/detail/RelationshipHealthCard.js +49 -0
  285. package/dist/modules/customers/components/detail/RelationshipHealthCard.js.map +7 -0
  286. package/dist/modules/customers/components/detail/RoleAssignmentRow.js +189 -0
  287. package/dist/modules/customers/components/detail/RoleAssignmentRow.js.map +7 -0
  288. package/dist/modules/customers/components/detail/RolesSection.js +234 -0
  289. package/dist/modules/customers/components/detail/RolesSection.js.map +7 -0
  290. package/dist/modules/customers/components/detail/ScheduleActivityDialog.js +410 -0
  291. package/dist/modules/customers/components/detail/ScheduleActivityDialog.js.map +7 -0
  292. package/dist/modules/customers/components/detail/aiActionCatalog.js +41 -0
  293. package/dist/modules/customers/components/detail/aiActionCatalog.js.map +7 -0
  294. package/dist/modules/customers/components/detail/assignableStaff.js +48 -0
  295. package/dist/modules/customers/components/detail/assignableStaff.js.map +7 -0
  296. package/dist/modules/customers/components/detail/dashboard/ActiveDealWidget.js +48 -0
  297. package/dist/modules/customers/components/detail/dashboard/ActiveDealWidget.js.map +7 -0
  298. package/dist/modules/customers/components/detail/dashboard/OpenTasksWidget.js +86 -0
  299. package/dist/modules/customers/components/detail/dashboard/OpenTasksWidget.js.map +7 -0
  300. package/dist/modules/customers/components/detail/dashboard/RecentActivityWidget.js +53 -0
  301. package/dist/modules/customers/components/detail/dashboard/RecentActivityWidget.js.map +7 -0
  302. package/dist/modules/customers/components/detail/dashboard/RelationshipHealthWidget.js +30 -0
  303. package/dist/modules/customers/components/detail/dashboard/RelationshipHealthWidget.js.map +7 -0
  304. package/dist/modules/customers/components/detail/dashboard/UpcomingMeetingsWidget.js +43 -0
  305. package/dist/modules/customers/components/detail/dashboard/UpcomingMeetingsWidget.js.map +7 -0
  306. package/dist/modules/customers/components/detail/dashboard/helpers.js +71 -0
  307. package/dist/modules/customers/components/detail/dashboard/helpers.js.map +7 -0
  308. package/dist/modules/customers/components/detail/healthScoreUtils.js +69 -0
  309. package/dist/modules/customers/components/detail/healthScoreUtils.js.map +7 -0
  310. package/dist/modules/customers/components/detail/hooks/useCurrencyDictionary.js +5 -5
  311. package/dist/modules/customers/components/detail/hooks/useCurrencyDictionary.js.map +2 -2
  312. package/dist/modules/customers/components/detail/hooks/useCustomerDictionary.js +9 -8
  313. package/dist/modules/customers/components/detail/hooks/useCustomerDictionary.js.map +3 -3
  314. package/dist/modules/customers/components/detail/hooks/useInteractionMutations.js +65 -0
  315. package/dist/modules/customers/components/detail/hooks/useInteractionMutations.js.map +7 -0
  316. package/dist/modules/customers/components/detail/notesAdapter.js +70 -30
  317. package/dist/modules/customers/components/detail/notesAdapter.js.map +2 -2
  318. package/dist/modules/customers/components/detail/pipelineStageUtils.js +26 -0
  319. package/dist/modules/customers/components/detail/pipelineStageUtils.js.map +7 -0
  320. package/dist/modules/customers/components/detail/schedule/DateTimeFields.js +144 -0
  321. package/dist/modules/customers/components/detail/schedule/DateTimeFields.js.map +7 -0
  322. package/dist/modules/customers/components/detail/schedule/FooterFields.js +60 -0
  323. package/dist/modules/customers/components/detail/schedule/FooterFields.js.map +7 -0
  324. package/dist/modules/customers/components/detail/schedule/LinkedEntitiesField.js +216 -0
  325. package/dist/modules/customers/components/detail/schedule/LinkedEntitiesField.js.map +7 -0
  326. package/dist/modules/customers/components/detail/schedule/LocationField.js +34 -0
  327. package/dist/modules/customers/components/detail/schedule/LocationField.js.map +7 -0
  328. package/dist/modules/customers/components/detail/schedule/ParticipantsField.js +226 -0
  329. package/dist/modules/customers/components/detail/schedule/ParticipantsField.js.map +7 -0
  330. package/dist/modules/customers/components/detail/schedule/fieldConfig.js +69 -0
  331. package/dist/modules/customers/components/detail/schedule/fieldConfig.js.map +7 -0
  332. package/dist/modules/customers/components/detail/schedule/index.js +21 -0
  333. package/dist/modules/customers/components/detail/schedule/index.js.map +7 -0
  334. package/dist/modules/customers/components/detail/schedule/useScheduleFormState.js +172 -0
  335. package/dist/modules/customers/components/detail/schedule/useScheduleFormState.js.map +7 -0
  336. package/dist/modules/customers/components/detail/utils.js +23 -0
  337. package/dist/modules/customers/components/detail/utils.js.map +2 -2
  338. package/dist/modules/customers/components/formConfig.js +144 -22
  339. package/dist/modules/customers/components/formConfig.js.map +2 -2
  340. package/dist/modules/customers/components/linking/LinkEntityDialog.js +661 -0
  341. package/dist/modules/customers/components/linking/LinkEntityDialog.js.map +7 -0
  342. package/dist/modules/customers/components/linking/adapters/companyAdapter.js +252 -0
  343. package/dist/modules/customers/components/linking/adapters/companyAdapter.js.map +7 -0
  344. package/dist/modules/customers/components/linking/adapters/dealAdapter.js +384 -0
  345. package/dist/modules/customers/components/linking/adapters/dealAdapter.js.map +7 -0
  346. package/dist/modules/customers/components/linking/adapters/personAdapter.js +324 -0
  347. package/dist/modules/customers/components/linking/adapters/personAdapter.js.map +7 -0
  348. package/dist/modules/customers/components/list/CollectionPreviewCell.js +53 -0
  349. package/dist/modules/customers/components/list/CollectionPreviewCell.js.map +7 -0
  350. package/dist/modules/customers/data/entities.js +407 -1
  351. package/dist/modules/customers/data/entities.js.map +2 -2
  352. package/dist/modules/customers/data/validators.js +139 -21
  353. package/dist/modules/customers/data/validators.js.map +2 -2
  354. package/dist/modules/customers/events.js +19 -1
  355. package/dist/modules/customers/events.js.map +2 -2
  356. package/dist/modules/customers/lib/customerRoleTypes.js +19 -0
  357. package/dist/modules/customers/lib/customerRoleTypes.js.map +7 -0
  358. package/dist/modules/customers/lib/dealClosureNotification.js +39 -0
  359. package/dist/modules/customers/lib/dealClosureNotification.js.map +7 -0
  360. package/dist/modules/customers/lib/dealStageTransitionTable.js +29 -0
  361. package/dist/modules/customers/lib/dealStageTransitionTable.js.map +7 -0
  362. package/dist/modules/customers/lib/dictionaries.js +25 -0
  363. package/dist/modules/customers/lib/dictionaries.js.map +2 -2
  364. package/dist/modules/customers/lib/interactionReadModel.js +10 -0
  365. package/dist/modules/customers/lib/interactionReadModel.js.map +2 -2
  366. package/dist/modules/customers/lib/personCompanies.js +235 -0
  367. package/dist/modules/customers/lib/personCompanies.js.map +7 -0
  368. package/dist/modules/customers/lib/personCompanyLinkTable.js +42 -0
  369. package/dist/modules/customers/lib/personCompanyLinkTable.js.map +7 -0
  370. package/dist/modules/customers/lib/roleTypeUsage.js +104 -0
  371. package/dist/modules/customers/lib/roleTypeUsage.js.map +7 -0
  372. package/dist/modules/customers/migrations/Migration20260406214502.js +18 -0
  373. package/dist/modules/customers/migrations/Migration20260406214502.js.map +7 -0
  374. package/dist/modules/customers/migrations/Migration20260408135736.js +17 -0
  375. package/dist/modules/customers/migrations/Migration20260408135736.js.map +7 -0
  376. package/dist/modules/customers/migrations/Migration20260408225345.js +21 -0
  377. package/dist/modules/customers/migrations/Migration20260408225345.js.map +7 -0
  378. package/dist/modules/customers/migrations/Migration20260411075533.js +27 -0
  379. package/dist/modules/customers/migrations/Migration20260411075533.js.map +7 -0
  380. package/dist/modules/customers/migrations/Migration20260411103551.js +13 -0
  381. package/dist/modules/customers/migrations/Migration20260411103551.js.map +7 -0
  382. package/dist/modules/customers/migrations/Migration20260411130944.js +26 -0
  383. package/dist/modules/customers/migrations/Migration20260411130944.js.map +7 -0
  384. package/dist/modules/customers/migrations/Migration20260415095203.js +13 -0
  385. package/dist/modules/customers/migrations/Migration20260415095203.js.map +7 -0
  386. package/dist/modules/customers/migrations/Migration20260415135056.js +20 -0
  387. package/dist/modules/customers/migrations/Migration20260415135056.js.map +7 -0
  388. package/dist/modules/customers/migrations/Migration20260417140000.js +15 -0
  389. package/dist/modules/customers/migrations/Migration20260417140000.js.map +7 -0
  390. package/dist/modules/customers/migrations/Migration20260417160000.js +17 -0
  391. package/dist/modules/customers/migrations/Migration20260417160000.js.map +7 -0
  392. package/dist/modules/customers/migrations/Migration20260417235407.js +13 -0
  393. package/dist/modules/customers/migrations/Migration20260417235407.js.map +7 -0
  394. package/dist/modules/customers/setup.js +16 -1
  395. package/dist/modules/customers/setup.js.map +2 -2
  396. package/dist/modules/customers/subscribers/deal-closure-notification.js +16 -0
  397. package/dist/modules/customers/subscribers/deal-closure-notification.js.map +7 -0
  398. package/dist/modules/customers/subscribers/deal-lost-notification.js +16 -0
  399. package/dist/modules/customers/subscribers/deal-lost-notification.js.map +7 -0
  400. package/dist/modules/dictionaries/api/[dictionaryId]/entries/[entryId]/route.js +2 -0
  401. package/dist/modules/dictionaries/api/[dictionaryId]/entries/[entryId]/route.js.map +2 -2
  402. package/dist/modules/dictionaries/api/[dictionaryId]/entries/reorder/route.js +154 -0
  403. package/dist/modules/dictionaries/api/[dictionaryId]/entries/reorder/route.js.map +7 -0
  404. package/dist/modules/dictionaries/api/[dictionaryId]/entries/route.js +6 -2
  405. package/dist/modules/dictionaries/api/[dictionaryId]/entries/route.js.map +2 -2
  406. package/dist/modules/dictionaries/api/[dictionaryId]/entries/set-default/route.js +154 -0
  407. package/dist/modules/dictionaries/api/[dictionaryId]/entries/set-default/route.js.map +7 -0
  408. package/dist/modules/dictionaries/api/context.js +8 -1
  409. package/dist/modules/dictionaries/api/context.js.map +2 -2
  410. package/dist/modules/dictionaries/api/openapi.js +18 -1
  411. package/dist/modules/dictionaries/api/openapi.js.map +2 -2
  412. package/dist/modules/dictionaries/commands/entry-operations.js +388 -0
  413. package/dist/modules/dictionaries/commands/entry-operations.js.map +7 -0
  414. package/dist/modules/dictionaries/commands/factory.js +24 -3
  415. package/dist/modules/dictionaries/commands/factory.js.map +2 -2
  416. package/dist/modules/dictionaries/commands/index.js +1 -0
  417. package/dist/modules/dictionaries/commands/index.js.map +2 -2
  418. package/dist/modules/dictionaries/components/DictionaryTable.js +6 -3
  419. package/dist/modules/dictionaries/components/DictionaryTable.js.map +2 -2
  420. package/dist/modules/dictionaries/data/entities.js +11 -1
  421. package/dist/modules/dictionaries/data/entities.js.map +2 -2
  422. package/dist/modules/dictionaries/data/validators.js +28 -2
  423. package/dist/modules/dictionaries/data/validators.js.map +2 -2
  424. package/dist/modules/dictionaries/events.js +18 -0
  425. package/dist/modules/dictionaries/events.js.map +7 -0
  426. package/dist/modules/dictionaries/lib/clientEntries.js +43 -0
  427. package/dist/modules/dictionaries/lib/clientEntries.js.map +7 -0
  428. package/dist/modules/dictionaries/migrations/Migration20260410171544.js +45 -0
  429. package/dist/modules/dictionaries/migrations/Migration20260410171544.js.map +7 -0
  430. package/dist/modules/inbox_ops/api/proposals/[id]/route.js +4 -1
  431. package/dist/modules/inbox_ops/api/proposals/[id]/route.js.map +2 -2
  432. package/dist/modules/query_index/lib/engine.js +1 -1
  433. package/dist/modules/query_index/lib/engine.js.map +2 -2
  434. package/dist/modules/sales/components/documents/AddressesSection.js +82 -42
  435. package/dist/modules/sales/components/documents/AddressesSection.js.map +2 -2
  436. package/dist/modules/sales/lib/dictionaries.js +16 -0
  437. package/dist/modules/sales/lib/dictionaries.js.map +2 -2
  438. package/dist/modules/sales/widgets/injection-table.js +5 -1
  439. package/dist/modules/sales/widgets/injection-table.js.map +2 -2
  440. package/generated/entities/action_log/index.ts +4 -0
  441. package/generated/entities/customer_company_billing/index.ts +10 -0
  442. package/generated/entities/customer_deal/index.ts +4 -0
  443. package/generated/entities/customer_deal_stage_transition/index.ts +14 -0
  444. package/generated/entities/customer_dictionary_kind_setting/index.ts +9 -0
  445. package/generated/entities/customer_entity/index.ts +4 -0
  446. package/generated/entities/customer_entity_role/index.ts +10 -0
  447. package/generated/entities/customer_interaction/index.ts +11 -0
  448. package/generated/entities/customer_label/index.ts +8 -0
  449. package/generated/entities/customer_label_assignment/index.ts +7 -0
  450. package/generated/entities/customer_person_company_link/index.ts +9 -0
  451. package/generated/entities/customer_person_company_role/index.ts +7 -0
  452. package/generated/entities/dictionary_entry/index.ts +2 -0
  453. package/generated/entities.ids.generated.ts +9 -1
  454. package/generated/entity-fields-registry.ts +116 -1
  455. package/package.json +3 -3
  456. package/src/modules/attachments/api/route.ts +48 -6
  457. package/src/modules/attachments/i18n/de.json +4 -0
  458. package/src/modules/attachments/i18n/en.json +4 -0
  459. package/src/modules/attachments/i18n/es.json +4 -0
  460. package/src/modules/attachments/i18n/pl.json +4 -0
  461. package/src/modules/audit_logs/api/audit-logs/actions/export/route.ts +260 -0
  462. package/src/modules/audit_logs/api/audit-logs/actions/route.ts +81 -6
  463. package/src/modules/audit_logs/cli.ts +79 -0
  464. package/src/modules/audit_logs/data/entities.ts +17 -0
  465. package/src/modules/audit_logs/data/validators.ts +9 -1
  466. package/src/modules/audit_logs/lib/changeRows.ts +47 -0
  467. package/src/modules/audit_logs/lib/display-helpers.tsx +4 -30
  468. package/src/modules/audit_logs/lib/projections.ts +110 -0
  469. package/src/modules/audit_logs/migrations/.snapshot-open-mercato.json +325 -2
  470. package/src/modules/audit_logs/migrations/Migration20260412160533.ts +21 -0
  471. package/src/modules/audit_logs/services/actionLogService.ts +455 -85
  472. package/src/modules/catalog/i18n/de.json +1 -0
  473. package/src/modules/catalog/i18n/en.json +1 -0
  474. package/src/modules/catalog/i18n/es.json +1 -0
  475. package/src/modules/catalog/i18n/pl.json +1 -0
  476. package/src/modules/customer_accounts/i18n/de.json +2 -0
  477. package/src/modules/customer_accounts/i18n/en.json +2 -0
  478. package/src/modules/customer_accounts/i18n/es.json +2 -0
  479. package/src/modules/customer_accounts/i18n/pl.json +2 -0
  480. package/src/modules/customers/acl.ts +2 -0
  481. package/src/modules/customers/api/activities/route.ts +4 -0
  482. package/src/modules/customers/api/assignable-staff/route.ts +250 -0
  483. package/src/modules/customers/api/companies/[id]/people/route.ts +244 -0
  484. package/src/modules/customers/api/companies/[id]/roles/route.ts +15 -0
  485. package/src/modules/customers/api/companies/[id]/route.ts +458 -40
  486. package/src/modules/customers/api/companies/route.ts +93 -15
  487. package/src/modules/customers/api/deals/[id]/companies/route.ts +203 -0
  488. package/src/modules/customers/api/deals/[id]/people/route.ts +182 -0
  489. package/src/modules/customers/api/deals/[id]/route.ts +554 -57
  490. package/src/modules/customers/api/deals/[id]/stats/route.ts +221 -0
  491. package/src/modules/customers/api/deals/route.ts +35 -46
  492. package/src/modules/customers/api/dictionaries/[kind]/[id]/route.ts +105 -3
  493. package/src/modules/customers/api/dictionaries/[kind]/route.ts +143 -44
  494. package/src/modules/customers/api/dictionaries/context.ts +45 -16
  495. package/src/modules/customers/api/dictionaries/kind-settings/route.ts +232 -0
  496. package/src/modules/customers/api/entity-roles-factory.ts +520 -0
  497. package/src/modules/customers/api/interactions/conflicts/route.ts +196 -0
  498. package/src/modules/customers/api/interactions/counts/route.ts +112 -0
  499. package/src/modules/customers/api/interactions/route.ts +95 -2
  500. package/src/modules/customers/api/labels/assign/route.ts +202 -0
  501. package/src/modules/customers/api/labels/auth.ts +19 -0
  502. package/src/modules/customers/api/labels/route.ts +310 -0
  503. package/src/modules/customers/api/labels/table-errors.ts +36 -0
  504. package/src/modules/customers/api/labels/unassign/route.ts +197 -0
  505. package/src/modules/customers/api/people/[id]/companies/[linkId]/route.ts +331 -0
  506. package/src/modules/customers/api/people/[id]/companies/context.ts +70 -0
  507. package/src/modules/customers/api/people/[id]/companies/enriched/route.ts +384 -0
  508. package/src/modules/customers/api/people/[id]/companies/route.ts +215 -0
  509. package/src/modules/customers/api/people/[id]/roles/route.ts +15 -0
  510. package/src/modules/customers/api/people/[id]/route.ts +153 -26
  511. package/src/modules/customers/api/people/route.ts +134 -31
  512. package/src/modules/customers/api/todos/route.ts +4 -0
  513. package/src/modules/customers/api/utils.ts +36 -0
  514. package/src/modules/customers/backend/config/customers/page.tsx +2 -6
  515. package/src/modules/customers/backend/customers/companies/page.tsx +36 -26
  516. package/src/modules/customers/backend/customers/companies-v2/[id]/page.tsx +277 -262
  517. package/src/modules/customers/backend/customers/deals/[id]/hooks/formatters.ts +19 -0
  518. package/src/modules/customers/backend/customers/deals/[id]/hooks/types.ts +104 -0
  519. package/src/modules/customers/backend/customers/deals/[id]/hooks/useDealActivities.ts +60 -0
  520. package/src/modules/customers/backend/customers/deals/[id]/hooks/useDealAssociations.ts +362 -0
  521. package/src/modules/customers/backend/customers/deals/[id]/hooks/useDealClosure.ts +113 -0
  522. package/src/modules/customers/backend/customers/deals/[id]/hooks/useDealData.ts +52 -0
  523. package/src/modules/customers/backend/customers/deals/[id]/hooks/useDealFormHandlers.ts +86 -0
  524. package/src/modules/customers/backend/customers/deals/[id]/hooks/useDealInjectedTabs.tsx +60 -0
  525. package/src/modules/customers/backend/customers/deals/[id]/hooks/useDealMutationContext.ts +76 -0
  526. package/src/modules/customers/backend/customers/deals/[id]/hooks/useDealPipeline.ts +56 -0
  527. package/src/modules/customers/backend/customers/deals/[id]/hooks/useScheduleDialog.ts +38 -0
  528. package/src/modules/customers/backend/customers/deals/[id]/page.tsx +587 -624
  529. package/src/modules/customers/backend/customers/deals/page.tsx +71 -28
  530. package/src/modules/customers/backend/customers/people/page.tsx +35 -29
  531. package/src/modules/customers/backend/customers/people-v2/[id]/page.tsx +343 -209
  532. package/src/modules/customers/cli.ts +107 -12
  533. package/src/modules/customers/commands/activities.ts +13 -0
  534. package/src/modules/customers/commands/deals.ts +386 -114
  535. package/src/modules/customers/commands/dictionaries.ts +175 -32
  536. package/src/modules/customers/commands/dictionaryKindSettings.ts +268 -0
  537. package/src/modules/customers/commands/entity-roles.ts +494 -0
  538. package/src/modules/customers/commands/index.ts +4 -0
  539. package/src/modules/customers/commands/interactions.ts +125 -21
  540. package/src/modules/customers/commands/labels.ts +626 -0
  541. package/src/modules/customers/commands/people.ts +373 -259
  542. package/src/modules/customers/commands/personCompanyLinks.ts +654 -0
  543. package/src/modules/customers/commands/shared.ts +16 -15
  544. package/src/modules/customers/commands/todos.ts +17 -1
  545. package/src/modules/customers/components/AddressEditor.tsx +1 -1
  546. package/src/modules/customers/components/CustomersConfigurationSections.tsx +36 -0
  547. package/src/modules/customers/components/DictionarySettings.tsx +43 -2
  548. package/src/modules/customers/components/detail/ActiveDealCard.tsx +175 -0
  549. package/src/modules/customers/components/detail/ActivitiesSection.tsx +267 -361
  550. package/src/modules/customers/components/detail/ActivityAiActions.tsx +49 -0
  551. package/src/modules/customers/components/detail/ActivityCard.tsx +154 -0
  552. package/src/modules/customers/components/detail/ActivityHistorySection.tsx +412 -0
  553. package/src/modules/customers/components/detail/ActivityLogTab.tsx +67 -0
  554. package/src/modules/customers/components/detail/ActivityTimeline.tsx +158 -0
  555. package/src/modules/customers/components/detail/ActivityTimelineFilters.tsx +163 -0
  556. package/src/modules/customers/components/detail/ActivityTypeSelector.tsx +53 -0
  557. package/src/modules/customers/components/detail/AiActionChips.tsx +48 -0
  558. package/src/modules/customers/components/detail/AssignRoleDialog.tsx +672 -0
  559. package/src/modules/customers/components/detail/ChangelogEntryRow.tsx +132 -0
  560. package/src/modules/customers/components/detail/ChangelogFilters.tsx +193 -0
  561. package/src/modules/customers/components/detail/ChangelogKpiCards.tsx +107 -0
  562. package/src/modules/customers/components/detail/ChangelogTab.tsx +629 -0
  563. package/src/modules/customers/components/detail/ComingSoonPlaceholder.tsx +21 -0
  564. package/src/modules/customers/components/detail/CompanyCard.tsx +419 -0
  565. package/src/modules/customers/components/detail/CompanyDashboardTab.tsx +161 -0
  566. package/src/modules/customers/components/detail/CompanyDetailHeader.tsx +243 -0
  567. package/src/modules/customers/components/detail/CompanyDetailTabs.tsx +172 -0
  568. package/src/modules/customers/components/detail/CompanyKpiBar.tsx +206 -0
  569. package/src/modules/customers/components/detail/CompanyPeopleSection.tsx +582 -288
  570. package/src/modules/customers/components/detail/CompanyTagsDialog.tsx +23 -0
  571. package/src/modules/customers/components/detail/ConfirmDealLostDialog.tsx +210 -0
  572. package/src/modules/customers/components/detail/CreatePersonDialog.tsx +178 -0
  573. package/src/modules/customers/components/detail/DealClosureActionBar.tsx +63 -0
  574. package/src/modules/customers/components/detail/DealDetailHeader.tsx +335 -0
  575. package/src/modules/customers/components/detail/DealDetailTabs.tsx +154 -0
  576. package/src/modules/customers/components/detail/DealForm.tsx +253 -101
  577. package/src/modules/customers/components/detail/DealLinkedEntitiesTab.tsx +349 -0
  578. package/src/modules/customers/components/detail/DealLostSummaryDialog.tsx +156 -0
  579. package/src/modules/customers/components/detail/DealWonPopup.tsx +164 -0
  580. package/src/modules/customers/components/detail/DealsSection.tsx +276 -221
  581. package/src/modules/customers/components/detail/DecisionMakersFooter.tsx +56 -0
  582. package/src/modules/customers/components/detail/EntityTagsDialog.tsx +1372 -0
  583. package/src/modules/customers/components/detail/InlineActivityComposer.tsx +239 -0
  584. package/src/modules/customers/components/detail/ManageTagsDialog.tsx +1331 -0
  585. package/src/modules/customers/components/detail/MiniWeekCalendar.tsx +338 -0
  586. package/src/modules/customers/components/detail/MobilePersonDetail.tsx +124 -0
  587. package/src/modules/customers/components/detail/NextStepCard.tsx +104 -0
  588. package/src/modules/customers/components/detail/PersonCard.tsx +238 -0
  589. package/src/modules/customers/components/detail/PersonCompaniesSection.tsx +426 -0
  590. package/src/modules/customers/components/detail/PersonDetailHeader.tsx +294 -0
  591. package/src/modules/customers/components/detail/PersonDetailTabs.tsx +172 -0
  592. package/src/modules/customers/components/detail/PersonTagsDialog.tsx +26 -0
  593. package/src/modules/customers/components/detail/PipelineStepper.tsx +245 -0
  594. package/src/modules/customers/components/detail/PlannedActivitiesSection.tsx +255 -0
  595. package/src/modules/customers/components/detail/RelationshipHealthCard.tsx +63 -0
  596. package/src/modules/customers/components/detail/RoleAssignmentRow.tsx +248 -0
  597. package/src/modules/customers/components/detail/RolesSection.tsx +311 -0
  598. package/src/modules/customers/components/detail/ScheduleActivityDialog.tsx +481 -0
  599. package/src/modules/customers/components/detail/aiActionCatalog.ts +77 -0
  600. package/src/modules/customers/components/detail/assignableStaff.ts +124 -0
  601. package/src/modules/customers/components/detail/dashboard/ActiveDealWidget.tsx +63 -0
  602. package/src/modules/customers/components/detail/dashboard/OpenTasksWidget.tsx +114 -0
  603. package/src/modules/customers/components/detail/dashboard/RecentActivityWidget.tsx +69 -0
  604. package/src/modules/customers/components/detail/dashboard/RelationshipHealthWidget.tsx +40 -0
  605. package/src/modules/customers/components/detail/dashboard/UpcomingMeetingsWidget.tsx +64 -0
  606. package/src/modules/customers/components/detail/dashboard/helpers.ts +78 -0
  607. package/src/modules/customers/components/detail/healthScoreUtils.ts +91 -0
  608. package/src/modules/customers/components/detail/hooks/useCurrencyDictionary.ts +8 -8
  609. package/src/modules/customers/components/detail/hooks/useCustomerDictionary.ts +10 -6
  610. package/src/modules/customers/components/detail/hooks/useInteractionMutations.ts +91 -0
  611. package/src/modules/customers/components/detail/notesAdapter.ts +91 -30
  612. package/src/modules/customers/components/detail/pipelineStageUtils.ts +29 -0
  613. package/src/modules/customers/components/detail/schedule/DateTimeFields.tsx +187 -0
  614. package/src/modules/customers/components/detail/schedule/FooterFields.tsx +79 -0
  615. package/src/modules/customers/components/detail/schedule/LinkedEntitiesField.tsx +277 -0
  616. package/src/modules/customers/components/detail/schedule/LocationField.tsx +42 -0
  617. package/src/modules/customers/components/detail/schedule/ParticipantsField.tsx +255 -0
  618. package/src/modules/customers/components/detail/schedule/fieldConfig.ts +70 -0
  619. package/src/modules/customers/components/detail/schedule/index.ts +9 -0
  620. package/src/modules/customers/components/detail/schedule/useScheduleFormState.ts +221 -0
  621. package/src/modules/customers/components/detail/types.ts +16 -0
  622. package/src/modules/customers/components/detail/utils.ts +25 -0
  623. package/src/modules/customers/components/formConfig.tsx +223 -28
  624. package/src/modules/customers/components/linking/LinkEntityDialog.tsx +920 -0
  625. package/src/modules/customers/components/linking/adapters/companyAdapter.tsx +398 -0
  626. package/src/modules/customers/components/linking/adapters/dealAdapter.tsx +578 -0
  627. package/src/modules/customers/components/linking/adapters/personAdapter.tsx +512 -0
  628. package/src/modules/customers/components/list/CollectionPreviewCell.tsx +66 -0
  629. package/src/modules/customers/data/entities.ts +353 -1
  630. package/src/modules/customers/data/validators.ts +170 -19
  631. package/src/modules/customers/events.ts +22 -0
  632. package/src/modules/customers/i18n/de.json +841 -2
  633. package/src/modules/customers/i18n/en.json +841 -2
  634. package/src/modules/customers/i18n/es.json +840 -1
  635. package/src/modules/customers/i18n/pl.json +841 -2
  636. package/src/modules/customers/lib/customerRoleTypes.ts +24 -0
  637. package/src/modules/customers/lib/dealClosureNotification.ts +64 -0
  638. package/src/modules/customers/lib/dealStageTransitionTable.ts +32 -0
  639. package/src/modules/customers/lib/dictionaries.ts +26 -10
  640. package/src/modules/customers/lib/interactionReadModel.ts +10 -0
  641. package/src/modules/customers/lib/personCompanies.ts +317 -0
  642. package/src/modules/customers/lib/personCompanyLinkTable.ts +58 -0
  643. package/src/modules/customers/lib/roleTypeUsage.ts +146 -0
  644. package/src/modules/customers/migrations/.snapshot-open-mercato.json +2747 -798
  645. package/src/modules/customers/migrations/Migration20260406214502.ts +19 -0
  646. package/src/modules/customers/migrations/Migration20260408135736.ts +15 -0
  647. package/src/modules/customers/migrations/Migration20260408225345.ts +23 -0
  648. package/src/modules/customers/migrations/Migration20260411075533.ts +30 -0
  649. package/src/modules/customers/migrations/Migration20260411103551.ts +13 -0
  650. package/src/modules/customers/migrations/Migration20260411130944.ts +30 -0
  651. package/src/modules/customers/migrations/Migration20260415095203.ts +13 -0
  652. package/src/modules/customers/migrations/Migration20260415135056.ts +22 -0
  653. package/src/modules/customers/migrations/Migration20260417140000.ts +15 -0
  654. package/src/modules/customers/migrations/Migration20260417160000.ts +17 -0
  655. package/src/modules/customers/migrations/Migration20260417235407.ts +13 -0
  656. package/src/modules/customers/setup.ts +15 -0
  657. package/src/modules/customers/subscribers/deal-closure-notification.ts +22 -0
  658. package/src/modules/customers/subscribers/deal-lost-notification.ts +22 -0
  659. package/src/modules/dictionaries/api/[dictionaryId]/entries/[entryId]/route.ts +2 -0
  660. package/src/modules/dictionaries/api/[dictionaryId]/entries/reorder/route.ts +162 -0
  661. package/src/modules/dictionaries/api/[dictionaryId]/entries/route.ts +6 -2
  662. package/src/modules/dictionaries/api/[dictionaryId]/entries/set-default/route.ts +162 -0
  663. package/src/modules/dictionaries/api/context.ts +9 -0
  664. package/src/modules/dictionaries/api/openapi.ts +17 -0
  665. package/src/modules/dictionaries/commands/entry-operations.ts +457 -0
  666. package/src/modules/dictionaries/commands/factory.ts +31 -3
  667. package/src/modules/dictionaries/commands/index.ts +1 -0
  668. package/src/modules/dictionaries/components/DictionaryTable.tsx +15 -6
  669. package/src/modules/dictionaries/data/entities.ts +9 -0
  670. package/src/modules/dictionaries/data/validators.ts +34 -0
  671. package/src/modules/dictionaries/events.ts +20 -0
  672. package/src/modules/dictionaries/i18n/de.json +2 -0
  673. package/src/modules/dictionaries/i18n/en.json +2 -0
  674. package/src/modules/dictionaries/i18n/es.json +2 -0
  675. package/src/modules/dictionaries/i18n/pl.json +2 -0
  676. package/src/modules/dictionaries/lib/clientEntries.ts +66 -0
  677. package/src/modules/dictionaries/migrations/.snapshot-open-mercato.json +185 -3
  678. package/src/modules/dictionaries/migrations/Migration20260410171544.ts +49 -0
  679. package/src/modules/inbox_ops/api/proposals/[id]/route.ts +4 -1
  680. package/src/modules/query_index/lib/engine.ts +9 -1
  681. package/src/modules/sales/components/documents/AddressesSection.tsx +92 -42
  682. package/src/modules/sales/i18n/de.json +28 -0
  683. package/src/modules/sales/i18n/en.json +28 -0
  684. package/src/modules/sales/i18n/es.json +28 -0
  685. package/src/modules/sales/i18n/pl.json +28 -0
  686. package/src/modules/sales/lib/dictionaries.ts +18 -0
  687. package/src/modules/sales/widgets/injection-table.ts +4 -0
@@ -1,538 +1,591 @@
1
1
  "use client";
2
- import { Fragment, jsx, jsxs } from "react/jsx-runtime";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
3
  import * as React from "react";
4
4
  import Link from "next/link";
5
- import { useRouter } from "next/navigation";
6
- import { Pencil, MousePointerClick } from "lucide-react";
5
+ import { Building2, Users } from "lucide-react";
6
+ import { useRouter, useSearchParams } from "next/navigation";
7
7
  import { Page, PageBody } from "@open-mercato/ui/backend/Page";
8
8
  import { Button } from "@open-mercato/ui/primitives/button";
9
- import { FormHeader } from "@open-mercato/ui/backend/forms";
10
- import { VersionHistoryAction } from "@open-mercato/ui/backend/version-history";
11
- import { SendObjectMessageDialog } from "@open-mercato/ui/backend/messages";
12
- import { Spinner } from "@open-mercato/ui/primitives/spinner";
13
- import { flash } from "@open-mercato/ui/backend/FlashMessages";
14
- import { apiCallOrThrow, readApiResultOrThrow } from "@open-mercato/ui/backend/utils/apiCall";
15
- import { useT } from "@open-mercato/shared/lib/i18n/context";
16
- import { useOrganizationScopeVersion } from "@open-mercato/shared/lib/frontend/useOrganizationScope";
9
+ import { AttachmentsSection, ErrorMessage, LoadingMessage, NotesSection } from "@open-mercato/ui/backend/detail";
10
+ import { InjectionSpot } from "@open-mercato/ui/backend/injection/InjectionSpot";
17
11
  import { useConfirmDialog } from "@open-mercato/ui/backend/confirm-dialog";
18
- import { NotesSection } from "@open-mercato/ui/backend/detail";
19
- import { ActivitiesSection } from "../../../../components/detail/ActivitiesSection.js";
20
- import { DealForm } from "../../../../components/detail/DealForm.js";
21
- import { useCustomerDictionary } from "../../../../components/detail/hooks/useCustomerDictionary.js";
12
+ import { CollapsibleZoneLayout } from "@open-mercato/ui/backend/crud/CollapsibleZoneLayout";
13
+ import { useT } from "@open-mercato/shared/lib/i18n/context";
22
14
  import { createTranslatorWithFallback } from "@open-mercato/shared/lib/i18n/translate";
23
- import { renderDictionaryColor, renderDictionaryIcon } from "@open-mercato/core/modules/dictionaries/components/dictionaryAppearance";
24
- import { ICON_SUGGESTIONS } from "../../../../lib/dictionaries.js";
15
+ import { E } from "../../../../../../generated/entities.ids.generated.js";
16
+ import { ActivitiesSection } from "../../../../components/detail/ActivitiesSection.js";
17
+ import { ChangelogTab } from "../../../../components/detail/ChangelogTab.js";
18
+ import { DealClosureActionBar } from "../../../../components/detail/DealClosureActionBar.js";
19
+ import { DealDetailHeader } from "../../../../components/detail/DealDetailHeader.js";
20
+ import { DealDetailTabs, resolveLegacyTab } from "../../../../components/detail/DealDetailTabs.js";
21
+ import { DealForm, useDealAssociationLookups } from "../../../../components/detail/DealForm.js";
22
+ import { DealLinkedEntitiesTab } from "../../../../components/detail/DealLinkedEntitiesTab.js";
23
+ import { ConfirmDealLostDialog } from "../../../../components/detail/ConfirmDealLostDialog.js";
24
+ import { DealLostSummaryDialog } from "../../../../components/detail/DealLostSummaryDialog.js";
25
+ import { DealWonPopup } from "../../../../components/detail/DealWonPopup.js";
26
+ import { InlineActivityComposer } from "../../../../components/detail/InlineActivityComposer.js";
27
+ import { PipelineStepper } from "../../../../components/detail/PipelineStepper.js";
28
+ import { PlannedActivitiesSection } from "../../../../components/detail/PlannedActivitiesSection.js";
29
+ import { ScheduleActivityDialog } from "../../../../components/detail/ScheduleActivityDialog.js";
25
30
  import { createCustomerNotesAdapter } from "../../../../components/detail/notesAdapter.js";
26
31
  import { readMarkdownPreferenceCookie, writeMarkdownPreferenceCookie } from "../../../../lib/markdownPreference.js";
27
- const CRUD_FOCUSABLE_SELECTOR = '[data-crud-focus-target], input:not([type="hidden"]):not([disabled]), textarea:not([disabled]), select:not([disabled]), [tabindex]:not([tabindex="-1"])';
28
- function formatCurrency(amount, currency) {
29
- if (!amount) return null;
30
- const value = Number(amount);
31
- if (!Number.isFinite(value)) return currency ? `${amount} ${currency}` : amount;
32
- if (!currency) return value.toLocaleString();
33
- try {
34
- return new Intl.NumberFormat(void 0, { style: "currency", currency }).format(value);
35
- } catch {
36
- return `${value.toLocaleString()} ${currency}`;
37
- }
38
- }
39
- function formatDate(value, fallback) {
40
- if (!value) return fallback;
41
- const date = new Date(value);
42
- if (Number.isNaN(date.getTime())) return fallback;
43
- return date.toLocaleDateString(void 0, { year: "numeric", month: "short", day: "numeric" });
44
- }
45
- function resolveDictionaryLabel(value, map) {
46
- if (!value) return null;
47
- const entry = map?.[value];
48
- if (entry && entry.label && entry.label.length) return entry.label;
49
- return value;
50
- }
32
+ import { ICON_SUGGESTIONS } from "../../../../lib/dictionaries.js";
33
+ import { renderDictionaryColor, renderDictionaryIcon } from "@open-mercato/core/modules/dictionaries/components/dictionaryAppearance";
34
+ import { formatCurrency, startOfNextQuarter } from "./hooks/formatters.js";
35
+ import { useDealActivities } from "./hooks/useDealActivities.js";
36
+ import { useDealAssociations } from "./hooks/useDealAssociations.js";
37
+ import { useDealClosure } from "./hooks/useDealClosure.js";
38
+ import { useDealData } from "./hooks/useDealData.js";
39
+ import { useDealFormHandlers } from "./hooks/useDealFormHandlers.js";
40
+ import { useDealInjectedTabs } from "./hooks/useDealInjectedTabs.js";
41
+ import { useDealMutationContext } from "./hooks/useDealMutationContext.js";
42
+ import { useDealPipeline } from "./hooks/useDealPipeline.js";
43
+ import { useScheduleDialog } from "./hooks/useScheduleDialog.js";
51
44
  function DealDetailPage({ params }) {
45
+ const id = params?.id ?? "";
52
46
  const t = useT();
47
+ const router = useRouter();
48
+ const searchParams = useSearchParams();
53
49
  const { confirm, ConfirmDialogElement } = useConfirmDialog();
54
50
  const detailTranslator = React.useMemo(() => createTranslatorWithFallback(t), [t]);
55
- const notesAdapter = React.useMemo(() => createCustomerNotesAdapter(detailTranslator), [detailTranslator]);
56
- const router = useRouter();
57
- const id = params?.id ?? "";
58
- const scopeVersion = useOrganizationScopeVersion();
59
- const statusDictionaryQuery = useCustomerDictionary("deal-statuses", scopeVersion);
60
- const pipelineDictionaryQuery = useCustomerDictionary("pipeline-stages", scopeVersion);
61
- const statusDictionaryMap = statusDictionaryQuery.data?.map ?? null;
62
- const pipelineDictionaryMap = pipelineDictionaryQuery.data?.map ?? null;
63
- const [data, setData] = React.useState(null);
64
- const [isLoading, setIsLoading] = React.useState(true);
65
- const [error, setError] = React.useState(null);
66
- const [isSaving, setIsSaving] = React.useState(false);
67
- const [isDeleting, setIsDeleting] = React.useState(false);
68
- const [reloadToken, setReloadToken] = React.useState(0);
69
- const [activeTab, setActiveTab] = React.useState("notes");
70
- const [sectionAction, setSectionAction] = React.useState(null);
71
- const handleNotesLoadingChange = React.useCallback(() => {
72
- }, []);
73
- const handleActivitiesLoadingChange = React.useCallback(() => {
74
- }, []);
75
- const focusDealField = React.useCallback(
76
- (fieldId) => {
77
- if (typeof window === "undefined" || typeof document === "undefined") return;
78
- const focusOnce = () => {
79
- const container = document.querySelector(`[data-crud-field-id="${fieldId}"]`);
80
- if (!container) return false;
81
- const target = container.querySelector(CRUD_FOCUSABLE_SELECTOR) ?? container;
82
- if (!target || typeof target.focus !== "function") return false;
83
- if (typeof container.scrollIntoView === "function") {
84
- container.scrollIntoView({ behavior: "smooth", block: "center" });
85
- }
86
- target.focus();
87
- if (target instanceof HTMLInputElement || target instanceof HTMLTextAreaElement) {
88
- try {
89
- target.select();
90
- } catch {
91
- }
92
- }
93
- return true;
94
- };
95
- const schedule = () => {
96
- const focused = focusOnce();
97
- if (focused) return;
98
- window.setTimeout(() => {
99
- focusOnce();
100
- }, 60);
101
- };
102
- if (typeof window.requestAnimationFrame === "function") {
103
- window.requestAnimationFrame(schedule);
104
- } else {
105
- schedule();
106
- }
107
- },
108
- []
51
+ const { data, setData, isLoading, error, loadData } = useDealData(id);
52
+ const [isDirty, setIsDirty] = React.useState(false);
53
+ const {
54
+ scheduleDialogOpen,
55
+ scheduleEditData,
56
+ openSchedule,
57
+ openEdit: openScheduleEdit,
58
+ closeSchedule
59
+ } = useScheduleDialog();
60
+ const formWrapperRef = React.useRef(null);
61
+ const initialTab = React.useMemo(() => resolveLegacyTab(searchParams?.get("tab")), [searchParams]);
62
+ const [activeTab, setActiveTab] = React.useState(initialTab);
63
+ React.useEffect(() => {
64
+ setActiveTab(initialTab);
65
+ }, [initialTab]);
66
+ const currentDealId = data?.deal.id ?? id;
67
+ const { injectionContext, runMutationWithContext } = useDealMutationContext({
68
+ currentDealId,
69
+ fallbackId: id,
70
+ data
71
+ });
72
+ const notesAdapter = React.useMemo(
73
+ () => createCustomerNotesAdapter(detailTranslator, { runMutation: runMutationWithContext }),
74
+ [detailTranslator, runMutationWithContext]
109
75
  );
110
- const dealSettingsRef = React.useRef(null);
111
- const scrollToDealSettings = React.useCallback(() => {
112
- if (typeof window === "undefined") return;
113
- if (dealSettingsRef.current && typeof dealSettingsRef.current.scrollIntoView === "function") {
114
- dealSettingsRef.current.scrollIntoView({ behavior: "smooth", block: "start" });
115
- }
116
- window.setTimeout(() => {
117
- focusDealField("title");
118
- }, 160);
119
- }, [focusDealField]);
76
+ const { injectedTabs, injectedTabMap } = useDealInjectedTabs({
77
+ injectionContext,
78
+ data,
79
+ setData
80
+ });
81
+ const { searchPeoplePage, fetchPeopleByIds, searchCompaniesPage, fetchCompaniesByIds } = useDealAssociationLookups({
82
+ excludeLinkedDealId: data?.deal.id ?? null
83
+ });
84
+ const {
85
+ plannedActivities,
86
+ activityRefreshKey,
87
+ loadPlannedActivities,
88
+ handleActivityCreated,
89
+ handleMarkDone,
90
+ handleCancelActivity
91
+ } = useDealActivities({ dealId: id, runMutationWithContext });
120
92
  React.useEffect(() => {
121
- if (!id) {
122
- setError(t("customers.deals.detail.missingId", "Deal id is required."));
123
- setIsLoading(false);
124
- return;
125
- }
126
- let cancelled = false;
127
- async function loadDeal() {
128
- setIsLoading(true);
129
- setError(null);
130
- try {
131
- const payload = await readApiResultOrThrow(
132
- `/api/customers/deals/${encodeURIComponent(id)}`,
133
- void 0,
134
- { errorMessage: t("customers.deals.detail.loadError", "Failed to load deal.") }
135
- );
136
- if (cancelled) return;
137
- setData(payload);
138
- } catch (err) {
139
- if (cancelled) return;
140
- const message = err instanceof Error && err.message ? err.message : t("customers.deals.detail.loadError", "Failed to load deal.");
141
- setError(message);
142
- setData(null);
143
- } finally {
144
- if (!cancelled) setIsLoading(false);
145
- }
146
- }
147
- loadDeal().catch(() => {
93
+ void Promise.all([loadData(), loadPlannedActivities()]);
94
+ }, [loadData, loadPlannedActivities]);
95
+ const activityEntities = React.useMemo(
96
+ () => data ? [...data.people, ...data.companies].map((entry) => ({
97
+ id: entry.id,
98
+ label: entry.subtitle ? `${entry.label} \xB7 ${entry.subtitle}` : entry.label,
99
+ kind: entry.kind
100
+ })) : [],
101
+ [data]
102
+ );
103
+ const [selectedActivityEntityId, setSelectedActivityEntityId] = React.useState(null);
104
+ React.useEffect(() => {
105
+ setSelectedActivityEntityId((current) => {
106
+ if (activityEntities.length === 1) return activityEntities[0].id;
107
+ if (current && activityEntities.some((entry) => entry.id === current)) return current;
108
+ return null;
148
109
  });
149
- return () => {
150
- cancelled = true;
151
- };
152
- }, [id, reloadToken, t]);
153
- const handleFormSubmit = React.useCallback(
154
- async ({ base, custom }) => {
155
- if (!data || isSaving) return;
156
- setIsSaving(true);
157
- try {
158
- const payload = {
159
- id: data.deal.id,
160
- title: base.title,
161
- status: base.status ?? void 0,
162
- pipelineStage: base.pipelineStage ?? void 0,
163
- pipelineId: base.pipelineId ?? void 0,
164
- pipelineStageId: base.pipelineStageId ?? void 0,
165
- valueAmount: typeof base.valueAmount === "number" ? base.valueAmount : void 0,
166
- valueCurrency: base.valueCurrency ?? void 0,
167
- probability: typeof base.probability === "number" ? base.probability : void 0,
168
- expectedCloseAt: base.expectedCloseAt ?? void 0,
169
- description: base.description ?? void 0,
170
- personIds: base.personIds && base.personIds.length ? base.personIds : void 0,
171
- companyIds: base.companyIds && base.companyIds.length ? base.companyIds : void 0
172
- };
173
- if (Object.keys(custom).length) payload.customFields = custom;
174
- await apiCallOrThrow(
175
- "/api/customers/deals",
176
- {
177
- method: "PUT",
178
- headers: { "content-type": "application/json" },
179
- body: JSON.stringify(payload)
180
- },
181
- { errorMessage: t("customers.deals.detail.saveError", "Failed to update deal.") }
182
- );
183
- flash(t("customers.deals.detail.saveSuccess", "Deal updated."), "success");
184
- setReloadToken((token) => token + 1);
185
- } catch (err) {
186
- const message = err instanceof Error && err.message ? err.message : t("customers.deals.detail.saveError", "Failed to update deal.");
187
- flash(message, "error");
188
- throw err instanceof Error ? err : new Error(message);
189
- } finally {
190
- setIsSaving(false);
191
- }
192
- },
193
- [data, isSaving, t]
110
+ }, [activityEntities]);
111
+ const selectedActivityEntity = React.useMemo(
112
+ () => activityEntities.find((entry) => entry.id === selectedActivityEntityId) ?? null,
113
+ [activityEntities, selectedActivityEntityId]
114
+ );
115
+ const dealOptions = React.useMemo(
116
+ () => data ? [{ id: data.deal.id, label: data.deal.title || t("customers.deals.detail.untitled", "Untitled deal") }] : [],
117
+ [data, t]
194
118
  );
195
- const handleDelete = React.useCallback(async () => {
196
- if (!data || isDeleting) return;
197
- const confirmed = await confirm({
198
- title: t(
199
- "customers.deals.detail.deleteConfirm",
200
- "Delete this deal? This action cannot be undone."
119
+ const entityOptions = React.useMemo(
120
+ () => activityEntities.map(({ id: id2, label }) => ({ id: id2, label })),
121
+ [activityEntities]
122
+ );
123
+ const confirmDiscardIfDirty = React.useCallback(async () => {
124
+ if (!isDirty) return true;
125
+ return confirm({
126
+ title: t("customers.deals.detail.unsavedTitle", "Discard unsaved changes?"),
127
+ description: t(
128
+ "customers.deals.detail.unsavedDescription",
129
+ "You have unsaved edits in this deal. Save them first or continue to discard them."
201
130
  ),
131
+ confirmText: t("customers.deals.detail.unsavedConfirm", "Discard changes"),
132
+ cancelText: t("customers.deals.detail.unsavedCancel", "Keep editing"),
202
133
  variant: "destructive"
203
134
  });
204
- if (!confirmed) return;
205
- setIsDeleting(true);
206
- try {
207
- await apiCallOrThrow(
208
- "/api/customers/deals",
209
- {
210
- method: "DELETE",
211
- headers: { "content-type": "application/json" },
212
- body: JSON.stringify({ id: data.deal.id })
213
- },
214
- { errorMessage: t("customers.deals.detail.deleteError", "Failed to delete deal.") }
215
- );
216
- flash(t("customers.deals.detail.deleteSuccess", "Deal deleted."), "success");
217
- router.push("/backend/customers/deals");
218
- } catch (err) {
219
- const message = err instanceof Error && err.message ? err.message : t("customers.deals.detail.deleteError", "Failed to delete deal.");
220
- flash(message, "error");
221
- } finally {
222
- setIsDeleting(false);
135
+ }, [confirm, isDirty, t]);
136
+ const {
137
+ peopleEditorIds,
138
+ companiesEditorIds,
139
+ peopleSaving,
140
+ companiesSaving,
141
+ handlePeopleAssociationsChange,
142
+ handleCompaniesAssociationsChange,
143
+ loadLinkedPeoplePage,
144
+ loadLinkedCompaniesPage
145
+ } = useDealAssociations({
146
+ currentDealId,
147
+ data,
148
+ setData,
149
+ runMutationWithContext
150
+ });
151
+ const { isStageSaving, handleStageChange } = useDealPipeline({
152
+ currentDealId,
153
+ data,
154
+ runMutationWithContext,
155
+ confirmDiscardIfDirty,
156
+ onStageChanged: loadData
157
+ });
158
+ const {
159
+ lostDialogOpen,
160
+ wonPopupOpen,
161
+ lostPopupOpen,
162
+ wonStats,
163
+ lostStats,
164
+ openLostDialog,
165
+ closeLostDialog,
166
+ closeWonPopup,
167
+ closeLostPopup,
168
+ handleWon,
169
+ handleLostConfirm
170
+ } = useDealClosure({
171
+ currentDealId,
172
+ runMutationWithContext,
173
+ confirmDiscardIfDirty,
174
+ onClosed: loadData
175
+ });
176
+ const handleTabChange = React.useCallback(async (tab) => {
177
+ if (!await confirmDiscardIfDirty()) return;
178
+ setActiveTab(tab);
179
+ const nextParams = new URLSearchParams(searchParams?.toString() ?? "");
180
+ nextParams.set("tab", tab);
181
+ router.replace(`/backend/customers/deals/${encodeURIComponent(id)}?${nextParams.toString()}`, { scroll: false });
182
+ }, [confirmDiscardIfDirty, id, router, searchParams]);
183
+ const { isSaving, handleFormSubmit, handleDelete, handleHeaderSave } = useDealFormHandlers({
184
+ data,
185
+ currentDealId,
186
+ loadData,
187
+ runMutationWithContext,
188
+ formWrapperRef,
189
+ confirm
190
+ });
191
+ const handleEditActivity = React.useCallback((activity) => {
192
+ if (activity.entityId && activityEntities.some((entry) => entry.id === activity.entityId)) {
193
+ setSelectedActivityEntityId(activity.entityId);
223
194
  }
224
- }, [confirm, data, isDeleting, router, t]);
225
- React.useEffect(() => {
226
- setSectionAction(null);
227
- }, [activeTab]);
228
- const handleSectionAction = React.useCallback(() => {
229
- if (!sectionAction || sectionAction.disabled) return;
230
- sectionAction.onClick();
231
- }, [sectionAction]);
232
- const dealOptions = React.useMemo(
233
- () => data ? [
234
- {
235
- id: data.deal.id,
236
- label: data.deal.title && data.deal.title.length ? data.deal.title : t("customers.deals.detail.untitled", "Untitled deal")
237
- }
238
- ] : [],
239
- [data, t]
240
- );
241
- const entityOptions = React.useMemo(() => {
242
- if (!data) return [];
243
- const entries = [];
244
- data.people.forEach((person) => {
245
- if (!person.id) return;
246
- const suffix = person.subtitle ? ` \xB7 ${person.subtitle}` : "";
247
- entries.push({ id: person.id, label: `${person.label}${suffix}` });
195
+ openScheduleEdit({
196
+ id: activity.id,
197
+ interactionType: activity.interactionType,
198
+ title: activity.title ?? null,
199
+ body: activity.body ?? null,
200
+ scheduledAt: activity.scheduledAt ?? null,
201
+ durationMinutes: activity.duration ?? null,
202
+ location: activity.location ?? null,
203
+ allDay: activity.allDay ?? null,
204
+ recurrenceRule: activity.recurrenceRule ?? null,
205
+ recurrenceEnd: activity.recurrenceEnd ?? null,
206
+ participants: activity.participants ?? null,
207
+ reminderMinutes: activity.reminderMinutes ?? null,
208
+ visibility: activity.visibility ?? null,
209
+ linkedEntities: activity.linkedEntities ?? null,
210
+ guestPermissions: activity.guestPermissions ?? null
248
211
  });
249
- data.companies.forEach((company) => {
250
- if (!company.id) return;
251
- const suffix = company.subtitle ? ` \xB7 ${company.subtitle}` : "";
252
- entries.push({ id: company.id, label: `${company.label}${suffix}` });
212
+ }, [activityEntities, openScheduleEdit]);
213
+ const handleViewDashboard = React.useCallback(() => {
214
+ closeWonPopup();
215
+ router.push("/backend");
216
+ }, [closeWonPopup, router]);
217
+ const handleBackToPipeline = React.useCallback(() => {
218
+ closeWonPopup();
219
+ closeLostPopup();
220
+ router.push("/backend/customers/deals/pipeline");
221
+ }, [closeLostPopup, closeWonPopup, router]);
222
+ const handleScheduleLostFollowUp = React.useCallback(() => {
223
+ if (!data || !selectedActivityEntity) return;
224
+ const nextQuarterDate = startOfNextQuarter(/* @__PURE__ */ new Date());
225
+ closeLostPopup();
226
+ openScheduleEdit({
227
+ id: "",
228
+ interactionType: "task",
229
+ title: data.deal.title ? t("customers.deals.detail.lost.followUpTitle", "Revisit {{title}}", { title: data.deal.title }) : t("customers.deals.detail.lost.followUpFallbackTitle", "Revisit closed deal"),
230
+ body: data.deal.lossNotes ?? null,
231
+ scheduledAt: nextQuarterDate.toISOString(),
232
+ durationMinutes: 30,
233
+ location: null,
234
+ allDay: false,
235
+ recurrenceRule: null,
236
+ recurrenceEnd: null,
237
+ participants: null,
238
+ reminderMinutes: 1440,
239
+ visibility: "team",
240
+ linkedEntities: [
241
+ {
242
+ id: data.deal.id,
243
+ type: "deal",
244
+ label: data.deal.title || t("customers.deals.detail.untitled", "Untitled deal")
245
+ }
246
+ ]
253
247
  });
254
- return entries;
255
- }, [data]);
256
- const defaultEntityId = React.useMemo(() => {
257
- if (entityOptions.length) return entityOptions[0].id;
258
- return null;
259
- }, [entityOptions]);
260
- const tabs = React.useMemo(
261
- () => [
262
- { id: "notes", label: t("customers.deals.detail.tabs.notes", "Notes") },
263
- { id: "activities", label: t("customers.deals.detail.tabs.activities", "Activities") }
264
- ],
265
- [t]
266
- );
248
+ }, [closeLostPopup, data, openScheduleEdit, selectedActivityEntity, t]);
267
249
  if (isLoading) {
268
- return /* @__PURE__ */ jsx(Page, { children: /* @__PURE__ */ jsx(PageBody, { children: /* @__PURE__ */ jsxs("div", { className: "flex h-[50vh] flex-col items-center justify-center gap-2 text-muted-foreground", children: [
269
- /* @__PURE__ */ jsx(Spinner, { className: "h-6 w-6" }),
270
- /* @__PURE__ */ jsx("span", { children: t("customers.deals.detail.loading", "Loading deal\u2026") })
271
- ] }) }) });
250
+ return /* @__PURE__ */ jsx(Page, { children: /* @__PURE__ */ jsx(PageBody, { children: /* @__PURE__ */ jsx(LoadingMessage, { label: t("customers.deals.detail.loading", "Loading deal\u2026") }) }) });
272
251
  }
273
252
  if (error || !data) {
274
- return /* @__PURE__ */ jsx(Page, { children: /* @__PURE__ */ jsx(PageBody, { children: /* @__PURE__ */ jsxs("div", { className: "flex h-[50vh] flex-col items-center justify-center gap-3 text-muted-foreground", children: [
275
- /* @__PURE__ */ jsx("p", { children: error || t("customers.deals.detail.notFound", "Deal not found.") }),
276
- /* @__PURE__ */ jsx(Button, { variant: "outline", asChild: true, children: /* @__PURE__ */ jsx(Link, { href: "/backend/customers/deals", children: t("customers.deals.detail.backToList", "Back to deals") }) })
277
- ] }) }) });
253
+ return /* @__PURE__ */ jsx(Page, { children: /* @__PURE__ */ jsx(PageBody, { children: /* @__PURE__ */ jsx(
254
+ ErrorMessage,
255
+ {
256
+ label: error || t("customers.deals.detail.error.notFound", "Deal not found."),
257
+ action: /* @__PURE__ */ jsx(Button, { asChild: true, variant: "outline", children: /* @__PURE__ */ jsx(Link, { href: "/backend/customers/deals", children: t("customers.deals.detail.actions.backToList", "Back to deals") }) })
258
+ }
259
+ ) }) });
278
260
  }
279
- const probabilityLabel = data.deal.probability !== null && data.deal.probability !== void 0 ? `${data.deal.probability}%` : t("customers.deals.detail.noValue", "Not provided");
280
- const valueLabel = formatCurrency(data.deal.valueAmount, data.deal.valueCurrency) ?? t("customers.deals.detail.noValue", "Not provided");
281
- const expectedCloseLabel = formatDate(data.deal.expectedCloseAt, t("customers.deals.detail.noValue", "Not provided"));
282
- const statusLabel = resolveDictionaryLabel(data.deal.status, statusDictionaryMap) ?? t("customers.deals.detail.noStatus", "No status");
283
- const statusDictEntry = data.deal.status ? statusDictionaryMap?.[data.deal.status] ?? null : null;
284
- const pipelineLabel = resolveDictionaryLabel(data.deal.pipelineStage, pipelineDictionaryMap);
285
- const pipelineDictEntry = data.deal.pipelineStage ? pipelineDictionaryMap?.[data.deal.pipelineStage] ?? null : null;
286
- const previewValueAmount = formatCurrency(data.deal.valueAmount, data.deal.valueCurrency);
287
- const previewProbability = data.deal.probability !== null && data.deal.probability !== void 0 ? `${data.deal.probability}%` : null;
288
- const dealPreviewMetadata = {};
289
- if (previewValueAmount) dealPreviewMetadata[t("customers.deals.detail.fields.value")] = previewValueAmount;
290
- if (previewProbability) dealPreviewMetadata[t("customers.deals.detail.fields.probability")] = previewProbability;
291
- const peopleSummaryLabel = data.people.length === 1 ? t("customers.deals.detail.peopleSummaryOne") : t("customers.deals.detail.peopleSummaryMany", void 0, { count: data.people.length });
292
- const companiesSummaryLabel = data.companies.length === 1 ? t("customers.deals.detail.companiesSummaryOne") : t("customers.deals.detail.companiesSummaryMany", void 0, { count: data.companies.length });
293
- const viewer = data.viewer ?? null;
294
- return /* @__PURE__ */ jsxs(Page, { children: [
295
- /* @__PURE__ */ jsx(PageBody, { children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-6", children: [
261
+ const amountLabel = formatCurrency(data.deal.valueAmount, data.deal.valueCurrency);
262
+ const currentPipelineName = data.pipelineName ?? wonStats?.pipelineName ?? lostStats?.pipelineName ?? null;
263
+ const dealName = data.deal.title || t("customers.deals.detail.untitled", "Untitled deal");
264
+ const zone1Content = /* @__PURE__ */ jsx("div", { ref: formWrapperRef, children: /* @__PURE__ */ jsx(
265
+ DealForm,
266
+ {
267
+ mode: "edit",
268
+ embedded: true,
269
+ trackDirtyWhenEmbedded: true,
270
+ hideFooterActions: true,
271
+ singleColumnGroups: true,
272
+ showAssociationsGroup: false,
273
+ showVersionHistory: false,
274
+ showCancelAction: false,
275
+ onDirtyChange: setIsDirty,
276
+ collapsibleGroups: { pageType: "deal-detail-v3", chevronPosition: "left" },
277
+ sortableGroups: { pageType: "deal-detail-v3" },
278
+ initialValues: {
279
+ ...data.deal,
280
+ valueAmount: typeof data.deal.valueAmount === "string" && data.deal.valueAmount.trim().length ? Number(data.deal.valueAmount) : null,
281
+ personIds: data.linkedPersonIds,
282
+ companyIds: data.linkedCompanyIds,
283
+ customFields: data.customFields,
284
+ ...Object.fromEntries(Object.entries(data.customFields ?? {}).map(([key, value]) => [`cf_${key}`, value]))
285
+ },
286
+ onSubmit: handleFormSubmit,
287
+ onCancel: () => {
288
+ void loadData();
289
+ },
290
+ onDelete: handleDelete
291
+ }
292
+ ) });
293
+ const zone2Content = /* @__PURE__ */ jsx("div", { className: "rounded-[10px] border border-border bg-card px-5 py-5", children: (() => {
294
+ const injected = injectedTabMap.get(activeTab);
295
+ if (injected) return injected();
296
+ if (activeTab === "activities") {
297
+ const activityEntitySelection = activityEntities.length > 1 ? /* @__PURE__ */ jsxs("div", { className: "rounded-[10px] border border-border bg-muted/20 px-5 py-5", children: [
298
+ /* @__PURE__ */ jsx("label", { htmlFor: "deal-activity-entity", className: "text-sm font-semibold text-foreground", children: t("customers.deals.detail.activities.selectEntityLabel", "Choose customer record") }),
299
+ /* @__PURE__ */ jsx("div", { className: "mt-1 text-sm text-muted-foreground", children: t(
300
+ "customers.deals.detail.activities.selectEntityDescription",
301
+ "Pick the person or company that should own new deal activities and follow-ups."
302
+ ) }),
303
+ /* @__PURE__ */ jsxs(
304
+ "select",
305
+ {
306
+ id: "deal-activity-entity",
307
+ "aria-label": t("customers.deals.detail.activities.selectEntityLabel", "Choose customer record"),
308
+ className: "mt-4 h-9 w-full rounded border border-muted-foreground/40 bg-background px-2 text-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary",
309
+ value: selectedActivityEntityId ?? "",
310
+ onChange: (event) => setSelectedActivityEntityId(event.target.value || null),
311
+ children: [
312
+ /* @__PURE__ */ jsx("option", { value: "", children: t("customers.deals.detail.activities.selectEntityPlaceholder", "Select a person or company") }),
313
+ activityEntities.map((entry) => /* @__PURE__ */ jsx("option", { value: entry.id, children: entry.label }, entry.id))
314
+ ]
315
+ }
316
+ )
317
+ ] }) : null;
318
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
319
+ activityEntities.length > 1 ? activityEntitySelection : null,
320
+ activityEntities.length === 0 ? /* @__PURE__ */ jsxs("div", { className: "rounded-[10px] border border-border bg-muted/20 px-5 py-5", children: [
321
+ /* @__PURE__ */ jsx("div", { className: "text-sm font-semibold text-foreground", children: t("customers.deals.detail.activities.linkEntityTitle", "Link a person or company first") }),
322
+ /* @__PURE__ */ jsx("div", { className: "mt-1 text-sm text-muted-foreground", children: t("customers.deals.detail.activities.linkEntityDescription", "Activities on a deal still need a customer record for timeline ownership.") }),
323
+ /* @__PURE__ */ jsxs("div", { className: "mt-4 flex gap-2", children: [
324
+ /* @__PURE__ */ jsx(Button, { type: "button", variant: "outline", size: "sm", onClick: () => handleTabChange("people"), children: t("customers.deals.detail.tabs.people", "People") }),
325
+ /* @__PURE__ */ jsx(Button, { type: "button", variant: "outline", size: "sm", onClick: () => handleTabChange("companies"), children: t("customers.deals.detail.tabs.companies", "Companies") })
326
+ ] })
327
+ ] }) : selectedActivityEntity ? /* @__PURE__ */ jsx(
328
+ InlineActivityComposer,
329
+ {
330
+ entityType: selectedActivityEntity.kind,
331
+ entityId: selectedActivityEntity.id,
332
+ dealId: data.deal.id,
333
+ onActivityCreated: () => {
334
+ void handleActivityCreated();
335
+ },
336
+ runGuardedMutation: runMutationWithContext,
337
+ onScheduleRequested: openSchedule
338
+ }
339
+ ) : /* @__PURE__ */ jsxs("div", { className: "rounded-[10px] border border-dashed border-border bg-muted/10 px-5 py-5", children: [
340
+ /* @__PURE__ */ jsx("div", { className: "text-sm font-semibold text-foreground", children: t("customers.deals.detail.activities.selectEntityRequiredTitle", "Choose a person or company to continue") }),
341
+ /* @__PURE__ */ jsx("div", { className: "mt-1 text-sm text-muted-foreground", children: t(
342
+ "customers.deals.detail.activities.selectEntityRequiredDescription",
343
+ "Select the customer record that should receive new deal activities before logging or scheduling anything."
344
+ ) })
345
+ ] }),
346
+ /* @__PURE__ */ jsx(
347
+ PlannedActivitiesSection,
348
+ {
349
+ activities: plannedActivities,
350
+ onComplete: (interactionId) => {
351
+ void handleMarkDone(interactionId);
352
+ },
353
+ onSchedule: selectedActivityEntity ? openSchedule : void 0,
354
+ onEdit: handleEditActivity,
355
+ onCancel: (interactionId) => {
356
+ void handleCancelActivity(interactionId);
357
+ }
358
+ }
359
+ ),
360
+ selectedActivityEntity ? /* @__PURE__ */ jsx(
361
+ ActivitiesSection,
362
+ {
363
+ entityId: selectedActivityEntity.id,
364
+ entityName: selectedActivityEntity.label,
365
+ dealId: data.deal.id,
366
+ dealOptions,
367
+ entityOptions,
368
+ defaultEntityId: selectedActivityEntity.id,
369
+ addActionLabel: t("customers.deals.detail.activitiesAdd", "Log activity"),
370
+ emptyState: {
371
+ title: t("customers.deals.detail.activitiesEmptyTitle", "No activities yet"),
372
+ actionLabel: t("customers.deals.detail.activitiesEmptyAction", "Log activity")
373
+ },
374
+ runGuardedMutation: runMutationWithContext,
375
+ onDataRefresh: () => {
376
+ void handleActivityCreated();
377
+ },
378
+ refreshKey: activityRefreshKey,
379
+ onEditActivity: handleEditActivity
380
+ }
381
+ ) : null
382
+ ] });
383
+ }
384
+ if (activeTab === "people") {
385
+ return /* @__PURE__ */ jsx(
386
+ DealLinkedEntitiesTab,
387
+ {
388
+ entityLabel: t("customers.deals.detail.tabs.peopleSingular", "Person"),
389
+ entityLabelPlural: t("customers.deals.detail.tabs.people", "People"),
390
+ manageLabel: t("customers.deals.detail.peopleEditorTitle", "Manage linked people"),
391
+ searchPlaceholder: t("customers.deals.detail.peopleSearch", "Search linked people\u2026"),
392
+ linkedItems: data.people,
393
+ linkedCount: data.counts.people,
394
+ selectedIds: peopleEditorIds,
395
+ disabled: peopleSaving || isSaving,
396
+ savePending: peopleSaving,
397
+ hrefBuilder: (personId) => `/backend/customers/people-v2/${encodeURIComponent(personId)}`,
398
+ onSaveSelection: (next) => handlePeopleAssociationsChange(next),
399
+ loadLinkedPage: loadLinkedPeoplePage,
400
+ searchEntities: searchPeoplePage,
401
+ fetchEntitiesByIds: fetchPeopleByIds,
402
+ icon: /* @__PURE__ */ jsx(Users, { className: "size-4" })
403
+ }
404
+ );
405
+ }
406
+ if (activeTab === "companies") {
407
+ return /* @__PURE__ */ jsx(
408
+ DealLinkedEntitiesTab,
409
+ {
410
+ entityLabel: t("customers.deals.detail.tabs.companySingular", "Company"),
411
+ entityLabelPlural: t("customers.deals.detail.tabs.companies", "Companies"),
412
+ manageLabel: t("customers.deals.detail.companiesEditorTitle", "Manage linked companies"),
413
+ searchPlaceholder: t("customers.deals.detail.companiesSearch", "Search linked companies\u2026"),
414
+ linkedItems: data.companies,
415
+ linkedCount: data.counts.companies,
416
+ selectedIds: companiesEditorIds,
417
+ disabled: companiesSaving || isSaving,
418
+ savePending: companiesSaving,
419
+ hrefBuilder: (companyId) => `/backend/customers/companies-v2/${encodeURIComponent(companyId)}`,
420
+ onSaveSelection: (next) => handleCompaniesAssociationsChange(next),
421
+ loadLinkedPage: loadLinkedCompaniesPage,
422
+ searchEntities: searchCompaniesPage,
423
+ fetchEntitiesByIds: fetchCompaniesByIds,
424
+ icon: /* @__PURE__ */ jsx(Building2, { className: "size-4" })
425
+ }
426
+ );
427
+ }
428
+ if (activeTab === "notes") {
429
+ return /* @__PURE__ */ jsx(
430
+ NotesSection,
431
+ {
432
+ entityId: null,
433
+ dealId: data.deal.id,
434
+ dealOptions,
435
+ entityOptions,
436
+ emptyLabel: t("customers.deals.detail.notesEmpty", "No notes yet."),
437
+ viewerUserId: data.viewer?.userId ?? null,
438
+ viewerName: data.viewer?.name ?? null,
439
+ viewerEmail: data.viewer?.email ?? null,
440
+ addActionLabel: t("customers.deals.detail.notesAdd", "Add note"),
441
+ emptyState: {
442
+ title: t("customers.deals.detail.notesEmptyTitle", "Keep everyone in the loop"),
443
+ actionLabel: t("customers.deals.detail.notesEmptyAction", "Add a note")
444
+ },
445
+ translator: detailTranslator,
446
+ dataAdapter: notesAdapter,
447
+ renderIcon: renderDictionaryIcon,
448
+ renderColor: renderDictionaryColor,
449
+ iconSuggestions: ICON_SUGGESTIONS,
450
+ readMarkdownPreference: readMarkdownPreferenceCookie,
451
+ writeMarkdownPreference: writeMarkdownPreferenceCookie
452
+ }
453
+ );
454
+ }
455
+ if (activeTab === "files") {
456
+ return /* @__PURE__ */ jsx(
457
+ AttachmentsSection,
458
+ {
459
+ entityId: E.customers.customer_deal,
460
+ recordId: data.deal.id,
461
+ title: t("customers.deals.detail.tabs.files", "Files"),
462
+ description: t("customers.deals.detail.files.subtitle", "Upload and manage files linked to this deal.")
463
+ }
464
+ );
465
+ }
466
+ if (activeTab === "changelog") {
467
+ return /* @__PURE__ */ jsx(ChangelogTab, { entityId: data.deal.id, entityType: "deal" });
468
+ }
469
+ return null;
470
+ })() });
471
+ return /* @__PURE__ */ jsx(Page, { children: /* @__PURE__ */ jsxs(PageBody, { children: [
472
+ /* @__PURE__ */ jsxs("div", { className: "space-y-6", children: [
473
+ /* @__PURE__ */ jsx(InjectionSpot, { spotId: "detail:customers.deal:header", context: injectionContext, data }),
296
474
  /* @__PURE__ */ jsx(
297
- FormHeader,
475
+ DealDetailHeader,
298
476
  {
299
- mode: "detail",
300
- backHref: "/backend/customers/deals",
301
- backLabel: t("customers.deals.detail.backToList", "Back to deals"),
302
- utilityActions: /* @__PURE__ */ jsxs(Fragment, { children: [
303
- /* @__PURE__ */ jsx(
304
- SendObjectMessageDialog,
305
- {
306
- object: {
307
- entityModule: "customers",
308
- entityType: "deal",
309
- entityId: data.deal.id,
310
- sourceEntityType: "customers.deal",
311
- sourceEntityId: data.deal.id,
312
- previewData: {
313
- title: data.deal.title || t("customers.deals.detail.untitled", "Untitled deal"),
314
- status: data.deal.status ? statusLabel : void 0,
315
- metadata: Object.keys(dealPreviewMetadata).length > 0 ? dealPreviewMetadata : void 0
316
- }
317
- },
318
- viewHref: `/backend/customers/deals/${data.deal.id}`,
319
- defaultValues: {
320
- sourceEntityType: "customers.deal",
321
- sourceEntityId: data.deal.id
322
- }
323
- }
324
- ),
325
- /* @__PURE__ */ jsx(
326
- VersionHistoryAction,
327
- {
328
- config: { resourceKind: "customers.deal", resourceId: data.deal.id },
329
- t
330
- }
331
- )
332
- ] }),
333
- title: /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [
334
- /* @__PURE__ */ jsx("span", { children: data.deal.title || t("customers.deals.detail.untitled", "Untitled deal") }),
335
- /* @__PURE__ */ jsxs(
336
- Button,
337
- {
338
- type: "button",
339
- variant: "ghost",
340
- size: "sm",
341
- className: "gap-1 text-muted-foreground hover:text-foreground",
342
- onClick: scrollToDealSettings,
343
- children: [
344
- /* @__PURE__ */ jsx(Pencil, { className: "h-4 w-4", "aria-hidden": true }),
345
- /* @__PURE__ */ jsx(MousePointerClick, { className: "h-4 w-4", "aria-hidden": true }),
346
- /* @__PURE__ */ jsx("span", { children: t("customers.deals.detail.goToSettings", "Edit deal details") })
347
- ]
348
- }
349
- )
350
- ] }),
351
- subtitle: t("customers.deals.detail.summary", void 0, {
352
- status: statusLabel,
353
- pipeline: pipelineLabel ?? t("customers.deals.detail.noPipeline", "No pipeline")
354
- }),
477
+ deal: data.deal,
478
+ owner: data.owner,
479
+ people: data.people,
480
+ companies: data.companies,
481
+ pipelineName: currentPipelineName,
482
+ stageOptions: data.pipelineStages,
483
+ currentStageId: data.deal.pipelineStageId,
484
+ onStageChange: handleStageChange,
485
+ isStageSaving,
486
+ onSave: handleHeaderSave,
355
487
  onDelete: handleDelete,
356
- isDeleting,
357
- deleteLabel: t("ui.actions.delete", "Delete")
488
+ isDirty,
489
+ isSaving
358
490
  }
359
491
  ),
360
- /* @__PURE__ */ jsxs("div", { className: "grid gap-6 lg:grid-cols-[minmax(0,2fr),minmax(0,1.1fr)]", children: [
361
- /* @__PURE__ */ jsxs("div", { className: "space-y-6", children: [
362
- /* @__PURE__ */ jsxs("div", { className: "rounded-lg border bg-card p-4", children: [
363
- /* @__PURE__ */ jsx("h2", { className: "mb-4 text-sm font-semibold uppercase text-muted-foreground", children: t("customers.deals.detail.highlights", "Highlights") }),
364
- /* @__PURE__ */ jsxs("div", { className: "grid gap-4 sm:grid-cols-2", children: [
365
- /* @__PURE__ */ jsxs("div", { children: [
366
- /* @__PURE__ */ jsx("p", { className: "text-xs font-medium uppercase text-muted-foreground", children: t("customers.deals.detail.fields.value", "Deal value") }),
367
- /* @__PURE__ */ jsx("p", { className: "text-base font-semibold text-foreground", children: valueLabel })
368
- ] }),
369
- /* @__PURE__ */ jsxs("div", { children: [
370
- /* @__PURE__ */ jsx("p", { className: "text-xs font-medium uppercase text-muted-foreground", children: t("customers.deals.detail.fields.probability", "Probability") }),
371
- /* @__PURE__ */ jsx("p", { className: "text-base font-semibold text-foreground", children: probabilityLabel })
372
- ] }),
373
- /* @__PURE__ */ jsxs("div", { children: [
374
- /* @__PURE__ */ jsx("p", { className: "text-xs font-medium uppercase text-muted-foreground", children: t("customers.deals.detail.fields.status", "Status") }),
375
- /* @__PURE__ */ jsxs("p", { className: "text-base text-foreground flex items-center gap-2", children: [
376
- statusDictEntry?.color ? renderDictionaryColor(statusDictEntry.color) : null,
377
- statusDictEntry?.icon ? renderDictionaryIcon(statusDictEntry.icon) : null,
378
- statusLabel
379
- ] })
380
- ] }),
381
- /* @__PURE__ */ jsxs("div", { children: [
382
- /* @__PURE__ */ jsx("p", { className: "text-xs font-medium uppercase text-muted-foreground", children: t("customers.deals.detail.fields.pipeline", "Pipeline stage") }),
383
- /* @__PURE__ */ jsxs("p", { className: "text-base text-foreground flex items-center gap-2", children: [
384
- pipelineDictEntry?.color ? renderDictionaryColor(pipelineDictEntry.color) : null,
385
- pipelineDictEntry?.icon ? renderDictionaryIcon(pipelineDictEntry.icon) : null,
386
- pipelineLabel ?? t("customers.deals.detail.noValue", "Not provided")
387
- ] })
388
- ] }),
389
- /* @__PURE__ */ jsxs("div", { children: [
390
- /* @__PURE__ */ jsx("p", { className: "text-xs font-medium uppercase text-muted-foreground", children: t("customers.deals.detail.fields.expectedClose", "Expected close") }),
391
- /* @__PURE__ */ jsx("p", { className: "text-base text-foreground", children: expectedCloseLabel })
392
- ] })
393
- ] })
394
- ] }),
395
- /* @__PURE__ */ jsxs("div", { className: "rounded-lg border bg-card p-4", children: [
396
- /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center justify-between gap-3", children: [
397
- /* @__PURE__ */ jsx("div", { className: "flex gap-2", children: tabs.map((tab) => /* @__PURE__ */ jsx(
398
- Button,
399
- {
400
- variant: "ghost",
401
- size: "sm",
402
- onClick: () => setActiveTab(tab.id),
403
- className: `h-auto rounded-none border-b-2 px-0 py-1 ${activeTab === tab.id ? "border-primary text-foreground" : "border-transparent text-muted-foreground hover:text-foreground hover:bg-transparent"}`,
404
- children: tab.label
405
- },
406
- tab.id
407
- )) }),
408
- sectionAction ? /* @__PURE__ */ jsxs(
409
- Button,
410
- {
411
- type: "button",
412
- size: "sm",
413
- disabled: sectionAction.disabled,
414
- onClick: handleSectionAction,
415
- children: [
416
- sectionAction.icon ?? null,
417
- sectionAction.label
418
- ]
419
- }
420
- ) : null
421
- ] }),
422
- activeTab === "notes" ? /* @__PURE__ */ jsx(
423
- NotesSection,
424
- {
425
- entityId: null,
426
- dealId: data.deal.id,
427
- dealOptions,
428
- entityOptions,
429
- emptyLabel: t("customers.deals.detail.notesEmpty", "No notes yet."),
430
- viewerUserId: viewer?.userId ?? null,
431
- viewerName: viewer?.name ?? null,
432
- viewerEmail: viewer?.email ?? null,
433
- addActionLabel: t("customers.deals.detail.notesAdd", "Add note"),
434
- emptyState: {
435
- title: t("customers.deals.detail.notesEmptyTitle", "Keep everyone in the loop"),
436
- actionLabel: t("customers.deals.detail.notesEmptyAction", "Add a note")
437
- },
438
- onActionChange: setSectionAction,
439
- translator: detailTranslator,
440
- onLoadingChange: handleNotesLoadingChange,
441
- dataAdapter: notesAdapter,
442
- renderIcon: renderDictionaryIcon,
443
- renderColor: renderDictionaryColor,
444
- iconSuggestions: ICON_SUGGESTIONS,
445
- readMarkdownPreference: readMarkdownPreferenceCookie,
446
- writeMarkdownPreference: writeMarkdownPreferenceCookie
447
- }
448
- ) : null,
449
- activeTab === "activities" ? /* @__PURE__ */ jsx(
450
- ActivitiesSection,
451
- {
452
- entityId: null,
453
- dealId: data.deal.id,
454
- dealOptions,
455
- entityOptions,
456
- defaultEntityId: defaultEntityId ?? void 0,
457
- addActionLabel: t("customers.deals.detail.activitiesAdd", "Log activity"),
458
- emptyState: {
459
- title: t("customers.deals.detail.activitiesEmptyTitle", "No activities yet"),
460
- actionLabel: t("customers.deals.detail.activitiesEmptyAction", "Add an activity")
461
- },
462
- onActionChange: setSectionAction,
463
- onLoadingChange: handleActivitiesLoadingChange
464
- }
465
- ) : null
466
- ] }),
467
- /* @__PURE__ */ jsxs("div", { className: "grid gap-4 md:grid-cols-2", children: [
468
- /* @__PURE__ */ jsxs("div", { className: "rounded-lg border bg-card p-4", children: [
469
- /* @__PURE__ */ jsxs("div", { className: "mb-3 space-y-1", children: [
470
- /* @__PURE__ */ jsx("h3", { className: "text-sm font-semibold text-foreground", children: t("customers.deals.detail.peopleSection", "People") }),
471
- /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: peopleSummaryLabel })
472
- ] }),
473
- data.people.length ? /* @__PURE__ */ jsx("ul", { className: "space-y-2 text-sm", children: data.people.map((person) => /* @__PURE__ */ jsxs("li", { className: "flex flex-col gap-1", children: [
474
- /* @__PURE__ */ jsx(Link, { href: `/backend/customers/people-v2/${encodeURIComponent(person.id)}`, className: "font-medium text-foreground hover:underline", children: person.label }),
475
- /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: person.subtitle ?? t("customers.deals.detail.peopleNoDetails", "No additional details") })
476
- ] }, person.id)) }) : /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: t("customers.deals.detail.noPeople", "No people linked to this deal yet.") })
477
- ] }),
478
- /* @__PURE__ */ jsxs("div", { className: "rounded-lg border bg-card p-4", children: [
479
- /* @__PURE__ */ jsxs("div", { className: "mb-3 space-y-1", children: [
480
- /* @__PURE__ */ jsx("h3", { className: "text-sm font-semibold text-foreground", children: t("customers.deals.detail.companiesSection", "Companies") }),
481
- /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: companiesSummaryLabel })
482
- ] }),
483
- data.companies.length ? /* @__PURE__ */ jsx("ul", { className: "space-y-2 text-sm", children: data.companies.map((company) => /* @__PURE__ */ jsxs("li", { className: "flex flex-col gap-1", children: [
484
- /* @__PURE__ */ jsx(Link, { href: `/backend/customers/companies-v2/${encodeURIComponent(company.id)}`, className: "font-medium text-foreground hover:underline", children: company.label }),
485
- /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: company.subtitle ?? t("customers.deals.detail.companiesNoDetails", "No additional details") })
486
- ] }, company.id)) }) : /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: t("customers.deals.detail.noCompanies", "No companies linked to this deal yet.") })
487
- ] })
488
- ] })
489
- ] }),
490
- /* @__PURE__ */ jsx("div", { className: "space-y-6", children: /* @__PURE__ */ jsxs(
491
- "div",
492
- {
493
- ref: dealSettingsRef,
494
- id: "deal-settings",
495
- className: "rounded-lg border bg-card p-4",
496
- children: [
497
- /* @__PURE__ */ jsx("h2", { className: "mb-4 text-sm font-semibold uppercase text-muted-foreground", children: t("customers.deals.detail.formTitle", "Deal settings") }),
498
- /* @__PURE__ */ jsx(
499
- DealForm,
500
- {
501
- mode: "edit",
502
- initialValues: {
503
- id: data.deal.id,
504
- title: data.deal.title ?? "",
505
- status: data.deal.status ?? "",
506
- pipelineStage: data.deal.pipelineStage ?? "",
507
- pipelineId: data.deal.pipelineId ?? "",
508
- pipelineStageId: data.deal.pipelineStageId ?? "",
509
- valueAmount: data.deal.valueAmount ? Number(data.deal.valueAmount) : null,
510
- valueCurrency: data.deal.valueCurrency ?? void 0,
511
- probability: data.deal.probability ?? null,
512
- expectedCloseAt: data.deal.expectedCloseAt ?? null,
513
- description: data.deal.description ?? "",
514
- personIds: data.people.map((person) => person.id),
515
- companyIds: data.companies.map((company) => company.id),
516
- people: data.people.map((person) => ({ id: person.id, label: person.label })),
517
- companies: data.companies.map((company) => ({ id: company.id, label: company.label })),
518
- ...Object.fromEntries(
519
- Object.entries(data.customFields).filter(([key]) => key.startsWith("cf_")).map(([key, value]) => [key, value])
520
- )
521
- },
522
- onSubmit: handleFormSubmit,
523
- onCancel: () => setReloadToken((token) => token + 1),
524
- onDelete: handleDelete,
525
- isSubmitting: isSaving || isDeleting
526
- },
527
- data.deal.updatedAt
528
- )
529
- ]
530
- }
531
- ) })
532
- ] })
533
- ] }) }),
534
- ConfirmDialogElement
535
- ] });
492
+ /* @__PURE__ */ jsx(InjectionSpot, { spotId: "detail:customers.deal:status-badges", context: injectionContext, data }),
493
+ /* @__PURE__ */ jsx(
494
+ PipelineStepper,
495
+ {
496
+ stages: data.pipelineStages,
497
+ transitions: data.stageTransitions,
498
+ currentStageId: data.deal.pipelineStageId,
499
+ pipelineName: currentPipelineName,
500
+ closureOutcome: data.deal.closureOutcome,
501
+ footer: data.deal.closureOutcome ? null : /* @__PURE__ */ jsx(
502
+ DealClosureActionBar,
503
+ {
504
+ embedded: true,
505
+ closureOutcome: data.deal.closureOutcome,
506
+ onWon: () => {
507
+ void handleWon();
508
+ },
509
+ onLost: openLostDialog
510
+ }
511
+ )
512
+ }
513
+ ),
514
+ /* @__PURE__ */ jsx(
515
+ DealDetailTabs,
516
+ {
517
+ activeTab,
518
+ onTabChange: handleTabChange,
519
+ injectedTabs: injectedTabs.map((tab) => ({ id: tab.id, label: tab.label })),
520
+ peopleCount: data.counts.people,
521
+ companiesCount: data.counts.companies,
522
+ children: /* @__PURE__ */ jsx(
523
+ CollapsibleZoneLayout,
524
+ {
525
+ pageType: "deal-detail-v3",
526
+ entityName: dealName,
527
+ isDirty,
528
+ zone1DefaultWidth: "540px",
529
+ zone1: zone1Content,
530
+ zone2: zone2Content
531
+ }
532
+ )
533
+ }
534
+ ),
535
+ /* @__PURE__ */ jsx(InjectionSpot, { spotId: "detail:customers.deal:footer", context: injectionContext, data })
536
+ ] }),
537
+ ConfirmDialogElement,
538
+ selectedActivityEntity ? /* @__PURE__ */ jsx(
539
+ ScheduleActivityDialog,
540
+ {
541
+ open: scheduleDialogOpen,
542
+ onClose: closeSchedule,
543
+ entityId: selectedActivityEntity.id,
544
+ dealId: data.deal.id,
545
+ entityType: selectedActivityEntity.kind,
546
+ entityName: selectedActivityEntity.label,
547
+ companyName: selectedActivityEntity.kind === "company" ? selectedActivityEntity.label : data.companies[0]?.label ?? null,
548
+ onActivityCreated: () => {
549
+ void handleActivityCreated();
550
+ },
551
+ editData: scheduleEditData
552
+ }
553
+ ) : null,
554
+ /* @__PURE__ */ jsx(
555
+ ConfirmDealLostDialog,
556
+ {
557
+ open: lostDialogOpen,
558
+ onClose: closeLostDialog,
559
+ dealTitle: data.deal.title || t("customers.deals.detail.untitled", "Untitled deal"),
560
+ dealValue: amountLabel,
561
+ companyName: data.companies[0]?.label ?? null,
562
+ onConfirm: handleLostConfirm
563
+ }
564
+ ),
565
+ /* @__PURE__ */ jsx(
566
+ DealWonPopup,
567
+ {
568
+ open: wonPopupOpen,
569
+ onClose: closeWonPopup,
570
+ dealTitle: data.deal.title || t("customers.deals.detail.untitled", "Untitled deal"),
571
+ stats: wonStats,
572
+ onViewDashboard: handleViewDashboard,
573
+ onBackToPipeline: handleBackToPipeline
574
+ }
575
+ ),
576
+ /* @__PURE__ */ jsx(
577
+ DealLostSummaryDialog,
578
+ {
579
+ open: lostPopupOpen,
580
+ onClose: closeLostPopup,
581
+ dealTitle: data.deal.title || t("customers.deals.detail.untitled", "Untitled deal"),
582
+ lossNotes: data.deal.lossNotes,
583
+ stats: lostStats,
584
+ onBackToPipeline: handleBackToPipeline,
585
+ onScheduleFollowUp: selectedActivityEntity ? handleScheduleLostFollowUp : void 0
586
+ }
587
+ )
588
+ ] }) });
536
589
  }
537
590
  export {
538
591
  DealDetailPage as default