@open-mercato/core 0.6.5-develop.4534.1.b459babe6d → 0.6.5-develop.4544.1.71c003c861

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 (633) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/AGENTS.md +5 -0
  3. package/dist/generated/entities/role/index.js +3 -1
  4. package/dist/generated/entities/role/index.js.map +2 -2
  5. package/dist/generated/entities/user/index.js +3 -1
  6. package/dist/generated/entities/user/index.js.map +2 -2
  7. package/dist/generated/entity-fields-registry.js +2 -0
  8. package/dist/generated/entity-fields-registry.js.map +2 -2
  9. package/dist/helpers/integration/optimisticLockUi.js +104 -0
  10. package/dist/helpers/integration/optimisticLockUi.js.map +7 -0
  11. package/dist/helpers/integration/salesFixtures.js +17 -0
  12. package/dist/helpers/integration/salesFixtures.js.map +2 -2
  13. package/dist/modules/api_keys/backend/api-keys/page.js +9 -5
  14. package/dist/modules/api_keys/backend/api-keys/page.js.map +2 -2
  15. package/dist/modules/attachments/components/AttachmentPartitionSettings.js +17 -9
  16. package/dist/modules/attachments/components/AttachmentPartitionSettings.js.map +2 -2
  17. package/dist/modules/auth/api/roles/acl/route.js +32 -13
  18. package/dist/modules/auth/api/roles/acl/route.js.map +2 -2
  19. package/dist/modules/auth/api/roles/route.js +3 -1
  20. package/dist/modules/auth/api/roles/route.js.map +2 -2
  21. package/dist/modules/auth/api/sidebar/preferences/route.js +71 -3
  22. package/dist/modules/auth/api/sidebar/preferences/route.js.map +2 -2
  23. package/dist/modules/auth/api/users/acl/route.js +42 -19
  24. package/dist/modules/auth/api/users/acl/route.js.map +2 -2
  25. package/dist/modules/auth/api/users/route.js +3 -1
  26. package/dist/modules/auth/api/users/route.js.map +2 -2
  27. package/dist/modules/auth/backend/roles/[id]/edit/page.js +24 -4
  28. package/dist/modules/auth/backend/roles/[id]/edit/page.js.map +2 -2
  29. package/dist/modules/auth/backend/roles/page.js +8 -4
  30. package/dist/modules/auth/backend/roles/page.js.map +2 -2
  31. package/dist/modules/auth/backend/users/[id]/edit/page.js +27 -5
  32. package/dist/modules/auth/backend/users/[id]/edit/page.js.map +2 -2
  33. package/dist/modules/auth/backend/users/page.js +6 -2
  34. package/dist/modules/auth/backend/users/page.js.map +2 -2
  35. package/dist/modules/auth/components/AclEditor.js +3 -1
  36. package/dist/modules/auth/components/AclEditor.js.map +2 -2
  37. package/dist/modules/auth/data/entities.js +6 -0
  38. package/dist/modules/auth/data/entities.js.map +2 -2
  39. package/dist/modules/auth/services/sidebarPreferencesService.js +32 -4
  40. package/dist/modules/auth/services/sidebarPreferencesService.js.map +2 -2
  41. package/dist/modules/business_rules/api/rules/route.js +28 -0
  42. package/dist/modules/business_rules/api/rules/route.js.map +2 -2
  43. package/dist/modules/business_rules/api/sets/route.js +28 -0
  44. package/dist/modules/business_rules/api/sets/route.js.map +2 -2
  45. package/dist/modules/business_rules/backend/rules/[id]/page.js +11 -4
  46. package/dist/modules/business_rules/backend/rules/[id]/page.js.map +3 -3
  47. package/dist/modules/business_rules/backend/rules/page.js +20 -11
  48. package/dist/modules/business_rules/backend/rules/page.js.map +2 -2
  49. package/dist/modules/business_rules/backend/sets/[id]/page.js +11 -4
  50. package/dist/modules/business_rules/backend/sets/[id]/page.js.map +2 -2
  51. package/dist/modules/business_rules/backend/sets/page.js +20 -11
  52. package/dist/modules/business_rules/backend/sets/page.js.map +2 -2
  53. package/dist/modules/catalog/api/categories/route.js +2 -0
  54. package/dist/modules/catalog/api/categories/route.js.map +2 -2
  55. package/dist/modules/catalog/api/products/route.js +2 -1
  56. package/dist/modules/catalog/api/products/route.js.map +2 -2
  57. package/dist/modules/catalog/backend/catalog/categories/[id]/edit/page.js +2 -0
  58. package/dist/modules/catalog/backend/catalog/categories/[id]/edit/page.js.map +2 -2
  59. package/dist/modules/catalog/backend/catalog/products/[id]/page.js +94 -40
  60. package/dist/modules/catalog/backend/catalog/products/[id]/page.js.map +2 -2
  61. package/dist/modules/catalog/backend/catalog/products/[productId]/variants/[variantId]/page.js +37 -8
  62. package/dist/modules/catalog/backend/catalog/products/[productId]/variants/[variantId]/page.js.map +2 -2
  63. package/dist/modules/catalog/backend/catalog/products/optionSchemaClient.js.map +2 -2
  64. package/dist/modules/catalog/commands/variants.js +32 -31
  65. package/dist/modules/catalog/commands/variants.js.map +2 -2
  66. package/dist/modules/catalog/components/PriceKindSettings.js +12 -5
  67. package/dist/modules/catalog/components/PriceKindSettings.js.map +2 -2
  68. package/dist/modules/catalog/components/categories/CategoriesDataTable.js.map +2 -2
  69. package/dist/modules/catalog/components/products/ProductMediaManager.js.map +2 -2
  70. package/dist/modules/catalog/components/products/ProductsDataTable.js +5 -3
  71. package/dist/modules/catalog/components/products/ProductsDataTable.js.map +2 -2
  72. package/dist/modules/catalog/components/products/productForm.js.map +2 -2
  73. package/dist/modules/catalog/components/products/variantForm.js +2 -1
  74. package/dist/modules/catalog/components/products/variantForm.js.map +2 -2
  75. package/dist/modules/communication_channels/backend/profile/communication-channels/page.js +5 -0
  76. package/dist/modules/communication_channels/backend/profile/communication-channels/page.js.map +2 -2
  77. package/dist/modules/currencies/backend/currencies/[id]/page.js +6 -3
  78. package/dist/modules/currencies/backend/currencies/[id]/page.js.map +2 -2
  79. package/dist/modules/currencies/backend/currencies/page.js +18 -11
  80. package/dist/modules/currencies/backend/currencies/page.js.map +2 -2
  81. package/dist/modules/currencies/backend/exchange-rates/[id]/page.js +1 -0
  82. package/dist/modules/currencies/backend/exchange-rates/[id]/page.js.map +2 -2
  83. package/dist/modules/currencies/backend/exchange-rates/page.js +10 -6
  84. package/dist/modules/currencies/backend/exchange-rates/page.js.map +2 -2
  85. package/dist/modules/currencies/commands/currencies.js +7 -5
  86. package/dist/modules/currencies/commands/currencies.js.map +2 -2
  87. package/dist/modules/currencies/components/CurrencyFetchingConfig.js +26 -19
  88. package/dist/modules/currencies/components/CurrencyFetchingConfig.js.map +2 -2
  89. package/dist/modules/customer_accounts/api/admin/roles/[id].js +28 -5
  90. package/dist/modules/customer_accounts/api/admin/roles/[id].js.map +2 -2
  91. package/dist/modules/customer_accounts/api/admin/roles.js +4 -2
  92. package/dist/modules/customer_accounts/api/admin/roles.js.map +2 -2
  93. package/dist/modules/customer_accounts/api/admin/users/[id].js +28 -5
  94. package/dist/modules/customer_accounts/api/admin/users/[id].js.map +2 -2
  95. package/dist/modules/customer_accounts/api/admin/users.js +2 -0
  96. package/dist/modules/customer_accounts/api/admin/users.js.map +2 -2
  97. package/dist/modules/customer_accounts/backend/customer_accounts/roles/[id]/page.js +16 -8
  98. package/dist/modules/customer_accounts/backend/customer_accounts/roles/[id]/page.js.map +2 -2
  99. package/dist/modules/customer_accounts/backend/customer_accounts/roles/page.js +8 -4
  100. package/dist/modules/customer_accounts/backend/customer_accounts/roles/page.js.map +2 -2
  101. package/dist/modules/customer_accounts/backend/customer_accounts/settings/domain/page.js +8 -4
  102. package/dist/modules/customer_accounts/backend/customer_accounts/settings/domain/page.js.map +2 -2
  103. package/dist/modules/customer_accounts/backend/customer_accounts/users/[id]/page.js +29 -18
  104. package/dist/modules/customer_accounts/backend/customer_accounts/users/[id]/page.js.map +2 -2
  105. package/dist/modules/customer_accounts/backend/customer_accounts/users/page.js +18 -11
  106. package/dist/modules/customer_accounts/backend/customer_accounts/users/page.js.map +2 -2
  107. package/dist/modules/customers/api/companies/route.js +13 -2
  108. package/dist/modules/customers/api/companies/route.js.map +2 -2
  109. package/dist/modules/customers/api/deals/route.js +2 -0
  110. package/dist/modules/customers/api/deals/route.js.map +2 -2
  111. package/dist/modules/customers/api/people/route.js +11 -2
  112. package/dist/modules/customers/api/people/route.js.map +2 -2
  113. package/dist/modules/customers/api/todos/route.js +1 -0
  114. package/dist/modules/customers/api/todos/route.js.map +2 -2
  115. package/dist/modules/customers/backend/config/customers/deals/page.js.map +2 -2
  116. package/dist/modules/customers/backend/config/customers/pipeline-stages/page.js +34 -21
  117. package/dist/modules/customers/backend/config/customers/pipeline-stages/page.js.map +2 -2
  118. package/dist/modules/customers/backend/customers/companies/[id]/page.js +45 -27
  119. package/dist/modules/customers/backend/customers/companies/[id]/page.js.map +2 -2
  120. package/dist/modules/customers/backend/customers/companies/page.js.map +2 -2
  121. package/dist/modules/customers/backend/customers/companies-v2/[id]/page.js +22 -5
  122. package/dist/modules/customers/backend/customers/companies-v2/[id]/page.js.map +2 -2
  123. package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealFormHandlers.js +30 -8
  124. package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealFormHandlers.js.map +2 -2
  125. package/dist/modules/customers/backend/customers/deals/[id]/page.js +1 -0
  126. package/dist/modules/customers/backend/customers/deals/[id]/page.js.map +2 -2
  127. package/dist/modules/customers/backend/customers/deals/page.js +16 -6
  128. package/dist/modules/customers/backend/customers/deals/page.js.map +2 -2
  129. package/dist/modules/customers/backend/customers/deals/pipeline/page.js +62 -39
  130. package/dist/modules/customers/backend/customers/deals/pipeline/page.js.map +2 -2
  131. package/dist/modules/customers/backend/customers/people/[id]/page.js +41 -26
  132. package/dist/modules/customers/backend/customers/people/[id]/page.js.map +2 -2
  133. package/dist/modules/customers/backend/customers/people/page.js.map +2 -2
  134. package/dist/modules/customers/backend/customers/people-v2/[id]/page.js +50 -23
  135. package/dist/modules/customers/backend/customers/people-v2/[id]/page.js.map +2 -2
  136. package/dist/modules/customers/commands/addresses.js +16 -14
  137. package/dist/modules/customers/commands/addresses.js.map +2 -2
  138. package/dist/modules/customers/commands/companies.js +1 -1
  139. package/dist/modules/customers/commands/companies.js.map +2 -2
  140. package/dist/modules/customers/commands/interactions.js +41 -4
  141. package/dist/modules/customers/commands/interactions.js.map +2 -2
  142. package/dist/modules/customers/commands/people.js +1 -1
  143. package/dist/modules/customers/commands/people.js.map +2 -2
  144. package/dist/modules/customers/commands/personCompanyLinks.js +8 -5
  145. package/dist/modules/customers/commands/personCompanyLinks.js.map +2 -2
  146. package/dist/modules/customers/commands/pipeline-stages.js +13 -11
  147. package/dist/modules/customers/commands/pipeline-stages.js.map +3 -3
  148. package/dist/modules/customers/components/AddressFormatSettings.js.map +2 -2
  149. package/dist/modules/customers/components/DictionarySettings.js +20 -13
  150. package/dist/modules/customers/components/DictionarySettings.js.map +2 -2
  151. package/dist/modules/customers/components/DictionarySortSettings.js +4 -0
  152. package/dist/modules/customers/components/DictionarySortSettings.js.map +2 -2
  153. package/dist/modules/customers/components/PipelineSettings.js +38 -23
  154. package/dist/modules/customers/components/PipelineSettings.js.map +2 -2
  155. package/dist/modules/customers/components/detail/ActivityTimeline.js +1 -1
  156. package/dist/modules/customers/components/detail/ActivityTimeline.js.map +2 -2
  157. package/dist/modules/customers/components/detail/AddressesSection.js +4 -0
  158. package/dist/modules/customers/components/detail/AddressesSection.js.map +2 -2
  159. package/dist/modules/customers/components/detail/CompanyPeopleSection.js +28 -22
  160. package/dist/modules/customers/components/detail/CompanyPeopleSection.js.map +2 -2
  161. package/dist/modules/customers/components/detail/DealsSection.js +36 -24
  162. package/dist/modules/customers/components/detail/DealsSection.js.map +2 -2
  163. package/dist/modules/customers/components/detail/EmailCardActions.js +5 -0
  164. package/dist/modules/customers/components/detail/EmailCardActions.js.map +2 -2
  165. package/dist/modules/customers/components/detail/EntityTagsDialog.js +7 -0
  166. package/dist/modules/customers/components/detail/EntityTagsDialog.js.map +2 -2
  167. package/dist/modules/customers/components/detail/ManageTagsDialog.js +34 -22
  168. package/dist/modules/customers/components/detail/ManageTagsDialog.js.map +2 -2
  169. package/dist/modules/customers/components/detail/PersonCompaniesSection.js +41 -29
  170. package/dist/modules/customers/components/detail/PersonCompaniesSection.js.map +2 -2
  171. package/dist/modules/customers/components/detail/RoleAssignmentRow.js +14 -8
  172. package/dist/modules/customers/components/detail/RoleAssignmentRow.js.map +2 -2
  173. package/dist/modules/customers/components/detail/ScheduleActivityDialog.js +14 -6
  174. package/dist/modules/customers/components/detail/ScheduleActivityDialog.js.map +2 -2
  175. package/dist/modules/customers/components/detail/hooks/useInteractionMutations.js +29 -13
  176. package/dist/modules/customers/components/detail/hooks/useInteractionMutations.js.map +2 -2
  177. package/dist/modules/customers/components/detail/hooks/useInteractions.js +77 -35
  178. package/dist/modules/customers/components/detail/hooks/useInteractions.js.map +2 -2
  179. package/dist/modules/customers/components/detail/hooks/usePersonTasks.js +25 -17
  180. package/dist/modules/customers/components/detail/hooks/usePersonTasks.js.map +2 -2
  181. package/dist/modules/customers/components/detail/schedule/useScheduleFormState.js.map +2 -2
  182. package/dist/modules/customers/components/formConfig.js.map +2 -2
  183. package/dist/modules/customers/data/guards.js +66 -0
  184. package/dist/modules/customers/data/guards.js.map +7 -0
  185. package/dist/modules/customers/di.js +37 -0
  186. package/dist/modules/customers/di.js.map +2 -2
  187. package/dist/modules/customers/lib/todoCompatibility.js +11 -0
  188. package/dist/modules/customers/lib/todoCompatibility.js.map +2 -2
  189. package/dist/modules/dashboards/components/WidgetVisibilityEditor.js.map +2 -2
  190. package/dist/modules/data_sync/api/options.js +4 -4
  191. package/dist/modules/data_sync/api/options.js.map +2 -2
  192. package/dist/modules/data_sync/api/schedules/route.js +9 -1
  193. package/dist/modules/data_sync/api/schedules/route.js.map +2 -2
  194. package/dist/modules/data_sync/backend/data-sync/page.js +17 -8
  195. package/dist/modules/data_sync/backend/data-sync/page.js.map +2 -2
  196. package/dist/modules/data_sync/components/IntegrationScheduleTab.js +43 -22
  197. package/dist/modules/data_sync/components/IntegrationScheduleTab.js.map +2 -2
  198. package/dist/modules/data_sync/lib/sync-schedule-service.js +9 -0
  199. package/dist/modules/data_sync/lib/sync-schedule-service.js.map +2 -2
  200. package/dist/modules/dictionaries/api/[dictionaryId]/entries/[entryId]/route.js +8 -1
  201. package/dist/modules/dictionaries/api/[dictionaryId]/entries/[entryId]/route.js.map +2 -2
  202. package/dist/modules/dictionaries/api/[dictionaryId]/route.js +17 -1
  203. package/dist/modules/dictionaries/api/[dictionaryId]/route.js.map +2 -2
  204. package/dist/modules/dictionaries/components/DictionariesManager.js +31 -10
  205. package/dist/modules/dictionaries/components/DictionariesManager.js.map +2 -2
  206. package/dist/modules/dictionaries/components/DictionaryEntriesEditor.js +28 -15
  207. package/dist/modules/dictionaries/components/DictionaryEntriesEditor.js.map +2 -2
  208. package/dist/modules/directory/api/organizations/route.js +3 -0
  209. package/dist/modules/directory/api/organizations/route.js.map +2 -2
  210. package/dist/modules/directory/backend/directory/organizations/[id]/edit/page.js +2 -0
  211. package/dist/modules/directory/backend/directory/organizations/[id]/edit/page.js.map +2 -2
  212. package/dist/modules/directory/backend/directory/organizations/page.js +9 -5
  213. package/dist/modules/directory/backend/directory/organizations/page.js.map +2 -2
  214. package/dist/modules/directory/backend/directory/tenants/[id]/edit/page.js +7 -3
  215. package/dist/modules/directory/backend/directory/tenants/[id]/edit/page.js.map +2 -2
  216. package/dist/modules/directory/backend/directory/tenants/page.js +8 -4
  217. package/dist/modules/directory/backend/directory/tenants/page.js.map +2 -2
  218. package/dist/modules/directory/commands/organizations.js +7 -2
  219. package/dist/modules/directory/commands/organizations.js.map +2 -2
  220. package/dist/modules/entities/api/records.js +66 -0
  221. package/dist/modules/entities/api/records.js.map +2 -2
  222. package/dist/modules/entities/backend/entities/user/[entityId]/records/[recordId]/page.js +1 -0
  223. package/dist/modules/entities/backend/entities/user/[entityId]/records/[recordId]/page.js.map +2 -2
  224. package/dist/modules/entities/backend/entities/user/[entityId]/records/page.js +8 -4
  225. package/dist/modules/entities/backend/entities/user/[entityId]/records/page.js.map +2 -2
  226. package/dist/modules/entities/lib/helpers.js +17 -0
  227. package/dist/modules/entities/lib/helpers.js.map +2 -2
  228. package/dist/modules/feature_toggles/api/global/[id]/override/route.js +2 -1
  229. package/dist/modules/feature_toggles/api/global/[id]/override/route.js.map +2 -2
  230. package/dist/modules/feature_toggles/api/overrides/route.js +15 -0
  231. package/dist/modules/feature_toggles/api/overrides/route.js.map +2 -2
  232. package/dist/modules/feature_toggles/backend/feature-toggles/global/[id]/edit/page.js +15 -14
  233. package/dist/modules/feature_toggles/backend/feature-toggles/global/[id]/edit/page.js.map +2 -2
  234. package/dist/modules/feature_toggles/components/FeatureToggleOverrideCard.js +20 -12
  235. package/dist/modules/feature_toggles/components/FeatureToggleOverrideCard.js.map +2 -2
  236. package/dist/modules/feature_toggles/components/FeatureTogglesTable.js +6 -2
  237. package/dist/modules/feature_toggles/components/FeatureTogglesTable.js.map +2 -2
  238. package/dist/modules/feature_toggles/components/formConfig.js +2 -1
  239. package/dist/modules/feature_toggles/components/formConfig.js.map +2 -2
  240. package/dist/modules/feature_toggles/components/overrideFormConfig.js +5 -1
  241. package/dist/modules/feature_toggles/components/overrideFormConfig.js.map +2 -2
  242. package/dist/modules/feature_toggles/data/validators.js +7 -4
  243. package/dist/modules/feature_toggles/data/validators.js.map +2 -2
  244. package/dist/modules/inbox_ops/api/settings/route.js +17 -2
  245. package/dist/modules/inbox_ops/api/settings/route.js.map +2 -2
  246. package/dist/modules/inbox_ops/backend/inbox-ops/settings/page.js +13 -8
  247. package/dist/modules/inbox_ops/backend/inbox-ops/settings/page.js.map +2 -2
  248. package/dist/modules/inbox_ops/components/proposals/EditActionDialog.js +9 -4
  249. package/dist/modules/inbox_ops/components/proposals/EditActionDialog.js.map +2 -2
  250. package/dist/modules/integrations/backend/integrations/bundle/[id]/page.js +18 -11
  251. package/dist/modules/integrations/backend/integrations/bundle/[id]/page.js.map +2 -2
  252. package/dist/modules/integrations/backend/integrations/page.js +12 -8
  253. package/dist/modules/integrations/backend/integrations/page.js.map +2 -2
  254. package/dist/modules/messages/commands/messages.js +13 -10
  255. package/dist/modules/messages/commands/messages.js.map +2 -2
  256. package/dist/modules/perspectives/api/[tableId]/route.js +39 -30
  257. package/dist/modules/perspectives/api/[tableId]/route.js.map +2 -2
  258. package/dist/modules/perspectives/services/perspectiveService.js +7 -0
  259. package/dist/modules/perspectives/services/perspectiveService.js.map +2 -2
  260. package/dist/modules/planner/backend/planner/availability-rulesets/[id]/page.js +6 -14
  261. package/dist/modules/planner/backend/planner/availability-rulesets/[id]/page.js.map +3 -3
  262. package/dist/modules/planner/backend/planner/availability-rulesets/page.js +4 -2
  263. package/dist/modules/planner/backend/planner/availability-rulesets/page.js.map +2 -2
  264. package/dist/modules/planner/components/AvailabilityRuleSetForm.js +2 -0
  265. package/dist/modules/planner/components/AvailabilityRuleSetForm.js.map +2 -2
  266. package/dist/modules/planner/components/AvailabilityRulesEditor.js +36 -11
  267. package/dist/modules/planner/components/AvailabilityRulesEditor.js.map +2 -2
  268. package/dist/modules/planner/components/AvailabilitySchedule.js +9 -5
  269. package/dist/modules/planner/components/AvailabilitySchedule.js.map +2 -2
  270. package/dist/modules/query_index/lib/engine.js +19 -0
  271. package/dist/modules/query_index/lib/engine.js.map +2 -2
  272. package/dist/modules/resources/backend/resources/resource-types/[id]/edit/page.js +1 -0
  273. package/dist/modules/resources/backend/resources/resource-types/[id]/edit/page.js.map +2 -2
  274. package/dist/modules/resources/backend/resources/resource-types/page.js +4 -2
  275. package/dist/modules/resources/backend/resources/resource-types/page.js.map +2 -2
  276. package/dist/modules/resources/backend/resources/resources/[id]/page.js +14 -3
  277. package/dist/modules/resources/backend/resources/resources/[id]/page.js.map +2 -2
  278. package/dist/modules/resources/backend/resources/resources/page.js +8 -4
  279. package/dist/modules/resources/backend/resources/resources/page.js.map +2 -2
  280. package/dist/modules/resources/components/ResourceCrudForm.js +2 -0
  281. package/dist/modules/resources/components/ResourceCrudForm.js.map +2 -2
  282. package/dist/modules/resources/components/ResourceTypeCrudForm.js +1 -0
  283. package/dist/modules/resources/components/ResourceTypeCrudForm.js.map +2 -2
  284. package/dist/modules/sales/api/documents/factory.js +7 -2
  285. package/dist/modules/sales/api/documents/factory.js.map +2 -2
  286. package/dist/modules/sales/backend/sales/channels/[channelId]/edit/page.js +3 -1
  287. package/dist/modules/sales/backend/sales/channels/[channelId]/edit/page.js.map +2 -2
  288. package/dist/modules/sales/backend/sales/channels/offers/page.js +13 -4
  289. package/dist/modules/sales/backend/sales/channels/offers/page.js.map +2 -2
  290. package/dist/modules/sales/backend/sales/channels/page.js +16 -4
  291. package/dist/modules/sales/backend/sales/channels/page.js.map +2 -2
  292. package/dist/modules/sales/backend/sales/documents/[id]/page.js +68 -22
  293. package/dist/modules/sales/backend/sales/documents/[id]/page.js.map +2 -2
  294. package/dist/modules/sales/backend/sales/documents/create/page.js.map +2 -2
  295. package/dist/modules/sales/commands/documentAddresses.js +181 -2
  296. package/dist/modules/sales/commands/documentAddresses.js.map +2 -2
  297. package/dist/modules/sales/commands/documents.js +29 -1
  298. package/dist/modules/sales/commands/documents.js.map +2 -2
  299. package/dist/modules/sales/commands/returns.js +12 -2
  300. package/dist/modules/sales/commands/returns.js.map +2 -2
  301. package/dist/modules/sales/commands/shared.js +15 -0
  302. package/dist/modules/sales/commands/shared.js.map +2 -2
  303. package/dist/modules/sales/commands/shipments.js +4 -1
  304. package/dist/modules/sales/commands/shipments.js.map +2 -2
  305. package/dist/modules/sales/components/AdjustmentKindSettings.js +19 -11
  306. package/dist/modules/sales/components/AdjustmentKindSettings.js.map +2 -2
  307. package/dist/modules/sales/components/DocumentNumberSettings.js.map +2 -2
  308. package/dist/modules/sales/components/OrderEditingSettings.js.map +2 -2
  309. package/dist/modules/sales/components/PaymentMethodsSettings.js +12 -4
  310. package/dist/modules/sales/components/PaymentMethodsSettings.js.map +2 -2
  311. package/dist/modules/sales/components/ShippingMethodsSettings.js +12 -4
  312. package/dist/modules/sales/components/ShippingMethodsSettings.js.map +2 -2
  313. package/dist/modules/sales/components/StatusSettings.js +18 -11
  314. package/dist/modules/sales/components/StatusSettings.js.map +2 -2
  315. package/dist/modules/sales/components/TaxRatesSettings.js +12 -4
  316. package/dist/modules/sales/components/TaxRatesSettings.js.map +2 -2
  317. package/dist/modules/sales/components/channels/ChannelOfferForm.js +47 -16
  318. package/dist/modules/sales/components/channels/ChannelOfferForm.js.map +2 -2
  319. package/dist/modules/sales/components/channels/SalesChannelOffersPanel.js +8 -4
  320. package/dist/modules/sales/components/channels/SalesChannelOffersPanel.js.map +2 -2
  321. package/dist/modules/sales/components/documents/AddressesSection.js +44 -25
  322. package/dist/modules/sales/components/documents/AddressesSection.js.map +2 -2
  323. package/dist/modules/sales/components/documents/AdjustmentsSection.js +43 -23
  324. package/dist/modules/sales/components/documents/AdjustmentsSection.js.map +2 -2
  325. package/dist/modules/sales/components/documents/ItemsSection.js +22 -13
  326. package/dist/modules/sales/components/documents/ItemsSection.js.map +2 -2
  327. package/dist/modules/sales/components/documents/LineItemDialog.js +23 -10
  328. package/dist/modules/sales/components/documents/LineItemDialog.js.map +2 -2
  329. package/dist/modules/sales/components/documents/PaymentDialog.js +29 -14
  330. package/dist/modules/sales/components/documents/PaymentDialog.js.map +2 -2
  331. package/dist/modules/sales/components/documents/PaymentsSection.js +20 -10
  332. package/dist/modules/sales/components/documents/PaymentsSection.js.map +2 -2
  333. package/dist/modules/sales/components/documents/ReturnDialog.js +26 -17
  334. package/dist/modules/sales/components/documents/ReturnDialog.js.map +2 -2
  335. package/dist/modules/sales/components/documents/ReturnsSection.js +3 -1
  336. package/dist/modules/sales/components/documents/ReturnsSection.js.map +2 -2
  337. package/dist/modules/sales/components/documents/SalesDocumentsTable.js +10 -5
  338. package/dist/modules/sales/components/documents/SalesDocumentsTable.js.map +2 -2
  339. package/dist/modules/sales/components/documents/ShipmentDialog.js +21 -7
  340. package/dist/modules/sales/components/documents/ShipmentDialog.js.map +2 -2
  341. package/dist/modules/sales/components/documents/ShipmentsSection.js +19 -10
  342. package/dist/modules/sales/components/documents/ShipmentsSection.js.map +2 -2
  343. package/dist/modules/sales/components/documents/optimisticLock.js +27 -0
  344. package/dist/modules/sales/components/documents/optimisticLock.js.map +7 -0
  345. package/dist/modules/sales/di.js +18 -0
  346. package/dist/modules/sales/di.js.map +2 -2
  347. package/dist/modules/staff/api/job-histories.js +11 -2
  348. package/dist/modules/staff/api/job-histories.js.map +2 -2
  349. package/dist/modules/staff/api/timesheets/time-entries/route.js +11 -4
  350. package/dist/modules/staff/api/timesheets/time-entries/route.js.map +2 -2
  351. package/dist/modules/staff/backend/staff/leave-requests/[id]/page.js +13 -8
  352. package/dist/modules/staff/backend/staff/leave-requests/[id]/page.js.map +2 -2
  353. package/dist/modules/staff/backend/staff/my-leave-requests/[id]/page.js +2 -1
  354. package/dist/modules/staff/backend/staff/my-leave-requests/[id]/page.js.map +2 -2
  355. package/dist/modules/staff/backend/staff/team-members/[id]/page.js +7 -4
  356. package/dist/modules/staff/backend/staff/team-members/[id]/page.js.map +2 -2
  357. package/dist/modules/staff/backend/staff/team-members/page.js +4 -2
  358. package/dist/modules/staff/backend/staff/team-members/page.js.map +2 -2
  359. package/dist/modules/staff/backend/staff/team-roles/[id]/edit/page.js +1 -0
  360. package/dist/modules/staff/backend/staff/team-roles/[id]/edit/page.js.map +2 -2
  361. package/dist/modules/staff/backend/staff/team-roles/page.js +4 -2
  362. package/dist/modules/staff/backend/staff/team-roles/page.js.map +2 -2
  363. package/dist/modules/staff/backend/staff/teams/[id]/edit/page.js +5 -2
  364. package/dist/modules/staff/backend/staff/teams/[id]/edit/page.js.map +2 -2
  365. package/dist/modules/staff/backend/staff/teams/page.js +12 -3
  366. package/dist/modules/staff/backend/staff/teams/page.js.map +2 -2
  367. package/dist/modules/staff/backend/staff/timesheets/page.js +4 -1
  368. package/dist/modules/staff/backend/staff/timesheets/page.js.map +2 -2
  369. package/dist/modules/staff/backend/staff/timesheets/projects/[id]/page.js.map +2 -2
  370. package/dist/modules/staff/backend/staff/timesheets/projects/page.js +12 -3
  371. package/dist/modules/staff/backend/staff/timesheets/projects/page.js.map +2 -2
  372. package/dist/modules/staff/commands/job-histories.js +40 -3
  373. package/dist/modules/staff/commands/job-histories.js.map +2 -2
  374. package/dist/modules/staff/components/LeaveRequestForm.js +1 -0
  375. package/dist/modules/staff/components/LeaveRequestForm.js.map +2 -2
  376. package/dist/modules/staff/components/TeamForm.js +1 -0
  377. package/dist/modules/staff/components/TeamForm.js.map +2 -2
  378. package/dist/modules/staff/components/TeamMemberForm.js +1 -0
  379. package/dist/modules/staff/components/TeamMemberForm.js.map +2 -2
  380. package/dist/modules/staff/components/TeamRoleForm.js +1 -0
  381. package/dist/modules/staff/components/TeamRoleForm.js.map +2 -2
  382. package/dist/modules/staff/components/detail/JobHistorySection.js +20 -7
  383. package/dist/modules/staff/components/detail/JobHistorySection.js.map +2 -2
  384. package/dist/modules/staff/data/validators.js +7 -1
  385. package/dist/modules/staff/data/validators.js.map +2 -2
  386. package/dist/modules/staff/lib/leaveRequestHelpers.js +2 -1
  387. package/dist/modules/staff/lib/leaveRequestHelpers.js.map +2 -2
  388. package/dist/modules/translations/components/TranslationManager.js +12 -8
  389. package/dist/modules/translations/components/TranslationManager.js.map +2 -2
  390. package/dist/modules/workflows/api/definitions/[id]/route.js +106 -0
  391. package/dist/modules/workflows/api/definitions/[id]/route.js.map +2 -2
  392. package/dist/modules/workflows/backend/definitions/[id]/page.js +11 -3
  393. package/dist/modules/workflows/backend/definitions/[id]/page.js.map +2 -2
  394. package/dist/modules/workflows/backend/definitions/page.js +19 -8
  395. package/dist/modules/workflows/backend/definitions/page.js.map +2 -2
  396. package/dist/modules/workflows/backend/definitions/visual-editor/page.js +29 -16
  397. package/dist/modules/workflows/backend/definitions/visual-editor/page.js.map +2 -2
  398. package/dist/modules/workflows/components/formConfig.js +4 -1
  399. package/dist/modules/workflows/components/formConfig.js.map +2 -2
  400. package/dist/modules/workflows/di.js +12 -0
  401. package/dist/modules/workflows/di.js.map +2 -2
  402. package/generated/entities/role/index.ts +1 -0
  403. package/generated/entities/user/index.ts +1 -0
  404. package/generated/entity-fields-registry.ts +2 -0
  405. package/jest.setup.ts +17 -0
  406. package/package.json +8 -7
  407. package/src/helpers/integration/optimisticLockUi.ts +172 -0
  408. package/src/helpers/integration/salesFixtures.ts +29 -0
  409. package/src/modules/api_keys/backend/api-keys/page.tsx +10 -5
  410. package/src/modules/attachments/components/AttachmentPartitionSettings.tsx +19 -9
  411. package/src/modules/auth/api/roles/acl/route.ts +37 -11
  412. package/src/modules/auth/api/roles/route.ts +2 -0
  413. package/src/modules/auth/api/sidebar/preferences/route.ts +73 -0
  414. package/src/modules/auth/api/users/acl/route.ts +46 -18
  415. package/src/modules/auth/api/users/route.ts +2 -0
  416. package/src/modules/auth/backend/roles/[id]/edit/page.tsx +29 -4
  417. package/src/modules/auth/backend/roles/page.tsx +9 -4
  418. package/src/modules/auth/backend/users/[id]/edit/page.tsx +37 -4
  419. package/src/modules/auth/backend/users/page.tsx +7 -2
  420. package/src/modules/auth/components/AclEditor.tsx +10 -1
  421. package/src/modules/auth/data/entities.ts +7 -1
  422. package/src/modules/auth/services/sidebarPreferencesService.ts +38 -4
  423. package/src/modules/business_rules/api/rules/route.ts +30 -0
  424. package/src/modules/business_rules/api/sets/route.ts +30 -0
  425. package/src/modules/business_rules/backend/rules/[id]/page.tsx +16 -4
  426. package/src/modules/business_rules/backend/rules/page.tsx +20 -11
  427. package/src/modules/business_rules/backend/sets/[id]/page.tsx +16 -4
  428. package/src/modules/business_rules/backend/sets/page.tsx +20 -11
  429. package/src/modules/catalog/api/categories/route.ts +3 -0
  430. package/src/modules/catalog/api/products/route.ts +4 -0
  431. package/src/modules/catalog/backend/catalog/categories/[id]/edit/page.tsx +5 -0
  432. package/src/modules/catalog/backend/catalog/products/[id]/page.tsx +112 -35
  433. package/src/modules/catalog/backend/catalog/products/[productId]/variants/[variantId]/page.tsx +56 -7
  434. package/src/modules/catalog/backend/catalog/products/optionSchemaClient.ts +2 -0
  435. package/src/modules/catalog/commands/variants.ts +32 -32
  436. package/src/modules/catalog/components/PriceKindSettings.tsx +20 -7
  437. package/src/modules/catalog/components/categories/CategoriesDataTable.tsx +1 -0
  438. package/src/modules/catalog/components/products/ProductMediaManager.tsx +2 -0
  439. package/src/modules/catalog/components/products/ProductsDataTable.tsx +8 -4
  440. package/src/modules/catalog/components/products/productForm.ts +3 -0
  441. package/src/modules/catalog/components/products/variantForm.ts +9 -0
  442. package/src/modules/communication_channels/backend/profile/communication-channels/page.tsx +5 -0
  443. package/src/modules/currencies/backend/currencies/[id]/page.tsx +13 -6
  444. package/src/modules/currencies/backend/currencies/page.tsx +18 -11
  445. package/src/modules/currencies/backend/exchange-rates/[id]/page.tsx +3 -0
  446. package/src/modules/currencies/backend/exchange-rates/page.tsx +10 -6
  447. package/src/modules/currencies/commands/currencies.ts +10 -5
  448. package/src/modules/currencies/components/CurrencyFetchingConfig.tsx +31 -21
  449. package/src/modules/customer_accounts/api/admin/roles/[id].ts +35 -5
  450. package/src/modules/customer_accounts/api/admin/roles.ts +2 -0
  451. package/src/modules/customer_accounts/api/admin/users/[id].ts +38 -5
  452. package/src/modules/customer_accounts/api/admin/users.ts +2 -0
  453. package/src/modules/customer_accounts/backend/customer_accounts/roles/[id]/page.tsx +34 -20
  454. package/src/modules/customer_accounts/backend/customer_accounts/roles/page.tsx +9 -4
  455. package/src/modules/customer_accounts/backend/customer_accounts/settings/domain/page.tsx +11 -4
  456. package/src/modules/customer_accounts/backend/customer_accounts/users/[id]/page.tsx +28 -17
  457. package/src/modules/customer_accounts/backend/customer_accounts/users/page.tsx +19 -11
  458. package/src/modules/customers/AGENTS.md +2 -2
  459. package/src/modules/customers/api/companies/route.ts +14 -1
  460. package/src/modules/customers/api/deals/route.ts +3 -0
  461. package/src/modules/customers/api/people/route.ts +12 -1
  462. package/src/modules/customers/api/todos/route.ts +1 -0
  463. package/src/modules/customers/backend/config/customers/deals/page.tsx +1 -0
  464. package/src/modules/customers/backend/config/customers/pipeline-stages/page.tsx +36 -21
  465. package/src/modules/customers/backend/customers/companies/[id]/page.tsx +52 -27
  466. package/src/modules/customers/backend/customers/companies/page.tsx +2 -0
  467. package/src/modules/customers/backend/customers/companies-v2/[id]/page.tsx +27 -5
  468. package/src/modules/customers/backend/customers/deals/[id]/hooks/useDealFormHandlers.ts +39 -7
  469. package/src/modules/customers/backend/customers/deals/[id]/page.tsx +1 -0
  470. package/src/modules/customers/backend/customers/deals/page.tsx +18 -6
  471. package/src/modules/customers/backend/customers/deals/pipeline/page.tsx +64 -39
  472. package/src/modules/customers/backend/customers/people/[id]/page.tsx +46 -26
  473. package/src/modules/customers/backend/customers/people/page.tsx +2 -0
  474. package/src/modules/customers/backend/customers/people-v2/[id]/page.tsx +84 -24
  475. package/src/modules/customers/commands/addresses.ts +16 -14
  476. package/src/modules/customers/commands/companies.ts +3 -1
  477. package/src/modules/customers/commands/interactions.ts +50 -4
  478. package/src/modules/customers/commands/people.ts +2 -1
  479. package/src/modules/customers/commands/personCompanyLinks.ts +8 -5
  480. package/src/modules/customers/commands/pipeline-stages.ts +16 -16
  481. package/src/modules/customers/components/AddressFormatSettings.tsx +1 -0
  482. package/src/modules/customers/components/DictionarySettings.tsx +18 -13
  483. package/src/modules/customers/components/DictionarySortSettings.tsx +4 -0
  484. package/src/modules/customers/components/PipelineSettings.tsx +42 -21
  485. package/src/modules/customers/components/detail/ActivityTimeline.tsx +3 -3
  486. package/src/modules/customers/components/detail/AddressesSection.tsx +4 -0
  487. package/src/modules/customers/components/detail/CompanyPeopleSection.tsx +2 -0
  488. package/src/modules/customers/components/detail/DealsSection.tsx +4 -0
  489. package/src/modules/customers/components/detail/EmailCardActions.tsx +5 -0
  490. package/src/modules/customers/components/detail/EntityTagsDialog.tsx +7 -0
  491. package/src/modules/customers/components/detail/ManageTagsDialog.tsx +4 -0
  492. package/src/modules/customers/components/detail/PersonCompaniesSection.tsx +4 -0
  493. package/src/modules/customers/components/detail/RoleAssignmentRow.tsx +2 -0
  494. package/src/modules/customers/components/detail/ScheduleActivityDialog.tsx +23 -7
  495. package/src/modules/customers/components/detail/hooks/useInteractionMutations.ts +25 -15
  496. package/src/modules/customers/components/detail/hooks/useInteractions.ts +76 -35
  497. package/src/modules/customers/components/detail/hooks/usePersonTasks.ts +30 -17
  498. package/src/modules/customers/components/detail/schedule/useScheduleFormState.ts +2 -0
  499. package/src/modules/customers/components/detail/types.ts +1 -0
  500. package/src/modules/customers/components/formConfig.tsx +2 -0
  501. package/src/modules/customers/data/guards.ts +67 -0
  502. package/src/modules/customers/di.ts +66 -0
  503. package/src/modules/customers/i18n/de.json +2 -0
  504. package/src/modules/customers/i18n/en.json +2 -0
  505. package/src/modules/customers/i18n/es.json +2 -0
  506. package/src/modules/customers/i18n/pl.json +2 -0
  507. package/src/modules/customers/lib/todoCompatibility.ts +14 -0
  508. package/src/modules/dashboards/components/WidgetVisibilityEditor.tsx +2 -0
  509. package/src/modules/data_sync/api/options.ts +7 -4
  510. package/src/modules/data_sync/api/schedules/route.ts +9 -1
  511. package/src/modules/data_sync/backend/data-sync/page.tsx +18 -5
  512. package/src/modules/data_sync/components/IntegrationScheduleTab.tsx +46 -19
  513. package/src/modules/data_sync/lib/sync-schedule-service.ts +11 -0
  514. package/src/modules/dictionaries/api/[dictionaryId]/entries/[entryId]/route.ts +8 -1
  515. package/src/modules/dictionaries/api/[dictionaryId]/route.ts +23 -0
  516. package/src/modules/dictionaries/components/DictionariesManager.tsx +32 -9
  517. package/src/modules/dictionaries/components/DictionaryEntriesEditor.tsx +30 -14
  518. package/src/modules/dictionaries/i18n/de.json +1 -0
  519. package/src/modules/dictionaries/i18n/en.json +1 -0
  520. package/src/modules/dictionaries/i18n/es.json +1 -0
  521. package/src/modules/dictionaries/i18n/pl.json +1 -0
  522. package/src/modules/directory/api/organizations/route.ts +3 -0
  523. package/src/modules/directory/backend/directory/organizations/[id]/edit/page.tsx +8 -0
  524. package/src/modules/directory/backend/directory/organizations/page.tsx +10 -5
  525. package/src/modules/directory/backend/directory/tenants/[id]/edit/page.tsx +16 -5
  526. package/src/modules/directory/backend/directory/tenants/page.tsx +8 -4
  527. package/src/modules/directory/commands/organizations.ts +7 -4
  528. package/src/modules/entities/api/records.ts +99 -0
  529. package/src/modules/entities/backend/entities/user/[entityId]/records/[recordId]/page.tsx +7 -0
  530. package/src/modules/entities/backend/entities/user/[entityId]/records/page.tsx +8 -4
  531. package/src/modules/entities/lib/helpers.ts +17 -0
  532. package/src/modules/feature_toggles/api/global/[id]/override/route.ts +1 -0
  533. package/src/modules/feature_toggles/api/overrides/route.ts +19 -0
  534. package/src/modules/feature_toggles/backend/feature-toggles/global/[id]/edit/page.tsx +19 -13
  535. package/src/modules/feature_toggles/components/FeatureToggleOverrideCard.tsx +22 -12
  536. package/src/modules/feature_toggles/components/FeatureTogglesTable.tsx +7 -2
  537. package/src/modules/feature_toggles/components/formConfig.tsx +2 -1
  538. package/src/modules/feature_toggles/components/overrideFormConfig.tsx +10 -1
  539. package/src/modules/feature_toggles/data/validators.ts +11 -3
  540. package/src/modules/inbox_ops/api/settings/route.ts +18 -0
  541. package/src/modules/inbox_ops/backend/inbox-ops/settings/page.tsx +15 -10
  542. package/src/modules/inbox_ops/components/proposals/EditActionDialog.tsx +9 -4
  543. package/src/modules/integrations/backend/integrations/bundle/[id]/page.tsx +20 -11
  544. package/src/modules/integrations/backend/integrations/page.tsx +13 -8
  545. package/src/modules/messages/commands/messages.ts +27 -15
  546. package/src/modules/perspectives/api/[tableId]/route.ts +11 -2
  547. package/src/modules/perspectives/services/perspectiveService.ts +13 -1
  548. package/src/modules/planner/backend/planner/availability-rulesets/[id]/page.tsx +16 -14
  549. package/src/modules/planner/backend/planner/availability-rulesets/page.tsx +6 -3
  550. package/src/modules/planner/components/AvailabilityRuleSetForm.tsx +3 -0
  551. package/src/modules/planner/components/AvailabilityRulesEditor.tsx +58 -15
  552. package/src/modules/planner/components/AvailabilitySchedule.tsx +22 -7
  553. package/src/modules/query_index/lib/engine.ts +34 -0
  554. package/src/modules/resources/backend/resources/resource-types/[id]/edit/page.tsx +7 -1
  555. package/src/modules/resources/backend/resources/resource-types/page.tsx +6 -3
  556. package/src/modules/resources/backend/resources/resources/[id]/page.tsx +23 -3
  557. package/src/modules/resources/backend/resources/resources/page.tsx +15 -4
  558. package/src/modules/resources/components/ResourceCrudForm.tsx +3 -0
  559. package/src/modules/resources/components/ResourceTypeCrudForm.tsx +2 -0
  560. package/src/modules/sales/api/documents/factory.ts +13 -1
  561. package/src/modules/sales/backend/sales/channels/[channelId]/edit/page.tsx +6 -0
  562. package/src/modules/sales/backend/sales/channels/offers/page.tsx +10 -4
  563. package/src/modules/sales/backend/sales/channels/page.tsx +19 -4
  564. package/src/modules/sales/backend/sales/documents/[id]/page.tsx +73 -20
  565. package/src/modules/sales/backend/sales/documents/create/page.tsx +2 -0
  566. package/src/modules/sales/commands/documentAddresses.ts +226 -4
  567. package/src/modules/sales/commands/documents.ts +28 -0
  568. package/src/modules/sales/commands/returns.ts +12 -3
  569. package/src/modules/sales/commands/shared.ts +36 -0
  570. package/src/modules/sales/commands/shipments.ts +17 -1
  571. package/src/modules/sales/components/AdjustmentKindSettings.tsx +20 -11
  572. package/src/modules/sales/components/DocumentNumberSettings.tsx +1 -0
  573. package/src/modules/sales/components/OrderEditingSettings.tsx +1 -0
  574. package/src/modules/sales/components/PaymentMethodsSettings.tsx +12 -4
  575. package/src/modules/sales/components/ShippingMethodsSettings.tsx +12 -4
  576. package/src/modules/sales/components/StatusSettings.tsx +20 -11
  577. package/src/modules/sales/components/TaxRatesSettings.tsx +12 -5
  578. package/src/modules/sales/components/channels/ChannelOfferForm.tsx +67 -14
  579. package/src/modules/sales/components/channels/SalesChannelOffersPanel.tsx +7 -4
  580. package/src/modules/sales/components/documents/AddressesSection.tsx +35 -25
  581. package/src/modules/sales/components/documents/AdjustmentsSection.tsx +50 -25
  582. package/src/modules/sales/components/documents/ItemsSection.tsx +24 -13
  583. package/src/modules/sales/components/documents/LineItemDialog.tsx +26 -9
  584. package/src/modules/sales/components/documents/PaymentDialog.tsx +33 -14
  585. package/src/modules/sales/components/documents/PaymentsSection.tsx +22 -10
  586. package/src/modules/sales/components/documents/ReturnDialog.tsx +28 -17
  587. package/src/modules/sales/components/documents/ReturnsSection.tsx +4 -1
  588. package/src/modules/sales/components/documents/SalesDocumentsTable.tsx +11 -4
  589. package/src/modules/sales/components/documents/ShipmentDialog.tsx +23 -8
  590. package/src/modules/sales/components/documents/ShipmentsSection.tsx +20 -10
  591. package/src/modules/sales/components/documents/optimisticLock.ts +34 -0
  592. package/src/modules/sales/components/documents/shipmentTypes.ts +1 -0
  593. package/src/modules/sales/di.ts +35 -0
  594. package/src/modules/sales/i18n/de.json +3 -0
  595. package/src/modules/sales/i18n/en.json +3 -0
  596. package/src/modules/sales/i18n/es.json +3 -0
  597. package/src/modules/sales/i18n/pl.json +3 -0
  598. package/src/modules/staff/api/job-histories.ts +12 -2
  599. package/src/modules/staff/api/timesheets/time-entries/route.ts +16 -4
  600. package/src/modules/staff/backend/staff/leave-requests/[id]/page.tsx +12 -7
  601. package/src/modules/staff/backend/staff/my-leave-requests/[id]/page.tsx +2 -0
  602. package/src/modules/staff/backend/staff/team-members/[id]/page.tsx +16 -5
  603. package/src/modules/staff/backend/staff/team-members/page.tsx +6 -2
  604. package/src/modules/staff/backend/staff/team-roles/[id]/edit/page.tsx +8 -0
  605. package/src/modules/staff/backend/staff/team-roles/page.tsx +6 -2
  606. package/src/modules/staff/backend/staff/teams/[id]/edit/page.tsx +13 -3
  607. package/src/modules/staff/backend/staff/teams/page.tsx +9 -3
  608. package/src/modules/staff/backend/staff/timesheets/page.tsx +10 -1
  609. package/src/modules/staff/backend/staff/timesheets/projects/[id]/page.tsx +4 -0
  610. package/src/modules/staff/backend/staff/timesheets/projects/page.tsx +9 -3
  611. package/src/modules/staff/commands/job-histories.ts +42 -3
  612. package/src/modules/staff/components/LeaveRequestForm.tsx +2 -0
  613. package/src/modules/staff/components/TeamForm.tsx +2 -0
  614. package/src/modules/staff/components/TeamMemberForm.tsx +2 -0
  615. package/src/modules/staff/components/TeamRoleForm.tsx +2 -0
  616. package/src/modules/staff/components/detail/JobHistorySection.tsx +28 -6
  617. package/src/modules/staff/data/validators.ts +6 -0
  618. package/src/modules/staff/i18n/de.json +1 -0
  619. package/src/modules/staff/i18n/en.json +1 -0
  620. package/src/modules/staff/i18n/es.json +1 -0
  621. package/src/modules/staff/i18n/pl.json +1 -0
  622. package/src/modules/staff/lib/leaveRequestHelpers.ts +4 -0
  623. package/src/modules/translations/components/TranslationManager.tsx +13 -8
  624. package/src/modules/workflows/api/definitions/[id]/route.ts +112 -0
  625. package/src/modules/workflows/backend/definitions/[id]/page.tsx +20 -4
  626. package/src/modules/workflows/backend/definitions/page.tsx +20 -9
  627. package/src/modules/workflows/backend/definitions/visual-editor/page.tsx +29 -16
  628. package/src/modules/workflows/components/formConfig.tsx +5 -0
  629. package/src/modules/workflows/di.ts +20 -0
  630. package/src/modules/workflows/i18n/de.json +1 -0
  631. package/src/modules/workflows/i18n/en.json +1 -0
  632. package/src/modules/workflows/i18n/es.json +1 -0
  633. package/src/modules/workflows/i18n/pl.json +1 -0
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/modules/customers/components/DictionarySortSettings.tsx"],
4
- "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { Spinner } from '@open-mercato/ui/primitives/spinner'\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '@open-mercato/ui/primitives/select'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { apiCallOrThrow, readApiResultOrThrow } from '@open-mercato/ui/backend/utils/apiCall'\nimport { useGuardedMutation } from '@open-mercato/ui/backend/injection/useGuardedMutation'\nimport { useOrganizationScopeVersion } from '@open-mercato/shared/lib/frontend/useOrganizationScope'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport {\n DEFAULT_DICTIONARY_ENTRY_SORT_MODE,\n dictionaryEntrySortModes,\n type DictionaryEntrySortMode,\n} from '@open-mercato/core/modules/dictionaries/lib/entrySort'\nimport type { CustomerDictionaryKind } from '../lib/dictionaries'\n\nconst SAVE_CONTEXT_ID = 'customers-dictionary-sort-modes'\n\ntype SortModeMap = Partial<Record<CustomerDictionaryKind, DictionaryEntrySortMode>>\n\ntype DictionarySortSection = {\n kind: CustomerDictionaryKind\n title: string\n description: string\n}\n\nfunction isDictionaryEntrySortMode(value: string): value is DictionaryEntrySortMode {\n return dictionaryEntrySortModes.includes(value as DictionaryEntrySortMode)\n}\n\nexport function DictionarySortSettings() {\n const t = useT()\n const scopeVersion = useOrganizationScopeVersion()\n const [sortModes, setSortModes] = React.useState<SortModeMap>({})\n const [loading, setLoading] = React.useState(true)\n const [savingKind, setSavingKind] = React.useState<CustomerDictionaryKind | null>(null)\n const [error, setError] = React.useState<string | null>(null)\n\n const sections = React.useMemo<DictionarySortSection[]>(() => [\n {\n kind: 'statuses',\n title: t('customers.config.dictionaries.sections.statuses.title', 'Statuses'),\n description: t('customers.config.dictionaries.sections.statuses.description', 'Define the statuses available for customer records.'),\n },\n {\n kind: 'sources',\n title: t('customers.config.dictionaries.sections.sources.title', 'Sources'),\n description: t('customers.config.dictionaries.sections.sources.description', 'Capture how customers were acquired.'),\n },\n {\n kind: 'lifecycle-stages',\n title: t('customers.config.dictionaries.sections.lifecycle.title', 'Lifecycle stages'),\n description: t('customers.config.dictionaries.sections.lifecycle.description', 'Configure lifecycle stages to track customer progress.'),\n },\n {\n kind: 'deal-statuses',\n title: t('customers.config.dictionaries.sections.dealStatuses.title', 'Deal statuses'),\n description: t('customers.config.dictionaries.sections.dealStatuses.description', 'Manage the statuses available for deals.'),\n },\n {\n kind: 'pipeline-stages',\n title: t('customers.config.dictionaries.sections.pipelineStages.title', 'Pipeline stages'),\n description: t('customers.config.dictionaries.sections.pipelineStages.description', 'Define the stages used in your deal pipeline.'),\n },\n {\n kind: 'person-company-roles',\n title: t('customers.config.dictionaries.sections.personCompanyRoles.title', 'Role types'),\n description: t('customers.config.dictionaries.sections.personCompanyRoles.description', 'Manage the ownership roles available in People tab assignments.'),\n },\n {\n kind: 'job-titles',\n title: t('customers.config.dictionaries.sections.jobTitles.title', 'Job titles'),\n description: t('customers.config.dictionaries.sections.jobTitles.description', 'Configure job titles with their appearance.'),\n },\n {\n kind: 'industries',\n title: t('customers.config.dictionaries.sections.industries.title', 'Industries'),\n description: t('customers.config.dictionaries.sections.industries.description', 'Manage the industries used by companies.'),\n },\n {\n kind: 'activity-types',\n title: t('customers.config.dictionaries.sections.activityTypes.title', 'Activity types'),\n description: t('customers.config.dictionaries.sections.activityTypes.description', 'Define the activity types used for customer interactions.'),\n },\n {\n kind: 'address-types',\n title: t('customers.config.dictionaries.sections.addressTypes.title', 'Address types'),\n description: t('customers.config.dictionaries.sections.addressTypes.description', 'Define the available address types.'),\n },\n ], [t])\n\n const sortOptions = React.useMemo(\n () => dictionaryEntrySortModes.map((mode) => ({\n value: mode,\n label:\n mode === 'label_asc'\n ? t('dictionaries.config.sortModes.labelAsc', 'A to Z')\n : mode === 'label_desc'\n ? t('dictionaries.config.sortModes.labelDesc', 'Z to A')\n : mode === 'value_asc'\n ? t('dictionaries.config.sortModes.valueAsc', 'Value A to Z')\n : mode === 'value_desc'\n ? t('dictionaries.config.sortModes.valueDesc', 'Value Z to A')\n : mode === 'created_at_asc'\n ? t('dictionaries.config.sortModes.createdAtAsc', 'Oldest first')\n : t('dictionaries.config.sortModes.createdAtDesc', 'Newest first'),\n })),\n [t],\n )\n\n const { runMutation, retryLastMutation } = useGuardedMutation<{\n formId: string\n resourceKind: string\n retryLastMutation: () => Promise<boolean>\n }>({\n contextId: SAVE_CONTEXT_ID,\n blockedMessage: t('ui.forms.flash.saveBlocked', 'Save blocked by validation'),\n })\n\n React.useEffect(() => {\n let cancelled = false\n async function load() {\n setLoading(true)\n setError(null)\n try {\n const data = await readApiResultOrThrow<{ dictionarySortModes?: Record<string, string> }>(\n '/api/customers/settings/dictionary-sort-modes',\n undefined,\n { errorMessage: t('customers.config.dictionarySorting.errorLoad', 'Failed to load dictionary sorting settings.') },\n )\n const next: SortModeMap = {}\n for (const section of sections) {\n const value = data?.dictionarySortModes?.[section.kind]\n next[section.kind] = value && isDictionaryEntrySortMode(value)\n ? value\n : DEFAULT_DICTIONARY_ENTRY_SORT_MODE\n }\n if (!cancelled) setSortModes(next)\n } catch (err) {\n console.error('customers.dictionarySorting.load failed', err)\n if (!cancelled) {\n const message = err instanceof Error && err.message\n ? err.message\n : t('customers.config.dictionarySorting.errorLoad', 'Failed to load dictionary sorting settings.')\n setError(message)\n flash(message, 'error')\n }\n } finally {\n if (!cancelled) setLoading(false)\n }\n }\n load().catch(() => {})\n return () => {\n cancelled = true\n }\n }, [scopeVersion, sections, t])\n\n const handleChange = React.useCallback(async (kind: CustomerDictionaryKind, mode: DictionaryEntrySortMode) => {\n const previous = sortModes\n const next = { ...sortModes, [kind]: mode }\n setSortModes(next)\n setSavingKind(kind)\n setError(null)\n try {\n await runMutation({\n operation: async () => {\n await apiCallOrThrow(\n '/api/customers/settings/dictionary-sort-modes',\n {\n method: 'PATCH',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ dictionarySortModes: next }),\n },\n { errorMessage: t('customers.config.dictionarySorting.errorSave', 'Failed to save dictionary sorting settings.') },\n )\n },\n context: {\n formId: SAVE_CONTEXT_ID,\n resourceKind: 'customers.settings',\n retryLastMutation,\n },\n })\n flash(t('customers.config.dictionarySorting.success', 'Dictionary sorting settings saved.'), 'success')\n } catch (err) {\n setSortModes(previous)\n const message = err instanceof Error && err.message\n ? err.message\n : t('customers.config.dictionarySorting.errorSave', 'Failed to save dictionary sorting settings.')\n setError(message)\n flash(message, 'error')\n } finally {\n setSavingKind(null)\n }\n }, [retryLastMutation, runMutation, sortModes, t])\n\n return (\n <section className=\"space-y-4 rounded-lg border bg-background p-4\">\n <header className=\"space-y-1\">\n <h2 className=\"text-lg font-semibold\">\n {t('customers.config.dictionarySorting.title', 'Dictionary sorting')}\n </h2>\n <p className=\"text-sm text-muted-foreground\">\n {t('customers.config.dictionarySorting.description', 'Choose how customer dictionary values are ordered in dropdowns and settings.')}\n </p>\n </header>\n {loading ? (\n <div className=\"flex items-center gap-2 text-sm text-muted-foreground\">\n <Spinner className=\"h-4 w-4\" />\n {t('customers.config.dictionarySorting.loading', 'Loading dictionary sorting settings\u2026')}\n </div>\n ) : (\n <div className=\"grid gap-3 lg:grid-cols-2\">\n {sections.map((section) => {\n const value = sortModes[section.kind] ?? DEFAULT_DICTIONARY_ENTRY_SORT_MODE\n const saving = savingKind === section.kind\n return (\n <div key={section.kind} className=\"rounded border p-3\">\n <div className=\"mb-3 space-y-1\">\n <div className=\"text-sm font-medium\">{section.title}</div>\n <div className=\"text-xs text-muted-foreground\">{section.description}</div>\n </div>\n <Select\n value={value}\n onValueChange={(next) => {\n if (!isDictionaryEntrySortMode(next) || next === value) return\n handleChange(section.kind, next).catch(() => {})\n }}\n disabled={savingKind !== null}\n >\n <SelectTrigger>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {sortOptions.map((option) => (\n <SelectItem key={option.value} value={option.value}>\n {option.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n {saving ? (\n <div className=\"mt-2 inline-flex items-center gap-2 text-xs text-muted-foreground\">\n <Spinner className=\"h-3 w-3\" />\n {t('customers.config.dictionarySorting.updating', 'Saving\u2026')}\n </div>\n ) : null}\n </div>\n )\n })}\n </div>\n )}\n {error ? <p className=\"text-sm text-status-error-text\">{error}</p> : null}\n </section>\n )\n}\n\nexport default DictionarySortSettings\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { Spinner } from '@open-mercato/ui/primitives/spinner'\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '@open-mercato/ui/primitives/select'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { apiCallOrThrow, readApiResultOrThrow } from '@open-mercato/ui/backend/utils/apiCall'\nimport { useGuardedMutation } from '@open-mercato/ui/backend/injection/useGuardedMutation'\nimport { useOrganizationScopeVersion } from '@open-mercato/shared/lib/frontend/useOrganizationScope'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport {\n DEFAULT_DICTIONARY_ENTRY_SORT_MODE,\n dictionaryEntrySortModes,\n type DictionaryEntrySortMode,\n} from '@open-mercato/core/modules/dictionaries/lib/entrySort'\nimport type { CustomerDictionaryKind } from '../lib/dictionaries'\n\nconst SAVE_CONTEXT_ID = 'customers-dictionary-sort-modes'\n\ntype SortModeMap = Partial<Record<CustomerDictionaryKind, DictionaryEntrySortMode>>\n\ntype DictionarySortSection = {\n kind: CustomerDictionaryKind\n title: string\n description: string\n}\n\nfunction isDictionaryEntrySortMode(value: string): value is DictionaryEntrySortMode {\n return dictionaryEntrySortModes.includes(value as DictionaryEntrySortMode)\n}\n\nexport function DictionarySortSettings() {\n const t = useT()\n const scopeVersion = useOrganizationScopeVersion()\n const [sortModes, setSortModes] = React.useState<SortModeMap>({})\n const [loading, setLoading] = React.useState(true)\n const [savingKind, setSavingKind] = React.useState<CustomerDictionaryKind | null>(null)\n const [error, setError] = React.useState<string | null>(null)\n\n const sections = React.useMemo<DictionarySortSection[]>(() => [\n {\n kind: 'statuses',\n title: t('customers.config.dictionaries.sections.statuses.title', 'Statuses'),\n description: t('customers.config.dictionaries.sections.statuses.description', 'Define the statuses available for customer records.'),\n },\n {\n kind: 'sources',\n title: t('customers.config.dictionaries.sections.sources.title', 'Sources'),\n description: t('customers.config.dictionaries.sections.sources.description', 'Capture how customers were acquired.'),\n },\n {\n kind: 'lifecycle-stages',\n title: t('customers.config.dictionaries.sections.lifecycle.title', 'Lifecycle stages'),\n description: t('customers.config.dictionaries.sections.lifecycle.description', 'Configure lifecycle stages to track customer progress.'),\n },\n {\n kind: 'deal-statuses',\n title: t('customers.config.dictionaries.sections.dealStatuses.title', 'Deal statuses'),\n description: t('customers.config.dictionaries.sections.dealStatuses.description', 'Manage the statuses available for deals.'),\n },\n {\n kind: 'pipeline-stages',\n title: t('customers.config.dictionaries.sections.pipelineStages.title', 'Pipeline stages'),\n description: t('customers.config.dictionaries.sections.pipelineStages.description', 'Define the stages used in your deal pipeline.'),\n },\n {\n kind: 'person-company-roles',\n title: t('customers.config.dictionaries.sections.personCompanyRoles.title', 'Role types'),\n description: t('customers.config.dictionaries.sections.personCompanyRoles.description', 'Manage the ownership roles available in People tab assignments.'),\n },\n {\n kind: 'job-titles',\n title: t('customers.config.dictionaries.sections.jobTitles.title', 'Job titles'),\n description: t('customers.config.dictionaries.sections.jobTitles.description', 'Configure job titles with their appearance.'),\n },\n {\n kind: 'industries',\n title: t('customers.config.dictionaries.sections.industries.title', 'Industries'),\n description: t('customers.config.dictionaries.sections.industries.description', 'Manage the industries used by companies.'),\n },\n {\n kind: 'activity-types',\n title: t('customers.config.dictionaries.sections.activityTypes.title', 'Activity types'),\n description: t('customers.config.dictionaries.sections.activityTypes.description', 'Define the activity types used for customer interactions.'),\n },\n {\n kind: 'address-types',\n title: t('customers.config.dictionaries.sections.addressTypes.title', 'Address types'),\n description: t('customers.config.dictionaries.sections.addressTypes.description', 'Define the available address types.'),\n },\n ], [t])\n\n const sortOptions = React.useMemo(\n () => dictionaryEntrySortModes.map((mode) => ({\n value: mode,\n label:\n mode === 'label_asc'\n ? t('dictionaries.config.sortModes.labelAsc', 'A to Z')\n : mode === 'label_desc'\n ? t('dictionaries.config.sortModes.labelDesc', 'Z to A')\n : mode === 'value_asc'\n ? t('dictionaries.config.sortModes.valueAsc', 'Value A to Z')\n : mode === 'value_desc'\n ? t('dictionaries.config.sortModes.valueDesc', 'Value Z to A')\n : mode === 'created_at_asc'\n ? t('dictionaries.config.sortModes.createdAtAsc', 'Oldest first')\n : t('dictionaries.config.sortModes.createdAtDesc', 'Newest first'),\n })),\n [t],\n )\n\n const { runMutation, retryLastMutation } = useGuardedMutation<{\n formId: string\n resourceKind: string\n retryLastMutation: () => Promise<boolean>\n }>({\n contextId: SAVE_CONTEXT_ID,\n blockedMessage: t('ui.forms.flash.saveBlocked', 'Save blocked by validation'),\n })\n\n React.useEffect(() => {\n let cancelled = false\n async function load() {\n setLoading(true)\n setError(null)\n try {\n const data = await readApiResultOrThrow<{ dictionarySortModes?: Record<string, string> }>(\n '/api/customers/settings/dictionary-sort-modes',\n undefined,\n { errorMessage: t('customers.config.dictionarySorting.errorLoad', 'Failed to load dictionary sorting settings.') },\n )\n const next: SortModeMap = {}\n for (const section of sections) {\n const value = data?.dictionarySortModes?.[section.kind]\n next[section.kind] = value && isDictionaryEntrySortMode(value)\n ? value\n : DEFAULT_DICTIONARY_ENTRY_SORT_MODE\n }\n if (!cancelled) setSortModes(next)\n } catch (err) {\n console.error('customers.dictionarySorting.load failed', err)\n if (!cancelled) {\n const message = err instanceof Error && err.message\n ? err.message\n : t('customers.config.dictionarySorting.errorLoad', 'Failed to load dictionary sorting settings.')\n setError(message)\n flash(message, 'error')\n }\n } finally {\n if (!cancelled) setLoading(false)\n }\n }\n load().catch(() => {})\n return () => {\n cancelled = true\n }\n }, [scopeVersion, sections, t])\n\n const handleChange = React.useCallback(async (kind: CustomerDictionaryKind, mode: DictionaryEntrySortMode) => {\n const previous = sortModes\n const next = { ...sortModes, [kind]: mode }\n setSortModes(next)\n setSavingKind(kind)\n setError(null)\n try {\n await runMutation({\n // optimistic-lock-exempt: tenant-scoped settings blob (dictionary sort\n // modes), not a versioned per-record entity \u2014 there is no `updatedAt`\n // round-trip to lock against, and concurrent writes converge on the\n // last-selected preference. Mirrors other singleton settings PATCHes.\n operation: async () => {\n await apiCallOrThrow(\n '/api/customers/settings/dictionary-sort-modes',\n {\n method: 'PATCH',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ dictionarySortModes: next }),\n },\n { errorMessage: t('customers.config.dictionarySorting.errorSave', 'Failed to save dictionary sorting settings.') },\n )\n },\n context: {\n formId: SAVE_CONTEXT_ID,\n resourceKind: 'customers.settings',\n retryLastMutation,\n },\n })\n flash(t('customers.config.dictionarySorting.success', 'Dictionary sorting settings saved.'), 'success')\n } catch (err) {\n setSortModes(previous)\n const message = err instanceof Error && err.message\n ? err.message\n : t('customers.config.dictionarySorting.errorSave', 'Failed to save dictionary sorting settings.')\n setError(message)\n flash(message, 'error')\n } finally {\n setSavingKind(null)\n }\n }, [retryLastMutation, runMutation, sortModes, t])\n\n return (\n <section className=\"space-y-4 rounded-lg border bg-background p-4\">\n <header className=\"space-y-1\">\n <h2 className=\"text-lg font-semibold\">\n {t('customers.config.dictionarySorting.title', 'Dictionary sorting')}\n </h2>\n <p className=\"text-sm text-muted-foreground\">\n {t('customers.config.dictionarySorting.description', 'Choose how customer dictionary values are ordered in dropdowns and settings.')}\n </p>\n </header>\n {loading ? (\n <div className=\"flex items-center gap-2 text-sm text-muted-foreground\">\n <Spinner className=\"h-4 w-4\" />\n {t('customers.config.dictionarySorting.loading', 'Loading dictionary sorting settings\u2026')}\n </div>\n ) : (\n <div className=\"grid gap-3 lg:grid-cols-2\">\n {sections.map((section) => {\n const value = sortModes[section.kind] ?? DEFAULT_DICTIONARY_ENTRY_SORT_MODE\n const saving = savingKind === section.kind\n return (\n <div key={section.kind} className=\"rounded border p-3\">\n <div className=\"mb-3 space-y-1\">\n <div className=\"text-sm font-medium\">{section.title}</div>\n <div className=\"text-xs text-muted-foreground\">{section.description}</div>\n </div>\n <Select\n value={value}\n onValueChange={(next) => {\n if (!isDictionaryEntrySortMode(next) || next === value) return\n handleChange(section.kind, next).catch(() => {})\n }}\n disabled={savingKind !== null}\n >\n <SelectTrigger>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {sortOptions.map((option) => (\n <SelectItem key={option.value} value={option.value}>\n {option.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n {saving ? (\n <div className=\"mt-2 inline-flex items-center gap-2 text-xs text-muted-foreground\">\n <Spinner className=\"h-3 w-3\" />\n {t('customers.config.dictionarySorting.updating', 'Saving\u2026')}\n </div>\n ) : null}\n </div>\n )\n })}\n </div>\n )}\n {error ? <p className=\"text-sm text-status-error-text\">{error}</p> : null}\n </section>\n )\n}\n\nexport default DictionarySortSettings\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -13,7 +13,8 @@ import {
13
13
  DialogTitle
