@open-mercato/core 0.6.8-develop.6924.1.a8d208fcdc → 0.6.8-develop.6930.1.1e5976efc3

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 (453) hide show
  1. package/.turbo/turbo-build.log +2 -2
  2. package/dist/generated/entities/eudr_due_diligence_statement/index.js +47 -0
  3. package/dist/generated/entities/eudr_due_diligence_statement/index.js.map +7 -0
  4. package/dist/generated/entities/eudr_evidence_submission/index.js +51 -0
  5. package/dist/generated/entities/eudr_evidence_submission/index.js.map +7 -0
  6. package/dist/generated/entities/eudr_mitigation_action/index.js +31 -0
  7. package/dist/generated/entities/eudr_mitigation_action/index.js.map +7 -0
  8. package/dist/generated/entities/eudr_plot/index.js +39 -0
  9. package/dist/generated/entities/eudr_plot/index.js.map +7 -0
  10. package/dist/generated/entities/eudr_product_mapping/index.js +31 -0
  11. package/dist/generated/entities/eudr_product_mapping/index.js.map +7 -0
  12. package/dist/generated/entities/eudr_risk_assessment/index.js +35 -0
  13. package/dist/generated/entities/eudr_risk_assessment/index.js.map +7 -0
  14. package/dist/generated/entities/role/index.js +2 -0
  15. package/dist/generated/entities/role/index.js.map +2 -2
  16. package/dist/generated/entities.ids.generated.js +9 -0
  17. package/dist/generated/entities.ids.generated.js.map +2 -2
  18. package/dist/generated/entity-fields-registry.js +121 -0
  19. package/dist/generated/entity-fields-registry.js.map +2 -2
  20. package/dist/helpers/integration/api.js +4 -0
  21. package/dist/helpers/integration/api.js.map +2 -2
  22. package/dist/modules/attachments/fields/attachment.js +5 -1
  23. package/dist/modules/attachments/fields/attachment.js.map +2 -2
  24. package/dist/modules/attachments/lib/crud.js +3 -1
  25. package/dist/modules/attachments/lib/crud.js.map +2 -2
  26. package/dist/modules/audit_logs/api/audit-logs/actions/redo/route.js +5 -0
  27. package/dist/modules/audit_logs/api/audit-logs/actions/redo/route.js.map +2 -2
  28. package/dist/modules/audit_logs/api/audit-logs/actions/undo/route.js +5 -0
  29. package/dist/modules/audit_logs/api/audit-logs/actions/undo/route.js.map +2 -2
  30. package/dist/modules/audit_logs/backend/audit-logs/page.js +4 -4
  31. package/dist/modules/audit_logs/backend/audit-logs/page.js.map +2 -2
  32. package/dist/modules/audit_logs/components/AuditLogsActions.js +9 -2
  33. package/dist/modules/audit_logs/components/AuditLogsActions.js.map +2 -2
  34. package/dist/modules/auth/api/login.js +5 -2
  35. package/dist/modules/auth/api/login.js.map +2 -2
  36. package/dist/modules/auth/api/users/route.js +8 -5
  37. package/dist/modules/auth/api/users/route.js.map +2 -2
  38. package/dist/modules/auth/backend/users/[id]/edit/page.js +15 -1
  39. package/dist/modules/auth/backend/users/[id]/edit/page.js.map +2 -2
  40. package/dist/modules/auth/backend/users/page.js +7 -1
  41. package/dist/modules/auth/backend/users/page.js.map +2 -2
  42. package/dist/modules/auth/commands/users.js +175 -76
  43. package/dist/modules/auth/commands/users.js.map +2 -2
  44. package/dist/modules/auth/data/entities.js +4 -0
  45. package/dist/modules/auth/data/entities.js.map +2 -2
  46. package/dist/modules/auth/lib/sessionIntegrity.js +1 -1
  47. package/dist/modules/auth/lib/sessionIntegrity.js.map +2 -2
  48. package/dist/modules/auth/lib/setup-app.js +1 -1
  49. package/dist/modules/auth/lib/setup-app.js.map +2 -2
  50. package/dist/modules/auth/migrations/Migration20260728134212_auth.js +14 -0
  51. package/dist/modules/auth/migrations/Migration20260728134212_auth.js.map +7 -0
  52. package/dist/modules/eudr/acl.js +43 -0
  53. package/dist/modules/eudr/acl.js.map +7 -0
  54. package/dist/modules/eudr/ai-agents.js +205 -0
  55. package/dist/modules/eudr/ai-agents.js.map +7 -0
  56. package/dist/modules/eudr/ai-tools/compliance-pack.js +495 -0
  57. package/dist/modules/eudr/ai-tools/compliance-pack.js.map +7 -0
  58. package/dist/modules/eudr/ai-tools/types.js +10 -0
  59. package/dist/modules/eudr/ai-tools/types.js.map +7 -0
  60. package/dist/modules/eudr/ai-tools.js +10 -0
  61. package/dist/modules/eudr/ai-tools.js.map +7 -0
  62. package/dist/modules/eudr/api/dashboard/widgets/compliance-overview/route.js +386 -0
  63. package/dist/modules/eudr/api/dashboard/widgets/compliance-overview/route.js.map +7 -0
  64. package/dist/modules/eudr/api/evidence-submissions/route.js +318 -0
  65. package/dist/modules/eudr/api/evidence-submissions/route.js.map +7 -0
  66. package/dist/modules/eudr/api/mitigation-actions/route.js +249 -0
  67. package/dist/modules/eudr/api/mitigation-actions/route.js.map +7 -0
  68. package/dist/modules/eudr/api/openapi.js +27 -0
  69. package/dist/modules/eudr/api/openapi.js.map +7 -0
  70. package/dist/modules/eudr/api/plots/import/route.js +294 -0
  71. package/dist/modules/eudr/api/plots/import/route.js.map +7 -0
  72. package/dist/modules/eudr/api/plots/route.js +279 -0
  73. package/dist/modules/eudr/api/plots/route.js.map +7 -0
  74. package/dist/modules/eudr/api/product-mappings/route.js +257 -0
  75. package/dist/modules/eudr/api/product-mappings/route.js.map +7 -0
  76. package/dist/modules/eudr/api/product-mappings/suggestions/apply/route.js +298 -0
  77. package/dist/modules/eudr/api/product-mappings/suggestions/apply/route.js.map +7 -0
  78. package/dist/modules/eudr/api/product-mappings/suggestions/route.js +132 -0
  79. package/dist/modules/eudr/api/product-mappings/suggestions/route.js.map +7 -0
  80. package/dist/modules/eudr/api/reports/annual/route.js +266 -0
  81. package/dist/modules/eudr/api/reports/annual/route.js.map +7 -0
  82. package/dist/modules/eudr/api/risk-assessments/route.js +300 -0
  83. package/dist/modules/eudr/api/risk-assessments/route.js.map +7 -0
  84. package/dist/modules/eudr/api/statements/[id]/export/route.js +631 -0
  85. package/dist/modules/eudr/api/statements/[id]/export/route.js.map +7 -0
  86. package/dist/modules/eudr/api/statements/[id]/readiness/route.js +111 -0
  87. package/dist/modules/eudr/api/statements/[id]/readiness/route.js.map +7 -0
  88. package/dist/modules/eudr/api/statements/route.js +314 -0
  89. package/dist/modules/eudr/api/statements/route.js.map +7 -0
  90. package/dist/modules/eudr/api/suppliers/compliance/route.js +173 -0
  91. package/dist/modules/eudr/api/suppliers/compliance/route.js.map +7 -0
  92. package/dist/modules/eudr/backend/eudr/evidence-submissions/[id]/page.js +468 -0
  93. package/dist/modules/eudr/backend/eudr/evidence-submissions/[id]/page.js.map +7 -0
  94. package/dist/modules/eudr/backend/eudr/evidence-submissions/[id]/page.meta.js +16 -0
  95. package/dist/modules/eudr/backend/eudr/evidence-submissions/[id]/page.meta.js.map +7 -0
  96. package/dist/modules/eudr/backend/eudr/evidence-submissions/create/page.js +351 -0
  97. package/dist/modules/eudr/backend/eudr/evidence-submissions/create/page.js.map +7 -0
  98. package/dist/modules/eudr/backend/eudr/evidence-submissions/create/page.meta.js +17 -0
  99. package/dist/modules/eudr/backend/eudr/evidence-submissions/create/page.meta.js.map +7 -0
  100. package/dist/modules/eudr/backend/eudr/evidence-submissions/page.js +313 -0
  101. package/dist/modules/eudr/backend/eudr/evidence-submissions/page.js.map +7 -0
  102. package/dist/modules/eudr/backend/eudr/evidence-submissions/page.meta.js +16 -0
  103. package/dist/modules/eudr/backend/eudr/evidence-submissions/page.meta.js.map +7 -0
  104. package/dist/modules/eudr/backend/eudr/page.js +360 -0
  105. package/dist/modules/eudr/backend/eudr/page.js.map +7 -0
  106. package/dist/modules/eudr/backend/eudr/page.meta.js +16 -0
  107. package/dist/modules/eudr/backend/eudr/page.meta.js.map +7 -0
  108. package/dist/modules/eudr/backend/eudr/plots/[id]/page.js +346 -0
  109. package/dist/modules/eudr/backend/eudr/plots/[id]/page.js.map +7 -0
  110. package/dist/modules/eudr/backend/eudr/plots/[id]/page.meta.js +16 -0
  111. package/dist/modules/eudr/backend/eudr/plots/[id]/page.meta.js.map +7 -0
  112. package/dist/modules/eudr/backend/eudr/plots/create/page.js +253 -0
  113. package/dist/modules/eudr/backend/eudr/plots/create/page.js.map +7 -0
  114. package/dist/modules/eudr/backend/eudr/plots/create/page.meta.js +17 -0
  115. package/dist/modules/eudr/backend/eudr/plots/create/page.meta.js.map +7 -0
  116. package/dist/modules/eudr/backend/eudr/plots/page.js +386 -0
  117. package/dist/modules/eudr/backend/eudr/plots/page.js.map +7 -0
  118. package/dist/modules/eudr/backend/eudr/plots/page.meta.js +16 -0
  119. package/dist/modules/eudr/backend/eudr/plots/page.meta.js.map +7 -0
  120. package/dist/modules/eudr/backend/eudr/product-mappings/[id]/page.js +253 -0
  121. package/dist/modules/eudr/backend/eudr/product-mappings/[id]/page.js.map +7 -0
  122. package/dist/modules/eudr/backend/eudr/product-mappings/[id]/page.meta.js +16 -0
  123. package/dist/modules/eudr/backend/eudr/product-mappings/[id]/page.meta.js.map +7 -0
  124. package/dist/modules/eudr/backend/eudr/product-mappings/create/page.js +174 -0
  125. package/dist/modules/eudr/backend/eudr/product-mappings/create/page.js.map +7 -0
  126. package/dist/modules/eudr/backend/eudr/product-mappings/create/page.meta.js +17 -0
  127. package/dist/modules/eudr/backend/eudr/product-mappings/create/page.meta.js.map +7 -0
  128. package/dist/modules/eudr/backend/eudr/product-mappings/page.js +306 -0
  129. package/dist/modules/eudr/backend/eudr/product-mappings/page.js.map +7 -0
  130. package/dist/modules/eudr/backend/eudr/product-mappings/page.meta.js +16 -0
  131. package/dist/modules/eudr/backend/eudr/product-mappings/page.meta.js.map +7 -0
  132. package/dist/modules/eudr/backend/eudr/risk-assessments/[id]/page.js +335 -0
  133. package/dist/modules/eudr/backend/eudr/risk-assessments/[id]/page.js.map +7 -0
  134. package/dist/modules/eudr/backend/eudr/risk-assessments/[id]/page.meta.js +16 -0
  135. package/dist/modules/eudr/backend/eudr/risk-assessments/[id]/page.meta.js.map +7 -0
  136. package/dist/modules/eudr/backend/eudr/risk-assessments/create/page.js +220 -0
  137. package/dist/modules/eudr/backend/eudr/risk-assessments/create/page.js.map +7 -0
  138. package/dist/modules/eudr/backend/eudr/risk-assessments/create/page.meta.js +17 -0
  139. package/dist/modules/eudr/backend/eudr/risk-assessments/create/page.meta.js.map +7 -0
  140. package/dist/modules/eudr/backend/eudr/risk-assessments/page.js +324 -0
  141. package/dist/modules/eudr/backend/eudr/risk-assessments/page.js.map +7 -0
  142. package/dist/modules/eudr/backend/eudr/risk-assessments/page.meta.js +16 -0
  143. package/dist/modules/eudr/backend/eudr/risk-assessments/page.meta.js.map +7 -0
  144. package/dist/modules/eudr/backend/eudr/statements/[id]/page.js +648 -0
  145. package/dist/modules/eudr/backend/eudr/statements/[id]/page.js.map +7 -0
  146. package/dist/modules/eudr/backend/eudr/statements/[id]/page.meta.js +16 -0
  147. package/dist/modules/eudr/backend/eudr/statements/[id]/page.meta.js.map +7 -0
  148. package/dist/modules/eudr/backend/eudr/statements/create/page.js +432 -0
  149. package/dist/modules/eudr/backend/eudr/statements/create/page.js.map +7 -0
  150. package/dist/modules/eudr/backend/eudr/statements/create/page.meta.js +17 -0
  151. package/dist/modules/eudr/backend/eudr/statements/create/page.meta.js.map +7 -0
  152. package/dist/modules/eudr/backend/eudr/statements/page.js +309 -0
  153. package/dist/modules/eudr/backend/eudr/statements/page.js.map +7 -0
  154. package/dist/modules/eudr/backend/eudr/statements/page.meta.js +16 -0
  155. package/dist/modules/eudr/backend/eudr/statements/page.meta.js.map +7 -0
  156. package/dist/modules/eudr/ce.js +56 -0
  157. package/dist/modules/eudr/ce.js.map +7 -0
  158. package/dist/modules/eudr/commands/evidence-submissions.js +571 -0
  159. package/dist/modules/eudr/commands/evidence-submissions.js.map +7 -0
  160. package/dist/modules/eudr/commands/index.js +7 -0
  161. package/dist/modules/eudr/commands/index.js.map +7 -0
  162. package/dist/modules/eudr/commands/lifecycle-events.js +19 -0
  163. package/dist/modules/eudr/commands/lifecycle-events.js.map +7 -0
  164. package/dist/modules/eudr/commands/mitigation-actions.js +488 -0
  165. package/dist/modules/eudr/commands/mitigation-actions.js.map +7 -0
  166. package/dist/modules/eudr/commands/plots.js +517 -0
  167. package/dist/modules/eudr/commands/plots.js.map +7 -0
  168. package/dist/modules/eudr/commands/product-mappings.js +468 -0
  169. package/dist/modules/eudr/commands/product-mappings.js.map +7 -0
  170. package/dist/modules/eudr/commands/risk-assessments.js +599 -0
  171. package/dist/modules/eudr/commands/risk-assessments.js.map +7 -0
  172. package/dist/modules/eudr/commands/statements.js +747 -0
  173. package/dist/modules/eudr/commands/statements.js.map +7 -0
  174. package/dist/modules/eudr/components/CountrySelectField.js +64 -0
  175. package/dist/modules/eudr/components/CountrySelectField.js.map +7 -0
  176. package/dist/modules/eudr/components/GeometryInput.js +133 -0
  177. package/dist/modules/eudr/components/GeometryInput.js.map +7 -0
  178. package/dist/modules/eudr/components/MappingSuggestionsDialog.js +307 -0
  179. package/dist/modules/eudr/components/MappingSuggestionsDialog.js.map +7 -0
  180. package/dist/modules/eudr/components/MitigationActionsSection.js +345 -0
  181. package/dist/modules/eudr/components/MitigationActionsSection.js.map +7 -0
  182. package/dist/modules/eudr/components/OrderSelectField.js +88 -0
  183. package/dist/modules/eudr/components/OrderSelectField.js.map +7 -0
  184. package/dist/modules/eudr/components/PlotImportDialog.js +229 -0
  185. package/dist/modules/eudr/components/PlotImportDialog.js.map +7 -0
  186. package/dist/modules/eudr/components/PlotMapPreview.js +35 -0
  187. package/dist/modules/eudr/components/PlotMapPreview.js.map +7 -0
  188. package/dist/modules/eudr/components/PlotMapPreviewImpl.js +97 -0
  189. package/dist/modules/eudr/components/PlotMapPreviewImpl.js.map +7 -0
  190. package/dist/modules/eudr/components/PlotMultiSelectField.js +198 -0
  191. package/dist/modules/eudr/components/PlotMultiSelectField.js.map +7 -0
  192. package/dist/modules/eudr/components/RiskCriteriaField.js +128 -0
  193. package/dist/modules/eudr/components/RiskCriteriaField.js.map +7 -0
  194. package/dist/modules/eudr/components/StatementLifecycleBar.js +274 -0
  195. package/dist/modules/eudr/components/StatementLifecycleBar.js.map +7 -0
  196. package/dist/modules/eudr/components/StatementReadinessChecklist.js +56 -0
  197. package/dist/modules/eudr/components/StatementReadinessChecklist.js.map +7 -0
  198. package/dist/modules/eudr/components/StatementRiskSection.js +179 -0
  199. package/dist/modules/eudr/components/StatementRiskSection.js.map +7 -0
  200. package/dist/modules/eudr/components/crudErrorI18n.js +31 -0
  201. package/dist/modules/eudr/components/crudErrorI18n.js.map +7 -0
  202. package/dist/modules/eudr/components/formConfig.js +593 -0
  203. package/dist/modules/eudr/components/formConfig.js.map +7 -0
  204. package/dist/modules/eudr/components/plotForm.js +68 -0
  205. package/dist/modules/eudr/components/plotForm.js.map +7 -0
  206. package/dist/modules/eudr/data/enrichers.js +62 -0
  207. package/dist/modules/eudr/data/enrichers.js.map +7 -0
  208. package/dist/modules/eudr/data/entities.js +437 -0
  209. package/dist/modules/eudr/data/entities.js.map +7 -0
  210. package/dist/modules/eudr/data/validators.js +271 -0
  211. package/dist/modules/eudr/data/validators.js.map +7 -0
  212. package/dist/modules/eudr/encryption.js +33 -0
  213. package/dist/modules/eudr/encryption.js.map +7 -0
  214. package/dist/modules/eudr/events.js +38 -0
  215. package/dist/modules/eudr/events.js.map +7 -0
  216. package/dist/modules/eudr/index.js +15 -0
  217. package/dist/modules/eudr/index.js.map +7 -0
  218. package/dist/modules/eudr/lib/annual-report.js +104 -0
  219. package/dist/modules/eudr/lib/annual-report.js.map +7 -0
  220. package/dist/modules/eudr/lib/completeness.js +64 -0
  221. package/dist/modules/eudr/lib/completeness.js.map +7 -0
  222. package/dist/modules/eudr/lib/detail-read-scope.js +16 -0
  223. package/dist/modules/eudr/lib/detail-read-scope.js.map +7 -0
  224. package/dist/modules/eudr/lib/geometry.js +142 -0
  225. package/dist/modules/eudr/lib/geometry.js.map +7 -0
  226. package/dist/modules/eudr/lib/notifications.js +56 -0
  227. package/dist/modules/eudr/lib/notifications.js.map +7 -0
  228. package/dist/modules/eudr/lib/plural.js +26 -0
  229. package/dist/modules/eudr/lib/plural.js.map +7 -0
  230. package/dist/modules/eudr/lib/reference-data.js +240 -0
  231. package/dist/modules/eudr/lib/reference-data.js.map +7 -0
  232. package/dist/modules/eudr/lib/species.js +10 -0
  233. package/dist/modules/eudr/lib/species.js.map +7 -0
  234. package/dist/modules/eudr/lib/statement-lifecycle.js +84 -0
  235. package/dist/modules/eudr/lib/statement-lifecycle.js.map +7 -0
  236. package/dist/modules/eudr/lib/statement-seeding.js +49 -0
  237. package/dist/modules/eudr/lib/statement-seeding.js.map +7 -0
  238. package/dist/modules/eudr/migrations/Migration20260706102002_eudr.js +15 -0
  239. package/dist/modules/eudr/migrations/Migration20260706102002_eudr.js.map +7 -0
  240. package/dist/modules/eudr/migrations/Migration20260706152612_eudr.js +24 -0
  241. package/dist/modules/eudr/migrations/Migration20260706152612_eudr.js.map +7 -0
  242. package/dist/modules/eudr/migrations/Migration20260722100000_eudr.js +15 -0
  243. package/dist/modules/eudr/migrations/Migration20260722100000_eudr.js.map +7 -0
  244. package/dist/modules/eudr/notifications.js +58 -0
  245. package/dist/modules/eudr/notifications.js.map +7 -0
  246. package/dist/modules/eudr/search.js +186 -0
  247. package/dist/modules/eudr/search.js.map +7 -0
  248. package/dist/modules/eudr/setup.js +12 -0
  249. package/dist/modules/eudr/setup.js.map +7 -0
  250. package/dist/modules/eudr/subscribers/notify-mitigation-completed.js +34 -0
  251. package/dist/modules/eudr/subscribers/notify-mitigation-completed.js.map +7 -0
  252. package/dist/modules/eudr/subscribers/notify-risk-concluded.js +35 -0
  253. package/dist/modules/eudr/subscribers/notify-risk-concluded.js.map +7 -0
  254. package/dist/modules/eudr/subscribers/notify-statement-reference-issued.js +37 -0
  255. package/dist/modules/eudr/subscribers/notify-statement-reference-issued.js.map +7 -0
  256. package/dist/modules/eudr/subscribers/notify-statement-submitted.js +34 -0
  257. package/dist/modules/eudr/subscribers/notify-statement-submitted.js.map +7 -0
  258. package/dist/modules/eudr/subscribers/notify-statement-withdrawn.js +34 -0
  259. package/dist/modules/eudr/subscribers/notify-statement-withdrawn.js.map +7 -0
  260. package/dist/modules/eudr/subscribers/recompute-completeness-on-attachment-created.js +124 -0
  261. package/dist/modules/eudr/subscribers/recompute-completeness-on-attachment-created.js.map +7 -0
  262. package/dist/modules/eudr/subscribers/recompute-completeness-on-attachment-deleted.js +22 -0
  263. package/dist/modules/eudr/subscribers/recompute-completeness-on-attachment-deleted.js.map +7 -0
  264. package/dist/modules/eudr/widgets/dashboard/compliance-overview/widget.client.js +203 -0
  265. package/dist/modules/eudr/widgets/dashboard/compliance-overview/widget.client.js.map +7 -0
  266. package/dist/modules/eudr/widgets/dashboard/compliance-overview/widget.js +23 -0
  267. package/dist/modules/eudr/widgets/dashboard/compliance-overview/widget.js.map +7 -0
  268. package/dist/modules/eudr/widgets/injection/eudr-product-column/widget.client.js +19 -0
  269. package/dist/modules/eudr/widgets/injection/eudr-product-column/widget.client.js.map +7 -0
  270. package/dist/modules/eudr/widgets/injection/eudr-product-column/widget.js +31 -0
  271. package/dist/modules/eudr/widgets/injection/eudr-product-column/widget.js.map +7 -0
  272. package/dist/modules/eudr/widgets/injection/order-compliance/widget.client.js +100 -0
  273. package/dist/modules/eudr/widgets/injection/order-compliance/widget.client.js.map +7 -0
  274. package/dist/modules/eudr/widgets/injection/order-compliance/widget.js +17 -0
  275. package/dist/modules/eudr/widgets/injection/order-compliance/widget.js.map +7 -0
  276. package/dist/modules/eudr/widgets/injection/supplier-compliance/widget.client.js +116 -0
  277. package/dist/modules/eudr/widgets/injection/supplier-compliance/widget.client.js.map +7 -0
  278. package/dist/modules/eudr/widgets/injection/supplier-compliance/widget.js +17 -0
  279. package/dist/modules/eudr/widgets/injection/supplier-compliance/widget.js.map +7 -0
  280. package/dist/modules/eudr/widgets/injection-table.js +32 -0
  281. package/dist/modules/eudr/widgets/injection-table.js.map +7 -0
  282. package/dist/modules/notifications/lib/notificationService.js +67 -3
  283. package/dist/modules/notifications/lib/notificationService.js.map +2 -2
  284. package/dist/modules/query_index/lib/engine.js +121 -48
  285. package/dist/modules/query_index/lib/engine.js.map +2 -2
  286. package/dist/modules/sales/api/documents/factory.js +17 -0
  287. package/dist/modules/sales/api/documents/factory.js.map +2 -2
  288. package/dist/modules/sales/commands/documents.js +32 -18
  289. package/dist/modules/sales/commands/documents.js.map +2 -2
  290. package/dist/modules/sales/data/entities.js +1 -0
  291. package/dist/modules/sales/data/entities.js.map +2 -2
  292. package/dist/modules/sales/migrations/Migration20260806120000_sales_tag_assignment_document_idx.js +17 -0
  293. package/dist/modules/sales/migrations/Migration20260806120000_sales_tag_assignment_document_idx.js.map +7 -0
  294. package/generated/entities/eudr_due_diligence_statement/index.ts +22 -0
  295. package/generated/entities/eudr_evidence_submission/index.ts +24 -0
  296. package/generated/entities/eudr_mitigation_action/index.ts +14 -0
  297. package/generated/entities/eudr_plot/index.ts +18 -0
  298. package/generated/entities/eudr_product_mapping/index.ts +14 -0
  299. package/generated/entities/eudr_risk_assessment/index.ts +16 -0
  300. package/generated/entities/role/index.ts +1 -0
  301. package/generated/entities.ids.generated.ts +9 -0
  302. package/generated/entity-fields-registry.ts +121 -0
  303. package/package.json +7 -7
  304. package/src/helpers/integration/api.ts +13 -0
  305. package/src/modules/attachments/fields/attachment.tsx +5 -0
  306. package/src/modules/attachments/lib/crud.ts +2 -0
  307. package/src/modules/audit_logs/api/audit-logs/actions/redo/route.ts +7 -0
  308. package/src/modules/audit_logs/api/audit-logs/actions/undo/route.ts +9 -0
  309. package/src/modules/audit_logs/backend/audit-logs/page.tsx +4 -4
  310. package/src/modules/audit_logs/components/AuditLogsActions.tsx +20 -4
  311. package/src/modules/auth/api/login.ts +9 -2
  312. package/src/modules/auth/api/users/route.ts +8 -4
  313. package/src/modules/auth/backend/users/[id]/edit/page.tsx +17 -1
  314. package/src/modules/auth/backend/users/page.tsx +11 -0
  315. package/src/modules/auth/commands/users.ts +251 -85
  316. package/src/modules/auth/data/entities.ts +3 -0
  317. package/src/modules/auth/i18n/de.json +6 -0
  318. package/src/modules/auth/i18n/en.json +6 -0
  319. package/src/modules/auth/i18n/es.json +6 -0
  320. package/src/modules/auth/i18n/ko.json +6 -0
  321. package/src/modules/auth/i18n/pl.json +6 -0
  322. package/src/modules/auth/lib/sessionIntegrity.ts +1 -1
  323. package/src/modules/auth/lib/setup-app.ts +1 -1
  324. package/src/modules/auth/migrations/.snapshot-open-mercato.json +16 -0
  325. package/src/modules/auth/migrations/Migration20260728134212_auth.ts +14 -0
  326. package/src/modules/eudr/acl.ts +39 -0
  327. package/src/modules/eudr/ai-agents.ts +258 -0
  328. package/src/modules/eudr/ai-tools/compliance-pack.ts +618 -0
  329. package/src/modules/eudr/ai-tools/types.ts +44 -0
  330. package/src/modules/eudr/ai-tools.ts +15 -0
  331. package/src/modules/eudr/api/dashboard/widgets/compliance-overview/route.ts +481 -0
  332. package/src/modules/eudr/api/evidence-submissions/route.ts +335 -0
  333. package/src/modules/eudr/api/mitigation-actions/route.ts +263 -0
  334. package/src/modules/eudr/api/openapi.ts +28 -0
  335. package/src/modules/eudr/api/plots/import/route.ts +369 -0
  336. package/src/modules/eudr/api/plots/route.ts +296 -0
  337. package/src/modules/eudr/api/product-mappings/route.ts +269 -0
  338. package/src/modules/eudr/api/product-mappings/suggestions/apply/route.ts +382 -0
  339. package/src/modules/eudr/api/product-mappings/suggestions/route.ts +169 -0
  340. package/src/modules/eudr/api/reports/annual/route.ts +457 -0
  341. package/src/modules/eudr/api/risk-assessments/route.ts +323 -0
  342. package/src/modules/eudr/api/statements/[id]/export/route.ts +713 -0
  343. package/src/modules/eudr/api/statements/[id]/readiness/route.ts +129 -0
  344. package/src/modules/eudr/api/statements/route.ts +329 -0
  345. package/src/modules/eudr/api/suppliers/compliance/route.ts +241 -0
  346. package/src/modules/eudr/backend/eudr/evidence-submissions/[id]/page.meta.ts +12 -0
  347. package/src/modules/eudr/backend/eudr/evidence-submissions/[id]/page.tsx +545 -0
  348. package/src/modules/eudr/backend/eudr/evidence-submissions/create/page.meta.ts +13 -0
  349. package/src/modules/eudr/backend/eudr/evidence-submissions/create/page.tsx +383 -0
  350. package/src/modules/eudr/backend/eudr/evidence-submissions/page.meta.ts +12 -0
  351. package/src/modules/eudr/backend/eudr/evidence-submissions/page.tsx +379 -0
  352. package/src/modules/eudr/backend/eudr/page.meta.ts +12 -0
  353. package/src/modules/eudr/backend/eudr/page.tsx +477 -0
  354. package/src/modules/eudr/backend/eudr/plots/[id]/page.meta.ts +12 -0
  355. package/src/modules/eudr/backend/eudr/plots/[id]/page.tsx +404 -0
  356. package/src/modules/eudr/backend/eudr/plots/create/page.meta.ts +13 -0
  357. package/src/modules/eudr/backend/eudr/plots/create/page.tsx +267 -0
  358. package/src/modules/eudr/backend/eudr/plots/page.meta.ts +12 -0
  359. package/src/modules/eudr/backend/eudr/plots/page.tsx +442 -0
  360. package/src/modules/eudr/backend/eudr/product-mappings/[id]/page.meta.ts +12 -0
  361. package/src/modules/eudr/backend/eudr/product-mappings/[id]/page.tsx +311 -0
  362. package/src/modules/eudr/backend/eudr/product-mappings/create/page.meta.ts +13 -0
  363. package/src/modules/eudr/backend/eudr/product-mappings/create/page.tsx +190 -0
  364. package/src/modules/eudr/backend/eudr/product-mappings/page.meta.ts +12 -0
  365. package/src/modules/eudr/backend/eudr/product-mappings/page.tsx +344 -0
  366. package/src/modules/eudr/backend/eudr/risk-assessments/[id]/page.meta.ts +12 -0
  367. package/src/modules/eudr/backend/eudr/risk-assessments/[id]/page.tsx +421 -0
  368. package/src/modules/eudr/backend/eudr/risk-assessments/create/page.meta.ts +13 -0
  369. package/src/modules/eudr/backend/eudr/risk-assessments/create/page.tsx +247 -0
  370. package/src/modules/eudr/backend/eudr/risk-assessments/page.meta.ts +12 -0
  371. package/src/modules/eudr/backend/eudr/risk-assessments/page.tsx +383 -0
  372. package/src/modules/eudr/backend/eudr/statements/[id]/page.meta.ts +12 -0
  373. package/src/modules/eudr/backend/eudr/statements/[id]/page.tsx +777 -0
  374. package/src/modules/eudr/backend/eudr/statements/create/page.meta.ts +13 -0
  375. package/src/modules/eudr/backend/eudr/statements/create/page.tsx +511 -0
  376. package/src/modules/eudr/backend/eudr/statements/page.meta.ts +12 -0
  377. package/src/modules/eudr/backend/eudr/statements/page.tsx +372 -0
  378. package/src/modules/eudr/ce.ts +52 -0
  379. package/src/modules/eudr/commands/evidence-submissions.ts +699 -0
  380. package/src/modules/eudr/commands/index.ts +6 -0
  381. package/src/modules/eudr/commands/lifecycle-events.ts +28 -0
  382. package/src/modules/eudr/commands/mitigation-actions.ts +574 -0
  383. package/src/modules/eudr/commands/plots.ts +627 -0
  384. package/src/modules/eudr/commands/product-mappings.ts +556 -0
  385. package/src/modules/eudr/commands/risk-assessments.ts +728 -0
  386. package/src/modules/eudr/commands/statements.ts +933 -0
  387. package/src/modules/eudr/components/CountrySelectField.tsx +77 -0
  388. package/src/modules/eudr/components/GeometryInput.tsx +170 -0
  389. package/src/modules/eudr/components/MappingSuggestionsDialog.tsx +385 -0
  390. package/src/modules/eudr/components/MitigationActionsSection.tsx +417 -0
  391. package/src/modules/eudr/components/OrderSelectField.tsx +116 -0
  392. package/src/modules/eudr/components/PlotImportDialog.tsx +277 -0
  393. package/src/modules/eudr/components/PlotMapPreview.tsx +46 -0
  394. package/src/modules/eudr/components/PlotMapPreviewImpl.tsx +111 -0
  395. package/src/modules/eudr/components/PlotMultiSelectField.tsx +238 -0
  396. package/src/modules/eudr/components/RiskCriteriaField.tsx +173 -0
  397. package/src/modules/eudr/components/StatementLifecycleBar.tsx +363 -0
  398. package/src/modules/eudr/components/StatementReadinessChecklist.tsx +82 -0
  399. package/src/modules/eudr/components/StatementRiskSection.tsx +242 -0
  400. package/src/modules/eudr/components/crudErrorI18n.ts +36 -0
  401. package/src/modules/eudr/components/formConfig.tsx +717 -0
  402. package/src/modules/eudr/components/plotForm.ts +75 -0
  403. package/src/modules/eudr/data/enrichers.ts +82 -0
  404. package/src/modules/eudr/data/entities.ts +369 -0
  405. package/src/modules/eudr/data/validators.ts +357 -0
  406. package/src/modules/eudr/encryption.ts +31 -0
  407. package/src/modules/eudr/events.ts +38 -0
  408. package/src/modules/eudr/i18n/de.json +747 -0
  409. package/src/modules/eudr/i18n/en.json +747 -0
  410. package/src/modules/eudr/i18n/es.json +747 -0
  411. package/src/modules/eudr/i18n/ko.json +747 -0
  412. package/src/modules/eudr/i18n/pl.json +747 -0
  413. package/src/modules/eudr/index.ts +13 -0
  414. package/src/modules/eudr/lib/annual-report.ts +120 -0
  415. package/src/modules/eudr/lib/completeness.ts +90 -0
  416. package/src/modules/eudr/lib/detail-read-scope.ts +44 -0
  417. package/src/modules/eudr/lib/geometry.ts +191 -0
  418. package/src/modules/eudr/lib/notifications.ts +85 -0
  419. package/src/modules/eudr/lib/plural.ts +36 -0
  420. package/src/modules/eudr/lib/reference-data.ts +128 -0
  421. package/src/modules/eudr/lib/species.ts +12 -0
  422. package/src/modules/eudr/lib/statement-lifecycle.ts +109 -0
  423. package/src/modules/eudr/lib/statement-seeding.ts +86 -0
  424. package/src/modules/eudr/migrations/.snapshot-open-mercato.json +2046 -0
  425. package/src/modules/eudr/migrations/Migration20260706102002_eudr.ts +16 -0
  426. package/src/modules/eudr/migrations/Migration20260706152612_eudr.ts +30 -0
  427. package/src/modules/eudr/migrations/Migration20260722100000_eudr.ts +17 -0
  428. package/src/modules/eudr/notifications.ts +56 -0
  429. package/src/modules/eudr/search.ts +212 -0
  430. package/src/modules/eudr/setup.ts +10 -0
  431. package/src/modules/eudr/subscribers/notify-mitigation-completed.ts +56 -0
  432. package/src/modules/eudr/subscribers/notify-risk-concluded.ts +58 -0
  433. package/src/modules/eudr/subscribers/notify-statement-reference-issued.ts +59 -0
  434. package/src/modules/eudr/subscribers/notify-statement-submitted.ts +49 -0
  435. package/src/modules/eudr/subscribers/notify-statement-withdrawn.ts +49 -0
  436. package/src/modules/eudr/subscribers/recompute-completeness-on-attachment-created.ts +189 -0
  437. package/src/modules/eudr/subscribers/recompute-completeness-on-attachment-deleted.ts +31 -0
  438. package/src/modules/eudr/widgets/dashboard/compliance-overview/widget.client.tsx +271 -0
  439. package/src/modules/eudr/widgets/dashboard/compliance-overview/widget.ts +24 -0
  440. package/src/modules/eudr/widgets/injection/eudr-product-column/widget.client.tsx +37 -0
  441. package/src/modules/eudr/widgets/injection/eudr-product-column/widget.ts +30 -0
  442. package/src/modules/eudr/widgets/injection/order-compliance/widget.client.tsx +131 -0
  443. package/src/modules/eudr/widgets/injection/order-compliance/widget.ts +16 -0
  444. package/src/modules/eudr/widgets/injection/supplier-compliance/widget.client.tsx +168 -0
  445. package/src/modules/eudr/widgets/injection/supplier-compliance/widget.ts +16 -0
  446. package/src/modules/eudr/widgets/injection-table.ts +31 -0
  447. package/src/modules/notifications/lib/notificationService.ts +83 -4
  448. package/src/modules/query_index/lib/engine.ts +139 -51
  449. package/src/modules/sales/api/documents/factory.ts +29 -0
  450. package/src/modules/sales/commands/documents.ts +65 -18
  451. package/src/modules/sales/data/entities.ts +1 -0
  452. package/src/modules/sales/migrations/.snapshot-open-mercato.json +10 -0
  453. package/src/modules/sales/migrations/Migration20260806120000_sales_tag_assignment_document_idx.ts +59 -0
