@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,207 @@
1
+ "use client"
2
+
3
+ import * as React from 'react'
4
+ import { Info, X } from 'lucide-react'
5
+ import { VisuallyHidden } from '@radix-ui/react-visually-hidden'
6
+ import { useT } from '@open-mercato/shared/lib/i18n/context'
7
+ import { Button } from '@open-mercato/ui/primitives/button'
8
+ import { Dialog, DialogContent, DialogTitle } from '@open-mercato/ui/primitives/dialog'
9
+ import { IconButton } from '@open-mercato/ui/primitives/icon-button'
10
+ import { Switch } from '@open-mercato/ui/primitives/switch'
11
+ import { TagInput } from '@open-mercato/ui/primitives/tag-input'
12
+ import { SimpleTooltip } from '@open-mercato/ui/primitives/tooltip'
13
+ import { useDialogKeyHandler } from '@open-mercato/ui/hooks/useDialogKeyHandler'
14
+ import {
15
+ CalendarPreferences,
16
+ ConflictScope,
17
+ MAX_ACTIVITY_TYPES,
18
+ MAX_EVENT_CATEGORIES,
19
+ } from '../../lib/calendar/preferences'
20
+ import { SegmentGroup } from './editor/SegmentGroup'
21
+
22
+ export type CalendarSettingsModalProps = {
23
+ open: boolean
24
+ preferences: CalendarPreferences
25
+ seedActivityTypes: string[]
26
+ onOpenChange(open: boolean): void
27
+ onSave(next: CalendarPreferences): void
28
+ }
29
+
30
+ type ToggleKey = 'showCrmActivities' | 'aiSummaries' | 'conflictWarnings' | 'showWeekends'
31
+
32
+ // An empty Activity Types list is an intentional floor meaning "surface all
33
+ // dictionary types" (see buildEditorCategoryOptions) rather than "surface none" —
34
+ // it keeps the editor's category picker usable. So when the stored list is empty
35
+ // the modal seeds the dictionary types for display; curating a non-empty subset
36
+ // persists and filters the editor as expected.
37
+ function buildDraft(preferences: CalendarPreferences, seedActivityTypes: string[]): CalendarPreferences {
38
+ return {
39
+ ...preferences,
40
+ eventCategories: [...preferences.eventCategories],
41
+ activityTypes:
42
+ preferences.activityTypes.length > 0
43
+ ? [...preferences.activityTypes]
44
+ : seedActivityTypes.slice(0, MAX_ACTIVITY_TYPES),
45
+ }
46
+ }
47
+
48
+ export function CalendarSettingsModal({
49
+ open,
50
+ preferences,
51
+ seedActivityTypes,
52
+ onOpenChange,
53
+ onSave,
54
+ }: CalendarSettingsModalProps) {
55
+ const t = useT()
56
+ const [draft, setDraft] = React.useState<CalendarPreferences>(() => buildDraft(preferences, seedActivityTypes))
57
+ const openRef = React.useRef(false)
58
+
59
+ React.useEffect(() => {
60
+ if (open && !openRef.current) setDraft(buildDraft(preferences, seedActivityTypes))
61
+ openRef.current = open
62
+ }, [open, preferences, seedActivityTypes])
63
+
64
+ const handleSave = React.useCallback(() => {
65
+ onSave(draft)
66
+ onOpenChange(false)
67
+ }, [draft, onOpenChange, onSave])
68
+
69
+ const handleKeyDown = useDialogKeyHandler({ onConfirm: handleSave })
70
+
71
+ const toggle = (key: ToggleKey) => (checked: boolean) => setDraft((current) => ({ ...current, [key]: checked }))
72
+
73
+ const toggleRows: Array<{ key: ToggleKey; label: string }> = [
74
+ { key: 'showCrmActivities', label: t('customers.calendar.settings.showCrmActivities', 'Show CRM activities on calendar') },
75
+ { key: 'aiSummaries', label: t('customers.calendar.settings.aiSummaries', 'AI summaries & quick actions') },
76
+ { key: 'conflictWarnings', label: t('customers.calendar.settings.conflictWarnings', 'Conflict warnings') },
77
+ { key: 'showWeekends', label: t('customers.calendar.settings.showWeekends', 'Show weekends') },
78
+ ]
79
+
80
+ const title = t('customers.calendar.settings.title', 'Customization')
81
+
82
+ return (
83
+ <Dialog open={open} onOpenChange={onOpenChange}>
84
+ <DialogContent
85
+ onKeyDown={handleKeyDown}
86
+ aria-describedby={undefined}
87
+ dismissible={false}
88
+ className="flex w-full max-w-[400px] flex-col gap-0 overflow-hidden rounded-2xl border-0 bg-card p-0 shadow-xl"
89
+ >
90
+ <VisuallyHidden>
91
+ <DialogTitle>{title}</DialogTitle>
92
+ </VisuallyHidden>
93
+ <div className="flex shrink-0 items-start gap-3.5 border-b border-border py-4 pl-5 pr-4">
94
+ <div className="flex min-w-0 flex-1 flex-col gap-1">
95
+ <p className="text-sm font-medium leading-5 text-foreground">{title}</p>
96
+ <p className="text-xs leading-4 text-muted-foreground">
97
+ {t('customers.calendar.settings.subtitle', 'Customise your calendar module.')}
98
+ </p>
99
+ </div>
100
+ <IconButton
101
+ variant="ghost"
102
+ size="sm"
103
+ onClick={() => onOpenChange(false)}
104
+ aria-label={t('customers.calendar.settings.close', 'Close')}
105
+ className="shrink-0 text-muted-foreground"
106
+ >
107
+ <X aria-hidden className="size-5" />
108
+ </IconButton>
109
+ </div>
110
+
111
+ <div className="flex flex-col gap-4 p-5">
112
+ <SettingsTagInput
113
+ label={t('customers.calendar.settings.eventCategories', 'Event Categories')}
114
+ maxLabel={t('customers.calendar.settings.max', '(max. {count})', { count: MAX_EVENT_CATEGORIES })}
115
+ hint={t(
116
+ 'customers.calendar.settings.eventCategoriesHint',
117
+ 'Your own grouping labels (e.g. Team Meeting, Sales Call). Offered when creating an event.',
118
+ )}
119
+ placeholder={t('customers.calendar.settings.addCategory', 'Add a category…')}
120
+ value={draft.eventCategories}
121
+ maxTags={MAX_EVENT_CATEGORIES}
122
+ onChange={(eventCategories) => setDraft((current) => ({ ...current, eventCategories }))}
123
+ />
124
+ <SettingsTagInput
125
+ label={t('customers.calendar.settings.activityTypes', 'Activity Types')}
126
+ maxLabel={t('customers.calendar.settings.max', '(max. {count})', { count: MAX_ACTIVITY_TYPES })}
127
+ hint={t(
128
+ 'customers.calendar.settings.activityTypesHint',
129
+ 'The activity types your calendar surfaces when creating an event. Seeded from your workspace dictionary.',
130
+ )}
131
+ placeholder={t('customers.calendar.settings.addType', 'Add a type…')}
132
+ value={draft.activityTypes}
133
+ maxTags={MAX_ACTIVITY_TYPES}
134
+ onChange={(activityTypes) => setDraft((current) => ({ ...current, activityTypes }))}
135
+ />
136
+ {toggleRows.map((row) => (
137
+ <React.Fragment key={row.key}>
138
+ <div className="flex items-center gap-2">
139
+ <Switch
140
+ checked={draft[row.key]}
141
+ onCheckedChange={toggle(row.key)}
142
+ aria-label={row.label}
143
+ />
144
+ <span className="text-sm leading-5 text-foreground">{row.label}</span>
145
+ </div>
146
+ {row.key === 'conflictWarnings' && draft.conflictWarnings ? (
147
+ <div className="flex flex-col gap-1.5 pl-11">
148
+ <span className="text-xs leading-4 text-muted-foreground">
149
+ {t(
150
+ 'customers.calendar.settings.conflictScopeHint',
151
+ 'Choose whose overlaps the calendar flags as conflicts.',
152
+ )}
153
+ </span>
154
+ <SegmentGroup<ConflictScope>
155
+ ariaLabel={t('customers.calendar.settings.conflictScope', 'Conflict scope')}
156
+ value={draft.conflictScope}
157
+ onChange={(conflictScope) => setDraft((current) => ({ ...current, conflictScope }))}
158
+ options={[
159
+ { value: 'mine', label: t('customers.calendar.settings.conflictScopeMine', 'My meetings only') },
160
+ { value: 'all', label: t('customers.calendar.settings.conflictScopeAll', 'All org meetings') },
161
+ ]}
162
+ />
163
+ </div>
164
+ ) : null}
165
+ </React.Fragment>
166
+ ))}
167
+ </div>
168
+
169
+ <div className="flex shrink-0 items-center gap-3 border-t border-border px-5 py-4">
170
+ <Button type="button" variant="outline" className="flex-1" onClick={() => onOpenChange(false)}>
171
+ {t('customers.calendar.settings.cancel', 'Cancel')}
172
+ </Button>
173
+ <Button type="button" className="flex-1" onClick={handleSave}>
174
+ {t('customers.calendar.settings.save', 'Save Changes')}
175
+ </Button>
176
+ </div>
177
+ </DialogContent>
178
+ </Dialog>
179
+ )
180
+ }
181
+
182
+ type SettingsTagInputProps = {
183
+ label: string
184
+ maxLabel: string
185
+ hint: string
186
+ placeholder: string
187
+ value: string[]
188
+ maxTags: number
189
+ onChange(value: string[]): void
190
+ }
191
+
192
+ function SettingsTagInput({ label, maxLabel, hint, placeholder, value, maxTags, onChange }: SettingsTagInputProps) {
193
+ return (
194
+ <div className="flex flex-col gap-1">
195
+ <div className="flex items-center gap-1">
196
+ <span className="text-sm font-medium leading-5 text-foreground">{label}</span>
197
+ <span className="text-sm leading-5 text-muted-foreground">{maxLabel}</span>
198
+ <SimpleTooltip content={hint}>
199
+ <span className="inline-flex text-muted-foreground" tabIndex={0} role="img" aria-label={hint}>
200
+ <Info aria-hidden className="size-4" />
201
+ </span>
202
+ </SimpleTooltip>
203
+ </div>
204
+ <TagInput value={value} onChange={onChange} placeholder={placeholder} maxTags={maxTags} aria-label={label} />
205
+ </div>
206
+ )
207
+ }
@@ -0,0 +1,63 @@
1
+ "use client"
2
+
3
+ import * as React from 'react'
4
+ import { Clock, LayoutGrid, List } from 'lucide-react'
5
+ import {
6
+ SegmentedControl,
7
+ SegmentedControlItem,
8
+ } from '@open-mercato/ui/primitives/segmented-control'
9
+ import { Tabs, TabsList, TabsTrigger } from '@open-mercato/ui/primitives/tabs'
10
+ import { useT } from '@open-mercato/shared/lib/i18n/context'
11
+ import type { CalendarTab, CalendarTabsProps, CalendarView } from './types'
12
+
13
+ function TabCount({ value }: { value: number }) {
14
+ return <span className="text-xs font-medium text-muted-foreground">({value})</span>
15
+ }
16
+
17
+ export function CalendarTabs({ tab, counts, view, onTabChange, onViewChange }: CalendarTabsProps) {
18
+ const t = useT()
19
+
20
+ return (
21
+ <Tabs
22
+ value={tab}
23
+ onValueChange={(value) => onTabChange(value as CalendarTab)}
24
+ variant="underline"
25
+ >
26
+ <div className="flex flex-wrap items-stretch justify-between gap-x-3 gap-y-2">
27
+ <div className="min-w-0 max-w-full overflow-x-auto">
28
+ <TabsList className="shrink-0">
29
+ <TabsTrigger value="all" leading={<LayoutGrid className="size-4" />}>
30
+ {t('customers.calendar.tabs.all', 'All Scheduled')}
31
+ </TabsTrigger>
32
+ <TabsTrigger value="meetings" leading={<List className="size-4" />}>
33
+ {t('customers.calendar.tabs.meetings', 'Meetings')} <TabCount value={counts.meetings} />
34
+ </TabsTrigger>
35
+ <TabsTrigger value="events" leading={<Clock className="size-4" />}>
36
+ {t('customers.calendar.tabs.events', 'Events')} <TabCount value={counts.events} />
37
+ </TabsTrigger>
38
+ </TabsList>
39
+ </div>
40
+ <div className="flex min-w-0 flex-1 items-center justify-end border-b border-input">
41
+ <SegmentedControl
42
+ value={view}
43
+ onValueChange={(value) => onViewChange(value as CalendarView)}
44
+ aria-label={t('customers.calendar.views.label', 'Calendar view')}
45
+ >
46
+ <SegmentedControlItem value="day">
47
+ {t('customers.calendar.views.day', 'Day')}
48
+ </SegmentedControlItem>
49
+ <SegmentedControlItem value="week">
50
+ {t('customers.calendar.views.week', 'Week')}
51
+ </SegmentedControlItem>
52
+ <SegmentedControlItem value="month">
53
+ {t('customers.calendar.views.month', 'Month')}
54
+ </SegmentedControlItem>
55
+ <SegmentedControlItem value="agenda">
56
+ {t('customers.calendar.views.agenda', 'Agenda')}
57
+ </SegmentedControlItem>
58
+ </SegmentedControl>
59
+ </div>
60
+ </div>
61
+ </Tabs>
62
+ )
63
+ }
@@ -0,0 +1,295 @@
1
+ "use client"
2
+
3
+ import * as React from 'react'
4
+ import { format } from 'date-fns/format'
5
+ import { CalendarRange, ListFilter, Settings } from 'lucide-react'
6
+ import { Badge } from '@open-mercato/ui/primitives/badge'
7
+ import { Button } from '@open-mercato/ui/primitives/button'
8
+ import { Calendar } from '@open-mercato/ui/primitives/calendar'
9
+ import { CheckboxField } from '@open-mercato/ui/primitives/checkbox-field'
10
+ import { IconButton } from '@open-mercato/ui/primitives/icon-button'
11
+ import { Kbd } from '@open-mercato/ui/primitives/kbd'
12
+ import { Popover, PopoverContent, PopoverTrigger } from '@open-mercato/ui/primitives/popover'
13
+ import { SearchInput } from '@open-mercato/ui/primitives/search-input'
14
+ import {
15
+ Select,
16
+ SelectContent,
17
+ SelectItem,
18
+ SelectTrigger,
19
+ SelectValue,
20
+ } from '@open-mercato/ui/primitives/select'
21
+ import { useT } from '@open-mercato/shared/lib/i18n/context'
22
+ import type {
23
+ CalendarFiltersValue,
24
+ CalendarRangePreset,
25
+ CalendarToolbarProps,
26
+ } from './types'
27
+
28
+ const RANGE_PRESETS: CalendarRangePreset[] = ['thisWeek', 'next7', 'thisMonth', 'next30']
29
+
30
+ const STATUS_OPTIONS = ['planned', 'done', 'canceled'] as const
31
+
32
+ const ALL_OPTION = 'all'
33
+
34
+ const EMPTY_FILTERS: CalendarFiltersValue = { types: [], status: null, ownerUserId: null }
35
+
36
+ function formatRangeLabel(from: Date, to: Date): string {
37
+ return `${format(from, 'MMM dd')} – ${format(to, 'MMM dd, yyyy')}`
38
+ }
39
+
40
+ export function CalendarToolbar(props: CalendarToolbarProps) {
41
+ const {
42
+ anchor,
43
+ range,
44
+ preset,
45
+ search,
46
+ filters,
47
+ typeOptions,
48
+ ownerOptions,
49
+ onToday,
50
+ onPresetChange,
51
+ onAnchorChange,
52
+ onSearchChange,
53
+ onFiltersChange,
54
+ onOpenSettings,
55
+ } = props
56
+ const t = useT()
57
+ const [rangeOpen, setRangeOpen] = React.useState(false)
58
+ const [filtersOpen, setFiltersOpen] = React.useState(false)
59
+ const [pendingFilters, setPendingFilters] = React.useState<CalendarFiltersValue>(filters)
60
+
61
+ const presetLabels: Record<CalendarRangePreset, string> = {
62
+ thisWeek: t('customers.calendar.toolbar.presets.thisWeek', 'This week'),
63
+ next7: t('customers.calendar.toolbar.presets.next7', 'Next 7 days'),
64
+ thisMonth: t('customers.calendar.toolbar.presets.thisMonth', 'This month'),
65
+ next30: t('customers.calendar.toolbar.presets.next30', 'Next 30 days'),
66
+ }
67
+
68
+ const activeFilterCount =
69
+ filters.types.length + (filters.status ? 1 : 0) + (filters.ownerUserId ? 1 : 0)
70
+
71
+ const handleFiltersOpenChange = (open: boolean) => {
72
+ if (open) setPendingFilters(filters)
73
+ setFiltersOpen(open)
74
+ }
75
+
76
+ const applyFilters = () => {
77
+ onFiltersChange(pendingFilters)
78
+ setFiltersOpen(false)
79
+ }
80
+
81
+ const clearFilters = () => {
82
+ setPendingFilters(EMPTY_FILTERS)
83
+ onFiltersChange(EMPTY_FILTERS)
84
+ setFiltersOpen(false)
85
+ }
86
+
87
+ const togglePendingType = (value: string, checked: boolean) => {
88
+ setPendingFilters((current) => ({
89
+ ...current,
90
+ types: checked
91
+ ? [...current.types, value]
92
+ : current.types.filter((entry) => entry !== value),
93
+ }))
94
+ }
95
+
96
+ return (
97
+ <div className="flex flex-wrap items-center gap-2 sm:gap-3">
98
+ <div className="flex min-w-0 flex-wrap items-center gap-2 sm:gap-3">
99
+ <Button type="button" variant="outline" onClick={onToday}>
100
+ {t('customers.calendar.toolbar.today', 'Today')}
101
+ </Button>
102
+ <div className="flex min-w-0 items-center">
103
+ <Select
104
+ value={preset ?? ''}
105
+ onValueChange={(value) => onPresetChange(value as CalendarRangePreset)}
106
+ >
107
+ <SelectTrigger
108
+ className="hidden w-auto min-w-32 rounded-r-none sm:flex"
109
+ aria-label={t('customers.calendar.toolbar.presetLabel', 'Date range preset')}
110
+ >
111
+ <SelectValue
112
+ placeholder={t('customers.calendar.toolbar.presetPlaceholder', 'Custom range')}
113
+ />
114
+ </SelectTrigger>
115
+ <SelectContent>
116
+ {RANGE_PRESETS.map((value) => (
117
+ <SelectItem key={value} value={value}>
118
+ {presetLabels[value]}
119
+ </SelectItem>
120
+ ))}
121
+ </SelectContent>
122
+ </Select>
123
+ <Popover open={rangeOpen} onOpenChange={setRangeOpen}>
124
+ <PopoverTrigger asChild>
125
+ <Button
126
+ type="button"
127
+ variant="outline"
128
+ className="min-w-0 text-muted-foreground sm:-ml-px sm:rounded-l-none"
129
+ >
130
+ <CalendarRange aria-hidden="true" />
131
+ <span className="truncate">{formatRangeLabel(range.from, range.to)}</span>
132
+ </Button>
133
+ </PopoverTrigger>
134
+ <PopoverContent align="start" className="w-auto min-w-0 p-2">
135
+ <Calendar
136
+ mode="single"
137
+ selected={anchor}
138
+ defaultMonth={anchor}
139
+ onSelect={(date) => {
140
+ if (!date) return
141
+ onAnchorChange(date)
142
+ setRangeOpen(false)
143
+ }}
144
+ />
145
+ </PopoverContent>
146
+ </Popover>
147
+ </div>
148
+ </div>
149
+ <div className="flex w-full min-w-0 items-center gap-2 sm:ml-auto sm:w-auto sm:flex-none sm:gap-3">
150
+ <div className="relative min-w-0 flex-1 sm:w-72 sm:flex-none">
151
+ <SearchInput
152
+ value={search}
153
+ onChange={onSearchChange}
154
+ placeholder={t('customers.calendar.toolbar.searchPlaceholder', 'Search…')}
155
+ aria-label={t('customers.calendar.toolbar.searchPlaceholder', 'Search…')}
156
+ data-calendar-search=""
157
+ />
158
+ {search.length === 0 ? (
159
+ <Kbd className="pointer-events-none absolute right-2 top-1/2 hidden -translate-y-1/2 sm:inline-flex">/</Kbd>
160
+ ) : null}
161
+ </div>
162
+ <Popover open={filtersOpen} onOpenChange={handleFiltersOpenChange}>
163
+ <PopoverTrigger asChild>
164
+ <Button
165
+ type="button"
166
+ variant="outline"
167
+ aria-label={t('customers.calendar.toolbar.filters.label', 'Filter')}
168
+ >
169
+ <ListFilter aria-hidden="true" />
170
+ <span className="hidden sm:inline">
171
+ {t('customers.calendar.toolbar.filters.label', 'Filter')}
172
+ </span>
173
+ {activeFilterCount > 0 ? (
174
+ <Badge variant="secondary" size="sm">
175
+ {activeFilterCount}
176
+ </Badge>
177
+ ) : null}
178
+ </Button>
179
+ </PopoverTrigger>
180
+ <PopoverContent
181
+ align="end"
182
+ className="w-72 p-3"
183
+ onKeyDown={(event) => {
184
+ if (event.key === 'Enter' && (event.metaKey || event.ctrlKey)) {
185
+ event.preventDefault()
186
+ applyFilters()
187
+ }
188
+ }}
189
+ >
190
+ <div className="flex flex-col gap-4">
191
+ {typeOptions.length > 0 ? (
192
+ <fieldset className="flex flex-col gap-2">
193
+ <legend className="pb-1 text-overline font-semibold uppercase tracking-widest text-muted-foreground">
194
+ {t('customers.calendar.toolbar.filters.types', 'Type')}
195
+ </legend>
196
+ {typeOptions.map((option) => (
197
+ <CheckboxField
198
+ key={option.value}
199
+ label={option.label}
200
+ size="sm"
201
+ checked={pendingFilters.types.includes(option.value)}
202
+ onCheckedChange={(checked) =>
203
+ togglePendingType(option.value, checked === true)
204
+ }
205
+ />
206
+ ))}
207
+ </fieldset>
208
+ ) : null}
209
+ <div className="flex flex-col gap-1.5">
210
+ <span className="text-overline font-semibold uppercase tracking-widest text-muted-foreground">
211
+ {t('customers.calendar.toolbar.filters.status', 'Status')}
212
+ </span>
213
+ <Select
214
+ value={pendingFilters.status ?? ALL_OPTION}
215
+ onValueChange={(value) =>
216
+ setPendingFilters((current) => ({
217
+ ...current,
218
+ status: value === ALL_OPTION ? null : value,
219
+ }))
220
+ }
221
+ >
222
+ <SelectTrigger
223
+ size="sm"
224
+ aria-label={t('customers.calendar.toolbar.filters.status', 'Status')}
225
+ >
226
+ <SelectValue />
227
+ </SelectTrigger>
228
+ <SelectContent>
229
+ <SelectItem value={ALL_OPTION}>
230
+ {t('customers.calendar.toolbar.filters.allStatuses', 'All statuses')}
231
+ </SelectItem>
232
+ {STATUS_OPTIONS.map((status) => (
233
+ <SelectItem key={status} value={status}>
234
+ {t(`customers.calendar.toolbar.filters.statuses.${status}`, status)}
235
+ </SelectItem>
236
+ ))}
237
+ </SelectContent>
238
+ </Select>
239
+ </div>
240
+ {ownerOptions.length > 0 ? (
241
+ <div className="flex flex-col gap-1.5">
242
+ <span className="text-overline font-semibold uppercase tracking-widest text-muted-foreground">
243
+ {t('customers.calendar.toolbar.filters.owner', 'Owner')}
244
+ </span>
245
+ <Select
246
+ value={pendingFilters.ownerUserId ?? ALL_OPTION}
247
+ onValueChange={(value) =>
248
+ setPendingFilters((current) => ({
249
+ ...current,
250
+ ownerUserId: value === ALL_OPTION ? null : value,
251
+ }))
252
+ }
253
+ >
254
+ <SelectTrigger
255
+ size="sm"
256
+ aria-label={t('customers.calendar.toolbar.filters.owner', 'Owner')}
257
+ >
258
+ <SelectValue />
259
+ </SelectTrigger>
260
+ <SelectContent>
261
+ <SelectItem value={ALL_OPTION}>
262
+ {t('customers.calendar.toolbar.filters.allOwners', 'All owners')}
263
+ </SelectItem>
264
+ {ownerOptions.map((option) => (
265
+ <SelectItem key={option.value} value={option.value}>
266
+ {option.label}
267
+ </SelectItem>
268
+ ))}
269
+ </SelectContent>
270
+ </Select>
271
+ </div>
272
+ ) : null}
273
+ <div className="flex items-center justify-end gap-2 border-t pt-3">
274
+ <Button type="button" variant="ghost" size="sm" onClick={clearFilters}>
275
+ {t('customers.calendar.toolbar.filters.clear', 'Clear')}
276
+ </Button>
277
+ <Button type="button" size="sm" onClick={applyFilters}>
278
+ {t('customers.calendar.toolbar.filters.apply', 'Apply')}
279
+ </Button>
280
+ </div>
281
+ </div>
282
+ </PopoverContent>
283
+ </Popover>
284
+ <IconButton
285
+ type="button"
286
+ variant="outline"
287
+ aria-label={t('customers.calendar.toolbar.settings', 'Calendar settings')}
288
+ onClick={onOpenSettings}
289
+ >
290
+ <Settings aria-hidden />
291
+ </IconButton>
292
+ </div>
293
+ </div>
294
+ )
295
+ }