@open-mercato/core 0.4.5-develop-754ef4d2f0 → 0.4.5-develop-9f9549ebc8

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 (434) hide show
  1. package/dist/generated/entities/message/index.js +65 -0
  2. package/dist/generated/entities/message/index.js.map +7 -0
  3. package/dist/generated/entities/message_access_token/index.js +19 -0
  4. package/dist/generated/entities/message_access_token/index.js.map +7 -0
  5. package/dist/generated/entities/message_confirmation/index.js +21 -0
  6. package/dist/generated/entities/message_confirmation/index.js.map +7 -0
  7. package/dist/generated/entities/message_object/index.js +23 -0
  8. package/dist/generated/entities/message_object/index.js.map +7 -0
  9. package/dist/generated/entities/message_recipient/index.js +31 -0
  10. package/dist/generated/entities/message_recipient/index.js.map +7 -0
  11. package/dist/generated/entities.ids.generated.js +8 -0
  12. package/dist/generated/entities.ids.generated.js.map +2 -2
  13. package/dist/generated/entity-fields-registry.js +10 -0
  14. package/dist/generated/entity-fields-registry.js.map +2 -2
  15. package/dist/modules/auth/components/AclEditor.js +4 -2
  16. package/dist/modules/auth/components/AclEditor.js.map +2 -2
  17. package/dist/modules/auth/frontend/reset.js +3 -3
  18. package/dist/modules/auth/frontend/reset.js.map +2 -2
  19. package/dist/modules/customers/backend/customers/deals/[id]/page.js +27 -8
  20. package/dist/modules/customers/backend/customers/deals/[id]/page.js.map +2 -2
  21. package/dist/modules/customers/lib/messageObjectPreviews.js +131 -0
  22. package/dist/modules/customers/lib/messageObjectPreviews.js.map +7 -0
  23. package/dist/modules/customers/message-objects.js +71 -0
  24. package/dist/modules/customers/message-objects.js.map +7 -0
  25. package/dist/modules/customers/widgets/messages/CustomerMessageObjectDetail.js +51 -0
  26. package/dist/modules/customers/widgets/messages/CustomerMessageObjectDetail.js.map +7 -0
  27. package/dist/modules/customers/widgets/messages/CustomerMessageObjectPreview.js +35 -0
  28. package/dist/modules/customers/widgets/messages/CustomerMessageObjectPreview.js.map +7 -0
  29. package/dist/modules/customers/widgets/messages/index.js +7 -0
  30. package/dist/modules/customers/widgets/messages/index.js.map +7 -0
  31. package/dist/modules/dashboards/components/WidgetVisibilityEditor.js +35 -6
  32. package/dist/modules/dashboards/components/WidgetVisibilityEditor.js.map +2 -2
  33. package/dist/modules/messages/acl.js +15 -0
  34. package/dist/modules/messages/acl.js.map +7 -0
  35. package/dist/modules/messages/api/[id]/actions/[actionId]/route.js +92 -0
  36. package/dist/modules/messages/api/[id]/actions/[actionId]/route.js.map +7 -0
  37. package/dist/modules/messages/api/[id]/archive/route.js +120 -0
  38. package/dist/modules/messages/api/[id]/archive/route.js.map +7 -0
  39. package/dist/modules/messages/api/[id]/attachments/route.js +195 -0
  40. package/dist/modules/messages/api/[id]/attachments/route.js.map +7 -0
  41. package/dist/modules/messages/api/[id]/confirmation/route.js +67 -0
  42. package/dist/modules/messages/api/[id]/confirmation/route.js.map +7 -0
  43. package/dist/modules/messages/api/[id]/conversation/archive/route.js +68 -0
  44. package/dist/modules/messages/api/[id]/conversation/archive/route.js.map +7 -0
  45. package/dist/modules/messages/api/[id]/conversation/read/route.js +68 -0
  46. package/dist/modules/messages/api/[id]/conversation/read/route.js.map +7 -0
  47. package/dist/modules/messages/api/[id]/conversation/route.js +68 -0
  48. package/dist/modules/messages/api/[id]/conversation/route.js.map +7 -0
  49. package/dist/modules/messages/api/[id]/forward/route.js +85 -0
  50. package/dist/modules/messages/api/[id]/forward/route.js.map +7 -0
  51. package/dist/modules/messages/api/[id]/forward-preview/route.js +70 -0
  52. package/dist/modules/messages/api/[id]/forward-preview/route.js.map +7 -0
  53. package/dist/modules/messages/api/[id]/read/route.js +120 -0
  54. package/dist/modules/messages/api/[id]/read/route.js.map +7 -0
  55. package/dist/modules/messages/api/[id]/reply/route.js +87 -0
  56. package/dist/modules/messages/api/[id]/reply/route.js.map +7 -0
  57. package/dist/modules/messages/api/[id]/route.js +350 -0
  58. package/dist/modules/messages/api/[id]/route.js.map +7 -0
  59. package/dist/modules/messages/api/object-types/route.js +54 -0
  60. package/dist/modules/messages/api/object-types/route.js.map +7 -0
  61. package/dist/modules/messages/api/openapi.js +261 -0
  62. package/dist/modules/messages/api/openapi.js.map +7 -0
  63. package/dist/modules/messages/api/route.js +262 -0
  64. package/dist/modules/messages/api/route.js.map +7 -0
  65. package/dist/modules/messages/api/token/[token]/route.js +99 -0
  66. package/dist/modules/messages/api/token/[token]/route.js.map +7 -0
  67. package/dist/modules/messages/api/types/route.js +40 -0
  68. package/dist/modules/messages/api/types/route.js.map +7 -0
  69. package/dist/modules/messages/api/unread-count/route.js +43 -0
  70. package/dist/modules/messages/api/unread-count/route.js.map +7 -0
  71. package/dist/modules/messages/backend/messages/[id]/page.js +10 -0
  72. package/dist/modules/messages/backend/messages/[id]/page.js.map +7 -0
  73. package/dist/modules/messages/backend/messages/[id]/page.meta.js +16 -0
  74. package/dist/modules/messages/backend/messages/[id]/page.meta.js.map +7 -0
  75. package/dist/modules/messages/backend/messages/compose/page.js +10 -0
  76. package/dist/modules/messages/backend/messages/compose/page.js.map +7 -0
  77. package/dist/modules/messages/backend/messages/compose/page.meta.js +17 -0
  78. package/dist/modules/messages/backend/messages/compose/page.meta.js.map +7 -0
  79. package/dist/modules/messages/backend/page.js +10 -0
  80. package/dist/modules/messages/backend/page.js.map +7 -0
  81. package/dist/modules/messages/backend/page.meta.js +33 -0
  82. package/dist/modules/messages/backend/page.meta.js.map +7 -0
  83. package/dist/modules/messages/commands/actions.js +265 -0
  84. package/dist/modules/messages/commands/actions.js.map +7 -0
  85. package/dist/modules/messages/commands/attachments.js +217 -0
  86. package/dist/modules/messages/commands/attachments.js.map +7 -0
  87. package/dist/modules/messages/commands/confirmations.js +151 -0
  88. package/dist/modules/messages/commands/confirmations.js.map +7 -0
  89. package/dist/modules/messages/commands/conversation.js +240 -0
  90. package/dist/modules/messages/commands/conversation.js.map +7 -0
  91. package/dist/modules/messages/commands/messages.js +748 -0
  92. package/dist/modules/messages/commands/messages.js.map +7 -0
  93. package/dist/modules/messages/commands/recipients.js +259 -0
  94. package/dist/modules/messages/commands/recipients.js.map +7 -0
  95. package/dist/modules/messages/commands/shared.js +258 -0
  96. package/dist/modules/messages/commands/shared.js.map +7 -0
  97. package/dist/modules/messages/commands/tokens.js +69 -0
  98. package/dist/modules/messages/commands/tokens.js.map +7 -0
  99. package/dist/modules/messages/components/ComposeMessagePageClient.js +24 -0
  100. package/dist/modules/messages/components/ComposeMessagePageClient.js.map +7 -0
  101. package/dist/modules/messages/components/MessageDetailPageClient.js +261 -0
  102. package/dist/modules/messages/components/MessageDetailPageClient.js.map +7 -0
  103. package/dist/modules/messages/components/MessagesInboxPageClient.js +390 -0
  104. package/dist/modules/messages/components/MessagesInboxPageClient.js.map +7 -0
  105. package/dist/modules/messages/components/confirmation/MessageConfirmationActions.js +31 -0
  106. package/dist/modules/messages/components/confirmation/MessageConfirmationActions.js.map +7 -0
  107. package/dist/modules/messages/components/confirmation/MessageConfirmationContent.js +69 -0
  108. package/dist/modules/messages/components/confirmation/MessageConfirmationContent.js.map +7 -0
  109. package/dist/modules/messages/components/defaults/DefaultMessageActions.js +31 -0
  110. package/dist/modules/messages/components/defaults/DefaultMessageActions.js.map +7 -0
  111. package/dist/modules/messages/components/defaults/DefaultMessageContent.js +19 -0
  112. package/dist/modules/messages/components/defaults/DefaultMessageContent.js.map +7 -0
  113. package/dist/modules/messages/components/defaults/DefaultMessageListItem.js +90 -0
  114. package/dist/modules/messages/components/defaults/DefaultMessageListItem.js.map +7 -0
  115. package/dist/modules/messages/components/defaults/MessageRecordObjectDetail.js +86 -0
  116. package/dist/modules/messages/components/defaults/MessageRecordObjectDetail.js.map +7 -0
  117. package/dist/modules/messages/components/defaults/MessageRecordObjectPreview.js +61 -0
  118. package/dist/modules/messages/components/defaults/MessageRecordObjectPreview.js.map +7 -0
  119. package/dist/modules/messages/components/message-detail/detail-panels.js +27 -0
  120. package/dist/modules/messages/components/message-detail/detail-panels.js.map +7 -0
  121. package/dist/modules/messages/components/message-detail/hooks/useMessageDetails.js +52 -0
  122. package/dist/modules/messages/components/message-detail/hooks/useMessageDetails.js.map +7 -0
  123. package/dist/modules/messages/components/message-detail/hooks/useMessageDetailsActions.js +289 -0
  124. package/dist/modules/messages/components/message-detail/hooks/useMessageDetailsActions.js.map +7 -0
  125. package/dist/modules/messages/components/message-detail/hooks/useMessageDetailsConversation.js +103 -0
  126. package/dist/modules/messages/components/message-detail/hooks/useMessageDetailsConversation.js.map +7 -0
  127. package/dist/modules/messages/components/message-detail/hooks/useMessageDetailsQueries.js +78 -0
  128. package/dist/modules/messages/components/message-detail/hooks/useMessageDetailsQueries.js.map +7 -0
  129. package/dist/modules/messages/components/message-detail/panels/MainMessageHeader.js +94 -0
  130. package/dist/modules/messages/components/message-detail/panels/MainMessageHeader.js.map +7 -0
  131. package/dist/modules/messages/components/message-detail/panels/MessageHeader.js +110 -0
  132. package/dist/modules/messages/components/message-detail/panels/MessageHeader.js.map +7 -0
  133. package/dist/modules/messages/components/message-detail/panels/MessageListComponent.js +58 -0
  134. package/dist/modules/messages/components/message-detail/panels/MessageListComponent.js.map +7 -0
  135. package/dist/modules/messages/components/message-detail/panels/actions-panel.js +51 -0
  136. package/dist/modules/messages/components/message-detail/panels/actions-panel.js.map +7 -0
  137. package/dist/modules/messages/components/message-detail/panels/attachments-panel.js +66 -0
  138. package/dist/modules/messages/components/message-detail/panels/attachments-panel.js.map +7 -0
  139. package/dist/modules/messages/components/message-detail/panels/body-panel.js +20 -0
  140. package/dist/modules/messages/components/message-detail/panels/body-panel.js.map +7 -0
  141. package/dist/modules/messages/components/message-detail/panels/composer-dialogs.js +36 -0
  142. package/dist/modules/messages/components/message-detail/panels/composer-dialogs.js.map +7 -0
  143. package/dist/modules/messages/components/message-detail/panels/dialogs.js +96 -0
  144. package/dist/modules/messages/components/message-detail/panels/dialogs.js.map +7 -0
  145. package/dist/modules/messages/components/message-detail/panels/index.js +25 -0
  146. package/dist/modules/messages/components/message-detail/panels/index.js.map +7 -0
  147. package/dist/modules/messages/components/message-detail/panels/meta-panel.js +14 -0
  148. package/dist/modules/messages/components/message-detail/panels/meta-panel.js.map +7 -0
  149. package/dist/modules/messages/components/message-detail/panels/objects-panel.js +51 -0
  150. package/dist/modules/messages/components/message-detail/panels/objects-panel.js.map +7 -0
  151. package/dist/modules/messages/components/message-detail/panels/thread-panel.js +54 -0
  152. package/dist/modules/messages/components/message-detail/panels/thread-panel.js.map +7 -0
  153. package/dist/modules/messages/components/message-detail/types.js +1 -0
  154. package/dist/modules/messages/components/message-detail/types.js.map +7 -0
  155. package/dist/modules/messages/components/message-detail/utils.js +54 -0
  156. package/dist/modules/messages/components/message-detail/utils.js.map +7 -0
  157. package/dist/modules/messages/components/utils/PriorityBadge.js +52 -0
  158. package/dist/modules/messages/components/utils/PriorityBadge.js.map +7 -0
  159. package/dist/modules/messages/components/utils/typeUiRegistry.js +77 -0
  160. package/dist/modules/messages/components/utils/typeUiRegistry.js.map +7 -0
  161. package/dist/modules/messages/data/entities.js +309 -0
  162. package/dist/modules/messages/data/entities.js.map +7 -0
  163. package/dist/modules/messages/data/validators.js +272 -0
  164. package/dist/modules/messages/data/validators.js.map +7 -0
  165. package/dist/modules/messages/emails/MessageEmail.js +108 -0
  166. package/dist/modules/messages/emails/MessageEmail.js.map +7 -0
  167. package/dist/modules/messages/events.js +24 -0
  168. package/dist/modules/messages/events.js.map +7 -0
  169. package/dist/modules/messages/frontend/messages/view/[token]/page.js +247 -0
  170. package/dist/modules/messages/frontend/messages/view/[token]/page.js.map +7 -0
  171. package/dist/modules/messages/frontend/messages/view/[token]/page.meta.js +9 -0
  172. package/dist/modules/messages/frontend/messages/view/[token]/page.meta.js.map +7 -0
  173. package/dist/modules/messages/index.js +21 -0
  174. package/dist/modules/messages/index.js.map +7 -0
  175. package/dist/modules/messages/lib/actions.js +141 -0
  176. package/dist/modules/messages/lib/actions.js.map +7 -0
  177. package/dist/modules/messages/lib/attachments.js +131 -0
  178. package/dist/modules/messages/lib/attachments.js.map +7 -0
  179. package/dist/modules/messages/lib/constants.js +7 -0
  180. package/dist/modules/messages/lib/constants.js.map +7 -0
  181. package/dist/modules/messages/lib/email-sender.js +201 -0
  182. package/dist/modules/messages/lib/email-sender.js.map +7 -0
  183. package/dist/modules/messages/lib/forwarding.js +179 -0
  184. package/dist/modules/messages/lib/forwarding.js.map +7 -0
  185. package/dist/modules/messages/lib/message-objects-registry.js +49 -0
  186. package/dist/modules/messages/lib/message-objects-registry.js.map +7 -0
  187. package/dist/modules/messages/lib/message-types-registry.js +41 -0
  188. package/dist/modules/messages/lib/message-types-registry.js.map +7 -0
  189. package/dist/modules/messages/lib/object-validation.js +20 -0
  190. package/dist/modules/messages/lib/object-validation.js.map +7 -0
  191. package/dist/modules/messages/lib/operationMetadata.js +21 -0
  192. package/dist/modules/messages/lib/operationMetadata.js.map +7 -0
  193. package/dist/modules/messages/lib/priorityUtils.js +61 -0
  194. package/dist/modules/messages/lib/priorityUtils.js.map +7 -0
  195. package/dist/modules/messages/lib/routeHelpers.js +44 -0
  196. package/dist/modules/messages/lib/routeHelpers.js.map +7 -0
  197. package/dist/modules/messages/message-objects.js +7 -0
  198. package/dist/modules/messages/message-objects.js.map +7 -0
  199. package/dist/modules/messages/message-types.js +67 -0
  200. package/dist/modules/messages/message-types.js.map +7 -0
  201. package/dist/modules/messages/migrations/Migration20260213181243.js +31 -0
  202. package/dist/modules/messages/migrations/Migration20260213181243.js.map +7 -0
  203. package/dist/modules/messages/migrations/Migration20260215165126.js +16 -0
  204. package/dist/modules/messages/migrations/Migration20260215165126.js.map +7 -0
  205. package/dist/modules/messages/notifications.js +27 -0
  206. package/dist/modules/messages/notifications.js.map +7 -0
  207. package/dist/modules/messages/setup.js +21 -0
  208. package/dist/modules/messages/setup.js.map +7 -0
  209. package/dist/modules/messages/subscribers/message-notification.js +108 -0
  210. package/dist/modules/messages/subscribers/message-notification.js.map +7 -0
  211. package/dist/modules/messages/workers/send-email.worker.js +253 -0
  212. package/dist/modules/messages/workers/send-email.worker.js.map +7 -0
  213. package/dist/modules/sales/backend/sales/documents/[id]/page.js +30 -11
  214. package/dist/modules/sales/backend/sales/documents/[id]/page.js.map +2 -2
  215. package/dist/modules/sales/commands/payments.js +12 -6
  216. package/dist/modules/sales/commands/payments.js.map +2 -2
  217. package/dist/modules/sales/lib/messageObjectPreviews.js +114 -0
  218. package/dist/modules/sales/lib/messageObjectPreviews.js.map +7 -0
  219. package/dist/modules/sales/message-objects.js +57 -0
  220. package/dist/modules/sales/message-objects.js.map +7 -0
  221. package/dist/modules/sales/widgets/messages/SalesDocumentMessageDetail.js +51 -0
  222. package/dist/modules/sales/widgets/messages/SalesDocumentMessageDetail.js.map +7 -0
  223. package/dist/modules/sales/widgets/messages/SalesDocumentMessagePreview.js +36 -0
  224. package/dist/modules/sales/widgets/messages/SalesDocumentMessagePreview.js.map +7 -0
  225. package/dist/modules/sales/widgets/messages/index.js +7 -0
  226. package/dist/modules/sales/widgets/messages/index.js.map +7 -0
  227. package/dist/modules/staff/backend/staff/leave-requests/[id]/page.js +55 -1
  228. package/dist/modules/staff/backend/staff/leave-requests/[id]/page.js.map +2 -2
  229. package/dist/modules/staff/backend/staff/my-leave-requests/[id]/page.js +60 -1
  230. package/dist/modules/staff/backend/staff/my-leave-requests/[id]/page.js.map +2 -2
  231. package/dist/modules/staff/backend/staff/team-members/[id]/page.js +2 -19
  232. package/dist/modules/staff/backend/staff/team-members/[id]/page.js.map +2 -2
  233. package/dist/modules/staff/components/LeaveRequestDetail.js +112 -0
  234. package/dist/modules/staff/components/LeaveRequestDetail.js.map +7 -0
  235. package/dist/modules/staff/components/LeaveRequestForm.js +3 -1
  236. package/dist/modules/staff/components/LeaveRequestForm.js.map +2 -2
  237. package/dist/modules/staff/components/LeaveRequestPreview.js +43 -0
  238. package/dist/modules/staff/components/LeaveRequestPreview.js.map +7 -0
  239. package/dist/modules/staff/lib/messageObjectPreviews.js +148 -0
  240. package/dist/modules/staff/lib/messageObjectPreviews.js.map +7 -0
  241. package/dist/modules/staff/message-objects.js +104 -0
  242. package/dist/modules/staff/message-objects.js.map +7 -0
  243. package/dist/modules/staff/message-types.js +23 -0
  244. package/dist/modules/staff/message-types.js.map +7 -0
  245. package/dist/modules/staff/widgets/messages/StaffMessageObjectDetail.js +51 -0
  246. package/dist/modules/staff/widgets/messages/StaffMessageObjectDetail.js.map +7 -0
  247. package/dist/modules/staff/widgets/messages/StaffMessageObjectPreview.js +34 -0
  248. package/dist/modules/staff/widgets/messages/StaffMessageObjectPreview.js.map +7 -0
  249. package/dist/modules/staff/widgets/messages/index.js +7 -0
  250. package/dist/modules/staff/widgets/messages/index.js.map +7 -0
  251. package/dist/modules/workflows/backend/definitions/visual-editor/page.js +6 -6
  252. package/dist/modules/workflows/backend/definitions/visual-editor/page.js.map +2 -2
  253. package/generated/entities/message/index.ts +31 -0
  254. package/generated/entities/message_access_token/index.ts +8 -0
  255. package/generated/entities/message_confirmation/index.ts +9 -0
  256. package/generated/entities/message_object/index.ts +10 -0
  257. package/generated/entities/message_recipient/index.ts +14 -0
  258. package/generated/entities.ids.generated.ts +8 -0
  259. package/generated/entity-fields-registry.ts +10 -0
  260. package/jest.setup.ts +5 -0
  261. package/package.json +2 -2
  262. package/src/modules/attachments/i18n/de.json +4 -0
  263. package/src/modules/attachments/i18n/en.json +4 -0
  264. package/src/modules/attachments/i18n/es.json +4 -0
  265. package/src/modules/attachments/i18n/pl.json +4 -0
  266. package/src/modules/auth/components/AclEditor.tsx +4 -2
  267. package/src/modules/auth/frontend/reset.tsx +3 -3
  268. package/src/modules/auth/i18n/de.json +5 -0
  269. package/src/modules/auth/i18n/en.json +5 -0
  270. package/src/modules/auth/i18n/es.json +5 -0
  271. package/src/modules/auth/i18n/pl.json +5 -0
  272. package/src/modules/catalog/i18n/de.json +21 -0
  273. package/src/modules/catalog/i18n/en.json +21 -0
  274. package/src/modules/catalog/i18n/es.json +21 -0
  275. package/src/modules/catalog/i18n/pl.json +21 -0
  276. package/src/modules/currencies/i18n/de.json +6 -0
  277. package/src/modules/currencies/i18n/en.json +6 -0
  278. package/src/modules/currencies/i18n/es.json +6 -0
  279. package/src/modules/currencies/i18n/pl.json +6 -0
  280. package/src/modules/customers/backend/customers/deals/[id]/page.tsx +20 -4
  281. package/src/modules/customers/i18n/de.json +26 -1
  282. package/src/modules/customers/i18n/en.json +25 -0
  283. package/src/modules/customers/i18n/es.json +25 -0
  284. package/src/modules/customers/i18n/pl.json +25 -0
  285. package/src/modules/customers/lib/messageObjectPreviews.ts +154 -0
  286. package/src/modules/customers/message-objects.ts +70 -0
  287. package/src/modules/customers/widgets/messages/CustomerMessageObjectDetail.tsx +57 -0
  288. package/src/modules/customers/widgets/messages/CustomerMessageObjectPreview.tsx +49 -0
  289. package/src/modules/customers/widgets/messages/index.ts +2 -0
  290. package/src/modules/dashboards/components/WidgetVisibilityEditor.tsx +41 -5
  291. package/src/modules/dashboards/i18n/de.json +5 -1
  292. package/src/modules/dashboards/i18n/en.json +5 -1
  293. package/src/modules/dashboards/i18n/es.json +5 -1
  294. package/src/modules/dashboards/i18n/pl.json +5 -1
  295. package/src/modules/dictionaries/i18n/de.json +14 -1
  296. package/src/modules/dictionaries/i18n/en.json +14 -1
  297. package/src/modules/dictionaries/i18n/es.json +14 -1
  298. package/src/modules/dictionaries/i18n/pl.json +14 -1
  299. package/src/modules/feature_toggles/i18n/de.json +3 -0
  300. package/src/modules/feature_toggles/i18n/en.json +3 -0
  301. package/src/modules/feature_toggles/i18n/es.json +3 -0
  302. package/src/modules/feature_toggles/i18n/pl.json +3 -0
  303. package/src/modules/messages/acl.ts +11 -0
  304. package/src/modules/messages/api/[id]/actions/[actionId]/route.ts +103 -0
  305. package/src/modules/messages/api/[id]/archive/route.ts +138 -0
  306. package/src/modules/messages/api/[id]/attachments/route.ts +217 -0
  307. package/src/modules/messages/api/[id]/confirmation/route.ts +73 -0
  308. package/src/modules/messages/api/[id]/conversation/archive/route.ts +69 -0
  309. package/src/modules/messages/api/[id]/conversation/read/route.ts +69 -0
  310. package/src/modules/messages/api/[id]/conversation/route.ts +69 -0
  311. package/src/modules/messages/api/[id]/forward/route.ts +87 -0
  312. package/src/modules/messages/api/[id]/forward-preview/route.ts +75 -0
  313. package/src/modules/messages/api/[id]/read/route.ts +138 -0
  314. package/src/modules/messages/api/[id]/reply/route.ts +89 -0
  315. package/src/modules/messages/api/[id]/route.ts +401 -0
  316. package/src/modules/messages/api/object-types/route.ts +54 -0
  317. package/src/modules/messages/api/openapi.ts +261 -0
  318. package/src/modules/messages/api/route.ts +374 -0
  319. package/src/modules/messages/api/token/[token]/route.ts +103 -0
  320. package/src/modules/messages/api/types/route.ts +39 -0
  321. package/src/modules/messages/api/unread-count/route.ts +55 -0
  322. package/src/modules/messages/backend/messages/[id]/page.meta.ts +12 -0
  323. package/src/modules/messages/backend/messages/[id]/page.tsx +12 -0
  324. package/src/modules/messages/backend/messages/compose/page.meta.ts +13 -0
  325. package/src/modules/messages/backend/messages/compose/page.tsx +12 -0
  326. package/src/modules/messages/backend/page.meta.ts +31 -0
  327. package/src/modules/messages/backend/page.tsx +12 -0
  328. package/src/modules/messages/commands/actions.ts +307 -0
  329. package/src/modules/messages/commands/attachments.ts +227 -0
  330. package/src/modules/messages/commands/confirmations.ts +183 -0
  331. package/src/modules/messages/commands/conversation.ts +292 -0
  332. package/src/modules/messages/commands/messages.ts +845 -0
  333. package/src/modules/messages/commands/recipients.ts +281 -0
  334. package/src/modules/messages/commands/shared.ts +350 -0
  335. package/src/modules/messages/commands/tokens.ts +80 -0
  336. package/src/modules/messages/components/ComposeMessagePageClient.tsx +23 -0
  337. package/src/modules/messages/components/MessageDetailPageClient.tsx +287 -0
  338. package/src/modules/messages/components/MessagesInboxPageClient.tsx +469 -0
  339. package/src/modules/messages/components/confirmation/MessageConfirmationActions.tsx +35 -0
  340. package/src/modules/messages/components/confirmation/MessageConfirmationContent.tsx +88 -0
  341. package/src/modules/messages/components/defaults/DefaultMessageActions.tsx +37 -0
  342. package/src/modules/messages/components/defaults/DefaultMessageContent.tsx +21 -0
  343. package/src/modules/messages/components/defaults/DefaultMessageListItem.tsx +102 -0
  344. package/src/modules/messages/components/defaults/MessageRecordObjectDetail.tsx +114 -0
  345. package/src/modules/messages/components/defaults/MessageRecordObjectPreview.tsx +74 -0
  346. package/src/modules/messages/components/message-detail/detail-panels.ts +13 -0
  347. package/src/modules/messages/components/message-detail/hooks/useMessageDetails.ts +56 -0
  348. package/src/modules/messages/components/message-detail/hooks/useMessageDetailsActions.ts +367 -0
  349. package/src/modules/messages/components/message-detail/hooks/useMessageDetailsConversation.ts +134 -0
  350. package/src/modules/messages/components/message-detail/hooks/useMessageDetailsQueries.ts +102 -0
  351. package/src/modules/messages/components/message-detail/panels/MainMessageHeader.tsx +108 -0
  352. package/src/modules/messages/components/message-detail/panels/MessageHeader.tsx +144 -0
  353. package/src/modules/messages/components/message-detail/panels/MessageListComponent.tsx +63 -0
  354. package/src/modules/messages/components/message-detail/panels/actions-panel.tsx +66 -0
  355. package/src/modules/messages/components/message-detail/panels/attachments-panel.tsx +86 -0
  356. package/src/modules/messages/components/message-detail/panels/body-panel.tsx +32 -0
  357. package/src/modules/messages/components/message-detail/panels/composer-dialogs.tsx +42 -0
  358. package/src/modules/messages/components/message-detail/panels/dialogs.tsx +107 -0
  359. package/src/modules/messages/components/message-detail/panels/index.ts +11 -0
  360. package/src/modules/messages/components/message-detail/panels/meta-panel.tsx +19 -0
  361. package/src/modules/messages/components/message-detail/panels/objects-panel.tsx +65 -0
  362. package/src/modules/messages/components/message-detail/panels/thread-panel.tsx +65 -0
  363. package/src/modules/messages/components/message-detail/types.ts +114 -0
  364. package/src/modules/messages/components/message-detail/utils.ts +62 -0
  365. package/src/modules/messages/components/utils/PriorityBadge.tsx +63 -0
  366. package/src/modules/messages/components/utils/typeUiRegistry.ts +106 -0
  367. package/src/modules/messages/data/entities.ts +284 -0
  368. package/src/modules/messages/data/validators.ts +297 -0
  369. package/src/modules/messages/emails/MessageEmail.tsx +143 -0
  370. package/src/modules/messages/events.ts +24 -0
  371. package/src/modules/messages/frontend/messages/view/[token]/page.meta.ts +5 -0
  372. package/src/modules/messages/frontend/messages/view/[token]/page.tsx +389 -0
  373. package/src/modules/messages/i18n/de.json +240 -0
  374. package/src/modules/messages/i18n/en.json +240 -0
  375. package/src/modules/messages/i18n/es.json +240 -0
  376. package/src/modules/messages/i18n/pl.json +240 -0
  377. package/src/modules/messages/index.ts +19 -0
  378. package/src/modules/messages/lib/actions.ts +204 -0
  379. package/src/modules/messages/lib/attachments.ts +197 -0
  380. package/src/modules/messages/lib/constants.ts +2 -0
  381. package/src/modules/messages/lib/email-sender.ts +255 -0
  382. package/src/modules/messages/lib/forwarding.ts +240 -0
  383. package/src/modules/messages/lib/message-objects-registry.ts +60 -0
  384. package/src/modules/messages/lib/message-types-registry.ts +48 -0
  385. package/src/modules/messages/lib/object-validation.ts +26 -0
  386. package/src/modules/messages/lib/operationMetadata.ts +43 -0
  387. package/src/modules/messages/lib/priorityUtils.ts +76 -0
  388. package/src/modules/messages/lib/routeHelpers.ts +65 -0
  389. package/src/modules/messages/message-objects.ts +5 -0
  390. package/src/modules/messages/message-types.ts +65 -0
  391. package/src/modules/messages/migrations/.snapshot-open-mercato.json +957 -0
  392. package/src/modules/messages/migrations/Migration20260213181243.ts +34 -0
  393. package/src/modules/messages/migrations/Migration20260215165126.ts +16 -0
  394. package/src/modules/messages/notifications.ts +25 -0
  395. package/src/modules/messages/setup.ts +19 -0
  396. package/src/modules/messages/subscribers/message-notification.ts +138 -0
  397. package/src/modules/messages/workers/send-email.worker.ts +321 -0
  398. package/src/modules/query_index/i18n/es.json +2 -2
  399. package/src/modules/resources/i18n/de.json +57 -0
  400. package/src/modules/resources/i18n/en.json +57 -0
  401. package/src/modules/resources/i18n/es.json +57 -0
  402. package/src/modules/resources/i18n/pl.json +57 -0
  403. package/src/modules/sales/backend/sales/documents/[id]/page.tsx +23 -7
  404. package/src/modules/sales/commands/payments.ts +12 -6
  405. package/src/modules/sales/i18n/de.json +26 -0
  406. package/src/modules/sales/i18n/en.json +26 -0
  407. package/src/modules/sales/i18n/es.json +26 -0
  408. package/src/modules/sales/i18n/pl.json +26 -0
  409. package/src/modules/sales/lib/messageObjectPreviews.ts +150 -0
  410. package/src/modules/sales/message-objects.ts +56 -0
  411. package/src/modules/sales/widgets/messages/SalesDocumentMessageDetail.tsx +57 -0
  412. package/src/modules/sales/widgets/messages/SalesDocumentMessagePreview.tsx +46 -0
  413. package/src/modules/sales/widgets/messages/index.ts +2 -0
  414. package/src/modules/staff/backend/staff/leave-requests/[id]/page.tsx +54 -0
  415. package/src/modules/staff/backend/staff/my-leave-requests/[id]/page.tsx +58 -0
  416. package/src/modules/staff/backend/staff/team-members/[id]/page.tsx +2 -32
  417. package/src/modules/staff/components/LeaveRequestDetail.tsx +135 -0
  418. package/src/modules/staff/components/LeaveRequestForm.tsx +3 -0
  419. package/src/modules/staff/components/LeaveRequestPreview.tsx +74 -0
  420. package/src/modules/staff/i18n/de.json +22 -0
  421. package/src/modules/staff/i18n/en.json +22 -0
  422. package/src/modules/staff/i18n/es.json +22 -0
  423. package/src/modules/staff/i18n/pl.json +22 -0
  424. package/src/modules/staff/lib/messageObjectPreviews.ts +182 -0
  425. package/src/modules/staff/message-objects.ts +102 -0
  426. package/src/modules/staff/message-types.ts +21 -0
  427. package/src/modules/staff/widgets/messages/StaffMessageObjectDetail.tsx +57 -0
  428. package/src/modules/staff/widgets/messages/StaffMessageObjectPreview.tsx +44 -0
  429. package/src/modules/staff/widgets/messages/index.ts +2 -0
  430. package/src/modules/workflows/backend/definitions/visual-editor/page.tsx +6 -6
  431. package/src/modules/workflows/i18n/de.json +41 -0
  432. package/src/modules/workflows/i18n/en.json +41 -0
  433. package/src/modules/workflows/i18n/es.json +41 -0
  434. package/src/modules/workflows/i18n/pl.json +41 -0
