@open-mercato/core 0.4.2-canary-3b5064ce72 → 0.4.2-canary-15e78de280

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 (512) hide show
  1. package/dist/generated/entities/api_key/index.js +2 -0
  2. package/dist/generated/entities/api_key/index.js.map +2 -2
  3. package/dist/generated/entities.ids.generated.js +1 -5
  4. package/dist/generated/entities.ids.generated.js.map +2 -2
  5. package/dist/generated/entity-fields-registry.js +0 -2
  6. package/dist/generated/entity-fields-registry.js.map +2 -2
  7. package/dist/modules/api_docs/frontend/docs/api/page.js +2 -3
  8. package/dist/modules/api_docs/frontend/docs/api/page.js.map +2 -2
  9. package/dist/modules/api_keys/backend/api-keys/page.js +1 -1
  10. package/dist/modules/api_keys/backend/api-keys/page.js.map +2 -2
  11. package/dist/modules/api_keys/data/entities.js +3 -0
  12. package/dist/modules/api_keys/data/entities.js.map +2 -2
  13. package/dist/modules/api_keys/migrations/Migration20260125204102.js +13 -0
  14. package/dist/modules/api_keys/migrations/Migration20260125204102.js.map +7 -0
  15. package/dist/modules/api_keys/services/apiKeyService.js +41 -0
  16. package/dist/modules/api_keys/services/apiKeyService.js.map +3 -3
  17. package/dist/modules/attachments/components/AttachmentLibrary.js +0 -4
  18. package/dist/modules/attachments/components/AttachmentLibrary.js.map +2 -2
  19. package/dist/modules/attachments/components/AttachmentPartitionSettings.js +0 -2
  20. package/dist/modules/attachments/components/AttachmentPartitionSettings.js.map +2 -2
  21. package/dist/modules/auth/api/admin/nav.js +3 -4
  22. package/dist/modules/auth/api/admin/nav.js.map +2 -2
  23. package/dist/modules/auth/api/login.js +6 -25
  24. package/dist/modules/auth/api/login.js.map +2 -2
  25. package/dist/modules/auth/api/reset/confirm.js +2 -25
  26. package/dist/modules/auth/api/reset/confirm.js.map +2 -2
  27. package/dist/modules/auth/api/reset.js +0 -23
  28. package/dist/modules/auth/api/reset.js.map +2 -2
  29. package/dist/modules/auth/api/sidebar/preferences/route.js +9 -14
  30. package/dist/modules/auth/api/sidebar/preferences/route.js.map +2 -2
  31. package/dist/modules/auth/api/users/route.js +2 -4
  32. package/dist/modules/auth/api/users/route.js.map +2 -2
  33. package/dist/modules/auth/backend/roles/[id]/edit/page.js +1 -4
  34. package/dist/modules/auth/backend/roles/[id]/edit/page.js.map +2 -2
  35. package/dist/modules/auth/backend/roles/page.js +3 -3
  36. package/dist/modules/auth/backend/roles/page.js.map +2 -2
  37. package/dist/modules/auth/backend/users/[id]/edit/page.js +3 -18
  38. package/dist/modules/auth/backend/users/[id]/edit/page.js.map +2 -2
  39. package/dist/modules/auth/backend/users/create/page.js +2 -15
  40. package/dist/modules/auth/backend/users/create/page.js.map +2 -2
  41. package/dist/modules/auth/backend/users/page.js +3 -3
  42. package/dist/modules/auth/backend/users/page.js.map +2 -2
  43. package/dist/modules/auth/cli.js +11 -25
  44. package/dist/modules/auth/cli.js.map +2 -2
  45. package/dist/modules/auth/commands/users.js +2 -59
  46. package/dist/modules/auth/commands/users.js.map +2 -2
  47. package/dist/modules/auth/data/validators.js +3 -6
  48. package/dist/modules/auth/data/validators.js.map +2 -2
  49. package/dist/modules/auth/frontend/login.js +3 -112
  50. package/dist/modules/auth/frontend/login.js.map +2 -2
  51. package/dist/modules/auth/frontend/reset/[token]/page.js +10 -20
  52. package/dist/modules/auth/frontend/reset/[token]/page.js.map +2 -2
  53. package/dist/modules/auth/lib/setup-app.js +8 -42
  54. package/dist/modules/auth/lib/setup-app.js.map +2 -2
  55. package/dist/modules/auth/services/authService.js +3 -24
  56. package/dist/modules/auth/services/authService.js.map +2 -2
  57. package/dist/modules/auth/services/rbacService.js.map +2 -2
  58. package/dist/modules/business_rules/api/execute/route.js +1 -7
  59. package/dist/modules/business_rules/api/execute/route.js.map +2 -2
  60. package/dist/modules/business_rules/backend/rules/page.js +0 -4
  61. package/dist/modules/business_rules/backend/rules/page.js.map +2 -2
  62. package/dist/modules/business_rules/backend/sets/page.js +0 -3
  63. package/dist/modules/business_rules/backend/sets/page.js.map +2 -2
  64. package/dist/modules/business_rules/cli.js +1 -2
  65. package/dist/modules/business_rules/cli.js.map +2 -2
  66. package/dist/modules/business_rules/lib/rule-engine.js +3 -33
  67. package/dist/modules/business_rules/lib/rule-engine.js.map +2 -2
  68. package/dist/modules/catalog/components/PriceKindSettings.js +0 -2
  69. package/dist/modules/catalog/components/PriceKindSettings.js.map +2 -2
  70. package/dist/modules/catalog/components/categories/CategoriesDataTable.js +2 -2
  71. package/dist/modules/catalog/components/categories/CategoriesDataTable.js.map +2 -2
  72. package/dist/modules/catalog/components/products/ProductsDataTable.js +0 -2
  73. package/dist/modules/catalog/components/products/ProductsDataTable.js.map +2 -2
  74. package/dist/modules/configs/cli.js +0 -6
  75. package/dist/modules/configs/cli.js.map +2 -2
  76. package/dist/modules/configs/components/CachePanel.js +4 -4
  77. package/dist/modules/configs/components/CachePanel.js.map +2 -2
  78. package/dist/modules/configs/lib/system-status.js +1 -48
  79. package/dist/modules/configs/lib/system-status.js.map +2 -2
  80. package/dist/modules/configs/lib/upgrade-actions.js +0 -18
  81. package/dist/modules/configs/lib/upgrade-actions.js.map +2 -2
  82. package/dist/modules/currencies/backend/currencies/page.js +0 -3
  83. package/dist/modules/currencies/backend/currencies/page.js.map +2 -2
  84. package/dist/modules/currencies/backend/exchange-rates/page.js +0 -2
  85. package/dist/modules/currencies/backend/exchange-rates/page.js.map +2 -2
  86. package/dist/modules/customers/backend/customers/companies/page.js +0 -3
  87. package/dist/modules/customers/backend/customers/companies/page.js.map +2 -2
  88. package/dist/modules/customers/backend/customers/deals/page.js +0 -3
  89. package/dist/modules/customers/backend/customers/deals/page.js.map +2 -2
  90. package/dist/modules/customers/backend/customers/people/page.js +0 -3
  91. package/dist/modules/customers/backend/customers/people/page.js.map +2 -2
  92. package/dist/modules/customers/commands/deals.js +0 -31
  93. package/dist/modules/customers/commands/deals.js.map +2 -2
  94. package/dist/modules/customers/components/CustomerTodosTable.js +0 -1
  95. package/dist/modules/customers/components/CustomerTodosTable.js.map +2 -2
  96. package/dist/modules/customers/widgets/dashboard/customer-todos/widget.js +1 -2
  97. package/dist/modules/customers/widgets/dashboard/customer-todos/widget.js.map +2 -2
  98. package/dist/modules/customers/widgets/dashboard/new-customers/widget.js +1 -2
  99. package/dist/modules/customers/widgets/dashboard/new-customers/widget.js.map +2 -2
  100. package/dist/modules/customers/widgets/dashboard/new-deals/widget.js +1 -2
  101. package/dist/modules/customers/widgets/dashboard/new-deals/widget.js.map +2 -2
  102. package/dist/modules/customers/widgets/dashboard/next-interactions/widget.js +1 -2
  103. package/dist/modules/customers/widgets/dashboard/next-interactions/widget.js.map +2 -2
  104. package/dist/modules/dashboards/cli.js +5 -44
  105. package/dist/modules/dashboards/cli.js.map +2 -2
  106. package/dist/modules/dashboards/components/WidgetVisibilityEditor.js +11 -16
  107. package/dist/modules/dashboards/components/WidgetVisibilityEditor.js.map +3 -3
  108. package/dist/modules/dashboards/services/widgetDataService.js +3 -139
  109. package/dist/modules/dashboards/services/widgetDataService.js.map +2 -2
  110. package/dist/modules/dashboards/widgets/dashboard/aov-kpi/widget.js +1 -2
  111. package/dist/modules/dashboards/widgets/dashboard/aov-kpi/widget.js.map +2 -2
  112. package/dist/modules/dashboards/widgets/dashboard/new-customers-kpi/widget.js +1 -2
  113. package/dist/modules/dashboards/widgets/dashboard/new-customers-kpi/widget.js.map +2 -2
  114. package/dist/modules/dashboards/widgets/dashboard/orders-by-status/widget.js +1 -2
  115. package/dist/modules/dashboards/widgets/dashboard/orders-by-status/widget.js.map +2 -2
  116. package/dist/modules/dashboards/widgets/dashboard/orders-kpi/widget.js +1 -2
  117. package/dist/modules/dashboards/widgets/dashboard/orders-kpi/widget.js.map +2 -2
  118. package/dist/modules/dashboards/widgets/dashboard/pipeline-summary/widget.js +1 -2
  119. package/dist/modules/dashboards/widgets/dashboard/pipeline-summary/widget.js.map +2 -2
  120. package/dist/modules/dashboards/widgets/dashboard/revenue-kpi/widget.js +1 -2
  121. package/dist/modules/dashboards/widgets/dashboard/revenue-kpi/widget.js.map +2 -2
  122. package/dist/modules/dashboards/widgets/dashboard/revenue-trend/widget.js +1 -2
  123. package/dist/modules/dashboards/widgets/dashboard/revenue-trend/widget.js.map +2 -2
  124. package/dist/modules/dashboards/widgets/dashboard/sales-by-region/widget.js +1 -2
  125. package/dist/modules/dashboards/widgets/dashboard/sales-by-region/widget.js.map +2 -2
  126. package/dist/modules/dashboards/widgets/dashboard/top-customers/widget.js +1 -2
  127. package/dist/modules/dashboards/widgets/dashboard/top-customers/widget.js.map +2 -2
  128. package/dist/modules/dashboards/widgets/dashboard/top-products/widget.js +1 -2
  129. package/dist/modules/dashboards/widgets/dashboard/top-products/widget.js.map +2 -2
  130. package/dist/modules/dictionaries/components/DictionaryTable.js +0 -2
  131. package/dist/modules/dictionaries/components/DictionaryTable.js.map +2 -2
  132. package/dist/modules/directory/backend/directory/organizations/page.js +2 -2
  133. package/dist/modules/directory/backend/directory/organizations/page.js.map +2 -2
  134. package/dist/modules/directory/backend/directory/tenants/page.js +2 -2
  135. package/dist/modules/directory/backend/directory/tenants/page.js.map +2 -2
  136. package/dist/modules/entities/backend/entities/user/[entityId]/records/page.js +2 -2
  137. package/dist/modules/entities/backend/entities/user/[entityId]/records/page.js.map +2 -2
  138. package/dist/modules/entities/components/SystemEntitiesTable.js +1 -1
  139. package/dist/modules/entities/components/SystemEntitiesTable.js.map +2 -2
  140. package/dist/modules/entities/components/UserEntitiesTable.js +2 -2
  141. package/dist/modules/entities/components/UserEntitiesTable.js.map +2 -2
  142. package/dist/modules/feature_toggles/components/FeatureTogglesTable.js +3 -3
  143. package/dist/modules/feature_toggles/components/FeatureTogglesTable.js.map +2 -2
  144. package/dist/modules/feature_toggles/components/OverridesTable.js +1 -1
  145. package/dist/modules/feature_toggles/components/OverridesTable.js.map +2 -2
  146. package/dist/modules/planner/backend/planner/availability-rulesets/page.js +2 -2
  147. package/dist/modules/planner/backend/planner/availability-rulesets/page.js.map +2 -2
  148. package/dist/modules/query_index/cli.js +7 -63
  149. package/dist/modules/query_index/cli.js.map +2 -2
  150. package/dist/modules/query_index/components/QueryIndexesTable.js +1 -7
  151. package/dist/modules/query_index/components/QueryIndexesTable.js.map +2 -2
  152. package/dist/modules/resources/backend/resources/resource-types/page.js +2 -2
  153. package/dist/modules/resources/backend/resources/resource-types/page.js.map +2 -2
  154. package/dist/modules/resources/backend/resources/resources/page.js +2 -2
  155. package/dist/modules/resources/backend/resources/resources/page.js.map +2 -2
  156. package/dist/modules/sales/backend/sales/channels/offers/page.js +0 -2
  157. package/dist/modules/sales/backend/sales/channels/offers/page.js.map +2 -2
  158. package/dist/modules/sales/backend/sales/channels/page.js +0 -2
  159. package/dist/modules/sales/backend/sales/channels/page.js.map +2 -2
  160. package/dist/modules/sales/commands/documents.js +0 -53
  161. package/dist/modules/sales/commands/documents.js.map +2 -2
  162. package/dist/modules/sales/commands/payments.js +0 -26
  163. package/dist/modules/sales/commands/payments.js.map +2 -2
  164. package/dist/modules/sales/components/AdjustmentKindSettings.js +2 -2
  165. package/dist/modules/sales/components/AdjustmentKindSettings.js.map +2 -2
  166. package/dist/modules/sales/components/PaymentMethodsSettings.js +2 -2
  167. package/dist/modules/sales/components/PaymentMethodsSettings.js.map +2 -2
  168. package/dist/modules/sales/components/ShippingMethodsSettings.js +2 -2
  169. package/dist/modules/sales/components/ShippingMethodsSettings.js.map +2 -2
  170. package/dist/modules/sales/components/TaxRatesSettings.js +2 -2
  171. package/dist/modules/sales/components/TaxRatesSettings.js.map +2 -2
  172. package/dist/modules/sales/components/channels/SalesChannelOffersPanel.js +0 -2
  173. package/dist/modules/sales/components/channels/SalesChannelOffersPanel.js.map +2 -2
  174. package/dist/modules/sales/components/documents/AdjustmentsSection.js +0 -2
  175. package/dist/modules/sales/components/documents/AdjustmentsSection.js.map +2 -2
  176. package/dist/modules/sales/components/documents/PaymentsSection.js +1 -2
  177. package/dist/modules/sales/components/documents/PaymentsSection.js.map +2 -2
  178. package/dist/modules/sales/components/documents/SalesDocumentsTable.js +0 -2
  179. package/dist/modules/sales/components/documents/SalesDocumentsTable.js.map +2 -2
  180. package/dist/modules/staff/backend/staff/team-members/page.js +1 -1
  181. package/dist/modules/staff/backend/staff/team-members/page.js.map +2 -2
  182. package/dist/modules/staff/backend/staff/team-roles/page.js +2 -2
  183. package/dist/modules/staff/backend/staff/team-roles/page.js.map +2 -2
  184. package/dist/modules/staff/backend/staff/teams/[id]/edit/page.js +2 -2
  185. package/dist/modules/staff/backend/staff/teams/[id]/edit/page.js.map +2 -2
  186. package/dist/modules/staff/backend/staff/teams/page.js +2 -2
  187. package/dist/modules/staff/backend/staff/teams/page.js.map +2 -2
  188. package/dist/modules/staff/commands/leave-requests.js +0 -79
  189. package/dist/modules/staff/commands/leave-requests.js.map +2 -2
  190. package/dist/modules/workflows/backend/definitions/page.js +0 -5
  191. package/dist/modules/workflows/backend/definitions/page.js.map +2 -2
  192. package/dist/modules/workflows/backend/instances/page.js +0 -3
  193. package/dist/modules/workflows/backend/instances/page.js.map +2 -2
  194. package/dist/modules/workflows/backend/tasks/page.js +0 -3
  195. package/dist/modules/workflows/backend/tasks/page.js.map +2 -2
  196. package/dist/modules/workflows/cli.js +12 -12
  197. package/dist/modules/workflows/cli.js.map +2 -2
  198. package/dist/modules/workflows/lib/transition-handler.js +6 -14
  199. package/dist/modules/workflows/lib/transition-handler.js.map +2 -2
  200. package/generated/entities/api_key/index.ts +1 -0
  201. package/generated/entities.ids.generated.ts +1 -5
  202. package/generated/entity-fields-registry.ts +0 -2
  203. package/package.json +2 -2
  204. package/src/modules/api_docs/frontend/docs/api/page.tsx +2 -3
  205. package/src/modules/api_keys/backend/api-keys/page.tsx +1 -1
  206. package/src/modules/api_keys/data/entities.ts +4 -0
  207. package/src/modules/api_keys/migrations/.snapshot-open-mercato.json +9 -0
  208. package/src/modules/api_keys/migrations/Migration20260125204102.ts +13 -0
  209. package/src/modules/api_keys/services/apiKeyService.ts +85 -0
  210. package/src/modules/attachments/components/AttachmentLibrary.tsx +0 -4
  211. package/src/modules/attachments/components/AttachmentPartitionSettings.tsx +0 -2
  212. package/src/modules/auth/README.md +1 -1
  213. package/src/modules/auth/__tests__/cli-setup-acl.test.ts +1 -1
  214. package/src/modules/auth/api/__tests__/login.test.ts +0 -2
  215. package/src/modules/auth/api/admin/nav.ts +6 -10
  216. package/src/modules/auth/api/login.ts +7 -26
  217. package/src/modules/auth/api/reset/confirm.ts +2 -25
  218. package/src/modules/auth/api/reset.ts +0 -23
  219. package/src/modules/auth/api/sidebar/preferences/route.ts +12 -21
  220. package/src/modules/auth/api/users/route.ts +2 -5
  221. package/src/modules/auth/backend/roles/[id]/edit/page.tsx +1 -4
  222. package/src/modules/auth/backend/roles/page.tsx +3 -3
  223. package/src/modules/auth/backend/users/[id]/edit/page.tsx +3 -22
  224. package/src/modules/auth/backend/users/create/page.tsx +2 -19
  225. package/src/modules/auth/backend/users/page.tsx +3 -3
  226. package/src/modules/auth/cli.ts +11 -38
  227. package/src/modules/auth/commands/users.ts +2 -73
  228. package/src/modules/auth/data/validators.ts +2 -6
  229. package/src/modules/auth/frontend/login.tsx +5 -134
  230. package/src/modules/auth/frontend/reset/[token]/page.tsx +11 -24
  231. package/src/modules/auth/i18n/de.json +1 -48
  232. package/src/modules/auth/i18n/en.json +1 -48
  233. package/src/modules/auth/i18n/es.json +1 -48
  234. package/src/modules/auth/i18n/pl.json +1 -48
  235. package/src/modules/auth/lib/setup-app.ts +9 -58
  236. package/src/modules/auth/services/authService.ts +4 -27
  237. package/src/modules/auth/services/rbacService.ts +1 -1
  238. package/src/modules/business_rules/api/execute/route.ts +1 -8
  239. package/src/modules/business_rules/backend/rules/page.tsx +0 -4
  240. package/src/modules/business_rules/backend/sets/page.tsx +0 -3
  241. package/src/modules/business_rules/cli.ts +1 -2
  242. package/src/modules/business_rules/i18n/en.json +1 -3
  243. package/src/modules/business_rules/lib/__tests__/rule-engine.test.ts +0 -51
  244. package/src/modules/business_rules/lib/rule-engine.ts +3 -57
  245. package/src/modules/catalog/components/PriceKindSettings.tsx +0 -2
  246. package/src/modules/catalog/components/categories/CategoriesDataTable.tsx +2 -2
  247. package/src/modules/catalog/components/products/ProductsDataTable.tsx +0 -2
  248. package/src/modules/catalog/i18n/en.json +1 -3
  249. package/src/modules/configs/cli.ts +0 -6
  250. package/src/modules/configs/components/CachePanel.tsx +4 -4
  251. package/src/modules/configs/i18n/en.json +2 -12
  252. package/src/modules/configs/i18n/pl.json +2 -12
  253. package/src/modules/configs/lib/system-status.ts +1 -48
  254. package/src/modules/configs/lib/system-status.types.ts +0 -1
  255. package/src/modules/configs/lib/upgrade-actions.ts +0 -18
  256. package/src/modules/currencies/backend/currencies/page.tsx +0 -3
  257. package/src/modules/currencies/backend/exchange-rates/page.tsx +0 -2
  258. package/src/modules/customers/backend/customers/companies/page.tsx +0 -3
  259. package/src/modules/customers/backend/customers/deals/page.tsx +0 -3
  260. package/src/modules/customers/backend/customers/people/page.tsx +0 -3
  261. package/src/modules/customers/commands/deals.ts +0 -39
  262. package/src/modules/customers/components/CustomerTodosTable.tsx +0 -1
  263. package/src/modules/customers/i18n/en.json +1 -5
  264. package/src/modules/customers/widgets/dashboard/customer-todos/widget.ts +2 -2
  265. package/src/modules/customers/widgets/dashboard/new-customers/widget.ts +2 -2
  266. package/src/modules/customers/widgets/dashboard/new-deals/widget.ts +2 -2
  267. package/src/modules/customers/widgets/dashboard/next-interactions/widget.ts +2 -2
  268. package/src/modules/dashboards/cli.ts +5 -55
  269. package/src/modules/dashboards/components/WidgetVisibilityEditor.tsx +11 -22
  270. package/src/modules/dashboards/services/widgetDataService.ts +4 -164
  271. package/src/modules/dashboards/widgets/dashboard/aov-kpi/widget.ts +2 -2
  272. package/src/modules/dashboards/widgets/dashboard/new-customers-kpi/widget.ts +2 -2
  273. package/src/modules/dashboards/widgets/dashboard/orders-by-status/widget.ts +2 -2
  274. package/src/modules/dashboards/widgets/dashboard/orders-kpi/widget.ts +2 -2
  275. package/src/modules/dashboards/widgets/dashboard/pipeline-summary/widget.ts +2 -2
  276. package/src/modules/dashboards/widgets/dashboard/revenue-kpi/widget.ts +2 -2
  277. package/src/modules/dashboards/widgets/dashboard/revenue-trend/widget.ts +2 -2
  278. package/src/modules/dashboards/widgets/dashboard/sales-by-region/widget.ts +2 -2
  279. package/src/modules/dashboards/widgets/dashboard/top-customers/widget.ts +2 -2
  280. package/src/modules/dashboards/widgets/dashboard/top-products/widget.ts +2 -2
  281. package/src/modules/dictionaries/components/DictionaryTable.tsx +0 -2
  282. package/src/modules/directory/backend/directory/organizations/page.tsx +2 -2
  283. package/src/modules/directory/backend/directory/tenants/page.tsx +2 -2
  284. package/src/modules/entities/backend/entities/user/[entityId]/records/page.tsx +2 -2
  285. package/src/modules/entities/components/SystemEntitiesTable.tsx +1 -1
  286. package/src/modules/entities/components/UserEntitiesTable.tsx +2 -2
  287. package/src/modules/feature_toggles/components/FeatureTogglesTable.tsx +4 -3
  288. package/src/modules/feature_toggles/components/OverridesTable.tsx +1 -1
  289. package/src/modules/planner/backend/planner/availability-rulesets/page.tsx +2 -2
  290. package/src/modules/query_index/cli.ts +13 -82
  291. package/src/modules/query_index/components/QueryIndexesTable.tsx +2 -8
  292. package/src/modules/resources/backend/resources/resource-types/page.tsx +2 -2
  293. package/src/modules/resources/backend/resources/resources/page.tsx +2 -2
  294. package/src/modules/sales/backend/sales/channels/offers/page.tsx +0 -2
  295. package/src/modules/sales/backend/sales/channels/page.tsx +0 -2
  296. package/src/modules/sales/commands/documents.ts +0 -65
  297. package/src/modules/sales/commands/payments.ts +0 -33
  298. package/src/modules/sales/components/AdjustmentKindSettings.tsx +2 -2
  299. package/src/modules/sales/components/PaymentMethodsSettings.tsx +2 -2
  300. package/src/modules/sales/components/ShippingMethodsSettings.tsx +2 -2
  301. package/src/modules/sales/components/TaxRatesSettings.tsx +2 -2
  302. package/src/modules/sales/components/channels/SalesChannelOffersPanel.tsx +0 -2
  303. package/src/modules/sales/components/documents/AdjustmentsSection.tsx +0 -2
  304. package/src/modules/sales/components/documents/PaymentsSection.tsx +1 -2
  305. package/src/modules/sales/components/documents/SalesDocumentsTable.tsx +0 -2
  306. package/src/modules/sales/i18n/de.json +0 -20
  307. package/src/modules/sales/i18n/en.json +1 -25
  308. package/src/modules/sales/i18n/es.json +0 -20
  309. package/src/modules/sales/i18n/pl.json +0 -20
  310. package/src/modules/staff/backend/staff/team-members/page.tsx +1 -1
  311. package/src/modules/staff/backend/staff/team-roles/page.tsx +2 -2
  312. package/src/modules/staff/backend/staff/teams/[id]/edit/page.tsx +2 -2
  313. package/src/modules/staff/backend/staff/teams/page.tsx +2 -2
  314. package/src/modules/staff/commands/leave-requests.ts +0 -94
  315. package/src/modules/staff/i18n/de.json +0 -4
  316. package/src/modules/staff/i18n/en.json +1 -9
  317. package/src/modules/staff/i18n/es.json +0 -4
  318. package/src/modules/staff/i18n/pl.json +0 -4
  319. package/src/modules/workflows/backend/definitions/page.tsx +0 -5
  320. package/src/modules/workflows/backend/instances/page.tsx +1 -4
  321. package/src/modules/workflows/backend/tasks/page.tsx +1 -4
  322. package/src/modules/workflows/cli.ts +12 -12
  323. package/src/modules/workflows/i18n/en.json +1 -3
  324. package/src/modules/workflows/lib/transition-handler.ts +6 -18
  325. package/dist/generated/entities/notification/index.js +0 -57
  326. package/dist/generated/entities/notification/index.js.map +0 -7
  327. package/dist/modules/auth/api/profile/route.js +0 -157
  328. package/dist/modules/auth/api/profile/route.js.map +0 -7
  329. package/dist/modules/auth/backend/auth/profile/page.js +0 -141
  330. package/dist/modules/auth/backend/auth/profile/page.js.map +0 -7
  331. package/dist/modules/auth/backend/auth/profile/page.meta.js +0 -13
  332. package/dist/modules/auth/backend/auth/profile/page.meta.js.map +0 -7
  333. package/dist/modules/auth/notifications.js +0 -112
  334. package/dist/modules/auth/notifications.js.map +0 -7
  335. package/dist/modules/business_rules/notifications.js +0 -28
  336. package/dist/modules/business_rules/notifications.js.map +0 -7
  337. package/dist/modules/business_rules/subscribers/rule-execution-failed-notification.js +0 -37
  338. package/dist/modules/business_rules/subscribers/rule-execution-failed-notification.js.map +0 -7
  339. package/dist/modules/catalog/notifications.js +0 -28
  340. package/dist/modules/catalog/notifications.js.map +0 -7
  341. package/dist/modules/catalog/subscribers/low-stock-notification.js +0 -38
  342. package/dist/modules/catalog/subscribers/low-stock-notification.js.map +0 -7
  343. package/dist/modules/customers/notifications.js +0 -48
  344. package/dist/modules/customers/notifications.js.map +0 -7
  345. package/dist/modules/dashboards/lib/role-widgets.js +0 -58
  346. package/dist/modules/dashboards/lib/role-widgets.js.map +0 -7
  347. package/dist/modules/directory/api/get/tenants/lookup.js +0 -70
  348. package/dist/modules/directory/api/get/tenants/lookup.js.map +0 -7
  349. package/dist/modules/notifications/acl.js +0 -11
  350. package/dist/modules/notifications/acl.js.map +0 -7
  351. package/dist/modules/notifications/api/[id]/action/route.js +0 -74
  352. package/dist/modules/notifications/api/[id]/action/route.js.map +0 -7
  353. package/dist/modules/notifications/api/[id]/dismiss/route.js +0 -15
  354. package/dist/modules/notifications/api/[id]/dismiss/route.js.map +0 -7
  355. package/dist/modules/notifications/api/[id]/read/route.js +0 -15
  356. package/dist/modules/notifications/api/[id]/read/route.js.map +0 -7
  357. package/dist/modules/notifications/api/[id]/restore/route.js +0 -53
  358. package/dist/modules/notifications/api/[id]/restore/route.js.map +0 -7
  359. package/dist/modules/notifications/api/batch/route.js +0 -17
  360. package/dist/modules/notifications/api/batch/route.js.map +0 -7
  361. package/dist/modules/notifications/api/feature/route.js +0 -17
  362. package/dist/modules/notifications/api/feature/route.js.map +0 -7
  363. package/dist/modules/notifications/api/mark-all-read/route.js +0 -35
  364. package/dist/modules/notifications/api/mark-all-read/route.js.map +0 -7
  365. package/dist/modules/notifications/api/openapi.js +0 -76
  366. package/dist/modules/notifications/api/openapi.js.map +0 -7
  367. package/dist/modules/notifications/api/role/route.js +0 -17
  368. package/dist/modules/notifications/api/role/route.js.map +0 -7
  369. package/dist/modules/notifications/api/route.js +0 -85
  370. package/dist/modules/notifications/api/route.js.map +0 -7
  371. package/dist/modules/notifications/api/settings/route.js +0 -155
  372. package/dist/modules/notifications/api/settings/route.js.map +0 -7
  373. package/dist/modules/notifications/api/unread-count/route.js +0 -38
  374. package/dist/modules/notifications/api/unread-count/route.js.map +0 -7
  375. package/dist/modules/notifications/backend/config/notifications/page.js +0 -10
  376. package/dist/modules/notifications/backend/config/notifications/page.js.map +0 -7
  377. package/dist/modules/notifications/backend/config/notifications/page.meta.js +0 -24
  378. package/dist/modules/notifications/backend/config/notifications/page.meta.js.map +0 -7
  379. package/dist/modules/notifications/cli.js +0 -16
  380. package/dist/modules/notifications/cli.js.map +0 -7
  381. package/dist/modules/notifications/data/entities.js +0 -112
  382. package/dist/modules/notifications/data/entities.js.map +0 -7
  383. package/dist/modules/notifications/data/validators.js +0 -98
  384. package/dist/modules/notifications/data/validators.js.map +0 -7
  385. package/dist/modules/notifications/di.js +0 -13
  386. package/dist/modules/notifications/di.js.map +0 -7
  387. package/dist/modules/notifications/emails/NotificationEmail.js +0 -58
  388. package/dist/modules/notifications/emails/NotificationEmail.js.map +0 -7
  389. package/dist/modules/notifications/frontend/NotificationInboxPageClient.js +0 -44
  390. package/dist/modules/notifications/frontend/NotificationInboxPageClient.js.map +0 -7
  391. package/dist/modules/notifications/frontend/NotificationSettingsPageClient.js +0 -220
  392. package/dist/modules/notifications/frontend/NotificationSettingsPageClient.js.map +0 -7
  393. package/dist/modules/notifications/index.js +0 -14
  394. package/dist/modules/notifications/index.js.map +0 -7
  395. package/dist/modules/notifications/lib/deliveryConfig.js +0 -107
  396. package/dist/modules/notifications/lib/deliveryConfig.js.map +0 -7
  397. package/dist/modules/notifications/lib/deliveryStrategies.js +0 -14
  398. package/dist/modules/notifications/lib/deliveryStrategies.js.map +0 -7
  399. package/dist/modules/notifications/lib/events.js +0 -12
  400. package/dist/modules/notifications/lib/events.js.map +0 -7
  401. package/dist/modules/notifications/lib/notificationBuilder.js +0 -66
  402. package/dist/modules/notifications/lib/notificationBuilder.js.map +0 -7
  403. package/dist/modules/notifications/lib/notificationFactory.js +0 -54
  404. package/dist/modules/notifications/lib/notificationFactory.js.map +0 -7
  405. package/dist/modules/notifications/lib/notificationMapper.js +0 -34
  406. package/dist/modules/notifications/lib/notificationMapper.js.map +0 -7
  407. package/dist/modules/notifications/lib/notificationRecipients.js +0 -35
  408. package/dist/modules/notifications/lib/notificationRecipients.js.map +0 -7
  409. package/dist/modules/notifications/lib/notificationService.js +0 -279
  410. package/dist/modules/notifications/lib/notificationService.js.map +0 -7
  411. package/dist/modules/notifications/lib/routeHelpers.js +0 -101
  412. package/dist/modules/notifications/lib/routeHelpers.js.map +0 -7
  413. package/dist/modules/notifications/lib/safeHref.js +0 -24
  414. package/dist/modules/notifications/lib/safeHref.js.map +0 -7
  415. package/dist/modules/notifications/migrations/Migration20260123000001.js +0 -70
  416. package/dist/modules/notifications/migrations/Migration20260123000001.js.map +0 -7
  417. package/dist/modules/notifications/migrations/Migration20260126150000.js +0 -37
  418. package/dist/modules/notifications/migrations/Migration20260126150000.js.map +0 -7
  419. package/dist/modules/notifications/migrations/Migration20260129082610.js +0 -13
  420. package/dist/modules/notifications/migrations/Migration20260129082610.js.map +0 -7
  421. package/dist/modules/notifications/subscribers/deliver-notification.js +0 -165
  422. package/dist/modules/notifications/subscribers/deliver-notification.js.map +0 -7
  423. package/dist/modules/notifications/workers/create-notification.worker.js +0 -70
  424. package/dist/modules/notifications/workers/create-notification.worker.js.map +0 -7
  425. package/dist/modules/sales/notifications.client.js +0 -51
  426. package/dist/modules/sales/notifications.client.js.map +0 -7
  427. package/dist/modules/sales/notifications.js +0 -88
  428. package/dist/modules/sales/notifications.js.map +0 -7
  429. package/dist/modules/sales/subscribers/quote-expiring-notification.js +0 -38
  430. package/dist/modules/sales/subscribers/quote-expiring-notification.js.map +0 -7
  431. package/dist/modules/sales/widgets/notifications/SalesOrderCreatedRenderer.js +0 -137
  432. package/dist/modules/sales/widgets/notifications/SalesOrderCreatedRenderer.js.map +0 -7
  433. package/dist/modules/sales/widgets/notifications/SalesQuoteCreatedRenderer.js +0 -137
  434. package/dist/modules/sales/widgets/notifications/SalesQuoteCreatedRenderer.js.map +0 -7
  435. package/dist/modules/sales/widgets/notifications/index.js +0 -7
  436. package/dist/modules/sales/widgets/notifications/index.js.map +0 -7
  437. package/dist/modules/sales/widgets/notifications/useSalesDocumentTotals.js +0 -60
  438. package/dist/modules/sales/widgets/notifications/useSalesDocumentTotals.js.map +0 -7
  439. package/dist/modules/staff/notifications.js +0 -75
  440. package/dist/modules/staff/notifications.js.map +0 -7
  441. package/dist/modules/workflows/notifications.js +0 -28
  442. package/dist/modules/workflows/notifications.js.map +0 -7
  443. package/dist/modules/workflows/subscribers/task-assigned-notification.js +0 -38
  444. package/dist/modules/workflows/subscribers/task-assigned-notification.js.map +0 -7
  445. package/generated/entities/notification/index.ts +0 -27
  446. package/src/modules/auth/api/profile/route.ts +0 -163
  447. package/src/modules/auth/backend/auth/profile/page.meta.ts +0 -9
  448. package/src/modules/auth/backend/auth/profile/page.tsx +0 -174
  449. package/src/modules/auth/notifications.ts +0 -109
  450. package/src/modules/business_rules/notifications.ts +0 -25
  451. package/src/modules/business_rules/subscribers/rule-execution-failed-notification.ts +0 -50
  452. package/src/modules/catalog/notifications.ts +0 -25
  453. package/src/modules/catalog/subscribers/low-stock-notification.ts +0 -52
  454. package/src/modules/customers/notifications.ts +0 -44
  455. package/src/modules/dashboards/lib/role-widgets.ts +0 -80
  456. package/src/modules/directory/api/get/tenants/lookup.ts +0 -75
  457. package/src/modules/notifications/__tests__/deliver-notification.test.ts +0 -195
  458. package/src/modules/notifications/__tests__/deliveryStrategies.test.ts +0 -19
  459. package/src/modules/notifications/__tests__/notificationService.test.ts +0 -208
  460. package/src/modules/notifications/acl.ts +0 -7
  461. package/src/modules/notifications/api/[id]/action/route.ts +0 -75
  462. package/src/modules/notifications/api/[id]/dismiss/route.ts +0 -12
  463. package/src/modules/notifications/api/[id]/read/route.ts +0 -12
  464. package/src/modules/notifications/api/[id]/restore/route.ts +0 -53
  465. package/src/modules/notifications/api/batch/route.ts +0 -14
  466. package/src/modules/notifications/api/feature/route.ts +0 -14
  467. package/src/modules/notifications/api/mark-all-read/route.ts +0 -34
  468. package/src/modules/notifications/api/openapi.ts +0 -76
  469. package/src/modules/notifications/api/role/route.ts +0 -14
  470. package/src/modules/notifications/api/route.ts +0 -92
  471. package/src/modules/notifications/api/settings/route.ts +0 -157
  472. package/src/modules/notifications/api/unread-count/route.ts +0 -38
  473. package/src/modules/notifications/backend/config/notifications/page.meta.ts +0 -22
  474. package/src/modules/notifications/backend/config/notifications/page.tsx +0 -12
  475. package/src/modules/notifications/cli.ts +0 -18
  476. package/src/modules/notifications/data/entities.ts +0 -99
  477. package/src/modules/notifications/data/validators.ts +0 -115
  478. package/src/modules/notifications/di.ts +0 -11
  479. package/src/modules/notifications/emails/NotificationEmail.tsx +0 -98
  480. package/src/modules/notifications/frontend/NotificationInboxPageClient.tsx +0 -42
  481. package/src/modules/notifications/frontend/NotificationSettingsPageClient.tsx +0 -233
  482. package/src/modules/notifications/i18n/de.json +0 -50
  483. package/src/modules/notifications/i18n/en.json +0 -50
  484. package/src/modules/notifications/i18n/es.json +0 -50
  485. package/src/modules/notifications/i18n/pl.json +0 -50
  486. package/src/modules/notifications/index.ts +0 -12
  487. package/src/modules/notifications/lib/deliveryConfig.ts +0 -153
  488. package/src/modules/notifications/lib/deliveryStrategies.ts +0 -50
  489. package/src/modules/notifications/lib/events.ts +0 -48
  490. package/src/modules/notifications/lib/notificationBuilder.ts +0 -121
  491. package/src/modules/notifications/lib/notificationFactory.ts +0 -76
  492. package/src/modules/notifications/lib/notificationMapper.ts +0 -33
  493. package/src/modules/notifications/lib/notificationRecipients.ts +0 -83
  494. package/src/modules/notifications/lib/notificationService.ts +0 -414
  495. package/src/modules/notifications/lib/routeHelpers.ts +0 -151
  496. package/src/modules/notifications/lib/safeHref.ts +0 -29
  497. package/src/modules/notifications/migrations/.snapshot-open-mercato.json +0 -336
  498. package/src/modules/notifications/migrations/Migration20260123000001.ts +0 -73
  499. package/src/modules/notifications/migrations/Migration20260126150000.ts +0 -39
  500. package/src/modules/notifications/migrations/Migration20260129082610.ts +0 -13
  501. package/src/modules/notifications/subscribers/deliver-notification.ts +0 -204
  502. package/src/modules/notifications/workers/create-notification.worker.ts +0 -122
  503. package/src/modules/sales/notifications.client.ts +0 -65
  504. package/src/modules/sales/notifications.ts +0 -82
  505. package/src/modules/sales/subscribers/quote-expiring-notification.ts +0 -53
  506. package/src/modules/sales/widgets/notifications/SalesOrderCreatedRenderer.tsx +0 -156
  507. package/src/modules/sales/widgets/notifications/SalesQuoteCreatedRenderer.tsx +0 -156
  508. package/src/modules/sales/widgets/notifications/index.ts +0 -2
  509. package/src/modules/sales/widgets/notifications/useSalesDocumentTotals.ts +0 -81
  510. package/src/modules/staff/notifications.ts +0 -71
  511. package/src/modules/workflows/notifications.ts +0 -25
  512. package/src/modules/workflows/subscribers/task-assigned-notification.ts +0 -53
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/modules/business_rules/lib/rule-engine.ts"],
4
- "sourcesContent": ["import type { EntityManager } from '@mikro-orm/core'\nimport type { EventBus } from '@open-mercato/events'\nimport { BusinessRule, RuleExecutionLog, type RuleType } from '../data/entities'\nimport * as ruleEvaluator from './rule-evaluator'\nimport * as actionExecutor from './action-executor'\nimport type { RuleEvaluationContext } from './rule-evaluator'\nimport type { ActionContext, ActionExecutionOutcome } from './action-executor'\nimport { ruleEngineContextSchema, ruleDiscoveryOptionsSchema } from '../data/validators'\n\n/**\n * Constants\n */\nconst DEFAULT_ENTITY_ID = 'unknown'\nconst RULE_TYPE_GUARD = 'GUARD'\nconst EXECUTION_RESULT_ERROR = 'ERROR'\nconst EXECUTION_RESULT_SUCCESS = 'SUCCESS'\nconst EXECUTION_RESULT_FAILURE = 'FAILURE'\n\n/**\n * Execution limits\n */\nconst MAX_RULES_PER_EXECUTION = 100\nconst MAX_SINGLE_RULE_TIMEOUT_MS = 30000 // 30 seconds\nconst MAX_TOTAL_EXECUTION_TIMEOUT_MS = 60000 // 60 seconds\n\n/**\n * Rule execution context\n */\nexport interface RuleEngineContext {\n entityType: string\n entityId?: string\n eventType?: string\n data: any\n user?: {\n id?: string\n email?: string\n role?: string\n [key: string]: any\n }\n tenant?: {\n id?: string\n [key: string]: any\n }\n organization?: {\n id?: string\n [key: string]: any\n }\n tenantId: string\n organizationId: string\n executedBy?: string\n dryRun?: boolean\n [key: string]: any\n}\n\n/**\n * Single rule execution result\n */\nexport interface RuleExecutionResult {\n rule: BusinessRule\n conditionResult: boolean\n actionsExecuted: ActionExecutionOutcome | null\n executionTime: number\n error?: string\n logId?: string // Database log ID (if logged)\n}\n\n/**\n * Overall rule engine result\n */\nexport interface RuleEngineResult {\n allowed: boolean\n executedRules: RuleExecutionResult[]\n totalExecutionTime: number\n errors?: string[]\n logIds?: string[]\n}\n\n/**\n * Rule discovery options\n */\nexport interface RuleDiscoveryOptions {\n entityType: string\n eventType?: string\n tenantId: string\n organizationId: string\n ruleType?: RuleType\n}\n\nexport type RuleEngineExecutionOptions = {\n eventBus?: Pick<EventBus, 'emitEvent'> | null\n}\n\ntype RuleExecutionFailedPayload = {\n ruleId: string\n ruleName: string\n entityType?: string | null\n errorMessage?: string | null\n tenantId: string\n organizationId?: string | null\n}\n\n/**\n * Execute a function with a timeout\n */\nasync function withTimeout<T>(\n promise: Promise<T>,\n timeoutMs: number,\n errorMessage: string\n): Promise<T> {\n let timeoutId: NodeJS.Timeout\n\n const timeoutPromise = new Promise<never>((_, reject) => {\n timeoutId = setTimeout(() => {\n reject(new Error(`${errorMessage} (timeout: ${timeoutMs}ms)`))\n }, timeoutMs)\n })\n\n try {\n return await Promise.race([promise, timeoutPromise])\n } finally {\n clearTimeout(timeoutId!)\n }\n}\n\n/**\n * Execute all applicable rules for the given context\n */\nexport async function executeRules(\n em: EntityManager,\n context: RuleEngineContext,\n options: RuleEngineExecutionOptions = {}\n): Promise<RuleEngineResult> {\n // Validate input\n const validation = ruleEngineContextSchema.safeParse(context)\n if (!validation.success) {\n const validationErrors = validation.error.issues.map(e => `${e.path.join('.')}: ${e.message}`)\n return {\n allowed: false,\n executedRules: [],\n totalExecutionTime: 0,\n errors: validationErrors,\n }\n }\n\n const startTime = Date.now()\n const executedRules: RuleExecutionResult[] = []\n const errors: string[] = []\n const logIds: string[] = []\n\n try {\n // Discover applicable rules\n const rules = await findApplicableRules(em, {\n entityType: context.entityType,\n eventType: context.eventType,\n tenantId: context.tenantId,\n organizationId: context.organizationId,\n })\n\n // Check rule count limit\n if (rules.length > MAX_RULES_PER_EXECUTION) {\n errors.push(\n `Rule count limit exceeded: ${rules.length} rules found, maximum is ${MAX_RULES_PER_EXECUTION}`\n )\n return {\n allowed: false,\n executedRules: [],\n totalExecutionTime: Date.now() - startTime,\n errors,\n }\n }\n\n // Rules already sorted by database query (priority DESC, ruleId ASC)\n // Execute each rule with total timeout\n const executionPromise = (async () => {\n for (const rule of rules) {\n try {\n const ruleResult = await executeSingleRule(em, rule, context, options)\n executedRules.push(ruleResult)\n\n if (ruleResult.logId) {\n logIds.push(ruleResult.logId)\n }\n\n if (ruleResult.error) {\n errors.push(\n `Rule execution failed [ruleId=${rule.ruleId}, type=${rule.ruleType}, entityType=${context.entityType}]: ${ruleResult.error}`\n )\n }\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error)\n errors.push(\n `Unexpected error in rule execution [ruleId=${rule.ruleId}, type=${rule.ruleType}]: ${errorMessage}`\n )\n\n if (!context.dryRun) {\n await emitRuleExecutionFailed(options.eventBus, {\n ruleId: rule.ruleId,\n ruleName: rule.ruleName,\n entityType: context.entityType ?? null,\n errorMessage,\n tenantId: context.tenantId,\n organizationId: context.organizationId ?? null,\n })\n }\n\n executedRules.push({\n rule,\n conditionResult: false,\n actionsExecuted: null,\n executionTime: 0,\n error: errorMessage,\n })\n }\n }\n })()\n\n // Execute with timeout\n await withTimeout(\n executionPromise,\n MAX_TOTAL_EXECUTION_TIMEOUT_MS,\n `Total rule execution timeout [entityType=${context.entityType}]`\n )\n\n // Determine overall allowed status\n // For GUARD rules: all must pass for operation to be allowed\n const guardRules = executedRules.filter((r) => r.rule.ruleType === RULE_TYPE_GUARD)\n const allowed = guardRules.length === 0 || guardRules.every((r) => r.conditionResult)\n\n const totalExecutionTime = Date.now() - startTime\n\n return {\n allowed,\n executedRules,\n totalExecutionTime,\n errors: errors.length > 0 ? errors : undefined,\n logIds: logIds.length > 0 ? logIds : undefined,\n }\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error)\n const stack = error instanceof Error ? error.stack : undefined\n errors.push(\n `Critical rule engine error [entityType=${context.entityType}, entityId=${context.entityId || 'unknown'}]: ${errorMessage}${stack ? `\\nStack: ${stack}` : ''}`\n )\n\n const totalExecutionTime = Date.now() - startTime\n\n return {\n allowed: false,\n executedRules,\n totalExecutionTime,\n errors,\n }\n }\n}\n\n/**\n * Execute a single rule\n */\nexport async function executeSingleRule(\n em: EntityManager,\n rule: BusinessRule,\n context: RuleEngineContext,\n options: RuleEngineExecutionOptions = {}\n): Promise<RuleExecutionResult> {\n const startTime = Date.now()\n\n try {\n // Wrap execution in timeout\n const executeWithTimeout = async () => {\n // Build evaluation context\n const evalContext: RuleEvaluationContext = {\n entityType: context.entityType,\n entityId: context.entityId,\n eventType: context.eventType,\n user: context.user,\n tenant: context.tenant,\n organization: context.organization,\n }\n\n // Evaluate rule conditions\n const result = await ruleEvaluator.evaluateSingleRule(rule, context.data, evalContext)\n\n // Check if evaluation completed (not just if conditions passed)\n if (!result.evaluationCompleted) {\n const executionTime = Date.now() - startTime\n\n let logId: string | undefined\n\n // Log failure if not dry run\n if (!context.dryRun) {\n logId = await logRuleExecution(em, {\n rule,\n context,\n conditionResult: false,\n actionsExecuted: null,\n executionTime,\n error: result.error,\n })\n\n await emitRuleExecutionFailed(options.eventBus, {\n ruleId: rule.ruleId,\n ruleName: rule.ruleName,\n entityType: context.entityType ?? null,\n errorMessage: result.error ?? null,\n tenantId: context.tenantId,\n organizationId: context.organizationId ?? null,\n })\n }\n\n return {\n rule,\n conditionResult: false,\n actionsExecuted: null,\n executionTime,\n error: result.error,\n logId,\n }\n }\n\n // Evaluation completed successfully - determine which actions to execute\n const actions = result.conditionsPassed ? rule.successActions : rule.failureActions\n\n let actionsExecuted: ActionExecutionOutcome | null = null\n\n if (actions && Array.isArray(actions) && actions.length > 0) {\n // Build action context\n const actionContext: ActionContext = {\n ...evalContext,\n data: context.data,\n ruleId: rule.ruleId,\n ruleName: rule.ruleName,\n }\n\n // Execute actions\n actionsExecuted = await actionExecutor.executeActions(actions, actionContext)\n }\n\n const executionTime = Date.now() - startTime\n\n let logId: string | undefined\n\n // Log execution if not dry run\n if (!context.dryRun) {\n logId = await logRuleExecution(em, {\n rule,\n context,\n conditionResult: result.conditionsPassed,\n actionsExecuted,\n executionTime,\n })\n }\n\n return {\n rule,\n conditionResult: result.conditionsPassed,\n actionsExecuted,\n executionTime,\n logId,\n }\n }\n\n // Execute with single rule timeout\n return await withTimeout(\n executeWithTimeout(),\n MAX_SINGLE_RULE_TIMEOUT_MS,\n `Single rule execution timeout [ruleId=${rule.ruleId}]`\n )\n } catch (error) {\n const executionTime = Date.now() - startTime\n const errorMessage = error instanceof Error ? error.message : String(error)\n const enhancedError = `Failed to execute rule [ruleId=${rule.ruleId}, entityType=${context.entityType}]: ${errorMessage}`\n\n let logId: string | undefined\n\n // Log error if not dry run\n if (!context.dryRun) {\n logId = await logRuleExecution(em, {\n rule,\n context,\n conditionResult: false,\n actionsExecuted: null,\n executionTime,\n error: enhancedError,\n })\n\n await emitRuleExecutionFailed(options.eventBus, {\n ruleId: rule.ruleId,\n ruleName: rule.ruleName,\n entityType: context.entityType ?? null,\n errorMessage: enhancedError,\n tenantId: context.tenantId,\n organizationId: context.organizationId ?? null,\n })\n }\n\n return {\n rule,\n conditionResult: false,\n actionsExecuted: null,\n executionTime,\n error: enhancedError,\n logId,\n }\n }\n}\n\n/**\n * Find all applicable rules for the given criteria\n */\nexport async function findApplicableRules(\n em: EntityManager,\n options: RuleDiscoveryOptions\n): Promise<BusinessRule[]> {\n // Validate input\n ruleDiscoveryOptionsSchema.parse(options)\n\n const { entityType, eventType, tenantId, organizationId, ruleType } = options\n\n const where: Partial<BusinessRule> = {\n entityType,\n tenantId,\n organizationId,\n enabled: true,\n deletedAt: null,\n }\n\n if (eventType) {\n where.eventType = eventType\n }\n\n if (ruleType) {\n where.ruleType = ruleType\n }\n\n const rules = await em.find(BusinessRule, where, {\n orderBy: { priority: 'DESC', ruleId: 'ASC' },\n })\n\n // Filter by effective date range\n const now = new Date()\n return rules.filter((rule) => {\n if (rule.effectiveFrom && rule.effectiveFrom > now) {\n return false\n }\n if (rule.effectiveTo && rule.effectiveTo < now) {\n return false\n }\n return true\n })\n}\n\n/**\n * Sensitive field patterns to exclude from logs\n */\nconst SENSITIVE_FIELD_PATTERNS = [\n /password/i,\n /passwd/i,\n /pwd/i,\n /secret/i,\n /token/i,\n /api[_-]?key/i,\n /auth/i,\n /credit[_-]?card/i,\n /card[_-]?number/i,\n /cvv/i,\n /ssn/i,\n /social[_-]?security/i,\n /tax[_-]?id/i,\n /driver[_-]?license/i,\n /passport/i,\n]\n\n/**\n * Maximum depth for nested object sanitization\n */\nconst MAX_SANITIZATION_DEPTH = 5\n\n/**\n * Sanitize data for logging by removing sensitive fields\n */\nfunction sanitizeForLogging(data: any, depth: number = 0): any {\n // Prevent infinite recursion\n if (depth > MAX_SANITIZATION_DEPTH) {\n return '[Max depth exceeded]'\n }\n\n // Handle null/undefined\n if (data === null || data === undefined) {\n return data\n }\n\n // Handle primitives\n if (typeof data !== 'object') {\n return data\n }\n\n // Handle arrays\n if (Array.isArray(data)) {\n return data.map(item => sanitizeForLogging(item, depth + 1))\n }\n\n // Handle objects\n const sanitized: Record<string, any> = {}\n\n for (const [key, value] of Object.entries(data)) {\n // Check if field name matches sensitive patterns\n const isSensitive = SENSITIVE_FIELD_PATTERNS.some(pattern => pattern.test(key))\n\n if (isSensitive) {\n sanitized[key] = '[REDACTED]'\n } else if (typeof value === 'object' && value !== null) {\n sanitized[key] = sanitizeForLogging(value, depth + 1)\n } else {\n sanitized[key] = value\n }\n }\n\n return sanitized\n}\n\n/**\n * Sanitize user object for logging (keep only safe fields)\n */\nfunction sanitizeUser(user: any): any {\n if (!user) {\n return undefined\n }\n\n // Only log safe user fields\n return {\n id: user.id,\n role: user.role,\n // Don't log: email, name, phone, address, etc.\n }\n}\n\n/**\n * Log rule execution to database\n */\ninterface LogExecutionOptions {\n rule: BusinessRule\n context: RuleEngineContext\n conditionResult: boolean\n actionsExecuted: ActionExecutionOutcome | null\n executionTime: number\n error?: string\n}\n\nexport async function logRuleExecution(\n em: EntityManager,\n options: LogExecutionOptions\n): Promise<string> {\n const { rule, context, conditionResult, actionsExecuted, executionTime, error } = options\n\n const executionResult: 'SUCCESS' | 'FAILURE' | 'ERROR' = error\n ? EXECUTION_RESULT_ERROR\n : conditionResult\n ? EXECUTION_RESULT_SUCCESS\n : EXECUTION_RESULT_FAILURE\n\n const log = em.create(RuleExecutionLog, {\n rule,\n entityId: context.entityId || DEFAULT_ENTITY_ID,\n entityType: context.entityType,\n executionResult,\n inputContext: {\n data: sanitizeForLogging(context.data),\n eventType: context.eventType,\n user: sanitizeUser(context.user),\n },\n outputContext: actionsExecuted\n ? {\n conditionResult,\n actionsExecuted: actionsExecuted.results.map((r) => ({\n type: r.action.type,\n success: r.success,\n error: r.error,\n })),\n }\n : null,\n errorMessage: error || null,\n executionTimeMs: executionTime,\n tenantId: context.tenantId,\n organizationId: context.organizationId,\n executedBy: context.executedBy || null,\n })\n\n await em.persistAndFlush(log)\n\n return log.id\n}\n\nasync function emitRuleExecutionFailed(\n eventBus: Pick<EventBus, 'emitEvent'> | null | undefined,\n payload: RuleExecutionFailedPayload\n): Promise<void> {\n if (!eventBus?.emitEvent) return\n\n await eventBus.emitEvent('business_rules.rule.execution_failed', payload).catch(() => undefined)\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import type { EntityManager } from '@mikro-orm/core'\nimport { BusinessRule, RuleExecutionLog, type RuleType } from '../data/entities'\nimport * as ruleEvaluator from './rule-evaluator'\nimport * as actionExecutor from './action-executor'\nimport type { RuleEvaluationContext } from './rule-evaluator'\nimport type { ActionContext, ActionExecutionOutcome } from './action-executor'\nimport { ruleEngineContextSchema, ruleDiscoveryOptionsSchema } from '../data/validators'\n\n/**\n * Constants\n */\nconst DEFAULT_ENTITY_ID = 'unknown'\nconst RULE_TYPE_GUARD = 'GUARD'\nconst EXECUTION_RESULT_ERROR = 'ERROR'\nconst EXECUTION_RESULT_SUCCESS = 'SUCCESS'\nconst EXECUTION_RESULT_FAILURE = 'FAILURE'\n\n/**\n * Execution limits\n */\nconst MAX_RULES_PER_EXECUTION = 100\nconst MAX_SINGLE_RULE_TIMEOUT_MS = 30000 // 30 seconds\nconst MAX_TOTAL_EXECUTION_TIMEOUT_MS = 60000 // 60 seconds\n\n/**\n * Rule execution context\n */\nexport interface RuleEngineContext {\n entityType: string\n entityId?: string\n eventType?: string\n data: any\n user?: {\n id?: string\n email?: string\n role?: string\n [key: string]: any\n }\n tenant?: {\n id?: string\n [key: string]: any\n }\n organization?: {\n id?: string\n [key: string]: any\n }\n tenantId: string\n organizationId: string\n executedBy?: string\n dryRun?: boolean\n [key: string]: any\n}\n\n/**\n * Single rule execution result\n */\nexport interface RuleExecutionResult {\n rule: BusinessRule\n conditionResult: boolean\n actionsExecuted: ActionExecutionOutcome | null\n executionTime: number\n error?: string\n logId?: string // Database log ID (if logged)\n}\n\n/**\n * Overall rule engine result\n */\nexport interface RuleEngineResult {\n allowed: boolean\n executedRules: RuleExecutionResult[]\n totalExecutionTime: number\n errors?: string[]\n logIds?: string[]\n}\n\n/**\n * Rule discovery options\n */\nexport interface RuleDiscoveryOptions {\n entityType: string\n eventType?: string\n tenantId: string\n organizationId: string\n ruleType?: RuleType\n}\n\n/**\n * Execute a function with a timeout\n */\nasync function withTimeout<T>(\n promise: Promise<T>,\n timeoutMs: number,\n errorMessage: string\n): Promise<T> {\n let timeoutId: NodeJS.Timeout\n\n const timeoutPromise = new Promise<never>((_, reject) => {\n timeoutId = setTimeout(() => {\n reject(new Error(`${errorMessage} (timeout: ${timeoutMs}ms)`))\n }, timeoutMs)\n })\n\n try {\n return await Promise.race([promise, timeoutPromise])\n } finally {\n clearTimeout(timeoutId!)\n }\n}\n\n/**\n * Execute all applicable rules for the given context\n */\nexport async function executeRules(\n em: EntityManager,\n context: RuleEngineContext\n): Promise<RuleEngineResult> {\n // Validate input\n const validation = ruleEngineContextSchema.safeParse(context)\n if (!validation.success) {\n const validationErrors = validation.error.issues.map(e => `${e.path.join('.')}: ${e.message}`)\n return {\n allowed: false,\n executedRules: [],\n totalExecutionTime: 0,\n errors: validationErrors,\n }\n }\n\n const startTime = Date.now()\n const executedRules: RuleExecutionResult[] = []\n const errors: string[] = []\n const logIds: string[] = []\n\n try {\n // Discover applicable rules\n const rules = await findApplicableRules(em, {\n entityType: context.entityType,\n eventType: context.eventType,\n tenantId: context.tenantId,\n organizationId: context.organizationId,\n })\n\n // Check rule count limit\n if (rules.length > MAX_RULES_PER_EXECUTION) {\n errors.push(\n `Rule count limit exceeded: ${rules.length} rules found, maximum is ${MAX_RULES_PER_EXECUTION}`\n )\n return {\n allowed: false,\n executedRules: [],\n totalExecutionTime: Date.now() - startTime,\n errors,\n }\n }\n\n // Rules already sorted by database query (priority DESC, ruleId ASC)\n // Execute each rule with total timeout\n const executionPromise = (async () => {\n for (const rule of rules) {\n try {\n const ruleResult = await executeSingleRule(em, rule, context)\n executedRules.push(ruleResult)\n\n if (ruleResult.logId) {\n logIds.push(ruleResult.logId)\n }\n\n if (ruleResult.error) {\n errors.push(\n `Rule execution failed [ruleId=${rule.ruleId}, type=${rule.ruleType}, entityType=${context.entityType}]: ${ruleResult.error}`\n )\n }\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error)\n errors.push(\n `Unexpected error in rule execution [ruleId=${rule.ruleId}, type=${rule.ruleType}]: ${errorMessage}`\n )\n\n executedRules.push({\n rule,\n conditionResult: false,\n actionsExecuted: null,\n executionTime: 0,\n error: errorMessage,\n })\n }\n }\n })()\n\n // Execute with timeout\n await withTimeout(\n executionPromise,\n MAX_TOTAL_EXECUTION_TIMEOUT_MS,\n `Total rule execution timeout [entityType=${context.entityType}]`\n )\n\n // Determine overall allowed status\n // For GUARD rules: all must pass for operation to be allowed\n const guardRules = executedRules.filter((r) => r.rule.ruleType === RULE_TYPE_GUARD)\n const allowed = guardRules.length === 0 || guardRules.every((r) => r.conditionResult)\n\n const totalExecutionTime = Date.now() - startTime\n\n return {\n allowed,\n executedRules,\n totalExecutionTime,\n errors: errors.length > 0 ? errors : undefined,\n logIds: logIds.length > 0 ? logIds : undefined,\n }\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error)\n const stack = error instanceof Error ? error.stack : undefined\n errors.push(\n `Critical rule engine error [entityType=${context.entityType}, entityId=${context.entityId || 'unknown'}]: ${errorMessage}${stack ? `\\nStack: ${stack}` : ''}`\n )\n\n const totalExecutionTime = Date.now() - startTime\n\n return {\n allowed: false,\n executedRules,\n totalExecutionTime,\n errors,\n }\n }\n}\n\n/**\n * Execute a single rule\n */\nexport async function executeSingleRule(\n em: EntityManager,\n rule: BusinessRule,\n context: RuleEngineContext\n): Promise<RuleExecutionResult> {\n const startTime = Date.now()\n\n try {\n // Wrap execution in timeout\n const executeWithTimeout = async () => {\n // Build evaluation context\n const evalContext: RuleEvaluationContext = {\n entityType: context.entityType,\n entityId: context.entityId,\n eventType: context.eventType,\n user: context.user,\n tenant: context.tenant,\n organization: context.organization,\n }\n\n // Evaluate rule conditions\n const result = await ruleEvaluator.evaluateSingleRule(rule, context.data, evalContext)\n\n // Check if evaluation completed (not just if conditions passed)\n if (!result.evaluationCompleted) {\n const executionTime = Date.now() - startTime\n\n let logId: string | undefined\n\n // Log failure if not dry run\n if (!context.dryRun) {\n logId = await logRuleExecution(em, {\n rule,\n context,\n conditionResult: false,\n actionsExecuted: null,\n executionTime,\n error: result.error,\n })\n }\n\n return {\n rule,\n conditionResult: false,\n actionsExecuted: null,\n executionTime,\n error: result.error,\n logId,\n }\n }\n\n // Evaluation completed successfully - determine which actions to execute\n const actions = result.conditionsPassed ? rule.successActions : rule.failureActions\n\n let actionsExecuted: ActionExecutionOutcome | null = null\n\n if (actions && Array.isArray(actions) && actions.length > 0) {\n // Build action context\n const actionContext: ActionContext = {\n ...evalContext,\n data: context.data,\n ruleId: rule.ruleId,\n ruleName: rule.ruleName,\n }\n\n // Execute actions\n actionsExecuted = await actionExecutor.executeActions(actions, actionContext)\n }\n\n const executionTime = Date.now() - startTime\n\n let logId: string | undefined\n\n // Log execution if not dry run\n if (!context.dryRun) {\n logId = await logRuleExecution(em, {\n rule,\n context,\n conditionResult: result.conditionsPassed,\n actionsExecuted,\n executionTime,\n })\n }\n\n return {\n rule,\n conditionResult: result.conditionsPassed,\n actionsExecuted,\n executionTime,\n logId,\n }\n }\n\n // Execute with single rule timeout\n return await withTimeout(\n executeWithTimeout(),\n MAX_SINGLE_RULE_TIMEOUT_MS,\n `Single rule execution timeout [ruleId=${rule.ruleId}]`\n )\n } catch (error) {\n const executionTime = Date.now() - startTime\n const errorMessage = error instanceof Error ? error.message : String(error)\n const enhancedError = `Failed to execute rule [ruleId=${rule.ruleId}, entityType=${context.entityType}]: ${errorMessage}`\n\n let logId: string | undefined\n\n // Log error if not dry run\n if (!context.dryRun) {\n logId = await logRuleExecution(em, {\n rule,\n context,\n conditionResult: false,\n actionsExecuted: null,\n executionTime,\n error: enhancedError,\n })\n }\n\n return {\n rule,\n conditionResult: false,\n actionsExecuted: null,\n executionTime,\n error: enhancedError,\n logId,\n }\n }\n}\n\n/**\n * Find all applicable rules for the given criteria\n */\nexport async function findApplicableRules(\n em: EntityManager,\n options: RuleDiscoveryOptions\n): Promise<BusinessRule[]> {\n // Validate input\n ruleDiscoveryOptionsSchema.parse(options)\n\n const { entityType, eventType, tenantId, organizationId, ruleType } = options\n\n const where: Partial<BusinessRule> = {\n entityType,\n tenantId,\n organizationId,\n enabled: true,\n deletedAt: null,\n }\n\n if (eventType) {\n where.eventType = eventType\n }\n\n if (ruleType) {\n where.ruleType = ruleType\n }\n\n const rules = await em.find(BusinessRule, where, {\n orderBy: { priority: 'DESC', ruleId: 'ASC' },\n })\n\n // Filter by effective date range\n const now = new Date()\n return rules.filter((rule) => {\n if (rule.effectiveFrom && rule.effectiveFrom > now) {\n return false\n }\n if (rule.effectiveTo && rule.effectiveTo < now) {\n return false\n }\n return true\n })\n}\n\n/**\n * Sensitive field patterns to exclude from logs\n */\nconst SENSITIVE_FIELD_PATTERNS = [\n /password/i,\n /passwd/i,\n /pwd/i,\n /secret/i,\n /token/i,\n /api[_-]?key/i,\n /auth/i,\n /credit[_-]?card/i,\n /card[_-]?number/i,\n /cvv/i,\n /ssn/i,\n /social[_-]?security/i,\n /tax[_-]?id/i,\n /driver[_-]?license/i,\n /passport/i,\n]\n\n/**\n * Maximum depth for nested object sanitization\n */\nconst MAX_SANITIZATION_DEPTH = 5\n\n/**\n * Sanitize data for logging by removing sensitive fields\n */\nfunction sanitizeForLogging(data: any, depth: number = 0): any {\n // Prevent infinite recursion\n if (depth > MAX_SANITIZATION_DEPTH) {\n return '[Max depth exceeded]'\n }\n\n // Handle null/undefined\n if (data === null || data === undefined) {\n return data\n }\n\n // Handle primitives\n if (typeof data !== 'object') {\n return data\n }\n\n // Handle arrays\n if (Array.isArray(data)) {\n return data.map(item => sanitizeForLogging(item, depth + 1))\n }\n\n // Handle objects\n const sanitized: Record<string, any> = {}\n\n for (const [key, value] of Object.entries(data)) {\n // Check if field name matches sensitive patterns\n const isSensitive = SENSITIVE_FIELD_PATTERNS.some(pattern => pattern.test(key))\n\n if (isSensitive) {\n sanitized[key] = '[REDACTED]'\n } else if (typeof value === 'object' && value !== null) {\n sanitized[key] = sanitizeForLogging(value, depth + 1)\n } else {\n sanitized[key] = value\n }\n }\n\n return sanitized\n}\n\n/**\n * Sanitize user object for logging (keep only safe fields)\n */\nfunction sanitizeUser(user: any): any {\n if (!user) {\n return undefined\n }\n\n // Only log safe user fields\n return {\n id: user.id,\n role: user.role,\n // Don't log: email, name, phone, address, etc.\n }\n}\n\n/**\n * Log rule execution to database\n */\ninterface LogExecutionOptions {\n rule: BusinessRule\n context: RuleEngineContext\n conditionResult: boolean\n actionsExecuted: ActionExecutionOutcome | null\n executionTime: number\n error?: string\n}\n\nexport async function logRuleExecution(\n em: EntityManager,\n options: LogExecutionOptions\n): Promise<string> {\n const { rule, context, conditionResult, actionsExecuted, executionTime, error } = options\n\n const executionResult: 'SUCCESS' | 'FAILURE' | 'ERROR' = error\n ? EXECUTION_RESULT_ERROR\n : conditionResult\n ? EXECUTION_RESULT_SUCCESS\n : EXECUTION_RESULT_FAILURE\n\n const log = em.create(RuleExecutionLog, {\n rule,\n entityId: context.entityId || DEFAULT_ENTITY_ID,\n entityType: context.entityType,\n executionResult,\n inputContext: {\n data: sanitizeForLogging(context.data),\n eventType: context.eventType,\n user: sanitizeUser(context.user),\n },\n outputContext: actionsExecuted\n ? {\n conditionResult,\n actionsExecuted: actionsExecuted.results.map((r) => ({\n type: r.action.type,\n success: r.success,\n error: r.error,\n })),\n }\n : null,\n errorMessage: error || null,\n executionTimeMs: executionTime,\n tenantId: context.tenantId,\n organizationId: context.organizationId,\n executedBy: context.executedBy || null,\n })\n\n await em.persistAndFlush(log)\n\n return log.id\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["executionTime", "logId"]
7
7
  }
