@open-mercato/core 0.6.4-develop.4217.1.c9aa050183 → 0.6.4-develop.4239.1.4a264a5828

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 (408) hide show
  1. package/.turbo/turbo-build.log +2 -2
  2. package/dist/generated/entities/staff_time_entry/index.js +37 -0
  3. package/dist/generated/entities/staff_time_entry/index.js.map +7 -0
  4. package/dist/generated/entities/staff_time_entry_segment/index.js +23 -0
  5. package/dist/generated/entities/staff_time_entry_segment/index.js.map +7 -0
  6. package/dist/generated/entities/staff_time_project/index.js +35 -0
  7. package/dist/generated/entities/staff_time_project/index.js.map +7 -0
  8. package/dist/generated/entities/staff_time_project_member/index.js +29 -0
  9. package/dist/generated/entities/staff_time_project_member/index.js.map +7 -0
  10. package/dist/generated/entities.ids.generated.js +5 -1
  11. package/dist/generated/entities.ids.generated.js.map +2 -2
  12. package/dist/generated/entity-fields-registry.js +64 -0
  13. package/dist/generated/entity-fields-registry.js.map +2 -2
  14. package/dist/helpers/integration/timesheetFixtures.js +50 -0
  15. package/dist/helpers/integration/timesheetFixtures.js.map +7 -0
  16. package/dist/modules/attachments/api/library/[id]/route.js +20 -16
  17. package/dist/modules/attachments/api/library/[id]/route.js.map +2 -2
  18. package/dist/modules/attachments/api/route.js +18 -14
  19. package/dist/modules/attachments/api/route.js.map +2 -2
  20. package/dist/modules/auth/api/roles/acl/route.js +10 -4
  21. package/dist/modules/auth/api/roles/acl/route.js.map +2 -2
  22. package/dist/modules/auth/api/sidebar/preferences/route.js +27 -20
  23. package/dist/modules/auth/api/sidebar/preferences/route.js.map +2 -2
  24. package/dist/modules/auth/api/users/acl/route.js +16 -11
  25. package/dist/modules/auth/api/users/acl/route.js.map +2 -2
  26. package/dist/modules/auth/commands/users.js +87 -71
  27. package/dist/modules/auth/commands/users.js.map +2 -2
  28. package/dist/modules/auth/services/sidebarPreferencesService.js +39 -30
  29. package/dist/modules/auth/services/sidebarPreferencesService.js.map +2 -2
  30. package/dist/modules/business_rules/backend/logs/[id]/page.js +24 -5
  31. package/dist/modules/business_rules/backend/logs/[id]/page.js.map +2 -2
  32. package/dist/modules/catalog/api/offers/route.js +15 -5
  33. package/dist/modules/catalog/api/offers/route.js.map +2 -2
  34. package/dist/modules/catalog/commands/categories.js +61 -12
  35. package/dist/modules/catalog/commands/categories.js.map +2 -2
  36. package/dist/modules/catalog/commands/products.js +79 -54
  37. package/dist/modules/catalog/commands/products.js.map +2 -2
  38. package/dist/modules/catalog/commands/variants.js +29 -16
  39. package/dist/modules/catalog/commands/variants.js.map +2 -2
  40. package/dist/modules/currencies/backend/currencies/[id]/page.js +19 -2
  41. package/dist/modules/currencies/backend/currencies/[id]/page.js.map +2 -2
  42. package/dist/modules/currencies/commands/currencies.js +15 -8
  43. package/dist/modules/currencies/commands/currencies.js.map +2 -2
  44. package/dist/modules/customer_accounts/api/admin/users.js +27 -26
  45. package/dist/modules/customer_accounts/api/admin/users.js.map +2 -2
  46. package/dist/modules/customer_accounts/api/password/reset-confirm.js +5 -5
  47. package/dist/modules/customer_accounts/api/password/reset-confirm.js.map +2 -2
  48. package/dist/modules/customer_accounts/api/portal/users/[id]/roles.js +11 -10
  49. package/dist/modules/customer_accounts/api/portal/users/[id]/roles.js.map +2 -2
  50. package/dist/modules/customer_accounts/backend/customer_accounts/roles/[id]/page.js +27 -7
  51. package/dist/modules/customer_accounts/backend/customer_accounts/roles/[id]/page.js.map +2 -2
  52. package/dist/modules/customer_accounts/backend/customer_accounts/users/[id]/page.js +27 -7
  53. package/dist/modules/customer_accounts/backend/customer_accounts/users/[id]/page.js.map +2 -2
  54. package/dist/modules/customers/backend/customers/people/[id]/page.js +29 -8
  55. package/dist/modules/customers/backend/customers/people/[id]/page.js.map +2 -2
  56. package/dist/modules/customers/commands/addresses.js +35 -21
  57. package/dist/modules/customers/commands/addresses.js.map +2 -2
  58. package/dist/modules/customers/commands/companies.js +163 -162
  59. package/dist/modules/customers/commands/companies.js.map +2 -2
  60. package/dist/modules/customers/commands/deals.js +3 -4
  61. package/dist/modules/customers/commands/deals.js.map +2 -2
  62. package/dist/modules/customers/commands/interactions.js +19 -22
  63. package/dist/modules/customers/commands/interactions.js.map +2 -2
  64. package/dist/modules/customers/commands/people.js +18 -15
  65. package/dist/modules/customers/commands/people.js.map +2 -2
  66. package/dist/modules/customers/commands/personCompanyLinks.js +105 -94
  67. package/dist/modules/customers/commands/personCompanyLinks.js.map +2 -2
  68. package/dist/modules/customers/commands/pipeline-stages.js +30 -23
  69. package/dist/modules/customers/commands/pipeline-stages.js.map +2 -2
  70. package/dist/modules/customers/commands/pipelines.js +27 -20
  71. package/dist/modules/customers/commands/pipelines.js.map +2 -2
  72. package/dist/modules/customers/commands/tags.js +13 -5
  73. package/dist/modules/customers/commands/tags.js.map +2 -2
  74. package/dist/modules/dashboards/api/users/widgets/route.js +0 -1
  75. package/dist/modules/dashboards/api/users/widgets/route.js.map +2 -2
  76. package/dist/modules/dashboards/api/widgets/data/route.js +29 -1
  77. package/dist/modules/dashboards/api/widgets/data/route.js.map +2 -2
  78. package/dist/modules/data_sync/lib/sync-engine.js +4 -4
  79. package/dist/modules/data_sync/lib/sync-engine.js.map +2 -2
  80. package/dist/modules/data_sync/lib/sync-run-service.js +51 -27
  81. package/dist/modules/data_sync/lib/sync-run-service.js.map +2 -2
  82. package/dist/modules/directory/commands/organizations.js +192 -158
  83. package/dist/modules/directory/commands/organizations.js.map +3 -3
  84. package/dist/modules/inbox_ops/api/emails/[id]/reprocess/route.js +22 -16
  85. package/dist/modules/inbox_ops/api/emails/[id]/reprocess/route.js.map +2 -2
  86. package/dist/modules/messages/commands/messages.js +77 -75
  87. package/dist/modules/messages/commands/messages.js.map +2 -2
  88. package/dist/modules/messages/commands/shared.js +132 -132
  89. package/dist/modules/messages/commands/shared.js.map +2 -2
  90. package/dist/modules/perspectives/api/[tableId]/route.js +37 -26
  91. package/dist/modules/perspectives/api/[tableId]/route.js.map +2 -2
  92. package/dist/modules/progress/acl.js +8 -4
  93. package/dist/modules/progress/acl.js.map +2 -2
  94. package/dist/modules/resources/commands/resources.js +125 -117
  95. package/dist/modules/resources/commands/resources.js.map +2 -2
  96. package/dist/modules/resources/commands/tags.js +7 -3
  97. package/dist/modules/resources/commands/tags.js.map +2 -2
  98. package/dist/modules/sales/api/quotes/send/route.js +12 -11
  99. package/dist/modules/sales/api/quotes/send/route.js.map +2 -2
  100. package/dist/modules/sales/commands/documents.js +629 -478
  101. package/dist/modules/sales/commands/documents.js.map +2 -2
  102. package/dist/modules/sales/commands/payments.js +146 -146
  103. package/dist/modules/sales/commands/payments.js.map +2 -2
  104. package/dist/modules/sales/commands/returns.js +68 -60
  105. package/dist/modules/sales/commands/returns.js.map +2 -2
  106. package/dist/modules/staff/acl.js +10 -1
  107. package/dist/modules/staff/acl.js.map +2 -2
  108. package/dist/modules/staff/analytics.js +33 -0
  109. package/dist/modules/staff/analytics.js.map +7 -0
  110. package/dist/modules/staff/api/guards.js +31 -0
  111. package/dist/modules/staff/api/guards.js.map +7 -0
  112. package/dist/modules/staff/api/interceptors.js +96 -0
  113. package/dist/modules/staff/api/interceptors.js.map +7 -0
  114. package/dist/modules/staff/api/timesheets/my-projects/[projectId]/route.js +170 -0
  115. package/dist/modules/staff/api/timesheets/my-projects/[projectId]/route.js.map +7 -0
  116. package/dist/modules/staff/api/timesheets/my-projects/route.js +103 -0
  117. package/dist/modules/staff/api/timesheets/my-projects/route.js.map +7 -0
  118. package/dist/modules/staff/api/timesheets/projects/kpis/route.js +147 -0
  119. package/dist/modules/staff/api/timesheets/projects/kpis/route.js.map +7 -0
  120. package/dist/modules/staff/api/timesheets/time-entries/[id]/segments/[segmentId]/route.js +171 -0
  121. package/dist/modules/staff/api/timesheets/time-entries/[id]/segments/[segmentId]/route.js.map +7 -0
  122. package/dist/modules/staff/api/timesheets/time-entries/[id]/segments/route.js +180 -0
  123. package/dist/modules/staff/api/timesheets/time-entries/[id]/segments/route.js.map +7 -0
  124. package/dist/modules/staff/api/timesheets/time-entries/[id]/timer-start/route.js +155 -0
  125. package/dist/modules/staff/api/timesheets/time-entries/[id]/timer-start/route.js.map +7 -0
  126. package/dist/modules/staff/api/timesheets/time-entries/[id]/timer-stop/route.js +173 -0
  127. package/dist/modules/staff/api/timesheets/time-entries/[id]/timer-stop/route.js.map +7 -0
  128. package/dist/modules/staff/api/timesheets/time-entries/bulk/route.js +260 -0
  129. package/dist/modules/staff/api/timesheets/time-entries/bulk/route.js.map +7 -0
  130. package/dist/modules/staff/api/timesheets/time-entries/route.js +188 -0
  131. package/dist/modules/staff/api/timesheets/time-entries/route.js.map +7 -0
  132. package/dist/modules/staff/api/timesheets/time-projects/[id]/employees/route.js +159 -0
  133. package/dist/modules/staff/api/timesheets/time-projects/[id]/employees/route.js.map +7 -0
  134. package/dist/modules/staff/api/timesheets/time-projects/route.js +230 -0
  135. package/dist/modules/staff/api/timesheets/time-projects/route.js.map +7 -0
  136. package/dist/modules/staff/backend/staff/timesheets/page.js +710 -0
  137. package/dist/modules/staff/backend/staff/timesheets/page.js.map +7 -0
  138. package/dist/modules/staff/backend/staff/timesheets/page.meta.js +22 -0
  139. package/dist/modules/staff/backend/staff/timesheets/page.meta.js.map +7 -0
  140. package/dist/modules/staff/backend/staff/timesheets/projects/[id]/edit/page.js +125 -0
  141. package/dist/modules/staff/backend/staff/timesheets/projects/[id]/edit/page.js.map +7 -0
  142. package/dist/modules/staff/backend/staff/timesheets/projects/[id]/edit/page.meta.js +16 -0
  143. package/dist/modules/staff/backend/staff/timesheets/projects/[id]/edit/page.meta.js.map +7 -0
  144. package/dist/modules/staff/backend/staff/timesheets/projects/[id]/page.js +418 -0
  145. package/dist/modules/staff/backend/staff/timesheets/projects/[id]/page.js.map +7 -0
  146. package/dist/modules/staff/backend/staff/timesheets/projects/[id]/page.meta.js +16 -0
  147. package/dist/modules/staff/backend/staff/timesheets/projects/[id]/page.meta.js.map +7 -0
  148. package/dist/modules/staff/backend/staff/timesheets/projects/create/page.js +79 -0
  149. package/dist/modules/staff/backend/staff/timesheets/projects/create/page.js.map +7 -0
  150. package/dist/modules/staff/backend/staff/timesheets/projects/create/page.meta.js +16 -0
  151. package/dist/modules/staff/backend/staff/timesheets/projects/create/page.meta.js.map +7 -0
  152. package/dist/modules/staff/backend/staff/timesheets/projects/page.js +602 -0
  153. package/dist/modules/staff/backend/staff/timesheets/projects/page.js.map +7 -0
  154. package/dist/modules/staff/backend/staff/timesheets/projects/page.meta.js +25 -0
  155. package/dist/modules/staff/backend/staff/timesheets/projects/page.meta.js.map +7 -0
  156. package/dist/modules/staff/backend/staff/timesheets/projects/projectFormConfig.js +123 -0
  157. package/dist/modules/staff/backend/staff/timesheets/projects/projectFormConfig.js.map +7 -0
  158. package/dist/modules/staff/cli.js +38 -1
  159. package/dist/modules/staff/cli.js.map +2 -2
  160. package/dist/modules/staff/commands/index.js +2 -0
  161. package/dist/modules/staff/commands/index.js.map +2 -2
  162. package/dist/modules/staff/commands/leave-requests.js +30 -28
  163. package/dist/modules/staff/commands/leave-requests.js.map +3 -3
  164. package/dist/modules/staff/commands/team-members.js +21 -20
  165. package/dist/modules/staff/commands/team-members.js.map +2 -2
  166. package/dist/modules/staff/commands/timesheets-entries.js +409 -0
  167. package/dist/modules/staff/commands/timesheets-entries.js.map +7 -0
  168. package/dist/modules/staff/commands/timesheets-projects.js +618 -0
  169. package/dist/modules/staff/commands/timesheets-projects.js.map +7 -0
  170. package/dist/modules/staff/data/enrichers.js +104 -0
  171. package/dist/modules/staff/data/enrichers.js.map +7 -0
  172. package/dist/modules/staff/data/entities.js +226 -1
  173. package/dist/modules/staff/data/entities.js.map +2 -2
  174. package/dist/modules/staff/data/validators.js +113 -1
  175. package/dist/modules/staff/data/validators.js.map +2 -2
  176. package/dist/modules/staff/events.js +13 -1
  177. package/dist/modules/staff/events.js.map +2 -2
  178. package/dist/modules/staff/lib/crud.js +7 -1
  179. package/dist/modules/staff/lib/crud.js.map +2 -2
  180. package/dist/modules/staff/lib/staffMemberResolver.js +15 -0
  181. package/dist/modules/staff/lib/staffMemberResolver.js.map +7 -0
  182. package/dist/modules/staff/lib/timesheets-projects/computeProjectHoursTrend.js +60 -0
  183. package/dist/modules/staff/lib/timesheets-projects/computeProjectHoursTrend.js.map +7 -0
  184. package/dist/modules/staff/lib/timesheets-projects/computeProjectsKpis.js +260 -0
  185. package/dist/modules/staff/lib/timesheets-projects/computeProjectsKpis.js.map +7 -0
  186. package/dist/modules/staff/lib/timesheets-projects/dateBuckets.js +41 -0
  187. package/dist/modules/staff/lib/timesheets-projects/dateBuckets.js.map +7 -0
  188. package/dist/modules/staff/lib/timesheets-projects/initials.js +10 -0
  189. package/dist/modules/staff/lib/timesheets-projects/initials.js.map +7 -0
  190. package/dist/modules/staff/lib/timesheets-projects/kpiMath.js +12 -0
  191. package/dist/modules/staff/lib/timesheets-projects/kpiMath.js.map +7 -0
  192. package/dist/modules/staff/lib/timesheets-projects/listProjectMembersPreview.js +55 -0
  193. package/dist/modules/staff/lib/timesheets-projects/listProjectMembersPreview.js.map +7 -0
  194. package/dist/modules/staff/lib/timesheets-projects-ui/HoursSparkline.js +66 -0
  195. package/dist/modules/staff/lib/timesheets-projects-ui/HoursSparkline.js.map +7 -0
  196. package/dist/modules/staff/lib/timesheets-projects-ui/ProjectCard.js +81 -0
  197. package/dist/modules/staff/lib/timesheets-projects-ui/ProjectCard.js.map +7 -0
  198. package/dist/modules/staff/lib/timesheets-projects-ui/ProjectMembersAvatarStack.js +58 -0
  199. package/dist/modules/staff/lib/timesheets-projects-ui/ProjectMembersAvatarStack.js.map +7 -0
  200. package/dist/modules/staff/lib/timesheets-projects-ui/ProjectsKpiStrip.js +152 -0
  201. package/dist/modules/staff/lib/timesheets-projects-ui/ProjectsKpiStrip.js.map +7 -0
  202. package/dist/modules/staff/lib/timesheets-projects-ui/SavedViewTabs.js +37 -0
  203. package/dist/modules/staff/lib/timesheets-projects-ui/SavedViewTabs.js.map +7 -0
  204. package/dist/modules/staff/lib/timesheets-projects-ui/ViewModeToggle.js +57 -0
  205. package/dist/modules/staff/lib/timesheets-projects-ui/ViewModeToggle.js.map +7 -0
  206. package/dist/modules/staff/lib/timesheets-projects-ui/useProjectsViewMode.js +50 -0
  207. package/dist/modules/staff/lib/timesheets-projects-ui/useProjectsViewMode.js.map +7 -0
  208. package/dist/modules/staff/lib/timesheets-ui/AddRowDropdown.js +163 -0
  209. package/dist/modules/staff/lib/timesheets-ui/AddRowDropdown.js.map +7 -0
  210. package/dist/modules/staff/lib/timesheets-ui/CalendarPicker.js +209 -0
  211. package/dist/modules/staff/lib/timesheets-ui/CalendarPicker.js.map +7 -0
  212. package/dist/modules/staff/lib/timesheets-ui/ColorPicker.js +52 -0
  213. package/dist/modules/staff/lib/timesheets-ui/ColorPicker.js.map +7 -0
  214. package/dist/modules/staff/lib/timesheets-ui/CreateProjectDialog.js +77 -0
  215. package/dist/modules/staff/lib/timesheets-ui/CreateProjectDialog.js.map +7 -0
  216. package/dist/modules/staff/lib/timesheets-ui/ListView.js +173 -0
  217. package/dist/modules/staff/lib/timesheets-ui/ListView.js.map +7 -0
  218. package/dist/modules/staff/lib/timesheets-ui/ProjectColorDot.js +32 -0
  219. package/dist/modules/staff/lib/timesheets-ui/ProjectColorDot.js.map +7 -0
  220. package/dist/modules/staff/lib/timesheets-ui/TimerBar.js +270 -0
  221. package/dist/modules/staff/lib/timesheets-ui/TimerBar.js.map +7 -0
  222. package/dist/modules/staff/lib/timesheets-ui/ViewSwitcher.js +57 -0
  223. package/dist/modules/staff/lib/timesheets-ui/ViewSwitcher.js.map +7 -0
  224. package/dist/modules/staff/lib/timesheets-ui/colors.js +43 -0
  225. package/dist/modules/staff/lib/timesheets-ui/colors.js.map +7 -0
  226. package/dist/modules/staff/migrations/Migration20260326135612.js +24 -0
  227. package/dist/modules/staff/migrations/Migration20260326135612.js.map +7 -0
  228. package/dist/modules/staff/migrations/Migration20260413102715.js +23 -0
  229. package/dist/modules/staff/migrations/Migration20260413102715.js.map +7 -0
  230. package/dist/modules/staff/migrations/Migration20260413111602.js +13 -0
  231. package/dist/modules/staff/migrations/Migration20260413111602.js.map +7 -0
  232. package/dist/modules/staff/migrations/Migration20260511112759.js +19 -0
  233. package/dist/modules/staff/migrations/Migration20260511112759.js.map +7 -0
  234. package/dist/modules/staff/search.js +35 -0
  235. package/dist/modules/staff/search.js.map +2 -2
  236. package/dist/modules/staff/setup.js +15 -1
  237. package/dist/modules/staff/setup.js.map +2 -2
  238. package/dist/modules/staff/widgets/dashboard/timesheets-hours-by-project/config.js +16 -0
  239. package/dist/modules/staff/widgets/dashboard/timesheets-hours-by-project/config.js.map +7 -0
  240. package/dist/modules/staff/widgets/dashboard/timesheets-hours-by-project/widget.client.js +126 -0
  241. package/dist/modules/staff/widgets/dashboard/timesheets-hours-by-project/widget.client.js.map +7 -0
  242. package/dist/modules/staff/widgets/dashboard/timesheets-hours-by-project/widget.js +26 -0
  243. package/dist/modules/staff/widgets/dashboard/timesheets-hours-by-project/widget.js.map +7 -0
  244. package/dist/modules/staff/widgets/dashboard/timesheets-time-reporting/config.js +15 -0
  245. package/dist/modules/staff/widgets/dashboard/timesheets-time-reporting/config.js.map +7 -0
  246. package/dist/modules/staff/widgets/dashboard/timesheets-time-reporting/widget.client.js +238 -0
  247. package/dist/modules/staff/widgets/dashboard/timesheets-time-reporting/widget.client.js.map +7 -0
  248. package/dist/modules/staff/widgets/dashboard/timesheets-time-reporting/widget.js +26 -0
  249. package/dist/modules/staff/widgets/dashboard/timesheets-time-reporting/widget.js.map +7 -0
  250. package/dist/modules/staff/widgets/injection/timer-sidebar-indicator/widget.js +145 -0
  251. package/dist/modules/staff/widgets/injection/timer-sidebar-indicator/widget.js.map +7 -0
  252. package/dist/modules/staff/widgets/injection-table.js +12 -0
  253. package/dist/modules/staff/widgets/injection-table.js.map +7 -0
  254. package/dist/modules/sync_excel/api/import/route.js +19 -17
  255. package/dist/modules/sync_excel/api/import/route.js.map +2 -2
  256. package/dist/modules/translations/commands/translations.js +22 -19
  257. package/dist/modules/translations/commands/translations.js.map +2 -2
  258. package/dist/modules/workflows/backend/events/[id]/page.js +24 -6
  259. package/dist/modules/workflows/backend/events/[id]/page.js.map +2 -2
  260. package/dist/modules/workflows/backend/instances/[id]/page.js +27 -5
  261. package/dist/modules/workflows/backend/instances/[id]/page.js.map +2 -2
  262. package/dist/modules/workflows/backend/tasks/[id]/page.js +25 -6
  263. package/dist/modules/workflows/backend/tasks/[id]/page.js.map +2 -2
  264. package/generated/entities/staff_time_entry/index.ts +17 -0
  265. package/generated/entities/staff_time_entry_segment/index.ts +10 -0
  266. package/generated/entities/staff_time_project/index.ts +16 -0
  267. package/generated/entities/staff_time_project_member/index.ts +13 -0
  268. package/generated/entities.ids.generated.ts +5 -1
  269. package/generated/entity-fields-registry.ts +64 -0
  270. package/package.json +7 -7
  271. package/src/helpers/integration/timesheetFixtures.ts +61 -0
  272. package/src/modules/attachments/api/library/[id]/route.ts +24 -17
  273. package/src/modules/attachments/api/route.ts +20 -14
  274. package/src/modules/auth/api/roles/acl/route.ts +11 -5
  275. package/src/modules/auth/api/sidebar/preferences/route.ts +33 -24
  276. package/src/modules/auth/api/users/acl/route.ts +17 -12
  277. package/src/modules/auth/commands/users.ts +96 -80
  278. package/src/modules/auth/services/sidebarPreferencesService.ts +40 -32
  279. package/src/modules/business_rules/backend/logs/[id]/page.tsx +32 -7
  280. package/src/modules/catalog/api/offers/route.ts +20 -5
  281. package/src/modules/catalog/commands/categories.ts +61 -12
  282. package/src/modules/catalog/commands/products.ts +93 -60
  283. package/src/modules/catalog/commands/variants.ts +29 -16
  284. package/src/modules/currencies/backend/currencies/[id]/page.tsx +21 -2
  285. package/src/modules/currencies/commands/currencies.ts +27 -14
  286. package/src/modules/currencies/i18n/de.json +1 -0
  287. package/src/modules/currencies/i18n/en.json +1 -0
  288. package/src/modules/currencies/i18n/es.json +1 -0
  289. package/src/modules/currencies/i18n/pl.json +1 -0
  290. package/src/modules/customer_accounts/api/admin/users.ts +31 -26
  291. package/src/modules/customer_accounts/api/password/reset-confirm.ts +5 -6
  292. package/src/modules/customer_accounts/api/portal/users/[id]/roles.ts +14 -13
  293. package/src/modules/customer_accounts/backend/customer_accounts/roles/[id]/page.tsx +34 -11
  294. package/src/modules/customer_accounts/backend/customer_accounts/users/[id]/page.tsx +34 -11
  295. package/src/modules/customers/backend/customers/people/[id]/page.tsx +35 -11
  296. package/src/modules/customers/commands/addresses.ts +35 -23
  297. package/src/modules/customers/commands/companies.ts +166 -165
  298. package/src/modules/customers/commands/deals.ts +2 -4
  299. package/src/modules/customers/commands/interactions.ts +20 -26
  300. package/src/modules/customers/commands/people.ts +18 -15
  301. package/src/modules/customers/commands/personCompanyLinks.ts +109 -100
  302. package/src/modules/customers/commands/pipeline-stages.ts +31 -27
  303. package/src/modules/customers/commands/pipelines.ts +29 -23
  304. package/src/modules/customers/commands/tags.ts +13 -5
  305. package/src/modules/dashboards/api/users/widgets/route.ts +0 -1
  306. package/src/modules/dashboards/api/widgets/data/route.ts +36 -1
  307. package/src/modules/data_sync/lib/sync-engine.ts +4 -5
  308. package/src/modules/data_sync/lib/sync-run-service.ts +57 -28
  309. package/src/modules/directory/commands/organizations.ts +203 -166
  310. package/src/modules/inbox_ops/api/emails/[id]/reprocess/route.ts +26 -18
  311. package/src/modules/messages/commands/messages.ts +82 -80
  312. package/src/modules/messages/commands/shared.ts +138 -133
  313. package/src/modules/perspectives/api/[tableId]/route.ts +38 -27
  314. package/src/modules/progress/acl.ts +4 -0
  315. package/src/modules/resources/commands/resources.ts +127 -117
  316. package/src/modules/resources/commands/tags.ts +7 -3
  317. package/src/modules/sales/api/quotes/send/route.ts +17 -12
  318. package/src/modules/sales/commands/documents.ts +673 -481
  319. package/src/modules/sales/commands/payments.ts +158 -152
  320. package/src/modules/sales/commands/returns.ts +74 -63
  321. package/src/modules/staff/acl.ts +11 -0
  322. package/src/modules/staff/analytics.ts +30 -0
  323. package/src/modules/staff/api/guards.ts +59 -0
  324. package/src/modules/staff/api/interceptors.ts +122 -0
  325. package/src/modules/staff/api/timesheets/my-projects/[projectId]/route.ts +191 -0
  326. package/src/modules/staff/api/timesheets/my-projects/route.ts +115 -0
  327. package/src/modules/staff/api/timesheets/projects/kpis/route.ts +159 -0
  328. package/src/modules/staff/api/timesheets/time-entries/[id]/segments/[segmentId]/route.ts +187 -0
  329. package/src/modules/staff/api/timesheets/time-entries/[id]/segments/route.ts +191 -0
  330. package/src/modules/staff/api/timesheets/time-entries/[id]/timer-start/route.ts +168 -0
  331. package/src/modules/staff/api/timesheets/time-entries/[id]/timer-stop/route.ts +191 -0
  332. package/src/modules/staff/api/timesheets/time-entries/bulk/route.ts +292 -0
  333. package/src/modules/staff/api/timesheets/time-entries/route.ts +193 -0
  334. package/src/modules/staff/api/timesheets/time-projects/[id]/employees/route.ts +167 -0
  335. package/src/modules/staff/api/timesheets/time-projects/route.ts +244 -0
  336. package/src/modules/staff/backend/staff/timesheets/page.meta.ts +20 -0
  337. package/src/modules/staff/backend/staff/timesheets/page.tsx +899 -0
  338. package/src/modules/staff/backend/staff/timesheets/projects/[id]/edit/page.meta.ts +12 -0
  339. package/src/modules/staff/backend/staff/timesheets/projects/[id]/edit/page.tsx +141 -0
  340. package/src/modules/staff/backend/staff/timesheets/projects/[id]/page.meta.ts +12 -0
  341. package/src/modules/staff/backend/staff/timesheets/projects/[id]/page.tsx +579 -0
  342. package/src/modules/staff/backend/staff/timesheets/projects/create/page.meta.ts +12 -0
  343. package/src/modules/staff/backend/staff/timesheets/projects/create/page.tsx +90 -0
  344. package/src/modules/staff/backend/staff/timesheets/projects/page.meta.ts +23 -0
  345. package/src/modules/staff/backend/staff/timesheets/projects/page.tsx +765 -0
  346. package/src/modules/staff/backend/staff/timesheets/projects/projectFormConfig.ts +138 -0
  347. package/src/modules/staff/cli.ts +40 -1
  348. package/src/modules/staff/commands/index.ts +2 -0
  349. package/src/modules/staff/commands/leave-requests.ts +37 -29
  350. package/src/modules/staff/commands/team-members.ts +25 -20
  351. package/src/modules/staff/commands/timesheets-entries.ts +504 -0
  352. package/src/modules/staff/commands/timesheets-projects.ts +699 -0
  353. package/src/modules/staff/data/enrichers.ts +134 -0
  354. package/src/modules/staff/data/entities.ts +198 -0
  355. package/src/modules/staff/data/validators.ts +129 -0
  356. package/src/modules/staff/events.ts +13 -0
  357. package/src/modules/staff/i18n/de.json +209 -1
  358. package/src/modules/staff/i18n/en.json +209 -1
  359. package/src/modules/staff/i18n/es.json +209 -1
  360. package/src/modules/staff/i18n/pl.json +209 -1
  361. package/src/modules/staff/lib/crud.ts +8 -0
  362. package/src/modules/staff/lib/staffMemberResolver.ts +22 -0
  363. package/src/modules/staff/lib/timesheets-projects/computeProjectHoursTrend.ts +89 -0
  364. package/src/modules/staff/lib/timesheets-projects/computeProjectsKpis.ts +311 -0
  365. package/src/modules/staff/lib/timesheets-projects/dateBuckets.ts +37 -0
  366. package/src/modules/staff/lib/timesheets-projects/initials.ts +6 -0
  367. package/src/modules/staff/lib/timesheets-projects/kpiMath.ts +8 -0
  368. package/src/modules/staff/lib/timesheets-projects/listProjectMembersPreview.ts +83 -0
  369. package/src/modules/staff/lib/timesheets-projects-ui/HoursSparkline.tsx +75 -0
  370. package/src/modules/staff/lib/timesheets-projects-ui/ProjectCard.tsx +110 -0
  371. package/src/modules/staff/lib/timesheets-projects-ui/ProjectMembersAvatarStack.tsx +73 -0
  372. package/src/modules/staff/lib/timesheets-projects-ui/ProjectsKpiStrip.tsx +185 -0
  373. package/src/modules/staff/lib/timesheets-projects-ui/SavedViewTabs.tsx +53 -0
  374. package/src/modules/staff/lib/timesheets-projects-ui/ViewModeToggle.tsx +63 -0
  375. package/src/modules/staff/lib/timesheets-projects-ui/useProjectsViewMode.ts +63 -0
  376. package/src/modules/staff/lib/timesheets-ui/AddRowDropdown.tsx +188 -0
  377. package/src/modules/staff/lib/timesheets-ui/CalendarPicker.tsx +229 -0
  378. package/src/modules/staff/lib/timesheets-ui/ColorPicker.tsx +65 -0
  379. package/src/modules/staff/lib/timesheets-ui/CreateProjectDialog.tsx +99 -0
  380. package/src/modules/staff/lib/timesheets-ui/ListView.tsx +230 -0
  381. package/src/modules/staff/lib/timesheets-ui/ProjectColorDot.tsx +40 -0
  382. package/src/modules/staff/lib/timesheets-ui/TimerBar.tsx +327 -0
  383. package/src/modules/staff/lib/timesheets-ui/ViewSwitcher.tsx +60 -0
  384. package/src/modules/staff/lib/timesheets-ui/colors.ts +58 -0
  385. package/src/modules/staff/migrations/.snapshot-open-mercato.json +1148 -0
  386. package/src/modules/staff/migrations/Migration20260326135612.ts +26 -0
  387. package/src/modules/staff/migrations/Migration20260413102715.ts +25 -0
  388. package/src/modules/staff/migrations/Migration20260413111602.ts +13 -0
  389. package/src/modules/staff/migrations/Migration20260511112759.ts +21 -0
  390. package/src/modules/staff/search.ts +35 -0
  391. package/src/modules/staff/setup.ts +15 -0
  392. package/src/modules/staff/widgets/dashboard/timesheets-hours-by-project/config.ts +17 -0
  393. package/src/modules/staff/widgets/dashboard/timesheets-hours-by-project/widget.client.tsx +158 -0
  394. package/src/modules/staff/widgets/dashboard/timesheets-hours-by-project/widget.ts +25 -0
  395. package/src/modules/staff/widgets/dashboard/timesheets-time-reporting/config.ts +15 -0
  396. package/src/modules/staff/widgets/dashboard/timesheets-time-reporting/widget.client.tsx +297 -0
  397. package/src/modules/staff/widgets/dashboard/timesheets-time-reporting/widget.ts +25 -0
  398. package/src/modules/staff/widgets/injection/timer-sidebar-indicator/widget.tsx +161 -0
  399. package/src/modules/staff/widgets/injection-table.ts +10 -0
  400. package/src/modules/sync_excel/api/import/route.ts +23 -18
  401. package/src/modules/translations/commands/translations.ts +49 -41
  402. package/src/modules/workflows/backend/events/[id]/page.tsx +32 -10
  403. package/src/modules/workflows/backend/instances/[id]/page.tsx +33 -9
  404. package/src/modules/workflows/backend/tasks/[id]/page.tsx +33 -10
  405. package/src/modules/workflows/i18n/de.json +1 -0
  406. package/src/modules/workflows/i18n/en.json +1 -0
  407. package/src/modules/workflows/i18n/es.json +1 -0
  408. package/src/modules/workflows/i18n/pl.json +1 -0
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../../../src/modules/staff/backend/staff/timesheets/projects/page.tsx"],
4
+ "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport Link from 'next/link'\nimport { useRouter, useSearchParams } from 'next/navigation'\nimport type { ColumnDef, SortingState } from '@tanstack/react-table'\nimport { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport { DataTable, withDataTableNamespaces } from '@open-mercato/ui/backend/DataTable'\nimport type { FilterDef, FilterValues } from '@open-mercato/ui/backend/FilterOverlay'\nimport { RowActions } from '@open-mercato/ui/backend/RowActions'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { readApiResultOrThrow } from '@open-mercato/ui/backend/utils/apiCall'\nimport { deleteCrud } from '@open-mercato/ui/backend/utils/crud'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { useConfirmDialog } from '@open-mercato/ui/backend/confirm-dialog'\nimport { useOrganizationScopeVersion } from '@open-mercato/shared/lib/frontend/useOrganizationScope'\nimport { useT, type TranslateFn } from '@open-mercato/shared/lib/i18n/context'\nimport { formatDateTime } from '@open-mercato/shared/lib/time'\nimport { ProjectColorDot } from '../../../../lib/timesheets-ui/ProjectColorDot'\nimport { resolveProjectColorHex } from '../../../../lib/timesheets-ui/colors'\nimport {\n ProjectsKpiStrip,\n type PmKpis,\n type CollabKpis,\n} from '../../../../lib/timesheets-projects-ui/ProjectsKpiStrip'\nimport { SavedViewTabs } from '../../../../lib/timesheets-projects-ui/SavedViewTabs'\nimport { HoursSparkline } from '../../../../lib/timesheets-projects-ui/HoursSparkline'\nimport {\n ProjectMembersAvatarStack,\n type AvatarMember,\n} from '../../../../lib/timesheets-projects-ui/ProjectMembersAvatarStack'\nimport { ViewModeToggle } from '../../../../lib/timesheets-projects-ui/ViewModeToggle'\nimport {\n useProjectsViewMode,\n type ProjectsViewMode,\n} from '../../../../lib/timesheets-projects-ui/useProjectsViewMode'\nimport {\n ProjectCard,\n type ProjectCardData,\n type ProjectCardLabels,\n} from '../../../../lib/timesheets-projects-ui/ProjectCard'\n\nconst PAGE_SIZE = 50\nconst INCLUDE_FIELDS = 'hoursWeek,hoursTrend,members,myRole'\n\ntype StaffEnrichment = {\n hoursWeek?: number\n hoursTrend?: number[]\n myRole?: string | null\n members?: AvatarMember[]\n memberCount?: number\n}\n\ntype ProjectRow = {\n id: string\n name: string\n code: string | null\n customerId: string | null\n customerName: string | null\n status: string\n projectType: string | null\n color: string | null\n startDate: string | null\n updatedAt: string | null\n hoursWeek: number\n hoursTrend: number[]\n myRole: string | null\n members: AvatarMember[]\n memberCount: number\n}\n\ntype ProjectsResponse = {\n items?: Array<Record<string, unknown>>\n total?: number\n totalPages?: number\n}\n\ntype KpisResponse = PmKpis | CollabKpis\n\nfunction formatRelativeTime(iso: string | null, fallback: string, t: TranslateFn): string {\n if (!iso) return fallback\n const parsed = new Date(iso)\n if (Number.isNaN(parsed.getTime())) return fallback\n const diffMs = Date.now() - parsed.getTime()\n const minutes = Math.round(diffMs / 60000)\n if (minutes < 1) return t('staff.timesheets.projects.portfolio.relativeTime.justNow', 'just now')\n if (minutes < 60) return t('staff.timesheets.projects.portfolio.relativeTime.minutesAgo', '{minutes}m ago', { minutes })\n const hours = Math.round(minutes / 60)\n if (hours < 24) return t('staff.timesheets.projects.portfolio.relativeTime.hoursAgo', '{hours}h ago', { hours })\n const days = Math.round(hours / 24)\n if (days < 14) return t('staff.timesheets.projects.portfolio.relativeTime.daysAgo', '{days}d ago', { days })\n return formatDateTime(iso) ?? fallback\n}\n\nfunction mapApiProject(item: Record<string, unknown>): ProjectRow {\n const id = typeof item.id === 'string' ? item.id : ''\n const name = typeof item.name === 'string' ? item.name : id\n const code = typeof item.code === 'string' && item.code.trim().length ? item.code.trim() : null\n const customerId =\n typeof item.customerId === 'string'\n ? item.customerId\n : typeof item.customer_id === 'string'\n ? item.customer_id\n : null\n const customerName =\n typeof item.customerName === 'string'\n ? item.customerName\n : typeof item.customer_name === 'string'\n ? item.customer_name\n : null\n const status = typeof item.status === 'string' ? item.status : 'active'\n const projectType =\n typeof item.projectType === 'string'\n ? item.projectType\n : typeof item.project_type === 'string'\n ? item.project_type\n : null\n const color = typeof item.color === 'string' ? item.color : null\n const startDate =\n typeof item.startDate === 'string'\n ? item.startDate\n : typeof item.start_date === 'string'\n ? item.start_date\n : null\n const updatedAt =\n typeof item.updatedAt === 'string'\n ? item.updatedAt\n : typeof item.updated_at === 'string'\n ? item.updated_at\n : null\n const enrichment =\n (item as { _staff?: StaffEnrichment })._staff ?? ({} as StaffEnrichment)\n const hoursWeek = typeof enrichment.hoursWeek === 'number' ? enrichment.hoursWeek : 0\n const hoursTrend = Array.isArray(enrichment.hoursTrend)\n ? enrichment.hoursTrend.filter((v): v is number => typeof v === 'number')\n : []\n const members = Array.isArray(enrichment.members)\n ? enrichment.members\n .filter((m): m is AvatarMember => !!m && typeof m === 'object' && typeof (m as AvatarMember).id === 'string')\n .map((m) => ({\n id: m.id,\n name: m.name ?? '',\n initials: m.initials ?? '',\n avatarUrl: m.avatarUrl ?? null,\n }))\n : []\n const memberCount = typeof enrichment.memberCount === 'number' ? enrichment.memberCount : members.length\n const myRole = typeof enrichment.myRole === 'string' ? enrichment.myRole : null\n\n return withDataTableNamespaces(\n {\n id,\n name,\n code,\n customerId,\n customerName,\n status,\n projectType,\n color,\n startDate,\n updatedAt,\n hoursWeek,\n hoursTrend,\n myRole,\n members,\n memberCount,\n },\n item,\n )\n}\n\nexport default function TimesheetProjectsPage() {\n const t = useT()\n const router = useRouter()\n const searchParams = useSearchParams()\n const scopeVersion = useOrganizationScopeVersion()\n const { confirm, ConfirmDialogElement } = useConfirmDialog()\n\n const [rows, setRows] = React.useState<ProjectRow[]>([])\n const [page, setPage] = React.useState(1)\n const [total, setTotal] = React.useState(0)\n const [totalPages, setTotalPages] = React.useState(1)\n const [sorting, setSorting] = React.useState<SortingState>([{ id: 'updatedAt', desc: true }])\n const [search, setSearch] = React.useState('')\n const [filterValues, setFilterValues] = React.useState<FilterValues>({})\n const [isLoading, setIsLoading] = React.useState(true)\n const [isRefreshing, setIsRefreshing] = React.useState(false)\n const hasLoadedOnceRef = React.useRef(false)\n const [reloadToken, setReloadToken] = React.useState(0)\n const [kpis, setKpis] = React.useState<KpisResponse | null>(null)\n const [isLoadingKpis, setIsLoadingKpis] = React.useState(true)\n\n const activeTab = searchParams.get('tab') ?? 'all'\n const urlViewMode = searchParams.get('view')\n const [viewMode, setViewMode] = useProjectsViewMode({\n userKey: null,\n urlOverride: urlViewMode,\n })\n\n const labels = React.useMemo(\n () => ({\n title: t('staff.timesheets.projects.page.title', 'Projects'),\n table: {\n name: t('staff.timesheets.projects.table.name', 'Project'),\n status: t('staff.timesheets.projects.table.status', 'Status'),\n type: t('staff.timesheets.projects.table.type', 'Type'),\n updatedAt: t('staff.timesheets.projects.table.updatedAt', 'Updated'),\n empty: t('staff.timesheets.projects.table.empty', 'No projects yet.'),\n search: t('staff.timesheets.projects.table.search', 'Search projects...'),\n team: t('staff.timesheets.projects.portfolio.team', 'Team'),\n myRole: t('staff.timesheets.projects.portfolio.myRole', 'My role'),\n hoursWeek: t('staff.timesheets.projects.portfolio.hoursWeek', 'Hours / week'),\n myHoursWeek: t('staff.timesheets.projects.portfolio.myHoursWeek', 'My hours / week'),\n },\n actions: {\n add: t('staff.timesheets.projects.actions.add', 'Add Project'),\n addFirst: t('staff.timesheets.projects.actions.addFirst', '+ Add first project'),\n viewDetails: t('staff.timesheets.projects.actions.viewDetails', 'View Details'),\n delete: t('staff.timesheets.projects.actions.delete', 'Delete'),\n deleteConfirm: t('staff.timesheets.projects.actions.deleteConfirm', 'Delete project \"{{name}}\"?'),\n refresh: t('staff.timesheets.projects.actions.refresh', 'Refresh'),\n },\n messages: {\n deleted: t('staff.timesheets.projects.messages.deleted', 'Project deleted.'),\n },\n errors: {\n load: t('staff.timesheets.projects.errors.load', 'Failed to load projects.'),\n delete: t('staff.timesheets.projects.errors.delete', 'Failed to delete project.'),\n },\n statuses: {\n all: t('staff.timesheets.projects.statuses.all', 'All'),\n active: t('staff.timesheets.projects.statuses.active', 'Active'),\n on_hold: t('staff.timesheets.projects.statuses.onHold', 'On Hold'),\n completed: t('staff.timesheets.projects.statuses.completed', 'Completed'),\n },\n tabs: {\n all: t('staff.timesheets.projects.portfolio.tabs.all', 'All'),\n active: t('staff.timesheets.projects.portfolio.tabs.active', 'Active'),\n onHold: t('staff.timesheets.projects.portfolio.tabs.onHold', 'On Hold'),\n completed: t('staff.timesheets.projects.portfolio.tabs.completed', 'Completed'),\n mine: t('staff.timesheets.projects.portfolio.tabs.mine', 'Mine'),\n },\n viewMode: {\n table: t('staff.timesheets.projects.portfolio.viewMode.table', 'Table'),\n cards: t('staff.timesheets.projects.portfolio.viewMode.cards', 'Cards'),\n },\n kpi: {\n totalProjects: t('staff.timesheets.projects.portfolio.kpi.totalProjects', 'Total Projects'),\n hoursWeek: t('staff.timesheets.projects.portfolio.kpi.hoursWeek', 'Hours this week'),\n hoursWeekSub: t('staff.timesheets.projects.portfolio.kpi.hoursWeekSub', 'vs previous week'),\n assignedToMe: t('staff.timesheets.projects.portfolio.kpi.assignedToMe', 'Assigned to me'),\n hoursMonth: t('staff.timesheets.projects.portfolio.kpi.hoursMonth', 'Hours this month'),\n hoursMonthSub: t('staff.timesheets.projects.portfolio.kpi.hoursMonthSub', 'vs previous month'),\n teamActive: t('staff.timesheets.projects.portfolio.kpi.teamActive', 'Active team'),\n teamActiveSub: t('staff.timesheets.projects.portfolio.kpi.teamActiveSub', 'Members with entries this month'),\n myProjects: t('staff.timesheets.projects.portfolio.kpi.myProjects', 'My projects'),\n myHoursWeek: t('staff.timesheets.projects.portfolio.kpi.myHoursWeek', 'My hours this week'),\n myHoursMonth: t('staff.timesheets.projects.portfolio.kpi.myHoursMonth', 'My hours this month'),\n deltaFlat: t('staff.timesheets.projects.portfolio.kpi.deltaFlat', 'no change'),\n noPrevious: t('staff.timesheets.projects.portfolio.kpi.noPrevious', 'no previous data'),\n },\n card: {\n hoursPanelPm: t('staff.timesheets.projects.portfolio.card.hoursPanelPm', 'Team hours \u00B7 last 7w'),\n hoursPanelCollab: t('staff.timesheets.projects.portfolio.card.hoursPanelCollab', 'My hours \u00B7 last 7w'),\n sparklineAria: t('staff.timesheets.projects.portfolio.sparkline.ariaLabel', 'Hours per week, last 7 weeks'),\n role: t('staff.timesheets.projects.portfolio.card.role', 'Role'),\n },\n emptyState: {\n noProjects: t('staff.timesheets.projects.portfolio.emptyState.noProjects', 'No projects yet.'),\n noAssignments: t(\n 'staff.timesheets.projects.portfolio.emptyState.noAssignments',\n \"You aren't assigned to any projects yet. Ask a PM to add you.\",\n ),\n noMatches: t('staff.timesheets.projects.portfolio.emptyState.noMatches', 'No projects match these filters.'),\n },\n }),\n [t],\n )\n\n const kpiLabels = React.useMemo(\n () => ({\n totalProjects: labels.kpi.totalProjects,\n totalProjectsSub: ({ active, onHold }: { active: number; onHold: number }) =>\n `${active} ${labels.statuses.active.toLowerCase()} \u00B7 ${onHold} ${labels.statuses.on_hold.toLowerCase()}`,\n hoursWeek: labels.kpi.hoursWeek,\n hoursWeekSub: labels.kpi.hoursWeekSub,\n assignedToMe: labels.kpi.assignedToMe,\n assignedToMeSub: (active: number) => `${active} ${labels.statuses.active.toLowerCase()}`,\n hoursMonth: labels.kpi.hoursMonth,\n hoursMonthSub: labels.kpi.hoursMonthSub,\n teamActive: labels.kpi.teamActive,\n teamActiveSub: labels.kpi.teamActiveSub,\n myProjects: labels.kpi.myProjects,\n myProjectsSub: (active: number) => `${active} ${labels.statuses.active.toLowerCase()}`,\n myHoursWeek: labels.kpi.myHoursWeek,\n myHoursMonth: labels.kpi.myHoursMonth,\n deltaUp: (pct: number) => `up ${pct}%`,\n deltaDown: (pct: number) => `down ${pct}%`,\n deltaFlat: labels.kpi.deltaFlat,\n noPrevious: labels.kpi.noPrevious,\n }),\n [labels],\n )\n\n const isPmRole = kpis?.role === 'pm'\n\n const filters = React.useMemo<FilterDef[]>(\n () => [\n {\n id: 'status',\n label: labels.table.status,\n type: 'select',\n options: [\n { value: 'active', label: labels.statuses.active },\n { value: 'on_hold', label: labels.statuses.on_hold },\n { value: 'completed', label: labels.statuses.completed },\n ],\n },\n ],\n [labels.table.status, labels.statuses],\n )\n\n const tabs = React.useMemo(() => {\n const base = [\n { id: 'all', label: labels.tabs.all },\n { id: 'active', label: labels.tabs.active },\n ]\n if (isPmRole) {\n base.push({ id: 'on_hold', label: labels.tabs.onHold })\n }\n base.push({ id: 'completed', label: labels.tabs.completed })\n if (isPmRole) {\n base.push({ id: 'mine', label: labels.tabs.mine })\n }\n return base\n }, [labels.tabs, isPmRole])\n\n const statusFromTab = (tabId: string): string | null => {\n if (tabId === 'active' || tabId === 'on_hold' || tabId === 'completed') return tabId\n return null\n }\n const mineFromTab = (tabId: string): boolean => tabId === 'mine' || !isPmRole\n\n const loadKpis = React.useCallback(async () => {\n setIsLoadingKpis(true)\n try {\n const payload = await readApiResultOrThrow<KpisResponse>(\n '/api/staff/timesheets/projects/kpis',\n undefined,\n {\n errorMessage: labels.errors.load,\n fallback: null as unknown as KpisResponse,\n },\n )\n setKpis(payload)\n } catch {\n setKpis(null)\n } finally {\n setIsLoadingKpis(false)\n }\n }, [labels.errors.load])\n\n const loadProjects = React.useCallback(async () => {\n if (hasLoadedOnceRef.current) {\n setIsRefreshing(true)\n } else {\n setIsLoading(true)\n }\n try {\n const params = new URLSearchParams({\n page: String(page),\n pageSize: String(PAGE_SIZE),\n include: INCLUDE_FIELDS,\n })\n const sort = sorting[0]\n if (sort?.id) {\n params.set('sortField', sort.id)\n params.set('sortDir', sort.desc ? 'desc' : 'asc')\n }\n if (search.trim()) params.set('q', search.trim())\n const tabStatus = statusFromTab(activeTab)\n if (tabStatus) params.set('status', tabStatus)\n else if (typeof filterValues.status === 'string' && filterValues.status.length > 0) {\n params.set('status', filterValues.status)\n }\n if (mineFromTab(activeTab)) params.set('mine', '1')\n\n const payload = await readApiResultOrThrow<ProjectsResponse>(\n `/api/staff/timesheets/time-projects?${params.toString()}`,\n undefined,\n { errorMessage: labels.errors.load, fallback: { items: [], total: 0, totalPages: 1 } },\n )\n const items = Array.isArray(payload.items) ? payload.items : []\n setRows(items.map(mapApiProject))\n setTotal(typeof payload.total === 'number' ? payload.total : items.length)\n setTotalPages(\n typeof payload.totalPages === 'number'\n ? payload.totalPages\n : Math.max(1, Math.ceil(items.length / PAGE_SIZE)),\n )\n } catch (error) {\n console.error('staff.timesheets.projects.list', error)\n flash(labels.errors.load, 'error')\n } finally {\n setIsLoading(false)\n setIsRefreshing(false)\n hasLoadedOnceRef.current = true\n }\n }, [labels.errors.load, page, search, sorting, filterValues.status, activeTab, isPmRole])\n\n React.useEffect(() => {\n void loadKpis()\n }, [loadKpis, scopeVersion, reloadToken])\n\n React.useEffect(() => {\n void loadProjects()\n }, [loadProjects, scopeVersion, reloadToken])\n\n const handleTabSelect = React.useCallback(\n (id: string) => {\n const params = new URLSearchParams(searchParams.toString())\n if (id === 'all') params.delete('tab')\n else params.set('tab', id)\n router.replace(`?${params.toString()}`)\n setPage(1)\n },\n [router, searchParams],\n )\n\n const handleViewModeChange = React.useCallback(\n (next: ProjectsViewMode) => {\n setViewMode(next)\n const params = new URLSearchParams(searchParams.toString())\n if (next === 'table') params.delete('view')\n else params.set('view', next)\n router.replace(`?${params.toString()}`)\n },\n [router, searchParams, setViewMode],\n )\n\n const handleSearchChange = React.useCallback((value: string) => {\n setSearch(value)\n setPage(1)\n }, [])\n\n const handleFiltersApply = React.useCallback((values: FilterValues) => {\n setFilterValues(values)\n setPage(1)\n }, [])\n\n const handleFiltersClear = React.useCallback(() => {\n setFilterValues({})\n setPage(1)\n }, [])\n\n const handleRefresh = React.useCallback(() => {\n setReloadToken((token) => token + 1)\n }, [])\n\n const handleDelete = React.useCallback(\n async (entry: ProjectRow) => {\n const message = labels.actions.deleteConfirm.replace('{{name}}', entry.name)\n const confirmed = await confirm({\n title: labels.actions.delete,\n text: message,\n variant: 'destructive',\n })\n if (!confirmed) return\n try {\n await deleteCrud('staff/timesheets/time-projects', entry.id, { errorMessage: labels.errors.delete })\n flash(labels.messages.deleted, 'success')\n handleRefresh()\n } catch (error) {\n console.error('staff.timesheets.projects.delete', error)\n flash(labels.errors.delete, 'error')\n }\n },\n [confirm, handleRefresh, labels.actions.deleteConfirm, labels.actions.delete, labels.errors.delete, labels.messages.deleted],\n )\n\n const columns = React.useMemo<ColumnDef<ProjectRow>[]>(\n () => [\n {\n accessorKey: 'name',\n header: labels.table.name,\n meta: { priority: 1, sticky: true },\n cell: ({ row }) => (\n <div className=\"flex items-center gap-2.5\">\n <ProjectColorDot colorKey={row.original.color} projectName={row.original.name} size=\"sm\" />\n <div className=\"flex min-w-0 flex-col\">\n <span className=\"truncate text-sm font-medium text-foreground\">{row.original.name}</span>\n <span className=\"truncate font-mono text-[11px] text-muted-foreground\">\n {row.original.code ?? '\u2014'}\n {row.original.customerName ? ` \u00B7 ${row.original.customerName}` : ''}\n </span>\n </div>\n </div>\n ),\n },\n {\n accessorKey: 'status',\n header: labels.table.status,\n meta: { priority: 2 },\n cell: ({ row }) => {\n const badgeClass =\n row.original.status === 'active'\n ? 'bg-lime-100 text-lime-800 dark:bg-lime-900/30 dark:text-lime-300'\n : row.original.status === 'on_hold'\n ? 'bg-amber-100 text-amber-800 dark:bg-amber-900/30 dark:text-amber-300'\n : 'bg-muted text-muted-foreground'\n const statusLabel =\n labels.statuses[row.original.status as keyof typeof labels.statuses] ?? row.original.status\n return (\n <span\n className={`inline-flex items-center rounded-full px-2 py-0.5 text-[11px] font-medium ${badgeClass}`}\n >\n {statusLabel}\n </span>\n )\n },\n },\n {\n accessorKey: 'projectType',\n header: labels.table.type,\n meta: { priority: 3 },\n cell: ({ row }) =>\n row.original.projectType ? (\n <span className=\"text-sm text-foreground\">{row.original.projectType}</span>\n ) : (\n <span className=\"text-xs text-muted-foreground/70\">\u2014</span>\n ),\n },\n isPmRole\n ? {\n accessorKey: 'members',\n id: 'members',\n header: labels.table.team,\n enableSorting: false,\n meta: { priority: 4 },\n cell: ({ row }) => (\n <ProjectMembersAvatarStack\n members={row.original.members}\n total={row.original.memberCount}\n peopleCountLabel={`${row.original.memberCount}`}\n />\n ),\n }\n : {\n accessorKey: 'myRole',\n header: labels.table.myRole,\n enableSorting: false,\n meta: { priority: 4 },\n cell: ({ row }) =>\n row.original.myRole ? (\n <span className=\"text-sm text-foreground\">{row.original.myRole}</span>\n ) : (\n <span className=\"text-xs text-muted-foreground/70\">\u2014</span>\n ),\n },\n {\n accessorKey: 'hoursWeek',\n header: isPmRole ? labels.table.hoursWeek : labels.table.myHoursWeek,\n enableSorting: false,\n meta: { priority: 5 },\n cell: ({ row }) => {\n const stripe = resolveProjectColorHex(row.original.color, row.original.name)\n return (\n <div className=\"flex items-center justify-end gap-2\">\n <HoursSparkline\n values={row.original.hoursTrend}\n color={stripe}\n ariaLabel={labels.card.sparklineAria}\n />\n <span className=\"text-xs font-medium tabular-nums text-foreground\">\n {row.original.hoursWeek > 0 ? `${row.original.hoursWeek}h` : '\u2014'}\n </span>\n </div>\n )\n },\n },\n {\n accessorKey: 'updatedAt',\n header: labels.table.updatedAt,\n meta: { priority: 6 },\n cell: ({ row }) => (\n <span className=\"text-xs text-muted-foreground\">\n {formatRelativeTime(row.original.updatedAt, '\u2014', t)}\n </span>\n ),\n },\n ],\n [labels.table, labels.statuses, labels.card.sparklineAria, isPmRole],\n )\n\n const cardLabels = React.useMemo<ProjectCardLabels>(\n () => ({\n hoursPanelPm: labels.card.hoursPanelPm,\n hoursPanelCollab: labels.card.hoursPanelCollab,\n sparklineAria: labels.card.sparklineAria,\n peopleCount: (count: number) => `${count}`,\n role: labels.card.role,\n noCustomer: '\u2014',\n statuses: labels.statuses,\n }),\n [labels.card, labels.statuses],\n )\n\n const canManage = isPmRole\n\n const emptyStateCopy = React.useMemo(() => {\n const hasFiltersApplied = activeTab !== 'all' || search.trim().length > 0 || Object.values(filterValues).some(Boolean)\n if (hasFiltersApplied) return labels.emptyState.noMatches\n if (!canManage) return labels.emptyState.noAssignments\n return labels.emptyState.noProjects\n }, [activeTab, search, filterValues, canManage, labels.emptyState])\n\n const cardsData: ProjectCardData[] = rows.map((row) => ({\n id: row.id,\n name: row.name,\n code: row.code,\n customerName: row.customerName,\n color: row.color,\n status: row.status,\n hoursWeek: row.hoursWeek,\n hoursTrend: row.hoursTrend,\n members: row.members,\n memberCount: row.memberCount,\n myRole: row.myRole,\n updatedAt: row.updatedAt,\n }))\n\n return (\n <Page>\n <PageBody>\n <div className=\"mb-4\">\n <ProjectsKpiStrip kpis={kpis} labels={kpiLabels} isLoading={isLoadingKpis} />\n </div>\n\n <div className=\"mb-3 flex flex-wrap items-center justify-between gap-3\">\n <SavedViewTabs\n tabs={tabs}\n activeId={activeTab}\n onSelect={handleTabSelect}\n ariaLabel={t('staff.timesheets.projects.portfolio.savedViews.ariaLabel', 'Saved views')}\n />\n <ViewModeToggle\n mode={viewMode}\n onChange={handleViewModeChange}\n tableLabel={labels.viewMode.table}\n cardsLabel={labels.viewMode.cards}\n ariaLabel={t('staff.timesheets.projects.portfolio.viewMode.ariaLabel', 'View mode')}\n />\n </div>\n\n {viewMode === 'cards' ? (\n <div>\n {isLoading ? (\n <div className=\"grid grid-cols-1 gap-3 md:grid-cols-2 lg:grid-cols-3\">\n {Array.from({ length: 6 }).map((_, idx) => (\n <div key={idx} className=\"h-48 animate-pulse rounded-lg border border-border bg-muted/40\" />\n ))}\n </div>\n ) : rows.length === 0 ? (\n <div className=\"rounded-lg border border-dashed border-border bg-card p-10 text-center\">\n <p className=\"text-sm text-muted-foreground\">{emptyStateCopy}</p>\n {canManage ? (\n <div className=\"mt-3\">\n <Button asChild size=\"sm\">\n <Link href=\"/backend/staff/timesheets/projects/create\">\n {labels.actions.addFirst}\n </Link>\n </Button>\n </div>\n ) : null}\n </div>\n ) : (\n <div className=\"grid grid-cols-1 gap-3 md:grid-cols-2 lg:grid-cols-3\">\n {cardsData.map((card) => (\n <ProjectCard\n key={card.id}\n data={card}\n labels={cardLabels}\n showTeam={isPmRole}\n href={`/backend/staff/timesheets/projects/${card.id}`}\n />\n ))}\n </div>\n )}\n </div>\n ) : (\n <DataTable<ProjectRow>\n title={labels.title}\n data={rows}\n columns={columns}\n isLoading={isLoading}\n searchValue={search}\n onSearchChange={handleSearchChange}\n searchPlaceholder={labels.table.search}\n filters={filters}\n filterValues={filterValues}\n onFiltersApply={handleFiltersApply}\n onFiltersClear={handleFiltersClear}\n emptyState={\n <div className=\"py-12 text-center\">\n <p className=\"text-sm text-muted-foreground mb-4\">{emptyStateCopy}</p>\n {canManage ? (\n <Button asChild size=\"sm\">\n <Link href=\"/backend/staff/timesheets/projects/create\">{labels.actions.addFirst}</Link>\n </Button>\n ) : null}\n </div>\n }\n actions={\n canManage ? (\n <Button asChild size=\"sm\">\n <Link href=\"/backend/staff/timesheets/projects/create\">{labels.actions.add}</Link>\n </Button>\n ) : undefined\n }\n refreshButton={{\n label: labels.actions.refresh,\n onRefresh: handleRefresh,\n isRefreshing: isLoading || isRefreshing,\n }}\n sortable\n sorting={sorting}\n onSortingChange={setSorting}\n pagination={{\n page,\n pageSize: PAGE_SIZE,\n total,\n totalPages,\n onPageChange: setPage,\n }}\n rowActions={(row) => (\n <RowActions\n items={[\n {\n id: 'view',\n label: labels.actions.viewDetails,\n href: `/backend/staff/timesheets/projects/${row.id}`,\n },\n ...(canManage\n ? [\n {\n id: 'delete',\n label: labels.actions.delete,\n destructive: true,\n onSelect: () => {\n void handleDelete(row)\n },\n },\n ]\n : []),\n ]}\n />\n )}\n onRowClick={(row) => router.push(`/backend/staff/timesheets/projects/${row.id}`)}\n />\n )}\n </PageBody>\n {ConfirmDialogElement}\n </Page>\n )\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,25 @@
1
+ import React from "react";
2
+ const folderIcon = React.createElement(
3
+ "svg",
4
+ { width: 16, height: 16, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2 },
5
+ React.createElement("path", { d: "M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z" })
6
+ );
7
+ const metadata = {
8
+ requireAuth: true,
9
+ requireFeatures: ["staff.timesheets.projects.view"],
10
+ navHidden: false,
11
+ pageTitle: "Projects",
12
+ pageTitleKey: "staff.timesheets.nav.projects",
13
+ pageGroup: "Employees",
14
+ pageGroupKey: "staff.nav.group",
15
+ pageOrder: 86,
16
+ icon: folderIcon,
17
+ breadcrumb: [
18
+ { label: "My Timesheets", labelKey: "staff.timesheets.nav.my_timesheets", href: "/backend/staff/timesheets" },
19
+ { label: "Projects", labelKey: "staff.timesheets.nav.projects" }
20
+ ]
21
+ };
22
+ export {
23
+ metadata
24
+ };
25
+ //# sourceMappingURL=page.meta.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../../../src/modules/staff/backend/staff/timesheets/projects/page.meta.ts"],
4
+ "sourcesContent": ["import React from 'react'\n\nconst folderIcon = React.createElement(\n 'svg',\n { width: 16, height: 16, viewBox: '0 0 24 24', fill: 'none', stroke: 'currentColor', strokeWidth: 2 },\n React.createElement('path', { d: 'M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z' }),\n)\n\nexport const metadata = {\n requireAuth: true,\n requireFeatures: ['staff.timesheets.projects.view'],\n navHidden: false,\n pageTitle: 'Projects',\n pageTitleKey: 'staff.timesheets.nav.projects',\n pageGroup: 'Employees',\n pageGroupKey: 'staff.nav.group',\n pageOrder: 86,\n icon: folderIcon,\n breadcrumb: [\n { label: 'My Timesheets', labelKey: 'staff.timesheets.nav.my_timesheets', href: '/backend/staff/timesheets' },\n { label: 'Projects', labelKey: 'staff.timesheets.nav.projects' },\n ],\n}\n"],
5
+ "mappings": "AAAA,OAAO,WAAW;AAElB,MAAM,aAAa,MAAM;AAAA,EACvB;AAAA,EACA,EAAE,OAAO,IAAI,QAAQ,IAAI,SAAS,aAAa,MAAM,QAAQ,QAAQ,gBAAgB,aAAa,EAAE;AAAA,EACpG,MAAM,cAAc,QAAQ,EAAE,GAAG,8EAA8E,CAAC;AAClH;AAEO,MAAM,WAAW;AAAA,EACtB,aAAa;AAAA,EACb,iBAAiB,CAAC,gCAAgC;AAAA,EAClD,WAAW;AAAA,EACX,WAAW;AAAA,EACX,cAAc;AAAA,EACd,WAAW;AAAA,EACX,cAAc;AAAA,EACd,WAAW;AAAA,EACX,MAAM;AAAA,EACN,YAAY;AAAA,IACV,EAAE,OAAO,iBAAiB,UAAU,sCAAsC,MAAM,4BAA4B;AAAA,IAC5G,EAAE,OAAO,YAAY,UAAU,gCAAgC;AAAA,EACjE;AACF;",
6
+ "names": []
7
+ }
@@ -0,0 +1,123 @@
1
+ import * as React from "react";
2
+ import { z } from "zod";
3
+ import { ColorPicker } from "../../../../lib/timesheets-ui/ColorPicker.js";
4
+ import { PROJECT_COLOR_KEYS } from "../../../../lib/timesheets-ui/colors.js";
5
+ function createProjectFormSchema() {
6
+ return z.object({
7
+ name: z.string().min(1),
8
+ code: z.string().min(1).max(50).regex(/^[a-zA-Z0-9-]+$/),
9
+ description: z.string().max(2e3).optional().nullable(),
10
+ projectType: z.string().max(100).optional().nullable(),
11
+ color: z.string().refine(
12
+ (value) => PROJECT_COLOR_KEYS.includes(value),
13
+ { message: "Invalid project color key." }
14
+ ).optional().nullable(),
15
+ startDate: z.string().optional().nullable(),
16
+ costCenter: z.string().max(100).optional().nullable(),
17
+ status: z.enum(["active", "on_hold", "completed"]).optional()
18
+ });
19
+ }
20
+ function createProjectFormFields(t) {
21
+ return [
22
+ {
23
+ id: "name",
24
+ type: "text",
25
+ label: t("staff.timesheets.projects.form.name", "Name"),
26
+ placeholder: t("staff.timesheets.projects.form.namePlaceholder", "Project name"),
27
+ required: true
28
+ },
29
+ {
30
+ id: "code",
31
+ type: "text",
32
+ label: t("staff.timesheets.projects.form.code", "Code"),
33
+ placeholder: t("staff.timesheets.projects.form.codePlaceholder", "PROJECT-001"),
34
+ required: true
35
+ },
36
+ {
37
+ id: "status",
38
+ type: "select",
39
+ label: t("staff.timesheets.projects.form.status", "Status"),
40
+ options: [
41
+ { value: "active", label: t("staff.timesheets.projects.statuses.active", "Active") },
42
+ { value: "on_hold", label: t("staff.timesheets.projects.statuses.onHold", "On Hold") },
43
+ { value: "completed", label: t("staff.timesheets.projects.statuses.completed", "Completed") }
44
+ ]
45
+ },
46
+ {
47
+ id: "description",
48
+ type: "textarea",
49
+ label: t("staff.timesheets.projects.form.description", "Description"),
50
+ placeholder: t("staff.timesheets.projects.form.descriptionPlaceholder", "Project description")
51
+ },
52
+ {
53
+ id: "projectType",
54
+ type: "text",
55
+ label: t("staff.timesheets.projects.form.projectType", "Project type"),
56
+ placeholder: t("staff.timesheets.projects.form.projectTypePlaceholder", "e.g. Internal, Client, R&D")
57
+ },
58
+ {
59
+ id: "color",
60
+ type: "custom",
61
+ label: t("staff.timesheets.projects.form.color", "Project color"),
62
+ component: ({ value, setValue }) => {
63
+ const current = typeof value === "string" ? value : null;
64
+ return React.createElement(ColorPicker, {
65
+ value: current,
66
+ onChange: (next) => setValue(next),
67
+ resetLabel: t("staff.timesheets.projects.form.colorAuto", "Auto")
68
+ });
69
+ }
70
+ },
71
+ {
72
+ id: "startDate",
73
+ type: "date",
74
+ label: t("staff.timesheets.projects.form.startDate", "Start date")
75
+ },
76
+ {
77
+ id: "costCenter",
78
+ type: "text",
79
+ label: t("staff.timesheets.projects.form.costCenter", "Cost center"),
80
+ placeholder: t("staff.timesheets.projects.form.costCenterPlaceholder", "Cost center code")
81
+ }
82
+ ];
83
+ }
84
+ function createProjectFormGroups(t) {
85
+ return [
86
+ {
87
+ id: "main",
88
+ title: t("staff.timesheets.projects.form.groupMain", "Project Details"),
89
+ fields: ["name", "code", "status", "color", "projectType", "startDate"]
90
+ },
91
+ {
92
+ id: "details",
93
+ title: t("staff.timesheets.projects.form.groupDetails", "Additional Information"),
94
+ fields: ["description", "costCenter"]
95
+ }
96
+ ];
97
+ }
98
+ function buildProjectPayload(values) {
99
+ const payload = {
100
+ name: values.name.trim(),
101
+ code: values.code.trim()
102
+ };
103
+ if (values.id) payload.id = values.id;
104
+ if (values.description?.trim()) payload.description = values.description.trim();
105
+ else payload.description = null;
106
+ if (values.projectType?.trim()) payload.projectType = values.projectType.trim();
107
+ else payload.projectType = null;
108
+ if (values.color?.trim()) payload.color = values.color.trim();
109
+ else payload.color = null;
110
+ if (values.startDate) payload.startDate = values.startDate;
111
+ else payload.startDate = null;
112
+ if (values.costCenter?.trim()) payload.costCenter = values.costCenter.trim();
113
+ else payload.costCenter = null;
114
+ if (values.status) payload.status = values.status;
115
+ return payload;
116
+ }
117
+ export {
118
+ buildProjectPayload,
119
+ createProjectFormFields,
120
+ createProjectFormGroups,
121
+ createProjectFormSchema
122
+ };
123
+ //# sourceMappingURL=projectFormConfig.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../../../src/modules/staff/backend/staff/timesheets/projects/projectFormConfig.ts"],
4
+ "sourcesContent": ["import * as React from 'react'\nimport { z } from 'zod'\nimport type { CrudField, CrudFormGroup } from '@open-mercato/ui/backend/CrudForm'\nimport type { TranslateFn } from '@open-mercato/shared/lib/i18n/context'\nimport { ColorPicker } from '../../../../lib/timesheets-ui/ColorPicker'\nimport { PROJECT_COLOR_KEYS } from '../../../../lib/timesheets-ui/colors'\n\nexport type ProjectFormValues = {\n id?: string\n name: string\n code: string\n description?: string | null\n projectType?: string | null\n color?: string | null\n startDate?: string | null\n costCenter?: string | null\n status?: string\n}\n\nexport function createProjectFormSchema() {\n return z.object({\n name: z.string().min(1),\n code: z.string().min(1).max(50).regex(/^[a-zA-Z0-9-]+$/),\n description: z.string().max(2000).optional().nullable(),\n projectType: z.string().max(100).optional().nullable(),\n color: z\n .string()\n .refine(\n (value) => (PROJECT_COLOR_KEYS as readonly string[]).includes(value),\n { message: 'Invalid project color key.' },\n )\n .optional()\n .nullable(),\n startDate: z.string().optional().nullable(),\n costCenter: z.string().max(100).optional().nullable(),\n status: z.enum(['active', 'on_hold', 'completed']).optional(),\n })\n}\n\nexport function createProjectFormFields(t: TranslateFn): CrudField[] {\n return [\n {\n id: 'name',\n type: 'text',\n label: t('staff.timesheets.projects.form.name', 'Name'),\n placeholder: t('staff.timesheets.projects.form.namePlaceholder', 'Project name'),\n required: true,\n },\n {\n id: 'code',\n type: 'text',\n label: t('staff.timesheets.projects.form.code', 'Code'),\n placeholder: t('staff.timesheets.projects.form.codePlaceholder', 'PROJECT-001'),\n required: true,\n },\n {\n id: 'status',\n type: 'select',\n label: t('staff.timesheets.projects.form.status', 'Status'),\n options: [\n { value: 'active', label: t('staff.timesheets.projects.statuses.active', 'Active') },\n { value: 'on_hold', label: t('staff.timesheets.projects.statuses.onHold', 'On Hold') },\n { value: 'completed', label: t('staff.timesheets.projects.statuses.completed', 'Completed') },\n ],\n },\n {\n id: 'description',\n type: 'textarea',\n label: t('staff.timesheets.projects.form.description', 'Description'),\n placeholder: t('staff.timesheets.projects.form.descriptionPlaceholder', 'Project description'),\n },\n {\n id: 'projectType',\n type: 'text',\n label: t('staff.timesheets.projects.form.projectType', 'Project type'),\n placeholder: t('staff.timesheets.projects.form.projectTypePlaceholder', 'e.g. Internal, Client, R&D'),\n },\n {\n id: 'color',\n type: 'custom',\n label: t('staff.timesheets.projects.form.color', 'Project color'),\n component: ({ value, setValue }) => {\n const current = typeof value === 'string' ? value : null\n return React.createElement(ColorPicker, {\n value: current,\n onChange: (next: string | null) => setValue(next),\n resetLabel: t('staff.timesheets.projects.form.colorAuto', 'Auto'),\n })\n },\n },\n {\n id: 'startDate',\n type: 'date',\n label: t('staff.timesheets.projects.form.startDate', 'Start date'),\n },\n {\n id: 'costCenter',\n type: 'text',\n label: t('staff.timesheets.projects.form.costCenter', 'Cost center'),\n placeholder: t('staff.timesheets.projects.form.costCenterPlaceholder', 'Cost center code'),\n },\n ]\n}\n\nexport function createProjectFormGroups(t: TranslateFn): CrudFormGroup[] {\n return [\n {\n id: 'main',\n title: t('staff.timesheets.projects.form.groupMain', 'Project Details'),\n fields: ['name', 'code', 'status', 'color', 'projectType', 'startDate'],\n },\n {\n id: 'details',\n title: t('staff.timesheets.projects.form.groupDetails', 'Additional Information'),\n fields: ['description', 'costCenter'],\n },\n ]\n}\n\nexport function buildProjectPayload(values: ProjectFormValues): Record<string, unknown> {\n const payload: Record<string, unknown> = {\n name: values.name.trim(),\n code: values.code.trim(),\n }\n if (values.id) payload.id = values.id\n if (values.description?.trim()) payload.description = values.description.trim()\n else payload.description = null\n if (values.projectType?.trim()) payload.projectType = values.projectType.trim()\n else payload.projectType = null\n if (values.color?.trim()) payload.color = values.color.trim()\n else payload.color = null\n if (values.startDate) payload.startDate = values.startDate\n else payload.startDate = null\n if (values.costCenter?.trim()) payload.costCenter = values.costCenter.trim()\n else payload.costCenter = null\n if (values.status) payload.status = values.status\n return payload\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -1,5 +1,10 @@
1
1
  import { createRequestContainer } from "@open-mercato/shared/lib/di/container";
2
2
  import { seedStaffActivityTypes, seedStaffAddressTypes, seedStaffTeamExamples } from "./lib/seeds.js";
3
+ import { appendWidgetsToRoles } from "@open-mercato/core/modules/dashboards/lib/role-widgets";
4
+ const TIMESHEETS_DASHBOARD_WIDGET_IDS = [
5
+ "staff.timesheets.timeReporting",
6
+ "staff.timesheets.hoursByProject"
7
+ ];
3
8
  function parseArgs(rest) {
4
9
  const args = {};
5
10
  for (let i = 0; i < rest.length; i += 1) {
@@ -94,7 +99,39 @@ const seedAddressTypesCommand = {
94
99
  }
95
100
  }
96
101
  };
97
- var cli_default = [seedActivityTypesCommand, seedAddressTypesCommand, seedExamplesCommand];
102
+ const seedTimesheetsWidgetsCommand = {
103
+ command: "seed-timesheets-widgets",
104
+ async run(rest) {
105
+ const args = parseArgs(rest);
106
+ const tenantId = String(args.tenantId ?? args.tenant ?? "");
107
+ const organizationId = String(args.organizationId ?? args.org ?? args.orgId ?? "");
108
+ if (!tenantId || !organizationId) {
109
+ console.error("Usage: mercato staff seed-timesheets-widgets --tenant <tenantId> --org <organizationId>");
110
+ console.error("Backfills timesheets dashboard widgets (timeReporting, hoursByProject) to existing tenant roles.");
111
+ process.exit(1);
112
+ return;
113
+ }
114
+ const container = await createRequestContainer();
115
+ try {
116
+ const em = container.resolve("em");
117
+ await em.transactional(async (tem) => {
118
+ await appendWidgetsToRoles(tem, {
119
+ tenantId,
120
+ organizationId,
121
+ roleNames: ["superadmin", "admin", "employee"],
122
+ widgetIds: TIMESHEETS_DASHBOARD_WIDGET_IDS
123
+ });
124
+ });
125
+ console.log("\u{1F4CA} Timesheets dashboard widgets seeded for organization", organizationId);
126
+ } finally {
127
+ const disposable = container;
128
+ if (typeof disposable.dispose === "function") {
129
+ await disposable.dispose();
130
+ }
131
+ }
132
+ }
133
+ };
134
+ var cli_default = [seedActivityTypesCommand, seedAddressTypesCommand, seedExamplesCommand, seedTimesheetsWidgetsCommand];
98
135
  export {
99
136
  cli_default as default
100
137
  };
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/modules/staff/cli.ts"],
4
- "sourcesContent": ["import type { ModuleCli } from '@open-mercato/shared/modules/registry'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport { seedStaffActivityTypes, seedStaffAddressTypes, seedStaffTeamExamples, type StaffSeedScope } from './lib/seeds'\n\nfunction parseArgs(rest: string[]) {\n const args: Record<string, string> = {}\n for (let i = 0; i < rest.length; i += 1) {\n const part = rest[i]\n if (!part) continue\n if (part.startsWith('--')) {\n const [rawKey, rawValue] = part.slice(2).split('=')\n if (rawValue !== undefined) args[rawKey] = rawValue\n else if (rest[i + 1] && !rest[i + 1]!.startsWith('--')) {\n args[rawKey] = rest[i + 1]!\n i += 1\n }\n }\n }\n return args\n}\n\nconst seedExamplesCommand: ModuleCli = {\n command: 'seed-examples',\n async run(rest) {\n const args = parseArgs(rest)\n const tenantId = String(args.tenantId ?? args.tenant ?? '')\n const organizationId = String(args.organizationId ?? args.org ?? args.orgId ?? '')\n if (!tenantId || !organizationId) {\n console.error('Usage: mercato staff seed-examples --tenant <tenantId> --org <organizationId>')\n return\n }\n const container = await createRequestContainer()\n const scope: StaffSeedScope = { tenantId, organizationId }\n try {\n const em = container.resolve<EntityManager>('em')\n await em.transactional(async (tem) => {\n await seedStaffTeamExamples(tem, scope)\n })\n console.log('\uD83E\uDDE9 Staff team examples seeded for organization', organizationId)\n } finally {\n const disposable = container as unknown as { dispose?: () => Promise<void> }\n if (typeof disposable.dispose === 'function') {\n await disposable.dispose()\n }\n }\n },\n}\n\nconst seedActivityTypesCommand: ModuleCli = {\n command: 'seed-activity-types',\n async run(rest) {\n const args = parseArgs(rest)\n const tenantId = String(args.tenantId ?? args.tenant ?? '')\n const organizationId = String(args.organizationId ?? args.org ?? args.orgId ?? '')\n if (!tenantId || !organizationId) {\n console.error('Usage: mercato staff seed-activity-types --tenant <tenantId> --org <organizationId>')\n return\n }\n const container = await createRequestContainer()\n const scope: StaffSeedScope = { tenantId, organizationId }\n try {\n const em = container.resolve<EntityManager>('em')\n await em.transactional(async (tem) => {\n await seedStaffActivityTypes(tem, scope)\n })\n console.log('\uD83D\uDDC2\uFE0F Staff activity types seeded for organization', organizationId)\n } finally {\n const disposable = container as unknown as { dispose?: () => Promise<void> }\n if (typeof disposable.dispose === 'function') {\n await disposable.dispose()\n }\n }\n },\n}\n\nconst seedAddressTypesCommand: ModuleCli = {\n command: 'seed-address-types',\n async run(rest) {\n const args = parseArgs(rest)\n const tenantId = String(args.tenantId ?? args.tenant ?? '')\n const organizationId = String(args.organizationId ?? args.org ?? args.orgId ?? '')\n if (!tenantId || !organizationId) {\n console.error('Usage: mercato staff seed-address-types --tenant <tenantId> --org <organizationId>')\n return\n }\n const container = await createRequestContainer()\n const scope: StaffSeedScope = { tenantId, organizationId }\n try {\n const em = container.resolve<EntityManager>('em')\n await em.transactional(async (tem) => {\n await seedStaffAddressTypes(tem, scope)\n })\n console.log('\uD83C\uDFE0 Staff address types seeded for organization', organizationId)\n } finally {\n const disposable = container as unknown as { dispose?: () => Promise<void> }\n if (typeof disposable.dispose === 'function') {\n await disposable.dispose()\n }\n }\n },\n}\n\nexport default [seedActivityTypesCommand, seedAddressTypesCommand, seedExamplesCommand]\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import type { ModuleCli } from '@open-mercato/shared/modules/registry'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport { seedStaffActivityTypes, seedStaffAddressTypes, seedStaffTeamExamples, type StaffSeedScope } from './lib/seeds'\nimport { appendWidgetsToRoles } from '@open-mercato/core/modules/dashboards/lib/role-widgets'\n\nconst TIMESHEETS_DASHBOARD_WIDGET_IDS = [\n 'staff.timesheets.timeReporting',\n 'staff.timesheets.hoursByProject',\n]\n\nfunction parseArgs(rest: string[]) {\n const args: Record<string, string> = {}\n for (let i = 0; i < rest.length; i += 1) {\n const part = rest[i]\n if (!part) continue\n if (part.startsWith('--')) {\n const [rawKey, rawValue] = part.slice(2).split('=')\n if (rawValue !== undefined) args[rawKey] = rawValue\n else if (rest[i + 1] && !rest[i + 1]!.startsWith('--')) {\n args[rawKey] = rest[i + 1]!\n i += 1\n }\n }\n }\n return args\n}\n\nconst seedExamplesCommand: ModuleCli = {\n command: 'seed-examples',\n async run(rest) {\n const args = parseArgs(rest)\n const tenantId = String(args.tenantId ?? args.tenant ?? '')\n const organizationId = String(args.organizationId ?? args.org ?? args.orgId ?? '')\n if (!tenantId || !organizationId) {\n console.error('Usage: mercato staff seed-examples --tenant <tenantId> --org <organizationId>')\n return\n }\n const container = await createRequestContainer()\n const scope: StaffSeedScope = { tenantId, organizationId }\n try {\n const em = container.resolve<EntityManager>('em')\n await em.transactional(async (tem) => {\n await seedStaffTeamExamples(tem, scope)\n })\n console.log('\uD83E\uDDE9 Staff team examples seeded for organization', organizationId)\n } finally {\n const disposable = container as unknown as { dispose?: () => Promise<void> }\n if (typeof disposable.dispose === 'function') {\n await disposable.dispose()\n }\n }\n },\n}\n\nconst seedActivityTypesCommand: ModuleCli = {\n command: 'seed-activity-types',\n async run(rest) {\n const args = parseArgs(rest)\n const tenantId = String(args.tenantId ?? args.tenant ?? '')\n const organizationId = String(args.organizationId ?? args.org ?? args.orgId ?? '')\n if (!tenantId || !organizationId) {\n console.error('Usage: mercato staff seed-activity-types --tenant <tenantId> --org <organizationId>')\n return\n }\n const container = await createRequestContainer()\n const scope: StaffSeedScope = { tenantId, organizationId }\n try {\n const em = container.resolve<EntityManager>('em')\n await em.transactional(async (tem) => {\n await seedStaffActivityTypes(tem, scope)\n })\n console.log('\uD83D\uDDC2\uFE0F Staff activity types seeded for organization', organizationId)\n } finally {\n const disposable = container as unknown as { dispose?: () => Promise<void> }\n if (typeof disposable.dispose === 'function') {\n await disposable.dispose()\n }\n }\n },\n}\n\nconst seedAddressTypesCommand: ModuleCli = {\n command: 'seed-address-types',\n async run(rest) {\n const args = parseArgs(rest)\n const tenantId = String(args.tenantId ?? args.tenant ?? '')\n const organizationId = String(args.organizationId ?? args.org ?? args.orgId ?? '')\n if (!tenantId || !organizationId) {\n console.error('Usage: mercato staff seed-address-types --tenant <tenantId> --org <organizationId>')\n return\n }\n const container = await createRequestContainer()\n const scope: StaffSeedScope = { tenantId, organizationId }\n try {\n const em = container.resolve<EntityManager>('em')\n await em.transactional(async (tem) => {\n await seedStaffAddressTypes(tem, scope)\n })\n console.log('\uD83C\uDFE0 Staff address types seeded for organization', organizationId)\n } finally {\n const disposable = container as unknown as { dispose?: () => Promise<void> }\n if (typeof disposable.dispose === 'function') {\n await disposable.dispose()\n }\n }\n },\n}\n\nconst seedTimesheetsWidgetsCommand: ModuleCli = {\n command: 'seed-timesheets-widgets',\n async run(rest) {\n const args = parseArgs(rest)\n const tenantId = String(args.tenantId ?? args.tenant ?? '')\n const organizationId = String(args.organizationId ?? args.org ?? args.orgId ?? '')\n if (!tenantId || !organizationId) {\n console.error('Usage: mercato staff seed-timesheets-widgets --tenant <tenantId> --org <organizationId>')\n console.error('Backfills timesheets dashboard widgets (timeReporting, hoursByProject) to existing tenant roles.')\n process.exit(1)\n return\n }\n const container = await createRequestContainer()\n try {\n const em = container.resolve<EntityManager>('em')\n await em.transactional(async (tem) => {\n await appendWidgetsToRoles(tem, {\n tenantId,\n organizationId,\n roleNames: ['superadmin', 'admin', 'employee'],\n widgetIds: TIMESHEETS_DASHBOARD_WIDGET_IDS,\n })\n })\n console.log('\uD83D\uDCCA Timesheets dashboard widgets seeded for organization', organizationId)\n } finally {\n const disposable = container as unknown as { dispose?: () => Promise<void> }\n if (typeof disposable.dispose === 'function') {\n await disposable.dispose()\n }\n }\n },\n}\n\nexport default [seedActivityTypesCommand, seedAddressTypesCommand, seedExamplesCommand, seedTimesheetsWidgetsCommand]\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -7,4 +7,6 @@ import "./activities.js";
7
7
  import "./addresses.js";
8
8
  import "./job-histories.js";
9
9
  import "./leave-requests.js";
10
+ import "./timesheets-entries.js";
11
+ import "./timesheets-projects.js";
10
12
  //# sourceMappingURL=index.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/modules/staff/commands/index.ts"],
4
- "sourcesContent": ["import './tag-assignments'\nimport './team-roles'\nimport './team-members'\nimport './teams'\nimport './comments'\nimport './activities'\nimport './addresses'\nimport './job-histories'\nimport './leave-requests'\n"],
5
- "mappings": "AAAA,OAAO;AACP,OAAO;AACP,OAAO;AACP,OAAO;AACP,OAAO;AACP,OAAO;AACP,OAAO;AACP,OAAO;AACP,OAAO;",
4
+ "sourcesContent": ["import './tag-assignments'\nimport './team-roles'\nimport './team-members'\nimport './teams'\nimport './comments'\nimport './activities'\nimport './addresses'\nimport './job-histories'\nimport './leave-requests'\nimport './timesheets-entries'\nimport './timesheets-projects'\n"],
5
+ "mappings": "AAAA,OAAO;AACP,OAAO;AACP,OAAO;AACP,OAAO;AACP,OAAO;AACP,OAAO;AACP,OAAO;AACP,OAAO;AACP,OAAO;AACP,OAAO;AACP,OAAO;",
6
6
  "names": []
7
7
  }
@@ -3,6 +3,7 @@ import { registerCommand } from "@open-mercato/shared/lib/commands";
3
3
  import { CrudHttpError } from "@open-mercato/shared/lib/crud/errors";
4
4
  import { resolveTranslations } from "@open-mercato/shared/lib/i18n/server";
5
5
  import { emitCrudSideEffects, emitCrudUndoSideEffects, buildChanges } from "@open-mercato/shared/lib/commands/helpers";
6
+ import { withAtomicFlush } from "@open-mercato/shared/lib/commands/flush";
6
7
  import { invalidateCrudCache } from "@open-mercato/shared/lib/crud/cache";
7
8
  import { findOneWithDecryption } from "@open-mercato/shared/lib/encryption/find";
8
9
  import { PlannerAvailabilityRule } from "@open-mercato/core/modules/planner/data/entities";
@@ -599,12 +600,23 @@ const acceptLeaveRequestCommand = {
599
600
  const em = ctx.container.resolve("em").fork();
600
601
  const request = await em.findOne(StaffLeaveRequest, { id: before.id });
601
602
  if (!request) return;
602
- request.status = before.status;
603
- request.decisionComment = before.decisionComment;
604
- request.decidedByUserId = before.decidedByUserId;
605
- request.decidedAt = before.decidedAt ? new Date(before.decidedAt) : null;
606
- request.updatedAt = /* @__PURE__ */ new Date();
607
- await em.flush();
603
+ const rules = availabilityRuleIds.length ? await em.find(PlannerAvailabilityRule, { id: { $in: availabilityRuleIds } }) : [];
604
+ await withAtomicFlush(em, [
605
+ () => {
606
+ request.status = before.status;
607
+ request.decisionComment = before.decisionComment;
608
+ request.decidedByUserId = before.decidedByUserId;
609
+ request.decidedAt = before.decidedAt ? new Date(before.decidedAt) : null;
610
+ request.updatedAt = /* @__PURE__ */ new Date();
611
+ if (rules.length) {
612
+ const now = /* @__PURE__ */ new Date();
613
+ rules.forEach((rule) => {
614
+ rule.deletedAt = now;
615
+ rule.updatedAt = now;
616
+ });
617
+ }
618
+ }
619
+ ], { transaction: true });
608
620
  const de = ctx.container.resolve("dataEngine");
609
621
  await emitCrudUndoSideEffects({
610
622
  dataEngine: de,
@@ -618,29 +630,19 @@ const acceptLeaveRequestCommand = {
618
630
  events: staffLeaveRequestCrudEvents,
619
631
  indexer: leaveRequestCrudIndexer
620
632
  });
621
- if (availabilityRuleIds.length) {
622
- const rules = await em.find(PlannerAvailabilityRule, { id: { $in: availabilityRuleIds } });
623
- const now = /* @__PURE__ */ new Date();
624
- rules.forEach((rule) => {
625
- rule.deletedAt = now;
626
- rule.updatedAt = now;
633
+ for (const rule of rules) {
634
+ await emitCrudUndoSideEffects({
635
+ dataEngine: de,
636
+ action: "deleted",
637
+ entity: rule,
638
+ identifiers: {
639
+ id: rule.id,
640
+ organizationId: rule.organizationId,
641
+ tenantId: rule.tenantId
642
+ },
643
+ events: plannerAvailabilityRuleCrudEvents,
644
+ indexer: availabilityRuleCrudIndexer
627
645
  });
628
- await em.flush();
629
- const de2 = ctx.container.resolve("dataEngine");
630
- for (const rule of rules) {
631
- await emitCrudUndoSideEffects({
632
- dataEngine: de2,
633
- action: "deleted",
634
- entity: rule,
635
- identifiers: {
636
- id: rule.id,
637
- organizationId: rule.organizationId,
638
- tenantId: rule.tenantId
639
- },
640
- events: plannerAvailabilityRuleCrudEvents,
641
- indexer: availabilityRuleCrudIndexer
642
- });
643
- }
644
646
  }
645
647
  await invalidateAvailabilityCache({
646
648
  container: ctx.container,