@open-mercato/core 0.7.1-develop.7178.1.ab93fbaf4e → 0.7.1-develop.7180.1.9717fbbb43

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 (808) hide show
  1. package/.turbo/turbo-build.log +2 -2
  2. package/dist/generated/entities/staff_time_entry/index.js +14 -0
  3. package/dist/generated/entities/staff_time_entry/index.js.map +2 -2
  4. package/dist/generated/entities/staff_time_entry_tag/index.js +15 -0
  5. package/dist/generated/entities/staff_time_entry_tag/index.js.map +7 -0
  6. package/dist/generated/entities/staff_time_project/index.js +16 -0
  7. package/dist/generated/entities/staff_time_project/index.js.map +2 -2
  8. package/dist/generated/entities/staff_time_report/index.js +57 -0
  9. package/dist/generated/entities/staff_time_report/index.js.map +7 -0
  10. package/dist/generated/entities/staff_time_report_entry/index.js +27 -0
  11. package/dist/generated/entities/staff_time_report_entry/index.js.map +7 -0
  12. package/dist/generated/entities/staff_time_report_event/index.js +21 -0
  13. package/dist/generated/entities/staff_time_report_event/index.js.map +7 -0
  14. package/dist/generated/entities/staff_time_report_project/index.js +15 -0
  15. package/dist/generated/entities/staff_time_report_project/index.js.map +7 -0
  16. package/dist/generated/entities/staff_time_tag/index.js +21 -0
  17. package/dist/generated/entities/staff_time_tag/index.js.map +7 -0
  18. package/dist/generated/entities/staff_time_task/index.js +37 -0
  19. package/dist/generated/entities/staff_time_task/index.js.map +7 -0
  20. package/dist/generated/entities/staff_time_task_comment/index.js +21 -0
  21. package/dist/generated/entities/staff_time_task_comment/index.js.map +7 -0
  22. package/dist/generated/entities/staff_time_task_status/index.js +29 -0
  23. package/dist/generated/entities/staff_time_task_status/index.js.map +7 -0
  24. package/dist/generated/entities/staff_time_task_tag/index.js +15 -0
  25. package/dist/generated/entities/staff_time_task_tag/index.js.map +7 -0
  26. package/dist/generated/entities.ids.generated.js +11 -1
  27. package/dist/generated/entities.ids.generated.js.map +2 -2
  28. package/dist/generated/entity-fields-registry.js +149 -0
  29. package/dist/generated/entity-fields-registry.js.map +2 -2
  30. package/dist/helpers/integration/timesheetFixtures.js +7 -0
  31. package/dist/helpers/integration/timesheetFixtures.js.map +2 -2
  32. package/dist/modules/auth/cli.js +16 -0
  33. package/dist/modules/auth/cli.js.map +2 -2
  34. package/dist/modules/auth/lib/backendChrome.js +1 -0
  35. package/dist/modules/auth/lib/backendChrome.js.map +2 -2
  36. package/dist/modules/customer_accounts/lib/customerRoleAcls.js +44 -0
  37. package/dist/modules/customer_accounts/lib/customerRoleAcls.js.map +7 -0
  38. package/dist/modules/customer_accounts/setup.js +1 -28
  39. package/dist/modules/customer_accounts/setup.js.map +2 -2
  40. package/dist/modules/data_sync/api/options.js +2 -0
  41. package/dist/modules/data_sync/api/options.js.map +2 -2
  42. package/dist/modules/data_sync/backend/data-sync/page.js +39 -17
  43. package/dist/modules/data_sync/backend/data-sync/page.js.map +2 -2
  44. package/dist/modules/data_sync/lib/start-controls.js +42 -0
  45. package/dist/modules/data_sync/lib/start-controls.js.map +7 -0
  46. package/dist/modules/staff/acl.js +9 -1
  47. package/dist/modules/staff/acl.js.map +2 -2
  48. package/dist/modules/staff/ai-agents.js +142 -0
  49. package/dist/modules/staff/ai-agents.js.map +7 -0
  50. package/dist/modules/staff/ai-tools/time-tracking-pack.js +348 -0
  51. package/dist/modules/staff/ai-tools/time-tracking-pack.js.map +7 -0
  52. package/dist/modules/staff/ai-tools/types.js +54 -0
  53. package/dist/modules/staff/ai-tools/types.js.map +7 -0
  54. package/dist/modules/staff/ai-tools.js +8 -0
  55. package/dist/modules/staff/ai-tools.js.map +7 -0
  56. package/dist/modules/staff/analytics.js +84 -1
  57. package/dist/modules/staff/analytics.js.map +2 -2
  58. package/dist/modules/staff/api/guards.js +37 -3
  59. package/dist/modules/staff/api/guards.js.map +2 -2
  60. package/dist/modules/staff/api/leave-requests/accept/route.js +1 -3
  61. package/dist/modules/staff/api/leave-requests/accept/route.js.map +2 -2
  62. package/dist/modules/staff/api/leave-requests/reject/route.js +1 -3
  63. package/dist/modules/staff/api/leave-requests/reject/route.js.map +2 -2
  64. package/dist/modules/staff/api/portal/time-reports/[id]/route.js +131 -0
  65. package/dist/modules/staff/api/portal/time-reports/[id]/route.js.map +7 -0
  66. package/dist/modules/staff/api/portal/time-reports/route.js +179 -0
  67. package/dist/modules/staff/api/portal/time-reports/route.js.map +7 -0
  68. package/dist/modules/staff/api/team-members/self/route.js +1 -3
  69. package/dist/modules/staff/api/team-members/self/route.js.map +2 -2
  70. package/dist/modules/staff/api/team-members/tags/assign/route.js +1 -3
  71. package/dist/modules/staff/api/team-members/tags/assign/route.js.map +2 -2
  72. package/dist/modules/staff/api/team-members/tags/unassign/route.js +1 -3
  73. package/dist/modules/staff/api/team-members/tags/unassign/route.js.map +2 -2
  74. package/dist/modules/staff/api/timesheets/_shared/withTimesheetInterceptors.js +174 -0
  75. package/dist/modules/staff/api/timesheets/_shared/withTimesheetInterceptors.js.map +7 -0
  76. package/dist/modules/staff/api/timesheets/access-requests/route.js +226 -0
  77. package/dist/modules/staff/api/timesheets/access-requests/route.js.map +7 -0
  78. package/dist/modules/staff/api/timesheets/my-projects/[projectId]/route.js +15 -8
  79. package/dist/modules/staff/api/timesheets/my-projects/[projectId]/route.js.map +2 -2
  80. package/dist/modules/staff/api/timesheets/my-projects/route.js +13 -1
  81. package/dist/modules/staff/api/timesheets/my-projects/route.js.map +2 -2
  82. package/dist/modules/staff/api/timesheets/my-work/myWorkAggregate.js +42 -0
  83. package/dist/modules/staff/api/timesheets/my-work/myWorkAggregate.js.map +7 -0
  84. package/dist/modules/staff/api/timesheets/my-work/route.js +383 -0
  85. package/dist/modules/staff/api/timesheets/my-work/route.js.map +7 -0
  86. package/dist/modules/staff/api/timesheets/projects/kpis/route.js +14 -2
  87. package/dist/modules/staff/api/timesheets/projects/kpis/route.js.map +2 -2
  88. package/dist/modules/staff/api/timesheets/reports/[id]/close/route.js +168 -0
  89. package/dist/modules/staff/api/timesheets/reports/[id]/close/route.js.map +7 -0
  90. package/dist/modules/staff/api/timesheets/reports/[id]/export/route.js +246 -0
  91. package/dist/modules/staff/api/timesheets/reports/[id]/export/route.js.map +7 -0
  92. package/dist/modules/staff/api/timesheets/reports/[id]/sheet/route.js +183 -0
  93. package/dist/modules/staff/api/timesheets/reports/[id]/sheet/route.js.map +7 -0
  94. package/dist/modules/staff/api/timesheets/reports/[id]/unlock/route.js +164 -0
  95. package/dist/modules/staff/api/timesheets/reports/[id]/unlock/route.js.map +7 -0
  96. package/dist/modules/staff/api/timesheets/reports/preview/route.js +360 -0
  97. package/dist/modules/staff/api/timesheets/reports/preview/route.js.map +7 -0
  98. package/dist/modules/staff/api/timesheets/reports/route.js +316 -0
  99. package/dist/modules/staff/api/timesheets/reports/route.js.map +7 -0
  100. package/dist/modules/staff/api/timesheets/reports/shared.js +63 -0
  101. package/dist/modules/staff/api/timesheets/reports/shared.js.map +7 -0
  102. package/dist/modules/staff/api/timesheets/settings/reapply-rounding/route.js +164 -0
  103. package/dist/modules/staff/api/timesheets/settings/reapply-rounding/route.js.map +7 -0
  104. package/dist/modules/staff/api/timesheets/settings/rounding-impact/route.js +168 -0
  105. package/dist/modules/staff/api/timesheets/settings/rounding-impact/route.js.map +7 -0
  106. package/dist/modules/staff/api/timesheets/settings/route.js +199 -0
  107. package/dist/modules/staff/api/timesheets/settings/route.js.map +7 -0
  108. package/dist/modules/staff/api/timesheets/tags/access.js +76 -0
  109. package/dist/modules/staff/api/timesheets/tags/access.js.map +7 -0
  110. package/dist/modules/staff/api/timesheets/tags/entry-assignments/route.js +235 -0
  111. package/dist/modules/staff/api/timesheets/tags/entry-assignments/route.js.map +7 -0
  112. package/dist/modules/staff/api/timesheets/tags/route.js +160 -0
  113. package/dist/modules/staff/api/timesheets/tags/route.js.map +7 -0
  114. package/dist/modules/staff/api/timesheets/tags/task-assignments/route.js +233 -0
  115. package/dist/modules/staff/api/timesheets/tags/task-assignments/route.js.map +7 -0
  116. package/dist/modules/staff/api/timesheets/task-statuses/route.js +188 -0
  117. package/dist/modules/staff/api/timesheets/task-statuses/route.js.map +7 -0
  118. package/dist/modules/staff/api/timesheets/tasks/[id]/comments/route.js +399 -0
  119. package/dist/modules/staff/api/timesheets/tasks/[id]/comments/route.js.map +7 -0
  120. package/dist/modules/staff/api/timesheets/tasks/[id]/status/route.js +210 -0
  121. package/dist/modules/staff/api/timesheets/tasks/[id]/status/route.js.map +7 -0
  122. package/dist/modules/staff/api/timesheets/tasks/route.js +333 -0
  123. package/dist/modules/staff/api/timesheets/tasks/route.js.map +7 -0
  124. package/dist/modules/staff/api/timesheets/time-entries/[id]/duplicate/route.js +228 -0
  125. package/dist/modules/staff/api/timesheets/time-entries/[id]/duplicate/route.js.map +7 -0
  126. package/dist/modules/staff/api/timesheets/time-entries/[id]/segments/[segmentId]/route.js +29 -10
  127. package/dist/modules/staff/api/timesheets/time-entries/[id]/segments/[segmentId]/route.js.map +2 -2
  128. package/dist/modules/staff/api/timesheets/time-entries/[id]/segments/route.js +31 -18
  129. package/dist/modules/staff/api/timesheets/time-entries/[id]/segments/route.js.map +2 -2
  130. package/dist/modules/staff/api/timesheets/time-entries/[id]/timer-start/route.js +21 -7
  131. package/dist/modules/staff/api/timesheets/time-entries/[id]/timer-start/route.js.map +2 -2
  132. package/dist/modules/staff/api/timesheets/time-entries/[id]/timer-stop/route.js +27 -7
  133. package/dist/modules/staff/api/timesheets/time-entries/[id]/timer-stop/route.js.map +2 -2
  134. package/dist/modules/staff/api/timesheets/time-entries/bulk/route.js +215 -32
  135. package/dist/modules/staff/api/timesheets/time-entries/bulk/route.js.map +2 -2
  136. package/dist/modules/staff/api/timesheets/time-entries/copy-day/route.js +378 -0
  137. package/dist/modules/staff/api/timesheets/time-entries/copy-day/route.js.map +7 -0
  138. package/dist/modules/staff/api/timesheets/time-entries/overlaps/route.js +340 -0
  139. package/dist/modules/staff/api/timesheets/time-entries/overlaps/route.js.map +7 -0
  140. package/dist/modules/staff/api/timesheets/time-entries/route.js +238 -26
  141. package/dist/modules/staff/api/timesheets/time-entries/route.js.map +2 -2
  142. package/dist/modules/staff/api/timesheets/time-entries/start-timer/route.js +23 -8
  143. package/dist/modules/staff/api/timesheets/time-entries/start-timer/route.js.map +2 -2
  144. package/dist/modules/staff/api/timesheets/time-projects/[id]/change-currency/route.js +209 -0
  145. package/dist/modules/staff/api/timesheets/time-projects/[id]/change-currency/route.js.map +7 -0
  146. package/dist/modules/staff/api/timesheets/time-projects/[id]/employees/route.js +59 -2
  147. package/dist/modules/staff/api/timesheets/time-projects/[id]/employees/route.js.map +2 -2
  148. package/dist/modules/staff/api/timesheets/time-projects/route.js +264 -22
  149. package/dist/modules/staff/api/timesheets/time-projects/route.js.map +2 -2
  150. package/dist/modules/staff/backend/staff/time-tracking/board/page.js +110 -0
  151. package/dist/modules/staff/backend/staff/time-tracking/board/page.js.map +7 -0
  152. package/dist/modules/staff/backend/staff/time-tracking/board/page.meta.js +18 -0
  153. package/dist/modules/staff/backend/staff/time-tracking/board/page.meta.js.map +7 -0
  154. package/dist/modules/staff/backend/staff/time-tracking/entries/page.js +981 -0
  155. package/dist/modules/staff/backend/staff/time-tracking/entries/page.js.map +7 -0
  156. package/dist/modules/staff/backend/staff/time-tracking/entries/page.meta.js +18 -0
  157. package/dist/modules/staff/backend/staff/time-tracking/entries/page.meta.js.map +7 -0
  158. package/dist/modules/staff/backend/staff/time-tracking/page.js +583 -0
  159. package/dist/modules/staff/backend/staff/time-tracking/page.js.map +7 -0
  160. package/dist/modules/staff/backend/staff/time-tracking/page.meta.js +15 -0
  161. package/dist/modules/staff/backend/staff/time-tracking/page.meta.js.map +7 -0
  162. package/dist/modules/staff/backend/staff/time-tracking/projects/[id]/board/page.js +65 -0
  163. package/dist/modules/staff/backend/staff/time-tracking/projects/[id]/board/page.js.map +7 -0
  164. package/dist/modules/staff/backend/staff/time-tracking/projects/[id]/board/page.meta.js +16 -0
  165. package/dist/modules/staff/backend/staff/time-tracking/projects/[id]/board/page.meta.js.map +7 -0
  166. package/dist/modules/staff/backend/staff/time-tracking/projects/[id]/edit/page.js +229 -0
  167. package/dist/modules/staff/backend/staff/time-tracking/projects/[id]/edit/page.js.map +7 -0
  168. package/dist/modules/staff/backend/staff/time-tracking/projects/[id]/edit/page.meta.js +16 -0
  169. package/dist/modules/staff/backend/staff/time-tracking/projects/[id]/edit/page.meta.js.map +7 -0
  170. package/dist/modules/staff/backend/staff/time-tracking/projects/[id]/page.js +1014 -0
  171. package/dist/modules/staff/backend/staff/time-tracking/projects/[id]/page.js.map +7 -0
  172. package/dist/modules/staff/backend/staff/time-tracking/projects/[id]/page.meta.js +16 -0
  173. package/dist/modules/staff/backend/staff/time-tracking/projects/[id]/page.meta.js.map +7 -0
  174. package/dist/modules/staff/backend/staff/time-tracking/projects/create/page.js +97 -0
  175. package/dist/modules/staff/backend/staff/time-tracking/projects/create/page.js.map +7 -0
  176. package/dist/modules/staff/backend/staff/time-tracking/projects/create/page.meta.js +16 -0
  177. package/dist/modules/staff/backend/staff/time-tracking/projects/create/page.meta.js.map +7 -0
  178. package/dist/modules/staff/backend/staff/time-tracking/projects/page.js +1040 -0
  179. package/dist/modules/staff/backend/staff/time-tracking/projects/page.js.map +7 -0
  180. package/dist/modules/staff/backend/staff/time-tracking/projects/page.meta.js +19 -0
  181. package/dist/modules/staff/backend/staff/time-tracking/projects/page.meta.js.map +7 -0
  182. package/dist/modules/staff/backend/staff/time-tracking/projects/projectFormConfig.js +353 -0
  183. package/dist/modules/staff/backend/staff/time-tracking/projects/projectFormConfig.js.map +7 -0
  184. package/dist/modules/staff/backend/staff/time-tracking/reports/[id]/page.js +457 -0
  185. package/dist/modules/staff/backend/staff/time-tracking/reports/[id]/page.js.map +7 -0
  186. package/dist/modules/staff/backend/staff/time-tracking/reports/[id]/page.meta.js +16 -0
  187. package/dist/modules/staff/backend/staff/time-tracking/reports/[id]/page.meta.js.map +7 -0
  188. package/dist/modules/staff/backend/staff/time-tracking/reports/create/page.js +697 -0
  189. package/dist/modules/staff/backend/staff/time-tracking/reports/create/page.js.map +7 -0
  190. package/dist/modules/staff/backend/staff/time-tracking/reports/create/page.meta.js +16 -0
  191. package/dist/modules/staff/backend/staff/time-tracking/reports/create/page.meta.js.map +7 -0
  192. package/dist/modules/staff/backend/staff/time-tracking/reports/page.js +174 -0
  193. package/dist/modules/staff/backend/staff/time-tracking/reports/page.js.map +7 -0
  194. package/dist/modules/staff/backend/staff/time-tracking/reports/page.meta.js +18 -0
  195. package/dist/modules/staff/backend/staff/time-tracking/reports/page.meta.js.map +7 -0
  196. package/dist/modules/staff/backend/staff/time-tracking/settings/page.js +546 -0
  197. package/dist/modules/staff/backend/staff/time-tracking/settings/page.js.map +7 -0
  198. package/dist/modules/staff/backend/staff/time-tracking/settings/page.meta.js +18 -0
  199. package/dist/modules/staff/backend/staff/time-tracking/settings/page.meta.js.map +7 -0
  200. package/dist/modules/staff/backend/staff/time-tracking/timesheet/GridView.js +710 -0
  201. package/dist/modules/staff/backend/staff/time-tracking/timesheet/GridView.js.map +7 -0
  202. package/dist/modules/staff/backend/staff/time-tracking/timesheet/page.js +646 -0
  203. package/dist/modules/staff/backend/staff/time-tracking/timesheet/page.js.map +7 -0
  204. package/dist/modules/staff/backend/staff/time-tracking/timesheet/page.meta.js +18 -0
  205. package/dist/modules/staff/backend/staff/time-tracking/timesheet/page.meta.js.map +7 -0
  206. package/dist/modules/staff/backend/staff/timesheets/page.js +4 -793
  207. package/dist/modules/staff/backend/staff/timesheets/page.js.map +2 -2
  208. package/dist/modules/staff/backend/staff/timesheets/page.meta.js +2 -7
  209. package/dist/modules/staff/backend/staff/timesheets/page.meta.js.map +2 -2
  210. package/dist/modules/staff/backend/staff/timesheets/projects/[id]/edit/page.js +5 -136
  211. package/dist/modules/staff/backend/staff/timesheets/projects/[id]/edit/page.js.map +2 -2
  212. package/dist/modules/staff/backend/staff/timesheets/projects/[id]/edit/page.meta.js +1 -7
  213. package/dist/modules/staff/backend/staff/timesheets/projects/[id]/edit/page.meta.js.map +2 -2
  214. package/dist/modules/staff/backend/staff/timesheets/projects/[id]/page.js +5 -445
  215. package/dist/modules/staff/backend/staff/timesheets/projects/[id]/page.js.map +3 -3
  216. package/dist/modules/staff/backend/staff/timesheets/projects/[id]/page.meta.js +1 -7
  217. package/dist/modules/staff/backend/staff/timesheets/projects/[id]/page.meta.js.map +2 -2
  218. package/dist/modules/staff/backend/staff/timesheets/projects/create/page.js +4 -76
  219. package/dist/modules/staff/backend/staff/timesheets/projects/create/page.js.map +2 -2
  220. package/dist/modules/staff/backend/staff/timesheets/projects/create/page.meta.js +1 -7
  221. package/dist/modules/staff/backend/staff/timesheets/projects/create/page.meta.js.map +2 -2
  222. package/dist/modules/staff/backend/staff/timesheets/projects/page.js +4 -613
  223. package/dist/modules/staff/backend/staff/timesheets/projects/page.js.map +2 -2
  224. package/dist/modules/staff/backend/staff/timesheets/projects/page.meta.js +2 -17
  225. package/dist/modules/staff/backend/staff/timesheets/projects/page.meta.js.map +2 -2
  226. package/dist/modules/staff/ce.js +40 -0
  227. package/dist/modules/staff/ce.js.map +2 -2
  228. package/dist/modules/staff/cli.js +166 -1
  229. package/dist/modules/staff/cli.js.map +2 -2
  230. package/dist/modules/staff/commands/index.js +5 -0
  231. package/dist/modules/staff/commands/index.js.map +2 -2
  232. package/dist/modules/staff/commands/timesheets-entries.js +569 -21
  233. package/dist/modules/staff/commands/timesheets-entries.js.map +3 -3
  234. package/dist/modules/staff/commands/timesheets-projects.js +450 -7
  235. package/dist/modules/staff/commands/timesheets-projects.js.map +2 -2
  236. package/dist/modules/staff/commands/timesheets-reports.js +1036 -0
  237. package/dist/modules/staff/commands/timesheets-reports.js.map +7 -0
  238. package/dist/modules/staff/commands/timesheets-tags.js +1015 -0
  239. package/dist/modules/staff/commands/timesheets-tags.js.map +7 -0
  240. package/dist/modules/staff/commands/timesheets-task-comments.js +438 -0
  241. package/dist/modules/staff/commands/timesheets-task-comments.js.map +7 -0
  242. package/dist/modules/staff/commands/timesheets-task-statuses.js +723 -0
  243. package/dist/modules/staff/commands/timesheets-task-statuses.js.map +7 -0
  244. package/dist/modules/staff/commands/timesheets-tasks.js +834 -0
  245. package/dist/modules/staff/commands/timesheets-tasks.js.map +7 -0
  246. package/dist/modules/staff/data/enrichers.js +426 -12
  247. package/dist/modules/staff/data/enrichers.js.map +2 -2
  248. package/dist/modules/staff/data/entities.js +552 -3
  249. package/dist/modules/staff/data/entities.js.map +2 -2
  250. package/dist/modules/staff/data/extensions.js +41 -0
  251. package/dist/modules/staff/data/extensions.js.map +7 -0
  252. package/dist/modules/staff/data/validators.js +254 -9
  253. package/dist/modules/staff/data/validators.js.map +2 -2
  254. package/dist/modules/staff/di.js +42 -1
  255. package/dist/modules/staff/di.js.map +2 -2
  256. package/dist/modules/staff/events.js +84 -6
  257. package/dist/modules/staff/events.js.map +2 -2
  258. package/dist/modules/staff/events.payloads.js +158 -0
  259. package/dist/modules/staff/events.payloads.js.map +7 -0
  260. package/dist/modules/staff/extension-points.js +261 -0
  261. package/dist/modules/staff/extension-points.js.map +7 -0
  262. package/dist/modules/staff/frontend/[orgSlug]/portal/time-reports/[id]/page.js +138 -0
  263. package/dist/modules/staff/frontend/[orgSlug]/portal/time-reports/[id]/page.js.map +7 -0
  264. package/dist/modules/staff/frontend/[orgSlug]/portal/time-reports/[id]/page.meta.js +12 -0
  265. package/dist/modules/staff/frontend/[orgSlug]/portal/time-reports/[id]/page.meta.js.map +7 -0
  266. package/dist/modules/staff/frontend/[orgSlug]/portal/time-reports/page.js +133 -0
  267. package/dist/modules/staff/frontend/[orgSlug]/portal/time-reports/page.js.map +7 -0
  268. package/dist/modules/staff/frontend/[orgSlug]/portal/time-reports/page.meta.js +19 -0
  269. package/dist/modules/staff/frontend/[orgSlug]/portal/time-reports/page.meta.js.map +7 -0
  270. package/dist/modules/staff/lib/crud.js +11 -1
  271. package/dist/modules/staff/lib/crud.js.map +2 -2
  272. package/dist/modules/staff/lib/time-tracking/access.js +92 -0
  273. package/dist/modules/staff/lib/time-tracking/access.js.map +7 -0
  274. package/dist/modules/staff/lib/time-tracking/billability.js +39 -0
  275. package/dist/modules/staff/lib/time-tracking/billability.js.map +7 -0
  276. package/dist/modules/staff/lib/time-tracking/capacity.js +68 -0
  277. package/dist/modules/staff/lib/time-tracking/capacity.js.map +7 -0
  278. package/dist/modules/staff/lib/time-tracking/componentContracts.js +15 -0
  279. package/dist/modules/staff/lib/time-tracking/componentContracts.js.map +7 -0
  280. package/dist/modules/staff/lib/time-tracking/cost.js +82 -0
  281. package/dist/modules/staff/lib/time-tracking/cost.js.map +7 -0
  282. package/dist/modules/staff/lib/time-tracking/duration.js +55 -0
  283. package/dist/modules/staff/lib/time-tracking/duration.js.map +7 -0
  284. package/dist/modules/staff/lib/time-tracking/featureAccess.js +41 -0
  285. package/dist/modules/staff/lib/time-tracking/featureAccess.js.map +7 -0
  286. package/dist/modules/staff/lib/time-tracking/interval.js +72 -0
  287. package/dist/modules/staff/lib/time-tracking/interval.js.map +7 -0
  288. package/dist/modules/staff/lib/time-tracking/migrateProjectCodes.js +88 -0
  289. package/dist/modules/staff/lib/time-tracking/migrateProjectCodes.js.map +7 -0
  290. package/dist/modules/staff/lib/time-tracking/moneyVisibility.js +10 -0
  291. package/dist/modules/staff/lib/time-tracking/moneyVisibility.js.map +7 -0
  292. package/dist/modules/staff/lib/time-tracking/overlap.js +87 -0
  293. package/dist/modules/staff/lib/time-tracking/overlap.js.map +7 -0
  294. package/dist/modules/staff/lib/time-tracking/portalRecipients.js +27 -0
  295. package/dist/modules/staff/lib/time-tracking/portalRecipients.js.map +7 -0
  296. package/dist/modules/staff/lib/time-tracking/portalReports.js +16 -0
  297. package/dist/modules/staff/lib/time-tracking/portalReports.js.map +7 -0
  298. package/dist/modules/staff/lib/time-tracking/projectCode.js +135 -0
  299. package/dist/modules/staff/lib/time-tracking/projectCode.js.map +7 -0
  300. package/dist/modules/staff/lib/time-tracking/reapplyRounding.js +187 -0
  301. package/dist/modules/staff/lib/time-tracking/reapplyRounding.js.map +7 -0
  302. package/dist/modules/staff/lib/time-tracking/recalculationRunner.js +80 -0
  303. package/dist/modules/staff/lib/time-tracking/recalculationRunner.js.map +7 -0
  304. package/dist/modules/staff/lib/time-tracking/recalculations.js +56 -0
  305. package/dist/modules/staff/lib/time-tracking/recalculations.js.map +7 -0
  306. package/dist/modules/staff/lib/time-tracking/registries/invoke.js +63 -0
  307. package/dist/modules/staff/lib/time-tracking/registries/invoke.js.map +7 -0
  308. package/dist/modules/staff/lib/time-tracking/registries/registry.js +62 -0
  309. package/dist/modules/staff/lib/time-tracking/registries/registry.js.map +7 -0
  310. package/dist/modules/staff/lib/time-tracking/registries/scope.js +21 -0
  311. package/dist/modules/staff/lib/time-tracking/registries/scope.js.map +7 -0
  312. package/dist/modules/staff/lib/time-tracking/rollup.js +34 -0
  313. package/dist/modules/staff/lib/time-tracking/rollup.js.map +7 -0
  314. package/dist/modules/staff/lib/time-tracking/rounding.js +66 -0
  315. package/dist/modules/staff/lib/time-tracking/rounding.js.map +7 -0
  316. package/dist/modules/staff/lib/time-tracking/roundingImpact.js +39 -0
  317. package/dist/modules/staff/lib/time-tracking/roundingImpact.js.map +7 -0
  318. package/dist/modules/staff/lib/time-tracking/settingKeys.js +214 -0
  319. package/dist/modules/staff/lib/time-tracking/settingKeys.js.map +7 -0
  320. package/dist/modules/staff/lib/time-tracking/settings.js +87 -0
  321. package/dist/modules/staff/lib/time-tracking/settings.js.map +7 -0
  322. package/dist/modules/staff/lib/time-tracking/sqlInClause.js +9 -0
  323. package/dist/modules/staff/lib/time-tracking/sqlInClause.js.map +7 -0
  324. package/dist/modules/staff/lib/time-tracking/timeEntrySources.js +48 -0
  325. package/dist/modules/staff/lib/time-tracking/timeEntrySources.js.map +7 -0
  326. package/dist/modules/staff/lib/time-tracking-ui/BoardFilterChips.js +283 -0
  327. package/dist/modules/staff/lib/time-tracking-ui/BoardFilterChips.js.map +7 -0
  328. package/dist/modules/staff/lib/time-tracking-ui/CustomerPicker.js +324 -0
  329. package/dist/modules/staff/lib/time-tracking-ui/CustomerPicker.js.map +7 -0
  330. package/dist/modules/staff/lib/time-tracking-ui/DurationInput.js +121 -0
  331. package/dist/modules/staff/lib/time-tracking-ui/DurationInput.js.map +7 -0
  332. package/dist/modules/staff/lib/time-tracking-ui/EntryDetailsFields.js +188 -0
  333. package/dist/modules/staff/lib/time-tracking-ui/EntryDetailsFields.js.map +7 -0
  334. package/dist/modules/staff/lib/time-tracking-ui/EntryFilterBar.js +89 -0
  335. package/dist/modules/staff/lib/time-tracking-ui/EntryFilterBar.js.map +7 -0
  336. package/dist/modules/staff/lib/time-tracking-ui/KanbanBoard.js +855 -0
  337. package/dist/modules/staff/lib/time-tracking-ui/KanbanBoard.js.map +7 -0
  338. package/dist/modules/staff/lib/time-tracking-ui/KanbanCard.js +360 -0
  339. package/dist/modules/staff/lib/time-tracking-ui/KanbanCard.js.map +7 -0
  340. package/dist/modules/staff/lib/time-tracking-ui/KanbanColumn.js +259 -0
  341. package/dist/modules/staff/lib/time-tracking-ui/KanbanColumn.js.map +7 -0
  342. package/dist/modules/staff/lib/time-tracking-ui/NewTaskDialog.js +238 -0
  343. package/dist/modules/staff/lib/time-tracking-ui/NewTaskDialog.js.map +7 -0
  344. package/dist/modules/staff/lib/time-tracking-ui/NoProjectAccess.js +130 -0
  345. package/dist/modules/staff/lib/time-tracking-ui/NoProjectAccess.js.map +7 -0
  346. package/dist/modules/staff/lib/time-tracking-ui/PeriodSelector.js +98 -0
  347. package/dist/modules/staff/lib/time-tracking-ui/PeriodSelector.js.map +7 -0
  348. package/dist/modules/staff/lib/time-tracking-ui/PhasePlaceholder.js +27 -0
  349. package/dist/modules/staff/lib/time-tracking-ui/PhasePlaceholder.js.map +7 -0
  350. package/dist/modules/staff/lib/time-tracking-ui/ProjectCodeField.js +166 -0
  351. package/dist/modules/staff/lib/time-tracking-ui/ProjectCodeField.js.map +7 -0
  352. package/dist/modules/staff/lib/time-tracking-ui/ProjectCurrencyField.js +295 -0
  353. package/dist/modules/staff/lib/time-tracking-ui/ProjectCurrencyField.js.map +7 -0
  354. package/dist/modules/staff/lib/time-tracking-ui/ProjectFormSections.js +212 -0
  355. package/dist/modules/staff/lib/time-tracking-ui/ProjectFormSections.js.map +7 -0
  356. package/dist/modules/staff/lib/time-tracking-ui/ProjectTeamDrawer.js +729 -0
  357. package/dist/modules/staff/lib/time-tracking-ui/ProjectTeamDrawer.js.map +7 -0
  358. package/dist/modules/staff/lib/time-tracking-ui/ReportSheet.js +217 -0
  359. package/dist/modules/staff/lib/time-tracking-ui/ReportSheet.js.map +7 -0
  360. package/dist/modules/staff/lib/time-tracking-ui/TagPicker.js +158 -0
  361. package/dist/modules/staff/lib/time-tracking-ui/TagPicker.js.map +7 -0
  362. package/dist/modules/staff/lib/time-tracking-ui/TaskBoardScreen.js +224 -0
  363. package/dist/modules/staff/lib/time-tracking-ui/TaskBoardScreen.js.map +7 -0
  364. package/dist/modules/staff/lib/time-tracking-ui/TaskCommentThread.js +93 -0
  365. package/dist/modules/staff/lib/time-tracking-ui/TaskCommentThread.js.map +7 -0
  366. package/dist/modules/staff/lib/time-tracking-ui/TaskDrawer.js +1196 -0
  367. package/dist/modules/staff/lib/time-tracking-ui/TaskDrawer.js.map +7 -0
  368. package/dist/modules/staff/lib/time-tracking-ui/TaskListView.js +176 -0
  369. package/dist/modules/staff/lib/time-tracking-ui/TaskListView.js.map +7 -0
  370. package/dist/modules/staff/lib/time-tracking-ui/TaskPicker.js +307 -0
  371. package/dist/modules/staff/lib/time-tracking-ui/TaskPicker.js.map +7 -0
  372. package/dist/modules/staff/lib/time-tracking-ui/TaskQuickLog.js +284 -0
  373. package/dist/modules/staff/lib/time-tracking-ui/TaskQuickLog.js.map +7 -0
  374. package/dist/modules/staff/lib/time-tracking-ui/TimeEntriesSummaryFooter.js +73 -0
  375. package/dist/modules/staff/lib/time-tracking-ui/TimeEntriesSummaryFooter.js.map +7 -0
  376. package/dist/modules/staff/lib/time-tracking-ui/TimeEntryDialog.js +1499 -0
  377. package/dist/modules/staff/lib/time-tracking-ui/TimeEntryDialog.js.map +7 -0
  378. package/dist/modules/staff/lib/time-tracking-ui/TimeEntryDurationCell.js +95 -0
  379. package/dist/modules/staff/lib/time-tracking-ui/TimeEntryDurationCell.js.map +7 -0
  380. package/dist/modules/staff/lib/time-tracking-ui/TimesheetCalendar.js +188 -0
  381. package/dist/modules/staff/lib/time-tracking-ui/TimesheetCalendar.js.map +7 -0
  382. package/dist/modules/staff/lib/time-tracking-ui/TimesheetPeriodFooter.js +61 -0
  383. package/dist/modules/staff/lib/time-tracking-ui/TimesheetPeriodFooter.js.map +7 -0
  384. package/dist/modules/staff/lib/time-tracking-ui/TimesheetViewSwitch.js +45 -0
  385. package/dist/modules/staff/lib/time-tracking-ui/TimesheetViewSwitch.js.map +7 -0
  386. package/dist/modules/staff/lib/time-tracking-ui/boardDirectory.js +176 -0
  387. package/dist/modules/staff/lib/time-tracking-ui/boardDirectory.js.map +7 -0
  388. package/dist/modules/staff/lib/time-tracking-ui/boardFilters.js +82 -0
  389. package/dist/modules/staff/lib/time-tracking-ui/boardFilters.js.map +7 -0
  390. package/dist/modules/staff/lib/time-tracking-ui/boardSummary.js +5 -0
  391. package/dist/modules/staff/lib/time-tracking-ui/boardSummary.js.map +7 -0
  392. package/dist/modules/staff/lib/time-tracking-ui/kanbanBoardData.js +152 -0
  393. package/dist/modules/staff/lib/time-tracking-ui/kanbanBoardData.js.map +7 -0
  394. package/dist/modules/staff/lib/time-tracking-ui/projectTeamAssignment.js +92 -0
  395. package/dist/modules/staff/lib/time-tracking-ui/projectTeamAssignment.js.map +7 -0
  396. package/dist/modules/staff/lib/time-tracking-ui/taskDrawerData.js +111 -0
  397. package/dist/modules/staff/lib/time-tracking-ui/taskDrawerData.js.map +7 -0
  398. package/dist/modules/staff/lib/time-tracking-ui/timeEntryDialogState.js +243 -0
  399. package/dist/modules/staff/lib/time-tracking-ui/timeEntryDialogState.js.map +7 -0
  400. package/dist/modules/staff/lib/time-tracking-ui/timeEntryListData.js +151 -0
  401. package/dist/modules/staff/lib/time-tracking-ui/timeEntryListData.js.map +7 -0
  402. package/dist/modules/staff/lib/time-tracking-ui/timeTrackingSettingsForm.js +105 -0
  403. package/dist/modules/staff/lib/time-tracking-ui/timeTrackingSettingsForm.js.map +7 -0
  404. package/dist/modules/staff/lib/time-tracking-ui/timesheetData.js +132 -0
  405. package/dist/modules/staff/lib/time-tracking-ui/timesheetData.js.map +7 -0
  406. package/dist/modules/staff/lib/time-tracking-ui/timesheetPeriod.js +205 -0
  407. package/dist/modules/staff/lib/time-tracking-ui/timesheetPeriod.js.map +7 -0
  408. package/dist/modules/staff/lib/time-tracking-ui/timesheetTargets.js +53 -0
  409. package/dist/modules/staff/lib/time-tracking-ui/timesheetTargets.js.map +7 -0
  410. package/dist/modules/staff/lib/time-tracking-ui/useBoardFilters.js +77 -0
  411. package/dist/modules/staff/lib/time-tracking-ui/useBoardFilters.js.map +7 -0
  412. package/dist/modules/staff/lib/time-tracking-ui/useTimesheetPreferences.js +151 -0
  413. package/dist/modules/staff/lib/time-tracking-ui/useTimesheetPreferences.js.map +7 -0
  414. package/dist/modules/staff/lib/timeTrackingSeeds.js +809 -0
  415. package/dist/modules/staff/lib/timeTrackingSeeds.js.map +7 -0
  416. package/dist/modules/staff/lib/timesheets/timeEntryCacheInvalidation.js +2 -3
  417. package/dist/modules/staff/lib/timesheets/timeEntryCacheInvalidation.js.map +2 -2
  418. package/dist/modules/staff/lib/timesheets/timeEntryDecoration.js +152 -0
  419. package/dist/modules/staff/lib/timesheets/timeEntryDecoration.js.map +7 -0
  420. package/dist/modules/staff/lib/timesheets-projects/budgetBurn.js +36 -0
  421. package/dist/modules/staff/lib/timesheets-projects/budgetBurn.js.map +7 -0
  422. package/dist/modules/staff/lib/timesheets-projects/budgetThreshold.js +66 -0
  423. package/dist/modules/staff/lib/timesheets-projects/budgetThreshold.js.map +7 -0
  424. package/dist/modules/staff/lib/timesheets-projects/budgetThresholdState.js +78 -0
  425. package/dist/modules/staff/lib/timesheets-projects/budgetThresholdState.js.map +7 -0
  426. package/dist/modules/staff/lib/timesheets-projects/computeProjectFinancials.js +81 -0
  427. package/dist/modules/staff/lib/timesheets-projects/computeProjectFinancials.js.map +7 -0
  428. package/dist/modules/staff/lib/timesheets-projects/reportSelection.js +44 -0
  429. package/dist/modules/staff/lib/timesheets-projects/reportSelection.js.map +7 -0
  430. package/dist/modules/staff/lib/timesheets-projects-ui/AssignMembersDialog.js +169 -0
  431. package/dist/modules/staff/lib/timesheets-projects-ui/AssignMembersDialog.js.map +7 -0
  432. package/dist/modules/staff/lib/timesheets-projects-ui/ProjectBudgetCell.js +22 -0
  433. package/dist/modules/staff/lib/timesheets-projects-ui/ProjectBudgetCell.js.map +7 -0
  434. package/dist/modules/staff/lib/timesheets-projects-ui/ProjectCard.js +51 -1
  435. package/dist/modules/staff/lib/timesheets-projects-ui/ProjectCard.js.map +2 -2
  436. package/dist/modules/staff/lib/timesheets-projects-ui/ProjectsBulkActionsBar.js +70 -0
  437. package/dist/modules/staff/lib/timesheets-projects-ui/ProjectsBulkActionsBar.js.map +7 -0
  438. package/dist/modules/staff/lib/timesheets-reports/buildReportSheet.js +63 -0
  439. package/dist/modules/staff/lib/timesheets-reports/buildReportSheet.js.map +7 -0
  440. package/dist/modules/staff/lib/timesheets-reports/loadReportData.js +170 -0
  441. package/dist/modules/staff/lib/timesheets-reports/loadReportData.js.map +7 -0
  442. package/dist/modules/staff/lib/timesheets-reports/pdf.js +205 -0
  443. package/dist/modules/staff/lib/timesheets-reports/pdf.js.map +7 -0
  444. package/dist/modules/staff/lib/timesheets-reports/reportApprovalPolicies.js +68 -0
  445. package/dist/modules/staff/lib/timesheets-reports/reportApprovalPolicies.js.map +7 -0
  446. package/dist/modules/staff/lib/timesheets-reports/reportConfigData.js +135 -0
  447. package/dist/modules/staff/lib/timesheets-reports/reportConfigData.js.map +7 -0
  448. package/dist/modules/staff/lib/timesheets-reports/reportConfigState.js +48 -0
  449. package/dist/modules/staff/lib/timesheets-reports/reportConfigState.js.map +7 -0
  450. package/dist/modules/staff/lib/timesheets-reports/reportExport.js +262 -0
  451. package/dist/modules/staff/lib/timesheets-reports/reportExport.js.map +7 -0
  452. package/dist/modules/staff/lib/timesheets-reports/reportExportFormats.js +34 -0
  453. package/dist/modules/staff/lib/timesheets-reports/reportExportFormats.js.map +7 -0
  454. package/dist/modules/staff/lib/timesheets-reports/reportGroupings.js +79 -0
  455. package/dist/modules/staff/lib/timesheets-reports/reportGroupings.js.map +7 -0
  456. package/dist/modules/staff/lib/timesheets-reports/reportLabels.js +11 -0
  457. package/dist/modules/staff/lib/timesheets-reports/reportLabels.js.map +7 -0
  458. package/dist/modules/staff/lib/timesheets-reports/reportReference.js +83 -0
  459. package/dist/modules/staff/lib/timesheets-reports/reportReference.js.map +7 -0
  460. package/dist/modules/staff/lib/timesheets-reports/reportRows.js +42 -0
  461. package/dist/modules/staff/lib/timesheets-reports/reportRows.js.map +7 -0
  462. package/dist/modules/staff/lib/timesheets-reports/reportSheetData.js +107 -0
  463. package/dist/modules/staff/lib/timesheets-reports/reportSheetData.js.map +7 -0
  464. package/dist/modules/staff/lib/timesheets-reports/reportTotals.js +289 -0
  465. package/dist/modules/staff/lib/timesheets-reports/reportTotals.js.map +7 -0
  466. package/dist/modules/staff/lib/timesheets-reports/xlsx.js +145 -0
  467. package/dist/modules/staff/lib/timesheets-reports/xlsx.js.map +7 -0
  468. package/dist/modules/staff/lib/timesheets-tasks/computeTaskRollups.js +116 -0
  469. package/dist/modules/staff/lib/timesheets-tasks/computeTaskRollups.js.map +7 -0
  470. package/dist/modules/staff/lib/timesheets-tasks/defaultStatusTemplate.js +50 -0
  471. package/dist/modules/staff/lib/timesheets-tasks/defaultStatusTemplate.js.map +7 -0
  472. package/dist/modules/staff/lib/timesheets-tasks/seedProjectStatuses.js +27 -0
  473. package/dist/modules/staff/lib/timesheets-tasks/seedProjectStatuses.js.map +7 -0
  474. package/dist/modules/staff/lib/timesheets-tasks/statusPositions.js +65 -0
  475. package/dist/modules/staff/lib/timesheets-tasks/statusPositions.js.map +7 -0
  476. package/dist/modules/staff/lib/timesheets-tasks/statusSlug.js +31 -0
  477. package/dist/modules/staff/lib/timesheets-tasks/statusSlug.js.map +7 -0
  478. package/dist/modules/staff/lib/timesheets-tasks/taskHierarchy.js +31 -0
  479. package/dist/modules/staff/lib/timesheets-tasks/taskHierarchy.js.map +7 -0
  480. package/dist/modules/staff/lib/timesheets-tasks/taskHoursTotals.js +17 -0
  481. package/dist/modules/staff/lib/timesheets-tasks/taskHoursTotals.js.map +7 -0
  482. package/dist/modules/staff/lib/timesheets-tasks/taskReference.js +51 -0
  483. package/dist/modules/staff/lib/timesheets-tasks/taskReference.js.map +7 -0
  484. package/dist/modules/staff/lib/timesheets-ui/CreateProjectDialog.js +11 -4
  485. package/dist/modules/staff/lib/timesheets-ui/CreateProjectDialog.js.map +2 -2
  486. package/dist/modules/staff/lib/timesheets-ui/ListView.js +369 -111
  487. package/dist/modules/staff/lib/timesheets-ui/ListView.js.map +2 -2
  488. package/dist/modules/staff/lib/timesheets-ui/TimerBar.js +47 -2
  489. package/dist/modules/staff/lib/timesheets-ui/TimerBar.js.map +2 -2
  490. package/dist/modules/staff/migrations/Migration20260813073131_staff.js +79 -0
  491. package/dist/modules/staff/migrations/Migration20260813073131_staff.js.map +7 -0
  492. package/dist/modules/staff/migrations/Migration20260824143357_staff.js +15 -0
  493. package/dist/modules/staff/migrations/Migration20260824143357_staff.js.map +7 -0
  494. package/dist/modules/staff/notifications.client.js +16 -0
  495. package/dist/modules/staff/notifications.client.js.map +7 -0
  496. package/dist/modules/staff/notifications.handlers.js +80 -0
  497. package/dist/modules/staff/notifications.handlers.js.map +7 -0
  498. package/dist/modules/staff/notifications.js +168 -0
  499. package/dist/modules/staff/notifications.js.map +2 -2
  500. package/dist/modules/staff/search.js +159 -1
  501. package/dist/modules/staff/search.js.map +2 -2
  502. package/dist/modules/staff/setup.js +20 -1
  503. package/dist/modules/staff/setup.js.map +2 -2
  504. package/dist/modules/staff/subscribers/time-project-access-requested-notification.js +68 -0
  505. package/dist/modules/staff/subscribers/time-project-access-requested-notification.js.map +7 -0
  506. package/dist/modules/staff/subscribers/time-project-budget-threshold-notification.js +149 -0
  507. package/dist/modules/staff/subscribers/time-project-budget-threshold-notification.js.map +7 -0
  508. package/dist/modules/staff/subscribers/time-report-approved-notification.js +78 -0
  509. package/dist/modules/staff/subscribers/time-report-approved-notification.js.map +7 -0
  510. package/dist/modules/staff/subscribers/time-report-portal-broadcast.js +78 -0
  511. package/dist/modules/staff/subscribers/time-report-portal-broadcast.js.map +7 -0
  512. package/dist/modules/staff/translations.js +4 -1
  513. package/dist/modules/staff/translations.js.map +2 -2
  514. package/dist/modules/staff/widgets/components.js +7 -0
  515. package/dist/modules/staff/widgets/components.js.map +7 -0
  516. package/dist/modules/staff/widgets/injection/timer-sidebar-indicator/widget.js +5 -4
  517. package/dist/modules/staff/widgets/injection/timer-sidebar-indicator/widget.js.map +2 -2
  518. package/dist/modules/staff/widgets/notifications/TimeProjectAccessRequestedRenderer.js +135 -0
  519. package/dist/modules/staff/widgets/notifications/TimeProjectAccessRequestedRenderer.js.map +7 -0
  520. package/dist/modules/staff/widgets/notifications/index.js +5 -0
  521. package/dist/modules/staff/widgets/notifications/index.js.map +7 -0
  522. package/dist/modules/staff/workers/timesheets-reapply-rounding.js +43 -0
  523. package/dist/modules/staff/workers/timesheets-reapply-rounding.js.map +7 -0
  524. package/generated/entities/staff_time_entry/index.ts +7 -0
  525. package/generated/entities/staff_time_entry_tag/index.ts +6 -0
  526. package/generated/entities/staff_time_project/index.ts +8 -0
  527. package/generated/entities/staff_time_report/index.ts +27 -0
  528. package/generated/entities/staff_time_report_entry/index.ts +12 -0
  529. package/generated/entities/staff_time_report_event/index.ts +9 -0
  530. package/generated/entities/staff_time_report_project/index.ts +6 -0
  531. package/generated/entities/staff_time_tag/index.ts +9 -0
  532. package/generated/entities/staff_time_task/index.ts +17 -0
  533. package/generated/entities/staff_time_task_comment/index.ts +9 -0
  534. package/generated/entities/staff_time_task_status/index.ts +13 -0
  535. package/generated/entities/staff_time_task_tag/index.ts +6 -0
  536. package/generated/entities.ids.generated.ts +11 -1
  537. package/generated/entity-fields-registry.ts +149 -0
  538. package/package.json +7 -7
  539. package/src/helpers/integration/timesheetFixtures.ts +31 -1
  540. package/src/modules/auth/README.md +1 -1
  541. package/src/modules/auth/cli.ts +35 -1
  542. package/src/modules/auth/i18n/de.json +7 -0
  543. package/src/modules/auth/i18n/en.json +7 -0
  544. package/src/modules/auth/i18n/es.json +7 -0
  545. package/src/modules/auth/i18n/ko.json +7 -0
  546. package/src/modules/auth/i18n/pl.json +7 -0
  547. package/src/modules/auth/lib/backendChrome.tsx +1 -0
  548. package/src/modules/customer_accounts/lib/customerRoleAcls.ts +79 -0
  549. package/src/modules/customer_accounts/setup.ts +1 -45
  550. package/src/modules/data_sync/AGENTS.md +34 -0
  551. package/src/modules/data_sync/api/options.ts +2 -0
  552. package/src/modules/data_sync/backend/data-sync/page.tsx +82 -33
  553. package/src/modules/data_sync/i18n/de.json +1 -0
  554. package/src/modules/data_sync/i18n/en.json +1 -0
  555. package/src/modules/data_sync/i18n/es.json +1 -0
  556. package/src/modules/data_sync/i18n/ko.json +1 -0
  557. package/src/modules/data_sync/i18n/pl.json +1 -0
  558. package/src/modules/data_sync/lib/adapter.ts +45 -0
  559. package/src/modules/data_sync/lib/start-controls.ts +89 -0
  560. package/src/modules/staff/AGENTS.md +769 -1
  561. package/src/modules/staff/acl.ts +9 -0
  562. package/src/modules/staff/ai-agents.ts +189 -0
  563. package/src/modules/staff/ai-tools/time-tracking-pack.ts +494 -0
  564. package/src/modules/staff/ai-tools/types.ts +82 -0
  565. package/src/modules/staff/ai-tools.ts +13 -0
  566. package/src/modules/staff/analytics.ts +113 -0
  567. package/src/modules/staff/api/guards.ts +85 -3
  568. package/src/modules/staff/api/leave-requests/accept/route.ts +0 -2
  569. package/src/modules/staff/api/leave-requests/reject/route.ts +0 -2
  570. package/src/modules/staff/api/portal/time-reports/[id]/route.ts +182 -0
  571. package/src/modules/staff/api/portal/time-reports/route.ts +270 -0
  572. package/src/modules/staff/api/team-members/self/route.ts +0 -2
  573. package/src/modules/staff/api/team-members/tags/assign/route.ts +0 -2
  574. package/src/modules/staff/api/team-members/tags/unassign/route.ts +0 -2
  575. package/src/modules/staff/api/timesheets/_shared/withTimesheetInterceptors.ts +292 -0
  576. package/src/modules/staff/api/timesheets/access-requests/route.ts +299 -0
  577. package/src/modules/staff/api/timesheets/my-projects/[projectId]/route.ts +15 -7
  578. package/src/modules/staff/api/timesheets/my-projects/route.ts +14 -1
  579. package/src/modules/staff/api/timesheets/my-work/myWorkAggregate.ts +90 -0
  580. package/src/modules/staff/api/timesheets/my-work/route.ts +475 -0
  581. package/src/modules/staff/api/timesheets/projects/kpis/route.ts +15 -2
  582. package/src/modules/staff/api/timesheets/reports/[id]/close/route.ts +203 -0
  583. package/src/modules/staff/api/timesheets/reports/[id]/export/route.ts +315 -0
  584. package/src/modules/staff/api/timesheets/reports/[id]/sheet/route.ts +220 -0
  585. package/src/modules/staff/api/timesheets/reports/[id]/unlock/route.ts +208 -0
  586. package/src/modules/staff/api/timesheets/reports/preview/route.ts +449 -0
  587. package/src/modules/staff/api/timesheets/reports/route.ts +386 -0
  588. package/src/modules/staff/api/timesheets/reports/shared.ts +121 -0
  589. package/src/modules/staff/api/timesheets/settings/reapply-rounding/route.ts +205 -0
  590. package/src/modules/staff/api/timesheets/settings/rounding-impact/route.ts +226 -0
  591. package/src/modules/staff/api/timesheets/settings/route.ts +242 -0
  592. package/src/modules/staff/api/timesheets/tags/access.ts +134 -0
  593. package/src/modules/staff/api/timesheets/tags/entry-assignments/route.ts +290 -0
  594. package/src/modules/staff/api/timesheets/tags/route.ts +177 -0
  595. package/src/modules/staff/api/timesheets/tags/task-assignments/route.ts +294 -0
  596. package/src/modules/staff/api/timesheets/task-statuses/route.ts +232 -0
  597. package/src/modules/staff/api/timesheets/tasks/[id]/comments/route.ts +532 -0
  598. package/src/modules/staff/api/timesheets/tasks/[id]/status/route.ts +271 -0
  599. package/src/modules/staff/api/timesheets/tasks/route.ts +443 -0
  600. package/src/modules/staff/api/timesheets/time-entries/[id]/duplicate/route.ts +306 -0
  601. package/src/modules/staff/api/timesheets/time-entries/[id]/segments/[segmentId]/route.ts +32 -10
  602. package/src/modules/staff/api/timesheets/time-entries/[id]/segments/route.ts +32 -17
  603. package/src/modules/staff/api/timesheets/time-entries/[id]/timer-start/route.ts +27 -6
  604. package/src/modules/staff/api/timesheets/time-entries/[id]/timer-stop/route.ts +36 -6
  605. package/src/modules/staff/api/timesheets/time-entries/bulk/route.ts +331 -34
  606. package/src/modules/staff/api/timesheets/time-entries/copy-day/route.ts +533 -0
  607. package/src/modules/staff/api/timesheets/time-entries/overlaps/route.ts +457 -0
  608. package/src/modules/staff/api/timesheets/time-entries/route.ts +378 -24
  609. package/src/modules/staff/api/timesheets/time-entries/start-timer/route.ts +31 -9
  610. package/src/modules/staff/api/timesheets/time-projects/[id]/change-currency/route.ts +246 -0
  611. package/src/modules/staff/api/timesheets/time-projects/[id]/employees/route.ts +62 -2
  612. package/src/modules/staff/api/timesheets/time-projects/route.ts +397 -22
  613. package/src/modules/staff/backend/staff/time-tracking/board/page.meta.ts +14 -0
  614. package/src/modules/staff/backend/staff/time-tracking/board/page.tsx +151 -0
  615. package/src/modules/staff/backend/staff/time-tracking/entries/page.meta.ts +14 -0
  616. package/src/modules/staff/backend/staff/time-tracking/entries/page.tsx +1229 -0
  617. package/src/modules/staff/backend/staff/time-tracking/page.meta.ts +11 -0
  618. package/src/modules/staff/backend/staff/time-tracking/page.tsx +823 -0
  619. package/src/modules/staff/backend/staff/time-tracking/projects/[id]/board/page.meta.ts +12 -0
  620. package/src/modules/staff/backend/staff/time-tracking/projects/[id]/board/page.tsx +81 -0
  621. package/src/modules/staff/backend/staff/time-tracking/projects/[id]/edit/page.meta.ts +12 -0
  622. package/src/modules/staff/backend/staff/time-tracking/projects/[id]/edit/page.tsx +275 -0
  623. package/src/modules/staff/backend/staff/time-tracking/projects/[id]/page.meta.ts +12 -0
  624. package/src/modules/staff/backend/staff/time-tracking/projects/[id]/page.tsx +1420 -0
  625. package/src/modules/staff/backend/staff/time-tracking/projects/create/page.meta.ts +12 -0
  626. package/src/modules/staff/backend/staff/time-tracking/projects/create/page.tsx +109 -0
  627. package/src/modules/staff/backend/staff/time-tracking/projects/page.meta.ts +15 -0
  628. package/src/modules/staff/backend/staff/time-tracking/projects/page.tsx +1254 -0
  629. package/src/modules/staff/backend/staff/time-tracking/projects/projectFormConfig.ts +466 -0
  630. package/src/modules/staff/backend/staff/time-tracking/reports/[id]/page.meta.ts +12 -0
  631. package/src/modules/staff/backend/staff/time-tracking/reports/[id]/page.tsx +632 -0
  632. package/src/modules/staff/backend/staff/time-tracking/reports/create/page.meta.ts +12 -0
  633. package/src/modules/staff/backend/staff/time-tracking/reports/create/page.tsx +867 -0
  634. package/src/modules/staff/backend/staff/time-tracking/reports/page.meta.ts +14 -0
  635. package/src/modules/staff/backend/staff/time-tracking/reports/page.tsx +246 -0
  636. package/src/modules/staff/backend/staff/time-tracking/settings/page.meta.ts +14 -0
  637. package/src/modules/staff/backend/staff/time-tracking/settings/page.tsx +701 -0
  638. package/src/modules/staff/backend/staff/time-tracking/timesheet/GridView.tsx +953 -0
  639. package/src/modules/staff/backend/staff/time-tracking/timesheet/page.meta.ts +14 -0
  640. package/src/modules/staff/backend/staff/time-tracking/timesheet/page.tsx +800 -0
  641. package/src/modules/staff/backend/staff/timesheets/page.meta.ts +6 -6
  642. package/src/modules/staff/backend/staff/timesheets/page.tsx +12 -1010
  643. package/src/modules/staff/backend/staff/timesheets/projects/[id]/edit/page.meta.ts +0 -6
  644. package/src/modules/staff/backend/staff/timesheets/projects/[id]/edit/page.tsx +4 -158
  645. package/src/modules/staff/backend/staff/timesheets/projects/[id]/page.meta.ts +0 -6
  646. package/src/modules/staff/backend/staff/timesheets/projects/[id]/page.tsx +4 -609
  647. package/src/modules/staff/backend/staff/timesheets/projects/create/page.meta.ts +0 -6
  648. package/src/modules/staff/backend/staff/timesheets/projects/create/page.tsx +3 -89
  649. package/src/modules/staff/backend/staff/timesheets/projects/page.meta.ts +2 -19
  650. package/src/modules/staff/backend/staff/timesheets/projects/page.tsx +3 -778
  651. package/src/modules/staff/ce.ts +63 -0
  652. package/src/modules/staff/cli.ts +207 -1
  653. package/src/modules/staff/commands/index.ts +5 -0
  654. package/src/modules/staff/commands/timesheets-entries.ts +1006 -28
  655. package/src/modules/staff/commands/timesheets-projects.ts +593 -7
  656. package/src/modules/staff/commands/timesheets-reports.ts +1329 -0
  657. package/src/modules/staff/commands/timesheets-tags.ts +1315 -0
  658. package/src/modules/staff/commands/timesheets-task-comments.ts +583 -0
  659. package/src/modules/staff/commands/timesheets-task-statuses.ts +889 -0
  660. package/src/modules/staff/commands/timesheets-tasks.ts +1121 -0
  661. package/src/modules/staff/data/enrichers.ts +675 -10
  662. package/src/modules/staff/data/entities.ts +494 -2
  663. package/src/modules/staff/data/extensions.ts +68 -0
  664. package/src/modules/staff/data/validators.ts +348 -3
  665. package/src/modules/staff/di.ts +96 -0
  666. package/src/modules/staff/events.payloads.ts +268 -0
  667. package/src/modules/staff/events.ts +87 -5
  668. package/src/modules/staff/extension-points.ts +308 -0
  669. package/src/modules/staff/frontend/[orgSlug]/portal/time-reports/[id]/page.meta.ts +10 -0
  670. package/src/modules/staff/frontend/[orgSlug]/portal/time-reports/[id]/page.tsx +225 -0
  671. package/src/modules/staff/frontend/[orgSlug]/portal/time-reports/page.meta.ts +17 -0
  672. package/src/modules/staff/frontend/[orgSlug]/portal/time-reports/page.tsx +182 -0
  673. package/src/modules/staff/i18n/de.json +899 -0
  674. package/src/modules/staff/i18n/en.json +899 -0
  675. package/src/modules/staff/i18n/es.json +899 -0
  676. package/src/modules/staff/i18n/ko.json +899 -0
  677. package/src/modules/staff/i18n/pl.json +899 -0
  678. package/src/modules/staff/lib/crud.ts +14 -3
  679. package/src/modules/staff/lib/time-tracking/access.ts +155 -0
  680. package/src/modules/staff/lib/time-tracking/billability.ts +68 -0
  681. package/src/modules/staff/lib/time-tracking/capacity.ts +124 -0
  682. package/src/modules/staff/lib/time-tracking/componentContracts.ts +26 -0
  683. package/src/modules/staff/lib/time-tracking/cost.ts +144 -0
  684. package/src/modules/staff/lib/time-tracking/duration.ts +68 -0
  685. package/src/modules/staff/lib/time-tracking/featureAccess.ts +115 -0
  686. package/src/modules/staff/lib/time-tracking/interval.ts +90 -0
  687. package/src/modules/staff/lib/time-tracking/migrateProjectCodes.ts +161 -0
  688. package/src/modules/staff/lib/time-tracking/moneyVisibility.ts +37 -0
  689. package/src/modules/staff/lib/time-tracking/overlap.ts +159 -0
  690. package/src/modules/staff/lib/time-tracking/portalRecipients.ts +76 -0
  691. package/src/modules/staff/lib/time-tracking/portalReports.ts +31 -0
  692. package/src/modules/staff/lib/time-tracking/projectCode.ts +221 -0
  693. package/src/modules/staff/lib/time-tracking/reapplyRounding.ts +313 -0
  694. package/src/modules/staff/lib/time-tracking/recalculationRunner.ts +118 -0
  695. package/src/modules/staff/lib/time-tracking/recalculations.ts +135 -0
  696. package/src/modules/staff/lib/time-tracking/registries/invoke.ts +122 -0
  697. package/src/modules/staff/lib/time-tracking/registries/registry.ts +124 -0
  698. package/src/modules/staff/lib/time-tracking/registries/scope.ts +56 -0
  699. package/src/modules/staff/lib/time-tracking/rollup.ts +59 -0
  700. package/src/modules/staff/lib/time-tracking/rounding.ts +126 -0
  701. package/src/modules/staff/lib/time-tracking/roundingImpact.ts +75 -0
  702. package/src/modules/staff/lib/time-tracking/settingKeys.ts +274 -0
  703. package/src/modules/staff/lib/time-tracking/settings.ts +168 -0
  704. package/src/modules/staff/lib/time-tracking/sqlInClause.ts +22 -0
  705. package/src/modules/staff/lib/time-tracking/timeEntrySources.ts +85 -0
  706. package/src/modules/staff/lib/time-tracking-ui/BoardFilterChips.tsx +360 -0
  707. package/src/modules/staff/lib/time-tracking-ui/CustomerPicker.tsx +427 -0
  708. package/src/modules/staff/lib/time-tracking-ui/DurationInput.tsx +192 -0
  709. package/src/modules/staff/lib/time-tracking-ui/EntryDetailsFields.tsx +224 -0
  710. package/src/modules/staff/lib/time-tracking-ui/EntryFilterBar.tsx +144 -0
  711. package/src/modules/staff/lib/time-tracking-ui/KanbanBoard.tsx +1065 -0
  712. package/src/modules/staff/lib/time-tracking-ui/KanbanCard.tsx +435 -0
  713. package/src/modules/staff/lib/time-tracking-ui/KanbanColumn.tsx +316 -0
  714. package/src/modules/staff/lib/time-tracking-ui/NewTaskDialog.tsx +291 -0
  715. package/src/modules/staff/lib/time-tracking-ui/NoProjectAccess.tsx +162 -0
  716. package/src/modules/staff/lib/time-tracking-ui/PeriodSelector.tsx +149 -0
  717. package/src/modules/staff/lib/time-tracking-ui/PhasePlaceholder.tsx +31 -0
  718. package/src/modules/staff/lib/time-tracking-ui/ProjectCodeField.tsx +230 -0
  719. package/src/modules/staff/lib/time-tracking-ui/ProjectCurrencyField.tsx +432 -0
  720. package/src/modules/staff/lib/time-tracking-ui/ProjectFormSections.tsx +323 -0
  721. package/src/modules/staff/lib/time-tracking-ui/ProjectTeamDrawer.tsx +930 -0
  722. package/src/modules/staff/lib/time-tracking-ui/ReportSheet.tsx +357 -0
  723. package/src/modules/staff/lib/time-tracking-ui/TagPicker.tsx +195 -0
  724. package/src/modules/staff/lib/time-tracking-ui/TaskBoardScreen.tsx +243 -0
  725. package/src/modules/staff/lib/time-tracking-ui/TaskCommentThread.tsx +137 -0
  726. package/src/modules/staff/lib/time-tracking-ui/TaskDrawer.tsx +1405 -0
  727. package/src/modules/staff/lib/time-tracking-ui/TaskListView.tsx +260 -0
  728. package/src/modules/staff/lib/time-tracking-ui/TaskPicker.tsx +435 -0
  729. package/src/modules/staff/lib/time-tracking-ui/TaskQuickLog.tsx +296 -0
  730. package/src/modules/staff/lib/time-tracking-ui/TimeEntriesSummaryFooter.tsx +97 -0
  731. package/src/modules/staff/lib/time-tracking-ui/TimeEntryDialog.tsx +1929 -0
  732. package/src/modules/staff/lib/time-tracking-ui/TimeEntryDurationCell.tsx +126 -0
  733. package/src/modules/staff/lib/time-tracking-ui/TimesheetCalendar.tsx +265 -0
  734. package/src/modules/staff/lib/time-tracking-ui/TimesheetPeriodFooter.tsx +78 -0
  735. package/src/modules/staff/lib/time-tracking-ui/TimesheetViewSwitch.tsx +70 -0
  736. package/src/modules/staff/lib/time-tracking-ui/boardDirectory.ts +231 -0
  737. package/src/modules/staff/lib/time-tracking-ui/boardFilters.ts +128 -0
  738. package/src/modules/staff/lib/time-tracking-ui/boardSummary.ts +20 -0
  739. package/src/modules/staff/lib/time-tracking-ui/kanbanBoardData.ts +228 -0
  740. package/src/modules/staff/lib/time-tracking-ui/projectTeamAssignment.ts +143 -0
  741. package/src/modules/staff/lib/time-tracking-ui/taskDrawerData.ts +194 -0
  742. package/src/modules/staff/lib/time-tracking-ui/timeEntryDialogState.ts +400 -0
  743. package/src/modules/staff/lib/time-tracking-ui/timeEntryListData.ts +271 -0
  744. package/src/modules/staff/lib/time-tracking-ui/timeTrackingSettingsForm.ts +168 -0
  745. package/src/modules/staff/lib/time-tracking-ui/timesheetData.ts +225 -0
  746. package/src/modules/staff/lib/time-tracking-ui/timesheetPeriod.ts +278 -0
  747. package/src/modules/staff/lib/time-tracking-ui/timesheetTargets.ts +93 -0
  748. package/src/modules/staff/lib/time-tracking-ui/useBoardFilters.ts +107 -0
  749. package/src/modules/staff/lib/time-tracking-ui/useTimesheetPreferences.ts +245 -0
  750. package/src/modules/staff/lib/timeTrackingSeeds.ts +1037 -0
  751. package/src/modules/staff/lib/timesheets/timeEntryCacheInvalidation.ts +11 -10
  752. package/src/modules/staff/lib/timesheets/timeEntryDecoration.ts +256 -0
  753. package/src/modules/staff/lib/timesheets-projects/budgetBurn.ts +60 -0
  754. package/src/modules/staff/lib/timesheets-projects/budgetThreshold.ts +135 -0
  755. package/src/modules/staff/lib/timesheets-projects/budgetThresholdState.ts +137 -0
  756. package/src/modules/staff/lib/timesheets-projects/computeProjectFinancials.ts +142 -0
  757. package/src/modules/staff/lib/timesheets-projects/reportSelection.ts +82 -0
  758. package/src/modules/staff/lib/timesheets-projects-ui/AssignMembersDialog.tsx +237 -0
  759. package/src/modules/staff/lib/timesheets-projects-ui/ProjectBudgetCell.tsx +33 -0
  760. package/src/modules/staff/lib/timesheets-projects-ui/ProjectCard.tsx +56 -1
  761. package/src/modules/staff/lib/timesheets-projects-ui/ProjectsBulkActionsBar.tsx +90 -0
  762. package/src/modules/staff/lib/timesheets-reports/buildReportSheet.ts +125 -0
  763. package/src/modules/staff/lib/timesheets-reports/loadReportData.ts +251 -0
  764. package/src/modules/staff/lib/timesheets-reports/pdf.ts +263 -0
  765. package/src/modules/staff/lib/timesheets-reports/reportApprovalPolicies.ts +137 -0
  766. package/src/modules/staff/lib/timesheets-reports/reportConfigData.ts +247 -0
  767. package/src/modules/staff/lib/timesheets-reports/reportConfigState.ts +89 -0
  768. package/src/modules/staff/lib/timesheets-reports/reportExport.ts +373 -0
  769. package/src/modules/staff/lib/timesheets-reports/reportExportFormats.ts +71 -0
  770. package/src/modules/staff/lib/timesheets-reports/reportGroupings.ts +153 -0
  771. package/src/modules/staff/lib/timesheets-reports/reportLabels.ts +23 -0
  772. package/src/modules/staff/lib/timesheets-reports/reportReference.ts +146 -0
  773. package/src/modules/staff/lib/timesheets-reports/reportRows.ts +89 -0
  774. package/src/modules/staff/lib/timesheets-reports/reportSheetData.ts +196 -0
  775. package/src/modules/staff/lib/timesheets-reports/reportTotals.ts +544 -0
  776. package/src/modules/staff/lib/timesheets-reports/xlsx.ts +207 -0
  777. package/src/modules/staff/lib/timesheets-tasks/computeTaskRollups.ts +238 -0
  778. package/src/modules/staff/lib/timesheets-tasks/defaultStatusTemplate.ts +90 -0
  779. package/src/modules/staff/lib/timesheets-tasks/seedProjectStatuses.ts +43 -0
  780. package/src/modules/staff/lib/timesheets-tasks/statusPositions.ts +132 -0
  781. package/src/modules/staff/lib/timesheets-tasks/statusSlug.ts +43 -0
  782. package/src/modules/staff/lib/timesheets-tasks/taskHierarchy.ts +99 -0
  783. package/src/modules/staff/lib/timesheets-tasks/taskHoursTotals.ts +42 -0
  784. package/src/modules/staff/lib/timesheets-tasks/taskReference.ts +108 -0
  785. package/src/modules/staff/lib/timesheets-ui/CreateProjectDialog.tsx +18 -4
  786. package/src/modules/staff/lib/timesheets-ui/ListView.tsx +504 -149
  787. package/src/modules/staff/lib/timesheets-ui/TimerBar.tsx +50 -2
  788. package/src/modules/staff/migrations/.snapshot-open-mercato.json +3244 -228
  789. package/src/modules/staff/migrations/Migration20260813073131_staff.ts +94 -0
  790. package/src/modules/staff/migrations/Migration20260824143357_staff.ts +17 -0
  791. package/src/modules/staff/notifications.client.ts +16 -0
  792. package/src/modules/staff/notifications.handlers.ts +88 -0
  793. package/src/modules/staff/notifications.ts +163 -0
  794. package/src/modules/staff/search.ts +191 -1
  795. package/src/modules/staff/setup.ts +22 -0
  796. package/src/modules/staff/subscribers/time-project-access-requested-notification.ts +95 -0
  797. package/src/modules/staff/subscribers/time-project-budget-threshold-notification.ts +226 -0
  798. package/src/modules/staff/subscribers/time-report-approved-notification.ts +116 -0
  799. package/src/modules/staff/subscribers/time-report-portal-broadcast.ts +120 -0
  800. package/src/modules/staff/translations.ts +17 -0
  801. package/src/modules/staff/widgets/components.ts +34 -0
  802. package/src/modules/staff/widgets/injection/timer-sidebar-indicator/widget.tsx +6 -5
  803. package/src/modules/staff/widgets/notifications/TimeProjectAccessRequestedRenderer.tsx +138 -0
  804. package/src/modules/staff/widgets/notifications/index.ts +1 -0
  805. package/src/modules/staff/workers/timesheets-reapply-rounding.ts +59 -0
  806. package/dist/modules/staff/backend/staff/timesheets/projects/projectFormConfig.js +0 -123
  807. package/dist/modules/staff/backend/staff/timesheets/projects/projectFormConfig.js.map +0 -7
  808. package/src/modules/staff/backend/staff/timesheets/projects/projectFormConfig.ts +0 -138
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../src/modules/staff/lib/time-tracking-ui/TaskDrawer.tsx"],
4
+ "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { useRouter } from 'next/navigation'\nimport { useQuery, useQueryClient } from '@tanstack/react-query'\nimport { Plus, X } from 'lucide-react'\nimport {\n Drawer,\n DrawerBody,\n DrawerContent,\n DrawerDescription,\n DrawerFooter,\n DrawerHeader,\n DrawerTitle,\n} from '@open-mercato/ui/primitives/drawer'\nimport { Avatar } from '@open-mercato/ui/primitives/avatar'\nimport { Badge } from '@open-mercato/ui/primitives/badge'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { Checkbox } from '@open-mercato/ui/primitives/checkbox'\nimport { Input } from '@open-mercato/ui/primitives/input'\nimport { Progress } from '@open-mercato/ui/primitives/progress'\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '@open-mercato/ui/primitives/select'\nimport { ErrorMessage, LoadingMessage } from '@open-mercato/ui/backend/detail'\nimport { apiCall, apiCallOrThrow, withScopedApiRequestHeaders } from '@open-mercato/ui/backend/utils/apiCall'\nimport { buildOptimisticLockHeader } from '@open-mercato/ui/backend/utils/optimisticLock'\nimport { surfaceRecordConflict } from '@open-mercato/ui/backend/conflicts'\nimport { useBackendChrome } from '@open-mercato/ui/backend/BackendChromeProvider'\nimport { useConfirmDialog } from '@open-mercato/ui/backend/confirm-dialog'\nimport { useGuardedMutation } from '@open-mercato/ui/backend/injection/useGuardedMutation'\nimport { InjectionSpot } from '@open-mercato/ui/backend/injection/InjectionSpot'\nimport { extensionPoints } from '@open-mercato/core/modules/staff/extension-points'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { formatCurrency, formatDate } from '@open-mercato/ui/utils/format'\nimport { hasFeature } from '@open-mercato/shared/security/features'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { useOrganizationScopeVersion } from '@open-mercato/shared/lib/frontend/useOrganizationScope'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\nimport { TaskCommentThread } from './TaskCommentThread'\nimport { TaskQuickLog, type QuickLogSubmission } from './TaskQuickLog'\nimport { TagPicker, tagChipStyle } from './TagPicker'\nimport { slugifyProjectName } from '../time-tracking/projectCode'\nimport type { TagOption } from './timeEntryDialogState'\nimport {\n computeSubtaskProgress,\n formatBoardMinutes,\n readItems,\n readString,\n readTotal,\n sortByPosition,\n toBoardStatus,\n toBoardTask,\n type BoardApiRow,\n type BoardStatus,\n type BoardTask,\n} from './kanbanBoardData'\nimport {\n childMinutes,\n formatElapsed,\n formatSplitMinutes,\n resolveDefaultStatusId,\n resolveDoneStatusId,\n summarizeEntries,\n toDrawerComment,\n toDrawerEntry,\n todayIsoDate,\n buildEntryClocks,\n type DrawerComment,\n type DrawerEntry,\n} from './taskDrawerData'\n\nconst logger = createLogger('staff').child({ component: 'TaskDrawer' })\n\nconst TASK_ENTITY_ID = 'staff:staff_time_task'\n\ntype TaskDetailInjectionContext = {\n entityId: string\n recordId: string\n taskId: string\n timeProjectId: string | null\n retryLastMutation: () => Promise<boolean>\n}\n\nexport const TASK_DRAWER_MUTATION_CONTEXT_ID = 'staff.time_tracking.task_drawer'\nexport const RATES_FEATURE = 'staff.timesheets.rates.view'\nexport const TASKS_MANAGE_FEATURE = 'staff.timesheets.tasks.manage'\nexport const ENTRIES_LIST_PATH = '/backend/staff/time-tracking/entries'\n\nconst DRAWER_QUERY_ROOT = ['staff', 'time-tracking', 'task-drawer'] as const\nconst DIRECTORY_PAGE_SIZE = 100\nconst CHILD_PAGE_SIZE = 100\nconst COMMENT_PAGE_SIZE = 50\nconst ENTRY_PAGE_SIZE = 100\n/** Bounded sweep: the entries route has no `taskId` filter (see the docblock). */\nconst MAX_ENTRY_PAGES = 3\nconst RECENT_ENTRY_COUNT = 5\nconst ELAPSED_TICK_MS = 1000\n\nexport type TaskDrawerProps = {\n taskId: string\n open: boolean\n onOpenChange: (open: boolean) => void\n /** Shown in the header line next to the created date; the host already knows it. */\n projectName?: string | null\n /** `?panel=time` \u2014 \"Add time\" on a board card lands with the quick log focused. */\n focusPanel?: string | null\n /** Lets the host (the board) refetch after a write that changed hours or status. */\n onChanged?: () => void\n}\n\ntype LoadedTask = { task: BoardTask; createdAt: string | null }\n\ntype RunningTimer = { entryId: string | null; taskId: string | null; startedAt: string | null }\n\ntype ProjectEntries = { rows: BoardApiRow[]; partial: boolean }\n\nasync function fetchProjectEntries(projectId: string): Promise<ProjectEntries> {\n const rows: BoardApiRow[] = []\n for (let page = 1; page <= MAX_ENTRY_PAGES; page += 1) {\n const call = await apiCall<Record<string, unknown>>(\n `/api/staff/timesheets/time-entries?projectId=${encodeURIComponent(projectId)}&page=${page}&pageSize=${ENTRY_PAGE_SIZE}&sortField=date&sortDir=desc`,\n )\n if (!call.ok) return { rows, partial: true }\n const items = readItems(call.result)\n rows.push(...items)\n if (items.length < ENTRY_PAGE_SIZE) return { rows, partial: false }\n if (rows.length >= readTotal(call.result, rows.length)) return { rows, partial: false }\n }\n return { rows, partial: true }\n}\n\n/**\n * The task drawer of screen 7 (T3.7, US-C3/C4/C5, US-D4).\n *\n * Four decisions carry the design intent:\n *\n * 1. **Subtasks are child tasks, and ticking one is a status move** (D-2, and\n * the decision that supersedes the mockup's note 4). There is no boolean on\n * a task, so the checkbox PATCHes the child to the project's first `is_done`\n * column and un-ticking returns it to the `is_default` one. Each row carries\n * its own assignee and its own hours because a subtask holds time like any\n * other task; the parent's headline is the inclusive rollup that already\n * contains them.\n * 2. **Depth is capped at one.** A child task's drawer renders no subtask\n * section at all: the server answers `400 subtask_depth_exceeded`, so an\n * \"add subtask\" affordance there could only ever fail.\n * 3. **Properties save per field, so each write carries its own version.** A\n * blur PATCHes with `buildOptimisticLockHeader(versionRef.current)` and then refreshes\n * the token \u2014 from the status route's `updatedAt` when it returns one, by\n * refetching the row when it does not (the CRUD update answers `{ok:true}`).\n * Saves are chained on `saveChainRef` so the second field never leaves with\n * the version the first one just invalidated.\n * 4. **One timer at a time** (note 2, US-D4). Starting here while a timer runs\n * on another task asks first, then stops that one before starting this one.\n *\n * Two known gaps, both other tasks' work, are handled honestly rather than faked:\n * the task projection carries no tag ids yet (T3.10), so the tag row can add but\n * cannot list what the server already has; and the entries route has no `taskId`\n * filter, so the recent-entries list and the billable split come from a bounded\n * sweep of the project's entries and say so when the bound is hit.\n */\nexport function TaskDrawer({\n taskId,\n open,\n onOpenChange,\n projectName,\n focusPanel,\n onChanged,\n}: TaskDrawerProps) {\n const t = useT()\n const router = useRouter()\n const queryClient = useQueryClient()\n const scopeVersion = useOrganizationScopeVersion()\n const { payload } = useBackendChrome()\n const { confirm, ConfirmDialogElement } = useConfirmDialog()\n\n const canSeeMoney = hasFeature(payload?.grantedFeatures, RATES_FEATURE)\n const canManage = hasFeature(payload?.grantedFeatures, TASKS_MANAGE_FEATURE)\n\n const [tagIds, setTagIds] = React.useState<string[]>([])\n const [subtaskDraft, setSubtaskDraft] = React.useState('')\n const [composingSubtask, setComposingSubtask] = React.useState(false)\n const [busy, setBusy] = React.useState(false)\n const [timerBusy, setTimerBusy] = React.useState(false)\n const [now, setNow] = React.useState(() => Date.now())\n\n const saveChainRef = React.useRef<Promise<void>>(Promise.resolve())\n /**\n * The lock token lives in a ref, not in state: a save queued behind another one\n * must read the version at the moment it *runs*, not the one its closure was\n * built with, or a second blur landing before a re-render would still leave\n * with the token the first blur just invalidated.\n */\n const versionRef = React.useRef<string | null>(null)\n\n const { runMutation, retryLastMutation } = useGuardedMutation<{\n formId: string\n resourceKind: string\n resourceId: string\n retryLastMutation: () => Promise<boolean>\n }>({\n contextId: TASK_DRAWER_MUTATION_CONTEXT_ID,\n blockedMessage: t('staff.time_tracking.taskDrawer.properties.saveError', 'Could not save the change.'),\n })\n\n const taskQuery = useQuery<LoadedTask | null>({\n queryKey: [...DRAWER_QUERY_ROOT, 'task', `scope:${scopeVersion}`, taskId],\n enabled: open && taskId.length > 0,\n staleTime: 5_000,\n queryFn: async () => {\n const call = await apiCall<Record<string, unknown>>(\n `/api/staff/timesheets/tasks?id=${encodeURIComponent(taskId)}&pageSize=1`,\n )\n if (!call.ok) throw new Error('[internal] task request failed')\n const row = readItems(call.result)[0]\n if (!row) return null\n const parsed = toBoardTask(row)\n return parsed ? { task: parsed, createdAt: readString(row, 'created_at', 'createdAt') } : null\n },\n })\n\n const task = taskQuery.data?.task ?? null\n const createdAt = taskQuery.data?.createdAt ?? null\n const projectId = task?.timeProjectId ?? null\n\n const taskInjectionContext = React.useMemo<TaskDetailInjectionContext>(\n () => ({\n entityId: TASK_ENTITY_ID,\n recordId: taskId,\n taskId,\n timeProjectId: projectId,\n retryLastMutation,\n }),\n [projectId, retryLastMutation, taskId],\n )\n const isChildTask = !!task?.parentTaskId\n\n React.useEffect(() => {\n if (!task) return\n versionRef.current = task.updatedAt\n setTagIds(task.tagIds)\n }, [task])\n\n const statusesQuery = useQuery<BoardStatus[]>({\n queryKey: [...DRAWER_QUERY_ROOT, 'statuses', `scope:${scopeVersion}`, projectId ?? 'none'],\n enabled: open && !!projectId,\n staleTime: 30_000,\n queryFn: async () => {\n if (!projectId) return []\n const call = await apiCall<Record<string, unknown>>(\n `/api/staff/timesheets/task-statuses?timeProjectId=${encodeURIComponent(projectId)}&page=1&pageSize=${DIRECTORY_PAGE_SIZE}&sortField=position&sortDir=asc`,\n )\n if (!call.ok) return []\n const statuses = readItems(call.result)\n .map(toBoardStatus)\n .filter((status): status is BoardStatus => status !== null)\n return sortByPosition(statuses)\n },\n })\n\n const statuses = React.useMemo(() => statusesQuery.data ?? [], [statusesQuery.data])\n\n const childrenQuery = useQuery<BoardTask[]>({\n queryKey: [...DRAWER_QUERY_ROOT, 'children', `scope:${scopeVersion}`, taskId],\n enabled: open && !isChildTask && !!task,\n staleTime: 10_000,\n queryFn: async () => {\n const call = await apiCall<Record<string, unknown>>(\n `/api/staff/timesheets/tasks?parentTaskId=${encodeURIComponent(taskId)}&page=1&pageSize=${CHILD_PAGE_SIZE}&sortField=position&sortDir=asc`,\n )\n if (!call.ok) return []\n const rows = readItems(call.result)\n .map(toBoardTask)\n .filter((row): row is BoardTask => row !== null)\n return sortByPosition(rows)\n },\n })\n\n const children = React.useMemo(() => childrenQuery.data ?? [], [childrenQuery.data])\n\n const commentsQuery = useQuery<DrawerComment[]>({\n queryKey: [...DRAWER_QUERY_ROOT, 'comments', `scope:${scopeVersion}`, taskId],\n enabled: open && taskId.length > 0,\n staleTime: 10_000,\n queryFn: async () => {\n const call = await apiCall<Record<string, unknown>>(\n `/api/staff/timesheets/tasks/${encodeURIComponent(taskId)}/comments?page=1&pageSize=${COMMENT_PAGE_SIZE}`,\n )\n if (!call.ok) throw new Error('[internal] comments request failed')\n return readItems(call.result)\n .map(toDrawerComment)\n .filter((comment): comment is DrawerComment => comment !== null)\n },\n })\n\n const entriesQuery = useQuery<ProjectEntries>({\n queryKey: [...DRAWER_QUERY_ROOT, 'entries', `scope:${scopeVersion}`, projectId ?? 'none'],\n enabled: open && !!projectId,\n staleTime: 10_000,\n queryFn: async () => (projectId ? fetchProjectEntries(projectId) : { rows: [], partial: false }),\n })\n\n const selfQuery = useQuery<string | null>({\n queryKey: [...DRAWER_QUERY_ROOT, 'self', `scope:${scopeVersion}`],\n enabled: open,\n staleTime: 300_000,\n queryFn: async () => {\n const call = await apiCall<{ member?: { id?: string | null } | null }>('/api/staff/team-members/self')\n return call.ok ? call.result?.member?.id ?? null : null\n },\n })\n\n const selfStaffMemberId = selfQuery.data ?? null\n\n const membersQuery = useQuery<{ id: string; name: string }[]>({\n queryKey: [...DRAWER_QUERY_ROOT, 'members', `scope:${scopeVersion}`],\n enabled: open,\n staleTime: 300_000,\n queryFn: async () => {\n const call = await apiCall<Record<string, unknown>>(\n `/api/staff/team-members?page=1&pageSize=${DIRECTORY_PAGE_SIZE}&isActive=true`,\n )\n if (!call.ok) return []\n return readItems(call.result)\n .map((row) => {\n const id = readString(row, 'id')\n if (!id) return null\n return { id, name: readString(row, 'display_name', 'displayName') ?? id }\n })\n .filter((member): member is { id: string; name: string } => member !== null)\n },\n })\n\n const members = React.useMemo(() => membersQuery.data ?? [], [membersQuery.data])\n\n const memberNames = React.useMemo(() => {\n const map = new Map<string, string>()\n for (const member of members) map.set(member.id, member.name)\n return map\n }, [members])\n\n const tagsQuery = useQuery<TagOption[]>({\n queryKey: [...DRAWER_QUERY_ROOT, 'tags', `scope:${scopeVersion}`],\n enabled: open,\n staleTime: 300_000,\n queryFn: async () => {\n const call = await apiCall<Record<string, unknown>>(\n `/api/staff/timesheets/tags?page=1&pageSize=${DIRECTORY_PAGE_SIZE}&sortField=label&sortDir=asc`,\n )\n if (!call.ok) return []\n return readItems(call.result)\n .map((row) => {\n const id = readString(row, 'id')\n if (!id) return null\n // The colour has to travel with the tag or the drawer's chips render\n // grey while the entry dialog's render tinted from the same rows.\n return { id, label: readString(row, 'label') ?? id, color: readString(row, 'color') }\n })\n .filter((tag): tag is TagOption => tag !== null)\n },\n })\n\n const tagOptions = React.useMemo(() => tagsQuery.data ?? [], [tagsQuery.data])\n\n const runningTimerQuery = useQuery<RunningTimer>({\n queryKey: [...DRAWER_QUERY_ROOT, 'running-timer', `scope:${scopeVersion}`, selfStaffMemberId ?? 'none'],\n enabled: open && !!selfStaffMemberId,\n staleTime: 15_000,\n refetchInterval: 30_000,\n queryFn: async () => {\n if (!selfStaffMemberId) return { entryId: null, taskId: null, startedAt: null }\n const call = await apiCall<Record<string, unknown>>(\n `/api/staff/timesheets/time-entries?staffMemberId=${encodeURIComponent(selfStaffMemberId)}&running=true&pageSize=${ENTRY_PAGE_SIZE}`,\n )\n if (!call.ok) return { entryId: null, taskId: null, startedAt: null }\n for (const row of readItems(call.result)) {\n const startedAt = readString(row, 'started_at', 'startedAt')\n const endedAt = readString(row, 'ended_at', 'endedAt')\n if (!startedAt || endedAt) continue\n return {\n entryId: readString(row, 'id'),\n taskId: readString(row, 'task_id', 'taskId'),\n startedAt,\n }\n }\n return { entryId: null, taskId: null, startedAt: null }\n },\n })\n\n const runningTimer = runningTimerQuery.data ?? { entryId: null, taskId: null, startedAt: null }\n const timerRunningHere = !!runningTimer.entryId && runningTimer.taskId === taskId\n\n React.useEffect(() => {\n if (!open || !timerRunningHere) return\n const handle = setInterval(() => setNow(Date.now()), ELAPSED_TICK_MS)\n return () => clearInterval(handle)\n }, [open, timerRunningHere])\n\n const doneStatusIds = React.useMemo(\n () => new Set(statuses.filter((status) => status.isDone).map((status) => status.id)),\n [statuses],\n )\n\n // `doneChildCount` does not exist on the API yet, so the drawer derives it the\n // way the board does \u2014 from the children it already fetched for the list. One\n // extra page of rows per open, no extra request.\n const progress = React.useMemo(\n () => computeSubtaskProgress(children, doneStatusIds).get(taskId) ?? { total: 0, done: 0 },\n [children, doneStatusIds, taskId],\n )\n\n const subtaskTotal = Math.max(progress.total, task?.childCount ?? 0)\n\n const taskIdsForEntries = React.useMemo(() => {\n const ids = new Set<string>([taskId])\n for (const child of children) ids.add(child.id)\n return ids\n }, [children, taskId])\n\n const entries = React.useMemo<DrawerEntry[]>(() => {\n const rows = entriesQuery.data?.rows ?? []\n return rows\n .map(toDrawerEntry)\n .filter((entry): entry is DrawerEntry => entry !== null && !!entry.taskId && taskIdsForEntries.has(entry.taskId))\n }, [entriesQuery.data, taskIdsForEntries])\n\n const totals = React.useMemo(\n () => summarizeEntries(entries, entriesQuery.data?.partial ?? false),\n [entries, entriesQuery.data],\n )\n\n const invalidate = React.useCallback(\n (part: 'task' | 'children' | 'entries' | 'comments') => {\n queryClient.invalidateQueries({ queryKey: [...DRAWER_QUERY_ROOT, part] }).catch(() => {})\n },\n [queryClient],\n )\n\n const refreshVersion = React.useCallback(async (): Promise<void> => {\n const refreshed = await taskQuery.refetch()\n const updatedAt = refreshed.data?.task.updatedAt ?? null\n if (updatedAt) versionRef.current = updatedAt\n }, [taskQuery])\n\n const reportError = React.useCallback(\n (error: unknown, fallback: string) => {\n if (surfaceRecordConflict(error, t)) {\n invalidate('task')\n invalidate('children')\n return\n }\n logger.error('staff.time_tracking task drawer mutation failed', { err: error })\n flash(error instanceof Error && error.message ? error.message : fallback, 'error')\n },\n [invalidate, t],\n )\n\n const handleQuickLog = React.useCallback(\n async ({ minutes, description, date, isBillable, startClock, endClock }: QuickLogSubmission): Promise<boolean> => {\n if (!selfStaffMemberId || !projectId) {\n flash(t('staff.time_tracking.taskDrawer.quickLog.error', 'Could not save the time entry.'), 'error')\n return false\n }\n setBusy(true)\n try {\n await runMutation({\n operation: () =>\n apiCallOrThrow(\n '/api/staff/timesheets/time-entries',\n {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({\n // US-C5 defaults \u2014 today, me, billable \u2014 unless the Details block\n // overrode them. The person is never overridable here: logging\n // for somebody else is a different act with different permissions.\n staffMemberId: selfStaffMemberId,\n date,\n durationMinutes: minutes,\n taskId,\n timeProjectId: projectId,\n isBillable,\n description,\n // The clocks are sent as a pair or not at all. A lone\n // `started_at` is indistinguishable from a running timer \u2014\n // `started_at IS NOT NULL AND ended_at IS NULL` is exactly how\n // the list identifies one \u2014 so an entry with a start and no end\n // shows up as a timer running since that moment, and stopping it\n // fails because no timer segment was ever opened for it.\n //\n // The duration is authoritative here, so the missing half is\n // derived from it rather than left blank: the same 2-of-3\n // arithmetic the full entry form does.\n ...buildEntryClocks({ date, startClock, endClock, minutes }),\n source: 'manual',\n }),\n },\n { errorMessage: t('staff.time_tracking.taskDrawer.quickLog.error', 'Could not save the time entry.') },\n ),\n context: {\n formId: TASK_DRAWER_MUTATION_CONTEXT_ID,\n resourceKind: 'staff.timesheets.time_entry',\n resourceId: taskId,\n retryLastMutation,\n },\n })\n flash(t('staff.time_tracking.taskDrawer.quickLog.saved', 'Time logged.'), 'success')\n invalidate('task')\n invalidate('entries')\n onChanged?.()\n return true\n } catch (error) {\n reportError(error, t('staff.time_tracking.taskDrawer.quickLog.error', 'Could not save the time entry.'))\n return false\n } finally {\n setBusy(false)\n }\n },\n [invalidate, onChanged, projectId, reportError, retryLastMutation, runMutation, selfStaffMemberId, t, taskId],\n )\n\n const stopTimerEntry = React.useCallback(\n async (entryId: string) => {\n await runMutation({\n operation: () =>\n apiCallOrThrow(\n `/api/staff/timesheets/time-entries/${encodeURIComponent(entryId)}/timer-stop`,\n { method: 'POST' },\n { errorMessage: t('staff.time_tracking.board.timer.stopError', 'Could not stop the timer.') },\n ),\n context: {\n formId: TASK_DRAWER_MUTATION_CONTEXT_ID,\n resourceKind: 'staff.timesheets.time_entry',\n resourceId: entryId,\n retryLastMutation,\n },\n })\n },\n [retryLastMutation, runMutation, t],\n )\n\n const handleStopTimer = React.useCallback(async () => {\n if (!runningTimer.entryId) return\n setTimerBusy(true)\n try {\n await stopTimerEntry(runningTimer.entryId)\n await runningTimerQuery.refetch()\n invalidate('task')\n invalidate('entries')\n onChanged?.()\n } catch (error) {\n reportError(error, t('staff.time_tracking.board.timer.stopError', 'Could not stop the timer.'))\n } finally {\n setTimerBusy(false)\n }\n }, [invalidate, onChanged, reportError, runningTimer.entryId, runningTimerQuery, stopTimerEntry, t])\n\n const handleStartTimer = React.useCallback(async () => {\n if (!selfStaffMemberId || !projectId) return\n // Note 2 / US-D4: one timer at a time. A timer running on another task is\n // stopped only after the person says so \u2014 never silently.\n if (runningTimer.entryId && runningTimer.taskId !== taskId) {\n const confirmed = await confirm({\n title: t('staff.time_tracking.taskDrawer.timer.switchTitle', 'A timer is running on another task'),\n text: t(\n 'staff.time_tracking.taskDrawer.timer.switchText',\n 'Only one timer can run at a time. Stop the other one and start it here?',\n ),\n })\n if (!confirmed) return\n }\n setTimerBusy(true)\n try {\n if (runningTimer.entryId && runningTimer.taskId !== taskId) {\n await stopTimerEntry(runningTimer.entryId)\n }\n const started = await runMutation({\n operation: () =>\n apiCallOrThrow<Record<string, unknown>>(\n '/api/staff/timesheets/time-entries/start-timer',\n {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({\n staffMemberId: selfStaffMemberId,\n timeProjectId: projectId,\n date: todayIsoDate(),\n notes: task?.title ?? null,\n }),\n },\n { errorMessage: t('staff.time_tracking.board.timer.startError', 'Could not start the timer.') },\n ),\n context: {\n formId: TASK_DRAWER_MUTATION_CONTEXT_ID,\n resourceKind: 'staff.timesheets.time_entry',\n resourceId: taskId,\n retryLastMutation,\n },\n })\n const entryId = typeof started?.result?.id === 'string' ? started.result.id : null\n if (entryId) {\n // `start-timer` is atomic but takes no task, so the link is a second\n // write \u2014 the board does the same. A failure leaves a running,\n // project-level timer rather than no timer at all.\n const linked = await apiCall('/api/staff/timesheets/time-entries', {\n method: 'PUT',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ id: entryId, taskId }),\n })\n if (!linked.ok) {\n flash(\n t(\n 'staff.time_tracking.board.timer.linkWarning',\n 'The timer is running but is not linked to this task yet.',\n ),\n 'warning',\n )\n }\n }\n await runningTimerQuery.refetch()\n onChanged?.()\n } catch (error) {\n reportError(error, t('staff.time_tracking.board.timer.startError', 'Could not start the timer.'))\n } finally {\n setTimerBusy(false)\n }\n }, [\n confirm,\n onChanged,\n projectId,\n reportError,\n retryLastMutation,\n runMutation,\n runningTimer.entryId,\n runningTimer.taskId,\n runningTimerQuery,\n selfStaffMemberId,\n stopTimerEntry,\n t,\n task?.title,\n taskId,\n ])\n\n /**\n * Property saves are serialized. Each one leaves with the version the previous\n * one produced, so the second blur cannot 409 against the first.\n */\n const runSerialized = React.useCallback(async (job: () => Promise<void>): Promise<void> => {\n const chained = saveChainRef.current.then(job, job)\n saveChainRef.current = chained.catch(() => {})\n return chained\n }, [])\n\n const saveTaskField = React.useCallback(\n async (patch: Record<string, unknown>) => {\n if (!task) return\n setBusy(true)\n try {\n await runSerialized(async () => {\n await runMutation({\n operation: () =>\n withScopedApiRequestHeaders(buildOptimisticLockHeader(versionRef.current), () =>\n apiCallOrThrow(\n '/api/staff/timesheets/tasks',\n {\n method: 'PUT',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ id: taskId, ...patch }),\n },\n {\n errorMessage: t(\n 'staff.time_tracking.taskDrawer.properties.saveError',\n 'Could not save the change.',\n ),\n },\n ),\n ),\n context: {\n formId: TASK_DRAWER_MUTATION_CONTEXT_ID,\n resourceKind: 'staff.timesheets.task',\n resourceId: taskId,\n retryLastMutation,\n },\n })\n // The CRUD update answers `{ok:true}`, so the new version comes from\n // the row itself \u2014 and it must land before the next field saves.\n await refreshVersion()\n })\n onChanged?.()\n } catch (error) {\n reportError(error, t('staff.time_tracking.taskDrawer.properties.saveError', 'Could not save the change.'))\n } finally {\n setBusy(false)\n }\n },\n [onChanged, refreshVersion, reportError, retryLastMutation, runMutation, runSerialized, t, task, taskId],\n )\n\n const handleStatusChange = React.useCallback(\n (statusId: string) => {\n if (!task || statusId === task.taskStatusId) return\n setBusy(true)\n void runSerialized(async () => {\n try {\n const moved = await runMutation({\n operation: () =>\n withScopedApiRequestHeaders(buildOptimisticLockHeader(versionRef.current), () =>\n apiCallOrThrow<Record<string, unknown>>(\n `/api/staff/timesheets/tasks/${encodeURIComponent(taskId)}/status`,\n {\n method: 'PATCH',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ taskStatusId: statusId }),\n },\n { errorMessage: t('staff.time_tracking.board.move.error', 'Could not move the task.') },\n ),\n ),\n context: {\n formId: TASK_DRAWER_MUTATION_CONTEXT_ID,\n resourceKind: 'staff.timesheets.task',\n resourceId: taskId,\n retryLastMutation,\n },\n })\n // This route does return the new version, so the token refreshes from\n // the response instead of costing a refetch.\n const updatedAt = typeof moved?.result?.updatedAt === 'string' ? moved.result.updatedAt : null\n if (updatedAt) versionRef.current = updatedAt\n else await refreshVersion()\n invalidate('task')\n onChanged?.()\n } catch (error) {\n reportError(error, t('staff.time_tracking.board.move.error', 'Could not move the task.'))\n } finally {\n setBusy(false)\n }\n })\n },\n [\n invalidate,\n onChanged,\n refreshVersion,\n reportError,\n retryLastMutation,\n runMutation,\n runSerialized,\n t,\n task,\n taskId,\n ],\n )\n\n const handleAssigneeChange = React.useCallback(\n (value: string) => {\n void saveTaskField({ assigneeStaffMemberId: value === '' ? null : value })\n },\n [saveTaskField],\n )\n\n const handleToggleSubtask = React.useCallback(\n async (child: BoardTask, done: boolean) => {\n const targetStatusId = done ? resolveDoneStatusId(statuses) : resolveDefaultStatusId(statuses)\n if (!targetStatusId) return\n setBusy(true)\n try {\n await runMutation({\n operation: () =>\n // The child's own version, not the parent's \u2014 this write touches the\n // child row.\n withScopedApiRequestHeaders(buildOptimisticLockHeader(child.updatedAt), () =>\n apiCallOrThrow(\n `/api/staff/timesheets/tasks/${encodeURIComponent(child.id)}/status`,\n {\n method: 'PATCH',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ taskStatusId: targetStatusId }),\n },\n {\n errorMessage: t(\n 'staff.time_tracking.taskDrawer.subtasks.toggleError',\n 'Could not change the subtask status.',\n ),\n },\n ),\n ),\n context: {\n formId: TASK_DRAWER_MUTATION_CONTEXT_ID,\n resourceKind: 'staff.timesheets.task',\n resourceId: child.id,\n retryLastMutation,\n },\n })\n invalidate('children')\n invalidate('task')\n onChanged?.()\n } catch (error) {\n reportError(\n error,\n t('staff.time_tracking.taskDrawer.subtasks.toggleError', 'Could not change the subtask status.'),\n )\n } finally {\n setBusy(false)\n }\n },\n [invalidate, onChanged, reportError, retryLastMutation, runMutation, statuses, t],\n )\n\n const handleAddSubtask = React.useCallback(async () => {\n const title = subtaskDraft.trim()\n if (!title || !projectId) {\n setComposingSubtask(false)\n setSubtaskDraft('')\n return\n }\n setBusy(true)\n try {\n await runMutation({\n operation: () =>\n apiCallOrThrow(\n '/api/staff/timesheets/tasks',\n {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({\n timeProjectId: projectId,\n parentTaskId: taskId,\n title,\n assigneeStaffMemberId: selfStaffMemberId,\n }),\n },\n {\n errorMessage: t('staff.time_tracking.taskDrawer.subtasks.addError', 'Could not add the subtask.'),\n },\n ),\n context: {\n formId: TASK_DRAWER_MUTATION_CONTEXT_ID,\n resourceKind: 'staff.timesheets.task',\n resourceId: taskId,\n retryLastMutation,\n },\n })\n setSubtaskDraft('')\n setComposingSubtask(false)\n invalidate('children')\n invalidate('task')\n onChanged?.()\n } catch (error) {\n reportError(error, t('staff.time_tracking.taskDrawer.subtasks.addError', 'Could not add the subtask.'))\n } finally {\n setBusy(false)\n }\n }, [\n invalidate,\n onChanged,\n projectId,\n reportError,\n retryLastMutation,\n runMutation,\n selfStaffMemberId,\n subtaskDraft,\n t,\n taskId,\n ])\n\n const handlePostComment = React.useCallback(\n async (body: string): Promise<boolean> => {\n setBusy(true)\n try {\n await runMutation({\n operation: () =>\n apiCallOrThrow(\n `/api/staff/timesheets/tasks/${encodeURIComponent(taskId)}/comments`,\n {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ body }),\n },\n { errorMessage: t('staff.time_tracking.taskDrawer.comments.error', 'Could not post the comment.') },\n ),\n context: {\n formId: TASK_DRAWER_MUTATION_CONTEXT_ID,\n resourceKind: 'staff.timesheets.task_comment',\n resourceId: taskId,\n retryLastMutation,\n },\n })\n invalidate('comments')\n return true\n } catch (error) {\n reportError(error, t('staff.time_tracking.taskDrawer.comments.error', 'Could not post the comment.'))\n return false\n } finally {\n setBusy(false)\n }\n },\n [invalidate, reportError, retryLastMutation, runMutation, t, taskId],\n )\n\n const handleTagChange = React.useCallback(\n async (tagId: string, assign: boolean) => {\n setBusy(true)\n const previous = tagIds\n setTagIds((current) =>\n assign ? Array.from(new Set([...current, tagId])) : current.filter((id) => id !== tagId),\n )\n try {\n await runMutation({\n operation: () =>\n apiCallOrThrow(\n '/api/staff/timesheets/tags/task-assignments',\n {\n method: assign ? 'POST' : 'DELETE',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ taskId, tagIds: [tagId] }),\n },\n { errorMessage: t('staff.time_tracking.taskDrawer.properties.tagError', 'Could not save the tags.') },\n ),\n context: {\n formId: TASK_DRAWER_MUTATION_CONTEXT_ID,\n resourceKind: 'staff.timesheets.task_tag',\n resourceId: taskId,\n retryLastMutation,\n },\n })\n onChanged?.()\n } catch (error) {\n setTagIds(previous)\n reportError(error, t('staff.time_tracking.taskDrawer.properties.tagError', 'Could not save the tags.'))\n } finally {\n setBusy(false)\n }\n },\n [onChanged, reportError, retryLastMutation, runMutation, t, tagIds, taskId],\n )\n\n /**\n * Creates the tag and hands it back so the picker can assign it through the\n * drawer's own `handleTagChange` \u2014 the task-assignments write is untouched, the\n * new row simply becomes assignable without leaving the drawer. The list is\n * invalidated rather than patched so the server-assigned colour arrives with it.\n */\n const createTag = React.useCallback(\n async (label: string): Promise<TagOption | null> => {\n try {\n const created = await apiCallOrThrow<Record<string, unknown>>(\n '/api/staff/timesheets/tags',\n {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ label, slug: slugifyProjectName(label).toLowerCase() }),\n },\n {\n errorMessage: t(\n 'staff.time_tracking.entryDialog.errors.createTag',\n 'Could not create the tag.',\n ),\n },\n )\n const id = typeof created?.result?.id === 'string' ? created.result.id : null\n if (!id) return null\n await queryClient.invalidateQueries({ queryKey: [...DRAWER_QUERY_ROOT, 'tags'] })\n return { id, label, color: null }\n } catch (error) {\n logger.warn('staff.time_tracking task drawer tag create failed', { err: error })\n flash(t('staff.time_tracking.entryDialog.errors.createTag', 'Could not create the tag.'), 'error')\n return null\n }\n },\n [queryClient, t],\n )\n\n const status = React.useMemo(\n () => statuses.find((entry) => entry.id === task?.taskStatusId) ?? null,\n [statuses, task?.taskStatusId],\n )\n\n const statusVariant = status?.isDone ? 'success' : status?.isDefault ? 'neutral' : 'info'\n\n const recentEntries = React.useMemo(() => entries.slice(0, RECENT_ENTRY_COUNT), [entries])\n\n const assignedTags = React.useMemo<TagOption[]>(() => {\n const byId = new Map(tagOptions.map((tag) => [tag.id, tag]))\n return tagIds.map((id) => byId.get(id) ?? { id, label: id, color: null })\n }, [tagIds, tagOptions])\n\n const availableTags = React.useMemo(\n () => tagOptions.filter((tag) => !tagIds.includes(tag.id)),\n [tagIds, tagOptions],\n )\n\n const doneStatusId = resolveDoneStatusId(statuses)\n\n const body = (() => {\n if (taskQuery.isLoading) {\n return <LoadingMessage label={t('staff.time_tracking.taskDrawer.loading', 'Loading the task\u2026')} />\n }\n if (taskQuery.isError) {\n return <ErrorMessage label={t('staff.time_tracking.taskDrawer.loadError', 'Could not load the task.')} />\n }\n if (!task) {\n return (\n <ErrorMessage\n label={t('staff.time_tracking.tasks.errors.notFound', 'Task not found or not accessible.')}\n />\n )\n }\n\n return (\n <div className=\"flex flex-col gap-6\">\n <TaskQuickLog\n onLog={handleQuickLog}\n logging={busy}\n timerRunningHere={timerRunningHere}\n elapsed={timerRunningHere ? formatElapsed(runningTimer.startedAt, now) : null}\n timerBusy={timerBusy}\n onStartTimer={() => { void handleStartTimer() }}\n onStopTimer={() => { void handleStopTimer() }}\n autoFocus={focusPanel === 'time'}\n disabled={!canManage}\n today={todayIsoDate()}\n />\n\n <section className=\"flex flex-col gap-2\" data-testid=\"task-drawer-logged\">\n <div className=\"flex items-baseline justify-between gap-3\">\n <h3 className=\"text-xs font-semibold uppercase tracking-wide text-muted-foreground\">\n {t('staff.time_tracking.taskDrawer.logged.title', 'Logged time')}\n </h3>\n <span className=\"font-mono text-base font-semibold tabular-nums text-foreground\" data-testid=\"task-drawer-logged-total\">\n {formatBoardMinutes(task.loggedMinutes)}\n </span>\n </div>\n <p className=\"text-xs text-muted-foreground\" data-testid=\"task-drawer-logged-split\">\n {t('staff.time_tracking.taskDrawer.logged.split', 'own {own} \u00B7 subtasks {children}', {\n own: formatSplitMinutes(task.ownMinutes),\n children: formatSplitMinutes(childMinutes(task.loggedMinutes, task.ownMinutes)),\n })}\n </p>\n <div className=\"flex flex-wrap items-center gap-2\">\n <Badge variant=\"success\">\n {t('staff.time_tracking.taskDrawer.logged.billable', 'billable {hours}', {\n hours: formatBoardMinutes(totals.billableMinutes),\n })}\n </Badge>\n <Badge variant=\"neutral\">\n {t('staff.time_tracking.taskDrawer.logged.nonBillable', 'non-billable {hours}', {\n hours: formatBoardMinutes(totals.nonBillableMinutes),\n })}\n </Badge>\n {canSeeMoney && totals.cost !== null ? (\n <Badge variant=\"info\" data-testid=\"task-drawer-cost\">\n {t('staff.time_tracking.taskDrawer.logged.cost', 'cost {amount}', {\n amount: formatCurrency(totals.cost, totals.currencyCode) ?? String(totals.cost),\n })}\n </Badge>\n ) : null}\n </div>\n {totals.partial ? (\n <p className=\"text-xs text-muted-foreground\">\n {t(\n 'staff.time_tracking.taskDrawer.logged.partialHint',\n 'The split is counted from the most recent entries in this project.',\n )}\n </p>\n ) : null}\n </section>\n\n {isChildTask ? null : (\n <section className=\"flex flex-col gap-3\" data-testid=\"task-drawer-subtasks\">\n <div className=\"flex items-baseline justify-between gap-3\">\n <h3 className=\"text-xs font-semibold uppercase tracking-wide text-muted-foreground\">\n {t('staff.time_tracking.taskDrawer.subtasks.title', 'Subtasks')}\n </h3>\n <span className=\"font-mono text-xs tabular-nums text-muted-foreground\">\n {t('staff.time_tracking.taskDrawer.subtasks.count', '{done}/{total}', {\n done: progress.done,\n total: subtaskTotal,\n })}\n </span>\n </div>\n {subtaskTotal > 0 ? (\n <Progress value={subtaskTotal > 0 ? (progress.done / subtaskTotal) * 100 : 0} max={100} />\n ) : null}\n {children.length === 0 ? (\n <p className=\"text-xs text-muted-foreground\">\n {t('staff.time_tracking.taskDrawer.subtasks.empty', 'No subtasks yet.')}\n </p>\n ) : (\n <ul className=\"flex flex-col\">\n {children.map((child) => {\n const done = (child.taskStatusId && doneStatusIds.has(child.taskStatusId)) || !!child.closedAt\n const assigneeName = child.assigneeStaffMemberId\n ? memberNames.get(child.assigneeStaffMemberId) ?? child.assigneeStaffMemberId\n : t('staff.time_tracking.taskDrawer.properties.unassigned', 'Unassigned')\n return (\n <li\n key={child.id}\n className=\"flex items-center gap-2.5 border-b border-border py-2 last:border-b-0\"\n data-subtask-id={child.id}\n >\n <Checkbox\n checked={done}\n disabled={!canManage || busy || !doneStatusId}\n aria-label={t('staff.time_tracking.taskDrawer.subtasks.toggle', 'Mark {title} as done', {\n title: child.title,\n })}\n onCheckedChange={(next) => { void handleToggleSubtask(child, next === true) }}\n />\n <span\n className={`min-w-0 flex-1 truncate text-sm ${done ? 'text-muted-foreground line-through' : 'text-foreground'}`}\n >\n {child.title}\n </span>\n <Avatar label={assigneeName} size=\"xs\" />\n <span className=\"font-mono text-xs tabular-nums text-muted-foreground\">\n {formatBoardMinutes(child.loggedMinutes)}\n </span>\n </li>\n )\n })}\n </ul>\n )}\n {!doneStatusId && children.length > 0 ? (\n <p className=\"text-xs text-muted-foreground\">\n {t(\n 'staff.time_tracking.taskDrawer.subtasks.noDoneColumn',\n 'This project has no done column, so a subtask has no way to close.',\n )}\n </p>\n ) : null}\n {canManage ? (\n composingSubtask ? (\n <Input\n autoFocus\n size=\"sm\"\n value={subtaskDraft}\n disabled={busy}\n onChange={(event) => setSubtaskDraft(event.target.value)}\n onKeyDown={(event) => {\n if (event.key === 'Enter') {\n event.preventDefault()\n void handleAddSubtask()\n }\n if (event.key === 'Escape') {\n event.preventDefault()\n event.stopPropagation()\n setComposingSubtask(false)\n setSubtaskDraft('')\n }\n }}\n placeholder={t('staff.time_tracking.taskDrawer.subtasks.placeholder', 'Subtask title')}\n aria-label={t('staff.time_tracking.taskDrawer.subtasks.add', 'Add subtask')}\n data-testid=\"task-drawer-subtask-input\"\n />\n ) : (\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n className=\"self-start\"\n onClick={() => setComposingSubtask(true)}\n data-testid=\"task-drawer-add-subtask\"\n >\n <Plus className=\"size-3.5\" aria-hidden=\"true\" />\n {t('staff.time_tracking.taskDrawer.subtasks.add', 'Add subtask')}\n </Button>\n )\n ) : null}\n </section>\n )}\n\n <section className=\"flex flex-col gap-3\" data-testid=\"task-drawer-entries\">\n <h3 className=\"text-xs font-semibold uppercase tracking-wide text-muted-foreground\">\n {t('staff.time_tracking.taskDrawer.entries.title', 'Time entries ({count})', { count: entries.length })}\n </h3>\n {recentEntries.length === 0 ? (\n <p className=\"text-xs text-muted-foreground\">\n {t('staff.time_tracking.taskDrawer.entries.empty', 'No time entries yet.')}\n </p>\n ) : (\n <ul className=\"flex flex-col\">\n {recentEntries.map((entry) => (\n <li\n key={entry.id}\n className=\"flex items-center gap-3 border-b border-border py-2 text-sm last:border-b-0\"\n data-entry-id={entry.id}\n >\n <span className=\"w-20 shrink-0 text-xs text-muted-foreground\">\n {formatDate(entry.date) ?? ''}\n </span>\n <span className=\"min-w-0 flex-1 truncate text-foreground\">\n {entry.description\n ?? t('staff.time_tracking.taskDrawer.entries.noDescription', 'No description')}\n </span>\n <span className=\"font-mono text-xs tabular-nums text-muted-foreground\">\n {formatBoardMinutes(entry.durationMinutes)}\n </span>\n </li>\n ))}\n </ul>\n )}\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n className=\"self-start\"\n onClick={() => router.push(`${ENTRIES_LIST_PATH}?taskId=${encodeURIComponent(taskId)}`)}\n >\n {t('staff.time_tracking.taskDrawer.entries.showAll', 'Show all')}\n </Button>\n </section>\n\n <TaskCommentThread\n comments={commentsQuery.data ?? []}\n loading={commentsQuery.isLoading}\n loadError={commentsQuery.isError}\n posting={busy}\n canComment={canManage}\n onPost={handlePostComment}\n />\n\n <section className=\"flex flex-col gap-3\" data-testid=\"task-drawer-properties\">\n <h3 className=\"text-xs font-semibold uppercase tracking-wide text-muted-foreground\">\n {t('staff.time_tracking.taskDrawer.properties.title', 'Properties')}\n </h3>\n <div className=\"grid grid-cols-1 gap-3 sm:grid-cols-2\">\n <div className=\"flex flex-col gap-1.5\">\n <span className=\"text-xs font-medium text-muted-foreground\">\n {t('staff.time_tracking.taskDrawer.properties.status', 'Status')}\n </span>\n <Select\n value={task.taskStatusId ?? undefined}\n disabled={!canManage || busy}\n onValueChange={handleStatusChange}\n >\n <SelectTrigger\n aria-label={t('staff.time_tracking.taskDrawer.properties.status', 'Status')}\n data-testid=\"task-drawer-status-select\"\n >\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {statuses.map((entry) => (\n <SelectItem key={entry.id} value={entry.id}>\n {entry.name}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <div className=\"flex flex-col gap-1.5\">\n <span className=\"text-xs font-medium text-muted-foreground\">\n {t('staff.time_tracking.taskDrawer.properties.assignee', 'Assignee')}\n </span>\n <Select\n value={task.assigneeStaffMemberId ?? undefined}\n disabled={!canManage || busy}\n onValueChange={handleAssigneeChange}\n >\n <SelectTrigger\n aria-label={t('staff.time_tracking.taskDrawer.properties.assignee', 'Assignee')}\n data-testid=\"task-drawer-assignee-select\"\n >\n <SelectValue\n placeholder={t('staff.time_tracking.taskDrawer.properties.unassigned', 'Unassigned')}\n />\n </SelectTrigger>\n <SelectContent>\n {members.map((member) => (\n <SelectItem key={member.id} value={member.id}>\n {member.name}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n </div>\n\n <div className=\"flex flex-col gap-1.5\">\n <span className=\"text-xs font-medium text-muted-foreground\">\n {t('staff.time_tracking.taskDrawer.properties.tags', 'Tags')}\n </span>\n <div className=\"flex flex-wrap items-center gap-2\">\n {assignedTags.map((tag) => (\n <Badge key={tag.id} variant=\"neutral\" className=\"gap-1\" style={tagChipStyle(tag)}>\n {tag.label}\n {canManage ? (\n <button\n type=\"button\"\n aria-label={t('staff.time_tracking.taskDrawer.properties.removeTag', 'Remove tag {label}', {\n label: tag.label,\n })}\n onClick={() => { void handleTagChange(tag.id, false) }}\n >\n <X className=\"size-3\" aria-hidden=\"true\" />\n </button>\n ) : null}\n </Badge>\n ))}\n {canManage ? (\n <TagPicker\n available={availableTags}\n disabled={busy}\n onAssign={(id) => { void handleTagChange(id, true) }}\n onCreate={createTag}\n labels={{\n add: t('staff.time_tracking.taskDrawer.properties.addTag', 'Add tag'),\n create: (name) =>\n t('staff.time_tracking.entryDialog.createTag', 'Create \"{name}\"', { name }),\n empty: t('staff.time_tracking.entryDialog.noTags', 'No matching tag'),\n }}\n testIdPrefix=\"task-drawer\"\n />\n ) : null}\n </div>\n <p className=\"text-xs text-muted-foreground\">\n {t(\n 'staff.time_tracking.taskDrawer.properties.tagsPending',\n 'Tags already saved on this task appear here once the task list returns them.',\n )}\n </p>\n </div>\n <InjectionSpot\n spotId={extensionPoints.hosts.taskDetailSidebar.spotId}\n context={taskInjectionContext}\n data={task}\n />\n </section>\n\n <InjectionSpot\n spotId={extensionPoints.hosts.taskDetailTabs.spotId}\n context={taskInjectionContext}\n data={task}\n />\n </div>\n )\n })()\n\n const createdLabel = formatDate(createdAt)\n const headerLine = [\n projectName ?? null,\n createdLabel\n ? t('staff.time_tracking.taskDrawer.created', 'created {date}', { date: createdLabel })\n : null,\n ]\n .filter((part): part is string => !!part)\n .join(' \u00B7 ')\n\n return (\n <Drawer open={open} onOpenChange={onOpenChange}>\n <DrawerContent\n className=\"sm:max-w-xl\"\n closeAriaLabel={t('staff.time_tracking.taskDrawer.close', 'Close')}\n data-testid=\"task-drawer\"\n >\n <DrawerHeader>\n <div className=\"flex min-w-0 flex-1 flex-col gap-1.5\">\n <div className=\"flex items-center gap-2\">\n {status ? <Badge variant={statusVariant}>{status.name}</Badge> : null}\n {task?.reference ? (\n <span className=\"text-xs text-muted-foreground\">{task.reference}</span>\n ) : null}\n <InjectionSpot\n spotId={extensionPoints.hosts.taskDetailStatusBadges.spotId}\n context={taskInjectionContext}\n data={task}\n />\n </div>\n <DrawerTitle className=\"truncate\">{task?.title ?? ''}</DrawerTitle>\n <DrawerDescription>{headerLine}</DrawerDescription>\n <InjectionSpot\n spotId={extensionPoints.hosts.taskDetailHeader.spotId}\n context={taskInjectionContext}\n data={task}\n />\n </div>\n </DrawerHeader>\n <DrawerBody>{body}</DrawerBody>\n <DrawerFooter\n leading={\n <span className=\"text-xs text-muted-foreground\">\n {t('staff.time_tracking.taskDrawer.autoSave', 'Changes are saved automatically')}\n </span>\n }\n >\n <InjectionSpot\n spotId={extensionPoints.hosts.taskDetailFooter.spotId}\n context={taskInjectionContext}\n data={task}\n />\n <Button type=\"button\" variant=\"outline\" onClick={() => onOpenChange(false)}>\n {t('staff.time_tracking.taskDrawer.close', 'Close')}\n </Button>\n </DrawerFooter>\n {ConfirmDialogElement}\n </DrawerContent>\n </Drawer>\n )\n}\n\nexport default TaskDrawer\n"],
5
+ "mappings": "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",
6
+ "names": ["statuses", "status", "body"]
7
+ }
@@ -0,0 +1,176 @@
1
+ "use client";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import * as React from "react";
4
+ import { useQuery } from "@tanstack/react-query";
5
+ import { Badge } from "@open-mercato/ui/primitives/badge";
6
+ import { Button } from "@open-mercato/ui/primitives/button";
7
+ import { EmptyState } from "@open-mercato/ui/primitives/empty-state";
8
+ import { Spinner } from "@open-mercato/ui/primitives/spinner";
9
+ import { ErrorMessage, LoadingMessage } from "@open-mercato/ui/backend/detail";
10
+ import { useT } from "@open-mercato/shared/lib/i18n/context";
11
+ import { useOrganizationScopeVersion } from "@open-mercato/shared/lib/frontend/useOrganizationScope";
12
+ import { sumTaskLoggedMinutes } from "../timesheets-tasks/taskHoursTotals.js";
13
+ import {
14
+ BOARD_PAGE_SIZE,
15
+ BOARD_QUERY_ROOT,
16
+ fetchTaskPages,
17
+ useAssigneeNames,
18
+ useTagLabels
19
+ } from "./boardDirectory.js";
20
+ import {
21
+ boardServerFilterKey,
22
+ boardServerFilterParams
23
+ } from "./boardFilters.js";
24
+ import {
25
+ formatBoardMinutes,
26
+ sortByPosition,
27
+ toBoardTask
28
+ } from "./kanbanBoardData.js";
29
+ function TaskListView({
30
+ timeProjectId,
31
+ filters,
32
+ statuses,
33
+ onOpenTask,
34
+ onSummaryChange
35
+ }) {
36
+ const t = useT();
37
+ const scopeVersion = useOrganizationScopeVersion();
38
+ const [pages, setPages] = React.useState(1);
39
+ const filterKey = boardServerFilterKey(filters, { includeStatus: true });
40
+ React.useEffect(() => {
41
+ setPages(1);
42
+ }, [filterKey, timeProjectId]);
43
+ const tasksQuery = useQuery({
44
+ queryKey: [
45
+ ...BOARD_QUERY_ROOT,
46
+ "list",
47
+ `scope:${scopeVersion}`,
48
+ `project:${timeProjectId}`,
49
+ `pages:${pages}`,
50
+ `filters:${filterKey}`
51
+ ],
52
+ staleTime: 15e3,
53
+ queryFn: () => fetchTaskPages(
54
+ (page) => `timeProjectId=${encodeURIComponent(timeProjectId)}&topLevelOnly=true&page=${page}&pageSize=${BOARD_PAGE_SIZE}&sortField=position&sortDir=asc${boardServerFilterParams(
55
+ filters,
56
+ { includeStatus: true }
57
+ )}`,
58
+ pages
59
+ )
60
+ });
61
+ const loadedTasks = React.useMemo(() => {
62
+ const rows = (tasksQuery.data?.items ?? []).map(toBoardTask).filter((task) => task !== null);
63
+ return sortByPosition(rows);
64
+ }, [tasksQuery.data]);
65
+ const tasks = loadedTasks;
66
+ const assigneeIds = React.useMemo(
67
+ () => tasks.map((task) => task.assigneeStaffMemberId).filter((id) => typeof id === "string"),
68
+ [tasks]
69
+ );
70
+ const tagIds = React.useMemo(() => tasks.flatMap((task) => task.tagIds), [tasks]);
71
+ const assigneeNames = useAssigneeNames(assigneeIds);
72
+ const tagLabels = useTagLabels(tagIds);
73
+ const statusNames = React.useMemo(() => {
74
+ const map = /* @__PURE__ */ new Map();
75
+ for (const status of statuses) map.set(status.id, status.name);
76
+ return map;
77
+ }, [statuses]);
78
+ const summary = React.useMemo(
79
+ () => ({
80
+ taskCount: tasks.length,
81
+ loggedMinutes: sumTaskLoggedMinutes(tasks)
82
+ }),
83
+ [tasks]
84
+ );
85
+ React.useEffect(() => {
86
+ onSummaryChange?.(summary);
87
+ }, [onSummaryChange, summary]);
88
+ if (tasksQuery.isLoading) {
89
+ return /* @__PURE__ */ jsx(LoadingMessage, { label: t("staff.time_tracking.board.loading", "Loading the board\u2026") });
90
+ }
91
+ if (tasksQuery.isError) {
92
+ return /* @__PURE__ */ jsx(
93
+ ErrorMessage,
94
+ {
95
+ label: t("staff.time_tracking.board.loadError", "Could not load the board."),
96
+ action: /* @__PURE__ */ jsx(Button, { type: "button", variant: "outline", size: "sm", onClick: () => void tasksQuery.refetch(), children: t("staff.time_tracking.board.reload", "Try again") })
97
+ }
98
+ );
99
+ }
100
+ if (tasks.length === 0) {
101
+ return /* @__PURE__ */ jsx(
102
+ EmptyState,
103
+ {
104
+ title: t("staff.time_tracking.board.list.empty.title", "No tasks match these filters"),
105
+ description: t(
106
+ "staff.time_tracking.board.list.empty.description",
107
+ "Remove a filter chip to widen the view."
108
+ )
109
+ }
110
+ );
111
+ }
112
+ const total = tasksQuery.data?.total ?? loadedTasks.length;
113
+ const remaining = Math.max(0, total - loadedTasks.length);
114
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3", children: [
115
+ /* @__PURE__ */ jsx("div", { className: "overflow-x-auto rounded-lg border border-border", children: /* @__PURE__ */ jsxs("table", { className: "w-full border-collapse text-sm", "data-testid": "board-task-list", children: [
116
+ /* @__PURE__ */ jsx("caption", { className: "sr-only", children: t("staff.time_tracking.board.list.caption", "Tasks") }),
117
+ /* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { className: "border-b border-border bg-muted/40 text-left", children: [
118
+ /* @__PURE__ */ jsx("th", { scope: "col", className: "px-3 py-2.5 font-semibold text-muted-foreground", children: t("staff.time_tracking.board.list.columns.reference", "Ref.") }),
119
+ /* @__PURE__ */ jsx("th", { scope: "col", className: "px-3 py-2.5 font-semibold text-muted-foreground", children: t("staff.time_tracking.board.list.columns.title", "Task") }),
120
+ /* @__PURE__ */ jsx("th", { scope: "col", className: "px-3 py-2.5 font-semibold text-muted-foreground", children: t("staff.time_tracking.board.list.columns.status", "Status") }),
121
+ /* @__PURE__ */ jsx("th", { scope: "col", className: "px-3 py-2.5 font-semibold text-muted-foreground", children: t("staff.time_tracking.board.list.columns.assignee", "Assignee") }),
122
+ /* @__PURE__ */ jsx("th", { scope: "col", className: "px-3 py-2.5 font-semibold text-muted-foreground", children: t("staff.time_tracking.board.list.columns.tags", "Tags") }),
123
+ /* @__PURE__ */ jsx("th", { scope: "col", className: "px-3 py-2.5 text-right font-semibold text-muted-foreground", children: t("staff.time_tracking.board.list.columns.hours", "Logged") })
124
+ ] }) }),
125
+ /* @__PURE__ */ jsx("tbody", { children: tasks.map((task) => /* @__PURE__ */ jsxs(
126
+ "tr",
127
+ {
128
+ "data-task-row": task.id,
129
+ className: "border-b border-border last:border-b-0 hover:bg-muted/40",
130
+ children: [
131
+ /* @__PURE__ */ jsx("td", { className: "px-3 py-2.5 text-xs tabular-nums text-muted-foreground", children: task.reference ?? "\u2014" }),
132
+ /* @__PURE__ */ jsx("td", { className: "px-3 py-2.5", children: /* @__PURE__ */ jsx(
133
+ Button,
134
+ {
135
+ type: "button",
136
+ variant: "link",
137
+ size: "2xs",
138
+ onClick: () => onOpenTask(task.id),
139
+ className: "h-auto px-0 text-left text-sm font-semibold text-foreground",
140
+ children: task.title
141
+ }
142
+ ) }),
143
+ /* @__PURE__ */ jsx("td", { className: "px-3 py-2.5 text-muted-foreground", children: task.taskStatusId ? statusNames.get(task.taskStatusId) ?? "\u2014" : "\u2014" }),
144
+ /* @__PURE__ */ jsx("td", { className: "px-3 py-2.5 text-muted-foreground", children: task.assigneeStaffMemberId ? assigneeNames.data?.get(task.assigneeStaffMemberId) ?? t("staff.time_tracking.board.card.unassigned", "Unassigned") : t("staff.time_tracking.board.card.unassigned", "Unassigned") }),
145
+ /* @__PURE__ */ jsx("td", { className: "px-3 py-2.5", children: /* @__PURE__ */ jsx("span", { className: "flex flex-wrap gap-1", children: task.tagIds.map((tagId) => {
146
+ const label = tagLabels.data?.get(tagId);
147
+ if (!label) return null;
148
+ return /* @__PURE__ */ jsx(Badge, { variant: "neutral", size: "sm", children: label }, tagId);
149
+ }) }) }),
150
+ /* @__PURE__ */ jsx("td", { className: "px-3 py-2.5 text-right font-semibold tabular-nums text-foreground", children: formatBoardMinutes(task.loggedMinutes) })
151
+ ]
152
+ },
153
+ task.id
154
+ )) })
155
+ ] }) }),
156
+ remaining > 0 ? /* @__PURE__ */ jsx(
157
+ Button,
158
+ {
159
+ type: "button",
160
+ variant: "ghost",
161
+ size: "sm",
162
+ disabled: tasksQuery.isFetching,
163
+ onClick: () => setPages((previous) => previous + 1),
164
+ "data-testid": "board-task-list-load-more",
165
+ className: "self-start rounded-lg border border-dashed border-muted-foreground/60 text-muted-foreground",
166
+ children: tasksQuery.isFetching ? /* @__PURE__ */ jsx(Spinner, { className: "size-4" }) : t("staff.time_tracking.board.loadMore", "Show more ({remaining})", { remaining })
167
+ }
168
+ ) : null
169
+ ] });
170
+ }
171
+ var TaskListView_default = TaskListView;
172
+ export {
173
+ TaskListView,
174
+ TaskListView_default as default
175
+ };
176
+ //# sourceMappingURL=TaskListView.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../src/modules/staff/lib/time-tracking-ui/TaskListView.tsx"],
4
+ "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { useQuery } from '@tanstack/react-query'\nimport { Badge } from '@open-mercato/ui/primitives/badge'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { EmptyState } from '@open-mercato/ui/primitives/empty-state'\nimport { Spinner } from '@open-mercato/ui/primitives/spinner'\nimport { ErrorMessage, LoadingMessage } from '@open-mercato/ui/backend/detail'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { useOrganizationScopeVersion } from '@open-mercato/shared/lib/frontend/useOrganizationScope'\nimport { sumTaskLoggedMinutes } from '../timesheets-tasks/taskHoursTotals'\nimport {\n BOARD_PAGE_SIZE,\n BOARD_QUERY_ROOT,\n fetchTaskPages,\n useAssigneeNames,\n useTagLabels,\n} from './boardDirectory'\nimport {\n boardServerFilterKey,\n boardServerFilterParams,\n type BoardFilters,\n} from './boardFilters'\nimport {\n formatBoardMinutes,\n sortByPosition,\n toBoardTask,\n type BoardStatus,\n type BoardTask,\n} from './kanbanBoardData'\nimport type { BoardSummary } from './boardSummary'\n\n/**\n * \"Lista\" \u2014 the flat half of the screen-6 view switch.\n *\n * It is a real view over the same tasks, not a placeholder: the filter set, the hours\n * arithmetic and the drawer are already built, so the only thing missing was a table to\n * put them in. Unlike the board it asks the server for the status filter (it has no\n * columns to select), which is the one place the two views build their request\n * differently \u2014 see `boardFilters.ts`.\n */\nexport function TaskListView({\n timeProjectId,\n filters,\n statuses,\n onOpenTask,\n onSummaryChange,\n}: {\n timeProjectId: string\n filters: BoardFilters\n statuses: readonly BoardStatus[]\n onOpenTask: (taskId: string) => void\n onSummaryChange?: (summary: BoardSummary) => void\n}): React.ReactElement {\n const t = useT()\n const scopeVersion = useOrganizationScopeVersion()\n const [pages, setPages] = React.useState(1)\n const filterKey = boardServerFilterKey(filters, { includeStatus: true })\n\n React.useEffect(() => {\n setPages(1)\n }, [filterKey, timeProjectId])\n\n const tasksQuery = useQuery({\n queryKey: [\n ...BOARD_QUERY_ROOT,\n 'list',\n `scope:${scopeVersion}`,\n `project:${timeProjectId}`,\n `pages:${pages}`,\n `filters:${filterKey}`,\n ],\n staleTime: 15_000,\n queryFn: () =>\n fetchTaskPages(\n (page) =>\n `timeProjectId=${encodeURIComponent(timeProjectId)}&topLevelOnly=true&page=${page}&pageSize=${BOARD_PAGE_SIZE}&sortField=position&sortDir=asc${boardServerFilterParams(\n filters,\n { includeStatus: true },\n )}`,\n pages,\n ),\n })\n\n const loadedTasks = React.useMemo(() => {\n const rows = (tasksQuery.data?.items ?? [])\n .map(toBoardTask)\n .filter((task): task is BoardTask => task !== null)\n return sortByPosition(rows)\n }, [tasksQuery.data])\n\n const tasks = loadedTasks\n\n const assigneeIds = React.useMemo(\n () =>\n tasks\n .map((task) => task.assigneeStaffMemberId)\n .filter((id): id is string => typeof id === 'string'),\n [tasks],\n )\n const tagIds = React.useMemo(() => tasks.flatMap((task) => task.tagIds), [tasks])\n const assigneeNames = useAssigneeNames(assigneeIds)\n const tagLabels = useTagLabels(tagIds)\n\n const statusNames = React.useMemo(() => {\n const map = new Map<string, string>()\n for (const status of statuses) map.set(status.id, status.name)\n return map\n }, [statuses])\n\n const summary = React.useMemo<BoardSummary>(\n () => ({\n taskCount: tasks.length,\n loggedMinutes: sumTaskLoggedMinutes(tasks),\n }),\n [tasks],\n )\n\n React.useEffect(() => {\n onSummaryChange?.(summary)\n }, [onSummaryChange, summary])\n\n if (tasksQuery.isLoading) {\n return <LoadingMessage label={t('staff.time_tracking.board.loading', 'Loading the board\u2026')} />\n }\n\n if (tasksQuery.isError) {\n return (\n <ErrorMessage\n label={t('staff.time_tracking.board.loadError', 'Could not load the board.')}\n action={\n <Button type=\"button\" variant=\"outline\" size=\"sm\" onClick={() => void tasksQuery.refetch()}>\n {t('staff.time_tracking.board.reload', 'Try again')}\n </Button>\n }\n />\n )\n }\n\n if (tasks.length === 0) {\n return (\n <EmptyState\n title={t('staff.time_tracking.board.list.empty.title', 'No tasks match these filters')}\n description={t(\n 'staff.time_tracking.board.list.empty.description',\n 'Remove a filter chip to widen the view.',\n )}\n />\n )\n }\n\n const total = tasksQuery.data?.total ?? loadedTasks.length\n const remaining = Math.max(0, total - loadedTasks.length)\n\n return (\n <div className=\"flex flex-col gap-3\">\n <div className=\"overflow-x-auto rounded-lg border border-border\">\n <table className=\"w-full border-collapse text-sm\" data-testid=\"board-task-list\">\n <caption className=\"sr-only\">\n {t('staff.time_tracking.board.list.caption', 'Tasks')}\n </caption>\n <thead>\n <tr className=\"border-b border-border bg-muted/40 text-left\">\n <th scope=\"col\" className=\"px-3 py-2.5 font-semibold text-muted-foreground\">\n {t('staff.time_tracking.board.list.columns.reference', 'Ref.')}\n </th>\n <th scope=\"col\" className=\"px-3 py-2.5 font-semibold text-muted-foreground\">\n {t('staff.time_tracking.board.list.columns.title', 'Task')}\n </th>\n <th scope=\"col\" className=\"px-3 py-2.5 font-semibold text-muted-foreground\">\n {t('staff.time_tracking.board.list.columns.status', 'Status')}\n </th>\n <th scope=\"col\" className=\"px-3 py-2.5 font-semibold text-muted-foreground\">\n {t('staff.time_tracking.board.list.columns.assignee', 'Assignee')}\n </th>\n <th scope=\"col\" className=\"px-3 py-2.5 font-semibold text-muted-foreground\">\n {t('staff.time_tracking.board.list.columns.tags', 'Tags')}\n </th>\n <th scope=\"col\" className=\"px-3 py-2.5 text-right font-semibold text-muted-foreground\">\n {t('staff.time_tracking.board.list.columns.hours', 'Logged')}\n </th>\n </tr>\n </thead>\n <tbody>\n {tasks.map((task) => (\n <tr\n key={task.id}\n data-task-row={task.id}\n className=\"border-b border-border last:border-b-0 hover:bg-muted/40\"\n >\n <td className=\"px-3 py-2.5 text-xs tabular-nums text-muted-foreground\">\n {task.reference ?? '\u2014'}\n </td>\n <td className=\"px-3 py-2.5\">\n <Button\n type=\"button\"\n variant=\"link\"\n size=\"2xs\"\n onClick={() => onOpenTask(task.id)}\n className=\"h-auto px-0 text-left text-sm font-semibold text-foreground\"\n >\n {task.title}\n </Button>\n </td>\n <td className=\"px-3 py-2.5 text-muted-foreground\">\n {task.taskStatusId ? statusNames.get(task.taskStatusId) ?? '\u2014' : '\u2014'}\n </td>\n <td className=\"px-3 py-2.5 text-muted-foreground\">\n {task.assigneeStaffMemberId\n ? assigneeNames.data?.get(task.assigneeStaffMemberId) ??\n t('staff.time_tracking.board.card.unassigned', 'Unassigned')\n : t('staff.time_tracking.board.card.unassigned', 'Unassigned')}\n </td>\n <td className=\"px-3 py-2.5\">\n <span className=\"flex flex-wrap gap-1\">\n {task.tagIds.map((tagId) => {\n // Same rule as the board card: a tag whose label has not\n // arrived yet is skipped, never drawn as its raw id.\n const label = tagLabels.data?.get(tagId)\n if (!label) return null\n return (\n <Badge key={tagId} variant=\"neutral\" size=\"sm\">\n {label}\n </Badge>\n )\n })}\n </span>\n </td>\n <td className=\"px-3 py-2.5 text-right font-semibold tabular-nums text-foreground\">\n {formatBoardMinutes(task.loggedMinutes)}\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n\n {remaining > 0 ? (\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n disabled={tasksQuery.isFetching}\n onClick={() => setPages((previous) => previous + 1)}\n data-testid=\"board-task-list-load-more\"\n className=\"self-start rounded-lg border border-dashed border-muted-foreground/60 text-muted-foreground\"\n >\n {tasksQuery.isFetching ? (\n <Spinner className=\"size-4\" />\n ) : (\n t('staff.time_tracking.board.loadMore', 'Show more ({remaining})', { remaining })\n )}\n </Button>\n ) : null}\n </div>\n )\n}\n\nexport default TaskListView\n"],
5
+ "mappings": ";AA4HW,cAuCC,YAvCD;AA1HX,YAAY,WAAW;AACvB,SAAS,gBAAgB;AACzB,SAAS,aAAa;AACtB,SAAS,cAAc;AACvB,SAAS,kBAAkB;AAC3B,SAAS,eAAe;AACxB,SAAS,cAAc,sBAAsB;AAC7C,SAAS,YAAY;AACrB,SAAS,mCAAmC;AAC5C,SAAS,4BAA4B;AACrC;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP;AAAA,EACE;AAAA,EACA;AAAA,OAEK;AACP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OAGK;AAYA,SAAS,aAAa;AAAA,EAC3B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAMuB;AACrB,QAAM,IAAI,KAAK;AACf,QAAM,eAAe,4BAA4B;AACjD,QAAM,CAAC,OAAO,QAAQ,IAAI,MAAM,SAAS,CAAC;AAC1C,QAAM,YAAY,qBAAqB,SAAS,EAAE,eAAe,KAAK,CAAC;AAEvE,QAAM,UAAU,MAAM;AACpB,aAAS,CAAC;AAAA,EACZ,GAAG,CAAC,WAAW,aAAa,CAAC;AAE7B,QAAM,aAAa,SAAS;AAAA,IAC1B,UAAU;AAAA,MACR,GAAG;AAAA,MACH;AAAA,MACA,SAAS,YAAY;AAAA,MACrB,WAAW,aAAa;AAAA,MACxB,SAAS,KAAK;AAAA,MACd,WAAW,SAAS;AAAA,IACtB;AAAA,IACA,WAAW;AAAA,IACX,SAAS,MACP;AAAA,MACE,CAAC,SACC,iBAAiB,mBAAmB,aAAa,CAAC,2BAA2B,IAAI,aAAa,eAAe,kCAAkC;AAAA,QAC7I;AAAA,QACA,EAAE,eAAe,KAAK;AAAA,MACxB,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACJ,CAAC;AAED,QAAM,cAAc,MAAM,QAAQ,MAAM;AACtC,UAAM,QAAQ,WAAW,MAAM,SAAS,CAAC,GACtC,IAAI,WAAW,EACf,OAAO,CAAC,SAA4B,SAAS,IAAI;AACpD,WAAO,eAAe,IAAI;AAAA,EAC5B,GAAG,CAAC,WAAW,IAAI,CAAC;AAEpB,QAAM,QAAQ;AAEd,QAAM,cAAc,MAAM;AAAA,IACxB,MACE,MACG,IAAI,CAAC,SAAS,KAAK,qBAAqB,EACxC,OAAO,CAAC,OAAqB,OAAO,OAAO,QAAQ;AAAA,IACxD,CAAC,KAAK;AAAA,EACR;AACA,QAAM,SAAS,MAAM,QAAQ,MAAM,MAAM,QAAQ,CAAC,SAAS,KAAK,MAAM,GAAG,CAAC,KAAK,CAAC;AAChF,QAAM,gBAAgB,iBAAiB,WAAW;AAClD,QAAM,YAAY,aAAa,MAAM;AAErC,QAAM,cAAc,MAAM,QAAQ,MAAM;AACtC,UAAM,MAAM,oBAAI,IAAoB;AACpC,eAAW,UAAU,SAAU,KAAI,IAAI,OAAO,IAAI,OAAO,IAAI;AAC7D,WAAO;AAAA,EACT,GAAG,CAAC,QAAQ,CAAC;AAEb,QAAM,UAAU,MAAM;AAAA,IACpB,OAAO;AAAA,MACL,WAAW,MAAM;AAAA,MACjB,eAAe,qBAAqB,KAAK;AAAA,IAC3C;AAAA,IACA,CAAC,KAAK;AAAA,EACR;AAEA,QAAM,UAAU,MAAM;AACpB,sBAAkB,OAAO;AAAA,EAC3B,GAAG,CAAC,iBAAiB,OAAO,CAAC;AAE7B,MAAI,WAAW,WAAW;AACxB,WAAO,oBAAC,kBAAe,OAAO,EAAE,qCAAqC,yBAAoB,GAAG;AAAA,EAC9F;AAEA,MAAI,WAAW,SAAS;AACtB,WACE;AAAA,MAAC;AAAA;AAAA,QACC,OAAO,EAAE,uCAAuC,2BAA2B;AAAA,QAC3E,QACE,oBAAC,UAAO,MAAK,UAAS,SAAQ,WAAU,MAAK,MAAK,SAAS,MAAM,KAAK,WAAW,QAAQ,GACtF,YAAE,oCAAoC,WAAW,GACpD;AAAA;AAAA,IAEJ;AAAA,EAEJ;AAEA,MAAI,MAAM,WAAW,GAAG;AACtB,WACE;AAAA,MAAC;AAAA;AAAA,QACC,OAAO,EAAE,8CAA8C,8BAA8B;AAAA,QACrF,aAAa;AAAA,UACX;AAAA,UACA;AAAA,QACF;AAAA;AAAA,IACF;AAAA,EAEJ;AAEA,QAAM,QAAQ,WAAW,MAAM,SAAS,YAAY;AACpD,QAAM,YAAY,KAAK,IAAI,GAAG,QAAQ,YAAY,MAAM;AAExD,SACE,qBAAC,SAAI,WAAU,uBACb;AAAA,wBAAC,SAAI,WAAU,mDACb,+BAAC,WAAM,WAAU,kCAAiC,eAAY,mBAC5D;AAAA,0BAAC,aAAQ,WAAU,WAChB,YAAE,0CAA0C,OAAO,GACtD;AAAA,MACA,oBAAC,WACC,+BAAC,QAAG,WAAU,gDACZ;AAAA,4BAAC,QAAG,OAAM,OAAM,WAAU,mDACvB,YAAE,oDAAoD,MAAM,GAC/D;AAAA,QACA,oBAAC,QAAG,OAAM,OAAM,WAAU,mDACvB,YAAE,gDAAgD,MAAM,GAC3D;AAAA,QACA,oBAAC,QAAG,OAAM,OAAM,WAAU,mDACvB,YAAE,iDAAiD,QAAQ,GAC9D;AAAA,QACA,oBAAC,QAAG,OAAM,OAAM,WAAU,mDACvB,YAAE,mDAAmD,UAAU,GAClE;AAAA,QACA,oBAAC,QAAG,OAAM,OAAM,WAAU,mDACvB,YAAE,+CAA+C,MAAM,GAC1D;AAAA,QACA,oBAAC,QAAG,OAAM,OAAM,WAAU,8DACvB,YAAE,gDAAgD,QAAQ,GAC7D;AAAA,SACF,GACF;AAAA,MACA,oBAAC,WACE,gBAAM,IAAI,CAAC,SACV;AAAA,QAAC;AAAA;AAAA,UAEC,iBAAe,KAAK;AAAA,UACpB,WAAU;AAAA,UAEV;AAAA,gCAAC,QAAG,WAAU,0DACX,eAAK,aAAa,UACrB;AAAA,YACA,oBAAC,QAAG,WAAU,eACZ;AAAA,cAAC;AAAA;AAAA,gBACC,MAAK;AAAA,gBACL,SAAQ;AAAA,gBACR,MAAK;AAAA,gBACL,SAAS,MAAM,WAAW,KAAK,EAAE;AAAA,gBACjC,WAAU;AAAA,gBAET,eAAK;AAAA;AAAA,YACR,GACF;AAAA,YACA,oBAAC,QAAG,WAAU,qCACX,eAAK,eAAe,YAAY,IAAI,KAAK,YAAY,KAAK,WAAM,UACnE;AAAA,YACA,oBAAC,QAAG,WAAU,qCACX,eAAK,wBACF,cAAc,MAAM,IAAI,KAAK,qBAAqB,KAClD,EAAE,6CAA6C,YAAY,IAC3D,EAAE,6CAA6C,YAAY,GACjE;AAAA,YACA,oBAAC,QAAG,WAAU,eACZ,8BAAC,UAAK,WAAU,wBACb,eAAK,OAAO,IAAI,CAAC,UAAU;AAG1B,oBAAM,QAAQ,UAAU,MAAM,IAAI,KAAK;AACvC,kBAAI,CAAC,MAAO,QAAO;AACnB,qBACE,oBAAC,SAAkB,SAAQ,WAAU,MAAK,MACvC,mBADS,KAEZ;AAAA,YAEJ,CAAC,GACH,GACF;AAAA,YACA,oBAAC,QAAG,WAAU,qEACX,6BAAmB,KAAK,aAAa,GACxC;AAAA;AAAA;AAAA,QA5CK,KAAK;AAAA,MA6CZ,CACD,GACH;AAAA,OACF,GACF;AAAA,IAEC,YAAY,IACX;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,SAAQ;AAAA,QACR,MAAK;AAAA,QACL,UAAU,WAAW;AAAA,QACrB,SAAS,MAAM,SAAS,CAAC,aAAa,WAAW,CAAC;AAAA,QAClD,eAAY;AAAA,QACZ,WAAU;AAAA,QAET,qBAAW,aACV,oBAAC,WAAQ,WAAU,UAAS,IAE5B,EAAE,sCAAsC,2BAA2B,EAAE,UAAU,CAAC;AAAA;AAAA,IAEpF,IACE;AAAA,KACN;AAEJ;AAEA,IAAO,uBAAQ;",
6
+ "names": []
7
+ }