@open-mercato/core 0.4.5-develop-5191db4ef3 → 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 (385) 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/customers/backend/customers/deals/[id]/page.js +27 -8
  16. package/dist/modules/customers/backend/customers/deals/[id]/page.js.map +2 -2
  17. package/dist/modules/customers/lib/messageObjectPreviews.js +131 -0
  18. package/dist/modules/customers/lib/messageObjectPreviews.js.map +7 -0
  19. package/dist/modules/customers/message-objects.js +71 -0
  20. package/dist/modules/customers/message-objects.js.map +7 -0
  21. package/dist/modules/customers/widgets/messages/CustomerMessageObjectDetail.js +51 -0
  22. package/dist/modules/customers/widgets/messages/CustomerMessageObjectDetail.js.map +7 -0
  23. package/dist/modules/customers/widgets/messages/CustomerMessageObjectPreview.js +35 -0
  24. package/dist/modules/customers/widgets/messages/CustomerMessageObjectPreview.js.map +7 -0
  25. package/dist/modules/customers/widgets/messages/index.js +7 -0
  26. package/dist/modules/customers/widgets/messages/index.js.map +7 -0
  27. package/dist/modules/messages/acl.js +15 -0
  28. package/dist/modules/messages/acl.js.map +7 -0
  29. package/dist/modules/messages/api/[id]/actions/[actionId]/route.js +92 -0
  30. package/dist/modules/messages/api/[id]/actions/[actionId]/route.js.map +7 -0
  31. package/dist/modules/messages/api/[id]/archive/route.js +120 -0
  32. package/dist/modules/messages/api/[id]/archive/route.js.map +7 -0
  33. package/dist/modules/messages/api/[id]/attachments/route.js +195 -0
  34. package/dist/modules/messages/api/[id]/attachments/route.js.map +7 -0
  35. package/dist/modules/messages/api/[id]/confirmation/route.js +67 -0
  36. package/dist/modules/messages/api/[id]/confirmation/route.js.map +7 -0
  37. package/dist/modules/messages/api/[id]/conversation/archive/route.js +68 -0
  38. package/dist/modules/messages/api/[id]/conversation/archive/route.js.map +7 -0
  39. package/dist/modules/messages/api/[id]/conversation/read/route.js +68 -0
  40. package/dist/modules/messages/api/[id]/conversation/read/route.js.map +7 -0
  41. package/dist/modules/messages/api/[id]/conversation/route.js +68 -0
  42. package/dist/modules/messages/api/[id]/conversation/route.js.map +7 -0
  43. package/dist/modules/messages/api/[id]/forward/route.js +85 -0
  44. package/dist/modules/messages/api/[id]/forward/route.js.map +7 -0
  45. package/dist/modules/messages/api/[id]/forward-preview/route.js +70 -0
  46. package/dist/modules/messages/api/[id]/forward-preview/route.js.map +7 -0
  47. package/dist/modules/messages/api/[id]/read/route.js +120 -0
  48. package/dist/modules/messages/api/[id]/read/route.js.map +7 -0
  49. package/dist/modules/messages/api/[id]/reply/route.js +87 -0
  50. package/dist/modules/messages/api/[id]/reply/route.js.map +7 -0
  51. package/dist/modules/messages/api/[id]/route.js +350 -0
  52. package/dist/modules/messages/api/[id]/route.js.map +7 -0
  53. package/dist/modules/messages/api/object-types/route.js +54 -0
  54. package/dist/modules/messages/api/object-types/route.js.map +7 -0
  55. package/dist/modules/messages/api/openapi.js +261 -0
  56. package/dist/modules/messages/api/openapi.js.map +7 -0
  57. package/dist/modules/messages/api/route.js +262 -0
  58. package/dist/modules/messages/api/route.js.map +7 -0
  59. package/dist/modules/messages/api/token/[token]/route.js +99 -0
  60. package/dist/modules/messages/api/token/[token]/route.js.map +7 -0
  61. package/dist/modules/messages/api/types/route.js +40 -0
  62. package/dist/modules/messages/api/types/route.js.map +7 -0
  63. package/dist/modules/messages/api/unread-count/route.js +43 -0
  64. package/dist/modules/messages/api/unread-count/route.js.map +7 -0
  65. package/dist/modules/messages/backend/messages/[id]/page.js +10 -0
  66. package/dist/modules/messages/backend/messages/[id]/page.js.map +7 -0
  67. package/dist/modules/messages/backend/messages/[id]/page.meta.js +16 -0
  68. package/dist/modules/messages/backend/messages/[id]/page.meta.js.map +7 -0
  69. package/dist/modules/messages/backend/messages/compose/page.js +10 -0
  70. package/dist/modules/messages/backend/messages/compose/page.js.map +7 -0
  71. package/dist/modules/messages/backend/messages/compose/page.meta.js +17 -0
  72. package/dist/modules/messages/backend/messages/compose/page.meta.js.map +7 -0
  73. package/dist/modules/messages/backend/page.js +10 -0
  74. package/dist/modules/messages/backend/page.js.map +7 -0
  75. package/dist/modules/messages/backend/page.meta.js +33 -0
  76. package/dist/modules/messages/backend/page.meta.js.map +7 -0
  77. package/dist/modules/messages/commands/actions.js +265 -0
  78. package/dist/modules/messages/commands/actions.js.map +7 -0
  79. package/dist/modules/messages/commands/attachments.js +217 -0
  80. package/dist/modules/messages/commands/attachments.js.map +7 -0
  81. package/dist/modules/messages/commands/confirmations.js +151 -0
  82. package/dist/modules/messages/commands/confirmations.js.map +7 -0
  83. package/dist/modules/messages/commands/conversation.js +240 -0
  84. package/dist/modules/messages/commands/conversation.js.map +7 -0
  85. package/dist/modules/messages/commands/messages.js +748 -0
  86. package/dist/modules/messages/commands/messages.js.map +7 -0
  87. package/dist/modules/messages/commands/recipients.js +259 -0
  88. package/dist/modules/messages/commands/recipients.js.map +7 -0
  89. package/dist/modules/messages/commands/shared.js +258 -0
  90. package/dist/modules/messages/commands/shared.js.map +7 -0
  91. package/dist/modules/messages/commands/tokens.js +69 -0
  92. package/dist/modules/messages/commands/tokens.js.map +7 -0
  93. package/dist/modules/messages/components/ComposeMessagePageClient.js +24 -0
  94. package/dist/modules/messages/components/ComposeMessagePageClient.js.map +7 -0
  95. package/dist/modules/messages/components/MessageDetailPageClient.js +261 -0
  96. package/dist/modules/messages/components/MessageDetailPageClient.js.map +7 -0
  97. package/dist/modules/messages/components/MessagesInboxPageClient.js +390 -0
  98. package/dist/modules/messages/components/MessagesInboxPageClient.js.map +7 -0
  99. package/dist/modules/messages/components/confirmation/MessageConfirmationActions.js +31 -0
  100. package/dist/modules/messages/components/confirmation/MessageConfirmationActions.js.map +7 -0
  101. package/dist/modules/messages/components/confirmation/MessageConfirmationContent.js +69 -0
  102. package/dist/modules/messages/components/confirmation/MessageConfirmationContent.js.map +7 -0
  103. package/dist/modules/messages/components/defaults/DefaultMessageActions.js +31 -0
  104. package/dist/modules/messages/components/defaults/DefaultMessageActions.js.map +7 -0
  105. package/dist/modules/messages/components/defaults/DefaultMessageContent.js +19 -0
  106. package/dist/modules/messages/components/defaults/DefaultMessageContent.js.map +7 -0
  107. package/dist/modules/messages/components/defaults/DefaultMessageListItem.js +90 -0
  108. package/dist/modules/messages/components/defaults/DefaultMessageListItem.js.map +7 -0
  109. package/dist/modules/messages/components/defaults/MessageRecordObjectDetail.js +86 -0
  110. package/dist/modules/messages/components/defaults/MessageRecordObjectDetail.js.map +7 -0
  111. package/dist/modules/messages/components/defaults/MessageRecordObjectPreview.js +61 -0
  112. package/dist/modules/messages/components/defaults/MessageRecordObjectPreview.js.map +7 -0
  113. package/dist/modules/messages/components/message-detail/detail-panels.js +27 -0
  114. package/dist/modules/messages/components/message-detail/detail-panels.js.map +7 -0
  115. package/dist/modules/messages/components/message-detail/hooks/useMessageDetails.js +52 -0
  116. package/dist/modules/messages/components/message-detail/hooks/useMessageDetails.js.map +7 -0
  117. package/dist/modules/messages/components/message-detail/hooks/useMessageDetailsActions.js +289 -0
  118. package/dist/modules/messages/components/message-detail/hooks/useMessageDetailsActions.js.map +7 -0
  119. package/dist/modules/messages/components/message-detail/hooks/useMessageDetailsConversation.js +103 -0
  120. package/dist/modules/messages/components/message-detail/hooks/useMessageDetailsConversation.js.map +7 -0
  121. package/dist/modules/messages/components/message-detail/hooks/useMessageDetailsQueries.js +78 -0
  122. package/dist/modules/messages/components/message-detail/hooks/useMessageDetailsQueries.js.map +7 -0
  123. package/dist/modules/messages/components/message-detail/panels/MainMessageHeader.js +94 -0
  124. package/dist/modules/messages/components/message-detail/panels/MainMessageHeader.js.map +7 -0
  125. package/dist/modules/messages/components/message-detail/panels/MessageHeader.js +110 -0
  126. package/dist/modules/messages/components/message-detail/panels/MessageHeader.js.map +7 -0
  127. package/dist/modules/messages/components/message-detail/panels/MessageListComponent.js +58 -0
  128. package/dist/modules/messages/components/message-detail/panels/MessageListComponent.js.map +7 -0
  129. package/dist/modules/messages/components/message-detail/panels/actions-panel.js +51 -0
  130. package/dist/modules/messages/components/message-detail/panels/actions-panel.js.map +7 -0
  131. package/dist/modules/messages/components/message-detail/panels/attachments-panel.js +66 -0
  132. package/dist/modules/messages/components/message-detail/panels/attachments-panel.js.map +7 -0
  133. package/dist/modules/messages/components/message-detail/panels/body-panel.js +20 -0
  134. package/dist/modules/messages/components/message-detail/panels/body-panel.js.map +7 -0
  135. package/dist/modules/messages/components/message-detail/panels/composer-dialogs.js +36 -0
  136. package/dist/modules/messages/components/message-detail/panels/composer-dialogs.js.map +7 -0
  137. package/dist/modules/messages/components/message-detail/panels/dialogs.js +96 -0
  138. package/dist/modules/messages/components/message-detail/panels/dialogs.js.map +7 -0
  139. package/dist/modules/messages/components/message-detail/panels/index.js +25 -0
  140. package/dist/modules/messages/components/message-detail/panels/index.js.map +7 -0
  141. package/dist/modules/messages/components/message-detail/panels/meta-panel.js +14 -0
  142. package/dist/modules/messages/components/message-detail/panels/meta-panel.js.map +7 -0
  143. package/dist/modules/messages/components/message-detail/panels/objects-panel.js +51 -0
  144. package/dist/modules/messages/components/message-detail/panels/objects-panel.js.map +7 -0
  145. package/dist/modules/messages/components/message-detail/panels/thread-panel.js +54 -0
  146. package/dist/modules/messages/components/message-detail/panels/thread-panel.js.map +7 -0
  147. package/dist/modules/messages/components/message-detail/types.js +1 -0
  148. package/dist/modules/messages/components/message-detail/types.js.map +7 -0
  149. package/dist/modules/messages/components/message-detail/utils.js +54 -0
  150. package/dist/modules/messages/components/message-detail/utils.js.map +7 -0
  151. package/dist/modules/messages/components/utils/PriorityBadge.js +52 -0
  152. package/dist/modules/messages/components/utils/PriorityBadge.js.map +7 -0
  153. package/dist/modules/messages/components/utils/typeUiRegistry.js +77 -0
  154. package/dist/modules/messages/components/utils/typeUiRegistry.js.map +7 -0
  155. package/dist/modules/messages/data/entities.js +309 -0
  156. package/dist/modules/messages/data/entities.js.map +7 -0
  157. package/dist/modules/messages/data/validators.js +272 -0
  158. package/dist/modules/messages/data/validators.js.map +7 -0
  159. package/dist/modules/messages/emails/MessageEmail.js +108 -0
  160. package/dist/modules/messages/emails/MessageEmail.js.map +7 -0
  161. package/dist/modules/messages/events.js +24 -0
  162. package/dist/modules/messages/events.js.map +7 -0
  163. package/dist/modules/messages/frontend/messages/view/[token]/page.js +247 -0
  164. package/dist/modules/messages/frontend/messages/view/[token]/page.js.map +7 -0
  165. package/dist/modules/messages/frontend/messages/view/[token]/page.meta.js +9 -0
  166. package/dist/modules/messages/frontend/messages/view/[token]/page.meta.js.map +7 -0
  167. package/dist/modules/messages/index.js +21 -0
  168. package/dist/modules/messages/index.js.map +7 -0
  169. package/dist/modules/messages/lib/actions.js +141 -0
  170. package/dist/modules/messages/lib/actions.js.map +7 -0
  171. package/dist/modules/messages/lib/attachments.js +131 -0
  172. package/dist/modules/messages/lib/attachments.js.map +7 -0
  173. package/dist/modules/messages/lib/constants.js +7 -0
  174. package/dist/modules/messages/lib/constants.js.map +7 -0
  175. package/dist/modules/messages/lib/email-sender.js +201 -0
  176. package/dist/modules/messages/lib/email-sender.js.map +7 -0
  177. package/dist/modules/messages/lib/forwarding.js +179 -0
  178. package/dist/modules/messages/lib/forwarding.js.map +7 -0
  179. package/dist/modules/messages/lib/message-objects-registry.js +49 -0
  180. package/dist/modules/messages/lib/message-objects-registry.js.map +7 -0
  181. package/dist/modules/messages/lib/message-types-registry.js +41 -0
  182. package/dist/modules/messages/lib/message-types-registry.js.map +7 -0
  183. package/dist/modules/messages/lib/object-validation.js +20 -0
  184. package/dist/modules/messages/lib/object-validation.js.map +7 -0
  185. package/dist/modules/messages/lib/operationMetadata.js +21 -0
  186. package/dist/modules/messages/lib/operationMetadata.js.map +7 -0
  187. package/dist/modules/messages/lib/priorityUtils.js +61 -0
  188. package/dist/modules/messages/lib/priorityUtils.js.map +7 -0
  189. package/dist/modules/messages/lib/routeHelpers.js +44 -0
  190. package/dist/modules/messages/lib/routeHelpers.js.map +7 -0
  191. package/dist/modules/messages/message-objects.js +7 -0
  192. package/dist/modules/messages/message-objects.js.map +7 -0
  193. package/dist/modules/messages/message-types.js +67 -0
  194. package/dist/modules/messages/message-types.js.map +7 -0
  195. package/dist/modules/messages/migrations/Migration20260213181243.js +31 -0
  196. package/dist/modules/messages/migrations/Migration20260213181243.js.map +7 -0
  197. package/dist/modules/messages/migrations/Migration20260215165126.js +16 -0
  198. package/dist/modules/messages/migrations/Migration20260215165126.js.map +7 -0
  199. package/dist/modules/messages/notifications.js +27 -0
  200. package/dist/modules/messages/notifications.js.map +7 -0
  201. package/dist/modules/messages/setup.js +21 -0
  202. package/dist/modules/messages/setup.js.map +7 -0
  203. package/dist/modules/messages/subscribers/message-notification.js +108 -0
  204. package/dist/modules/messages/subscribers/message-notification.js.map +7 -0
  205. package/dist/modules/messages/workers/send-email.worker.js +253 -0
  206. package/dist/modules/messages/workers/send-email.worker.js.map +7 -0
  207. package/dist/modules/sales/backend/sales/documents/[id]/page.js +30 -11
  208. package/dist/modules/sales/backend/sales/documents/[id]/page.js.map +2 -2
  209. package/dist/modules/sales/commands/payments.js +12 -6
  210. package/dist/modules/sales/commands/payments.js.map +2 -2
  211. package/dist/modules/sales/lib/messageObjectPreviews.js +114 -0
  212. package/dist/modules/sales/lib/messageObjectPreviews.js.map +7 -0
  213. package/dist/modules/sales/message-objects.js +57 -0
  214. package/dist/modules/sales/message-objects.js.map +7 -0
  215. package/dist/modules/sales/widgets/messages/SalesDocumentMessageDetail.js +51 -0
  216. package/dist/modules/sales/widgets/messages/SalesDocumentMessageDetail.js.map +7 -0
  217. package/dist/modules/sales/widgets/messages/SalesDocumentMessagePreview.js +36 -0
  218. package/dist/modules/sales/widgets/messages/SalesDocumentMessagePreview.js.map +7 -0
  219. package/dist/modules/sales/widgets/messages/index.js +7 -0
  220. package/dist/modules/sales/widgets/messages/index.js.map +7 -0
  221. package/dist/modules/staff/backend/staff/leave-requests/[id]/page.js +55 -1
  222. package/dist/modules/staff/backend/staff/leave-requests/[id]/page.js.map +2 -2
  223. package/dist/modules/staff/backend/staff/my-leave-requests/[id]/page.js +60 -1
  224. package/dist/modules/staff/backend/staff/my-leave-requests/[id]/page.js.map +2 -2
  225. package/dist/modules/staff/backend/staff/team-members/[id]/page.js +2 -19
  226. package/dist/modules/staff/backend/staff/team-members/[id]/page.js.map +2 -2
  227. package/dist/modules/staff/components/LeaveRequestDetail.js +112 -0
  228. package/dist/modules/staff/components/LeaveRequestDetail.js.map +7 -0
  229. package/dist/modules/staff/components/LeaveRequestForm.js +3 -1
  230. package/dist/modules/staff/components/LeaveRequestForm.js.map +2 -2
  231. package/dist/modules/staff/components/LeaveRequestPreview.js +43 -0
  232. package/dist/modules/staff/components/LeaveRequestPreview.js.map +7 -0
  233. package/dist/modules/staff/lib/messageObjectPreviews.js +148 -0
  234. package/dist/modules/staff/lib/messageObjectPreviews.js.map +7 -0
  235. package/dist/modules/staff/message-objects.js +104 -0
  236. package/dist/modules/staff/message-objects.js.map +7 -0
  237. package/dist/modules/staff/message-types.js +23 -0
  238. package/dist/modules/staff/message-types.js.map +7 -0
  239. package/dist/modules/staff/widgets/messages/StaffMessageObjectDetail.js +51 -0
  240. package/dist/modules/staff/widgets/messages/StaffMessageObjectDetail.js.map +7 -0
  241. package/dist/modules/staff/widgets/messages/StaffMessageObjectPreview.js +34 -0
  242. package/dist/modules/staff/widgets/messages/StaffMessageObjectPreview.js.map +7 -0
  243. package/dist/modules/staff/widgets/messages/index.js +7 -0
  244. package/dist/modules/staff/widgets/messages/index.js.map +7 -0
  245. package/generated/entities/message/index.ts +31 -0
  246. package/generated/entities/message_access_token/index.ts +8 -0
  247. package/generated/entities/message_confirmation/index.ts +9 -0
  248. package/generated/entities/message_object/index.ts +10 -0
  249. package/generated/entities/message_recipient/index.ts +14 -0
  250. package/generated/entities.ids.generated.ts +8 -0
  251. package/generated/entity-fields-registry.ts +10 -0
  252. package/jest.setup.ts +5 -0
  253. package/package.json +2 -2
  254. package/src/modules/customers/backend/customers/deals/[id]/page.tsx +20 -4
  255. package/src/modules/customers/i18n/de.json +4 -0
  256. package/src/modules/customers/i18n/en.json +4 -0
  257. package/src/modules/customers/i18n/es.json +4 -0
  258. package/src/modules/customers/i18n/pl.json +4 -0
  259. package/src/modules/customers/lib/messageObjectPreviews.ts +154 -0
  260. package/src/modules/customers/message-objects.ts +70 -0
  261. package/src/modules/customers/widgets/messages/CustomerMessageObjectDetail.tsx +57 -0
  262. package/src/modules/customers/widgets/messages/CustomerMessageObjectPreview.tsx +49 -0
  263. package/src/modules/customers/widgets/messages/index.ts +2 -0
  264. package/src/modules/messages/acl.ts +11 -0
  265. package/src/modules/messages/api/[id]/actions/[actionId]/route.ts +103 -0
  266. package/src/modules/messages/api/[id]/archive/route.ts +138 -0
  267. package/src/modules/messages/api/[id]/attachments/route.ts +217 -0
  268. package/src/modules/messages/api/[id]/confirmation/route.ts +73 -0
  269. package/src/modules/messages/api/[id]/conversation/archive/route.ts +69 -0
  270. package/src/modules/messages/api/[id]/conversation/read/route.ts +69 -0
  271. package/src/modules/messages/api/[id]/conversation/route.ts +69 -0
  272. package/src/modules/messages/api/[id]/forward/route.ts +87 -0
  273. package/src/modules/messages/api/[id]/forward-preview/route.ts +75 -0
  274. package/src/modules/messages/api/[id]/read/route.ts +138 -0
  275. package/src/modules/messages/api/[id]/reply/route.ts +89 -0
  276. package/src/modules/messages/api/[id]/route.ts +401 -0
  277. package/src/modules/messages/api/object-types/route.ts +54 -0
  278. package/src/modules/messages/api/openapi.ts +261 -0
  279. package/src/modules/messages/api/route.ts +374 -0
  280. package/src/modules/messages/api/token/[token]/route.ts +103 -0
  281. package/src/modules/messages/api/types/route.ts +39 -0
  282. package/src/modules/messages/api/unread-count/route.ts +55 -0
  283. package/src/modules/messages/backend/messages/[id]/page.meta.ts +12 -0
  284. package/src/modules/messages/backend/messages/[id]/page.tsx +12 -0
  285. package/src/modules/messages/backend/messages/compose/page.meta.ts +13 -0
  286. package/src/modules/messages/backend/messages/compose/page.tsx +12 -0
  287. package/src/modules/messages/backend/page.meta.ts +31 -0
  288. package/src/modules/messages/backend/page.tsx +12 -0
  289. package/src/modules/messages/commands/actions.ts +307 -0
  290. package/src/modules/messages/commands/attachments.ts +227 -0
  291. package/src/modules/messages/commands/confirmations.ts +183 -0
  292. package/src/modules/messages/commands/conversation.ts +292 -0
  293. package/src/modules/messages/commands/messages.ts +845 -0
  294. package/src/modules/messages/commands/recipients.ts +281 -0
  295. package/src/modules/messages/commands/shared.ts +350 -0
  296. package/src/modules/messages/commands/tokens.ts +80 -0
  297. package/src/modules/messages/components/ComposeMessagePageClient.tsx +23 -0
  298. package/src/modules/messages/components/MessageDetailPageClient.tsx +287 -0
  299. package/src/modules/messages/components/MessagesInboxPageClient.tsx +469 -0
  300. package/src/modules/messages/components/confirmation/MessageConfirmationActions.tsx +35 -0
  301. package/src/modules/messages/components/confirmation/MessageConfirmationContent.tsx +88 -0
  302. package/src/modules/messages/components/defaults/DefaultMessageActions.tsx +37 -0
  303. package/src/modules/messages/components/defaults/DefaultMessageContent.tsx +21 -0
  304. package/src/modules/messages/components/defaults/DefaultMessageListItem.tsx +102 -0
  305. package/src/modules/messages/components/defaults/MessageRecordObjectDetail.tsx +114 -0
  306. package/src/modules/messages/components/defaults/MessageRecordObjectPreview.tsx +74 -0
  307. package/src/modules/messages/components/message-detail/detail-panels.ts +13 -0
  308. package/src/modules/messages/components/message-detail/hooks/useMessageDetails.ts +56 -0
  309. package/src/modules/messages/components/message-detail/hooks/useMessageDetailsActions.ts +367 -0
  310. package/src/modules/messages/components/message-detail/hooks/useMessageDetailsConversation.ts +134 -0
  311. package/src/modules/messages/components/message-detail/hooks/useMessageDetailsQueries.ts +102 -0
  312. package/src/modules/messages/components/message-detail/panels/MainMessageHeader.tsx +108 -0
  313. package/src/modules/messages/components/message-detail/panels/MessageHeader.tsx +144 -0
  314. package/src/modules/messages/components/message-detail/panels/MessageListComponent.tsx +63 -0
  315. package/src/modules/messages/components/message-detail/panels/actions-panel.tsx +66 -0
  316. package/src/modules/messages/components/message-detail/panels/attachments-panel.tsx +86 -0
  317. package/src/modules/messages/components/message-detail/panels/body-panel.tsx +32 -0
  318. package/src/modules/messages/components/message-detail/panels/composer-dialogs.tsx +42 -0
  319. package/src/modules/messages/components/message-detail/panels/dialogs.tsx +107 -0
  320. package/src/modules/messages/components/message-detail/panels/index.ts +11 -0
  321. package/src/modules/messages/components/message-detail/panels/meta-panel.tsx +19 -0
  322. package/src/modules/messages/components/message-detail/panels/objects-panel.tsx +65 -0
  323. package/src/modules/messages/components/message-detail/panels/thread-panel.tsx +65 -0
  324. package/src/modules/messages/components/message-detail/types.ts +114 -0
  325. package/src/modules/messages/components/message-detail/utils.ts +62 -0
  326. package/src/modules/messages/components/utils/PriorityBadge.tsx +63 -0
  327. package/src/modules/messages/components/utils/typeUiRegistry.ts +106 -0
  328. package/src/modules/messages/data/entities.ts +284 -0
  329. package/src/modules/messages/data/validators.ts +297 -0
  330. package/src/modules/messages/emails/MessageEmail.tsx +143 -0
  331. package/src/modules/messages/events.ts +24 -0
  332. package/src/modules/messages/frontend/messages/view/[token]/page.meta.ts +5 -0
  333. package/src/modules/messages/frontend/messages/view/[token]/page.tsx +389 -0
  334. package/src/modules/messages/i18n/de.json +240 -0
  335. package/src/modules/messages/i18n/en.json +240 -0
  336. package/src/modules/messages/i18n/es.json +240 -0
  337. package/src/modules/messages/i18n/pl.json +240 -0
  338. package/src/modules/messages/index.ts +19 -0
  339. package/src/modules/messages/lib/actions.ts +204 -0
  340. package/src/modules/messages/lib/attachments.ts +197 -0
  341. package/src/modules/messages/lib/constants.ts +2 -0
  342. package/src/modules/messages/lib/email-sender.ts +255 -0
  343. package/src/modules/messages/lib/forwarding.ts +240 -0
  344. package/src/modules/messages/lib/message-objects-registry.ts +60 -0
  345. package/src/modules/messages/lib/message-types-registry.ts +48 -0
  346. package/src/modules/messages/lib/object-validation.ts +26 -0
  347. package/src/modules/messages/lib/operationMetadata.ts +43 -0
  348. package/src/modules/messages/lib/priorityUtils.ts +76 -0
  349. package/src/modules/messages/lib/routeHelpers.ts +65 -0
  350. package/src/modules/messages/message-objects.ts +5 -0
  351. package/src/modules/messages/message-types.ts +65 -0
  352. package/src/modules/messages/migrations/.snapshot-open-mercato.json +957 -0
  353. package/src/modules/messages/migrations/Migration20260213181243.ts +34 -0
  354. package/src/modules/messages/migrations/Migration20260215165126.ts +16 -0
  355. package/src/modules/messages/notifications.ts +25 -0
  356. package/src/modules/messages/setup.ts +19 -0
  357. package/src/modules/messages/subscribers/message-notification.ts +138 -0
  358. package/src/modules/messages/workers/send-email.worker.ts +321 -0
  359. package/src/modules/sales/backend/sales/documents/[id]/page.tsx +23 -7
  360. package/src/modules/sales/commands/payments.ts +12 -6
  361. package/src/modules/sales/i18n/de.json +3 -0
  362. package/src/modules/sales/i18n/en.json +3 -0
  363. package/src/modules/sales/i18n/es.json +3 -0
  364. package/src/modules/sales/i18n/pl.json +3 -0
  365. package/src/modules/sales/lib/messageObjectPreviews.ts +150 -0
  366. package/src/modules/sales/message-objects.ts +56 -0
  367. package/src/modules/sales/widgets/messages/SalesDocumentMessageDetail.tsx +57 -0
  368. package/src/modules/sales/widgets/messages/SalesDocumentMessagePreview.tsx +46 -0
  369. package/src/modules/sales/widgets/messages/index.ts +2 -0
  370. package/src/modules/staff/backend/staff/leave-requests/[id]/page.tsx +54 -0
  371. package/src/modules/staff/backend/staff/my-leave-requests/[id]/page.tsx +58 -0
  372. package/src/modules/staff/backend/staff/team-members/[id]/page.tsx +2 -32
  373. package/src/modules/staff/components/LeaveRequestDetail.tsx +135 -0
  374. package/src/modules/staff/components/LeaveRequestForm.tsx +3 -0
  375. package/src/modules/staff/components/LeaveRequestPreview.tsx +74 -0
  376. package/src/modules/staff/i18n/de.json +8 -0
  377. package/src/modules/staff/i18n/en.json +8 -0
  378. package/src/modules/staff/i18n/es.json +8 -0
  379. package/src/modules/staff/i18n/pl.json +8 -0
  380. package/src/modules/staff/lib/messageObjectPreviews.ts +182 -0
  381. package/src/modules/staff/message-objects.ts +102 -0
  382. package/src/modules/staff/message-types.ts +21 -0
  383. package/src/modules/staff/widgets/messages/StaffMessageObjectDetail.tsx +57 -0
  384. package/src/modules/staff/widgets/messages/StaffMessageObjectPreview.tsx +44 -0
  385. package/src/modules/staff/widgets/messages/index.ts +2 -0
