@open-mercato/core 0.6.6-develop.6317.1.b3be10ab84 → 0.6.6-develop.6331.1.a33b8e99b7

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 (304) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/dist/modules/attachments/components/AttachmentPartitionSettings.js +3 -0
  3. package/dist/modules/attachments/components/AttachmentPartitionSettings.js.map +2 -2
  4. package/dist/modules/auth/api/roles/acl/route.js +2 -2
  5. package/dist/modules/auth/api/roles/acl/route.js.map +2 -2
  6. package/dist/modules/auth/api/users/acl/route.js +2 -2
  7. package/dist/modules/auth/api/users/acl/route.js.map +2 -2
  8. package/dist/modules/auth/backend/roles/[id]/edit/page.js +12 -0
  9. package/dist/modules/auth/backend/roles/[id]/edit/page.js.map +2 -2
  10. package/dist/modules/auth/backend/users/[id]/edit/page.js +12 -0
  11. package/dist/modules/auth/backend/users/[id]/edit/page.js.map +2 -2
  12. package/dist/modules/auth/data/entities.js +2 -2
  13. package/dist/modules/auth/data/entities.js.map +2 -2
  14. package/dist/modules/business_rules/api/rules/route.js +3 -3
  15. package/dist/modules/business_rules/api/rules/route.js.map +2 -2
  16. package/dist/modules/business_rules/api/sets/route.js +3 -3
  17. package/dist/modules/business_rules/api/sets/route.js.map +2 -2
  18. package/dist/modules/business_rules/backend/rules/[id]/page.js +12 -1
  19. package/dist/modules/business_rules/backend/rules/[id]/page.js.map +2 -2
  20. package/dist/modules/business_rules/backend/sets/[id]/page.js +12 -1
  21. package/dist/modules/business_rules/backend/sets/[id]/page.js.map +2 -2
  22. package/dist/modules/catalog/api/product-media/route.js.map +2 -2
  23. package/dist/modules/catalog/backend/catalog/categories/[id]/edit/page.js +12 -0
  24. package/dist/modules/catalog/backend/catalog/categories/[id]/edit/page.js.map +2 -2
  25. package/dist/modules/catalog/backend/catalog/products/[id]/page.js +15 -0
  26. package/dist/modules/catalog/backend/catalog/products/[id]/page.js.map +2 -2
  27. package/dist/modules/catalog/backend/catalog/products/[productId]/variants/[variantId]/page.js +12 -1
  28. package/dist/modules/catalog/backend/catalog/products/[productId]/variants/[variantId]/page.js.map +2 -2
  29. package/dist/modules/catalog/components/PriceKindSettings.js +13 -3
  30. package/dist/modules/catalog/components/PriceKindSettings.js.map +2 -2
  31. package/dist/modules/catalog/lib/bulkDelete.js.map +2 -2
  32. package/dist/modules/currencies/backend/currencies/[id]/page.js +15 -3
  33. package/dist/modules/currencies/backend/currencies/[id]/page.js.map +2 -2
  34. package/dist/modules/currencies/backend/currencies/page.js +2 -1
  35. package/dist/modules/currencies/backend/currencies/page.js.map +2 -2
  36. package/dist/modules/currencies/backend/exchange-rates/[id]/page.js +12 -1
  37. package/dist/modules/currencies/backend/exchange-rates/[id]/page.js.map +2 -2
  38. package/dist/modules/currencies/backend/exchange-rates/page.js +3 -2
  39. package/dist/modules/currencies/backend/exchange-rates/page.js.map +2 -2
  40. package/dist/modules/customer_accounts/api/admin/roles/[id].js +3 -3
  41. package/dist/modules/customer_accounts/api/admin/roles/[id].js.map +2 -2
  42. package/dist/modules/customer_accounts/api/admin/users/[id].js +3 -3
  43. package/dist/modules/customer_accounts/api/admin/users/[id].js.map +2 -2
  44. package/dist/modules/customer_accounts/backend/customer_accounts/roles/[id]/page.js +7 -12
  45. package/dist/modules/customer_accounts/backend/customer_accounts/roles/[id]/page.js.map +2 -2
  46. package/dist/modules/customer_accounts/backend/customer_accounts/users/page.js +5 -2
  47. package/dist/modules/customer_accounts/backend/customer_accounts/users/page.js.map +2 -2
  48. package/dist/modules/customer_accounts/widgets/injection/account-status/widget.client.js +2 -1
  49. package/dist/modules/customer_accounts/widgets/injection/account-status/widget.client.js.map +2 -2
  50. package/dist/modules/customer_accounts/widgets/injection/company-users/widget.client.js +2 -1
  51. package/dist/modules/customer_accounts/widgets/injection/company-users/widget.client.js.map +2 -2
  52. package/dist/modules/customers/api/addresses/route.js +4 -2
  53. package/dist/modules/customers/api/addresses/route.js.map +2 -2
  54. package/dist/modules/customers/api/tags/route.js +8 -3
  55. package/dist/modules/customers/api/tags/route.js.map +2 -2
  56. package/dist/modules/customers/backend/customers/companies-v2/[id]/page.js +13 -2
  57. package/dist/modules/customers/backend/customers/companies-v2/[id]/page.js.map +2 -2
  58. package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealAssociations.js +24 -9
  59. package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealAssociations.js.map +2 -2
  60. package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealClosure.js +53 -23
  61. package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealClosure.js.map +2 -2
  62. package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealPipeline.js +13 -3
  63. package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealPipeline.js.map +2 -2
  64. package/dist/modules/customers/backend/customers/deals/[id]/page.js +19 -2
  65. package/dist/modules/customers/backend/customers/deals/[id]/page.js.map +2 -2
  66. package/dist/modules/customers/backend/customers/people-v2/[id]/page.js +13 -2
  67. package/dist/modules/customers/backend/customers/people-v2/[id]/page.js.map +2 -2
  68. package/dist/modules/customers/commands/interactions.js +5 -5
  69. package/dist/modules/customers/commands/interactions.js.map +2 -2
  70. package/dist/modules/customers/commands/pipeline-stages.js +24 -2
  71. package/dist/modules/customers/commands/pipeline-stages.js.map +2 -2
  72. package/dist/modules/customers/commands/pipelines.js +24 -2
  73. package/dist/modules/customers/commands/pipelines.js.map +2 -2
  74. package/dist/modules/customers/components/detail/AddressesSection.js +46 -29
  75. package/dist/modules/customers/components/detail/AddressesSection.js.map +2 -2
  76. package/dist/modules/customers/components/detail/DealForm.js +5 -1
  77. package/dist/modules/customers/components/detail/DealForm.js.map +2 -2
  78. package/dist/modules/customers/components/detail/EntityTagsDialog.js +76 -67
  79. package/dist/modules/customers/components/detail/EntityTagsDialog.js.map +3 -3
  80. package/dist/modules/customers/components/detail/notesAdapter.js +25 -18
  81. package/dist/modules/customers/components/detail/notesAdapter.js.map +2 -2
  82. package/dist/modules/dashboards/components/WidgetVisibilityEditor.js +4 -3
  83. package/dist/modules/dashboards/components/WidgetVisibilityEditor.js.map +2 -2
  84. package/dist/modules/data_sync/api/runs.js +1 -0
  85. package/dist/modules/data_sync/api/runs.js.map +2 -2
  86. package/dist/modules/data_sync/api/schedules/[id]/route.js +38 -19
  87. package/dist/modules/data_sync/api/schedules/[id]/route.js.map +2 -2
  88. package/dist/modules/data_sync/api/schedules/route.js +1 -1
  89. package/dist/modules/data_sync/api/schedules/route.js.map +2 -2
  90. package/dist/modules/data_sync/backend/data-sync/page.js +35 -16
  91. package/dist/modules/data_sync/backend/data-sync/page.js.map +2 -2
  92. package/dist/modules/data_sync/data/validators.js +1 -0
  93. package/dist/modules/data_sync/data/validators.js.map +2 -2
  94. package/dist/modules/data_sync/lib/sync-run-service.js +20 -0
  95. package/dist/modules/data_sync/lib/sync-run-service.js.map +2 -2
  96. package/dist/modules/data_sync/lib/sync-schedule-service.js +19 -5
  97. package/dist/modules/data_sync/lib/sync-schedule-service.js.map +2 -2
  98. package/dist/modules/dictionaries/api/[dictionaryId]/entries/[entryId]/route.js +3 -3
  99. package/dist/modules/dictionaries/api/[dictionaryId]/entries/[entryId]/route.js.map +2 -2
  100. package/dist/modules/dictionaries/api/[dictionaryId]/route.js +3 -3
  101. package/dist/modules/dictionaries/api/[dictionaryId]/route.js.map +2 -2
  102. package/dist/modules/dictionaries/components/DictionariesManager.js +12 -1
  103. package/dist/modules/dictionaries/components/DictionariesManager.js.map +2 -2
  104. package/dist/modules/dictionaries/components/DictionaryEntriesEditor.js.map +2 -2
  105. package/dist/modules/directory/backend/directory/organizations/[id]/edit/page.js +12 -0
  106. package/dist/modules/directory/backend/directory/organizations/[id]/edit/page.js.map +2 -2
  107. package/dist/modules/directory/backend/directory/tenants/[id]/edit/page.js +12 -0
  108. package/dist/modules/directory/backend/directory/tenants/[id]/edit/page.js.map +2 -2
  109. package/dist/modules/entities/api/entities.js +2 -2
  110. package/dist/modules/entities/api/entities.js.map +2 -2
  111. package/dist/modules/entities/api/records.js +18 -6
  112. package/dist/modules/entities/api/records.js.map +2 -2
  113. package/dist/modules/entities/backend/entities/user/[entityId]/records/page.js +17 -10
  114. package/dist/modules/entities/backend/entities/user/[entityId]/records/page.js.map +2 -2
  115. package/dist/modules/feature_toggles/api/overrides/route.js +2 -2
  116. package/dist/modules/feature_toggles/api/overrides/route.js.map +2 -2
  117. package/dist/modules/feature_toggles/backend/feature-toggles/global/[id]/edit/page.js.map +2 -2
  118. package/dist/modules/feature_toggles/data/entities.js +1 -1
  119. package/dist/modules/feature_toggles/data/entities.js.map +2 -2
  120. package/dist/modules/feature_toggles/data/validators.js +2 -1
  121. package/dist/modules/feature_toggles/data/validators.js.map +2 -2
  122. package/dist/modules/feature_toggles/lib/queries.js +2 -1
  123. package/dist/modules/feature_toggles/lib/queries.js.map +2 -2
  124. package/dist/modules/inbox_ops/api/settings/route.js +2 -2
  125. package/dist/modules/inbox_ops/api/settings/route.js.map +2 -2
  126. package/dist/modules/messages/api/unread-count/route.js +32 -0
  127. package/dist/modules/messages/api/unread-count/route.js.map +2 -2
  128. package/dist/modules/query_index/components/QueryIndexesTable.js +13 -5
  129. package/dist/modules/query_index/components/QueryIndexesTable.js.map +2 -2
  130. package/dist/modules/resources/backend/resources/resource-types/[id]/edit/page.js +12 -1
  131. package/dist/modules/resources/backend/resources/resource-types/[id]/edit/page.js.map +2 -2
  132. package/dist/modules/resources/backend/resources/resources/[id]/page.js +12 -1
  133. package/dist/modules/resources/backend/resources/resources/[id]/page.js.map +2 -2
  134. package/dist/modules/resources/components/detail/notesAdapter.js +25 -18
  135. package/dist/modules/resources/components/detail/notesAdapter.js.map +2 -2
  136. package/dist/modules/sales/backend/sales/documents/[id]/page.js +14 -1
  137. package/dist/modules/sales/backend/sales/documents/[id]/page.js.map +2 -2
  138. package/dist/modules/sales/commands/documents.js +11 -10
  139. package/dist/modules/sales/commands/documents.js.map +2 -2
  140. package/dist/modules/sales/commands/payments.js +6 -1
  141. package/dist/modules/sales/commands/payments.js.map +2 -2
  142. package/dist/modules/sales/commands/returns.js +3 -3
  143. package/dist/modules/sales/commands/returns.js.map +2 -2
  144. package/dist/modules/sales/commands/shared.js +3 -3
  145. package/dist/modules/sales/commands/shared.js.map +2 -2
  146. package/dist/modules/sales/commands/shipments.js +6 -1
  147. package/dist/modules/sales/commands/shipments.js.map +2 -2
  148. package/dist/modules/sales/components/documents/PaymentDialog.js +6 -3
  149. package/dist/modules/sales/components/documents/PaymentDialog.js.map +2 -2
  150. package/dist/modules/sales/components/documents/PaymentsSection.js +7 -3
  151. package/dist/modules/sales/components/documents/PaymentsSection.js.map +2 -2
  152. package/dist/modules/sales/components/documents/ShipmentDialog.js +6 -3
  153. package/dist/modules/sales/components/documents/ShipmentDialog.js.map +2 -2
  154. package/dist/modules/sales/components/documents/ShipmentsSection.js +7 -3
  155. package/dist/modules/sales/components/documents/ShipmentsSection.js.map +2 -2
  156. package/dist/modules/sales/di.js +39 -3
  157. package/dist/modules/sales/di.js.map +2 -2
  158. package/dist/modules/sales/setup.js +2 -0
  159. package/dist/modules/sales/setup.js.map +2 -2
  160. package/dist/modules/shipping_carriers/i18n/en.js +11 -1
  161. package/dist/modules/shipping_carriers/i18n/en.js.map +2 -2
  162. package/dist/modules/shipping_carriers/i18n/pl.js +11 -1
  163. package/dist/modules/shipping_carriers/i18n/pl.js.map +2 -2
  164. package/dist/modules/shipping_carriers/widgets/injection/tracking-status-badge/widget.client.js +25 -0
  165. package/dist/modules/shipping_carriers/widgets/injection/tracking-status-badge/widget.client.js.map +7 -0
  166. package/dist/modules/shipping_carriers/widgets/injection/tracking-status-badge/widget.js +3 -17
  167. package/dist/modules/shipping_carriers/widgets/injection/tracking-status-badge/widget.js.map +2 -2
  168. package/dist/modules/staff/backend/staff/leave-requests/[id]/page.js +12 -1
  169. package/dist/modules/staff/backend/staff/leave-requests/[id]/page.js.map +2 -2
  170. package/dist/modules/staff/backend/staff/team-members/[id]/page.js +12 -1
  171. package/dist/modules/staff/backend/staff/team-members/[id]/page.js.map +2 -2
  172. package/dist/modules/staff/backend/staff/team-roles/[id]/edit/page.js +12 -1
  173. package/dist/modules/staff/backend/staff/team-roles/[id]/edit/page.js.map +2 -2
  174. package/dist/modules/staff/backend/staff/teams/[id]/edit/page.js +12 -1
  175. package/dist/modules/staff/backend/staff/teams/[id]/edit/page.js.map +2 -2
  176. package/dist/modules/staff/commands/job-histories.js +3 -3
  177. package/dist/modules/staff/commands/job-histories.js.map +2 -2
  178. package/dist/modules/staff/components/detail/addressesAdapter.js +33 -24
  179. package/dist/modules/staff/components/detail/addressesAdapter.js.map +2 -2
  180. package/dist/modules/staff/components/detail/notesAdapter.js +25 -18
  181. package/dist/modules/staff/components/detail/notesAdapter.js.map +2 -2
  182. package/dist/modules/translations/api/[entityType]/[entityId]/route.js +37 -0
  183. package/dist/modules/translations/api/[entityType]/[entityId]/route.js.map +2 -2
  184. package/dist/modules/translations/components/TranslationManager.js +7 -1
  185. package/dist/modules/translations/components/TranslationManager.js.map +2 -2
  186. package/dist/modules/translations/widgets/injection/translation-manager/widget.client.js +19 -14
  187. package/dist/modules/translations/widgets/injection/translation-manager/widget.client.js.map +2 -2
  188. package/dist/modules/workflows/api/definitions/[id]/route.js +3 -3
  189. package/dist/modules/workflows/api/definitions/[id]/route.js.map +2 -2
  190. package/dist/modules/workflows/backend/definitions/[id]/page.js +12 -1
  191. package/dist/modules/workflows/backend/definitions/[id]/page.js.map +2 -2
  192. package/dist/modules/workflows/backend/definitions/visual-editor/page.js +11 -1
  193. package/dist/modules/workflows/backend/definitions/visual-editor/page.js.map +2 -2
  194. package/package.json +7 -7
  195. package/src/modules/attachments/components/AttachmentPartitionSettings.tsx +3 -0
  196. package/src/modules/auth/api/roles/acl/route.ts +2 -2
  197. package/src/modules/auth/api/users/acl/route.ts +2 -2
  198. package/src/modules/auth/backend/roles/[id]/edit/page.tsx +17 -0
  199. package/src/modules/auth/backend/users/[id]/edit/page.tsx +17 -0
  200. package/src/modules/auth/data/entities.ts +2 -2
  201. package/src/modules/business_rules/api/rules/route.ts +3 -3
  202. package/src/modules/business_rules/api/sets/route.ts +3 -3
  203. package/src/modules/business_rules/backend/rules/[id]/page.tsx +17 -1
  204. package/src/modules/business_rules/backend/sets/[id]/page.tsx +18 -1
  205. package/src/modules/catalog/api/product-media/route.ts +4 -0
  206. package/src/modules/catalog/backend/catalog/categories/[id]/edit/page.tsx +17 -0
  207. package/src/modules/catalog/backend/catalog/products/[id]/page.tsx +21 -0
  208. package/src/modules/catalog/backend/catalog/products/[productId]/variants/[variantId]/page.tsx +16 -1
  209. package/src/modules/catalog/components/PriceKindSettings.tsx +15 -7
  210. package/src/modules/catalog/lib/bulkDelete.ts +6 -0
  211. package/src/modules/currencies/backend/currencies/[id]/page.tsx +20 -3
  212. package/src/modules/currencies/backend/currencies/page.tsx +2 -1
  213. package/src/modules/currencies/backend/exchange-rates/[id]/page.tsx +17 -1
  214. package/src/modules/currencies/backend/exchange-rates/page.tsx +3 -2
  215. package/src/modules/customer_accounts/api/admin/roles/[id].ts +3 -3
  216. package/src/modules/customer_accounts/api/admin/users/[id].ts +3 -3
  217. package/src/modules/customer_accounts/backend/customer_accounts/roles/[id]/page.tsx +7 -10
  218. package/src/modules/customer_accounts/backend/customer_accounts/users/page.tsx +6 -7
  219. package/src/modules/customer_accounts/widgets/injection/account-status/widget.client.tsx +3 -2
  220. package/src/modules/customer_accounts/widgets/injection/company-users/widget.client.tsx +3 -2
  221. package/src/modules/customers/api/addresses/route.ts +2 -0
  222. package/src/modules/customers/api/tags/route.ts +6 -1
  223. package/src/modules/customers/backend/customers/companies-v2/[id]/page.tsx +19 -2
  224. package/src/modules/customers/backend/customers/deals/[id]/hooks/useDealAssociations.ts +29 -8
  225. package/src/modules/customers/backend/customers/deals/[id]/hooks/useDealClosure.ts +47 -20
  226. package/src/modules/customers/backend/customers/deals/[id]/hooks/useDealPipeline.ts +13 -3
  227. package/src/modules/customers/backend/customers/deals/[id]/page.tsx +21 -1
  228. package/src/modules/customers/backend/customers/people-v2/[id]/page.tsx +18 -2
  229. package/src/modules/customers/commands/interactions.ts +5 -5
  230. package/src/modules/customers/commands/pipeline-stages.ts +26 -2
  231. package/src/modules/customers/commands/pipelines.ts +26 -2
  232. package/src/modules/customers/components/detail/AddressesSection.tsx +50 -28
  233. package/src/modules/customers/components/detail/DealForm.tsx +12 -0
  234. package/src/modules/customers/components/detail/EntityTagsDialog.tsx +89 -71
  235. package/src/modules/customers/components/detail/notesAdapter.ts +29 -18
  236. package/src/modules/customers/i18n/de.json +2 -0
  237. package/src/modules/customers/i18n/en.json +2 -0
  238. package/src/modules/customers/i18n/es.json +2 -0
  239. package/src/modules/customers/i18n/pl.json +2 -0
  240. package/src/modules/dashboards/components/WidgetVisibilityEditor.tsx +6 -3
  241. package/src/modules/data_sync/api/runs.ts +1 -0
  242. package/src/modules/data_sync/api/schedules/[id]/route.ts +38 -20
  243. package/src/modules/data_sync/api/schedules/route.ts +1 -1
  244. package/src/modules/data_sync/backend/data-sync/page.tsx +35 -16
  245. package/src/modules/data_sync/data/validators.ts +1 -0
  246. package/src/modules/data_sync/i18n/de.json +1 -0
  247. package/src/modules/data_sync/i18n/en.json +1 -0
  248. package/src/modules/data_sync/i18n/es.json +1 -0
  249. package/src/modules/data_sync/i18n/pl.json +1 -0
  250. package/src/modules/data_sync/lib/sync-run-service.ts +23 -0
  251. package/src/modules/data_sync/lib/sync-schedule-service.ts +30 -5
  252. package/src/modules/dictionaries/api/[dictionaryId]/entries/[entryId]/route.ts +3 -3
  253. package/src/modules/dictionaries/api/[dictionaryId]/route.ts +3 -3
  254. package/src/modules/dictionaries/components/DictionariesManager.tsx +21 -1
  255. package/src/modules/dictionaries/components/DictionaryEntriesEditor.tsx +2 -0
  256. package/src/modules/directory/backend/directory/organizations/[id]/edit/page.tsx +17 -0
  257. package/src/modules/directory/backend/directory/tenants/[id]/edit/page.tsx +17 -0
  258. package/src/modules/entities/api/entities.ts +2 -2
  259. package/src/modules/entities/api/records.ts +24 -6
  260. package/src/modules/entities/backend/entities/user/[entityId]/records/page.tsx +25 -12
  261. package/src/modules/feature_toggles/api/overrides/route.ts +2 -2
  262. package/src/modules/feature_toggles/backend/feature-toggles/global/[id]/edit/page.tsx +12 -0
  263. package/src/modules/feature_toggles/data/entities.ts +1 -1
  264. package/src/modules/feature_toggles/data/validators.ts +1 -0
  265. package/src/modules/feature_toggles/lib/queries.ts +1 -0
  266. package/src/modules/inbox_ops/api/settings/route.ts +2 -2
  267. package/src/modules/messages/api/unread-count/route.ts +40 -0
  268. package/src/modules/query_index/components/QueryIndexesTable.tsx +17 -15
  269. package/src/modules/resources/backend/resources/resource-types/[id]/edit/page.tsx +17 -1
  270. package/src/modules/resources/backend/resources/resources/[id]/page.tsx +17 -1
  271. package/src/modules/resources/components/detail/notesAdapter.ts +29 -18
  272. package/src/modules/sales/backend/sales/documents/[id]/page.tsx +17 -1
  273. package/src/modules/sales/commands/documents.ts +11 -10
  274. package/src/modules/sales/commands/payments.ts +11 -0
  275. package/src/modules/sales/commands/returns.ts +3 -3
  276. package/src/modules/sales/commands/shared.ts +10 -4
  277. package/src/modules/sales/commands/shipments.ts +14 -0
  278. package/src/modules/sales/components/documents/PaymentDialog.tsx +7 -3
  279. package/src/modules/sales/components/documents/PaymentsSection.tsx +8 -3
  280. package/src/modules/sales/components/documents/ShipmentDialog.tsx +7 -3
  281. package/src/modules/sales/components/documents/ShipmentsSection.tsx +8 -3
  282. package/src/modules/sales/di.ts +68 -9
  283. package/src/modules/sales/setup.ts +2 -0
  284. package/src/modules/shipping_carriers/i18n/de.json +11 -1
  285. package/src/modules/shipping_carriers/i18n/en.json +11 -1
  286. package/src/modules/shipping_carriers/i18n/en.ts +10 -0
  287. package/src/modules/shipping_carriers/i18n/es.json +11 -1
  288. package/src/modules/shipping_carriers/i18n/pl.json +11 -1
  289. package/src/modules/shipping_carriers/i18n/pl.ts +10 -0
  290. package/src/modules/shipping_carriers/widgets/injection/tracking-status-badge/widget.client.tsx +35 -0
  291. package/src/modules/shipping_carriers/widgets/injection/tracking-status-badge/widget.tsx +3 -22
  292. package/src/modules/staff/backend/staff/leave-requests/[id]/page.tsx +17 -1
  293. package/src/modules/staff/backend/staff/team-members/[id]/page.tsx +17 -1
  294. package/src/modules/staff/backend/staff/team-roles/[id]/edit/page.tsx +17 -1
  295. package/src/modules/staff/backend/staff/teams/[id]/edit/page.tsx +17 -1
  296. package/src/modules/staff/commands/job-histories.ts +3 -3
  297. package/src/modules/staff/components/detail/addressesAdapter.ts +40 -23
  298. package/src/modules/staff/components/detail/notesAdapter.ts +28 -18
  299. package/src/modules/translations/api/[entityType]/[entityId]/route.ts +74 -0
  300. package/src/modules/translations/components/TranslationManager.tsx +14 -1
  301. package/src/modules/translations/widgets/injection/translation-manager/widget.client.tsx +30 -13
  302. package/src/modules/workflows/api/definitions/[id]/route.ts +3 -3
  303. package/src/modules/workflows/backend/definitions/[id]/page.tsx +18 -1
  304. package/src/modules/workflows/backend/definitions/visual-editor/page.tsx +19 -1
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../../src/modules/customers/backend/customers/companies-v2/%5Bid%5D/page.tsx"],
4
- "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport Link from 'next/link'\nimport { useRouter, useSearchParams } from 'next/navigation'\nimport { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport { Building2, Hash, Users, BarChart3, StickyNote } from 'lucide-react'\nimport { updateCrud, deleteCrud } from '@open-mercato/ui/backend/utils/crud'\nimport { apiCallOrThrow, readApiResultOrThrow, withScopedApiRequestHeaders } from '@open-mercato/ui/backend/utils/apiCall'\nimport { buildOptimisticLockHeader } from '@open-mercato/ui/backend/utils/optimisticLock'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { surfaceRecordConflict } from '@open-mercato/ui/backend/conflicts'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { AttachmentsSection, ErrorMessage, LoadingMessage, RecordNotFoundState, type SectionAction } from '@open-mercato/ui/backend/detail'\nimport { useConfirmDialog } from '@open-mercato/ui/backend/confirm-dialog'\nimport { InjectionSpot, useInjectionWidgets } from '@open-mercato/ui/backend/injection/InjectionSpot'\nimport { useGuardedMutation } from '@open-mercato/ui/backend/injection/useGuardedMutation'\nimport { createTranslatorWithFallback } from '@open-mercato/shared/lib/i18n/translate'\nimport { CrudForm } from '@open-mercato/ui/backend/CrudForm'\nimport { CollapsibleZoneLayout, type ZoneSectionDescriptor } from '@open-mercato/ui/backend/crud/CollapsibleZoneLayout'\nimport { createCrudFormError } from '@open-mercato/ui/backend/utils/serverErrors'\nimport { E } from '#generated/entities.ids.generated'\nimport { useOrganizationScopeDetail } from '@open-mercato/shared/lib/frontend/useOrganizationScope'\nimport { DealsSection } from '../../../../components/detail/DealsSection'\nimport { ActivityLogTab } from '../../../../components/detail/ActivityLogTab'\nimport { CompanyPeopleSection, type CompanyPersonSummary } from '../../../../components/detail/CompanyPeopleSection'\nimport type { TagSummary } from '../../../../components/detail/types'\nimport type { TagsSectionController } from '@open-mercato/ui/backend/detail'\nimport { coerceDisplayName } from '../../../../lib/displayName'\nimport { CompanyDetailHeader } from '../../../../components/detail/CompanyDetailHeader'\nimport { CompanyDetailTabs, resolveLegacyTab, type CompanyTabId } from '../../../../components/detail/CompanyDetailTabs'\nimport { CompanyKpiBar } from '../../../../components/detail/CompanyKpiBar'\nimport { ScheduleActivityDialog, type ScheduleActivityEditData } from '../../../../components/detail/ScheduleActivityDialog'\nimport { ChangelogTab } from '../../../../components/detail/ChangelogTab'\nimport { useInteractionMutations } from '../../../../components/detail/hooks/useInteractionMutations'\nimport {\n buildCompanyEditPayload,\n createCompanyEditFields,\n createCompanyDaneFiremyGroups,\n createCompanyEditSchema,\n mapCompanyOverviewToFormValues,\n type CompanyEditFormValues,\n type CompanyOverview,\n} from '../../../../components/formConfig'\n\nexport default function CompanyDetailV2Page({ params }: { params?: { id?: string } }) {\n const id = params?.id\n const t = useT()\n const router = useRouter()\n const searchParams = useSearchParams()\n const { confirm, ConfirmDialogElement } = useConfirmDialog()\n\n const detailTranslator = React.useMemo(() => createTranslatorWithFallback(t), [t])\n\n const [data, setData] = React.useState<CompanyOverview | null>(null)\n const [isLoading, setIsLoading] = React.useState(true)\n const [error, setError] = React.useState<string | null>(null)\n const [isNotFound, setIsNotFound] = React.useState(false)\n\n // Tab state\n const initialTab = React.useMemo(() => {\n return resolveLegacyTab(searchParams?.get('tab'))\n }, [searchParams])\n const [activeTab, setActiveTab] = React.useState<CompanyTabId>(initialTab)\n const [sectionAction, setSectionAction] = React.useState<SectionAction | null>(null)\n\n // Form state\n const [isDirty, setIsDirty] = React.useState(false)\n const [isSaving, setIsSaving] = React.useState(false)\n const formWrapperRef = React.useRef<HTMLDivElement>(null)\n const { organizationId } = useOrganizationScopeDetail()\n const formSchema = React.useMemo(() => createCompanyEditSchema(), [])\n const formFields = React.useMemo(() => createCompanyEditFields(t), [t])\n const formGroups = React.useMemo(() => createCompanyDaneFiremyGroups(t), [t])\n const initialValues = React.useMemo(\n () => (data ? mapCompanyOverviewToFormValues(data) : undefined),\n [data],\n )\n const zoneSections = React.useMemo<ZoneSectionDescriptor[]>(() => [\n { id: 'identity', icon: Building2, label: t('customers.companies.form.sections.identity', 'Identity') },\n { id: 'contact', icon: Hash, label: t('customers.companies.form.sections.contact', 'Contact') },\n { id: 'classification', icon: Users, label: t('customers.companies.form.sections.classification', 'Classification') },\n { id: 'businessProfile', icon: BarChart3, label: t('customers.companies.form.sections.businessProfile', 'Business profile') },\n { id: 'notes', icon: StickyNote, label: t('customers.companies.form.groups.notes', 'Notes') },\n { id: 'customFields', icon: Hash, label: t('customers.companies.form.groups.customAttributes', 'Custom attributes') },\n ], [t])\n const [scheduleDialogOpen, setScheduleDialogOpen] = React.useState(false)\n const [scheduleEditData, setScheduleEditData] = React.useState<ScheduleActivityEditData | null>(null)\n const [activityRefreshKey, setActivityRefreshKey] = React.useState(0)\n const [dealCount, setDealCount] = React.useState(0)\n\n const currentCompanyId = data?.company?.id ?? null\n const mutationContextId = React.useMemo(\n () => (currentCompanyId ? `customer-company:${currentCompanyId}` : `customer-company:${id ?? 'pending'}`),\n [currentCompanyId, id],\n )\n const { runMutation, retryLastMutation } = useGuardedMutation<{\n formId: string\n companyId?: string | null\n resourceKind: string\n resourceId?: string\n data: CompanyOverview | null\n retryLastMutation: () => Promise<boolean>\n }>({\n contextId: mutationContextId,\n blockedMessage: t('ui.forms.flash.saveBlocked', 'Save blocked by validation'),\n })\n\n const companyDisplayName = coerceDisplayName(data?.company?.displayName)\n const companyName = companyDisplayName.trim().length\n ? companyDisplayName\n : t('customers.companies.list.deleteFallbackName', 'this company')\n\n // Data loading\n const initialLoadDoneRef = React.useRef(false)\n const loadData = React.useCallback(async () => {\n if (!id) {\n setIsNotFound(true)\n setIsLoading(false)\n return\n }\n if (!initialLoadDoneRef.current) {\n setIsLoading(true)\n }\n setError(null)\n setIsNotFound(false)\n try {\n const payload = await readApiResultOrThrow<CompanyOverview>(\n `/api/customers/companies/${encodeURIComponent(id)}`,\n undefined,\n { errorMessage: t('customers.companies.detail.error.load', 'Failed to load company.') },\n )\n setData(payload as CompanyOverview)\n } catch (err) {\n if ((err as { status?: number }).status === 404) {\n setIsNotFound(true)\n } else {\n const message = err instanceof Error ? err.message : t('customers.companies.detail.error.load', 'Failed to load company.')\n setError(message)\n }\n if (!initialLoadDoneRef.current) setData(null)\n } finally {\n setIsLoading(false)\n initialLoadDoneRef.current = true\n }\n }, [id, t])\n\n React.useEffect(() => {\n loadData().catch((err) => console.warn('[companies-v2] loadData failed', err))\n }, [loadData])\n\n React.useEffect(() => {\n setDealCount(data?.counts?.deals ?? 0)\n }, [data?.counts?.deals])\n\n const handleActivityCreated = React.useCallback(() => {\n setActivityRefreshKey((k) => k + 1)\n loadData().catch((err) => console.warn('[companies-v2] reload after activity failed', err))\n }, [loadData])\n\n // Planned activities for the activity-log tab\n const plannedActivities = React.useMemo(() => {\n return data?.plannedActivitiesPreview ?? []\n }, [data?.plannedActivitiesPreview])\n\n // Injection context for UMES\n const injectionContext = React.useMemo(\n () => ({\n formId: mutationContextId,\n companyId: currentCompanyId,\n resourceKind: 'customers.company',\n resourceId: currentCompanyId ?? (id ?? undefined),\n data,\n retryLastMutation,\n }),\n [currentCompanyId, data, id, mutationContextId, retryLastMutation],\n )\n const runMutationWithContext = React.useCallback(\n async <T,>(operation: () => Promise<T>, mutationPayload?: Record<string, unknown>): Promise<T> => {\n return runMutation({\n operation,\n mutationPayload,\n context: injectionContext,\n })\n },\n [injectionContext, runMutation],\n )\n\n const { completeInteraction: handleMarkDone, cancelInteraction: handleCancelActivity } = useInteractionMutations({\n runMutationWithContext,\n onAfterChange: handleActivityCreated,\n logContext: 'customers.companies-v2',\n })\n\n const handleEditActivity = React.useCallback((activity: { id: string; interactionType?: string; title?: string | null; body?: string | null; scheduledAt?: string | null; occurredAt?: string | null; [key: string]: unknown }) => {\n const raw = activity as Record<string, unknown>\n const durationValue = typeof raw.duration === 'number'\n ? raw.duration\n : typeof raw.durationMinutes === 'number'\n ? raw.durationMinutes as number\n : null\n // Forward `customValues` so per-type chip state (callPhoneNumber, callDirection,\n // taskPriority, \u2026) round-trips on edit (#1808 phone persistence).\n // Forward `occurredAt` so historical activity edits prefill from the original\n // moment instead of \"today\" (#1807 prefill).\n const editPayload = {\n id: activity.id,\n updatedAt: typeof raw.updatedAt === 'string' ? raw.updatedAt as string : typeof raw.updated_at === 'string' ? raw.updated_at as string : null,\n interactionType: typeof activity.interactionType === 'string' ? activity.interactionType : undefined,\n title: typeof activity.title === 'string' ? activity.title : null,\n body: typeof activity.body === 'string' ? activity.body : null,\n scheduledAt: typeof activity.scheduledAt === 'string' ? activity.scheduledAt : null,\n occurredAt: typeof activity.occurredAt === 'string' ? activity.occurredAt : null,\n durationMinutes: durationValue,\n location: typeof raw.location === 'string' ? raw.location as string : null,\n allDay: typeof raw.allDay === 'boolean' ? raw.allDay as boolean : null,\n recurrenceRule: typeof raw.recurrenceRule === 'string' ? raw.recurrenceRule as string : null,\n recurrenceEnd: typeof raw.recurrenceEnd === 'string' ? raw.recurrenceEnd as string : null,\n participants: Array.isArray(raw.participants) ? raw.participants as ScheduleActivityEditData['participants'] : null,\n reminderMinutes: typeof raw.reminderMinutes === 'number' ? raw.reminderMinutes as number : null,\n visibility: typeof raw.visibility === 'string' ? raw.visibility as string : null,\n linkedEntities: Array.isArray(raw.linkedEntities) ? raw.linkedEntities as ScheduleActivityEditData['linkedEntities'] : null,\n guestPermissions: raw.guestPermissions && typeof raw.guestPermissions === 'object'\n ? raw.guestPermissions as ScheduleActivityEditData['guestPermissions']\n : null,\n customValues: raw.customValues && typeof raw.customValues === 'object'\n ? raw.customValues as Record<string, unknown>\n : null,\n phoneNumber: typeof raw.phoneNumber === 'string' ? raw.phoneNumber as string : null,\n } as ScheduleActivityEditData & { customValues?: Record<string, unknown> | null; phoneNumber?: string | null }\n setScheduleEditData(editPayload)\n setScheduleDialogOpen(true)\n }, [])\n\n const openNewScheduleDialog = React.useCallback(() => {\n setScheduleEditData(null)\n setScheduleDialogOpen(true)\n }, [])\n\n const handleAddActivity = React.useCallback((kind: 'meeting' | 'call' | 'task' | 'email') => {\n setScheduleEditData({\n id: '',\n interactionType: kind,\n title: null,\n body: null,\n scheduledAt: null,\n durationMinutes: null,\n location: null,\n allDay: null,\n recurrenceRule: null,\n recurrenceEnd: null,\n participants: null,\n reminderMinutes: null,\n visibility: null,\n linkedEntities: null,\n guestPermissions: null,\n })\n setScheduleDialogOpen(true)\n }, [])\n\n // Injected tabs from UMES\n const { widgets: injectedTabWidgets } = useInjectionWidgets('detail:customers.company:tabs', {\n context: injectionContext,\n triggerOnLoad: true,\n })\n\n const injectedTabs = React.useMemo(\n () =>\n (injectedTabWidgets ?? [])\n .filter((widget) => (widget.placement?.kind ?? 'tab') === 'tab')\n .map((widget) => {\n const tabId = widget.placement?.groupId ?? widget.widgetId\n const label = widget.placement?.groupLabel ?? widget.module.metadata.title ?? tabId\n const priority = typeof widget.placement?.priority === 'number' ? widget.placement.priority : 0\n const render = () => (\n <widget.module.Widget\n context={injectionContext}\n data={data}\n onDataChange={(next: unknown) => setData(next as CompanyOverview)}\n />\n )\n return { id: tabId, label, priority, render }\n })\n .sort((a, b) => b.priority - a.priority),\n [data, injectedTabWidgets, injectionContext],\n )\n\n const injectedTabMap = React.useMemo(() => new Map(injectedTabs.map((tab) => [tab.id, tab.render])), [injectedTabs])\n\n // Tags\n const handleTagsChange = React.useCallback((nextTags: TagSummary[]) => {\n setData((prev) => (prev ? { ...prev, tags: nextTags } : prev))\n }, [])\n const tagsSectionControllerRef = React.useRef<TagsSectionController | null>(null)\n\n // Section action (for tabs that expose add/create buttons)\n const handleSectionActionChange = React.useCallback((action: SectionAction | null) => {\n setSectionAction((prev) => (action !== null ? action : prev))\n }, [])\n\n const handleSectionAction = React.useCallback(() => {\n if (!sectionAction || sectionAction.disabled) return\n sectionAction.onClick()\n }, [sectionAction])\n\n React.useEffect(() => {\n setSectionAction(null)\n }, [activeTab])\n\n // Deals scope\n const dealsScope = React.useMemo(\n () => (currentCompanyId ? ({ kind: 'company', entityId: currentCompanyId } as const) : null),\n [currentCompanyId],\n )\n\n // Delete handler (shared between header and form)\n const handleDelete = React.useCallback(async () => {\n const companyId = data?.company?.id ?? ''\n if (!companyId) return\n const approved = await confirm({\n title: t('customers.companies.detail.deleteConfirmTitle', 'Delete company?'),\n description: t('customers.companies.detail.deleteConfirmDescription', 'This action cannot be undone.'),\n confirmText: t('customers.companies.detail.actions.delete', 'Delete company'),\n cancelText: t('customers.companies.detail.actions.cancel', 'Cancel'),\n variant: 'destructive',\n })\n if (!approved) return\n try {\n await runMutationWithContext(\n () => withScopedApiRequestHeaders(\n buildOptimisticLockHeader((data?.company as { updatedAt?: string } | undefined)?.updatedAt),\n () => deleteCrud('customers/companies', { id: companyId }),\n ),\n { id: companyId, operation: 'deleteCompany' },\n )\n } catch (err) {\n // The guarded mutation already routes a 409 to the unified conflict bar;\n // surface any other server error (e.g. \"Cannot delete company: linked\n // deals\u2026\") as a flash instead of letting it crash the page.\n if (!surfaceRecordConflict(err, t)) {\n flash(\n err instanceof Error && err.message.trim().length > 0\n ? err.message\n : t('customers.companies.detail.deleteError', 'Failed to delete company.'),\n 'error',\n )\n }\n return\n }\n flash(t('customers.companies.list.deleteSuccess', 'Company deleted.'), 'success')\n router.push('/backend/customers/companies')\n }, [confirm, data?.company?.id, router, runMutationWithContext, t])\n\n // Form submit handler (lifted from CompanyDataTab)\n const handleFormSubmit = React.useCallback(\n async (values: CompanyEditFormValues) => {\n setIsSaving(true)\n try {\n let payload: Record<string, unknown>\n try {\n payload = buildCompanyEditPayload(values, organizationId)\n } catch (err) {\n if (err instanceof Error) {\n if (err.message === 'DISPLAY_NAME_REQUIRED') {\n const message = t('customers.companies.form.displayName.error')\n throw createCrudFormError(message, { displayName: message })\n }\n if (err.message === 'ANNUAL_REVENUE_INVALID') {\n const message = t('customers.companies.form.annualRevenue.error')\n throw createCrudFormError(message, { annualRevenue: message })\n }\n }\n throw err\n }\n await updateCrud('customers/companies', payload)\n flash(t('customers.companies.form.updateSuccess', 'Company updated.'), 'success')\n await loadData()\n } finally {\n setIsSaving(false)\n }\n },\n [loadData, organizationId, t],\n )\n\n // Save handler (triggers form submit via ref)\n const handleHeaderSave = React.useCallback(() => {\n const form = formWrapperRef.current?.querySelector('form')\n if (form) form.requestSubmit()\n }, [])\n\n // Loading / error states\n if (isLoading) {\n return (\n <Page>\n <PageBody>\n <LoadingMessage label={t('customers.companies.detail.loading', 'Loading company\u2026')} />\n </PageBody>\n </Page>\n )\n }\n\n if (isNotFound) {\n return (\n <Page>\n <PageBody>\n <RecordNotFoundState\n label={t('customers.companies.detail.error.notFound', 'Company not found.')}\n backHref=\"/backend/customers/companies\"\n backLabel={t('customers.companies.detail.actions.backToList', 'Back to companies')}\n />\n </PageBody>\n </Page>\n )\n }\n\n if (error || !data?.company?.id) {\n return (\n <Page>\n <PageBody>\n <ErrorMessage\n label={error ?? t('customers.companies.detail.error.load', 'Failed to load company.')}\n action={(\n <Button asChild variant=\"outline\">\n <Link href=\"/backend/customers/companies\">\n {t('customers.companies.detail.actions.backToList', 'Back to companies')}\n </Link>\n </Button>\n )}\n />\n </PageBody>\n </Page>\n )\n }\n\n const companyId = data.company.id\n const useCanonicalInteractions = data.interactionMode === 'canonical'\n\n return (\n <Page>\n <PageBody>\n <div className=\"space-y-4\">\n {/* UMES header injection */}\n <InjectionSpot spotId=\"detail:customers.company:header\" context={injectionContext} data={data} />\n <InjectionSpot spotId=\"detail:customers.company:status-badges\" context={injectionContext} data={data} />\n\n {/* Persistent company header */}\n <CompanyDetailHeader\n data={data}\n onTagsChange={handleTagsChange}\n tagsSectionControllerRef={tagsSectionControllerRef}\n onSave={handleHeaderSave}\n onDelete={handleDelete}\n isDirty={isDirty}\n isSaving={isSaving}\n onDataReload={() => { loadData().catch((err) => console.warn('[companies-v2] onDataReload failed', err)) }}\n />\n\n {/* KPI bar \u2014 always visible above zones */}\n <CompanyKpiBar data={data} />\n\n {/* Two-zone layout: zone1 = form, zone2 = tabs */}\n <CollapsibleZoneLayout\n pageType=\"company-v2\"\n entityName={companyName}\n isDirty={isDirty}\n sections={zoneSections}\n zone1={\n <div ref={formWrapperRef}>\n <CrudForm<CompanyEditFormValues>\n embedded\n trackDirtyWhenEmbedded\n injectionSpotId=\"customers.company\"\n entityIds={[E.customers.customer_entity, E.customers.customer_company_profile]}\n schema={formSchema}\n fields={formFields}\n groups={formGroups}\n initialValues={initialValues}\n onSubmit={handleFormSubmit}\n onDelete={handleDelete}\n optimisticLockUpdatedAt={(data?.company as { updatedAt?: string } | undefined)?.updatedAt}\n hideFooterActions\n collapsibleGroups={{ pageType: 'company-v2', chevronPosition: 'right' }}\n sortableGroups={{ pageType: 'company-v2' }}\n onDirtyChange={setIsDirty}\n />\n </div>\n }\n zone2={\n <CompanyDetailTabs\n activeTab={activeTab}\n onTabChange={setActiveTab}\n injectedTabs={injectedTabs.map((tab) => ({ id: tab.id, label: tab.label }))}\n peopleCount={data.counts?.people ?? 0}\n dealsCount={dealCount}\n activitiesCount={data.counts?.activities ?? 0}\n sectionAction={sectionAction}\n >\n {activeTab === 'people' && (\n <CompanyPeopleSection\n companyId={companyId}\n companyName={companyDisplayName}\n initialPeople={[]}\n addActionLabel={t('customers.companies.detail.people.add', 'Add person')}\n emptyLabel={t('customers.companies.detail.people.empty', 'No people linked to this company yet.')}\n emptyState={{\n title: t('customers.companies.detail.emptyState.people.title', 'Build the account team'),\n actionLabel: t('customers.companies.detail.emptyState.people.action', 'Create person'),\n }}\n onActionChange={handleSectionActionChange}\n translator={detailTranslator}\n runGuardedMutation={runMutationWithContext}\n onPeopleChange={(next) => {\n setData((prev) => {\n if (!prev) return prev\n const nextCount = next.length\n return {\n ...prev,\n people: next,\n counts: prev.counts ? { ...prev.counts, people: nextCount } : prev.counts,\n }\n })\n }}\n />\n )}\n\n {activeTab === 'deals' && (\n <DealsSection\n scope={dealsScope}\n emptyLabel={t('customers.companies.detail.empty.deals', 'No deals linked to this company.')}\n addActionLabel={t('customers.companies.detail.actions.addDeal', 'Add deal')}\n emptyState={{\n title: t('customers.companies.detail.emptyState.deals.title', 'No deals yet'),\n actionLabel: t('customers.companies.detail.emptyState.deals.action', 'Create a deal'),\n }}\n onActionChange={handleSectionActionChange}\n translator={detailTranslator}\n runGuardedMutation={runMutationWithContext}\n onCountDelta={(delta) => setDealCount((current) => Math.max(0, current + delta))}\n />\n )}\n\n {activeTab === 'activity-log' && (\n <ActivityLogTab\n entityId={companyId}\n plannedActivities={plannedActivities}\n onActivityCreated={handleActivityCreated}\n onScheduleRequested={openNewScheduleDialog}\n onAddActivity={handleAddActivity}\n onMarkDone={handleMarkDone}\n onEditActivity={handleEditActivity}\n onCancelActivity={handleCancelActivity}\n runGuardedMutation={runMutationWithContext}\n refreshKey={activityRefreshKey}\n useCanonicalInteractions={useCanonicalInteractions}\n />\n )}\n\n {activeTab === 'changelog' && companyId && (\n <ChangelogTab entityId={companyId} entityType=\"company\" />\n )}\n\n {activeTab === 'files' && (\n <AttachmentsSection\n entityId={E.customers.customer_entity}\n recordId={companyId}\n title={t('customers.companies.detail.tabs.files', 'Files')}\n description={t('customers.companies.detail.files.subtitle', 'Upload and manage files linked to this company.')}\n />\n )}\n\n {/* Injected tabs from UMES */}\n {injectedTabMap.has(activeTab) && injectedTabMap.get(activeTab)!()}\n </CompanyDetailTabs>\n }\n />\n\n {/* UMES footer injection */}\n <InjectionSpot spotId=\"detail:customers.company:footer\" context={injectionContext} data={data} />\n\n {/* Schedule Activity Dialog */}\n <ScheduleActivityDialog\n open={scheduleDialogOpen}\n onClose={() => { setScheduleDialogOpen(false); setScheduleEditData(null) }}\n entityId={companyId}\n entityName={companyName}\n entityType=\"company\"\n onActivityCreated={handleActivityCreated}\n editData={scheduleEditData}\n />\n {ConfirmDialogElement}\n </div>\n </PageBody>\n </Page>\n )\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport Link from 'next/link'\nimport { useRouter, useSearchParams, usePathname } from 'next/navigation'\nimport { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport { Building2, Hash, Users, BarChart3, StickyNote } from 'lucide-react'\nimport { updateCrud, deleteCrud } from '@open-mercato/ui/backend/utils/crud'\nimport { apiCallOrThrow, readApiResultOrThrow, withScopedApiRequestHeaders } from '@open-mercato/ui/backend/utils/apiCall'\nimport { buildOptimisticLockHeader } from '@open-mercato/ui/backend/utils/optimisticLock'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { surfaceRecordConflict } from '@open-mercato/ui/backend/conflicts'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { AttachmentsSection, ErrorMessage, LoadingMessage, RecordNotFoundState, type SectionAction } from '@open-mercato/ui/backend/detail'\nimport { useConfirmDialog } from '@open-mercato/ui/backend/confirm-dialog'\nimport { InjectionSpot, useInjectionWidgets } from '@open-mercato/ui/backend/injection/InjectionSpot'\nimport { useGuardedMutation } from '@open-mercato/ui/backend/injection/useGuardedMutation'\nimport { buildRecordInjectionContext, useSetCurrentRecordInjectionContext } from '@open-mercato/ui/backend/injection/recordContext'\nimport { createTranslatorWithFallback } from '@open-mercato/shared/lib/i18n/translate'\nimport { CrudForm } from '@open-mercato/ui/backend/CrudForm'\nimport { CollapsibleZoneLayout, type ZoneSectionDescriptor } from '@open-mercato/ui/backend/crud/CollapsibleZoneLayout'\nimport { createCrudFormError } from '@open-mercato/ui/backend/utils/serverErrors'\nimport { E } from '#generated/entities.ids.generated'\nimport { useOrganizationScopeDetail } from '@open-mercato/shared/lib/frontend/useOrganizationScope'\nimport { DealsSection } from '../../../../components/detail/DealsSection'\nimport { ActivityLogTab } from '../../../../components/detail/ActivityLogTab'\nimport { CompanyPeopleSection, type CompanyPersonSummary } from '../../../../components/detail/CompanyPeopleSection'\nimport type { TagSummary } from '../../../../components/detail/types'\nimport type { TagsSectionController } from '@open-mercato/ui/backend/detail'\nimport { coerceDisplayName } from '../../../../lib/displayName'\nimport { CompanyDetailHeader } from '../../../../components/detail/CompanyDetailHeader'\nimport { CompanyDetailTabs, resolveLegacyTab, type CompanyTabId } from '../../../../components/detail/CompanyDetailTabs'\nimport { CompanyKpiBar } from '../../../../components/detail/CompanyKpiBar'\nimport { ScheduleActivityDialog, type ScheduleActivityEditData } from '../../../../components/detail/ScheduleActivityDialog'\nimport { ChangelogTab } from '../../../../components/detail/ChangelogTab'\nimport { useInteractionMutations } from '../../../../components/detail/hooks/useInteractionMutations'\nimport {\n buildCompanyEditPayload,\n createCompanyEditFields,\n createCompanyDaneFiremyGroups,\n createCompanyEditSchema,\n mapCompanyOverviewToFormValues,\n type CompanyEditFormValues,\n type CompanyOverview,\n} from '../../../../components/formConfig'\n\nexport default function CompanyDetailV2Page({ params }: { params?: { id?: string } }) {\n const id = params?.id\n const t = useT()\n const router = useRouter()\n const searchParams = useSearchParams()\n const pathname = usePathname()\n const { confirm, ConfirmDialogElement } = useConfirmDialog()\n\n const detailTranslator = React.useMemo(() => createTranslatorWithFallback(t), [t])\n\n const [data, setData] = React.useState<CompanyOverview | null>(null)\n const [isLoading, setIsLoading] = React.useState(true)\n const [error, setError] = React.useState<string | null>(null)\n const [isNotFound, setIsNotFound] = React.useState(false)\n\n // Tab state\n const initialTab = React.useMemo(() => {\n return resolveLegacyTab(searchParams?.get('tab'))\n }, [searchParams])\n const [activeTab, setActiveTab] = React.useState<CompanyTabId>(initialTab)\n const [sectionAction, setSectionAction] = React.useState<SectionAction | null>(null)\n\n // Form state\n const [isDirty, setIsDirty] = React.useState(false)\n const [isSaving, setIsSaving] = React.useState(false)\n const formWrapperRef = React.useRef<HTMLDivElement>(null)\n const { organizationId } = useOrganizationScopeDetail()\n const formSchema = React.useMemo(() => createCompanyEditSchema(), [])\n const formFields = React.useMemo(() => createCompanyEditFields(t), [t])\n const formGroups = React.useMemo(() => createCompanyDaneFiremyGroups(t), [t])\n const initialValues = React.useMemo(\n () => (data ? mapCompanyOverviewToFormValues(data) : undefined),\n [data],\n )\n const zoneSections = React.useMemo<ZoneSectionDescriptor[]>(() => [\n { id: 'identity', icon: Building2, label: t('customers.companies.form.sections.identity', 'Identity') },\n { id: 'contact', icon: Hash, label: t('customers.companies.form.sections.contact', 'Contact') },\n { id: 'classification', icon: Users, label: t('customers.companies.form.sections.classification', 'Classification') },\n { id: 'businessProfile', icon: BarChart3, label: t('customers.companies.form.sections.businessProfile', 'Business profile') },\n { id: 'notes', icon: StickyNote, label: t('customers.companies.form.groups.notes', 'Notes') },\n { id: 'customFields', icon: Hash, label: t('customers.companies.form.groups.customAttributes', 'Custom attributes') },\n ], [t])\n const [scheduleDialogOpen, setScheduleDialogOpen] = React.useState(false)\n const [scheduleEditData, setScheduleEditData] = React.useState<ScheduleActivityEditData | null>(null)\n const [activityRefreshKey, setActivityRefreshKey] = React.useState(0)\n const [dealCount, setDealCount] = React.useState(0)\n\n const currentCompanyId = data?.company?.id ?? null\n const mutationContextId = React.useMemo(\n () => (currentCompanyId ? `customer-company:${currentCompanyId}` : `customer-company:${id ?? 'pending'}`),\n [currentCompanyId, id],\n )\n const { runMutation, retryLastMutation } = useGuardedMutation<{\n formId: string\n companyId?: string | null\n resourceKind: string\n resourceId?: string\n data: CompanyOverview | null\n retryLastMutation: () => Promise<boolean>\n }>({\n contextId: mutationContextId,\n blockedMessage: t('ui.forms.flash.saveBlocked', 'Save blocked by validation'),\n })\n\n const companyDisplayName = coerceDisplayName(data?.company?.displayName)\n const companyName = companyDisplayName.trim().length\n ? companyDisplayName\n : t('customers.companies.list.deleteFallbackName', 'this company')\n\n // Data loading\n const initialLoadDoneRef = React.useRef(false)\n const loadData = React.useCallback(async () => {\n if (!id) {\n setIsNotFound(true)\n setIsLoading(false)\n return\n }\n if (!initialLoadDoneRef.current) {\n setIsLoading(true)\n }\n setError(null)\n setIsNotFound(false)\n try {\n const payload = await readApiResultOrThrow<CompanyOverview>(\n `/api/customers/companies/${encodeURIComponent(id)}`,\n undefined,\n { errorMessage: t('customers.companies.detail.error.load', 'Failed to load company.') },\n )\n setData(payload as CompanyOverview)\n } catch (err) {\n if ((err as { status?: number }).status === 404) {\n setIsNotFound(true)\n } else {\n const message = err instanceof Error ? err.message : t('customers.companies.detail.error.load', 'Failed to load company.')\n setError(message)\n }\n if (!initialLoadDoneRef.current) setData(null)\n } finally {\n setIsLoading(false)\n initialLoadDoneRef.current = true\n }\n }, [id, t])\n\n React.useEffect(() => {\n loadData().catch((err) => console.warn('[companies-v2] loadData failed', err))\n }, [loadData])\n\n React.useEffect(() => {\n setDealCount(data?.counts?.deals ?? 0)\n }, [data?.counts?.deals])\n\n const handleActivityCreated = React.useCallback(() => {\n setActivityRefreshKey((k) => k + 1)\n loadData().catch((err) => console.warn('[companies-v2] reload after activity failed', err))\n }, [loadData])\n\n // Planned activities for the activity-log tab\n const plannedActivities = React.useMemo(() => {\n return data?.plannedActivitiesPreview ?? []\n }, [data?.plannedActivitiesPreview])\n\n // Injection context for UMES\n const injectionContext = React.useMemo(\n () => ({\n formId: mutationContextId,\n companyId: currentCompanyId,\n resourceKind: 'customers.company',\n resourceId: currentCompanyId ?? (id ?? undefined),\n data,\n retryLastMutation,\n }),\n [currentCompanyId, data, id, mutationContextId, retryLastMutation],\n )\n const runMutationWithContext = React.useCallback(\n async <T,>(operation: () => Promise<T>, mutationPayload?: Record<string, unknown>): Promise<T> => {\n return runMutation({\n operation,\n mutationPayload,\n context: injectionContext,\n })\n },\n [injectionContext, runMutation],\n )\n\n const { completeInteraction: handleMarkDone, cancelInteraction: handleCancelActivity } = useInteractionMutations({\n runMutationWithContext,\n onAfterChange: handleActivityCreated,\n logContext: 'customers.companies-v2',\n })\n\n // Publish page-load record context to the AppShell-owned `backend:record:current`\n // mount so the enterprise record_locks widget resolves `customers.company` + id\n // explicitly (the hardcoded path allowlist misses the `companies-v2` route).\n useSetCurrentRecordInjectionContext(\n buildRecordInjectionContext({\n resourceKind: 'customers.company',\n resourceId: currentCompanyId,\n updatedAt: (data?.company as { updatedAt?: string | null; updated_at?: string | null } | undefined)?.updatedAt\n ?? (data?.company as { updated_at?: string | null } | undefined)?.updated_at\n ?? null,\n data: data as Record<string, unknown> | null,\n path: pathname,\n }),\n )\n\n const handleEditActivity = React.useCallback((activity: { id: string; interactionType?: string; title?: string | null; body?: string | null; scheduledAt?: string | null; occurredAt?: string | null; [key: string]: unknown }) => {\n const raw = activity as Record<string, unknown>\n const durationValue = typeof raw.duration === 'number'\n ? raw.duration\n : typeof raw.durationMinutes === 'number'\n ? raw.durationMinutes as number\n : null\n // Forward `customValues` so per-type chip state (callPhoneNumber, callDirection,\n // taskPriority, \u2026) round-trips on edit (#1808 phone persistence).\n // Forward `occurredAt` so historical activity edits prefill from the original\n // moment instead of \"today\" (#1807 prefill).\n const editPayload = {\n id: activity.id,\n updatedAt: typeof raw.updatedAt === 'string' ? raw.updatedAt as string : typeof raw.updated_at === 'string' ? raw.updated_at as string : null,\n interactionType: typeof activity.interactionType === 'string' ? activity.interactionType : undefined,\n title: typeof activity.title === 'string' ? activity.title : null,\n body: typeof activity.body === 'string' ? activity.body : null,\n scheduledAt: typeof activity.scheduledAt === 'string' ? activity.scheduledAt : null,\n occurredAt: typeof activity.occurredAt === 'string' ? activity.occurredAt : null,\n durationMinutes: durationValue,\n location: typeof raw.location === 'string' ? raw.location as string : null,\n allDay: typeof raw.allDay === 'boolean' ? raw.allDay as boolean : null,\n recurrenceRule: typeof raw.recurrenceRule === 'string' ? raw.recurrenceRule as string : null,\n recurrenceEnd: typeof raw.recurrenceEnd === 'string' ? raw.recurrenceEnd as string : null,\n participants: Array.isArray(raw.participants) ? raw.participants as ScheduleActivityEditData['participants'] : null,\n reminderMinutes: typeof raw.reminderMinutes === 'number' ? raw.reminderMinutes as number : null,\n visibility: typeof raw.visibility === 'string' ? raw.visibility as string : null,\n linkedEntities: Array.isArray(raw.linkedEntities) ? raw.linkedEntities as ScheduleActivityEditData['linkedEntities'] : null,\n guestPermissions: raw.guestPermissions && typeof raw.guestPermissions === 'object'\n ? raw.guestPermissions as ScheduleActivityEditData['guestPermissions']\n : null,\n customValues: raw.customValues && typeof raw.customValues === 'object'\n ? raw.customValues as Record<string, unknown>\n : null,\n phoneNumber: typeof raw.phoneNumber === 'string' ? raw.phoneNumber as string : null,\n } as ScheduleActivityEditData & { customValues?: Record<string, unknown> | null; phoneNumber?: string | null }\n setScheduleEditData(editPayload)\n setScheduleDialogOpen(true)\n }, [])\n\n const openNewScheduleDialog = React.useCallback(() => {\n setScheduleEditData(null)\n setScheduleDialogOpen(true)\n }, [])\n\n const handleAddActivity = React.useCallback((kind: 'meeting' | 'call' | 'task' | 'email') => {\n setScheduleEditData({\n id: '',\n interactionType: kind,\n title: null,\n body: null,\n scheduledAt: null,\n durationMinutes: null,\n location: null,\n allDay: null,\n recurrenceRule: null,\n recurrenceEnd: null,\n participants: null,\n reminderMinutes: null,\n visibility: null,\n linkedEntities: null,\n guestPermissions: null,\n })\n setScheduleDialogOpen(true)\n }, [])\n\n // Injected tabs from UMES\n const { widgets: injectedTabWidgets } = useInjectionWidgets('detail:customers.company:tabs', {\n context: injectionContext,\n triggerOnLoad: true,\n })\n\n const injectedTabs = React.useMemo(\n () =>\n (injectedTabWidgets ?? [])\n .filter((widget) => (widget.placement?.kind ?? 'tab') === 'tab')\n .map((widget) => {\n const tabId = widget.placement?.groupId ?? widget.widgetId\n const label = widget.placement?.groupLabel ?? widget.module.metadata.title ?? tabId\n const priority = typeof widget.placement?.priority === 'number' ? widget.placement.priority : 0\n const render = () => (\n <widget.module.Widget\n context={injectionContext}\n data={data}\n onDataChange={(next: unknown) => setData(next as CompanyOverview)}\n />\n )\n return { id: tabId, label, priority, render }\n })\n .sort((a, b) => b.priority - a.priority),\n [data, injectedTabWidgets, injectionContext],\n )\n\n const injectedTabMap = React.useMemo(() => new Map(injectedTabs.map((tab) => [tab.id, tab.render])), [injectedTabs])\n\n // Tags\n const handleTagsChange = React.useCallback((nextTags: TagSummary[]) => {\n setData((prev) => (prev ? { ...prev, tags: nextTags } : prev))\n }, [])\n const tagsSectionControllerRef = React.useRef<TagsSectionController | null>(null)\n\n // Section action (for tabs that expose add/create buttons)\n const handleSectionActionChange = React.useCallback((action: SectionAction | null) => {\n setSectionAction((prev) => (action !== null ? action : prev))\n }, [])\n\n const handleSectionAction = React.useCallback(() => {\n if (!sectionAction || sectionAction.disabled) return\n sectionAction.onClick()\n }, [sectionAction])\n\n React.useEffect(() => {\n setSectionAction(null)\n }, [activeTab])\n\n // Deals scope\n const dealsScope = React.useMemo(\n () => (currentCompanyId ? ({ kind: 'company', entityId: currentCompanyId } as const) : null),\n [currentCompanyId],\n )\n\n // Delete handler (shared between header and form)\n const handleDelete = React.useCallback(async () => {\n const companyId = data?.company?.id ?? ''\n if (!companyId) return\n const approved = await confirm({\n title: t('customers.companies.detail.deleteConfirmTitle', 'Delete company?'),\n description: t('customers.companies.detail.deleteConfirmDescription', 'This action cannot be undone.'),\n confirmText: t('customers.companies.detail.actions.delete', 'Delete company'),\n cancelText: t('customers.companies.detail.actions.cancel', 'Cancel'),\n variant: 'destructive',\n })\n if (!approved) return\n try {\n await runMutationWithContext(\n () => withScopedApiRequestHeaders(\n buildOptimisticLockHeader((data?.company as { updatedAt?: string } | undefined)?.updatedAt),\n () => deleteCrud('customers/companies', { id: companyId }),\n ),\n { id: companyId, operation: 'deleteCompany' },\n )\n } catch (err) {\n // The guarded mutation already routes a 409 to the unified conflict bar;\n // surface any other server error (e.g. \"Cannot delete company: linked\n // deals\u2026\") as a flash instead of letting it crash the page.\n if (!surfaceRecordConflict(err, t)) {\n flash(\n err instanceof Error && err.message.trim().length > 0\n ? err.message\n : t('customers.companies.detail.deleteError', 'Failed to delete company.'),\n 'error',\n )\n }\n return\n }\n flash(t('customers.companies.list.deleteSuccess', 'Company deleted.'), 'success')\n router.push('/backend/customers/companies')\n }, [confirm, data?.company?.id, router, runMutationWithContext, t])\n\n // Form submit handler (lifted from CompanyDataTab)\n const handleFormSubmit = React.useCallback(\n async (values: CompanyEditFormValues) => {\n setIsSaving(true)\n try {\n let payload: Record<string, unknown>\n try {\n payload = buildCompanyEditPayload(values, organizationId)\n } catch (err) {\n if (err instanceof Error) {\n if (err.message === 'DISPLAY_NAME_REQUIRED') {\n const message = t('customers.companies.form.displayName.error')\n throw createCrudFormError(message, { displayName: message })\n }\n if (err.message === 'ANNUAL_REVENUE_INVALID') {\n const message = t('customers.companies.form.annualRevenue.error')\n throw createCrudFormError(message, { annualRevenue: message })\n }\n }\n throw err\n }\n await updateCrud('customers/companies', payload)\n flash(t('customers.companies.form.updateSuccess', 'Company updated.'), 'success')\n await loadData()\n } finally {\n setIsSaving(false)\n }\n },\n [loadData, organizationId, t],\n )\n\n // Save handler (triggers form submit via ref)\n const handleHeaderSave = React.useCallback(() => {\n const form = formWrapperRef.current?.querySelector('form')\n if (form) form.requestSubmit()\n }, [])\n\n // Loading / error states\n if (isLoading) {\n return (\n <Page>\n <PageBody>\n <LoadingMessage label={t('customers.companies.detail.loading', 'Loading company\u2026')} />\n </PageBody>\n </Page>\n )\n }\n\n if (isNotFound) {\n return (\n <Page>\n <PageBody>\n <RecordNotFoundState\n label={t('customers.companies.detail.error.notFound', 'Company not found.')}\n backHref=\"/backend/customers/companies\"\n backLabel={t('customers.companies.detail.actions.backToList', 'Back to companies')}\n />\n </PageBody>\n </Page>\n )\n }\n\n if (error || !data?.company?.id) {\n return (\n <Page>\n <PageBody>\n <ErrorMessage\n label={error ?? t('customers.companies.detail.error.load', 'Failed to load company.')}\n action={(\n <Button asChild variant=\"outline\">\n <Link href=\"/backend/customers/companies\">\n {t('customers.companies.detail.actions.backToList', 'Back to companies')}\n </Link>\n </Button>\n )}\n />\n </PageBody>\n </Page>\n )\n }\n\n const companyId = data.company.id\n const useCanonicalInteractions = data.interactionMode === 'canonical'\n\n return (\n <Page>\n <PageBody>\n <div className=\"space-y-4\">\n {/* UMES header injection */}\n <InjectionSpot spotId=\"detail:customers.company:header\" context={injectionContext} data={data} />\n <InjectionSpot spotId=\"detail:customers.company:status-badges\" context={injectionContext} data={data} />\n\n {/* Persistent company header */}\n <CompanyDetailHeader\n data={data}\n onTagsChange={handleTagsChange}\n tagsSectionControllerRef={tagsSectionControllerRef}\n onSave={handleHeaderSave}\n onDelete={handleDelete}\n isDirty={isDirty}\n isSaving={isSaving}\n onDataReload={() => { loadData().catch((err) => console.warn('[companies-v2] onDataReload failed', err)) }}\n />\n\n {/* KPI bar \u2014 always visible above zones */}\n <CompanyKpiBar data={data} />\n\n {/* Two-zone layout: zone1 = form, zone2 = tabs */}\n <CollapsibleZoneLayout\n pageType=\"company-v2\"\n entityName={companyName}\n isDirty={isDirty}\n sections={zoneSections}\n zone1={\n <div ref={formWrapperRef}>\n <CrudForm<CompanyEditFormValues>\n embedded\n trackDirtyWhenEmbedded\n injectionSpotId=\"crud-form:customers.company\"\n entityIds={[E.customers.customer_entity, E.customers.customer_company_profile]}\n schema={formSchema}\n fields={formFields}\n groups={formGroups}\n initialValues={initialValues}\n onSubmit={handleFormSubmit}\n onDelete={handleDelete}\n optimisticLockUpdatedAt={(data?.company as { updatedAt?: string } | undefined)?.updatedAt}\n hideFooterActions\n collapsibleGroups={{ pageType: 'company-v2', chevronPosition: 'right' }}\n sortableGroups={{ pageType: 'company-v2' }}\n onDirtyChange={setIsDirty}\n />\n </div>\n }\n zone2={\n <CompanyDetailTabs\n activeTab={activeTab}\n onTabChange={setActiveTab}\n injectedTabs={injectedTabs.map((tab) => ({ id: tab.id, label: tab.label }))}\n peopleCount={data.counts?.people ?? 0}\n dealsCount={dealCount}\n activitiesCount={data.counts?.activities ?? 0}\n sectionAction={sectionAction}\n >\n {activeTab === 'people' && (\n <CompanyPeopleSection\n companyId={companyId}\n companyName={companyDisplayName}\n initialPeople={[]}\n addActionLabel={t('customers.companies.detail.people.add', 'Add person')}\n emptyLabel={t('customers.companies.detail.people.empty', 'No people linked to this company yet.')}\n emptyState={{\n title: t('customers.companies.detail.emptyState.people.title', 'Build the account team'),\n actionLabel: t('customers.companies.detail.emptyState.people.action', 'Create person'),\n }}\n onActionChange={handleSectionActionChange}\n translator={detailTranslator}\n runGuardedMutation={runMutationWithContext}\n onPeopleChange={(next) => {\n setData((prev) => {\n if (!prev) return prev\n const nextCount = next.length\n return {\n ...prev,\n people: next,\n counts: prev.counts ? { ...prev.counts, people: nextCount } : prev.counts,\n }\n })\n }}\n />\n )}\n\n {activeTab === 'deals' && (\n <DealsSection\n scope={dealsScope}\n emptyLabel={t('customers.companies.detail.empty.deals', 'No deals linked to this company.')}\n addActionLabel={t('customers.companies.detail.actions.addDeal', 'Add deal')}\n emptyState={{\n title: t('customers.companies.detail.emptyState.deals.title', 'No deals yet'),\n actionLabel: t('customers.companies.detail.emptyState.deals.action', 'Create a deal'),\n }}\n onActionChange={handleSectionActionChange}\n translator={detailTranslator}\n runGuardedMutation={runMutationWithContext}\n onCountDelta={(delta) => setDealCount((current) => Math.max(0, current + delta))}\n />\n )}\n\n {activeTab === 'activity-log' && (\n <ActivityLogTab\n entityId={companyId}\n plannedActivities={plannedActivities}\n onActivityCreated={handleActivityCreated}\n onScheduleRequested={openNewScheduleDialog}\n onAddActivity={handleAddActivity}\n onMarkDone={handleMarkDone}\n onEditActivity={handleEditActivity}\n onCancelActivity={handleCancelActivity}\n runGuardedMutation={runMutationWithContext}\n refreshKey={activityRefreshKey}\n useCanonicalInteractions={useCanonicalInteractions}\n />\n )}\n\n {activeTab === 'changelog' && companyId && (\n <ChangelogTab entityId={companyId} entityType=\"company\" />\n )}\n\n {activeTab === 'files' && (\n <AttachmentsSection\n entityId={E.customers.customer_entity}\n recordId={companyId}\n title={t('customers.companies.detail.tabs.files', 'Files')}\n description={t('customers.companies.detail.files.subtitle', 'Upload and manage files linked to this company.')}\n />\n )}\n\n {/* Injected tabs from UMES */}\n {injectedTabMap.has(activeTab) && injectedTabMap.get(activeTab)!()}\n </CompanyDetailTabs>\n }\n />\n\n {/* UMES footer injection */}\n <InjectionSpot spotId=\"detail:customers.company:footer\" context={injectionContext} data={data} />\n\n {/* Schedule Activity Dialog */}\n <ScheduleActivityDialog\n open={scheduleDialogOpen}\n onClose={() => { setScheduleDialogOpen(false); setScheduleEditData(null) }}\n entityId={companyId}\n entityName={companyName}\n entityType=\"company\"\n onActivityCreated={handleActivityCreated}\n editData={scheduleEditData}\n />\n {ConfirmDialogElement}\n </div>\n </PageBody>\n </Page>\n )\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["companyId"]
7
7
  }
