@open-mercato/core 0.10.1-develop.7716.1.cefe7975df → 0.10.1-develop.7721.1.b5c4a00a68

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 (384) hide show
  1. package/.turbo/turbo-build.log +2 -2
  2. package/dist/generated/entities/staff_support_routing_rule/index.js +21 -0
  3. package/dist/generated/entities/staff_support_routing_rule/index.js.map +7 -0
  4. package/dist/generated/entities/staff_support_ticket/index.js +37 -0
  5. package/dist/generated/entities/staff_support_ticket/index.js.map +7 -0
  6. package/dist/generated/entities/staff_time_project/index.js +2 -0
  7. package/dist/generated/entities/staff_time_project/index.js.map +2 -2
  8. package/dist/generated/entities/staff_time_project_member/index.js +2 -0
  9. package/dist/generated/entities/staff_time_project_member/index.js.map +2 -2
  10. package/dist/generated/entities/staff_time_task/index.js +4 -0
  11. package/dist/generated/entities/staff_time_task/index.js.map +2 -2
  12. package/dist/generated/entities/staff_time_task_comment/index.js +9 -1
  13. package/dist/generated/entities/staff_time_task_comment/index.js.map +2 -2
  14. package/dist/generated/entities.ids.generated.js +2 -0
  15. package/dist/generated/entities.ids.generated.js.map +2 -2
  16. package/dist/generated/entity-fields-registry.js +38 -0
  17. package/dist/generated/entity-fields-registry.js.map +2 -2
  18. package/dist/helpers/integration/auth.js +1 -0
  19. package/dist/helpers/integration/auth.js.map +2 -2
  20. package/dist/helpers/integration/communicationChannelsFixtures.js +20 -0
  21. package/dist/helpers/integration/communicationChannelsFixtures.js.map +2 -2
  22. package/dist/modules/catalog/api/bulk-delete/route.js +12 -2
  23. package/dist/modules/catalog/api/bulk-delete/route.js.map +2 -2
  24. package/dist/modules/communication_channels/api/post/test-seed/route.js +17 -3
  25. package/dist/modules/communication_channels/api/post/test-seed/route.js.map +2 -2
  26. package/dist/modules/communication_channels/lib/test-seed.js +38 -5
  27. package/dist/modules/communication_channels/lib/test-seed.js.map +2 -2
  28. package/dist/modules/messages/commands/messages.js +2 -3
  29. package/dist/modules/messages/commands/messages.js.map +2 -2
  30. package/dist/modules/portal/frontend/[orgSlug]/portal/dashboard/page.js +2 -2
  31. package/dist/modules/portal/frontend/[orgSlug]/portal/dashboard/page.js.map +2 -2
  32. package/dist/modules/staff/api/portal/support-tickets/[id]/attachments/route.js +299 -0
  33. package/dist/modules/staff/api/portal/support-tickets/[id]/attachments/route.js.map +7 -0
  34. package/dist/modules/staff/api/portal/support-tickets/[id]/messages/route.js +91 -0
  35. package/dist/modules/staff/api/portal/support-tickets/[id]/messages/route.js.map +7 -0
  36. package/dist/modules/staff/api/portal/support-tickets/[id]/route.js +146 -0
  37. package/dist/modules/staff/api/portal/support-tickets/[id]/route.js.map +7 -0
  38. package/dist/modules/staff/api/portal/support-tickets/options/route.js +60 -0
  39. package/dist/modules/staff/api/portal/support-tickets/options/route.js.map +7 -0
  40. package/dist/modules/staff/api/portal/support-tickets/route.js +220 -0
  41. package/dist/modules/staff/api/portal/support-tickets/route.js.map +7 -0
  42. package/dist/modules/staff/api/timesheets/settings/route.js +7 -1
  43. package/dist/modules/staff/api/timesheets/settings/route.js.map +2 -2
  44. package/dist/modules/staff/api/timesheets/support-routing-rules/fallback-project/route.js +122 -0
  45. package/dist/modules/staff/api/timesheets/support-routing-rules/fallback-project/route.js.map +7 -0
  46. package/dist/modules/staff/api/timesheets/support-routing-rules/preview/route.js +180 -0
  47. package/dist/modules/staff/api/timesheets/support-routing-rules/preview/route.js.map +7 -0
  48. package/dist/modules/staff/api/timesheets/support-routing-rules/route.js +147 -0
  49. package/dist/modules/staff/api/timesheets/support-routing-rules/route.js.map +7 -0
  50. package/dist/modules/staff/api/timesheets/support-tickets/options/route.js +133 -0
  51. package/dist/modules/staff/api/timesheets/support-tickets/options/route.js.map +7 -0
  52. package/dist/modules/staff/api/timesheets/tasks/[id]/claim/route.js +33 -0
  53. package/dist/modules/staff/api/timesheets/tasks/[id]/claim/route.js.map +7 -0
  54. package/dist/modules/staff/api/timesheets/tasks/[id]/comments/route.js +25 -7
  55. package/dist/modules/staff/api/timesheets/tasks/[id]/comments/route.js.map +2 -2
  56. package/dist/modules/staff/api/timesheets/tasks/[id]/release/route.js +32 -0
  57. package/dist/modules/staff/api/timesheets/tasks/[id]/release/route.js.map +7 -0
  58. package/dist/modules/staff/api/timesheets/tasks/route.js +94 -47
  59. package/dist/modules/staff/api/timesheets/tasks/route.js.map +2 -2
  60. package/dist/modules/staff/api/timesheets/time-projects/[id]/employees/route.js +3 -0
  61. package/dist/modules/staff/api/timesheets/time-projects/[id]/employees/route.js.map +2 -2
  62. package/dist/modules/staff/api/timesheets/time-projects/route.js +3 -0
  63. package/dist/modules/staff/api/timesheets/time-projects/route.js.map +2 -2
  64. package/dist/modules/staff/backend/staff/time-tracking/projects/[id]/edit/page.js +1 -0
  65. package/dist/modules/staff/backend/staff/time-tracking/projects/[id]/edit/page.js.map +2 -2
  66. package/dist/modules/staff/backend/staff/time-tracking/projects/[id]/page.js +54 -4
  67. package/dist/modules/staff/backend/staff/time-tracking/projects/[id]/page.js.map +2 -2
  68. package/dist/modules/staff/backend/staff/time-tracking/projects/projectFormConfig.js +21 -5
  69. package/dist/modules/staff/backend/staff/time-tracking/projects/projectFormConfig.js.map +2 -2
  70. package/dist/modules/staff/backend/staff/time-tracking/settings/page.js +319 -254
  71. package/dist/modules/staff/backend/staff/time-tracking/settings/page.js.map +2 -2
  72. package/dist/modules/staff/backend/staff/time-tracking/support/page.js +363 -0
  73. package/dist/modules/staff/backend/staff/time-tracking/support/page.js.map +7 -0
  74. package/dist/modules/staff/backend/staff/time-tracking/support/page.meta.js +18 -0
  75. package/dist/modules/staff/backend/staff/time-tracking/support/page.meta.js.map +7 -0
  76. package/dist/modules/staff/cli.js +27 -0
  77. package/dist/modules/staff/cli.js.map +2 -2
  78. package/dist/modules/staff/commands/index.js +3 -0
  79. package/dist/modules/staff/commands/index.js.map +2 -2
  80. package/dist/modules/staff/commands/shared.js +10 -1
  81. package/dist/modules/staff/commands/shared.js.map +2 -2
  82. package/dist/modules/staff/commands/support-routing-rules.js +505 -0
  83. package/dist/modules/staff/commands/support-routing-rules.js.map +7 -0
  84. package/dist/modules/staff/commands/support-tickets.js +513 -0
  85. package/dist/modules/staff/commands/support-tickets.js.map +7 -0
  86. package/dist/modules/staff/commands/timesheets-projects.js +72 -14
  87. package/dist/modules/staff/commands/timesheets-projects.js.map +2 -2
  88. package/dist/modules/staff/commands/timesheets-task-assignment.js +270 -0
  89. package/dist/modules/staff/commands/timesheets-task-assignment.js.map +7 -0
  90. package/dist/modules/staff/commands/timesheets-task-comments.js +58 -12
  91. package/dist/modules/staff/commands/timesheets-task-comments.js.map +2 -2
  92. package/dist/modules/staff/commands/timesheets-tasks.js +91 -9
  93. package/dist/modules/staff/commands/timesheets-tasks.js.map +3 -3
  94. package/dist/modules/staff/data/enrichers.js +141 -0
  95. package/dist/modules/staff/data/enrichers.js.map +2 -2
  96. package/dist/modules/staff/data/entities.js +143 -2
  97. package/dist/modules/staff/data/entities.js.map +2 -2
  98. package/dist/modules/staff/data/extensions.js +8 -0
  99. package/dist/modules/staff/data/extensions.js.map +2 -2
  100. package/dist/modules/staff/data/validators.js +34 -5
  101. package/dist/modules/staff/data/validators.js.map +2 -2
  102. package/dist/modules/staff/encryption.js +6 -0
  103. package/dist/modules/staff/encryption.js.map +2 -2
  104. package/dist/modules/staff/events.js +25 -0
  105. package/dist/modules/staff/events.js.map +2 -2
  106. package/dist/modules/staff/events.payloads.js +54 -0
  107. package/dist/modules/staff/events.payloads.js.map +2 -2
  108. package/dist/modules/staff/extension-points.js +1 -0
  109. package/dist/modules/staff/extension-points.js.map +2 -2
  110. package/dist/modules/staff/frontend/[orgSlug]/portal/support/[id]/page.js +468 -0
  111. package/dist/modules/staff/frontend/[orgSlug]/portal/support/[id]/page.js.map +7 -0
  112. package/dist/modules/staff/frontend/[orgSlug]/portal/support/[id]/page.meta.js +12 -0
  113. package/dist/modules/staff/frontend/[orgSlug]/portal/support/[id]/page.meta.js.map +7 -0
  114. package/dist/modules/staff/frontend/[orgSlug]/portal/support/new/page.js +316 -0
  115. package/dist/modules/staff/frontend/[orgSlug]/portal/support/new/page.js.map +7 -0
  116. package/dist/modules/staff/frontend/[orgSlug]/portal/support/new/page.meta.js +12 -0
  117. package/dist/modules/staff/frontend/[orgSlug]/portal/support/new/page.meta.js.map +7 -0
  118. package/dist/modules/staff/frontend/[orgSlug]/portal/support/page.js +190 -0
  119. package/dist/modules/staff/frontend/[orgSlug]/portal/support/page.js.map +7 -0
  120. package/dist/modules/staff/frontend/[orgSlug]/portal/support/page.meta.js +19 -0
  121. package/dist/modules/staff/frontend/[orgSlug]/portal/support/page.meta.js.map +7 -0
  122. package/dist/modules/staff/index.js +1 -1
  123. package/dist/modules/staff/index.js.map +2 -2
  124. package/dist/modules/staff/lib/crud.js +2 -0
  125. package/dist/modules/staff/lib/crud.js.map +2 -2
  126. package/dist/modules/staff/lib/support/attachments.js +36 -0
  127. package/dist/modules/staff/lib/support/attachments.js.map +7 -0
  128. package/dist/modules/staff/lib/support/dictionaries.js +87 -0
  129. package/dist/modules/staff/lib/support/dictionaries.js.map +7 -0
  130. package/dist/modules/staff/lib/support/notifications.js +111 -0
  131. package/dist/modules/staff/lib/support/notifications.js.map +7 -0
  132. package/dist/modules/staff/lib/support/portalAttachments.js +100 -0
  133. package/dist/modules/staff/lib/support/portalAttachments.js.map +7 -0
  134. package/dist/modules/staff/lib/support/portalBroadcast.js +117 -0
  135. package/dist/modules/staff/lib/support/portalBroadcast.js.map +7 -0
  136. package/dist/modules/staff/lib/support/portalRoute.js +99 -0
  137. package/dist/modules/staff/lib/support/portalRoute.js.map +7 -0
  138. package/dist/modules/staff/lib/support/portalStatus.js +12 -0
  139. package/dist/modules/staff/lib/support/portalStatus.js.map +7 -0
  140. package/dist/modules/staff/lib/support/portalTickets.js +148 -0
  141. package/dist/modules/staff/lib/support/portalTickets.js.map +7 -0
  142. package/dist/modules/staff/lib/support/routing.js +81 -0
  143. package/dist/modules/staff/lib/support/routing.js.map +7 -0
  144. package/dist/modules/staff/lib/support/routingRuleDraft.js +25 -0
  145. package/dist/modules/staff/lib/support/routingRuleDraft.js.map +7 -0
  146. package/dist/modules/staff/lib/support/seedDefaults.js +114 -0
  147. package/dist/modules/staff/lib/support/seedDefaults.js.map +7 -0
  148. package/dist/modules/staff/lib/support/supportActivity.js +26 -0
  149. package/dist/modules/staff/lib/support/supportActivity.js.map +7 -0
  150. package/dist/modules/staff/lib/support-ui/PortalSupportNotLinked.js +23 -0
  151. package/dist/modules/staff/lib/support-ui/PortalSupportNotLinked.js.map +7 -0
  152. package/dist/modules/staff/lib/support-ui/portalAttachmentValidation.js +112 -0
  153. package/dist/modules/staff/lib/support-ui/portalAttachmentValidation.js.map +7 -0
  154. package/dist/modules/staff/lib/support-ui/portalPendingUploads.js +45 -0
  155. package/dist/modules/staff/lib/support-ui/portalPendingUploads.js.map +7 -0
  156. package/dist/modules/staff/lib/support-ui/portalSupport.js +51 -0
  157. package/dist/modules/staff/lib/support-ui/portalSupport.js.map +7 -0
  158. package/dist/modules/staff/lib/time-tracking/access.js +3 -39
  159. package/dist/modules/staff/lib/time-tracking/access.js.map +2 -2
  160. package/dist/modules/staff/lib/time-tracking/listProjectAccess.js +54 -0
  161. package/dist/modules/staff/lib/time-tracking/listProjectAccess.js.map +7 -0
  162. package/dist/modules/staff/lib/time-tracking/portalRecipients.js +92 -2
  163. package/dist/modules/staff/lib/time-tracking/portalRecipients.js.map +2 -2
  164. package/dist/modules/staff/lib/time-tracking/projectAssignment.js +112 -0
  165. package/dist/modules/staff/lib/time-tracking/projectAssignment.js.map +7 -0
  166. package/dist/modules/staff/lib/time-tracking/settingKeys.js +14 -0
  167. package/dist/modules/staff/lib/time-tracking/settingKeys.js.map +2 -2
  168. package/dist/modules/staff/lib/time-tracking/settings.js +28 -1
  169. package/dist/modules/staff/lib/time-tracking/settings.js.map +2 -2
  170. package/dist/modules/staff/lib/time-tracking/taskAssignmentRoute.js +143 -0
  171. package/dist/modules/staff/lib/time-tracking/taskAssignmentRoute.js.map +7 -0
  172. package/dist/modules/staff/lib/time-tracking/workRecipients.js +92 -0
  173. package/dist/modules/staff/lib/time-tracking/workRecipients.js.map +7 -0
  174. package/dist/modules/staff/lib/time-tracking-ui/BoardFilterChips.js +32 -3
  175. package/dist/modules/staff/lib/time-tracking-ui/BoardFilterChips.js.map +2 -2
  176. package/dist/modules/staff/lib/time-tracking-ui/KanbanBoard.js +29 -0
  177. package/dist/modules/staff/lib/time-tracking-ui/KanbanBoard.js.map +2 -2
  178. package/dist/modules/staff/lib/time-tracking-ui/KanbanCard.js +4 -0
  179. package/dist/modules/staff/lib/time-tracking-ui/KanbanCard.js.map +2 -2
  180. package/dist/modules/staff/lib/time-tracking-ui/ProjectFormSections.js +141 -1
  181. package/dist/modules/staff/lib/time-tracking-ui/ProjectFormSections.js.map +2 -2
  182. package/dist/modules/staff/lib/time-tracking-ui/SupportAttachmentsSection.js +153 -0
  183. package/dist/modules/staff/lib/time-tracking-ui/SupportAttachmentsSection.js.map +7 -0
  184. package/dist/modules/staff/lib/time-tracking-ui/SupportRequestPanel.js +67 -0
  185. package/dist/modules/staff/lib/time-tracking-ui/SupportRequestPanel.js.map +7 -0
  186. package/dist/modules/staff/lib/time-tracking-ui/TaskBoardScreen.js +3 -1
  187. package/dist/modules/staff/lib/time-tracking-ui/TaskBoardScreen.js.map +2 -2
  188. package/dist/modules/staff/lib/time-tracking-ui/TaskCommentThread.js +80 -17
  189. package/dist/modules/staff/lib/time-tracking-ui/TaskCommentThread.js.map +2 -2
  190. package/dist/modules/staff/lib/time-tracking-ui/TaskDrawer.js +230 -41
  191. package/dist/modules/staff/lib/time-tracking-ui/TaskDrawer.js.map +2 -2
  192. package/dist/modules/staff/lib/time-tracking-ui/boardDirectory.js +21 -1
  193. package/dist/modules/staff/lib/time-tracking-ui/boardDirectory.js.map +2 -2
  194. package/dist/modules/staff/lib/time-tracking-ui/boardFilters.js +16 -4
  195. package/dist/modules/staff/lib/time-tracking-ui/boardFilters.js.map +2 -2
  196. package/dist/modules/staff/lib/time-tracking-ui/kanbanBoardData.js +3 -1
  197. package/dist/modules/staff/lib/time-tracking-ui/kanbanBoardData.js.map +2 -2
  198. package/dist/modules/staff/lib/time-tracking-ui/projectDefaultAssignee.js +68 -0
  199. package/dist/modules/staff/lib/time-tracking-ui/projectDefaultAssignee.js.map +7 -0
  200. package/dist/modules/staff/lib/time-tracking-ui/settingsTabs.js +7 -0
  201. package/dist/modules/staff/lib/time-tracking-ui/settingsTabs.js.map +7 -0
  202. package/dist/modules/staff/lib/time-tracking-ui/supportTicketData.js +50 -0
  203. package/dist/modules/staff/lib/time-tracking-ui/supportTicketData.js.map +7 -0
  204. package/dist/modules/staff/lib/time-tracking-ui/taskDrawerData.js +13 -1
  205. package/dist/modules/staff/lib/time-tracking-ui/taskDrawerData.js.map +2 -2
  206. package/dist/modules/staff/lib/time-tracking-ui/timeTrackingSettingsForm.js +36 -2
  207. package/dist/modules/staff/lib/time-tracking-ui/timeTrackingSettingsForm.js.map +2 -2
  208. package/dist/modules/staff/migrations/Migration20261009180543_staff.js +42 -0
  209. package/dist/modules/staff/migrations/Migration20261009180543_staff.js.map +7 -0
  210. package/dist/modules/staff/notifications.js +92 -0
  211. package/dist/modules/staff/notifications.js.map +2 -2
  212. package/dist/modules/staff/setup.js +6 -2
  213. package/dist/modules/staff/setup.js.map +2 -2
  214. package/dist/modules/staff/subscribers/support-portal-comment-created.js +26 -0
  215. package/dist/modules/staff/subscribers/support-portal-comment-created.js.map +7 -0
  216. package/dist/modules/staff/subscribers/support-portal-comment-deleted.js +26 -0
  217. package/dist/modules/staff/subscribers/support-portal-comment-deleted.js.map +7 -0
  218. package/dist/modules/staff/subscribers/support-portal-comment-updated.js +26 -0
  219. package/dist/modules/staff/subscribers/support-portal-comment-updated.js.map +7 -0
  220. package/dist/modules/staff/subscribers/support-portal-status-column-updated.js +24 -0
  221. package/dist/modules/staff/subscribers/support-portal-status-column-updated.js.map +7 -0
  222. package/dist/modules/staff/subscribers/support-portal-task-status-changed.js +25 -0
  223. package/dist/modules/staff/subscribers/support-portal-task-status-changed.js.map +7 -0
  224. package/dist/modules/staff/subscribers/support-portal-task-updated.js +25 -0
  225. package/dist/modules/staff/subscribers/support-portal-task-updated.js.map +7 -0
  226. package/dist/modules/staff/subscribers/support-ticket-created-notification.js +25 -0
  227. package/dist/modules/staff/subscribers/support-ticket-created-notification.js.map +7 -0
  228. package/dist/modules/staff/subscribers/support-ticket-customer-replied-notification.js +25 -0
  229. package/dist/modules/staff/subscribers/support-ticket-customer-replied-notification.js.map +7 -0
  230. package/dist/modules/staff/subscribers/support-ticket-unnotified-clear.js +26 -0
  231. package/dist/modules/staff/subscribers/support-ticket-unnotified-clear.js.map +7 -0
  232. package/dist/modules/staff/subscribers/time-task-assignee-notification.js +83 -0
  233. package/dist/modules/staff/subscribers/time-task-assignee-notification.js.map +7 -0
  234. package/dist/modules/staff/widgets/injection/portal-support-tickets/widget.client.js +112 -0
  235. package/dist/modules/staff/widgets/injection/portal-support-tickets/widget.client.js.map +7 -0
  236. package/dist/modules/staff/widgets/injection/portal-support-tickets/widget.js +17 -0
  237. package/dist/modules/staff/widgets/injection/portal-support-tickets/widget.js.map +7 -0
  238. package/dist/modules/staff/widgets/injection/time-tracking-settings-support/widget.client.js +870 -0
  239. package/dist/modules/staff/widgets/injection/time-tracking-settings-support/widget.client.js.map +7 -0
  240. package/dist/modules/staff/widgets/injection/time-tracking-settings-support/widget.js +17 -0
  241. package/dist/modules/staff/widgets/injection/time-tracking-settings-support/widget.js.map +7 -0
  242. package/dist/modules/staff/widgets/injection-table.js +16 -1
  243. package/dist/modules/staff/widgets/injection-table.js.map +2 -2
  244. package/dist/modules/wms/components/backend/WmsLocationDetailPage.js +4 -18
  245. package/dist/modules/wms/components/backend/WmsLocationDetailPage.js.map +2 -2
  246. package/dist/modules/wms/components/backend/WmsLotDetailPage.js +4 -18
  247. package/dist/modules/wms/components/backend/WmsLotDetailPage.js.map +2 -2
  248. package/dist/modules/wms/components/backend/WmsSkuDetailPage.js +4 -18
  249. package/dist/modules/wms/components/backend/WmsSkuDetailPage.js.map +2 -2
  250. package/dist/modules/wms/lib/inventoryCsvExport.js +19 -0
  251. package/dist/modules/wms/lib/inventoryCsvExport.js.map +7 -0
  252. package/generated/entities/staff_support_routing_rule/index.ts +9 -0
  253. package/generated/entities/staff_support_ticket/index.ts +17 -0
  254. package/generated/entities/staff_time_project/index.ts +1 -0
  255. package/generated/entities/staff_time_project_member/index.ts +1 -0
  256. package/generated/entities/staff_time_task/index.ts +2 -0
  257. package/generated/entities/staff_time_task_comment/index.ts +4 -0
  258. package/generated/entities.ids.generated.ts +2 -0
  259. package/generated/entity-fields-registry.ts +38 -0
  260. package/package.json +8 -8
  261. package/src/helpers/integration/auth.ts +1 -1
  262. package/src/helpers/integration/communicationChannelsFixtures.ts +60 -2
  263. package/src/modules/catalog/api/bulk-delete/route.ts +12 -2
  264. package/src/modules/communication_channels/api/post/test-seed/route.ts +29 -12
  265. package/src/modules/communication_channels/lib/test-seed.ts +49 -10
  266. package/src/modules/messages/commands/messages.ts +8 -10
  267. package/src/modules/portal/frontend/[orgSlug]/portal/dashboard/page.tsx +2 -2
  268. package/src/modules/staff/AGENTS.md +22 -6
  269. package/src/modules/staff/api/portal/support-tickets/[id]/attachments/route.ts +327 -0
  270. package/src/modules/staff/api/portal/support-tickets/[id]/messages/route.ts +94 -0
  271. package/src/modules/staff/api/portal/support-tickets/[id]/route.ts +160 -0
  272. package/src/modules/staff/api/portal/support-tickets/options/route.ts +60 -0
  273. package/src/modules/staff/api/portal/support-tickets/route.ts +253 -0
  274. package/src/modules/staff/api/timesheets/settings/route.ts +7 -1
  275. package/src/modules/staff/api/timesheets/support-routing-rules/fallback-project/route.ts +131 -0
  276. package/src/modules/staff/api/timesheets/support-routing-rules/preview/route.ts +248 -0
  277. package/src/modules/staff/api/timesheets/support-routing-rules/route.ts +150 -0
  278. package/src/modules/staff/api/timesheets/support-tickets/options/route.ts +181 -0
  279. package/src/modules/staff/api/timesheets/tasks/[id]/claim/route.ts +31 -0
  280. package/src/modules/staff/api/timesheets/tasks/[id]/comments/route.ts +25 -7
  281. package/src/modules/staff/api/timesheets/tasks/[id]/release/route.ts +30 -0
  282. package/src/modules/staff/api/timesheets/tasks/route.ts +119 -67
  283. package/src/modules/staff/api/timesheets/time-projects/[id]/employees/route.ts +3 -0
  284. package/src/modules/staff/api/timesheets/time-projects/route.ts +3 -0
  285. package/src/modules/staff/backend/staff/time-tracking/projects/[id]/edit/page.tsx +1 -0
  286. package/src/modules/staff/backend/staff/time-tracking/projects/[id]/page.tsx +67 -2
  287. package/src/modules/staff/backend/staff/time-tracking/projects/projectFormConfig.ts +22 -3
  288. package/src/modules/staff/backend/staff/time-tracking/settings/page.tsx +405 -308
  289. package/src/modules/staff/backend/staff/time-tracking/support/page.meta.ts +14 -0
  290. package/src/modules/staff/backend/staff/time-tracking/support/page.tsx +428 -0
  291. package/src/modules/staff/cli.ts +28 -0
  292. package/src/modules/staff/commands/index.ts +3 -0
  293. package/src/modules/staff/commands/shared.ts +22 -1
  294. package/src/modules/staff/commands/support-routing-rules.ts +595 -0
  295. package/src/modules/staff/commands/support-tickets.ts +580 -0
  296. package/src/modules/staff/commands/timesheets-projects.ts +84 -13
  297. package/src/modules/staff/commands/timesheets-task-assignment.ts +319 -0
  298. package/src/modules/staff/commands/timesheets-task-comments.ts +70 -15
  299. package/src/modules/staff/commands/timesheets-tasks.ts +106 -15
  300. package/src/modules/staff/data/enrichers.ts +203 -0
  301. package/src/modules/staff/data/entities.ts +133 -2
  302. package/src/modules/staff/data/extensions.ts +9 -1
  303. package/src/modules/staff/data/validators.ts +36 -0
  304. package/src/modules/staff/encryption.ts +6 -0
  305. package/src/modules/staff/events.payloads.ts +87 -1
  306. package/src/modules/staff/events.ts +26 -0
  307. package/src/modules/staff/extension-points.ts +1 -0
  308. package/src/modules/staff/frontend/[orgSlug]/portal/support/[id]/page.meta.ts +10 -0
  309. package/src/modules/staff/frontend/[orgSlug]/portal/support/[id]/page.tsx +553 -0
  310. package/src/modules/staff/frontend/[orgSlug]/portal/support/new/page.meta.ts +10 -0
  311. package/src/modules/staff/frontend/[orgSlug]/portal/support/new/page.tsx +346 -0
  312. package/src/modules/staff/frontend/[orgSlug]/portal/support/page.meta.ts +17 -0
  313. package/src/modules/staff/frontend/[orgSlug]/portal/support/page.tsx +253 -0
  314. package/src/modules/staff/i18n/de.json +291 -0
  315. package/src/modules/staff/i18n/en.json +291 -0
  316. package/src/modules/staff/i18n/es.json +291 -0
  317. package/src/modules/staff/i18n/ko.json +291 -0
  318. package/src/modules/staff/i18n/pl.json +291 -0
  319. package/src/modules/staff/index.ts +1 -1
  320. package/src/modules/staff/lib/crud.ts +2 -1
  321. package/src/modules/staff/lib/support/attachments.ts +43 -0
  322. package/src/modules/staff/lib/support/dictionaries.ts +120 -0
  323. package/src/modules/staff/lib/support/notifications.ts +138 -0
  324. package/src/modules/staff/lib/support/portalAttachments.ts +140 -0
  325. package/src/modules/staff/lib/support/portalBroadcast.ts +161 -0
  326. package/src/modules/staff/lib/support/portalRoute.ts +108 -0
  327. package/src/modules/staff/lib/support/portalStatus.ts +15 -0
  328. package/src/modules/staff/lib/support/portalTickets.ts +233 -0
  329. package/src/modules/staff/lib/support/routing.ts +117 -0
  330. package/src/modules/staff/lib/support/routingRuleDraft.ts +45 -0
  331. package/src/modules/staff/lib/support/seedDefaults.ts +151 -0
  332. package/src/modules/staff/lib/support/supportActivity.ts +39 -0
  333. package/src/modules/staff/lib/support-ui/PortalSupportNotLinked.tsx +20 -0
  334. package/src/modules/staff/lib/support-ui/portalAttachmentValidation.ts +125 -0
  335. package/src/modules/staff/lib/support-ui/portalPendingUploads.ts +49 -0
  336. package/src/modules/staff/lib/support-ui/portalSupport.ts +116 -0
  337. package/src/modules/staff/lib/time-tracking/access.ts +2 -62
  338. package/src/modules/staff/lib/time-tracking/listProjectAccess.ts +78 -0
  339. package/src/modules/staff/lib/time-tracking/portalRecipients.ts +173 -5
  340. package/src/modules/staff/lib/time-tracking/projectAssignment.ts +172 -0
  341. package/src/modules/staff/lib/time-tracking/settingKeys.ts +11 -0
  342. package/src/modules/staff/lib/time-tracking/settings.ts +46 -1
  343. package/src/modules/staff/lib/time-tracking/taskAssignmentRoute.ts +165 -0
  344. package/src/modules/staff/lib/time-tracking/workRecipients.ts +183 -0
  345. package/src/modules/staff/lib/time-tracking-ui/BoardFilterChips.tsx +36 -1
  346. package/src/modules/staff/lib/time-tracking-ui/KanbanBoard.tsx +30 -0
  347. package/src/modules/staff/lib/time-tracking-ui/KanbanCard.tsx +9 -0
  348. package/src/modules/staff/lib/time-tracking-ui/ProjectFormSections.tsx +185 -6
  349. package/src/modules/staff/lib/time-tracking-ui/SupportAttachmentsSection.tsx +188 -0
  350. package/src/modules/staff/lib/time-tracking-ui/SupportRequestPanel.tsx +102 -0
  351. package/src/modules/staff/lib/time-tracking-ui/TaskBoardScreen.tsx +2 -0
  352. package/src/modules/staff/lib/time-tracking-ui/TaskCommentThread.tsx +105 -22
  353. package/src/modules/staff/lib/time-tracking-ui/TaskDrawer.tsx +278 -43
  354. package/src/modules/staff/lib/time-tracking-ui/boardDirectory.ts +21 -0
  355. package/src/modules/staff/lib/time-tracking-ui/boardFilters.ts +16 -2
  356. package/src/modules/staff/lib/time-tracking-ui/kanbanBoardData.ts +4 -0
  357. package/src/modules/staff/lib/time-tracking-ui/projectDefaultAssignee.ts +117 -0
  358. package/src/modules/staff/lib/time-tracking-ui/settingsTabs.ts +17 -0
  359. package/src/modules/staff/lib/time-tracking-ui/supportTicketData.ts +71 -0
  360. package/src/modules/staff/lib/time-tracking-ui/taskDrawerData.ts +15 -0
  361. package/src/modules/staff/lib/time-tracking-ui/timeTrackingSettingsForm.ts +48 -1
  362. package/src/modules/staff/migrations/.snapshot-open-mercato.json +714 -0
  363. package/src/modules/staff/migrations/Migration20261009180543_staff.ts +50 -0
  364. package/src/modules/staff/notifications.ts +92 -0
  365. package/src/modules/staff/setup.ts +6 -2
  366. package/src/modules/staff/subscribers/support-portal-comment-created.ts +35 -0
  367. package/src/modules/staff/subscribers/support-portal-comment-deleted.ts +35 -0
  368. package/src/modules/staff/subscribers/support-portal-comment-updated.ts +35 -0
  369. package/src/modules/staff/subscribers/support-portal-status-column-updated.ts +36 -0
  370. package/src/modules/staff/subscribers/support-portal-task-status-changed.ts +34 -0
  371. package/src/modules/staff/subscribers/support-portal-task-updated.ts +34 -0
  372. package/src/modules/staff/subscribers/support-ticket-created-notification.ts +27 -0
  373. package/src/modules/staff/subscribers/support-ticket-customer-replied-notification.ts +27 -0
  374. package/src/modules/staff/subscribers/support-ticket-unnotified-clear.ts +29 -0
  375. package/src/modules/staff/subscribers/time-task-assignee-notification.ts +102 -0
  376. package/src/modules/staff/widgets/injection/portal-support-tickets/widget.client.tsx +151 -0
  377. package/src/modules/staff/widgets/injection/portal-support-tickets/widget.ts +16 -0
  378. package/src/modules/staff/widgets/injection/time-tracking-settings-support/widget.client.tsx +1058 -0
  379. package/src/modules/staff/widgets/injection/time-tracking-settings-support/widget.ts +17 -0
  380. package/src/modules/staff/widgets/injection-table.ts +15 -0
  381. package/src/modules/wms/components/backend/WmsLocationDetailPage.tsx +4 -20
  382. package/src/modules/wms/components/backend/WmsLotDetailPage.tsx +4 -20
  383. package/src/modules/wms/components/backend/WmsSkuDetailPage.tsx +4 -19
  384. package/src/modules/wms/lib/inventoryCsvExport.ts +18 -0
