@open-mercato/core 0.7.1-develop.7178.1.ab93fbaf4e → 0.7.1-develop.7180.1.9717fbbb43
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +2 -2
- package/dist/generated/entities/staff_time_entry/index.js +14 -0
- package/dist/generated/entities/staff_time_entry/index.js.map +2 -2
- package/dist/generated/entities/staff_time_entry_tag/index.js +15 -0
- package/dist/generated/entities/staff_time_entry_tag/index.js.map +7 -0
- package/dist/generated/entities/staff_time_project/index.js +16 -0
- package/dist/generated/entities/staff_time_project/index.js.map +2 -2
- package/dist/generated/entities/staff_time_report/index.js +57 -0
- package/dist/generated/entities/staff_time_report/index.js.map +7 -0
- package/dist/generated/entities/staff_time_report_entry/index.js +27 -0
- package/dist/generated/entities/staff_time_report_entry/index.js.map +7 -0
- package/dist/generated/entities/staff_time_report_event/index.js +21 -0
- package/dist/generated/entities/staff_time_report_event/index.js.map +7 -0
- package/dist/generated/entities/staff_time_report_project/index.js +15 -0
- package/dist/generated/entities/staff_time_report_project/index.js.map +7 -0
- package/dist/generated/entities/staff_time_tag/index.js +21 -0
- package/dist/generated/entities/staff_time_tag/index.js.map +7 -0
- package/dist/generated/entities/staff_time_task/index.js +37 -0
- package/dist/generated/entities/staff_time_task/index.js.map +7 -0
- package/dist/generated/entities/staff_time_task_comment/index.js +21 -0
- package/dist/generated/entities/staff_time_task_comment/index.js.map +7 -0
- package/dist/generated/entities/staff_time_task_status/index.js +29 -0
- package/dist/generated/entities/staff_time_task_status/index.js.map +7 -0
- package/dist/generated/entities/staff_time_task_tag/index.js +15 -0
- package/dist/generated/entities/staff_time_task_tag/index.js.map +7 -0
- package/dist/generated/entities.ids.generated.js +11 -1
- package/dist/generated/entities.ids.generated.js.map +2 -2
- package/dist/generated/entity-fields-registry.js +149 -0
- package/dist/generated/entity-fields-registry.js.map +2 -2
- package/dist/helpers/integration/timesheetFixtures.js +7 -0
- package/dist/helpers/integration/timesheetFixtures.js.map +2 -2
- package/dist/modules/auth/cli.js +16 -0
- package/dist/modules/auth/cli.js.map +2 -2
- package/dist/modules/auth/lib/backendChrome.js +1 -0
- package/dist/modules/auth/lib/backendChrome.js.map +2 -2
- package/dist/modules/customer_accounts/lib/customerRoleAcls.js +44 -0
- package/dist/modules/customer_accounts/lib/customerRoleAcls.js.map +7 -0
- package/dist/modules/customer_accounts/setup.js +1 -28
- package/dist/modules/customer_accounts/setup.js.map +2 -2
- package/dist/modules/data_sync/api/options.js +2 -0
- package/dist/modules/data_sync/api/options.js.map +2 -2
- package/dist/modules/data_sync/backend/data-sync/page.js +39 -17
- package/dist/modules/data_sync/backend/data-sync/page.js.map +2 -2
- package/dist/modules/data_sync/lib/start-controls.js +42 -0
- package/dist/modules/data_sync/lib/start-controls.js.map +7 -0
- package/dist/modules/staff/acl.js +9 -1
- package/dist/modules/staff/acl.js.map +2 -2
- package/dist/modules/staff/ai-agents.js +142 -0
- package/dist/modules/staff/ai-agents.js.map +7 -0
- package/dist/modules/staff/ai-tools/time-tracking-pack.js +348 -0
- package/dist/modules/staff/ai-tools/time-tracking-pack.js.map +7 -0
- package/dist/modules/staff/ai-tools/types.js +54 -0
- package/dist/modules/staff/ai-tools/types.js.map +7 -0
- package/dist/modules/staff/ai-tools.js +8 -0
- package/dist/modules/staff/ai-tools.js.map +7 -0
- package/dist/modules/staff/analytics.js +84 -1
- package/dist/modules/staff/analytics.js.map +2 -2
- package/dist/modules/staff/api/guards.js +37 -3
- package/dist/modules/staff/api/guards.js.map +2 -2
- package/dist/modules/staff/api/leave-requests/accept/route.js +1 -3
- package/dist/modules/staff/api/leave-requests/accept/route.js.map +2 -2
- package/dist/modules/staff/api/leave-requests/reject/route.js +1 -3
- package/dist/modules/staff/api/leave-requests/reject/route.js.map +2 -2
- package/dist/modules/staff/api/portal/time-reports/[id]/route.js +131 -0
- package/dist/modules/staff/api/portal/time-reports/[id]/route.js.map +7 -0
- package/dist/modules/staff/api/portal/time-reports/route.js +179 -0
- package/dist/modules/staff/api/portal/time-reports/route.js.map +7 -0
- package/dist/modules/staff/api/team-members/self/route.js +1 -3
- package/dist/modules/staff/api/team-members/self/route.js.map +2 -2
- package/dist/modules/staff/api/team-members/tags/assign/route.js +1 -3
- package/dist/modules/staff/api/team-members/tags/assign/route.js.map +2 -2
- package/dist/modules/staff/api/team-members/tags/unassign/route.js +1 -3
- package/dist/modules/staff/api/team-members/tags/unassign/route.js.map +2 -2
- package/dist/modules/staff/api/timesheets/_shared/withTimesheetInterceptors.js +174 -0
- package/dist/modules/staff/api/timesheets/_shared/withTimesheetInterceptors.js.map +7 -0
- package/dist/modules/staff/api/timesheets/access-requests/route.js +226 -0
- package/dist/modules/staff/api/timesheets/access-requests/route.js.map +7 -0
- package/dist/modules/staff/api/timesheets/my-projects/[projectId]/route.js +15 -8
- package/dist/modules/staff/api/timesheets/my-projects/[projectId]/route.js.map +2 -2
- package/dist/modules/staff/api/timesheets/my-projects/route.js +13 -1
- package/dist/modules/staff/api/timesheets/my-projects/route.js.map +2 -2
- package/dist/modules/staff/api/timesheets/my-work/myWorkAggregate.js +42 -0
- package/dist/modules/staff/api/timesheets/my-work/myWorkAggregate.js.map +7 -0
- package/dist/modules/staff/api/timesheets/my-work/route.js +383 -0
- package/dist/modules/staff/api/timesheets/my-work/route.js.map +7 -0
- package/dist/modules/staff/api/timesheets/projects/kpis/route.js +14 -2
- package/dist/modules/staff/api/timesheets/projects/kpis/route.js.map +2 -2
- package/dist/modules/staff/api/timesheets/reports/[id]/close/route.js +168 -0
- package/dist/modules/staff/api/timesheets/reports/[id]/close/route.js.map +7 -0
- package/dist/modules/staff/api/timesheets/reports/[id]/export/route.js +246 -0
- package/dist/modules/staff/api/timesheets/reports/[id]/export/route.js.map +7 -0
- package/dist/modules/staff/api/timesheets/reports/[id]/sheet/route.js +183 -0
- package/dist/modules/staff/api/timesheets/reports/[id]/sheet/route.js.map +7 -0
- package/dist/modules/staff/api/timesheets/reports/[id]/unlock/route.js +164 -0
- package/dist/modules/staff/api/timesheets/reports/[id]/unlock/route.js.map +7 -0
- package/dist/modules/staff/api/timesheets/reports/preview/route.js +360 -0
- package/dist/modules/staff/api/timesheets/reports/preview/route.js.map +7 -0
- package/dist/modules/staff/api/timesheets/reports/route.js +316 -0
- package/dist/modules/staff/api/timesheets/reports/route.js.map +7 -0
- package/dist/modules/staff/api/timesheets/reports/shared.js +63 -0
- package/dist/modules/staff/api/timesheets/reports/shared.js.map +7 -0
- package/dist/modules/staff/api/timesheets/settings/reapply-rounding/route.js +164 -0
- package/dist/modules/staff/api/timesheets/settings/reapply-rounding/route.js.map +7 -0
- package/dist/modules/staff/api/timesheets/settings/rounding-impact/route.js +168 -0
- package/dist/modules/staff/api/timesheets/settings/rounding-impact/route.js.map +7 -0
- package/dist/modules/staff/api/timesheets/settings/route.js +199 -0
- package/dist/modules/staff/api/timesheets/settings/route.js.map +7 -0
- package/dist/modules/staff/api/timesheets/tags/access.js +76 -0
- package/dist/modules/staff/api/timesheets/tags/access.js.map +7 -0
- package/dist/modules/staff/api/timesheets/tags/entry-assignments/route.js +235 -0
- package/dist/modules/staff/api/timesheets/tags/entry-assignments/route.js.map +7 -0
- package/dist/modules/staff/api/timesheets/tags/route.js +160 -0
- package/dist/modules/staff/api/timesheets/tags/route.js.map +7 -0
- package/dist/modules/staff/api/timesheets/tags/task-assignments/route.js +233 -0
- package/dist/modules/staff/api/timesheets/tags/task-assignments/route.js.map +7 -0
- package/dist/modules/staff/api/timesheets/task-statuses/route.js +188 -0
- package/dist/modules/staff/api/timesheets/task-statuses/route.js.map +7 -0
- package/dist/modules/staff/api/timesheets/tasks/[id]/comments/route.js +399 -0
- package/dist/modules/staff/api/timesheets/tasks/[id]/comments/route.js.map +7 -0
- package/dist/modules/staff/api/timesheets/tasks/[id]/status/route.js +210 -0
- package/dist/modules/staff/api/timesheets/tasks/[id]/status/route.js.map +7 -0
- package/dist/modules/staff/api/timesheets/tasks/route.js +333 -0
- package/dist/modules/staff/api/timesheets/tasks/route.js.map +7 -0
- package/dist/modules/staff/api/timesheets/time-entries/[id]/duplicate/route.js +228 -0
- package/dist/modules/staff/api/timesheets/time-entries/[id]/duplicate/route.js.map +7 -0
- package/dist/modules/staff/api/timesheets/time-entries/[id]/segments/[segmentId]/route.js +29 -10
- package/dist/modules/staff/api/timesheets/time-entries/[id]/segments/[segmentId]/route.js.map +2 -2
- package/dist/modules/staff/api/timesheets/time-entries/[id]/segments/route.js +31 -18
- package/dist/modules/staff/api/timesheets/time-entries/[id]/segments/route.js.map +2 -2
- package/dist/modules/staff/api/timesheets/time-entries/[id]/timer-start/route.js +21 -7
- package/dist/modules/staff/api/timesheets/time-entries/[id]/timer-start/route.js.map +2 -2
- package/dist/modules/staff/api/timesheets/time-entries/[id]/timer-stop/route.js +27 -7
- package/dist/modules/staff/api/timesheets/time-entries/[id]/timer-stop/route.js.map +2 -2
- package/dist/modules/staff/api/timesheets/time-entries/bulk/route.js +215 -32
- package/dist/modules/staff/api/timesheets/time-entries/bulk/route.js.map +2 -2
- package/dist/modules/staff/api/timesheets/time-entries/copy-day/route.js +378 -0
- package/dist/modules/staff/api/timesheets/time-entries/copy-day/route.js.map +7 -0
- package/dist/modules/staff/api/timesheets/time-entries/overlaps/route.js +340 -0
- package/dist/modules/staff/api/timesheets/time-entries/overlaps/route.js.map +7 -0
- package/dist/modules/staff/api/timesheets/time-entries/route.js +238 -26
- package/dist/modules/staff/api/timesheets/time-entries/route.js.map +2 -2
- package/dist/modules/staff/api/timesheets/time-entries/start-timer/route.js +23 -8
- package/dist/modules/staff/api/timesheets/time-entries/start-timer/route.js.map +2 -2
- package/dist/modules/staff/api/timesheets/time-projects/[id]/change-currency/route.js +209 -0
- package/dist/modules/staff/api/timesheets/time-projects/[id]/change-currency/route.js.map +7 -0
- package/dist/modules/staff/api/timesheets/time-projects/[id]/employees/route.js +59 -2
- package/dist/modules/staff/api/timesheets/time-projects/[id]/employees/route.js.map +2 -2
- package/dist/modules/staff/api/timesheets/time-projects/route.js +264 -22
- package/dist/modules/staff/api/timesheets/time-projects/route.js.map +2 -2
- package/dist/modules/staff/backend/staff/time-tracking/board/page.js +110 -0
- package/dist/modules/staff/backend/staff/time-tracking/board/page.js.map +7 -0
- package/dist/modules/staff/backend/staff/time-tracking/board/page.meta.js +18 -0
- package/dist/modules/staff/backend/staff/time-tracking/board/page.meta.js.map +7 -0
- package/dist/modules/staff/backend/staff/time-tracking/entries/page.js +981 -0
- package/dist/modules/staff/backend/staff/time-tracking/entries/page.js.map +7 -0
- package/dist/modules/staff/backend/staff/time-tracking/entries/page.meta.js +18 -0
- package/dist/modules/staff/backend/staff/time-tracking/entries/page.meta.js.map +7 -0
- package/dist/modules/staff/backend/staff/time-tracking/page.js +583 -0
- package/dist/modules/staff/backend/staff/time-tracking/page.js.map +7 -0
- package/dist/modules/staff/backend/staff/time-tracking/page.meta.js +15 -0
- package/dist/modules/staff/backend/staff/time-tracking/page.meta.js.map +7 -0
- package/dist/modules/staff/backend/staff/time-tracking/projects/[id]/board/page.js +65 -0
- package/dist/modules/staff/backend/staff/time-tracking/projects/[id]/board/page.js.map +7 -0
- package/dist/modules/staff/backend/staff/time-tracking/projects/[id]/board/page.meta.js +16 -0
- package/dist/modules/staff/backend/staff/time-tracking/projects/[id]/board/page.meta.js.map +7 -0
- package/dist/modules/staff/backend/staff/time-tracking/projects/[id]/edit/page.js +229 -0
- package/dist/modules/staff/backend/staff/time-tracking/projects/[id]/edit/page.js.map +7 -0
- package/dist/modules/staff/backend/staff/time-tracking/projects/[id]/edit/page.meta.js +16 -0
- package/dist/modules/staff/backend/staff/time-tracking/projects/[id]/edit/page.meta.js.map +7 -0
- package/dist/modules/staff/backend/staff/time-tracking/projects/[id]/page.js +1014 -0
- package/dist/modules/staff/backend/staff/time-tracking/projects/[id]/page.js.map +7 -0
- package/dist/modules/staff/backend/staff/time-tracking/projects/[id]/page.meta.js +16 -0
- package/dist/modules/staff/backend/staff/time-tracking/projects/[id]/page.meta.js.map +7 -0
- package/dist/modules/staff/backend/staff/time-tracking/projects/create/page.js +97 -0
- package/dist/modules/staff/backend/staff/time-tracking/projects/create/page.js.map +7 -0
- package/dist/modules/staff/backend/staff/time-tracking/projects/create/page.meta.js +16 -0
- package/dist/modules/staff/backend/staff/time-tracking/projects/create/page.meta.js.map +7 -0
- package/dist/modules/staff/backend/staff/time-tracking/projects/page.js +1040 -0
- package/dist/modules/staff/backend/staff/time-tracking/projects/page.js.map +7 -0
- package/dist/modules/staff/backend/staff/time-tracking/projects/page.meta.js +19 -0
- package/dist/modules/staff/backend/staff/time-tracking/projects/page.meta.js.map +7 -0
- package/dist/modules/staff/backend/staff/time-tracking/projects/projectFormConfig.js +353 -0
- package/dist/modules/staff/backend/staff/time-tracking/projects/projectFormConfig.js.map +7 -0
- package/dist/modules/staff/backend/staff/time-tracking/reports/[id]/page.js +457 -0
- package/dist/modules/staff/backend/staff/time-tracking/reports/[id]/page.js.map +7 -0
- package/dist/modules/staff/backend/staff/time-tracking/reports/[id]/page.meta.js +16 -0
- package/dist/modules/staff/backend/staff/time-tracking/reports/[id]/page.meta.js.map +7 -0
- package/dist/modules/staff/backend/staff/time-tracking/reports/create/page.js +697 -0
- package/dist/modules/staff/backend/staff/time-tracking/reports/create/page.js.map +7 -0
- package/dist/modules/staff/backend/staff/time-tracking/reports/create/page.meta.js +16 -0
- package/dist/modules/staff/backend/staff/time-tracking/reports/create/page.meta.js.map +7 -0
- package/dist/modules/staff/backend/staff/time-tracking/reports/page.js +174 -0
- package/dist/modules/staff/backend/staff/time-tracking/reports/page.js.map +7 -0
- package/dist/modules/staff/backend/staff/time-tracking/reports/page.meta.js +18 -0
- package/dist/modules/staff/backend/staff/time-tracking/reports/page.meta.js.map +7 -0
- package/dist/modules/staff/backend/staff/time-tracking/settings/page.js +546 -0
- package/dist/modules/staff/backend/staff/time-tracking/settings/page.js.map +7 -0
- package/dist/modules/staff/backend/staff/time-tracking/settings/page.meta.js +18 -0
- package/dist/modules/staff/backend/staff/time-tracking/settings/page.meta.js.map +7 -0
- package/dist/modules/staff/backend/staff/time-tracking/timesheet/GridView.js +710 -0
- package/dist/modules/staff/backend/staff/time-tracking/timesheet/GridView.js.map +7 -0
- package/dist/modules/staff/backend/staff/time-tracking/timesheet/page.js +646 -0
- package/dist/modules/staff/backend/staff/time-tracking/timesheet/page.js.map +7 -0
- package/dist/modules/staff/backend/staff/time-tracking/timesheet/page.meta.js +18 -0
- package/dist/modules/staff/backend/staff/time-tracking/timesheet/page.meta.js.map +7 -0
- package/dist/modules/staff/backend/staff/timesheets/page.js +4 -793
- package/dist/modules/staff/backend/staff/timesheets/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/timesheets/page.meta.js +2 -7
- package/dist/modules/staff/backend/staff/timesheets/page.meta.js.map +2 -2
- package/dist/modules/staff/backend/staff/timesheets/projects/[id]/edit/page.js +5 -136
- package/dist/modules/staff/backend/staff/timesheets/projects/[id]/edit/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/timesheets/projects/[id]/edit/page.meta.js +1 -7
- package/dist/modules/staff/backend/staff/timesheets/projects/[id]/edit/page.meta.js.map +2 -2
- package/dist/modules/staff/backend/staff/timesheets/projects/[id]/page.js +5 -445
- package/dist/modules/staff/backend/staff/timesheets/projects/[id]/page.js.map +3 -3
- package/dist/modules/staff/backend/staff/timesheets/projects/[id]/page.meta.js +1 -7
- package/dist/modules/staff/backend/staff/timesheets/projects/[id]/page.meta.js.map +2 -2
- package/dist/modules/staff/backend/staff/timesheets/projects/create/page.js +4 -76
- package/dist/modules/staff/backend/staff/timesheets/projects/create/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/timesheets/projects/create/page.meta.js +1 -7
- package/dist/modules/staff/backend/staff/timesheets/projects/create/page.meta.js.map +2 -2
- package/dist/modules/staff/backend/staff/timesheets/projects/page.js +4 -613
- package/dist/modules/staff/backend/staff/timesheets/projects/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/timesheets/projects/page.meta.js +2 -17
- package/dist/modules/staff/backend/staff/timesheets/projects/page.meta.js.map +2 -2
- package/dist/modules/staff/ce.js +40 -0
- package/dist/modules/staff/ce.js.map +2 -2
- package/dist/modules/staff/cli.js +166 -1
- package/dist/modules/staff/cli.js.map +2 -2
- package/dist/modules/staff/commands/index.js +5 -0
- package/dist/modules/staff/commands/index.js.map +2 -2
- package/dist/modules/staff/commands/timesheets-entries.js +569 -21
- package/dist/modules/staff/commands/timesheets-entries.js.map +3 -3
- package/dist/modules/staff/commands/timesheets-projects.js +450 -7
- package/dist/modules/staff/commands/timesheets-projects.js.map +2 -2
- package/dist/modules/staff/commands/timesheets-reports.js +1036 -0
- package/dist/modules/staff/commands/timesheets-reports.js.map +7 -0
- package/dist/modules/staff/commands/timesheets-tags.js +1015 -0
- package/dist/modules/staff/commands/timesheets-tags.js.map +7 -0
- package/dist/modules/staff/commands/timesheets-task-comments.js +438 -0
- package/dist/modules/staff/commands/timesheets-task-comments.js.map +7 -0
- package/dist/modules/staff/commands/timesheets-task-statuses.js +723 -0
- package/dist/modules/staff/commands/timesheets-task-statuses.js.map +7 -0
- package/dist/modules/staff/commands/timesheets-tasks.js +834 -0
- package/dist/modules/staff/commands/timesheets-tasks.js.map +7 -0
- package/dist/modules/staff/data/enrichers.js +426 -12
- package/dist/modules/staff/data/enrichers.js.map +2 -2
- package/dist/modules/staff/data/entities.js +552 -3
- package/dist/modules/staff/data/entities.js.map +2 -2
- package/dist/modules/staff/data/extensions.js +41 -0
- package/dist/modules/staff/data/extensions.js.map +7 -0
- package/dist/modules/staff/data/validators.js +254 -9
- package/dist/modules/staff/data/validators.js.map +2 -2
- package/dist/modules/staff/di.js +42 -1
- package/dist/modules/staff/di.js.map +2 -2
- package/dist/modules/staff/events.js +84 -6
- package/dist/modules/staff/events.js.map +2 -2
- package/dist/modules/staff/events.payloads.js +158 -0
- package/dist/modules/staff/events.payloads.js.map +7 -0
- package/dist/modules/staff/extension-points.js +261 -0
- package/dist/modules/staff/extension-points.js.map +7 -0
- package/dist/modules/staff/frontend/[orgSlug]/portal/time-reports/[id]/page.js +138 -0
- package/dist/modules/staff/frontend/[orgSlug]/portal/time-reports/[id]/page.js.map +7 -0
- package/dist/modules/staff/frontend/[orgSlug]/portal/time-reports/[id]/page.meta.js +12 -0
- package/dist/modules/staff/frontend/[orgSlug]/portal/time-reports/[id]/page.meta.js.map +7 -0
- package/dist/modules/staff/frontend/[orgSlug]/portal/time-reports/page.js +133 -0
- package/dist/modules/staff/frontend/[orgSlug]/portal/time-reports/page.js.map +7 -0
- package/dist/modules/staff/frontend/[orgSlug]/portal/time-reports/page.meta.js +19 -0
- package/dist/modules/staff/frontend/[orgSlug]/portal/time-reports/page.meta.js.map +7 -0
- package/dist/modules/staff/lib/crud.js +11 -1
- package/dist/modules/staff/lib/crud.js.map +2 -2
- package/dist/modules/staff/lib/time-tracking/access.js +92 -0
- package/dist/modules/staff/lib/time-tracking/access.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking/billability.js +39 -0
- package/dist/modules/staff/lib/time-tracking/billability.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking/capacity.js +68 -0
- package/dist/modules/staff/lib/time-tracking/capacity.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking/componentContracts.js +15 -0
- package/dist/modules/staff/lib/time-tracking/componentContracts.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking/cost.js +82 -0
- package/dist/modules/staff/lib/time-tracking/cost.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking/duration.js +55 -0
- package/dist/modules/staff/lib/time-tracking/duration.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking/featureAccess.js +41 -0
- package/dist/modules/staff/lib/time-tracking/featureAccess.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking/interval.js +72 -0
- package/dist/modules/staff/lib/time-tracking/interval.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking/migrateProjectCodes.js +88 -0
- package/dist/modules/staff/lib/time-tracking/migrateProjectCodes.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking/moneyVisibility.js +10 -0
- package/dist/modules/staff/lib/time-tracking/moneyVisibility.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking/overlap.js +87 -0
- package/dist/modules/staff/lib/time-tracking/overlap.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking/portalRecipients.js +27 -0
- package/dist/modules/staff/lib/time-tracking/portalRecipients.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking/portalReports.js +16 -0
- package/dist/modules/staff/lib/time-tracking/portalReports.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking/projectCode.js +135 -0
- package/dist/modules/staff/lib/time-tracking/projectCode.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking/reapplyRounding.js +187 -0
- package/dist/modules/staff/lib/time-tracking/reapplyRounding.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking/recalculationRunner.js +80 -0
- package/dist/modules/staff/lib/time-tracking/recalculationRunner.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking/recalculations.js +56 -0
- package/dist/modules/staff/lib/time-tracking/recalculations.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking/registries/invoke.js +63 -0
- package/dist/modules/staff/lib/time-tracking/registries/invoke.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking/registries/registry.js +62 -0
- package/dist/modules/staff/lib/time-tracking/registries/registry.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking/registries/scope.js +21 -0
- package/dist/modules/staff/lib/time-tracking/registries/scope.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking/rollup.js +34 -0
- package/dist/modules/staff/lib/time-tracking/rollup.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking/rounding.js +66 -0
- package/dist/modules/staff/lib/time-tracking/rounding.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking/roundingImpact.js +39 -0
- package/dist/modules/staff/lib/time-tracking/roundingImpact.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking/settingKeys.js +214 -0
- package/dist/modules/staff/lib/time-tracking/settingKeys.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking/settings.js +87 -0
- package/dist/modules/staff/lib/time-tracking/settings.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking/sqlInClause.js +9 -0
- package/dist/modules/staff/lib/time-tracking/sqlInClause.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking/timeEntrySources.js +48 -0
- package/dist/modules/staff/lib/time-tracking/timeEntrySources.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking-ui/BoardFilterChips.js +283 -0
- package/dist/modules/staff/lib/time-tracking-ui/BoardFilterChips.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking-ui/CustomerPicker.js +324 -0
- package/dist/modules/staff/lib/time-tracking-ui/CustomerPicker.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking-ui/DurationInput.js +121 -0
- package/dist/modules/staff/lib/time-tracking-ui/DurationInput.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking-ui/EntryDetailsFields.js +188 -0
- package/dist/modules/staff/lib/time-tracking-ui/EntryDetailsFields.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking-ui/EntryFilterBar.js +89 -0
- package/dist/modules/staff/lib/time-tracking-ui/EntryFilterBar.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking-ui/KanbanBoard.js +855 -0
- package/dist/modules/staff/lib/time-tracking-ui/KanbanBoard.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking-ui/KanbanCard.js +360 -0
- package/dist/modules/staff/lib/time-tracking-ui/KanbanCard.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking-ui/KanbanColumn.js +259 -0
- package/dist/modules/staff/lib/time-tracking-ui/KanbanColumn.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking-ui/NewTaskDialog.js +238 -0
- package/dist/modules/staff/lib/time-tracking-ui/NewTaskDialog.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking-ui/NoProjectAccess.js +130 -0
- package/dist/modules/staff/lib/time-tracking-ui/NoProjectAccess.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking-ui/PeriodSelector.js +98 -0
- package/dist/modules/staff/lib/time-tracking-ui/PeriodSelector.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking-ui/PhasePlaceholder.js +27 -0
- package/dist/modules/staff/lib/time-tracking-ui/PhasePlaceholder.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking-ui/ProjectCodeField.js +166 -0
- package/dist/modules/staff/lib/time-tracking-ui/ProjectCodeField.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking-ui/ProjectCurrencyField.js +295 -0
- package/dist/modules/staff/lib/time-tracking-ui/ProjectCurrencyField.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking-ui/ProjectFormSections.js +212 -0
- package/dist/modules/staff/lib/time-tracking-ui/ProjectFormSections.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking-ui/ProjectTeamDrawer.js +729 -0
- package/dist/modules/staff/lib/time-tracking-ui/ProjectTeamDrawer.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking-ui/ReportSheet.js +217 -0
- package/dist/modules/staff/lib/time-tracking-ui/ReportSheet.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking-ui/TagPicker.js +158 -0
- package/dist/modules/staff/lib/time-tracking-ui/TagPicker.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking-ui/TaskBoardScreen.js +224 -0
- package/dist/modules/staff/lib/time-tracking-ui/TaskBoardScreen.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking-ui/TaskCommentThread.js +93 -0
- package/dist/modules/staff/lib/time-tracking-ui/TaskCommentThread.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking-ui/TaskDrawer.js +1196 -0
- package/dist/modules/staff/lib/time-tracking-ui/TaskDrawer.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking-ui/TaskListView.js +176 -0
- package/dist/modules/staff/lib/time-tracking-ui/TaskListView.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking-ui/TaskPicker.js +307 -0
- package/dist/modules/staff/lib/time-tracking-ui/TaskPicker.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking-ui/TaskQuickLog.js +284 -0
- package/dist/modules/staff/lib/time-tracking-ui/TaskQuickLog.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking-ui/TimeEntriesSummaryFooter.js +73 -0
- package/dist/modules/staff/lib/time-tracking-ui/TimeEntriesSummaryFooter.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking-ui/TimeEntryDialog.js +1499 -0
- package/dist/modules/staff/lib/time-tracking-ui/TimeEntryDialog.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking-ui/TimeEntryDurationCell.js +95 -0
- package/dist/modules/staff/lib/time-tracking-ui/TimeEntryDurationCell.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking-ui/TimesheetCalendar.js +188 -0
- package/dist/modules/staff/lib/time-tracking-ui/TimesheetCalendar.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking-ui/TimesheetPeriodFooter.js +61 -0
- package/dist/modules/staff/lib/time-tracking-ui/TimesheetPeriodFooter.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking-ui/TimesheetViewSwitch.js +45 -0
- package/dist/modules/staff/lib/time-tracking-ui/TimesheetViewSwitch.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking-ui/boardDirectory.js +176 -0
- package/dist/modules/staff/lib/time-tracking-ui/boardDirectory.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking-ui/boardFilters.js +82 -0
- package/dist/modules/staff/lib/time-tracking-ui/boardFilters.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking-ui/boardSummary.js +5 -0
- package/dist/modules/staff/lib/time-tracking-ui/boardSummary.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking-ui/kanbanBoardData.js +152 -0
- package/dist/modules/staff/lib/time-tracking-ui/kanbanBoardData.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking-ui/projectTeamAssignment.js +92 -0
- package/dist/modules/staff/lib/time-tracking-ui/projectTeamAssignment.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking-ui/taskDrawerData.js +111 -0
- package/dist/modules/staff/lib/time-tracking-ui/taskDrawerData.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking-ui/timeEntryDialogState.js +243 -0
- package/dist/modules/staff/lib/time-tracking-ui/timeEntryDialogState.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking-ui/timeEntryListData.js +151 -0
- package/dist/modules/staff/lib/time-tracking-ui/timeEntryListData.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking-ui/timeTrackingSettingsForm.js +105 -0
- package/dist/modules/staff/lib/time-tracking-ui/timeTrackingSettingsForm.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking-ui/timesheetData.js +132 -0
- package/dist/modules/staff/lib/time-tracking-ui/timesheetData.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking-ui/timesheetPeriod.js +205 -0
- package/dist/modules/staff/lib/time-tracking-ui/timesheetPeriod.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking-ui/timesheetTargets.js +53 -0
- package/dist/modules/staff/lib/time-tracking-ui/timesheetTargets.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking-ui/useBoardFilters.js +77 -0
- package/dist/modules/staff/lib/time-tracking-ui/useBoardFilters.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking-ui/useTimesheetPreferences.js +151 -0
- package/dist/modules/staff/lib/time-tracking-ui/useTimesheetPreferences.js.map +7 -0
- package/dist/modules/staff/lib/timeTrackingSeeds.js +809 -0
- package/dist/modules/staff/lib/timeTrackingSeeds.js.map +7 -0
- package/dist/modules/staff/lib/timesheets/timeEntryCacheInvalidation.js +2 -3
- package/dist/modules/staff/lib/timesheets/timeEntryCacheInvalidation.js.map +2 -2
- package/dist/modules/staff/lib/timesheets/timeEntryDecoration.js +152 -0
- package/dist/modules/staff/lib/timesheets/timeEntryDecoration.js.map +7 -0
- package/dist/modules/staff/lib/timesheets-projects/budgetBurn.js +36 -0
- package/dist/modules/staff/lib/timesheets-projects/budgetBurn.js.map +7 -0
- package/dist/modules/staff/lib/timesheets-projects/budgetThreshold.js +66 -0
- package/dist/modules/staff/lib/timesheets-projects/budgetThreshold.js.map +7 -0
- package/dist/modules/staff/lib/timesheets-projects/budgetThresholdState.js +78 -0
- package/dist/modules/staff/lib/timesheets-projects/budgetThresholdState.js.map +7 -0
- package/dist/modules/staff/lib/timesheets-projects/computeProjectFinancials.js +81 -0
- package/dist/modules/staff/lib/timesheets-projects/computeProjectFinancials.js.map +7 -0
- package/dist/modules/staff/lib/timesheets-projects/reportSelection.js +44 -0
- package/dist/modules/staff/lib/timesheets-projects/reportSelection.js.map +7 -0
- package/dist/modules/staff/lib/timesheets-projects-ui/AssignMembersDialog.js +169 -0
- package/dist/modules/staff/lib/timesheets-projects-ui/AssignMembersDialog.js.map +7 -0
- package/dist/modules/staff/lib/timesheets-projects-ui/ProjectBudgetCell.js +22 -0
- package/dist/modules/staff/lib/timesheets-projects-ui/ProjectBudgetCell.js.map +7 -0
- package/dist/modules/staff/lib/timesheets-projects-ui/ProjectCard.js +51 -1
- package/dist/modules/staff/lib/timesheets-projects-ui/ProjectCard.js.map +2 -2
- package/dist/modules/staff/lib/timesheets-projects-ui/ProjectsBulkActionsBar.js +70 -0
- package/dist/modules/staff/lib/timesheets-projects-ui/ProjectsBulkActionsBar.js.map +7 -0
- package/dist/modules/staff/lib/timesheets-reports/buildReportSheet.js +63 -0
- package/dist/modules/staff/lib/timesheets-reports/buildReportSheet.js.map +7 -0
- package/dist/modules/staff/lib/timesheets-reports/loadReportData.js +170 -0
- package/dist/modules/staff/lib/timesheets-reports/loadReportData.js.map +7 -0
- package/dist/modules/staff/lib/timesheets-reports/pdf.js +205 -0
- package/dist/modules/staff/lib/timesheets-reports/pdf.js.map +7 -0
- package/dist/modules/staff/lib/timesheets-reports/reportApprovalPolicies.js +68 -0
- package/dist/modules/staff/lib/timesheets-reports/reportApprovalPolicies.js.map +7 -0
- package/dist/modules/staff/lib/timesheets-reports/reportConfigData.js +135 -0
- package/dist/modules/staff/lib/timesheets-reports/reportConfigData.js.map +7 -0
- package/dist/modules/staff/lib/timesheets-reports/reportConfigState.js +48 -0
- package/dist/modules/staff/lib/timesheets-reports/reportConfigState.js.map +7 -0
- package/dist/modules/staff/lib/timesheets-reports/reportExport.js +262 -0
- package/dist/modules/staff/lib/timesheets-reports/reportExport.js.map +7 -0
- package/dist/modules/staff/lib/timesheets-reports/reportExportFormats.js +34 -0
- package/dist/modules/staff/lib/timesheets-reports/reportExportFormats.js.map +7 -0
- package/dist/modules/staff/lib/timesheets-reports/reportGroupings.js +79 -0
- package/dist/modules/staff/lib/timesheets-reports/reportGroupings.js.map +7 -0
- package/dist/modules/staff/lib/timesheets-reports/reportLabels.js +11 -0
- package/dist/modules/staff/lib/timesheets-reports/reportLabels.js.map +7 -0
- package/dist/modules/staff/lib/timesheets-reports/reportReference.js +83 -0
- package/dist/modules/staff/lib/timesheets-reports/reportReference.js.map +7 -0
- package/dist/modules/staff/lib/timesheets-reports/reportRows.js +42 -0
- package/dist/modules/staff/lib/timesheets-reports/reportRows.js.map +7 -0
- package/dist/modules/staff/lib/timesheets-reports/reportSheetData.js +107 -0
- package/dist/modules/staff/lib/timesheets-reports/reportSheetData.js.map +7 -0
- package/dist/modules/staff/lib/timesheets-reports/reportTotals.js +289 -0
- package/dist/modules/staff/lib/timesheets-reports/reportTotals.js.map +7 -0
- package/dist/modules/staff/lib/timesheets-reports/xlsx.js +145 -0
- package/dist/modules/staff/lib/timesheets-reports/xlsx.js.map +7 -0
- package/dist/modules/staff/lib/timesheets-tasks/computeTaskRollups.js +116 -0
- package/dist/modules/staff/lib/timesheets-tasks/computeTaskRollups.js.map +7 -0
- package/dist/modules/staff/lib/timesheets-tasks/defaultStatusTemplate.js +50 -0
- package/dist/modules/staff/lib/timesheets-tasks/defaultStatusTemplate.js.map +7 -0
- package/dist/modules/staff/lib/timesheets-tasks/seedProjectStatuses.js +27 -0
- package/dist/modules/staff/lib/timesheets-tasks/seedProjectStatuses.js.map +7 -0
- package/dist/modules/staff/lib/timesheets-tasks/statusPositions.js +65 -0
- package/dist/modules/staff/lib/timesheets-tasks/statusPositions.js.map +7 -0
- package/dist/modules/staff/lib/timesheets-tasks/statusSlug.js +31 -0
- package/dist/modules/staff/lib/timesheets-tasks/statusSlug.js.map +7 -0
- package/dist/modules/staff/lib/timesheets-tasks/taskHierarchy.js +31 -0
- package/dist/modules/staff/lib/timesheets-tasks/taskHierarchy.js.map +7 -0
- package/dist/modules/staff/lib/timesheets-tasks/taskHoursTotals.js +17 -0
- package/dist/modules/staff/lib/timesheets-tasks/taskHoursTotals.js.map +7 -0
- package/dist/modules/staff/lib/timesheets-tasks/taskReference.js +51 -0
- package/dist/modules/staff/lib/timesheets-tasks/taskReference.js.map +7 -0
- package/dist/modules/staff/lib/timesheets-ui/CreateProjectDialog.js +11 -4
- package/dist/modules/staff/lib/timesheets-ui/CreateProjectDialog.js.map +2 -2
- package/dist/modules/staff/lib/timesheets-ui/ListView.js +369 -111
- package/dist/modules/staff/lib/timesheets-ui/ListView.js.map +2 -2
- package/dist/modules/staff/lib/timesheets-ui/TimerBar.js +47 -2
- package/dist/modules/staff/lib/timesheets-ui/TimerBar.js.map +2 -2
- package/dist/modules/staff/migrations/Migration20260813073131_staff.js +79 -0
- package/dist/modules/staff/migrations/Migration20260813073131_staff.js.map +7 -0
- package/dist/modules/staff/migrations/Migration20260824143357_staff.js +15 -0
- package/dist/modules/staff/migrations/Migration20260824143357_staff.js.map +7 -0
- package/dist/modules/staff/notifications.client.js +16 -0
- package/dist/modules/staff/notifications.client.js.map +7 -0
- package/dist/modules/staff/notifications.handlers.js +80 -0
- package/dist/modules/staff/notifications.handlers.js.map +7 -0
- package/dist/modules/staff/notifications.js +168 -0
- package/dist/modules/staff/notifications.js.map +2 -2
- package/dist/modules/staff/search.js +159 -1
- package/dist/modules/staff/search.js.map +2 -2
- package/dist/modules/staff/setup.js +20 -1
- package/dist/modules/staff/setup.js.map +2 -2
- package/dist/modules/staff/subscribers/time-project-access-requested-notification.js +68 -0
- package/dist/modules/staff/subscribers/time-project-access-requested-notification.js.map +7 -0
- package/dist/modules/staff/subscribers/time-project-budget-threshold-notification.js +149 -0
- package/dist/modules/staff/subscribers/time-project-budget-threshold-notification.js.map +7 -0
- package/dist/modules/staff/subscribers/time-report-approved-notification.js +78 -0
- package/dist/modules/staff/subscribers/time-report-approved-notification.js.map +7 -0
- package/dist/modules/staff/subscribers/time-report-portal-broadcast.js +78 -0
- package/dist/modules/staff/subscribers/time-report-portal-broadcast.js.map +7 -0
- package/dist/modules/staff/translations.js +4 -1
- package/dist/modules/staff/translations.js.map +2 -2
- package/dist/modules/staff/widgets/components.js +7 -0
- package/dist/modules/staff/widgets/components.js.map +7 -0
- package/dist/modules/staff/widgets/injection/timer-sidebar-indicator/widget.js +5 -4
- package/dist/modules/staff/widgets/injection/timer-sidebar-indicator/widget.js.map +2 -2
- package/dist/modules/staff/widgets/notifications/TimeProjectAccessRequestedRenderer.js +135 -0
- package/dist/modules/staff/widgets/notifications/TimeProjectAccessRequestedRenderer.js.map +7 -0
- package/dist/modules/staff/widgets/notifications/index.js +5 -0
- package/dist/modules/staff/widgets/notifications/index.js.map +7 -0
- package/dist/modules/staff/workers/timesheets-reapply-rounding.js +43 -0
- package/dist/modules/staff/workers/timesheets-reapply-rounding.js.map +7 -0
- package/generated/entities/staff_time_entry/index.ts +7 -0
- package/generated/entities/staff_time_entry_tag/index.ts +6 -0
- package/generated/entities/staff_time_project/index.ts +8 -0
- package/generated/entities/staff_time_report/index.ts +27 -0
- package/generated/entities/staff_time_report_entry/index.ts +12 -0
- package/generated/entities/staff_time_report_event/index.ts +9 -0
- package/generated/entities/staff_time_report_project/index.ts +6 -0
- package/generated/entities/staff_time_tag/index.ts +9 -0
- package/generated/entities/staff_time_task/index.ts +17 -0
- package/generated/entities/staff_time_task_comment/index.ts +9 -0
- package/generated/entities/staff_time_task_status/index.ts +13 -0
- package/generated/entities/staff_time_task_tag/index.ts +6 -0
- package/generated/entities.ids.generated.ts +11 -1
- package/generated/entity-fields-registry.ts +149 -0
- package/package.json +7 -7
- package/src/helpers/integration/timesheetFixtures.ts +31 -1
- package/src/modules/auth/README.md +1 -1
- package/src/modules/auth/cli.ts +35 -1
- package/src/modules/auth/i18n/de.json +7 -0
- package/src/modules/auth/i18n/en.json +7 -0
- package/src/modules/auth/i18n/es.json +7 -0
- package/src/modules/auth/i18n/ko.json +7 -0
- package/src/modules/auth/i18n/pl.json +7 -0
- package/src/modules/auth/lib/backendChrome.tsx +1 -0
- package/src/modules/customer_accounts/lib/customerRoleAcls.ts +79 -0
- package/src/modules/customer_accounts/setup.ts +1 -45
- package/src/modules/data_sync/AGENTS.md +34 -0
- package/src/modules/data_sync/api/options.ts +2 -0
- package/src/modules/data_sync/backend/data-sync/page.tsx +82 -33
- package/src/modules/data_sync/i18n/de.json +1 -0
- package/src/modules/data_sync/i18n/en.json +1 -0
- package/src/modules/data_sync/i18n/es.json +1 -0
- package/src/modules/data_sync/i18n/ko.json +1 -0
- package/src/modules/data_sync/i18n/pl.json +1 -0
- package/src/modules/data_sync/lib/adapter.ts +45 -0
- package/src/modules/data_sync/lib/start-controls.ts +89 -0
- package/src/modules/staff/AGENTS.md +769 -1
- package/src/modules/staff/acl.ts +9 -0
- package/src/modules/staff/ai-agents.ts +189 -0
- package/src/modules/staff/ai-tools/time-tracking-pack.ts +494 -0
- package/src/modules/staff/ai-tools/types.ts +82 -0
- package/src/modules/staff/ai-tools.ts +13 -0
- package/src/modules/staff/analytics.ts +113 -0
- package/src/modules/staff/api/guards.ts +85 -3
- package/src/modules/staff/api/leave-requests/accept/route.ts +0 -2
- package/src/modules/staff/api/leave-requests/reject/route.ts +0 -2
- package/src/modules/staff/api/portal/time-reports/[id]/route.ts +182 -0
- package/src/modules/staff/api/portal/time-reports/route.ts +270 -0
- package/src/modules/staff/api/team-members/self/route.ts +0 -2
- package/src/modules/staff/api/team-members/tags/assign/route.ts +0 -2
- package/src/modules/staff/api/team-members/tags/unassign/route.ts +0 -2
- package/src/modules/staff/api/timesheets/_shared/withTimesheetInterceptors.ts +292 -0
- package/src/modules/staff/api/timesheets/access-requests/route.ts +299 -0
- package/src/modules/staff/api/timesheets/my-projects/[projectId]/route.ts +15 -7
- package/src/modules/staff/api/timesheets/my-projects/route.ts +14 -1
- package/src/modules/staff/api/timesheets/my-work/myWorkAggregate.ts +90 -0
- package/src/modules/staff/api/timesheets/my-work/route.ts +475 -0
- package/src/modules/staff/api/timesheets/projects/kpis/route.ts +15 -2
- package/src/modules/staff/api/timesheets/reports/[id]/close/route.ts +203 -0
- package/src/modules/staff/api/timesheets/reports/[id]/export/route.ts +315 -0
- package/src/modules/staff/api/timesheets/reports/[id]/sheet/route.ts +220 -0
- package/src/modules/staff/api/timesheets/reports/[id]/unlock/route.ts +208 -0
- package/src/modules/staff/api/timesheets/reports/preview/route.ts +449 -0
- package/src/modules/staff/api/timesheets/reports/route.ts +386 -0
- package/src/modules/staff/api/timesheets/reports/shared.ts +121 -0
- package/src/modules/staff/api/timesheets/settings/reapply-rounding/route.ts +205 -0
- package/src/modules/staff/api/timesheets/settings/rounding-impact/route.ts +226 -0
- package/src/modules/staff/api/timesheets/settings/route.ts +242 -0
- package/src/modules/staff/api/timesheets/tags/access.ts +134 -0
- package/src/modules/staff/api/timesheets/tags/entry-assignments/route.ts +290 -0
- package/src/modules/staff/api/timesheets/tags/route.ts +177 -0
- package/src/modules/staff/api/timesheets/tags/task-assignments/route.ts +294 -0
- package/src/modules/staff/api/timesheets/task-statuses/route.ts +232 -0
- package/src/modules/staff/api/timesheets/tasks/[id]/comments/route.ts +532 -0
- package/src/modules/staff/api/timesheets/tasks/[id]/status/route.ts +271 -0
- package/src/modules/staff/api/timesheets/tasks/route.ts +443 -0
- package/src/modules/staff/api/timesheets/time-entries/[id]/duplicate/route.ts +306 -0
- package/src/modules/staff/api/timesheets/time-entries/[id]/segments/[segmentId]/route.ts +32 -10
- package/src/modules/staff/api/timesheets/time-entries/[id]/segments/route.ts +32 -17
- package/src/modules/staff/api/timesheets/time-entries/[id]/timer-start/route.ts +27 -6
- package/src/modules/staff/api/timesheets/time-entries/[id]/timer-stop/route.ts +36 -6
- package/src/modules/staff/api/timesheets/time-entries/bulk/route.ts +331 -34
- package/src/modules/staff/api/timesheets/time-entries/copy-day/route.ts +533 -0
- package/src/modules/staff/api/timesheets/time-entries/overlaps/route.ts +457 -0
- package/src/modules/staff/api/timesheets/time-entries/route.ts +378 -24
- package/src/modules/staff/api/timesheets/time-entries/start-timer/route.ts +31 -9
- package/src/modules/staff/api/timesheets/time-projects/[id]/change-currency/route.ts +246 -0
- package/src/modules/staff/api/timesheets/time-projects/[id]/employees/route.ts +62 -2
- package/src/modules/staff/api/timesheets/time-projects/route.ts +397 -22
- package/src/modules/staff/backend/staff/time-tracking/board/page.meta.ts +14 -0
- package/src/modules/staff/backend/staff/time-tracking/board/page.tsx +151 -0
- package/src/modules/staff/backend/staff/time-tracking/entries/page.meta.ts +14 -0
- package/src/modules/staff/backend/staff/time-tracking/entries/page.tsx +1229 -0
- package/src/modules/staff/backend/staff/time-tracking/page.meta.ts +11 -0
- package/src/modules/staff/backend/staff/time-tracking/page.tsx +823 -0
- package/src/modules/staff/backend/staff/time-tracking/projects/[id]/board/page.meta.ts +12 -0
- package/src/modules/staff/backend/staff/time-tracking/projects/[id]/board/page.tsx +81 -0
- package/src/modules/staff/backend/staff/time-tracking/projects/[id]/edit/page.meta.ts +12 -0
- package/src/modules/staff/backend/staff/time-tracking/projects/[id]/edit/page.tsx +275 -0
- package/src/modules/staff/backend/staff/time-tracking/projects/[id]/page.meta.ts +12 -0
- package/src/modules/staff/backend/staff/time-tracking/projects/[id]/page.tsx +1420 -0
- package/src/modules/staff/backend/staff/time-tracking/projects/create/page.meta.ts +12 -0
- package/src/modules/staff/backend/staff/time-tracking/projects/create/page.tsx +109 -0
- package/src/modules/staff/backend/staff/time-tracking/projects/page.meta.ts +15 -0
- package/src/modules/staff/backend/staff/time-tracking/projects/page.tsx +1254 -0
- package/src/modules/staff/backend/staff/time-tracking/projects/projectFormConfig.ts +466 -0
- package/src/modules/staff/backend/staff/time-tracking/reports/[id]/page.meta.ts +12 -0
- package/src/modules/staff/backend/staff/time-tracking/reports/[id]/page.tsx +632 -0
- package/src/modules/staff/backend/staff/time-tracking/reports/create/page.meta.ts +12 -0
- package/src/modules/staff/backend/staff/time-tracking/reports/create/page.tsx +867 -0
- package/src/modules/staff/backend/staff/time-tracking/reports/page.meta.ts +14 -0
- package/src/modules/staff/backend/staff/time-tracking/reports/page.tsx +246 -0
- package/src/modules/staff/backend/staff/time-tracking/settings/page.meta.ts +14 -0
- package/src/modules/staff/backend/staff/time-tracking/settings/page.tsx +701 -0
- package/src/modules/staff/backend/staff/time-tracking/timesheet/GridView.tsx +953 -0
- package/src/modules/staff/backend/staff/time-tracking/timesheet/page.meta.ts +14 -0
- package/src/modules/staff/backend/staff/time-tracking/timesheet/page.tsx +800 -0
- package/src/modules/staff/backend/staff/timesheets/page.meta.ts +6 -6
- package/src/modules/staff/backend/staff/timesheets/page.tsx +12 -1010
- package/src/modules/staff/backend/staff/timesheets/projects/[id]/edit/page.meta.ts +0 -6
- package/src/modules/staff/backend/staff/timesheets/projects/[id]/edit/page.tsx +4 -158
- package/src/modules/staff/backend/staff/timesheets/projects/[id]/page.meta.ts +0 -6
- package/src/modules/staff/backend/staff/timesheets/projects/[id]/page.tsx +4 -609
- package/src/modules/staff/backend/staff/timesheets/projects/create/page.meta.ts +0 -6
- package/src/modules/staff/backend/staff/timesheets/projects/create/page.tsx +3 -89
- package/src/modules/staff/backend/staff/timesheets/projects/page.meta.ts +2 -19
- package/src/modules/staff/backend/staff/timesheets/projects/page.tsx +3 -778
- package/src/modules/staff/ce.ts +63 -0
- package/src/modules/staff/cli.ts +207 -1
- package/src/modules/staff/commands/index.ts +5 -0
- package/src/modules/staff/commands/timesheets-entries.ts +1006 -28
- package/src/modules/staff/commands/timesheets-projects.ts +593 -7
- package/src/modules/staff/commands/timesheets-reports.ts +1329 -0
- package/src/modules/staff/commands/timesheets-tags.ts +1315 -0
- package/src/modules/staff/commands/timesheets-task-comments.ts +583 -0
- package/src/modules/staff/commands/timesheets-task-statuses.ts +889 -0
- package/src/modules/staff/commands/timesheets-tasks.ts +1121 -0
- package/src/modules/staff/data/enrichers.ts +675 -10
- package/src/modules/staff/data/entities.ts +494 -2
- package/src/modules/staff/data/extensions.ts +68 -0
- package/src/modules/staff/data/validators.ts +348 -3
- package/src/modules/staff/di.ts +96 -0
- package/src/modules/staff/events.payloads.ts +268 -0
- package/src/modules/staff/events.ts +87 -5
- package/src/modules/staff/extension-points.ts +308 -0
- package/src/modules/staff/frontend/[orgSlug]/portal/time-reports/[id]/page.meta.ts +10 -0
- package/src/modules/staff/frontend/[orgSlug]/portal/time-reports/[id]/page.tsx +225 -0
- package/src/modules/staff/frontend/[orgSlug]/portal/time-reports/page.meta.ts +17 -0
- package/src/modules/staff/frontend/[orgSlug]/portal/time-reports/page.tsx +182 -0
- package/src/modules/staff/i18n/de.json +899 -0
- package/src/modules/staff/i18n/en.json +899 -0
- package/src/modules/staff/i18n/es.json +899 -0
- package/src/modules/staff/i18n/ko.json +899 -0
- package/src/modules/staff/i18n/pl.json +899 -0
- package/src/modules/staff/lib/crud.ts +14 -3
- package/src/modules/staff/lib/time-tracking/access.ts +155 -0
- package/src/modules/staff/lib/time-tracking/billability.ts +68 -0
- package/src/modules/staff/lib/time-tracking/capacity.ts +124 -0
- package/src/modules/staff/lib/time-tracking/componentContracts.ts +26 -0
- package/src/modules/staff/lib/time-tracking/cost.ts +144 -0
- package/src/modules/staff/lib/time-tracking/duration.ts +68 -0
- package/src/modules/staff/lib/time-tracking/featureAccess.ts +115 -0
- package/src/modules/staff/lib/time-tracking/interval.ts +90 -0
- package/src/modules/staff/lib/time-tracking/migrateProjectCodes.ts +161 -0
- package/src/modules/staff/lib/time-tracking/moneyVisibility.ts +37 -0
- package/src/modules/staff/lib/time-tracking/overlap.ts +159 -0
- package/src/modules/staff/lib/time-tracking/portalRecipients.ts +76 -0
- package/src/modules/staff/lib/time-tracking/portalReports.ts +31 -0
- package/src/modules/staff/lib/time-tracking/projectCode.ts +221 -0
- package/src/modules/staff/lib/time-tracking/reapplyRounding.ts +313 -0
- package/src/modules/staff/lib/time-tracking/recalculationRunner.ts +118 -0
- package/src/modules/staff/lib/time-tracking/recalculations.ts +135 -0
- package/src/modules/staff/lib/time-tracking/registries/invoke.ts +122 -0
- package/src/modules/staff/lib/time-tracking/registries/registry.ts +124 -0
- package/src/modules/staff/lib/time-tracking/registries/scope.ts +56 -0
- package/src/modules/staff/lib/time-tracking/rollup.ts +59 -0
- package/src/modules/staff/lib/time-tracking/rounding.ts +126 -0
- package/src/modules/staff/lib/time-tracking/roundingImpact.ts +75 -0
- package/src/modules/staff/lib/time-tracking/settingKeys.ts +274 -0
- package/src/modules/staff/lib/time-tracking/settings.ts +168 -0
- package/src/modules/staff/lib/time-tracking/sqlInClause.ts +22 -0
- package/src/modules/staff/lib/time-tracking/timeEntrySources.ts +85 -0
- package/src/modules/staff/lib/time-tracking-ui/BoardFilterChips.tsx +360 -0
- package/src/modules/staff/lib/time-tracking-ui/CustomerPicker.tsx +427 -0
- package/src/modules/staff/lib/time-tracking-ui/DurationInput.tsx +192 -0
- package/src/modules/staff/lib/time-tracking-ui/EntryDetailsFields.tsx +224 -0
- package/src/modules/staff/lib/time-tracking-ui/EntryFilterBar.tsx +144 -0
- package/src/modules/staff/lib/time-tracking-ui/KanbanBoard.tsx +1065 -0
- package/src/modules/staff/lib/time-tracking-ui/KanbanCard.tsx +435 -0
- package/src/modules/staff/lib/time-tracking-ui/KanbanColumn.tsx +316 -0
- package/src/modules/staff/lib/time-tracking-ui/NewTaskDialog.tsx +291 -0
- package/src/modules/staff/lib/time-tracking-ui/NoProjectAccess.tsx +162 -0
- package/src/modules/staff/lib/time-tracking-ui/PeriodSelector.tsx +149 -0
- package/src/modules/staff/lib/time-tracking-ui/PhasePlaceholder.tsx +31 -0
- package/src/modules/staff/lib/time-tracking-ui/ProjectCodeField.tsx +230 -0
- package/src/modules/staff/lib/time-tracking-ui/ProjectCurrencyField.tsx +432 -0
- package/src/modules/staff/lib/time-tracking-ui/ProjectFormSections.tsx +323 -0
- package/src/modules/staff/lib/time-tracking-ui/ProjectTeamDrawer.tsx +930 -0
- package/src/modules/staff/lib/time-tracking-ui/ReportSheet.tsx +357 -0
- package/src/modules/staff/lib/time-tracking-ui/TagPicker.tsx +195 -0
- package/src/modules/staff/lib/time-tracking-ui/TaskBoardScreen.tsx +243 -0
- package/src/modules/staff/lib/time-tracking-ui/TaskCommentThread.tsx +137 -0
- package/src/modules/staff/lib/time-tracking-ui/TaskDrawer.tsx +1405 -0
- package/src/modules/staff/lib/time-tracking-ui/TaskListView.tsx +260 -0
- package/src/modules/staff/lib/time-tracking-ui/TaskPicker.tsx +435 -0
- package/src/modules/staff/lib/time-tracking-ui/TaskQuickLog.tsx +296 -0
- package/src/modules/staff/lib/time-tracking-ui/TimeEntriesSummaryFooter.tsx +97 -0
- package/src/modules/staff/lib/time-tracking-ui/TimeEntryDialog.tsx +1929 -0
- package/src/modules/staff/lib/time-tracking-ui/TimeEntryDurationCell.tsx +126 -0
- package/src/modules/staff/lib/time-tracking-ui/TimesheetCalendar.tsx +265 -0
- package/src/modules/staff/lib/time-tracking-ui/TimesheetPeriodFooter.tsx +78 -0
- package/src/modules/staff/lib/time-tracking-ui/TimesheetViewSwitch.tsx +70 -0
- package/src/modules/staff/lib/time-tracking-ui/boardDirectory.ts +231 -0
- package/src/modules/staff/lib/time-tracking-ui/boardFilters.ts +128 -0
- package/src/modules/staff/lib/time-tracking-ui/boardSummary.ts +20 -0
- package/src/modules/staff/lib/time-tracking-ui/kanbanBoardData.ts +228 -0
- package/src/modules/staff/lib/time-tracking-ui/projectTeamAssignment.ts +143 -0
- package/src/modules/staff/lib/time-tracking-ui/taskDrawerData.ts +194 -0
- package/src/modules/staff/lib/time-tracking-ui/timeEntryDialogState.ts +400 -0
- package/src/modules/staff/lib/time-tracking-ui/timeEntryListData.ts +271 -0
- package/src/modules/staff/lib/time-tracking-ui/timeTrackingSettingsForm.ts +168 -0
- package/src/modules/staff/lib/time-tracking-ui/timesheetData.ts +225 -0
- package/src/modules/staff/lib/time-tracking-ui/timesheetPeriod.ts +278 -0
- package/src/modules/staff/lib/time-tracking-ui/timesheetTargets.ts +93 -0
- package/src/modules/staff/lib/time-tracking-ui/useBoardFilters.ts +107 -0
- package/src/modules/staff/lib/time-tracking-ui/useTimesheetPreferences.ts +245 -0
- package/src/modules/staff/lib/timeTrackingSeeds.ts +1037 -0
- package/src/modules/staff/lib/timesheets/timeEntryCacheInvalidation.ts +11 -10
- package/src/modules/staff/lib/timesheets/timeEntryDecoration.ts +256 -0
- package/src/modules/staff/lib/timesheets-projects/budgetBurn.ts +60 -0
- package/src/modules/staff/lib/timesheets-projects/budgetThreshold.ts +135 -0
- package/src/modules/staff/lib/timesheets-projects/budgetThresholdState.ts +137 -0
- package/src/modules/staff/lib/timesheets-projects/computeProjectFinancials.ts +142 -0
- package/src/modules/staff/lib/timesheets-projects/reportSelection.ts +82 -0
- package/src/modules/staff/lib/timesheets-projects-ui/AssignMembersDialog.tsx +237 -0
- package/src/modules/staff/lib/timesheets-projects-ui/ProjectBudgetCell.tsx +33 -0
- package/src/modules/staff/lib/timesheets-projects-ui/ProjectCard.tsx +56 -1
- package/src/modules/staff/lib/timesheets-projects-ui/ProjectsBulkActionsBar.tsx +90 -0
- package/src/modules/staff/lib/timesheets-reports/buildReportSheet.ts +125 -0
- package/src/modules/staff/lib/timesheets-reports/loadReportData.ts +251 -0
- package/src/modules/staff/lib/timesheets-reports/pdf.ts +263 -0
- package/src/modules/staff/lib/timesheets-reports/reportApprovalPolicies.ts +137 -0
- package/src/modules/staff/lib/timesheets-reports/reportConfigData.ts +247 -0
- package/src/modules/staff/lib/timesheets-reports/reportConfigState.ts +89 -0
- package/src/modules/staff/lib/timesheets-reports/reportExport.ts +373 -0
- package/src/modules/staff/lib/timesheets-reports/reportExportFormats.ts +71 -0
- package/src/modules/staff/lib/timesheets-reports/reportGroupings.ts +153 -0
- package/src/modules/staff/lib/timesheets-reports/reportLabels.ts +23 -0
- package/src/modules/staff/lib/timesheets-reports/reportReference.ts +146 -0
- package/src/modules/staff/lib/timesheets-reports/reportRows.ts +89 -0
- package/src/modules/staff/lib/timesheets-reports/reportSheetData.ts +196 -0
- package/src/modules/staff/lib/timesheets-reports/reportTotals.ts +544 -0
- package/src/modules/staff/lib/timesheets-reports/xlsx.ts +207 -0
- package/src/modules/staff/lib/timesheets-tasks/computeTaskRollups.ts +238 -0
- package/src/modules/staff/lib/timesheets-tasks/defaultStatusTemplate.ts +90 -0
- package/src/modules/staff/lib/timesheets-tasks/seedProjectStatuses.ts +43 -0
- package/src/modules/staff/lib/timesheets-tasks/statusPositions.ts +132 -0
- package/src/modules/staff/lib/timesheets-tasks/statusSlug.ts +43 -0
- package/src/modules/staff/lib/timesheets-tasks/taskHierarchy.ts +99 -0
- package/src/modules/staff/lib/timesheets-tasks/taskHoursTotals.ts +42 -0
- package/src/modules/staff/lib/timesheets-tasks/taskReference.ts +108 -0
- package/src/modules/staff/lib/timesheets-ui/CreateProjectDialog.tsx +18 -4
- package/src/modules/staff/lib/timesheets-ui/ListView.tsx +504 -149
- package/src/modules/staff/lib/timesheets-ui/TimerBar.tsx +50 -2
- package/src/modules/staff/migrations/.snapshot-open-mercato.json +3244 -228
- package/src/modules/staff/migrations/Migration20260813073131_staff.ts +94 -0
- package/src/modules/staff/migrations/Migration20260824143357_staff.ts +17 -0
- package/src/modules/staff/notifications.client.ts +16 -0
- package/src/modules/staff/notifications.handlers.ts +88 -0
- package/src/modules/staff/notifications.ts +163 -0
- package/src/modules/staff/search.ts +191 -1
- package/src/modules/staff/setup.ts +22 -0
- package/src/modules/staff/subscribers/time-project-access-requested-notification.ts +95 -0
- package/src/modules/staff/subscribers/time-project-budget-threshold-notification.ts +226 -0
- package/src/modules/staff/subscribers/time-report-approved-notification.ts +116 -0
- package/src/modules/staff/subscribers/time-report-portal-broadcast.ts +120 -0
- package/src/modules/staff/translations.ts +17 -0
- package/src/modules/staff/widgets/components.ts +34 -0
- package/src/modules/staff/widgets/injection/timer-sidebar-indicator/widget.tsx +6 -5
- package/src/modules/staff/widgets/notifications/TimeProjectAccessRequestedRenderer.tsx +138 -0
- package/src/modules/staff/widgets/notifications/index.ts +1 -0
- package/src/modules/staff/workers/timesheets-reapply-rounding.ts +59 -0
- package/dist/modules/staff/backend/staff/timesheets/projects/projectFormConfig.js +0 -123
- package/dist/modules/staff/backend/staff/timesheets/projects/projectFormConfig.js.map +0 -7
- package/src/modules/staff/backend/staff/timesheets/projects/projectFormConfig.ts +0 -138
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../src/modules/staff/lib/timesheets-ui/ListView.tsx"],
|
|
4
|
-
"sourcesContent": ["'use client'\n\nimport * as React from 'react'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport type { TranslateFn } from '@open-mercato/shared/lib/i18n/context'\nimport { apiCallOrThrow } from '@open-mercato/ui/backend/utils/apiCall'\nimport { surfaceRecordConflict } from '@open-mercato/ui/backend/conflicts'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { ProjectColorDot } from './ProjectColorDot'\n\ntype TimeEntry = {\n id: string\n date: string\n durationMinutes: number\n projectId: string\n projectName: string\n projectCode: string | null\n projectColor: string | null\n notes: string | null\n source: string\n startedAt: string | null\n endedAt: string | null\n}\n\ntype ListViewProps = {\n entries: TimeEntry[]\n onEntryUpdated?: () => void\n}\n\nfunction getLocalDateStr(date: Date): string {\n const year = date.getFullYear()\n const month = String(date.getMonth() + 1).padStart(2, '0')\n const day = String(date.getDate()).padStart(2, '0')\n return `${year}-${month}-${day}`\n}\n\nfunction formatDayLabel(dateStr: string, translate: TranslateFn): string {\n const today = new Date()\n const todayStr = getLocalDateStr(today)\n\n const yesterday = new Date(today)\n yesterday.setDate(yesterday.getDate() - 1)\n const yesterdayStr = getLocalDateStr(yesterday)\n\n if (dateStr === todayStr) return translate('staff.timesheets.my.list.today', 'Today')\n if (dateStr === yesterdayStr) return translate('staff.timesheets.my.list.yesterday', 'Yesterday')\n\n const date = new Date(dateStr + 'T00:00:00')\n const dayName = date.toLocaleDateString(undefined, { weekday: 'short' })\n const day = date.getDate()\n const month = date.toLocaleDateString(undefined, { month: 'short' })\n\n return `${dayName}, ${day} ${month}`\n}\n\nfunction formatDuration(minutes: number): string {\n if (minutes < 60) return `${minutes}m`\n\n const hours = Math.floor(minutes / 60)\n const remainingMinutes = minutes % 60\n\n if (remainingMinutes === 0) return `${hours}h`\n return `${hours}h ${remainingMinutes}m`\n}\n\nfunction formatTimeRange(startedAt: string, endedAt: string): string {\n const start = new Date(startedAt)\n const end = new Date(endedAt)\n\n const format = (date: Date) =>\n date.toLocaleTimeString(undefined, {\n hour: 'numeric',\n minute: '2-digit',\n hour12: true,\n })\n\n return `${format(start)} - ${format(end)}`\n}\n\nfunction InlineDescription({\n entryId,\n initialValue,\n placeholder,\n onSaved,\n}: {\n entryId: string\n initialValue: string | null\n placeholder: string\n onSaved?: () => void\n}) {\n const t = useT()\n const [editing, setEditing] = React.useState(false)\n const [value, setValue] = React.useState(initialValue ?? '')\n const [saving, setSaving] = React.useState(false)\n const inputRef = React.useRef<HTMLInputElement>(null)\n\n React.useEffect(() => {\n if (editing && inputRef.current) inputRef.current.focus()\n }, [editing])\n\n const save = React.useCallback(async () => {\n const trimmed = value.trim()\n if (trimmed === (initialValue ?? '')) {\n setEditing(false)\n return\n }\n setSaving(true)\n try {\n await apiCallOrThrow(`/api/staff/timesheets/time-entries`, {\n method: 'PUT',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ id: entryId, notes: trimmed || null }),\n })\n setSaving(false)\n setEditing(false)\n onSaved?.()\n } catch (err) {\n setSaving(false)\n if (!surfaceRecordConflict(err, t)) {\n flash(\n t('staff.timesheets.my.list.saveError', 'Failed to save description. Please try again.'),\n 'error',\n )\n }\n }\n }, [entryId, value, initialValue, onSaved, t])\n\n if (!editing) {\n return (\n <button\n type=\"button\"\n onClick={() => setEditing(true)}\n className={`text-sm text-left cursor-pointer hover:underline ${\n initialValue ? '' : 'text-muted-foreground italic'\n }`}\n >\n {initialValue || placeholder}\n </button>\n )\n }\n\n return (\n <input\n ref={inputRef}\n type=\"text\"\n value={value}\n disabled={saving}\n onChange={(e) => setValue(e.target.value)}\n onBlur={() => { void save() }}\n onKeyDown={(e) => {\n if (e.key === 'Enter') { void save() }\n if (e.key === 'Escape') { setValue(initialValue ?? ''); setEditing(false) }\n }}\n placeholder={placeholder}\n className=\"text-sm w-full bg-transparent border-b border-primary/40 outline-none py-0.5 placeholder:text-muted-foreground/50\"\n />\n )\n}\n\nexport function ListView({ entries, onEntryUpdated }: ListViewProps) {\n const t = useT()\n\n if (entries.length === 0) {\n return (\n <div className=\"flex items-center justify-center py-12 text-sm text-muted-foreground\">\n {t('staff.timesheets.my.list.noEntries', 'No entries for this period.')}\n </div>\n )\n }\n\n const grouped = new Map<string, TimeEntry[]>()\n for (const entry of entries) {\n const existing = grouped.get(entry.date)\n if (existing) {\n existing.push(entry)\n } else {\n grouped.set(entry.date, [entry])\n }\n }\n\n const sortedDays = [...grouped.keys()].sort((a, b) => b.localeCompare(a))\n\n return (\n <div>\n {sortedDays.map((dateStr) => {\n const dayEntries = grouped.get(dateStr)!\n const dailyTotal = dayEntries.reduce(\n (sum, entry) => sum + entry.durationMinutes,\n 0,\n )\n\n return (\n <div key={dateStr} className=\"rounded-lg border mb-4\">\n <div className=\"flex justify-between items-center p-4 border-b bg-muted/30 font-medium text-sm\">\n <span>{formatDayLabel(dateStr, t)}</span>\n <span className=\"font-mono tabular-nums\">\n {formatDuration(dailyTotal)}\n </span>\n </div>\n\n {dayEntries.map((entry) => (\n <div\n key={entry.id}\n className=\"flex items-center justify-between p-3 border-b last:border-0 hover:bg-muted/20\"\n >\n <div className=\"flex flex-col gap-1 min-w-0 flex-1 mr-4\">\n <InlineDescription\n entryId={entry.id}\n initialValue={entry.notes}\n placeholder={t('staff.timesheets.my.list.addDescription', 'Add description')}\n onSaved={onEntryUpdated}\n />\n <span className=\"inline-flex items-center gap-1 text-xs font-medium text-muted-foreground\">\n <ProjectColorDot colorKey={entry.projectColor} projectName={entry.projectName} size=\"xs\" />\n {entry.projectName}\n </span>\n </div>\n\n <div className=\"flex flex-col items-end gap-1 shrink-0\">\n {entry.source === 'timer' &&\n entry.startedAt &&\n entry.endedAt ? (\n <span className=\"text-xs text-muted-foreground\">\n {formatTimeRange(entry.startedAt, entry.endedAt)}\n </span>\n ) : null}\n <span className=\"text-sm font-mono tabular-nums\">\n {formatDuration(entry.durationMinutes)}\n </span>\n </div>\n </div>\n ))}\n </div>\n )\n })}\n </div>\n )\n}\n"],
|
|
5
|
-
"mappings": ";
|
|
4
|
+
"sourcesContent": ["'use client'\n\nimport * as React from 'react'\nimport { z } from 'zod'\nimport { registerComponent } from '@open-mercato/shared/modules/widgets/component-registry'\nimport { useRegisteredComponent } from '@open-mercato/ui/backend/injection/useRegisteredComponent'\nimport { extensionPoints } from '@open-mercato/core/modules/staff/extension-points'\nimport {\n callbackProp,\n opaqueProp,\n optionalCallbackProp,\n} from '../time-tracking/componentContracts'\nimport { Copy, Lock, Pencil, Plus } from 'lucide-react'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { Input } from '@open-mercato/ui/primitives/input'\nimport { Progress } from '@open-mercato/ui/primitives/progress'\nimport { StatusBadge } from '@open-mercato/ui/primitives/status-badge'\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '@open-mercato/ui/primitives/select'\nimport { apiCallOrThrow, withScopedApiRequestHeaders } from '@open-mercato/ui/backend/utils/apiCall'\nimport { buildOptimisticLockHeader } from '@open-mercato/ui/backend/utils/optimisticLock'\nimport { surfaceRecordConflict } from '@open-mercato/ui/backend/conflicts'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { useGuardedMutation } from '@open-mercato/ui/backend/injection/useGuardedMutation'\nimport { cn } from '@open-mercato/shared/lib/utils'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { DurationInput } from '../time-tracking-ui/DurationInput'\nimport { formatDuration } from '../time-tracking/duration'\nimport {\n loadPercent,\n suggestNextStartClock,\n type TimesheetDay,\n type TimesheetEntry,\n} from '../time-tracking-ui/timesheetData'\nimport { formatDayLabel, formatLongDayLabel } from '../time-tracking-ui/timesheetPeriod'\nimport { targetLabel, type TimesheetLogTarget } from '../time-tracking-ui/timesheetTargets'\n\n/**\n * Screen 12 \u2014 the period as a stack of days (T5.3).\n *\n * Four notes on the mockup, four rules here:\n *\n * 1. **The author is on the line only when the view is showing more than one\n * person** (note 1). A Team Member filtered to themselves does not need to\n * be told, on every row, that they logged it.\n * 2. **Exactly one day starts expanded \u2014 the one that deviates from the\n * target** (note 2), chosen by `pickDefaultExpandedDay`. Every bar is\n * clickable, so any other day is one click away, and the expansion is a\n * controlled prop so the page can re-derive it when the period changes.\n * 3. **The quick-add row's third field is the start time, prefilled with the\n * end of the previous entry of that day** (note 3). The suggestion is\n * recomputed from the day's entries rather than remembered, so adding a\n * second entry immediately offers the end of the first.\n * 4. **A weekend is greyed and contributes no target** but still shows any time\n * logged on it (note 4). It reads `\u2014`, never `0:00`: nothing was logged, a\n * zero-length day was not worked.\n */\n\nexport type ListViewQuickAdd = {\n date: string\n targetKey: string\n durationMinutes: number\n startClock: string | null\n}\n\nexport type ListViewProps = {\n days: readonly TimesheetDay[]\n scaleMinutes: number | null\n /** Per-day target in minutes; `null` when the tenant cleared `targets.dailyHours`. */\n dailyTargetMinutes: number | null\n expandedDate: string | null\n onExpandedDateChange: (date: string | null) => void\n targets: readonly TimesheetLogTarget[]\n showAuthor: boolean\n authorNames: ReadonlyMap<string, string>\n canManage: boolean\n onQuickAdd: (input: ListViewQuickAdd) => Promise<void> | void\n onEditEntry: (entry: TimesheetEntry) => void\n onDuplicateEntry: (entry: TimesheetEntry) => void\n /** Fired after a successful inline description save, so the page can refetch. */\n onEntryUpdated?: () => void\n locale?: string\n}\n\nconst ENTRIES_ENDPOINT = '/api/staff/timesheets/time-entries'\nconst DESCRIPTION_CONTEXT_ID = 'staff.time_tracking.timesheet.list.description'\n\n/**\n * The description of a row, editable in place \u2014 carried over from the previous\n * list view, which is where the one-word note that makes an entry readable is\n * normally typed. Its three rules are regression-tested and predate this\n * redesign:\n *\n * * a failed PUT is NOT success \u2014 the editor stays open, an error is flashed and\n * the caller is not told the row changed;\n * * a 2xx closes the editor and notifies the caller;\n * * a 409 raises the shared conflict bar instead of a generic error.\n *\n * The write now also carries the record's version (`buildOptimisticLockHeader`),\n * which the old inline editor did not, so two people editing the same entry's\n * description get a conflict rather than a silent last-write-wins.\n *\n * A save is single-flight (`savingRef`). Committing with Enter disables the\n * input, which blurs it, and the blur handler would otherwise fire a second PUT\n * carrying the version captured before the first one landed \u2014 the user's own\n * successful edit coming back at them as a conflict.\n */\nfunction InlineDescription({\n entry,\n placeholder,\n onSaved,\n}: {\n entry: TimesheetEntry\n placeholder: string\n onSaved?: () => void\n}) {\n const t = useT()\n const [editing, setEditing] = React.useState(false)\n const [value, setValue] = React.useState(entry.description ?? '')\n const [saving, setSaving] = React.useState(false)\n const savingRef = React.useRef(false)\n const inputRef = React.useRef<HTMLInputElement>(null)\n const { runMutation, retryLastMutation } = useGuardedMutation<{\n formId: string\n resourceKind: string\n resourceId: string\n retryLastMutation: () => Promise<boolean>\n }>({\n contextId: DESCRIPTION_CONTEXT_ID,\n blockedMessage: t('ui.forms.flash.saveBlocked', 'Save blocked by validation'),\n })\n\n React.useEffect(() => {\n if (editing && inputRef.current) inputRef.current.focus()\n }, [editing])\n\n const save = React.useCallback(async () => {\n if (savingRef.current) return\n const trimmed = value.trim()\n if (trimmed === (entry.description ?? '')) {\n setEditing(false)\n return\n }\n const payload = { id: entry.id, notes: trimmed || null }\n savingRef.current = true\n setSaving(true)\n try {\n await runMutation({\n operation: () =>\n withScopedApiRequestHeaders(buildOptimisticLockHeader(entry.updatedAt), () =>\n apiCallOrThrow(ENTRIES_ENDPOINT, {\n method: 'PUT',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(payload),\n }),\n ),\n context: {\n formId: DESCRIPTION_CONTEXT_ID,\n resourceKind: 'staff.timesheets.time_entry',\n resourceId: entry.id,\n retryLastMutation,\n },\n mutationPayload: payload,\n })\n savingRef.current = false\n setSaving(false)\n setEditing(false)\n onSaved?.()\n } catch (error) {\n savingRef.current = false\n setSaving(false)\n if (!surfaceRecordConflict(error, t)) {\n flash(\n t('staff.timesheets.my.list.saveError', 'Failed to save description. Please try again.'),\n 'error',\n )\n }\n }\n }, [entry.description, entry.id, entry.updatedAt, onSaved, retryLastMutation, runMutation, t, value])\n\n if (!editing) {\n return (\n <button\n type=\"button\"\n onClick={() => setEditing(true)}\n className={cn(\n 'text-left text-xs hover:underline',\n entry.description ? 'text-muted-foreground' : 'italic text-muted-foreground/70',\n )}\n >\n {entry.description || placeholder}\n </button>\n )\n }\n\n return (\n <input\n ref={inputRef}\n type=\"text\"\n value={value}\n disabled={saving}\n onChange={(event) => setValue(event.target.value)}\n onBlur={() => {\n if (savingRef.current) return\n void save()\n }}\n onKeyDown={(event) => {\n if (event.key === 'Enter') void save()\n if (event.key === 'Escape') {\n setValue(entry.description ?? '')\n setEditing(false)\n }\n }}\n placeholder={placeholder}\n className=\"w-full border-b border-primary/40 bg-transparent py-0.5 text-xs outline-none placeholder:text-muted-foreground/50\"\n />\n )\n}\n\nfunction DefaultListView({\n days,\n scaleMinutes,\n dailyTargetMinutes,\n expandedDate,\n onExpandedDateChange,\n targets,\n showAuthor,\n authorNames,\n canManage,\n onQuickAdd,\n onEditEntry,\n onDuplicateEntry,\n onEntryUpdated,\n locale,\n}: ListViewProps) {\n const t = useT()\n\n if (days.length === 0) {\n return (\n <div className=\"flex items-center justify-center py-12 text-sm text-muted-foreground\">\n {t('staff.time_tracking.timesheet.list.empty', 'No days in this period.')}\n </div>\n )\n }\n\n return (\n <div className=\"flex flex-col gap-4\">\n <div className=\"flex flex-col gap-2\">\n {days.map((day) => {\n const expanded = day.date === expandedDate\n const deviation =\n dailyTargetMinutes !== null && !day.isWeekend ? day.totalMinutes - dailyTargetMinutes : null\n return (\n <button\n key={day.date}\n type=\"button\"\n aria-expanded={expanded}\n onClick={() => onExpandedDateChange(expanded ? null : day.date)}\n className={cn(\n 'flex w-full items-center gap-3 rounded-md px-2 py-1.5 text-left transition-colors',\n 'hover:bg-muted/50 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring',\n expanded ? 'bg-muted/50' : null,\n )}\n >\n <span\n className={cn(\n 'w-32 shrink-0 text-sm',\n day.isWeekend ? 'text-muted-foreground' : 'text-foreground',\n )}\n >\n {formatDayLabel(day.date, locale)}\n </span>\n <span className=\"min-w-0 flex-1\">\n <Progress value={loadPercent(day.totalMinutes, scaleMinutes)} size=\"sm\" />\n </span>\n <span\n className={cn(\n 'w-16 shrink-0 text-right font-mono text-sm tabular-nums',\n day.totalMinutes > 0 ? 'text-foreground' : 'text-muted-foreground',\n )}\n >\n {day.totalMinutes > 0 ? formatDuration(day.totalMinutes, 'clock') : '\u2014'}\n </span>\n {deviation !== null && deviation < 0 ? (\n <StatusBadge variant=\"warning\">\n {t('staff.time_tracking.timesheet.list.belowTarget', '{duration} below target', {\n duration: formatDuration(Math.abs(deviation), 'clock'),\n })}\n </StatusBadge>\n ) : null}\n </button>\n )\n })}\n </div>\n\n {expandedDate ? (\n <ExpandedDay\n day={days.find((day) => day.date === expandedDate) ?? null}\n dailyTargetMinutes={dailyTargetMinutes}\n targets={targets}\n showAuthor={showAuthor}\n authorNames={authorNames}\n canManage={canManage}\n onQuickAdd={onQuickAdd}\n onEditEntry={onEditEntry}\n onDuplicateEntry={onDuplicateEntry}\n onEntryUpdated={onEntryUpdated}\n locale={locale}\n />\n ) : null}\n </div>\n )\n}\n\nfunction ExpandedDay({\n day,\n dailyTargetMinutes,\n targets,\n showAuthor,\n authorNames,\n canManage,\n onQuickAdd,\n onEditEntry,\n onDuplicateEntry,\n onEntryUpdated,\n locale,\n}: {\n day: TimesheetDay | null\n dailyTargetMinutes: number | null\n targets: readonly TimesheetLogTarget[]\n showAuthor: boolean\n authorNames: ReadonlyMap<string, string>\n canManage: boolean\n onQuickAdd: (input: ListViewQuickAdd) => Promise<void> | void\n onEditEntry: (entry: TimesheetEntry) => void\n onDuplicateEntry: (entry: TimesheetEntry) => void\n onEntryUpdated?: () => void\n locale?: string\n}) {\n const t = useT()\n if (!day) return null\n const deviation = dailyTargetMinutes !== null && !day.isWeekend ? day.totalMinutes - dailyTargetMinutes : null\n\n return (\n <div className=\"flex flex-col gap-3 border-t pt-4\">\n <div className=\"flex flex-wrap items-center justify-between gap-2\">\n <span className=\"text-xs font-semibold uppercase tracking-wide text-muted-foreground\">\n {formatLongDayLabel(day.date, locale)} \u2014 {formatDuration(day.totalMinutes, 'clock')}\n </span>\n {deviation !== null && deviation !== 0 ? (\n <StatusBadge variant={deviation > 0 ? 'success' : 'warning'}>\n {deviation > 0\n ? t('staff.time_tracking.timesheet.list.aboveTarget', '{duration} above target', {\n duration: formatDuration(deviation, 'clock'),\n })\n : t('staff.time_tracking.timesheet.list.belowTarget', '{duration} below target', {\n duration: formatDuration(Math.abs(deviation), 'clock'),\n })}\n </StatusBadge>\n ) : null}\n </div>\n\n {day.entries.length === 0 ? (\n <p className=\"text-sm text-muted-foreground\">\n {t('staff.time_tracking.timesheet.list.noEntries', 'Nothing logged on this day yet.')}\n </p>\n ) : (\n <table className=\"w-full text-sm\">\n <tbody>\n {day.entries.map((entry) => (\n <tr key={entry.id} className=\"border-b last:border-0\">\n <td className=\"w-28 py-2 align-top text-xs text-muted-foreground\">\n {entry.startText && entry.endText ? `${entry.startText} \u2013 ${entry.endText}` : '\u2014'}\n </td>\n <td className=\"py-2 align-top\">\n <div className=\"flex flex-wrap items-center gap-2\">\n <span className=\"font-medium\">\n {entry.taskTitle ??\n entry.description ??\n t('staff.time_tracking.timesheet.list.noTask', 'No task')}\n </span>\n {entry.isBillable ? null : (\n <StatusBadge variant=\"neutral\">\n {t('staff.time_tracking.timesheet.list.nonBillable', 'non-billable')}\n </StatusBadge>\n )}\n {entry.isLocked ? (\n <StatusBadge variant=\"neutral\">\n <Lock className=\"size-3\" aria-hidden=\"true\" />\n {t('staff.time_tracking.timesheet.list.locked', 'locked')}\n </StatusBadge>\n ) : null}\n </div>\n <div className=\"text-xs text-muted-foreground\">\n {[\n entry.projectLabel,\n showAuthor && entry.staffMemberId ? authorNames.get(entry.staffMemberId) ?? null : null,\n ]\n .filter((part): part is string => Boolean(part))\n .join(' \u00B7 ')}\n </div>\n {canManage && !entry.isLocked ? (\n <InlineDescription\n entry={entry}\n placeholder={t('staff.timesheets.my.list.addDescription', 'Add description')}\n onSaved={onEntryUpdated}\n />\n ) : entry.description ? (\n <div className=\"text-xs text-muted-foreground\">{entry.description}</div>\n ) : null}\n </td>\n <td className=\"w-20 py-2 text-right align-top font-mono font-semibold tabular-nums\">\n {formatDuration(entry.durationMinutes, 'clock')}\n </td>\n <td className=\"w-24 py-2 text-right align-top\">\n {canManage ? (\n <span className=\"inline-flex items-center gap-1\">\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"2xs\"\n aria-label={t('staff.time_tracking.timesheet.list.duplicate', 'Duplicate')}\n onClick={() => onDuplicateEntry(entry)}\n disabled={entry.isLocked}\n >\n <Copy className=\"size-3.5\" aria-hidden=\"true\" />\n </Button>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"2xs\"\n aria-label={t('staff.time_tracking.timesheet.list.edit', 'Edit')}\n onClick={() => onEditEntry(entry)}\n disabled={entry.isLocked}\n >\n <Pencil className=\"size-3.5\" aria-hidden=\"true\" />\n </Button>\n </span>\n ) : null}\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n )}\n\n {canManage && targets.length > 0 ? (\n <QuickAddRow key={day.date} day={day} targets={targets} onQuickAdd={onQuickAdd} />\n ) : null}\n </div>\n )\n}\n\nfunction QuickAddRow({\n day,\n targets,\n onQuickAdd,\n}: {\n day: TimesheetDay\n targets: readonly TimesheetLogTarget[]\n onQuickAdd: (input: ListViewQuickAdd) => Promise<void> | void\n}) {\n const t = useT()\n const [targetKey, setTargetKey] = React.useState<string>(() => targets[0]?.key ?? '')\n const [minutes, setMinutes] = React.useState<number | null>(null)\n const [durationEpoch, setDurationEpoch] = React.useState(0)\n const suggestedStart = suggestNextStartClock(day)\n const [startClock, setStartClock] = React.useState<string>(suggestedStart ?? '')\n const [submitting, setSubmitting] = React.useState(false)\n const suggestedRef = React.useRef(suggestedStart)\n\n // The suggestion follows the day's entries: saving one immediately offers its\n // end for the next. A start the user typed themselves is never overwritten.\n React.useEffect(() => {\n if (suggestedRef.current === suggestedStart) return\n const previousSuggestion = suggestedRef.current\n suggestedRef.current = suggestedStart\n setStartClock((current) => (current === (previousSuggestion ?? '') ? suggestedStart ?? '' : current))\n }, [suggestedStart])\n\n const submit = React.useCallback(async () => {\n if (!targetKey || minutes === null || minutes <= 0 || submitting) return\n setSubmitting(true)\n try {\n await onQuickAdd({\n date: day.date,\n targetKey,\n durationMinutes: minutes,\n startClock: startClock.trim() ? startClock.trim() : null,\n })\n setMinutes(null)\n setDurationEpoch((epoch) => epoch + 1)\n } finally {\n setSubmitting(false)\n }\n }, [day.date, minutes, onQuickAdd, startClock, submitting, targetKey])\n\n return (\n <div\n className=\"flex flex-wrap items-start gap-2\"\n onKeyDown={(event) => {\n if ((event.metaKey || event.ctrlKey) && event.key === 'Enter') {\n event.preventDefault()\n void submit()\n }\n }}\n >\n <Select value={targetKey} onValueChange={setTargetKey}>\n <SelectTrigger\n className=\"w-72\"\n aria-label={t('staff.time_tracking.timesheet.list.quickAdd.target', 'Project or task')}\n >\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {targets.map((target) => (\n <SelectItem key={target.key} value={target.key}>\n {targetLabel(target)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n <div className=\"w-32\">\n <DurationInput\n key={durationEpoch}\n variant=\"compact\"\n value={minutes}\n onChange={(next) => setMinutes(next)}\n ariaLabel={t('staff.time_tracking.timesheet.list.quickAdd.duration', 'Duration')}\n placeholder={t('staff.time_tracking.duration.placeholder', '1h 30m')}\n />\n </div>\n <Input\n size=\"sm\"\n className=\"w-24\"\n inputClassName=\"font-mono tabular-nums\"\n value={startClock}\n onChange={(event) => setStartClock(event.target.value)}\n aria-label={t('staff.time_tracking.timesheet.list.quickAdd.start', 'Start time')}\n placeholder={t('staff.time_tracking.timesheet.list.quickAdd.startPlaceholder', '13:30')}\n />\n <Button\n type=\"button\"\n size=\"sm\"\n onClick={() => void submit()}\n disabled={submitting || minutes === null || minutes <= 0 || !targetKey}\n >\n <Plus className=\"size-4\" aria-hidden=\"true\" />\n {t('staff.time_tracking.timesheet.list.quickAdd.submit', 'Add')}\n </Button>\n </div>\n )\n}\n\nconst listViewPropsSchema: z.ZodType<ListViewProps> = z.object({\n days: z.array(opaqueProp<TimesheetDay>()),\n scaleMinutes: z.number().nullable(),\n dailyTargetMinutes: z.number().nullable(),\n expandedDate: z.string().nullable(),\n onExpandedDateChange: callbackProp<(date: string | null) => void>(),\n targets: z.array(opaqueProp<TimesheetLogTarget>()),\n showAuthor: z.boolean(),\n authorNames: opaqueProp<ReadonlyMap<string, string>>(),\n canManage: z.boolean(),\n onQuickAdd: callbackProp<(input: ListViewQuickAdd) => Promise<void> | void>(),\n onEditEntry: callbackProp<(entry: TimesheetEntry) => void>(),\n onDuplicateEntry: callbackProp<(entry: TimesheetEntry) => void>(),\n onEntryUpdated: optionalCallbackProp<() => void>(),\n locale: z.string().optional(),\n})\n\nregisterComponent<ListViewProps>({\n id: extensionPoints.hosts.timesheetListComponent.componentId,\n component: DefaultListView,\n metadata: {\n module: 'staff',\n description: 'Timesheet list view \u2014 one expandable row per day.',\n propsSchema: listViewPropsSchema,\n },\n})\n\nexport function ListView(props: ListViewProps) {\n const Resolved = useRegisteredComponent<ListViewProps>(\n extensionPoints.hosts.timesheetListComponent.componentId,\n DefaultListView,\n )\n return <Resolved {...props} />\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
-
import { useState, useEffect, useRef, useCallback } from "react";
|
|
3
|
+
import { useState, useEffect, useMemo, useRef, useCallback } from "react";
|
|
4
|
+
import { z } from "zod";
|
|
4
5
|
import { Play, Square } from "lucide-react";
|
|
5
6
|
import { Button } from "@open-mercato/ui/primitives/button";
|
|
6
7
|
import { IconButton } from "@open-mercato/ui/primitives/icon-button";
|
|
@@ -8,6 +9,11 @@ import { useT } from "@open-mercato/shared/lib/i18n/context";
|
|
|
8
9
|
import { apiCallOrThrow } from "@open-mercato/ui/backend/utils/apiCall";
|
|
9
10
|
import { flash } from "@open-mercato/ui/backend/FlashMessages";
|
|
10
11
|
import { useGuardedMutation } from "@open-mercato/ui/backend/injection/useGuardedMutation";
|
|
12
|
+
import { InjectionSpot } from "@open-mercato/ui/backend/injection/InjectionSpot";
|
|
13
|
+
import { extensionPoints } from "@open-mercato/core/modules/staff/extension-points";
|
|
14
|
+
import { registerComponent } from "@open-mercato/shared/modules/widgets/component-registry";
|
|
15
|
+
import { useRegisteredComponent } from "@open-mercato/ui/backend/injection/useRegisteredComponent";
|
|
16
|
+
import { callbackProp } from "../time-tracking/componentContracts.js";
|
|
11
17
|
import { ProjectColorDot } from "./ProjectColorDot.js";
|
|
12
18
|
import { useActiveTimesheetTimer } from "./useActiveTimesheetTimer.js";
|
|
13
19
|
import { startTimerEntry } from "./startTimer.js";
|
|
@@ -26,12 +32,16 @@ function getToday() {
|
|
|
26
32
|
const day = String(now.getDate()).padStart(2, "0");
|
|
27
33
|
return `${year}-${month}-${day}`;
|
|
28
34
|
}
|
|
29
|
-
function
|
|
35
|
+
function DefaultTimerBar({ projects, staffMemberId, onTimerStopped }) {
|
|
30
36
|
const t = useT();
|
|
31
37
|
const { runMutation, retryLastMutation } = useGuardedMutation({
|
|
32
38
|
contextId: TIMER_MUTATION_CONTEXT_ID,
|
|
33
39
|
blockedMessage: t("ui.forms.flash.saveBlocked", "Save blocked by validation")
|
|
34
40
|
});
|
|
41
|
+
const timerBarInjectionContext = useMemo(
|
|
42
|
+
() => ({ staffMemberId, retryLastMutation }),
|
|
43
|
+
[retryLastMutation, staffMemberId]
|
|
44
|
+
);
|
|
35
45
|
const [elapsedSeconds, setElapsedSeconds] = useState(0);
|
|
36
46
|
const [description, setDescription] = useState("");
|
|
37
47
|
const [selectedProjectId, setSelectedProjectId] = useState(null);
|
|
@@ -243,6 +253,14 @@ function TimerBar({ projects, staffMemberId, onTimerStopped }) {
|
|
|
243
253
|
] })
|
|
244
254
|
] }) }),
|
|
245
255
|
/* @__PURE__ */ jsx("span", { className: "font-mono text-sm tabular-nums min-w-[64px] text-right", children: formatElapsed(elapsedSeconds) }),
|
|
256
|
+
/* @__PURE__ */ jsx(
|
|
257
|
+
InjectionSpot,
|
|
258
|
+
{
|
|
259
|
+
spotId: extensionPoints.hosts.timerBarActions.spotId,
|
|
260
|
+
context: timerBarInjectionContext,
|
|
261
|
+
data: { isRunning, activeEntryId, selectedProjectId }
|
|
262
|
+
}
|
|
263
|
+
),
|
|
246
264
|
isRunning ? /* @__PURE__ */ jsx(
|
|
247
265
|
IconButton,
|
|
248
266
|
{
|
|
@@ -268,6 +286,33 @@ function TimerBar({ projects, staffMemberId, onTimerStopped }) {
|
|
|
268
286
|
)
|
|
269
287
|
] });
|
|
270
288
|
}
|
|
289
|
+
const projectOptionSchema = z.object({
|
|
290
|
+
id: z.string(),
|
|
291
|
+
name: z.string(),
|
|
292
|
+
code: z.string().nullable(),
|
|
293
|
+
color: z.string().nullable().optional()
|
|
294
|
+
});
|
|
295
|
+
const timerBarPropsSchema = z.object({
|
|
296
|
+
projects: z.array(projectOptionSchema),
|
|
297
|
+
staffMemberId: z.string().nullable(),
|
|
298
|
+
onTimerStopped: callbackProp()
|
|
299
|
+
});
|
|
300
|
+
registerComponent({
|
|
301
|
+
id: extensionPoints.hosts.timerBarComponent.componentId,
|
|
302
|
+
component: DefaultTimerBar,
|
|
303
|
+
metadata: {
|
|
304
|
+
module: "staff",
|
|
305
|
+
description: "Running-timer bar with the project picker and start/stop controls.",
|
|
306
|
+
propsSchema: timerBarPropsSchema
|
|
307
|
+
}
|
|
308
|
+
});
|
|
309
|
+
function TimerBar(props) {
|
|
310
|
+
const Resolved = useRegisteredComponent(
|
|
311
|
+
extensionPoints.hosts.timerBarComponent.componentId,
|
|
312
|
+
DefaultTimerBar
|
|
313
|
+
);
|
|
314
|
+
return /* @__PURE__ */ jsx(Resolved, { ...props });
|
|
315
|
+
}
|
|
271
316
|
export {
|
|
272
317
|
TimerBar
|
|
273
318
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
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 { apiCallOrThrow } from '@open-mercato/ui/backend/utils/apiCall'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { useGuardedMutation } from '@open-mercato/ui/backend/injection/useGuardedMutation'\nimport { ProjectColorDot } from './ProjectColorDot'\nimport { useActiveTimesheetTimer } from './useActiveTimesheetTimer'\nimport { startTimerEntry } from './startTimer'\nimport { resolveTimerActionError } from './timerErrors'\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\nconst TIMER_MUTATION_CONTEXT_ID = 'staff-timesheets-timer-bar'\n\ntype TimerMutationContext = {\n formId: string\n resourceKind: string\n resourceId: string\n staffMemberId: string | null\n action: 'timer-create' | 'timer-start' | 'timer-stop'\n retryLastMutation: () => Promise<boolean>\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 const { runMutation, retryLastMutation } = useGuardedMutation<TimerMutationContext>({\n contextId: TIMER_MUTATION_CONTEXT_ID,\n blockedMessage: t('ui.forms.flash.saveBlocked', 'Save blocked by validation'),\n })\n\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 const activeTimer = useActiveTimesheetTimer({ staffMemberId })\n\n const activeEntryId = activeTimer.entryId\n const activeProjectId = activeTimer.projectId\n const isRunning = activeTimer.running\n\n const activeProject = projects.find((p) => p.id === activeProjectId)\n const activeProjectName = activeProject?.name ?? activeTimer.projectName\n const activeProjectColor = activeProject?.color ?? activeTimer.projectColor\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 calcElapsed = () => Math.max(0, Math.floor((Date.now() - startTime) / 1000))\n setElapsedSeconds(calcElapsed())\n\n if (intervalRef.current) clearInterval(intervalRef.current)\n intervalRef.current = setInterval(() => {\n setElapsedSeconds(calcElapsed())\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 (activeTimer.running && activeTimer.startedAt) {\n startElapsedCounter(activeTimer.startedAt)\n if (activeTimer.notes != null) setDescription(activeTimer.notes)\n return\n }\n stopElapsedCounter()\n }, [activeTimer.running, activeTimer.startedAt, activeTimer.notes, startElapsedCounter, stopElapsedCounter])\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 startPayload = {\n staffMemberId,\n timeProjectId: selectedProjectId,\n date: today,\n notes: description || null,\n }\n await runMutation({\n operation: () => startTimerEntry(startPayload),\n context: {\n formId: TIMER_MUTATION_CONTEXT_ID,\n resourceKind: 'staff.timesheets.time_entry',\n resourceId: staffMemberId,\n staffMemberId,\n action: 'timer-start',\n retryLastMutation,\n },\n mutationPayload: startPayload,\n })\n\n await activeTimer.refresh()\n } catch (err) {\n flash(\n resolveTimerActionError(err, 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 const stopPayload = {\n id: activeEntryId,\n action: 'timer-stop',\n staffMemberId,\n }\n await runMutation({\n operation: () =>\n apiCallOrThrow(\n `/api/staff/timesheets/time-entries/${activeEntryId}/timer-stop`,\n { method: 'POST' },\n ),\n context: {\n formId: TIMER_MUTATION_CONTEXT_ID,\n resourceKind: 'staff.timesheets.time_entry',\n resourceId: activeEntryId,\n staffMemberId,\n action: 'timer-stop',\n retryLastMutation,\n },\n mutationPayload: stopPayload,\n })\n\n setDescription('')\n await activeTimer.refresh()\n onTimerStopped()\n } catch (err) {\n flash(\n resolveTimerActionError(err, 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 activeProjectName ? (\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={activeProjectColor} projectName={activeProjectName} size=\"xs\" />\n {activeProjectName}\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=\"destructive\"\n size=\"default\"\n onClick={handleStop}\n disabled={isStopping}\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=\"primary\"\n size=\"default\"\n onClick={handleStart}\n disabled={isStarting || !selectedProjectId}\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": ";
|
|
4
|
+
"sourcesContent": ["'use client'\n\nimport * as React from 'react'\nimport { useState, useEffect, useMemo, useRef, useCallback } from 'react'\nimport { z } from 'zod'\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 { apiCallOrThrow } from '@open-mercato/ui/backend/utils/apiCall'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { useGuardedMutation } from '@open-mercato/ui/backend/injection/useGuardedMutation'\nimport { InjectionSpot } from '@open-mercato/ui/backend/injection/InjectionSpot'\nimport { extensionPoints } from '@open-mercato/core/modules/staff/extension-points'\nimport { registerComponent } from '@open-mercato/shared/modules/widgets/component-registry'\nimport { useRegisteredComponent } from '@open-mercato/ui/backend/injection/useRegisteredComponent'\nimport { callbackProp } from '../time-tracking/componentContracts'\nimport { ProjectColorDot } from './ProjectColorDot'\nimport { useActiveTimesheetTimer } from './useActiveTimesheetTimer'\nimport { startTimerEntry } from './startTimer'\nimport { resolveTimerActionError } from './timerErrors'\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\nconst TIMER_MUTATION_CONTEXT_ID = 'staff-timesheets-timer-bar'\n\ntype TimerMutationContext = {\n formId: string\n resourceKind: string\n resourceId: string\n staffMemberId: string | null\n action: 'timer-create' | 'timer-start' | 'timer-stop'\n retryLastMutation: () => Promise<boolean>\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\nfunction DefaultTimerBar({ projects, staffMemberId, onTimerStopped }: TimerBarProps) {\n const t = useT()\n const { runMutation, retryLastMutation } = useGuardedMutation<TimerMutationContext>({\n contextId: TIMER_MUTATION_CONTEXT_ID,\n blockedMessage: t('ui.forms.flash.saveBlocked', 'Save blocked by validation'),\n })\n const timerBarInjectionContext = useMemo(\n () => ({ staffMemberId, retryLastMutation }),\n [retryLastMutation, staffMemberId],\n )\n\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 const activeTimer = useActiveTimesheetTimer({ staffMemberId })\n\n const activeEntryId = activeTimer.entryId\n const activeProjectId = activeTimer.projectId\n const isRunning = activeTimer.running\n\n const activeProject = projects.find((p) => p.id === activeProjectId)\n const activeProjectName = activeProject?.name ?? activeTimer.projectName\n const activeProjectColor = activeProject?.color ?? activeTimer.projectColor\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 calcElapsed = () => Math.max(0, Math.floor((Date.now() - startTime) / 1000))\n setElapsedSeconds(calcElapsed())\n\n if (intervalRef.current) clearInterval(intervalRef.current)\n intervalRef.current = setInterval(() => {\n setElapsedSeconds(calcElapsed())\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 (activeTimer.running && activeTimer.startedAt) {\n startElapsedCounter(activeTimer.startedAt)\n if (activeTimer.notes != null) setDescription(activeTimer.notes)\n return\n }\n stopElapsedCounter()\n }, [activeTimer.running, activeTimer.startedAt, activeTimer.notes, startElapsedCounter, stopElapsedCounter])\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 startPayload = {\n staffMemberId,\n timeProjectId: selectedProjectId,\n date: today,\n notes: description || null,\n }\n await runMutation({\n operation: () => startTimerEntry(startPayload),\n context: {\n formId: TIMER_MUTATION_CONTEXT_ID,\n resourceKind: 'staff.timesheets.time_entry',\n resourceId: staffMemberId,\n staffMemberId,\n action: 'timer-start',\n retryLastMutation,\n },\n mutationPayload: startPayload,\n })\n\n await activeTimer.refresh()\n } catch (err) {\n flash(\n resolveTimerActionError(err, 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 const stopPayload = {\n id: activeEntryId,\n action: 'timer-stop',\n staffMemberId,\n }\n await runMutation({\n operation: () =>\n apiCallOrThrow(\n `/api/staff/timesheets/time-entries/${activeEntryId}/timer-stop`,\n { method: 'POST' },\n ),\n context: {\n formId: TIMER_MUTATION_CONTEXT_ID,\n resourceKind: 'staff.timesheets.time_entry',\n resourceId: activeEntryId,\n staffMemberId,\n action: 'timer-stop',\n retryLastMutation,\n },\n mutationPayload: stopPayload,\n })\n\n setDescription('')\n await activeTimer.refresh()\n onTimerStopped()\n } catch (err) {\n flash(\n resolveTimerActionError(err, 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 activeProjectName ? (\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={activeProjectColor} projectName={activeProjectName} size=\"xs\" />\n {activeProjectName}\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 <InjectionSpot\n spotId={extensionPoints.hosts.timerBarActions.spotId}\n context={timerBarInjectionContext}\n data={{ isRunning, activeEntryId, selectedProjectId }}\n />\n\n {isRunning ? (\n <IconButton\n type=\"button\"\n variant=\"destructive\"\n size=\"default\"\n onClick={handleStop}\n disabled={isStopping}\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=\"primary\"\n size=\"default\"\n onClick={handleStart}\n disabled={isStarting || !selectedProjectId}\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\nconst projectOptionSchema = z.object({\n id: z.string(),\n name: z.string(),\n code: z.string().nullable(),\n color: z.string().nullable().optional(),\n})\n\nconst timerBarPropsSchema: z.ZodType<TimerBarProps> = z.object({\n projects: z.array(projectOptionSchema),\n staffMemberId: z.string().nullable(),\n onTimerStopped: callbackProp<() => void>(),\n})\n\nregisterComponent<TimerBarProps>({\n id: extensionPoints.hosts.timerBarComponent.componentId,\n component: DefaultTimerBar,\n metadata: {\n module: 'staff',\n description: 'Running-timer bar with the project picker and start/stop controls.',\n propsSchema: timerBarPropsSchema,\n },\n})\n\nexport function TimerBar(props: TimerBarProps) {\n const Resolved = useRegisteredComponent<TimerBarProps>(\n extensionPoints.hosts.timerBarComponent.componentId,\n DefaultTimerBar,\n )\n return <Resolved {...props} />\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { Migration } from "@mikro-orm/migrations";
|
|
2
|
+
class Migration20260813073131_staff extends Migration {
|
|
3
|
+
up() {
|
|
4
|
+
this.addSql(`create table "staff_time_entry_tags" ("id" uuid not null default gen_random_uuid(), "tenant_id" uuid not null, "organization_id" uuid not null, "tag_id" uuid not null, "time_entry_id" uuid not null, "created_at" timestamptz not null, primary key ("id"));`);
|
|
5
|
+
this.addSql(`create unique index "staff_time_entry_tags_unique_idx" on "staff_time_entry_tags" ("tag_id", "time_entry_id");`);
|
|
6
|
+
this.addSql(`create index "staff_time_entry_tags_entry_idx" on "staff_time_entry_tags" ("organization_id", "time_entry_id");`);
|
|
7
|
+
this.addSql(`create index "staff_time_entry_tags_tenant_org_idx" on "staff_time_entry_tags" ("tenant_id", "organization_id");`);
|
|
8
|
+
this.addSql(`create table "staff_time_reports" ("id" uuid not null default gen_random_uuid(), "tenant_id" uuid not null, "organization_id" uuid not null, "customer_id" uuid not null, "customer_snapshot" jsonb null, "reference" text not null, "title" text not null, "period_kind" text not null default 'month', "period_from" date not null, "period_to" date not null, "currency_code" text not null, "grouping" text not null default 'project_task', "nonbillable_mode" text not null default 'separate', "include_already_reported" boolean not null default false, "show_rates" boolean not null default true, "rounding_unit_minutes" int not null default 0, "rounding_direction" text not null default 'up', "status" text not null default 'draft', "total_billable_minutes" int null, "total_nonbillable_minutes" int null, "total_amount" numeric(14,2) null, "closed_at" timestamptz null, "closed_by_user_id" uuid null, "created_by_user_id" uuid null, "created_at" timestamptz not null, "updated_at" timestamptz not null, "deleted_at" timestamptz null, primary key ("id"));`);
|
|
9
|
+
this.addSql(`create unique index "staff_time_reports_reference_unique_idx" on "staff_time_reports" ("organization_id", "tenant_id", "reference") where "deleted_at" is null;`);
|
|
10
|
+
this.addSql(`create index "staff_time_reports_status_idx" on "staff_time_reports" ("organization_id", "status", "period_from");`);
|
|
11
|
+
this.addSql(`create index "staff_time_reports_customer_idx" on "staff_time_reports" ("organization_id", "customer_id");`);
|
|
12
|
+
this.addSql(`create index "staff_time_reports_tenant_org_idx" on "staff_time_reports" ("tenant_id", "organization_id");`);
|
|
13
|
+
this.addSql(`create table "staff_time_report_entries" ("id" uuid not null default gen_random_uuid(), "tenant_id" uuid not null, "organization_id" uuid not null, "report_id" uuid not null, "time_entry_id" uuid not null, "frozen_raw_minutes" int not null default 0, "frozen_rounded_minutes" int not null default 0, "frozen_rate_amount" numeric(14,4) null, "frozen_currency_code" text not null, "frozen_amount" numeric(14,2) null, "frozen_is_billable" boolean not null default true, "created_at" timestamptz not null, primary key ("id"));`);
|
|
14
|
+
this.addSql(`create unique index "staff_time_report_entries_unique_idx" on "staff_time_report_entries" ("report_id", "time_entry_id");`);
|
|
15
|
+
this.addSql(`create index "staff_time_report_entries_entry_idx" on "staff_time_report_entries" ("organization_id", "time_entry_id");`);
|
|
16
|
+
this.addSql(`create index "staff_time_report_entries_tenant_org_idx" on "staff_time_report_entries" ("tenant_id", "organization_id");`);
|
|
17
|
+
this.addSql(`create table "staff_time_report_events" ("id" uuid not null default gen_random_uuid(), "tenant_id" uuid not null, "organization_id" uuid not null, "report_id" uuid not null, "event_type" text not null, "reason" text null, "actor_user_id" uuid null, "metadata" jsonb null, "created_at" timestamptz not null, primary key ("id"));`);
|
|
18
|
+
this.addSql(`create index "staff_time_report_events_report_idx" on "staff_time_report_events" ("organization_id", "report_id", "created_at");`);
|
|
19
|
+
this.addSql(`create index "staff_time_report_events_tenant_org_idx" on "staff_time_report_events" ("tenant_id", "organization_id");`);
|
|
20
|
+
this.addSql(`create table "staff_time_report_projects" ("id" uuid not null default gen_random_uuid(), "tenant_id" uuid not null, "organization_id" uuid not null, "report_id" uuid not null, "time_project_id" uuid not null, "created_at" timestamptz not null, primary key ("id"));`);
|
|
21
|
+
this.addSql(`create unique index "staff_time_report_projects_unique_idx" on "staff_time_report_projects" ("report_id", "time_project_id");`);
|
|
22
|
+
this.addSql(`create index "staff_time_report_projects_project_idx" on "staff_time_report_projects" ("organization_id", "time_project_id");`);
|
|
23
|
+
this.addSql(`create index "staff_time_report_projects_tenant_org_idx" on "staff_time_report_projects" ("tenant_id", "organization_id");`);
|
|
24
|
+
this.addSql(`create table "staff_time_tags" ("id" uuid not null default gen_random_uuid(), "tenant_id" uuid not null, "organization_id" uuid not null, "slug" text not null, "label" text not null, "color" text null, "created_at" timestamptz not null, "updated_at" timestamptz not null, "deleted_at" timestamptz null, primary key ("id"));`);
|
|
25
|
+
this.addSql(`create unique index "staff_time_tags_slug_unique_idx" on "staff_time_tags" ("organization_id", "tenant_id", "slug") where "deleted_at" is null;`);
|
|
26
|
+
this.addSql(`create index "staff_time_tags_tenant_org_idx" on "staff_time_tags" ("tenant_id", "organization_id");`);
|
|
27
|
+
this.addSql(`create table "staff_time_tasks" ("id" uuid not null default gen_random_uuid(), "tenant_id" uuid not null, "organization_id" uuid not null, "time_project_id" uuid not null, "parent_task_id" uuid null, "task_status_id" uuid not null, "sequence_number" int not null default 0, "reference" text not null, "title" text not null, "description" text null, "assignee_staff_member_id" uuid null, "position" int not null default 0, "created_by_user_id" uuid null, "closed_at" timestamptz null, "created_at" timestamptz not null, "updated_at" timestamptz not null, "deleted_at" timestamptz null, primary key ("id"));`);
|
|
28
|
+
this.addSql(`create unique index "staff_time_tasks_reference_unique_idx" on "staff_time_tasks" ("organization_id", "tenant_id", "reference") where "deleted_at" is null;`);
|
|
29
|
+
this.addSql(`create unique index "staff_time_tasks_sequence_unique_idx" on "staff_time_tasks" ("organization_id", "tenant_id", "time_project_id", "sequence_number") where "deleted_at" is null;`);
|
|
30
|
+
this.addSql(`create index "staff_time_tasks_assignee_idx" on "staff_time_tasks" ("organization_id", "assignee_staff_member_id");`);
|
|
31
|
+
this.addSql(`create index "staff_time_tasks_parent_idx" on "staff_time_tasks" ("organization_id", "parent_task_id");`);
|
|
32
|
+
this.addSql(`create index "staff_time_tasks_board_idx" on "staff_time_tasks" ("organization_id", "time_project_id", "task_status_id", "position");`);
|
|
33
|
+
this.addSql(`create index "staff_time_tasks_tenant_org_idx" on "staff_time_tasks" ("tenant_id", "organization_id");`);
|
|
34
|
+
this.addSql(`create table "staff_time_task_comments" ("id" uuid not null default gen_random_uuid(), "tenant_id" uuid not null, "organization_id" uuid not null, "task_id" uuid not null, "body" text not null, "author_user_id" uuid null, "created_at" timestamptz not null, "updated_at" timestamptz not null, "deleted_at" timestamptz null, primary key ("id"));`);
|
|
35
|
+
this.addSql(`create index "staff_time_task_comments_task_idx" on "staff_time_task_comments" ("organization_id", "task_id", "created_at");`);
|
|
36
|
+
this.addSql(`create index "staff_time_task_comments_tenant_org_idx" on "staff_time_task_comments" ("tenant_id", "organization_id");`);
|
|
37
|
+
this.addSql(`create table "staff_time_task_statuses" ("id" uuid not null default gen_random_uuid(), "tenant_id" uuid not null, "organization_id" uuid not null, "time_project_id" uuid not null, "name" text not null, "slug" text not null, "color" text null, "position" int not null default 0, "is_default" boolean not null default false, "is_done" boolean not null default false, "created_at" timestamptz not null, "updated_at" timestamptz not null, "deleted_at" timestamptz null, primary key ("id"));`);
|
|
38
|
+
this.addSql(`create unique index "staff_time_task_statuses_slug_unique_idx" on "staff_time_task_statuses" ("organization_id", "tenant_id", "time_project_id", "slug") where "deleted_at" is null;`);
|
|
39
|
+
this.addSql(`create index "staff_time_task_statuses_project_idx" on "staff_time_task_statuses" ("organization_id", "time_project_id", "position");`);
|
|
40
|
+
this.addSql(`create index "staff_time_task_statuses_tenant_org_idx" on "staff_time_task_statuses" ("tenant_id", "organization_id");`);
|
|
41
|
+
this.addSql(`create table "staff_time_task_tags" ("id" uuid not null default gen_random_uuid(), "tenant_id" uuid not null, "organization_id" uuid not null, "tag_id" uuid not null, "task_id" uuid not null, "created_at" timestamptz not null, primary key ("id"));`);
|
|
42
|
+
this.addSql(`create unique index "staff_time_task_tags_unique_idx" on "staff_time_task_tags" ("tag_id", "task_id");`);
|
|
43
|
+
this.addSql(`create index "staff_time_task_tags_task_idx" on "staff_time_task_tags" ("organization_id", "task_id");`);
|
|
44
|
+
this.addSql(`create index "staff_time_task_tags_tenant_org_idx" on "staff_time_task_tags" ("tenant_id", "organization_id");`);
|
|
45
|
+
this.addSql(`alter table "staff_time_reports" add constraint "staff_time_reports_period_kind_check" check ("period_kind" in ('week', 'month', 'year', 'custom'));`);
|
|
46
|
+
this.addSql(`alter table "staff_time_reports" add constraint "staff_time_reports_grouping_check" check ("grouping" in ('project_task', 'project_person', 'project_day'));`);
|
|
47
|
+
this.addSql(`alter table "staff_time_reports" add constraint "staff_time_reports_nonbillable_mode_check" check ("nonbillable_mode" in ('separate', 'exclude'));`);
|
|
48
|
+
this.addSql(`alter table "staff_time_reports" add constraint "staff_time_reports_status_check" check ("status" in ('draft', 'closed'));`);
|
|
49
|
+
this.addSql(`alter table "staff_time_report_events" add constraint "staff_time_report_events_event_type_check" check ("event_type" in ('closed', 'unlocked', 'exported'));`);
|
|
50
|
+
this.addSql(`alter table "staff_time_entries" add "task_id" uuid null, add "is_billable" boolean not null default true, add "rounded_minutes" int null, add "rate_override_amount" numeric(14,4) null, add "rate_currency_code" text null, add "locked_report_id" uuid null, add "locked_at" timestamptz null;`);
|
|
51
|
+
this.addSql(`create index "staff_time_entries_locked_report_idx" on "staff_time_entries" ("organization_id", "locked_report_id");`);
|
|
52
|
+
this.addSql(`create index "staff_time_entries_member_overlap_idx" on "staff_time_entries" ("organization_id", "staff_member_id", "date", "started_at");`);
|
|
53
|
+
this.addSql(`create index "staff_time_entries_task_idx" on "staff_time_entries" ("organization_id", "task_id");`);
|
|
54
|
+
this.addSql(`alter table "staff_time_projects" add "customer_snapshot" jsonb null, add "hourly_rate" numeric(14,4) null, add "currency_code" text null, add "billable_by_default" boolean not null default true, add "budget_kind" text not null default 'none', add "budget_value" numeric(14,4) null, add "budget_warn_at_percent" int not null default 80, add "budget_alerted_at_percent" int null;`);
|
|
55
|
+
this.addSql(`alter table "staff_time_projects" add constraint "staff_time_projects_budget_kind_check" check ("budget_kind" in ('none', 'hours', 'amount'));`);
|
|
56
|
+
}
|
|
57
|
+
down() {
|
|
58
|
+
this.addSql(`drop table if exists "staff_time_entry_tags" cascade;`);
|
|
59
|
+
this.addSql(`drop table if exists "staff_time_report_entries" cascade;`);
|
|
60
|
+
this.addSql(`drop table if exists "staff_time_report_events" cascade;`);
|
|
61
|
+
this.addSql(`drop table if exists "staff_time_report_projects" cascade;`);
|
|
62
|
+
this.addSql(`drop table if exists "staff_time_reports" cascade;`);
|
|
63
|
+
this.addSql(`drop table if exists "staff_time_task_tags" cascade;`);
|
|
64
|
+
this.addSql(`drop table if exists "staff_time_tags" cascade;`);
|
|
65
|
+
this.addSql(`drop table if exists "staff_time_task_comments" cascade;`);
|
|
66
|
+
this.addSql(`drop table if exists "staff_time_tasks" cascade;`);
|
|
67
|
+
this.addSql(`drop table if exists "staff_time_task_statuses" cascade;`);
|
|
68
|
+
this.addSql(`drop index "staff_time_entries_locked_report_idx";`);
|
|
69
|
+
this.addSql(`drop index "staff_time_entries_member_overlap_idx";`);
|
|
70
|
+
this.addSql(`drop index "staff_time_entries_task_idx";`);
|
|
71
|
+
this.addSql(`alter table "staff_time_entries" drop column "task_id", drop column "is_billable", drop column "rounded_minutes", drop column "rate_override_amount", drop column "rate_currency_code", drop column "locked_report_id", drop column "locked_at";`);
|
|
72
|
+
this.addSql(`alter table "staff_time_projects" drop constraint if exists "staff_time_projects_budget_kind_check";`);
|
|
73
|
+
this.addSql(`alter table "staff_time_projects" drop column "customer_snapshot", drop column "hourly_rate", drop column "currency_code", drop column "billable_by_default", drop column "budget_kind", drop column "budget_value", drop column "budget_warn_at_percent", drop column "budget_alerted_at_percent";`);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
export {
|
|
77
|
+
Migration20260813073131_staff
|
|
78
|
+
};
|
|
79
|
+
//# sourceMappingURL=Migration20260813073131_staff.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/modules/staff/migrations/Migration20260813073131_staff.ts"],
|
|
4
|
+
"sourcesContent": ["import { Migration } from '@mikro-orm/migrations';\n\nexport class Migration20260813073131_staff extends Migration {\n\n override up(): void | Promise<void> {\n this.addSql(`create table \"staff_time_entry_tags\" (\"id\" uuid not null default gen_random_uuid(), \"tenant_id\" uuid not null, \"organization_id\" uuid not null, \"tag_id\" uuid not null, \"time_entry_id\" uuid not null, \"created_at\" timestamptz not null, primary key (\"id\"));`);\n this.addSql(`create unique index \"staff_time_entry_tags_unique_idx\" on \"staff_time_entry_tags\" (\"tag_id\", \"time_entry_id\");`);\n this.addSql(`create index \"staff_time_entry_tags_entry_idx\" on \"staff_time_entry_tags\" (\"organization_id\", \"time_entry_id\");`);\n this.addSql(`create index \"staff_time_entry_tags_tenant_org_idx\" on \"staff_time_entry_tags\" (\"tenant_id\", \"organization_id\");`);\n\n this.addSql(`create table \"staff_time_reports\" (\"id\" uuid not null default gen_random_uuid(), \"tenant_id\" uuid not null, \"organization_id\" uuid not null, \"customer_id\" uuid not null, \"customer_snapshot\" jsonb null, \"reference\" text not null, \"title\" text not null, \"period_kind\" text not null default 'month', \"period_from\" date not null, \"period_to\" date not null, \"currency_code\" text not null, \"grouping\" text not null default 'project_task', \"nonbillable_mode\" text not null default 'separate', \"include_already_reported\" boolean not null default false, \"show_rates\" boolean not null default true, \"rounding_unit_minutes\" int not null default 0, \"rounding_direction\" text not null default 'up', \"status\" text not null default 'draft', \"total_billable_minutes\" int null, \"total_nonbillable_minutes\" int null, \"total_amount\" numeric(14,2) null, \"closed_at\" timestamptz null, \"closed_by_user_id\" uuid null, \"created_by_user_id\" uuid null, \"created_at\" timestamptz not null, \"updated_at\" timestamptz not null, \"deleted_at\" timestamptz null, primary key (\"id\"));`);\n this.addSql(`create unique index \"staff_time_reports_reference_unique_idx\" on \"staff_time_reports\" (\"organization_id\", \"tenant_id\", \"reference\") where \"deleted_at\" is null;`);\n this.addSql(`create index \"staff_time_reports_status_idx\" on \"staff_time_reports\" (\"organization_id\", \"status\", \"period_from\");`);\n this.addSql(`create index \"staff_time_reports_customer_idx\" on \"staff_time_reports\" (\"organization_id\", \"customer_id\");`);\n this.addSql(`create index \"staff_time_reports_tenant_org_idx\" on \"staff_time_reports\" (\"tenant_id\", \"organization_id\");`);\n\n this.addSql(`create table \"staff_time_report_entries\" (\"id\" uuid not null default gen_random_uuid(), \"tenant_id\" uuid not null, \"organization_id\" uuid not null, \"report_id\" uuid not null, \"time_entry_id\" uuid not null, \"frozen_raw_minutes\" int not null default 0, \"frozen_rounded_minutes\" int not null default 0, \"frozen_rate_amount\" numeric(14,4) null, \"frozen_currency_code\" text not null, \"frozen_amount\" numeric(14,2) null, \"frozen_is_billable\" boolean not null default true, \"created_at\" timestamptz not null, primary key (\"id\"));`);\n this.addSql(`create unique index \"staff_time_report_entries_unique_idx\" on \"staff_time_report_entries\" (\"report_id\", \"time_entry_id\");`);\n this.addSql(`create index \"staff_time_report_entries_entry_idx\" on \"staff_time_report_entries\" (\"organization_id\", \"time_entry_id\");`);\n this.addSql(`create index \"staff_time_report_entries_tenant_org_idx\" on \"staff_time_report_entries\" (\"tenant_id\", \"organization_id\");`);\n\n this.addSql(`create table \"staff_time_report_events\" (\"id\" uuid not null default gen_random_uuid(), \"tenant_id\" uuid not null, \"organization_id\" uuid not null, \"report_id\" uuid not null, \"event_type\" text not null, \"reason\" text null, \"actor_user_id\" uuid null, \"metadata\" jsonb null, \"created_at\" timestamptz not null, primary key (\"id\"));`);\n this.addSql(`create index \"staff_time_report_events_report_idx\" on \"staff_time_report_events\" (\"organization_id\", \"report_id\", \"created_at\");`);\n this.addSql(`create index \"staff_time_report_events_tenant_org_idx\" on \"staff_time_report_events\" (\"tenant_id\", \"organization_id\");`);\n\n this.addSql(`create table \"staff_time_report_projects\" (\"id\" uuid not null default gen_random_uuid(), \"tenant_id\" uuid not null, \"organization_id\" uuid not null, \"report_id\" uuid not null, \"time_project_id\" uuid not null, \"created_at\" timestamptz not null, primary key (\"id\"));`);\n this.addSql(`create unique index \"staff_time_report_projects_unique_idx\" on \"staff_time_report_projects\" (\"report_id\", \"time_project_id\");`);\n this.addSql(`create index \"staff_time_report_projects_project_idx\" on \"staff_time_report_projects\" (\"organization_id\", \"time_project_id\");`);\n this.addSql(`create index \"staff_time_report_projects_tenant_org_idx\" on \"staff_time_report_projects\" (\"tenant_id\", \"organization_id\");`);\n\n this.addSql(`create table \"staff_time_tags\" (\"id\" uuid not null default gen_random_uuid(), \"tenant_id\" uuid not null, \"organization_id\" uuid not null, \"slug\" text not null, \"label\" text not null, \"color\" text null, \"created_at\" timestamptz not null, \"updated_at\" timestamptz not null, \"deleted_at\" timestamptz null, primary key (\"id\"));`);\n this.addSql(`create unique index \"staff_time_tags_slug_unique_idx\" on \"staff_time_tags\" (\"organization_id\", \"tenant_id\", \"slug\") where \"deleted_at\" is null;`);\n this.addSql(`create index \"staff_time_tags_tenant_org_idx\" on \"staff_time_tags\" (\"tenant_id\", \"organization_id\");`);\n\n this.addSql(`create table \"staff_time_tasks\" (\"id\" uuid not null default gen_random_uuid(), \"tenant_id\" uuid not null, \"organization_id\" uuid not null, \"time_project_id\" uuid not null, \"parent_task_id\" uuid null, \"task_status_id\" uuid not null, \"sequence_number\" int not null default 0, \"reference\" text not null, \"title\" text not null, \"description\" text null, \"assignee_staff_member_id\" uuid null, \"position\" int not null default 0, \"created_by_user_id\" uuid null, \"closed_at\" timestamptz null, \"created_at\" timestamptz not null, \"updated_at\" timestamptz not null, \"deleted_at\" timestamptz null, primary key (\"id\"));`);\n this.addSql(`create unique index \"staff_time_tasks_reference_unique_idx\" on \"staff_time_tasks\" (\"organization_id\", \"tenant_id\", \"reference\") where \"deleted_at\" is null;`);\n this.addSql(`create unique index \"staff_time_tasks_sequence_unique_idx\" on \"staff_time_tasks\" (\"organization_id\", \"tenant_id\", \"time_project_id\", \"sequence_number\") where \"deleted_at\" is null;`);\n this.addSql(`create index \"staff_time_tasks_assignee_idx\" on \"staff_time_tasks\" (\"organization_id\", \"assignee_staff_member_id\");`);\n this.addSql(`create index \"staff_time_tasks_parent_idx\" on \"staff_time_tasks\" (\"organization_id\", \"parent_task_id\");`);\n this.addSql(`create index \"staff_time_tasks_board_idx\" on \"staff_time_tasks\" (\"organization_id\", \"time_project_id\", \"task_status_id\", \"position\");`);\n this.addSql(`create index \"staff_time_tasks_tenant_org_idx\" on \"staff_time_tasks\" (\"tenant_id\", \"organization_id\");`);\n\n this.addSql(`create table \"staff_time_task_comments\" (\"id\" uuid not null default gen_random_uuid(), \"tenant_id\" uuid not null, \"organization_id\" uuid not null, \"task_id\" uuid not null, \"body\" text not null, \"author_user_id\" uuid null, \"created_at\" timestamptz not null, \"updated_at\" timestamptz not null, \"deleted_at\" timestamptz null, primary key (\"id\"));`);\n this.addSql(`create index \"staff_time_task_comments_task_idx\" on \"staff_time_task_comments\" (\"organization_id\", \"task_id\", \"created_at\");`);\n this.addSql(`create index \"staff_time_task_comments_tenant_org_idx\" on \"staff_time_task_comments\" (\"tenant_id\", \"organization_id\");`);\n\n this.addSql(`create table \"staff_time_task_statuses\" (\"id\" uuid not null default gen_random_uuid(), \"tenant_id\" uuid not null, \"organization_id\" uuid not null, \"time_project_id\" uuid not null, \"name\" text not null, \"slug\" text not null, \"color\" text null, \"position\" int not null default 0, \"is_default\" boolean not null default false, \"is_done\" boolean not null default false, \"created_at\" timestamptz not null, \"updated_at\" timestamptz not null, \"deleted_at\" timestamptz null, primary key (\"id\"));`);\n this.addSql(`create unique index \"staff_time_task_statuses_slug_unique_idx\" on \"staff_time_task_statuses\" (\"organization_id\", \"tenant_id\", \"time_project_id\", \"slug\") where \"deleted_at\" is null;`);\n this.addSql(`create index \"staff_time_task_statuses_project_idx\" on \"staff_time_task_statuses\" (\"organization_id\", \"time_project_id\", \"position\");`);\n this.addSql(`create index \"staff_time_task_statuses_tenant_org_idx\" on \"staff_time_task_statuses\" (\"tenant_id\", \"organization_id\");`);\n\n this.addSql(`create table \"staff_time_task_tags\" (\"id\" uuid not null default gen_random_uuid(), \"tenant_id\" uuid not null, \"organization_id\" uuid not null, \"tag_id\" uuid not null, \"task_id\" uuid not null, \"created_at\" timestamptz not null, primary key (\"id\"));`);\n this.addSql(`create unique index \"staff_time_task_tags_unique_idx\" on \"staff_time_task_tags\" (\"tag_id\", \"task_id\");`);\n this.addSql(`create index \"staff_time_task_tags_task_idx\" on \"staff_time_task_tags\" (\"organization_id\", \"task_id\");`);\n this.addSql(`create index \"staff_time_task_tags_tenant_org_idx\" on \"staff_time_task_tags\" (\"tenant_id\", \"organization_id\");`);\n\n this.addSql(`alter table \"staff_time_reports\" add constraint \"staff_time_reports_period_kind_check\" check (\"period_kind\" in ('week', 'month', 'year', 'custom'));`);\n this.addSql(`alter table \"staff_time_reports\" add constraint \"staff_time_reports_grouping_check\" check (\"grouping\" in ('project_task', 'project_person', 'project_day'));`);\n this.addSql(`alter table \"staff_time_reports\" add constraint \"staff_time_reports_nonbillable_mode_check\" check (\"nonbillable_mode\" in ('separate', 'exclude'));`);\n this.addSql(`alter table \"staff_time_reports\" add constraint \"staff_time_reports_status_check\" check (\"status\" in ('draft', 'closed'));`);\n\n this.addSql(`alter table \"staff_time_report_events\" add constraint \"staff_time_report_events_event_type_check\" check (\"event_type\" in ('closed', 'unlocked', 'exported'));`);\n\n this.addSql(`alter table \"staff_time_entries\" add \"task_id\" uuid null, add \"is_billable\" boolean not null default true, add \"rounded_minutes\" int null, add \"rate_override_amount\" numeric(14,4) null, add \"rate_currency_code\" text null, add \"locked_report_id\" uuid null, add \"locked_at\" timestamptz null;`);\n this.addSql(`create index \"staff_time_entries_locked_report_idx\" on \"staff_time_entries\" (\"organization_id\", \"locked_report_id\");`);\n this.addSql(`create index \"staff_time_entries_member_overlap_idx\" on \"staff_time_entries\" (\"organization_id\", \"staff_member_id\", \"date\", \"started_at\");`);\n this.addSql(`create index \"staff_time_entries_task_idx\" on \"staff_time_entries\" (\"organization_id\", \"task_id\");`);\n\n this.addSql(`alter table \"staff_time_projects\" add \"customer_snapshot\" jsonb null, add \"hourly_rate\" numeric(14,4) null, add \"currency_code\" text null, add \"billable_by_default\" boolean not null default true, add \"budget_kind\" text not null default 'none', add \"budget_value\" numeric(14,4) null, add \"budget_warn_at_percent\" int not null default 80, add \"budget_alerted_at_percent\" int null;`);\n this.addSql(`alter table \"staff_time_projects\" add constraint \"staff_time_projects_budget_kind_check\" check (\"budget_kind\" in ('none', 'hours', 'amount'));`);\n }\n\n override down(): void | Promise<void> {\n this.addSql(`drop table if exists \"staff_time_entry_tags\" cascade;`);\n this.addSql(`drop table if exists \"staff_time_report_entries\" cascade;`);\n this.addSql(`drop table if exists \"staff_time_report_events\" cascade;`);\n this.addSql(`drop table if exists \"staff_time_report_projects\" cascade;`);\n this.addSql(`drop table if exists \"staff_time_reports\" cascade;`);\n this.addSql(`drop table if exists \"staff_time_task_tags\" cascade;`);\n this.addSql(`drop table if exists \"staff_time_tags\" cascade;`);\n this.addSql(`drop table if exists \"staff_time_task_comments\" cascade;`);\n this.addSql(`drop table if exists \"staff_time_tasks\" cascade;`);\n this.addSql(`drop table if exists \"staff_time_task_statuses\" cascade;`);\n\n this.addSql(`drop index \"staff_time_entries_locked_report_idx\";`);\n this.addSql(`drop index \"staff_time_entries_member_overlap_idx\";`);\n this.addSql(`drop index \"staff_time_entries_task_idx\";`);\n this.addSql(`alter table \"staff_time_entries\" drop column \"task_id\", drop column \"is_billable\", drop column \"rounded_minutes\", drop column \"rate_override_amount\", drop column \"rate_currency_code\", drop column \"locked_report_id\", drop column \"locked_at\";`);\n\n this.addSql(`alter table \"staff_time_projects\" drop constraint if exists \"staff_time_projects_budget_kind_check\";`);\n this.addSql(`alter table \"staff_time_projects\" drop column \"customer_snapshot\", drop column \"hourly_rate\", drop column \"currency_code\", drop column \"billable_by_default\", drop column \"budget_kind\", drop column \"budget_value\", drop column \"budget_warn_at_percent\", drop column \"budget_alerted_at_percent\";`);\n }\n\n}\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,iBAAiB;AAEnB,MAAM,sCAAsC,UAAU;AAAA,EAElD,KAA2B;AAClC,SAAK,OAAO,gQAAgQ;AAC5Q,SAAK,OAAO,gHAAgH;AAC5H,SAAK,OAAO,iHAAiH;AAC7H,SAAK,OAAO,kHAAkH;AAE9H,SAAK,OAAO,0hCAA0hC;AACtiC,SAAK,OAAO,iKAAiK;AAC7K,SAAK,OAAO,oHAAoH;AAChI,SAAK,OAAO,4GAA4G;AACxH,SAAK,OAAO,4GAA4G;AAExH,SAAK,OAAO,4gBAA4gB;AACxhB,SAAK,OAAO,2HAA2H;AACvI,SAAK,OAAO,yHAAyH;AACrI,SAAK,OAAO,0HAA0H;AAEtI,SAAK,OAAO,yUAAyU;AACrV,SAAK,OAAO,kIAAkI;AAC9I,SAAK,OAAO,wHAAwH;AAEpI,SAAK,OAAO,0QAA0Q;AACtR,SAAK,OAAO,+HAA+H;AAC3I,SAAK,OAAO,+HAA+H;AAC3I,SAAK,OAAO,4HAA4H;AAExI,SAAK,OAAO,qUAAqU;AACjV,SAAK,OAAO,iJAAiJ;AAC7J,SAAK,OAAO,sGAAsG;AAElH,SAAK,OAAO,+lBAA+lB;AAC3mB,SAAK,OAAO,6JAA6J;AACzK,SAAK,OAAO,qLAAqL;AACjM,SAAK,OAAO,qHAAqH;AACjI,SAAK,OAAO,yGAAyG;AACrH,SAAK,OAAO,uIAAuI;AACnJ,SAAK,OAAO,wGAAwG;AAEpH,SAAK,OAAO,yVAAyV;AACrW,SAAK,OAAO,8HAA8H;AAC1I,SAAK,OAAO,wHAAwH;AAEpI,SAAK,OAAO,weAAwe;AACpf,SAAK,OAAO,sLAAsL;AAClM,SAAK,OAAO,uIAAuI;AACnJ,SAAK,OAAO,wHAAwH;AAEpI,SAAK,OAAO,yPAAyP;AACrQ,SAAK,OAAO,wGAAwG;AACpH,SAAK,OAAO,wGAAwG;AACpH,SAAK,OAAO,gHAAgH;AAE5H,SAAK,OAAO,sJAAsJ;AAClK,SAAK,OAAO,8JAA8J;AAC1K,SAAK,OAAO,oJAAoJ;AAChK,SAAK,OAAO,4HAA4H;AAExI,SAAK,OAAO,+JAA+J;AAE3K,SAAK,OAAO,mSAAmS;AAC/S,SAAK,OAAO,sHAAsH;AAClI,SAAK,OAAO,4IAA4I;AACxJ,SAAK,OAAO,oGAAoG;AAEhH,SAAK,OAAO,4XAA4X;AACxY,SAAK,OAAO,gJAAgJ;AAAA,EAC9J;AAAA,EAES,OAA6B;AACpC,SAAK,OAAO,uDAAuD;AACnE,SAAK,OAAO,2DAA2D;AACvE,SAAK,OAAO,0DAA0D;AACtE,SAAK,OAAO,4DAA4D;AACxE,SAAK,OAAO,oDAAoD;AAChE,SAAK,OAAO,sDAAsD;AAClE,SAAK,OAAO,iDAAiD;AAC7D,SAAK,OAAO,0DAA0D;AACtE,SAAK,OAAO,kDAAkD;AAC9D,SAAK,OAAO,0DAA0D;AAEtE,SAAK,OAAO,oDAAoD;AAChE,SAAK,OAAO,qDAAqD;AACjE,SAAK,OAAO,2CAA2C;AACvD,SAAK,OAAO,kPAAkP;AAE9P,SAAK,OAAO,sGAAsG;AAClH,SAAK,OAAO,qSAAqS;AAAA,EACnT;AAEF;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Migration } from "@mikro-orm/migrations";
|
|
2
|
+
class Migration20260824143357_staff extends Migration {
|
|
3
|
+
up() {
|
|
4
|
+
this.addSql(`alter table "staff_time_entries" drop constraint if exists "staff_time_entries_source_check";`);
|
|
5
|
+
this.addSql(`alter table "staff_time_reports" drop constraint if exists "staff_time_reports_grouping_check";`);
|
|
6
|
+
}
|
|
7
|
+
down() {
|
|
8
|
+
this.addSql(`alter table "staff_time_entries" add constraint "staff_time_entries_source_check" check ("source" in ('manual', 'timer', 'kiosk', 'mobile'));`);
|
|
9
|
+
this.addSql(`alter table "staff_time_reports" add constraint "staff_time_reports_grouping_check" check ("grouping" in ('project_task', 'project_person', 'project_day'));`);
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
export {
|
|
13
|
+
Migration20260824143357_staff
|
|
14
|
+
};
|
|
15
|
+
//# sourceMappingURL=Migration20260824143357_staff.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/modules/staff/migrations/Migration20260824143357_staff.ts"],
|
|
4
|
+
"sourcesContent": ["import { Migration } from '@mikro-orm/migrations';\n\nexport class Migration20260824143357_staff extends Migration {\n\n override up(): void | Promise<void> {\n this.addSql(`alter table \"staff_time_entries\" drop constraint if exists \"staff_time_entries_source_check\";`);\n\n this.addSql(`alter table \"staff_time_reports\" drop constraint if exists \"staff_time_reports_grouping_check\";`);\n }\n\n override down(): void | Promise<void> {\n this.addSql(`alter table \"staff_time_entries\" add constraint \"staff_time_entries_source_check\" check (\"source\" in ('manual', 'timer', 'kiosk', 'mobile'));`);\n\n this.addSql(`alter table \"staff_time_reports\" add constraint \"staff_time_reports_grouping_check\" check (\"grouping\" in ('project_task', 'project_person', 'project_day'));`);\n }\n\n}\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,iBAAiB;AAEnB,MAAM,sCAAsC,UAAU;AAAA,EAElD,KAA2B;AAClC,SAAK,OAAO,+FAA+F;AAE3G,SAAK,OAAO,iGAAiG;AAAA,EAC/G;AAAA,EAES,OAA6B;AACpC,SAAK,OAAO,+IAA+I;AAE3J,SAAK,OAAO,8JAA8J;AAAA,EAC5K;AAEF;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { notificationTypes } from "./notifications.js";
|
|
3
|
+
import { TimeProjectAccessRequestedRenderer } from "./widgets/notifications/TimeProjectAccessRequestedRenderer.js";
|
|
4
|
+
const rendererMap = {
|
|
5
|
+
"staff.timesheets.project_access.requested": TimeProjectAccessRequestedRenderer
|
|
6
|
+
};
|
|
7
|
+
const staffNotificationTypes = notificationTypes.map((type) => ({
|
|
8
|
+
...type,
|
|
9
|
+
Renderer: rendererMap[type.type]
|
|
10
|
+
}));
|
|
11
|
+
var notifications_client_default = staffNotificationTypes;
|
|
12
|
+
export {
|
|
13
|
+
notifications_client_default as default,
|
|
14
|
+
staffNotificationTypes
|
|
15
|
+
};
|
|
16
|
+
//# sourceMappingURL=notifications.client.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/modules/staff/notifications.client.ts"],
|
|
4
|
+
"sourcesContent": ["'use client'\n\nimport type { NotificationTypeDefinition } from '@open-mercato/shared/modules/notifications/types'\nimport { notificationTypes } from './notifications'\nimport { TimeProjectAccessRequestedRenderer } from './widgets/notifications/TimeProjectAccessRequestedRenderer'\n\nconst rendererMap: Record<string, NotificationTypeDefinition['Renderer']> = {\n 'staff.timesheets.project_access.requested': TimeProjectAccessRequestedRenderer,\n}\n\nexport const staffNotificationTypes: NotificationTypeDefinition[] = notificationTypes.map((type) => ({\n ...type,\n Renderer: rendererMap[type.type],\n}))\n\nexport default staffNotificationTypes\n"],
|
|
5
|
+
"mappings": ";AAGA,SAAS,yBAAyB;AAClC,SAAS,0CAA0C;AAEnD,MAAM,cAAsE;AAAA,EAC1E,6CAA6C;AAC/C;AAEO,MAAM,yBAAuD,kBAAkB,IAAI,CAAC,UAAU;AAAA,EACnG,GAAG;AAAA,EACH,UAAU,YAAY,KAAK,IAAI;AACjC,EAAE;AAEF,IAAO,+BAAQ;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
const TIME_REPORT_APPROVED_EVENT = "om:staff:time-report-approved";
|
|
2
|
+
const TIME_REPORT_READY_FOR_APPROVAL_EVENT = "om:staff:time-report-ready-for-approval";
|
|
3
|
+
const TIMER_RUNNING_LONG_EVENT = "om:staff:timer-running-long";
|
|
4
|
+
const TIMESHEET_PERIOD_INCOMPLETE_EVENT = "om:staff:timesheet-period-incomplete";
|
|
5
|
+
const notificationHandlers = [
|
|
6
|
+
{
|
|
7
|
+
id: "staff.time-report-approved-event",
|
|
8
|
+
notificationType: "staff.timesheets.time_report.approved",
|
|
9
|
+
features: ["staff.timesheets.reports.view"],
|
|
10
|
+
priority: 100,
|
|
11
|
+
handle(notification, context) {
|
|
12
|
+
context.emitEvent(TIME_REPORT_APPROVED_EVENT, {
|
|
13
|
+
notificationId: notification.id,
|
|
14
|
+
reportId: notification.sourceEntityId ?? null,
|
|
15
|
+
reference: notification.bodyVariables?.reference ?? null
|
|
16
|
+
});
|
|
17
|
+
context.refreshNotifications();
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
id: "staff.time-report-ready-for-approval-event",
|
|
22
|
+
notificationType: "staff.timesheets.time_report.ready_for_approval",
|
|
23
|
+
features: ["staff.timesheets.reports.view"],
|
|
24
|
+
priority: 100,
|
|
25
|
+
handle(notification, context) {
|
|
26
|
+
context.emitEvent(TIME_REPORT_READY_FOR_APPROVAL_EVENT, {
|
|
27
|
+
notificationId: notification.id,
|
|
28
|
+
reportId: notification.sourceEntityId ?? null,
|
|
29
|
+
reference: notification.bodyVariables?.reference ?? null
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
/**
|
|
35
|
+
* A running timer keeps billing until somebody stops it, so this one toasts
|
|
36
|
+
* as well as broadcasting — the bell alone is too quiet for a notification
|
|
37
|
+
* whose whole point is that the person has forgotten something.
|
|
38
|
+
*/
|
|
39
|
+
id: "staff.timer-running-long-toast",
|
|
40
|
+
notificationType: "staff.timesheets.time_entry.timer_running_long",
|
|
41
|
+
features: ["staff.timesheets.view"],
|
|
42
|
+
priority: 110,
|
|
43
|
+
debounceMs: 6e4,
|
|
44
|
+
handle(notification, context) {
|
|
45
|
+
context.toast({
|
|
46
|
+
title: notification.title,
|
|
47
|
+
body: notification.body ?? void 0,
|
|
48
|
+
severity: "warning"
|
|
49
|
+
});
|
|
50
|
+
context.emitEvent(TIMER_RUNNING_LONG_EVENT, {
|
|
51
|
+
notificationId: notification.id,
|
|
52
|
+
timeEntryId: notification.sourceEntityId ?? null
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
id: "staff.timesheet-period-incomplete-event",
|
|
58
|
+
notificationType: "staff.timesheets.timesheet.period_incomplete",
|
|
59
|
+
features: ["staff.timesheets.view"],
|
|
60
|
+
priority: 90,
|
|
61
|
+
handle(notification, context) {
|
|
62
|
+
context.emitEvent(TIMESHEET_PERIOD_INCOMPLETE_EVENT, {
|
|
63
|
+
notificationId: notification.id,
|
|
64
|
+
staffMemberId: notification.sourceEntityId ?? null,
|
|
65
|
+
periodFrom: notification.bodyVariables?.periodFrom ?? null,
|
|
66
|
+
periodTo: notification.bodyVariables?.periodTo ?? null
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
];
|
|
71
|
+
var notifications_handlers_default = notificationHandlers;
|
|
72
|
+
export {
|
|
73
|
+
TIMER_RUNNING_LONG_EVENT,
|
|
74
|
+
TIMESHEET_PERIOD_INCOMPLETE_EVENT,
|
|
75
|
+
TIME_REPORT_APPROVED_EVENT,
|
|
76
|
+
TIME_REPORT_READY_FOR_APPROVAL_EVENT,
|
|
77
|
+
notifications_handlers_default as default,
|
|
78
|
+
notificationHandlers
|
|
79
|
+
};
|
|
80
|
+
//# sourceMappingURL=notifications.handlers.js.map
|