@open-mercato/core 0.6.6-develop.6094.1.28b081ea16 → 0.6.6-develop.6121.1.5797a901b3

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 (317) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/dist/generated/entities/catalog_product/index.js +52 -0
  3. package/dist/generated/entities/catalog_product/index.js.map +2 -2
  4. package/dist/generated/entities/catalog_product_variant/index.js +4 -0
  5. package/dist/generated/entities/catalog_product_variant/index.js.map +2 -2
  6. package/dist/generated/entity-fields-registry.js +28 -0
  7. package/dist/generated/entity-fields-registry.js.map +2 -2
  8. package/dist/modules/catalog/api/products/route.js +103 -33
  9. package/dist/modules/catalog/api/products/route.js.map +2 -2
  10. package/dist/modules/catalog/api/variants/route.js +4 -0
  11. package/dist/modules/catalog/api/variants/route.js.map +2 -2
  12. package/dist/modules/catalog/backend/catalog/products/[id]/page.js +46 -2
  13. package/dist/modules/catalog/backend/catalog/products/[id]/page.js.map +2 -2
  14. package/dist/modules/catalog/backend/catalog/products/[productId]/variants/[variantId]/page.js +4 -0
  15. package/dist/modules/catalog/backend/catalog/products/[productId]/variants/[variantId]/page.js.map +2 -2
  16. package/dist/modules/catalog/backend/catalog/products/[productId]/variants/create/page.js +2 -0
  17. package/dist/modules/catalog/backend/catalog/products/[productId]/variants/create/page.js.map +2 -2
  18. package/dist/modules/catalog/backend/catalog/products/create/page.js +42 -2
  19. package/dist/modules/catalog/backend/catalog/products/create/page.js.map +2 -2
  20. package/dist/modules/catalog/commands/products.js +251 -14
  21. package/dist/modules/catalog/commands/products.js.map +2 -2
  22. package/dist/modules/catalog/commands/variants.js +72 -1
  23. package/dist/modules/catalog/commands/variants.js.map +2 -2
  24. package/dist/modules/catalog/components/products/ProductComplianceSection.js +500 -0
  25. package/dist/modules/catalog/components/products/ProductComplianceSection.js.map +7 -0
  26. package/dist/modules/catalog/components/products/VariantBuilder.js +39 -1
  27. package/dist/modules/catalog/components/products/VariantBuilder.js.map +2 -2
  28. package/dist/modules/catalog/components/products/productForm.js +164 -2
  29. package/dist/modules/catalog/components/products/productForm.js.map +2 -2
  30. package/dist/modules/catalog/components/products/variantForm.js +2 -0
  31. package/dist/modules/catalog/components/products/variantForm.js.map +2 -2
  32. package/dist/modules/catalog/data/entities.js +93 -0
  33. package/dist/modules/catalog/data/entities.js.map +2 -2
  34. package/dist/modules/catalog/data/types.js +28 -0
  35. package/dist/modules/catalog/data/types.js.map +2 -2
  36. package/dist/modules/catalog/data/validators.js +100 -5
  37. package/dist/modules/catalog/data/validators.js.map +2 -2
  38. package/dist/modules/catalog/lib/gtin.js +61 -0
  39. package/dist/modules/catalog/lib/gtin.js.map +7 -0
  40. package/dist/modules/catalog/migrations/Migration20260611090000.js +17 -0
  41. package/dist/modules/catalog/migrations/Migration20260611090000.js.map +7 -0
  42. package/dist/modules/catalog/translations.js +1 -1
  43. package/dist/modules/catalog/translations.js.map +2 -2
  44. package/dist/modules/configs/api/cache/route.js +60 -10
  45. package/dist/modules/configs/api/cache/route.js.map +3 -3
  46. package/dist/modules/configs/components/CachePanel.js +52 -29
  47. package/dist/modules/configs/components/CachePanel.js.map +2 -2
  48. package/dist/modules/currencies/api/currencies/options/route.js +18 -4
  49. package/dist/modules/currencies/api/currencies/options/route.js.map +2 -2
  50. package/dist/modules/currencies/services/rateFetchingService.js +35 -18
  51. package/dist/modules/currencies/services/rateFetchingService.js.map +2 -2
  52. package/dist/modules/customer_accounts/backend/customer_accounts/users/[id]/page.js +16 -16
  53. package/dist/modules/customer_accounts/backend/customer_accounts/users/[id]/page.js.map +2 -2
  54. package/dist/modules/customer_accounts/backend/customer_accounts/users/page.js +1 -1
  55. package/dist/modules/customer_accounts/backend/customer_accounts/users/page.js.map +2 -2
  56. package/dist/modules/customers/backend/calendar/page.js +10 -0
  57. package/dist/modules/customers/backend/calendar/page.js.map +7 -0
  58. package/dist/modules/customers/backend/calendar/page.meta.js +25 -0
  59. package/dist/modules/customers/backend/calendar/page.meta.js.map +7 -0
  60. package/dist/modules/customers/cli.js +1 -0
  61. package/dist/modules/customers/cli.js.map +2 -2
  62. package/dist/modules/customers/components/calendar/AgendaList.js +182 -0
  63. package/dist/modules/customers/components/calendar/AgendaList.js.map +7 -0
  64. package/dist/modules/customers/components/calendar/CalendarEventEditor.js +331 -0
  65. package/dist/modules/customers/components/calendar/CalendarEventEditor.js.map +7 -0
  66. package/dist/modules/customers/components/calendar/CalendarFooter.js +48 -0
  67. package/dist/modules/customers/components/calendar/CalendarFooter.js.map +7 -0
  68. package/dist/modules/customers/components/calendar/CalendarHeader.js +36 -0
  69. package/dist/modules/customers/components/calendar/CalendarHeader.js.map +7 -0
  70. package/dist/modules/customers/components/calendar/CalendarScreen.js +516 -0
  71. package/dist/modules/customers/components/calendar/CalendarScreen.js.map +7 -0
  72. package/dist/modules/customers/components/calendar/CalendarSettingsModal.js +163 -0
  73. package/dist/modules/customers/components/calendar/CalendarSettingsModal.js.map +7 -0
  74. package/dist/modules/customers/components/calendar/CalendarTabs.js +60 -0
  75. package/dist/modules/customers/components/calendar/CalendarTabs.js.map +7 -0
  76. package/dist/modules/customers/components/calendar/CalendarToolbar.js +262 -0
  77. package/dist/modules/customers/components/calendar/CalendarToolbar.js.map +7 -0
  78. package/dist/modules/customers/components/calendar/EventBlock.js +149 -0
  79. package/dist/modules/customers/components/calendar/EventBlock.js.map +7 -0
  80. package/dist/modules/customers/components/calendar/EventPeekPopover.js +72 -0
  81. package/dist/modules/customers/components/calendar/EventPeekPopover.js.map +7 -0
  82. package/dist/modules/customers/components/calendar/MonthGrid.js +214 -0
  83. package/dist/modules/customers/components/calendar/MonthGrid.js.map +7 -0
  84. package/dist/modules/customers/components/calendar/ShortcutsDialog.js +44 -0
  85. package/dist/modules/customers/components/calendar/ShortcutsDialog.js.map +7 -0
  86. package/dist/modules/customers/components/calendar/TimeGrid.js +410 -0
  87. package/dist/modules/customers/components/calendar/TimeGrid.js.map +7 -0
  88. package/dist/modules/customers/components/calendar/UpcomingCards.js +175 -0
  89. package/dist/modules/customers/components/calendar/UpcomingCards.js.map +7 -0
  90. package/dist/modules/customers/components/calendar/editor/CategoryField.js +75 -0
  91. package/dist/modules/customers/components/calendar/editor/CategoryField.js.map +7 -0
  92. package/dist/modules/customers/components/calendar/editor/LocationField.js +30 -0
  93. package/dist/modules/customers/components/calendar/editor/LocationField.js.map +7 -0
  94. package/dist/modules/customers/components/calendar/editor/PeopleField.js +135 -0
  95. package/dist/modules/customers/components/calendar/editor/PeopleField.js.map +7 -0
  96. package/dist/modules/customers/components/calendar/editor/RelatedToField.js +218 -0
  97. package/dist/modules/customers/components/calendar/editor/RelatedToField.js.map +7 -0
  98. package/dist/modules/customers/components/calendar/editor/RepeatField.js +119 -0
  99. package/dist/modules/customers/components/calendar/editor/RepeatField.js.map +7 -0
  100. package/dist/modules/customers/components/calendar/editor/ScheduleSection.js +83 -0
  101. package/dist/modules/customers/components/calendar/editor/ScheduleSection.js.map +7 -0
  102. package/dist/modules/customers/components/calendar/editor/SegmentGroup.js +44 -0
  103. package/dist/modules/customers/components/calendar/editor/SegmentGroup.js.map +7 -0
  104. package/dist/modules/customers/components/calendar/editor/hooks.js +132 -0
  105. package/dist/modules/customers/components/calendar/editor/hooks.js.map +7 -0
  106. package/dist/modules/customers/components/calendar/editor/inputs.js +160 -0
  107. package/dist/modules/customers/components/calendar/editor/inputs.js.map +7 -0
  108. package/dist/modules/customers/components/calendar/editor/lookups.js +107 -0
  109. package/dist/modules/customers/components/calendar/editor/lookups.js.map +7 -0
  110. package/dist/modules/customers/components/calendar/types.js +30 -0
  111. package/dist/modules/customers/components/calendar/types.js.map +7 -0
  112. package/dist/modules/customers/components/calendar/useCalendarItems.js +131 -0
  113. package/dist/modules/customers/components/calendar/useCalendarItems.js.map +7 -0
  114. package/dist/modules/customers/components/calendar/useCalendarPreferences.js +41 -0
  115. package/dist/modules/customers/components/calendar/useCalendarPreferences.js.map +7 -0
  116. package/dist/modules/customers/lib/calendar/categories.js +28 -0
  117. package/dist/modules/customers/lib/calendar/categories.js.map +7 -0
  118. package/dist/modules/customers/lib/calendar/conflicts.js +72 -0
  119. package/dist/modules/customers/lib/calendar/conflicts.js.map +7 -0
  120. package/dist/modules/customers/lib/calendar/editorPayload.js +271 -0
  121. package/dist/modules/customers/lib/calendar/editorPayload.js.map +7 -0
  122. package/dist/modules/customers/lib/calendar/grid.js +48 -0
  123. package/dist/modules/customers/lib/calendar/grid.js.map +7 -0
  124. package/dist/modules/customers/lib/calendar/layout.js +39 -0
  125. package/dist/modules/customers/lib/calendar/layout.js.map +7 -0
  126. package/dist/modules/customers/lib/calendar/mapItem.js +79 -0
  127. package/dist/modules/customers/lib/calendar/mapItem.js.map +7 -0
  128. package/dist/modules/customers/lib/calendar/preferences.js +71 -0
  129. package/dist/modules/customers/lib/calendar/preferences.js.map +7 -0
  130. package/dist/modules/customers/lib/calendar/range.js +46 -0
  131. package/dist/modules/customers/lib/calendar/range.js.map +7 -0
  132. package/dist/modules/customers/lib/calendar/recurrence.js +113 -0
  133. package/dist/modules/customers/lib/calendar/recurrence.js.map +7 -0
  134. package/dist/modules/dashboards/services/widgetDataService.js +5 -5
  135. package/dist/modules/dashboards/services/widgetDataService.js.map +2 -2
  136. package/dist/modules/dictionaries/api/[dictionaryId]/entries/[entryId]/route.js +61 -1
  137. package/dist/modules/dictionaries/api/[dictionaryId]/entries/[entryId]/route.js.map +2 -2
  138. package/dist/modules/dictionaries/api/[dictionaryId]/entries/route.js +33 -1
  139. package/dist/modules/dictionaries/api/[dictionaryId]/entries/route.js.map +2 -2
  140. package/dist/modules/dictionaries/api/[dictionaryId]/route.js +61 -1
  141. package/dist/modules/dictionaries/api/[dictionaryId]/route.js.map +2 -2
  142. package/dist/modules/dictionaries/api/route.js +33 -1
  143. package/dist/modules/dictionaries/api/route.js.map +2 -2
  144. package/dist/modules/feature_toggles/lib/queries.js +36 -52
  145. package/dist/modules/feature_toggles/lib/queries.js.map +2 -2
  146. package/dist/modules/perspectives/api/[tableId]/[perspectiveId]/route.js +32 -1
  147. package/dist/modules/perspectives/api/[tableId]/[perspectiveId]/route.js.map +2 -2
  148. package/dist/modules/perspectives/api/[tableId]/roles/[roleId]/route.js +32 -1
  149. package/dist/modules/perspectives/api/[tableId]/roles/[roleId]/route.js.map +2 -2
  150. package/dist/modules/perspectives/api/[tableId]/route.js +73 -2
  151. package/dist/modules/perspectives/api/[tableId]/route.js.map +2 -2
  152. package/dist/modules/perspectives/services/perspectiveService.js +5 -3
  153. package/dist/modules/perspectives/services/perspectiveService.js.map +2 -2
  154. package/dist/modules/planner/api/access.js +9 -0
  155. package/dist/modules/planner/api/access.js.map +2 -2
  156. package/dist/modules/planner/api/availability-date-specific.js +22 -1
  157. package/dist/modules/planner/api/availability-date-specific.js.map +2 -2
  158. package/dist/modules/planner/api/availability-weekly.js +22 -1
  159. package/dist/modules/planner/api/availability-weekly.js.map +2 -2
  160. package/dist/modules/resources/api/resources/tags/assign/route.js +39 -0
  161. package/dist/modules/resources/api/resources/tags/assign/route.js.map +2 -2
  162. package/dist/modules/resources/api/resources/tags/unassign/route.js +39 -0
  163. package/dist/modules/resources/api/resources/tags/unassign/route.js.map +2 -2
  164. package/dist/modules/sales/api/settings/document-numbers/route.js +33 -1
  165. package/dist/modules/sales/api/settings/document-numbers/route.js.map +2 -2
  166. package/dist/modules/sales/api/settings/order-editing/route.js +35 -3
  167. package/dist/modules/sales/api/settings/order-editing/route.js.map +2 -2
  168. package/dist/modules/staff/api/leave-requests/accept/route.js +41 -0
  169. package/dist/modules/staff/api/leave-requests/accept/route.js.map +2 -2
  170. package/dist/modules/staff/api/leave-requests/reject/route.js +41 -0
  171. package/dist/modules/staff/api/leave-requests/reject/route.js.map +2 -2
  172. package/dist/modules/staff/api/team-members/self/route.js +40 -0
  173. package/dist/modules/staff/api/team-members/self/route.js.map +2 -2
  174. package/dist/modules/staff/api/team-members/tags/assign/route.js +41 -0
  175. package/dist/modules/staff/api/team-members/tags/assign/route.js.map +2 -2
  176. package/dist/modules/staff/api/team-members/tags/unassign/route.js +41 -0
  177. package/dist/modules/staff/api/team-members/tags/unassign/route.js.map +2 -2
  178. package/dist/modules/translations/api/[entityType]/[entityId]/route.js +61 -1
  179. package/dist/modules/translations/api/[entityType]/[entityId]/route.js.map +2 -2
  180. package/dist/modules/translations/api/context.js +7 -0
  181. package/dist/modules/translations/api/context.js.map +2 -2
  182. package/dist/modules/translations/api/put/locales.js +33 -1
  183. package/dist/modules/translations/api/put/locales.js.map +2 -2
  184. package/dist/modules/workflows/backend/definitions/visual-editor/page.js +6 -7
  185. package/dist/modules/workflows/backend/definitions/visual-editor/page.js.map +2 -2
  186. package/dist/modules/workflows/backend/instances/[id]/page.js.map +1 -1
  187. package/dist/modules/workflows/components/EdgeEditDialog.js.map +1 -1
  188. package/dist/modules/workflows/components/EdgeEditDialogCrudForm.js.map +1 -1
  189. package/dist/modules/workflows/components/NodeEditDialog.js.map +1 -1
  190. package/dist/modules/workflows/components/NodeEditDialogCrudForm.js.map +1 -1
  191. package/dist/modules/workflows/components/WorkflowGraph.js.map +1 -1
  192. package/dist/modules/workflows/components/WorkflowGraphImpl.js +17 -9
  193. package/dist/modules/workflows/components/WorkflowGraphImpl.js.map +2 -2
  194. package/dist/modules/workflows/components/mobile/MobileVisualEditor.js.map +1 -1
  195. package/dist/modules/workflows/frontend/checkout-demo/deriveCurrentStep.js +8 -0
  196. package/dist/modules/workflows/frontend/checkout-demo/deriveCurrentStep.js.map +7 -0
  197. package/dist/modules/workflows/frontend/checkout-demo/page.js +2 -20
  198. package/dist/modules/workflows/frontend/checkout-demo/page.js.map +2 -2
  199. package/dist/modules/workflows/lib/graph-utils.js +8 -0
  200. package/dist/modules/workflows/lib/graph-utils.js.map +2 -2
  201. package/generated/entities/catalog_product/index.ts +26 -0
  202. package/generated/entities/catalog_product_variant/index.ts +2 -0
  203. package/generated/entity-fields-registry.ts +28 -0
  204. package/package.json +7 -7
  205. package/src/modules/catalog/api/products/route.ts +123 -39
  206. package/src/modules/catalog/api/variants/route.ts +4 -0
  207. package/src/modules/catalog/backend/catalog/products/[id]/page.tsx +43 -0
  208. package/src/modules/catalog/backend/catalog/products/[productId]/variants/[variantId]/page.tsx +14 -0
  209. package/src/modules/catalog/backend/catalog/products/[productId]/variants/create/page.tsx +2 -0
  210. package/src/modules/catalog/backend/catalog/products/create/page.tsx +41 -0
  211. package/src/modules/catalog/commands/products.ts +307 -2
  212. package/src/modules/catalog/commands/variants.ts +90 -1
  213. package/src/modules/catalog/components/products/ProductComplianceSection.tsx +497 -0
  214. package/src/modules/catalog/components/products/VariantBuilder.tsx +43 -0
  215. package/src/modules/catalog/components/products/productForm.ts +262 -0
  216. package/src/modules/catalog/components/products/variantForm.ts +4 -0
  217. package/src/modules/catalog/data/entities.ts +97 -0
  218. package/src/modules/catalog/data/types.ts +36 -0
  219. package/src/modules/catalog/data/validators.ts +159 -3
  220. package/src/modules/catalog/i18n/de.json +64 -0
  221. package/src/modules/catalog/i18n/en.json +64 -0
  222. package/src/modules/catalog/i18n/es.json +64 -0
  223. package/src/modules/catalog/i18n/pl.json +64 -0
  224. package/src/modules/catalog/lib/gtin.ts +66 -0
  225. package/src/modules/catalog/migrations/.snapshot-open-mercato.json +457 -0
  226. package/src/modules/catalog/migrations/Migration20260611090000.ts +17 -0
  227. package/src/modules/catalog/translations.ts +1 -1
  228. package/src/modules/configs/api/cache/route.ts +72 -10
  229. package/src/modules/configs/components/CachePanel.tsx +59 -29
  230. package/src/modules/currencies/api/currencies/options/route.ts +22 -4
  231. package/src/modules/currencies/services/rateFetchingService.ts +63 -26
  232. package/src/modules/customer_accounts/backend/customer_accounts/users/[id]/page.tsx +18 -18
  233. package/src/modules/customer_accounts/backend/customer_accounts/users/page.tsx +1 -1
  234. package/src/modules/customer_accounts/i18n/de.json +1 -1
  235. package/src/modules/customer_accounts/i18n/en.json +1 -1
  236. package/src/modules/customer_accounts/i18n/es.json +1 -1
  237. package/src/modules/customer_accounts/i18n/pl.json +1 -1
  238. package/src/modules/customers/backend/calendar/page.meta.ts +23 -0
  239. package/src/modules/customers/backend/calendar/page.tsx +12 -0
  240. package/src/modules/customers/cli.ts +1 -0
  241. package/src/modules/customers/components/calendar/AgendaList.tsx +219 -0
  242. package/src/modules/customers/components/calendar/CalendarEventEditor.tsx +386 -0
  243. package/src/modules/customers/components/calendar/CalendarFooter.tsx +61 -0
  244. package/src/modules/customers/components/calendar/CalendarHeader.tsx +40 -0
  245. package/src/modules/customers/components/calendar/CalendarScreen.tsx +590 -0
  246. package/src/modules/customers/components/calendar/CalendarSettingsModal.tsx +207 -0
  247. package/src/modules/customers/components/calendar/CalendarTabs.tsx +63 -0
  248. package/src/modules/customers/components/calendar/CalendarToolbar.tsx +295 -0
  249. package/src/modules/customers/components/calendar/EventBlock.tsx +205 -0
  250. package/src/modules/customers/components/calendar/EventPeekPopover.tsx +100 -0
  251. package/src/modules/customers/components/calendar/MonthGrid.tsx +236 -0
  252. package/src/modules/customers/components/calendar/ShortcutsDialog.tsx +57 -0
  253. package/src/modules/customers/components/calendar/TimeGrid.tsx +510 -0
  254. package/src/modules/customers/components/calendar/UpcomingCards.tsx +220 -0
  255. package/src/modules/customers/components/calendar/editor/CategoryField.tsx +79 -0
  256. package/src/modules/customers/components/calendar/editor/LocationField.tsx +37 -0
  257. package/src/modules/customers/components/calendar/editor/PeopleField.tsx +148 -0
  258. package/src/modules/customers/components/calendar/editor/RelatedToField.tsx +242 -0
  259. package/src/modules/customers/components/calendar/editor/RepeatField.tsx +132 -0
  260. package/src/modules/customers/components/calendar/editor/ScheduleSection.tsx +110 -0
  261. package/src/modules/customers/components/calendar/editor/SegmentGroup.tsx +50 -0
  262. package/src/modules/customers/components/calendar/editor/hooks.ts +162 -0
  263. package/src/modules/customers/components/calendar/editor/inputs.tsx +158 -0
  264. package/src/modules/customers/components/calendar/editor/lookups.ts +160 -0
  265. package/src/modules/customers/components/calendar/types.ts +163 -0
  266. package/src/modules/customers/components/calendar/useCalendarItems.ts +162 -0
  267. package/src/modules/customers/components/calendar/useCalendarPreferences.ts +52 -0
  268. package/src/modules/customers/i18n/de.json +195 -0
  269. package/src/modules/customers/i18n/en.json +195 -0
  270. package/src/modules/customers/i18n/es.json +195 -0
  271. package/src/modules/customers/i18n/pl.json +195 -0
  272. package/src/modules/customers/lib/calendar/categories.ts +26 -0
  273. package/src/modules/customers/lib/calendar/conflicts.ts +117 -0
  274. package/src/modules/customers/lib/calendar/editorPayload.ts +388 -0
  275. package/src/modules/customers/lib/calendar/grid.ts +50 -0
  276. package/src/modules/customers/lib/calendar/layout.ts +47 -0
  277. package/src/modules/customers/lib/calendar/mapItem.ts +94 -0
  278. package/src/modules/customers/lib/calendar/preferences.ts +95 -0
  279. package/src/modules/customers/lib/calendar/range.ts +45 -0
  280. package/src/modules/customers/lib/calendar/recurrence.ts +137 -0
  281. package/src/modules/dashboards/services/widgetDataService.ts +8 -6
  282. package/src/modules/dictionaries/api/[dictionaryId]/entries/[entryId]/route.ts +61 -1
  283. package/src/modules/dictionaries/api/[dictionaryId]/entries/route.ts +33 -1
  284. package/src/modules/dictionaries/api/[dictionaryId]/route.ts +65 -1
  285. package/src/modules/dictionaries/api/route.ts +36 -1
  286. package/src/modules/feature_toggles/lib/queries.ts +41 -60
  287. package/src/modules/perspectives/api/[tableId]/[perspectiveId]/route.ts +34 -1
  288. package/src/modules/perspectives/api/[tableId]/roles/[roleId]/route.ts +34 -1
  289. package/src/modules/perspectives/api/[tableId]/route.ts +107 -32
  290. package/src/modules/perspectives/services/perspectiveService.ts +9 -5
  291. package/src/modules/planner/api/access.ts +9 -0
  292. package/src/modules/planner/api/availability-date-specific.ts +22 -1
  293. package/src/modules/planner/api/availability-weekly.ts +22 -1
  294. package/src/modules/resources/api/resources/tags/assign/route.ts +42 -0
  295. package/src/modules/resources/api/resources/tags/unassign/route.ts +42 -0
  296. package/src/modules/sales/api/settings/document-numbers/route.ts +35 -1
  297. package/src/modules/sales/api/settings/order-editing/route.ts +37 -3
  298. package/src/modules/staff/api/leave-requests/accept/route.ts +45 -0
  299. package/src/modules/staff/api/leave-requests/reject/route.ts +45 -0
  300. package/src/modules/staff/api/team-members/self/route.ts +43 -0
  301. package/src/modules/staff/api/team-members/tags/assign/route.ts +45 -0
  302. package/src/modules/staff/api/team-members/tags/unassign/route.ts +45 -0
  303. package/src/modules/translations/api/[entityType]/[entityId]/route.ts +65 -1
  304. package/src/modules/translations/api/context.ts +7 -0
  305. package/src/modules/translations/api/put/locales.ts +35 -1
  306. package/src/modules/workflows/backend/definitions/visual-editor/page.tsx +11 -9
  307. package/src/modules/workflows/backend/instances/[id]/page.tsx +1 -1
  308. package/src/modules/workflows/components/EdgeEditDialog.tsx +1 -1
  309. package/src/modules/workflows/components/EdgeEditDialogCrudForm.tsx +1 -1
  310. package/src/modules/workflows/components/NodeEditDialog.tsx +1 -1
  311. package/src/modules/workflows/components/NodeEditDialogCrudForm.tsx +1 -1
  312. package/src/modules/workflows/components/WorkflowGraph.tsx +2 -2
  313. package/src/modules/workflows/components/WorkflowGraphImpl.tsx +27 -13
  314. package/src/modules/workflows/components/mobile/MobileVisualEditor.tsx +3 -3
  315. package/src/modules/workflows/frontend/checkout-demo/deriveCurrentStep.ts +12 -0
  316. package/src/modules/workflows/frontend/checkout-demo/page.tsx +3 -23
  317. package/src/modules/workflows/lib/graph-utils.ts +21 -1