@@ -1,8 +1,9 @@
1
1
  "use client";
2
- import { jsx, jsxs } from "react/jsx-runtime";
3
- import { InjectionSpot } from "@open-mercato/ui/backend/injection/InjectionSpot";
2
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
+ import { InjectionSpot, useInjectionWidgets } from "@open-mercato/ui/backend/injection/InjectionSpot";
4
4
  import { extensionPoints } from "@open-mercato/core/modules/staff/extension-points";
5
5
  import * as React from "react";
6
+ import { usePathname, useRouter, useSearchParams } from "next/navigation";
6
7
  import { AlertTriangle, History, Info, Save } from "lucide-react";
7
8
  import { Page, PageBody, PageHeader } from "@open-mercato/ui/backend/Page";
8
9
  import { Alert, AlertDescription, AlertTitle } from "@open-mercato/ui/primitives/alert";
@@ -12,6 +13,7 @@ import { Input } from "@open-mercato/ui/primitives/input";
12
13
  import { Label } from "@open-mercato/ui/primitives/label";
13
14
  import { SegmentedControl, SegmentedControlItem } from "@open-mercato/ui/primitives/segmented-control";
14
15
  import { SwitchField } from "@open-mercato/ui/primitives/switch-field";
16
+ import { Tabs, TabsContent, TabsList, TabsTrigger } from "@open-mercato/ui/primitives/tabs";
15
17
  import { Spinner } from "@open-mercato/ui/primitives/spinner";
