@hed-hog/operations 0.0.329 → 0.0.331
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/README.md +5 -5
- package/dist/controllers/operations-collaborators.controller.d.ts +7 -216
- package/dist/controllers/operations-collaborators.controller.d.ts.map +1 -1
- package/dist/controllers/operations-contracts.controller.d.ts +6 -6
- package/dist/controllers/operations-projects.controller.d.ts +25 -0
- package/dist/controllers/operations-projects.controller.d.ts.map +1 -1
- package/dist/controllers/operations-projects.controller.js +48 -0
- package/dist/controllers/operations-projects.controller.js.map +1 -1
- package/dist/controllers/operations-reports.controller.d.ts +1 -1
- package/dist/controllers/operations-tasks.controller.d.ts +30 -5
- package/dist/controllers/operations-tasks.controller.d.ts.map +1 -1
- package/dist/controllers/operations-tasks.controller.js +43 -32
- package/dist/controllers/operations-tasks.controller.js.map +1 -1
- package/dist/controllers/operations-timesheets.controller.d.ts +9 -9
- package/dist/dashboard/components/DashboardLayout.d.ts +30 -0
- package/dist/dashboard/components/DashboardLayout.d.ts.map +1 -0
- package/dist/dashboard/components/DashboardLayout.js +87 -0
- package/dist/dashboard/components/DashboardLayout.js.map +1 -0
- package/dist/dashboard/components/widget-registry.d.ts +23 -0
- package/dist/dashboard/components/widget-registry.d.ts.map +1 -0
- package/dist/dashboard/components/widget-registry.js +245 -0
- package/dist/dashboard/components/widget-registry.js.map +1 -0
- package/dist/dashboard/hooks/useDashboardData.d.ts +20 -0
- package/dist/dashboard/hooks/useDashboardData.d.ts.map +1 -0
- package/dist/dashboard/hooks/useDashboardData.js +24 -0
- package/dist/dashboard/hooks/useDashboardData.js.map +1 -0
- package/dist/dashboard/types/widgets.types.d.ts +233 -0
- package/dist/dashboard/types/widgets.types.d.ts.map +1 -0
- package/dist/dashboard/types/widgets.types.js +6 -0
- package/dist/dashboard/types/widgets.types.js.map +1 -0
- package/dist/dashboard/widgets/CapacityDistribution.d.ts +23 -0
- package/dist/dashboard/widgets/CapacityDistribution.d.ts.map +1 -0
- package/dist/dashboard/widgets/CapacityDistribution.js +11 -0
- package/dist/dashboard/widgets/CapacityDistribution.js.map +1 -0
- package/dist/dashboard/widgets/EffortByProject.d.ts +22 -0
- package/dist/dashboard/widgets/EffortByProject.d.ts.map +1 -0
- package/dist/dashboard/widgets/EffortByProject.js +11 -0
- package/dist/dashboard/widgets/EffortByProject.js.map +1 -0
- package/dist/dashboard/widgets/HeadcountByArea.d.ts +24 -0
- package/dist/dashboard/widgets/HeadcountByArea.d.ts.map +1 -0
- package/dist/dashboard/widgets/HeadcountByArea.js +11 -0
- package/dist/dashboard/widgets/HeadcountByArea.js.map +1 -0
- package/dist/dashboard/widgets/ManagedProjectsStatus.d.ts +18 -0
- package/dist/dashboard/widgets/ManagedProjectsStatus.d.ts.map +1 -0
- package/dist/dashboard/widgets/ManagedProjectsStatus.js +12 -0
- package/dist/dashboard/widgets/ManagedProjectsStatus.js.map +1 -0
- package/dist/dashboard/widgets/MyHoursPeriodKpi.d.ts +22 -0
- package/dist/dashboard/widgets/MyHoursPeriodKpi.d.ts.map +1 -0
- package/dist/dashboard/widgets/MyHoursPeriodKpi.js +12 -0
- package/dist/dashboard/widgets/MyHoursPeriodKpi.js.map +1 -0
- package/dist/dashboard/widgets/MyOpenRequestsKpi.d.ts +19 -0
- package/dist/dashboard/widgets/MyOpenRequestsKpi.d.ts.map +1 -0
- package/dist/dashboard/widgets/MyOpenRequestsKpi.js +17 -0
- package/dist/dashboard/widgets/MyOpenRequestsKpi.js.map +1 -0
- package/dist/dashboard/widgets/MyPendingRequestsList.d.ts +23 -0
- package/dist/dashboard/widgets/MyPendingRequestsList.d.ts.map +1 -0
- package/dist/dashboard/widgets/MyPendingRequestsList.js +14 -0
- package/dist/dashboard/widgets/MyPendingRequestsList.js.map +1 -0
- package/dist/dashboard/widgets/MyProjectAllocationsKpi.d.ts +22 -0
- package/dist/dashboard/widgets/MyProjectAllocationsKpi.d.ts.map +1 -0
- package/dist/dashboard/widgets/MyProjectAllocationsKpi.js +11 -0
- package/dist/dashboard/widgets/MyProjectAllocationsKpi.js.map +1 -0
- package/dist/dashboard/widgets/MyQuickActions.d.ts +23 -0
- package/dist/dashboard/widgets/MyQuickActions.d.ts.map +1 -0
- package/dist/dashboard/widgets/MyQuickActions.js +18 -0
- package/dist/dashboard/widgets/MyQuickActions.js.map +1 -0
- package/dist/dashboard/widgets/MyRelevantDeadlines.d.ts +23 -0
- package/dist/dashboard/widgets/MyRelevantDeadlines.d.ts.map +1 -0
- package/dist/dashboard/widgets/MyRelevantDeadlines.js +22 -0
- package/dist/dashboard/widgets/MyRelevantDeadlines.js.map +1 -0
- package/dist/dashboard/widgets/MyTimesheetStatusKpi.d.ts +17 -0
- package/dist/dashboard/widgets/MyTimesheetStatusKpi.d.ts.map +1 -0
- package/dist/dashboard/widgets/MyTimesheetStatusKpi.js +11 -0
- package/dist/dashboard/widgets/MyTimesheetStatusKpi.js.map +1 -0
- package/dist/dashboard/widgets/MyWeeklyJourney.d.ts +21 -0
- package/dist/dashboard/widgets/MyWeeklyJourney.d.ts.map +1 -0
- package/dist/dashboard/widgets/MyWeeklyJourney.js +19 -0
- package/dist/dashboard/widgets/MyWeeklyJourney.js.map +1 -0
- package/dist/dashboard/widgets/PortfolioCostsKpi.d.ts +19 -0
- package/dist/dashboard/widgets/PortfolioCostsKpi.d.ts.map +1 -0
- package/dist/dashboard/widgets/PortfolioCostsKpi.js +12 -0
- package/dist/dashboard/widgets/PortfolioCostsKpi.js.map +1 -0
- package/dist/dashboard/widgets/PortfolioEffortKpi.d.ts +18 -0
- package/dist/dashboard/widgets/PortfolioEffortKpi.d.ts.map +1 -0
- package/dist/dashboard/widgets/PortfolioEffortKpi.js +8 -0
- package/dist/dashboard/widgets/PortfolioEffortKpi.js.map +1 -0
- package/dist/dashboard/widgets/PortfolioProjectsKpi.d.ts +22 -0
- package/dist/dashboard/widgets/PortfolioProjectsKpi.d.ts.map +1 -0
- package/dist/dashboard/widgets/PortfolioProjectsKpi.js +56 -0
- package/dist/dashboard/widgets/PortfolioProjectsKpi.js.map +1 -0
- package/dist/dashboard/widgets/PortfolioRiskKpi.d.ts +19 -0
- package/dist/dashboard/widgets/PortfolioRiskKpi.d.ts.map +1 -0
- package/dist/dashboard/widgets/PortfolioRiskKpi.js +11 -0
- package/dist/dashboard/widgets/PortfolioRiskKpi.js.map +1 -0
- package/dist/dashboard/widgets/ProjectStatusOverview.d.ts +19 -0
- package/dist/dashboard/widgets/ProjectStatusOverview.d.ts.map +1 -0
- package/dist/dashboard/widgets/ProjectStatusOverview.js +18 -0
- package/dist/dashboard/widgets/ProjectStatusOverview.js.map +1 -0
- package/dist/dashboard/widgets/StrategicDeadlines.d.ts +24 -0
- package/dist/dashboard/widgets/StrategicDeadlines.d.ts.map +1 -0
- package/dist/dashboard/widgets/StrategicDeadlines.js +22 -0
- package/dist/dashboard/widgets/StrategicDeadlines.js.map +1 -0
- package/dist/dashboard/widgets/TeamApprovalQueue.d.ts +24 -0
- package/dist/dashboard/widgets/TeamApprovalQueue.d.ts.map +1 -0
- package/dist/dashboard/widgets/TeamApprovalQueue.js +12 -0
- package/dist/dashboard/widgets/TeamApprovalQueue.js.map +1 -0
- package/dist/dashboard/widgets/TeamCapacityKpi.d.ts +18 -0
- package/dist/dashboard/widgets/TeamCapacityKpi.d.ts.map +1 -0
- package/dist/dashboard/widgets/TeamCapacityKpi.js +19 -0
- package/dist/dashboard/widgets/TeamCapacityKpi.js.map +1 -0
- package/dist/dashboard/widgets/TeamHeadcountKpi.d.ts +22 -0
- package/dist/dashboard/widgets/TeamHeadcountKpi.d.ts.map +1 -0
- package/dist/dashboard/widgets/TeamHeadcountKpi.js +56 -0
- package/dist/dashboard/widgets/TeamHeadcountKpi.js.map +1 -0
- package/dist/dashboard/widgets/TeamHoursKpi.d.ts +19 -0
- package/dist/dashboard/widgets/TeamHoursKpi.d.ts.map +1 -0
- package/dist/dashboard/widgets/TeamHoursKpi.js +13 -0
- package/dist/dashboard/widgets/TeamHoursKpi.js.map +1 -0
- package/dist/dashboard/widgets/TeamPendingApprovalsKpi.d.ts +20 -0
- package/dist/dashboard/widgets/TeamPendingApprovalsKpi.d.ts.map +1 -0
- package/dist/dashboard/widgets/TeamPendingApprovalsKpi.js +11 -0
- package/dist/dashboard/widgets/TeamPendingApprovalsKpi.js.map +1 -0
- package/dist/dashboard/widgets/TeamUtilizationOverview.d.ts +18 -0
- package/dist/dashboard/widgets/TeamUtilizationOverview.d.ts.map +1 -0
- package/dist/dashboard/widgets/TeamUtilizationOverview.js +17 -0
- package/dist/dashboard/widgets/TeamUtilizationOverview.js.map +1 -0
- package/dist/dashboard/widgets/TeamWorkloadAlerts.d.ts +24 -0
- package/dist/dashboard/widgets/TeamWorkloadAlerts.d.ts.map +1 -0
- package/dist/dashboard/widgets/TeamWorkloadAlerts.js +19 -0
- package/dist/dashboard/widgets/TeamWorkloadAlerts.js.map +1 -0
- package/dist/dashboard/widgets/index.d.ts +24 -0
- package/dist/dashboard/widgets/index.d.ts.map +1 -0
- package/dist/dashboard/widgets/index.js +54 -0
- package/dist/dashboard/widgets/index.js.map +1 -0
- package/dist/dto/create-collaborator.dto.d.ts +0 -1
- package/dist/dto/create-collaborator.dto.d.ts.map +1 -1
- package/dist/dto/create-collaborator.dto.js +0 -6
- package/dist/dto/create-collaborator.dto.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/operations.controller.d.ts +42 -0
- package/dist/operations.controller.d.ts.map +1 -1
- package/dist/operations.service.d.ts +178 -264
- package/dist/operations.service.d.ts.map +1 -1
- package/dist/operations.service.js +2170 -1340
- package/dist/operations.service.js.map +1 -1
- package/dist/operations.service.spec.js +345 -174
- package/dist/operations.service.spec.js.map +1 -1
- package/hedhog/data/dashboard_component.yaml +66 -0
- package/hedhog/data/dashboard_component_role.yaml +8 -8
- package/hedhog/data/dashboard_item.yaml +25 -25
- package/hedhog/data/dashboard_role.yaml +1 -1
- package/hedhog/data/menu.yaml +6 -16
- package/hedhog/data/role.yaml +1 -1
- package/hedhog/data/route.yaml +116 -55
- package/hedhog/frontend/app/_components/async-options-combobox.tsx.ejs +15 -9
- package/hedhog/frontend/app/_components/collaborator-form-screen.tsx.ejs +39 -99
- package/hedhog/frontend/app/_components/collaborator-picker.tsx.ejs +158 -0
- package/hedhog/frontend/app/_components/my-project-summary-screen.tsx.ejs +314 -116
- package/hedhog/frontend/app/_components/project-assignments-tab.tsx.ejs +434 -449
- package/hedhog/frontend/app/_components/project-costs-section.tsx.ejs +51 -81
- package/hedhog/frontend/app/_components/project-details-screen.tsx.ejs +328 -423
- package/hedhog/frontend/app/_components/project-file-attachments.tsx.ejs +371 -0
- package/hedhog/frontend/app/_components/project-form-screen.tsx.ejs +446 -377
- package/hedhog/frontend/app/_components/task-detail-sheet.tsx.ejs +803 -581
- package/hedhog/frontend/app/_components/task-file-attachments.tsx.ejs +14 -9
- package/hedhog/frontend/app/_components/task-form-fields.tsx.ejs +406 -0
- package/hedhog/frontend/app/_components/task-form-sheet.tsx.ejs +629 -784
- package/hedhog/frontend/app/_components/task-info-display.tsx.ejs +137 -0
- package/hedhog/frontend/app/_components/timesheet-entry-create-sheet.tsx.ejs +306 -0
- package/hedhog/frontend/app/_lib/api.ts.ejs +480 -476
- package/hedhog/frontend/app/_lib/hooks/use-values-visibility.ts.ejs +61 -0
- package/hedhog/frontend/app/_lib/types.ts.ejs +66 -5
- package/hedhog/frontend/app/_lib/utils/format.ts.ejs +0 -2
- package/hedhog/frontend/app/_lib/utils/task-ui.ts.ejs +43 -0
- package/hedhog/frontend/app/approvals/page.tsx.ejs +11 -2
- package/hedhog/frontend/app/collaborator-types/page.tsx.ejs +6 -1
- package/hedhog/frontend/app/collaborators/page.tsx.ejs +127 -42
- package/hedhog/frontend/app/contracts/page.tsx.ejs +29 -8
- package/hedhog/frontend/app/dashboard/widgets/CapacityDistribution.tsx.ejs +84 -0
- package/hedhog/frontend/app/dashboard/widgets/EffortByProject.tsx.ejs +85 -0
- package/hedhog/frontend/app/dashboard/widgets/HeadcountByArea.tsx.ejs +101 -0
- package/hedhog/frontend/app/dashboard/widgets/ManagedProjectsStatus.tsx.ejs +113 -0
- package/hedhog/frontend/app/dashboard/widgets/MyHoursPeriodKpi.tsx.ejs +87 -0
- package/hedhog/frontend/app/dashboard/widgets/MyOpenRequestsKpi.tsx.ejs +97 -0
- package/hedhog/frontend/app/dashboard/widgets/MyPendingRequestsList.tsx.ejs +99 -0
- package/hedhog/frontend/app/dashboard/widgets/MyProjectAllocationsKpi.tsx.ejs +78 -0
- package/hedhog/frontend/app/dashboard/widgets/MyQuickActions.tsx.ejs +130 -0
- package/hedhog/frontend/app/dashboard/widgets/MyRelevantDeadlines.tsx.ejs +144 -0
- package/hedhog/frontend/app/dashboard/widgets/MyTimesheetStatusKpi.tsx.ejs +78 -0
- package/hedhog/frontend/app/dashboard/widgets/MyWeeklyJourney.tsx.ejs +99 -0
- package/hedhog/frontend/app/dashboard/widgets/PortfolioCostsKpi.tsx.ejs +112 -0
- package/hedhog/frontend/app/dashboard/widgets/PortfolioEffortKpi.tsx.ejs +93 -0
- package/hedhog/frontend/app/dashboard/widgets/PortfolioProjectsKpi.tsx.ejs +96 -0
- package/hedhog/frontend/app/dashboard/widgets/PortfolioRiskKpi.tsx.ejs +115 -0
- package/hedhog/frontend/app/dashboard/widgets/ProjectStatusOverview.tsx.ejs +120 -0
- package/hedhog/frontend/app/dashboard/widgets/StrategicDeadlines.tsx.ejs +146 -0
- package/hedhog/frontend/app/dashboard/widgets/TeamApprovalQueue.tsx.ejs +108 -0
- package/hedhog/frontend/app/dashboard/widgets/TeamCapacityKpi.tsx.ejs +97 -0
- package/hedhog/frontend/app/dashboard/widgets/TeamHeadcountKpi.tsx.ejs +100 -0
- package/hedhog/frontend/app/dashboard/widgets/TeamHoursKpi.tsx.ejs +104 -0
- package/hedhog/frontend/app/dashboard/widgets/TeamPendingApprovalsKpi.tsx.ejs +110 -0
- package/hedhog/frontend/app/dashboard/widgets/TeamUtilizationOverview.tsx.ejs +115 -0
- package/hedhog/frontend/app/dashboard/widgets/TeamWorkloadAlerts.tsx.ejs +117 -0
- package/hedhog/frontend/app/dashboard/widgets/index.ts.ejs +26 -0
- package/hedhog/frontend/app/departments/page.tsx.ejs +6 -1
- package/hedhog/frontend/app/my-projects/page.tsx.ejs +59 -16
- package/hedhog/frontend/app/my-tasks/page.tsx.ejs +329 -106
- package/hedhog/frontend/app/project-cost-categories/page.tsx.ejs +58 -52
- package/hedhog/frontend/app/project-cost-types/page.tsx.ejs +58 -51
- package/hedhog/frontend/app/projects/page.tsx.ejs +436 -35
- package/hedhog/frontend/app/reports/collaborators/page.tsx.ejs +65 -52
- package/hedhog/frontend/app/reports/projects/page.tsx.ejs +80 -82
- package/hedhog/frontend/app/schedule-adjustments/page.tsx.ejs +13 -2
- package/hedhog/frontend/app/time-off/page.tsx.ejs +6 -1
- package/hedhog/frontend/app/timesheets/page.tsx.ejs +10 -4
- package/hedhog/frontend/messages/en.json +460 -61
- package/hedhog/frontend/messages/operations/en.json +61 -52
- package/hedhog/frontend/messages/operations/pt.json +59 -43
- package/hedhog/frontend/messages/pt.json +460 -61
- package/hedhog/frontend/widgets/capacity-distribution.tsx.ejs +17 -0
- package/hedhog/frontend/widgets/effort-by-project.tsx.ejs +17 -0
- package/hedhog/frontend/widgets/headcount-by-area.tsx.ejs +17 -0
- package/hedhog/frontend/widgets/index.ts.ejs +25 -0
- package/hedhog/frontend/widgets/managed-projects-status.tsx.ejs +17 -0
- package/hedhog/frontend/widgets/my-hours-period-kpi.tsx.ejs +17 -0
- package/hedhog/frontend/widgets/my-open-requests-kpi.tsx.ejs +17 -0
- package/hedhog/frontend/widgets/my-pending-requests-list.tsx.ejs +17 -0
- package/hedhog/frontend/widgets/my-project-allocations-kpi.tsx.ejs +17 -0
- package/hedhog/frontend/widgets/my-quick-actions.tsx.ejs +17 -0
- package/hedhog/frontend/widgets/my-relevant-deadlines.tsx.ejs +17 -0
- package/hedhog/frontend/widgets/my-timesheet-status-kpi.tsx.ejs +17 -0
- package/hedhog/frontend/widgets/my-weekly-journey.tsx.ejs +17 -0
- package/hedhog/frontend/widgets/portfolio-costs-kpi.tsx.ejs +17 -0
- package/hedhog/frontend/widgets/portfolio-effort-kpi.tsx.ejs +17 -0
- package/hedhog/frontend/widgets/portfolio-projects-kpi.tsx.ejs +17 -0
- package/hedhog/frontend/widgets/portfolio-risk-kpi.tsx.ejs +17 -0
- package/hedhog/frontend/widgets/project-status-overview.tsx.ejs +17 -0
- package/hedhog/frontend/widgets/shared-operations-widget.tsx.ejs +170 -0
- package/hedhog/frontend/widgets/strategic-deadlines.tsx.ejs +17 -0
- package/hedhog/frontend/widgets/team-approval-queue.tsx.ejs +17 -0
- package/hedhog/frontend/widgets/team-capacity-kpi.tsx.ejs +17 -0
- package/hedhog/frontend/widgets/team-headcount-kpi.tsx.ejs +17 -0
- package/hedhog/frontend/widgets/team-hours-kpi.tsx.ejs +17 -0
- package/hedhog/frontend/widgets/team-pending-approvals-kpi.tsx.ejs +17 -0
- package/hedhog/frontend/widgets/team-utilization-overview.tsx.ejs +17 -0
- package/hedhog/frontend/widgets/team-workload-alerts.tsx.ejs +17 -0
- package/hedhog/table/operations_collaborator.yaml +8 -13
- package/hedhog/table/operations_project.yaml +1 -1
- package/hedhog/table/operations_project_file.yaml +23 -0
- package/hedhog/table/operations_task.yaml +76 -69
- package/hedhog/table/operations_task_activity.yaml +51 -0
- package/package.json +7 -6
- package/src/controllers/operations-projects.controller.ts +41 -8
- package/src/controllers/operations-tasks.controller.ts +156 -166
- package/src/dashboard/README.md +214 -0
- package/src/dashboard/components/DashboardLayout.tsx +131 -0
- package/src/dashboard/components/widget-registry.ts +255 -0
- package/src/dashboard/hooks/useDashboardData.ts +29 -0
- package/src/dashboard/types/widgets.types.ts +237 -0
- package/src/dashboard/widgets/CapacityDistribution.tsx +56 -0
- package/src/dashboard/widgets/EffortByProject.tsx +51 -0
- package/src/dashboard/widgets/HeadcountByArea.tsx +57 -0
- package/src/dashboard/widgets/ManagedProjectsStatus.tsx +53 -0
- package/src/dashboard/widgets/MyHoursPeriodKpi.tsx +87 -0
- package/src/dashboard/widgets/MyOpenRequestsKpi.tsx +51 -0
- package/src/dashboard/widgets/MyPendingRequestsList.tsx +63 -0
- package/src/dashboard/widgets/MyProjectAllocationsKpi.tsx +57 -0
- package/src/dashboard/widgets/MyQuickActions.tsx +62 -0
- package/src/dashboard/widgets/MyRelevantDeadlines.tsx +84 -0
- package/src/dashboard/widgets/MyTimesheetStatusKpi.tsx +65 -0
- package/src/dashboard/widgets/MyWeeklyJourney.tsx +57 -0
- package/src/dashboard/widgets/PortfolioCostsKpi.tsx +48 -0
- package/src/dashboard/widgets/PortfolioEffortKpi.tsx +41 -0
- package/src/dashboard/widgets/PortfolioRiskKpi.tsx +50 -0
- package/src/dashboard/widgets/ProjectStatusOverview.tsx +52 -0
- package/src/dashboard/widgets/StrategicDeadlines.tsx +93 -0
- package/src/dashboard/widgets/TeamApprovalQueue.tsx +70 -0
- package/src/dashboard/widgets/TeamCapacityKpi.tsx +50 -0
- package/src/dashboard/widgets/TeamHoursKpi.tsx +51 -0
- package/src/dashboard/widgets/TeamPendingApprovalsKpi.tsx +53 -0
- package/src/dashboard/widgets/TeamUtilizationOverview.tsx +62 -0
- package/src/dashboard/widgets/TeamWorkloadAlerts.tsx +81 -0
- package/src/dashboard/widgets/index.ts +26 -0
- package/src/dto/create-collaborator.dto.ts +4 -11
- package/src/index.ts +3 -0
- package/src/operations.service.spec.ts +988 -764
- package/src/operations.service.ts +4300 -2538
|
@@ -48,6 +48,7 @@ import {
|
|
|
48
48
|
TrendingUp,
|
|
49
49
|
} from 'lucide-react';
|
|
50
50
|
import Link from 'next/link';
|
|
51
|
+
import { useTranslations } from 'next-intl';
|
|
51
52
|
import { useState } from 'react';
|
|
52
53
|
import { OperationsHeader } from '../../_components/operations-header';
|
|
53
54
|
import { fetchOperations } from '../../_lib/api';
|
|
@@ -57,13 +58,6 @@ import type {
|
|
|
57
58
|
} from '../../_lib/types';
|
|
58
59
|
import { formatCurrency, formatHours } from '../../_lib/utils/format';
|
|
59
60
|
|
|
60
|
-
const statusLabels: Record<string, string> = {
|
|
61
|
-
on_track: 'No prazo',
|
|
62
|
-
attention: 'Atenção',
|
|
63
|
-
late: 'Atrasado',
|
|
64
|
-
paused: 'Pausado',
|
|
65
|
-
};
|
|
66
|
-
|
|
67
61
|
const statusClasses: Record<string, string> = {
|
|
68
62
|
on_track: 'border-emerald-200 bg-emerald-50 text-emerald-700',
|
|
69
63
|
attention: 'border-amber-200 bg-amber-50 text-amber-700',
|
|
@@ -71,12 +65,6 @@ const statusClasses: Record<string, string> = {
|
|
|
71
65
|
paused: 'border-slate-200 bg-slate-100 text-slate-700',
|
|
72
66
|
};
|
|
73
67
|
|
|
74
|
-
const contractLabels: Record<string, string> = {
|
|
75
|
-
fixed_price: 'Preço fechado',
|
|
76
|
-
time_materials: 'Hora / Material',
|
|
77
|
-
retainer: 'Recorrente',
|
|
78
|
-
};
|
|
79
|
-
|
|
80
68
|
const scenarioLabels: Record<OperationsReportScenario, string> = {
|
|
81
69
|
base: 'Base',
|
|
82
70
|
growth: 'Crescimento',
|
|
@@ -92,20 +80,12 @@ function formatPercent(value: number) {
|
|
|
92
80
|
return `${Math.round(Number(value || 0))}%`;
|
|
93
81
|
}
|
|
94
82
|
|
|
95
|
-
function getStatusLabel(status: string) {
|
|
96
|
-
return statusLabels[status] ?? status;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
83
|
function getStatusClass(status: string) {
|
|
100
84
|
return (
|
|
101
85
|
statusClasses[status] ?? 'border-slate-200 bg-slate-100 text-slate-700'
|
|
102
86
|
);
|
|
103
87
|
}
|
|
104
88
|
|
|
105
|
-
function getContractLabel(contractType: string) {
|
|
106
|
-
return contractLabels[contractType] ?? contractType.replace(/_/g, ' ');
|
|
107
|
-
}
|
|
108
|
-
|
|
109
89
|
function KpiLabel({ text, tooltip }: { text: string; tooltip: string }) {
|
|
110
90
|
return (
|
|
111
91
|
<span className="flex items-center gap-1">
|
|
@@ -123,6 +103,7 @@ function KpiLabel({ text, tooltip }: { text: string; tooltip: string }) {
|
|
|
123
103
|
}
|
|
124
104
|
|
|
125
105
|
export default function OperationsProjectReportsPage() {
|
|
106
|
+
const t = useTranslations('operations.ReportsProjectsPage');
|
|
126
107
|
const defaults = getDefaultRange();
|
|
127
108
|
const { request } = useApp();
|
|
128
109
|
const [startDate, setStartDate] = useState(defaults.from);
|
|
@@ -182,15 +163,15 @@ export default function OperationsProjectReportsPage() {
|
|
|
182
163
|
return (
|
|
183
164
|
<Page>
|
|
184
165
|
<OperationsHeader
|
|
185
|
-
title=
|
|
186
|
-
description=
|
|
187
|
-
current=
|
|
166
|
+
title={t('title')}
|
|
167
|
+
description={t('description')}
|
|
168
|
+
current={t('breadcrumb')}
|
|
188
169
|
/>
|
|
189
170
|
|
|
190
171
|
<div className="grid gap-3 rounded-lg border bg-card p-3 md:grid-cols-[1fr_1fr_180px_180px_180px_auto]">
|
|
191
172
|
<div className="space-y-1">
|
|
192
173
|
<span className="text-xs font-medium text-muted-foreground">
|
|
193
|
-
|
|
174
|
+
{t('filters.start')}
|
|
194
175
|
</span>
|
|
195
176
|
<Input
|
|
196
177
|
type="date"
|
|
@@ -199,7 +180,7 @@ export default function OperationsProjectReportsPage() {
|
|
|
199
180
|
/>
|
|
200
181
|
</div>
|
|
201
182
|
<div className="space-y-1">
|
|
202
|
-
<span className="text-xs font-medium text-muted-foreground">
|
|
183
|
+
<span className="text-xs font-medium text-muted-foreground">{t('filters.end')}</span>
|
|
203
184
|
<Input
|
|
204
185
|
type="date"
|
|
205
186
|
value={endDate}
|
|
@@ -208,31 +189,31 @@ export default function OperationsProjectReportsPage() {
|
|
|
208
189
|
</div>
|
|
209
190
|
<div className="space-y-1">
|
|
210
191
|
<span className="text-xs font-medium text-muted-foreground">
|
|
211
|
-
|
|
192
|
+
{t('filters.status')}
|
|
212
193
|
</span>
|
|
213
194
|
<Select value={statusFilter} onValueChange={setStatusFilter}>
|
|
214
195
|
<SelectTrigger className="w-full">
|
|
215
196
|
<SelectValue />
|
|
216
197
|
</SelectTrigger>
|
|
217
198
|
<SelectContent>
|
|
218
|
-
<SelectItem value="all">
|
|
219
|
-
<SelectItem value="on_track">
|
|
220
|
-
<SelectItem value="attention">
|
|
221
|
-
<SelectItem value="late">
|
|
222
|
-
<SelectItem value="paused">
|
|
199
|
+
<SelectItem value="all">{t('filters.all')}</SelectItem>
|
|
200
|
+
<SelectItem value="on_track">{t('status.on_track')}</SelectItem>
|
|
201
|
+
<SelectItem value="attention">{t('status.attention')}</SelectItem>
|
|
202
|
+
<SelectItem value="late">{t('status.late')}</SelectItem>
|
|
203
|
+
<SelectItem value="paused">{t('status.paused')}</SelectItem>
|
|
223
204
|
</SelectContent>
|
|
224
205
|
</Select>
|
|
225
206
|
</div>
|
|
226
207
|
<div className="space-y-1">
|
|
227
208
|
<span className="text-xs font-medium text-muted-foreground">
|
|
228
|
-
|
|
209
|
+
{t('filters.client')}
|
|
229
210
|
</span>
|
|
230
211
|
<Select value={clientFilter} onValueChange={setClientFilter}>
|
|
231
212
|
<SelectTrigger className="w-full">
|
|
232
213
|
<SelectValue />
|
|
233
214
|
</SelectTrigger>
|
|
234
215
|
<SelectContent>
|
|
235
|
-
<SelectItem value="all">
|
|
216
|
+
<SelectItem value="all">{t('filters.all')}</SelectItem>
|
|
236
217
|
{clients.map((client) => (
|
|
237
218
|
<SelectItem key={client} value={client}>
|
|
238
219
|
{client}
|
|
@@ -243,7 +224,7 @@ export default function OperationsProjectReportsPage() {
|
|
|
243
224
|
</div>
|
|
244
225
|
<div className="space-y-1">
|
|
245
226
|
<span className="text-xs font-medium text-muted-foreground">
|
|
246
|
-
|
|
227
|
+
{t('filters.scenario')}
|
|
247
228
|
</span>
|
|
248
229
|
<Select
|
|
249
230
|
value={scenario}
|
|
@@ -255,9 +236,9 @@ export default function OperationsProjectReportsPage() {
|
|
|
255
236
|
<SelectValue />
|
|
256
237
|
</SelectTrigger>
|
|
257
238
|
<SelectContent>
|
|
258
|
-
<SelectItem value="base">
|
|
259
|
-
<SelectItem value="growth">
|
|
260
|
-
<SelectItem value="conservative">
|
|
239
|
+
<SelectItem value="base">{t('scenario.base')}</SelectItem>
|
|
240
|
+
<SelectItem value="growth">{t('scenario.growth')}</SelectItem>
|
|
241
|
+
<SelectItem value="conservative">{t('scenario.conservative')}</SelectItem>
|
|
261
242
|
</SelectContent>
|
|
262
243
|
</Select>
|
|
263
244
|
</div>
|
|
@@ -273,7 +254,7 @@ export default function OperationsProjectReportsPage() {
|
|
|
273
254
|
setScenario('base');
|
|
274
255
|
}}
|
|
275
256
|
>
|
|
276
|
-
|
|
257
|
+
{t('actions.clear')}
|
|
277
258
|
</Button>
|
|
278
259
|
</div>
|
|
279
260
|
</div>
|
|
@@ -286,12 +267,12 @@ export default function OperationsProjectReportsPage() {
|
|
|
286
267
|
key: 'active',
|
|
287
268
|
title: (
|
|
288
269
|
<KpiLabel
|
|
289
|
-
text=
|
|
290
|
-
tooltip=
|
|
270
|
+
text={t('cards.projects.title')}
|
|
271
|
+
tooltip={t('cards.projects.tooltip')}
|
|
291
272
|
/>
|
|
292
273
|
),
|
|
293
274
|
value: data?.rows.length ?? 0,
|
|
294
|
-
description:
|
|
275
|
+
description: t('cards.projects.description', { count: summary.atRisk }),
|
|
295
276
|
icon: FolderKanban,
|
|
296
277
|
accentClassName: 'from-sky-500/20 via-cyan-400/10 to-transparent',
|
|
297
278
|
iconContainerClassName: 'bg-sky-50 text-sky-700',
|
|
@@ -300,12 +281,12 @@ export default function OperationsProjectReportsPage() {
|
|
|
300
281
|
key: 'budget',
|
|
301
282
|
title: (
|
|
302
283
|
<KpiLabel
|
|
303
|
-
text=
|
|
304
|
-
tooltip=
|
|
284
|
+
text={t('cards.budget.title')}
|
|
285
|
+
tooltip={t('cards.budget.tooltip')}
|
|
305
286
|
/>
|
|
306
287
|
),
|
|
307
288
|
value: formatCurrency(summary.contractedRevenue),
|
|
308
|
-
description:
|
|
289
|
+
description: t('cards.budget.description', { count: data?.rows.length ?? 0 }),
|
|
309
290
|
icon: Banknote,
|
|
310
291
|
accentClassName:
|
|
311
292
|
'from-emerald-500/20 via-green-400/10 to-transparent',
|
|
@@ -315,12 +296,14 @@ export default function OperationsProjectReportsPage() {
|
|
|
315
296
|
key: 'allocated-cost',
|
|
316
297
|
title: (
|
|
317
298
|
<KpiLabel
|
|
318
|
-
text=
|
|
319
|
-
tooltip=
|
|
299
|
+
text={t('cards.allocatedCost.title')}
|
|
300
|
+
tooltip={t('cards.allocatedCost.tooltip')}
|
|
320
301
|
/>
|
|
321
302
|
),
|
|
322
303
|
value: formatCurrency(summary.allocatedCost),
|
|
323
|
-
description:
|
|
304
|
+
description: t('cards.allocatedCost.description', {
|
|
305
|
+
value: formatCurrency(summary.consumedHoursCost),
|
|
306
|
+
}),
|
|
324
307
|
icon: Gauge,
|
|
325
308
|
accentClassName: 'from-rose-500/20 via-red-400/10 to-transparent',
|
|
326
309
|
iconContainerClassName: 'bg-rose-50 text-rose-700',
|
|
@@ -329,12 +312,18 @@ export default function OperationsProjectReportsPage() {
|
|
|
329
312
|
key: 'planned-profit',
|
|
330
313
|
title: (
|
|
331
314
|
<KpiLabel
|
|
332
|
-
text=
|
|
333
|
-
tooltip=
|
|
315
|
+
text={t('cards.plannedProfit.title')}
|
|
316
|
+
tooltip={t('cards.plannedProfit.tooltip')}
|
|
334
317
|
/>
|
|
335
318
|
),
|
|
336
319
|
value: formatCurrency(summary.plannedProfit),
|
|
337
|
-
description:
|
|
320
|
+
description: t('cards.plannedProfit.description', {
|
|
321
|
+
value: formatPercent(
|
|
322
|
+
summary.contractedRevenue > 0
|
|
323
|
+
? (summary.plannedProfit / summary.contractedRevenue) * 100
|
|
324
|
+
: 0
|
|
325
|
+
),
|
|
326
|
+
}),
|
|
338
327
|
icon: TrendingUp,
|
|
339
328
|
accentClassName:
|
|
340
329
|
'from-violet-500/20 via-fuchsia-400/10 to-transparent',
|
|
@@ -344,12 +333,14 @@ export default function OperationsProjectReportsPage() {
|
|
|
344
333
|
key: 'hours',
|
|
345
334
|
title: (
|
|
346
335
|
<KpiLabel
|
|
347
|
-
text=
|
|
348
|
-
tooltip=
|
|
336
|
+
text={t('cards.hours.title')}
|
|
337
|
+
tooltip={t('cards.hours.tooltip')}
|
|
349
338
|
/>
|
|
350
339
|
),
|
|
351
340
|
value: formatHours(summary.actualHours),
|
|
352
|
-
description:
|
|
341
|
+
description: t('cards.hours.description', {
|
|
342
|
+
value: formatHours(summary.billableHours),
|
|
343
|
+
}),
|
|
353
344
|
icon: Clock3,
|
|
354
345
|
layout: 'compact',
|
|
355
346
|
accentClassName:
|
|
@@ -360,12 +351,14 @@ export default function OperationsProjectReportsPage() {
|
|
|
360
351
|
key: 'consumed-hours-cost',
|
|
361
352
|
title: (
|
|
362
353
|
<KpiLabel
|
|
363
|
-
text=
|
|
364
|
-
tooltip=
|
|
354
|
+
text={t('cards.consumedHoursCost.title')}
|
|
355
|
+
tooltip={t('cards.consumedHoursCost.tooltip')}
|
|
365
356
|
/>
|
|
366
357
|
),
|
|
367
358
|
value: formatCurrency(summary.consumedHoursCost),
|
|
368
|
-
description:
|
|
359
|
+
description: t('cards.consumedHoursCost.description', {
|
|
360
|
+
value: formatHours(summary.actualHours),
|
|
361
|
+
}),
|
|
369
362
|
icon: Receipt,
|
|
370
363
|
layout: 'compact',
|
|
371
364
|
accentClassName:
|
|
@@ -376,12 +369,14 @@ export default function OperationsProjectReportsPage() {
|
|
|
376
369
|
key: 'idleness-rate',
|
|
377
370
|
title: (
|
|
378
371
|
<KpiLabel
|
|
379
|
-
text=
|
|
380
|
-
tooltip=
|
|
372
|
+
text={t('cards.idlenessRate.title')}
|
|
373
|
+
tooltip={t('cards.idlenessRate.tooltip')}
|
|
381
374
|
/>
|
|
382
375
|
),
|
|
383
376
|
value: formatPercent(summary.idlenessRate),
|
|
384
|
-
description:
|
|
377
|
+
description: t('cards.idlenessRate.description', {
|
|
378
|
+
value: formatCurrency(summary.idlenessCost),
|
|
379
|
+
}),
|
|
385
380
|
icon: TimerOff,
|
|
386
381
|
layout: 'compact',
|
|
387
382
|
accentClassName:
|
|
@@ -392,12 +387,14 @@ export default function OperationsProjectReportsPage() {
|
|
|
392
387
|
key: 'idleness-cost',
|
|
393
388
|
title: (
|
|
394
389
|
<KpiLabel
|
|
395
|
-
text=
|
|
396
|
-
tooltip=
|
|
390
|
+
text={t('cards.idlenessCost.title')}
|
|
391
|
+
tooltip={t('cards.idlenessCost.tooltip')}
|
|
397
392
|
/>
|
|
398
393
|
),
|
|
399
394
|
value: formatCurrency(summary.idlenessCost),
|
|
400
|
-
description:
|
|
395
|
+
description: t('cards.idlenessCost.description', {
|
|
396
|
+
value: formatPercent(summary.idlenessRate),
|
|
397
|
+
}),
|
|
401
398
|
icon: CircleDollarSign,
|
|
402
399
|
layout: 'compact',
|
|
403
400
|
accentClassName:
|
|
@@ -410,27 +407,26 @@ export default function OperationsProjectReportsPage() {
|
|
|
410
407
|
|
|
411
408
|
<Card>
|
|
412
409
|
<CardHeader>
|
|
413
|
-
<CardTitle>
|
|
410
|
+
<CardTitle>{t('table.title')}</CardTitle>
|
|
414
411
|
<CardDescription>
|
|
415
|
-
|
|
416
|
-
ociosidade e risco por projeto.
|
|
412
|
+
{t('table.description')}
|
|
417
413
|
</CardDescription>
|
|
418
414
|
</CardHeader>
|
|
419
415
|
<CardContent className="overflow-x-auto">
|
|
420
416
|
<Table>
|
|
421
417
|
<TableHeader>
|
|
422
418
|
<TableRow>
|
|
423
|
-
<TableHead>
|
|
424
|
-
<TableHead>
|
|
425
|
-
<TableHead>
|
|
426
|
-
<TableHead>
|
|
427
|
-
<TableHead>
|
|
428
|
-
<TableHead>
|
|
429
|
-
<TableHead>
|
|
430
|
-
<TableHead>
|
|
431
|
-
<TableHead>
|
|
432
|
-
<TableHead>
|
|
433
|
-
<TableHead>
|
|
419
|
+
<TableHead>{t('table.columns.project')}</TableHead>
|
|
420
|
+
<TableHead>{t('table.columns.status')}</TableHead>
|
|
421
|
+
<TableHead>{t('table.columns.budget')}</TableHead>
|
|
422
|
+
<TableHead>{t('table.columns.allocatedCost')}</TableHead>
|
|
423
|
+
<TableHead>{t('table.columns.plannedProfit')}</TableHead>
|
|
424
|
+
<TableHead>{t('table.columns.hours')}</TableHead>
|
|
425
|
+
<TableHead>{t('table.columns.consumedHoursCost')}</TableHead>
|
|
426
|
+
<TableHead>{t('table.columns.idlenessRate')}</TableHead>
|
|
427
|
+
<TableHead>{t('table.columns.idlenessCost')}</TableHead>
|
|
428
|
+
<TableHead>{t('table.columns.risk')}</TableHead>
|
|
429
|
+
<TableHead>{t('table.columns.recommendation')}</TableHead>
|
|
434
430
|
<TableHead />
|
|
435
431
|
</TableRow>
|
|
436
432
|
</TableHeader>
|
|
@@ -452,7 +448,7 @@ export default function OperationsProjectReportsPage() {
|
|
|
452
448
|
<div className="font-medium">{row.name}</div>
|
|
453
449
|
<div className="text-xs text-muted-foreground">
|
|
454
450
|
{row.client} · {row.manager} · {row.squad} ·{' '}
|
|
455
|
-
{
|
|
451
|
+
{t(`contractType.${row.contractType}`)}
|
|
456
452
|
</div>
|
|
457
453
|
</TableCell>
|
|
458
454
|
<TableCell>
|
|
@@ -460,7 +456,7 @@ export default function OperationsProjectReportsPage() {
|
|
|
460
456
|
variant="outline"
|
|
461
457
|
className={getStatusClass(row.status)}
|
|
462
458
|
>
|
|
463
|
-
{
|
|
459
|
+
{t(`status.${row.status}`)}
|
|
464
460
|
</Badge>
|
|
465
461
|
</TableCell>
|
|
466
462
|
<TableCell>
|
|
@@ -482,7 +478,9 @@ export default function OperationsProjectReportsPage() {
|
|
|
482
478
|
<TableCell>
|
|
483
479
|
<div>{formatHours(row.actualHours)}</div>
|
|
484
480
|
<div className="text-xs text-muted-foreground">
|
|
485
|
-
{
|
|
481
|
+
{t('table.billableHours', {
|
|
482
|
+
value: formatHours(row.billableHours),
|
|
483
|
+
})}
|
|
486
484
|
</div>
|
|
487
485
|
</TableCell>
|
|
488
486
|
<TableCell>
|
|
@@ -508,7 +506,7 @@ export default function OperationsProjectReportsPage() {
|
|
|
508
506
|
: 'border-emerald-200 bg-emerald-50 text-emerald-700'
|
|
509
507
|
}
|
|
510
508
|
>
|
|
511
|
-
{row.risk}
|
|
509
|
+
{t(`risk.${row.risk}`)}
|
|
512
510
|
</Badge>
|
|
513
511
|
</TableCell>
|
|
514
512
|
<TableCell className="min-w-72 text-sm text-muted-foreground">
|
|
@@ -523,7 +521,7 @@ export default function OperationsProjectReportsPage() {
|
|
|
523
521
|
size="icon"
|
|
524
522
|
variant="ghost"
|
|
525
523
|
className="size-8"
|
|
526
|
-
title=
|
|
524
|
+
title={t('actions.viewDetails')}
|
|
527
525
|
>
|
|
528
526
|
<ExternalLink className="size-4" />
|
|
529
527
|
</Button>
|
|
@@ -52,6 +52,7 @@ import { OperationsHeader } from '../_components/operations-header';
|
|
|
52
52
|
import { StatusBadge } from '../_components/status-badge';
|
|
53
53
|
import { fetchOperations, mutateOperations } from '../_lib/api';
|
|
54
54
|
import { useOperationsAccess } from '../_lib/hooks/use-operations-access';
|
|
55
|
+
import { usePersistedPageSize } from '@/hooks/use-persisted-page-size';
|
|
55
56
|
import type {
|
|
56
57
|
OperationsScheduleAdjustmentDay,
|
|
57
58
|
OperationsScheduleAdjustmentRequest,
|
|
@@ -163,10 +164,12 @@ function SchedulePanel({
|
|
|
163
164
|
days,
|
|
164
165
|
locale,
|
|
165
166
|
emptyLabel,
|
|
167
|
+
dayOffLabel,
|
|
166
168
|
}: {
|
|
167
169
|
days: ScheduleDay[];
|
|
168
170
|
locale: string;
|
|
169
171
|
emptyLabel: string;
|
|
172
|
+
dayOffLabel: string;
|
|
170
173
|
}) {
|
|
171
174
|
const lines = groupScheduleLines(days, locale);
|
|
172
175
|
if (!lines.length)
|
|
@@ -182,7 +185,7 @@ function SchedulePanel({
|
|
|
182
185
|
{line.dayLabel}
|
|
183
186
|
</span>
|
|
184
187
|
{line.isOff ? (
|
|
185
|
-
<span className="text-muted-foreground">
|
|
188
|
+
<span className="text-muted-foreground">{dayOffLabel}</span>
|
|
186
189
|
) : (
|
|
187
190
|
<span className="text-foreground">
|
|
188
191
|
{line.time}
|
|
@@ -235,7 +238,11 @@ export default function OperationsScheduleAdjustmentsPage() {
|
|
|
235
238
|
const [search, setSearch] = useState('');
|
|
236
239
|
const [statusFilter, setStatusFilter] = useState('all');
|
|
237
240
|
const [page, setPage] = useState(1);
|
|
238
|
-
const [pageSize, setPageSize] =
|
|
241
|
+
const [pageSize, setPageSize] = usePersistedPageSize({
|
|
242
|
+
storageKey: 'pagination:operations-schedule-adjustments:pageSize',
|
|
243
|
+
defaultValue: 12,
|
|
244
|
+
allowedValues: [12, 24, 48],
|
|
245
|
+
});
|
|
239
246
|
const [viewMode, setViewMode] = useState<'table' | 'cards'>(() => {
|
|
240
247
|
if (typeof window === 'undefined') return 'cards';
|
|
241
248
|
const saved = window.localStorage.getItem(
|
|
@@ -539,6 +546,7 @@ export default function OperationsScheduleAdjustmentsPage() {
|
|
|
539
546
|
days={requestItem.currentSchedule ?? []}
|
|
540
547
|
locale={currentLocaleCode}
|
|
541
548
|
emptyLabel={commonT('labels.notAssigned')}
|
|
549
|
+
dayOffLabel={commonT('labels.dayOff')}
|
|
542
550
|
/>
|
|
543
551
|
</div>
|
|
544
552
|
<div className="bg-card px-4 py-3">
|
|
@@ -552,6 +560,7 @@ export default function OperationsScheduleAdjustmentsPage() {
|
|
|
552
560
|
}
|
|
553
561
|
locale={currentLocaleCode}
|
|
554
562
|
emptyLabel={commonT('labels.notAssigned')}
|
|
563
|
+
dayOffLabel={commonT('labels.dayOff')}
|
|
555
564
|
/>
|
|
556
565
|
</div>
|
|
557
566
|
</div>
|
|
@@ -946,6 +955,7 @@ export default function OperationsScheduleAdjustmentsPage() {
|
|
|
946
955
|
days={selectedRequest.currentSchedule ?? []}
|
|
947
956
|
locale={currentLocaleCode}
|
|
948
957
|
emptyLabel={commonT('labels.notAssigned')}
|
|
958
|
+
dayOffLabel={commonT('labels.dayOff')}
|
|
949
959
|
/>
|
|
950
960
|
</div>
|
|
951
961
|
</div>
|
|
@@ -961,6 +971,7 @@ export default function OperationsScheduleAdjustmentsPage() {
|
|
|
961
971
|
}
|
|
962
972
|
locale={currentLocaleCode}
|
|
963
973
|
emptyLabel={commonT('labels.notAssigned')}
|
|
974
|
+
dayOffLabel={commonT('labels.dayOff')}
|
|
964
975
|
/>
|
|
965
976
|
</div>
|
|
966
977
|
</div>
|
|
@@ -43,6 +43,7 @@ import { OperationsHeader } from '../_components/operations-header';
|
|
|
43
43
|
import { StatusBadge } from '../_components/status-badge';
|
|
44
44
|
import { fetchOperations, mutateOperations } from '../_lib/api';
|
|
45
45
|
import { useOperationsAccess } from '../_lib/hooks/use-operations-access';
|
|
46
|
+
import { usePersistedPageSize } from '@/hooks/use-persisted-page-size';
|
|
46
47
|
import type {
|
|
47
48
|
OperationsTimeOffRequest,
|
|
48
49
|
PaginatedResponse,
|
|
@@ -106,7 +107,11 @@ export default function OperationsTimeOffPage() {
|
|
|
106
107
|
const [search, setSearch] = useState('');
|
|
107
108
|
const [statusFilter, setStatusFilter] = useState('all');
|
|
108
109
|
const [page, setPage] = useState(1);
|
|
109
|
-
const [pageSize, setPageSize] =
|
|
110
|
+
const [pageSize, setPageSize] = usePersistedPageSize({
|
|
111
|
+
storageKey: 'pagination:operations-time-off:pageSize',
|
|
112
|
+
defaultValue: 12,
|
|
113
|
+
allowedValues: [12, 24, 48],
|
|
114
|
+
});
|
|
110
115
|
const [viewMode, setViewMode] = useState<'table' | 'cards'>(() => {
|
|
111
116
|
if (typeof window === 'undefined') return 'table';
|
|
112
117
|
const saved = window.localStorage.getItem('operations-time-off-view-mode');
|
|
@@ -80,6 +80,7 @@ import {
|
|
|
80
80
|
mutateOperations,
|
|
81
81
|
} from '../_lib/api';
|
|
82
82
|
import { useOperationsAccess } from '../_lib/hooks/use-operations-access';
|
|
83
|
+
import { usePersistedPageSize } from '@/hooks/use-persisted-page-size';
|
|
83
84
|
import type {
|
|
84
85
|
OperationsCollaborator,
|
|
85
86
|
OperationsProjectOption,
|
|
@@ -242,7 +243,11 @@ export default function OperationsTimesheetsPage() {
|
|
|
242
243
|
() => new Date().getMonth() + 1
|
|
243
244
|
);
|
|
244
245
|
const [page, setPage] = useState(1);
|
|
245
|
-
const [pageSize, setPageSize] =
|
|
246
|
+
const [pageSize, setPageSize] = usePersistedPageSize({
|
|
247
|
+
storageKey: 'pagination:operations-timesheets:pageSize',
|
|
248
|
+
defaultValue: 12,
|
|
249
|
+
allowedValues: [12, 24, 48],
|
|
250
|
+
});
|
|
246
251
|
const [viewMode, setViewMode] = useState<'table' | 'cards' | 'calendar'>(
|
|
247
252
|
() => {
|
|
248
253
|
if (typeof window === 'undefined') return 'table';
|
|
@@ -733,8 +738,7 @@ export default function OperationsTimesheetsPage() {
|
|
|
733
738
|
status: entry.status ?? 'submitted',
|
|
734
739
|
projectId: entry.projectId,
|
|
735
740
|
projectAssignmentId: entry.projectAssignmentId ?? 0,
|
|
736
|
-
projectName:
|
|
737
|
-
entry.projectName || commonT('labels.unassigned'),
|
|
741
|
+
projectName: entry.projectName || commonT('labels.unassigned'),
|
|
738
742
|
},
|
|
739
743
|
]
|
|
740
744
|
: []
|
|
@@ -1188,7 +1192,9 @@ export default function OperationsTimesheetsPage() {
|
|
|
1188
1192
|
{canSubmitTimesheet(timesheet) ? (
|
|
1189
1193
|
<Button
|
|
1190
1194
|
size="icon"
|
|
1191
|
-
onClick={() =>
|
|
1195
|
+
onClick={() =>
|
|
1196
|
+
void submitTimesheet(timesheet.id)
|
|
1197
|
+
}
|
|
1192
1198
|
>
|
|
1193
1199
|
<Send className="size-4" />
|
|
1194
1200
|
</Button>
|