@open-mercato/core 0.6.6-develop.6089.1.a7ed560528 → 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 (320) 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/messages/commands/actions.js +81 -9
  147. package/dist/modules/messages/commands/actions.js.map +2 -2
  148. package/dist/modules/perspectives/api/[tableId]/[perspectiveId]/route.js +32 -1
  149. package/dist/modules/perspectives/api/[tableId]/[perspectiveId]/route.js.map +2 -2
  150. package/dist/modules/perspectives/api/[tableId]/roles/[roleId]/route.js +32 -1
  151. package/dist/modules/perspectives/api/[tableId]/roles/[roleId]/route.js.map +2 -2
  152. package/dist/modules/perspectives/api/[tableId]/route.js +73 -2
  153. package/dist/modules/perspectives/api/[tableId]/route.js.map +2 -2
  154. package/dist/modules/perspectives/services/perspectiveService.js +5 -3
  155. package/dist/modules/perspectives/services/perspectiveService.js.map +2 -2
  156. package/dist/modules/planner/api/access.js +9 -0
  157. package/dist/modules/planner/api/access.js.map +2 -2
  158. package/dist/modules/planner/api/availability-date-specific.js +22 -1
  159. package/dist/modules/planner/api/availability-date-specific.js.map +2 -2
  160. package/dist/modules/planner/api/availability-weekly.js +22 -1
  161. package/dist/modules/planner/api/availability-weekly.js.map +2 -2
  162. package/dist/modules/resources/api/resources/tags/assign/route.js +39 -0
  163. package/dist/modules/resources/api/resources/tags/assign/route.js.map +2 -2
  164. package/dist/modules/resources/api/resources/tags/unassign/route.js +39 -0
  165. package/dist/modules/resources/api/resources/tags/unassign/route.js.map +2 -2
  166. package/dist/modules/sales/api/settings/document-numbers/route.js +33 -1
  167. package/dist/modules/sales/api/settings/document-numbers/route.js.map +2 -2
  168. package/dist/modules/sales/api/settings/order-editing/route.js +35 -3
  169. package/dist/modules/sales/api/settings/order-editing/route.js.map +2 -2
  170. package/dist/modules/staff/api/leave-requests/accept/route.js +41 -0
  171. package/dist/modules/staff/api/leave-requests/accept/route.js.map +2 -2
  172. package/dist/modules/staff/api/leave-requests/reject/route.js +41 -0
  173. package/dist/modules/staff/api/leave-requests/reject/route.js.map +2 -2
  174. package/dist/modules/staff/api/team-members/self/route.js +40 -0
  175. package/dist/modules/staff/api/team-members/self/route.js.map +2 -2
  176. package/dist/modules/staff/api/team-members/tags/assign/route.js +41 -0
  177. package/dist/modules/staff/api/team-members/tags/assign/route.js.map +2 -2
  178. package/dist/modules/staff/api/team-members/tags/unassign/route.js +41 -0
  179. package/dist/modules/staff/api/team-members/tags/unassign/route.js.map +2 -2
  180. package/dist/modules/translations/api/[entityType]/[entityId]/route.js +61 -1
  181. package/dist/modules/translations/api/[entityType]/[entityId]/route.js.map +2 -2
  182. package/dist/modules/translations/api/context.js +7 -0
  183. package/dist/modules/translations/api/context.js.map +2 -2
  184. package/dist/modules/translations/api/put/locales.js +33 -1
  185. package/dist/modules/translations/api/put/locales.js.map +2 -2
  186. package/dist/modules/workflows/backend/definitions/visual-editor/page.js +6 -7
  187. package/dist/modules/workflows/backend/definitions/visual-editor/page.js.map +2 -2
  188. package/dist/modules/workflows/backend/instances/[id]/page.js.map +1 -1
  189. package/dist/modules/workflows/components/EdgeEditDialog.js.map +1 -1
  190. package/dist/modules/workflows/components/EdgeEditDialogCrudForm.js.map +1 -1
  191. package/dist/modules/workflows/components/NodeEditDialog.js.map +1 -1
  192. package/dist/modules/workflows/components/NodeEditDialogCrudForm.js.map +1 -1
  193. package/dist/modules/workflows/components/WorkflowGraph.js.map +1 -1
  194. package/dist/modules/workflows/components/WorkflowGraphImpl.js +17 -9
  195. package/dist/modules/workflows/components/WorkflowGraphImpl.js.map +2 -2
  196. package/dist/modules/workflows/components/mobile/MobileVisualEditor.js.map +1 -1
  197. package/dist/modules/workflows/frontend/checkout-demo/deriveCurrentStep.js +8 -0
  198. package/dist/modules/workflows/frontend/checkout-demo/deriveCurrentStep.js.map +7 -0
  199. package/dist/modules/workflows/frontend/checkout-demo/page.js +2 -20
  200. package/dist/modules/workflows/frontend/checkout-demo/page.js.map +2 -2
  201. package/dist/modules/workflows/lib/graph-utils.js +8 -0
  202. package/dist/modules/workflows/lib/graph-utils.js.map +2 -2
  203. package/generated/entities/catalog_product/index.ts +26 -0
  204. package/generated/entities/catalog_product_variant/index.ts +2 -0
  205. package/generated/entity-fields-registry.ts +28 -0
  206. package/package.json +7 -7
  207. package/src/modules/catalog/api/products/route.ts +123 -39
  208. package/src/modules/catalog/api/variants/route.ts +4 -0
  209. package/src/modules/catalog/backend/catalog/products/[id]/page.tsx +43 -0
  210. package/src/modules/catalog/backend/catalog/products/[productId]/variants/[variantId]/page.tsx +14 -0
  211. package/src/modules/catalog/backend/catalog/products/[productId]/variants/create/page.tsx +2 -0
  212. package/src/modules/catalog/backend/catalog/products/create/page.tsx +41 -0
  213. package/src/modules/catalog/commands/products.ts +307 -2
  214. package/src/modules/catalog/commands/variants.ts +90 -1
  215. package/src/modules/catalog/components/products/ProductComplianceSection.tsx +497 -0
  216. package/src/modules/catalog/components/products/VariantBuilder.tsx +43 -0
  217. package/src/modules/catalog/components/products/productForm.ts +262 -0
  218. package/src/modules/catalog/components/products/variantForm.ts +4 -0
  219. package/src/modules/catalog/data/entities.ts +97 -0
  220. package/src/modules/catalog/data/types.ts +36 -0
  221. package/src/modules/catalog/data/validators.ts +159 -3
  222. package/src/modules/catalog/i18n/de.json +64 -0
  223. package/src/modules/catalog/i18n/en.json +64 -0
  224. package/src/modules/catalog/i18n/es.json +64 -0
  225. package/src/modules/catalog/i18n/pl.json +64 -0
  226. package/src/modules/catalog/lib/gtin.ts +66 -0
  227. package/src/modules/catalog/migrations/.snapshot-open-mercato.json +457 -0
  228. package/src/modules/catalog/migrations/Migration20260611090000.ts +17 -0
  229. package/src/modules/catalog/translations.ts +1 -1
  230. package/src/modules/configs/api/cache/route.ts +72 -10
  231. package/src/modules/configs/components/CachePanel.tsx +59 -29
  232. package/src/modules/currencies/api/currencies/options/route.ts +22 -4
  233. package/src/modules/currencies/services/rateFetchingService.ts +63 -26
  234. package/src/modules/customer_accounts/backend/customer_accounts/users/[id]/page.tsx +18 -18
  235. package/src/modules/customer_accounts/backend/customer_accounts/users/page.tsx +1 -1
  236. package/src/modules/customer_accounts/i18n/de.json +1 -1
  237. package/src/modules/customer_accounts/i18n/en.json +1 -1
  238. package/src/modules/customer_accounts/i18n/es.json +1 -1
  239. package/src/modules/customer_accounts/i18n/pl.json +1 -1
  240. package/src/modules/customers/backend/calendar/page.meta.ts +23 -0
  241. package/src/modules/customers/backend/calendar/page.tsx +12 -0
  242. package/src/modules/customers/cli.ts +1 -0
  243. package/src/modules/customers/components/calendar/AgendaList.tsx +219 -0
  244. package/src/modules/customers/components/calendar/CalendarEventEditor.tsx +386 -0
  245. package/src/modules/customers/components/calendar/CalendarFooter.tsx +61 -0
  246. package/src/modules/customers/components/calendar/CalendarHeader.tsx +40 -0
  247. package/src/modules/customers/components/calendar/CalendarScreen.tsx +590 -0
  248. package/src/modules/customers/components/calendar/CalendarSettingsModal.tsx +207 -0
  249. package/src/modules/customers/components/calendar/CalendarTabs.tsx +63 -0
  250. package/src/modules/customers/components/calendar/CalendarToolbar.tsx +295 -0
  251. package/src/modules/customers/components/calendar/EventBlock.tsx +205 -0
  252. package/src/modules/customers/components/calendar/EventPeekPopover.tsx +100 -0
  253. package/src/modules/customers/components/calendar/MonthGrid.tsx +236 -0
  254. package/src/modules/customers/components/calendar/ShortcutsDialog.tsx +57 -0
  255. package/src/modules/customers/components/calendar/TimeGrid.tsx +510 -0
  256. package/src/modules/customers/components/calendar/UpcomingCards.tsx +220 -0
  257. package/src/modules/customers/components/calendar/editor/CategoryField.tsx +79 -0
  258. package/src/modules/customers/components/calendar/editor/LocationField.tsx +37 -0
  259. package/src/modules/customers/components/calendar/editor/PeopleField.tsx +148 -0
  260. package/src/modules/customers/components/calendar/editor/RelatedToField.tsx +242 -0
  261. package/src/modules/customers/components/calendar/editor/RepeatField.tsx +132 -0
  262. package/src/modules/customers/components/calendar/editor/ScheduleSection.tsx +110 -0
  263. package/src/modules/customers/components/calendar/editor/SegmentGroup.tsx +50 -0
  264. package/src/modules/customers/components/calendar/editor/hooks.ts +162 -0
  265. package/src/modules/customers/components/calendar/editor/inputs.tsx +158 -0
  266. package/src/modules/customers/components/calendar/editor/lookups.ts +160 -0
  267. package/src/modules/customers/components/calendar/types.ts +163 -0
  268. package/src/modules/customers/components/calendar/useCalendarItems.ts +162 -0
  269. package/src/modules/customers/components/calendar/useCalendarPreferences.ts +52 -0
  270. package/src/modules/customers/i18n/de.json +195 -0
  271. package/src/modules/customers/i18n/en.json +195 -0
  272. package/src/modules/customers/i18n/es.json +195 -0
  273. package/src/modules/customers/i18n/pl.json +195 -0
  274. package/src/modules/customers/lib/calendar/categories.ts +26 -0
  275. package/src/modules/customers/lib/calendar/conflicts.ts +117 -0
  276. package/src/modules/customers/lib/calendar/editorPayload.ts +388 -0
  277. package/src/modules/customers/lib/calendar/grid.ts +50 -0
  278. package/src/modules/customers/lib/calendar/layout.ts +47 -0
  279. package/src/modules/customers/lib/calendar/mapItem.ts +94 -0
  280. package/src/modules/customers/lib/calendar/preferences.ts +95 -0
  281. package/src/modules/customers/lib/calendar/range.ts +45 -0
  282. package/src/modules/customers/lib/calendar/recurrence.ts +137 -0
  283. package/src/modules/dashboards/services/widgetDataService.ts +8 -6
  284. package/src/modules/dictionaries/api/[dictionaryId]/entries/[entryId]/route.ts +61 -1
  285. package/src/modules/dictionaries/api/[dictionaryId]/entries/route.ts +33 -1
  286. package/src/modules/dictionaries/api/[dictionaryId]/route.ts +65 -1
  287. package/src/modules/dictionaries/api/route.ts +36 -1
  288. package/src/modules/feature_toggles/lib/queries.ts +41 -60
  289. package/src/modules/messages/commands/actions.ts +100 -7
  290. package/src/modules/perspectives/api/[tableId]/[perspectiveId]/route.ts +34 -1
  291. package/src/modules/perspectives/api/[tableId]/roles/[roleId]/route.ts +34 -1
  292. package/src/modules/perspectives/api/[tableId]/route.ts +107 -32
  293. package/src/modules/perspectives/services/perspectiveService.ts +9 -5
  294. package/src/modules/planner/api/access.ts +9 -0
  295. package/src/modules/planner/api/availability-date-specific.ts +22 -1
  296. package/src/modules/planner/api/availability-weekly.ts +22 -1
  297. package/src/modules/resources/api/resources/tags/assign/route.ts +42 -0
  298. package/src/modules/resources/api/resources/tags/unassign/route.ts +42 -0
  299. package/src/modules/sales/api/settings/document-numbers/route.ts +35 -1
  300. package/src/modules/sales/api/settings/order-editing/route.ts +37 -3
  301. package/src/modules/staff/api/leave-requests/accept/route.ts +45 -0
  302. package/src/modules/staff/api/leave-requests/reject/route.ts +45 -0
  303. package/src/modules/staff/api/team-members/self/route.ts +43 -0
  304. package/src/modules/staff/api/team-members/tags/assign/route.ts +45 -0
  305. package/src/modules/staff/api/team-members/tags/unassign/route.ts +45 -0
  306. package/src/modules/translations/api/[entityType]/[entityId]/route.ts +65 -1
  307. package/src/modules/translations/api/context.ts +7 -0
  308. package/src/modules/translations/api/put/locales.ts +35 -1
  309. package/src/modules/workflows/backend/definitions/visual-editor/page.tsx +11 -9
  310. package/src/modules/workflows/backend/instances/[id]/page.tsx +1 -1
  311. package/src/modules/workflows/components/EdgeEditDialog.tsx +1 -1
  312. package/src/modules/workflows/components/EdgeEditDialogCrudForm.tsx +1 -1
  313. package/src/modules/workflows/components/NodeEditDialog.tsx +1 -1
  314. package/src/modules/workflows/components/NodeEditDialogCrudForm.tsx +1 -1
  315. package/src/modules/workflows/components/WorkflowGraph.tsx +2 -2
  316. package/src/modules/workflows/components/WorkflowGraphImpl.tsx +27 -13
  317. package/src/modules/workflows/components/mobile/MobileVisualEditor.tsx +3 -3
  318. package/src/modules/workflows/frontend/checkout-demo/deriveCurrentStep.ts +12 -0
  319. package/src/modules/workflows/frontend/checkout-demo/page.tsx +3 -23
  320. package/src/modules/workflows/lib/graph-utils.ts +21 -1