16
18
  import { ErrorMessage, LoadingMessage } from "@open-mercato/ui/backend/detail";
17
19
  import { apiCall } from "@open-mercato/ui/backend/utils/apiCall";
@@ -31,10 +33,15 @@ import {
31
33
  draftRounding,
32
34
  formatSignedMinutes,
33
35
  isSettingsDraftDirty,
36
+ rebaseSettingsDraft,
34
37
  settingsDraftErrors,
35
38
  toSettingsDraft,
36
39
  toSettingsPayload
37
40
  } from "../../../../lib/time-tracking-ui/timeTrackingSettingsForm.js";
41
+ import {
42
+ TIME_TRACKING_SETTINGS_GENERAL_TAB,
43
+ TIME_TRACKING_SETTINGS_TAB_PARAM
44
+ } from "../../../../lib/time-tracking-ui/settingsTabs.js";
38
45
  const logger = createLogger("staff").child({ component: "time-tracking/settings" });
39
46
  const SETTINGS_API = "/api/staff/timesheets/settings";
40
47
  const IMPACT_API = "/api/staff/timesheets/settings/rounding-impact";
@@ -67,6 +74,11 @@ function TimeTrackingSettingsPage() {
67
74
  const latestLoadRef = React.useRef(0);
68
75
  const { confirm, ConfirmDialogElement } = useConfirmDialog();
69
76
  const canManage = hasFeature(payload?.grantedFeatures, MANAGE_FEATURE);
77
+ const router = useRouter();
78
+ const pathname = usePathname();
79
+ const searchParams = useSearchParams();
80
+ const activeTab = searchParams?.get(TIME_TRACKING_SETTINGS_TAB_PARAM) ?? TIME_TRACKING_SETTINGS_GENERAL_TAB;
81
+ const [savedSettings, setSavedSettings] = React.useState(null);
70
82
  const [baseline, setBaseline] = React.useState(null);
71
83
  const [draft, setDraft] = React.useState(null);
72
84
  const draftRef = React.useRef(draft);
@@ -97,6 +109,7 @@ function TimeTrackingSettingsPage() {
97
109
  return;
98
110
  }
99
111
  const next = toSettingsDraft(call.result);
112
+ setSavedSettings(call.result);
100
113
  const pending = draftRef.current;
101
114
  const previous = baselineRef.current;
102
115
  const loadedScope = loadedScopeRef.current;
@@ -171,6 +184,49 @@ function TimeTrackingSettingsPage() {
171
184
  }),