@@ -0,0 +1,77 @@
1
+ "use client"
2
+
3
+ import * as React from 'react'
4
+ import { useLocale } from '@open-mercato/shared/lib/i18n/context'
5
+ import {
6
+ ISO_COUNTRIES,
7
+ buildCountryOptions,
8
+ resolveCountryName,
9
+ } from '@open-mercato/shared/lib/location/countries'
10
+ import { ComboboxInput, type ComboboxOption } from '@open-mercato/ui/backend/inputs/ComboboxInput'
11
+
12
+ export type CountrySelectFieldProps = {
13
+ id: string
14
+ value: string | null
15
+ onChange: (value: string | null) => void
16
+ disabled?: boolean
17
+ placeholder?: string
18
+ }
19
+
20
+ function formatCountryLabel(code: string, name: string): string {
21
+ return `${name} (${code})`
22
+ }
23
+
24
+ function normalizeCountryCode(value: string): string {
25
+ return value.trim().toUpperCase()
26
+ }
27
+
28
+ export function CountrySelectField({
29
+ id,
30
+ value,
31
+ onChange,
32
+ disabled,
33
+ placeholder,
34
+ }: CountrySelectFieldProps) {
35
+ const locale = useLocale()
36
+ const options = React.useMemo<ComboboxOption[]>(() => {
37
+ return buildCountryOptions({
38
+ locale,
39
+ transformLabel: formatCountryLabel,
40
+ }).map((option) => ({
41
+ value: option.code,
42
+ label: option.label,
43
+ }))
44
+ }, [locale])
45
+
46
+ const knownCodes = React.useMemo(() => new Set(ISO_COUNTRIES.map((country) => country.code)), [])
47
+ const selectedValue = typeof value === 'string' ? normalizeCountryCode(value) : ''
48
+
49
+ const resolveLabel = React.useCallback((code: string) => {
50
+ const normalized = normalizeCountryCode(code)
51
+ const localizedName = knownCodes.has(normalized)
52
+ ? resolveCountryName(normalized, { locale })
53
+ : normalized
54
+ return formatCountryLabel(normalized, localizedName)
55
+ }, [knownCodes, locale])
56
+
57
+ return (
58
+ <div id={id}>
59
+ <ComboboxInput
60
+ value={selectedValue}
61
+ onChange={(nextValue) => {
62
+ const normalized = normalizeCountryCode(nextValue)
63
+ onChange(normalized.length > 0 ? normalized : null)
64
+ }}
65
+ suggestions={options}
66
+ seedOptions={selectedValue ? [{ value: selectedValue, label: resolveLabel(selectedValue) }] : undefined}
67
+ resolveLabel={resolveLabel}
68
+ placeholder={placeholder}
69
+ disabled={disabled}
70
+ allowCustomValues={false}
71
+ clearable
72
+ />
73
+ </div>
74
+ )
75
+ }
76
+
77
+ export default CountrySelectField
@@ -0,0 +1,170 @@
1
+ "use client"
2
+
3
+ import * as React from 'react'
4
+ import { FileJson, Upload } from 'lucide-react'
5
+ import { useT } from '@open-mercato/shared/lib/i18n/context'
6
+ import { Button } from '@open-mercato/ui/primitives/button'
7
+ import { Textarea } from '@open-mercato/ui/primitives/textarea'
8
+ import { validatePlotGeometry, type GeometryValidationResult } from '../lib/geometry'
9
+ import { pointAreaExceedsLimit } from './plotForm'
10
+ import { PlotMapPreview } from './PlotMapPreview'
11
+
12
+ export type GeometryInputProps = {
13
+ id: string
14
+ value: string
15
+ onChange: (value: string) => void
16
+ disabled?: boolean
17
+ areaHa?: string
18
+ }
19
+
20
+ type ParsedGeometryState =
21
+ | { state: 'empty' }
22
+ | { state: 'invalid'; errorKey: string }
23
+ | { state: 'valid'; result: Extract<GeometryValidationResult, { ok: true }> }
24
+
25
+ export async function readJsonFileText(file: File): Promise<string> {
26
+ return file.text()
27
+ }
28
+
29
+ export function parseGeometryText(raw: string): unknown | null {
30
+ const trimmed = raw.trim()
31
+ if (!trimmed) return null
32
+ return JSON.parse(trimmed)
33
+ }
34
+
35
+ function validateGeometryText(raw: string): ParsedGeometryState {
36
+ const trimmed = raw.trim()
37
+ if (!trimmed) return { state: 'empty' }
38
+ let parsed: unknown
39
+ try {
40
+ parsed = JSON.parse(trimmed)
41
+ } catch {
42
+ return { state: 'invalid', errorKey: 'geometryInvalid' }
43
+ }
44
+ const result = validatePlotGeometry(parsed)
45
+ if (!result.ok) return { state: 'invalid', errorKey: result.errorKey }
46
+ return { state: 'valid', result }
47
+ }
48
+
49
+ function formatArea(value: number | null): string {
50
+ if (value === null) return ''
51
+ return new Intl.NumberFormat(undefined, { maximumFractionDigits: 4 }).format(value)
52
+ }
53
+
54
+ export function GeometryInput({
55
+ id,
56
+ value,
57
+ onChange,
58
+ disabled,
59
+ areaHa,
60
+ }: GeometryInputProps) {
61
+ const translate = useT()
62
+ const fileInputRef = React.useRef<HTMLInputElement | null>(null)
63
+ const [showTextarea, setShowTextarea] = React.useState(() => value.trim().length > 0)
64
+ const validation = React.useMemo(() => validateGeometryText(value), [value])
65
+ const pointAreaTooLarge =
66
+ validation.state === 'valid' &&
67
+ pointAreaExceedsLimit(validation.result.plotType, areaHa)
68
+
69
+ React.useEffect(() => {
70
+ if (value.trim().length > 0) setShowTextarea(true)
71
+ }, [value])
72
+
73
+ const handleFile = React.useCallback(async (files: FileList | null) => {
74
+ const file = files?.[0]
75
+ if (!file) return
76
+ const text = await readJsonFileText(file)
77
+ onChange(text)
78
+ }, [onChange])
79
+
80
+ return (
81
+ <div id={id} className="space-y-3">
82
+ <div className="flex flex-wrap items-center gap-2">
83
+ <Button
84
+ type="button"
85
+ variant="outline"
86
+ onClick={() => fileInputRef.current?.click()}
87
+ disabled={disabled}
88
+ >
89
+ <Upload className="size-4" aria-hidden="true" />
90
+ {translate('eudr.plots.geometry.upload')}
91
+ </Button>
92
+ <Button
93
+ type="button"
94
+ variant="outline"
95
+ onClick={() => setShowTextarea((current) => !current)}
96
+ disabled={disabled}
97
+ >
98
+ <FileJson className="size-4" aria-hidden="true" />
99
+ {translate('eudr.plots.geometry.togglePaste')}
100
+ </Button>
101
+ <input
102
+ ref={fileInputRef}
103
+ type="file"
104
+ className="hidden"
105
+ accept=".json,.geojson,application/json,application/geo+json"
106
+ disabled={disabled}
107
+ onChange={(event) => {
108
+ void handleFile(event.target.files)
109
+ event.target.value = ''
110
+ }}
111
+ />
112
+ </div>
113
+
114
+ {showTextarea ? (
115
+ <Textarea
116
+ value={value}
117
+ disabled={disabled}
118
+ rows={10}
119
+ placeholder={translate('eudr.plots.geometry.placeholder')}
120
+ onChange={(event) => onChange(event.target.value)}
121
+ />
122
+ ) : null}
123
+
124
+ {validation.state === 'empty' ? (
125
+ <div className="rounded-md border border-dashed border-border/70 bg-muted/30 px-3 py-2 text-sm text-muted-foreground">
126
+ {translate('eudr.plots.geometry.empty')}
127
+ </div>
128
+ ) : null}
129
+
130
+ {validation.state === 'invalid' ? (
131
+ <div className="rounded-md border border-status-error-border bg-status-error-bg px-3 py-2 text-sm text-status-error-text">
132
+ {translate(`eudr.errors.${validation.errorKey}`)}
133
+ </div>
134
+ ) : null}
135
+
136
+ {validation.state === 'valid' ? (
137
+ <div className="space-y-3">
138
+ {pointAreaTooLarge ? (
139
+ <div className="rounded-md border border-status-error-border bg-status-error-bg px-3 py-2 text-sm text-status-error-text">
140
+ {translate('eudr.errors.polygonRequired')}
141
+ </div>
142
+ ) : (
143
+ <div className="rounded-md border border-status-success-border bg-status-success-bg px-3 py-2 text-sm text-status-success-text">
144
+ <div className="font-medium">
145
+ {translate('eudr.plots.geometry.valid', {
146
+ type: translate(`eudr.plotType.${validation.result.plotType}`),
147
+ })}
148
+ </div>
149
+ {validation.result.computedAreaHa !== null ? (
150
+ <div>
151
+ {translate('eudr.plots.geometry.computedArea', {
152
+ area: formatArea(validation.result.computedAreaHa),
153
+ })}
154
+ </div>
155
+ ) : null}
156
+ {validation.result.warnings.includes('low_precision') ? (
157
+ <div className="mt-1 text-status-warning-text">
158
+ {translate('eudr.errors.low_precision')}
159
+ </div>
160
+ ) : null}
161
+ </div>
162
+ )}
163
+ <PlotMapPreview features={[validation.result.feature]} />
164
+ </div>
165
+ ) : null}
166
+ </div>
167
+ )
168
+ }
169
+
170
+ export default GeometryInput
@@ -0,0 +1,385 @@
1
+ "use client"
2
+
3
+ import * as React from 'react'
4
+ import type { LegacyColumnDef as ColumnDef } from '@tanstack/react-table/legacy'
5
+ import { useT } from '@open-mercato/shared/lib/i18n/context'
6
+ import { DataTable } from '@open-mercato/ui/backend/DataTable'
7
+ import { EmptyState } from '@open-mercato/ui/backend/EmptyState'
8
+ import { flash } from '@open-mercato/ui/backend/FlashMessages'
9
+ import { useGuardedMutation } from '@open-mercato/ui/backend/injection/useGuardedMutation'
10
+ import { ErrorMessage, LoadingMessage } from '@open-mercato/ui/backend/detail'
11
+ import { apiCall, apiCallOrThrow } from '@open-mercato/ui/backend/utils/apiCall'
12
+ import { Button } from '@open-mercato/ui/primitives/button'
13
+ import { Checkbox } from '@open-mercato/ui/primitives/checkbox'
14
+ import {
15
+ Dialog,
16
+ DialogContent,
17
+ DialogFooter,
18
+ DialogHeader,
19
+ DialogTitle,
20
+ } from '@open-mercato/ui/primitives/dialog'
21
+ import { Tag } from '@open-mercato/ui/primitives/tag'
22
+ import {
23
+ EUDR_COMMODITIES,
24
+ type EudrCommodity,
25
+ } from '../data/validators'
26
+
27
+ type MappingSuggestion = {
28
+ productId: string
29
+ name: string
30
+ sku: string | null
31
+ hsCode: string
32
+ suggestedCommodity: EudrCommodity
33
+ }
34
+
35
+ type SuggestionsResponse = {
36
+ items: MappingSuggestion[]
37
+ }
38
+
39
+ type ApplyResponse = {
40
+ created: number
41
+ failed: Array<{ productId: string; errorKey: string }>
42
+ }
43
+
44
+ type ApplyItem = {
45
+ productId: string
46
+ commodity: EudrCommodity
47
+ hsCode: string
48
+ }
49
+
50
+ type MappingSuggestionsDialogProps = {
51
+ open: boolean
52
+ onOpenChange: (open: boolean) => void
53
+ onApplied?: () => void
54
+ }
55
+
56
+ const commoditySet = new Set<string>(EUDR_COMMODITIES)
57
+
58
+ function isRecord(value: unknown): value is Record<string, unknown> {
59
+ return value !== null && typeof value === 'object' && !Array.isArray(value)
60
+ }
61
+
62
+ function isEudrCommodity(value: unknown): value is EudrCommodity {
63
+ return typeof value === 'string' && commoditySet.has(value)
64
+ }
65
+
66
+ function normalizeSuggestion(value: unknown): MappingSuggestion | null {
67
+ if (!isRecord(value)) return null
68
+ const { productId, name, sku, hsCode, suggestedCommodity } = value
69
+ if (
70
+ typeof productId !== 'string'
71
+ || typeof name !== 'string'
72
+ || typeof hsCode !== 'string'
73
+ || !isEudrCommodity(suggestedCommodity)
74
+ ) {
75
+ return null
76
+ }
77
+ return {
78
+ productId,
79
+ name,
80
+ sku: typeof sku === 'string' ? sku : null,
81
+ hsCode,
82
+ suggestedCommodity,
83
+ }
84
+ }
85
+
86
+ function normalizeSuggestionsResponse(value: SuggestionsResponse | null): MappingSuggestion[] {
87
+ const rawItems = Array.isArray((value as { items?: unknown[] } | null)?.items)
88
+ ? (value as { items: unknown[] }).items
89
+ : []
90
+ return rawItems
91
+ .map(normalizeSuggestion)
92
+ .filter((item): item is MappingSuggestion => item !== null)
93
+ }
94
+
95
+ function formatProductLabel(item: MappingSuggestion): string {
96
+ return item.sku ? `${item.name} (${item.sku})` : item.name
97
+ }
98
+
99
+ export function MappingSuggestionsDialog({
100
+ open,
101
+ onOpenChange,
102
+ onApplied,
103
+ }: MappingSuggestionsDialogProps) {
104
+ const t = useT()
105
+ const [items, setItems] = React.useState<MappingSuggestion[]>([])
106
+ const [selectedIds, setSelectedIds] = React.useState<Set<string>>(() => new Set())
107
+ const [loading, setLoading] = React.useState(false)
108
+ const [error, setError] = React.useState<string | null>(null)
109
+ const [applying, setApplying] = React.useState(false)
110
+ const [failures, setFailures] = React.useState<ApplyResponse['failed']>([])
111
+ const appliedDuringSessionRef = React.useRef(false)
112
+ const mutationContextId = 'eudr-product-mapping-suggestions:apply'
113
+ const { runMutation, retryLastMutation } = useGuardedMutation<{
114
+ formId: string
115
+ resourceKind: string
116
+ resourceId: string
117
+ retryLastMutation: () => Promise<boolean>
118
+ }>({
119
+ contextId: mutationContextId,
120
+ blockedMessage: t('ui.forms.flash.saveBlocked'),
121
+ })
122
+
123
+ const closeDialog = React.useCallback((nextOpen: boolean) => {
124
+ if (!nextOpen && appliedDuringSessionRef.current) {
125
+ onApplied?.()
126
+ appliedDuringSessionRef.current = false
127
+ }
128
+ onOpenChange(nextOpen)
129
+ }, [onApplied, onOpenChange])
130
+
131
+ React.useEffect(() => {
132
+ if (!open) return
133
+ appliedDuringSessionRef.current = false
134
+ setFailures([])
135
+ setSelectedIds(new Set<string>())
136
+
137
+ let cancelled = false
138
+ async function loadSuggestions() {
139
+ setLoading(true)
140
+ setError(null)
141
+ try {
142
+ const fallback: SuggestionsResponse = { items: [] }
143
+ const call = await apiCall<SuggestionsResponse>(
144
+ '/api/eudr/product-mappings/suggestions',
145
+ undefined,
146
+ { fallback },
147
+ )
148
+ if (!call.ok) {
149
+ setError(t('eudr.suggestions.loadError'))
150
+ return
151
+ }
152
+ const nextItems = normalizeSuggestionsResponse(call.result ?? fallback)
153
+ if (cancelled) return
154
+ setItems(nextItems)
155
+ setSelectedIds(new Set(nextItems.map((item) => item.productId)))
156
+ } catch {
157
+ if (!cancelled) setError(t('eudr.suggestions.loadError'))
158
+ } finally {
159
+ if (!cancelled) setLoading(false)
160
+ }
161
+ }
162
+
163
+ void loadSuggestions()
164
+ return () => {
165
+ cancelled = true
166
+ }
167
+ }, [open, t])
168
+
169
+ const selectedItems = React.useMemo(() => {
170
+ return items.filter((item) => selectedIds.has(item.productId))
171
+ }, [items, selectedIds])
172
+
173
+ const selectedCount = selectedItems.length
174
+ const allSelected = items.length > 0 && selectedCount === items.length
175
+ const partiallySelected = selectedCount > 0 && selectedCount < items.length
176
+ const canApply = selectedCount > 0 && !applying && !loading
177
+
178
+ const toggleAll = React.useCallback((checked: boolean | 'indeterminate') => {
179
+ if (checked) {
180
+ setSelectedIds(new Set(items.map((item) => item.productId)))
181
+ } else {
182
+ setSelectedIds(new Set<string>())
183
+ }
184
+ }, [items])
185
+
186
+ const toggleOne = React.useCallback((productId: string, checked: boolean | 'indeterminate') => {
187
+ setSelectedIds((current) => {
188
+ const next = new Set(current)
189
+ if (checked) next.add(productId)
190
+ else next.delete(productId)
191
+ return next
192
+ })
193
+ }, [])
194
+
195
+ const columns = React.useMemo<ColumnDef<MappingSuggestion>[]>(() => [
196
+ {
197
+ id: 'select',
198
+ header: () => (
199
+ <Checkbox
200
+ aria-label={t('eudr.suggestions.selectAll')}
201
+ checked={allSelected ? true : partiallySelected ? 'indeterminate' : false}
202
+ onCheckedChange={toggleAll}
203
+ />
204
+ ),
205
+ cell: ({ row }) => (
206
+ <Checkbox
207
+ aria-label={t('eudr.suggestions.selectRow', { product: formatProductLabel(row.original) })}
208
+ checked={selectedIds.has(row.original.productId)}
209
+ onCheckedChange={(checked) => toggleOne(row.original.productId, checked)}
210
+ />
211
+ ),
212
+ enableSorting: false,
213
+ size: 48,
214
+ },
215
+ {
216
+ accessorKey: 'name',
217
+ header: t('eudr.suggestions.columns.product'),
218
+ cell: ({ row }) => (
219
+ <div className="min-w-0">
220
+ <p className="truncate font-medium">{row.original.name}</p>
221
+ {row.original.sku ? (
222
+ <p className="truncate text-xs text-muted-foreground">{row.original.sku}</p>
223
+ ) : null}
224
+ </div>
225
+ ),
226
+ meta: { maxWidth: '260px', truncate: true },
227
+ },
228
+ {
229
+ accessorKey: 'hsCode',
230
+ header: t('eudr.suggestions.columns.hsCode'),
231
+ cell: ({ row }) => <span className="font-mono text-xs">{row.original.hsCode}</span>,
232
+ },
233
+ {
234
+ accessorKey: 'suggestedCommodity',
235
+ header: t('eudr.suggestions.columns.suggestedCommodity'),
236
+ cell: ({ row }) => (
237
+ <Tag variant="success">
238
+ {t(`eudr.commodity.${row.original.suggestedCommodity}`)}
239
+ </Tag>
240
+ ),
241
+ },
242
+ ], [allSelected, partiallySelected, selectedIds, t, toggleAll, toggleOne])
243
+
244
+ const handleApply = React.useCallback(async () => {
245
+ if (!canApply) return
246
+ setApplying(true)
247
+ setFailures([])
248
+ try {
249
+ const payloadItems: ApplyItem[] = selectedItems.map((item) => ({
250
+ productId: item.productId,
251
+ commodity: item.suggestedCommodity,
252
+ hsCode: item.hsCode,
253
+ }))
254
+ const call = await runMutation({
255
+ operation: () => apiCallOrThrow<ApplyResponse>(
256
+ '/api/eudr/product-mappings/suggestions/apply',
257
+ {
258
+ method: 'POST',
259
+ headers: { 'Content-Type': 'application/json' },
260
+ body: JSON.stringify({ items: payloadItems }),
261
+ },
262
+ { errorMessage: t('eudr.suggestions.applyError') },
263
+ ),
264
+ context: {
265
+ formId: mutationContextId,
266
+ resourceKind: 'eudr.product_mapping',
267
+ resourceId: 'bulk-suggestions',
268
+ retryLastMutation,
269
+ },
270
+ mutationPayload: { items: payloadItems },
271
+ })
272
+ const result = call.result ?? { created: 0, failed: [] }
273
+ appliedDuringSessionRef.current = true
274
+ flash(t('eudr.suggestions.applySuccess', { count: result.created }), result.created > 0 ? 'success' : 'warning')
275
+ const failures = Array.isArray(result.failed) ? result.failed : []
276
+ setFailures(failures)
277
+ if (!failures.length) {
278
+ closeDialog(false)
279
+ } else {
280
+ setSelectedIds(new Set(failures.map((failure) => failure.productId)))
281
+ }
282
+ } catch {
283
+ flash(t('eudr.suggestions.applyError'), 'error')
284
+ } finally {
285
+ setApplying(false)
286
+ }
287
+ }, [canApply, closeDialog, mutationContextId, retryLastMutation, runMutation, selectedItems, t])
288
+
289
+ return (
290
+ <Dialog open={open} onOpenChange={closeDialog}>
291
+ <DialogContent
292
+ size="xl"
293
+ onKeyDown={(event) => {
294
+ if (event.key === 'Escape') {
295
+ event.preventDefault()
296
+ closeDialog(false)
297
+ return
298
+ }
299
+ if ((event.metaKey || event.ctrlKey) && event.key === 'Enter') {
300
+ event.preventDefault()
301
+ void handleApply()
302
+ }
303
+ }}
304
+ >
305
+ <DialogHeader>
306
+ <DialogTitle>{t('eudr.suggestions.title')}</DialogTitle>
307
+ </DialogHeader>
308
+
309
+ <div className="min-h-64">
310
+ {error ? (
311
+ <ErrorMessage label={error} />
312
+ ) : loading ? (
313
+ <LoadingMessage label={t('eudr.suggestions.loading')} />
314
+ ) : items.length === 0 ? (
315
+ <EmptyState
316
+ size="sm"
317
+ variant="subtle"
318
+ title={t('eudr.suggestions.empty')}
319
+ description={t('eudr.suggestions.emptyHint')}
320
+ />
321
+ ) : (
322
+ <div className="space-y-3">
323
+ <DataTable<MappingSuggestion>
324
+ title={t('eudr.suggestions.tableTitle')}
325
+ columns={columns}
326
+ data={items}
327
+ emptyState={(
328
+ <EmptyState
329
+ size="sm"
330
+ variant="subtle"
331
+ title={t('eudr.suggestions.empty')}
332
+ description={t('eudr.suggestions.emptyHint')}
333
+ />
334
+ )}
335
+ perspective={{ tableId: 'eudr.product_mapping_suggestions.dialog' }}
336
+ disableRowClick
337
+ />
338
+ {failures.length > 0 ? (
339
+ <div className="rounded-md border border-status-error-border bg-status-error-bg p-3 text-sm text-status-error-text">
340
+ <p className="font-medium">{t('eudr.suggestions.failuresTitle')}</p>
341
+ <ul className="mt-2 space-y-1">
342
+ {failures.map((failure) => {
343
+ const item = items.find((candidate) => candidate.productId === failure.productId)
344
+ return (
345
+ <li key={failure.productId}>
346
+ <span className="font-medium">
347
+ {item ? formatProductLabel(item) : t('eudr.common.recordUnavailable')}
348
+ </span>
349
+ {': '}
350
+ <span>{t(failure.errorKey)}</span>
351
+ </li>
352
+ )
353
+ })}
354
+ </ul>
355
+ </div>
356
+ ) : null}
357
+ </div>
358
+ )}
359
+ </div>
360
+
361
+ <DialogFooter>
362
+ <span className="mr-auto text-sm text-muted-foreground">
363
+ {t('eudr.suggestions.selectedCount', { count: selectedCount })}
364
+ </span>
365
+ <Button
366
+ type="button"
367
+ variant="outline"
368
+ onClick={() => closeDialog(false)}
369
+ >
370
+ {t('eudr.suggestions.cancel')}
371
+ </Button>
372
+ <Button
373
+ type="button"
374
+ onClick={() => void handleApply()}
375
+ disabled={!canApply}
376
+ >
377
+ {applying ? t('eudr.suggestions.applying') : t('eudr.suggestions.apply')}
378
+ </Button>
379
+ </DialogFooter>
380
+ </DialogContent>
381
+ </Dialog>
382
+ )
383
+ }
384
+
385
+ export default MappingSuggestionsDialog