@@ -0,0 +1,162 @@
1
+ "use client"
2
+
3
+ import * as React from 'react'
4
+ import { endOfDay } from 'date-fns/endOfDay'
5
+ import { startOfDay } from 'date-fns/startOfDay'
6
+ import { useT } from '@open-mercato/shared/lib/i18n/context'
7
+ import { computeDurationMinutes, type EditorFormState, type EditorKindConfig } from '../../../lib/calendar/editorPayload'
8
+ import { findEditorConflictItems } from '../../../lib/calendar/conflicts'
9
+ import type { ConflictScope } from '../../../lib/calendar/preferences'
10
+ import { mapInteractionToCalendarItem } from '../../../lib/calendar/mapItem'
11
+ import { expandOccurrences } from '../../../lib/calendar/recurrence'
12
+ import { getFetchWindow } from '../../../lib/calendar/range'
13
+ import type { CalendarItem } from '../types'
14
+ import { fetchInteractionWindow } from '../useCalendarItems'
15
+ import { fetchDealById, fetchRelatedEntityById, findStaffMemberName } from './lookups'
16
+
17
+ // Edit-mode prefill stores ids only (parseItemToFormState is pure); resolve the
18
+ // human labels for the related entity, the deal chip and the task assignee.
19
+ export function useEditorLabelResolution(
20
+ open: boolean,
21
+ form: EditorFormState,
22
+ update: (patch: Partial<EditorFormState>) => void,
23
+ ): void {
24
+ React.useEffect(() => {
25
+ if (!open) return
26
+ const controller = new AbortController()
27
+ let cancelled = false
28
+ async function resolveLabels() {
29
+ if (form.relatedTo && form.relatedTo.kind === 'unknown') {
30
+ const resolved = await fetchRelatedEntityById(form.relatedTo.id, controller.signal)
31
+ if (!cancelled && resolved) update({ relatedTo: { id: resolved.id, kind: resolved.kind, label: resolved.label } })
32
+ }
33
+ if (form.dealId && !form.dealLabel) {
34
+ const deal = await fetchDealById(form.dealId, controller.signal)
35
+ if (!cancelled && deal) update({ dealLabel: deal.label })
36
+ }
37
+ if (form.assigneeUserId && !form.assigneeName) {
38
+ const name = await findStaffMemberName(form.assigneeUserId, controller.signal)
39
+ if (!cancelled && name) update({ assigneeName: name })
40
+ }
41
+ }
42
+ resolveLabels().catch(() => {
43
+ if (cancelled || controller.signal.aborted || !form.relatedTo || form.relatedTo.kind !== 'unknown' || form.relatedTo.label) {
44
+ return
45
+ }
46
+ update({ relatedTo: { ...form.relatedTo, label: form.relatedTo.id } })
47
+ })
48
+ return () => {
49
+ cancelled = true
50
+ controller.abort()
51
+ }
52
+ }, [open, form.relatedTo, form.dealId, form.dealLabel, form.assigneeUserId, form.assigneeName, update])
53
+ }
54
+
55
+ function formatClock(date: Date): string {
56
+ return date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })
57
+ }
58
+
59
+ // Debounced save-time conflict probe. Detection uses the SAME `findConflicts`
60
+ // logic the grid uses (overlap + shared owner/participant) against a freshly
61
+ // fetched ±1-day window, so the editor warning is always consistent with the
62
+ // conflict badges/rings the user sees on the calendar. The warning is
63
+ // informational and never blocks saving.
64
+ export function useConflictProbe(
65
+ open: boolean,
66
+ form: EditorFormState,
67
+ config: EditorKindConfig,
68
+ excludeId: string | null,
69
+ draftOwnerUserId: string | null,
70
+ scope: ConflictScope,
71
+ currentUserId: string | null,
72
+ ): string | null {
73
+ const t = useT()
74
+ const [conflict, setConflict] = React.useState<string | null>(null)
75
+ const participantsKey = form.participants.map((participant) => participant.userId).join(',')
76
+ React.useEffect(() => {
77
+ if (!open || !form.date) {
78
+ setConflict(null)
79
+ return
80
+ }
81
+ // Resolve the draft's [start, end] span exactly as the grid will after save:
82
+ // all-day spans startOfDay..endOfDay (matching mapInteractionToCalendarItem),
83
+ // timed events use the start + computed duration (multi-day endDate included).
84
+ const isAllDay = config.hasAllDay && form.allDay
85
+ let start: Date
86
+ let end: Date
87
+ if (isAllDay) {
88
+ const dayDate = new Date(`${form.date}T00:00:00`)
89
+ if (Number.isNaN(dayDate.getTime())) {
90
+ setConflict(null)
91
+ return
92
+ }
93
+ start = startOfDay(dayDate)
94
+ end = endOfDay(dayDate)
95
+ } else {
96
+ if (!form.startTime) {
97
+ setConflict(null)
98
+ return
99
+ }
100
+ start = new Date(`${form.date}T${form.startTime}:00`)
101
+ if (Number.isNaN(start.getTime())) {
102
+ setConflict(null)
103
+ return
104
+ }
105
+ const durationMinutes = config.hasEnd ? computeDurationMinutes(form) ?? 30 : 30
106
+ end = new Date(start.getTime() + durationMinutes * 60_000)
107
+ }
108
+ // The same padded window + recurrence expansion the grid uses, so the probe
109
+ // sees the exact candidate set behind the grid's conflict badges/rings. The
110
+ // window pads ±1 day around the FULL draft span so multi-day drafts still
111
+ // catch neighbours near their end, not just their start day.
112
+ const dayStart = startOfDay(start)
113
+ dayStart.setDate(dayStart.getDate() - 1)
114
+ const dayEnd = endOfDay(end)
115
+ dayEnd.setDate(dayEnd.getDate() + 1)
116
+ const fetchWindow = getFetchWindow({ from: dayStart, to: dayEnd })
117
+ const controller = new AbortController()
118
+ let active = true
119
+ const timer = setTimeout(async () => {
120
+ try {
121
+ const { payloads } = await fetchInteractionWindow(fetchWindow, controller.signal)
122
+ if (!active) return
123
+ const others: CalendarItem[] = []
124
+ for (const payload of payloads) {
125
+ const item = mapInteractionToCalendarItem(payload, {})
126
+ if (!item) continue
127
+ others.push(...expandOccurrences(item, fetchWindow))
128
+ }
129
+ const conflictItems = findEditorConflictItems(
130
+ {
131
+ start,
132
+ end,
133
+ ownerUserId: draftOwnerUserId,
134
+ participants: form.participants.map((participant) => ({ userId: participant.userId, name: participant.name })),
135
+ status: form.status,
136
+ },
137
+ others,
138
+ excludeId,
139
+ { scope, currentUserId },
140
+ )
141
+ if (!active) return
142
+ if (conflictItems.length === 0) {
143
+ setConflict(null)
144
+ return
145
+ }
146
+ const summary = conflictItems
147
+ .map((item) => `${formatClock(item.start)}–${formatClock(item.end)}: ${item.title || t('customers.calendar.grid.untitled', 'Untitled')}`)
148
+ .join(', ')
149
+ setConflict(summary ? t('customers.calendar.editor.conflictWarning', 'Overlaps with: {items}', { items: summary }) : null)
150
+ } catch {
151
+ if (active) setConflict(null)
152
+ }
153
+ }, 500)
154
+ return () => {
155
+ active = false
156
+ clearTimeout(timer)
157
+ controller.abort()
158
+ }
159
+ // Re-probe when schedule-relevant inputs change (time window, all-day, attendees, owner, status, scope).
160
+ }, [open, form.date, form.startTime, form.endDate, form.endTime, form.allDay, form.status, participantsKey, config.hasAllDay, config.hasEnd, excludeId, draftOwnerUserId, scope, currentUserId, t]) // eslint-disable-line react-hooks/exhaustive-deps
161
+ return conflict
162
+ }
@@ -0,0 +1,158 @@
1
+ "use client"
2
+
3
+ import * as React from 'react'
4
+ import { ChevronDown, Plus } from 'lucide-react'
5
+ import { cn } from '@open-mercato/shared/lib/utils'
6
+ import { Avatar } from '@open-mercato/ui/primitives/avatar'
7
+ import { IconButton } from '@open-mercato/ui/primitives/icon-button'
8
+ import { Input } from '@open-mercato/ui/primitives/input'
9
+ import { Switch } from '@open-mercato/ui/primitives/switch'
10
+
11
+ export const CONTROL_BORDER = 'border border-input'
12
+ export const CONTROL_TEXT = 'text-sm text-foreground placeholder:text-muted-foreground'
13
+ export const LABEL_CLASS = 'text-xs font-medium text-muted-foreground'
14
+ export const DROPDOWN_PANEL_CLASS =
15
+ 'absolute z-50 mt-1 max-h-56 w-full overflow-y-auto rounded-md border border-border bg-popover p-1 text-popover-foreground shadow-md'
16
+
17
+ export function Field({ label, children, error }: { label: string; children: React.ReactNode; error?: string | null }) {
18
+ return (
19
+ <div className="flex w-full flex-col gap-1.5">
20
+ <span className={LABEL_CLASS}>{label}</span>
21
+ {children}
22
+ {error ? <p className="text-xs text-status-error-text">{error}</p> : null}
23
+ </div>
24
+ )
25
+ }
26
+
27
+ export function UppercaseBadge({ style, className, children }: { style?: React.CSSProperties; className?: string; children: React.ReactNode }) {
28
+ return (
29
+ <span
30
+ className={cn(
31
+ 'inline-flex shrink-0 items-center justify-center rounded-full bg-muted px-2 py-0.5 text-overline font-medium uppercase text-muted-foreground',
32
+ className,
33
+ )}
34
+ style={style}
35
+ >
36
+ {children}
37
+ </span>
38
+ )
39
+ }
40
+
41
+ // Mockup tint colors are illustrative; runtime pills derive from the
42
+ // dictionary entry color using the appearanceColor hex-alpha tint technique
43
+ // (see EventBlock.softTintStyle) with a darkened text shade of the same hue.
44
+ export function categoryPillStyle(color: string | null | undefined): React.CSSProperties {
45
+ if (typeof color === 'string' && /^#[0-9a-fA-F]{6}$/.test(color)) {
46
+ return { backgroundColor: `${color}59`, color: `color-mix(in srgb, ${color} 55%, black)` }
47
+ }
48
+ if (typeof color === 'string' && color.length > 0) {
49
+ return {
50
+ backgroundColor: `color-mix(in srgb, ${color} 35%, white)`,
51
+ color: `color-mix(in srgb, ${color} 55%, black)`,
52
+ }
53
+ }
54
+ return {}
55
+ }
56
+
57
+ export function AllDayToggle({ checked, onCheckedChange, label }: { checked: boolean; onCheckedChange(next: boolean): void; label: string }) {
58
+ return (
59
+ <Switch
60
+ checked={checked}
61
+ aria-label={label}
62
+ onCheckedChange={onCheckedChange}
63
+ className="h-6 w-10"
64
+ />
65
+ )
66
+ }
67
+
68
+ function formatDisplayDate(value: string, locale: string): string {
69
+ const parsed = new Date(`${value}T00:00:00`)
70
+ if (Number.isNaN(parsed.getTime())) return value
71
+ return new Intl.DateTimeFormat(locale, { weekday: 'short', month: 'short', day: 'numeric', year: 'numeric' }).format(parsed)
72
+ }
73
+
74
+ export function DateControl({
75
+ value,
76
+ onChange,
77
+ ariaLabel,
78
+ locale,
79
+ className,
80
+ }: {
81
+ value: string
82
+ onChange(next: string): void
83
+ ariaLabel: string
84
+ locale: string
85
+ className?: string
86
+ }) {
87
+ return (
88
+ <div
89
+ className={cn(
90
+ 'relative flex h-9 w-full items-center justify-between rounded-md bg-background px-3',
91
+ CONTROL_BORDER,
92
+ className,
93
+ )}
94
+ >
95
+ <span className="truncate text-sm text-foreground">{formatDisplayDate(value, locale)}</span>
96
+ <span aria-hidden className="h-px w-2 shrink-0" />
97
+ <ChevronDown aria-hidden className="size-4 shrink-0 opacity-60" />
98
+ <Input
99
+ type="date"
100
+ value={value}
101
+ onChange={(event) => { if (event.target.value) onChange(event.target.value) }}
102
+ aria-label={ariaLabel}
103
+ className="absolute inset-0 h-full w-full cursor-pointer border-0 bg-transparent p-0 opacity-0 shadow-none hover:bg-transparent"
104
+ inputClassName="h-full cursor-pointer"
105
+ />
106
+ </div>
107
+ )
108
+ }
109
+
110
+ export function TimeControl({ value, onChange, ariaLabel }: { value: string; onChange(next: string): void; ariaLabel: string }) {
111
+ return (
112
+ <Input
113
+ type="time"
114
+ value={value}
115
+ onChange={(event) => { if (event.target.value) onChange(event.target.value) }}
116
+ aria-label={ariaLabel}
117
+ className="h-9 w-32 shrink-0"
118
+ />
119
+ )
120
+ }
121
+
122
+ export function PersonChip({
123
+ name,
124
+ badge,
125
+ compact,
126
+ onRemove,
127
+ removeLabel,
128
+ }: {
129
+ name: string
130
+ badge?: React.ReactNode
131
+ compact?: boolean
132
+ onRemove?: () => void
133
+ removeLabel?: string
134
+ }) {
135
+ return (
136
+ <span
137
+ className={cn(
138
+ 'inline-flex shrink-0 items-center gap-1.5 rounded-full bg-muted pl-1 pr-2',
139
+ compact ? 'py-0.5' : 'py-1',
140
+ )}
141
+ >
142
+ <Avatar size="xs" label={name} />
143
+ <span className="max-w-40 truncate text-xs font-medium text-foreground">{name}</span>
144
+ {badge}
145
+ {onRemove ? (
146
+ <IconButton
147
+ variant="ghost"
148
+ size="xs"
149
+ onClick={(event) => { event.stopPropagation(); onRemove() }}
150
+ aria-label={removeLabel}
151
+ className="size-5 shrink-0"
152
+ >
153
+ <Plus aria-hidden className="size-3.5 rotate-45 opacity-50" />
154
+ </IconButton>
155
+ ) : null}
156
+ </span>
157
+ )
158
+ }
@@ -0,0 +1,160 @@
1
+ import { readApiResultOrThrow } from '@open-mercato/ui/backend/utils/apiCall'
2
+ import { fetchAssignableStaffMembers } from '../../detail/assignableStaff'
3
+
4
+ export type RelatedEntityKind = 'person' | 'company'
5
+
6
+ export type RelatedEntityOption = {
7
+ id: string
8
+ kind: RelatedEntityKind
9
+ label: string
10
+ subtitle: string | null
11
+ }
12
+
13
+ export type DealOption = {
14
+ id: string
15
+ label: string
16
+ }
17
+
18
+ export type PersonOption = {
19
+ userId: string
20
+ name: string
21
+ email: string | null
22
+ isCustomer: boolean
23
+ }
24
+
25
+ function readNonEmptyString(value: unknown): string | null {
26
+ if (typeof value !== 'string') return null
27
+ const trimmed = value.trim()
28
+ return trimmed.length > 0 ? trimmed : null
29
+ }
30
+
31
+ function extractRelatedEntityOption(item: Record<string, unknown>, kind: RelatedEntityKind): RelatedEntityOption | null {
32
+ const id = typeof item.id === 'string' ? item.id : null
33
+ if (!id) return null
34
+ const displayName = readNonEmptyString(item.displayName) ?? readNonEmptyString(item.display_name)
35
+ const detail = kind === 'person'
36
+ ? readNonEmptyString(item.primaryEmail) ?? readNonEmptyString(item.primary_email)
37
+ : readNonEmptyString(item.domain)
38
+ ?? readNonEmptyString(item.websiteUrl)
39
+ ?? readNonEmptyString(item.website_url)
40
+ const label = displayName ?? detail ?? id
41
+ return { id, kind, label, subtitle: detail && detail !== label ? detail : null }
42
+ }
43
+
44
+ // Same lookup source as the deal-association pattern in DealForm
45
+ // (useDealAssociationLookups): the people/companies CRUD list APIs with
46
+ // `search` + name sorting, merged into a single related-to picker.
47
+ export async function searchRelatedEntities(
48
+ kind: RelatedEntityKind,
49
+ query: string,
50
+ signal: AbortSignal,
51
+ ): Promise<RelatedEntityOption[]> {
52
+ const params = new URLSearchParams({ page: '1', pageSize: '20', sortField: 'name', sortDir: 'asc' })
53
+ if (query.length) params.set('search', query)
54
+ const endpoint = kind === 'person'
55
+ ? `/api/customers/people?${params.toString()}`
56
+ : `/api/customers/companies?${params.toString()}`
57
+ const data = await readApiResultOrThrow<{ items?: Array<Record<string, unknown>> }>(endpoint, { signal })
58
+ const items = Array.isArray(data?.items) ? data.items : []
59
+ return items
60
+ .map((item) => (item && typeof item === 'object' ? extractRelatedEntityOption(item, kind) : null))
61
+ .filter((option): option is RelatedEntityOption => option !== null)
62
+ }
63
+
64
+ async function fetchRelatedEntityOfKind(
65
+ kind: RelatedEntityKind,
66
+ entityId: string,
67
+ signal: AbortSignal,
68
+ ): Promise<RelatedEntityOption | null> {
69
+ const params = new URLSearchParams({ page: '1', pageSize: '1', ids: entityId })
70
+ const endpoint = kind === 'person'
71
+ ? `/api/customers/people?${params.toString()}`
72
+ : `/api/customers/companies?${params.toString()}`
73
+ try {
74
+ const data = await readApiResultOrThrow<{ items?: Array<Record<string, unknown>> }>(endpoint, { signal })
75
+ const item = Array.isArray(data?.items) ? data.items[0] : null
76
+ return item && typeof item === 'object' ? extractRelatedEntityOption(item, kind) : null
77
+ } catch {
78
+ return null
79
+ }
80
+ }
81
+
82
+ export async function fetchRelatedEntityById(entityId: string, signal: AbortSignal): Promise<RelatedEntityOption | null> {
83
+ const [person, company] = await Promise.all([
84
+ fetchRelatedEntityOfKind('person', entityId, signal),
85
+ fetchRelatedEntityOfKind('company', entityId, signal),
86
+ ])
87
+ return person ?? company
88
+ }
89
+
90
+ function extractDealOption(item: Record<string, unknown>): DealOption | null {
91
+ const id = typeof item.id === 'string' ? item.id : null
92
+ if (!id) return null
93
+ const label = readNonEmptyString(item.title) ?? id
94
+ return { id, label }
95
+ }
96
+
97
+ export async function fetchDealsForEntity(
98
+ entity: { id: string; kind: RelatedEntityKind },
99
+ signal: AbortSignal,
100
+ ): Promise<DealOption[]> {
101
+ const params = new URLSearchParams({ page: '1', pageSize: '20' })
102
+ params.set(entity.kind === 'person' ? 'personId' : 'companyId', entity.id)
103
+ const data = await readApiResultOrThrow<{ items?: Array<Record<string, unknown>> }>(
104
+ `/api/customers/deals?${params.toString()}`,
105
+ { signal },
106
+ )
107
+ const items = Array.isArray(data?.items) ? data.items : []
108
+ return items
109
+ .map((item) => (item && typeof item === 'object' ? extractDealOption(item) : null))
110
+ .filter((option): option is DealOption => option !== null)
111
+ }
112
+
113
+ export async function fetchDealById(dealId: string, signal: AbortSignal): Promise<DealOption | null> {
114
+ try {
115
+ const params = new URLSearchParams({ page: '1', pageSize: '1', ids: dealId })
116
+ const data = await readApiResultOrThrow<{ items?: Array<Record<string, unknown>> }>(
117
+ `/api/customers/deals?${params.toString()}`,
118
+ { signal },
119
+ )
120
+ const item = Array.isArray(data?.items) ? data.items[0] : null
121
+ return item && typeof item === 'object' ? extractDealOption(item) : null
122
+ } catch {
123
+ return null
124
+ }
125
+ }
126
+
127
+ export async function searchPeopleOptions(
128
+ query: string,
129
+ options: { includeCustomers: boolean; signal: AbortSignal },
130
+ ): Promise<PersonOption[]> {
131
+ const [staff, customers] = await Promise.all([
132
+ fetchAssignableStaffMembers(query, { pageSize: 10, signal: options.signal }),
133
+ options.includeCustomers
134
+ ? searchRelatedEntities('person', query, options.signal)
135
+ : Promise.resolve<RelatedEntityOption[]>([]),
136
+ ])
137
+ const staffOptions: PersonOption[] = staff.map((member) => ({
138
+ userId: member.userId,
139
+ name: member.displayName,
140
+ email: member.email,
141
+ isCustomer: false,
142
+ }))
143
+ const customerOptions: PersonOption[] = customers.map((person) => ({
144
+ userId: person.id,
145
+ name: person.label,
146
+ email: person.subtitle,
147
+ isCustomer: true,
148
+ }))
149
+ return [...staffOptions, ...customerOptions]
150
+ }
151
+
152
+ export async function findStaffMemberName(userId: string, signal: AbortSignal): Promise<string | null> {
153
+ try {
154
+ const members = await fetchAssignableStaffMembers('', { pageSize: 100, signal })
155
+ const match = members.find((member) => member.userId === userId)
156
+ return match ? match.displayName : null
157
+ } catch {
158
+ return null
159
+ }
160
+ }
@@ -0,0 +1,163 @@
1
+ import { z } from 'zod'
2
+
3
+ export type CalendarView = 'day' | 'week' | 'month' | 'agenda'
4
+
5
+ export type CalendarCategory = 'meeting' | 'event' | 'task' | 'other'
6
+
7
+ export type CalendarItemStatus = 'planned' | 'done' | 'canceled'
8
+
9
+ export type CalendarPlatform = 'zoom' | 'meet' | 'slack' | 'teams'
10
+
11
+ export type CalendarLocationKind = 'url' | 'venue' | 'platform'
12
+
13
+ export type CalendarTab = 'all' | 'meetings' | 'events'
14
+
15
+ export type CalendarRangePreset = 'thisWeek' | 'next7' | 'thisMonth' | 'next30'
16
+
17
+ export type CalendarRange = { from: Date; to: Date }
18
+
19
+ const calendarParticipantSchema = z
20
+ .object({
21
+ userId: z.string(),
22
+ name: z.string().optional(),
23
+ email: z.string().optional(),
24
+ })
25
+ .passthrough()
26
+
27
+ export const calendarInteractionPayloadSchema = z
28
+ .object({
29
+ id: z.string(),
30
+ interactionType: z.string(),
31
+ title: z.string().nullable().optional(),
32
+ status: z.string(),
33
+ scheduledAt: z.string().nullable().optional(),
34
+ occurredAt: z.string().nullable().optional(),
35
+ durationMinutes: z.number().nullable().optional(),
36
+ allDay: z.boolean().nullable().optional(),
37
+ location: z.string().nullable().optional(),
38
+ participants: z.array(calendarParticipantSchema).nullable().optional(),
39
+ recurrenceRule: z.string().nullable().optional(),
40
+ recurrenceEnd: z.string().nullable().optional(),
41
+ appearanceIcon: z.string().nullable().optional(),
42
+ appearanceColor: z.string().nullable().optional(),
43
+ ownerUserId: z.string().nullable().optional(),
44
+ entityId: z.string().nullable().optional(),
45
+ dealId: z.string().nullable().optional(),
46
+ updatedAt: z.string().nullable().optional(),
47
+ })
48
+ .passthrough()
49
+
50
+ export type CalendarInteractionPayload = z.infer<typeof calendarInteractionPayloadSchema>
51
+
52
+ export type CalendarParticipant = { userId: string; name?: string; email?: string }
53
+
54
+ export interface CalendarItem {
55
+ id: string
56
+ title: string
57
+ interactionType: string
58
+ category: CalendarCategory
59
+ status: CalendarItemStatus
60
+ start: Date
61
+ end: Date
62
+ allDay: boolean
63
+ location: string | null
64
+ platform: CalendarPlatform | null
65
+ locationKind: CalendarLocationKind | null
66
+ participants: CalendarParticipant[]
67
+ ownerUserId: string | null
68
+ entityId: string | null
69
+ dealId: string | null
70
+ color: string | null
71
+ isRecurringOccurrence: boolean
72
+ updatedAt: string | null
73
+ raw: CalendarInteractionPayload
74
+ }
75
+
76
+ export interface CalendarFiltersValue {
77
+ types: string[]
78
+ status: string | null
79
+ ownerUserId: string | null
80
+ }
81
+
82
+ export interface TimeGridProps {
83
+ days: 1 | 7
84
+ anchor: Date
85
+ items: CalendarItem[]
86
+ conflictIds: Set<string>
87
+ showWeekends: boolean
88
+ showConflicts: boolean
89
+ aiSummaries: boolean
90
+ highlightItemId?: string | null
91
+ onItemClick(item: CalendarItem): void
92
+ onJoin(item: CalendarItem): void
93
+ onNavigate(deltaDays: number): void
94
+ onCreate?: () => void
95
+ onCreateRange?(start: Date, end: Date): void
96
+ }
97
+
98
+ export interface MonthGridProps {
99
+ anchor: Date
100
+ items: CalendarItem[]
101
+ onItemClick(item: CalendarItem): void
102
+ onDayOpen(date: Date): void
103
+ }
104
+
105
+ export interface AgendaListProps {
106
+ anchor: Date
107
+ horizonDays: number
108
+ items: CalendarItem[]
109
+ typeLabels?: Record<string, string>
110
+ onItemClick(item: CalendarItem): void
111
+ }
112
+
113
+ export interface UpcomingCard {
114
+ item: CalendarItem
115
+ kind: 'today' | 'conflicted' | 'cancelled' | 'future'
116
+ conflictCount: number
117
+ }
118
+
119
+ export interface UpcomingCardsProps {
120
+ cards: UpcomingCard[]
121
+ canManage?: boolean
122
+ onJoin(item: CalendarItem): void
123
+ onSeeConflict(item: CalendarItem): void
124
+ onOpen(item: CalendarItem): void
125
+ onEdit(item: CalendarItem): void
126
+ onCancel(item: CalendarItem): void
127
+ }
128
+
129
+ export interface CalendarHeaderProps {
130
+ view: CalendarView
131
+ anchor: Date
132
+ onNewEvent?: () => void
133
+ }
134
+
135
+ export interface CalendarToolbarProps {
136
+ view: CalendarView
137
+ anchor: Date
138
+ range: CalendarRange
139
+ preset: CalendarRangePreset | null
140
+ search: string
141
+ filters: CalendarFiltersValue
142
+ typeOptions: Array<{ value: string; label: string }>
143
+ ownerOptions: Array<{ value: string; label: string }>
144
+ onToday(): void
145
+ onPresetChange(preset: CalendarRangePreset): void
146
+ onAnchorChange(date: Date): void
147
+ onSearchChange(value: string): void
148
+ onFiltersChange(value: CalendarFiltersValue): void
149
+ onOpenSettings(): void
150
+ }
151
+
152
+ export interface CalendarTabsProps {
153
+ tab: CalendarTab
154
+ counts: { all: number; meetings: number; events: number }
155
+ view: CalendarView
156
+ onTabChange(tab: CalendarTab): void
157
+ onViewChange(view: CalendarView): void
158
+ }
159
+
160
+ export interface CalendarFooterProps {
161
+ timezoneLabel: string
162
+ onOpenShortcuts?: () => void
163
+ }