172
185
  [canManage, contributedValues, setContributedSetting]
173
186
  );
187
+ const handleTabSettingsSaved = React.useCallback(
188
+ (saved) => {
189
+ const nextBaseline = toSettingsDraft(saved);
190
+ setSavedSettings(saved);
191
+ setDraft((current) => current && baseline ? rebaseSettingsDraft(current, baseline, nextBaseline) : nextBaseline);
192
+ setBaseline(nextBaseline);
193
+ },
194
+ [baseline]
195
+ );
196
+ const tabInjectionContext = React.useMemo(
197
+ () => savedSettings ? {
198
+ moduleId: TIME_TRACKING_SETTINGS_MODULE_ID,
199
+ canManage,
200
+ settings: savedSettings,
201
+ onSettingsSaved: handleTabSettingsSaved
202
+ } : null,
203
+ [canManage, handleTabSettingsSaved, savedSettings]
204
+ );
205
+ const { widgets: tabWidgets } = useInjectionWidgets(
206
+ extensionPoints.hosts.timeTrackingSettingsTabs.spotId,
207
+ { context: tabInjectionContext, triggerOnLoad: true }
208
+ );
209
+ const injectedTabs = React.useMemo(
210
+ () => tabWidgets.filter((widget) => (widget.placement?.kind ?? "tab") === "tab").map((widget) => {
211
+ const tabId = widget.placement?.groupId ?? widget.widgetId;
212
+ const groupLabel = widget.placement?.groupLabel;
213
+ const label = groupLabel ? t(groupLabel, widget.module.metadata.title ?? tabId) : widget.module.metadata.title ?? tabId;
214
+ const priority = typeof widget.placement?.priority === "number" ? widget.placement.priority : 0;
215
+ return { tabId, label, priority, Widget: widget.module.Widget };
216
+ }).sort((left, right) => right.priority - left.priority),
217
+ [t, tabWidgets]
218
+ );
219
+ const selectedTab = injectedTabs.some((tab) => tab.tabId === activeTab) ? activeTab : TIME_TRACKING_SETTINGS_GENERAL_TAB;
220
+ const selectTab = React.useCallback(
221
+ (tabId) => {
222
+ const params = new URLSearchParams(searchParams?.toString() ?? "");
223
+ if (tabId === TIME_TRACKING_SETTINGS_GENERAL_TAB) params.delete(TIME_TRACKING_SETTINGS_TAB_PARAM);
224
+ else params.set(TIME_TRACKING_SETTINGS_TAB_PARAM, tabId);
225
+ const query = params.toString();
226
+ router.replace(query ? `${pathname}?${query}` : pathname ?? "");
227
+ },
228
+ [pathname, router, searchParams]
229
+ );
174
230
  const canSave = canManage && isDirty && fieldErrors.length === 0 && !isSaving && !isLoading;