@@ -1,7 +1,9 @@
1
1
  import * as React from "react";
2
2
  import { flash } from "@open-mercato/ui/backend/FlashMessages";
3
+ import { surfaceRecordConflict } from "@open-mercato/ui/backend/conflicts";
3
4
  import { updateCrud } from "@open-mercato/ui/backend/utils/crud";
4
- import { readApiResultOrThrow } from "@open-mercato/ui/backend/utils/apiCall";
5
+ import { readApiResultOrThrow, withScopedApiRequestHeaders } from "@open-mercato/ui/backend/utils/apiCall";
6
+ import { buildOptimisticLockHeader } from "@open-mercato/ui/backend/utils/optimisticLock";
5
7
  import { useT } from "@open-mercato/shared/lib/i18n/context";
6
8
  function normalizePersonAssociationRecord(record, fallbackId) {
7
9
  const displayName = typeof record.displayName === "string" && record.displayName.trim().length ? record.displayName.trim() : typeof record.display_name === "string" && record.display_name.trim().length ? record.display_name.trim() : null;
@@ -36,7 +38,8 @@ function useDealAssociations({
36
38
  currentDealId,
37
39
  data,
38
40
  setData,
39
- runMutationWithContext
41
+ runMutationWithContext,
42
+ onRefresh
40
43
  }) {
41
44
  const t = useT();
42
45
  const [peopleEditorIds, setPeopleEditorIds] = React.useState([]);
@@ -169,7 +172,10 @@ function useDealAssociations({
169
172
  setPeopleSaving(true);
170
173
  try {
171
174
  await runMutationWithContext(
172
- () => updateCrud("customers/deals", { id: currentDealId, personIds: nextIds }),
175
+ () => withScopedApiRequestHeaders(
176
+ buildOptimisticLockHeader(data?.deal.updatedAt),
177
+ () => updateCrud("customers/deals", { id: currentDealId, personIds: nextIds })
178
+ ),
173
179
  { id: currentDealId, personIds: nextIds, operation: "updateDealPeople" }
174
180
  );
175
181
  const nextPeople = await loadPeopleAssociations(nextIds.slice(0, 3));
@@ -181,7 +187,7 @@ function useDealAssociations({
181
187
  counts: { ...prev.counts, people: nextIds.length }
182
188
  } : prev
183
189
  );
184
- } catch {
190
+ } catch (error) {
185
191
  setPeopleEditorIds(previousIds);
186
192
  setData(
187
193
  (prev) => prev ? {
@@ -191,12 +197,14 @@ function useDealAssociations({
191
197
  counts: { ...prev.counts, people: previousIds.length }
192
198
  } : prev
193
199
  );
194
- flash(t("customers.deals.detail.peopleUpdateError", "Failed to update linked people."), "error");
200
+ if (!surfaceRecordConflict(error, t, { onRefresh: onRefresh ?? null })) {
201
+ flash(t("customers.deals.detail.peopleUpdateError", "Failed to update linked people."), "error");
202
+ }
195
203
  } finally {
196
204
  setPeopleSaving(false);
197
205
  }
198
206
  },
199
- [currentDealId, data?.people, loadPeopleAssociations, peopleEditorIds, runMutationWithContext, setData, t]
207
+ [currentDealId, data?.deal.updatedAt, data?.people, loadPeopleAssociations, onRefresh, peopleEditorIds, runMutationWithContext, setData, t]
200
208
  );
201
209
  const handleCompaniesAssociationsChange = React.useCallback(
202
210
  async (nextIds) => {
@@ -208,7 +216,10 @@ function useDealAssociations({
208
216
  setCompaniesSaving(true);
209
217
  try {
210
218
  await runMutationWithContext(
211
- () => updateCrud("customers/deals", { id: currentDealId, companyIds: nextIds }),
219
+ () => withScopedApiRequestHeaders(
220
+ buildOptimisticLockHeader(data?.deal.updatedAt),
221
+ () => updateCrud("customers/deals", { id: currentDealId, companyIds: nextIds })
222
+ ),
212
223
  { id: currentDealId, companyIds: nextIds, operation: "updateDealCompanies" }
213
224
  );
214
225
  const nextCompanies = await loadCompanyAssociations(nextIds.slice(0, 3));
@@ -220,7 +231,7 @@ function useDealAssociations({
220
231
  counts: { ...prev.counts, companies: nextIds.length }
221
232
  } : prev
222
233
  );
223
- } catch {
234
+ } catch (error) {
224
235
  setCompaniesEditorIds(previousIds);
225
236
  setData(
226
237
  (prev) => prev ? {
@@ -230,7 +241,9 @@ function useDealAssociations({
230
241
  counts: { ...prev.counts, companies: previousIds.length }
231
242
  } : prev
232
243
  );
233
- flash(t("customers.deals.detail.companiesUpdateError", "Failed to update linked companies."), "error");
244
+ if (!surfaceRecordConflict(error, t, { onRefresh: onRefresh ?? null })) {
245
+ flash(t("customers.deals.detail.companiesUpdateError", "Failed to update linked companies."), "error");
246
+ }
234
247
  } finally {
235
248
  setCompaniesSaving(false);
236
249
  }
@@ -239,7 +252,9 @@ function useDealAssociations({
239
252
  companiesEditorIds,
240
253
  currentDealId,
241
254
  data?.companies,
255
+ data?.deal.updatedAt,
242
256
  loadCompanyAssociations,
257
+ onRefresh,
243
258
  runMutationWithContext,
244
259
  setData,
245
260
  t
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../../../src/modules/customers/backend/customers/deals/%5Bid%5D/hooks/useDealAssociations.ts"],
4
- "sourcesContent": ["import * as React from 'react'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { updateCrud } from '@open-mercato/ui/backend/utils/crud'\nimport { readApiResultOrThrow } from '@open-mercato/ui/backend/utils/apiCall'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport type {\n CompanyAssociationApiRecord,\n DealAssociation,\n DealDetailPayload,\n GuardedMutationRunner,\n PersonAssociationApiRecord,\n} from './types'\n\nexport function normalizePersonAssociationRecord(\n record: PersonAssociationApiRecord,\n fallbackId: string,\n): DealAssociation {\n const displayName =\n typeof record.displayName === 'string' && record.displayName.trim().length\n ? record.displayName.trim()\n : typeof record.display_name === 'string' && record.display_name.trim().length\n ? record.display_name.trim()\n : null\n const email =\n typeof record.primaryEmail === 'string' && record.primaryEmail.trim().length\n ? record.primaryEmail.trim()\n : typeof record.primary_email === 'string' && record.primary_email.trim().length\n ? record.primary_email.trim()\n : null\n const phone =\n typeof record.primaryPhone === 'string' && record.primaryPhone.trim().length\n ? record.primaryPhone.trim()\n : typeof record.primary_phone === 'string' && record.primary_phone.trim().length\n ? record.primary_phone.trim()\n : null\n const profile = record.personProfile ?? record.person_profile ?? null\n const jobTitle =\n profile && typeof profile.jobTitle === 'string' && profile.jobTitle.trim().length\n ? profile.jobTitle.trim()\n : null\n return {\n id: typeof record.id === 'string' ? record.id : fallbackId,\n label: displayName ?? email ?? phone ?? fallbackId,\n subtitle: jobTitle ?? email ?? phone ?? null,\n kind: 'person',\n }\n}\n\nexport function normalizeCompanyAssociationRecord(\n record: CompanyAssociationApiRecord,\n fallbackId: string,\n): DealAssociation {\n const displayName =\n typeof record.displayName === 'string' && record.displayName.trim().length\n ? record.displayName.trim()\n : typeof record.display_name === 'string' && record.display_name.trim().length\n ? record.display_name.trim()\n : null\n const profile = record.companyProfile ?? record.company_profile ?? null\n const domain =\n typeof record.domain === 'string' && record.domain.trim().length\n ? record.domain.trim()\n : profile && typeof profile.domain === 'string' && profile.domain.trim().length\n ? profile.domain.trim()\n : null\n const website =\n typeof record.websiteUrl === 'string' && record.websiteUrl.trim().length\n ? record.websiteUrl.trim()\n : typeof record.website_url === 'string' && record.website_url.trim().length\n ? record.website_url.trim()\n : profile && typeof profile.websiteUrl === 'string' && profile.websiteUrl.trim().length\n ? profile.websiteUrl.trim()\n : null\n return {\n id: typeof record.id === 'string' ? record.id : fallbackId,\n label: displayName ?? domain ?? website ?? fallbackId,\n subtitle: domain ?? website ?? null,\n kind: 'company',\n }\n}\n\nfunction sameIdList(left: string[], right: string[]): boolean {\n if (left.length !== right.length) return false\n return left.every((value, index) => value === right[index])\n}\n\ntype LinkedPageResult = {\n items: DealAssociation[]\n totalPages: number\n total: number\n}\n\ntype UseDealAssociationsOptions = {\n currentDealId: string | null\n data: DealDetailPayload | null\n setData: React.Dispatch<React.SetStateAction<DealDetailPayload | null>>\n runMutationWithContext: GuardedMutationRunner\n}\n\ntype UseDealAssociationsResult = {\n peopleEditorIds: string[]\n companiesEditorIds: string[]\n peopleSaving: boolean\n companiesSaving: boolean\n handlePeopleAssociationsChange: (nextIds: string[]) => Promise<void>\n handleCompaniesAssociationsChange: (nextIds: string[]) => Promise<void>\n loadLinkedPeoplePage: (page: number, query: string) => Promise<LinkedPageResult>\n loadLinkedCompaniesPage: (page: number, query: string) => Promise<LinkedPageResult>\n}\n\nexport function useDealAssociations({\n currentDealId,\n data,\n setData,\n runMutationWithContext,\n}: UseDealAssociationsOptions): UseDealAssociationsResult {\n const t = useT()\n const [peopleEditorIds, setPeopleEditorIds] = React.useState<string[]>([])\n const [companiesEditorIds, setCompaniesEditorIds] = React.useState<string[]>([])\n const [peopleSaving, setPeopleSaving] = React.useState(false)\n const [companiesSaving, setCompaniesSaving] = React.useState(false)\n\n React.useEffect(() => {\n setPeopleEditorIds(data?.linkedPersonIds ?? [])\n setCompaniesEditorIds(data?.linkedCompanyIds ?? [])\n }, [data?.linkedCompanyIds, data?.linkedPersonIds])\n\n const loadPeopleAssociations = React.useCallback(async (ids: string[]): Promise<DealAssociation[]> => {\n const uniqueIds = Array.from(new Set(ids.map((value) => value.trim()).filter(Boolean)))\n if (!uniqueIds.length) return []\n try {\n const params = new URLSearchParams({\n ids: uniqueIds.join(','),\n pageSize: String(Math.max(uniqueIds.length, 1)),\n })\n const payload = await readApiResultOrThrow<{ items?: PersonAssociationApiRecord[] }>(\n `/api/customers/people?${params.toString()}`,\n )\n const items = Array.isArray(payload.items) ? payload.items : []\n const byId = new Map<string, PersonAssociationApiRecord>()\n items.forEach((record) => {\n if (record && typeof record.id === 'string') byId.set(record.id, record)\n })\n return uniqueIds.map((personId) => {\n const record = byId.get(personId)\n return record\n ? normalizePersonAssociationRecord(record, personId)\n : {\n id: personId,\n label: personId,\n subtitle: null,\n kind: 'person' as const,\n }\n })\n } catch {\n return uniqueIds.map((personId) => ({\n id: personId,\n label: personId,\n subtitle: null,\n kind: 'person' as const,\n }))\n }\n }, [])\n\n const loadCompanyAssociations = React.useCallback(async (ids: string[]): Promise<DealAssociation[]> => {\n const uniqueIds = Array.from(new Set(ids.map((value) => value.trim()).filter(Boolean)))\n if (!uniqueIds.length) return []\n try {\n const params = new URLSearchParams({\n ids: uniqueIds.join(','),\n pageSize: String(Math.max(uniqueIds.length, 1)),\n })\n const payload = await readApiResultOrThrow<{ items?: CompanyAssociationApiRecord[] }>(\n `/api/customers/companies?${params.toString()}`,\n )\n const items = Array.isArray(payload.items) ? payload.items : []\n const byId = new Map<string, CompanyAssociationApiRecord>()\n items.forEach((record) => {\n if (record && typeof record.id === 'string') byId.set(record.id, record)\n })\n return uniqueIds.map((companyId) => {\n const record = byId.get(companyId)\n return record\n ? normalizeCompanyAssociationRecord(record, companyId)\n : {\n id: companyId,\n label: companyId,\n subtitle: null,\n kind: 'company' as const,\n }\n })\n } catch {\n return uniqueIds.map((companyId) => ({\n id: companyId,\n label: companyId,\n subtitle: null,\n kind: 'company' as const,\n }))\n }\n }, [])\n\n const loadLinkedPeoplePage = React.useCallback(\n async (page: number, query: string): Promise<LinkedPageResult> => {\n if (!currentDealId) {\n return { items: [], totalPages: 1, total: 0 }\n }\n const params = new URLSearchParams({\n page: String(page),\n pageSize: '20',\n sort: 'name-asc',\n })\n if (query.trim().length > 0) {\n params.set('search', query.trim())\n }\n const payload = await readApiResultOrThrow<{\n items?: DealAssociation[]\n total?: number\n totalPages?: number\n }>(`/api/customers/deals/${encodeURIComponent(currentDealId)}/people?${params.toString()}`)\n return {\n items: Array.isArray(payload.items) ? payload.items : [],\n totalPages: typeof payload.totalPages === 'number' ? payload.totalPages : 1,\n total: typeof payload.total === 'number' ? payload.total : 0,\n }\n },\n [currentDealId],\n )\n\n const loadLinkedCompaniesPage = React.useCallback(\n async (page: number, query: string): Promise<LinkedPageResult> => {\n if (!currentDealId) {\n return { items: [], totalPages: 1, total: 0 }\n }\n const params = new URLSearchParams({\n page: String(page),\n pageSize: '20',\n sort: 'name-asc',\n })\n if (query.trim().length > 0) {\n params.set('search', query.trim())\n }\n const payload = await readApiResultOrThrow<{\n items?: DealAssociation[]\n total?: number\n totalPages?: number\n }>(`/api/customers/deals/${encodeURIComponent(currentDealId)}/companies?${params.toString()}`)\n return {\n items: Array.isArray(payload.items) ? payload.items : [],\n totalPages: typeof payload.totalPages === 'number' ? payload.totalPages : 1,\n total: typeof payload.total === 'number' ? payload.total : 0,\n }\n },\n [currentDealId],\n )\n\n const handlePeopleAssociationsChange = React.useCallback(\n async (nextIds: string[]) => {\n if (!currentDealId) return\n if (sameIdList(nextIds, peopleEditorIds)) return\n const previousIds = peopleEditorIds\n const previousPeople = data?.people ?? []\n setPeopleEditorIds(nextIds)\n setPeopleSaving(true)\n try {\n await runMutationWithContext(\n () => updateCrud('customers/deals', { id: currentDealId, personIds: nextIds }),\n { id: currentDealId, personIds: nextIds, operation: 'updateDealPeople' },\n )\n const nextPeople = await loadPeopleAssociations(nextIds.slice(0, 3))\n setData((prev) =>\n prev\n ? {\n ...prev,\n people: nextPeople,\n linkedPersonIds: nextIds,\n counts: { ...prev.counts, people: nextIds.length },\n }\n : prev,\n )\n } catch {\n setPeopleEditorIds(previousIds)\n setData((prev) =>\n prev\n ? {\n ...prev,\n people: previousPeople,\n linkedPersonIds: previousIds,\n counts: { ...prev.counts, people: previousIds.length },\n }\n : prev,\n )\n flash(t('customers.deals.detail.peopleUpdateError', 'Failed to update linked people.'), 'error')\n } finally {\n setPeopleSaving(false)\n }\n },\n [currentDealId, data?.people, loadPeopleAssociations, peopleEditorIds, runMutationWithContext, setData, t],\n )\n\n const handleCompaniesAssociationsChange = React.useCallback(\n async (nextIds: string[]) => {\n if (!currentDealId) return\n if (sameIdList(nextIds, companiesEditorIds)) return\n const previousIds = companiesEditorIds\n const previousCompanies = data?.companies ?? []\n setCompaniesEditorIds(nextIds)\n setCompaniesSaving(true)\n try {\n await runMutationWithContext(\n () => updateCrud('customers/deals', { id: currentDealId, companyIds: nextIds }),\n { id: currentDealId, companyIds: nextIds, operation: 'updateDealCompanies' },\n )\n const nextCompanies = await loadCompanyAssociations(nextIds.slice(0, 3))\n setData((prev) =>\n prev\n ? {\n ...prev,\n companies: nextCompanies,\n linkedCompanyIds: nextIds,\n counts: { ...prev.counts, companies: nextIds.length },\n }\n : prev,\n )\n } catch {\n setCompaniesEditorIds(previousIds)\n setData((prev) =>\n prev\n ? {\n ...prev,\n companies: previousCompanies,\n linkedCompanyIds: previousIds,\n counts: { ...prev.counts, companies: previousIds.length },\n }\n : prev,\n )\n flash(t('customers.deals.detail.companiesUpdateError', 'Failed to update linked companies.'), 'error')\n } finally {\n setCompaniesSaving(false)\n }\n },\n [\n companiesEditorIds,\n currentDealId,\n data?.companies,\n loadCompanyAssociations,\n runMutationWithContext,\n setData,\n t,\n ],\n )\n\n return {\n peopleEditorIds,\n companiesEditorIds,\n peopleSaving,\n companiesSaving,\n handlePeopleAssociationsChange,\n handleCompaniesAssociationsChange,\n loadLinkedPeoplePage,\n loadLinkedCompaniesPage,\n }\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import * as React from 'react'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { surfaceRecordConflict } from '@open-mercato/ui/backend/conflicts'\nimport { updateCrud } from '@open-mercato/ui/backend/utils/crud'\nimport { readApiResultOrThrow, withScopedApiRequestHeaders } from '@open-mercato/ui/backend/utils/apiCall'\nimport { buildOptimisticLockHeader } from '@open-mercato/ui/backend/utils/optimisticLock'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport type {\n CompanyAssociationApiRecord,\n DealAssociation,\n DealDetailPayload,\n GuardedMutationRunner,\n PersonAssociationApiRecord,\n} from './types'\n\nexport function normalizePersonAssociationRecord(\n record: PersonAssociationApiRecord,\n fallbackId: string,\n): DealAssociation {\n const displayName =\n typeof record.displayName === 'string' && record.displayName.trim().length\n ? record.displayName.trim()\n : typeof record.display_name === 'string' && record.display_name.trim().length\n ? record.display_name.trim()\n : null\n const email =\n typeof record.primaryEmail === 'string' && record.primaryEmail.trim().length\n ? record.primaryEmail.trim()\n : typeof record.primary_email === 'string' && record.primary_email.trim().length\n ? record.primary_email.trim()\n : null\n const phone =\n typeof record.primaryPhone === 'string' && record.primaryPhone.trim().length\n ? record.primaryPhone.trim()\n : typeof record.primary_phone === 'string' && record.primary_phone.trim().length\n ? record.primary_phone.trim()\n : null\n const profile = record.personProfile ?? record.person_profile ?? null\n const jobTitle =\n profile && typeof profile.jobTitle === 'string' && profile.jobTitle.trim().length\n ? profile.jobTitle.trim()\n : null\n return {\n id: typeof record.id === 'string' ? record.id : fallbackId,\n label: displayName ?? email ?? phone ?? fallbackId,\n subtitle: jobTitle ?? email ?? phone ?? null,\n kind: 'person',\n }\n}\n\nexport function normalizeCompanyAssociationRecord(\n record: CompanyAssociationApiRecord,\n fallbackId: string,\n): DealAssociation {\n const displayName =\n typeof record.displayName === 'string' && record.displayName.trim().length\n ? record.displayName.trim()\n : typeof record.display_name === 'string' && record.display_name.trim().length\n ? record.display_name.trim()\n : null\n const profile = record.companyProfile ?? record.company_profile ?? null\n const domain =\n typeof record.domain === 'string' && record.domain.trim().length\n ? record.domain.trim()\n : profile && typeof profile.domain === 'string' && profile.domain.trim().length\n ? profile.domain.trim()\n : null\n const website =\n typeof record.websiteUrl === 'string' && record.websiteUrl.trim().length\n ? record.websiteUrl.trim()\n : typeof record.website_url === 'string' && record.website_url.trim().length\n ? record.website_url.trim()\n : profile && typeof profile.websiteUrl === 'string' && profile.websiteUrl.trim().length\n ? profile.websiteUrl.trim()\n : null\n return {\n id: typeof record.id === 'string' ? record.id : fallbackId,\n label: displayName ?? domain ?? website ?? fallbackId,\n subtitle: domain ?? website ?? null,\n kind: 'company',\n }\n}\n\nfunction sameIdList(left: string[], right: string[]): boolean {\n if (left.length !== right.length) return false\n return left.every((value, index) => value === right[index])\n}\n\ntype LinkedPageResult = {\n items: DealAssociation[]\n totalPages: number\n total: number\n}\n\ntype UseDealAssociationsOptions = {\n currentDealId: string | null\n data: DealDetailPayload | null\n setData: React.Dispatch<React.SetStateAction<DealDetailPayload | null>>\n runMutationWithContext: GuardedMutationRunner\n /** Re-fetch the deal detail; wired into the conflict bar's refresh action on a 409. */\n onRefresh?: (() => void) | null\n}\n\ntype UseDealAssociationsResult = {\n peopleEditorIds: string[]\n companiesEditorIds: string[]\n peopleSaving: boolean\n companiesSaving: boolean\n handlePeopleAssociationsChange: (nextIds: string[]) => Promise<void>\n handleCompaniesAssociationsChange: (nextIds: string[]) => Promise<void>\n loadLinkedPeoplePage: (page: number, query: string) => Promise<LinkedPageResult>\n loadLinkedCompaniesPage: (page: number, query: string) => Promise<LinkedPageResult>\n}\n\nexport function useDealAssociations({\n currentDealId,\n data,\n setData,\n runMutationWithContext,\n onRefresh,\n}: UseDealAssociationsOptions): UseDealAssociationsResult {\n const t = useT()\n const [peopleEditorIds, setPeopleEditorIds] = React.useState<string[]>([])\n const [companiesEditorIds, setCompaniesEditorIds] = React.useState<string[]>([])\n const [peopleSaving, setPeopleSaving] = React.useState(false)\n const [companiesSaving, setCompaniesSaving] = React.useState(false)\n\n React.useEffect(() => {\n setPeopleEditorIds(data?.linkedPersonIds ?? [])\n setCompaniesEditorIds(data?.linkedCompanyIds ?? [])\n }, [data?.linkedCompanyIds, data?.linkedPersonIds])\n\n const loadPeopleAssociations = React.useCallback(async (ids: string[]): Promise<DealAssociation[]> => {\n const uniqueIds = Array.from(new Set(ids.map((value) => value.trim()).filter(Boolean)))\n if (!uniqueIds.length) return []\n try {\n const params = new URLSearchParams({\n ids: uniqueIds.join(','),\n pageSize: String(Math.max(uniqueIds.length, 1)),\n })\n const payload = await readApiResultOrThrow<{ items?: PersonAssociationApiRecord[] }>(\n `/api/customers/people?${params.toString()}`,\n )\n const items = Array.isArray(payload.items) ? payload.items : []\n const byId = new Map<string, PersonAssociationApiRecord>()\n items.forEach((record) => {\n if (record && typeof record.id === 'string') byId.set(record.id, record)\n })\n return uniqueIds.map((personId) => {\n const record = byId.get(personId)\n return record\n ? normalizePersonAssociationRecord(record, personId)\n : {\n id: personId,\n label: personId,\n subtitle: null,\n kind: 'person' as const,\n }\n })\n } catch {\n return uniqueIds.map((personId) => ({\n id: personId,\n label: personId,\n subtitle: null,\n kind: 'person' as const,\n }))\n }\n }, [])\n\n const loadCompanyAssociations = React.useCallback(async (ids: string[]): Promise<DealAssociation[]> => {\n const uniqueIds = Array.from(new Set(ids.map((value) => value.trim()).filter(Boolean)))\n if (!uniqueIds.length) return []\n try {\n const params = new URLSearchParams({\n ids: uniqueIds.join(','),\n pageSize: String(Math.max(uniqueIds.length, 1)),\n })\n const payload = await readApiResultOrThrow<{ items?: CompanyAssociationApiRecord[] }>(\n `/api/customers/companies?${params.toString()}`,\n )\n const items = Array.isArray(payload.items) ? payload.items : []\n const byId = new Map<string, CompanyAssociationApiRecord>()\n items.forEach((record) => {\n if (record && typeof record.id === 'string') byId.set(record.id, record)\n })\n return uniqueIds.map((companyId) => {\n const record = byId.get(companyId)\n return record\n ? normalizeCompanyAssociationRecord(record, companyId)\n : {\n id: companyId,\n label: companyId,\n subtitle: null,\n kind: 'company' as const,\n }\n })\n } catch {\n return uniqueIds.map((companyId) => ({\n id: companyId,\n label: companyId,\n subtitle: null,\n kind: 'company' as const,\n }))\n }\n }, [])\n\n const loadLinkedPeoplePage = React.useCallback(\n async (page: number, query: string): Promise<LinkedPageResult> => {\n if (!currentDealId) {\n return { items: [], totalPages: 1, total: 0 }\n }\n const params = new URLSearchParams({\n page: String(page),\n pageSize: '20',\n sort: 'name-asc',\n })\n if (query.trim().length > 0) {\n params.set('search', query.trim())\n }\n const payload = await readApiResultOrThrow<{\n items?: DealAssociation[]\n total?: number\n totalPages?: number\n }>(`/api/customers/deals/${encodeURIComponent(currentDealId)}/people?${params.toString()}`)\n return {\n items: Array.isArray(payload.items) ? payload.items : [],\n totalPages: typeof payload.totalPages === 'number' ? payload.totalPages : 1,\n total: typeof payload.total === 'number' ? payload.total : 0,\n }\n },\n [currentDealId],\n )\n\n const loadLinkedCompaniesPage = React.useCallback(\n async (page: number, query: string): Promise<LinkedPageResult> => {\n if (!currentDealId) {\n return { items: [], totalPages: 1, total: 0 }\n }\n const params = new URLSearchParams({\n page: String(page),\n pageSize: '20',\n sort: 'name-asc',\n })\n if (query.trim().length > 0) {\n params.set('search', query.trim())\n }\n const payload = await readApiResultOrThrow<{\n items?: DealAssociation[]\n total?: number\n totalPages?: number\n }>(`/api/customers/deals/${encodeURIComponent(currentDealId)}/companies?${params.toString()}`)\n return {\n items: Array.isArray(payload.items) ? payload.items : [],\n totalPages: typeof payload.totalPages === 'number' ? payload.totalPages : 1,\n total: typeof payload.total === 'number' ? payload.total : 0,\n }\n },\n [currentDealId],\n )\n\n const handlePeopleAssociationsChange = React.useCallback(\n async (nextIds: string[]) => {\n if (!currentDealId) return\n if (sameIdList(nextIds, peopleEditorIds)) return\n const previousIds = peopleEditorIds\n const previousPeople = data?.people ?? []\n setPeopleEditorIds(nextIds)\n setPeopleSaving(true)\n try {\n await runMutationWithContext(\n () => withScopedApiRequestHeaders(\n buildOptimisticLockHeader(data?.deal.updatedAt),\n () => updateCrud('customers/deals', { id: currentDealId, personIds: nextIds }),\n ),\n { id: currentDealId, personIds: nextIds, operation: 'updateDealPeople' },\n )\n const nextPeople = await loadPeopleAssociations(nextIds.slice(0, 3))\n setData((prev) =>\n prev\n ? {\n ...prev,\n people: nextPeople,\n linkedPersonIds: nextIds,\n counts: { ...prev.counts, people: nextIds.length },\n }\n : prev,\n )\n } catch (error) {\n setPeopleEditorIds(previousIds)\n setData((prev) =>\n prev\n ? {\n ...prev,\n people: previousPeople,\n linkedPersonIds: previousIds,\n counts: { ...prev.counts, people: previousIds.length },\n }\n : prev,\n )\n // runMutationWithContext already surfaces the conflict bar on a 409; only\n // fall back to the generic flash when this is not a record conflict.\n if (!surfaceRecordConflict(error, t, { onRefresh: onRefresh ?? null })) {\n flash(t('customers.deals.detail.peopleUpdateError', 'Failed to update linked people.'), 'error')\n }\n } finally {\n setPeopleSaving(false)\n }\n },\n [currentDealId, data?.deal.updatedAt, data?.people, loadPeopleAssociations, onRefresh, peopleEditorIds, runMutationWithContext, setData, t],\n )\n\n const handleCompaniesAssociationsChange = React.useCallback(\n async (nextIds: string[]) => {\n if (!currentDealId) return\n if (sameIdList(nextIds, companiesEditorIds)) return\n const previousIds = companiesEditorIds\n const previousCompanies = data?.companies ?? []\n setCompaniesEditorIds(nextIds)\n setCompaniesSaving(true)\n try {\n await runMutationWithContext(\n () => withScopedApiRequestHeaders(\n buildOptimisticLockHeader(data?.deal.updatedAt),\n () => updateCrud('customers/deals', { id: currentDealId, companyIds: nextIds }),\n ),\n { id: currentDealId, companyIds: nextIds, operation: 'updateDealCompanies' },\n )\n const nextCompanies = await loadCompanyAssociations(nextIds.slice(0, 3))\n setData((prev) =>\n prev\n ? {\n ...prev,\n companies: nextCompanies,\n linkedCompanyIds: nextIds,\n counts: { ...prev.counts, companies: nextIds.length },\n }\n : prev,\n )\n } catch (error) {\n setCompaniesEditorIds(previousIds)\n setData((prev) =>\n prev\n ? {\n ...prev,\n companies: previousCompanies,\n linkedCompanyIds: previousIds,\n counts: { ...prev.counts, companies: previousIds.length },\n }\n : prev,\n )\n // runMutationWithContext already surfaces the conflict bar on a 409; only\n // fall back to the generic flash when this is not a record conflict.\n if (!surfaceRecordConflict(error, t, { onRefresh: onRefresh ?? null })) {\n flash(t('customers.deals.detail.companiesUpdateError', 'Failed to update linked companies.'), 'error')\n }\n } finally {\n setCompaniesSaving(false)\n }\n },\n [\n companiesEditorIds,\n currentDealId,\n data?.companies,\n data?.deal.updatedAt,\n loadCompanyAssociations,\n onRefresh,\n runMutationWithContext,\n setData,\n t,\n ],\n )\n\n return {\n peopleEditorIds,\n companiesEditorIds,\n peopleSaving,\n companiesSaving,\n handlePeopleAssociationsChange,\n handleCompaniesAssociationsChange,\n loadLinkedPeoplePage,\n loadLinkedCompaniesPage,\n }\n}\n"],
5
+ "mappings": "AAAA,YAAY,WAAW;AACvB,SAAS,aAAa;AACtB,SAAS,6BAA6B;AACtC,SAAS,kBAAkB;AAC3B,SAAS,sBAAsB,mCAAmC;AAClE,SAAS,iCAAiC;AAC1C,SAAS,YAAY;AASd,SAAS,iCACd,QACA,YACiB;AACjB,QAAM,cACJ,OAAO,OAAO,gBAAgB,YAAY,OAAO,YAAY,KAAK,EAAE,SAChE,OAAO,YAAY,KAAK,IACxB,OAAO,OAAO,iBAAiB,YAAY,OAAO,aAAa,KAAK,EAAE,SACpE,OAAO,aAAa,KAAK,IACzB;AACR,QAAM,QACJ,OAAO,OAAO,iBAAiB,YAAY,OAAO,aAAa,KAAK,EAAE,SAClE,OAAO,aAAa,KAAK,IACzB,OAAO,OAAO,kBAAkB,YAAY,OAAO,cAAc,KAAK,EAAE,SACtE,OAAO,cAAc,KAAK,IAC1B;AACR,QAAM,QACJ,OAAO,OAAO,iBAAiB,YAAY,OAAO,aAAa,KAAK,EAAE,SAClE,OAAO,aAAa,KAAK,IACzB,OAAO,OAAO,kBAAkB,YAAY,OAAO,cAAc,KAAK,EAAE,SACtE,OAAO,cAAc,KAAK,IAC1B;AACR,QAAM,UAAU,OAAO,iBAAiB,OAAO,kBAAkB;AACjE,QAAM,WACJ,WAAW,OAAO,QAAQ,aAAa,YAAY,QAAQ,SAAS,KAAK,EAAE,SACvE,QAAQ,SAAS,KAAK,IACtB;AACN,SAAO;AAAA,IACL,IAAI,OAAO,OAAO,OAAO,WAAW,OAAO,KAAK;AAAA,IAChD,OAAO,eAAe,SAAS,SAAS;AAAA,IACxC,UAAU,YAAY,SAAS,SAAS;AAAA,IACxC,MAAM;AAAA,EACR;AACF;AAEO,SAAS,kCACd,QACA,YACiB;AACjB,QAAM,cACJ,OAAO,OAAO,gBAAgB,YAAY,OAAO,YAAY,KAAK,EAAE,SAChE,OAAO,YAAY,KAAK,IACxB,OAAO,OAAO,iBAAiB,YAAY,OAAO,aAAa,KAAK,EAAE,SACpE,OAAO,aAAa,KAAK,IACzB;AACR,QAAM,UAAU,OAAO,kBAAkB,OAAO,mBAAmB;AACnE,QAAM,SACJ,OAAO,OAAO,WAAW,YAAY,OAAO,OAAO,KAAK,EAAE,SACtD,OAAO,OAAO,KAAK,IACnB,WAAW,OAAO,QAAQ,WAAW,YAAY,QAAQ,OAAO,KAAK,EAAE,SACrE,QAAQ,OAAO,KAAK,IACpB;AACR,QAAM,UACJ,OAAO,OAAO,eAAe,YAAY,OAAO,WAAW,KAAK,EAAE,SAC9D,OAAO,WAAW,KAAK,IACvB,OAAO,OAAO,gBAAgB,YAAY,OAAO,YAAY,KAAK,EAAE,SAClE,OAAO,YAAY,KAAK,IACxB,WAAW,OAAO,QAAQ,eAAe,YAAY,QAAQ,WAAW,KAAK,EAAE,SAC7E,QAAQ,WAAW,KAAK,IACxB;AACV,SAAO;AAAA,IACL,IAAI,OAAO,OAAO,OAAO,WAAW,OAAO,KAAK;AAAA,IAChD,OAAO,eAAe,UAAU,WAAW;AAAA,IAC3C,UAAU,UAAU,WAAW;AAAA,IAC/B,MAAM;AAAA,EACR;AACF;AAEA,SAAS,WAAW,MAAgB,OAA0B;AAC5D,MAAI,KAAK,WAAW,MAAM,OAAQ,QAAO;AACzC,SAAO,KAAK,MAAM,CAAC,OAAO,UAAU,UAAU,MAAM,KAAK,CAAC;AAC5D;AA4BO,SAAS,oBAAoB;AAAA,EAClC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAA0D;AACxD,QAAM,IAAI,KAAK;AACf,QAAM,CAAC,iBAAiB,kBAAkB,IAAI,MAAM,SAAmB,CAAC,CAAC;AACzE,QAAM,CAAC,oBAAoB,qBAAqB,IAAI,MAAM,SAAmB,CAAC,CAAC;AAC/E,QAAM,CAAC,cAAc,eAAe,IAAI,MAAM,SAAS,KAAK;AAC5D,QAAM,CAAC,iBAAiB,kBAAkB,IAAI,MAAM,SAAS,KAAK;AAElE,QAAM,UAAU,MAAM;AACpB,uBAAmB,MAAM,mBAAmB,CAAC,CAAC;AAC9C,0BAAsB,MAAM,oBAAoB,CAAC,CAAC;AAAA,EACpD,GAAG,CAAC,MAAM,kBAAkB,MAAM,eAAe,CAAC;AAElD,QAAM,yBAAyB,MAAM,YAAY,OAAO,QAA8C;AACpG,UAAM,YAAY,MAAM,KAAK,IAAI,IAAI,IAAI,IAAI,CAAC,UAAU,MAAM,KAAK,CAAC,EAAE,OAAO,OAAO,CAAC,CAAC;AACtF,QAAI,CAAC,UAAU,OAAQ,QAAO,CAAC;AAC/B,QAAI;AACF,YAAM,SAAS,IAAI,gBAAgB;AAAA,QACjC,KAAK,UAAU,KAAK,GAAG;AAAA,QACvB,UAAU,OAAO,KAAK,IAAI,UAAU,QAAQ,CAAC,CAAC;AAAA,MAChD,CAAC;AACD,YAAM,UAAU,MAAM;AAAA,QACpB,yBAAyB,OAAO,SAAS,CAAC;AAAA,MAC5C;AACA,YAAM,QAAQ,MAAM,QAAQ,QAAQ,KAAK,IAAI,QAAQ,QAAQ,CAAC;AAC9D,YAAM,OAAO,oBAAI,IAAwC;AACzD,YAAM,QAAQ,CAAC,WAAW;AACxB,YAAI,UAAU,OAAO,OAAO,OAAO,SAAU,MAAK,IAAI,OAAO,IAAI,MAAM;AAAA,MACzE,CAAC;AACD,aAAO,UAAU,IAAI,CAAC,aAAa;AACjC,cAAM,SAAS,KAAK,IAAI,QAAQ;AAChC,eAAO,SACH,iCAAiC,QAAQ,QAAQ,IACjD;AAAA,UACE,IAAI;AAAA,UACJ,OAAO;AAAA,UACP,UAAU;AAAA,UACV,MAAM;AAAA,QACR;AAAA,MACN,CAAC;AAAA,IACH,QAAQ;AACN,aAAO,UAAU,IAAI,CAAC,cAAc;AAAA,QAClC,IAAI;AAAA,QACJ,OAAO;AAAA,QACP,UAAU;AAAA,QACV,MAAM;AAAA,MACR,EAAE;AAAA,IACJ;AAAA,EACF,GAAG,CAAC,CAAC;AAEL,QAAM,0BAA0B,MAAM,YAAY,OAAO,QAA8C;AACrG,UAAM,YAAY,MAAM,KAAK,IAAI,IAAI,IAAI,IAAI,CAAC,UAAU,MAAM,KAAK,CAAC,EAAE,OAAO,OAAO,CAAC,CAAC;AACtF,QAAI,CAAC,UAAU,OAAQ,QAAO,CAAC;AAC/B,QAAI;AACF,YAAM,SAAS,IAAI,gBAAgB;AAAA,QACjC,KAAK,UAAU,KAAK,GAAG;AAAA,QACvB,UAAU,OAAO,KAAK,IAAI,UAAU,QAAQ,CAAC,CAAC;AAAA,MAChD,CAAC;AACD,YAAM,UAAU,MAAM;AAAA,QACpB,4BAA4B,OAAO,SAAS,CAAC;AAAA,MAC/C;AACA,YAAM,QAAQ,MAAM,QAAQ,QAAQ,KAAK,IAAI,QAAQ,QAAQ,CAAC;AAC9D,YAAM,OAAO,oBAAI,IAAyC;AAC1D,YAAM,QAAQ,CAAC,WAAW;AACxB,YAAI,UAAU,OAAO,OAAO,OAAO,SAAU,MAAK,IAAI,OAAO,IAAI,MAAM;AAAA,MACzE,CAAC;AACD,aAAO,UAAU,IAAI,CAAC,cAAc;AAClC,cAAM,SAAS,KAAK,IAAI,SAAS;AACjC,eAAO,SACH,kCAAkC,QAAQ,SAAS,IACnD;AAAA,UACE,IAAI;AAAA,UACJ,OAAO;AAAA,UACP,UAAU;AAAA,UACV,MAAM;AAAA,QACR;AAAA,MACN,CAAC;AAAA,IACH,QAAQ;AACN,aAAO,UAAU,IAAI,CAAC,eAAe;AAAA,QACnC,IAAI;AAAA,QACJ,OAAO;AAAA,QACP,UAAU;AAAA,QACV,MAAM;AAAA,MACR,EAAE;AAAA,IACJ;AAAA,EACF,GAAG,CAAC,CAAC;AAEL,QAAM,uBAAuB,MAAM;AAAA,IACjC,OAAO,MAAc,UAA6C;AAChE,UAAI,CAAC,eAAe;AAClB,eAAO,EAAE,OAAO,CAAC,GAAG,YAAY,GAAG,OAAO,EAAE;AAAA,MAC9C;AACA,YAAM,SAAS,IAAI,gBAAgB;AAAA,QACjC,MAAM,OAAO,IAAI;AAAA,QACjB,UAAU;AAAA,QACV,MAAM;AAAA,MACR,CAAC;AACD,UAAI,MAAM,KAAK,EAAE,SAAS,GAAG;AAC3B,eAAO,IAAI,UAAU,MAAM,KAAK,CAAC;AAAA,MACnC;AACA,YAAM,UAAU,MAAM,qBAInB,wBAAwB,mBAAmB,aAAa,CAAC,WAAW,OAAO,SAAS,CAAC,EAAE;AAC1F,aAAO;AAAA,QACL,OAAO,MAAM,QAAQ,QAAQ,KAAK,IAAI,QAAQ,QAAQ,CAAC;AAAA,QACvD,YAAY,OAAO,QAAQ,eAAe,WAAW,QAAQ,aAAa;AAAA,QAC1E,OAAO,OAAO,QAAQ,UAAU,WAAW,QAAQ,QAAQ;AAAA,MAC7D;AAAA,IACF;AAAA,IACA,CAAC,aAAa;AAAA,EAChB;AAEA,QAAM,0BAA0B,MAAM;AAAA,IACpC,OAAO,MAAc,UAA6C;AAChE,UAAI,CAAC,eAAe;AAClB,eAAO,EAAE,OAAO,CAAC,GAAG,YAAY,GAAG,OAAO,EAAE;AAAA,MAC9C;AACA,YAAM,SAAS,IAAI,gBAAgB;AAAA,QACjC,MAAM,OAAO,IAAI;AAAA,QACjB,UAAU;AAAA,QACV,MAAM;AAAA,MACR,CAAC;AACD,UAAI,MAAM,KAAK,EAAE,SAAS,GAAG;AAC3B,eAAO,IAAI,UAAU,MAAM,KAAK,CAAC;AAAA,MACnC;AACA,YAAM,UAAU,MAAM,qBAInB,wBAAwB,mBAAmB,aAAa,CAAC,cAAc,OAAO,SAAS,CAAC,EAAE;AAC7F,aAAO;AAAA,QACL,OAAO,MAAM,QAAQ,QAAQ,KAAK,IAAI,QAAQ,QAAQ,CAAC;AAAA,QACvD,YAAY,OAAO,QAAQ,eAAe,WAAW,QAAQ,aAAa;AAAA,QAC1E,OAAO,OAAO,QAAQ,UAAU,WAAW,QAAQ,QAAQ;AAAA,MAC7D;AAAA,IACF;AAAA,IACA,CAAC,aAAa;AAAA,EAChB;AAEA,QAAM,iCAAiC,MAAM;AAAA,IAC3C,OAAO,YAAsB;AAC3B,UAAI,CAAC,cAAe;AACpB,UAAI,WAAW,SAAS,eAAe,EAAG;AAC1C,YAAM,cAAc;AACpB,YAAM,iBAAiB,MAAM,UAAU,CAAC;AACxC,yBAAmB,OAAO;AAC1B,sBAAgB,IAAI;AACpB,UAAI;AACF,cAAM;AAAA,UACJ,MAAM;AAAA,YACJ,0BAA0B,MAAM,KAAK,SAAS;AAAA,YAC9C,MAAM,WAAW,mBAAmB,EAAE,IAAI,eAAe,WAAW,QAAQ,CAAC;AAAA,UAC/E;AAAA,UACA,EAAE,IAAI,eAAe,WAAW,SAAS,WAAW,mBAAmB;AAAA,QACzE;AACA,cAAM,aAAa,MAAM,uBAAuB,QAAQ,MAAM,GAAG,CAAC,CAAC;AACnE;AAAA,UAAQ,CAAC,SACP,OACI;AAAA,YACE,GAAG;AAAA,YACH,QAAQ;AAAA,YACR,iBAAiB;AAAA,YACjB,QAAQ,EAAE,GAAG,KAAK,QAAQ,QAAQ,QAAQ,OAAO;AAAA,UACnD,IACA;AAAA,QACN;AAAA,MACF,SAAS,OAAO;AACd,2BAAmB,WAAW;AAC9B;AAAA,UAAQ,CAAC,SACP,OACI;AAAA,YACE,GAAG;AAAA,YACH,QAAQ;AAAA,YACR,iBAAiB;AAAA,YACjB,QAAQ,EAAE,GAAG,KAAK,QAAQ,QAAQ,YAAY,OAAO;AAAA,UACvD,IACA;AAAA,QACN;AAGA,YAAI,CAAC,sBAAsB,OAAO,GAAG,EAAE,WAAW,aAAa,KAAK,CAAC,GAAG;AACtE,gBAAM,EAAE,4CAA4C,iCAAiC,GAAG,OAAO;AAAA,QACjG;AAAA,MACF,UAAE;AACA,wBAAgB,KAAK;AAAA,MACvB;AAAA,IACF;AAAA,IACA,CAAC,eAAe,MAAM,KAAK,WAAW,MAAM,QAAQ,wBAAwB,WAAW,iBAAiB,wBAAwB,SAAS,CAAC;AAAA,EAC5I;AAEA,QAAM,oCAAoC,MAAM;AAAA,IAC9C,OAAO,YAAsB;AAC3B,UAAI,CAAC,cAAe;AACpB,UAAI,WAAW,SAAS,kBAAkB,EAAG;AAC7C,YAAM,cAAc;AACpB,YAAM,oBAAoB,MAAM,aAAa,CAAC;AAC9C,4BAAsB,OAAO;AAC7B,yBAAmB,IAAI;AACvB,UAAI;AACF,cAAM;AAAA,UACJ,MAAM;AAAA,YACJ,0BAA0B,MAAM,KAAK,SAAS;AAAA,YAC9C,MAAM,WAAW,mBAAmB,EAAE,IAAI,eAAe,YAAY,QAAQ,CAAC;AAAA,UAChF;AAAA,UACA,EAAE,IAAI,eAAe,YAAY,SAAS,WAAW,sBAAsB;AAAA,QAC7E;AACA,cAAM,gBAAgB,MAAM,wBAAwB,QAAQ,MAAM,GAAG,CAAC,CAAC;AACvE;AAAA,UAAQ,CAAC,SACP,OACI;AAAA,YACE,GAAG;AAAA,YACH,WAAW;AAAA,YACX,kBAAkB;AAAA,YAClB,QAAQ,EAAE,GAAG,KAAK,QAAQ,WAAW,QAAQ,OAAO;AAAA,UACtD,IACA;AAAA,QACN;AAAA,MACF,SAAS,OAAO;AACd,8BAAsB,WAAW;AACjC;AAAA,UAAQ,CAAC,SACP,OACI;AAAA,YACE,GAAG;AAAA,YACH,WAAW;AAAA,YACX,kBAAkB;AAAA,YAClB,QAAQ,EAAE,GAAG,KAAK,QAAQ,WAAW,YAAY,OAAO;AAAA,UAC1D,IACA;AAAA,QACN;AAGA,YAAI,CAAC,sBAAsB,OAAO,GAAG,EAAE,WAAW,aAAa,KAAK,CAAC,GAAG;AACtE,gBAAM,EAAE,+CAA+C,oCAAoC,GAAG,OAAO;AAAA,QACvG;AAAA,MACF,UAAE;AACA,2BAAmB,KAAK;AAAA,MAC1B;AAAA,IACF;AAAA,IACA;AAAA,MACE;AAAA,MACA;AAAA,MACA,MAAM;AAAA,MACN,MAAM,KAAK;AAAA,MACX;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;",
6
6
  "names": []
7
7
  }
@@ -1,12 +1,18 @@
1
1
  import * as React from "react";
2
2
  import { updateCrud } from "@open-mercato/ui/backend/utils/crud";
3
- import { readApiResultOrThrow } from "@open-mercato/ui/backend/utils/apiCall";
3
+ import { readApiResultOrThrow, withScopedApiRequestHeaders } from "@open-mercato/ui/backend/utils/apiCall";
4
+ import { buildOptimisticLockHeader } from "@open-mercato/ui/backend/utils/optimisticLock";
5
+ import { surfaceRecordConflict } from "@open-mercato/ui/backend/conflicts";
6
+ import { flash } from "@open-mercato/ui/backend/FlashMessages";
7
+ import { useT } from "@open-mercato/shared/lib/i18n/context";
4
8
  function useDealClosure({
5
9
  currentDealId,
10
+ dealUpdatedAt,
6
11
  runMutationWithContext,
7
12
  confirmDiscardIfDirty,
8
13
  onClosed
9
14
  }) {
15
+ const t = useT();
10
16
  const [lostDialogOpen, setLostDialogOpen] = React.useState(false);
11
17
  const [wonPopupOpen, setWonPopupOpen] = React.useState(false);
12
18
  const [lostPopupOpen, setLostPopupOpen] = React.useState(false);
@@ -26,43 +32,67 @@ function useDealClosure({
26
32
  const handleWon = React.useCallback(async () => {
27
33
  if (!currentDealId) return;
28
34
  if (!await confirmDiscardIfDirty()) return;
29
- await runMutationWithContext(
30
- () => updateCrud("customers/deals", { id: currentDealId, closureOutcome: "won", status: "win" }),
31
- { id: currentDealId, closureOutcome: "won", status: "win", operation: "closeWon" }
32
- );
35
+ try {
36
+ await runMutationWithContext(
37
+ () => withScopedApiRequestHeaders(
38
+ buildOptimisticLockHeader(dealUpdatedAt),
39
+ () => updateCrud("customers/deals", { id: currentDealId, closureOutcome: "won", status: "win" })
40
+ ),
41
+ { id: currentDealId, closureOutcome: "won", status: "win", operation: "closeWon" }
42
+ );
43
+ } catch (err) {
44
+ if (!surfaceRecordConflict(err, t, { onRefresh: () => {
45
+ void onClosed();
46
+ } })) {
47
+ flash(t("customers.deals.detail.closeWonError", "Failed to mark deal as won."), "error");
48
+ }
49
+ return;
50
+ }
33
51
  const stats = await fetchDealStats();
34
52
  setWonStats(stats);
35
53
  setWonPopupOpen(true);
36
54
  await onClosed();
37
- }, [confirmDiscardIfDirty, currentDealId, fetchDealStats, onClosed, runMutationWithContext]);
55
+ }, [confirmDiscardIfDirty, currentDealId, dealUpdatedAt, fetchDealStats, onClosed, runMutationWithContext, t]);
38
56
  const handleLostConfirm = React.useCallback(
39
57
  async (input) => {
40
58
  if (!currentDealId) return;
41
59
  if (!await confirmDiscardIfDirty()) return;
42
- await runMutationWithContext(
43
- () => updateCrud("customers/deals", {
44
- id: currentDealId,
45
- closureOutcome: "lost",
46
- status: "loose",
47
- lossReasonId: input.lossReasonId,
48
- lossNotes: input.lossNotes ?? null
49
- }),
50
- {
51
- id: currentDealId,
52
- closureOutcome: "lost",
53
- status: "loose",
54
- lossReasonId: input.lossReasonId,
55
- lossNotes: input.lossNotes ?? null,
56
- operation: "closeLost"
60
+ try {
61
+ await runMutationWithContext(
62
+ () => withScopedApiRequestHeaders(
63
+ buildOptimisticLockHeader(dealUpdatedAt),
64
+ () => updateCrud("customers/deals", {
65
+ id: currentDealId,
66
+ closureOutcome: "lost",
67
+ status: "loose",
68
+ lossReasonId: input.lossReasonId,
69
+ lossNotes: input.lossNotes ?? null
70
+ })
71
+ ),
72
+ {
73
+ id: currentDealId,
74
+ closureOutcome: "lost",
75
+ status: "loose",
76
+ lossReasonId: input.lossReasonId,
77
+ lossNotes: input.lossNotes ?? null,
78
+ operation: "closeLost"
79
+ }
80
+ );
81
+ } catch (err) {
82
+ if (!surfaceRecordConflict(err, t, { onRefresh: () => {
83
+ void onClosed();
84
+ } })) {
85
+ flash(t("customers.deals.detail.closeLostError", "Failed to mark deal as lost."), "error");
57
86
  }
58
- );
87
+ return;
88
+ }
59
89
  setLostDialogOpen(false);
60
90
  const stats = await fetchDealStats();
61
91
  setLostStats(stats);
62
92
  setLostPopupOpen(true);
63
93
  await onClosed();
64
94
  },
65
- [confirmDiscardIfDirty, currentDealId, fetchDealStats, onClosed, runMutationWithContext]
95
+ [confirmDiscardIfDirty, currentDealId, dealUpdatedAt, fetchDealStats, onClosed, runMutationWithContext, t]
66
96
  );
67
97
  const openLostDialog = React.useCallback(() => setLostDialogOpen(true), []);
68
98
  const closeLostDialog = React.useCallback(() => setLostDialogOpen(false), []);
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../../../src/modules/customers/backend/customers/deals/%5Bid%5D/hooks/useDealClosure.ts"],
4
- "sourcesContent": ["import * as React from 'react'\nimport { updateCrud } from '@open-mercato/ui/backend/utils/crud'\nimport { readApiResultOrThrow } from '@open-mercato/ui/backend/utils/apiCall'\nimport type { DealStatsPayload, GuardedMutationRunner } from './types'\n\ntype UseDealClosureOptions = {\n currentDealId: string | null\n runMutationWithContext: GuardedMutationRunner\n confirmDiscardIfDirty: () => Promise<boolean>\n onClosed: () => Promise<void>\n}\n\ntype UseDealClosureResult = {\n lostDialogOpen: boolean\n wonPopupOpen: boolean\n lostPopupOpen: boolean\n wonStats: DealStatsPayload | null\n lostStats: DealStatsPayload | null\n openLostDialog: () => void\n closeLostDialog: () => void\n closeWonPopup: () => void\n closeLostPopup: () => void\n handleWon: () => Promise<void>\n handleLostConfirm: (input: { lossReasonId: string; lossNotes?: string }) => Promise<void>\n}\n\nexport function useDealClosure({\n currentDealId,\n runMutationWithContext,\n confirmDiscardIfDirty,\n onClosed,\n}: UseDealClosureOptions): UseDealClosureResult {\n const [lostDialogOpen, setLostDialogOpen] = React.useState(false)\n const [wonPopupOpen, setWonPopupOpen] = React.useState(false)\n const [lostPopupOpen, setLostPopupOpen] = React.useState(false)\n const [wonStats, setWonStats] = React.useState<DealStatsPayload | null>(null)\n const [lostStats, setLostStats] = React.useState<DealStatsPayload | null>(null)\n\n const fetchDealStats = React.useCallback(async (): Promise<DealStatsPayload | null> => {\n if (!currentDealId) return null\n try {\n return await readApiResultOrThrow<DealStatsPayload>(\n `/api/customers/deals/${encodeURIComponent(currentDealId)}/stats`,\n )\n } catch (statsError) {\n console.error('customers.deals.detail.stats failed', statsError)\n return null\n }\n }, [currentDealId])\n\n const handleWon = React.useCallback(async () => {\n if (!currentDealId) return\n if (!(await confirmDiscardIfDirty())) return\n await runMutationWithContext(\n () => updateCrud('customers/deals', { id: currentDealId, closureOutcome: 'won', status: 'win' }),\n { id: currentDealId, closureOutcome: 'won', status: 'win', operation: 'closeWon' },\n )\n const stats = await fetchDealStats()\n setWonStats(stats)\n setWonPopupOpen(true)\n await onClosed()\n }, [confirmDiscardIfDirty, currentDealId, fetchDealStats, onClosed, runMutationWithContext])\n\n const handleLostConfirm = React.useCallback(\n async (input: { lossReasonId: string; lossNotes?: string }) => {\n if (!currentDealId) return\n if (!(await confirmDiscardIfDirty())) return\n await runMutationWithContext(\n () =>\n updateCrud('customers/deals', {\n id: currentDealId,\n closureOutcome: 'lost',\n status: 'loose',\n lossReasonId: input.lossReasonId,\n lossNotes: input.lossNotes ?? null,\n }),\n {\n id: currentDealId,\n closureOutcome: 'lost',\n status: 'loose',\n lossReasonId: input.lossReasonId,\n lossNotes: input.lossNotes ?? null,\n operation: 'closeLost',\n },\n )\n setLostDialogOpen(false)\n const stats = await fetchDealStats()\n setLostStats(stats)\n setLostPopupOpen(true)\n await onClosed()\n },\n [confirmDiscardIfDirty, currentDealId, fetchDealStats, onClosed, runMutationWithContext],\n )\n\n const openLostDialog = React.useCallback(() => setLostDialogOpen(true), [])\n const closeLostDialog = React.useCallback(() => setLostDialogOpen(false), [])\n const closeWonPopup = React.useCallback(() => setWonPopupOpen(false), [])\n const closeLostPopup = React.useCallback(() => setLostPopupOpen(false), [])\n\n return {\n lostDialogOpen,\n wonPopupOpen,\n lostPopupOpen,\n wonStats,\n lostStats,\n openLostDialog,\n closeLostDialog,\n closeWonPopup,\n closeLostPopup,\n handleWon,\n handleLostConfirm,\n }\n}\n"],
5
- "mappings": "AAAA,YAAY,WAAW;AACvB,SAAS,kBAAkB;AAC3B,SAAS,4BAA4B;AAwB9B,SAAS,eAAe;AAAA,EAC7B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAgD;AAC9C,QAAM,CAAC,gBAAgB,iBAAiB,IAAI,MAAM,SAAS,KAAK;AAChE,QAAM,CAAC,cAAc,eAAe,IAAI,MAAM,SAAS,KAAK;AAC5D,QAAM,CAAC,eAAe,gBAAgB,IAAI,MAAM,SAAS,KAAK;AAC9D,QAAM,CAAC,UAAU,WAAW,IAAI,MAAM,SAAkC,IAAI;AAC5E,QAAM,CAAC,WAAW,YAAY,IAAI,MAAM,SAAkC,IAAI;AAE9E,QAAM,iBAAiB,MAAM,YAAY,YAA8C;AACrF,QAAI,CAAC,cAAe,QAAO;AAC3B,QAAI;AACF,aAAO,MAAM;AAAA,QACX,wBAAwB,mBAAmB,aAAa,CAAC;AAAA,MAC3D;AAAA,IACF,SAAS,YAAY;AACnB,cAAQ,MAAM,uCAAuC,UAAU;AAC/D,aAAO;AAAA,IACT;AAAA,EACF,GAAG,CAAC,aAAa,CAAC;AAElB,QAAM,YAAY,MAAM,YAAY,YAAY;AAC9C,QAAI,CAAC,cAAe;AACpB,QAAI,CAAE,MAAM,sBAAsB,EAAI;AACtC,UAAM;AAAA,MACJ,MAAM,WAAW,mBAAmB,EAAE,IAAI,eAAe,gBAAgB,OAAO,QAAQ,MAAM,CAAC;AAAA,MAC/F,EAAE,IAAI,eAAe,gBAAgB,OAAO,QAAQ,OAAO,WAAW,WAAW;AAAA,IACnF;AACA,UAAM,QAAQ,MAAM,eAAe;AACnC,gBAAY,KAAK;AACjB,oBAAgB,IAAI;AACpB,UAAM,SAAS;AAAA,EACjB,GAAG,CAAC,uBAAuB,eAAe,gBAAgB,UAAU,sBAAsB,CAAC;AAE3F,QAAM,oBAAoB,MAAM;AAAA,IAC9B,OAAO,UAAwD;AAC7D,UAAI,CAAC,cAAe;AACpB,UAAI,CAAE,MAAM,sBAAsB,EAAI;AACtC,YAAM;AAAA,QACJ,MACE,WAAW,mBAAmB;AAAA,UAC5B,IAAI;AAAA,UACJ,gBAAgB;AAAA,UAChB,QAAQ;AAAA,UACR,cAAc,MAAM;AAAA,UACpB,WAAW,MAAM,aAAa;AAAA,QAChC,CAAC;AAAA,QACH;AAAA,UACE,IAAI;AAAA,UACJ,gBAAgB;AAAA,UAChB,QAAQ;AAAA,UACR,cAAc,MAAM;AAAA,UACpB,WAAW,MAAM,aAAa;AAAA,UAC9B,WAAW;AAAA,QACb;AAAA,MACF;AACA,wBAAkB,KAAK;AACvB,YAAM,QAAQ,MAAM,eAAe;AACnC,mBAAa,KAAK;AAClB,uBAAiB,IAAI;AACrB,YAAM,SAAS;AAAA,IACjB;AAAA,IACA,CAAC,uBAAuB,eAAe,gBAAgB,UAAU,sBAAsB;AAAA,EACzF;AAEA,QAAM,iBAAiB,MAAM,YAAY,MAAM,kBAAkB,IAAI,GAAG,CAAC,CAAC;AAC1E,QAAM,kBAAkB,MAAM,YAAY,MAAM,kBAAkB,KAAK,GAAG,CAAC,CAAC;AAC5E,QAAM,gBAAgB,MAAM,YAAY,MAAM,gBAAgB,KAAK,GAAG,CAAC,CAAC;AACxE,QAAM,iBAAiB,MAAM,YAAY,MAAM,iBAAiB,KAAK,GAAG,CAAC,CAAC;AAE1E,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;",
4
+ "sourcesContent": ["import * as React from 'react'\nimport { updateCrud } from '@open-mercato/ui/backend/utils/crud'\nimport { readApiResultOrThrow, withScopedApiRequestHeaders } from '@open-mercato/ui/backend/utils/apiCall'\nimport { buildOptimisticLockHeader } from '@open-mercato/ui/backend/utils/optimisticLock'\nimport { surfaceRecordConflict } from '@open-mercato/ui/backend/conflicts'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport type { DealStatsPayload, GuardedMutationRunner } from './types'\n\ntype UseDealClosureOptions = {\n currentDealId: string | null\n dealUpdatedAt: string | null\n runMutationWithContext: GuardedMutationRunner\n confirmDiscardIfDirty: () => Promise<boolean>\n onClosed: () => Promise<void>\n}\n\ntype UseDealClosureResult = {\n lostDialogOpen: boolean\n wonPopupOpen: boolean\n lostPopupOpen: boolean\n wonStats: DealStatsPayload | null\n lostStats: DealStatsPayload | null\n openLostDialog: () => void\n closeLostDialog: () => void\n closeWonPopup: () => void\n closeLostPopup: () => void\n handleWon: () => Promise<void>\n handleLostConfirm: (input: { lossReasonId: string; lossNotes?: string }) => Promise<void>\n}\n\nexport function useDealClosure({\n currentDealId,\n dealUpdatedAt,\n runMutationWithContext,\n confirmDiscardIfDirty,\n onClosed,\n}: UseDealClosureOptions): UseDealClosureResult {\n const t = useT()\n const [lostDialogOpen, setLostDialogOpen] = React.useState(false)\n const [wonPopupOpen, setWonPopupOpen] = React.useState(false)\n const [lostPopupOpen, setLostPopupOpen] = React.useState(false)\n const [wonStats, setWonStats] = React.useState<DealStatsPayload | null>(null)\n const [lostStats, setLostStats] = React.useState<DealStatsPayload | null>(null)\n\n const fetchDealStats = React.useCallback(async (): Promise<DealStatsPayload | null> => {\n if (!currentDealId) return null\n try {\n return await readApiResultOrThrow<DealStatsPayload>(\n `/api/customers/deals/${encodeURIComponent(currentDealId)}/stats`,\n )\n } catch (statsError) {\n console.error('customers.deals.detail.stats failed', statsError)\n return null\n }\n }, [currentDealId])\n\n const handleWon = React.useCallback(async () => {\n if (!currentDealId) return\n if (!(await confirmDiscardIfDirty())) return\n try {\n await runMutationWithContext(\n () => withScopedApiRequestHeaders(\n buildOptimisticLockHeader(dealUpdatedAt),\n () => updateCrud('customers/deals', { id: currentDealId, closureOutcome: 'won', status: 'win' }),\n ),\n { id: currentDealId, closureOutcome: 'won', status: 'win', operation: 'closeWon' },\n )\n } catch (err) {\n if (!surfaceRecordConflict(err, t, { onRefresh: () => { void onClosed() } })) {\n flash(t('customers.deals.detail.closeWonError', 'Failed to mark deal as won.'), 'error')\n }\n return\n }\n const stats = await fetchDealStats()\n setWonStats(stats)\n setWonPopupOpen(true)\n await onClosed()\n }, [confirmDiscardIfDirty, currentDealId, dealUpdatedAt, fetchDealStats, onClosed, runMutationWithContext, t])\n\n const handleLostConfirm = React.useCallback(\n async (input: { lossReasonId: string; lossNotes?: string }) => {\n if (!currentDealId) return\n if (!(await confirmDiscardIfDirty())) return\n try {\n await runMutationWithContext(\n () => withScopedApiRequestHeaders(\n buildOptimisticLockHeader(dealUpdatedAt),\n () =>\n updateCrud('customers/deals', {\n id: currentDealId,\n closureOutcome: 'lost',\n status: 'loose',\n lossReasonId: input.lossReasonId,\n lossNotes: input.lossNotes ?? null,\n }),\n ),\n {\n id: currentDealId,\n closureOutcome: 'lost',\n status: 'loose',\n lossReasonId: input.lossReasonId,\n lossNotes: input.lossNotes ?? null,\n operation: 'closeLost',\n },\n )\n } catch (err) {\n if (!surfaceRecordConflict(err, t, { onRefresh: () => { void onClosed() } })) {\n flash(t('customers.deals.detail.closeLostError', 'Failed to mark deal as lost.'), 'error')\n }\n return\n }\n setLostDialogOpen(false)\n const stats = await fetchDealStats()\n setLostStats(stats)\n setLostPopupOpen(true)\n await onClosed()\n },\n [confirmDiscardIfDirty, currentDealId, dealUpdatedAt, fetchDealStats, onClosed, runMutationWithContext, t],\n )\n\n const openLostDialog = React.useCallback(() => setLostDialogOpen(true), [])\n const closeLostDialog = React.useCallback(() => setLostDialogOpen(false), [])\n const closeWonPopup = React.useCallback(() => setWonPopupOpen(false), [])\n const closeLostPopup = React.useCallback(() => setLostPopupOpen(false), [])\n\n return {\n lostDialogOpen,\n wonPopupOpen,\n lostPopupOpen,\n wonStats,\n lostStats,\n openLostDialog,\n closeLostDialog,\n closeWonPopup,\n closeLostPopup,\n handleWon,\n handleLostConfirm,\n }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -1,6 +1,9 @@
1
1
  import * as React from "react";
2
2
  import { flash } from "@open-mercato/ui/backend/FlashMessages";
3
3
  import { updateCrud } from "@open-mercato/ui/backend/utils/crud";
4
+ import { withScopedApiRequestHeaders } from "@open-mercato/ui/backend/utils/apiCall";
5
+ import { buildOptimisticLockHeader } from "@open-mercato/ui/backend/utils/optimisticLock";
6
+ import { surfaceRecordConflict } from "@open-mercato/ui/backend/conflicts";
4
7
  import { useT } from "@open-mercato/shared/lib/i18n/context";
5
8
  function useDealPipeline({
6
9
  currentDealId,
@@ -19,13 +22,20 @@ function useDealPipeline({
19
22
  setIsStageSaving(true);
20
23
  try {
21
24
  await runMutationWithContext(
22
- () => updateCrud("customers/deals", { id: currentDealId, pipelineStageId: nextStageId }),
25
+ () => withScopedApiRequestHeaders(
26
+ buildOptimisticLockHeader(data.deal.updatedAt),
27
+ () => updateCrud("customers/deals", { id: currentDealId, pipelineStageId: nextStageId })
28
+ ),
23
29
  { id: currentDealId, pipelineStageId: nextStageId, operation: "updateDealStage" }
24
30
  );
25
31
  flash(t("customers.deals.detail.stageUpdateSuccess", "Deal stage updated."), "success");
26
32
  await onStageChanged();
27
- } catch {
28
- flash(t("customers.deals.detail.stageUpdateError", "Failed to update deal stage."), "error");
33
+ } catch (err) {
34
+ if (!surfaceRecordConflict(err, t, { onRefresh: () => {
35
+ void onStageChanged();
36
+ } })) {
37
+ flash(t("customers.deals.detail.stageUpdateError", "Failed to update deal stage."), "error");
38
+ }
29
39
  } finally {
30
40
  setIsStageSaving(false);
31
41
  }