@@ -4,6 +4,12 @@
4
4
  "audit_logs.resource_kind.sales.payment": "Płatność",
5
5
  "audit_logs.resource_kind.sales.shipment": "Wysyłka",
6
6
  "customers~sales.nav.group": "Sprzedaż",
7
+ "sales.audit.channels.create": "Utwórz kanał sprzedaży",
8
+ "sales.audit.channels.delete": "Usuń kanał sprzedaży",
9
+ "sales.audit.channels.update": "Zaktualizuj kanał sprzedaży",
10
+ "sales.audit.notes.create": "Utwórz notatkę",
11
+ "sales.audit.notes.delete": "Usuń notatkę",
12
+ "sales.audit.notes.update": "Zaktualizuj notatkę",
7
13
  "sales.audit.orders.adjustments.delete": "Usuń korektę zamówienia",
8
14
  "sales.audit.orders.adjustments.upsert": "Zaktualizuj korektę zamówienia",
9
15
  "sales.audit.orders.create": "Utwórz zamówienie sprzedaży",
@@ -11,8 +17,12 @@
11
17
  "sales.audit.orders.lines.delete": "Usuń pozycję zamówienia",
12
18
  "sales.audit.orders.lines.upsert": "Zaktualizuj pozycję zamówienia",
13
19
  "sales.audit.orders.update": "Aktualizuj zamówienie sprzedaży",