175
231
  const handleSave = React.useCallback(async () => {
176
232
  if (!draft) return;
@@ -225,6 +281,7 @@ function TimeTrackingSettingsPage() {
225
281
  return;
226
282
  }
227
283
  const saved = toSettingsDraft(call.result);
284
+ setSavedSettings(call.result);
228
285
  setBaseline(saved);
229
286
  setDraft(saved);
230
287
  flash(t("staff.time_tracking.settings.saved", "Settings saved."), "success");
@@ -317,290 +374,298 @@ function TimeTrackingSettingsPage() {
317
374
  ) })
318
375
  ] });
319
376
  }
320
- return /* @__PURE__ */ jsxs(Page, { children: [
321
- /* @__PURE__ */ jsx(
322
- PageHeader,
323
- {
324
- title: t("staff.time_tracking.settings.title", "Module settings"),
325
- description: t(
326
- "staff.time_tracking.settings.subtitle",
327
- "Rules shared by all customers and projects"
328
- )
329
- }
330
- ),
331
- /* @__PURE__ */ jsxs(PageBody, { children: [
332
- /* @__PURE__ */ jsxs("div", { className: "grid gap-6 lg:grid-cols-[minmax(0,2fr)_minmax(0,1fr)]", children: [
333
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-6", children: [
334
- /* @__PURE__ */ jsxs(Card, { children: [
335
- /* @__PURE__ */ jsxs(CardHeader, { children: [
336
- /* @__PURE__ */ jsx(CardTitle, { children: t("staff.time_tracking.settings.rounding.title", "Time rounding") }),
337
- /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: t(
338
- "staff.time_tracking.settings.rounding.description",
339
- "Applies to all projects. The rounded value is the one cost is calculated from."
340
- ) })
341
- ] }),
342
- /* @__PURE__ */ jsxs(CardContent, { className: "flex flex-col gap-4", children: [
343
- /* @__PURE__ */ jsxs("div", { className: "grid gap-4 sm:grid-cols-2", children: [
344
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
345
- /* @__PURE__ */ jsx(Label, { children: t("staff.time_tracking.settings.rounding.unit", "Unit") }),
346
- /* @__PURE__ */ jsx(
347
- SegmentedControl,
348
- {
349
- value: String(draft.roundingUnitMinutes),
350
- onValueChange: (value) => {
351
- const parsed = Number(value);
352
- if (!ROUNDING_UNIT_OPTIONS.includes(parsed)) return;
353
- patchDraft({ roundingUnitMinutes: parsed });
354
- },
355
- disabled: !canManage,
356
- "aria-label": t("staff.time_tracking.settings.rounding.unit", "Unit"),
357
- children: ROUNDING_UNIT_OPTIONS.map((unit) => /* @__PURE__ */ jsx(SegmentedControlItem, { value: String(unit), children: unit === 0 ? t("staff.time_tracking.settings.rounding.unit.none", "None") : t("staff.time_tracking.settings.rounding.unit.minutes", "{count} min", {
358
- count: unit
359
- }) }, unit))
360
- }
361
- )
362
- ] }),
363
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
364
- /* @__PURE__ */ jsx(Label, { children: t("staff.time_tracking.settings.rounding.direction", "Direction") }),
365
- /* @__PURE__ */ jsxs(
366
- SegmentedControl,
367
- {
368
- value: draft.roundingDirection,
369
- onValueChange: (value) => {
370
- if (value !== "up" && value !== "nearest") return;
371
- patchDraft({ roundingDirection: value });
372
- },
373
- disabled: !canManage || draft.roundingUnitMinutes === 0,
374
- "aria-label": t("staff.time_tracking.settings.rounding.direction", "Direction"),
375
- children: [
376
- /* @__PURE__ */ jsx(SegmentedControlItem, { value: "up", children: t("staff.time_tracking.settings.rounding.direction.up", "Up") }),
377
- /* @__PURE__ */ jsx(SegmentedControlItem, { value: "nearest", children: t("staff.time_tracking.settings.rounding.direction.nearest", "To nearest") })
378
- ]
379
- }
380
- )
381
- ] })
382
- ] }),
383
- /* @__PURE__ */ jsxs(Alert, { status: "information", icon: /* @__PURE__ */ jsx(Info, { "aria-hidden": "true" }), children: [
384
- /* @__PURE__ */ jsx(AlertTitle, { children: t("staff.time_tracking.settings.rounding.examples.title", "Examples at the current setting") }),
385
- /* @__PURE__ */ jsx(AlertDescription, { children: /* @__PURE__ */ jsx("span", { className: "font-mono text-sm", "data-testid": "rounding-examples", children: examples.map((example) => `${example.rawLabel} \u2192 ${example.roundedLabel}`).join(" \xB7 ") }) })
377
+ const generalSettings = /* @__PURE__ */ jsxs(Fragment, { children: [
378
+ /* @__PURE__ */ jsxs("div", { className: "grid gap-6 lg:grid-cols-[minmax(0,2fr)_minmax(0,1fr)]", children: [
379
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-6", children: [
380
+ /* @__PURE__ */ jsxs(Card, { children: [
381
+ /* @__PURE__ */ jsxs(CardHeader, { children: [
382
+ /* @__PURE__ */ jsx(CardTitle, { children: t("staff.time_tracking.settings.rounding.title", "Time rounding") }),
383
+ /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: t(
384
+ "staff.time_tracking.settings.rounding.description",
385
+ "Applies to all projects. The rounded value is the one cost is calculated from."
386
+ ) })
387
+ ] }),
388
+ /* @__PURE__ */ jsxs(CardContent, { className: "flex flex-col gap-4", children: [
389
+ /* @__PURE__ */ jsxs("div", { className: "grid gap-4 sm:grid-cols-2", children: [
390
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
391
+ /* @__PURE__ */ jsx(Label, { children: t("staff.time_tracking.settings.rounding.unit", "Unit") }),
392
+ /* @__PURE__ */ jsx(
393
+ SegmentedControl,
394
+ {
395
+ value: String(draft.roundingUnitMinutes),
396
+ onValueChange: (value) => {
397
+ const parsed = Number(value);
398
+ if (!ROUNDING_UNIT_OPTIONS.includes(parsed)) return;
399
+ patchDraft({ roundingUnitMinutes: parsed });
400
+ },
401
+ disabled: !canManage,
402
+ "aria-label": t("staff.time_tracking.settings.rounding.unit", "Unit"),
403
+ children: ROUNDING_UNIT_OPTIONS.map((unit) => /* @__PURE__ */ jsx(SegmentedControlItem, { value: String(unit), children: unit === 0 ? t("staff.time_tracking.settings.rounding.unit.none", "None") : t("staff.time_tracking.settings.rounding.unit.minutes", "{count} min", {
404
+ count: unit
405
+ }) }, unit))
406
+ }
407
+ )
386
408
  ] }),
387
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2 rounded-md border border-border p-4", children: [
388
- /* @__PURE__ */ jsx("span", { className: "text-sm font-medium", children: t(
389
- "staff.time_tracking.settings.retro.title",
390
- "Apply retroactively to existing entries"
391
- ) }),
392
- /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: t(
393
- "staff.time_tracking.settings.retro.hint",
394
- "Saving changes new entries only. Recalculating existing ones is a separate, explicit action \u2014 and it never changes entries locked in closed reports."
395
- ) }),
396
- /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsxs(
397
- Button,
409
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
410
+ /* @__PURE__ */ jsx(Label, { children: t("staff.time_tracking.settings.rounding.direction", "Direction") }),
411
+ /* @__PURE__ */ jsxs(
412
+ SegmentedControl,
398
413
  {
399
- type: "button",
400
- variant: "outline",
401
- onClick: () => void handleReapply(),
402
- disabled: !canManage || isReapplying || isDirty,
403
- "data-testid": "reapply-rounding",
414
+ value: draft.roundingDirection,
415
+ onValueChange: (value) => {
416
+ if (value !== "up" && value !== "nearest") return;
417
+ patchDraft({ roundingDirection: value });
418
+ },
419
+ disabled: !canManage || draft.roundingUnitMinutes === 0,
420
+ "aria-label": t("staff.time_tracking.settings.rounding.direction", "Direction"),
404
421
  children: [
405
- isReapplying ? /* @__PURE__ */ jsx(Spinner, { className: "size-4" }) : /* @__PURE__ */ jsx(History, { className: "size-4", "aria-hidden": "true" }),
406
- t("staff.time_tracking.settings.retro.cta", "Reapply to existing entries")
422
+ /* @__PURE__ */ jsx(SegmentedControlItem, { value: "up", children: t("staff.time_tracking.settings.rounding.direction.up", "Up") }),
423
+ /* @__PURE__ */ jsx(SegmentedControlItem, { value: "nearest", children: t("staff.time_tracking.settings.rounding.direction.nearest", "To nearest") })
407
424
  ]
408
425
  }
409
- ) }),
410
- isDirty ? /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: t(
411
- "staff.time_tracking.settings.retro.saveFirst",
412
- "Save the rule first \u2014 the recalculation uses the saved rule, not the one on screen."
413
- ) }) : null
426
+ )
414
427
  ] })
415
- ] })
416
- ] }),
417
- /* @__PURE__ */ jsxs(Card, { children: [
418
- /* @__PURE__ */ jsx(CardHeader, { children: /* @__PURE__ */ jsx(CardTitle, { children: t("staff.time_tracking.settings.defaults.title", "Entry defaults") }) }),
419
- /* @__PURE__ */ jsxs(CardContent, { className: "flex flex-col gap-4", children: [
420
- /* @__PURE__ */ jsx(
421
- SwitchField,
422
- {
423
- label: t("staff.time_tracking.settings.defaults.billable", "New entries are billable"),
424
- description: t(
425
- "staff.time_tracking.settings.defaults.billableHint",
426
- "A project can override this."
427
- ),
428
- checked: draft.defaultsBillable,
429
- onCheckedChange: (value) => patchDraft({ defaultsBillable: value === true }),
430
- disabled: !canManage
431
- }
432
- ),
433
- /* @__PURE__ */ jsx(
434
- SwitchField,
435
- {
436
- label: t(
437
- "staff.time_tracking.settings.defaults.chainStart",
438
- "Start = end of the previous entry"
439
- ),
440
- description: t(
441
- "staff.time_tracking.settings.defaults.chainStartHint",
442
- "A suggestion when adding another entry on the same day."
443
- ),
444
- checked: draft.defaultsChainStartFromPreviousEnd,
445
- onCheckedChange: (value) => patchDraft({ defaultsChainStartFromPreviousEnd: value === true }),
446
- disabled: !canManage
447
- }
448
- ),
449
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
450
- /* @__PURE__ */ jsx(Label, { htmlFor: "time-tracking-daily-hours", children: t("staff.time_tracking.settings.targets.dailyHours", "Daily hours target") }),
451
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
452
- /* @__PURE__ */ jsx(
453
- Input,
454
- {
455
- id: "time-tracking-daily-hours",
456
- className: "max-w-28",
457
- inputMode: "decimal",
458
- value: draft.dailyHoursText,
459
- onChange: (event) => patchDraft({ dailyHoursText: event.target.value }),
460
- disabled: !canManage,
461
- "aria-invalid": fieldErrors.includes("dailyHours")
462
- }
463
- ),
464
- /* @__PURE__ */ jsx("span", { className: "text-sm text-muted-foreground", children: t("staff.time_tracking.settings.targets.hoursUnit", "h") })
465
- ] }),
466
- /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: t(
467
- "staff.time_tracking.settings.targets.dailyHoursHint",
468
- "Scales the load bars in the timesheet. Leave empty to turn targets off."
469
- ) }),
470
- fieldErrors.includes("dailyHours") ? /* @__PURE__ */ jsx("span", { className: "text-xs text-status-error-text", children: t(
471
- "staff.time_tracking.settings.targets.dailyHoursError",
472
- "Enter a number of hours between 0 and 24, or leave the field empty."
473
- ) }) : null
474
- ] })
475
- ] })
476
- ] }),
477
- /* @__PURE__ */ jsxs(Card, { children: [
478
- /* @__PURE__ */ jsx(CardHeader, { children: /* @__PURE__ */ jsx(CardTitle, { children: t("staff.time_tracking.settings.warnings.title", "Warnings") }) }),
479
- /* @__PURE__ */ jsxs(CardContent, { className: "flex flex-col gap-4", children: [
480
- /* @__PURE__ */ jsx(
481
- SwitchField,
482
- {
483
- label: t("staff.time_tracking.settings.warnings.overlap", "Warn about overlapping entries"),
484
- description: t("staff.time_tracking.settings.warnings.overlapHint", "A warning, not a block."),
485
- checked: draft.warningsOverlap,
486
- onCheckedChange: (value) => patchDraft({ warningsOverlap: value === true }),
487
- disabled: !canManage
488
- }
489
- ),
490
- /* @__PURE__ */ jsx(
491
- SwitchField,
428
+ ] }),
429
+ /* @__PURE__ */ jsxs(Alert, { status: "information", icon: /* @__PURE__ */ jsx(Info, { "aria-hidden": "true" }), children: [
430
+ /* @__PURE__ */ jsx(AlertTitle, { children: t("staff.time_tracking.settings.rounding.examples.title", "Examples at the current setting") }),
431
+ /* @__PURE__ */ jsx(AlertDescription, { children: /* @__PURE__ */ jsx("span", { className: "font-mono text-sm", "data-testid": "rounding-examples", children: examples.map((example) => `${example.rawLabel} \u2192 ${example.roundedLabel}`).join(" \xB7 ") }) })
432
+ ] }),
433
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2 rounded-md border border-border p-4", children: [
434
+ /* @__PURE__ */ jsx("span", { className: "text-sm font-medium", children: t(
435
+ "staff.time_tracking.settings.retro.title",
436
+ "Apply retroactively to existing entries"
437
+ ) }),
438
+ /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: t(
439
+ "staff.time_tracking.settings.retro.hint",
440
+ "Saving changes new entries only. Recalculating existing ones is a separate, explicit action \u2014 and it never changes entries locked in closed reports."
441
+ ) }),
442
+ /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsxs(
443
+ Button,
492
444
  {
493
- label: t("staff.time_tracking.settings.warnings.runningTimer", "Remind about a running timer"),
494
- description: t(
495
- "staff.time_tracking.settings.warnings.runningTimerHint",
496
- "An unobtrusive reminder when leaving the module and after 8 h of continuous running."
497
- ),
498
- checked: draft.warningsRunningTimer,
499
- onCheckedChange: (value) => patchDraft({ warningsRunningTimer: value === true }),
500
- disabled: !canManage
445
+ type: "button",
446
+ variant: "outline",
447
+ onClick: () => void handleReapply(),
448
+ disabled: !canManage || isReapplying || isDirty,
449
+ "data-testid": "reapply-rounding",
450
+ children: [
451
+ isReapplying ? /* @__PURE__ */ jsx(Spinner, { className: "size-4" }) : /* @__PURE__ */ jsx(History, { className: "size-4", "aria-hidden": "true" }),
452
+ t("staff.time_tracking.settings.retro.cta", "Reapply to existing entries")
453
+ ]
501
454
  }
502
- )
503
- ] })
504
- ] }),
505
- /* @__PURE__ */ jsxs(Card, { children: [
506
- /* @__PURE__ */ jsx(CardHeader, { children: /* @__PURE__ */ jsx(CardTitle, { children: t("staff.time_tracking.settings.access.title", "Project access") }) }),
507
- /* @__PURE__ */ jsxs(CardContent, { className: "flex flex-col gap-2", children: [
508
- /* @__PURE__ */ jsx(Label, { htmlFor: "time-tracking-grace-days", children: t(
509
- "staff.time_tracking.settings.access.graceDays",
510
- "Access grace period after an assignment ends"
511
455
  ) }),
456
+ isDirty ? /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: t(
457
+ "staff.time_tracking.settings.retro.saveFirst",
458
+ "Save the rule first \u2014 the recalculation uses the saved rule, not the one on screen."
459
+ ) }) : null
460
+ ] })
461
+ ] })
462
+ ] }),
463
+ /* @__PURE__ */ jsxs(Card, { children: [
464
+ /* @__PURE__ */ jsx(CardHeader, { children: /* @__PURE__ */ jsx(CardTitle, { children: t("staff.time_tracking.settings.defaults.title", "Entry defaults") }) }),
465
+ /* @__PURE__ */ jsxs(CardContent, { className: "flex flex-col gap-4", children: [
466
+ /* @__PURE__ */ jsx(
467
+ SwitchField,
468
+ {
469
+ label: t("staff.time_tracking.settings.defaults.billable", "New entries are billable"),
470
+ description: t(
471
+ "staff.time_tracking.settings.defaults.billableHint",
472
+ "A project can override this."
473
+ ),
474
+ checked: draft.defaultsBillable,
475
+ onCheckedChange: (value) => patchDraft({ defaultsBillable: value === true }),
476
+ disabled: !canManage
477
+ }
478
+ ),
479
+ /* @__PURE__ */ jsx(
480
+ SwitchField,
481
+ {
482
+ label: t(
483
+ "staff.time_tracking.settings.defaults.chainStart",
484
+ "Start = end of the previous entry"
485
+ ),
486
+ description: t(
487
+ "staff.time_tracking.settings.defaults.chainStartHint",
488
+ "A suggestion when adding another entry on the same day."
489
+ ),
490
+ checked: draft.defaultsChainStartFromPreviousEnd,
491
+ onCheckedChange: (value) => patchDraft({ defaultsChainStartFromPreviousEnd: value === true }),
492
+ disabled: !canManage
493
+ }
494
+ ),
495
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
496
+ /* @__PURE__ */ jsx(Label, { htmlFor: "time-tracking-daily-hours", children: t("staff.time_tracking.settings.targets.dailyHours", "Daily hours target") }),
512
497
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
513
498
  /* @__PURE__ */ jsx(
514
499
  Input,
515
500
  {
516
- id: "time-tracking-grace-days",
501
+ id: "time-tracking-daily-hours",
517
502
  className: "max-w-28",
518
- inputMode: "numeric",
519
- value: draft.assignmentGraceDaysText,
520
- onChange: (event) => patchDraft({ assignmentGraceDaysText: event.target.value }),
503
+ inputMode: "decimal",
504
+ value: draft.dailyHoursText,
505
+ onChange: (event) => patchDraft({ dailyHoursText: event.target.value }),
521
506
  disabled: !canManage,
522
- "aria-invalid": fieldErrors.includes("assignmentGraceDays")
507
+ "aria-invalid": fieldErrors.includes("dailyHours")
523
508
  }
524
509
  ),
525
- /* @__PURE__ */ jsx("span", { className: "text-sm text-muted-foreground", children: t("staff.time_tracking.settings.access.daysUnit", "days") })
510
+ /* @__PURE__ */ jsx("span", { className: "text-sm text-muted-foreground", children: t("staff.time_tracking.settings.targets.hoursUnit", "h") })
526
511
  ] }),
527
512
  /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: t(
528
- "staff.time_tracking.settings.access.graceDaysHint",
529
- "A member keeps access to a project for this many days after their assignment end date, so the last week of work can still be logged and corrected. 0 ends access on the end date itself."
513
+ "staff.time_tracking.settings.targets.dailyHoursHint",
514
+ "Scales the load bars in the timesheet. Leave empty to turn targets off."
530
515
  ) }),
531
- fieldErrors.includes("assignmentGraceDays") ? /* @__PURE__ */ jsx("span", { className: "text-xs text-status-error-text", children: t(
532
- "staff.time_tracking.settings.access.graceDaysError",
533
- "Enter a whole number of days between 0 and 365."
516
+ fieldErrors.includes("dailyHours") ? /* @__PURE__ */ jsx("span", { className: "text-xs text-status-error-text", children: t(
517
+ "staff.time_tracking.settings.targets.dailyHoursError",
518
+ "Enter a number of hours between 0 and 24, or leave the field empty."
534
519
  ) }) : null
535
520
  ] })
536
- ] }),
537
- /* @__PURE__ */ jsx(
538
- InjectionSpot,
539
- {
540
- spotId: extensionPoints.hosts.timeTrackingSettingsSections.spotId,
541
- context: settingsInjectionContext,
542
- data: draft
543
- }
544
- )
521
+ ] })
545
522
  ] }),
