@open-mercato/core 0.6.6-develop.6094.1.28b081ea16 → 0.6.6-develop.6126.1.0b9392fdae

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,205 @@
1
+ "use client"
2
+
3
+ import * as React from 'react'
4
+ import { Globe, MapPin } from 'lucide-react'
5
+ import { cn } from '@open-mercato/shared/lib/utils'
6
+ import { useLocale, useT } from '@open-mercato/shared/lib/i18n/context'
7
+ import { Avatar, AvatarStack } from '@open-mercato/ui/primitives/avatar'
8
+ import { Button } from '@open-mercato/ui/primitives/button'
9
+ import type { CalendarItem, CalendarPlatform } from './types'
10
+
11
+ const SHOW_TIME_MIN_HEIGHT_PX = 44
12
+ const SHOW_META_MIN_HEIGHT_PX = 96
13
+ const WRAP_TITLE_MIN_HEIGHT_PX = 128
14
+ const MAX_VISIBLE_AVATARS = 3
15
+
16
+ const PLATFORM_LABELS: Record<CalendarPlatform, { key: string; fallback: string }> = {
17
+ zoom: { key: 'customers.calendar.platform.zoom', fallback: 'Zoom' },
18
+ meet: { key: 'customers.calendar.platform.meet', fallback: 'Meet' },
19
+ slack: { key: 'customers.calendar.platform.slack', fallback: 'Slack' },
20
+ teams: { key: 'customers.calendar.platform.teams', fallback: 'Teams' },
21
+ }
22
+
23
+ export type EventTone = {
24
+ surfaceClassName: string
25
+ titleClassName: string
26
+ subClassName: string
27
+ style?: React.CSSProperties
28
+ }
29
+
30
+ function softTintStyle(color: string): React.CSSProperties {
31
+ if (/^#[0-9a-fA-F]{6}$/.test(color)) return { backgroundColor: `${color}1A` }
32
+ return { backgroundColor: `color-mix(in srgb, ${color} 10%, transparent)` }
33
+ }
34
+
35
+ export function resolveEventTone(item: CalendarItem, nowMs: number): EventTone {
36
+ if (item.status === 'canceled') {
37
+ return {
38
+ surfaceClassName: 'bg-muted/60',
39
+ titleClassName: 'text-muted-foreground line-through',
40
+ subClassName: 'text-muted-foreground/70',
41
+ }
42
+ }
43
+ if (item.status === 'done' || item.end.getTime() < nowMs) {
44
+ return {
45
+ surfaceClassName: 'bg-muted',
46
+ titleClassName: 'text-muted-foreground',
47
+ subClassName: 'text-muted-foreground',
48
+ }
49
+ }
50
+ if (item.color) {
51
+ return {
52
+ surfaceClassName: '',
53
+ titleClassName: 'text-foreground',
54
+ subClassName: 'text-muted-foreground',
55
+ style: softTintStyle(item.color),
56
+ }
57
+ }
58
+ return {
59
+ surfaceClassName: 'bg-muted/60',
60
+ titleClassName: 'text-foreground',
61
+ subClassName: 'text-muted-foreground',
62
+ }
63
+ }
64
+
65
+ export function formatTimeRange(locale: string, start: Date, end: Date): string {
66
+ const formatter = new Intl.DateTimeFormat(locale, { hour: 'numeric', minute: '2-digit' })
67
+ try {
68
+ return formatter.formatRange(start, end)
69
+ } catch {
70
+ return `${formatter.format(start)} - ${formatter.format(end)}`
71
+ }
72
+ }
73
+
74
+ function participantLabel(participant: CalendarItem['participants'][number]): string {
75
+ return participant.name ?? participant.email ?? '?'
76
+ }
77
+
78
+ type LocationMetaProps = {
79
+ item: CalendarItem
80
+ subClassName: string
81
+ accentColor: string | null
82
+ }
83
+
84
+ function LocationMeta({ item, subClassName, accentColor }: LocationMetaProps) {
85
+ const t = useT()
86
+ if (!item.location || !item.locationKind) return null
87
+ const iconStyle = accentColor ? { color: accentColor } : undefined
88
+ if (item.locationKind === 'platform' && item.platform) {
89
+ const platform = PLATFORM_LABELS[item.platform]
90
+ return (
91
+ <span className={cn('truncate text-xs', subClassName)}>
92
+ {t('customers.calendar.grid.onPlatform', 'on {platform}', { platform: t(platform.key, platform.fallback) })}
93
+ </span>
94
+ )
95
+ }
96
+ if (item.locationKind === 'url') {
97
+ return (
98
+ <>
99
+ <Globe className={cn('size-4 shrink-0', !accentColor && subClassName)} style={iconStyle} aria-hidden />
100
+ <span className="truncate text-xs text-foreground">{item.location}</span>
101
+ </>
102
+ )
103
+ }
104
+ return (
105
+ <>
106
+ <MapPin className={cn('size-4 shrink-0', !accentColor && subClassName)} style={iconStyle} aria-hidden />
107
+ <span className="truncate text-xs text-foreground">
108
+ {t('customers.calendar.grid.venue', 'Venue: {name}', { name: item.location })}
109
+ </span>
110
+ </>
111
+ )
112
+ }
113
+
114
+ export type EventBlockProps = {
115
+ item: CalendarItem
116
+ top: number
117
+ height: number
118
+ insetInlineStart: string
119
+ width: string
120
+ conflicted: boolean
121
+ highlighted: boolean
122
+ selected?: boolean
123
+ nowMs: number
124
+ } & Omit<React.ComponentProps<typeof Button>, 'style' | 'children'>
125
+
126
+ export const EventBlock = React.forwardRef<HTMLButtonElement, EventBlockProps>(function EventBlock(
127
+ {
128
+ item,
129
+ top,
130
+ height,
131
+ insetInlineStart,
132
+ width,
133
+ conflicted,
134
+ highlighted,
135
+ selected,
136
+ nowMs,
137
+ className,
138
+ ...buttonProps
139
+ },
140
+ ref,
141
+ ) {
142
+ const t = useT()
143
+ const locale = useLocale()
144
+ const tone = resolveEventTone(item, nowMs)
145
+ const title = item.title || t('customers.calendar.grid.untitled', 'Untitled')
146
+ const timeRange = formatTimeRange(locale, item.start, item.end)
147
+ const showTime = height >= SHOW_TIME_MIN_HEIGHT_PX
148
+ const wrapTitle = height >= WRAP_TITLE_MIN_HEIGHT_PX
149
+ const hasMetaContent = item.participants.length > 0 || (item.location !== null && item.locationKind !== null)
150
+ const showMeta = height >= SHOW_META_MIN_HEIGHT_PX && hasMetaContent
151
+ const visibleParticipants = item.participants.slice(0, MAX_VISIBLE_AVATARS)
152
+ const overflowCount = item.participants.length - visibleParticipants.length
153
+
154
+ return (
155
+ <Button
156
+ ref={ref}
157
+ type="button"
158
+ variant="ghost"
159
+ aria-label={`${title}, ${timeRange}`}
160
+ className={cn(
161
+ 'pointer-events-auto absolute h-auto flex-col items-start justify-start gap-1 whitespace-normal overflow-hidden rounded-md px-1.5 text-start outline-none hover:bg-muted/70 sm:px-3',
162
+ height >= SHOW_TIME_MIN_HEIGHT_PX ? 'py-1 sm:py-2' : 'py-0.5 sm:py-1',
163
+ tone.surfaceClassName,
164
+ conflicted && 'ring-1 ring-status-warning-icon',
165
+ selected && 'shadow-md ring-2 ring-foreground',
166
+ highlighted && 'motion-safe:animate-pulse',
167
+ conflicted || highlighted || selected ? 'z-30' : 'z-10',
168
+ 'focus-visible:z-30 focus-visible:ring-2 focus-visible:ring-ring',
169
+ className,
170
+ )}
171
+ style={{ top, height, insetInlineStart, width, ...tone.style }}
172
+ {...buttonProps}
173
+ >
174
+ <span className={cn('w-full text-xs font-medium leading-4', wrapTitle ? 'line-clamp-2' : 'truncate', tone.titleClassName)}>
175
+ {title}
176
+ </span>
177
+ {showTime ? (
178
+ <span className={cn('w-full truncate text-overline uppercase tracking-wide', tone.subClassName)}>
179
+ {timeRange}
180
+ </span>
181
+ ) : null}
182
+ {showMeta ? (
183
+ <span className="mt-auto flex w-full min-w-0 items-center gap-1.5">
184
+ {visibleParticipants.length > 0 ? (
185
+ <>
186
+ <AvatarStack size="xs" max={MAX_VISIBLE_AVATARS} className="shrink-0 gap-px [&>*:not(:first-child)]:-ml-1">
187
+ {visibleParticipants.map((participant) => (
188
+ <Avatar key={participant.userId} size="xs" label={participantLabel(participant)} />
189
+ ))}
190
+ </AvatarStack>
191
+ {overflowCount > 0 ? (
192
+ <span className={cn('shrink-0 text-xs', tone.subClassName)}>+{overflowCount}</span>
193
+ ) : null}
194
+ </>
195
+ ) : null}
196
+ <span className="ms-auto flex min-w-0 items-center gap-1.5">
197
+ <LocationMeta item={item} subClassName={tone.subClassName} accentColor={item.color} />
198
+ </span>
199
+ </span>
200
+ ) : null}
201
+ </Button>
202
+ )
203
+ })
204
+
205
+ EventBlock.displayName = 'EventBlock'
@@ -0,0 +1,100 @@
1
+ "use client"
2
+
3
+ import * as React from 'react'
4
+ import { Sparkles } from 'lucide-react'
5
+ import { useLocale, useT } from '@open-mercato/shared/lib/i18n/context'
6
+ import { Button } from '@open-mercato/ui/primitives/button'
7
+ import { Popover, PopoverContent, PopoverTrigger } from '@open-mercato/ui/primitives/popover'
8
+ import { formatTimeRange } from './EventBlock'
9
+ import type { CalendarItem, CalendarPlatform } from './types'
10
+
11
+ const PLATFORM_FULL_LABELS: Record<CalendarPlatform, { key: string; fallback: string }> = {
12
+ zoom: { key: 'customers.calendar.platformFull.zoom', fallback: 'Zoom' },
13
+ meet: { key: 'customers.calendar.platformFull.meet', fallback: 'Google Meet' },
14
+ slack: { key: 'customers.calendar.platformFull.slack', fallback: 'Slack' },
15
+ teams: { key: 'customers.calendar.platformFull.teams', fallback: 'Microsoft Teams' },
16
+ }
17
+
18
+ export type EventPeekPopoverProps = {
19
+ item: CalendarItem
20
+ open: boolean
21
+ joinUrl: string | null
22
+ aiSummaries: boolean
23
+ onOpenChange(open: boolean): void
24
+ onJoin(item: CalendarItem): void
25
+ onEdit(item: CalendarItem): void
26
+ children: React.ReactNode
27
+ }
28
+
29
+ export function EventPeekPopover({
30
+ item,
31
+ open,
32
+ joinUrl,
33
+ aiSummaries,
34
+ onOpenChange,
35
+ onJoin,
36
+ onEdit,
37
+ children,
38
+ }: EventPeekPopoverProps) {
39
+ const t = useT()
40
+ const locale = useLocale()
41
+ const title = item.title || t('customers.calendar.grid.untitled', 'Untitled')
42
+ const dateLabel = React.useMemo(
43
+ () => new Intl.DateTimeFormat(locale, { weekday: 'short', month: 'short', day: 'numeric' }).format(item.start),
44
+ [locale, item.start],
45
+ )
46
+ const timeRange = item.allDay
47
+ ? t('customers.calendar.grid.allDay', 'All day')
48
+ : formatTimeRange(locale, item.start, item.end)
49
+
50
+ const attendeeCount = item.participants.length
51
+ const attendeesLabel =
52
+ attendeeCount === 1
53
+ ? t('customers.calendar.peek.attendee', '1 attendee')
54
+ : t('customers.calendar.peek.attendees', '{count} attendees', { count: attendeeCount })
55
+ const platformLabel =
56
+ item.locationKind === 'platform' && item.platform
57
+ ? t(PLATFORM_FULL_LABELS[item.platform].key, PLATFORM_FULL_LABELS[item.platform].fallback)
58
+ : null
59
+ const metaParts = [platformLabel, attendeeCount > 0 ? attendeesLabel : null].filter(
60
+ (part): part is string => Boolean(part),
61
+ )
62
+ const showSummary = aiSummaries && metaParts.length > 0
63
+ const showJoin = aiSummaries && Boolean(joinUrl)
64
+
65
+ return (
66
+ <Popover open={open} onOpenChange={onOpenChange}>
67
+ <PopoverTrigger asChild>{children}</PopoverTrigger>
68
+ <PopoverContent align="start" side="right" sideOffset={8} className="w-56 p-3">
69
+ <div className="flex flex-col gap-2">
70
+ <p className="text-sm font-semibold leading-5 text-foreground">{title}</p>
71
+ <p className="text-xs leading-4 text-muted-foreground">{`${dateLabel} · ${timeRange}`}</p>
72
+ {showSummary ? (
73
+ <p className="flex items-center gap-1 text-xs leading-4 text-muted-foreground">
74
+ <Sparkles aria-hidden className="size-3.5 shrink-0" />
75
+ <span className="truncate">{metaParts.join(' · ')}</span>
76
+ </p>
77
+ ) : null}
78
+ <div className="flex items-center gap-2 pt-1">
79
+ {showJoin ? (
80
+ <Button type="button" size="sm" onClick={() => onJoin(item)}>
81
+ {t('customers.calendar.peek.join', 'Join')}
82
+ </Button>
83
+ ) : null}
84
+ <Button
85
+ type="button"
86
+ size="sm"
87
+ variant="secondary"
88
+ onClick={() => {
89
+ onOpenChange(false)
90
+ onEdit(item)
91
+ }}
92
+ >
93
+ {t('customers.calendar.peek.edit', 'Edit')}
94
+ </Button>
95
+ </div>
96
+ </div>
97
+ </PopoverContent>
98
+ </Popover>
99
+ )
100
+ }
@@ -0,0 +1,236 @@
1
+ "use client"
2
+
3
+ import * as React from 'react'
4
+ import { addDays } from 'date-fns/addDays'
5
+ import { format } from 'date-fns/format'
6
+ import { isSameMonth } from 'date-fns/isSameMonth'
7
+ import { isToday } from 'date-fns/isToday'
8
+ import { CalendarDays } from 'lucide-react'
9
+ import { useT } from '@open-mercato/shared/lib/i18n/context'
10
+ import { cn } from '@open-mercato/shared/lib/utils'
11
+ import { Button } from '@open-mercato/ui/primitives/button'
12
+ import { EmptyState } from '@open-mercato/ui/primitives/empty-state'
13
+ import { getVisibleRange } from '../../lib/calendar/range'
14
+ import type { CalendarItem, MonthGridProps } from './types'
15
+
16
+ const MAX_PILLS_PER_DAY = 2
17
+ const SOFT_TINT_ALPHA = '1A'
18
+
19
+ function dayKeyOf(date: Date): string {
20
+ return format(date, 'yyyy-MM-dd')
21
+ }
22
+
23
+ function formatTime(date: Date): string {
24
+ return date.toLocaleTimeString(undefined, { hour: 'numeric', minute: '2-digit' })
25
+ }
26
+
27
+ function fullDateLabel(date: Date): string {
28
+ return date.toLocaleDateString(undefined, { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' })
29
+ }
30
+
31
+ function isWeekend(date: Date): boolean {
32
+ const weekday = date.getDay()
33
+ return weekday === 0 || weekday === 6
34
+ }
35
+
36
+ function buildWeeks(anchor: Date): Date[][] {
37
+ const range = getVisibleRange('month', anchor, 0)
38
+ const weeks: Date[][] = []
39
+ let cursor = range.from
40
+ while (cursor.getTime() <= range.to.getTime()) {
41
+ const week: Date[] = []
42
+ for (let dayIndex = 0; dayIndex < 7; dayIndex += 1) {
43
+ week.push(cursor)
44
+ cursor = addDays(cursor, 1)
45
+ }
46
+ weeks.push(week)
47
+ }
48
+ return weeks
49
+ }
50
+
51
+ function groupItemsByDay(items: CalendarItem[]): Map<string, CalendarItem[]> {
52
+ const sorted = [...items].sort((first, second) => first.start.getTime() - second.start.getTime())
53
+ const byDay = new Map<string, CalendarItem[]>()
54
+ for (const item of sorted) {
55
+ const key = dayKeyOf(item.start)
56
+ const bucket = byDay.get(key)
57
+ if (bucket) bucket.push(item)
58
+ else byDay.set(key, [item])
59
+ }
60
+ return byDay
61
+ }
62
+
63
+ function MonthPill({ item, onItemClick }: { item: CalendarItem; onItemClick: (item: CalendarItem) => void }) {
64
+ const canceled = item.status === 'canceled'
65
+ const timeLabel = item.allDay ? '' : ` · ${formatTime(item.start)} – ${formatTime(item.end)}`
66
+ const tintStyle = item.color
67
+ ? { backgroundColor: `${item.color}${SOFT_TINT_ALPHA}`, color: item.color }
68
+ : undefined
69
+ return (
70
+ <Button
71
+ type="button"
72
+ variant="ghost"
73
+ aria-label={`${item.title}${timeLabel}`}
74
+ onClick={(event) => {
75
+ event.stopPropagation()
76
+ onItemClick(item)
77
+ }}
78
+ className={cn(
79
+ 'h-4 w-full min-w-0 justify-center gap-0 rounded-full p-0 pr-2',
80
+ !item.color && 'bg-muted text-muted-foreground',
81
+ canceled && 'opacity-60',
82
+ )}
83
+ style={tintStyle}
84
+ >
85
+ <span aria-hidden="true" className="flex size-4 shrink-0 items-center justify-center">
86
+ <span
87
+ className={cn('size-1.5 rounded-full', !item.color && 'bg-muted-foreground')}
88
+ style={item.color ? { backgroundColor: item.color } : undefined}
89
+ />
90
+ </span>
91
+ <span
92
+ className={cn(
93
+ 'min-w-0 truncate text-overline font-medium uppercase tracking-wide',
94
+ canceled && 'line-through',
95
+ )}
96
+ >
97
+ {item.title}
98
+ </span>
99
+ </Button>
100
+ )
101
+ }
102
+
103
+ function MonthDayCell({
104
+ day,
105
+ anchor,
106
+ items,
107
+ onItemClick,
108
+ onDayOpen,
109
+ }: {
110
+ day: Date
111
+ anchor: Date
112
+ items: CalendarItem[]
113
+ onItemClick: (item: CalendarItem) => void
114
+ onDayOpen: (date: Date) => void
115
+ }) {
116
+ const t = useT()
117
+ const inMonth = isSameMonth(day, anchor)
118
+ const today = isToday(day)
119
+ const visibleItems = items.slice(0, MAX_PILLS_PER_DAY)
120
+ const hiddenCount = items.length - visibleItems.length
121
+ const dayLabel = fullDateLabel(day)
122
+ return (
123
+ <div
124
+ className={cn(
125
+ 'relative flex h-full min-w-0 flex-1 flex-col items-start gap-1 overflow-hidden border-r border-border p-2 text-left last:border-r-0',
126
+ isWeekend(day) ? 'bg-muted/40' : 'bg-background',
127
+ )}
128
+ >
129
+ <Button
130
+ type="button"
131
+ variant="ghost"
132
+ aria-label={dayLabel}
133
+ onClick={() => onDayOpen(day)}
134
+ className="absolute inset-0 z-0 h-full w-full rounded-none p-0 hover:bg-muted/50"
135
+ >
136
+ <span className="sr-only">{dayLabel}</span>
137
+ </Button>
138
+ {today ? (
139
+ <span className="pointer-events-none relative z-10 flex items-center justify-center rounded-full bg-primary px-1.5 py-0.5 text-xs font-semibold text-primary-foreground">
140
+ {day.getDate()}
141
+ </span>
142
+ ) : (
143
+ <span className={cn('pointer-events-none relative z-10 text-xs font-medium', inMonth ? 'text-foreground' : 'text-muted-foreground')}>
144
+ {day.getDate()}
145
+ </span>
146
+ )}
147
+ <span className="relative z-20 hidden w-full flex-col gap-1 sm:flex">
148
+ {visibleItems.map((item) => (
149
+ <MonthPill key={item.id} item={item} onItemClick={onItemClick} />
150
+ ))}
151
+ {hiddenCount > 0 ? (
152
+ <Button
153
+ type="button"
154
+ variant="ghost"
155
+ size="sm"
156
+ className="h-auto self-start p-0 text-overline font-medium text-muted-foreground hover:bg-transparent hover:underline"
157
+ onClick={(event) => {
158
+ event.stopPropagation()
159
+ onDayOpen(day)
160
+ }}
161
+ >
162
+ {t('customers.calendar.grid.more', '+{count} more', { count: hiddenCount })}
163
+ </Button>
164
+ ) : null}
165
+ </span>
166
+ {items.length > 0 ? (
167
+ <span aria-hidden="true" className="pointer-events-none relative z-10 flex w-full flex-wrap items-center gap-0.5 sm:hidden">
168
+ {items.slice(0, 4).map((item) => (
169
+ <span
170
+ key={item.id}
171
+ className={cn('size-1.5 rounded-full', !item.color && 'bg-muted-foreground')}
172
+ style={item.color ? { backgroundColor: item.color } : undefined}
173
+ />
174
+ ))}
175
+ {items.length > 4 ? (
176
+ <span className="text-overline font-medium leading-none text-muted-foreground">
177
+ +{items.length - 4}
178
+ </span>
179
+ ) : null}
180
+ </span>
181
+ ) : null}
182
+ </div>
183
+ )
184
+ }
185
+
186
+ export function MonthGrid({ anchor, items, onItemClick, onDayOpen }: MonthGridProps) {
187
+ const t = useT()
188
+ const weeks = React.useMemo(() => buildWeeks(anchor), [anchor])
189
+ const itemsByDay = React.useMemo(() => groupItemsByDay(items), [items])
190
+ return (
191
+ <div className="relative flex h-full w-full flex-col overflow-hidden border border-border bg-background">
192
+ <div className="flex h-9 w-full shrink-0 border-b border-border">
193
+ {weeks[0]?.map((day) => {
194
+ const label = day.toLocaleDateString(undefined, { weekday: 'short' }).toUpperCase()
195
+ return (
196
+ <div
197
+ key={dayKeyOf(day)}
198
+ className="flex min-w-0 flex-1 items-center justify-center border-r border-border last:border-r-0 sm:justify-start sm:pl-2.5"
199
+ >
200
+ <span className="truncate text-overline font-medium uppercase tracking-widest text-muted-foreground">
201
+ <span className="sm:hidden">{label.charAt(0)}</span>
202
+ <span className="hidden sm:inline">{label}</span>
203
+ </span>
204
+ </div>
205
+ )
206
+ })}
207
+ </div>
208
+ {weeks.map((week) => (
209
+ <div
210
+ key={dayKeyOf(week[0])}
211
+ className="flex w-full flex-1 border-b border-border last:border-b-0 min-h-14 sm:min-h-[86px]"
212
+ >
213
+ {week.map((day) => (
214
+ <MonthDayCell
215
+ key={dayKeyOf(day)}
216
+ day={day}
217
+ anchor={anchor}
218
+ items={itemsByDay.get(dayKeyOf(day)) ?? []}
219
+ onItemClick={onItemClick}
220
+ onDayOpen={onDayOpen}
221
+ />
222
+ ))}
223
+ </div>
224
+ ))}
225
+ {items.length === 0 ? (
226
+ <div className="pointer-events-none absolute inset-0 z-10 flex items-center justify-center p-6">
227
+ <EmptyState
228
+ icon={<CalendarDays className="h-6 w-6" aria-hidden="true" />}
229
+ title={t('customers.calendar.empty.month', 'Nothing scheduled this month')}
230
+ className="bg-background/90"
231
+ />
232
+ </div>
233
+ ) : null}
234
+ </div>
235
+ )
236
+ }
@@ -0,0 +1,57 @@
1
+ "use client"
2
+
3
+ import * as React from 'react'
4
+ import {
5
+ Dialog,
6
+ DialogContent,
7
+ DialogDescription,
8
+ DialogHeader,
9
+ DialogTitle,
10
+ } from '@open-mercato/ui/primitives/dialog'
11
+ import { Kbd } from '@open-mercato/ui/primitives/kbd'
12
+ import { useT } from '@open-mercato/shared/lib/i18n/context'
13
+ import { CALENDAR_SHORTCUTS } from './CalendarFooter'
14
+
15
+ export type ShortcutsDialogProps = {
16
+ open: boolean
17
+ onOpenChange(open: boolean): void
18
+ }
19
+
20
+ export function ShortcutsDialog({ open, onOpenChange }: ShortcutsDialogProps) {
21
+ const t = useT()
22
+ return (
23
+ <Dialog open={open} onOpenChange={onOpenChange}>
24
+ <DialogContent
25
+ size="sm"
26
+ onKeyDown={(event) => {
27
+ if (event.key === 'Enter' && (event.metaKey || event.ctrlKey)) {
28
+ event.preventDefault()
29
+ onOpenChange(false)
30
+ }
31
+ }}
32
+ >
33
+ <DialogHeader>
34
+ <DialogTitle>
35
+ {t('customers.calendar.shortcuts.title', 'Keyboard shortcuts')}
36
+ </DialogTitle>
37
+ <DialogDescription>
38
+ {t(
39
+ 'customers.calendar.shortcuts.description',
40
+ 'Navigate the calendar faster with these keys.',
41
+ )}
42
+ </DialogDescription>
43
+ </DialogHeader>
44
+ <ul className="flex flex-col gap-2">
45
+ {CALENDAR_SHORTCUTS.map((shortcut) => (
46
+ <li key={shortcut.key} className="flex items-center justify-between gap-3">
47
+ <span className="text-sm text-muted-foreground">
48
+ {t(shortcut.labelKey, shortcut.fallback)}
49
+ </span>
50
+ <Kbd>{shortcut.key}</Kbd>
51
+ </li>
52
+ ))}
53
+ </ul>
54
+ </DialogContent>
55
+ </Dialog>
56
+ )
57
+ }