@open-mercato/core 0.6.4-develop.4217.1.c9aa050183 → 0.6.4-develop.4236.1.9fa6806b34

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 (370) 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/catalog/commands/categories.js +61 -12
  31. package/dist/modules/catalog/commands/categories.js.map +2 -2
  32. package/dist/modules/catalog/commands/products.js +79 -54
  33. package/dist/modules/catalog/commands/products.js.map +2 -2
  34. package/dist/modules/catalog/commands/variants.js +29 -16
  35. package/dist/modules/catalog/commands/variants.js.map +2 -2
  36. package/dist/modules/currencies/commands/currencies.js +15 -8
  37. package/dist/modules/currencies/commands/currencies.js.map +2 -2
  38. package/dist/modules/customer_accounts/api/admin/users.js +27 -26
  39. package/dist/modules/customer_accounts/api/admin/users.js.map +2 -2
  40. package/dist/modules/customer_accounts/api/password/reset-confirm.js +5 -5
  41. package/dist/modules/customer_accounts/api/password/reset-confirm.js.map +2 -2
  42. package/dist/modules/customer_accounts/api/portal/users/[id]/roles.js +11 -10
  43. package/dist/modules/customer_accounts/api/portal/users/[id]/roles.js.map +2 -2
  44. package/dist/modules/customers/commands/addresses.js +35 -21
  45. package/dist/modules/customers/commands/addresses.js.map +2 -2
  46. package/dist/modules/customers/commands/companies.js +163 -162
  47. package/dist/modules/customers/commands/companies.js.map +2 -2
  48. package/dist/modules/customers/commands/deals.js +3 -4
  49. package/dist/modules/customers/commands/deals.js.map +2 -2
  50. package/dist/modules/customers/commands/interactions.js +19 -22
  51. package/dist/modules/customers/commands/interactions.js.map +2 -2
  52. package/dist/modules/customers/commands/people.js +18 -15
  53. package/dist/modules/customers/commands/people.js.map +2 -2
  54. package/dist/modules/customers/commands/personCompanyLinks.js +105 -94
  55. package/dist/modules/customers/commands/personCompanyLinks.js.map +2 -2
  56. package/dist/modules/customers/commands/pipeline-stages.js +30 -23
  57. package/dist/modules/customers/commands/pipeline-stages.js.map +2 -2
  58. package/dist/modules/customers/commands/pipelines.js +27 -20
  59. package/dist/modules/customers/commands/pipelines.js.map +2 -2
  60. package/dist/modules/customers/commands/tags.js +13 -5
  61. package/dist/modules/customers/commands/tags.js.map +2 -2
  62. package/dist/modules/dashboards/api/users/widgets/route.js +0 -1
  63. package/dist/modules/dashboards/api/users/widgets/route.js.map +2 -2
  64. package/dist/modules/dashboards/api/widgets/data/route.js +29 -1
  65. package/dist/modules/dashboards/api/widgets/data/route.js.map +2 -2
  66. package/dist/modules/data_sync/lib/sync-engine.js +4 -4
  67. package/dist/modules/data_sync/lib/sync-engine.js.map +2 -2
  68. package/dist/modules/data_sync/lib/sync-run-service.js +51 -27
  69. package/dist/modules/data_sync/lib/sync-run-service.js.map +2 -2
  70. package/dist/modules/directory/commands/organizations.js +192 -158
  71. package/dist/modules/directory/commands/organizations.js.map +3 -3
  72. package/dist/modules/inbox_ops/api/emails/[id]/reprocess/route.js +22 -16
  73. package/dist/modules/inbox_ops/api/emails/[id]/reprocess/route.js.map +2 -2
  74. package/dist/modules/messages/commands/messages.js +77 -75
  75. package/dist/modules/messages/commands/messages.js.map +2 -2
  76. package/dist/modules/messages/commands/shared.js +132 -132
  77. package/dist/modules/messages/commands/shared.js.map +2 -2
  78. package/dist/modules/perspectives/api/[tableId]/route.js +37 -26
  79. package/dist/modules/perspectives/api/[tableId]/route.js.map +2 -2
  80. package/dist/modules/resources/commands/resources.js +125 -117
  81. package/dist/modules/resources/commands/resources.js.map +2 -2
  82. package/dist/modules/resources/commands/tags.js +7 -3
  83. package/dist/modules/resources/commands/tags.js.map +2 -2
  84. package/dist/modules/sales/api/quotes/send/route.js +12 -11
  85. package/dist/modules/sales/api/quotes/send/route.js.map +2 -2
  86. package/dist/modules/sales/commands/documents.js +629 -478
  87. package/dist/modules/sales/commands/documents.js.map +2 -2
  88. package/dist/modules/sales/commands/payments.js +146 -146
  89. package/dist/modules/sales/commands/payments.js.map +2 -2
  90. package/dist/modules/sales/commands/returns.js +68 -60
  91. package/dist/modules/sales/commands/returns.js.map +2 -2
  92. package/dist/modules/staff/acl.js +10 -1
  93. package/dist/modules/staff/acl.js.map +2 -2
  94. package/dist/modules/staff/analytics.js +33 -0
  95. package/dist/modules/staff/analytics.js.map +7 -0
  96. package/dist/modules/staff/api/guards.js +31 -0
  97. package/dist/modules/staff/api/guards.js.map +7 -0
  98. package/dist/modules/staff/api/interceptors.js +96 -0
  99. package/dist/modules/staff/api/interceptors.js.map +7 -0
  100. package/dist/modules/staff/api/timesheets/my-projects/[projectId]/route.js +170 -0
  101. package/dist/modules/staff/api/timesheets/my-projects/[projectId]/route.js.map +7 -0
  102. package/dist/modules/staff/api/timesheets/my-projects/route.js +103 -0
  103. package/dist/modules/staff/api/timesheets/my-projects/route.js.map +7 -0
  104. package/dist/modules/staff/api/timesheets/projects/kpis/route.js +147 -0
  105. package/dist/modules/staff/api/timesheets/projects/kpis/route.js.map +7 -0
  106. package/dist/modules/staff/api/timesheets/time-entries/[id]/segments/[segmentId]/route.js +171 -0
  107. package/dist/modules/staff/api/timesheets/time-entries/[id]/segments/[segmentId]/route.js.map +7 -0
  108. package/dist/modules/staff/api/timesheets/time-entries/[id]/segments/route.js +180 -0
  109. package/dist/modules/staff/api/timesheets/time-entries/[id]/segments/route.js.map +7 -0
  110. package/dist/modules/staff/api/timesheets/time-entries/[id]/timer-start/route.js +155 -0
  111. package/dist/modules/staff/api/timesheets/time-entries/[id]/timer-start/route.js.map +7 -0
  112. package/dist/modules/staff/api/timesheets/time-entries/[id]/timer-stop/route.js +173 -0
  113. package/dist/modules/staff/api/timesheets/time-entries/[id]/timer-stop/route.js.map +7 -0
  114. package/dist/modules/staff/api/timesheets/time-entries/bulk/route.js +260 -0
  115. package/dist/modules/staff/api/timesheets/time-entries/bulk/route.js.map +7 -0
  116. package/dist/modules/staff/api/timesheets/time-entries/route.js +188 -0
  117. package/dist/modules/staff/api/timesheets/time-entries/route.js.map +7 -0
  118. package/dist/modules/staff/api/timesheets/time-projects/[id]/employees/route.js +159 -0
  119. package/dist/modules/staff/api/timesheets/time-projects/[id]/employees/route.js.map +7 -0
  120. package/dist/modules/staff/api/timesheets/time-projects/route.js +230 -0
  121. package/dist/modules/staff/api/timesheets/time-projects/route.js.map +7 -0
  122. package/dist/modules/staff/backend/staff/timesheets/page.js +710 -0
  123. package/dist/modules/staff/backend/staff/timesheets/page.js.map +7 -0
  124. package/dist/modules/staff/backend/staff/timesheets/page.meta.js +22 -0
  125. package/dist/modules/staff/backend/staff/timesheets/page.meta.js.map +7 -0
  126. package/dist/modules/staff/backend/staff/timesheets/projects/[id]/edit/page.js +125 -0
  127. package/dist/modules/staff/backend/staff/timesheets/projects/[id]/edit/page.js.map +7 -0
  128. package/dist/modules/staff/backend/staff/timesheets/projects/[id]/edit/page.meta.js +16 -0
  129. package/dist/modules/staff/backend/staff/timesheets/projects/[id]/edit/page.meta.js.map +7 -0
  130. package/dist/modules/staff/backend/staff/timesheets/projects/[id]/page.js +418 -0
  131. package/dist/modules/staff/backend/staff/timesheets/projects/[id]/page.js.map +7 -0
  132. package/dist/modules/staff/backend/staff/timesheets/projects/[id]/page.meta.js +16 -0
  133. package/dist/modules/staff/backend/staff/timesheets/projects/[id]/page.meta.js.map +7 -0
  134. package/dist/modules/staff/backend/staff/timesheets/projects/create/page.js +79 -0
  135. package/dist/modules/staff/backend/staff/timesheets/projects/create/page.js.map +7 -0
  136. package/dist/modules/staff/backend/staff/timesheets/projects/create/page.meta.js +16 -0
  137. package/dist/modules/staff/backend/staff/timesheets/projects/create/page.meta.js.map +7 -0
  138. package/dist/modules/staff/backend/staff/timesheets/projects/page.js +602 -0
  139. package/dist/modules/staff/backend/staff/timesheets/projects/page.js.map +7 -0
  140. package/dist/modules/staff/backend/staff/timesheets/projects/page.meta.js +25 -0
  141. package/dist/modules/staff/backend/staff/timesheets/projects/page.meta.js.map +7 -0
  142. package/dist/modules/staff/backend/staff/timesheets/projects/projectFormConfig.js +123 -0
  143. package/dist/modules/staff/backend/staff/timesheets/projects/projectFormConfig.js.map +7 -0
  144. package/dist/modules/staff/cli.js +38 -1
  145. package/dist/modules/staff/cli.js.map +2 -2
  146. package/dist/modules/staff/commands/index.js +2 -0
  147. package/dist/modules/staff/commands/index.js.map +2 -2
  148. package/dist/modules/staff/commands/leave-requests.js +30 -28
  149. package/dist/modules/staff/commands/leave-requests.js.map +3 -3
  150. package/dist/modules/staff/commands/team-members.js +21 -20
  151. package/dist/modules/staff/commands/team-members.js.map +2 -2
  152. package/dist/modules/staff/commands/timesheets-entries.js +409 -0
  153. package/dist/modules/staff/commands/timesheets-entries.js.map +7 -0
  154. package/dist/modules/staff/commands/timesheets-projects.js +618 -0
  155. package/dist/modules/staff/commands/timesheets-projects.js.map +7 -0
  156. package/dist/modules/staff/data/enrichers.js +104 -0
  157. package/dist/modules/staff/data/enrichers.js.map +7 -0
  158. package/dist/modules/staff/data/entities.js +226 -1
  159. package/dist/modules/staff/data/entities.js.map +2 -2
  160. package/dist/modules/staff/data/validators.js +113 -1
  161. package/dist/modules/staff/data/validators.js.map +2 -2
  162. package/dist/modules/staff/events.js +13 -1
  163. package/dist/modules/staff/events.js.map +2 -2
  164. package/dist/modules/staff/lib/crud.js +7 -1
  165. package/dist/modules/staff/lib/crud.js.map +2 -2
  166. package/dist/modules/staff/lib/staffMemberResolver.js +15 -0
  167. package/dist/modules/staff/lib/staffMemberResolver.js.map +7 -0
  168. package/dist/modules/staff/lib/timesheets-projects/computeProjectHoursTrend.js +60 -0
  169. package/dist/modules/staff/lib/timesheets-projects/computeProjectHoursTrend.js.map +7 -0
  170. package/dist/modules/staff/lib/timesheets-projects/computeProjectsKpis.js +260 -0
  171. package/dist/modules/staff/lib/timesheets-projects/computeProjectsKpis.js.map +7 -0
  172. package/dist/modules/staff/lib/timesheets-projects/dateBuckets.js +41 -0
  173. package/dist/modules/staff/lib/timesheets-projects/dateBuckets.js.map +7 -0
  174. package/dist/modules/staff/lib/timesheets-projects/initials.js +10 -0
  175. package/dist/modules/staff/lib/timesheets-projects/initials.js.map +7 -0
  176. package/dist/modules/staff/lib/timesheets-projects/kpiMath.js +12 -0
  177. package/dist/modules/staff/lib/timesheets-projects/kpiMath.js.map +7 -0
  178. package/dist/modules/staff/lib/timesheets-projects/listProjectMembersPreview.js +55 -0
  179. package/dist/modules/staff/lib/timesheets-projects/listProjectMembersPreview.js.map +7 -0
  180. package/dist/modules/staff/lib/timesheets-projects-ui/HoursSparkline.js +66 -0
  181. package/dist/modules/staff/lib/timesheets-projects-ui/HoursSparkline.js.map +7 -0
  182. package/dist/modules/staff/lib/timesheets-projects-ui/ProjectCard.js +81 -0
  183. package/dist/modules/staff/lib/timesheets-projects-ui/ProjectCard.js.map +7 -0
  184. package/dist/modules/staff/lib/timesheets-projects-ui/ProjectMembersAvatarStack.js +58 -0
  185. package/dist/modules/staff/lib/timesheets-projects-ui/ProjectMembersAvatarStack.js.map +7 -0
  186. package/dist/modules/staff/lib/timesheets-projects-ui/ProjectsKpiStrip.js +152 -0
  187. package/dist/modules/staff/lib/timesheets-projects-ui/ProjectsKpiStrip.js.map +7 -0
  188. package/dist/modules/staff/lib/timesheets-projects-ui/SavedViewTabs.js +37 -0
  189. package/dist/modules/staff/lib/timesheets-projects-ui/SavedViewTabs.js.map +7 -0
  190. package/dist/modules/staff/lib/timesheets-projects-ui/ViewModeToggle.js +57 -0
  191. package/dist/modules/staff/lib/timesheets-projects-ui/ViewModeToggle.js.map +7 -0
  192. package/dist/modules/staff/lib/timesheets-projects-ui/useProjectsViewMode.js +50 -0
  193. package/dist/modules/staff/lib/timesheets-projects-ui/useProjectsViewMode.js.map +7 -0
  194. package/dist/modules/staff/lib/timesheets-ui/AddRowDropdown.js +163 -0
  195. package/dist/modules/staff/lib/timesheets-ui/AddRowDropdown.js.map +7 -0
  196. package/dist/modules/staff/lib/timesheets-ui/CalendarPicker.js +209 -0
  197. package/dist/modules/staff/lib/timesheets-ui/CalendarPicker.js.map +7 -0
  198. package/dist/modules/staff/lib/timesheets-ui/ColorPicker.js +52 -0
  199. package/dist/modules/staff/lib/timesheets-ui/ColorPicker.js.map +7 -0
  200. package/dist/modules/staff/lib/timesheets-ui/CreateProjectDialog.js +77 -0
  201. package/dist/modules/staff/lib/timesheets-ui/CreateProjectDialog.js.map +7 -0
  202. package/dist/modules/staff/lib/timesheets-ui/ListView.js +173 -0
  203. package/dist/modules/staff/lib/timesheets-ui/ListView.js.map +7 -0
  204. package/dist/modules/staff/lib/timesheets-ui/ProjectColorDot.js +32 -0
  205. package/dist/modules/staff/lib/timesheets-ui/ProjectColorDot.js.map +7 -0
  206. package/dist/modules/staff/lib/timesheets-ui/TimerBar.js +270 -0
  207. package/dist/modules/staff/lib/timesheets-ui/TimerBar.js.map +7 -0
  208. package/dist/modules/staff/lib/timesheets-ui/ViewSwitcher.js +57 -0
  209. package/dist/modules/staff/lib/timesheets-ui/ViewSwitcher.js.map +7 -0
  210. package/dist/modules/staff/lib/timesheets-ui/colors.js +43 -0
  211. package/dist/modules/staff/lib/timesheets-ui/colors.js.map +7 -0
  212. package/dist/modules/staff/migrations/Migration20260326135612.js +24 -0
  213. package/dist/modules/staff/migrations/Migration20260326135612.js.map +7 -0
  214. package/dist/modules/staff/migrations/Migration20260413102715.js +23 -0
  215. package/dist/modules/staff/migrations/Migration20260413102715.js.map +7 -0
  216. package/dist/modules/staff/migrations/Migration20260413111602.js +13 -0
  217. package/dist/modules/staff/migrations/Migration20260413111602.js.map +7 -0
  218. package/dist/modules/staff/migrations/Migration20260511112759.js +19 -0
  219. package/dist/modules/staff/migrations/Migration20260511112759.js.map +7 -0
  220. package/dist/modules/staff/search.js +35 -0
  221. package/dist/modules/staff/search.js.map +2 -2
  222. package/dist/modules/staff/setup.js +15 -1
  223. package/dist/modules/staff/setup.js.map +2 -2
  224. package/dist/modules/staff/widgets/dashboard/timesheets-hours-by-project/config.js +16 -0
  225. package/dist/modules/staff/widgets/dashboard/timesheets-hours-by-project/config.js.map +7 -0
  226. package/dist/modules/staff/widgets/dashboard/timesheets-hours-by-project/widget.client.js +126 -0
  227. package/dist/modules/staff/widgets/dashboard/timesheets-hours-by-project/widget.client.js.map +7 -0
  228. package/dist/modules/staff/widgets/dashboard/timesheets-hours-by-project/widget.js +26 -0
  229. package/dist/modules/staff/widgets/dashboard/timesheets-hours-by-project/widget.js.map +7 -0
  230. package/dist/modules/staff/widgets/dashboard/timesheets-time-reporting/config.js +15 -0
  231. package/dist/modules/staff/widgets/dashboard/timesheets-time-reporting/config.js.map +7 -0
  232. package/dist/modules/staff/widgets/dashboard/timesheets-time-reporting/widget.client.js +238 -0
  233. package/dist/modules/staff/widgets/dashboard/timesheets-time-reporting/widget.client.js.map +7 -0
  234. package/dist/modules/staff/widgets/dashboard/timesheets-time-reporting/widget.js +26 -0
  235. package/dist/modules/staff/widgets/dashboard/timesheets-time-reporting/widget.js.map +7 -0
  236. package/dist/modules/staff/widgets/injection/timer-sidebar-indicator/widget.js +145 -0
  237. package/dist/modules/staff/widgets/injection/timer-sidebar-indicator/widget.js.map +7 -0
  238. package/dist/modules/staff/widgets/injection-table.js +12 -0
  239. package/dist/modules/staff/widgets/injection-table.js.map +7 -0
  240. package/dist/modules/sync_excel/api/import/route.js +19 -17
  241. package/dist/modules/sync_excel/api/import/route.js.map +2 -2
  242. package/dist/modules/translations/commands/translations.js +22 -19
  243. package/dist/modules/translations/commands/translations.js.map +2 -2
  244. package/generated/entities/staff_time_entry/index.ts +17 -0
  245. package/generated/entities/staff_time_entry_segment/index.ts +10 -0
  246. package/generated/entities/staff_time_project/index.ts +16 -0
  247. package/generated/entities/staff_time_project_member/index.ts +13 -0
  248. package/generated/entities.ids.generated.ts +5 -1
  249. package/generated/entity-fields-registry.ts +64 -0
  250. package/package.json +7 -7
  251. package/src/helpers/integration/timesheetFixtures.ts +61 -0
  252. package/src/modules/attachments/api/library/[id]/route.ts +24 -17
  253. package/src/modules/attachments/api/route.ts +20 -14
  254. package/src/modules/auth/api/roles/acl/route.ts +11 -5
  255. package/src/modules/auth/api/sidebar/preferences/route.ts +33 -24
  256. package/src/modules/auth/api/users/acl/route.ts +17 -12
  257. package/src/modules/auth/commands/users.ts +96 -80
  258. package/src/modules/auth/services/sidebarPreferencesService.ts +40 -32
  259. package/src/modules/catalog/commands/categories.ts +61 -12
  260. package/src/modules/catalog/commands/products.ts +93 -60
  261. package/src/modules/catalog/commands/variants.ts +29 -16
  262. package/src/modules/currencies/commands/currencies.ts +27 -14
  263. package/src/modules/customer_accounts/api/admin/users.ts +31 -26
  264. package/src/modules/customer_accounts/api/password/reset-confirm.ts +5 -6
  265. package/src/modules/customer_accounts/api/portal/users/[id]/roles.ts +14 -13
  266. package/src/modules/customers/commands/addresses.ts +35 -23
  267. package/src/modules/customers/commands/companies.ts +166 -165
  268. package/src/modules/customers/commands/deals.ts +2 -4
  269. package/src/modules/customers/commands/interactions.ts +20 -26
  270. package/src/modules/customers/commands/people.ts +18 -15
  271. package/src/modules/customers/commands/personCompanyLinks.ts +109 -100
  272. package/src/modules/customers/commands/pipeline-stages.ts +31 -27
  273. package/src/modules/customers/commands/pipelines.ts +29 -23
  274. package/src/modules/customers/commands/tags.ts +13 -5
  275. package/src/modules/dashboards/api/users/widgets/route.ts +0 -1
  276. package/src/modules/dashboards/api/widgets/data/route.ts +36 -1
  277. package/src/modules/data_sync/lib/sync-engine.ts +4 -5
  278. package/src/modules/data_sync/lib/sync-run-service.ts +57 -28
  279. package/src/modules/directory/commands/organizations.ts +203 -166
  280. package/src/modules/inbox_ops/api/emails/[id]/reprocess/route.ts +26 -18
  281. package/src/modules/messages/commands/messages.ts +82 -80
  282. package/src/modules/messages/commands/shared.ts +138 -133
  283. package/src/modules/perspectives/api/[tableId]/route.ts +38 -27
  284. package/src/modules/resources/commands/resources.ts +127 -117
  285. package/src/modules/resources/commands/tags.ts +7 -3
  286. package/src/modules/sales/api/quotes/send/route.ts +17 -12
  287. package/src/modules/sales/commands/documents.ts +673 -481
  288. package/src/modules/sales/commands/payments.ts +158 -152
  289. package/src/modules/sales/commands/returns.ts +74 -63
  290. package/src/modules/staff/acl.ts +11 -0
  291. package/src/modules/staff/analytics.ts +30 -0
  292. package/src/modules/staff/api/guards.ts +59 -0
  293. package/src/modules/staff/api/interceptors.ts +122 -0
  294. package/src/modules/staff/api/timesheets/my-projects/[projectId]/route.ts +191 -0
  295. package/src/modules/staff/api/timesheets/my-projects/route.ts +115 -0
  296. package/src/modules/staff/api/timesheets/projects/kpis/route.ts +159 -0
  297. package/src/modules/staff/api/timesheets/time-entries/[id]/segments/[segmentId]/route.ts +187 -0
  298. package/src/modules/staff/api/timesheets/time-entries/[id]/segments/route.ts +191 -0
  299. package/src/modules/staff/api/timesheets/time-entries/[id]/timer-start/route.ts +168 -0
  300. package/src/modules/staff/api/timesheets/time-entries/[id]/timer-stop/route.ts +191 -0
  301. package/src/modules/staff/api/timesheets/time-entries/bulk/route.ts +292 -0
  302. package/src/modules/staff/api/timesheets/time-entries/route.ts +193 -0
  303. package/src/modules/staff/api/timesheets/time-projects/[id]/employees/route.ts +167 -0
  304. package/src/modules/staff/api/timesheets/time-projects/route.ts +244 -0
  305. package/src/modules/staff/backend/staff/timesheets/page.meta.ts +20 -0
  306. package/src/modules/staff/backend/staff/timesheets/page.tsx +899 -0
  307. package/src/modules/staff/backend/staff/timesheets/projects/[id]/edit/page.meta.ts +12 -0
  308. package/src/modules/staff/backend/staff/timesheets/projects/[id]/edit/page.tsx +141 -0
  309. package/src/modules/staff/backend/staff/timesheets/projects/[id]/page.meta.ts +12 -0
  310. package/src/modules/staff/backend/staff/timesheets/projects/[id]/page.tsx +579 -0
  311. package/src/modules/staff/backend/staff/timesheets/projects/create/page.meta.ts +12 -0
  312. package/src/modules/staff/backend/staff/timesheets/projects/create/page.tsx +90 -0
  313. package/src/modules/staff/backend/staff/timesheets/projects/page.meta.ts +23 -0
  314. package/src/modules/staff/backend/staff/timesheets/projects/page.tsx +765 -0
  315. package/src/modules/staff/backend/staff/timesheets/projects/projectFormConfig.ts +138 -0
  316. package/src/modules/staff/cli.ts +40 -1
  317. package/src/modules/staff/commands/index.ts +2 -0
  318. package/src/modules/staff/commands/leave-requests.ts +37 -29
  319. package/src/modules/staff/commands/team-members.ts +25 -20
  320. package/src/modules/staff/commands/timesheets-entries.ts +504 -0
  321. package/src/modules/staff/commands/timesheets-projects.ts +699 -0
  322. package/src/modules/staff/data/enrichers.ts +134 -0
  323. package/src/modules/staff/data/entities.ts +198 -0
  324. package/src/modules/staff/data/validators.ts +129 -0
  325. package/src/modules/staff/events.ts +13 -0
  326. package/src/modules/staff/i18n/de.json +209 -1
  327. package/src/modules/staff/i18n/en.json +209 -1
  328. package/src/modules/staff/i18n/es.json +209 -1
  329. package/src/modules/staff/i18n/pl.json +209 -1
  330. package/src/modules/staff/lib/crud.ts +8 -0
  331. package/src/modules/staff/lib/staffMemberResolver.ts +22 -0
  332. package/src/modules/staff/lib/timesheets-projects/computeProjectHoursTrend.ts +89 -0
  333. package/src/modules/staff/lib/timesheets-projects/computeProjectsKpis.ts +311 -0
  334. package/src/modules/staff/lib/timesheets-projects/dateBuckets.ts +37 -0
  335. package/src/modules/staff/lib/timesheets-projects/initials.ts +6 -0
  336. package/src/modules/staff/lib/timesheets-projects/kpiMath.ts +8 -0
  337. package/src/modules/staff/lib/timesheets-projects/listProjectMembersPreview.ts +83 -0
  338. package/src/modules/staff/lib/timesheets-projects-ui/HoursSparkline.tsx +75 -0
  339. package/src/modules/staff/lib/timesheets-projects-ui/ProjectCard.tsx +110 -0
  340. package/src/modules/staff/lib/timesheets-projects-ui/ProjectMembersAvatarStack.tsx +73 -0
  341. package/src/modules/staff/lib/timesheets-projects-ui/ProjectsKpiStrip.tsx +185 -0
  342. package/src/modules/staff/lib/timesheets-projects-ui/SavedViewTabs.tsx +53 -0
  343. package/src/modules/staff/lib/timesheets-projects-ui/ViewModeToggle.tsx +63 -0
  344. package/src/modules/staff/lib/timesheets-projects-ui/useProjectsViewMode.ts +63 -0
  345. package/src/modules/staff/lib/timesheets-ui/AddRowDropdown.tsx +188 -0
  346. package/src/modules/staff/lib/timesheets-ui/CalendarPicker.tsx +229 -0
  347. package/src/modules/staff/lib/timesheets-ui/ColorPicker.tsx +65 -0
  348. package/src/modules/staff/lib/timesheets-ui/CreateProjectDialog.tsx +99 -0
  349. package/src/modules/staff/lib/timesheets-ui/ListView.tsx +230 -0
  350. package/src/modules/staff/lib/timesheets-ui/ProjectColorDot.tsx +40 -0
  351. package/src/modules/staff/lib/timesheets-ui/TimerBar.tsx +327 -0
  352. package/src/modules/staff/lib/timesheets-ui/ViewSwitcher.tsx +60 -0
  353. package/src/modules/staff/lib/timesheets-ui/colors.ts +58 -0
  354. package/src/modules/staff/migrations/.snapshot-open-mercato.json +1148 -0
  355. package/src/modules/staff/migrations/Migration20260326135612.ts +26 -0
  356. package/src/modules/staff/migrations/Migration20260413102715.ts +25 -0
  357. package/src/modules/staff/migrations/Migration20260413111602.ts +13 -0
  358. package/src/modules/staff/migrations/Migration20260511112759.ts +21 -0
  359. package/src/modules/staff/search.ts +35 -0
  360. package/src/modules/staff/setup.ts +15 -0
  361. package/src/modules/staff/widgets/dashboard/timesheets-hours-by-project/config.ts +17 -0
  362. package/src/modules/staff/widgets/dashboard/timesheets-hours-by-project/widget.client.tsx +158 -0
  363. package/src/modules/staff/widgets/dashboard/timesheets-hours-by-project/widget.ts +25 -0
  364. package/src/modules/staff/widgets/dashboard/timesheets-time-reporting/config.ts +15 -0
  365. package/src/modules/staff/widgets/dashboard/timesheets-time-reporting/widget.client.tsx +297 -0
  366. package/src/modules/staff/widgets/dashboard/timesheets-time-reporting/widget.ts +25 -0
  367. package/src/modules/staff/widgets/injection/timer-sidebar-indicator/widget.tsx +161 -0
  368. package/src/modules/staff/widgets/injection-table.ts +10 -0
  369. package/src/modules/sync_excel/api/import/route.ts +23 -18
  370. package/src/modules/translations/commands/translations.ts +49 -41
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../src/modules/staff/lib/timesheets-ui/ProjectColorDot.tsx"],
4
+ "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { resolveProjectColorHex } from './colors'\n\nexport type ProjectColorDotSize = 'xs' | 'sm' | 'md'\n\nexport type ProjectColorDotProps = {\n colorKey: string | null | undefined\n projectName: string | null | undefined\n size?: ProjectColorDotSize\n className?: string\n title?: string\n}\n\nconst SIZE_CLASS: Record<ProjectColorDotSize, string> = {\n xs: 'h-2 w-2',\n sm: 'h-2.5 w-2.5',\n md: 'h-3 w-3',\n}\n\nexport function ProjectColorDot({\n colorKey,\n projectName,\n size = 'sm',\n className,\n title,\n}: ProjectColorDotProps) {\n const hex = resolveProjectColorHex(colorKey, projectName)\n const base = 'inline-block shrink-0 rounded-full'\n const classes = [base, SIZE_CLASS[size], className].filter(Boolean).join(' ')\n return (\n <span\n aria-hidden=\"true\"\n title={title}\n className={classes}\n style={{ backgroundColor: hex }}\n />\n )\n}\n"],
5
+ "mappings": ";AAgCI;AA7BJ,SAAS,8BAA8B;AAYvC,MAAM,aAAkD;AAAA,EACtD,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AACN;AAEO,SAAS,gBAAgB;AAAA,EAC9B;AAAA,EACA;AAAA,EACA,OAAO;AAAA,EACP;AAAA,EACA;AACF,GAAyB;AACvB,QAAM,MAAM,uBAAuB,UAAU,WAAW;AACxD,QAAM,OAAO;AACb,QAAM,UAAU,CAAC,MAAM,WAAW,IAAI,GAAG,SAAS,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG;AAC5E,SACE;AAAA,IAAC;AAAA;AAAA,MACC,eAAY;AAAA,MACZ;AAAA,MACA,WAAW;AAAA,MACX,OAAO,EAAE,iBAAiB,IAAI;AAAA;AAAA,EAChC;AAEJ;",
6
+ "names": []
7
+ }
@@ -0,0 +1,270 @@
1
+ "use client";
2
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
+ import { useState, useEffect, useRef, useCallback } from "react";
4
+ import { Play, Square } from "lucide-react";
5
+ import { Button } from "@open-mercato/ui/primitives/button";
6
+ import { IconButton } from "@open-mercato/ui/primitives/icon-button";
7
+ import { useT } from "@open-mercato/shared/lib/i18n/context";
8
+ import { apiCall, apiCallOrThrow } from "@open-mercato/ui/backend/utils/apiCall";
9
+ import { flash } from "@open-mercato/ui/backend/FlashMessages";
10
+ import { ProjectColorDot } from "./ProjectColorDot.js";
11
+ function formatElapsed(seconds) {
12
+ const h = Math.floor(seconds / 3600);
13
+ const m = Math.floor(seconds % 3600 / 60);
14
+ const s = seconds % 60;
15
+ return `${h}:${String(m).padStart(2, "0")}:${String(s).padStart(2, "0")}`;
16
+ }
17
+ function getToday() {
18
+ const now = /* @__PURE__ */ new Date();
19
+ const year = now.getFullYear();
20
+ const month = String(now.getMonth() + 1).padStart(2, "0");
21
+ const day = String(now.getDate()).padStart(2, "0");
22
+ return `${year}-${month}-${day}`;
23
+ }
24
+ function TimerBar({ projects, staffMemberId, onTimerStopped }) {
25
+ const t = useT();
26
+ const [activeEntryId, setActiveEntryId] = useState(null);
27
+ const [activeProjectId, setActiveProjectId] = useState(null);
28
+ const [elapsedSeconds, setElapsedSeconds] = useState(0);
29
+ const [description, setDescription] = useState("");
30
+ const [selectedProjectId, setSelectedProjectId] = useState(null);
31
+ const [isStarting, setIsStarting] = useState(false);
32
+ const [isStopping, setIsStopping] = useState(false);
33
+ const [showProjectDropdown, setShowProjectDropdown] = useState(false);
34
+ const [projectFilter, setProjectFilter] = useState("");
35
+ const dropdownRef = useRef(null);
36
+ const intervalRef = useRef(null);
37
+ const isRunning = activeEntryId !== null;
38
+ const activeProject = projects.find((p) => p.id === activeProjectId);
39
+ const selectedProject = projects.find((p) => p.id === selectedProjectId);
40
+ const filteredProjects = projects.filter(
41
+ (p) => p.name.toLowerCase().includes(projectFilter.toLowerCase())
42
+ );
43
+ const startElapsedCounter = useCallback((startedAt) => {
44
+ const startTime = new Date(startedAt).getTime();
45
+ const now = Date.now();
46
+ const initialElapsed = Math.max(0, Math.floor((now - startTime) / 1e3));
47
+ setElapsedSeconds(initialElapsed);
48
+ if (intervalRef.current) clearInterval(intervalRef.current);
49
+ intervalRef.current = setInterval(() => {
50
+ setElapsedSeconds((prev) => prev + 1);
51
+ }, 1e3);
52
+ }, []);
53
+ const stopElapsedCounter = useCallback(() => {
54
+ if (intervalRef.current) {
55
+ clearInterval(intervalRef.current);
56
+ intervalRef.current = null;
57
+ }
58
+ setElapsedSeconds(0);
59
+ }, []);
60
+ useEffect(() => {
61
+ if (!staffMemberId) return;
62
+ const today = getToday();
63
+ const checkActiveTimer = async () => {
64
+ const response = await apiCall(
65
+ `/api/staff/timesheets/time-entries?staffMemberId=${staffMemberId}&from=${today}&to=${today}&pageSize=50`
66
+ );
67
+ if (!response.ok) return;
68
+ const data = response.result;
69
+ const items = data?.items ?? data?.data ?? [];
70
+ const activeEntry = items.find(
71
+ (entry) => entry.started_at && !entry.ended_at
72
+ );
73
+ if (activeEntry) {
74
+ setActiveEntryId(String(activeEntry.id ?? ""));
75
+ setActiveProjectId(String(activeEntry.time_project_id ?? ""));
76
+ setDescription(String(activeEntry.notes ?? ""));
77
+ startElapsedCounter(String(activeEntry.started_at ?? ""));
78
+ }
79
+ };
80
+ checkActiveTimer();
81
+ }, [staffMemberId, startElapsedCounter]);
82
+ useEffect(() => {
83
+ return () => {
84
+ if (intervalRef.current) clearInterval(intervalRef.current);
85
+ };
86
+ }, []);
87
+ useEffect(() => {
88
+ function handleClickOutside(event) {
89
+ if (dropdownRef.current && !dropdownRef.current.contains(event.target)) {
90
+ setShowProjectDropdown(false);
91
+ setProjectFilter("");
92
+ }
93
+ }
94
+ if (showProjectDropdown) {
95
+ document.addEventListener("mousedown", handleClickOutside);
96
+ }
97
+ return () => document.removeEventListener("mousedown", handleClickOutside);
98
+ }, [showProjectDropdown]);
99
+ const handleStart = async () => {
100
+ if (!selectedProjectId || !staffMemberId) return;
101
+ setIsStarting(true);
102
+ try {
103
+ const today = getToday();
104
+ const createResponse = await apiCallOrThrow(
105
+ "/api/staff/timesheets/time-entries",
106
+ {
107
+ method: "POST",
108
+ headers: { "Content-Type": "application/json" },
109
+ body: JSON.stringify({
110
+ staffMemberId,
111
+ timeProjectId: selectedProjectId,
112
+ date: today,
113
+ durationMinutes: 0,
114
+ source: "timer",
115
+ notes: description || null
116
+ })
117
+ }
118
+ );
119
+ const created = createResponse.result;
120
+ const entryId = created?.id;
121
+ await apiCallOrThrow(
122
+ `/api/staff/timesheets/time-entries/${entryId}/timer-start`,
123
+ { method: "POST" }
124
+ );
125
+ setActiveEntryId(entryId ?? null);
126
+ setActiveProjectId(selectedProjectId);
127
+ startElapsedCounter((/* @__PURE__ */ new Date()).toISOString());
128
+ } catch {
129
+ flash(
130
+ t("staff.timesheets.my.timer.startError", "Failed to start timer"),
131
+ "error"
132
+ );
133
+ } finally {
134
+ setIsStarting(false);
135
+ }
136
+ };
137
+ const handleStop = async () => {
138
+ if (!activeEntryId) return;
139
+ setIsStopping(true);
140
+ try {
141
+ await apiCallOrThrow(
142
+ `/api/staff/timesheets/time-entries/${activeEntryId}/timer-stop`,
143
+ { method: "POST" }
144
+ );
145
+ setActiveEntryId(null);
146
+ setActiveProjectId(null);
147
+ setDescription("");
148
+ stopElapsedCounter();
149
+ onTimerStopped();
150
+ } catch {
151
+ flash(
152
+ t("staff.timesheets.my.timer.stopError", "Failed to stop timer"),
153
+ "error"
154
+ );
155
+ } finally {
156
+ setIsStopping(false);
157
+ }
158
+ };
159
+ return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 rounded-lg border bg-card p-3 mb-4", children: [
160
+ /* @__PURE__ */ jsx(
161
+ "input",
162
+ {
163
+ type: "text",
164
+ value: description,
165
+ onChange: (e) => setDescription(e.target.value),
166
+ readOnly: isRunning,
167
+ placeholder: t(
168
+ "staff.timesheets.my.timer.placeholder",
169
+ "What are you working on?"
170
+ ),
171
+ className: "flex-1 bg-transparent border-0 outline-none text-sm placeholder:text-muted-foreground"
172
+ }
173
+ ),
174
+ /* @__PURE__ */ jsx("div", { className: "relative", ref: dropdownRef, children: isRunning ? activeProject ? /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-1.5 text-xs font-medium px-2 py-1 rounded border bg-muted", children: [
175
+ /* @__PURE__ */ jsx(ProjectColorDot, { colorKey: activeProject.color, projectName: activeProject.name, size: "xs" }),
176
+ activeProject.name
177
+ ] }) : null : /* @__PURE__ */ jsxs(Fragment, { children: [
178
+ /* @__PURE__ */ jsx(
179
+ Button,
180
+ {
181
+ type: "button",
182
+ variant: "outline",
183
+ size: "sm",
184
+ onClick: () => {
185
+ setShowProjectDropdown(!showProjectDropdown);
186
+ setProjectFilter("");
187
+ },
188
+ className: "text-xs font-medium",
189
+ children: selectedProject ? /* @__PURE__ */ jsxs(Fragment, { children: [
190
+ /* @__PURE__ */ jsx(ProjectColorDot, { colorKey: selectedProject.color, projectName: selectedProject.name, size: "xs" }),
191
+ /* @__PURE__ */ jsx("span", { className: "ml-1", children: selectedProject.name })
192
+ ] }) : t("staff.timesheets.my.timer.selectProject", "Project")
193
+ }
194
+ ),
195
+ showProjectDropdown && /* @__PURE__ */ jsxs("div", { className: "absolute right-0 top-full mt-1 z-50 min-w-[200px] rounded-md border bg-popover p-1 shadow-md", children: [
196
+ /* @__PURE__ */ jsx(
197
+ "input",
198
+ {
199
+ type: "text",
200
+ value: projectFilter,
201
+ onChange: (e) => setProjectFilter(e.target.value),
202
+ placeholder: t(
203
+ "staff.timesheets.my.timer.searchProject",
204
+ "Search projects..."
205
+ ),
206
+ className: "w-full bg-transparent border-b px-2 py-1.5 text-xs outline-none placeholder:text-muted-foreground mb-1",
207
+ autoFocus: true
208
+ }
209
+ ),
210
+ /* @__PURE__ */ jsx("div", { className: "max-h-[200px] overflow-y-auto", children: filteredProjects.length === 0 ? /* @__PURE__ */ jsx("div", { className: "px-2 py-1.5 text-xs text-muted-foreground", children: t(
211
+ "staff.timesheets.my.timer.noProjects",
212
+ "No projects found"
213
+ ) }) : filteredProjects.map((project) => /* @__PURE__ */ jsxs(
214
+ Button,
215
+ {
216
+ type: "button",
217
+ variant: "ghost",
218
+ size: "sm",
219
+ className: "w-full justify-start text-xs h-auto py-1.5",
220
+ onClick: () => {
221
+ setSelectedProjectId(project.id);
222
+ setShowProjectDropdown(false);
223
+ setProjectFilter("");
224
+ },
225
+ children: [
226
+ /* @__PURE__ */ jsx(ProjectColorDot, { colorKey: project.color, projectName: project.name, size: "xs" }),
227
+ /* @__PURE__ */ jsx("span", { className: "ml-1", children: project.name }),
228
+ project.code ? /* @__PURE__ */ jsxs("span", { className: "ml-1 text-muted-foreground", children: [
229
+ "(",
230
+ project.code,
231
+ ")"
232
+ ] }) : null
233
+ ]
234
+ },
235
+ project.id
236
+ )) })
237
+ ] })
238
+ ] }) }),
239
+ /* @__PURE__ */ jsx("span", { className: "font-mono text-sm tabular-nums min-w-[64px] text-right", children: formatElapsed(elapsedSeconds) }),
240
+ isRunning ? /* @__PURE__ */ jsx(
241
+ IconButton,
242
+ {
243
+ type: "button",
244
+ variant: "outline",
245
+ size: "default",
246
+ onClick: handleStop,
247
+ disabled: isStopping,
248
+ className: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
249
+ "aria-label": t("staff.timesheets.my.timer.stop", "Stop timer"),
250
+ children: /* @__PURE__ */ jsx(Square, { className: "size-4" })
251
+ }
252
+ ) : /* @__PURE__ */ jsx(
253
+ IconButton,
254
+ {
255
+ type: "button",
256
+ variant: "outline",
257
+ size: "default",
258
+ onClick: handleStart,
259
+ disabled: isStarting || !selectedProjectId,
260
+ className: "bg-primary text-primary-foreground hover:bg-primary/90",
261
+ "aria-label": t("staff.timesheets.my.timer.start", "Start timer"),
262
+ children: /* @__PURE__ */ jsx(Play, { className: "size-4" })
263
+ }
264
+ )
265
+ ] });
266
+ }
267
+ export {
268
+ TimerBar
269
+ };
270
+ //# sourceMappingURL=TimerBar.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../src/modules/staff/lib/timesheets-ui/TimerBar.tsx"],
4
+ "sourcesContent": ["'use client'\n\nimport { useState, useEffect, useRef, useCallback } from 'react'\nimport { Play, Square } from 'lucide-react'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { IconButton } from '@open-mercato/ui/primitives/icon-button'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { apiCall, apiCallOrThrow } from '@open-mercato/ui/backend/utils/apiCall'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { ProjectColorDot } from './ProjectColorDot'\n\ntype ProjectOption = {\n id: string\n name: string\n code: string | null\n color?: string | null\n}\n\ntype TimerBarProps = {\n projects: ProjectOption[]\n staffMemberId: string | null\n onTimerStopped: () => void\n}\n\nfunction formatElapsed(seconds: number): string {\n const h = Math.floor(seconds / 3600)\n const m = Math.floor((seconds % 3600) / 60)\n const s = seconds % 60\n return `${h}:${String(m).padStart(2, '0')}:${String(s).padStart(2, '0')}`\n}\n\nfunction getToday(): string {\n const now = new Date()\n const year = now.getFullYear()\n const month = String(now.getMonth() + 1).padStart(2, '0')\n const day = String(now.getDate()).padStart(2, '0')\n return `${year}-${month}-${day}`\n}\n\nexport function TimerBar({ projects, staffMemberId, onTimerStopped }: TimerBarProps) {\n const t = useT()\n\n const [activeEntryId, setActiveEntryId] = useState<string | null>(null)\n const [activeProjectId, setActiveProjectId] = useState<string | null>(null)\n const [elapsedSeconds, setElapsedSeconds] = useState(0)\n const [description, setDescription] = useState('')\n const [selectedProjectId, setSelectedProjectId] = useState<string | null>(null)\n const [isStarting, setIsStarting] = useState(false)\n const [isStopping, setIsStopping] = useState(false)\n const [showProjectDropdown, setShowProjectDropdown] = useState(false)\n const [projectFilter, setProjectFilter] = useState('')\n\n const dropdownRef = useRef<HTMLDivElement>(null)\n const intervalRef = useRef<ReturnType<typeof setInterval> | null>(null)\n\n const isRunning = activeEntryId !== null\n\n const activeProject = projects.find((p) => p.id === activeProjectId)\n const selectedProject = projects.find((p) => p.id === selectedProjectId)\n\n const filteredProjects = projects.filter((p) =>\n p.name.toLowerCase().includes(projectFilter.toLowerCase()),\n )\n\n const startElapsedCounter = useCallback((startedAt: string) => {\n const startTime = new Date(startedAt).getTime()\n const now = Date.now()\n const initialElapsed = Math.max(0, Math.floor((now - startTime) / 1000))\n setElapsedSeconds(initialElapsed)\n\n if (intervalRef.current) clearInterval(intervalRef.current)\n intervalRef.current = setInterval(() => {\n setElapsedSeconds((prev) => prev + 1)\n }, 1000)\n }, [])\n\n const stopElapsedCounter = useCallback(() => {\n if (intervalRef.current) {\n clearInterval(intervalRef.current)\n intervalRef.current = null\n }\n setElapsedSeconds(0)\n }, [])\n\n useEffect(() => {\n if (!staffMemberId) return\n\n const today = getToday()\n const checkActiveTimer = async () => {\n const response = await apiCall(\n `/api/staff/timesheets/time-entries?staffMemberId=${staffMemberId}&from=${today}&to=${today}&pageSize=50`,\n )\n if (!response.ok) return\n\n const data = response.result as Record<string, unknown> | null\n const items = (data?.items ?? data?.data ?? []) as Array<Record<string, unknown>>\n\n const activeEntry = items.find(\n (entry: Record<string, unknown>) =>\n entry.started_at && !entry.ended_at,\n )\n\n if (activeEntry) {\n setActiveEntryId(String(activeEntry.id ?? ''))\n setActiveProjectId(String(activeEntry.time_project_id ?? ''))\n setDescription(String(activeEntry.notes ?? ''))\n startElapsedCounter(String(activeEntry.started_at ?? ''))\n }\n }\n\n checkActiveTimer()\n }, [staffMemberId, startElapsedCounter])\n\n useEffect(() => {\n return () => {\n if (intervalRef.current) clearInterval(intervalRef.current)\n }\n }, [])\n\n useEffect(() => {\n function handleClickOutside(event: MouseEvent) {\n if (\n dropdownRef.current &&\n !dropdownRef.current.contains(event.target as Node)\n ) {\n setShowProjectDropdown(false)\n setProjectFilter('')\n }\n }\n\n if (showProjectDropdown) {\n document.addEventListener('mousedown', handleClickOutside)\n }\n return () => document.removeEventListener('mousedown', handleClickOutside)\n }, [showProjectDropdown])\n\n const handleStart = async () => {\n if (!selectedProjectId || !staffMemberId) return\n\n setIsStarting(true)\n try {\n const today = getToday()\n const createResponse = await apiCallOrThrow(\n '/api/staff/timesheets/time-entries',\n {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n staffMemberId,\n timeProjectId: selectedProjectId,\n date: today,\n durationMinutes: 0,\n source: 'timer',\n notes: description || null,\n }),\n },\n )\n\n const created = createResponse.result as Record<string, unknown> | null\n const entryId = created?.id as string | undefined\n\n await apiCallOrThrow(\n `/api/staff/timesheets/time-entries/${entryId}/timer-start`,\n { method: 'POST' },\n )\n\n setActiveEntryId(entryId ?? null)\n setActiveProjectId(selectedProjectId)\n startElapsedCounter(new Date().toISOString())\n } catch {\n flash(\n t('staff.timesheets.my.timer.startError', 'Failed to start timer'),\n 'error',\n )\n } finally {\n setIsStarting(false)\n }\n }\n\n const handleStop = async () => {\n if (!activeEntryId) return\n\n setIsStopping(true)\n try {\n await apiCallOrThrow(\n `/api/staff/timesheets/time-entries/${activeEntryId}/timer-stop`,\n { method: 'POST' },\n )\n\n setActiveEntryId(null)\n setActiveProjectId(null)\n setDescription('')\n stopElapsedCounter()\n onTimerStopped()\n } catch {\n flash(\n t('staff.timesheets.my.timer.stopError', 'Failed to stop timer'),\n 'error',\n )\n } finally {\n setIsStopping(false)\n }\n }\n\n return (\n <div className=\"flex items-center gap-3 rounded-lg border bg-card p-3 mb-4\">\n <input\n type=\"text\"\n value={description}\n onChange={(e) => setDescription(e.target.value)}\n readOnly={isRunning}\n placeholder={t(\n 'staff.timesheets.my.timer.placeholder',\n 'What are you working on?',\n )}\n className=\"flex-1 bg-transparent border-0 outline-none text-sm placeholder:text-muted-foreground\"\n />\n\n <div className=\"relative\" ref={dropdownRef}>\n {isRunning ? (\n activeProject ? (\n <span className=\"inline-flex items-center gap-1.5 text-xs font-medium px-2 py-1 rounded border bg-muted\">\n <ProjectColorDot colorKey={activeProject.color} projectName={activeProject.name} size=\"xs\" />\n {activeProject.name}\n </span>\n ) : null\n ) : (\n <>\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n onClick={() => {\n setShowProjectDropdown(!showProjectDropdown)\n setProjectFilter('')\n }}\n className=\"text-xs font-medium\"\n >\n {selectedProject\n ? (<><ProjectColorDot colorKey={selectedProject.color} projectName={selectedProject.name} size=\"xs\" /><span className=\"ml-1\">{selectedProject.name}</span></>)\n : t('staff.timesheets.my.timer.selectProject', 'Project')}\n </Button>\n\n {showProjectDropdown && (\n <div className=\"absolute right-0 top-full mt-1 z-50 min-w-[200px] rounded-md border bg-popover p-1 shadow-md\">\n <input\n type=\"text\"\n value={projectFilter}\n onChange={(e) => setProjectFilter(e.target.value)}\n placeholder={t(\n 'staff.timesheets.my.timer.searchProject',\n 'Search projects...',\n )}\n className=\"w-full bg-transparent border-b px-2 py-1.5 text-xs outline-none placeholder:text-muted-foreground mb-1\"\n autoFocus\n />\n <div className=\"max-h-[200px] overflow-y-auto\">\n {filteredProjects.length === 0 ? (\n <div className=\"px-2 py-1.5 text-xs text-muted-foreground\">\n {t(\n 'staff.timesheets.my.timer.noProjects',\n 'No projects found',\n )}\n </div>\n ) : (\n filteredProjects.map((project) => (\n <Button\n key={project.id}\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n className=\"w-full justify-start text-xs h-auto py-1.5\"\n onClick={() => {\n setSelectedProjectId(project.id)\n setShowProjectDropdown(false)\n setProjectFilter('')\n }}\n >\n <ProjectColorDot colorKey={project.color} projectName={project.name} size=\"xs\" />\n <span className=\"ml-1\">{project.name}</span>\n {project.code ? (\n <span className=\"ml-1 text-muted-foreground\">\n ({project.code})\n </span>\n ) : null}\n </Button>\n ))\n )}\n </div>\n </div>\n )}\n </>\n )}\n </div>\n\n <span className=\"font-mono text-sm tabular-nums min-w-[64px] text-right\">\n {formatElapsed(elapsedSeconds)}\n </span>\n\n {isRunning ? (\n <IconButton\n type=\"button\"\n variant=\"outline\"\n size=\"default\"\n onClick={handleStop}\n disabled={isStopping}\n className=\"bg-destructive text-destructive-foreground hover:bg-destructive/90\"\n aria-label={t('staff.timesheets.my.timer.stop', 'Stop timer')}\n >\n <Square className=\"size-4\" />\n </IconButton>\n ) : (\n <IconButton\n type=\"button\"\n variant=\"outline\"\n size=\"default\"\n onClick={handleStart}\n disabled={isStarting || !selectedProjectId}\n className=\"bg-primary text-primary-foreground hover:bg-primary/90\"\n aria-label={t('staff.timesheets.my.timer.start', 'Start timer')}\n >\n <Play className=\"size-4\" />\n </IconButton>\n )}\n </div>\n )\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,57 @@
1
+ "use client";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import { Button } from "@open-mercato/ui/primitives/button";
4
+ import { useT } from "@open-mercato/shared/lib/i18n/context";
5
+ function ViewSwitcher({ viewMode, onViewModeChange, viewType, onViewTypeChange }) {
6
+ const t = useT();
7
+ return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-4", children: [
8
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1 rounded-md border p-1", children: [
9
+ /* @__PURE__ */ jsx(
10
+ Button,
11
+ {
12
+ type: "button",
13
+ size: "sm",
14
+ variant: viewMode === "weekly" ? "default" : "outline",
15
+ onClick: () => onViewModeChange("weekly"),
16
+ children: t("staff.timesheets.my.viewMode.weekly", "Weekly")
17
+ }
18
+ ),
19
+ /* @__PURE__ */ jsx(
20
+ Button,
21
+ {
22
+ type: "button",
23
+ size: "sm",
24
+ variant: viewMode === "monthly" ? "default" : "outline",
25
+ onClick: () => onViewModeChange("monthly"),
26
+ children: t("staff.timesheets.my.viewMode.monthly", "Monthly")
27
+ }
28
+ )
29
+ ] }),
30
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1 rounded-md border p-1", children: [
31
+ /* @__PURE__ */ jsx(
32
+ Button,
33
+ {
34
+ type: "button",
35
+ size: "sm",
36
+ variant: viewType === "timesheet" ? "default" : "outline",
37
+ onClick: () => onViewTypeChange("timesheet"),
38
+ children: t("staff.timesheets.my.viewType.timesheet", "Timesheet")
39
+ }
40
+ ),
41
+ /* @__PURE__ */ jsx(
42
+ Button,
43
+ {
44
+ type: "button",
45
+ size: "sm",
46
+ variant: viewType === "list" ? "default" : "outline",
47
+ onClick: () => onViewTypeChange("list"),
48
+ children: t("staff.timesheets.my.viewType.list", "List view")
49
+ }
50
+ )
51
+ ] })
52
+ ] });
53
+ }
54
+ export {
55
+ ViewSwitcher
56
+ };
57
+ //# sourceMappingURL=ViewSwitcher.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../src/modules/staff/lib/timesheets-ui/ViewSwitcher.tsx"],
4
+ "sourcesContent": ["\"use client\"\n\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\n\ntype ViewMode = 'weekly' | 'monthly'\ntype ViewType = 'timesheet' | 'list'\n\ninterface ViewSwitcherProps {\n viewMode: ViewMode\n onViewModeChange: (mode: ViewMode) => void\n viewType: ViewType\n onViewTypeChange: (type: ViewType) => void\n}\n\nexport function ViewSwitcher({ viewMode, onViewModeChange, viewType, onViewTypeChange }: ViewSwitcherProps) {\n const t = useT()\n\n return (\n <div className=\"flex items-center gap-4\">\n <div className=\"flex items-center gap-1 rounded-md border p-1\">\n <Button\n type=\"button\"\n size=\"sm\"\n variant={viewMode === 'weekly' ? 'default' : 'outline'}\n onClick={() => onViewModeChange('weekly')}\n >\n {t('staff.timesheets.my.viewMode.weekly', 'Weekly')}\n </Button>\n <Button\n type=\"button\"\n size=\"sm\"\n variant={viewMode === 'monthly' ? 'default' : 'outline'}\n onClick={() => onViewModeChange('monthly')}\n >\n {t('staff.timesheets.my.viewMode.monthly', 'Monthly')}\n </Button>\n </div>\n\n <div className=\"flex items-center gap-1 rounded-md border p-1\">\n <Button\n type=\"button\"\n size=\"sm\"\n variant={viewType === 'timesheet' ? 'default' : 'outline'}\n onClick={() => onViewTypeChange('timesheet')}\n >\n {t('staff.timesheets.my.viewType.timesheet', 'Timesheet')}\n </Button>\n <Button\n type=\"button\"\n size=\"sm\"\n variant={viewType === 'list' ? 'default' : 'outline'}\n onClick={() => onViewTypeChange('list')}\n >\n {t('staff.timesheets.my.viewType.list', 'List view')}\n </Button>\n </div>\n </div>\n )\n}\n"],
5
+ "mappings": ";AAoBM,SACE,KADF;AAlBN,SAAS,cAAc;AACvB,SAAS,YAAY;AAYd,SAAS,aAAa,EAAE,UAAU,kBAAkB,UAAU,iBAAiB,GAAsB;AAC1G,QAAM,IAAI,KAAK;AAEf,SACE,qBAAC,SAAI,WAAU,2BACb;AAAA,yBAAC,SAAI,WAAU,iDACb;AAAA;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,MAAK;AAAA,UACL,SAAS,aAAa,WAAW,YAAY;AAAA,UAC7C,SAAS,MAAM,iBAAiB,QAAQ;AAAA,UAEvC,YAAE,uCAAuC,QAAQ;AAAA;AAAA,MACpD;AAAA,MACA;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,MAAK;AAAA,UACL,SAAS,aAAa,YAAY,YAAY;AAAA,UAC9C,SAAS,MAAM,iBAAiB,SAAS;AAAA,UAExC,YAAE,wCAAwC,SAAS;AAAA;AAAA,MACtD;AAAA,OACF;AAAA,IAEA,qBAAC,SAAI,WAAU,iDACb;AAAA;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,MAAK;AAAA,UACL,SAAS,aAAa,cAAc,YAAY;AAAA,UAChD,SAAS,MAAM,iBAAiB,WAAW;AAAA,UAE1C,YAAE,0CAA0C,WAAW;AAAA;AAAA,MAC1D;AAAA,MACA;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,MAAK;AAAA,UACL,SAAS,aAAa,SAAS,YAAY;AAAA,UAC3C,SAAS,MAAM,iBAAiB,MAAM;AAAA,UAErC,YAAE,qCAAqC,WAAW;AAAA;AAAA,MACrD;AAAA,OACF;AAAA,KACF;AAEJ;",
6
+ "names": []
7
+ }
@@ -0,0 +1,43 @@
1
+ const PROJECT_COLORS = [
2
+ { key: "blue", hex: "#3B82F6" },
3
+ { key: "green", hex: "#22C55E" },
4
+ { key: "purple", hex: "#A855F7" },
5
+ { key: "red", hex: "#EF4444" },
6
+ { key: "orange", hex: "#F97316" },
7
+ { key: "yellow", hex: "#EAB308" },
8
+ { key: "pink", hex: "#EC4899" },
9
+ { key: "teal", hex: "#14B8A6" },
10
+ { key: "indigo", hex: "#6366F1" },
11
+ { key: "cyan", hex: "#06B6D4" },
12
+ { key: "emerald", hex: "#10B981" },
13
+ { key: "slate", hex: "#64748B" }
14
+ ];
15
+ const PROJECT_COLOR_KEYS = PROJECT_COLORS.map((c) => c.key);
16
+ const COLOR_BY_KEY = new Map(PROJECT_COLORS.map((c) => [c.key, c.hex]));
17
+ function isProjectColorKey(value) {
18
+ return typeof value === "string" && COLOR_BY_KEY.has(value);
19
+ }
20
+ function hashString(input) {
21
+ let hash = 5381;
22
+ for (let i = 0; i < input.length; i += 1) {
23
+ hash = (hash << 5) + hash + input.charCodeAt(i) | 0;
24
+ }
25
+ return Math.abs(hash);
26
+ }
27
+ function autoColorFromName(name) {
28
+ const safe = (name ?? "").trim().toLowerCase();
29
+ const index = safe.length === 0 ? 0 : hashString(safe) % PROJECT_COLORS.length;
30
+ return PROJECT_COLORS[index];
31
+ }
32
+ function resolveProjectColorHex(explicitKey, name) {
33
+ if (isProjectColorKey(explicitKey)) return COLOR_BY_KEY.get(explicitKey);
34
+ return autoColorFromName(name).hex;
35
+ }
36
+ export {
37
+ PROJECT_COLORS,
38
+ PROJECT_COLOR_KEYS,
39
+ autoColorFromName,
40
+ isProjectColorKey,
41
+ resolveProjectColorHex
42
+ };
43
+ //# sourceMappingURL=colors.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../src/modules/staff/lib/timesheets-ui/colors.ts"],
4
+ "sourcesContent": ["export const PROJECT_COLORS = [\n { key: 'blue', hex: '#3B82F6' },\n { key: 'green', hex: '#22C55E' },\n { key: 'purple', hex: '#A855F7' },\n { key: 'red', hex: '#EF4444' },\n { key: 'orange', hex: '#F97316' },\n { key: 'yellow', hex: '#EAB308' },\n { key: 'pink', hex: '#EC4899' },\n { key: 'teal', hex: '#14B8A6' },\n { key: 'indigo', hex: '#6366F1' },\n { key: 'cyan', hex: '#06B6D4' },\n { key: 'emerald', hex: '#10B981' },\n { key: 'slate', hex: '#64748B' },\n] as const\n\nexport type ProjectColorKey = typeof PROJECT_COLORS[number]['key']\n\nexport const PROJECT_COLOR_KEYS: ProjectColorKey[] = PROJECT_COLORS.map((c) => c.key)\n\nconst COLOR_BY_KEY = new Map<string, string>(PROJECT_COLORS.map((c) => [c.key, c.hex]))\n\nexport function isProjectColorKey(value: unknown): value is ProjectColorKey {\n return typeof value === 'string' && COLOR_BY_KEY.has(value)\n}\n\n/**\n * Stable, non-cryptographic string hash (djb2). Positive integer output.\n * Used to derive a deterministic fallback color from a project's name.\n */\nfunction hashString(input: string): number {\n let hash = 5381\n for (let i = 0; i < input.length; i += 1) {\n hash = ((hash << 5) + hash + input.charCodeAt(i)) | 0\n }\n return Math.abs(hash)\n}\n\n/**\n * Returns a stable color for a project based on its name when no explicit\n * color is set. Same name \u2192 same color across reloads and devices.\n */\nexport function autoColorFromName(name: string | null | undefined): { key: ProjectColorKey; hex: string } {\n const safe = (name ?? '').trim().toLowerCase()\n const index = safe.length === 0 ? 0 : hashString(safe) % PROJECT_COLORS.length\n return PROJECT_COLORS[index]\n}\n\n/**\n * Resolve the hex for a project, preferring the explicit color key when\n * valid and falling back to the deterministic name-based palette otherwise.\n */\nexport function resolveProjectColorHex(\n explicitKey: string | null | undefined,\n name: string | null | undefined,\n): string {\n if (isProjectColorKey(explicitKey)) return COLOR_BY_KEY.get(explicitKey)!\n return autoColorFromName(name).hex\n}\n"],
5
+ "mappings": "AAAO,MAAM,iBAAiB;AAAA,EAC5B,EAAE,KAAK,QAAQ,KAAK,UAAU;AAAA,EAC9B,EAAE,KAAK,SAAS,KAAK,UAAU;AAAA,EAC/B,EAAE,KAAK,UAAU,KAAK,UAAU;AAAA,EAChC,EAAE,KAAK,OAAO,KAAK,UAAU;AAAA,EAC7B,EAAE,KAAK,UAAU,KAAK,UAAU;AAAA,EAChC,EAAE,KAAK,UAAU,KAAK,UAAU;AAAA,EAChC,EAAE,KAAK,QAAQ,KAAK,UAAU;AAAA,EAC9B,EAAE,KAAK,QAAQ,KAAK,UAAU;AAAA,EAC9B,EAAE,KAAK,UAAU,KAAK,UAAU;AAAA,EAChC,EAAE,KAAK,QAAQ,KAAK,UAAU;AAAA,EAC9B,EAAE,KAAK,WAAW,KAAK,UAAU;AAAA,EACjC,EAAE,KAAK,SAAS,KAAK,UAAU;AACjC;AAIO,MAAM,qBAAwC,eAAe,IAAI,CAAC,MAAM,EAAE,GAAG;AAEpF,MAAM,eAAe,IAAI,IAAoB,eAAe,IAAI,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,GAAG,CAAC,CAAC;AAE/E,SAAS,kBAAkB,OAA0C;AAC1E,SAAO,OAAO,UAAU,YAAY,aAAa,IAAI,KAAK;AAC5D;AAMA,SAAS,WAAW,OAAuB;AACzC,MAAI,OAAO;AACX,WAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK,GAAG;AACxC,YAAS,QAAQ,KAAK,OAAO,MAAM,WAAW,CAAC,IAAK;AAAA,EACtD;AACA,SAAO,KAAK,IAAI,IAAI;AACtB;AAMO,SAAS,kBAAkB,MAAwE;AACxG,QAAM,QAAQ,QAAQ,IAAI,KAAK,EAAE,YAAY;AAC7C,QAAM,QAAQ,KAAK,WAAW,IAAI,IAAI,WAAW,IAAI,IAAI,eAAe;AACxE,SAAO,eAAe,KAAK;AAC7B;AAMO,SAAS,uBACd,aACA,MACQ;AACR,MAAI,kBAAkB,WAAW,EAAG,QAAO,aAAa,IAAI,WAAW;AACvE,SAAO,kBAAkB,IAAI,EAAE;AACjC;",
6
+ "names": []
7
+ }
@@ -0,0 +1,24 @@
1
+ import { Migration } from "@mikro-orm/migrations";
2
+ class Migration20260326135612 extends Migration {
3
+ async up() {
4
+ this.addSql(`create table "staff_time_entries" ("id" uuid not null default gen_random_uuid(), "tenant_id" uuid not null, "organization_id" uuid not null, "staff_member_id" uuid not null, "date" date not null, "duration_minutes" int not null default 0, "started_at" timestamptz null, "ended_at" timestamptz null, "notes" text null, "time_project_id" uuid null, "customer_id" uuid null, "deal_id" uuid null, "order_id" uuid null, "source" text check ("source" in ('manual', 'timer', 'kiosk', 'mobile')) not null default 'manual', "created_at" timestamptz not null, "updated_at" timestamptz not null, "deleted_at" timestamptz null, constraint "staff_time_entries_pkey" primary key ("id"));`);
5
+ this.addSql(`create index "staff_time_entries_project_date_idx" on "staff_time_entries" ("organization_id", "time_project_id", "date");`);
6
+ this.addSql(`create index "staff_time_entries_member_date_idx" on "staff_time_entries" ("organization_id", "staff_member_id", "date");`);
7
+ this.addSql(`create index "staff_time_entries_tenant_org_idx" on "staff_time_entries" ("tenant_id", "organization_id");`);
8
+ this.addSql(`create table "staff_time_entry_segments" ("id" uuid not null default gen_random_uuid(), "tenant_id" uuid not null, "organization_id" uuid not null, "time_entry_id" uuid not null, "started_at" timestamptz not null, "ended_at" timestamptz null, "segment_type" text check ("segment_type" in ('work', 'break')) not null default 'work', "created_at" timestamptz not null, "updated_at" timestamptz not null, "deleted_at" timestamptz null, constraint "staff_time_entry_segments_pkey" primary key ("id"));`);
9
+ this.addSql(`create index "staff_time_entry_segments_entry_idx" on "staff_time_entry_segments" ("time_entry_id");`);
10
+ this.addSql(`create index "staff_time_entry_segments_tenant_org_idx" on "staff_time_entry_segments" ("tenant_id", "organization_id");`);
11
+ this.addSql(`create table "staff_time_projects" ("id" uuid not null default gen_random_uuid(), "tenant_id" uuid not null, "organization_id" uuid not null, "name" text not null, "customer_id" uuid null, "code" text not null, "description" text null, "project_type" text null, "status" text check ("status" in ('active', 'on_hold', 'completed')) not null default 'active', "owner_user_id" uuid null, "cost_center" text null, "start_date" date null, "created_at" timestamptz not null, "updated_at" timestamptz not null, "deleted_at" timestamptz null, constraint "staff_time_projects_pkey" primary key ("id"));`);
12
+ this.addSql(`create index "staff_time_projects_code_unique_idx" on "staff_time_projects" ("organization_id", "tenant_id", "code");`);
13
+ this.addSql(`create index "staff_time_projects_tenant_org_idx" on "staff_time_projects" ("tenant_id", "organization_id");`);
14
+ this.addSql(`create table "staff_time_project_members" ("id" uuid not null default gen_random_uuid(), "tenant_id" uuid not null, "organization_id" uuid not null, "time_project_id" uuid not null, "staff_member_id" uuid not null, "role" text null, "status" text check ("status" in ('active', 'inactive')) not null default 'active', "assigned_start_date" date not null, "assigned_end_date" date null, "created_at" timestamptz not null, "updated_at" timestamptz not null, "deleted_at" timestamptz null, constraint "staff_time_project_members_pkey" primary key ("id"));`);
15
+ this.addSql(`create index "staff_time_project_members_unique_idx" on "staff_time_project_members" ("organization_id", "tenant_id", "time_project_id", "staff_member_id");`);
16
+ this.addSql(`create index "staff_time_project_members_member_idx" on "staff_time_project_members" ("organization_id", "staff_member_id");`);
17
+ this.addSql(`create index "staff_time_project_members_project_idx" on "staff_time_project_members" ("organization_id", "time_project_id");`);
18
+ this.addSql(`create index "staff_time_project_members_tenant_org_idx" on "staff_time_project_members" ("tenant_id", "organization_id");`);
19
+ }
20
+ }
21
+ export {
22
+ Migration20260326135612
23
+ };
24
+ //# sourceMappingURL=Migration20260326135612.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/modules/staff/migrations/Migration20260326135612.ts"],
4
+ "sourcesContent": ["import { Migration } from '@mikro-orm/migrations';\n\nexport class Migration20260326135612 extends Migration {\n\n override async up(): Promise<void> {\n this.addSql(`create table \"staff_time_entries\" (\"id\" uuid not null default gen_random_uuid(), \"tenant_id\" uuid not null, \"organization_id\" uuid not null, \"staff_member_id\" uuid not null, \"date\" date not null, \"duration_minutes\" int not null default 0, \"started_at\" timestamptz null, \"ended_at\" timestamptz null, \"notes\" text null, \"time_project_id\" uuid null, \"customer_id\" uuid null, \"deal_id\" uuid null, \"order_id\" uuid null, \"source\" text check (\"source\" in ('manual', 'timer', 'kiosk', 'mobile')) not null default 'manual', \"created_at\" timestamptz not null, \"updated_at\" timestamptz not null, \"deleted_at\" timestamptz null, constraint \"staff_time_entries_pkey\" primary key (\"id\"));`);\n this.addSql(`create index \"staff_time_entries_project_date_idx\" on \"staff_time_entries\" (\"organization_id\", \"time_project_id\", \"date\");`);\n this.addSql(`create index \"staff_time_entries_member_date_idx\" on \"staff_time_entries\" (\"organization_id\", \"staff_member_id\", \"date\");`);\n this.addSql(`create index \"staff_time_entries_tenant_org_idx\" on \"staff_time_entries\" (\"tenant_id\", \"organization_id\");`);\n\n this.addSql(`create table \"staff_time_entry_segments\" (\"id\" uuid not null default gen_random_uuid(), \"tenant_id\" uuid not null, \"organization_id\" uuid not null, \"time_entry_id\" uuid not null, \"started_at\" timestamptz not null, \"ended_at\" timestamptz null, \"segment_type\" text check (\"segment_type\" in ('work', 'break')) not null default 'work', \"created_at\" timestamptz not null, \"updated_at\" timestamptz not null, \"deleted_at\" timestamptz null, constraint \"staff_time_entry_segments_pkey\" primary key (\"id\"));`);\n this.addSql(`create index \"staff_time_entry_segments_entry_idx\" on \"staff_time_entry_segments\" (\"time_entry_id\");`);\n this.addSql(`create index \"staff_time_entry_segments_tenant_org_idx\" on \"staff_time_entry_segments\" (\"tenant_id\", \"organization_id\");`);\n\n this.addSql(`create table \"staff_time_projects\" (\"id\" uuid not null default gen_random_uuid(), \"tenant_id\" uuid not null, \"organization_id\" uuid not null, \"name\" text not null, \"customer_id\" uuid null, \"code\" text not null, \"description\" text null, \"project_type\" text null, \"status\" text check (\"status\" in ('active', 'on_hold', 'completed')) not null default 'active', \"owner_user_id\" uuid null, \"cost_center\" text null, \"start_date\" date null, \"created_at\" timestamptz not null, \"updated_at\" timestamptz not null, \"deleted_at\" timestamptz null, constraint \"staff_time_projects_pkey\" primary key (\"id\"));`);\n this.addSql(`create index \"staff_time_projects_code_unique_idx\" on \"staff_time_projects\" (\"organization_id\", \"tenant_id\", \"code\");`);\n this.addSql(`create index \"staff_time_projects_tenant_org_idx\" on \"staff_time_projects\" (\"tenant_id\", \"organization_id\");`);\n\n this.addSql(`create table \"staff_time_project_members\" (\"id\" uuid not null default gen_random_uuid(), \"tenant_id\" uuid not null, \"organization_id\" uuid not null, \"time_project_id\" uuid not null, \"staff_member_id\" uuid not null, \"role\" text null, \"status\" text check (\"status\" in ('active', 'inactive')) not null default 'active', \"assigned_start_date\" date not null, \"assigned_end_date\" date null, \"created_at\" timestamptz not null, \"updated_at\" timestamptz not null, \"deleted_at\" timestamptz null, constraint \"staff_time_project_members_pkey\" primary key (\"id\"));`);\n this.addSql(`create index \"staff_time_project_members_unique_idx\" on \"staff_time_project_members\" (\"organization_id\", \"tenant_id\", \"time_project_id\", \"staff_member_id\");`);\n this.addSql(`create index \"staff_time_project_members_member_idx\" on \"staff_time_project_members\" (\"organization_id\", \"staff_member_id\");`);\n this.addSql(`create index \"staff_time_project_members_project_idx\" on \"staff_time_project_members\" (\"organization_id\", \"time_project_id\");`);\n this.addSql(`create index \"staff_time_project_members_tenant_org_idx\" on \"staff_time_project_members\" (\"tenant_id\", \"organization_id\");`);\n }\n\n}\n"],
5
+ "mappings": "AAAA,SAAS,iBAAiB;AAEnB,MAAM,gCAAgC,UAAU;AAAA,EAErD,MAAe,KAAoB;AACjC,SAAK,OAAO,mqBAAmqB;AAC/qB,SAAK,OAAO,4HAA4H;AACxI,SAAK,OAAO,2HAA2H;AACvI,SAAK,OAAO,4GAA4G;AAExH,SAAK,OAAO,mfAAmf;AAC/f,SAAK,OAAO,sGAAsG;AAClH,SAAK,OAAO,0HAA0H;AAEtI,SAAK,OAAO,mlBAAmlB;AAC/lB,SAAK,OAAO,uHAAuH;AACnI,SAAK,OAAO,8GAA8G;AAE1H,SAAK,OAAO,yiBAAyiB;AACrjB,SAAK,OAAO,8JAA8J;AAC1K,SAAK,OAAO,8HAA8H;AAC1I,SAAK,OAAO,+HAA+H;AAC3I,SAAK,OAAO,4HAA4H;AAAA,EAC1I;AAEF;",
6
+ "names": []
7
+ }
@@ -0,0 +1,23 @@
1
+ import { Migration } from "@mikro-orm/migrations";
2
+ class Migration20260413102715 extends Migration {
3
+ async up() {
4
+ this.addSql(`alter table "staff_time_project_members" add column "show_in_grid" boolean not null default false;`);
5
+ this.addSql(`
6
+ update "staff_time_project_members" m
7
+ set "show_in_grid" = true
8
+ where exists (
9
+ select 1 from "staff_time_entries" e
10
+ where e."time_project_id" = m."time_project_id"
11
+ and e."staff_member_id" = m."staff_member_id"
12
+ and e."deleted_at" is null
13
+ );
14
+ `);
15
+ }
16
+ async down() {
17
+ this.addSql(`alter table "staff_time_project_members" drop column "show_in_grid";`);
18
+ }
19
+ }
20
+ export {
21
+ Migration20260413102715
22
+ };
23
+ //# sourceMappingURL=Migration20260413102715.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/modules/staff/migrations/Migration20260413102715.ts"],
4
+ "sourcesContent": ["import { Migration } from '@mikro-orm/migrations';\n\nexport class Migration20260413102715 extends Migration {\n\n override async up(): Promise<void> {\n this.addSql(`alter table \"staff_time_project_members\" add column \"show_in_grid\" boolean not null default false;`);\n // Backfill: preserve grid visibility for memberships that already have time entries,\n // so existing users don't lose rows the first time the new visibility filter is applied.\n this.addSql(`\n update \"staff_time_project_members\" m\n set \"show_in_grid\" = true\n where exists (\n select 1 from \"staff_time_entries\" e\n where e.\"time_project_id\" = m.\"time_project_id\"\n and e.\"staff_member_id\" = m.\"staff_member_id\"\n and e.\"deleted_at\" is null\n );\n `);\n }\n\n override async down(): Promise<void> {\n this.addSql(`alter table \"staff_time_project_members\" drop column \"show_in_grid\";`);\n }\n\n}\n"],
5
+ "mappings": "AAAA,SAAS,iBAAiB;AAEnB,MAAM,gCAAgC,UAAU;AAAA,EAErD,MAAe,KAAoB;AACjC,SAAK,OAAO,oGAAoG;AAGhH,SAAK,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,KASX;AAAA,EACH;AAAA,EAEA,MAAe,OAAsB;AACnC,SAAK,OAAO,sEAAsE;AAAA,EACpF;AAEF;",
6
+ "names": []
7
+ }
@@ -0,0 +1,13 @@
1
+ import { Migration } from "@mikro-orm/migrations";
2
+ class Migration20260413111602 extends Migration {
3
+ async up() {
4
+ this.addSql(`alter table "staff_time_projects" add column "color" varchar(20) null;`);
5
+ }
6
+ async down() {
7
+ this.addSql(`alter table "staff_time_projects" drop column "color";`);
8
+ }
9
+ }
10
+ export {
11
+ Migration20260413111602
12
+ };
13
+ //# sourceMappingURL=Migration20260413111602.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/modules/staff/migrations/Migration20260413111602.ts"],
4
+ "sourcesContent": ["import { Migration } from '@mikro-orm/migrations';\n\nexport class Migration20260413111602 extends Migration {\n\n override async up(): Promise<void> {\n this.addSql(`alter table \"staff_time_projects\" add column \"color\" varchar(20) null;`);\n }\n\n override async down(): Promise<void> {\n this.addSql(`alter table \"staff_time_projects\" drop column \"color\";`);\n }\n\n}\n"],
5
+ "mappings": "AAAA,SAAS,iBAAiB;AAEnB,MAAM,gCAAgC,UAAU;AAAA,EAErD,MAAe,KAAoB;AACjC,SAAK,OAAO,wEAAwE;AAAA,EACtF;AAAA,EAEA,MAAe,OAAsB;AACnC,SAAK,OAAO,wDAAwD;AAAA,EACtE;AAEF;",
6
+ "names": []
7
+ }
@@ -0,0 +1,19 @@
1
+ import { Migration } from "@mikro-orm/migrations";
2
+ class Migration20260511112759 extends Migration {
3
+ async up() {
4
+ this.addSql(`drop index if exists "staff_time_projects_code_unique_idx";`);
5
+ this.addSql(`create unique index "staff_time_projects_code_unique_idx" on "staff_time_projects" ("organization_id", "tenant_id", "code") where "deleted_at" is null;`);
6
+ this.addSql(`drop index if exists "staff_time_project_members_unique_idx";`);
7
+ this.addSql(`create unique index "staff_time_project_members_unique_idx" on "staff_time_project_members" ("organization_id", "tenant_id", "time_project_id", "staff_member_id") where "deleted_at" is null;`);
8
+ }
9
+ async down() {
10
+ this.addSql(`drop index if exists "staff_time_project_members_unique_idx";`);
11
+ this.addSql(`create index "staff_time_project_members_unique_idx" on "staff_time_project_members" ("organization_id", "tenant_id", "time_project_id", "staff_member_id");`);
12
+ this.addSql(`drop index if exists "staff_time_projects_code_unique_idx";`);
13
+ this.addSql(`create index "staff_time_projects_code_unique_idx" on "staff_time_projects" ("organization_id", "tenant_id", "code");`);
14
+ }
15
+ }
16
+ export {
17
+ Migration20260511112759
18
+ };
19
+ //# sourceMappingURL=Migration20260511112759.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/modules/staff/migrations/Migration20260511112759.ts"],
4
+ "sourcesContent": ["import { Migration } from '@mikro-orm/migrations';\n\nexport class Migration20260511112759 extends Migration {\n\n override async up(): Promise<void> {\n this.addSql(`drop index if exists \"staff_time_projects_code_unique_idx\";`);\n this.addSql(`create unique index \"staff_time_projects_code_unique_idx\" on \"staff_time_projects\" (\"organization_id\", \"tenant_id\", \"code\") where \"deleted_at\" is null;`);\n\n this.addSql(`drop index if exists \"staff_time_project_members_unique_idx\";`);\n this.addSql(`create unique index \"staff_time_project_members_unique_idx\" on \"staff_time_project_members\" (\"organization_id\", \"tenant_id\", \"time_project_id\", \"staff_member_id\") where \"deleted_at\" is null;`);\n }\n\n override async down(): Promise<void> {\n this.addSql(`drop index if exists \"staff_time_project_members_unique_idx\";`);\n this.addSql(`create index \"staff_time_project_members_unique_idx\" on \"staff_time_project_members\" (\"organization_id\", \"tenant_id\", \"time_project_id\", \"staff_member_id\");`);\n\n this.addSql(`drop index if exists \"staff_time_projects_code_unique_idx\";`);\n this.addSql(`create index \"staff_time_projects_code_unique_idx\" on \"staff_time_projects\" (\"organization_id\", \"tenant_id\", \"code\");`);\n }\n\n}\n"],
5
+ "mappings": "AAAA,SAAS,iBAAiB;AAEnB,MAAM,gCAAgC,UAAU;AAAA,EAErD,MAAe,KAAoB;AACjC,SAAK,OAAO,6DAA6D;AACzE,SAAK,OAAO,yJAAyJ;AAErK,SAAK,OAAO,+DAA+D;AAC3E,SAAK,OAAO,gMAAgM;AAAA,EAC9M;AAAA,EAEA,MAAe,OAAsB;AACnC,SAAK,OAAO,+DAA+D;AAC3E,SAAK,OAAO,8JAA8J;AAE1K,SAAK,OAAO,6DAA6D;AACzE,SAAK,OAAO,uHAAuH;AAAA,EACrI;AAEF;",
6
+ "names": []
7
+ }