546
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-6", children: [
547
- /* @__PURE__ */ jsxs(Alert, { status: "warning", icon: /* @__PURE__ */ jsx(AlertTriangle, { "aria-hidden": "true" }), children: [
548
- /* @__PURE__ */ jsx(AlertTitle, { children: t("staff.time_tracking.settings.impact.title", "Changing rounding affects amounts") }),
549
- /* @__PURE__ */ jsx(AlertDescription, { children: impactState === "loading" && !impact ? /* @__PURE__ */ jsx("span", { className: "text-sm", children: t("staff.time_tracking.settings.impact.loading", "Calculating the impact\u2026") }) : impactState === "error" ? /* @__PURE__ */ jsx("span", { className: "text-sm", children: t("staff.time_tracking.settings.impact.error", "The impact preview is unavailable.") }) : impact && impact.projected.entryCount > 0 ? /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", "data-testid": "rounding-impact", children: [
550
- /* @__PURE__ */ jsx("span", { className: "text-sm", children: t(
551
- "staff.time_tracking.settings.impact.body",
552
- "With the current {count} entries from the last {days} days, {rule} gives {rounded} ({delta} against raw time). Closed reports stay unchanged.",
523
+ /* @__PURE__ */ jsxs(Card, { children: [
524
+ /* @__PURE__ */ jsx(CardHeader, { children: /* @__PURE__ */ jsx(CardTitle, { children: t("staff.time_tracking.settings.warnings.title", "Warnings") }) }),
525
+ /* @__PURE__ */ jsxs(CardContent, { className: "flex flex-col gap-4", children: [
526
+ /* @__PURE__ */ jsx(
527
+ SwitchField,
528
+ {
529
+ label: t("staff.time_tracking.settings.warnings.overlap", "Warn about overlapping entries"),
530
+ description: t("staff.time_tracking.settings.warnings.overlapHint", "A warning, not a block."),
531
+ checked: draft.warningsOverlap,
532
+ onCheckedChange: (value) => patchDraft({ warningsOverlap: value === true }),
533
+ disabled: !canManage
534
+ }
535
+ ),
536
+ /* @__PURE__ */ jsx(
537
+ SwitchField,
538
+ {
539
+ label: t("staff.time_tracking.settings.warnings.runningTimer", "Remind about a running timer"),
540
+ description: t(
541
+ "staff.time_tracking.settings.warnings.runningTimerHint",
542
+ "An unobtrusive reminder when leaving the module and after 8 h of continuous running."
543
+ ),
544
+ checked: draft.warningsRunningTimer,
545
+ onCheckedChange: (value) => patchDraft({ warningsRunningTimer: value === true }),
546
+ disabled: !canManage
547
+ }
548
+ )
549
+ ] })
550
+ ] }),
551
+ /* @__PURE__ */ jsxs(Card, { children: [
552
+ /* @__PURE__ */ jsx(CardHeader, { children: /* @__PURE__ */ jsx(CardTitle, { children: t("staff.time_tracking.settings.access.title", "Project access") }) }),
553
+ /* @__PURE__ */ jsxs(CardContent, { className: "flex flex-col gap-2", children: [
554
+ /* @__PURE__ */ jsx(Label, { htmlFor: "time-tracking-grace-days", children: t(
555
+ "staff.time_tracking.settings.access.graceDays",
556
+ "Access grace period after an assignment ends"
557
+ ) }),
558
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
559
+ /* @__PURE__ */ jsx(
560
+ Input,
553
561
  {
554
- count: impact.projected.entryCount,
555
- days: impact.windowDays,
556
- rule: ruleLabel,
557
- rounded: formatDuration(impact.projected.roundedMinutes, "clock"),
558
- delta: formatSignedMinutes(impact.projected.deltaMinutes)
562
+ id: "time-tracking-grace-days",
563
+ className: "max-w-28",
564
+ inputMode: "numeric",
565
+ value: draft.assignmentGraceDaysText,
566
+ onChange: (event) => patchDraft({ assignmentGraceDaysText: event.target.value }),
567
+ disabled: !canManage,
568
+ "aria-invalid": fieldErrors.includes("assignmentGraceDays")
559
569
  }
560
- ) }),
561
- impact.lockedEntryCount > 0 ? /* @__PURE__ */ jsx("span", { className: "text-xs", children: t(
562
- "staff.time_tracking.settings.impact.locked",
563
- "{count} entries in the window are locked in closed reports and are excluded.",
564
- { count: impact.lockedEntryCount }
565
- ) }) : null
566
- ] }) : /* @__PURE__ */ jsx("span", { className: "text-sm", children: t(
567
- "staff.time_tracking.settings.impact.empty",
568
- "There are no unlocked entries in the last {days} days to project against.",
569
- { days: impact?.windowDays ?? 90 }
570
- ) }) })
571
- ] }),
572
- /* @__PURE__ */ jsxs(Card, { children: [
573
- /* @__PURE__ */ jsx(CardHeader, { children: /* @__PURE__ */ jsx(CardTitle, { children: t("staff.time_tracking.settings.scope.title", "Settings scope") }) }),
574
- /* @__PURE__ */ jsxs(CardContent, { className: "flex flex-col gap-2", children: [
575
- /* @__PURE__ */ jsx("span", { className: "text-sm", children: t(
576
- "staff.time_tracking.settings.scope.body",
577
- "These rules are global \u2014 they cannot be set per customer or per project."
578
- ) }),
579
- /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: t(
580
- "staff.time_tracking.settings.scope.hint",
581
- "The rate and currency stay at project level, and a rate override stays at entry level."
582
- ) })
583
- ] })
570
+ ),
571
+ /* @__PURE__ */ jsx("span", { className: "text-sm text-muted-foreground", children: t("staff.time_tracking.settings.access.daysUnit", "days") })
572
+ ] }),
573
+ /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: t(
574
+ "staff.time_tracking.settings.access.graceDaysHint",
575
+ "A member keeps access to a project for this many days after their assignment end date, so the last week of work can still be logged and corrected. 0 ends access on the end date itself."
576
+ ) }),
577
+ fieldErrors.includes("assignmentGraceDays") ? /* @__PURE__ */ jsx("span", { className: "text-xs text-status-error-text", children: t(
578
+ "staff.time_tracking.settings.access.graceDaysError",
579
+ "Enter a whole number of days between 0 and 365."
580
+ ) }) : null
584
581
  ] })
