@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,510 @@
1
+ "use client"
2
+
3
+ import * as React from 'react'
4
+ import { CalendarDays, ChevronLeft, ChevronRight } from 'lucide-react'
5
+ import { addDays } from 'date-fns/addDays'
6
+ import { isSameDay } from 'date-fns/isSameDay'
7
+ import { startOfDay } from 'date-fns/startOfDay'
8
+ import { cn } from '@open-mercato/shared/lib/utils'
9
+ import { useLocale, useT } from '@open-mercato/shared/lib/i18n/context'
10
+ import { Button } from '@open-mercato/ui/primitives/button'
11
+ import { IconButton } from '@open-mercato/ui/primitives/icon-button'
12
+ import { EmptyState } from '@open-mercato/ui/primitives/empty-state'
13
+ import { packOverlaps } from '../../lib/calendar/layout'
14
+ import { getVisibleRange } from '../../lib/calendar/range'
15
+ import {
16
+ applyWeekendVisibility,
17
+ buildDragRange,
18
+ DRAG_SNAP_MINUTES,
19
+ isWeekendDay,
20
+ offsetYToMinutes,
21
+ } from '../../lib/calendar/grid'
22
+ import { EventBlock, formatTimeRange, resolveEventTone } from './EventBlock'
23
+ import { EventPeekPopover } from './EventPeekPopover'
24
+ import type { CalendarItem, TimeGridProps } from './types'
25
+
26
+ const HOUR_HEIGHT_PX = 120
27
+ const HOURS_PER_DAY = 24
28
+ const GRID_BODY_MAX_HEIGHT_PX = 654
29
+ const INITIAL_SCROLL_HOUR = 8
30
+ const BLOCK_VERTICAL_GAP_PX = 1
31
+ const MIN_BLOCK_HEIGHT_PX = 32
32
+ const PACKED_COLUMN_GAP_PX = 2
33
+
34
+ const NON_WORKING_HATCH_BACKGROUND =
35
+ 'repeating-linear-gradient(45deg, transparent 0px, transparent 8px, var(--border) 8px, var(--border) 9px)'
36
+
37
+ type PositionedBlock = {
38
+ item: CalendarItem
39
+ top: number
40
+ height: number
41
+ insetInlineStart: string
42
+ width: string
43
+ }
44
+
45
+ type DayColumnData = {
46
+ dayStart: Date
47
+ allDayItems: CalendarItem[]
48
+ blocks: PositionedBlock[]
49
+ }
50
+
51
+ type DragState = { dayMs: number; startMin: number; endMin: number; moved: boolean }
52
+
53
+ function buildDayColumn(dayStart: Date, items: CalendarItem[]): DayColumnData {
54
+ const dayEnd = addDays(dayStart, 1)
55
+ const dayStartMs = dayStart.getTime()
56
+ const dayEndMs = dayEnd.getTime()
57
+ const allDayItems: CalendarItem[] = []
58
+ const segments: Array<{ original: CalendarItem; start: Date; end: Date }> = []
59
+
60
+ for (const item of items) {
61
+ const startMs = item.start.getTime()
62
+ const endMs = item.end.getTime()
63
+ if (startMs >= dayEndMs || endMs <= dayStartMs) continue
64
+ if (item.allDay) {
65
+ allDayItems.push(item)
66
+ continue
67
+ }
68
+ segments.push({
69
+ original: item,
70
+ start: startMs < dayStartMs ? dayStart : item.start,
71
+ end: endMs > dayEndMs ? dayEnd : item.end,
72
+ })
73
+ }
74
+
75
+ allDayItems.sort((first, second) => first.start.getTime() - second.start.getTime())
76
+
77
+ const clones = segments.map((segment) => ({ ...segment.original, start: segment.start, end: segment.end }))
78
+ const originalByClone = new Map<CalendarItem, CalendarItem>()
79
+ clones.forEach((clone, index) => originalByClone.set(clone, segments[index].original))
80
+
81
+ const blocks: PositionedBlock[] = packOverlaps(clones).map(({ item: clone, column, columns }) => {
82
+ const startMinutes = (clone.start.getTime() - dayStartMs) / 60000
83
+ const durationMinutes = (clone.end.getTime() - clone.start.getTime()) / 60000
84
+ const rawTop = (startMinutes / 60) * HOUR_HEIGHT_PX
85
+ const rawHeight = (durationMinutes / 60) * HOUR_HEIGHT_PX
86
+ const widthPct = 100 / columns
87
+ return {
88
+ item: originalByClone.get(clone) ?? clone,
89
+ top: rawTop + BLOCK_VERTICAL_GAP_PX,
90
+ height: Math.max(MIN_BLOCK_HEIGHT_PX, rawHeight - BLOCK_VERTICAL_GAP_PX * 2),
91
+ insetInlineStart: `calc(${column * widthPct}% + ${column * PACKED_COLUMN_GAP_PX}px)`,
92
+ width: `calc(${widthPct}% - ${((columns - 1) * PACKED_COLUMN_GAP_PX) / columns}px)`,
93
+ }
94
+ })
95
+
96
+ return { dayStart, allDayItems, blocks }
97
+ }
98
+
99
+ type ConflictBadgeProps = { count: number }
100
+
101
+ function ConflictBadge({ count }: ConflictBadgeProps) {
102
+ const t = useT()
103
+ const label =
104
+ count === 1
105
+ ? t('customers.calendar.grid.conflictCount', '1 conflict')
106
+ : t('customers.calendar.grid.conflictsCount', '{count} conflicts', { count })
107
+ return (
108
+ <span className="pointer-events-none absolute left-2 top-1 z-40 inline-flex items-center gap-1 rounded-full bg-status-error-bg px-2 py-0.5 text-overline font-medium uppercase tracking-wide text-status-error-text">
109
+ <span aria-hidden className="size-1.5 rounded-full bg-status-error-icon" />
110
+ {label}
111
+ </span>
112
+ )
113
+ }
114
+
115
+ type AllDayChipProps = {
116
+ item: CalendarItem
117
+ conflicted: boolean
118
+ highlighted: boolean
119
+ selected: boolean
120
+ nowMs: number
121
+ } & Omit<React.ComponentProps<typeof Button>, 'style' | 'children'>
122
+
123
+ const AllDayChip = React.forwardRef<HTMLButtonElement, AllDayChipProps>(function AllDayChip(
124
+ { item, conflicted, highlighted, selected, nowMs, className, ...buttonProps },
125
+ ref,
126
+ ) {
127
+ const t = useT()
128
+ const tone = resolveEventTone(item, nowMs)
129
+ const title = item.title || t('customers.calendar.grid.untitled', 'Untitled')
130
+ return (
131
+ <Button
132
+ ref={ref}
133
+ type="button"
134
+ variant="ghost"
135
+ aria-label={`${title}, ${t('customers.calendar.grid.allDay', 'All day')}`}
136
+ className={cn(
137
+ 'h-auto w-full min-w-0 justify-start rounded-sm px-2 py-0.5 text-start hover:bg-muted/70',
138
+ tone.surfaceClassName,
139
+ conflicted && 'ring-1 ring-status-warning-icon',
140
+ selected && 'shadow-md ring-2 ring-foreground',
141
+ highlighted && 'motion-safe:animate-pulse',
142
+ 'focus-visible:ring-2 focus-visible:ring-ring',
143
+ className,
144
+ )}
145
+ style={tone.style}
146
+ {...buttonProps}
147
+ >
148
+ <span className={cn('truncate text-xs font-medium', tone.titleClassName)}>{title}</span>
149
+ </Button>
150
+ )
151
+ })
152
+
153
+ AllDayChip.displayName = 'AllDayChip'
154
+
155
+ export function TimeGrid({
156
+ days,
157
+ anchor,
158
+ items,
159
+ conflictIds,
160
+ showWeekends,
161
+ showConflicts,
162
+ aiSummaries,
163
+ highlightItemId,
164
+ onItemClick,
165
+ onJoin,
166
+ onNavigate,
167
+ onCreate,
168
+ onCreateRange,
169
+ }: TimeGridProps) {
170
+ const t = useT()
171
+ const locale = useLocale()
172
+ const scrollRef = React.useRef<HTMLDivElement | null>(null)
173
+ const nowMs = Date.now()
174
+ const today = startOfDay(new Date())
175
+ const anchorMs = anchor.getTime()
176
+ const [selectedId, setSelectedId] = React.useState<string | null>(null)
177
+ const [drag, setDrag] = React.useState<DragState | null>(null)
178
+
179
+ const dayStarts = React.useMemo(() => {
180
+ const rangeStart = getVisibleRange(days === 7 ? 'week' : 'day', new Date(anchorMs), 0).from
181
+ const all = Array.from({ length: days }, (_, index) => addDays(rangeStart, index))
182
+ return days === 7 ? applyWeekendVisibility(all, showWeekends) : all
183
+ }, [days, anchorMs, showWeekends])
184
+
185
+ const dayColumns = React.useMemo(
186
+ () => dayStarts.map((dayStart) => buildDayColumn(dayStart, items)),
187
+ [dayStarts, items],
188
+ )
189
+
190
+ const resolveJoinUrl = React.useCallback((location: string | null): string | null => {
191
+ const trimmed = location?.trim() ?? ''
192
+ if (!trimmed) return null
193
+ if (/^https?:\/\//i.test(trimmed)) return trimmed
194
+ if (/^www\./i.test(trimmed)) return `https://${trimmed}`
195
+ return null
196
+ }, [])
197
+
198
+ const hasAllDayLane = dayColumns.some((column) => column.allDayItems.length > 0)
199
+
200
+ const formatters = React.useMemo(
201
+ () => ({
202
+ dayNumber: new Intl.DateTimeFormat(locale, { day: '2-digit' }),
203
+ weekdayShort: new Intl.DateTimeFormat(locale, { weekday: 'short' }),
204
+ weekdayLong: new Intl.DateTimeFormat(locale, { weekday: 'long' }),
205
+ }),
206
+ [locale],
207
+ )
208
+
209
+ const hourLabels = React.useMemo(() => {
210
+ const formatter = new Intl.DateTimeFormat(locale, { hour: 'numeric' })
211
+ return Array.from({ length: HOURS_PER_DAY }, (_, hour) => formatter.format(new Date(2024, 0, 1, hour)))
212
+ }, [locale])
213
+
214
+ React.useEffect(() => {
215
+ const node = scrollRef.current
216
+ if (!node) return
217
+ node.scrollTop = INITIAL_SCROLL_HOUR * HOUR_HEIGHT_PX
218
+ }, [])
219
+
220
+ React.useEffect(() => {
221
+ if (!highlightItemId) return
222
+ const node = scrollRef.current
223
+ if (!node) return
224
+ const target = items.find((item) => item.id === highlightItemId && !item.allDay)
225
+ if (!target) return
226
+ const minutes = (target.start.getTime() - startOfDay(target.start).getTime()) / 60000
227
+ const top = (minutes / 60) * HOUR_HEIGHT_PX
228
+ const reduceMotion =
229
+ typeof window !== 'undefined' && window.matchMedia('(prefers-reduced-motion: reduce)').matches
230
+ node.scrollTo({ top: Math.max(0, top - HOUR_HEIGHT_PX), behavior: reduceMotion ? 'auto' : 'smooth' })
231
+ }, [highlightItemId, items])
232
+
233
+ const nonWorkingLabel = t('customers.calendar.grid.nonWorking', 'Non-working day')
234
+ const previousLabel =
235
+ days === 7
236
+ ? t('customers.calendar.previousWeek', 'Previous week')
237
+ : t('customers.calendar.grid.previousDay', 'Previous day')
238
+ const nextLabel =
239
+ days === 7 ? t('customers.calendar.nextWeek', 'Next week') : t('customers.calendar.grid.nextDay', 'Next day')
240
+
241
+ const headerLabelFor = (dayStart: Date): string => {
242
+ const dayNumber = formatters.dayNumber.format(dayStart)
243
+ if (days === 1) return `${formatters.weekdayLong.format(dayStart).toUpperCase()} · ${dayNumber}`
244
+ return `${dayNumber} ${formatters.weekdayShort.format(dayStart).toUpperCase()}`
245
+ }
246
+
247
+ const canCreateRange = Boolean(onCreateRange)
248
+
249
+ const beginDrag = (event: React.PointerEvent<HTMLDivElement>, dayStart: Date) => {
250
+ if (!canCreateRange || event.button !== 0) return
251
+ const layer = event.currentTarget
252
+ const rect = layer.getBoundingClientRect()
253
+ const minute = offsetYToMinutes(event.clientY - rect.top, HOUR_HEIGHT_PX)
254
+ try {
255
+ layer.setPointerCapture(event.pointerId)
256
+ } catch {
257
+ // Pointer capture is best-effort; ignore environments that reject it.
258
+ }
259
+ setSelectedId(null)
260
+ setDrag({ dayMs: dayStart.getTime(), startMin: minute, endMin: minute, moved: false })
261
+ }
262
+
263
+ const moveDrag = (event: React.PointerEvent<HTMLDivElement>) => {
264
+ // Read the layer rect synchronously: `event.currentTarget` is only valid during
265
+ // event dispatch, but the setDrag updater below runs later during re-render.
266
+ const rect = event.currentTarget.getBoundingClientRect()
267
+ const minute = offsetYToMinutes(event.clientY - rect.top, HOUR_HEIGHT_PX)
268
+ setDrag((previous) => {
269
+ if (!previous) return previous
270
+ return {
271
+ ...previous,
272
+ endMin: minute,
273
+ moved: previous.moved || Math.abs(minute - previous.startMin) >= DRAG_SNAP_MINUTES,
274
+ }
275
+ })
276
+ }
277
+
278
+ const endDrag = (dayStart: Date) => {
279
+ setDrag((previous) => {
280
+ if (previous && previous.moved && onCreateRange) {
281
+ const range = buildDragRange(dayStart, previous.startMin, previous.endMin)
282
+ onCreateRange(range.start, range.end)
283
+ }
284
+ return null
285
+ })
286
+ }
287
+
288
+ return (
289
+ <div className="relative flex flex-col overflow-hidden rounded-lg border border-border bg-card">
290
+ <div
291
+ ref={scrollRef}
292
+ className="overflow-auto overscroll-contain"
293
+ style={{ maxHeight: GRID_BODY_MAX_HEIGHT_PX }}
294
+ >
295
+ <div className="sticky top-0 z-30 min-w-full bg-card max-md:w-max">
296
+ <div className="flex border-b border-border">
297
+ <div className="sticky start-0 z-10 flex w-14 shrink-0 bg-card md:w-26">
298
+ <span className="flex flex-1 items-center justify-center border-e border-border">
299
+ <IconButton type="button" variant="ghost" size="xs" aria-label={previousLabel} onClick={() => onNavigate(-days)}>
300
+ <ChevronLeft aria-hidden />
301
+ </IconButton>
302
+ </span>
303
+ <span className="flex flex-1 items-center justify-center border-e border-border">
304
+ <IconButton type="button" variant="ghost" size="xs" aria-label={nextLabel} onClick={() => onNavigate(days)}>
305
+ <ChevronRight aria-hidden />
306
+ </IconButton>
307
+ </span>
308
+ </div>
309
+ {dayColumns.map(({ dayStart }) => {
310
+ const isToday = isSameDay(dayStart, today)
311
+ return (
312
+ <div
313
+ key={dayStart.getTime()}
314
+ className={cn(
315
+ 'flex min-w-0 flex-1 items-center justify-center border-e border-border bg-muted px-1 py-2 last:border-e-0',
316
+ days === 7 && 'min-w-[120px] max-md:max-w-[120px] md:min-w-0',
317
+ )}
318
+ >
319
+ <span
320
+ className={cn(
321
+ 'truncate text-xs uppercase tracking-wide',
322
+ isToday ? 'font-semibold text-foreground' : 'font-medium text-muted-foreground',
323
+ )}
324
+ >
325
+ {headerLabelFor(dayStart)}
326
+ </span>
327
+ </div>
328
+ )
329
+ })}
330
+ </div>
331
+ {hasAllDayLane ? (
332
+ <div className="flex border-b border-border">
333
+ <div className="sticky start-0 z-10 flex w-14 shrink-0 items-center justify-center border-e border-border bg-card py-1 md:w-26">
334
+ <span className="truncate text-overline uppercase tracking-wide text-muted-foreground">
335
+ {t('customers.calendar.grid.allDay', 'All day')}
336
+ </span>
337
+ </div>
338
+ {dayColumns.map(({ dayStart, allDayItems }) => (
339
+ <div
340
+ key={dayStart.getTime()}
341
+ className={cn(
342
+ 'min-w-0 flex-1 space-y-1 border-e border-border p-1 last:border-e-0',
343
+ days === 7 && 'min-w-[120px] max-md:max-w-[120px] md:min-w-0',
344
+ )}
345
+ >
346
+ {allDayItems.map((item) => (
347
+ <EventPeekPopover
348
+ key={item.id}
349
+ item={item}
350
+ open={selectedId === item.id}
351
+ joinUrl={resolveJoinUrl(item.location)}
352
+ aiSummaries={aiSummaries}
353
+ onOpenChange={(open) => setSelectedId(open ? item.id : null)}
354
+ onJoin={onJoin}
355
+ onEdit={onItemClick}
356
+ >
357
+ <AllDayChip
358
+ item={item}
359
+ conflicted={showConflicts && conflictIds.has(item.id)}
360
+ highlighted={highlightItemId === item.id}
361
+ selected={selectedId === item.id}
362
+ nowMs={nowMs}
363
+ />
364
+ </EventPeekPopover>
365
+ ))}
366
+ </div>
367
+ ))}
368
+ </div>
369
+ ) : null}
370
+ </div>
371
+ <div className="flex min-w-full max-md:w-max" style={{ height: HOURS_PER_DAY * HOUR_HEIGHT_PX }}>
372
+ <div className="sticky start-0 z-10 w-14 shrink-0 border-e border-border bg-card md:w-26">
373
+ <div className="relative h-full">
374
+ {hourLabels.map((label, hour) =>
375
+ hour === 0 ? null : (
376
+ <span
377
+ key={hour}
378
+ className="absolute w-full -translate-y-1/2 px-1 text-center text-xs font-medium text-muted-foreground md:px-3 md:text-sm"
379
+ style={{ top: hour * HOUR_HEIGHT_PX }}
380
+ >
381
+ {label}
382
+ </span>
383
+ ),
384
+ )}
385
+ </div>
386
+ </div>
387
+ {dayColumns.map(({ dayStart, blocks }) => {
388
+ const nonWorking = isWeekendDay(dayStart)
389
+ const conflictCount = showConflicts
390
+ ? blocks.filter((block) => conflictIds.has(block.item.id)).length
391
+ : 0
392
+ const dragActive = drag && drag.moved && drag.dayMs === dayStart.getTime()
393
+ const dragRange = dragActive ? buildDragRange(dayStart, drag.startMin, drag.endMin) : null
394
+ const dragStartMinutes = dragRange
395
+ ? (dragRange.start.getTime() - startOfDay(dragRange.start).getTime()) / 60000
396
+ : 0
397
+ const dragDurationMinutes = dragRange
398
+ ? (dragRange.end.getTime() - dragRange.start.getTime()) / 60000
399
+ : 0
400
+ return (
401
+ <div
402
+ key={dayStart.getTime()}
403
+ className={cn(
404
+ 'relative min-w-0 flex-1 border-e border-border last:border-e-0',
405
+ days === 7 && 'min-w-[120px] max-md:max-w-[120px] md:min-w-0',
406
+ )}
407
+ title={nonWorking ? nonWorkingLabel : undefined}
408
+ >
409
+ {nonWorking ? <span className="sr-only">{nonWorkingLabel}</span> : null}
410
+ <div aria-hidden className="absolute inset-0">
411
+ {Array.from({ length: HOURS_PER_DAY }, (_, hour) => (
412
+ <div key={hour} className="relative h-30 border-b border-border">
413
+ <span className="absolute inset-x-0 top-1/2 h-px bg-border/50" />
414
+ </div>
415
+ ))}
416
+ </div>
417
+ {nonWorking ? (
418
+ <div
419
+ aria-hidden
420
+ className="pointer-events-none absolute inset-0"
421
+ style={{ backgroundImage: NON_WORKING_HATCH_BACKGROUND }}
422
+ />
423
+ ) : null}
424
+ {canCreateRange ? (
425
+ <div
426
+ className="absolute inset-0 cursor-cell"
427
+ onPointerDown={(event) => beginDrag(event, dayStart)}
428
+ onPointerMove={moveDrag}
429
+ onPointerUp={() => endDrag(dayStart)}
430
+ onPointerCancel={() => setDrag(null)}
431
+ aria-hidden
432
+ />
433
+ ) : null}
434
+ {dragRange ? (
435
+ <div
436
+ aria-hidden
437
+ className="pointer-events-none absolute z-30 flex flex-col gap-0.5 overflow-hidden rounded-md border-2 border-dashed border-foreground bg-accent-indigo/10 px-2 pt-1.5"
438
+ style={{
439
+ top: (dragStartMinutes / 60) * HOUR_HEIGHT_PX,
440
+ height: Math.max(MIN_BLOCK_HEIGHT_PX, (dragDurationMinutes / 60) * HOUR_HEIGHT_PX),
441
+ insetInlineStart: 8,
442
+ insetInlineEnd: 8,
443
+ }}
444
+ >
445
+ <span className="text-overline font-semibold text-foreground">
446
+ {t('customers.calendar.actions.newEvent', 'New event')}
447
+ </span>
448
+ <span className="text-overline text-muted-foreground">
449
+ {formatTimeRange(locale, dragRange.start, dragRange.end)}
450
+ </span>
451
+ </div>
452
+ ) : null}
453
+ {conflictCount > 0 ? <ConflictBadge count={conflictCount} /> : null}
454
+ {/* Click-through container so empty space reaches the drag-to-create layer
455
+ below; each block re-enables pointer events for its own click/peek. */}
456
+ <div className="pointer-events-none absolute inset-y-0" style={{ insetInlineStart: 8, insetInlineEnd: 8 }}>
457
+ {blocks.map((block) => (
458
+ <EventPeekPopover
459
+ key={`${block.item.id}-${block.top}`}
460
+ item={block.item}
461
+ open={selectedId === block.item.id}
462
+ joinUrl={resolveJoinUrl(block.item.location)}
463
+ aiSummaries={aiSummaries}
464
+ onOpenChange={(open) => setSelectedId(open ? block.item.id : null)}
465
+ onJoin={onJoin}
466
+ onEdit={onItemClick}
467
+ >
468
+ <EventBlock
469
+ item={block.item}
470
+ top={block.top}
471
+ height={block.height}
472
+ insetInlineStart={block.insetInlineStart}
473
+ width={block.width}
474
+ conflicted={showConflicts && conflictIds.has(block.item.id)}
475
+ highlighted={highlightItemId === block.item.id}
476
+ selected={selectedId === block.item.id}
477
+ nowMs={nowMs}
478
+ />
479
+ </EventPeekPopover>
480
+ ))}
481
+ </div>
482
+ </div>
483
+ )
484
+ })}
485
+ </div>
486
+ </div>
487
+ {items.length === 0 ? (
488
+ <div className="pointer-events-none absolute inset-0 z-40 flex items-center justify-center p-6">
489
+ <EmptyState
490
+ className="pointer-events-auto bg-card/95 shadow-sm"
491
+ icon={<CalendarDays className="h-6 w-6" aria-hidden />}
492
+ title={
493
+ days === 7
494
+ ? t('customers.calendar.empty.week', 'Nothing scheduled this week')
495
+ : t('customers.calendar.empty.day', 'Nothing scheduled this day')
496
+ }
497
+ description={t('customers.calendar.empty.description', 'Plan a meeting, event or task to fill your week.')}
498
+ actions={
499
+ onCreate ? (
500
+ <Button type="button" size="sm" onClick={onCreate}>
501
+ {t('customers.calendar.actions.newEvent', 'New event')}
502
+ </Button>
503
+ ) : undefined
504
+ }
505
+ />
506
+ </div>
507
+ ) : null}
508
+ </div>
509
+ )
510
+ }