@@ -0,0 +1,281 @@
1
+ import type { EntityManager } from '@mikro-orm/postgresql'
2
+ import { z } from 'zod'
3
+ import { registerCommand, type CommandHandler } from '@open-mercato/shared/lib/commands'
4
+ import { extractUndoPayload, type UndoPayload } from '@open-mercato/shared/lib/commands/undo'
5
+ import { Message, MessageRecipient } from '../data/entities'
6
+ import { emitMessagesEvent, type MessagesEventId } from '../events'
7
+ import { assertOrganizationAccess, type MessageRecipientSnapshot, type MessageScopeInput } from './shared'
8
+
9
+ const recipientMutationSchema = z.object({
10
+ messageId: z.string().uuid(),
11
+ tenantId: z.string().uuid(),
12
+ organizationId: z.string().uuid().nullable(),
13
+ userId: z.string().uuid(),
14
+ })
15
+
16
+ type RecipientMutationInput = z.infer<typeof recipientMutationSchema>
17
+
18
+ type RecipientUndoPayload = UndoPayload<MessageRecipientSnapshot>
19
+
20
+ function toIso(value: Date | null | undefined): string | null {
21
+ return value ? value.toISOString() : null
22
+ }
23
+
24
+ function toDate(value: string | null | undefined): Date | null {
25
+ if (!value) return null
26
+ return new Date(value)
27
+ }
28
+
29
+ async function loadRecipientForMutation(em: EntityManager, input: RecipientMutationInput) {
30
+ const message = await em.findOne(Message, {
31
+ id: input.messageId,
32
+ tenantId: input.tenantId,
33
+ deletedAt: null,
34
+ })
35
+ if (!message) throw new Error('Message not found')
36
+ assertOrganizationAccess(input as MessageScopeInput, message)
37
+
38
+ const recipient = await em.findOne(MessageRecipient, {
39
+ messageId: input.messageId,
40
+ recipientUserId: input.userId,
41
+ deletedAt: null,
42
+ })
43
+ if (!recipient) throw new Error('Access denied')
44
+
45
+ return { message, recipient }
46
+ }
47
+
48
+ function snapshotRecipient(recipient: MessageRecipient): MessageRecipientSnapshot {
49
+ return {
50
+ id: recipient.id,
51
+ messageId: recipient.messageId,
52
+ recipientUserId: recipient.recipientUserId,
53
+ recipientType: recipient.recipientType,
54
+ status: recipient.status,
55
+ readAt: toIso(recipient.readAt),
56
+ archivedAt: toIso(recipient.archivedAt),
57
+ deletedAt: toIso(recipient.deletedAt),
58
+ }
59
+ }
60
+
61
+ function buildLog(actionLabel: string, payload: RecipientUndoPayload, input: RecipientMutationInput) {
62
+ return {
63
+ actionLabel,
64
+ resourceKind: 'messages.message',
65
+ resourceId: input.messageId,
66
+ tenantId: input.tenantId,
67
+ organizationId: input.organizationId,
68
+ payload: { undo: payload },
69
+ snapshotBefore: payload.before ?? null,
70
+ snapshotAfter: payload.after ?? null,
71
+ }
72
+ }
73
+
74
+ function applyRecipientSnapshot(recipient: MessageRecipient, snapshot: MessageRecipientSnapshot) {
75
+ recipient.status = snapshot.status
76
+ recipient.readAt = toDate(snapshot.readAt)
77
+ recipient.archivedAt = toDate(snapshot.archivedAt)
78
+ recipient.deletedAt = toDate(snapshot.deletedAt)
79
+ }
80
+
81
+ async function emitRecipientMutationEvent(
82
+ eventId: MessagesEventId,
83
+ input: RecipientMutationInput,
84
+ ): Promise<void> {
85
+ await emitMessagesEvent(
86
+ eventId,
87
+ {
88
+ messageId: input.messageId,
89
+ recipientUserId: input.userId,
90
+ userId: input.userId,
91
+ tenantId: input.tenantId,
92
+ organizationId: input.organizationId,
93
+ },
94
+ { persistent: true },
95
+ )
96
+ }
97
+
98
+ const markReadCommand: CommandHandler<unknown, { ok: true }> = {
99
+ id: 'messages.recipients.mark_read',
100
+ async prepare(rawInput, ctx) {
101
+ const input = recipientMutationSchema.parse(rawInput)
102
+ const em = (ctx.container.resolve('em') as EntityManager).fork()
103
+ const { recipient } = await loadRecipientForMutation(em, input)
104
+ return { before: snapshotRecipient(recipient) }
105
+ },
106
+ async execute(rawInput, ctx) {
107
+ const input = recipientMutationSchema.parse(rawInput)
108
+ const em = (ctx.container.resolve('em') as EntityManager).fork()
109
+ const { recipient } = await loadRecipientForMutation(em, input)
110
+ if (recipient.status !== 'read') {
111
+ recipient.status = 'read'
112
+ recipient.readAt = new Date()
113
+ await em.flush()
114
+ await emitRecipientMutationEvent('messages.message.read', input)
115
+ }
116
+ return { ok: true }
117
+ },
118
+ async captureAfter(rawInput, _result, ctx) {
119
+ const input = recipientMutationSchema.parse(rawInput)
120
+ const em = (ctx.container.resolve('em') as EntityManager).fork()
121
+ const { recipient } = await loadRecipientForMutation(em, input)
122
+ return snapshotRecipient(recipient)
123
+ },
124
+ async buildLog({ input, snapshots }) {
125
+ const parsed = recipientMutationSchema.parse(input)
126
+ return buildLog('Mark message as read', {
127
+ before: (snapshots.before as MessageRecipientSnapshot | undefined) ?? null,
128
+ after: (snapshots.after as MessageRecipientSnapshot | undefined) ?? null,
129
+ }, parsed)
130
+ },
131
+ undo: async ({ logEntry, ctx }) => {
132
+ const undo = extractUndoPayload<RecipientUndoPayload>(logEntry)
133
+ const before = undo?.before
134
+ if (!before) return
135
+ const em = (ctx.container.resolve('em') as EntityManager).fork()
136
+ const recipient = await em.findOne(MessageRecipient, { id: before.id })
137
+ if (!recipient) return
138
+ applyRecipientSnapshot(recipient, before)
139
+ await em.flush()
140
+ },
141
+ }
142
+
143
+ const markUnreadCommand: CommandHandler<unknown, { ok: true }> = {
144
+ id: 'messages.recipients.mark_unread',
145
+ async prepare(rawInput, ctx) {
146
+ const input = recipientMutationSchema.parse(rawInput)
147
+ const em = (ctx.container.resolve('em') as EntityManager).fork()
148
+ const { recipient } = await loadRecipientForMutation(em, input)
149
+ return { before: snapshotRecipient(recipient) }
150
+ },
151
+ async execute(rawInput, ctx) {
152
+ const input = recipientMutationSchema.parse(rawInput)
153
+ const em = (ctx.container.resolve('em') as EntityManager).fork()
154
+ const { recipient } = await loadRecipientForMutation(em, input)
155
+ if (recipient.status !== 'unread' || recipient.readAt !== null) {
156
+ recipient.status = 'unread'
157
+ recipient.readAt = null
158
+ await em.flush()
159
+ await emitRecipientMutationEvent('messages.message.marked_unread', input)
160
+ }
161
+ return { ok: true }
162
+ },
163
+ async captureAfter(rawInput, _result, ctx) {
164
+ const input = recipientMutationSchema.parse(rawInput)
165
+ const em = (ctx.container.resolve('em') as EntityManager).fork()
166
+ const { recipient } = await loadRecipientForMutation(em, input)
167
+ return snapshotRecipient(recipient)
168
+ },
169
+ async buildLog({ input, snapshots }) {
170
+ const parsed = recipientMutationSchema.parse(input)
171
+ return buildLog('Mark message as unread', {
172
+ before: (snapshots.before as MessageRecipientSnapshot | undefined) ?? null,
173
+ after: (snapshots.after as MessageRecipientSnapshot | undefined) ?? null,
174
+ }, parsed)
175
+ },
176
+ undo: async ({ logEntry, ctx }) => {
177
+ const undo = extractUndoPayload<RecipientUndoPayload>(logEntry)
178
+ const before = undo?.before
179
+ if (!before) return
180
+ const em = (ctx.container.resolve('em') as EntityManager).fork()
181
+ const recipient = await em.findOne(MessageRecipient, { id: before.id })
182
+ if (!recipient) return
183
+ applyRecipientSnapshot(recipient, before)
184
+ await em.flush()
185
+ },
186
+ }
187
+
188
+ const archiveRecipientCommand: CommandHandler<unknown, { ok: true }> = {
189
+ id: 'messages.recipients.archive',
190
+ async prepare(rawInput, ctx) {
191
+ const input = recipientMutationSchema.parse(rawInput)
192
+ const em = (ctx.container.resolve('em') as EntityManager).fork()
193
+ const { recipient } = await loadRecipientForMutation(em, input)
194
+ return { before: snapshotRecipient(recipient) }
195
+ },
196
+ async execute(rawInput, ctx) {
197
+ const input = recipientMutationSchema.parse(rawInput)
198
+ const em = (ctx.container.resolve('em') as EntityManager).fork()
199
+ const { recipient } = await loadRecipientForMutation(em, input)
200
+ if (recipient.status !== 'archived' || recipient.archivedAt === null) {
201
+ recipient.archivedAt = new Date()
202
+ recipient.status = 'archived'
203
+ await em.flush()
204
+ await emitRecipientMutationEvent('messages.message.archived', input)
205
+ }
206
+ return { ok: true }
207
+ },
208
+ async captureAfter(rawInput, _result, ctx) {
209
+ const input = recipientMutationSchema.parse(rawInput)
210
+ const em = (ctx.container.resolve('em') as EntityManager).fork()
211
+ const { recipient } = await loadRecipientForMutation(em, input)
212
+ return snapshotRecipient(recipient)
213
+ },
214
+ async buildLog({ input, snapshots }) {
215
+ const parsed = recipientMutationSchema.parse(input)
216
+ return buildLog('Archive message', {
217
+ before: (snapshots.before as MessageRecipientSnapshot | undefined) ?? null,
218
+ after: (snapshots.after as MessageRecipientSnapshot | undefined) ?? null,
219
+ }, parsed)
220
+ },
221
+ undo: async ({ logEntry, ctx }) => {
222
+ const undo = extractUndoPayload<RecipientUndoPayload>(logEntry)
223
+ const before = undo?.before
224
+ if (!before) return
225
+ const em = (ctx.container.resolve('em') as EntityManager).fork()
226
+ const recipient = await em.findOne(MessageRecipient, { id: before.id })
227
+ if (!recipient) return
228
+ applyRecipientSnapshot(recipient, before)
229
+ await em.flush()
230
+ },
231
+ }
232
+
233
+ const unarchiveRecipientCommand: CommandHandler<unknown, { ok: true }> = {
234
+ id: 'messages.recipients.unarchive',
235
+ async prepare(rawInput, ctx) {
236
+ const input = recipientMutationSchema.parse(rawInput)
237
+ const em = (ctx.container.resolve('em') as EntityManager).fork()
238
+ const { recipient } = await loadRecipientForMutation(em, input)
239
+ return { before: snapshotRecipient(recipient) }
240
+ },
241
+ async execute(rawInput, ctx) {
242
+ const input = recipientMutationSchema.parse(rawInput)
243
+ const em = (ctx.container.resolve('em') as EntityManager).fork()
244
+ const { recipient } = await loadRecipientForMutation(em, input)
245
+ if (recipient.archivedAt !== null || recipient.status === 'archived') {
246
+ recipient.archivedAt = null
247
+ recipient.status = recipient.readAt ? 'read' : 'unread'
248
+ await em.flush()
249
+ await emitRecipientMutationEvent('messages.message.unarchived', input)
250
+ }
251
+ return { ok: true }
252
+ },
253
+ async captureAfter(rawInput, _result, ctx) {
254
+ const input = recipientMutationSchema.parse(rawInput)
255
+ const em = (ctx.container.resolve('em') as EntityManager).fork()
256
+ const { recipient } = await loadRecipientForMutation(em, input)
257
+ return snapshotRecipient(recipient)
258
+ },
259
+ async buildLog({ input, snapshots }) {
260
+ const parsed = recipientMutationSchema.parse(input)
261
+ return buildLog('Unarchive message', {
262
+ before: (snapshots.before as MessageRecipientSnapshot | undefined) ?? null,
263
+ after: (snapshots.after as MessageRecipientSnapshot | undefined) ?? null,
264
+ }, parsed)
265
+ },
266
+ undo: async ({ logEntry, ctx }) => {
267
+ const undo = extractUndoPayload<RecipientUndoPayload>(logEntry)
268
+ const before = undo?.before
269
+ if (!before) return
270
+ const em = (ctx.container.resolve('em') as EntityManager).fork()
271
+ const recipient = await em.findOne(MessageRecipient, { id: before.id })
272
+ if (!recipient) return
273
+ applyRecipientSnapshot(recipient, before)
274
+ await em.flush()
275
+ },
276
+ }
277
+
278
+ registerCommand(markReadCommand)
279
+ registerCommand(markUnreadCommand)
280
+ registerCommand(archiveRecipientCommand)
281
+ registerCommand(unarchiveRecipientCommand)
@@ -0,0 +1,350 @@
1
+ import type { EntityManager } from '@mikro-orm/postgresql'
2
+ import { Message, MessageObject, MessageRecipient, type MessageActionData, type RecipientStatus } from '../data/entities'
3
+ import { MESSAGE_ATTACHMENT_ENTITY_ID } from '../lib/constants'
4
+
5
+ export type MessageCommandExecuteResult = {
6
+ id: string
7
+ externalEmail: string | null
8
+ recipientUserIds: string[]
9
+ }
10
+
11
+ export type MessageScopeInput = {
12
+ tenantId: string
13
+ organizationId: string | null
14
+ userId: string
15
+ }
16
+
17
+ export type MessageRecipientSnapshot = {
18
+ id: string
19
+ messageId: string
20
+ recipientUserId: string
21
+ recipientType: 'to' | 'cc' | 'bcc'
22
+ status: RecipientStatus
23
+ readAt: string | null
24
+ archivedAt: string | null
25
+ deletedAt: string | null
26
+ }
27
+
28
+ export type MessageObjectSnapshot = {
29
+ id: string
30
+ messageId: string
31
+ entityModule: string
32
+ entityType: string
33
+ entityId: string
34
+ actionRequired: boolean
35
+ actionType: string | null
36
+ actionLabel: string | null
37
+ entitySnapshot: Record<string, unknown> | null
38
+ }
39
+
40
+ export type MessageSnapshot = {
41
+ id: string
42
+ type: string
43
+ visibility: 'public' | 'internal' | null
44
+ sourceEntityType: string | null
45
+ sourceEntityId: string | null
46
+ externalEmail: string | null
47
+ externalName: string | null
48
+ threadId: string | null
49
+ parentMessageId: string | null
50
+ senderUserId: string
51
+ subject: string
52
+ body: string
53
+ bodyFormat: 'text' | 'markdown'
54
+ priority: 'low' | 'normal' | 'high' | 'urgent'
55
+ status: 'draft' | 'sent'
56
+ isDraft: boolean
57
+ sentAt: string | null
58
+ actionData: MessageActionData | null
59
+ actionResult: Record<string, unknown> | null
60
+ actionTaken: string | null
61
+ actionTakenByUserId: string | null
62
+ actionTakenAt: string | null
63
+ sendViaEmail: boolean
64
+ tenantId: string
65
+ organizationId: string | null
66
+ deletedAt: string | null
67
+ }
68
+
69
+ export type MessageAggregateSnapshot = {
70
+ message: MessageSnapshot
71
+ recipients: MessageRecipientSnapshot[]
72
+ objects: MessageObjectSnapshot[]
73
+ attachmentIds: string[]
74
+ }
75
+
76
+ function toIso(value: Date | null | undefined): string | null {
77
+ return value ? value.toISOString() : null
78
+ }
79
+
80
+ function toDate(value: string | null | undefined): Date | null {
81
+ if (!value) return null
82
+ return new Date(value)
83
+ }
84
+
85
+ function hasOrganizationAccess(scopeOrganizationId: string | null, messageOrganizationId: string | null | undefined): boolean {
86
+ if (scopeOrganizationId) {
87
+ return messageOrganizationId === scopeOrganizationId
88
+ }
89
+ return messageOrganizationId == null
90
+ }
91
+
92
+ export function assertOrganizationAccess(scope: MessageScopeInput, message: Message): void {
93
+ if (!hasOrganizationAccess(scope.organizationId, message.organizationId)) {
94
+ throw new Error('Access denied')
95
+ }
96
+ }
97
+
98
+ export async function getAttachmentIdsForMessage(
99
+ em: EntityManager,
100
+ messageId: string,
101
+ scope: { tenantId: string; organizationId: string | null },
102
+ ): Promise<string[]> {
103
+ const { Attachment } = await import('@open-mercato/core/modules/attachments/data/entities')
104
+ const attachments = await em.find(Attachment, {
105
+ entityId: MESSAGE_ATTACHMENT_ENTITY_ID,
106
+ recordId: messageId,
107
+ tenantId: scope.tenantId,
108
+ organizationId: scope.organizationId,
109
+ })
110
+ return attachments.map((item) => item.id)
111
+ }
112
+
113
+ export async function loadMessageAggregateSnapshot(
114
+ em: EntityManager,
115
+ messageId: string,
116
+ scope?: { tenantId: string; organizationId: string | null },
117
+ ): Promise<MessageAggregateSnapshot | null> {
118
+ const where: Record<string, unknown> = { id: messageId }
119
+ if (scope) {
120
+ where.tenantId = scope.tenantId
121
+ where.organizationId = scope.organizationId
122
+ }
123
+ const message = await em.findOne(Message, where)
124
+ if (!message) return null
125
+ const recipients = await em.find(MessageRecipient, { messageId })
126
+ const objects = await em.find(MessageObject, { messageId })
127
+ const attachmentIds = await getAttachmentIdsForMessage(em, messageId, {
128
+ tenantId: message.tenantId,
129
+ organizationId: message.organizationId ?? null,
130
+ })
131
+
132
+ return {
133
+ message: {
134
+ id: message.id,
135
+ type: message.type,
136
+ visibility: message.visibility ?? null,
137
+ sourceEntityType: message.sourceEntityType ?? null,
138
+ sourceEntityId: message.sourceEntityId ?? null,
139
+ externalEmail: message.externalEmail ?? null,
140
+ externalName: message.externalName ?? null,
141
+ threadId: message.threadId ?? null,
142
+ parentMessageId: message.parentMessageId ?? null,
143
+ senderUserId: message.senderUserId,
144
+ subject: message.subject,
145
+ body: message.body,
146
+ bodyFormat: message.bodyFormat,
147
+ priority: message.priority,
148
+ status: message.status,
149
+ isDraft: message.isDraft,
150
+ sentAt: toIso(message.sentAt),
151
+ actionData: (message.actionData as MessageActionData | null) ?? null,
152
+ actionResult: message.actionResult ?? null,
153
+ actionTaken: message.actionTaken ?? null,
154
+ actionTakenByUserId: message.actionTakenByUserId ?? null,
155
+ actionTakenAt: toIso(message.actionTakenAt),
156
+ sendViaEmail: message.sendViaEmail,
157
+ tenantId: message.tenantId,
158
+ organizationId: message.organizationId ?? null,
159
+ deletedAt: toIso(message.deletedAt),
160
+ },
161
+ recipients: recipients.map((item) => ({
162
+ id: item.id,
163
+ messageId: item.messageId,
164
+ recipientUserId: item.recipientUserId,
165
+ recipientType: item.recipientType,
166
+ status: item.status,
167
+ readAt: toIso(item.readAt),
168
+ archivedAt: toIso(item.archivedAt),
169
+ deletedAt: toIso(item.deletedAt),
170
+ })),
171
+ objects: objects.map((item) => ({
172
+ id: item.id,
173
+ messageId: item.messageId,
174
+ entityModule: item.entityModule,
175
+ entityType: item.entityType,
176
+ entityId: item.entityId,
177
+ actionRequired: item.actionRequired,
178
+ actionType: item.actionType ?? null,
179
+ actionLabel: item.actionLabel ?? null,
180
+ entitySnapshot: item.entitySnapshot ?? null,
181
+ })),
182
+ attachmentIds,
183
+ }
184
+ }
185
+
186
+ export async function restoreMessageAggregateSnapshot(
187
+ em: EntityManager,
188
+ snapshot: MessageAggregateSnapshot,
189
+ ): Promise<void> {
190
+ const existingMessage = await em.findOne(Message, { id: snapshot.message.id })
191
+ if (!existingMessage) {
192
+ const created = em.create(Message, {
193
+ id: snapshot.message.id,
194
+ type: snapshot.message.type,
195
+ visibility: snapshot.message.visibility,
196
+ sourceEntityType: snapshot.message.sourceEntityType,
197
+ sourceEntityId: snapshot.message.sourceEntityId,
198
+ externalEmail: snapshot.message.externalEmail,
199
+ externalName: snapshot.message.externalName,
200
+ threadId: snapshot.message.threadId,
201
+ parentMessageId: snapshot.message.parentMessageId,
202
+ senderUserId: snapshot.message.senderUserId,
203
+ subject: snapshot.message.subject,
204
+ body: snapshot.message.body,
205
+ bodyFormat: snapshot.message.bodyFormat,
206
+ priority: snapshot.message.priority,
207
+ status: snapshot.message.status,
208
+ isDraft: snapshot.message.isDraft,
209
+ sentAt: toDate(snapshot.message.sentAt),
210
+ actionData: snapshot.message.actionData as MessageActionData,
211
+ actionResult: snapshot.message.actionResult,
212
+ actionTaken: snapshot.message.actionTaken,
213
+ actionTakenByUserId: snapshot.message.actionTakenByUserId,
214
+ actionTakenAt: toDate(snapshot.message.actionTakenAt),
215
+ sendViaEmail: snapshot.message.sendViaEmail,
216
+ tenantId: snapshot.message.tenantId,
217
+ organizationId: snapshot.message.organizationId,
218
+ deletedAt: toDate(snapshot.message.deletedAt),
219
+ })
220
+ em.persist(created)
221
+ } else {
222
+ existingMessage.type = snapshot.message.type
223
+ existingMessage.visibility = snapshot.message.visibility
224
+ existingMessage.sourceEntityType = snapshot.message.sourceEntityType
225
+ existingMessage.sourceEntityId = snapshot.message.sourceEntityId
226
+ existingMessage.externalEmail = snapshot.message.externalEmail
227
+ existingMessage.externalName = snapshot.message.externalName
228
+ existingMessage.threadId = snapshot.message.threadId
229
+ existingMessage.parentMessageId = snapshot.message.parentMessageId
230
+ existingMessage.senderUserId = snapshot.message.senderUserId
231
+ existingMessage.subject = snapshot.message.subject
232
+ existingMessage.body = snapshot.message.body
233
+ existingMessage.bodyFormat = snapshot.message.bodyFormat
234
+ existingMessage.priority = snapshot.message.priority
235
+ existingMessage.status = snapshot.message.status
236
+ existingMessage.isDraft = snapshot.message.isDraft
237
+ existingMessage.sentAt = toDate(snapshot.message.sentAt)
238
+ existingMessage.actionData = snapshot.message.actionData as MessageActionData
239
+ existingMessage.actionResult = snapshot.message.actionResult
240
+ existingMessage.actionTaken = snapshot.message.actionTaken
241
+ existingMessage.actionTakenByUserId = snapshot.message.actionTakenByUserId
242
+ existingMessage.actionTakenAt = toDate(snapshot.message.actionTakenAt)
243
+ existingMessage.sendViaEmail = snapshot.message.sendViaEmail
244
+ existingMessage.tenantId = snapshot.message.tenantId
245
+ existingMessage.organizationId = snapshot.message.organizationId
246
+ existingMessage.deletedAt = toDate(snapshot.message.deletedAt)
247
+ }
248
+
249
+ const existingRecipients = await em.find(MessageRecipient, { messageId: snapshot.message.id })
250
+ const recipientById = new Map(existingRecipients.map((item) => [item.id, item]))
251
+ const snapshotRecipientIds = new Set(snapshot.recipients.map((item) => item.id))
252
+ for (const current of existingRecipients) {
253
+ if (!snapshotRecipientIds.has(current.id)) {
254
+ em.remove(current)
255
+ }
256
+ }
257
+ for (const recipient of snapshot.recipients) {
258
+ const existing = recipientById.get(recipient.id)
259
+ if (!existing) {
260
+ em.persist(em.create(MessageRecipient, {
261
+ id: recipient.id,
262
+ messageId: recipient.messageId,
263
+ recipientUserId: recipient.recipientUserId,
264
+ recipientType: recipient.recipientType,
265
+ status: recipient.status,
266
+ readAt: toDate(recipient.readAt),
267
+ archivedAt: toDate(recipient.archivedAt),
268
+ deletedAt: toDate(recipient.deletedAt),
269
+ }))
270
+ continue
271
+ }
272
+ existing.messageId = recipient.messageId
273
+ existing.recipientUserId = recipient.recipientUserId
274
+ existing.recipientType = recipient.recipientType
275
+ existing.status = recipient.status
276
+ existing.readAt = toDate(recipient.readAt)
277
+ existing.archivedAt = toDate(recipient.archivedAt)
278
+ existing.deletedAt = toDate(recipient.deletedAt)
279
+ }
280
+
281
+ const existingObjects = await em.find(MessageObject, { messageId: snapshot.message.id })
282
+ const objectById = new Map(existingObjects.map((item) => [item.id, item]))
283
+ const snapshotObjectIds = new Set(snapshot.objects.map((item) => item.id))
284
+ for (const current of existingObjects) {
285
+ if (!snapshotObjectIds.has(current.id)) {
286
+ em.remove(current)
287
+ }
288
+ }
289
+ for (const object of snapshot.objects) {
290
+ const existing = objectById.get(object.id)
291
+ if (!existing) {
292
+ em.persist(em.create(MessageObject, {
293
+ id: object.id,
294
+ messageId: object.messageId,
295
+ entityModule: object.entityModule,
296
+ entityType: object.entityType,
297
+ entityId: object.entityId,
298
+ actionRequired: object.actionRequired,
299
+ actionType: object.actionType,
300
+ actionLabel: object.actionLabel,
301
+ entitySnapshot: object.entitySnapshot,
302
+ }))
303
+ continue
304
+ }
305
+ existing.messageId = object.messageId
306
+ existing.entityModule = object.entityModule
307
+ existing.entityType = object.entityType
308
+ existing.entityId = object.entityId
309
+ existing.actionRequired = object.actionRequired
310
+ existing.actionType = object.actionType
311
+ existing.actionLabel = object.actionLabel
312
+ existing.entitySnapshot = object.entitySnapshot
313
+ }
314
+
315
+ const { Attachment } = await import('@open-mercato/core/modules/attachments/data/entities')
316
+ await em.nativeDelete(Attachment, {
317
+ entityId: MESSAGE_ATTACHMENT_ENTITY_ID,
318
+ recordId: snapshot.message.id,
319
+ tenantId: snapshot.message.tenantId,
320
+ organizationId: snapshot.message.organizationId,
321
+ id: { $nin: snapshot.attachmentIds.length > 0 ? snapshot.attachmentIds : ['00000000-0000-0000-0000-000000000000'] },
322
+ })
323
+ if (snapshot.attachmentIds.length > 0) {
324
+ const attachments = await em.find(Attachment, {
325
+ id: { $in: snapshot.attachmentIds },
326
+ tenantId: snapshot.message.tenantId,
327
+ organizationId: snapshot.message.organizationId,
328
+ })
329
+ for (const attachment of attachments) {
330
+ attachment.entityId = MESSAGE_ATTACHMENT_ENTITY_ID
331
+ attachment.recordId = snapshot.message.id
332
+ }
333
+ }
334
+
335
+ await em.flush()
336
+ }
337
+
338
+ export function buildCommandLogBase(
339
+ actionLabel: string,
340
+ resourceId: string,
341
+ snapshot: { tenantId: string; organizationId: string | null },
342
+ ) {
343
+ return {
344
+ actionLabel,
345
+ resourceKind: 'messages.message',
346
+ resourceId,
347
+ tenantId: snapshot.tenantId,
348
+ organizationId: snapshot.organizationId,
349
+ }
350
+ }