585
- ] })
586
- ] }),
587
- /* @__PURE__ */ jsxs("div", { className: "mt-6 flex items-center justify-end gap-2", children: [
582
+ ] }),
588
583
  /* @__PURE__ */ jsx(
589
- Button,
584
+ InjectionSpot,
590
585
  {
591
- type: "button",
592
- variant: "ghost",
593
- onClick: () => setDraft(baseline),
594
- disabled: !isDirty || isSaving || isLoading,
595
- children: t("staff.time_tracking.settings.actions.cancel", "Cancel")
586
+ spotId: extensionPoints.hosts.timeTrackingSettingsSections.spotId,
587
+ context: settingsInjectionContext,
588
+ data: draft
596
589
  }
597
- ),
598
- /* @__PURE__ */ jsxs(Button, { type: "button", onClick: () => void handleSave(), disabled: !canSave, "data-testid": "save-settings", children: [
599
- isSaving ? /* @__PURE__ */ jsx(Spinner, { className: "size-4" }) : /* @__PURE__ */ jsx(Save, { className: "size-4", "aria-hidden": "true" }),
600
- t("staff.time_tracking.settings.actions.save", "Save")
590
+ )
591
+ ] }),
592
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-6", children: [
593
+ /* @__PURE__ */ jsxs(Alert, { status: "warning", icon: /* @__PURE__ */ jsx(AlertTriangle, { "aria-hidden": "true" }), children: [
594
+ /* @__PURE__ */ jsx(AlertTitle, { children: t("staff.time_tracking.settings.impact.title", "Changing rounding affects amounts") }),
595
+ /* @__PURE__ */ jsx(AlertDescription, { children: impactState === "loading" && !impact ? /* @__PURE__ */ jsx("span", { className: "text-sm", children: t("staff.time_tracking.settings.impact.loading", "Calculating the impact\u2026") }) : impactState === "error" ? /* @__PURE__ */ jsx("span", { className: "text-sm", children: t("staff.time_tracking.settings.impact.error", "The impact preview is unavailable.") }) : impact && impact.projected.entryCount > 0 ? /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", "data-testid": "rounding-impact", children: [
596
+ /* @__PURE__ */ jsx("span", { className: "text-sm", children: t(
597
+ "staff.time_tracking.settings.impact.body",
598
+ "With the current {count} entries from the last {days} days, {rule} gives {rounded} ({delta} against raw time). Closed reports stay unchanged.",
599
+ {
600
+ count: impact.projected.entryCount,
601
+ days: impact.windowDays,
602
+ rule: ruleLabel,
603
+ rounded: formatDuration(impact.projected.roundedMinutes, "clock"),
604
+ delta: formatSignedMinutes(impact.projected.deltaMinutes)
605
+ }
606
+ ) }),
607
+ impact.lockedEntryCount > 0 ? /* @__PURE__ */ jsx("span", { className: "text-xs", children: t(
608
+ "staff.time_tracking.settings.impact.locked",
609
+ "{count} entries in the window are locked in closed reports and are excluded.",
610
+ { count: impact.lockedEntryCount }
611
+ ) }) : null
612
+ ] }) : /* @__PURE__ */ jsx("span", { className: "text-sm", children: t(
613
+ "staff.time_tracking.settings.impact.empty",
614
+ "There are no unlocked entries in the last {days} days to project against.",
615
+ { days: impact?.windowDays ?? 90 }
616
+ ) }) })
617
+ ] }),
618
+ /* @__PURE__ */ jsxs(Card, { children: [
619
+ /* @__PURE__ */ jsx(CardHeader, { children: /* @__PURE__ */ jsx(CardTitle, { children: t("staff.time_tracking.settings.scope.title", "Settings scope") }) }),
620
+ /* @__PURE__ */ jsxs(CardContent, { className: "flex flex-col gap-2", children: [
621
+ /* @__PURE__ */ jsx("span", { className: "text-sm", children: t(
622
+ "staff.time_tracking.settings.scope.body",
623
+ "These rules are global \u2014 they cannot be set per customer or per project."
624
+ ) }),
625
+ /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: t(
626
+ "staff.time_tracking.settings.scope.hint",
627
+ "The rate and currency stay at project level, and a rate override stays at entry level."
628
+ ) })
629
+ ] })
601
630
  ] })