@@ -0,0 +1,131 @@
1
+ "use client";
2
+ import * as React from "react";
3
+ import { apiCall } from "@open-mercato/ui/backend/utils/apiCall";
4
+ import { expandOccurrences } from "../../lib/calendar/recurrence.js";
5
+ import { getFetchWindow } from "../../lib/calendar/range.js";
6
+ import { mapInteractionToCalendarItem } from "../../lib/calendar/mapItem.js";
7
+ import {
8
+ calendarInteractionPayloadSchema
9
+ } from "./types.js";
10
+ const PAGE_LIMIT = 100;
11
+ const MAX_WINDOW_ITEMS = 500;
12
+ async function fetchInteractionWindow(window, signal) {
13
+ const collected = [];
14
+ let cursor;
15
+ let truncated = false;
16
+ do {
17
+ const params = new URLSearchParams({
18
+ from: window.from.toISOString(),
19
+ to: window.to.toISOString(),
20
+ limit: String(PAGE_LIMIT)
21
+ });
22
+ if (cursor) params.set("cursor", cursor);
23
+ const call = await apiCall(
24
+ `/api/customers/interactions?${params.toString()}`,
25
+ { signal }
26
+ );
27
+ if (!call.ok) throw new Error(`[internal] calendar interactions fetch failed (${call.status})`);
28
+ const pageItems = Array.isArray(call.result?.items) ? call.result.items : [];
29
+ for (const rawItem of pageItems) {
30
+ const parsed = calendarInteractionPayloadSchema.safeParse(rawItem);
31
+ if (parsed.success) collected.push(parsed.data);
32
+ }
33
+ cursor = typeof call.result?.nextCursor === "string" ? call.result.nextCursor : void 0;
34
+ if (cursor && collected.length >= MAX_WINDOW_ITEMS) {
35
+ truncated = true;
36
+ cursor = void 0;
37
+ }
38
+ } while (cursor);
39
+ return { payloads: collected.slice(0, MAX_WINDOW_ITEMS), truncated };
40
+ }
41
+ function useCalendarItems(range) {
42
+ const [payloads, setPayloads] = React.useState([]);
43
+ const [isLoading, setIsLoading] = React.useState(true);
44
+ const [error, setError] = React.useState(null);
45
+ const [truncated, setTruncated] = React.useState(false);
46
+ const [typeLabels, setTypeLabels] = React.useState({});
47
+ const [typeColors, setTypeColors] = React.useState({});
48
+ const [reloadToken, setReloadToken] = React.useState(0);
49
+ const fromTime = range.from.getTime();
50
+ const toTime = range.to.getTime();
51
+ React.useEffect(() => {
52
+ const controller = new AbortController();
53
+ let cancelled = false;
54
+ async function loadActivityTypes() {
55
+ const call = await apiCall(
56
+ "/api/customers/dictionaries/activity-types",
57
+ { signal: controller.signal }
58
+ );
59
+ if (cancelled || !call.ok) return;
60
+ const entries = Array.isArray(call.result?.items) ? call.result.items : [];
61
+ const labels = {};
62
+ const colors = {};
63
+ for (const entry of entries) {
64
+ if (typeof entry?.value !== "string" || entry.value.length === 0) continue;
65
+ labels[entry.value] = typeof entry.label === "string" && entry.label.length > 0 ? entry.label : entry.value;
66
+ colors[entry.value] = typeof entry.color === "string" && entry.color.length > 0 ? entry.color : null;
67
+ }
68
+ setTypeLabels(labels);
69
+ setTypeColors(colors);
70
+ }
71
+ loadActivityTypes().catch(() => {
72
+ if (cancelled || controller.signal.aborted) return;
73
+ setTypeLabels({});
74
+ setTypeColors({});
75
+ });
76
+ return () => {
77
+ cancelled = true;
78
+ controller.abort();
79
+ };
80
+ }, []);
81
+ React.useEffect(() => {
82
+ const controller = new AbortController();
83
+ let cancelled = false;
84
+ async function loadInteractions() {
85
+ setIsLoading(true);
86
+ setError(null);
87
+ try {
88
+ const fetchWindow = getFetchWindow({ from: new Date(fromTime), to: new Date(toTime) });
89
+ const { payloads: collected, truncated: windowTruncated } = await fetchInteractionWindow(
90
+ fetchWindow,
91
+ controller.signal
92
+ );
93
+ if (cancelled) return;
94
+ setPayloads(collected);
95
+ setTruncated(windowTruncated);
96
+ } catch (err) {
97
+ if (cancelled || controller.signal.aborted) return;
98
+ setPayloads([]);
99
+ setTruncated(false);
100
+ setError(err instanceof Error ? err.message : "[internal] calendar interactions fetch failed");
101
+ } finally {
102
+ if (!cancelled) setIsLoading(false);
103
+ }
104
+ }
105
+ void loadInteractions();
106
+ return () => {
107
+ cancelled = true;
108
+ controller.abort();
109
+ };
110
+ }, [fromTime, toTime, reloadToken]);
111
+ const items = React.useMemo(() => {
112
+ const expansionWindow = getFetchWindow({ from: new Date(fromTime), to: new Date(toTime) });
113
+ const mapped = [];
114
+ for (const payload of payloads) {
115
+ const item = mapInteractionToCalendarItem(payload, typeColors);
116
+ if (!item) continue;
117
+ mapped.push(...expandOccurrences(item, expansionWindow));
118
+ }
119
+ return mapped;
120
+ }, [payloads, typeColors, fromTime, toTime]);
121
+ const refetch = React.useCallback(() => {
122
+ setReloadToken((token) => token + 1);
123
+ }, []);
124
+ return { items, isLoading, error, truncated, typeLabels, typeColors, refetch };
125
+ }
126
+ export {
127
+ MAX_WINDOW_ITEMS,
128
+ fetchInteractionWindow,
129
+ useCalendarItems
130
+ };
131
+ //# sourceMappingURL=useCalendarItems.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../src/modules/customers/components/calendar/useCalendarItems.ts"],
4
+ "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { apiCall } from '@open-mercato/ui/backend/utils/apiCall'\nimport { expandOccurrences } from '../../lib/calendar/recurrence'\nimport { getFetchWindow } from '../../lib/calendar/range'\nimport { mapInteractionToCalendarItem } from '../../lib/calendar/mapItem'\nimport {\n calendarInteractionPayloadSchema,\n type CalendarInteractionPayload,\n type CalendarItem,\n type CalendarRange,\n} from './types'\n\nconst PAGE_LIMIT = 100\nexport const MAX_WINDOW_ITEMS = 500\n\n/**\n * Cursor-follows `/api/customers/interactions` across the given window (already\n * padded by the caller) up to `MAX_WINDOW_ITEMS`. Shared by the grid data hook\n * and the editor's conflict probe so both see the exact same candidate set.\n */\nexport async function fetchInteractionWindow(\n window: CalendarRange,\n signal?: AbortSignal,\n): Promise<{ payloads: CalendarInteractionPayload[]; truncated: boolean }> {\n const collected: CalendarInteractionPayload[] = []\n let cursor: string | undefined\n let truncated = false\n do {\n const params = new URLSearchParams({\n from: window.from.toISOString(),\n to: window.to.toISOString(),\n limit: String(PAGE_LIMIT),\n })\n if (cursor) params.set('cursor', cursor)\n const call = await apiCall<{ items?: unknown[]; nextCursor?: string }>(\n `/api/customers/interactions?${params.toString()}`,\n { signal },\n )\n if (!call.ok) throw new Error(`[internal] calendar interactions fetch failed (${call.status})`)\n const pageItems = Array.isArray(call.result?.items) ? call.result.items : []\n for (const rawItem of pageItems) {\n const parsed = calendarInteractionPayloadSchema.safeParse(rawItem)\n if (parsed.success) collected.push(parsed.data)\n }\n cursor = typeof call.result?.nextCursor === 'string' ? call.result.nextCursor : undefined\n if (cursor && collected.length >= MAX_WINDOW_ITEMS) {\n truncated = true\n cursor = undefined\n }\n } while (cursor)\n return { payloads: collected.slice(0, MAX_WINDOW_ITEMS), truncated }\n}\n\ntype ActivityTypeDictionaryEntry = {\n value?: unknown\n label?: unknown\n color?: unknown\n}\n\nexport type UseCalendarItemsResult = {\n items: CalendarItem[]\n isLoading: boolean\n error: string | null\n truncated: boolean\n typeLabels: Record<string, string>\n typeColors: Record<string, string | null>\n refetch: () => void\n}\n\nexport function useCalendarItems(range: CalendarRange): UseCalendarItemsResult {\n const [payloads, setPayloads] = React.useState<CalendarInteractionPayload[]>([])\n const [isLoading, setIsLoading] = React.useState(true)\n const [error, setError] = React.useState<string | null>(null)\n const [truncated, setTruncated] = React.useState(false)\n const [typeLabels, setTypeLabels] = React.useState<Record<string, string>>({})\n const [typeColors, setTypeColors] = React.useState<Record<string, string | null>>({})\n const [reloadToken, setReloadToken] = React.useState(0)\n\n const fromTime = range.from.getTime()\n const toTime = range.to.getTime()\n\n React.useEffect(() => {\n const controller = new AbortController()\n let cancelled = false\n async function loadActivityTypes() {\n const call = await apiCall<{ items?: ActivityTypeDictionaryEntry[] }>(\n '/api/customers/dictionaries/activity-types',\n { signal: controller.signal },\n )\n if (cancelled || !call.ok) return\n const entries = Array.isArray(call.result?.items) ? call.result.items : []\n const labels: Record<string, string> = {}\n const colors: Record<string, string | null> = {}\n for (const entry of entries) {\n if (typeof entry?.value !== 'string' || entry.value.length === 0) continue\n labels[entry.value] = typeof entry.label === 'string' && entry.label.length > 0 ? entry.label : entry.value\n colors[entry.value] = typeof entry.color === 'string' && entry.color.length > 0 ? entry.color : null\n }\n setTypeLabels(labels)\n setTypeColors(colors)\n }\n loadActivityTypes().catch(() => {\n if (cancelled || controller.signal.aborted) return\n setTypeLabels({})\n setTypeColors({})\n })\n return () => {\n cancelled = true\n controller.abort()\n }\n }, [])\n\n React.useEffect(() => {\n const controller = new AbortController()\n let cancelled = false\n async function loadInteractions() {\n setIsLoading(true)\n setError(null)\n try {\n const fetchWindow = getFetchWindow({ from: new Date(fromTime), to: new Date(toTime) })\n const { payloads: collected, truncated: windowTruncated } = await fetchInteractionWindow(\n fetchWindow,\n controller.signal,\n )\n if (cancelled) return\n setPayloads(collected)\n setTruncated(windowTruncated)\n } catch (err) {\n if (cancelled || controller.signal.aborted) return\n setPayloads([])\n setTruncated(false)\n setError(err instanceof Error ? err.message : '[internal] calendar interactions fetch failed')\n } finally {\n if (!cancelled) setIsLoading(false)\n }\n }\n void loadInteractions()\n return () => {\n cancelled = true\n controller.abort()\n }\n }, [fromTime, toTime, reloadToken])\n\n const items = React.useMemo(() => {\n const expansionWindow = getFetchWindow({ from: new Date(fromTime), to: new Date(toTime) })\n const mapped: CalendarItem[] = []\n for (const payload of payloads) {\n const item = mapInteractionToCalendarItem(payload, typeColors)\n if (!item) continue\n mapped.push(...expandOccurrences(item, expansionWindow))\n }\n return mapped\n }, [payloads, typeColors, fromTime, toTime])\n\n const refetch = React.useCallback(() => {\n setReloadToken((token) => token + 1)\n }, [])\n\n return { items, isLoading, error, truncated, typeLabels, typeColors, refetch }\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,41 @@
1
+ "use client";
2
+ import * as React from "react";
3
+ import { useCurrentUserId } from "@open-mercato/ui/backend/utils/useCurrentUserId";
4
+ import {
5
+ DEFAULT_CALENDAR_PREFERENCES,
6
+ calendarPreferencesStorageKey,
7
+ parseStoredCalendarPreferences
8
+ } from "../../lib/calendar/preferences.js";
9
+ function useCalendarPreferences() {
10
+ const userId = useCurrentUserId();
11
+ const scopeKey = userId || "anon";
12
+ const [preferences, setPreferencesState] = React.useState(DEFAULT_CALENDAR_PREFERENCES);
13
+ const [hydrated, setHydrated] = React.useState(false);
14
+ React.useEffect(() => {
15
+ if (typeof window === "undefined") return;
16
+ let raw = null;
17
+ try {
18
+ raw = window.localStorage.getItem(calendarPreferencesStorageKey(scopeKey));
19
+ } catch {
20
+ raw = null;
21
+ }
22
+ setPreferencesState(parseStoredCalendarPreferences(raw));
23
+ setHydrated(true);
24
+ }, [scopeKey]);
25
+ const setPreferences = React.useCallback(
26
+ (next) => {
27
+ setPreferencesState(next);
28
+ if (typeof window === "undefined") return;
29
+ try {
30
+ window.localStorage.setItem(calendarPreferencesStorageKey(scopeKey), JSON.stringify(next));
31
+ } catch {
32
+ }
33
+ },
34
+ [scopeKey]
35
+ );
36
+ return { preferences, setPreferences, hydrated, userId: userId || null };
37
+ }
38
+ export {
39
+ useCalendarPreferences
40
+ };
41
+ //# sourceMappingURL=useCalendarPreferences.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../src/modules/customers/components/calendar/useCalendarPreferences.ts"],
4
+ "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { useCurrentUserId } from '@open-mercato/ui/backend/utils/useCurrentUserId'\nimport {\n CalendarPreferences,\n DEFAULT_CALENDAR_PREFERENCES,\n calendarPreferencesStorageKey,\n parseStoredCalendarPreferences,\n} from '../../lib/calendar/preferences'\n\nexport type UseCalendarPreferencesResult = {\n preferences: CalendarPreferences\n setPreferences(next: CalendarPreferences): void\n hydrated: boolean\n // The current user's id (JWT subject), reused to scope \"my meetings\" conflicts.\n userId: string | null\n}\n\nexport function useCalendarPreferences(): UseCalendarPreferencesResult {\n const userId = useCurrentUserId()\n const scopeKey = userId || 'anon'\n const [preferences, setPreferencesState] = React.useState<CalendarPreferences>(DEFAULT_CALENDAR_PREFERENCES)\n const [hydrated, setHydrated] = React.useState(false)\n\n React.useEffect(() => {\n if (typeof window === 'undefined') return\n let raw: string | null = null\n try {\n raw = window.localStorage.getItem(calendarPreferencesStorageKey(scopeKey))\n } catch {\n raw = null\n }\n setPreferencesState(parseStoredCalendarPreferences(raw))\n setHydrated(true)\n }, [scopeKey])\n\n const setPreferences = React.useCallback(\n (next: CalendarPreferences) => {\n setPreferencesState(next)\n if (typeof window === 'undefined') return\n try {\n window.localStorage.setItem(calendarPreferencesStorageKey(scopeKey), JSON.stringify(next))\n } catch {\n // Storage may be unavailable (private mode / quota) \u2014 keep the in-memory value.\n }\n },\n [scopeKey],\n )\n\n return { preferences, setPreferences, hydrated, userId: userId || null }\n}\n"],
5
+ "mappings": ";AAEA,YAAY,WAAW;AACvB,SAAS,wBAAwB;AACjC;AAAA,EAEE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAUA,SAAS,yBAAuD;AACrE,QAAM,SAAS,iBAAiB;AAChC,QAAM,WAAW,UAAU;AAC3B,QAAM,CAAC,aAAa,mBAAmB,IAAI,MAAM,SAA8B,4BAA4B;AAC3G,QAAM,CAAC,UAAU,WAAW,IAAI,MAAM,SAAS,KAAK;AAEpD,QAAM,UAAU,MAAM;AACpB,QAAI,OAAO,WAAW,YAAa;AACnC,QAAI,MAAqB;AACzB,QAAI;AACF,YAAM,OAAO,aAAa,QAAQ,8BAA8B,QAAQ,CAAC;AAAA,IAC3E,QAAQ;AACN,YAAM;AAAA,IACR;AACA,wBAAoB,+BAA+B,GAAG,CAAC;AACvD,gBAAY,IAAI;AAAA,EAClB,GAAG,CAAC,QAAQ,CAAC;AAEb,QAAM,iBAAiB,MAAM;AAAA,IAC3B,CAAC,SAA8B;AAC7B,0BAAoB,IAAI;AACxB,UAAI,OAAO,WAAW,YAAa;AACnC,UAAI;AACF,eAAO,aAAa,QAAQ,8BAA8B,QAAQ,GAAG,KAAK,UAAU,IAAI,CAAC;AAAA,MAC3F,QAAQ;AAAA,MAER;AAAA,IACF;AAAA,IACA,CAAC,QAAQ;AAAA,EACX;AAEA,SAAO,EAAE,aAAa,gBAAgB,UAAU,QAAQ,UAAU,KAAK;AACzE;",
6
+ "names": []
7
+ }
@@ -0,0 +1,28 @@
1
+ const CATEGORY_BY_TYPE = {
2
+ meeting: "meeting",
3
+ call: "meeting",
4
+ "video-call": "meeting",
5
+ event: "event",
6
+ webinar: "event",
7
+ task: "task",
8
+ todo: "task",
9
+ deadline: "task"
10
+ };
11
+ function categoryOf(interactionType) {
12
+ return CATEGORY_BY_TYPE[interactionType] ?? "other";
13
+ }
14
+ function countByCategory(items) {
15
+ let meetings = 0;
16
+ let events = 0;
17
+ for (const item of items) {
18
+ if (item.category === "meeting") meetings += 1;
19
+ else if (item.category === "event") events += 1;
20
+ }
21
+ return { all: items.length, meetings, events };
22
+ }
23
+ export {
24
+ CATEGORY_BY_TYPE,
25
+ categoryOf,
26
+ countByCategory
27
+ };
28
+ //# sourceMappingURL=categories.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../src/modules/customers/lib/calendar/categories.ts"],
4
+ "sourcesContent": ["import type { CalendarCategory, CalendarItem } from '../../components/calendar/types'\n\nexport const CATEGORY_BY_TYPE: Record<string, CalendarCategory> = {\n meeting: 'meeting',\n call: 'meeting',\n 'video-call': 'meeting',\n event: 'event',\n webinar: 'event',\n task: 'task',\n todo: 'task',\n deadline: 'task',\n}\n\nexport function categoryOf(interactionType: string): CalendarCategory {\n return CATEGORY_BY_TYPE[interactionType] ?? 'other'\n}\n\nexport function countByCategory(items: CalendarItem[]): { all: number; meetings: number; events: number } {\n let meetings = 0\n let events = 0\n for (const item of items) {\n if (item.category === 'meeting') meetings += 1\n else if (item.category === 'event') events += 1\n }\n return { all: items.length, meetings, events }\n}\n"],
5
+ "mappings": "AAEO,MAAM,mBAAqD;AAAA,EAChE,SAAS;AAAA,EACT,MAAM;AAAA,EACN,cAAc;AAAA,EACd,OAAO;AAAA,EACP,SAAS;AAAA,EACT,MAAM;AAAA,EACN,MAAM;AAAA,EACN,UAAU;AACZ;AAEO,SAAS,WAAW,iBAA2C;AACpE,SAAO,iBAAiB,eAAe,KAAK;AAC9C;AAEO,SAAS,gBAAgB,OAA0E;AACxG,MAAI,WAAW;AACf,MAAI,SAAS;AACb,aAAW,QAAQ,OAAO;AACxB,QAAI,KAAK,aAAa,UAAW,aAAY;AAAA,aACpC,KAAK,aAAa,QAAS,WAAU;AAAA,EAChD;AACA,SAAO,EAAE,KAAK,MAAM,QAAQ,UAAU,OAAO;AAC/C;",
6
+ "names": []
7
+ }
@@ -0,0 +1,72 @@
1
+ const EDITOR_DRAFT_CONFLICT_ID = "__draft__";
2
+ function sharesActor(first, second) {
3
+ if (first.ownerUserId && second.ownerUserId && first.ownerUserId === second.ownerUserId) return true;
4
+ if (first.participants.length === 0 || second.participants.length === 0) return false;
5
+ const firstParticipantIds = new Set(first.participants.map((participant) => participant.userId));
6
+ return second.participants.some((participant) => firstParticipantIds.has(participant.userId));
7
+ }
8
+ function isActor(item, userId) {
9
+ if (item.ownerUserId === userId) return true;
10
+ return item.participants.some((participant) => participant.userId === userId);
11
+ }
12
+ function appendConflict(conflicts, itemId, otherId) {
13
+ const existing = conflicts.get(itemId);
14
+ if (existing) existing.push(otherId);
15
+ else conflicts.set(itemId, [otherId]);
16
+ }
17
+ function findConflicts(items, options = {}) {
18
+ const conflicts = /* @__PURE__ */ new Map();
19
+ const restrictToCurrentUser = options.scope === "mine" && Boolean(options.currentUserId);
20
+ const currentUserId = options.currentUserId ?? "";
21
+ const candidates = items.filter((item) => item.status !== "canceled").sort((first, second) => first.start.getTime() - second.start.getTime());
22
+ for (let index = 0; index < candidates.length; index += 1) {
23
+ const current = candidates[index];
24
+ const currentEnd = current.end.getTime();
25
+ for (let lookahead = index + 1; lookahead < candidates.length; lookahead += 1) {
26
+ const other = candidates[lookahead];
27
+ if (other.start.getTime() >= currentEnd) break;
28
+ if (current.start.getTime() >= other.end.getTime()) continue;
29
+ if (!sharesActor(current, other)) continue;
30
+ if (restrictToCurrentUser && !(isActor(current, currentUserId) && isActor(other, currentUserId))) continue;
31
+ appendConflict(conflicts, current.id, other.id);
32
+ appendConflict(conflicts, other.id, current.id);
33
+ }
34
+ }
35
+ return conflicts;
36
+ }
37
+ function findEditorConflictItems(draft, others, excludeId, options = {}) {
38
+ const draftStatus = draft.status ?? "planned";
39
+ const draftItem = {
40
+ id: EDITOR_DRAFT_CONFLICT_ID,
41
+ title: "",
42
+ interactionType: "meeting",
43
+ category: "other",
44
+ status: draftStatus,
45
+ start: draft.start,
46
+ end: draft.end,
47
+ allDay: false,
48
+ location: null,
49
+ platform: null,
50
+ locationKind: null,
51
+ participants: draft.participants,
52
+ ownerUserId: draft.ownerUserId,
53
+ entityId: null,
54
+ dealId: null,
55
+ color: null,
56
+ isRecurringOccurrence: false,
57
+ updatedAt: null,
58
+ raw: { id: EDITOR_DRAFT_CONFLICT_ID, interactionType: "meeting", status: draftStatus }
59
+ };
60
+ const candidates = others.filter(
61
+ (item) => item.id !== EDITOR_DRAFT_CONFLICT_ID && item.raw.id !== excludeId
62
+ );
63
+ const conflictIds = findConflicts([draftItem, ...candidates], options).get(EDITOR_DRAFT_CONFLICT_ID) ?? [];
64
+ const byId = new Map(candidates.map((item) => [item.id, item]));
65
+ return conflictIds.map((id) => byId.get(id)).filter((item) => Boolean(item));
66
+ }
67
+ export {
68
+ EDITOR_DRAFT_CONFLICT_ID,
69
+ findConflicts,
70
+ findEditorConflictItems
71
+ };
72
+ //# sourceMappingURL=conflicts.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../src/modules/customers/lib/calendar/conflicts.ts"],
4
+ "sourcesContent": ["import type { CalendarItem, CalendarItemStatus, CalendarParticipant } from '../../components/calendar/types'\nimport type { ConflictScope } from './preferences'\n\nexport const EDITOR_DRAFT_CONFLICT_ID = '__draft__'\n\nexport type FindConflictsOptions = {\n // 'all' (default) flags any actor-sharing overlap; 'mine' only flags overlaps\n // where `currentUserId` is an actor of BOTH events (the user is double-booked).\n // 'mine' with no `currentUserId` degrades to 'all' \u2014 it cannot resolve \"mine\".\n scope?: ConflictScope\n currentUserId?: string | null\n}\n\nfunction sharesActor(first: CalendarItem, second: CalendarItem): boolean {\n if (first.ownerUserId && second.ownerUserId && first.ownerUserId === second.ownerUserId) return true\n if (first.participants.length === 0 || second.participants.length === 0) return false\n const firstParticipantIds = new Set(first.participants.map((participant) => participant.userId))\n return second.participants.some((participant) => firstParticipantIds.has(participant.userId))\n}\n\nfunction isActor(item: CalendarItem, userId: string): boolean {\n if (item.ownerUserId === userId) return true\n return item.participants.some((participant) => participant.userId === userId)\n}\n\nfunction appendConflict(conflicts: Map<string, string[]>, itemId: string, otherId: string): void {\n const existing = conflicts.get(itemId)\n if (existing) existing.push(otherId)\n else conflicts.set(itemId, [otherId])\n}\n\nexport function findConflicts(items: CalendarItem[], options: FindConflictsOptions = {}): Map<string, string[]> {\n const conflicts = new Map<string, string[]>()\n const restrictToCurrentUser = options.scope === 'mine' && Boolean(options.currentUserId)\n const currentUserId = options.currentUserId ?? ''\n const candidates = items\n .filter((item) => item.status !== 'canceled')\n .sort((first, second) => first.start.getTime() - second.start.getTime())\n\n for (let index = 0; index < candidates.length; index += 1) {\n const current = candidates[index]\n const currentEnd = current.end.getTime()\n for (let lookahead = index + 1; lookahead < candidates.length; lookahead += 1) {\n const other = candidates[lookahead]\n if (other.start.getTime() >= currentEnd) break\n if (current.start.getTime() >= other.end.getTime()) continue\n // Org-wide rule first: the two events must share at least one actor.\n if (!sharesActor(current, other)) continue\n // 'mine' narrows that set to the current user's OWN double-bookings \u2014 they\n // must be an actor of both events. Because they are then the shared actor,\n // 'mine' is always a strict subset of 'all' (it never invents new conflicts).\n if (restrictToCurrentUser && !(isActor(current, currentUserId) && isActor(other, currentUserId))) continue\n appendConflict(conflicts, current.id, other.id)\n appendConflict(conflicts, other.id, current.id)\n }\n }\n return conflicts\n}\n\nexport type EditorConflictDraft = {\n start: Date\n end: Date\n ownerUserId: string | null\n participants: CalendarParticipant[]\n // The edited record's status. A canceled draft is excluded by `findConflicts`\n // exactly as the grid excludes canceled items, so the editor never warns about\n // a record the grid would not badge/ring. Defaults to 'planned'.\n status?: CalendarItemStatus\n}\n\n/**\n * Resolves the items a calendar editor draft conflicts with, using the SAME\n * `findConflicts` rules as the grid (overlap + shared owner/participant) so the\n * editor's conflict warning is always consistent with the grid badges/rings.\n * The edited record itself (`excludeId`) is never treated as a conflict.\n */\nexport function findEditorConflictItems(\n draft: EditorConflictDraft,\n others: CalendarItem[],\n excludeId: string | null,\n options: FindConflictsOptions = {},\n): CalendarItem[] {\n const draftStatus: CalendarItemStatus = draft.status ?? 'planned'\n const draftItem: CalendarItem = {\n id: EDITOR_DRAFT_CONFLICT_ID,\n title: '',\n interactionType: 'meeting',\n category: 'other',\n status: draftStatus,\n start: draft.start,\n end: draft.end,\n allDay: false,\n location: null,\n platform: null,\n locationKind: null,\n participants: draft.participants,\n ownerUserId: draft.ownerUserId,\n entityId: null,\n dealId: null,\n color: null,\n isRecurringOccurrence: false,\n updatedAt: null,\n raw: { id: EDITOR_DRAFT_CONFLICT_ID, interactionType: 'meeting', status: draftStatus },\n }\n // Exclude the edited record by its underlying interaction id (`raw.id`), which\n // also drops every expanded occurrence of an edited recurring series (those\n // share the series `raw.id` but get distinct display ids) so it never conflicts\n // with itself.\n const candidates = others.filter(\n (item) => item.id !== EDITOR_DRAFT_CONFLICT_ID && item.raw.id !== excludeId,\n )\n const conflictIds = findConflicts([draftItem, ...candidates], options).get(EDITOR_DRAFT_CONFLICT_ID) ?? []\n const byId = new Map(candidates.map((item) => [item.id, item]))\n return conflictIds\n .map((id) => byId.get(id))\n .filter((item): item is CalendarItem => Boolean(item))\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,271 @@
1
+ import { parseRecurrenceRule } from "./recurrence.js";
2
+ const EDITOR_KINDS = ["meeting", "call", "email", "note", "event", "task"];
3
+ const KIND_CONFIG = {
4
+ meeting: { dateLabel: "starts", hasEnd: true, hasAllDay: true, hasRepeat: true, location: "location", people: "attendees", hasPriority: false },
5
+ call: { dateLabel: "when", hasEnd: false, hasAllDay: true, hasRepeat: true, location: "phoneLink", people: "participants", hasPriority: false },
6
+ email: { dateLabel: "sent", hasEnd: false, hasAllDay: true, hasRepeat: true, location: null, people: "to", hasPriority: false },
7
+ note: { dateLabel: "logged", hasEnd: false, hasAllDay: false, hasRepeat: false, location: null, people: null, hasPriority: false },
8
+ event: { dateLabel: "starts", hasEnd: true, hasAllDay: true, hasRepeat: true, location: "location", people: "attendees", hasPriority: false },
9
+ task: { dateLabel: "due", hasEnd: false, hasAllDay: true, hasRepeat: true, location: null, people: "assignee", hasPriority: true }
10
+ };
11
+ const KIND_BY_INTERACTION_TYPE = {
12
+ meeting: "meeting",
13
+ call: "call",
14
+ "video-call": "call",
15
+ email: "email",
16
+ note: "note",
17
+ event: "event",
18
+ webinar: "event",
19
+ task: "task",
20
+ todo: "task",
21
+ deadline: "task"
22
+ };
23
+ function editorKindOfInteractionType(interactionType) {
24
+ return KIND_BY_INTERACTION_TYPE[interactionType] ?? "meeting";
25
+ }
26
+ function buildEditorCategoryOptions(params) {
27
+ const { typeLabels, surfacedTypes, eventCategories, selectedValue, selectedFallbackLabel } = params;
28
+ const dictionaryOptions = Object.entries(typeLabels).map(([value, label]) => ({ value, label }));
29
+ const surfacedSet = new Set(surfacedTypes);
30
+ const filtered = surfacedTypes.length > 0 ? dictionaryOptions.filter((option) => surfacedSet.has(option.label)) : dictionaryOptions;
31
+ const options = [...filtered];
32
+ const knownLabels = new Set(options.map((option) => option.label));
33
+ const knownValues = new Set(options.map((option) => option.value));
34
+ const customLabels = [];
35
+ for (const label of [...eventCategories, ...surfacedTypes]) {
36
+ const trimmed = label.trim();
37
+ if (!trimmed || knownLabels.has(trimmed) || customLabels.includes(trimmed)) continue;
38
+ customLabels.push(trimmed);
39
+ }
40
+ for (const label of customLabels) {
41
+ options.push({ value: label, label });
42
+ knownValues.add(label);
43
+ }
44
+ if (!knownValues.has(selectedValue)) {
45
+ options.unshift({ value: selectedValue, label: typeLabels[selectedValue] ?? selectedFallbackLabel });
46
+ }
47
+ return options;
48
+ }
49
+ const PRIORITY_NUMBER = { low: 10, medium: 50, high: 90 };
50
+ function priorityFromNumber(value) {
51
+ if (typeof value !== "number" || Number.isNaN(value)) return "medium";
52
+ if (value <= 33) return "low";
53
+ if (value <= 66) return "medium";
54
+ return "high";
55
+ }
56
+ const MO_FIRST_DAY_TOKENS = ["MO", "TU", "WE", "TH", "FR", "SA", "SU"];
57
+ function padDatePart(value) {
58
+ return String(value).padStart(2, "0");
59
+ }
60
+ function formatLocalDateInput(date) {
61
+ return `${date.getFullYear()}-${padDatePart(date.getMonth() + 1)}-${padDatePart(date.getDate())}`;
62
+ }
63
+ function formatLocalTimeInput(date) {
64
+ return `${padDatePart(date.getHours())}:${padDatePart(date.getMinutes())}`;
65
+ }
66
+ function moFirstIndexOfDate(date) {
67
+ return (date.getDay() + 6) % 7;
68
+ }
69
+ function defaultRepeatDaysForDateInput(dateInput) {
70
+ const parsed = /* @__PURE__ */ new Date(`${dateInput}T00:00:00`);
71
+ return defaultRepeatDays(Number.isNaN(parsed.getTime()) ? /* @__PURE__ */ new Date() : parsed);
72
+ }
73
+ function defaultRepeatDays(start) {
74
+ const days = [false, false, false, false, false, false, false];
75
+ days[moFirstIndexOfDate(start)] = true;
76
+ return days;
77
+ }
78
+ function resolveSavedOwnerUserId(config, form, isEdit, existingOwnerUserId) {
79
+ if (config.people === "assignee") return form.assigneeUserId ?? null;
80
+ return isEdit ? existingOwnerUserId : null;
81
+ }
82
+ function createDefaultFormState(defaultDate, now = /* @__PURE__ */ new Date(), range) {
83
+ let base;
84
+ let end;
85
+ if (range) {
86
+ base = new Date(range.start);
87
+ end = new Date(range.end);
88
+ } else {
89
+ base = defaultDate ? new Date(defaultDate) : new Date(now);
90
+ base.setHours(now.getHours(), 0, 0, 0);
91
+ base.setHours(base.getHours() + 1);
92
+ end = new Date(base.getTime() + 90 * 6e4);
93
+ }
94
+ return {
95
+ kind: "meeting",
96
+ title: "",
97
+ relatedTo: null,
98
+ dealId: null,
99
+ dealLabel: null,
100
+ allDay: false,
101
+ date: formatLocalDateInput(base),
102
+ startTime: formatLocalTimeInput(base),
103
+ endDate: formatLocalDateInput(end),
104
+ endTime: formatLocalTimeInput(end),
105
+ repeatFreq: "none",
106
+ repeatDays: defaultRepeatDays(base),
107
+ repeatEndType: "never",
108
+ repeatCount: 8,
109
+ repeatUntilDate: "",
110
+ category: null,
111
+ location: "",
112
+ participants: [],
113
+ assigneeUserId: null,
114
+ assigneeName: null,
115
+ priority: "medium",
116
+ description: "",
117
+ status: "planned"
118
+ };
119
+ }
120
+ function buildRecurrenceRule(state) {
121
+ if (state.repeatFreq === "none") return null;
122
+ let rule;
123
+ if (state.repeatFreq === "daily") {
124
+ rule = "FREQ=DAILY";
125
+ } else {
126
+ const selected = MO_FIRST_DAY_TOKENS.filter((_, index) => state.repeatDays[index]);
127
+ const tokens = selected.length > 0 ? selected : [MO_FIRST_DAY_TOKENS[moFirstIndexOfDate(/* @__PURE__ */ new Date(`${state.date}T00:00:00`))]];
128
+ rule = `FREQ=WEEKLY;BYDAY=${tokens.join(",")}`;
129
+ }
130
+ if (state.repeatEndType === "count") rule += `;COUNT=${state.repeatCount}`;
131
+ if (state.repeatEndType === "date" && state.repeatUntilDate) {
132
+ rule += `;UNTIL=${state.repeatUntilDate.replace(/-/g, "")}T235959Z`;
133
+ }
134
+ return rule;
135
+ }
136
+ function computeDurationMinutes(state) {
137
+ const start = /* @__PURE__ */ new Date(`${state.date}T${state.startTime}:00`);
138
+ const end = /* @__PURE__ */ new Date(`${state.endDate}T${state.endTime}:00`);
139
+ if (Number.isNaN(start.getTime()) || Number.isNaN(end.getTime())) return null;
140
+ const minutes = Math.round((end.getTime() - start.getTime()) / 6e4);
141
+ return minutes > 0 ? minutes : null;
142
+ }
143
+ function buildInteractionPayload(state, options) {
144
+ const config = KIND_CONFIG[state.kind];
145
+ const time = state.allDay && config.hasAllDay ? "00:00" : state.startTime;
146
+ const scheduledAt = (/* @__PURE__ */ new Date(`${state.date}T${time}:00`)).toISOString();
147
+ const recurrenceRule = config.hasRepeat ? buildRecurrenceRule(state) : null;
148
+ const payload = {
149
+ ...options.mode === "edit" && options.id ? { id: options.id } : {},
150
+ entityId: state.relatedTo?.id ?? null,
151
+ dealId: state.dealId ?? null,
152
+ interactionType: state.category ?? state.kind,
153
+ title: state.title.trim(),
154
+ body: state.description.trim() || null,
155
+ status: options.mode === "create" ? "planned" : state.status,
156
+ date: state.date,
157
+ time,
158
+ scheduledAt,
159
+ durationMinutes: config.hasEnd && !(state.allDay && config.hasAllDay) ? computeDurationMinutes(state) : null,
160
+ allDay: config.hasAllDay ? state.allDay : null,
161
+ location: config.location ? state.location.trim() || null : null,
162
+ recurrenceRule,
163
+ recurrenceEnd: recurrenceRule && state.repeatEndType === "date" && state.repeatUntilDate ? new Date(state.repeatUntilDate).toISOString() : null,
164
+ participants: config.people && config.people !== "assignee" && state.participants.length > 0 ? state.participants.map((participant) => ({
165
+ userId: participant.userId,
166
+ name: participant.name,
167
+ email: participant.email,
168
+ status: participant.isCustomer ? "customer" : "pending"
169
+ })) : null
170
+ };
171
+ if (config.people === "assignee") payload.ownerUserId = state.assigneeUserId ?? null;
172
+ if (config.hasPriority) payload.priority = PRIORITY_NUMBER[state.priority];
173
+ return payload;
174
+ }
175
+ function readUnknownString(value) {
176
+ return typeof value === "string" && value.length > 0 ? value : null;
177
+ }
178
+ function readUnknownNumber(value) {
179
+ return typeof value === "number" && Number.isFinite(value) ? value : null;
180
+ }
181
+ function parseRepeatFromRule(rawRule, start) {
182
+ const fallback = {
183
+ repeatFreq: "none",
184
+ repeatDays: defaultRepeatDays(start),
185
+ repeatEndType: "never",
186
+ repeatCount: 8,
187
+ repeatUntilDate: ""
188
+ };
189
+ const ruleText = readUnknownString(rawRule);
190
+ if (!ruleText) return fallback;
191
+ const parsed = parseRecurrenceRule(ruleText);
192
+ if (!parsed) return fallback;
193
+ const repeatDays = defaultRepeatDays(start);
194
+ if (parsed.byDay) {
195
+ repeatDays.fill(false);
196
+ for (const jsWeekday of parsed.byDay) repeatDays[(jsWeekday + 6) % 7] = true;
197
+ }
198
+ let repeatEndType = "never";
199
+ let repeatCount = 8;
200
+ let repeatUntilDate = "";
201
+ if (parsed.count !== null) {
202
+ repeatEndType = "count";
203
+ repeatCount = parsed.count;
204
+ } else if (parsed.until) {
205
+ repeatEndType = "date";
206
+ repeatUntilDate = `${parsed.until.getUTCFullYear()}-${padDatePart(parsed.until.getUTCMonth() + 1)}-${padDatePart(parsed.until.getUTCDate())}`;
207
+ }
208
+ return {
209
+ repeatFreq: parsed.freq === "DAILY" ? "daily" : "weekly",
210
+ repeatDays,
211
+ repeatEndType,
212
+ repeatCount,
213
+ repeatUntilDate
214
+ };
215
+ }
216
+ function parseParticipants(item) {
217
+ const rawParticipants = Array.isArray(item.raw.participants) ? item.raw.participants : [];
218
+ const statusByUserId = /* @__PURE__ */ new Map();
219
+ for (const raw of rawParticipants) {
220
+ statusByUserId.set(raw.userId, readUnknownString(raw.status));
221
+ }
222
+ return item.participants.map((participant) => ({
223
+ userId: participant.userId,
224
+ name: participant.name ?? participant.email ?? participant.userId,
225
+ email: participant.email,
226
+ isCustomer: statusByUserId.get(participant.userId) === "customer"
227
+ }));
228
+ }
229
+ function parseItemToFormState(item) {
230
+ const kind = editorKindOfInteractionType(item.interactionType);
231
+ const raw = item.raw;
232
+ return {
233
+ kind,
234
+ title: item.title,
235
+ relatedTo: item.entityId ? { id: item.entityId, kind: "unknown", label: "" } : null,
236
+ dealId: item.dealId,
237
+ dealLabel: null,
238
+ allDay: item.allDay,
239
+ date: formatLocalDateInput(item.start),
240
+ startTime: formatLocalTimeInput(item.start),
241
+ endDate: formatLocalDateInput(item.end),
242
+ endTime: formatLocalTimeInput(item.end),
243
+ ...parseRepeatFromRule(item.raw.recurrenceRule, item.start),
244
+ category: item.interactionType,
245
+ location: item.location ?? "",
246
+ participants: parseParticipants(item),
247
+ assigneeUserId: item.ownerUserId,
248
+ assigneeName: null,
249
+ priority: priorityFromNumber(readUnknownNumber(raw.priority)),
250
+ description: readUnknownString(raw.body) ?? "",
251
+ status: item.status
252
+ };
253
+ }
254
+ export {
255
+ EDITOR_KINDS,
256
+ KIND_CONFIG,
257
+ PRIORITY_NUMBER,
258
+ buildEditorCategoryOptions,
259
+ buildInteractionPayload,
260
+ buildRecurrenceRule,
261
+ computeDurationMinutes,
262
+ createDefaultFormState,
263
+ defaultRepeatDaysForDateInput,
264
+ editorKindOfInteractionType,
265
+ formatLocalDateInput,
266
+ formatLocalTimeInput,
267
+ parseItemToFormState,
268
+ priorityFromNumber,
269
+ resolveSavedOwnerUserId
270
+ };
271
+ //# sourceMappingURL=editorPayload.js.map