20
+ "sales.audit.payments.create": "Utwórz płatność",
21
+ "sales.audit.payments.delete": "Usuń płatność",
22
+ "sales.audit.payments.update": "Zaktualizuj płatność",
14
23
  "sales.audit.quotes.adjustments.delete": "Usuń korektę oferty",
15
24
  "sales.audit.quotes.adjustments.upsert": "Zaktualizuj korektę oferty",
25
+ "sales.audit.quotes.convert": "Przekształć ofertę w zamówienie",
16
26
  "sales.audit.quotes.create": "Utwórz ofertę",
17
27
  "sales.audit.quotes.delete": "Usuń ofertę",
18
28
  "sales.audit.quotes.lines.delete": "Usuń pozycję oferty",
@@ -351,7 +361,11 @@
351
361
  "sales.config.statuses.lines.title": "Statusy pozycji",
352
362
  "sales.config.statuses.orders.description": "Skonfiguruj dostępne statusy dla zamówień sprzedaży.",
353
363
  "sales.config.statuses.orders.title": "Statusy zamówień",
364
+ "sales.config.statuses.payments.description": "Skonfiguruj dostępne wartości statusów dla płatności.",
365
+ "sales.config.statuses.payments.title": "Statusy płatności",
354
366
  "sales.config.statuses.search": "Szukaj statusów…",