602
631
  ] })
603
632
  ] }),
633
+ /* @__PURE__ */ jsxs("div", { className: "mt-6 flex items-center justify-end gap-2", children: [
634
+ /* @__PURE__ */ jsx(
635
+ Button,
636
+ {
637
+ type: "button",
638
+ variant: "ghost",
639
+ onClick: () => setDraft(baseline),
640
+ disabled: !isDirty || isSaving || isLoading,
641
+ children: t("staff.time_tracking.settings.actions.cancel", "Cancel")
642
+ }
643
+ ),
644
+ /* @__PURE__ */ jsxs(Button, { type: "button", onClick: () => void handleSave(), disabled: !canSave, "data-testid": "save-settings", children: [
645
+ isSaving ? /* @__PURE__ */ jsx(Spinner, { className: "size-4" }) : /* @__PURE__ */ jsx(Save, { className: "size-4", "aria-hidden": "true" }),
646
+ t("staff.time_tracking.settings.actions.save", "Save")
647
+ ] })
648
+ ] })
649
+ ] });
650
+ return /* @__PURE__ */ jsxs(Page, { children: [
651
+ /* @__PURE__ */ jsx(
652
+ PageHeader,
653
+ {
654
+ title: t("staff.time_tracking.settings.title", "Module settings"),
655
+ description: t(
656
+ "staff.time_tracking.settings.subtitle",
657
+ "Rules shared by all customers and projects"
658
+ )
659
+ }
660
+ ),
661
+ /* @__PURE__ */ jsx(PageBody, { children: injectedTabs.length > 0 ? /* @__PURE__ */ jsxs(Tabs, { value: selectedTab, onValueChange: selectTab, variant: "underline", children: [
662
+ /* @__PURE__ */ jsxs(TabsList, { "aria-label": t("staff.time_tracking.settings.tabs.label", "Settings sections"), className: "mb-4", children: [
663
+ /* @__PURE__ */ jsx(TabsTrigger, { value: TIME_TRACKING_SETTINGS_GENERAL_TAB, children: t("staff.time_tracking.settings.tabs.general", "Time tracking") }),
664
+ injectedTabs.map((tab) => /* @__PURE__ */ jsx(TabsTrigger, { value: tab.tabId, children: tab.label }, tab.tabId))
665
+ ] }),
666
+ /* @__PURE__ */ jsx(TabsContent, { value: TIME_TRACKING_SETTINGS_GENERAL_TAB, children: generalSettings }),
667
+ injectedTabs.map((tab) => /* @__PURE__ */ jsx(TabsContent, { value: tab.tabId, children: tabInjectionContext ? /* @__PURE__ */ jsx(tab.Widget, { context: tabInjectionContext }) : null }, tab.tabId))
668
+ ] }) : generalSettings }),
604
669
  ConfirmDialogElement
605
670
  ] });
606
671
  }