@@ -326,12 +326,10 @@ function PriceKindSettings() {
326
326
  {
327
327
  items: [
328
328
  {
329
- id: "edit",
330
329
  label: t("catalog.priceKinds.actions.edit", "Edit"),
331
330
  onSelect: () => openDialog({ mode: "edit", entry })
332
331
  },
333
332
  {
334
- id: "delete",
335
333
  label: t("catalog.priceKinds.actions.delete", "Delete"),
336
334
  destructive: true,
337
335
  onSelect: () => {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/modules/catalog/components/PriceKindSettings.tsx"],
4
- "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport type { ColumnDef } from '@tanstack/react-table'\nimport { DataTable } from '@open-mercato/ui/backend/DataTable'\nimport { RowActions } from '@open-mercato/ui/backend/RowActions'\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 {\n Dialog,\n DialogContent,\n DialogDescription,\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 { DictionaryEntrySelect } from '@open-mercato/core/modules/dictionaries/components/DictionaryEntrySelect'\nimport { useCurrencyDictionary } from '@open-mercato/core/modules/customers/components/detail/hooks/useCurrencyDictionary'\nimport type { DictionaryOption } from '@open-mercato/core/modules/dictionaries/components/DictionaryEntrySelect'\nimport type { CatalogPriceDisplayMode } from '../data/types'\n\ntype PriceKind = {\n id: string\n code: string\n title: string\n displayMode: CatalogPriceDisplayMode\n currencyCode: string | null\n isPromotion: boolean\n isActive: boolean\n createdAt: string\n updatedAt: string\n}\n\ntype DialogState =\n | { mode: 'create' }\n | { mode: 'edit'; entry: PriceKind }\n\ntype PriceKindApiPayload = Partial<PriceKind> & {\n display_mode?: PriceKind['displayMode']\n currency_code?: string | null\n is_promotion?: boolean\n is_active?: boolean\n created_at?: string\n updated_at?: string\n}\n\nconst DISPLAY_MODES: Array<{ value: 'including-tax' | 'excluding-tax'; label: string }> = [\n { value: 'excluding-tax', label: 'Excluding tax' },\n { value: 'including-tax', label: 'Including tax' },\n]\n\nconst PAGE_SIZE = 100\n\ntype PriceKindFormState = {\n code: string\n title: string\n displayMode: CatalogPriceDisplayMode\n currencyCode: string\n isPromotion: boolean\n isActive: boolean\n}\n\nconst DEFAULT_FORM: PriceKindFormState = {\n code: '',\n title: '',\n displayMode: 'excluding-tax' as const,\n currencyCode: '',\n isPromotion: false,\n isActive: true,\n}\n\nconst normalizePriceKind = (input: PriceKindApiPayload | null | undefined): PriceKind => {\n const raw = input ?? {}\n const toStringValue = (value: unknown): string | null => {\n if (typeof value === 'string') return value\n if (typeof value === 'number' || typeof value === 'bigint') return String(value)\n return null\n }\n const toBooleanValue = (value: unknown): boolean | null => (typeof value === 'boolean' ? value : null)\n const resolveDisplayMode = (value: string | null): PriceKind['displayMode'] =>\n value === 'including-tax' ? 'including-tax' : value === 'excluding-tax' ? 'excluding-tax' : 'excluding-tax'\n\n const displayMode = resolveDisplayMode(\n toStringValue(raw.displayMode) ?? toStringValue(raw.display_mode),\n )\n const currencyCode = toStringValue(raw.currencyCode) ?? toStringValue(raw.currency_code)\n const isPromotion = toBooleanValue(raw.isPromotion) ?? toBooleanValue(raw.is_promotion)\n const isActive = toBooleanValue(raw.isActive) ?? toBooleanValue(raw.is_active)\n\n return {\n id: toStringValue(raw.id) ?? '',\n code: toStringValue(raw.code) ?? '',\n title: toStringValue(raw.title) ?? '',\n displayMode,\n currencyCode: currencyCode ?? null,\n isPromotion: isPromotion ?? false,\n isActive: isActive ?? true,\n createdAt: toStringValue(raw.createdAt) ?? toStringValue(raw.created_at) ?? '',\n updatedAt: toStringValue(raw.updatedAt) ?? toStringValue(raw.updated_at) ?? '',\n }\n}\n\nexport function PriceKindSettings() {\n const t = useT()\n const scopeVersion = useOrganizationScopeVersion()\n const [items, setItems] = React.useState<PriceKind[]>([])\n const [loading, setLoading] = React.useState(false)\n const [search, setSearch] = React.useState('')\n const [dialog, setDialog] = React.useState<DialogState | null>(null)\n const [form, setForm] = React.useState<PriceKindFormState>(DEFAULT_FORM)\n const [submitting, setSubmitting] = React.useState(false)\n const [error, setError] = React.useState<string | null>(null)\n const { data: currencyDictionary, refetch: refetchCurrencyDictionary } = useCurrencyDictionary()\n\n const currencyOptionsLoader = React.useCallback(async (): Promise<DictionaryOption[]> => {\n if (currencyDictionary && Array.isArray(currencyDictionary.entries)) {\n return currencyDictionary.entries.map((entry) => ({\n value: entry.value,\n label: entry.label,\n color: entry.color ?? null,\n icon: entry.icon ?? null,\n }))\n }\n const payload = await refetchCurrencyDictionary()\n return payload.entries.map((entry) => ({\n value: entry.value,\n label: entry.label,\n color: entry.color ?? null,\n icon: entry.icon ?? null,\n }))\n }, [currencyDictionary, refetchCurrencyDictionary])\n\n const loadItems = React.useCallback(async () => {\n setLoading(true)\n const loadErrorMessage = t('catalog.priceKinds.errors.load', 'Failed to load price kinds.')\n try {\n const payload = await readApiResultOrThrow<{ items?: PriceKindApiPayload[] }>(\n `/api/catalog/price-kinds?pageSize=${PAGE_SIZE}`,\n undefined,\n { errorMessage: loadErrorMessage },\n )\n const normalized = Array.isArray(payload.items) ? payload.items.map((item) => normalizePriceKind(item)) : []\n setItems(normalized)\n } catch (err) {\n console.error('catalog.price-kinds.list failed', err)\n flash(loadErrorMessage, 'error')\n } finally {\n setLoading(false)\n }\n }, [t])\n\n React.useEffect(() => {\n loadItems().catch(() => {})\n }, [loadItems, scopeVersion])\n\n const openDialog = React.useCallback((state: DialogState) => {\n if (state.mode === 'edit') {\n setForm({\n code: state.entry.code,\n title: state.entry.title,\n displayMode: state.entry.displayMode,\n currencyCode: state.entry.currencyCode ?? '',\n isPromotion: state.entry.isPromotion,\n isActive: state.entry.isActive,\n })\n } else {\n setForm(DEFAULT_FORM)\n }\n setError(null)\n setDialog(state)\n }, [])\n\n const closeDialog = React.useCallback(() => {\n setDialog(null)\n setError(null)\n setSubmitting(false)\n setForm(DEFAULT_FORM)\n }, [])\n\n const handleSubmit = React.useCallback(async () => {\n if (!dialog) return\n const trimmedCode = form.code.trim().toLowerCase()\n const trimmedTitle = form.title.trim()\n if (!trimmedCode || !trimmedTitle) {\n setError(t('catalog.priceKinds.errors.required', 'Code and title are required.'))\n return\n }\n setSubmitting(true)\n setError(null)\n try {\n const payload = {\n code: trimmedCode,\n title: trimmedTitle,\n displayMode: form.displayMode,\n currencyCode: form.currencyCode.trim() || undefined,\n isPromotion: form.isPromotion,\n isActive: form.isActive,\n }\n const path = '/api/catalog/price-kinds'\n const method = dialog.mode === 'create' ? 'POST' : 'PUT'\n const body =\n dialog.mode === 'edit'\n ? JSON.stringify({ id: dialog.entry.id, ...payload })\n : JSON.stringify(payload)\n const call = await apiCall(path, {\n method,\n headers: { 'content-type': 'application/json' },\n body,\n })\n if (!call.ok) {\n await raiseCrudError(call.response, t('catalog.priceKinds.errors.save', 'Failed to save price kind.'))\n }\n flash(\n dialog.mode === 'create'\n ? t('catalog.priceKinds.messages.created', 'Price kind created.')\n : t('catalog.priceKinds.messages.updated', 'Price kind updated.'),\n 'success',\n )\n closeDialog()\n await loadItems()\n } catch (err) {\n console.error('catalog.price-kinds.save failed', err)\n const message =\n err instanceof Error ? err.message : t('catalog.priceKinds.errors.save', 'Failed to save price kind.')\n setError(message)\n } finally {\n setSubmitting(false)\n }\n }, [dialog, form, t, closeDialog, loadItems])\n\n const handleDelete = React.useCallback(\n async (entry: PriceKind) => {\n const confirmMessage = t('catalog.priceKinds.confirm.delete', 'Delete price kind \"{{code}}\"?').replace('{{code}}', entry.code)\n if (!window.confirm(confirmMessage)) return\n try {\n const call = await apiCall('/api/catalog/price-kinds', {\n method: 'DELETE',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ id: entry.id }),\n })\n if (!call.ok) {\n await raiseCrudError(call.response, t('catalog.priceKinds.errors.delete', 'Failed to delete price kind.'))\n }\n flash(t('catalog.priceKinds.messages.deleted', 'Price kind deleted.'), 'success')\n await loadItems()\n } catch (err) {\n console.error('catalog.price-kinds.delete failed', err)\n const message =\n err instanceof Error ? err.message : t('catalog.priceKinds.errors.delete', 'Failed to delete price kind.')\n flash(message, 'error')\n }\n },\n [loadItems, t],\n )\n\n const formKeyHandler = React.useCallback(\n (event: React.KeyboardEvent<HTMLFormElement>) => {\n if ((event.metaKey || event.ctrlKey) && event.key === 'Enter') {\n event.preventDefault()\n void handleSubmit()\n }\n },\n [handleSubmit],\n )\n\n const displayModeLabels = React.useMemo(() => ({\n 'including-tax': t('catalog.priceKinds.form.displayMode.include', 'Including tax'),\n 'excluding-tax': t('catalog.priceKinds.form.displayMode.exclude', 'Excluding tax'),\n }), [t])\n\n const displayModeOptions = React.useMemo(\n () =>\n DISPLAY_MODES.map((mode) => ({\n ...mode,\n label: displayModeLabels[mode.value],\n })),\n [displayModeLabels],\n )\n\n const currencyLabels = React.useMemo(() => ({\n placeholder: t('catalog.priceKinds.form.currency.placeholder', 'Select currency\u2026'),\n addLabel: t('catalog.priceKinds.form.currency.add', 'Add currency'),\n addPrompt: t('catalog.priceKinds.form.currency.addPrompt', 'Provide a currency code.'),\n dialogTitle: t('catalog.priceKinds.form.currency.dialogTitle', 'Add currency'),\n valueLabel: t('catalog.priceKinds.form.currency.valueLabel', 'Currency code'),\n valuePlaceholder: t('catalog.priceKinds.form.currency.valuePlaceholder', 'e.g. USD'),\n labelLabel: t('catalog.priceKinds.form.currency.labelLabel', 'Display label (optional)'),\n labelPlaceholder: t('catalog.priceKinds.form.currency.labelPlaceholder', 'e.g. US Dollar'),\n emptyError: t('catalog.priceKinds.form.currency.required', 'Currency code is required.'),\n cancelLabel: t('catalog.priceKinds.form.currency.cancel', 'Cancel'),\n saveLabel: t('catalog.priceKinds.form.currency.save', 'Save'),\n saveShortcutHint: t('catalog.priceKinds.form.currency.saveShortcut', 'Press Enter to save'),\n successCreateLabel: t('catalog.priceKinds.form.currency.success', 'Currency added.'),\n errorLoad: t('catalog.priceKinds.form.currency.loadError', 'Unable to load currencies.'),\n errorSave: t('catalog.priceKinds.form.currency.createError', 'Unable to add currency.'),\n loadingLabel: t('catalog.priceKinds.form.currency.loading', 'Loading currencies\u2026'),\n manageTitle: t('catalog.priceKinds.form.currency.manage', 'Manage currencies'),\n }), [t])\n\n const tableLabels = React.useMemo(() => ({\n code: t('catalog.priceKinds.table.code', 'Code'),\n title: t('catalog.priceKinds.table.title', 'Title'),\n displayMode: t('catalog.priceKinds.table.displayMode', 'Display mode'),\n currency: t('catalog.priceKinds.table.currency', 'Currency'),\n promotion: t('catalog.priceKinds.table.promotion', 'Promotion'),\n promotionYes: t('catalog.priceKinds.table.promotionYes', 'Yes'),\n promotionNo: t('catalog.priceKinds.table.promotionNo', 'No'),\n active: t('catalog.priceKinds.table.active', 'Active'),\n activeYes: t('catalog.priceKinds.table.activeYes', 'Active'),\n activeNo: t('catalog.priceKinds.table.activeNo', 'Inactive'),\n search: t('catalog.priceKinds.search.placeholder', 'Search by code or title\u2026'),\n empty: t('catalog.priceKinds.table.empty', 'No price kinds yet.'),\n }), [t])\n\n const columns = React.useMemo<ColumnDef<PriceKind>[]>(() => [\n {\n accessorKey: 'code',\n header: tableLabels.code,\n cell: ({ row }) => <span className=\"font-mono uppercase\">{row.original.code}</span>,\n },\n {\n accessorKey: 'title',\n header: tableLabels.title,\n cell: ({ row }) => <span className=\"font-medium\">{row.original.title}</span>,\n },\n {\n accessorKey: 'displayMode',\n header: tableLabels.displayMode,\n cell: ({ row }) => displayModeLabels[row.original.displayMode] ?? row.original.displayMode,\n },\n {\n accessorKey: 'currencyCode',\n header: tableLabels.currency,\n cell: ({ row }) => (row.original.currencyCode ? row.original.currencyCode.toUpperCase() : '\u2014'),\n },\n {\n id: 'promotion',\n header: tableLabels.promotion,\n cell: ({ row }) =>\n row.original.isPromotion ? (\n <span className=\"inline-flex items-center rounded-full border border-amber-200 bg-amber-50 px-2 py-0.5 text-xs font-medium text-amber-900 dark:border-amber-500/50 dark:bg-amber-500/10 dark:text-amber-100\">\n {tableLabels.promotionYes}\n </span>\n ) : (\n <span className=\"inline-flex items-center rounded-full border px-2 py-0.5 text-xs font-medium\">\n {tableLabels.promotionNo}\n </span>\n ),\n },\n {\n id: 'active',\n header: tableLabels.active,\n cell: ({ row }) =>\n row.original.isActive ? (\n <span className=\"inline-flex items-center rounded-full border border-emerald-200 bg-emerald-50 px-2 py-0.5 text-xs font-medium text-emerald-900 dark:border-emerald-500/50 dark:bg-emerald-500/10 dark:text-emerald-100\">\n {tableLabels.activeYes}\n </span>\n ) : (\n <span className=\"inline-flex items-center rounded-full border px-2 py-0.5 text-xs font-medium\">\n {tableLabels.activeNo}\n </span>\n ),\n },\n ], [displayModeLabels, tableLabels])\n\n const filteredItems = React.useMemo(() => {\n const term = search.trim().toLowerCase()\n if (!term) return items\n return items.filter((item) => {\n const currency = (item.currencyCode ?? '').toLowerCase()\n const modeLabel = (displayModeLabels[item.displayMode] ?? item.displayMode).toLowerCase()\n return (\n item.code.toLowerCase().includes(term) ||\n item.title.toLowerCase().includes(term) ||\n currency.includes(term) ||\n modeLabel.includes(term)\n )\n })\n }, [displayModeLabels, items, search])\n\n const handleRowClick = React.useCallback((entry: PriceKind) => {\n openDialog({ mode: 'edit', entry })\n }, [openDialog])\n\n return (\n <section className=\"border bg-card text-card-foreground shadow-sm\">\n <div className=\"border-b px-6 py-4 space-y-1\">\n <h2 className=\"text-lg font-semibold\">{t('catalog.priceKinds.title', 'Price kinds')}</h2>\n <p className=\"text-sm text-muted-foreground\">\n {t('catalog.priceKinds.description', 'Configure reusable price kinds that control pricing columns and tax display.')}\n </p>\n </div>\n <div className=\"px-2 py-4 sm:px-4\">\n <DataTable<PriceKind>\n data={filteredItems}\n columns={columns}\n embedded\n isLoading={loading}\n searchValue={search}\n onSearchChange={setSearch}\n searchPlaceholder={tableLabels.search}\n emptyState={<p className=\"py-8 text-center text-sm text-muted-foreground\">{tableLabels.empty}</p>}\n actions={(\n <Button size=\"sm\" onClick={() => openDialog({ mode: 'create' })}>\n {t('catalog.priceKinds.actions.add', 'Add price kind')}\n </Button>\n )}\n refreshButton={{\n label: t('catalog.priceKinds.actions.refresh', 'Refresh'),\n onRefresh: () => { void loadItems() },\n isRefreshing: loading,\n }}\n rowActions={(entry) => (\n <RowActions\n items={[\n {\n id: 'edit',\n label: t('catalog.priceKinds.actions.edit', 'Edit'),\n onSelect: () => openDialog({ mode: 'edit', entry }),\n },\n {\n id: 'delete',\n label: t('catalog.priceKinds.actions.delete', 'Delete'),\n destructive: true,\n onSelect: () => { void handleDelete(entry) },\n },\n ]}\n />\n )}\n onRowClick={handleRowClick}\n />\n </div>\n <Dialog open={dialog !== null} onOpenChange={(open) => { if (!open) closeDialog(); }}>\n <DialogContent>\n <DialogHeader>\n <DialogTitle>\n {dialog?.mode === 'edit'\n ? t('catalog.priceKinds.dialog.editTitle', 'Edit price kind')\n : t('catalog.priceKinds.dialog.createTitle', 'Create price kind')}\n </DialogTitle>\n <DialogDescription>\n {dialog?.mode === 'edit'\n ? t('catalog.priceKinds.dialog.editDescription', 'Update labels or tax behavior for this price kind.')\n : t('catalog.priceKinds.dialog.createDescription', 'Define a reusable price kind for product pricing.')}\n </DialogDescription>\n </DialogHeader>\n <form className=\"space-y-4\" onKeyDown={formKeyHandler} onSubmit={(event) => { event.preventDefault(); void handleSubmit() }}>\n <div className=\"space-y-2\">\n <Label htmlFor=\"price-kind-code\">{t('catalog.priceKinds.form.codeLabel', 'Code')}</Label>\n <Input\n id=\"price-kind-code\"\n value={form.code}\n onChange={(event) => setForm((prev) => ({ ...prev, code: event.target.value }))}\n placeholder={t('catalog.priceKinds.form.codePlaceholder', 'e.g. regular')}\n className=\"font-mono uppercase\"\n disabled={dialog?.mode === 'edit'}\n />\n </div>\n <div className=\"space-y-2\">\n <Label htmlFor=\"price-kind-title\">{t('catalog.priceKinds.form.titleLabel', 'Title')}</Label>\n <Input\n id=\"price-kind-title\"\n value={form.title}\n onChange={(event) => setForm((prev) => ({ ...prev, title: event.target.value }))}\n placeholder={t('catalog.priceKinds.form.titlePlaceholder', 'e.g. Regular price')}\n />\n </div>\n <div className=\"space-y-2\">\n <Label>{t('catalog.priceKinds.form.displayModeLabel', 'Display mode')}</Label>\n <div className=\"grid gap-2 md:grid-cols-2\">\n {displayModeOptions.map((mode) => (\n <label\n key={mode.value}\n className={`flex cursor-pointer items-center gap-2 rounded-md border p-3 text-sm ${\n form.displayMode === mode.value ? 'border-primary bg-primary/5' : 'border-border'\n }`}\n >\n <input\n type=\"radio\"\n name=\"displayMode\"\n value={mode.value}\n checked={form.displayMode === mode.value}\n onChange={() => setForm((prev) => ({ ...prev, displayMode: mode.value }))}\n />\n <span>{mode.label}</span>\n </label>\n ))}\n </div>\n </div>\n <div className=\"space-y-2\">\n <Label>{t('catalog.priceKinds.form.currencyLabel', 'Currency (optional)')}</Label>\n <DictionaryEntrySelect\n value={form.currencyCode || undefined}\n onChange={(value) => setForm((prev) => ({ ...prev, currencyCode: value ?? '' }))}\n fetchOptions={currencyOptionsLoader}\n labels={currencyLabels}\n allowInlineCreate={false}\n />\n </div>\n <div className=\"flex flex-col gap-2\">\n <label className=\"flex items-center gap-2 text-sm font-medium\">\n <input\n type=\"checkbox\"\n className=\"h-4 w-4 rounded border\"\n checked={form.isPromotion}\n onChange={(event) => setForm((prev) => ({ ...prev, isPromotion: event.target.checked }))}\n />\n {t('catalog.priceKinds.form.promotionLabel', 'Mark as promotion')}\n </label>\n <label className=\"flex items-center gap-2 text-sm font-medium\">\n <input\n type=\"checkbox\"\n className=\"h-4 w-4 rounded border\"\n checked={form.isActive}\n onChange={(event) => setForm((prev) => ({ ...prev, isActive: event.target.checked }))}\n />\n {t('catalog.priceKinds.form.activeLabel', 'Active')}\n </label>\n </div>\n {error ? <p className=\"text-sm text-red-600\">{error}</p> : null}\n </form>\n <DialogFooter>\n <Button variant=\"ghost\" onClick={closeDialog}>\n {t('catalog.priceKinds.actions.cancel', 'Cancel')}\n </Button>\n <Button onClick={() => void handleSubmit()} disabled={submitting}>\n {dialog?.mode === 'edit'\n ? t('catalog.priceKinds.actions.saveChanges', 'Save changes')\n : t('catalog.priceKinds.actions.create', 'Create')}\n </Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n </section>\n )\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport type { ColumnDef } from '@tanstack/react-table'\nimport { DataTable } from '@open-mercato/ui/backend/DataTable'\nimport { RowActions } from '@open-mercato/ui/backend/RowActions'\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 {\n Dialog,\n DialogContent,\n DialogDescription,\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 { DictionaryEntrySelect } from '@open-mercato/core/modules/dictionaries/components/DictionaryEntrySelect'\nimport { useCurrencyDictionary } from '@open-mercato/core/modules/customers/components/detail/hooks/useCurrencyDictionary'\nimport type { DictionaryOption } from '@open-mercato/core/modules/dictionaries/components/DictionaryEntrySelect'\nimport type { CatalogPriceDisplayMode } from '../data/types'\n\ntype PriceKind = {\n id: string\n code: string\n title: string\n displayMode: CatalogPriceDisplayMode\n currencyCode: string | null\n isPromotion: boolean\n isActive: boolean\n createdAt: string\n updatedAt: string\n}\n\ntype DialogState =\n | { mode: 'create' }\n | { mode: 'edit'; entry: PriceKind }\n\ntype PriceKindApiPayload = Partial<PriceKind> & {\n display_mode?: PriceKind['displayMode']\n currency_code?: string | null\n is_promotion?: boolean\n is_active?: boolean\n created_at?: string\n updated_at?: string\n}\n\nconst DISPLAY_MODES: Array<{ value: 'including-tax' | 'excluding-tax'; label: string }> = [\n { value: 'excluding-tax', label: 'Excluding tax' },\n { value: 'including-tax', label: 'Including tax' },\n]\n\nconst PAGE_SIZE = 100\n\ntype PriceKindFormState = {\n code: string\n title: string\n displayMode: CatalogPriceDisplayMode\n currencyCode: string\n isPromotion: boolean\n isActive: boolean\n}\n\nconst DEFAULT_FORM: PriceKindFormState = {\n code: '',\n title: '',\n displayMode: 'excluding-tax' as const,\n currencyCode: '',\n isPromotion: false,\n isActive: true,\n}\n\nconst normalizePriceKind = (input: PriceKindApiPayload | null | undefined): PriceKind => {\n const raw = input ?? {}\n const toStringValue = (value: unknown): string | null => {\n if (typeof value === 'string') return value\n if (typeof value === 'number' || typeof value === 'bigint') return String(value)\n return null\n }\n const toBooleanValue = (value: unknown): boolean | null => (typeof value === 'boolean' ? value : null)\n const resolveDisplayMode = (value: string | null): PriceKind['displayMode'] =>\n value === 'including-tax' ? 'including-tax' : value === 'excluding-tax' ? 'excluding-tax' : 'excluding-tax'\n\n const displayMode = resolveDisplayMode(\n toStringValue(raw.displayMode) ?? toStringValue(raw.display_mode),\n )\n const currencyCode = toStringValue(raw.currencyCode) ?? toStringValue(raw.currency_code)\n const isPromotion = toBooleanValue(raw.isPromotion) ?? toBooleanValue(raw.is_promotion)\n const isActive = toBooleanValue(raw.isActive) ?? toBooleanValue(raw.is_active)\n\n return {\n id: toStringValue(raw.id) ?? '',\n code: toStringValue(raw.code) ?? '',\n title: toStringValue(raw.title) ?? '',\n displayMode,\n currencyCode: currencyCode ?? null,\n isPromotion: isPromotion ?? false,\n isActive: isActive ?? true,\n createdAt: toStringValue(raw.createdAt) ?? toStringValue(raw.created_at) ?? '',\n updatedAt: toStringValue(raw.updatedAt) ?? toStringValue(raw.updated_at) ?? '',\n }\n}\n\nexport function PriceKindSettings() {\n const t = useT()\n const scopeVersion = useOrganizationScopeVersion()\n const [items, setItems] = React.useState<PriceKind[]>([])\n const [loading, setLoading] = React.useState(false)\n const [search, setSearch] = React.useState('')\n const [dialog, setDialog] = React.useState<DialogState | null>(null)\n const [form, setForm] = React.useState<PriceKindFormState>(DEFAULT_FORM)\n const [submitting, setSubmitting] = React.useState(false)\n const [error, setError] = React.useState<string | null>(null)\n const { data: currencyDictionary, refetch: refetchCurrencyDictionary } = useCurrencyDictionary()\n\n const currencyOptionsLoader = React.useCallback(async (): Promise<DictionaryOption[]> => {\n if (currencyDictionary && Array.isArray(currencyDictionary.entries)) {\n return currencyDictionary.entries.map((entry) => ({\n value: entry.value,\n label: entry.label,\n color: entry.color ?? null,\n icon: entry.icon ?? null,\n }))\n }\n const payload = await refetchCurrencyDictionary()\n return payload.entries.map((entry) => ({\n value: entry.value,\n label: entry.label,\n color: entry.color ?? null,\n icon: entry.icon ?? null,\n }))\n }, [currencyDictionary, refetchCurrencyDictionary])\n\n const loadItems = React.useCallback(async () => {\n setLoading(true)\n const loadErrorMessage = t('catalog.priceKinds.errors.load', 'Failed to load price kinds.')\n try {\n const payload = await readApiResultOrThrow<{ items?: PriceKindApiPayload[] }>(\n `/api/catalog/price-kinds?pageSize=${PAGE_SIZE}`,\n undefined,\n { errorMessage: loadErrorMessage },\n )\n const normalized = Array.isArray(payload.items) ? payload.items.map((item) => normalizePriceKind(item)) : []\n setItems(normalized)\n } catch (err) {\n console.error('catalog.price-kinds.list failed', err)\n flash(loadErrorMessage, 'error')\n } finally {\n setLoading(false)\n }\n }, [t])\n\n React.useEffect(() => {\n loadItems().catch(() => {})\n }, [loadItems, scopeVersion])\n\n const openDialog = React.useCallback((state: DialogState) => {\n if (state.mode === 'edit') {\n setForm({\n code: state.entry.code,\n title: state.entry.title,\n displayMode: state.entry.displayMode,\n currencyCode: state.entry.currencyCode ?? '',\n isPromotion: state.entry.isPromotion,\n isActive: state.entry.isActive,\n })\n } else {\n setForm(DEFAULT_FORM)\n }\n setError(null)\n setDialog(state)\n }, [])\n\n const closeDialog = React.useCallback(() => {\n setDialog(null)\n setError(null)\n setSubmitting(false)\n setForm(DEFAULT_FORM)\n }, [])\n\n const handleSubmit = React.useCallback(async () => {\n if (!dialog) return\n const trimmedCode = form.code.trim().toLowerCase()\n const trimmedTitle = form.title.trim()\n if (!trimmedCode || !trimmedTitle) {\n setError(t('catalog.priceKinds.errors.required', 'Code and title are required.'))\n return\n }\n setSubmitting(true)\n setError(null)\n try {\n const payload = {\n code: trimmedCode,\n title: trimmedTitle,\n displayMode: form.displayMode,\n currencyCode: form.currencyCode.trim() || undefined,\n isPromotion: form.isPromotion,\n isActive: form.isActive,\n }\n const path = '/api/catalog/price-kinds'\n const method = dialog.mode === 'create' ? 'POST' : 'PUT'\n const body =\n dialog.mode === 'edit'\n ? JSON.stringify({ id: dialog.entry.id, ...payload })\n : JSON.stringify(payload)\n const call = await apiCall(path, {\n method,\n headers: { 'content-type': 'application/json' },\n body,\n })\n if (!call.ok) {\n await raiseCrudError(call.response, t('catalog.priceKinds.errors.save', 'Failed to save price kind.'))\n }\n flash(\n dialog.mode === 'create'\n ? t('catalog.priceKinds.messages.created', 'Price kind created.')\n : t('catalog.priceKinds.messages.updated', 'Price kind updated.'),\n 'success',\n )\n closeDialog()\n await loadItems()\n } catch (err) {\n console.error('catalog.price-kinds.save failed', err)\n const message =\n err instanceof Error ? err.message : t('catalog.priceKinds.errors.save', 'Failed to save price kind.')\n setError(message)\n } finally {\n setSubmitting(false)\n }\n }, [dialog, form, t, closeDialog, loadItems])\n\n const handleDelete = React.useCallback(\n async (entry: PriceKind) => {\n const confirmMessage = t('catalog.priceKinds.confirm.delete', 'Delete price kind \"{{code}}\"?').replace('{{code}}', entry.code)\n if (!window.confirm(confirmMessage)) return\n try {\n const call = await apiCall('/api/catalog/price-kinds', {\n method: 'DELETE',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ id: entry.id }),\n })\n if (!call.ok) {\n await raiseCrudError(call.response, t('catalog.priceKinds.errors.delete', 'Failed to delete price kind.'))\n }\n flash(t('catalog.priceKinds.messages.deleted', 'Price kind deleted.'), 'success')\n await loadItems()\n } catch (err) {\n console.error('catalog.price-kinds.delete failed', err)\n const message =\n err instanceof Error ? err.message : t('catalog.priceKinds.errors.delete', 'Failed to delete price kind.')\n flash(message, 'error')\n }\n },\n [loadItems, t],\n )\n\n const formKeyHandler = React.useCallback(\n (event: React.KeyboardEvent<HTMLFormElement>) => {\n if ((event.metaKey || event.ctrlKey) && event.key === 'Enter') {\n event.preventDefault()\n void handleSubmit()\n }\n },\n [handleSubmit],\n )\n\n const displayModeLabels = React.useMemo(() => ({\n 'including-tax': t('catalog.priceKinds.form.displayMode.include', 'Including tax'),\n 'excluding-tax': t('catalog.priceKinds.form.displayMode.exclude', 'Excluding tax'),\n }), [t])\n\n const displayModeOptions = React.useMemo(\n () =>\n DISPLAY_MODES.map((mode) => ({\n ...mode,\n label: displayModeLabels[mode.value],\n })),\n [displayModeLabels],\n )\n\n const currencyLabels = React.useMemo(() => ({\n placeholder: t('catalog.priceKinds.form.currency.placeholder', 'Select currency\u2026'),\n addLabel: t('catalog.priceKinds.form.currency.add', 'Add currency'),\n addPrompt: t('catalog.priceKinds.form.currency.addPrompt', 'Provide a currency code.'),\n dialogTitle: t('catalog.priceKinds.form.currency.dialogTitle', 'Add currency'),\n valueLabel: t('catalog.priceKinds.form.currency.valueLabel', 'Currency code'),\n valuePlaceholder: t('catalog.priceKinds.form.currency.valuePlaceholder', 'e.g. USD'),\n labelLabel: t('catalog.priceKinds.form.currency.labelLabel', 'Display label (optional)'),\n labelPlaceholder: t('catalog.priceKinds.form.currency.labelPlaceholder', 'e.g. US Dollar'),\n emptyError: t('catalog.priceKinds.form.currency.required', 'Currency code is required.'),\n cancelLabel: t('catalog.priceKinds.form.currency.cancel', 'Cancel'),\n saveLabel: t('catalog.priceKinds.form.currency.save', 'Save'),\n saveShortcutHint: t('catalog.priceKinds.form.currency.saveShortcut', 'Press Enter to save'),\n successCreateLabel: t('catalog.priceKinds.form.currency.success', 'Currency added.'),\n errorLoad: t('catalog.priceKinds.form.currency.loadError', 'Unable to load currencies.'),\n errorSave: t('catalog.priceKinds.form.currency.createError', 'Unable to add currency.'),\n loadingLabel: t('catalog.priceKinds.form.currency.loading', 'Loading currencies\u2026'),\n manageTitle: t('catalog.priceKinds.form.currency.manage', 'Manage currencies'),\n }), [t])\n\n const tableLabels = React.useMemo(() => ({\n code: t('catalog.priceKinds.table.code', 'Code'),\n title: t('catalog.priceKinds.table.title', 'Title'),\n displayMode: t('catalog.priceKinds.table.displayMode', 'Display mode'),\n currency: t('catalog.priceKinds.table.currency', 'Currency'),\n promotion: t('catalog.priceKinds.table.promotion', 'Promotion'),\n promotionYes: t('catalog.priceKinds.table.promotionYes', 'Yes'),\n promotionNo: t('catalog.priceKinds.table.promotionNo', 'No'),\n active: t('catalog.priceKinds.table.active', 'Active'),\n activeYes: t('catalog.priceKinds.table.activeYes', 'Active'),\n activeNo: t('catalog.priceKinds.table.activeNo', 'Inactive'),\n search: t('catalog.priceKinds.search.placeholder', 'Search by code or title\u2026'),\n empty: t('catalog.priceKinds.table.empty', 'No price kinds yet.'),\n }), [t])\n\n const columns = React.useMemo<ColumnDef<PriceKind>[]>(() => [\n {\n accessorKey: 'code',\n header: tableLabels.code,\n cell: ({ row }) => <span className=\"font-mono uppercase\">{row.original.code}</span>,\n },\n {\n accessorKey: 'title',\n header: tableLabels.title,\n cell: ({ row }) => <span className=\"font-medium\">{row.original.title}</span>,\n },\n {\n accessorKey: 'displayMode',\n header: tableLabels.displayMode,\n cell: ({ row }) => displayModeLabels[row.original.displayMode] ?? row.original.displayMode,\n },\n {\n accessorKey: 'currencyCode',\n header: tableLabels.currency,\n cell: ({ row }) => (row.original.currencyCode ? row.original.currencyCode.toUpperCase() : '\u2014'),\n },\n {\n id: 'promotion',\n header: tableLabels.promotion,\n cell: ({ row }) =>\n row.original.isPromotion ? (\n <span className=\"inline-flex items-center rounded-full border border-amber-200 bg-amber-50 px-2 py-0.5 text-xs font-medium text-amber-900 dark:border-amber-500/50 dark:bg-amber-500/10 dark:text-amber-100\">\n {tableLabels.promotionYes}\n </span>\n ) : (\n <span className=\"inline-flex items-center rounded-full border px-2 py-0.5 text-xs font-medium\">\n {tableLabels.promotionNo}\n </span>\n ),\n },\n {\n id: 'active',\n header: tableLabels.active,\n cell: ({ row }) =>\n row.original.isActive ? (\n <span className=\"inline-flex items-center rounded-full border border-emerald-200 bg-emerald-50 px-2 py-0.5 text-xs font-medium text-emerald-900 dark:border-emerald-500/50 dark:bg-emerald-500/10 dark:text-emerald-100\">\n {tableLabels.activeYes}\n </span>\n ) : (\n <span className=\"inline-flex items-center rounded-full border px-2 py-0.5 text-xs font-medium\">\n {tableLabels.activeNo}\n </span>\n ),\n },\n ], [displayModeLabels, tableLabels])\n\n const filteredItems = React.useMemo(() => {\n const term = search.trim().toLowerCase()\n if (!term) return items\n return items.filter((item) => {\n const currency = (item.currencyCode ?? '').toLowerCase()\n const modeLabel = (displayModeLabels[item.displayMode] ?? item.displayMode).toLowerCase()\n return (\n item.code.toLowerCase().includes(term) ||\n item.title.toLowerCase().includes(term) ||\n currency.includes(term) ||\n modeLabel.includes(term)\n )\n })\n }, [displayModeLabels, items, search])\n\n const handleRowClick = React.useCallback((entry: PriceKind) => {\n openDialog({ mode: 'edit', entry })\n }, [openDialog])\n\n return (\n <section className=\"border bg-card text-card-foreground shadow-sm\">\n <div className=\"border-b px-6 py-4 space-y-1\">\n <h2 className=\"text-lg font-semibold\">{t('catalog.priceKinds.title', 'Price kinds')}</h2>\n <p className=\"text-sm text-muted-foreground\">\n {t('catalog.priceKinds.description', 'Configure reusable price kinds that control pricing columns and tax display.')}\n </p>\n </div>\n <div className=\"px-2 py-4 sm:px-4\">\n <DataTable<PriceKind>\n data={filteredItems}\n columns={columns}\n embedded\n isLoading={loading}\n searchValue={search}\n onSearchChange={setSearch}\n searchPlaceholder={tableLabels.search}\n emptyState={<p className=\"py-8 text-center text-sm text-muted-foreground\">{tableLabels.empty}</p>}\n actions={(\n <Button size=\"sm\" onClick={() => openDialog({ mode: 'create' })}>\n {t('catalog.priceKinds.actions.add', 'Add price kind')}\n </Button>\n )}\n refreshButton={{\n label: t('catalog.priceKinds.actions.refresh', 'Refresh'),\n onRefresh: () => { void loadItems() },\n isRefreshing: loading,\n }}\n rowActions={(entry) => (\n <RowActions\n items={[\n {\n label: t('catalog.priceKinds.actions.edit', 'Edit'),\n onSelect: () => openDialog({ mode: 'edit', entry }),\n },\n {\n label: t('catalog.priceKinds.actions.delete', 'Delete'),\n destructive: true,\n onSelect: () => { void handleDelete(entry) },\n },\n ]}\n />\n )}\n onRowClick={handleRowClick}\n />\n </div>\n <Dialog open={dialog !== null} onOpenChange={(open) => { if (!open) closeDialog(); }}>\n <DialogContent>\n <DialogHeader>\n <DialogTitle>\n {dialog?.mode === 'edit'\n ? t('catalog.priceKinds.dialog.editTitle', 'Edit price kind')\n : t('catalog.priceKinds.dialog.createTitle', 'Create price kind')}\n </DialogTitle>\n <DialogDescription>\n {dialog?.mode === 'edit'\n ? t('catalog.priceKinds.dialog.editDescription', 'Update labels or tax behavior for this price kind.')\n : t('catalog.priceKinds.dialog.createDescription', 'Define a reusable price kind for product pricing.')}\n </DialogDescription>\n </DialogHeader>\n <form className=\"space-y-4\" onKeyDown={formKeyHandler} onSubmit={(event) => { event.preventDefault(); void handleSubmit() }}>\n <div className=\"space-y-2\">\n <Label htmlFor=\"price-kind-code\">{t('catalog.priceKinds.form.codeLabel', 'Code')}</Label>\n <Input\n id=\"price-kind-code\"\n value={form.code}\n onChange={(event) => setForm((prev) => ({ ...prev, code: event.target.value }))}\n placeholder={t('catalog.priceKinds.form.codePlaceholder', 'e.g. regular')}\n className=\"font-mono uppercase\"\n disabled={dialog?.mode === 'edit'}\n />\n </div>\n <div className=\"space-y-2\">\n <Label htmlFor=\"price-kind-title\">{t('catalog.priceKinds.form.titleLabel', 'Title')}</Label>\n <Input\n id=\"price-kind-title\"\n value={form.title}\n onChange={(event) => setForm((prev) => ({ ...prev, title: event.target.value }))}\n placeholder={t('catalog.priceKinds.form.titlePlaceholder', 'e.g. Regular price')}\n />\n </div>\n <div className=\"space-y-2\">\n <Label>{t('catalog.priceKinds.form.displayModeLabel', 'Display mode')}</Label>\n <div className=\"grid gap-2 md:grid-cols-2\">\n {displayModeOptions.map((mode) => (\n <label\n key={mode.value}\n className={`flex cursor-pointer items-center gap-2 rounded-md border p-3 text-sm ${\n form.displayMode === mode.value ? 'border-primary bg-primary/5' : 'border-border'\n }`}\n >\n <input\n type=\"radio\"\n name=\"displayMode\"\n value={mode.value}\n checked={form.displayMode === mode.value}\n onChange={() => setForm((prev) => ({ ...prev, displayMode: mode.value }))}\n />\n <span>{mode.label}</span>\n </label>\n ))}\n </div>\n </div>\n <div className=\"space-y-2\">\n <Label>{t('catalog.priceKinds.form.currencyLabel', 'Currency (optional)')}</Label>\n <DictionaryEntrySelect\n value={form.currencyCode || undefined}\n onChange={(value) => setForm((prev) => ({ ...prev, currencyCode: value ?? '' }))}\n fetchOptions={currencyOptionsLoader}\n labels={currencyLabels}\n allowInlineCreate={false}\n />\n </div>\n <div className=\"flex flex-col gap-2\">\n <label className=\"flex items-center gap-2 text-sm font-medium\">\n <input\n type=\"checkbox\"\n className=\"h-4 w-4 rounded border\"\n checked={form.isPromotion}\n onChange={(event) => setForm((prev) => ({ ...prev, isPromotion: event.target.checked }))}\n />\n {t('catalog.priceKinds.form.promotionLabel', 'Mark as promotion')}\n </label>\n <label className=\"flex items-center gap-2 text-sm font-medium\">\n <input\n type=\"checkbox\"\n className=\"h-4 w-4 rounded border\"\n checked={form.isActive}\n onChange={(event) => setForm((prev) => ({ ...prev, isActive: event.target.checked }))}\n />\n {t('catalog.priceKinds.form.activeLabel', 'Active')}\n </label>\n </div>\n {error ? <p className=\"text-sm text-red-600\">{error}</p> : null}\n </form>\n <DialogFooter>\n <Button variant=\"ghost\" onClick={closeDialog}>\n {t('catalog.priceKinds.actions.cancel', 'Cancel')}\n </Button>\n <Button onClick={() => void handleSubmit()} disabled={submitting}>\n {dialog?.mode === 'edit'\n ? t('catalog.priceKinds.actions.saveChanges', 'Save changes')\n : t('catalog.priceKinds.actions.create', 'Create')}\n </Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n </section>\n )\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -178,8 +178,8 @@ function CategoriesDataTable() {
178
178
  RowActions,
179
179
  {
180
180
  items: [
181
- { id: "edit", label: t("catalog.categories.list.actions.edit", "Edit"), href: `/backend/catalog/categories/${row.id}/edit` },
182
- { id: "delete", label: t("catalog.categories.list.actions.delete", "Delete"), destructive: true, onSelect: () => handleDelete(row) }
181
+ { label: t("catalog.categories.list.actions.edit", "Edit"), href: `/backend/catalog/categories/${row.id}/edit` },
182
+ { label: t("catalog.categories.list.actions.delete", "Delete"), destructive: true, onSelect: () => handleDelete(row) }
183
183
  ]
184
184
  }
185
185
  ) : null,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/modules/catalog/components/categories/CategoriesDataTable.tsx"],
4
- "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport Link from 'next/link'\nimport { useQuery, useQueryClient } from '@tanstack/react-query'\nimport type { ColumnDef } from '@tanstack/react-table'\nimport { DataTable } from '@open-mercato/ui/backend/DataTable'\nimport type { FilterValues } from '@open-mercato/ui/backend/FilterBar'\nimport { RowActions } from '@open-mercato/ui/backend/RowActions'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { BooleanIcon } from '@open-mercato/ui/backend/ValueIcons'\nimport { apiCall, apiCallOrThrow, readApiResultOrThrow } from '@open-mercato/ui/backend/utils/apiCall'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { useOrganizationScopeVersion } from '@open-mercato/shared/lib/frontend/useOrganizationScope'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { formatCategoryTreeLabel } from '../../lib/categoryTree'\n\ntype CategoryRow = {\n id: string\n name: string\n slug: string | null\n description: string | null\n parentId: string | null\n parentName: string | null\n depth: number\n treePath: string\n pathLabel: string\n childCount: number\n descendantCount: number\n isActive: boolean\n}\n\ntype CategoriesResponse = {\n items: CategoryRow[]\n total: number\n page: number\n pageSize: number\n totalPages: number\n}\n\nconst PAGE_SIZE = 50\nconst TREE_BASE_INDENT = 18\nconst TREE_STEP_INDENT = 14\n\nfunction computeIndent(depth: number): number {\n if (depth <= 0) return 0\n return TREE_BASE_INDENT + (depth - 1) * TREE_STEP_INDENT\n}\n\nexport default function CategoriesDataTable() {\n const t = useT()\n const queryClient = useQueryClient()\n const scopeVersion = useOrganizationScopeVersion()\n const [page, setPage] = React.useState(1)\n const [status, setStatus] = React.useState<'all' | 'active' | 'inactive'>('all')\n const [search, setSearch] = React.useState('')\n const [canManage, setCanManage] = React.useState(false)\n\n React.useEffect(() => {\n let cancelled = false\n async function load() {\n try {\n const call = await apiCall<{ granted?: string[]; ok?: boolean }>('/api/auth/feature-check', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ features: ['catalog.categories.manage'] }),\n })\n if (!cancelled) {\n const granted = Array.isArray(call.result?.granted) ? call.result.granted : []\n setCanManage(call.result?.ok === true || granted.includes('catalog.categories.manage'))\n }\n } catch {\n if (!cancelled) setCanManage(false)\n }\n }\n load()\n return () => {\n cancelled = true\n }\n }, [])\n\n const queryParams = React.useMemo(() => {\n const params = new URLSearchParams()\n params.set('view', 'manage')\n params.set('page', String(page))\n params.set('pageSize', String(PAGE_SIZE))\n params.set('status', status)\n if (search) params.set('search', search)\n return params.toString()\n }, [page, status, search])\n\n const { data, isLoading } = useQuery<CategoriesResponse>({\n queryKey: ['catalog-categories', queryParams, scopeVersion],\n queryFn: async () => {\n const payload = await readApiResultOrThrow<CategoriesResponse>(\n `/api/catalog/categories?${queryParams}`,\n undefined,\n { errorMessage: t('catalog.categories.list.error.load', 'Failed to load categories') },\n )\n return {\n items: Array.isArray(payload.items) ? payload.items : [],\n total: typeof payload.total === 'number' ? payload.total : 0,\n page: typeof payload.page === 'number' ? payload.page : 1,\n pageSize: typeof payload.pageSize === 'number' ? payload.pageSize : PAGE_SIZE,\n totalPages: typeof payload.totalPages === 'number' ? payload.totalPages : 1,\n }\n },\n })\n\n const rows = data?.items ?? []\n const total = data?.total ?? 0\n const totalPages = data?.totalPages ?? 1\n\n const columns = React.useMemo<ColumnDef<CategoryRow>[]>(() => [\n {\n accessorKey: 'name',\n header: t('catalog.categories.list.columns.category', 'Category'),\n meta: { priority: 1 },\n cell: ({ row }) => {\n const depth = row.original.depth ?? 0\n return (\n <div className=\"flex items-center text-sm font-medium leading-none text-foreground\">\n <span style={{ marginLeft: computeIndent(depth), whiteSpace: 'pre' }}>\n {formatCategoryTreeLabel(row.original.name, depth)}\n </span>\n </div>\n )\n },\n },\n {\n accessorKey: 'pathLabel',\n header: t('catalog.categories.list.columns.path', 'Path'),\n meta: { priority: 3 },\n cell: ({ getValue }) => {\n const value = getValue<string>()\n return <span className=\"text-xs text-muted-foreground\">{value || '\u2014'}</span>\n },\n },\n {\n accessorKey: 'parentName',\n header: t('catalog.categories.list.columns.parent', 'Parent'),\n meta: { priority: 4 },\n cell: ({ getValue }) => getValue<string>() || t('catalog.categories.list.none', '\u2014'),\n },\n {\n accessorKey: 'childCount',\n header: t('catalog.categories.list.columns.children', 'Children'),\n meta: { priority: 5 },\n },\n {\n accessorKey: 'isActive',\n header: t('catalog.categories.list.columns.active', 'Active'),\n enableSorting: false,\n meta: { priority: 2 },\n cell: ({ getValue }) => <BooleanIcon value={Boolean(getValue())} />,\n },\n ], [t])\n\n const handleDelete = React.useCallback(async (category: CategoryRow) => {\n const confirmLabel = t(\n 'catalog.categories.list.confirmDelete',\n 'Archive category \"{{name}}\"?',\n { name: category.name },\n )\n if (!window.confirm(confirmLabel)) return\n try {\n await apiCallOrThrow(\n `/api/catalog/categories?id=${encodeURIComponent(category.id)}`,\n { method: 'DELETE' },\n { errorMessage: t('catalog.categories.list.error.delete', 'Failed to delete category') },\n )\n await queryClient.invalidateQueries({ queryKey: ['catalog-categories'] })\n flash(t('catalog.categories.flash.deleted', 'Category archived'), 'success')\n } catch (err: unknown) {\n const fallback = t('catalog.categories.list.error.delete', 'Failed to delete category')\n const message = err instanceof Error ? err.message : fallback\n flash(message, 'error')\n }\n }, [queryClient, t])\n\n return (\n <DataTable\n title={t('catalog.categories.list.title', 'Categories')}\n actions={canManage ? (\n <Button asChild>\n <Link href=\"/backend/catalog/categories/create\">\n {t('catalog.categories.list.actions.create', 'Create')}\n </Link>\n </Button>\n ) : undefined}\n columns={columns}\n data={rows}\n searchValue={search}\n searchPlaceholder={t('catalog.categories.list.searchPlaceholder', 'Search categories')}\n onSearchChange={(value) => { setSearch(value); setPage(1) }}\n filters={[\n {\n id: 'status',\n label: t('catalog.categories.list.filters.status', 'Status'),\n type: 'select',\n options: [\n { value: 'all', label: t('catalog.categories.list.filters.all', 'All') },\n { value: 'active', label: t('catalog.categories.list.filters.active', 'Active') },\n { value: 'inactive', label: t('catalog.categories.list.filters.inactive', 'Inactive') },\n ],\n },\n ]}\n filterValues={status === 'all' ? {} : { status }}\n onFiltersApply={(values: FilterValues) => {\n const nextStatus = (values.status as 'all' | 'active' | 'inactive' | undefined) ?? 'all'\n setStatus(nextStatus)\n setPage(1)\n }}\n onFiltersClear={() => {\n setStatus('all')\n setPage(1)\n }}\n sortable={false}\n perspective={{ tableId: 'catalog.categories.list' }}\n rowActions={(row) => (\n canManage ? (\n <RowActions\n items={[\n { id: 'edit', label: t('catalog.categories.list.actions.edit', 'Edit'), href: `/backend/catalog/categories/${row.id}/edit` },\n { id: 'delete', label: t('catalog.categories.list.actions.delete', 'Delete'), destructive: true, onSelect: () => handleDelete(row) },\n ]}\n />\n ) : null\n )}\n pagination={{\n page,\n pageSize: PAGE_SIZE,\n total,\n totalPages,\n onPageChange: setPage,\n }}\n isLoading={isLoading}\n />\n )\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport Link from 'next/link'\nimport { useQuery, useQueryClient } from '@tanstack/react-query'\nimport type { ColumnDef } from '@tanstack/react-table'\nimport { DataTable } from '@open-mercato/ui/backend/DataTable'\nimport type { FilterValues } from '@open-mercato/ui/backend/FilterBar'\nimport { RowActions } from '@open-mercato/ui/backend/RowActions'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { BooleanIcon } from '@open-mercato/ui/backend/ValueIcons'\nimport { apiCall, apiCallOrThrow, readApiResultOrThrow } from '@open-mercato/ui/backend/utils/apiCall'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { useOrganizationScopeVersion } from '@open-mercato/shared/lib/frontend/useOrganizationScope'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { formatCategoryTreeLabel } from '../../lib/categoryTree'\n\ntype CategoryRow = {\n id: string\n name: string\n slug: string | null\n description: string | null\n parentId: string | null\n parentName: string | null\n depth: number\n treePath: string\n pathLabel: string\n childCount: number\n descendantCount: number\n isActive: boolean\n}\n\ntype CategoriesResponse = {\n items: CategoryRow[]\n total: number\n page: number\n pageSize: number\n totalPages: number\n}\n\nconst PAGE_SIZE = 50\nconst TREE_BASE_INDENT = 18\nconst TREE_STEP_INDENT = 14\n\nfunction computeIndent(depth: number): number {\n if (depth <= 0) return 0\n return TREE_BASE_INDENT + (depth - 1) * TREE_STEP_INDENT\n}\n\nexport default function CategoriesDataTable() {\n const t = useT()\n const queryClient = useQueryClient()\n const scopeVersion = useOrganizationScopeVersion()\n const [page, setPage] = React.useState(1)\n const [status, setStatus] = React.useState<'all' | 'active' | 'inactive'>('all')\n const [search, setSearch] = React.useState('')\n const [canManage, setCanManage] = React.useState(false)\n\n React.useEffect(() => {\n let cancelled = false\n async function load() {\n try {\n const call = await apiCall<{ granted?: string[]; ok?: boolean }>('/api/auth/feature-check', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ features: ['catalog.categories.manage'] }),\n })\n if (!cancelled) {\n const granted = Array.isArray(call.result?.granted) ? call.result.granted : []\n setCanManage(call.result?.ok === true || granted.includes('catalog.categories.manage'))\n }\n } catch {\n if (!cancelled) setCanManage(false)\n }\n }\n load()\n return () => {\n cancelled = true\n }\n }, [])\n\n const queryParams = React.useMemo(() => {\n const params = new URLSearchParams()\n params.set('view', 'manage')\n params.set('page', String(page))\n params.set('pageSize', String(PAGE_SIZE))\n params.set('status', status)\n if (search) params.set('search', search)\n return params.toString()\n }, [page, status, search])\n\n const { data, isLoading } = useQuery<CategoriesResponse>({\n queryKey: ['catalog-categories', queryParams, scopeVersion],\n queryFn: async () => {\n const payload = await readApiResultOrThrow<CategoriesResponse>(\n `/api/catalog/categories?${queryParams}`,\n undefined,\n { errorMessage: t('catalog.categories.list.error.load', 'Failed to load categories') },\n )\n return {\n items: Array.isArray(payload.items) ? payload.items : [],\n total: typeof payload.total === 'number' ? payload.total : 0,\n page: typeof payload.page === 'number' ? payload.page : 1,\n pageSize: typeof payload.pageSize === 'number' ? payload.pageSize : PAGE_SIZE,\n totalPages: typeof payload.totalPages === 'number' ? payload.totalPages : 1,\n }\n },\n })\n\n const rows = data?.items ?? []\n const total = data?.total ?? 0\n const totalPages = data?.totalPages ?? 1\n\n const columns = React.useMemo<ColumnDef<CategoryRow>[]>(() => [\n {\n accessorKey: 'name',\n header: t('catalog.categories.list.columns.category', 'Category'),\n meta: { priority: 1 },\n cell: ({ row }) => {\n const depth = row.original.depth ?? 0\n return (\n <div className=\"flex items-center text-sm font-medium leading-none text-foreground\">\n <span style={{ marginLeft: computeIndent(depth), whiteSpace: 'pre' }}>\n {formatCategoryTreeLabel(row.original.name, depth)}\n </span>\n </div>\n )\n },\n },\n {\n accessorKey: 'pathLabel',\n header: t('catalog.categories.list.columns.path', 'Path'),\n meta: { priority: 3 },\n cell: ({ getValue }) => {\n const value = getValue<string>()\n return <span className=\"text-xs text-muted-foreground\">{value || '\u2014'}</span>\n },\n },\n {\n accessorKey: 'parentName',\n header: t('catalog.categories.list.columns.parent', 'Parent'),\n meta: { priority: 4 },\n cell: ({ getValue }) => getValue<string>() || t('catalog.categories.list.none', '\u2014'),\n },\n {\n accessorKey: 'childCount',\n header: t('catalog.categories.list.columns.children', 'Children'),\n meta: { priority: 5 },\n },\n {\n accessorKey: 'isActive',\n header: t('catalog.categories.list.columns.active', 'Active'),\n enableSorting: false,\n meta: { priority: 2 },\n cell: ({ getValue }) => <BooleanIcon value={Boolean(getValue())} />,\n },\n ], [t])\n\n const handleDelete = React.useCallback(async (category: CategoryRow) => {\n const confirmLabel = t(\n 'catalog.categories.list.confirmDelete',\n 'Archive category \"{{name}}\"?',\n { name: category.name },\n )\n if (!window.confirm(confirmLabel)) return\n try {\n await apiCallOrThrow(\n `/api/catalog/categories?id=${encodeURIComponent(category.id)}`,\n { method: 'DELETE' },\n { errorMessage: t('catalog.categories.list.error.delete', 'Failed to delete category') },\n )\n await queryClient.invalidateQueries({ queryKey: ['catalog-categories'] })\n flash(t('catalog.categories.flash.deleted', 'Category archived'), 'success')\n } catch (err: unknown) {\n const fallback = t('catalog.categories.list.error.delete', 'Failed to delete category')\n const message = err instanceof Error ? err.message : fallback\n flash(message, 'error')\n }\n }, [queryClient, t])\n\n return (\n <DataTable\n title={t('catalog.categories.list.title', 'Categories')}\n actions={canManage ? (\n <Button asChild>\n <Link href=\"/backend/catalog/categories/create\">\n {t('catalog.categories.list.actions.create', 'Create')}\n </Link>\n </Button>\n ) : undefined}\n columns={columns}\n data={rows}\n searchValue={search}\n searchPlaceholder={t('catalog.categories.list.searchPlaceholder', 'Search categories')}\n onSearchChange={(value) => { setSearch(value); setPage(1) }}\n filters={[\n {\n id: 'status',\n label: t('catalog.categories.list.filters.status', 'Status'),\n type: 'select',\n options: [\n { value: 'all', label: t('catalog.categories.list.filters.all', 'All') },\n { value: 'active', label: t('catalog.categories.list.filters.active', 'Active') },\n { value: 'inactive', label: t('catalog.categories.list.filters.inactive', 'Inactive') },\n ],\n },\n ]}\n filterValues={status === 'all' ? {} : { status }}\n onFiltersApply={(values: FilterValues) => {\n const nextStatus = (values.status as 'all' | 'active' | 'inactive' | undefined) ?? 'all'\n setStatus(nextStatus)\n setPage(1)\n }}\n onFiltersClear={() => {\n setStatus('all')\n setPage(1)\n }}\n sortable={false}\n perspective={{ tableId: 'catalog.categories.list' }}\n rowActions={(row) => (\n canManage ? (\n <RowActions\n items={[\n { label: t('catalog.categories.list.actions.edit', 'Edit'), href: `/backend/catalog/categories/${row.id}/edit` },\n { label: t('catalog.categories.list.actions.delete', 'Delete'), destructive: true, onSelect: () => handleDelete(row) },\n ]}\n />\n ) : null\n )}\n pagination={{\n page,\n pageSize: PAGE_SIZE,\n total,\n totalPages,\n onPageChange: setPage,\n }}\n isLoading={isLoading}\n />\n )\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -509,12 +509,10 @@ function ProductsDataTable() {
509
509
  {
510
510
  items: [
511
511
  {
512
- id: "edit",
513
512
  label: t("catalog.products.table.actions.edit", "Edit"),
514
513
  href: `/backend/catalog/products/${row.id}`
515
514
  },
516
515
  {
517
- id: "delete",
518
516
  label: t("catalog.products.table.actions.delete", "Delete"),
519
517
  destructive: true,
520
518
  onSelect: () => {