367
+ "sales.config.statuses.shipments.description": "Skonfiguruj dostępne wartości statusów dla wysyłek.",
368
+ "sales.config.statuses.shipments.title": "Statusy wysyłek",
355
369
  "sales.config.statuses.success.delete": "Status usunięty.",
356
370
  "sales.config.statuses.success.save": "Status zapisany.",
357
371
  "sales.config.taxRates.actions.add": "Dodaj stawkę podatkową",
@@ -637,9 +651,11 @@
637
651
  "sales.documents.detail.items.variantSearch": "Szukaj wariantu",
638
652
  "sales.documents.detail.loading": "Ładowanie dokumentu…",
639
653
  "sales.documents.detail.number": "Numer dokumentu",
654
+ "sales.documents.detail.numberEditForbidden": "Numer dokumentu nie może być edytowany.",
640
655
  "sales.documents.detail.numberEmpty": "Brak numeru",
641
656
  "sales.documents.detail.numberGenerateError": "Nie udało się wygenerować numeru.",
642
657
  "sales.documents.detail.numberGenerated": "Wygenerowano nowy numer.",
658
+ "sales.documents.detail.numberRequired": "Numer dokumentu jest wymagany.",
643
659
  "sales.documents.detail.order": "Zamówienie",
644
660
  "sales.documents.detail.paymentMethod.empty": "Brak metod płatności.",