14
14
  } from "@open-mercato/ui/primitives/dialog";
15
15
  import { flash } from "@open-mercato/ui/backend/FlashMessages";
16
- import { apiCall, readApiResultOrThrow } from "@open-mercato/ui/backend/utils/apiCall";
16
+ import { apiCall, readApiResultOrThrow, withScopedApiRequestHeaders } from "@open-mercato/ui/backend/utils/apiCall";
17
+ import { buildOptimisticLockHeader } from "@open-mercato/ui/backend/utils/optimisticLock";
17
18
  import { raiseCrudError } from "@open-mercato/ui/backend/utils/serverErrors";
18
19
  import { useOrganizationScopeVersion } from "@open-mercato/shared/lib/frontend/useOrganizationScope";
19
20
  import { useT } from "@open-mercato/shared/lib/i18n/context";
@@ -38,7 +39,8 @@ function normalizePipeline(raw) {
38
39
  name: typeof raw.name === "string" ? raw.name : "",
39
40
  isDefault: raw.isDefault === true || raw.is_default === true,
40
41
  organizationId: typeof raw.organizationId === "string" ? raw.organizationId : typeof raw.organization_id === "string" ? raw.organization_id : "",
41
- tenantId: typeof raw.tenantId === "string" ? raw.tenantId : typeof raw.tenant_id === "string" ? raw.tenant_id : ""
42
+ tenantId: typeof raw.tenantId === "string" ? raw.tenantId : typeof raw.tenant_id === "string" ? raw.tenant_id : "",
43
+ updatedAt: typeof raw.updatedAt === "string" ? raw.updatedAt : typeof raw.updated_at === "string" ? raw.updated_at : null
42
44
  };