645
661
  "sales.documents.detail.paymentMethod.label": "Metoda płatności",
@@ -779,6 +795,8 @@
779
795
  "sales.documents.empty.adjustments.description": "Dodaj rabaty, opłaty lub podatki, aby doprecyzować sumy.",
780
796
  "sales.documents.empty.adjustments.title": "Brak korekt.",
781
797
  "sales.documents.errors.forbidden": "Brak uprawnień do generowania numerów.",
798
+ "sales.documents.errors.number_edit_forbidden": "Numer dokumentu nie może być edytowany.",
799
+ "sales.documents.errors.number_forbidden": "Operacja na numerze dokumentu jest niedozwolona.",
782
800
  "sales.documents.errors.number_generate_failed": "Nie udało się wygenerować numeru dokumentu.",
783
801
  "sales.documents.errors.organization_required": "Wymagany jest kontekst organizacji.",
784
802
  "sales.documents.errors.unauthorized": "Brak autoryzacji",
@@ -1084,8 +1102,13 @@
1084
1102
  "sales.documents.status.sectionTitle": "Zmiany statusu",
1085
1103
  "sales.errors.invalid_query": "Nieprawidłowe parametry zapytania",
1086
1104
  "sales.errors.organization_required": "Wymagany jest kontekst organizacji",
1105
+ "sales.errors.tag_invalid": "Nieprawidłowy format tagu.",
1106
+ "sales.errors.tag_required": "Tag jest wymagany.",
1087
1107
  "sales.errors.tenant_required": "Wymagany jest kontekst najemcy",
1088
1108
  "sales.errors.unauthorized": "Brak autoryzacji",
1109
+ "sales.messageObjects.notFound": "Nie znaleziono",
1110
+ "sales.messageObjects.order.title": "Zamówienie",
1111
+ "sales.messageObjects.quote.title": "Oferta",
1089
1112
  "sales.module.description": "Oferty, zamówienia, realizacja, fakturowanie i płatności powiązane z katalogiem produktów.",
1090
1113
  "sales.module.title": "Sprzedaż",
1091
1114
  "sales.nav.channels": "Kanały sprzedaży",
@@ -1141,6 +1164,9 @@
1141
1164
  "sales.orders.status_change.empty": "brak",
1142
1165
  "sales.orders.status_change.note": "Status zmieniony z {from} na {to} przez {actor}.",
1143
1166
  "sales.orders.update": "Aktualizuj zamówienie sprzedaży",
1167
+ "sales.payments.currency_mismatch": "Waluta płatności nie zgadza się z walutą zamówienia.",
1168
+ "sales.payments.not_found": "Nie znaleziono płatności.",
1169
+ "sales.payments.order_required": "Zamówienie jest wymagane dla tej płatności.",
1144
1170
  "sales.quotes.accept.adminEmail.body": "Klient zaakceptował ofertę {quoteNumber}. Utworzono zamówienie: {orderNumber}.",
1145
1171
  "sales.quotes.accept.adminEmail.cta": "Zobacz zamówienie",
1146
1172
  "sales.quotes.accept.adminEmail.footer": "Open Mercato",
@@ -0,0 +1,150 @@
1
+ import { createRequestContainer } from '@open-mercato/shared/lib/di/container'
2
+ import { findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'
3
+ import { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'
4
+ import type { ObjectPreviewData } from '@open-mercato/shared/modules/messages/types'
5
+ import type { EntityManager } from '@mikro-orm/postgresql'
6
+ import { SalesOrder, SalesQuote } from '../data/entities'
7
+
8
+ type PreviewContext = {
9
+ tenantId: string
10
+ organizationId?: string | null
11
+ }
12
+
13
+ type DocumentKind = 'order' | 'quote'
14
+
15
+ type SalesDocumentPreviewRecord = {
16
+ id: string
17
+ status?: string | null
18
+ customerSnapshot?: Record<string, unknown> | null
19
+ currencyCode?: string | null
20
+ grandTotalGrossAmount?: string | null
21
+ orderNumber?: string
22
+ quoteNumber?: string
23
+ }
24
+
25
+ function resolveCustomerName(snapshot: Record<string, unknown> | null): string | null {
26
+ if (!snapshot) return null
27
+ const customer = snapshot.customer as Record<string, unknown> | undefined
28
+ const contact = snapshot.contact as Record<string, unknown> | undefined
29
+ const displayName = typeof customer?.displayName === 'string' ? customer.displayName : null
30
+ if (displayName && displayName.trim().length > 0) return displayName.trim()
31
+ const first = typeof contact?.firstName === 'string' ? contact.firstName : null
32
+ const last = typeof contact?.lastName === 'string' ? contact.lastName : null
33
+ const preferred = typeof contact?.preferredName === 'string' ? contact.preferredName : null
34
+ const parts = [preferred ?? first, last]
35
+ .map((part) => (typeof part === 'string' ? part.trim() : ''))
36
+ .filter((part) => part.length > 0)
37
+ return parts.length > 0 ? parts.join(' ') : null
38
+ }
39
+
40
+ function formatTotal(amount: string | null | undefined, currency: string | null | undefined): string | null {
41
+ if (!amount) return null
42
+ const value = Number(amount)
43
+ if (!Number.isFinite(value)) return currency ? `${amount} ${currency}` : amount
44
+ if (!currency) return value.toLocaleString()
45
+ try {
46
+ return new Intl.NumberFormat(undefined, { style: 'currency', currency }).format(value)
47
+ } catch {
48
+ return `${value.toLocaleString()} ${currency}`
49
+ }
50
+ }
51
+
52
+ function statusColor(status: string | null | undefined): string | undefined {
53
+ if (!status) return undefined
54
+ const value = status.toLowerCase()
55
+ if (value.includes('approved') || value.includes('paid') || value.includes('fulfilled') || value.includes('accepted')) {
56
+ return 'green'
57
+ }
58
+ if (value.includes('cancel') || value.includes('rejected') || value.includes('void')) {
59
+ return 'red'
60
+ }
61
+ if (value.includes('draft') || value.includes('pending') || value.includes('open') || value.includes('sent')) {
62
+ return 'amber'
63
+ }
64
+ return 'blue'
65
+ }
66
+
67
+ async function buildPreview(kind: DocumentKind, entityId: string, record: SalesDocumentPreviewRecord | null): Promise<ObjectPreviewData> {
68
+ const { t } = await resolveTranslations()
69
+ const defaultTitle = kind === 'quote' ? t('sales.messageObjects.quote.title') : t('sales.messageObjects.order.title')
70
+ if (!record) {
71
+ return {
72
+ title: defaultTitle,
73
+ subtitle: entityId,
74
+ status: t('sales.messageObjects.notFound'),
75
+ statusColor: 'gray',
76
+ }
77
+ }
78
+
79
+ const number = kind === 'quote' ? record.quoteNumber : record.orderNumber
80
+ const customerName = resolveCustomerName(record.customerSnapshot ?? null)
81
+ const total = formatTotal(record.grandTotalGrossAmount, record.currencyCode)
82
+
83
+ const subtitleParts = [customerName, total].filter((part): part is string => Boolean(part && part.trim().length > 0))
84
+ const subtitle = subtitleParts.length > 0 ? subtitleParts.join(' • ') : entityId
85
+
86
+ const metadata: Record<string, string> = {}
87
+ if (number) metadata.Number = number
88
+ if (customerName) metadata.Customer = customerName
89
+ if (total) metadata.Total = total
90
+
91
+ return {
92
+ title: number && number.trim().length > 0 ? number : defaultTitle,
93
+ subtitle,
94
+ status: record.status ?? undefined,
95
+ statusColor: statusColor(record.status),
96
+ metadata: Object.keys(metadata).length > 0 ? metadata : undefined,
97
+ }
98
+ }
99
+
100
+ async function loadDocumentRecord(
101
+ kind: DocumentKind,
102
+ entityId: string,
103
+ ctx: PreviewContext,
104
+ ): Promise<SalesDocumentPreviewRecord | null> {
105
+ if (!ctx.organizationId) return null
106
+
107
+ const { resolve } = await createRequestContainer()
108
+ const em = resolve('em') as EntityManager
109
+ const scope = { tenantId: ctx.tenantId, organizationId: ctx.organizationId }
110
+
111
+ if (kind === 'quote') {
112
+ return await findOneWithDecryption(
113
+ em,
114
+ SalesQuote,
115
+ {
116
+ id: entityId,
117
+ tenantId: ctx.tenantId,
118
+ organizationId: ctx.organizationId,
119
+ deletedAt: null,
120
+ },
121
+ undefined,
122
+ scope,
123
+ )
124
+ }
125
+
126
+ return await findOneWithDecryption(
127
+ em,
128
+ SalesOrder,
129
+ {
130
+ id: entityId,
131
+ tenantId: ctx.tenantId,
132
+ organizationId: ctx.organizationId,
133
+ deletedAt: null,
134
+ },
135
+ undefined,
136
+ scope,
137
+ )
138
+ }
139
+
140
+ export async function loadSalesQuotePreview(entityId: string, ctx: PreviewContext): Promise<ObjectPreviewData> {
141
+ const record = await loadDocumentRecord('quote', entityId, ctx)
142
+ return await buildPreview('quote', entityId, record)
143
+ }
144
+
145
+ export async function loadSalesOrderPreview(entityId: string, ctx: PreviewContext): Promise<ObjectPreviewData> {
146
+ const record = await loadDocumentRecord('order', entityId, ctx)
147
+ return await buildPreview('order', entityId, record)
148
+ }
149
+
150
+
@@ -0,0 +1,56 @@
1
+ import type { MessageObjectTypeDefinition } from '@open-mercato/shared/modules/messages/types'
2
+ import { SalesDocumentMessageDetail } from './widgets/messages/SalesDocumentMessageDetail'
3
+ import { SalesDocumentMessagePreview } from './widgets/messages/SalesDocumentMessagePreview'
4
+
5
+ const objectMessageTypes = ['default', 'messages.defaultWithObjects']
6
+
7
+ export const messageObjectTypes: MessageObjectTypeDefinition[] = [
8
+ {
9
+ module: 'sales',
10
+ entityType: 'order',
11
+ messageTypes: objectMessageTypes,
12
+ entityId: 'sales:sales_order',
13
+ optionLabelField: 'number',
14
+ optionSubtitleField: 'status',
15
+ labelKey: 'sales.documents.detail.order',
16
+ icon: 'receipt-text',
17
+ PreviewComponent: SalesDocumentMessagePreview,
18
+ DetailComponent: SalesDocumentMessageDetail,
19
+ actions: [],
20
+ loadPreview: async (entityId, ctx) => {
21
+ if (typeof window !== 'undefined') {
22
+ return {
23
+ title: 'Sales order',
24
+ subtitle: entityId,
25
+ }
26
+ }
27
+ const { loadSalesOrderPreview } = await import('./lib/messageObjectPreviews')
28
+ return loadSalesOrderPreview(entityId, ctx)
29
+ },
30
+ },
31
+ {
32
+ module: 'sales',
33
+ entityType: 'quote',
34
+ messageTypes: objectMessageTypes,
35
+ entityId: 'sales:sales_quote',
36
+ optionLabelField: 'number',
37
+ optionSubtitleField: 'status',
38
+ labelKey: 'sales.documents.detail.quote',
39
+ icon: 'file-text',
40
+ PreviewComponent: SalesDocumentMessagePreview,
41
+ DetailComponent: SalesDocumentMessageDetail,
42
+ actions: [],
43
+ loadPreview: async (entityId, ctx) => {
44
+ if (typeof window !== 'undefined') {
45
+ return {
46
+ title: 'Sales quote',
47
+ subtitle: entityId,
48
+ }
49
+ }
50
+ const { loadSalesQuotePreview } = await import('./lib/messageObjectPreviews')
51
+ return loadSalesQuotePreview(entityId, ctx)
52
+ },
53
+ },
54
+ ]
55
+
56
+ export default messageObjectTypes
@@ -0,0 +1,57 @@
1
+ "use client"
2
+
3
+ import * as React from 'react'
4
+ import { useT } from '@open-mercato/shared/lib/i18n/context'
5
+ import type { ObjectDetailProps } from '@open-mercato/shared/modules/messages/types'
6
+ import { Button } from '@open-mercato/ui/primitives/button'
7
+ import { SalesDocumentMessagePreview } from './SalesDocumentMessagePreview'
8
+
9
+ export function SalesDocumentMessageDetail(props: ObjectDetailProps) {
10
+ const t = useT()
11
+ const [executingActionId, setExecutingActionId] = React.useState<string | null>(null)
12
+
13
+ return (
14
+ <div className="space-y-3 rounded border p-3">
15
+ <SalesDocumentMessagePreview
16
+ entityId={props.entityId}
17
+ entityModule={props.entityModule}
18
+ entityType={props.entityType}
19
+ snapshot={props.snapshot}
20
+ previewData={props.previewData}
21
+ actionRequired={props.actionRequired}
22
+ actionType={props.actionType}
23
+ actionLabel={props.actionLabel}
24
+ />
25
+
26
+ {props.actions.length > 0 ? (
27
+ <div className="flex flex-wrap gap-2">
28
+ {props.actions.map((action) => (
29
+ <Button
30
+ key={action.id}
31
+ type="button"
32
+ size="sm"
33
+ variant={action.variant ?? 'default'}
34
+ disabled={executingActionId !== null}
35
+ onClick={async () => {
36
+ if (executingActionId) return
37
+ setExecutingActionId(action.id)
38
+ try {
39
+ await props.onAction(action.id, { id: props.entityId })
40
+ } finally {
41
+ setExecutingActionId(null)
42
+ }
43
+ }}
44
+ >
45
+ {executingActionId === action.id
46
+ ? t('messages.actions.executing', 'Executing...')
47
+ : t(action.labelKey ?? action.id, action.id)}
48
+ </Button>
49
+ ))}
50
+ </div>
51
+ ) : null}
52
+ </div>
53
+ )
54
+ }
55
+
56
+ export default SalesDocumentMessageDetail
57
+
@@ -0,0 +1,46 @@
1
+ "use client"
2
+
3
+ import { FileText, ReceiptText } from 'lucide-react'
4
+ import { useT } from '@open-mercato/shared/lib/i18n/context'
5
+ import type { ObjectPreviewProps } from '@open-mercato/shared/modules/messages/types'
6
+ import { Badge } from '@open-mercato/ui/primitives/badge'
7
+
8
+ export function SalesDocumentMessagePreview({
9
+ entityType,
10
+ entityId,
11
+ previewData,
12
+ actionRequired,
13
+ actionLabel,
14
+ }: ObjectPreviewProps) {
15
+ const t = useT()
16
+ const isQuote = entityType === 'quote'
17
+ const Icon = isQuote ? FileText : ReceiptText
18
+ const fallbackTitle = isQuote
19
+ ? t('sales.documents.detail.quote', 'Sales quote')
20
+ : t('sales.documents.detail.order', 'Sales order')
21
+ const title = previewData?.title || fallbackTitle
22
+ const subtitle = previewData?.subtitle || entityId
23
+
24
+ return (
25
+ <div className="flex items-start gap-3 rounded-md border bg-muted/20 p-3">
26
+ <Icon className="mt-0.5 h-4 w-4 text-muted-foreground" />
27
+ <div className="min-w-0 flex-1 space-y-1">
28
+ <div className="flex items-center gap-2">
29
+ <p className="truncate text-sm font-medium">{title}</p>
30
+ {actionRequired ? (
31
+ <Badge variant="secondary" className="text-xs">
32
+ {actionLabel || t('messages.composer.objectActionRequired', 'Action required')}
33
+ </Badge>
34
+ ) : null}
35
+ </div>
36
+ <p className="truncate text-xs text-muted-foreground">{subtitle}</p>
37
+ {previewData?.status ? (
38
+ <Badge variant="outline" className="text-xs">{previewData.status}</Badge>
39
+ ) : null}
40
+ </div>
41
+ </div>
42
+ )
43
+ }
44
+
45
+ export default SalesDocumentMessagePreview
46
+
@@ -0,0 +1,2 @@
1
+ export { SalesDocumentMessageDetail } from './SalesDocumentMessageDetail'
2
+ export { SalesDocumentMessagePreview } from './SalesDocumentMessagePreview'
@@ -2,11 +2,13 @@
2
2
 
3
3
  import * as React from 'react'
4
4
  import { useRouter } from 'next/navigation'
5
+ import { Send } from 'lucide-react'
5
6
  import { Page, PageBody } from '@open-mercato/ui/backend/Page'
6
7
  import { Badge } from '@open-mercato/ui/primitives/badge'
7
8
  import { Button } from '@open-mercato/ui/primitives/button'
8
9
  import { Textarea } from '@open-mercato/ui/primitives/textarea'
9
10
  import { LoadingMessage, ErrorMessage } from '@open-mercato/ui/backend/detail'
11
+ import { SendObjectMessageDialog } from '@open-mercato/ui/backend/messages'
10
12
  import { apiCallOrThrow, readApiResultOrThrow } from '@open-mercato/ui/backend/utils/apiCall'
11
13
  import { updateCrud } from '@open-mercato/ui/backend/utils/crud'
12
14
  import { flash } from '@open-mercato/ui/backend/FlashMessages'
@@ -110,6 +112,20 @@ export default function StaffLeaveRequestDetailPage({ params }: { params?: { id?
110
112
  note: record?.note ?? null,
111
113
  }), [record, memberLabel])
112
114
 
115
+ const messageContextPreview = React.useMemo(() => (
116
+ <div className="space-y-1">
117
+ <p className="font-medium">{t('staff.leaveRequests.messages.contextTitle', 'Linked leave request')}</p>
118
+ {memberLabel ? (
119
+ <p className="text-xs text-muted-foreground">
120
+ {t('staff.leaveRequests.detail.member', 'Team member')}: {memberLabel}
121
+ </p>
122
+ ) : null}
123
+ <p className="text-xs text-muted-foreground">
124
+ {t('staff.leaveRequests.detail.dates', 'Dates')}: {dateSummary}
125
+ </p>
126
+ </div>
127
+ ), [dateSummary, memberLabel, t])
128
+
113
129
  const handleSubmit = React.useCallback(async (values: LeaveRequestFormValues) => {
114
130
  if (!record?.id) return
115
131
  const payload = buildLeaveRequestPayload(values, { id: record.id })
@@ -215,6 +231,44 @@ export default function StaffLeaveRequestDetailPage({ params }: { params?: { id?
215
231
  onSubmit={handleSubmit}
216
232
  allowMemberSelect
217
233
  memberLabel={memberLabel}
234
+ extraActions={record.id ? (
235
+ <SendObjectMessageDialog
236
+ object={{
237
+ entityModule: 'staff',
238
+ entityType: 'leave_request',
239
+ entityId: record.id,
240
+ sourceEntityType: 'staff:leave_request',
241
+ sourceEntityId: record.id,
242
+ }}
243
+ lockedType="staff.leave_request_approval"
244
+ requiredActionConfig={{
245
+ mode: 'required',
246
+ options: [
247
+ { id: 'approve', label: t('staff.notifications.leaveRequest.actions.approve', 'Approve') },
248
+ { id: 'reject', label: t('staff.notifications.leaveRequest.actions.reject', 'Reject') },
249
+ ],
250
+ }}
251
+ defaultValues={{
252
+ type: 'staff.leave_request_approval',
253
+ subject: t('staff.leaveRequests.messages.compose.subject', 'Leave request approval needed'),
254
+ body: t('staff.leaveRequests.messages.compose.body', 'Please review this leave request and take action.'),
255
+ }}
256
+ contextPreview={messageContextPreview}
257
+ renderTrigger={({ openComposer, disabled }) => (
258
+ <Button
259
+ type="button"
260
+ size="icon"
261
+ variant="outline"
262
+ onClick={openComposer}
263
+ disabled={disabled}
264
+ aria-label={t('staff.leaveRequests.messages.compose.action', 'Send for review')}
265
+ title={t('staff.leaveRequests.messages.compose.action', 'Send for review')}
266
+ >
267
+ <Send className="h-4 w-4" />
268
+ </Button>
269
+ )}
270
+ />
271
+ ) : null}
218
272
  />
219
273
  </PageBody>
220
274
  </Page>
@@ -2,9 +2,12 @@
2
2
 
3
3
  import * as React from 'react'
4
4
  import { useRouter } from 'next/navigation'
5
+ import { Leaf } from 'lucide-react'
5
6
  import { Page, PageBody } from '@open-mercato/ui/backend/Page'
6
7
  import { Badge } from '@open-mercato/ui/primitives/badge'
8
+ import { Button } from '@open-mercato/ui/primitives/button'
7
9
  import { LoadingMessage, ErrorMessage } from '@open-mercato/ui/backend/detail'
10
+ import { SendObjectMessageDialog } from '@open-mercato/ui/backend/messages'
8
11
  import { readApiResultOrThrow } from '@open-mercato/ui/backend/utils/apiCall'
9
12
  import { updateCrud } from '@open-mercato/ui/backend/utils/crud'
10
13
  import { flash } from '@open-mercato/ui/backend/FlashMessages'
@@ -95,6 +98,23 @@ export default function StaffMyLeaveRequestDetailPage({ params }: { params?: { i
95
98
  unavailabilityReasonValue: record?.unavailabilityReasonValue ?? record?.unavailability_reason_value ?? null,
96
99
  note: record?.note ?? null,
97
100
  }), [record, memberLabel])
101
+ const dateSummary = formatDateRange(
102
+ record?.startDate ?? record?.start_date ?? null,
103
+ record?.endDate ?? record?.end_date ?? null,
104
+ )
105
+ const messageContextPreview = React.useMemo(() => (
106
+ <div className="space-y-1">
107
+ <p className="font-medium">{t('staff.leaveRequests.messages.contextTitle', 'Linked leave request')}</p>
108
+ {memberLabel ? (
109
+ <p className="text-xs text-muted-foreground">
110
+ {t('staff.leaveRequests.detail.member', 'Team member')}: {memberLabel}
111
+ </p>
112
+ ) : null}
113
+ <p className="text-xs text-muted-foreground">
114
+ {t('staff.leaveRequests.detail.dates', 'Dates')}: {dateSummary}
115
+ </p>
116
+ </div>
117
+ ), [dateSummary, memberLabel, t])
98
118
 
99
119
  const handleSubmit = React.useCallback(async (values: LeaveRequestFormValues) => {
100
120
  if (!record?.id) return
@@ -158,6 +178,44 @@ export default function StaffMyLeaveRequestDetailPage({ params }: { params?: { i
158
178
  onSubmit={handleSubmit}
159
179
  allowMemberSelect={false}
160
180
  memberLabel={memberLabel}
181
+ extraActions={record.id ? (
182
+ <SendObjectMessageDialog
183
+ object={{
184
+ entityModule: 'staff',
185
+ entityType: 'leave_request',
186
+ entityId: record.id,
187
+ sourceEntityType: 'staff:leave_request',
188
+ sourceEntityId: record.id,
189
+ }}
190
+ lockedType="staff.leave_request_approval"
191
+ requiredActionConfig={{
192
+ mode: 'required',
193
+ options: [
194
+ { id: 'approve', label: t('staff.notifications.leaveRequest.actions.approve', 'Approve') },
195
+ { id: 'reject', label: t('staff.notifications.leaveRequest.actions.reject', 'Reject') },
196
+ ],
197
+ }}
198
+ defaultValues={{
199
+ type: 'staff.leave_request_approval',
200
+ subject: t('staff.leaveRequests.messages.compose.subject', 'Leave request approval needed'),
201
+ body: t('staff.leaveRequests.messages.compose.body', 'Please review this leave request and take action.'),
202
+ }}
203
+ contextPreview={messageContextPreview}
204
+ renderTrigger={({ openComposer, disabled }) => (
205
+ <Button
206
+ type="button"
207
+ size="icon"
208
+ variant="outline"
209
+ onClick={openComposer}
210
+ disabled={disabled}
211
+ aria-label={t('staff.leaveRequests.messages.compose.action', 'Send for review')}
212
+ title={t('staff.leaveRequests.messages.compose.action', 'Send for review')}
213
+ >
214
+ <Leaf className="h-4 w-4" />
215
+ </Button>
216
+ )}
217
+ />
218
+ ) : null}
161
219
  />
162
220
  ) : (
163
221
  <div className="rounded-lg border bg-card p-4 text-sm text-muted-foreground">
@@ -2,9 +2,7 @@
2
2
 
3
3
  import * as React from 'react'
4
4
  import Link from 'next/link'
5
- import dynamic from 'next/dynamic'
6
5
  import { useRouter, useSearchParams } from 'next/navigation'
7
- import type { PluggableList } from 'unified'
8
6
  import { Page, PageBody } from '@open-mercato/ui/backend/Page'
9
7
  import { Button } from '@open-mercato/ui/primitives/button'
10
8
  import { readApiResultOrThrow } from '@open-mercato/ui/backend/utils/apiCall'
@@ -23,6 +21,7 @@ import { renderDictionaryColor, renderDictionaryIcon, ICON_SUGGESTIONS } from '@
23
21
  import { createStaffNotesAdapter } from '@open-mercato/core/modules/staff/components/detail/notesAdapter'
24
22
  import { createStaffActivitiesAdapter } from '@open-mercato/core/modules/staff/components/detail/activitiesAdapter'
25
23
  import { createStaffAddressAdapter, createStaffAddressTypesAdapter } from '@open-mercato/core/modules/staff/components/detail/addressesAdapter'
24
+ import { MarkdownContent } from '@open-mercato/ui/backend/markdown/MarkdownContent'
26
25
  import {
27
26
  createStaffDictionaryEntry,
28
27
  loadStaffDictionary,
@@ -32,31 +31,9 @@ import { JobHistorySection } from '@open-mercato/core/modules/staff/components/d
32
31
  import type { DictionarySelectLabels } from '@open-mercato/core/modules/dictionaries/components/DictionaryEntrySelect'
33
32
  import { Plus } from 'lucide-react'
34
33
 
35
- const isTestEnv = typeof process !== 'undefined' && process.env.NODE_ENV === 'test'
36
34
  const MARKDOWN_CLASSNAME =
37
35
  'text-sm text-muted-foreground break-words [&>*]:mb-2 [&>*:last-child]:mb-0 [&_ul]:ml-4 [&_ul]:list-disc [&_ol]:ml-4 [&_ol]:list-decimal [&_code]:rounded [&_code]:bg-muted [&_code]:px-1 [&_code]:py-0.5 [&_pre]:rounded-md [&_pre]:bg-muted [&_pre]:p-3 [&_pre]:text-xs'
38
36
 
39
- type MarkdownPreviewProps = { children: string; className?: string; remarkPlugins?: PluggableList }
40
-
41
- const MarkdownPreview: React.ComponentType<MarkdownPreviewProps> = isTestEnv
42
- ? ({ children, className }) => <div className={className}>{children}</div>
43
- : (dynamic(() => import('react-markdown').then((mod) => mod.default as React.ComponentType<MarkdownPreviewProps>), {
44
- ssr: false,
45
- loading: () => null,
46
- }) as unknown as React.ComponentType<MarkdownPreviewProps>)
47
-
48
- let markdownPluginsPromise: Promise<PluggableList> | null = null
49
-
50
- async function loadMarkdownPlugins(): Promise<PluggableList> {
51
- if (isTestEnv) return []
52
- if (!markdownPluginsPromise) {
53
- markdownPluginsPromise = import('remark-gfm')
54
- .then((mod) => [mod.default ?? mod] as PluggableList)
55
- .catch(() => [])
56
- }
57
- return markdownPluginsPromise
58
- }
59
-
60
37
  type TeamMemberRecord = {
61
38
  id: string
62
39
  teamId?: string | null
@@ -97,7 +74,6 @@ export default function StaffTeamMemberDetailPage({ params }: { params?: { id?:
97
74
  const [sectionAction, setSectionAction] = React.useState<SectionAction | null>(null)
98
75
  const [activityDictionaryId, setActivityDictionaryId] = React.useState<string | null>(null)
99
76
  const [activityTypeEntries, setActivityTypeEntries] = React.useState<DictionaryEntryOption[]>([])
100
- const [markdownPlugins, setMarkdownPlugins] = React.useState<PluggableList>([])
101
77
  const flashShownRef = React.useRef(false)
102
78
 
103
79
  const notesAdapter = React.useMemo(() => createStaffNotesAdapter(detailTranslator), [detailTranslator])
@@ -105,10 +81,6 @@ export default function StaffTeamMemberDetailPage({ params }: { params?: { id?:
105
81
  const addressesAdapter = React.useMemo(() => createStaffAddressAdapter(detailTranslator), [detailTranslator])
106
82
  const addressTypesAdapter = React.useMemo(() => createStaffAddressTypesAdapter(detailTranslator), [detailTranslator])
107
83
 
108
- React.useEffect(() => {
109
- void loadMarkdownPlugins().then((plugins) => setMarkdownPlugins(plugins))
110
- }, [])
111
-
112
84
  const activityTypeLabels = React.useMemo<DictionarySelectLabels>(() => ({
113
85
  placeholder: t('staff.teamMembers.detail.activities.dictionary.placeholder', 'Select an activity type'),
114
86
  addLabel: t('staff.teamMembers.detail.activities.dictionary.add', 'Add type'),
@@ -519,9 +491,7 @@ export default function StaffTeamMemberDetailPage({ params }: { params?: { id?:
519
491
  </h2>
520
492
  <div className="space-y-2">
521
493
  {memberRecord?.description ? (
522
- <MarkdownPreview remarkPlugins={markdownPlugins} className={MARKDOWN_CLASSNAME}>
523
- {memberRecord.description}
524
- </MarkdownPreview>
494
+ <MarkdownContent body={memberRecord.description} format="markdown" className={MARKDOWN_CLASSNAME} />
525
495
  ) : (
526
496
  <p className="text-sm text-muted-foreground">
527
497
  {t('staff.teamMembers.detail.descriptionEmpty', 'No description provided.')}