43
45
  }
44
46
  function normalizeStage(raw) {
@@ -48,7 +50,8 @@ function normalizeStage(raw) {
48
50
  label: typeof raw.label === "string" ? raw.label : "",
49
51
  order: typeof raw.order === "number" ? raw.order : 0,
50
52
  color: typeof raw.color === "string" && raw.color.trim().length ? raw.color.trim() : null,
51
- icon: typeof raw.icon === "string" && raw.icon.trim().length ? raw.icon.trim() : null
53
+ icon: typeof raw.icon === "string" && raw.icon.trim().length ? raw.icon.trim() : null,
54
+ updatedAt: typeof raw.updatedAt === "string" ? raw.updatedAt : typeof raw.updated_at === "string" ? raw.updated_at : null
52
55
  };
53
56
  }
54
57
  function PipelineSettings() {
@@ -132,11 +135,14 @@ function PipelineSettings() {
132
135
  }
133
136
  flash(t("customers.pipelines.flash.created", "Pipeline created"), "success");
134
137
  } else if (pipelineDialog?.mode === "edit") {
135
- const res = await apiCall("/api/customers/pipelines", {
136
- method: "PUT",
137
- headers: { "content-type": "application/json" },
138
- body: JSON.stringify({ id: pipelineDialog.entry.id, name: pipelineForm.name.trim(), isDefault: pipelineForm.isDefault })
139
- });
138
+ const res = await withScopedApiRequestHeaders(
139
+ buildOptimisticLockHeader(pipelineDialog.entry.updatedAt),
140
+ () => apiCall("/api/customers/pipelines", {
141
+ method: "PUT",
142
+ headers: { "content-type": "application/json" },
143
+ body: JSON.stringify({ id: pipelineDialog.entry.id, name: pipelineForm.name.trim(), isDefault: pipelineForm.isDefault })
144
+ })
145
+ );
140
146
  if (!res.ok) {
141
147
  await raiseCrudError(res.response, t("customers.pipelines.errors.updateFailed", "Failed to update pipeline"));
142
148
  return;
@@ -157,11 +163,14 @@ function PipelineSettings() {
157
163
  variant: "destructive"
158
164
  });
159
165
  if (!confirmed) return;
160
- const res = await apiCall("/api/customers/pipelines", {
161
- method: "DELETE",
162
- headers: { "content-type": "application/json" },
163
- body: JSON.stringify({ id: pipeline.id })
164
- });
166
+ const res = await withScopedApiRequestHeaders(
167
+ buildOptimisticLockHeader(pipeline.updatedAt),
168
+ () => apiCall("/api/customers/pipelines", {
169
+ method: "DELETE",
170
+ headers: { "content-type": "application/json" },
171
+ body: JSON.stringify({ id: pipeline.id })
172
+ })
173
+ );
165
174
  if (!res.ok) {
166
175
  const body = res.result ?? {};
167
176
  const msg = typeof body.error === "string" ? body.error : t("customers.pipelines.errors.deleteFailed", "Failed to delete pipeline");
@@ -203,11 +212,14 @@ function PipelineSettings() {
203
212
  flash(t("customers.pipelines.flash.stageCreated", "Stage created"), "success");
204
213
  await loadStages(stageDialog.pipelineId);
205
214
  } else if (stageDialog?.mode === "edit") {
206
- const res = await apiCall("/api/customers/pipeline-stages", {
207
- method: "PUT",
208
- headers: { "content-type": "application/json" },
209
- body: JSON.stringify({ id: stageDialog.entry.id, label: stageForm.label.trim(), ...appearance })
210
- });
215
+ const res = await withScopedApiRequestHeaders(
216
+ buildOptimisticLockHeader(stageDialog.entry.updatedAt),
217
+ () => apiCall("/api/customers/pipeline-stages", {
218
+ method: "PUT",
219
+ headers: { "content-type": "application/json" },
220
+ body: JSON.stringify({ id: stageDialog.entry.id, label: stageForm.label.trim(), ...appearance })
221
+ })
222
+ );
211
223
  if (!res.ok) {
212
224
  await raiseCrudError(res.response, t("customers.pipelines.errors.stageUpdateFailed", "Failed to update stage"));
213
225
  return;
@@ -228,11 +240,14 @@ function PipelineSettings() {
228
240
  variant: "destructive"
229
241
  });
230
242
  if (!confirmed) return;
231
- const res = await apiCall("/api/customers/pipeline-stages", {
232
- method: "DELETE",
233
- headers: { "content-type": "application/json" },
234
- body: JSON.stringify({ id: stage.id })
235
- });
243
+ const res = await withScopedApiRequestHeaders(
244
+ buildOptimisticLockHeader(stage.updatedAt),
245
+ () => apiCall("/api/customers/pipeline-stages", {
246
+ method: "DELETE",
247
+ headers: { "content-type": "application/json" },
248
+ body: JSON.stringify({ id: stage.id })
249
+ })
250
+ );
236
251
  if (!res.ok) {
237
252
  const body = res.result ?? {};
238
253
  const msg = typeof body.error === "string" ? body.error : t("customers.pipelines.errors.stageDeleteFailed", "Failed to delete stage");
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/modules/customers/components/PipelineSettings.tsx"],
4
- "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { Input } from '@open-mercato/ui/primitives/input'\nimport { Label } from '@open-mercato/ui/primitives/label'\nimport { Checkbox } from '@open-mercato/ui/primitives/checkbox'\nimport {\n Dialog,\n DialogContent,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n} from '@open-mercato/ui/primitives/dialog'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { apiCall, readApiResultOrThrow } from '@open-mercato/ui/backend/utils/apiCall'\nimport { raiseCrudError } from '@open-mercato/ui/backend/utils/serverErrors'\nimport { useOrganizationScopeVersion } from '@open-mercato/shared/lib/frontend/useOrganizationScope'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { useConfirmDialog } from '@open-mercato/ui/backend/confirm-dialog'\nimport { Spinner } from '@open-mercato/ui/primitives/spinner'\nimport {\n Accordion,\n AccordionContent,\n AccordionItem,\n AccordionTrigger,\n} from '@open-mercato/ui/primitives/accordion'\nimport {\n AppearanceSelector,\n type AppearanceSelectorLabels,\n} from '@open-mercato/core/modules/dictionaries/components/AppearanceSelector'\nimport {\n renderDictionaryColor,\n renderDictionaryIcon,\n} from '@open-mercato/core/modules/dictionaries/components/dictionaryAppearance'\n\ntype Pipeline = {\n id: string\n name: string\n isDefault: boolean\n organizationId: string\n tenantId: string\n}\n\ntype PipelineStage = {\n id: string\n pipelineId: string\n label: string\n order: number\n color: string | null\n icon: string | null\n}\n\ntype PipelineDialogState =\n | { mode: 'create' }\n | { mode: 'edit'; entry: Pipeline }\n\ntype StageDialogState =\n | { mode: 'create'; pipelineId: string }\n | { mode: 'edit'; entry: PipelineStage }\n\nfunction normalizePipeline(raw: Record<string, unknown>): Pipeline {\n return {\n id: typeof raw.id === 'string' ? raw.id : '',\n name: typeof raw.name === 'string' ? raw.name : '',\n isDefault: raw.isDefault === true || raw.is_default === true,\n organizationId: typeof raw.organizationId === 'string' ? raw.organizationId : (typeof raw.organization_id === 'string' ? raw.organization_id : ''),\n tenantId: typeof raw.tenantId === 'string' ? raw.tenantId : (typeof raw.tenant_id === 'string' ? raw.tenant_id : ''),\n }\n}\n\nfunction normalizeStage(raw: Record<string, unknown>): PipelineStage {\n return {\n id: typeof raw.id === 'string' ? raw.id : '',\n pipelineId: typeof raw.pipelineId === 'string' ? raw.pipelineId : (typeof raw.pipeline_id === 'string' ? raw.pipeline_id : ''),\n label: typeof raw.label === 'string' ? raw.label : '',\n order: typeof raw.order === 'number' ? raw.order : 0,\n color: typeof raw.color === 'string' && raw.color.trim().length ? raw.color.trim() : null,\n icon: typeof raw.icon === 'string' && raw.icon.trim().length ? raw.icon.trim() : null,\n }\n}\n\nexport default function PipelineSettings(): React.ReactElement {\n const t = useT()\n const scopeVersion = useOrganizationScopeVersion()\n const { confirm, ConfirmDialogElement } = useConfirmDialog()\n\n const [pipelines, setPipelines] = React.useState<Pipeline[]>([])\n const [loadingPipelines, setLoadingPipelines] = React.useState(false)\n const [pipelineDialog, setPipelineDialog] = React.useState<PipelineDialogState | null>(null)\n const [pipelineForm, setPipelineForm] = React.useState({ name: '', isDefault: false })\n const [submittingPipeline, setSubmittingPipeline] = React.useState(false)\n\n const [expandedPipelineId, setExpandedPipelineId] = React.useState<string | null>(null)\n const [stages, setStages] = React.useState<Record<string, PipelineStage[]>>({})\n const [loadingStages, setLoadingStages] = React.useState<Record<string, boolean>>({})\n const [stageDialog, setStageDialog] = React.useState<StageDialogState | null>(null)\n const [stageForm, setStageForm] = React.useState({ label: '', color: null as string | null, icon: null as string | null })\n const [submittingStage, setSubmittingStage] = React.useState(false)\n\n const loadPipelines = React.useCallback(async () => {\n setLoadingPipelines(true)\n try {\n const data = await readApiResultOrThrow<{ items?: unknown[] }>(\n '/api/customers/pipelines',\n undefined,\n { errorMessage: t('customers.pipelines.errors.loadFailed', 'Failed to load pipelines'), fallback: { items: [] } },\n )\n const items = Array.isArray(data?.items) ? data.items : []\n setPipelines(items.map((item) => normalizePipeline(item as Record<string, unknown>)))\n } finally {\n setLoadingPipelines(false)\n }\n }, [t])\n\n const loadStages = React.useCallback(async (pipelineId: string) => {\n setLoadingStages((prev) => ({ ...prev, [pipelineId]: true }))\n try {\n const data = await readApiResultOrThrow<{ items?: unknown[] }>(\n `/api/customers/pipeline-stages?pipelineId=${encodeURIComponent(pipelineId)}`,\n undefined,\n { errorMessage: t('customers.pipelines.errors.stagesLoadFailed', 'Failed to load stages'), fallback: { items: [] } },\n )\n const items = Array.isArray(data?.items) ? data.items : []\n setStages((prev) => ({\n ...prev,\n [pipelineId]: items.map((item) => normalizeStage(item as Record<string, unknown>)),\n }))\n } finally {\n setLoadingStages((prev) => ({ ...prev, [pipelineId]: false }))\n }\n }, [t])\n\n React.useEffect(() => {\n void loadPipelines()\n }, [loadPipelines, scopeVersion])\n\n React.useEffect(() => {\n if (expandedPipelineId) {\n void loadStages(expandedPipelineId)\n }\n }, [expandedPipelineId, loadStages])\n\n const openCreatePipeline = React.useCallback(() => {\n setPipelineForm({ name: '', isDefault: false })\n setPipelineDialog({ mode: 'create' })\n }, [])\n\n const openEditPipeline = React.useCallback((pipeline: Pipeline) => {\n setPipelineForm({ name: pipeline.name, isDefault: pipeline.isDefault })\n setPipelineDialog({ mode: 'edit', entry: pipeline })\n }, [])\n\n const closePipelineDialog = React.useCallback(() => {\n setPipelineDialog(null)\n }, [])\n\n const handlePipelineSubmit = React.useCallback(async () => {\n if (!pipelineForm.name.trim()) return\n setSubmittingPipeline(true)\n try {\n if (pipelineDialog?.mode === 'create') {\n const res = await apiCall('/api/customers/pipelines', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ name: pipelineForm.name.trim(), isDefault: pipelineForm.isDefault }),\n })\n if (!res.ok) {\n await raiseCrudError(res.response, t('customers.pipelines.errors.createFailed', 'Failed to create pipeline'))\n return\n }\n flash(t('customers.pipelines.flash.created', 'Pipeline created'), 'success')\n } else if (pipelineDialog?.mode === 'edit') {\n const res = await apiCall('/api/customers/pipelines', {\n method: 'PUT',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ id: pipelineDialog.entry.id, name: pipelineForm.name.trim(), isDefault: pipelineForm.isDefault }),\n })\n if (!res.ok) {\n await raiseCrudError(res.response, t('customers.pipelines.errors.updateFailed', 'Failed to update pipeline'))\n return\n }\n flash(t('customers.pipelines.flash.updated', 'Pipeline updated'), 'success')\n }\n setPipelineDialog(null)\n await loadPipelines()\n } finally {\n setSubmittingPipeline(false)\n }\n }, [pipelineDialog, pipelineForm, loadPipelines, t])\n\n const handleDeletePipeline = React.useCallback(async (pipeline: Pipeline) => {\n const confirmed = await confirm({\n title: t('customers.pipelines.confirm.deleteTitle', 'Delete pipeline'),\n text: t('customers.pipelines.confirm.deleteDesc', 'Are you sure you want to delete this pipeline? This cannot be undone.'),\n confirmText: t('customers.pipelines.confirm.deleteConfirm', 'Delete'),\n variant: 'destructive',\n })\n if (!confirmed) return\n const res = await apiCall('/api/customers/pipelines', {\n method: 'DELETE',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ id: pipeline.id }),\n })\n if (!res.ok) {\n const body = (res.result ?? {}) as Record<string, unknown>\n const msg = typeof body.error === 'string' ? body.error : t('customers.pipelines.errors.deleteFailed', 'Failed to delete pipeline')\n flash(msg, 'error')\n return\n }\n flash(t('customers.pipelines.flash.deleted', 'Pipeline deleted'), 'success')\n if (expandedPipelineId === pipeline.id) setExpandedPipelineId(null)\n await loadPipelines()\n }, [confirm, expandedPipelineId, loadPipelines, t])\n\n const openCreateStage = React.useCallback((pipelineId: string) => {\n setStageForm({ label: '', color: null, icon: null })\n setStageDialog({ mode: 'create', pipelineId })\n }, [])\n\n const openEditStage = React.useCallback((stage: PipelineStage) => {\n setStageForm({ label: stage.label, color: stage.color, icon: stage.icon })\n setStageDialog({ mode: 'edit', entry: stage })\n }, [])\n\n const closeStageDialog = React.useCallback(() => {\n setStageDialog(null)\n }, [])\n\n const handleStageSubmit = React.useCallback(async () => {\n if (!stageForm.label.trim()) return\n setSubmittingStage(true)\n try {\n const appearance: Record<string, unknown> = {}\n if (stageForm.color) appearance.color = stageForm.color\n if (stageForm.icon) appearance.icon = stageForm.icon\n\n if (stageDialog?.mode === 'create') {\n const res = await apiCall('/api/customers/pipeline-stages', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ pipelineId: stageDialog.pipelineId, label: stageForm.label.trim(), ...appearance }),\n })\n if (!res.ok) {\n await raiseCrudError(res.response, t('customers.pipelines.errors.stageCreateFailed', 'Failed to create stage'))\n return\n }\n flash(t('customers.pipelines.flash.stageCreated', 'Stage created'), 'success')\n await loadStages(stageDialog.pipelineId)\n } else if (stageDialog?.mode === 'edit') {\n const res = await apiCall('/api/customers/pipeline-stages', {\n method: 'PUT',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ id: stageDialog.entry.id, label: stageForm.label.trim(), ...appearance }),\n })\n if (!res.ok) {\n await raiseCrudError(res.response, t('customers.pipelines.errors.stageUpdateFailed', 'Failed to update stage'))\n return\n }\n flash(t('customers.pipelines.flash.stageUpdated', 'Stage updated'), 'success')\n await loadStages(stageDialog.entry.pipelineId)\n }\n setStageDialog(null)\n } finally {\n setSubmittingStage(false)\n }\n }, [stageDialog, stageForm, loadStages, t])\n\n const handleDeleteStage = React.useCallback(async (stage: PipelineStage) => {\n const confirmed = await confirm({\n title: t('customers.pipelines.confirm.stageDeleteTitle', 'Delete stage'),\n text: t('customers.pipelines.confirm.stageDeleteDesc', 'Are you sure you want to delete this stage?'),\n confirmText: t('customers.pipelines.confirm.stageDeleteConfirm', 'Delete'),\n variant: 'destructive',\n })\n if (!confirmed) return\n const res = await apiCall('/api/customers/pipeline-stages', {\n method: 'DELETE',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ id: stage.id }),\n })\n if (!res.ok) {\n const body = (res.result ?? {}) as Record<string, unknown>\n const msg = typeof body.error === 'string' ? body.error : t('customers.pipelines.errors.stageDeleteFailed', 'Failed to delete stage')\n flash(msg, 'error')\n return\n }\n flash(t('customers.pipelines.flash.stageDeleted', 'Stage deleted'), 'success')\n await loadStages(stage.pipelineId)\n }, [confirm, loadStages, t])\n\n const handleMoveStage = React.useCallback(async (stage: PipelineStage, direction: 'up' | 'down') => {\n const pipelineStages = stages[stage.pipelineId] ?? []\n const idx = pipelineStages.findIndex((s) => s.id === stage.id)\n if (idx < 0) return\n const swapIdx = direction === 'up' ? idx - 1 : idx + 1\n if (swapIdx < 0 || swapIdx >= pipelineStages.length) return\n\n const reordered = [...pipelineStages]\n const temp = reordered[idx]\n reordered[idx] = reordered[swapIdx]\n reordered[swapIdx] = temp\n\n const orderedStages = reordered.map((s, i) => ({ id: s.id, order: i }))\n const res = await apiCall('/api/customers/pipeline-stages/reorder', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ stages: orderedStages }),\n })\n if (!res.ok) {\n flash(t('customers.pipelines.errors.reorderFailed', 'Failed to reorder stages'), 'error')\n return\n }\n await loadStages(stage.pipelineId)\n }, [stages, loadStages, t])\n\n const handleKeyDown = React.useCallback(\n (handler: () => void) => (e: React.KeyboardEvent) => {\n if ((e.metaKey || e.ctrlKey) && e.key === 'Enter') {\n e.preventDefault()\n handler()\n }\n },\n [],\n )\n\n const appearanceLabels = React.useMemo<AppearanceSelectorLabels>(() => ({\n colorLabel: t('customers.pipelines.stageForm.color', 'Color'),\n colorClearLabel: t('customers.pipelines.stageForm.colorClear', 'Remove color'),\n iconLabel: t('customers.pipelines.stageForm.icon', 'Icon'),\n iconPlaceholder: t('customers.pipelines.stageForm.iconPlaceholder', 'e.g. lucide:star'),\n iconPickerTriggerLabel: t('customers.pipelines.stageForm.iconPicker', 'Pick icon'),\n iconSearchPlaceholder: t('customers.pipelines.stageForm.iconSearch', 'Search icons\u2026'),\n iconSearchEmptyLabel: t('customers.pipelines.stageForm.iconSearchEmpty', 'No icons found'),\n iconSuggestionsLabel: t('customers.pipelines.stageForm.iconSuggestions', 'Suggestions'),\n iconClearLabel: t('customers.pipelines.stageForm.iconClear', 'Remove icon'),\n previewEmptyLabel: t('customers.pipelines.stageForm.previewEmpty', 'No appearance set'),\n }), [t])\n\n return (\n <div className=\"space-y-4\">\n <div className=\"flex items-center justify-between\">\n <div>\n <h3 className=\"text-base font-semibold\">{t('customers.pipelines.title', 'Sales Pipelines')}</h3>\n <p className=\"text-sm text-muted-foreground\">\n {t('customers.pipelines.description', 'Manage sales pipelines and their stages.')}\n </p>\n </div>\n <Button size=\"sm\" onClick={openCreatePipeline}>\n {t('customers.pipelines.actions.create', 'Add pipeline')}\n </Button>\n </div>\n\n {loadingPipelines ? (\n <div className=\"flex items-center gap-2 text-sm text-muted-foreground\">\n <Spinner className=\"h-4 w-4\" />\n {t('customers.pipelines.loading', 'Loading pipelines\u2026')}\n </div>\n ) : pipelines.length === 0 ? (\n <p className=\"text-sm text-muted-foreground\">\n {t('customers.pipelines.empty', 'No pipelines yet. Create one to get started.')}\n </p>\n ) : (\n <Accordion\n type=\"single\"\n collapsible\n value={expandedPipelineId ?? ''}\n onValueChange={(next) => setExpandedPipelineId(next || null)}\n className=\"space-y-2\"\n >\n {pipelines.map((pipeline) => {\n const pipelineStages = stages[pipeline.id] ?? []\n const isLoadingStages = loadingStages[pipeline.id] ?? false\n\n return (\n <AccordionItem key={pipeline.id} value={pipeline.id}>\n <AccordionTrigger triggerIcon=\"chevron\">\n <span className=\"flex items-center gap-2\">\n <span className=\"text-sm font-medium\">{pipeline.name}</span>\n {pipeline.isDefault ? (\n <span className=\"rounded-full bg-primary/10 px-2 py-0.5 text-xs text-primary\">\n {t('customers.pipelines.defaultBadge', 'Default')}\n </span>\n ) : null}\n </span>\n </AccordionTrigger>\n <AccordionContent>\n <div className=\"mb-3 flex items-center justify-between\">\n <span className=\"text-xs font-medium text-muted-foreground uppercase tracking-wide\">\n {t('customers.pipelines.stages.title', 'Stages')}\n </span>\n <Button size=\"sm\" variant=\"outline\" onClick={() => openCreateStage(pipeline.id)}>\n {t('customers.pipelines.stages.add', 'Add stage')}\n </Button>\n </div>\n\n {isLoadingStages ? (\n <div className=\"flex items-center gap-2 text-sm text-muted-foreground\">\n <Spinner className=\"h-3 w-3\" />\n {t('customers.pipelines.stages.loading', 'Loading\u2026')}\n </div>\n ) : pipelineStages.length === 0 ? (\n <p className=\"text-sm text-muted-foreground\">\n {t('customers.pipelines.stages.empty', 'No stages yet.')}\n </p>\n ) : (\n <div className=\"divide-y divide-border rounded-md border bg-background\">\n {pipelineStages.map((stage, idx) => (\n <div key={stage.id} className=\"flex items-center justify-between gap-3 px-3 py-2\">\n <div className=\"flex items-center gap-2\">\n <span className=\"w-5 text-center text-xs text-muted-foreground\">{idx + 1}</span>\n {stage.color ? renderDictionaryColor(stage.color, 'h-3 w-3 rounded-full') : null}\n {stage.icon ? renderDictionaryIcon(stage.icon, 'h-4 w-4') : null}\n <span className=\"text-sm\">{stage.label}</span>\n </div>\n <div className=\"flex items-center gap-1\">\n <Button\n variant=\"ghost\"\n size=\"icon\"\n className=\"h-7 w-7\"\n disabled={idx === 0}\n onClick={() => void handleMoveStage(stage, 'up')}\n title={t('customers.pipelines.stages.moveUp', 'Move up')}\n >\n \u2191\n </Button>\n <Button\n variant=\"ghost\"\n size=\"icon\"\n className=\"h-7 w-7\"\n disabled={idx === pipelineStages.length - 1}\n onClick={() => void handleMoveStage(stage, 'down')}\n title={t('customers.pipelines.stages.moveDown', 'Move down')}\n >\n \u2193\n </Button>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n onClick={() => openEditStage(stage)}\n >\n {t('customers.pipelines.stages.edit', 'Edit')}\n </Button>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n className=\"text-destructive hover:text-destructive\"\n onClick={() => void handleDeleteStage(stage)}\n >\n {t('customers.pipelines.stages.delete', 'Delete')}\n </Button>\n </div>\n </div>\n ))}\n </div>\n )}\n\n <div className=\"mt-4 flex items-center justify-end gap-2 border-t pt-3\">\n <Button\n variant=\"ghost\"\n size=\"sm\"\n onClick={() => openEditPipeline(pipeline)}\n >\n {t('customers.pipelines.actions.edit', 'Edit pipeline')}\n </Button>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n className=\"text-destructive hover:text-destructive\"\n onClick={() => void handleDeletePipeline(pipeline)}\n >\n {t('customers.pipelines.actions.delete', 'Delete pipeline')}\n </Button>\n </div>\n </AccordionContent>\n </AccordionItem>\n )\n })}\n </Accordion>\n )}\n\n {/* Pipeline Dialog */}\n <Dialog open={pipelineDialog !== null} onOpenChange={(open) => { if (!open) closePipelineDialog() }}>\n <DialogContent onKeyDown={handleKeyDown(handlePipelineSubmit)}>\n <DialogHeader>\n <DialogTitle>\n {pipelineDialog?.mode === 'create'\n ? t('customers.pipelines.dialog.createTitle', 'Create pipeline')\n : t('customers.pipelines.dialog.editTitle', 'Edit pipeline')}\n </DialogTitle>\n </DialogHeader>\n <div className=\"space-y-4 py-2\">\n <div className=\"space-y-2\">\n <Label htmlFor=\"pipeline-name\">{t('customers.pipelines.form.name', 'Name')}</Label>\n <Input\n id=\"pipeline-name\"\n value={pipelineForm.name}\n onChange={(e) => setPipelineForm((prev) => ({ ...prev, name: e.target.value }))}\n placeholder={t('customers.pipelines.form.namePlaceholder', 'e.g. New Business')}\n autoFocus\n />\n </div>\n <div className=\"flex items-center gap-2\">\n <Checkbox\n id=\"pipeline-default\"\n checked={pipelineForm.isDefault}\n onCheckedChange={(checked) => setPipelineForm((prev) => ({ ...prev, isDefault: checked === true }))}\n />\n <Label htmlFor=\"pipeline-default\" className=\"cursor-pointer\">\n {t('customers.pipelines.form.isDefault', 'Set as default pipeline')}\n </Label>\n </div>\n </div>\n <DialogFooter>\n <Button variant=\"outline\" onClick={closePipelineDialog} disabled={submittingPipeline}>\n {t('customers.pipelines.dialog.cancel', 'Cancel')}\n </Button>\n <Button onClick={() => void handlePipelineSubmit()} disabled={submittingPipeline || !pipelineForm.name.trim()}>\n {submittingPipeline ? <Spinner className=\"mr-2 h-4 w-4\" /> : null}\n {t('customers.pipelines.dialog.save', 'Save')}\n </Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n\n {ConfirmDialogElement}\n\n {/* Stage Dialog */}\n <Dialog open={stageDialog !== null} onOpenChange={(open) => { if (!open) closeStageDialog() }}>\n <DialogContent onKeyDown={handleKeyDown(handleStageSubmit)}>\n <DialogHeader>\n <DialogTitle>\n {stageDialog?.mode === 'create'\n ? t('customers.pipelines.stageDialog.createTitle', 'Add stage')\n : t('customers.pipelines.stageDialog.editTitle', 'Edit stage')}\n </DialogTitle>\n </DialogHeader>\n <div className=\"space-y-4 py-2\">\n <div className=\"space-y-2\">\n <Label htmlFor=\"stage-label\">{t('customers.pipelines.stageForm.label', 'Label')}</Label>\n <Input\n id=\"stage-label\"\n value={stageForm.label}\n onChange={(e) => setStageForm((prev) => ({ ...prev, label: e.target.value }))}\n placeholder={t('customers.pipelines.stageForm.labelPlaceholder', 'e.g. Discovery')}\n autoFocus\n />\n </div>\n <AppearanceSelector\n color={stageForm.color}\n icon={stageForm.icon}\n onColorChange={(next) => setStageForm((prev) => ({ ...prev, color: next }))}\n onIconChange={(next) => setStageForm((prev) => ({ ...prev, icon: next }))}\n labels={appearanceLabels}\n />\n </div>\n <DialogFooter>\n <Button variant=\"outline\" onClick={closeStageDialog} disabled={submittingStage}>\n {t('customers.pipelines.stageDialog.cancel', 'Cancel')}\n </Button>\n <Button onClick={() => void handleStageSubmit()} disabled={submittingStage || !stageForm.label.trim()}>\n {submittingStage ? <Spinner className=\"mr-2 h-4 w-4\" /> : null}\n {t('customers.pipelines.stageDialog.save', 'Save')}\n </Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n </div>\n )\n}\n"],
5
- "mappings": ";AAsVQ,SACE,KADF;AApVR,YAAY,WAAW;AACvB,SAAS,cAAc;AACvB,SAAS,aAAa;AACtB,SAAS,aAAa;AACtB,SAAS,gBAAgB;AACzB;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,aAAa;AACtB,SAAS,SAAS,4BAA4B;AAC9C,SAAS,sBAAsB;AAC/B,SAAS,mCAAmC;AAC5C,SAAS,YAAY;AACrB,SAAS,wBAAwB;AACjC,SAAS,eAAe;AACxB;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP;AAAA,EACE;AAAA,OAEK;AACP;AAAA,EACE;AAAA,EACA;AAAA,OACK;AA2BP,SAAS,kBAAkB,KAAwC;AACjE,SAAO;AAAA,IACL,IAAI,OAAO,IAAI,OAAO,WAAW,IAAI,KAAK;AAAA,IAC1C,MAAM,OAAO,IAAI,SAAS,WAAW,IAAI,OAAO;AAAA,IAChD,WAAW,IAAI,cAAc,QAAQ,IAAI,eAAe;AAAA,IACxD,gBAAgB,OAAO,IAAI,mBAAmB,WAAW,IAAI,iBAAkB,OAAO,IAAI,oBAAoB,WAAW,IAAI,kBAAkB;AAAA,IAC/I,UAAU,OAAO,IAAI,aAAa,WAAW,IAAI,WAAY,OAAO,IAAI,cAAc,WAAW,IAAI,YAAY;AAAA,EACnH;AACF;AAEA,SAAS,eAAe,KAA6C;AACnE,SAAO;AAAA,IACL,IAAI,OAAO,IAAI,OAAO,WAAW,IAAI,KAAK;AAAA,IAC1C,YAAY,OAAO,IAAI,eAAe,WAAW,IAAI,aAAc,OAAO,IAAI,gBAAgB,WAAW,IAAI,cAAc;AAAA,IAC3H,OAAO,OAAO,IAAI,UAAU,WAAW,IAAI,QAAQ;AAAA,IACnD,OAAO,OAAO,IAAI,UAAU,WAAW,IAAI,QAAQ;AAAA,IACnD,OAAO,OAAO,IAAI,UAAU,YAAY,IAAI,MAAM,KAAK,EAAE,SAAS,IAAI,MAAM,KAAK,IAAI;AAAA,IACrF,MAAM,OAAO,IAAI,SAAS,YAAY,IAAI,KAAK,KAAK,EAAE,SAAS,IAAI,KAAK,KAAK,IAAI;AAAA,EACnF;AACF;AAEe,SAAR,mBAAwD;AAC7D,QAAM,IAAI,KAAK;AACf,QAAM,eAAe,4BAA4B;AACjD,QAAM,EAAE,SAAS,qBAAqB,IAAI,iBAAiB;AAE3D,QAAM,CAAC,WAAW,YAAY,IAAI,MAAM,SAAqB,CAAC,CAAC;AAC/D,QAAM,CAAC,kBAAkB,mBAAmB,IAAI,MAAM,SAAS,KAAK;AACpE,QAAM,CAAC,gBAAgB,iBAAiB,IAAI,MAAM,SAAqC,IAAI;AAC3F,QAAM,CAAC,cAAc,eAAe,IAAI,MAAM,SAAS,EAAE,MAAM,IAAI,WAAW,MAAM,CAAC;AACrF,QAAM,CAAC,oBAAoB,qBAAqB,IAAI,MAAM,SAAS,KAAK;AAExE,QAAM,CAAC,oBAAoB,qBAAqB,IAAI,MAAM,SAAwB,IAAI;AACtF,QAAM,CAAC,QAAQ,SAAS,IAAI,MAAM,SAA0C,CAAC,CAAC;AAC9E,QAAM,CAAC,eAAe,gBAAgB,IAAI,MAAM,SAAkC,CAAC,CAAC;AACpF,QAAM,CAAC,aAAa,cAAc,IAAI,MAAM,SAAkC,IAAI;AAClF,QAAM,CAAC,WAAW,YAAY,IAAI,MAAM,SAAS,EAAE,OAAO,IAAI,OAAO,MAAuB,MAAM,KAAsB,CAAC;AACzH,QAAM,CAAC,iBAAiB,kBAAkB,IAAI,MAAM,SAAS,KAAK;AAElE,QAAM,gBAAgB,MAAM,YAAY,YAAY;AAClD,wBAAoB,IAAI;AACxB,QAAI;AACF,YAAM,OAAO,MAAM;AAAA,QACjB;AAAA,QACA;AAAA,QACA,EAAE,cAAc,EAAE,yCAAyC,0BAA0B,GAAG,UAAU,EAAE,OAAO,CAAC,EAAE,EAAE;AAAA,MAClH;AACA,YAAM,QAAQ,MAAM,QAAQ,MAAM,KAAK,IAAI,KAAK,QAAQ,CAAC;AACzD,mBAAa,MAAM,IAAI,CAAC,SAAS,kBAAkB,IAA+B,CAAC,CAAC;AAAA,IACtF,UAAE;AACA,0BAAoB,KAAK;AAAA,IAC3B;AAAA,EACF,GAAG,CAAC,CAAC,CAAC;AAEN,QAAM,aAAa,MAAM,YAAY,OAAO,eAAuB;AACjE,qBAAiB,CAAC,UAAU,EAAE,GAAG,MAAM,CAAC,UAAU,GAAG,KAAK,EAAE;AAC5D,QAAI;AACF,YAAM,OAAO,MAAM;AAAA,QACjB,6CAA6C,mBAAmB,UAAU,CAAC;AAAA,QAC3E;AAAA,QACA,EAAE,cAAc,EAAE,+CAA+C,uBAAuB,GAAG,UAAU,EAAE,OAAO,CAAC,EAAE,EAAE;AAAA,MACrH;AACA,YAAM,QAAQ,MAAM,QAAQ,MAAM,KAAK,IAAI,KAAK,QAAQ,CAAC;AACzD,gBAAU,CAAC,UAAU;AAAA,QACnB,GAAG;AAAA,QACH,CAAC,UAAU,GAAG,MAAM,IAAI,CAAC,SAAS,eAAe,IAA+B,CAAC;AAAA,MACnF,EAAE;AAAA,IACJ,UAAE;AACA,uBAAiB,CAAC,UAAU,EAAE,GAAG,MAAM,CAAC,UAAU,GAAG,MAAM,EAAE;AAAA,IAC/D;AAAA,EACF,GAAG,CAAC,CAAC,CAAC;AAEN,QAAM,UAAU,MAAM;AACpB,SAAK,cAAc;AAAA,EACrB,GAAG,CAAC,eAAe,YAAY,CAAC;AAEhC,QAAM,UAAU,MAAM;AACpB,QAAI,oBAAoB;AACtB,WAAK,WAAW,kBAAkB;AAAA,IACpC;AAAA,EACF,GAAG,CAAC,oBAAoB,UAAU,CAAC;AAEnC,QAAM,qBAAqB,MAAM,YAAY,MAAM;AACjD,oBAAgB,EAAE,MAAM,IAAI,WAAW,MAAM,CAAC;AAC9C,sBAAkB,EAAE,MAAM,SAAS,CAAC;AAAA,EACtC,GAAG,CAAC,CAAC;AAEL,QAAM,mBAAmB,MAAM,YAAY,CAAC,aAAuB;AACjE,oBAAgB,EAAE,MAAM,SAAS,MAAM,WAAW,SAAS,UAAU,CAAC;AACtE,sBAAkB,EAAE,MAAM,QAAQ,OAAO,SAAS,CAAC;AAAA,EACrD,GAAG,CAAC,CAAC;AAEL,QAAM,sBAAsB,MAAM,YAAY,MAAM;AAClD,sBAAkB,IAAI;AAAA,EACxB,GAAG,CAAC,CAAC;AAEL,QAAM,uBAAuB,MAAM,YAAY,YAAY;AACzD,QAAI,CAAC,aAAa,KAAK,KAAK,EAAG;AAC/B,0BAAsB,IAAI;AAC1B,QAAI;AACF,UAAI,gBAAgB,SAAS,UAAU;AACrC,cAAM,MAAM,MAAM,QAAQ,4BAA4B;AAAA,UACpD,QAAQ;AAAA,UACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,UAC9C,MAAM,KAAK,UAAU,EAAE,MAAM,aAAa,KAAK,KAAK,GAAG,WAAW,aAAa,UAAU,CAAC;AAAA,QAC5F,CAAC;AACD,YAAI,CAAC,IAAI,IAAI;AACX,gBAAM,eAAe,IAAI,UAAU,EAAE,2CAA2C,2BAA2B,CAAC;AAC5G;AAAA,QACF;AACA,cAAM,EAAE,qCAAqC,kBAAkB,GAAG,SAAS;AAAA,MAC7E,WAAW,gBAAgB,SAAS,QAAQ;AAC1C,cAAM,MAAM,MAAM,QAAQ,4BAA4B;AAAA,UACpD,QAAQ;AAAA,UACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,UAC9C,MAAM,KAAK,UAAU,EAAE,IAAI,eAAe,MAAM,IAAI,MAAM,aAAa,KAAK,KAAK,GAAG,WAAW,aAAa,UAAU,CAAC;AAAA,QACzH,CAAC;AACD,YAAI,CAAC,IAAI,IAAI;AACX,gBAAM,eAAe,IAAI,UAAU,EAAE,2CAA2C,2BAA2B,CAAC;AAC5G;AAAA,QACF;AACA,cAAM,EAAE,qCAAqC,kBAAkB,GAAG,SAAS;AAAA,MAC7E;AACA,wBAAkB,IAAI;AACtB,YAAM,cAAc;AAAA,IACtB,UAAE;AACA,4BAAsB,KAAK;AAAA,IAC7B;AAAA,EACF,GAAG,CAAC,gBAAgB,cAAc,eAAe,CAAC,CAAC;AAEnD,QAAM,uBAAuB,MAAM,YAAY,OAAO,aAAuB;AAC3E,UAAM,YAAY,MAAM,QAAQ;AAAA,MAC9B,OAAO,EAAE,2CAA2C,iBAAiB;AAAA,MACrE,MAAM,EAAE,0CAA0C,uEAAuE;AAAA,MACzH,aAAa,EAAE,6CAA6C,QAAQ;AAAA,MACpE,SAAS;AAAA,IACX,CAAC;AACD,QAAI,CAAC,UAAW;AAChB,UAAM,MAAM,MAAM,QAAQ,4BAA4B;AAAA,MACpD,QAAQ;AAAA,MACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,MAC9C,MAAM,KAAK,UAAU,EAAE,IAAI,SAAS,GAAG,CAAC;AAAA,IAC1C,CAAC;AACD,QAAI,CAAC,IAAI,IAAI;AACX,YAAM,OAAQ,IAAI,UAAU,CAAC;AAC7B,YAAM,MAAM,OAAO,KAAK,UAAU,WAAW,KAAK,QAAQ,EAAE,2CAA2C,2BAA2B;AAClI,YAAM,KAAK,OAAO;AAClB;AAAA,IACF;AACA,UAAM,EAAE,qCAAqC,kBAAkB,GAAG,SAAS;AAC3E,QAAI,uBAAuB,SAAS,GAAI,uBAAsB,IAAI;AAClE,UAAM,cAAc;AAAA,EACtB,GAAG,CAAC,SAAS,oBAAoB,eAAe,CAAC,CAAC;AAElD,QAAM,kBAAkB,MAAM,YAAY,CAAC,eAAuB;AAChE,iBAAa,EAAE,OAAO,IAAI,OAAO,MAAM,MAAM,KAAK,CAAC;AACnD,mBAAe,EAAE,MAAM,UAAU,WAAW,CAAC;AAAA,EAC/C,GAAG,CAAC,CAAC;AAEL,QAAM,gBAAgB,MAAM,YAAY,CAAC,UAAyB;AAChE,iBAAa,EAAE,OAAO,MAAM,OAAO,OAAO,MAAM,OAAO,MAAM,MAAM,KAAK,CAAC;AACzE,mBAAe,EAAE,MAAM,QAAQ,OAAO,MAAM,CAAC;AAAA,EAC/C,GAAG,CAAC,CAAC;AAEL,QAAM,mBAAmB,MAAM,YAAY,MAAM;AAC/C,mBAAe,IAAI;AAAA,EACrB,GAAG,CAAC,CAAC;AAEL,QAAM,oBAAoB,MAAM,YAAY,YAAY;AACtD,QAAI,CAAC,UAAU,MAAM,KAAK,EAAG;AAC7B,uBAAmB,IAAI;AACvB,QAAI;AACF,YAAM,aAAsC,CAAC;AAC7C,UAAI,UAAU,MAAO,YAAW,QAAQ,UAAU;AAClD,UAAI,UAAU,KAAM,YAAW,OAAO,UAAU;AAEhD,UAAI,aAAa,SAAS,UAAU;AAClC,cAAM,MAAM,MAAM,QAAQ,kCAAkC;AAAA,UAC1D,QAAQ;AAAA,UACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,UAC9C,MAAM,KAAK,UAAU,EAAE,YAAY,YAAY,YAAY,OAAO,UAAU,MAAM,KAAK,GAAG,GAAG,WAAW,CAAC;AAAA,QAC3G,CAAC;AACD,YAAI,CAAC,IAAI,IAAI;AACX,gBAAM,eAAe,IAAI,UAAU,EAAE,gDAAgD,wBAAwB,CAAC;AAC9G;AAAA,QACF;AACA,cAAM,EAAE,0CAA0C,eAAe,GAAG,SAAS;AAC7E,cAAM,WAAW,YAAY,UAAU;AAAA,MACzC,WAAW,aAAa,SAAS,QAAQ;AACvC,cAAM,MAAM,MAAM,QAAQ,kCAAkC;AAAA,UAC1D,QAAQ;AAAA,UACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,UAC9C,MAAM,KAAK,UAAU,EAAE,IAAI,YAAY,MAAM,IAAI,OAAO,UAAU,MAAM,KAAK,GAAG,GAAG,WAAW,CAAC;AAAA,QACjG,CAAC;AACD,YAAI,CAAC,IAAI,IAAI;AACX,gBAAM,eAAe,IAAI,UAAU,EAAE,gDAAgD,wBAAwB,CAAC;AAC9G;AAAA,QACF;AACA,cAAM,EAAE,0CAA0C,eAAe,GAAG,SAAS;AAC7E,cAAM,WAAW,YAAY,MAAM,UAAU;AAAA,MAC/C;AACA,qBAAe,IAAI;AAAA,IACrB,UAAE;AACA,yBAAmB,KAAK;AAAA,IAC1B;AAAA,EACF,GAAG,CAAC,aAAa,WAAW,YAAY,CAAC,CAAC;AAE1C,QAAM,oBAAoB,MAAM,YAAY,OAAO,UAAyB;AAC1E,UAAM,YAAY,MAAM,QAAQ;AAAA,MAC9B,OAAO,EAAE,gDAAgD,cAAc;AAAA,MACvE,MAAM,EAAE,+CAA+C,6CAA6C;AAAA,MACpG,aAAa,EAAE,kDAAkD,QAAQ;AAAA,MACzE,SAAS;AAAA,IACX,CAAC;AACD,QAAI,CAAC,UAAW;AAChB,UAAM,MAAM,MAAM,QAAQ,kCAAkC;AAAA,MAC1D,QAAQ;AAAA,MACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,MAC9C,MAAM,KAAK,UAAU,EAAE,IAAI,MAAM,GAAG,CAAC;AAAA,IACvC,CAAC;AACD,QAAI,CAAC,IAAI,IAAI;AACX,YAAM,OAAQ,IAAI,UAAU,CAAC;AAC7B,YAAM,MAAM,OAAO,KAAK,UAAU,WAAW,KAAK,QAAQ,EAAE,gDAAgD,wBAAwB;AACpI,YAAM,KAAK,OAAO;AAClB;AAAA,IACF;AACA,UAAM,EAAE,0CAA0C,eAAe,GAAG,SAAS;AAC7E,UAAM,WAAW,MAAM,UAAU;AAAA,EACnC,GAAG,CAAC,SAAS,YAAY,CAAC,CAAC;AAE3B,QAAM,kBAAkB,MAAM,YAAY,OAAO,OAAsB,cAA6B;AAClG,UAAM,iBAAiB,OAAO,MAAM,UAAU,KAAK,CAAC;AACpD,UAAM,MAAM,eAAe,UAAU,CAAC,MAAM,EAAE,OAAO,MAAM,EAAE;AAC7D,QAAI,MAAM,EAAG;AACb,UAAM,UAAU,cAAc,OAAO,MAAM,IAAI,MAAM;AACrD,QAAI,UAAU,KAAK,WAAW,eAAe,OAAQ;AAErD,UAAM,YAAY,CAAC,GAAG,cAAc;AACpC,UAAM,OAAO,UAAU,GAAG;AAC1B,cAAU,GAAG,IAAI,UAAU,OAAO;AAClC,cAAU,OAAO,IAAI;AAErB,UAAM,gBAAgB,UAAU,IAAI,CAAC,GAAG,OAAO,EAAE,IAAI,EAAE,IAAI,OAAO,EAAE,EAAE;AACtE,UAAM,MAAM,MAAM,QAAQ,0CAA0C;AAAA,MAClE,QAAQ;AAAA,MACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,MAC9C,MAAM,KAAK,UAAU,EAAE,QAAQ,cAAc,CAAC;AAAA,IAChD,CAAC;AACD,QAAI,CAAC,IAAI,IAAI;AACX,YAAM,EAAE,4CAA4C,0BAA0B,GAAG,OAAO;AACxF;AAAA,IACF;AACA,UAAM,WAAW,MAAM,UAAU;AAAA,EACnC,GAAG,CAAC,QAAQ,YAAY,CAAC,CAAC;AAE1B,QAAM,gBAAgB,MAAM;AAAA,IAC1B,CAAC,YAAwB,CAAC,MAA2B;AACnD,WAAK,EAAE,WAAW,EAAE,YAAY,EAAE,QAAQ,SAAS;AACjD,UAAE,eAAe;AACjB,gBAAQ;AAAA,MACV;AAAA,IACF;AAAA,IACA,CAAC;AAAA,EACH;AAEA,QAAM,mBAAmB,MAAM,QAAkC,OAAO;AAAA,IACtE,YAAY,EAAE,uCAAuC,OAAO;AAAA,IAC5D,iBAAiB,EAAE,4CAA4C,cAAc;AAAA,IAC7E,WAAW,EAAE,sCAAsC,MAAM;AAAA,IACzD,iBAAiB,EAAE,iDAAiD,kBAAkB;AAAA,IACtF,wBAAwB,EAAE,4CAA4C,WAAW;AAAA,IACjF,uBAAuB,EAAE,4CAA4C,oBAAe;AAAA,IACpF,sBAAsB,EAAE,iDAAiD,gBAAgB;AAAA,IACzF,sBAAsB,EAAE,iDAAiD,aAAa;AAAA,IACtF,gBAAgB,EAAE,2CAA2C,aAAa;AAAA,IAC1E,mBAAmB,EAAE,8CAA8C,mBAAmB;AAAA,EACxF,IAAI,CAAC,CAAC,CAAC;AAEP,SACE,qBAAC,SAAI,WAAU,aACb;AAAA,yBAAC,SAAI,WAAU,qCACb;AAAA,2BAAC,SACC;AAAA,4BAAC,QAAG,WAAU,2BAA2B,YAAE,6BAA6B,iBAAiB,GAAE;AAAA,QAC3F,oBAAC,OAAE,WAAU,iCACV,YAAE,mCAAmC,0CAA0C,GAClF;AAAA,SACF;AAAA,MACA,oBAAC,UAAO,MAAK,MAAK,SAAS,oBACxB,YAAE,sCAAsC,cAAc,GACzD;AAAA,OACF;AAAA,IAEC,mBACC,qBAAC,SAAI,WAAU,yDACb;AAAA,0BAAC,WAAQ,WAAU,WAAU;AAAA,MAC5B,EAAE,+BAA+B,yBAAoB;AAAA,OACxD,IACE,UAAU,WAAW,IACvB,oBAAC,OAAE,WAAU,iCACV,YAAE,6BAA6B,8CAA8C,GAChF,IAEA;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,aAAW;AAAA,QACX,OAAO,sBAAsB;AAAA,QAC7B,eAAe,CAAC,SAAS,sBAAsB,QAAQ,IAAI;AAAA,QAC3D,WAAU;AAAA,QAET,oBAAU,IAAI,CAAC,aAAa;AAC3B,gBAAM,iBAAiB,OAAO,SAAS,EAAE,KAAK,CAAC;AAC/C,gBAAM,kBAAkB,cAAc,SAAS,EAAE,KAAK;AAEtD,iBACE,qBAAC,iBAAgC,OAAO,SAAS,IAC/C;AAAA,gCAAC,oBAAiB,aAAY,WAC5B,+BAAC,UAAK,WAAU,2BACd;AAAA,kCAAC,UAAK,WAAU,uBAAuB,mBAAS,MAAK;AAAA,cACpD,SAAS,YACR,oBAAC,UAAK,WAAU,+DACb,YAAE,oCAAoC,SAAS,GAClD,IACE;AAAA,eACN,GACF;AAAA,YACA,qBAAC,oBACC;AAAA,mCAAC,SAAI,WAAU,0CACb;AAAA,oCAAC,UAAK,WAAU,qEACb,YAAE,oCAAoC,QAAQ,GACjD;AAAA,gBACA,oBAAC,UAAO,MAAK,MAAK,SAAQ,WAAU,SAAS,MAAM,gBAAgB,SAAS,EAAE,GAC3E,YAAE,kCAAkC,WAAW,GAClD;AAAA,iBACF;AAAA,cAEC,kBACC,qBAAC,SAAI,WAAU,yDACb;AAAA,oCAAC,WAAQ,WAAU,WAAU;AAAA,gBAC5B,EAAE,sCAAsC,eAAU;AAAA,iBACrD,IACE,eAAe,WAAW,IAC5B,oBAAC,OAAE,WAAU,iCACV,YAAE,oCAAoC,gBAAgB,GACzD,IAEA,oBAAC,SAAI,WAAU,0DACZ,yBAAe,IAAI,CAAC,OAAO,QAC1B,qBAAC,SAAmB,WAAU,qDAC5B;AAAA,qCAAC,SAAI,WAAU,2BACb;AAAA,sCAAC,UAAK,WAAU,iDAAiD,gBAAM,GAAE;AAAA,kBACxE,MAAM,QAAQ,sBAAsB,MAAM,OAAO,sBAAsB,IAAI;AAAA,kBAC3E,MAAM,OAAO,qBAAqB,MAAM,MAAM,SAAS,IAAI;AAAA,kBAC5D,oBAAC,UAAK,WAAU,WAAW,gBAAM,OAAM;AAAA,mBACzC;AAAA,gBACA,qBAAC,SAAI,WAAU,2BACb;AAAA;AAAA,oBAAC;AAAA;AAAA,sBACC,SAAQ;AAAA,sBACR,MAAK;AAAA,sBACL,WAAU;AAAA,sBACV,UAAU,QAAQ;AAAA,sBAClB,SAAS,MAAM,KAAK,gBAAgB,OAAO,IAAI;AAAA,sBAC/C,OAAO,EAAE,qCAAqC,SAAS;AAAA,sBACxD;AAAA;AAAA,kBAED;AAAA,kBACA;AAAA,oBAAC;AAAA;AAAA,sBACC,SAAQ;AAAA,sBACR,MAAK;AAAA,sBACL,WAAU;AAAA,sBACV,UAAU,QAAQ,eAAe,SAAS;AAAA,sBAC1C,SAAS,MAAM,KAAK,gBAAgB,OAAO,MAAM;AAAA,sBACjD,OAAO,EAAE,uCAAuC,WAAW;AAAA,sBAC5D;AAAA;AAAA,kBAED;AAAA,kBACA;AAAA,oBAAC;AAAA;AAAA,sBACC,SAAQ;AAAA,sBACR,MAAK;AAAA,sBACL,SAAS,MAAM,cAAc,KAAK;AAAA,sBAEjC,YAAE,mCAAmC,MAAM;AAAA;AAAA,kBAC9C;AAAA,kBACA;AAAA,oBAAC;AAAA;AAAA,sBACC,SAAQ;AAAA,sBACR,MAAK;AAAA,sBACL,WAAU;AAAA,sBACV,SAAS,MAAM,KAAK,kBAAkB,KAAK;AAAA,sBAE1C,YAAE,qCAAqC,QAAQ;AAAA;AAAA,kBAClD;AAAA,mBACF;AAAA,mBA3CQ,MAAM,EA4ChB,CACD,GACH;AAAA,cAGF,qBAAC,SAAI,WAAU,0DACb;AAAA;AAAA,kBAAC;AAAA;AAAA,oBACC,SAAQ;AAAA,oBACR,MAAK;AAAA,oBACL,SAAS,MAAM,iBAAiB,QAAQ;AAAA,oBAEvC,YAAE,oCAAoC,eAAe;AAAA;AAAA,gBACxD;AAAA,gBACA;AAAA,kBAAC;AAAA;AAAA,oBACC,SAAQ;AAAA,oBACR,MAAK;AAAA,oBACL,WAAU;AAAA,oBACV,SAAS,MAAM,KAAK,qBAAqB,QAAQ;AAAA,oBAEhD,YAAE,sCAAsC,iBAAiB;AAAA;AAAA,gBAC5D;AAAA,iBACF;AAAA,eACF;AAAA,eAnGkB,SAAS,EAoG7B;AAAA,QAEJ,CAAC;AAAA;AAAA,IACH;AAAA,IAIF,oBAAC,UAAO,MAAM,mBAAmB,MAAM,cAAc,CAAC,SAAS;AAAE,UAAI,CAAC,KAAM,qBAAoB;AAAA,IAAE,GAChG,+BAAC,iBAAc,WAAW,cAAc,oBAAoB,GAC1D;AAAA,0BAAC,gBACC,8BAAC,eACE,0BAAgB,SAAS,WACtB,EAAE,0CAA0C,iBAAiB,IAC7D,EAAE,wCAAwC,eAAe,GAC/D,GACF;AAAA,MACA,qBAAC,SAAI,WAAU,kBACb;AAAA,6BAAC,SAAI,WAAU,aACb;AAAA,8BAAC,SAAM,SAAQ,iBAAiB,YAAE,iCAAiC,MAAM,GAAE;AAAA,UAC3E;AAAA,YAAC;AAAA;AAAA,cACC,IAAG;AAAA,cACH,OAAO,aAAa;AAAA,cACpB,UAAU,CAAC,MAAM,gBAAgB,CAAC,UAAU,EAAE,GAAG,MAAM,MAAM,EAAE,OAAO,MAAM,EAAE;AAAA,cAC9E,aAAa,EAAE,4CAA4C,mBAAmB;AAAA,cAC9E,WAAS;AAAA;AAAA,UACX;AAAA,WACF;AAAA,QACA,qBAAC,SAAI,WAAU,2BACb;AAAA;AAAA,YAAC;AAAA;AAAA,cACC,IAAG;AAAA,cACH,SAAS,aAAa;AAAA,cACtB,iBAAiB,CAAC,YAAY,gBAAgB,CAAC,UAAU,EAAE,GAAG,MAAM,WAAW,YAAY,KAAK,EAAE;AAAA;AAAA,UACpG;AAAA,UACA,oBAAC,SAAM,SAAQ,oBAAmB,WAAU,kBACzC,YAAE,sCAAsC,yBAAyB,GACpE;AAAA,WACF;AAAA,SACF;AAAA,MACA,qBAAC,gBACC;AAAA,4BAAC,UAAO,SAAQ,WAAU,SAAS,qBAAqB,UAAU,oBAC/D,YAAE,qCAAqC,QAAQ,GAClD;AAAA,QACA,qBAAC,UAAO,SAAS,MAAM,KAAK,qBAAqB,GAAG,UAAU,sBAAsB,CAAC,aAAa,KAAK,KAAK,GACzG;AAAA,+BAAqB,oBAAC,WAAQ,WAAU,gBAAe,IAAK;AAAA,UAC5D,EAAE,mCAAmC,MAAM;AAAA,WAC9C;AAAA,SACF;AAAA,OACF,GACF;AAAA,IAEC;AAAA,IAGD,oBAAC,UAAO,MAAM,gBAAgB,MAAM,cAAc,CAAC,SAAS;AAAE,UAAI,CAAC,KAAM,kBAAiB;AAAA,IAAE,GAC1F,+BAAC,iBAAc,WAAW,cAAc,iBAAiB,GACvD;AAAA,0BAAC,gBACC,8BAAC,eACE,uBAAa,SAAS,WACnB,EAAE,+CAA+C,WAAW,IAC5D,EAAE,6CAA6C,YAAY,GACjE,GACF;AAAA,MACA,qBAAC,SAAI,WAAU,kBACb;AAAA,6BAAC,SAAI,WAAU,aACb;AAAA,8BAAC,SAAM,SAAQ,eAAe,YAAE,uCAAuC,OAAO,GAAE;AAAA,UAChF;AAAA,YAAC;AAAA;AAAA,cACC,IAAG;AAAA,cACH,OAAO,UAAU;AAAA,cACjB,UAAU,CAAC,MAAM,aAAa,CAAC,UAAU,EAAE,GAAG,MAAM,OAAO,EAAE,OAAO,MAAM,EAAE;AAAA,cAC5E,aAAa,EAAE,kDAAkD,gBAAgB;AAAA,cACjF,WAAS;AAAA;AAAA,UACX;AAAA,WACF;AAAA,QACA;AAAA,UAAC;AAAA;AAAA,YACC,OAAO,UAAU;AAAA,YACjB,MAAM,UAAU;AAAA,YAChB,eAAe,CAAC,SAAS,aAAa,CAAC,UAAU,EAAE,GAAG,MAAM,OAAO,KAAK,EAAE;AAAA,YAC1E,cAAc,CAAC,SAAS,aAAa,CAAC,UAAU,EAAE,GAAG,MAAM,MAAM,KAAK,EAAE;AAAA,YACxE,QAAQ;AAAA;AAAA,QACV;AAAA,SACF;AAAA,MACA,qBAAC,gBACC;AAAA,4BAAC,UAAO,SAAQ,WAAU,SAAS,kBAAkB,UAAU,iBAC5D,YAAE,0CAA0C,QAAQ,GACvD;AAAA,QACA,qBAAC,UAAO,SAAS,MAAM,KAAK,kBAAkB,GAAG,UAAU,mBAAmB,CAAC,UAAU,MAAM,KAAK,GACjG;AAAA,4BAAkB,oBAAC,WAAQ,WAAU,gBAAe,IAAK;AAAA,UACzD,EAAE,wCAAwC,MAAM;AAAA,WACnD;AAAA,SACF;AAAA,OACF,GACF;AAAA,KACF;AAEJ;",
4
+ "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { Input } from '@open-mercato/ui/primitives/input'\nimport { Label } from '@open-mercato/ui/primitives/label'\nimport { Checkbox } from '@open-mercato/ui/primitives/checkbox'\nimport {\n Dialog,\n DialogContent,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n} from '@open-mercato/ui/primitives/dialog'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { apiCall, readApiResultOrThrow, withScopedApiRequestHeaders } from '@open-mercato/ui/backend/utils/apiCall'\nimport { buildOptimisticLockHeader } from '@open-mercato/ui/backend/utils/optimisticLock'\nimport { raiseCrudError } from '@open-mercato/ui/backend/utils/serverErrors'\nimport { useOrganizationScopeVersion } from '@open-mercato/shared/lib/frontend/useOrganizationScope'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { useConfirmDialog } from '@open-mercato/ui/backend/confirm-dialog'\nimport { Spinner } from '@open-mercato/ui/primitives/spinner'\nimport {\n Accordion,\n AccordionContent,\n AccordionItem,\n AccordionTrigger,\n} from '@open-mercato/ui/primitives/accordion'\nimport {\n AppearanceSelector,\n type AppearanceSelectorLabels,\n} from '@open-mercato/core/modules/dictionaries/components/AppearanceSelector'\nimport {\n renderDictionaryColor,\n renderDictionaryIcon,\n} from '@open-mercato/core/modules/dictionaries/components/dictionaryAppearance'\n\ntype Pipeline = {\n id: string\n name: string\n isDefault: boolean\n organizationId: string\n tenantId: string\n updatedAt?: string | null\n}\n\ntype PipelineStage = {\n id: string\n pipelineId: string\n label: string\n order: number\n color: string | null\n icon: string | null\n updatedAt?: string | null\n}\n\ntype PipelineDialogState =\n | { mode: 'create' }\n | { mode: 'edit'; entry: Pipeline }\n\ntype StageDialogState =\n | { mode: 'create'; pipelineId: string }\n | { mode: 'edit'; entry: PipelineStage }\n\nfunction normalizePipeline(raw: Record<string, unknown>): Pipeline {\n return {\n id: typeof raw.id === 'string' ? raw.id : '',\n name: typeof raw.name === 'string' ? raw.name : '',\n isDefault: raw.isDefault === true || raw.is_default === true,\n organizationId: typeof raw.organizationId === 'string' ? raw.organizationId : (typeof raw.organization_id === 'string' ? raw.organization_id : ''),\n tenantId: typeof raw.tenantId === 'string' ? raw.tenantId : (typeof raw.tenant_id === 'string' ? raw.tenant_id : ''),\n updatedAt: typeof raw.updatedAt === 'string' ? raw.updatedAt : (typeof raw.updated_at === 'string' ? raw.updated_at : null),\n }\n}\n\nfunction normalizeStage(raw: Record<string, unknown>): PipelineStage {\n return {\n id: typeof raw.id === 'string' ? raw.id : '',\n pipelineId: typeof raw.pipelineId === 'string' ? raw.pipelineId : (typeof raw.pipeline_id === 'string' ? raw.pipeline_id : ''),\n label: typeof raw.label === 'string' ? raw.label : '',\n order: typeof raw.order === 'number' ? raw.order : 0,\n color: typeof raw.color === 'string' && raw.color.trim().length ? raw.color.trim() : null,\n icon: typeof raw.icon === 'string' && raw.icon.trim().length ? raw.icon.trim() : null,\n updatedAt: typeof raw.updatedAt === 'string' ? raw.updatedAt : (typeof raw.updated_at === 'string' ? raw.updated_at : null),\n }\n}\n\nexport default function PipelineSettings(): React.ReactElement {\n const t = useT()\n const scopeVersion = useOrganizationScopeVersion()\n const { confirm, ConfirmDialogElement } = useConfirmDialog()\n\n const [pipelines, setPipelines] = React.useState<Pipeline[]>([])\n const [loadingPipelines, setLoadingPipelines] = React.useState(false)\n const [pipelineDialog, setPipelineDialog] = React.useState<PipelineDialogState | null>(null)\n const [pipelineForm, setPipelineForm] = React.useState({ name: '', isDefault: false })\n const [submittingPipeline, setSubmittingPipeline] = React.useState(false)\n\n const [expandedPipelineId, setExpandedPipelineId] = React.useState<string | null>(null)\n const [stages, setStages] = React.useState<Record<string, PipelineStage[]>>({})\n const [loadingStages, setLoadingStages] = React.useState<Record<string, boolean>>({})\n const [stageDialog, setStageDialog] = React.useState<StageDialogState | null>(null)\n const [stageForm, setStageForm] = React.useState({ label: '', color: null as string | null, icon: null as string | null })\n const [submittingStage, setSubmittingStage] = React.useState(false)\n\n const loadPipelines = React.useCallback(async () => {\n setLoadingPipelines(true)\n try {\n const data = await readApiResultOrThrow<{ items?: unknown[] }>(\n '/api/customers/pipelines',\n undefined,\n { errorMessage: t('customers.pipelines.errors.loadFailed', 'Failed to load pipelines'), fallback: { items: [] } },\n )\n const items = Array.isArray(data?.items) ? data.items : []\n setPipelines(items.map((item) => normalizePipeline(item as Record<string, unknown>)))\n } finally {\n setLoadingPipelines(false)\n }\n }, [t])\n\n const loadStages = React.useCallback(async (pipelineId: string) => {\n setLoadingStages((prev) => ({ ...prev, [pipelineId]: true }))\n try {\n const data = await readApiResultOrThrow<{ items?: unknown[] }>(\n `/api/customers/pipeline-stages?pipelineId=${encodeURIComponent(pipelineId)}`,\n undefined,\n { errorMessage: t('customers.pipelines.errors.stagesLoadFailed', 'Failed to load stages'), fallback: { items: [] } },\n )\n const items = Array.isArray(data?.items) ? data.items : []\n setStages((prev) => ({\n ...prev,\n [pipelineId]: items.map((item) => normalizeStage(item as Record<string, unknown>)),\n }))\n } finally {\n setLoadingStages((prev) => ({ ...prev, [pipelineId]: false }))\n }\n }, [t])\n\n React.useEffect(() => {\n void loadPipelines()\n }, [loadPipelines, scopeVersion])\n\n React.useEffect(() => {\n if (expandedPipelineId) {\n void loadStages(expandedPipelineId)\n }\n }, [expandedPipelineId, loadStages])\n\n const openCreatePipeline = React.useCallback(() => {\n setPipelineForm({ name: '', isDefault: false })\n setPipelineDialog({ mode: 'create' })\n }, [])\n\n const openEditPipeline = React.useCallback((pipeline: Pipeline) => {\n setPipelineForm({ name: pipeline.name, isDefault: pipeline.isDefault })\n setPipelineDialog({ mode: 'edit', entry: pipeline })\n }, [])\n\n const closePipelineDialog = React.useCallback(() => {\n setPipelineDialog(null)\n }, [])\n\n const handlePipelineSubmit = React.useCallback(async () => {\n if (!pipelineForm.name.trim()) return\n setSubmittingPipeline(true)\n try {\n if (pipelineDialog?.mode === 'create') {\n const res = await apiCall('/api/customers/pipelines', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ name: pipelineForm.name.trim(), isDefault: pipelineForm.isDefault }),\n })\n if (!res.ok) {\n await raiseCrudError(res.response, t('customers.pipelines.errors.createFailed', 'Failed to create pipeline'))\n return\n }\n flash(t('customers.pipelines.flash.created', 'Pipeline created'), 'success')\n } else if (pipelineDialog?.mode === 'edit') {\n const res = await withScopedApiRequestHeaders(\n buildOptimisticLockHeader(pipelineDialog.entry.updatedAt),\n () =>\n apiCall('/api/customers/pipelines', {\n method: 'PUT',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ id: pipelineDialog.entry.id, name: pipelineForm.name.trim(), isDefault: pipelineForm.isDefault }),\n }),\n )\n if (!res.ok) {\n await raiseCrudError(res.response, t('customers.pipelines.errors.updateFailed', 'Failed to update pipeline'))\n return\n }\n flash(t('customers.pipelines.flash.updated', 'Pipeline updated'), 'success')\n }\n setPipelineDialog(null)\n await loadPipelines()\n } finally {\n setSubmittingPipeline(false)\n }\n }, [pipelineDialog, pipelineForm, loadPipelines, t])\n\n const handleDeletePipeline = React.useCallback(async (pipeline: Pipeline) => {\n const confirmed = await confirm({\n title: t('customers.pipelines.confirm.deleteTitle', 'Delete pipeline'),\n text: t('customers.pipelines.confirm.deleteDesc', 'Are you sure you want to delete this pipeline? This cannot be undone.'),\n confirmText: t('customers.pipelines.confirm.deleteConfirm', 'Delete'),\n variant: 'destructive',\n })\n if (!confirmed) return\n const res = await withScopedApiRequestHeaders(\n buildOptimisticLockHeader(pipeline.updatedAt),\n () =>\n apiCall('/api/customers/pipelines', {\n method: 'DELETE',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ id: pipeline.id }),\n }),\n )\n if (!res.ok) {\n const body = (res.result ?? {}) as Record<string, unknown>\n const msg = typeof body.error === 'string' ? body.error : t('customers.pipelines.errors.deleteFailed', 'Failed to delete pipeline')\n flash(msg, 'error')\n return\n }\n flash(t('customers.pipelines.flash.deleted', 'Pipeline deleted'), 'success')\n if (expandedPipelineId === pipeline.id) setExpandedPipelineId(null)\n await loadPipelines()\n }, [confirm, expandedPipelineId, loadPipelines, t])\n\n const openCreateStage = React.useCallback((pipelineId: string) => {\n setStageForm({ label: '', color: null, icon: null })\n setStageDialog({ mode: 'create', pipelineId })\n }, [])\n\n const openEditStage = React.useCallback((stage: PipelineStage) => {\n setStageForm({ label: stage.label, color: stage.color, icon: stage.icon })\n setStageDialog({ mode: 'edit', entry: stage })\n }, [])\n\n const closeStageDialog = React.useCallback(() => {\n setStageDialog(null)\n }, [])\n\n const handleStageSubmit = React.useCallback(async () => {\n if (!stageForm.label.trim()) return\n setSubmittingStage(true)\n try {\n const appearance: Record<string, unknown> = {}\n if (stageForm.color) appearance.color = stageForm.color\n if (stageForm.icon) appearance.icon = stageForm.icon\n\n if (stageDialog?.mode === 'create') {\n const res = await apiCall('/api/customers/pipeline-stages', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ pipelineId: stageDialog.pipelineId, label: stageForm.label.trim(), ...appearance }),\n })\n if (!res.ok) {\n await raiseCrudError(res.response, t('customers.pipelines.errors.stageCreateFailed', 'Failed to create stage'))\n return\n }\n flash(t('customers.pipelines.flash.stageCreated', 'Stage created'), 'success')\n await loadStages(stageDialog.pipelineId)\n } else if (stageDialog?.mode === 'edit') {\n const res = await withScopedApiRequestHeaders(\n buildOptimisticLockHeader(stageDialog.entry.updatedAt),\n () =>\n apiCall('/api/customers/pipeline-stages', {\n method: 'PUT',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ id: stageDialog.entry.id, label: stageForm.label.trim(), ...appearance }),\n }),\n )\n if (!res.ok) {\n await raiseCrudError(res.response, t('customers.pipelines.errors.stageUpdateFailed', 'Failed to update stage'))\n return\n }\n flash(t('customers.pipelines.flash.stageUpdated', 'Stage updated'), 'success')\n await loadStages(stageDialog.entry.pipelineId)\n }\n setStageDialog(null)\n } finally {\n setSubmittingStage(false)\n }\n }, [stageDialog, stageForm, loadStages, t])\n\n const handleDeleteStage = React.useCallback(async (stage: PipelineStage) => {\n const confirmed = await confirm({\n title: t('customers.pipelines.confirm.stageDeleteTitle', 'Delete stage'),\n text: t('customers.pipelines.confirm.stageDeleteDesc', 'Are you sure you want to delete this stage?'),\n confirmText: t('customers.pipelines.confirm.stageDeleteConfirm', 'Delete'),\n variant: 'destructive',\n })\n if (!confirmed) return\n const res = await withScopedApiRequestHeaders(\n buildOptimisticLockHeader(stage.updatedAt),\n () =>\n apiCall('/api/customers/pipeline-stages', {\n method: 'DELETE',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ id: stage.id }),\n }),\n )\n if (!res.ok) {\n const body = (res.result ?? {}) as Record<string, unknown>\n const msg = typeof body.error === 'string' ? body.error : t('customers.pipelines.errors.stageDeleteFailed', 'Failed to delete stage')\n flash(msg, 'error')\n return\n }\n flash(t('customers.pipelines.flash.stageDeleted', 'Stage deleted'), 'success')\n await loadStages(stage.pipelineId)\n }, [confirm, loadStages, t])\n\n const handleMoveStage = React.useCallback(async (stage: PipelineStage, direction: 'up' | 'down') => {\n const pipelineStages = stages[stage.pipelineId] ?? []\n const idx = pipelineStages.findIndex((s) => s.id === stage.id)\n if (idx < 0) return\n const swapIdx = direction === 'up' ? idx - 1 : idx + 1\n if (swapIdx < 0 || swapIdx >= pipelineStages.length) return\n\n const reordered = [...pipelineStages]\n const temp = reordered[idx]\n reordered[idx] = reordered[swapIdx]\n reordered[swapIdx] = temp\n\n const orderedStages = reordered.map((s, i) => ({ id: s.id, order: i }))\n const res = await apiCall('/api/customers/pipeline-stages/reorder', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ stages: orderedStages }),\n })\n if (!res.ok) {\n flash(t('customers.pipelines.errors.reorderFailed', 'Failed to reorder stages'), 'error')\n return\n }\n await loadStages(stage.pipelineId)\n }, [stages, loadStages, t])\n\n const handleKeyDown = React.useCallback(\n (handler: () => void) => (e: React.KeyboardEvent) => {\n if ((e.metaKey || e.ctrlKey) && e.key === 'Enter') {\n e.preventDefault()\n handler()\n }\n },\n [],\n )\n\n const appearanceLabels = React.useMemo<AppearanceSelectorLabels>(() => ({\n colorLabel: t('customers.pipelines.stageForm.color', 'Color'),\n colorClearLabel: t('customers.pipelines.stageForm.colorClear', 'Remove color'),\n iconLabel: t('customers.pipelines.stageForm.icon', 'Icon'),\n iconPlaceholder: t('customers.pipelines.stageForm.iconPlaceholder', 'e.g. lucide:star'),\n iconPickerTriggerLabel: t('customers.pipelines.stageForm.iconPicker', 'Pick icon'),\n iconSearchPlaceholder: t('customers.pipelines.stageForm.iconSearch', 'Search icons\u2026'),\n iconSearchEmptyLabel: t('customers.pipelines.stageForm.iconSearchEmpty', 'No icons found'),\n iconSuggestionsLabel: t('customers.pipelines.stageForm.iconSuggestions', 'Suggestions'),\n iconClearLabel: t('customers.pipelines.stageForm.iconClear', 'Remove icon'),\n previewEmptyLabel: t('customers.pipelines.stageForm.previewEmpty', 'No appearance set'),\n }), [t])\n\n return (\n <div className=\"space-y-4\">\n <div className=\"flex items-center justify-between\">\n <div>\n <h3 className=\"text-base font-semibold\">{t('customers.pipelines.title', 'Sales Pipelines')}</h3>\n <p className=\"text-sm text-muted-foreground\">\n {t('customers.pipelines.description', 'Manage sales pipelines and their stages.')}\n </p>\n </div>\n <Button size=\"sm\" onClick={openCreatePipeline}>\n {t('customers.pipelines.actions.create', 'Add pipeline')}\n </Button>\n </div>\n\n {loadingPipelines ? (\n <div className=\"flex items-center gap-2 text-sm text-muted-foreground\">\n <Spinner className=\"h-4 w-4\" />\n {t('customers.pipelines.loading', 'Loading pipelines\u2026')}\n </div>\n ) : pipelines.length === 0 ? (\n <p className=\"text-sm text-muted-foreground\">\n {t('customers.pipelines.empty', 'No pipelines yet. Create one to get started.')}\n </p>\n ) : (\n <Accordion\n type=\"single\"\n collapsible\n value={expandedPipelineId ?? ''}\n onValueChange={(next) => setExpandedPipelineId(next || null)}\n className=\"space-y-2\"\n >\n {pipelines.map((pipeline) => {\n const pipelineStages = stages[pipeline.id] ?? []\n const isLoadingStages = loadingStages[pipeline.id] ?? false\n\n return (\n <AccordionItem key={pipeline.id} value={pipeline.id}>\n <AccordionTrigger triggerIcon=\"chevron\">\n <span className=\"flex items-center gap-2\">\n <span className=\"text-sm font-medium\">{pipeline.name}</span>\n {pipeline.isDefault ? (\n <span className=\"rounded-full bg-primary/10 px-2 py-0.5 text-xs text-primary\">\n {t('customers.pipelines.defaultBadge', 'Default')}\n </span>\n ) : null}\n </span>\n </AccordionTrigger>\n <AccordionContent>\n <div className=\"mb-3 flex items-center justify-between\">\n <span className=\"text-xs font-medium text-muted-foreground uppercase tracking-wide\">\n {t('customers.pipelines.stages.title', 'Stages')}\n </span>\n <Button size=\"sm\" variant=\"outline\" onClick={() => openCreateStage(pipeline.id)}>\n {t('customers.pipelines.stages.add', 'Add stage')}\n </Button>\n </div>\n\n {isLoadingStages ? (\n <div className=\"flex items-center gap-2 text-sm text-muted-foreground\">\n <Spinner className=\"h-3 w-3\" />\n {t('customers.pipelines.stages.loading', 'Loading\u2026')}\n </div>\n ) : pipelineStages.length === 0 ? (\n <p className=\"text-sm text-muted-foreground\">\n {t('customers.pipelines.stages.empty', 'No stages yet.')}\n </p>\n ) : (\n <div className=\"divide-y divide-border rounded-md border bg-background\">\n {pipelineStages.map((stage, idx) => (\n <div key={stage.id} className=\"flex items-center justify-between gap-3 px-3 py-2\">\n <div className=\"flex items-center gap-2\">\n <span className=\"w-5 text-center text-xs text-muted-foreground\">{idx + 1}</span>\n {stage.color ? renderDictionaryColor(stage.color, 'h-3 w-3 rounded-full') : null}\n {stage.icon ? renderDictionaryIcon(stage.icon, 'h-4 w-4') : null}\n <span className=\"text-sm\">{stage.label}</span>\n </div>\n <div className=\"flex items-center gap-1\">\n <Button\n variant=\"ghost\"\n size=\"icon\"\n className=\"h-7 w-7\"\n disabled={idx === 0}\n onClick={() => void handleMoveStage(stage, 'up')}\n title={t('customers.pipelines.stages.moveUp', 'Move up')}\n >\n \u2191\n </Button>\n <Button\n variant=\"ghost\"\n size=\"icon\"\n className=\"h-7 w-7\"\n disabled={idx === pipelineStages.length - 1}\n onClick={() => void handleMoveStage(stage, 'down')}\n title={t('customers.pipelines.stages.moveDown', 'Move down')}\n >\n \u2193\n </Button>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n onClick={() => openEditStage(stage)}\n >\n {t('customers.pipelines.stages.edit', 'Edit')}\n </Button>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n className=\"text-destructive hover:text-destructive\"\n onClick={() => void handleDeleteStage(stage)}\n >\n {t('customers.pipelines.stages.delete', 'Delete')}\n </Button>\n </div>\n </div>\n ))}\n </div>\n )}\n\n <div className=\"mt-4 flex items-center justify-end gap-2 border-t pt-3\">\n <Button\n variant=\"ghost\"\n size=\"sm\"\n onClick={() => openEditPipeline(pipeline)}\n >\n {t('customers.pipelines.actions.edit', 'Edit pipeline')}\n </Button>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n className=\"text-destructive hover:text-destructive\"\n onClick={() => void handleDeletePipeline(pipeline)}\n >\n {t('customers.pipelines.actions.delete', 'Delete pipeline')}\n </Button>\n </div>\n </AccordionContent>\n </AccordionItem>\n )\n })}\n </Accordion>\n )}\n\n {/* Pipeline Dialog */}\n <Dialog open={pipelineDialog !== null} onOpenChange={(open) => { if (!open) closePipelineDialog() }}>\n <DialogContent onKeyDown={handleKeyDown(handlePipelineSubmit)}>\n <DialogHeader>\n <DialogTitle>\n {pipelineDialog?.mode === 'create'\n ? t('customers.pipelines.dialog.createTitle', 'Create pipeline')\n : t('customers.pipelines.dialog.editTitle', 'Edit pipeline')}\n </DialogTitle>\n </DialogHeader>\n <div className=\"space-y-4 py-2\">\n <div className=\"space-y-2\">\n <Label htmlFor=\"pipeline-name\">{t('customers.pipelines.form.name', 'Name')}</Label>\n <Input\n id=\"pipeline-name\"\n value={pipelineForm.name}\n onChange={(e) => setPipelineForm((prev) => ({ ...prev, name: e.target.value }))}\n placeholder={t('customers.pipelines.form.namePlaceholder', 'e.g. New Business')}\n autoFocus\n />\n </div>\n <div className=\"flex items-center gap-2\">\n <Checkbox\n id=\"pipeline-default\"\n checked={pipelineForm.isDefault}\n onCheckedChange={(checked) => setPipelineForm((prev) => ({ ...prev, isDefault: checked === true }))}\n />\n <Label htmlFor=\"pipeline-default\" className=\"cursor-pointer\">\n {t('customers.pipelines.form.isDefault', 'Set as default pipeline')}\n </Label>\n </div>\n </div>\n <DialogFooter>\n <Button variant=\"outline\" onClick={closePipelineDialog} disabled={submittingPipeline}>\n {t('customers.pipelines.dialog.cancel', 'Cancel')}\n </Button>\n <Button onClick={() => void handlePipelineSubmit()} disabled={submittingPipeline || !pipelineForm.name.trim()}>\n {submittingPipeline ? <Spinner className=\"mr-2 h-4 w-4\" /> : null}\n {t('customers.pipelines.dialog.save', 'Save')}\n </Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n\n {ConfirmDialogElement}\n\n {/* Stage Dialog */}\n <Dialog open={stageDialog !== null} onOpenChange={(open) => { if (!open) closeStageDialog() }}>\n <DialogContent onKeyDown={handleKeyDown(handleStageSubmit)}>\n <DialogHeader>\n <DialogTitle>\n {stageDialog?.mode === 'create'\n ? t('customers.pipelines.stageDialog.createTitle', 'Add stage')\n : t('customers.pipelines.stageDialog.editTitle', 'Edit stage')}\n </DialogTitle>\n </DialogHeader>\n <div className=\"space-y-4 py-2\">\n <div className=\"space-y-2\">\n <Label htmlFor=\"stage-label\">{t('customers.pipelines.stageForm.label', 'Label')}</Label>\n <Input\n id=\"stage-label\"\n value={stageForm.label}\n onChange={(e) => setStageForm((prev) => ({ ...prev, label: e.target.value }))}\n placeholder={t('customers.pipelines.stageForm.labelPlaceholder', 'e.g. Discovery')}\n autoFocus\n />\n </div>\n <AppearanceSelector\n color={stageForm.color}\n icon={stageForm.icon}\n onColorChange={(next) => setStageForm((prev) => ({ ...prev, color: next }))}\n onIconChange={(next) => setStageForm((prev) => ({ ...prev, icon: next }))}\n labels={appearanceLabels}\n />\n </div>\n <DialogFooter>\n <Button variant=\"outline\" onClick={closeStageDialog} disabled={submittingStage}>\n {t('customers.pipelines.stageDialog.cancel', 'Cancel')}\n </Button>\n <Button onClick={() => void handleStageSubmit()} disabled={submittingStage || !stageForm.label.trim()}>\n {submittingStage ? <Spinner className=\"mr-2 h-4 w-4\" /> : null}\n {t('customers.pipelines.stageDialog.save', 'Save')}\n </Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n </div>\n )\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -60,7 +60,7 @@ function TimelineEntry({
60
60
  if (!onMarkDone || markingDone) return;
61
61
  setMarkingDone(true);
62
62
  try {
63
- await onMarkDone(activity.id);
63
+ await onMarkDone(activity.id, activity.updatedAt);
64
64
  } finally {
65
65
  setMarkingDone(false);
66
66
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/modules/customers/components/detail/ActivityTimeline.tsx"],
4
- "sourcesContent": ["'use client'\nimport * as React from 'react'\nimport { Check, ListTodo, Phone, Mail, Users, StickyNote, User } from 'lucide-react'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport type { TranslateFn } from '@open-mercato/shared/lib/i18n/context'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { AiActionChips } from './AiActionChips'\nimport type { InteractionSummary } from './types'\n\nconst TYPE_ICONS: Record<string, React.ComponentType<{ className?: string }>> = {\n call: Phone,\n email: Mail,\n meeting: Users,\n note: StickyNote,\n task: ListTodo,\n}\n\ninterface ActivityTimelineProps {\n activities: InteractionSummary[]\n onEdit?: (activity: InteractionSummary) => void\n onMarkDone?: (activityId: string) => void | Promise<void>\n}\n\nexport function ActivityTimeline({ activities, onEdit, onMarkDone }: ActivityTimelineProps) {\n const t = useT()\n\n if (activities.length === 0) {\n return (\n <div className=\"py-6 text-center text-sm text-muted-foreground\">\n {t('customers.timeline.empty', 'No activities match the current filters.')}\n </div>\n )\n }\n\n return (\n <div>\n {activities.map((activity, index) => {\n const dateStr = activity.scheduledAt ?? activity.occurredAt ?? activity.createdAt\n const activityYear = dateStr ? new Date(dateStr).getFullYear() : null\n const prevDateStr = index > 0 ? (activities[index - 1].scheduledAt ?? activities[index - 1].occurredAt ?? activities[index - 1].createdAt) : null\n const prevYear = prevDateStr ? new Date(prevDateStr).getFullYear() : null\n const showYearSeparator = activityYear !== null && prevYear !== null && activityYear !== prevYear\n\n return (\n <React.Fragment key={activity.id}>\n {showYearSeparator && (\n <div className=\"flex items-center gap-3 py-3 px-5\">\n <div className=\"h-px flex-1 bg-border\" />\n <span className=\"text-xs font-semibold text-muted-foreground\">\n {t('customers.activities.yearSeparator', '{year}', { year: activityYear })}\n </span>\n <div className=\"h-px flex-1 bg-border\" />\n </div>\n )}\n <TimelineEntry\n activity={activity}\n t={t}\n withBorder={index < activities.length - 1}\n onEdit={onEdit}\n onMarkDone={onMarkDone}\n />\n </React.Fragment>\n )\n })}\n </div>\n )\n}\n\nfunction TimelineEntry({\n activity,\n t,\n withBorder,\n onEdit,\n onMarkDone,\n}: {\n activity: InteractionSummary\n t: TranslateFn\n withBorder: boolean\n onEdit?: (activity: InteractionSummary) => void\n onMarkDone?: (activityId: string) => void | Promise<void>\n}) {\n const dateStr = activity.scheduledAt ?? activity.occurredAt ?? activity.createdAt\n const TypeIcon = TYPE_ICONS[activity.interactionType]\n const title = activity.title ?? activity.body ?? activity.interactionType\n const duration = activity.duration ? ` (${activity.duration} min)` : ''\n const isPlanned = activity.status === 'planned'\n const [markingDone, setMarkingDone] = React.useState(false)\n\n const handleMarkDone = React.useCallback(async (event: React.MouseEvent | React.KeyboardEvent) => {\n event.stopPropagation()\n if (!onMarkDone || markingDone) return\n setMarkingDone(true)\n try {\n await onMarkDone(activity.id)\n } finally {\n setMarkingDone(false)\n }\n }, [activity.id, markingDone, onMarkDone])\n\n return (\n <div\n className={`py-2.5 ${withBorder ? 'border-b border-border/60' : ''} ${onEdit ? 'cursor-pointer hover:bg-accent/40 transition-colors' : ''}`}\n onClick={() => onEdit?.(activity)}\n role={onEdit ? 'button' : undefined}\n tabIndex={onEdit ? 0 : undefined}\n onKeyDown={onEdit ? (e) => { if (e.key === 'Enter') onEdit(activity) } : undefined}\n >\n <div className=\"grid items-start gap-3\" style={{ gridTemplateColumns: '75px 32px 1fr' }}>\n {/* Column 1: Date */}\n <div className=\"shrink-0\">\n <span className=\"block text-[11px] font-semibold leading-tight text-foreground\">\n {formatRelativeDate(dateStr, t)}\n </span>\n <span className=\"block text-[10px] leading-tight text-muted-foreground\">\n {formatTime(dateStr)}\n </span>\n </div>\n\n {/* Column 2: Type icon */}\n <div className=\"flex size-8 items-center justify-center rounded-md bg-muted shrink-0\">\n {TypeIcon ? <TypeIcon className=\"size-3.5 text-muted-foreground\" /> : null}\n </div>\n\n {/* Column 3: Content */}\n <div className=\"min-w-0 space-y-1.5\">\n <div className=\"flex items-start justify-between gap-2\">\n <span className=\"block text-[12px] font-semibold leading-tight text-foreground\">\n {title}{duration}\n </span>\n {isPlanned && onMarkDone ? (\n <Button\n type=\"button\"\n variant=\"default\"\n size=\"sm\"\n disabled={markingDone}\n onClick={handleMarkDone}\n className=\"shrink-0\"\n >\n <Check className=\"size-3.5\" />\n {t('customers.activities.actions.markDone', 'Mark done')}\n </Button>\n ) : null}\n </div>\n\n {activity.body && activity.title && (\n <p className=\"text-[11px] leading-snug text-muted-foreground\">\n {activity.body}\n </p>\n )}\n\n {activity.authorName && (\n <div className=\"flex items-center gap-1 text-[10px] text-muted-foreground\">\n <User className=\"size-2.5 shrink-0\" />\n <span>{t('customers.timeline.author', 'by {{name}}', { name: activity.authorName })}</span>\n </div>\n )}\n\n <AiActionChips activityType={activity.interactionType} />\n </div>\n </div>\n </div>\n )\n}\n\nfunction formatRelativeDate(isoString: string, t: TranslateFn): string {\n try {\n const date = new Date(isoString)\n const now = new Date()\n // Compare calendar dates (not time-based diff) to correctly handle same-day future times\n const dateDay = new Date(date.getFullYear(), date.getMonth(), date.getDate())\n const nowDay = new Date(now.getFullYear(), now.getMonth(), now.getDate())\n const diffDays = Math.round((nowDay.getTime() - dateDay.getTime()) / (1000 * 60 * 60 * 24))\n\n if (diffDays === 0) return t('customers.timeline.date.today', 'today')\n if (diffDays === 1) return t('customers.timeline.date.yesterday', 'yesterday')\n return date.toLocaleDateString(undefined, { day: 'numeric', month: 'short' })\n } catch {\n return ''\n }\n}\n\nfunction formatTime(isoString: string): string {\n try {\n return new Date(isoString).toLocaleTimeString(undefined, { hour: '2-digit', minute: '2-digit' })\n } catch {\n return ''\n }\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["'use client'\nimport * as React from 'react'\nimport { Check, ListTodo, Phone, Mail, Users, StickyNote, User } from 'lucide-react'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport type { TranslateFn } from '@open-mercato/shared/lib/i18n/context'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { AiActionChips } from './AiActionChips'\nimport type { InteractionSummary } from './types'\n\nconst TYPE_ICONS: Record<string, React.ComponentType<{ className?: string }>> = {\n call: Phone,\n email: Mail,\n meeting: Users,\n note: StickyNote,\n task: ListTodo,\n}\n\ninterface ActivityTimelineProps {\n activities: InteractionSummary[]\n onEdit?: (activity: InteractionSummary) => void\n onMarkDone?: (activityId: string, updatedAt?: string | null) => void | Promise<void>\n}\n\nexport function ActivityTimeline({ activities, onEdit, onMarkDone }: ActivityTimelineProps) {\n const t = useT()\n\n if (activities.length === 0) {\n return (\n <div className=\"py-6 text-center text-sm text-muted-foreground\">\n {t('customers.timeline.empty', 'No activities match the current filters.')}\n </div>\n )\n }\n\n return (\n <div>\n {activities.map((activity, index) => {\n const dateStr = activity.scheduledAt ?? activity.occurredAt ?? activity.createdAt\n const activityYear = dateStr ? new Date(dateStr).getFullYear() : null\n const prevDateStr = index > 0 ? (activities[index - 1].scheduledAt ?? activities[index - 1].occurredAt ?? activities[index - 1].createdAt) : null\n const prevYear = prevDateStr ? new Date(prevDateStr).getFullYear() : null\n const showYearSeparator = activityYear !== null && prevYear !== null && activityYear !== prevYear\n\n return (\n <React.Fragment key={activity.id}>\n {showYearSeparator && (\n <div className=\"flex items-center gap-3 py-3 px-5\">\n <div className=\"h-px flex-1 bg-border\" />\n <span className=\"text-xs font-semibold text-muted-foreground\">\n {t('customers.activities.yearSeparator', '{year}', { year: activityYear })}\n </span>\n <div className=\"h-px flex-1 bg-border\" />\n </div>\n )}\n <TimelineEntry\n activity={activity}\n t={t}\n withBorder={index < activities.length - 1}\n onEdit={onEdit}\n onMarkDone={onMarkDone}\n />\n </React.Fragment>\n )\n })}\n </div>\n )\n}\n\nfunction TimelineEntry({\n activity,\n t,\n withBorder,\n onEdit,\n onMarkDone,\n}: {\n activity: InteractionSummary\n t: TranslateFn\n withBorder: boolean\n onEdit?: (activity: InteractionSummary) => void\n onMarkDone?: (activityId: string, updatedAt?: string | null) => void | Promise<void>\n}) {\n const dateStr = activity.scheduledAt ?? activity.occurredAt ?? activity.createdAt\n const TypeIcon = TYPE_ICONS[activity.interactionType]\n const title = activity.title ?? activity.body ?? activity.interactionType\n const duration = activity.duration ? ` (${activity.duration} min)` : ''\n const isPlanned = activity.status === 'planned'\n const [markingDone, setMarkingDone] = React.useState(false)\n\n const handleMarkDone = React.useCallback(async (event: React.MouseEvent | React.KeyboardEvent) => {\n event.stopPropagation()\n if (!onMarkDone || markingDone) return\n setMarkingDone(true)\n try {\n await onMarkDone(activity.id, activity.updatedAt)\n } finally {\n setMarkingDone(false)\n }\n }, [activity.id, markingDone, onMarkDone])\n\n return (\n <div\n className={`py-2.5 ${withBorder ? 'border-b border-border/60' : ''} ${onEdit ? 'cursor-pointer hover:bg-accent/40 transition-colors' : ''}`}\n onClick={() => onEdit?.(activity)}\n role={onEdit ? 'button' : undefined}\n tabIndex={onEdit ? 0 : undefined}\n onKeyDown={onEdit ? (e) => { if (e.key === 'Enter') onEdit(activity) } : undefined}\n >\n <div className=\"grid items-start gap-3\" style={{ gridTemplateColumns: '75px 32px 1fr' }}>\n {/* Column 1: Date */}\n <div className=\"shrink-0\">\n <span className=\"block text-[11px] font-semibold leading-tight text-foreground\">\n {formatRelativeDate(dateStr, t)}\n </span>\n <span className=\"block text-[10px] leading-tight text-muted-foreground\">\n {formatTime(dateStr)}\n </span>\n </div>\n\n {/* Column 2: Type icon */}\n <div className=\"flex size-8 items-center justify-center rounded-md bg-muted shrink-0\">\n {TypeIcon ? <TypeIcon className=\"size-3.5 text-muted-foreground\" /> : null}\n </div>\n\n {/* Column 3: Content */}\n <div className=\"min-w-0 space-y-1.5\">\n <div className=\"flex items-start justify-between gap-2\">\n <span className=\"block text-[12px] font-semibold leading-tight text-foreground\">\n {title}{duration}\n </span>\n {isPlanned && onMarkDone ? (\n <Button\n type=\"button\"\n variant=\"default\"\n size=\"sm\"\n disabled={markingDone}\n onClick={handleMarkDone}\n className=\"shrink-0\"\n >\n <Check className=\"size-3.5\" />\n {t('customers.activities.actions.markDone', 'Mark done')}\n </Button>\n ) : null}\n </div>\n\n {activity.body && activity.title && (\n <p className=\"text-[11px] leading-snug text-muted-foreground\">\n {activity.body}\n </p>\n )}\n\n {activity.authorName && (\n <div className=\"flex items-center gap-1 text-[10px] text-muted-foreground\">\n <User className=\"size-2.5 shrink-0\" />\n <span>{t('customers.timeline.author', 'by {{name}}', { name: activity.authorName })}</span>\n </div>\n )}\n\n <AiActionChips activityType={activity.interactionType} />\n </div>\n </div>\n </div>\n )\n}\n\nfunction formatRelativeDate(isoString: string, t: TranslateFn): string {\n try {\n const date = new Date(isoString)\n const now = new Date()\n // Compare calendar dates (not time-based diff) to correctly handle same-day future times\n const dateDay = new Date(date.getFullYear(), date.getMonth(), date.getDate())\n const nowDay = new Date(now.getFullYear(), now.getMonth(), now.getDate())\n const diffDays = Math.round((nowDay.getTime() - dateDay.getTime()) / (1000 * 60 * 60 * 24))\n\n if (diffDays === 0) return t('customers.timeline.date.today', 'today')\n if (diffDays === 1) return t('customers.timeline.date.yesterday', 'yesterday')\n return date.toLocaleDateString(undefined, { day: 'numeric', month: 'short' })\n } catch {\n return ''\n }\n}\n\nfunction formatTime(isoString: string): string {\n try {\n return new Date(isoString).toLocaleTimeString(undefined, { hour: '2-digit', minute: '2-digit' })\n } catch {\n return ''\n }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -56,6 +56,7 @@ function AddressesSection({
56
56
  const response = await apiCallOrThrow(
57
57
  "/api/customers/addresses",
58
58
  {
59
+ // optimistic-lock-exempt: address link add/remove sub-resource
59
60
  method: "POST",
60
61
  headers: { "content-type": "application/json" },
61
62
  body: JSON.stringify({
@@ -72,6 +73,7 @@ function AddressesSection({
72
73
  await apiCallOrThrow(
73
74
  "/api/customers/addresses",
74
75
  {
76
+ // optimistic-lock-exempt: address link add/remove sub-resource
75
77
  method: "PUT",
76
78
  headers: { "content-type": "application/json" },
77
79
  body: JSON.stringify({
@@ -87,6 +89,7 @@ function AddressesSection({
87
89
  await apiCallOrThrow(
88
90
  "/api/customers/addresses",
89
91
  {
92
+ // optimistic-lock-exempt: address link add/remove sub-resource
90
93
  method: "DELETE",
91
94
  headers: { "content-type": "application/json" },
92
95
  body: JSON.stringify({ id })
@@ -116,6 +119,7 @@ function AddressesSection({
116
119
  const response = await apiCallOrThrow(
117
120
  "/api/customers/dictionaries/address-types",
118
121
  {
122
+ // optimistic-lock-exempt: address-type dictionary create-only
119
123
  method: "POST",
120
124
  headers: { "content-type": "application/json" },
121
125
  body: JSON.stringify({ value })
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/modules/customers/components/detail/AddressesSection.tsx"],
4
- "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { apiCall, apiCallOrThrow, readApiResultOrThrow } from '@open-mercato/ui/backend/utils/apiCall'\nimport { AddressesSection as SharedAddressesSection } from '@open-mercato/ui/backend/detail'\nimport type { AddressDataAdapter, AddressTypesAdapter, AddressFormatStrategy, SectionAction } from '@open-mercato/ui/backend/detail'\nimport { createTranslatorWithFallback } from '@open-mercato/shared/lib/i18n/translate'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\n\nexport type AddressesSectionProps = {\n entityId: string | null\n emptyLabel: string\n addActionLabel: string\n emptyState: { title: string; actionLabel: string; description?: string }\n onActionChange?: (action: SectionAction | null) => void\n translator?: (key: string, fallback?: string, params?: Record<string, string | number>) => string\n onLoadingChange?: (isLoading: boolean) => void\n}\n\ntype ApiAddressPayload = Record<string, unknown>\n\nexport function AddressesSection({\n entityId,\n emptyLabel,\n addActionLabel,\n emptyState,\n onActionChange,\n translator,\n onLoadingChange,\n}: AddressesSectionProps) {\n const tHook = useT()\n const fallbackTranslator = React.useMemo(() => createTranslatorWithFallback(tHook), [tHook])\n const t = translator ?? fallbackTranslator\n\n const dataAdapter = React.useMemo<AddressDataAdapter>(() => ({\n list: async ({ entityId: listEntityId }) => {\n if (!listEntityId) return []\n const params = new URLSearchParams({ entityId: listEntityId, pageSize: '100' })\n const payload = await readApiResultOrThrow<ApiAddressPayload>(\n `/api/customers/addresses?${params.toString()}`,\n undefined,\n { errorMessage: t('customers.people.detail.addresses.error') },\n )\n const items = Array.isArray(payload?.items) ? payload.items : []\n return items\n .map((item) => {\n if (!item || typeof item !== 'object') return null\n const record = item as Record<string, unknown>\n const rawId = record.id ?? record.address_id ?? null\n const id =\n typeof rawId === 'string'\n ? rawId\n : typeof rawId === 'number' || typeof rawId === 'bigint'\n ? String(rawId)\n : null\n if (!id) return null\n const addressLine1 = typeof record.address_line1 === 'string'\n ? record.address_line1\n : typeof record.addressLine1 === 'string'\n ? record.addressLine1\n : null\n if (!addressLine1) return null\n return {\n id,\n name: typeof record.name === 'string' ? record.name : null,\n purpose: typeof record.purpose === 'string' ? record.purpose : null,\n companyName: typeof record.company_name === 'string'\n ? record.company_name\n : typeof record.companyName === 'string'\n ? record.companyName\n : null,\n addressLine1,\n addressLine2: typeof record.address_line2 === 'string'\n ? record.address_line2\n : typeof record.addressLine2 === 'string'\n ? record.addressLine2\n : null,\n buildingNumber: typeof record.building_number === 'string'\n ? record.building_number\n : typeof record.buildingNumber === 'string'\n ? record.buildingNumber\n : null,\n flatNumber: typeof record.flat_number === 'string'\n ? record.flat_number\n : typeof record.flatNumber === 'string'\n ? record.flatNumber\n : null,\n city: typeof record.city === 'string' ? record.city : null,\n region: typeof record.region === 'string' ? record.region : null,\n postalCode: typeof record.postal_code === 'string'\n ? record.postal_code\n : typeof record.postalCode === 'string'\n ? record.postalCode\n : null,\n country: typeof record.country === 'string' ? record.country : null,\n isPrimary:\n typeof record.is_primary === 'boolean'\n ? record.is_primary\n : typeof record.isPrimary === 'boolean'\n ? record.isPrimary\n : false,\n }\n })\n .filter((value): value is NonNullable<typeof value> => value !== null)\n },\n create: async ({ entityId: targetId, payload }) => {\n const response = await apiCallOrThrow<Record<string, unknown>>(\n '/api/customers/addresses',\n {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({\n entityId: targetId,\n ...payload,\n country: payload.country ? payload.country.toUpperCase() : undefined,\n }),\n },\n { errorMessage: t('customers.people.detail.addresses.error') },\n )\n return response.result ?? {}\n },\n update: async ({ id, payload }) => {\n await apiCallOrThrow(\n '/api/customers/addresses',\n {\n method: 'PUT',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({\n id,\n ...payload,\n country: payload.country ? payload.country.toUpperCase() : undefined,\n }),\n },\n { errorMessage: t('customers.people.detail.addresses.error') },\n )\n },\n delete: async ({ id }) => {\n await apiCallOrThrow(\n '/api/customers/addresses',\n {\n method: 'DELETE',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ id }),\n },\n { errorMessage: t('customers.people.detail.addresses.error') },\n )\n },\n }), [t])\n\n const addressTypesAdapter = React.useMemo<AddressTypesAdapter>(() => ({\n list: async () => {\n const call = await apiCall<Record<string, unknown>>('/api/customers/dictionaries/address-types', {\n method: 'GET',\n })\n const payload = call.result ?? {}\n const rawItems = (payload as { items?: unknown[] }).items\n const items = Array.isArray(rawItems) ? rawItems : []\n return items\n .map((item) => {\n if (!item || typeof item !== 'object') return null\n const record = item as Record<string, unknown>\n const value = typeof record.value === 'string' ? record.value : null\n if (!value) return null\n const label = typeof record.label === 'string' && record.label.trim().length ? record.label : value\n return { value, label }\n })\n .filter((entry): entry is { value: string; label: string } => !!entry)\n },\n create: async (value: string) => {\n const response = await apiCallOrThrow<Record<string, unknown>>(\n '/api/customers/dictionaries/address-types',\n {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ value }),\n },\n { errorMessage: t('customers.people.detail.addresses.types.saveError', 'Failed to save address type') },\n )\n const payload = response.result ?? {}\n const createdValue = typeof payload.value === 'string' ? payload.value : value\n const label = typeof payload.label === 'string' && payload.label.trim().length ? payload.label : createdValue\n return { value: createdValue, label }\n },\n manageHref: '/backend/config/customers',\n }), [t])\n\n const loadFormat = React.useCallback(async (): Promise<AddressFormatStrategy> => {\n const call = await apiCall<{ addressFormat?: string; error?: string }>(\n '/api/customers/settings/address-format',\n )\n const payload = (call.result ?? {}) as Record<string, unknown>\n if (!call.ok) {\n const message =\n typeof (payload as Record<string, unknown>)?.error === 'string'\n ? (payload as Record<string, unknown>).error as string\n : t('customers.people.detail.addresses.formatLoadError', 'Failed to load address configuration')\n throw new Error(message)\n }\n const valueRaw = payload?.addressFormat\n const value = typeof valueRaw === 'string' ? valueRaw : null\n if (value === 'street_first' || value === 'line_first') {\n return value\n }\n return 'line_first'\n }, [t])\n\n return (\n <SharedAddressesSection\n entityId={entityId}\n emptyLabel={emptyLabel}\n addActionLabel={addActionLabel}\n emptyState={emptyState}\n onActionChange={onActionChange}\n onLoadingChange={onLoadingChange}\n translator={t}\n dataAdapter={dataAdapter}\n addressTypesAdapter={addressTypesAdapter}\n loadFormat={loadFormat}\n />\n )\n}\n\nexport default AddressesSection\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { apiCall, apiCallOrThrow, readApiResultOrThrow } from '@open-mercato/ui/backend/utils/apiCall'\nimport { AddressesSection as SharedAddressesSection } from '@open-mercato/ui/backend/detail'\nimport type { AddressDataAdapter, AddressTypesAdapter, AddressFormatStrategy, SectionAction } from '@open-mercato/ui/backend/detail'\nimport { createTranslatorWithFallback } from '@open-mercato/shared/lib/i18n/translate'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\n\nexport type AddressesSectionProps = {\n entityId: string | null\n emptyLabel: string\n addActionLabel: string\n emptyState: { title: string; actionLabel: string; description?: string }\n onActionChange?: (action: SectionAction | null) => void\n translator?: (key: string, fallback?: string, params?: Record<string, string | number>) => string\n onLoadingChange?: (isLoading: boolean) => void\n}\n\ntype ApiAddressPayload = Record<string, unknown>\n\nexport function AddressesSection({\n entityId,\n emptyLabel,\n addActionLabel,\n emptyState,\n onActionChange,\n translator,\n onLoadingChange,\n}: AddressesSectionProps) {\n const tHook = useT()\n const fallbackTranslator = React.useMemo(() => createTranslatorWithFallback(tHook), [tHook])\n const t = translator ?? fallbackTranslator\n\n const dataAdapter = React.useMemo<AddressDataAdapter>(() => ({\n list: async ({ entityId: listEntityId }) => {\n if (!listEntityId) return []\n const params = new URLSearchParams({ entityId: listEntityId, pageSize: '100' })\n const payload = await readApiResultOrThrow<ApiAddressPayload>(\n `/api/customers/addresses?${params.toString()}`,\n undefined,\n { errorMessage: t('customers.people.detail.addresses.error') },\n )\n const items = Array.isArray(payload?.items) ? payload.items : []\n return items\n .map((item) => {\n if (!item || typeof item !== 'object') return null\n const record = item as Record<string, unknown>\n const rawId = record.id ?? record.address_id ?? null\n const id =\n typeof rawId === 'string'\n ? rawId\n : typeof rawId === 'number' || typeof rawId === 'bigint'\n ? String(rawId)\n : null\n if (!id) return null\n const addressLine1 = typeof record.address_line1 === 'string'\n ? record.address_line1\n : typeof record.addressLine1 === 'string'\n ? record.addressLine1\n : null\n if (!addressLine1) return null\n return {\n id,\n name: typeof record.name === 'string' ? record.name : null,\n purpose: typeof record.purpose === 'string' ? record.purpose : null,\n companyName: typeof record.company_name === 'string'\n ? record.company_name\n : typeof record.companyName === 'string'\n ? record.companyName\n : null,\n addressLine1,\n addressLine2: typeof record.address_line2 === 'string'\n ? record.address_line2\n : typeof record.addressLine2 === 'string'\n ? record.addressLine2\n : null,\n buildingNumber: typeof record.building_number === 'string'\n ? record.building_number\n : typeof record.buildingNumber === 'string'\n ? record.buildingNumber\n : null,\n flatNumber: typeof record.flat_number === 'string'\n ? record.flat_number\n : typeof record.flatNumber === 'string'\n ? record.flatNumber\n : null,\n city: typeof record.city === 'string' ? record.city : null,\n region: typeof record.region === 'string' ? record.region : null,\n postalCode: typeof record.postal_code === 'string'\n ? record.postal_code\n : typeof record.postalCode === 'string'\n ? record.postalCode\n : null,\n country: typeof record.country === 'string' ? record.country : null,\n isPrimary:\n typeof record.is_primary === 'boolean'\n ? record.is_primary\n : typeof record.isPrimary === 'boolean'\n ? record.isPrimary\n : false,\n }\n })\n .filter((value): value is NonNullable<typeof value> => value !== null)\n },\n create: async ({ entityId: targetId, payload }) => {\n const response = await apiCallOrThrow<Record<string, unknown>>(\n '/api/customers/addresses',\n {\n // optimistic-lock-exempt: address link add/remove sub-resource\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({\n entityId: targetId,\n ...payload,\n country: payload.country ? payload.country.toUpperCase() : undefined,\n }),\n },\n { errorMessage: t('customers.people.detail.addresses.error') },\n )\n return response.result ?? {}\n },\n update: async ({ id, payload }) => {\n await apiCallOrThrow(\n '/api/customers/addresses',\n {\n // optimistic-lock-exempt: address link add/remove sub-resource\n method: 'PUT',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({\n id,\n ...payload,\n country: payload.country ? payload.country.toUpperCase() : undefined,\n }),\n },\n { errorMessage: t('customers.people.detail.addresses.error') },\n )\n },\n delete: async ({ id }) => {\n await apiCallOrThrow(\n '/api/customers/addresses',\n {\n // optimistic-lock-exempt: address link add/remove sub-resource\n method: 'DELETE',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ id }),\n },\n { errorMessage: t('customers.people.detail.addresses.error') },\n )\n },\n }), [t])\n\n const addressTypesAdapter = React.useMemo<AddressTypesAdapter>(() => ({\n list: async () => {\n const call = await apiCall<Record<string, unknown>>('/api/customers/dictionaries/address-types', {\n method: 'GET',\n })\n const payload = call.result ?? {}\n const rawItems = (payload as { items?: unknown[] }).items\n const items = Array.isArray(rawItems) ? rawItems : []\n return items\n .map((item) => {\n if (!item || typeof item !== 'object') return null\n const record = item as Record<string, unknown>\n const value = typeof record.value === 'string' ? record.value : null\n if (!value) return null\n const label = typeof record.label === 'string' && record.label.trim().length ? record.label : value\n return { value, label }\n })\n .filter((entry): entry is { value: string; label: string } => !!entry)\n },\n create: async (value: string) => {\n const response = await apiCallOrThrow<Record<string, unknown>>(\n '/api/customers/dictionaries/address-types',\n {\n // optimistic-lock-exempt: address-type dictionary create-only\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ value }),\n },\n { errorMessage: t('customers.people.detail.addresses.types.saveError', 'Failed to save address type') },\n )\n const payload = response.result ?? {}\n const createdValue = typeof payload.value === 'string' ? payload.value : value\n const label = typeof payload.label === 'string' && payload.label.trim().length ? payload.label : createdValue\n return { value: createdValue, label }\n },\n manageHref: '/backend/config/customers',\n }), [t])\n\n const loadFormat = React.useCallback(async (): Promise<AddressFormatStrategy> => {\n const call = await apiCall<{ addressFormat?: string; error?: string }>(\n '/api/customers/settings/address-format',\n )\n const payload = (call.result ?? {}) as Record<string, unknown>\n if (!call.ok) {\n const message =\n typeof (payload as Record<string, unknown>)?.error === 'string'\n ? (payload as Record<string, unknown>).error as string\n : t('customers.people.detail.addresses.formatLoadError', 'Failed to load address configuration')\n throw new Error(message)\n }\n const valueRaw = payload?.addressFormat\n const value = typeof valueRaw === 'string' ? valueRaw : null\n if (value === 'street_first' || value === 'line_first') {\n return value\n }\n return 'line_first'\n }, [t])\n\n return (\n <SharedAddressesSection\n entityId={entityId}\n emptyLabel={emptyLabel}\n addActionLabel={addActionLabel}\n emptyState={emptyState}\n onActionChange={onActionChange}\n onLoadingChange={onLoadingChange}\n translator={t}\n dataAdapter={dataAdapter}\n addressTypesAdapter={addressTypesAdapter}\n loadFormat={loadFormat}\n />\n )\n}\n\nexport default AddressesSection\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }