@hed-hog/operations 0.0.330 → 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 +34 -9
- 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 +182 -268
- package/dist/operations.service.d.ts.map +1 -1
- package/dist/operations.service.js +2147 -1337
- 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_item.yaml +25 -25
- package/hedhog/data/route.yaml +61 -0
- 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-details-screen.tsx.ejs +289 -412
- package/hedhog/frontend/app/_components/project-file-attachments.tsx.ejs +371 -0
- package/hedhog/frontend/app/_components/project-form-screen.tsx.ejs +426 -374
- package/hedhog/frontend/app/_components/task-detail-sheet.tsx.ejs +803 -581
- package/hedhog/frontend/app/_components/task-file-attachments.tsx.ejs +4 -1
- 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/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 +6 -1
- package/hedhog/frontend/app/collaborator-types/page.tsx.ejs +6 -1
- package/hedhog/frontend/app/collaborators/page.tsx.ejs +59 -8
- 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 +14 -10
- package/hedhog/frontend/app/my-tasks/page.tsx.ejs +328 -105
- 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 +376 -30
- package/hedhog/frontend/app/schedule-adjustments/page.tsx.ejs +6 -1
- 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 +238 -46
- package/hedhog/frontend/messages/operations/en.json +61 -52
- package/hedhog/frontend/messages/operations/pt.json +59 -43
- package/hedhog/frontend/messages/pt.json +238 -46
- 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 +6 -5
- 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 +4277 -2535
|
@@ -1,50 +1,53 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
3
|
import { EmptyState, Page } from '@/components/entity-list';
|
|
4
|
-
import { RichTextEditor } from '@/components/rich-text-editor';
|
|
5
4
|
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar';
|
|
6
5
|
import { Button } from '@/components/ui/button';
|
|
7
|
-
import {
|
|
8
|
-
Dialog,
|
|
9
|
-
DialogContent,
|
|
6
|
+
import {
|
|
7
|
+
Dialog,
|
|
8
|
+
DialogContent,
|
|
9
|
+
DialogDescription,
|
|
10
10
|
DialogFooter,
|
|
11
11
|
DialogHeader,
|
|
12
|
-
DialogTitle,
|
|
13
|
-
} from '@/components/ui/dialog';
|
|
14
|
-
import { Input } from '@/components/ui/input';
|
|
15
|
-
import { Label } from '@/components/ui/label';
|
|
16
|
-
import { Progress } from '@/components/ui/progress';
|
|
17
|
-
import {
|
|
18
|
-
Select,
|
|
19
|
-
SelectContent,
|
|
20
|
-
SelectItem,
|
|
21
|
-
SelectTrigger,
|
|
22
|
-
SelectValue,
|
|
23
|
-
} from '@/components/ui/select';
|
|
24
|
-
import {
|
|
25
|
-
Sheet,
|
|
26
|
-
SheetContent,
|
|
27
|
-
SheetHeader,
|
|
28
|
-
SheetTitle,
|
|
29
|
-
} from '@/components/ui/sheet';
|
|
30
|
-
import {
|
|
31
|
-
Table,
|
|
32
|
-
TableBody,
|
|
33
|
-
TableCell,
|
|
12
|
+
DialogTitle,
|
|
13
|
+
} from '@/components/ui/dialog';
|
|
14
|
+
import { Input } from '@/components/ui/input';
|
|
15
|
+
import { Label } from '@/components/ui/label';
|
|
16
|
+
import { Progress } from '@/components/ui/progress';
|
|
17
|
+
import {
|
|
18
|
+
Select,
|
|
19
|
+
SelectContent,
|
|
20
|
+
SelectItem,
|
|
21
|
+
SelectTrigger,
|
|
22
|
+
SelectValue,
|
|
23
|
+
} from '@/components/ui/select';
|
|
24
|
+
import {
|
|
25
|
+
Sheet,
|
|
26
|
+
SheetContent,
|
|
27
|
+
SheetHeader,
|
|
28
|
+
SheetTitle,
|
|
29
|
+
} from '@/components/ui/sheet';
|
|
30
|
+
import {
|
|
31
|
+
Table,
|
|
32
|
+
TableBody,
|
|
33
|
+
TableCell,
|
|
34
34
|
TableHead,
|
|
35
35
|
TableHeader,
|
|
36
|
-
TableRow,
|
|
37
|
-
} from '@/components/ui/table';
|
|
38
|
-
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
|
|
36
|
+
TableRow,
|
|
37
|
+
} from '@/components/ui/table';
|
|
38
|
+
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
|
|
39
|
+
import { RichTextEditor } from '@/components/rich-text-editor';
|
|
39
40
|
import {
|
|
40
41
|
closestCenter,
|
|
41
42
|
DndContext,
|
|
43
|
+
DragOverlay,
|
|
42
44
|
PointerSensor,
|
|
43
45
|
useDraggable,
|
|
44
46
|
useDroppable,
|
|
45
47
|
useSensor,
|
|
46
48
|
useSensors,
|
|
47
49
|
type DragEndEvent,
|
|
50
|
+
type DragStartEvent,
|
|
48
51
|
type UniqueIdentifier,
|
|
49
52
|
} from '@dnd-kit/core';
|
|
50
53
|
import { CSS } from '@dnd-kit/utilities';
|
|
@@ -60,16 +63,17 @@ import {
|
|
|
60
63
|
Paperclip,
|
|
61
64
|
Pencil,
|
|
62
65
|
Plus,
|
|
66
|
+
Send,
|
|
63
67
|
Timer,
|
|
64
68
|
Trash2,
|
|
65
69
|
} from 'lucide-react';
|
|
66
|
-
import { useTranslations } from 'next-intl';
|
|
67
|
-
import { useCallback, useMemo, useState } from 'react';
|
|
68
|
-
import { fetchOperations, mutateOperations } from '../_lib/api';
|
|
69
|
-
import { useMentionItems } from '../_lib/hooks/use-mention-items';
|
|
70
|
-
import type {
|
|
71
|
-
OperationsMyProjectSummary,
|
|
72
|
-
OperationsTaskOption,
|
|
70
|
+
import { useTranslations } from 'next-intl';
|
|
71
|
+
import { useCallback, useMemo, useState } from 'react';
|
|
72
|
+
import { fetchOperations, mutateOperations } from '../_lib/api';
|
|
73
|
+
import { useMentionItems } from '../_lib/hooks/use-mention-items';
|
|
74
|
+
import type {
|
|
75
|
+
OperationsMyProjectSummary,
|
|
76
|
+
OperationsTaskOption,
|
|
73
77
|
PaginatedResponse,
|
|
74
78
|
} from '../_lib/types';
|
|
75
79
|
import {
|
|
@@ -80,12 +84,13 @@ import {
|
|
|
80
84
|
import { OperationsHeader } from './operations-header';
|
|
81
85
|
import { SectionCard } from './section-card';
|
|
82
86
|
import { StatusBadge } from './status-badge';
|
|
83
|
-
import {
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
type TaskDetailSheetData,
|
|
87
|
-
} from './task-detail-sheet';
|
|
88
|
-
import { TaskFileAttachments } from './task-file-attachments';
|
|
87
|
+
import {
|
|
88
|
+
TaskDetailSheet,
|
|
89
|
+
TaskCommentsSection,
|
|
90
|
+
type TaskDetailSheetData,
|
|
91
|
+
} from './task-detail-sheet';
|
|
92
|
+
import { TaskFileAttachments } from './task-file-attachments';
|
|
93
|
+
import { TimesheetEntryCreateSheet } from './timesheet-entry-create-sheet';
|
|
89
94
|
|
|
90
95
|
type BoardColumnId = 'todo' | 'doing' | 'review' | 'done';
|
|
91
96
|
|
|
@@ -101,16 +106,19 @@ type BoardTask = {
|
|
|
101
106
|
assigneeCollaboratorId: number | null;
|
|
102
107
|
assigneeName: string | null;
|
|
103
108
|
assigneeUserPhotoId: number | null;
|
|
104
|
-
assigneePersonAvatarId: number | null;
|
|
105
|
-
commentCount: number;
|
|
106
|
-
fileCount: number;
|
|
107
|
-
|
|
109
|
+
assigneePersonAvatarId: number | null;
|
|
110
|
+
commentCount: number;
|
|
111
|
+
fileCount: number;
|
|
112
|
+
doingStartedAt: string | null;
|
|
113
|
+
totalDoingMinutes: number;
|
|
114
|
+
};
|
|
108
115
|
|
|
109
116
|
type TaskFormState = {
|
|
110
117
|
name: string;
|
|
111
118
|
description: string;
|
|
112
119
|
priority: 'low' | 'medium' | 'high';
|
|
113
120
|
status: BoardColumnId;
|
|
121
|
+
assigneeCollaboratorId: string;
|
|
114
122
|
dueDate: string;
|
|
115
123
|
estimateHours: string;
|
|
116
124
|
tags: string;
|
|
@@ -121,6 +129,7 @@ const EMPTY_TASK_FORM: TaskFormState = {
|
|
|
121
129
|
description: '',
|
|
122
130
|
priority: 'medium',
|
|
123
131
|
status: 'todo',
|
|
132
|
+
assigneeCollaboratorId: 'none',
|
|
124
133
|
dueDate: '',
|
|
125
134
|
estimateHours: '',
|
|
126
135
|
tags: '',
|
|
@@ -133,6 +142,14 @@ type BoardState = {
|
|
|
133
142
|
columns: BoardColumns;
|
|
134
143
|
};
|
|
135
144
|
|
|
145
|
+
type TimesheetEntryPrefill = {
|
|
146
|
+
projectId: number;
|
|
147
|
+
projectAssignmentId?: number | null;
|
|
148
|
+
projectLabel: string;
|
|
149
|
+
taskId: number;
|
|
150
|
+
taskLabel: string;
|
|
151
|
+
};
|
|
152
|
+
|
|
136
153
|
const KANBAN_COLUMNS: Array<{ id: BoardColumnId; label: string }> = [
|
|
137
154
|
{ id: 'todo', label: 'Backlog' },
|
|
138
155
|
{ id: 'doing', label: 'Em execução' },
|
|
@@ -154,24 +171,34 @@ function parseTaskId(value: UniqueIdentifier | null | undefined) {
|
|
|
154
171
|
return match ? Number(match[1]) : null;
|
|
155
172
|
}
|
|
156
173
|
|
|
157
|
-
function parseColumnId(
|
|
158
|
-
value: UniqueIdentifier | null | undefined
|
|
159
|
-
): BoardColumnId | null {
|
|
160
|
-
if (!value) return null;
|
|
161
|
-
const match = String(value).match(/^col-(.+)$/);
|
|
162
|
-
const id = match?.[1];
|
|
163
|
-
return KANBAN_COLUMNS.some((c) => c.id === id) ? (id as BoardColumnId) : null;
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
function
|
|
167
|
-
|
|
168
|
-
|
|
174
|
+
function parseColumnId(
|
|
175
|
+
value: UniqueIdentifier | null | undefined
|
|
176
|
+
): BoardColumnId | null {
|
|
177
|
+
if (!value) return null;
|
|
178
|
+
const match = String(value).match(/^col-(.+)$/);
|
|
179
|
+
const id = match?.[1];
|
|
180
|
+
return KANBAN_COLUMNS.some((c) => c.id === id) ? (id as BoardColumnId) : null;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
function normalizeDateInputValue(value?: string | null) {
|
|
184
|
+
if (!value) return '';
|
|
185
|
+
const match = String(value)
|
|
186
|
+
.trim()
|
|
187
|
+
.match(/^\d{4}-\d{2}-\d{2}/);
|
|
188
|
+
return match?.[0] ?? '';
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
function apiTaskToBoardTask(
|
|
192
|
+
row: OperationsMyProjectSummary['tasks'][number] | OperationsTaskOption
|
|
193
|
+
): BoardTask {
|
|
169
194
|
const status = KANBAN_COLUMNS.some((c) => c.id === row.status)
|
|
170
195
|
? (row.status as BoardColumnId)
|
|
171
196
|
: 'todo';
|
|
172
197
|
const taskCounts = row as typeof row & {
|
|
173
198
|
commentCount?: number | null;
|
|
174
199
|
fileCount?: number | null;
|
|
200
|
+
doingStartedAt?: string | null;
|
|
201
|
+
totalDoingMinutes?: number | null;
|
|
175
202
|
};
|
|
176
203
|
|
|
177
204
|
return {
|
|
@@ -191,6 +218,8 @@ function apiTaskToBoardTask(
|
|
|
191
218
|
((row as unknown as Record<string, unknown>).commentCount as number) ?? 0,
|
|
192
219
|
fileCount:
|
|
193
220
|
((row as unknown as Record<string, unknown>).fileCount as number) ?? 0,
|
|
221
|
+
doingStartedAt: taskCounts.doingStartedAt ?? null,
|
|
222
|
+
totalDoingMinutes: taskCounts.totalDoingMinutes ?? 0,
|
|
194
223
|
};
|
|
195
224
|
}
|
|
196
225
|
|
|
@@ -203,6 +232,23 @@ function splitTasksByColumn(tasks: BoardTask[]): BoardColumns {
|
|
|
203
232
|
};
|
|
204
233
|
}
|
|
205
234
|
|
|
235
|
+
function replaceTaskInColumns(
|
|
236
|
+
columns: BoardColumns,
|
|
237
|
+
task: BoardTask
|
|
238
|
+
): BoardColumns {
|
|
239
|
+
const nextColumns = {
|
|
240
|
+
todo: columns.todo.filter((item) => item.id !== task.id),
|
|
241
|
+
doing: columns.doing.filter((item) => item.id !== task.id),
|
|
242
|
+
review: columns.review.filter((item) => item.id !== task.id),
|
|
243
|
+
done: columns.done.filter((item) => item.id !== task.id),
|
|
244
|
+
};
|
|
245
|
+
|
|
246
|
+
return {
|
|
247
|
+
...nextColumns,
|
|
248
|
+
[task.status]: [task, ...nextColumns[task.status]],
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
|
|
206
252
|
function getInitials(value?: string | null) {
|
|
207
253
|
const parts = String(value ?? '')
|
|
208
254
|
.trim()
|
|
@@ -225,26 +271,6 @@ function getUserPhotoUrl(photoId?: number | null) {
|
|
|
225
271
|
: null;
|
|
226
272
|
}
|
|
227
273
|
|
|
228
|
-
function normalizeDateInputValue(value?: string | null) {
|
|
229
|
-
if (!value) {
|
|
230
|
-
return '';
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
const normalizedValue = String(value).trim();
|
|
234
|
-
const directMatch = normalizedValue.match(/^\d{4}-\d{2}-\d{2}/);
|
|
235
|
-
|
|
236
|
-
if (directMatch?.[0]) {
|
|
237
|
-
return directMatch[0];
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
const parsedDate = new Date(normalizedValue);
|
|
241
|
-
if (Number.isNaN(parsedDate.getTime())) {
|
|
242
|
-
return '';
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
return parsedDate.toISOString().slice(0, 10);
|
|
246
|
-
}
|
|
247
|
-
|
|
248
274
|
function getTaskPriorityLabel(value?: string | null) {
|
|
249
275
|
const labels: Record<string, string> = {
|
|
250
276
|
low: 'Baixa',
|
|
@@ -326,10 +352,12 @@ function DraggableTaskCard({
|
|
|
326
352
|
return (
|
|
327
353
|
<div
|
|
328
354
|
ref={setNodeRef}
|
|
329
|
-
style={{
|
|
355
|
+
style={{
|
|
356
|
+
transform: CSS.Translate.toString(transform),
|
|
357
|
+
...(isDragging ? { opacity: 0, pointerEvents: 'none' } : {}),
|
|
358
|
+
}}
|
|
330
359
|
{...listeners}
|
|
331
360
|
{...attributes}
|
|
332
|
-
className={isDragging ? 'z-20' : undefined}
|
|
333
361
|
>
|
|
334
362
|
{children(isDragging)}
|
|
335
363
|
</div>
|
|
@@ -349,13 +377,12 @@ function DroppableColumn({
|
|
|
349
377
|
|
|
350
378
|
export function MyProjectSummaryScreen({ projectId }: { projectId: number }) {
|
|
351
379
|
const t = useTranslations('operations.ProjectDetailsPage');
|
|
352
|
-
const commonT = useTranslations('operations.Common');
|
|
353
|
-
const formT = useTranslations('operations.ProjectFormPage');
|
|
354
|
-
const { request, currentLocaleCode, getSettingValue } = useApp();
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
const getProjectStatusLabel = (value?: string | null) => {
|
|
380
|
+
const commonT = useTranslations('operations.Common');
|
|
381
|
+
const formT = useTranslations('operations.ProjectFormPage');
|
|
382
|
+
const { request, currentLocaleCode, getSettingValue } = useApp();
|
|
383
|
+
const mentionItems = useMentionItems(request);
|
|
384
|
+
|
|
385
|
+
const getProjectStatusLabel = (value?: string | null) => {
|
|
359
386
|
if (!value) return commonT('labels.notAvailable');
|
|
360
387
|
try {
|
|
361
388
|
return formT(`options.statuses.${value}`);
|
|
@@ -397,7 +424,12 @@ export function MyProjectSummaryScreen({ projectId }: { projectId: number }) {
|
|
|
397
424
|
const [editingTaskId, setEditingTaskId] = useState<number | null>(null);
|
|
398
425
|
const [taskFormData, setTaskFormData] =
|
|
399
426
|
useState<TaskFormState>(EMPTY_TASK_FORM);
|
|
427
|
+
const [activeDragTask, setActiveDragTask] = useState<BoardTask | null>(null);
|
|
400
428
|
const [taskFormLoading, setTaskFormLoading] = useState(false);
|
|
429
|
+
const [isTimesheetEntrySheetOpen, setIsTimesheetEntrySheetOpen] =
|
|
430
|
+
useState(false);
|
|
431
|
+
const [timesheetPrefill, setTimesheetPrefill] =
|
|
432
|
+
useState<TimesheetEntryPrefill | null>(null);
|
|
401
433
|
|
|
402
434
|
const apiTasks = useMemo(
|
|
403
435
|
() => (project?.tasks ?? []).map(apiTaskToBoardTask),
|
|
@@ -429,6 +461,27 @@ export function MyProjectSummaryScreen({ projectId }: { projectId: number }) {
|
|
|
429
461
|
return splitTasksByColumn(apiTasks);
|
|
430
462
|
}, [project, boardState, apiTasks]);
|
|
431
463
|
|
|
464
|
+
const taskAssigneeOptions = useMemo(() => {
|
|
465
|
+
const seen = new Set<number>();
|
|
466
|
+
return (
|
|
467
|
+
project?.assignments
|
|
468
|
+
.filter((assignment) => {
|
|
469
|
+
if (
|
|
470
|
+
!assignment.collaboratorId ||
|
|
471
|
+
seen.has(assignment.collaboratorId)
|
|
472
|
+
) {
|
|
473
|
+
return false;
|
|
474
|
+
}
|
|
475
|
+
seen.add(assignment.collaboratorId);
|
|
476
|
+
return true;
|
|
477
|
+
})
|
|
478
|
+
.map((assignment) => ({
|
|
479
|
+
id: String(assignment.collaboratorId),
|
|
480
|
+
label: assignment.collaboratorName,
|
|
481
|
+
})) ?? []
|
|
482
|
+
);
|
|
483
|
+
}, [project]);
|
|
484
|
+
|
|
432
485
|
const sensors = useSensors(
|
|
433
486
|
useSensor(PointerSensor, { activationConstraint: { distance: 6 } })
|
|
434
487
|
);
|
|
@@ -464,31 +517,73 @@ export function MyProjectSummaryScreen({ projectId }: { projectId: number }) {
|
|
|
464
517
|
},
|
|
465
518
|
});
|
|
466
519
|
|
|
467
|
-
mutateOperations(
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
520
|
+
mutateOperations<OperationsTaskOption>(
|
|
521
|
+
request,
|
|
522
|
+
`/operations/tasks/${taskId}`,
|
|
523
|
+
'PATCH',
|
|
524
|
+
{
|
|
525
|
+
status: targetColumn,
|
|
526
|
+
}
|
|
527
|
+
)
|
|
528
|
+
.then((updatedTask) => {
|
|
529
|
+
if (!updatedTask) {
|
|
530
|
+
return;
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
const updatedBoardTask = apiTaskToBoardTask(updatedTask);
|
|
534
|
+
setBoardState((current) => ({
|
|
535
|
+
projectId: current?.projectId ?? project.id,
|
|
536
|
+
columns: replaceTaskInColumns(
|
|
537
|
+
current?.columns ?? taskColumns,
|
|
538
|
+
updatedBoardTask
|
|
539
|
+
),
|
|
540
|
+
}));
|
|
541
|
+
})
|
|
542
|
+
.catch(() => {
|
|
543
|
+
setBoardState(null);
|
|
544
|
+
void refetch();
|
|
545
|
+
});
|
|
473
546
|
},
|
|
474
547
|
[taskColumns, project, request, refetch] // eslint-disable-line react-hooks/exhaustive-deps
|
|
475
548
|
);
|
|
476
549
|
|
|
477
550
|
const onBoardDragEnd = (event: DragEndEvent) => {
|
|
551
|
+
setActiveDragTask(null);
|
|
478
552
|
const taskId = parseTaskId(event.active.id);
|
|
479
553
|
const targetColumn = parseColumnId(event.over?.id);
|
|
480
554
|
if (!taskId || !targetColumn) return;
|
|
481
555
|
moveTaskToColumn(taskId, targetColumn);
|
|
482
556
|
};
|
|
483
557
|
|
|
484
|
-
const
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
558
|
+
const onBoardDragStart = (event: DragStartEvent) => {
|
|
559
|
+
const taskId = parseTaskId(event.active.id);
|
|
560
|
+
if (!taskId) {
|
|
561
|
+
setActiveDragTask(null);
|
|
562
|
+
return;
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
const task = KANBAN_COLUMNS.map((column) => taskColumns[column.id])
|
|
566
|
+
.find((items) => items.some((item) => item.id === taskId))
|
|
567
|
+
?.find((item) => item.id === taskId);
|
|
568
|
+
|
|
569
|
+
setActiveDragTask(task ?? null);
|
|
570
|
+
};
|
|
571
|
+
|
|
572
|
+
const openCreateTaskForm = useCallback(
|
|
573
|
+
(defaultStatus: BoardColumnId = 'todo') => {
|
|
574
|
+
setEditingTaskId(null);
|
|
575
|
+
setTaskFormData({
|
|
576
|
+
...EMPTY_TASK_FORM,
|
|
577
|
+
status: defaultStatus,
|
|
578
|
+
assigneeCollaboratorId:
|
|
579
|
+
currentCollaboratorId != null
|
|
580
|
+
? String(currentCollaboratorId)
|
|
581
|
+
: 'none',
|
|
582
|
+
});
|
|
488
583
|
setSelectedTask(null);
|
|
489
584
|
setTaskFormOpen(true);
|
|
490
585
|
},
|
|
491
|
-
[]
|
|
586
|
+
[currentCollaboratorId]
|
|
492
587
|
);
|
|
493
588
|
|
|
494
589
|
const openEditTaskForm = useCallback((task: BoardTask) => {
|
|
@@ -498,6 +593,9 @@ export function MyProjectSummaryScreen({ projectId }: { projectId: number }) {
|
|
|
498
593
|
description: task.description ?? '',
|
|
499
594
|
priority: task.priority as TaskFormState['priority'],
|
|
500
595
|
status: task.status,
|
|
596
|
+
assigneeCollaboratorId: task.assigneeCollaboratorId
|
|
597
|
+
? String(task.assigneeCollaboratorId)
|
|
598
|
+
: 'none',
|
|
501
599
|
dueDate: normalizeDateInputValue(task.dueDate),
|
|
502
600
|
estimateHours:
|
|
503
601
|
task.estimateHours != null ? String(task.estimateHours) : '',
|
|
@@ -519,7 +617,10 @@ export function MyProjectSummaryScreen({ projectId }: { projectId: number }) {
|
|
|
519
617
|
const payload: Record<string, unknown> = {
|
|
520
618
|
projectId,
|
|
521
619
|
projectAssignmentId: project?.myAssignmentId ?? null,
|
|
522
|
-
assigneeCollaboratorId:
|
|
620
|
+
assigneeCollaboratorId:
|
|
621
|
+
taskFormData.assigneeCollaboratorId !== 'none'
|
|
622
|
+
? Number(taskFormData.assigneeCollaboratorId)
|
|
623
|
+
: null,
|
|
523
624
|
name: taskFormData.name.trim(),
|
|
524
625
|
description: taskFormData.description || null,
|
|
525
626
|
priority: taskFormData.priority,
|
|
@@ -550,15 +651,7 @@ export function MyProjectSummaryScreen({ projectId }: { projectId: number }) {
|
|
|
550
651
|
} finally {
|
|
551
652
|
setTaskFormLoading(false);
|
|
552
653
|
}
|
|
553
|
-
}, [
|
|
554
|
-
currentCollaboratorId,
|
|
555
|
-
editingTaskId,
|
|
556
|
-
project,
|
|
557
|
-
projectId,
|
|
558
|
-
refetchAll,
|
|
559
|
-
request,
|
|
560
|
-
taskFormData,
|
|
561
|
-
]);
|
|
654
|
+
}, [editingTaskId, project, projectId, refetchAll, request, taskFormData]);
|
|
562
655
|
|
|
563
656
|
const [archivingTaskId, setArchivingTaskId] = useState<number | null>(null);
|
|
564
657
|
|
|
@@ -612,6 +705,29 @@ export function MyProjectSummaryScreen({ projectId }: { projectId: number }) {
|
|
|
612
705
|
[request, refetchAll]
|
|
613
706
|
);
|
|
614
707
|
|
|
708
|
+
const openTimesheetEntrySheet = useCallback(
|
|
709
|
+
(task: TaskDetailSheetData) => {
|
|
710
|
+
if (!project) {
|
|
711
|
+
return;
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
const projectLabel = [project.name, project.code]
|
|
715
|
+
.filter(Boolean)
|
|
716
|
+
.join(' • ');
|
|
717
|
+
|
|
718
|
+
setTimesheetPrefill({
|
|
719
|
+
projectId,
|
|
720
|
+
projectAssignmentId: project.myAssignmentId ?? null,
|
|
721
|
+
projectLabel: projectLabel || commonT('labels.notAssigned'),
|
|
722
|
+
taskId: task.id,
|
|
723
|
+
taskLabel: task.name,
|
|
724
|
+
});
|
|
725
|
+
setSelectedTask(null);
|
|
726
|
+
setIsTimesheetEntrySheetOpen(true);
|
|
727
|
+
},
|
|
728
|
+
[commonT, project, projectId]
|
|
729
|
+
);
|
|
730
|
+
|
|
615
731
|
if (!project) {
|
|
616
732
|
return (
|
|
617
733
|
<Page>
|
|
@@ -708,6 +824,8 @@ export function MyProjectSummaryScreen({ projectId }: { projectId: number }) {
|
|
|
708
824
|
<DndContext
|
|
709
825
|
sensors={sensors}
|
|
710
826
|
collisionDetection={closestCenter}
|
|
827
|
+
onDragStart={onBoardDragStart}
|
|
828
|
+
onDragCancel={() => setActiveDragTask(null)}
|
|
711
829
|
onDragEnd={onBoardDragEnd}
|
|
712
830
|
>
|
|
713
831
|
<div className="grid gap-4 xl:grid-cols-4">
|
|
@@ -924,6 +1042,18 @@ export function MyProjectSummaryScreen({ projectId }: { projectId: number }) {
|
|
|
924
1042
|
</DroppableColumn>
|
|
925
1043
|
))}
|
|
926
1044
|
</div>
|
|
1045
|
+
<DragOverlay zIndex={1200}>
|
|
1046
|
+
{activeDragTask ? (
|
|
1047
|
+
<div className="w-76 cursor-grabbing rounded-2xl border border-primary/60 bg-card p-3 text-left shadow-2xl ring-2 ring-primary/20 opacity-95">
|
|
1048
|
+
<p className="line-clamp-2 text-sm font-semibold leading-snug">
|
|
1049
|
+
{activeDragTask.name}
|
|
1050
|
+
</p>
|
|
1051
|
+
<p className="mt-1 truncate text-xs text-muted-foreground">
|
|
1052
|
+
{activeDragTask.assigneeName || commonT('labels.notAssigned')}
|
|
1053
|
+
</p>
|
|
1054
|
+
</div>
|
|
1055
|
+
) : null}
|
|
1056
|
+
</DragOverlay>
|
|
927
1057
|
</DndContext>
|
|
928
1058
|
</SectionCard>
|
|
929
1059
|
|
|
@@ -1091,13 +1221,13 @@ export function MyProjectSummaryScreen({ projectId }: { projectId: number }) {
|
|
|
1091
1221
|
}}
|
|
1092
1222
|
footer={
|
|
1093
1223
|
selectedTask ? (
|
|
1094
|
-
<div className="grid grid-cols-
|
|
1224
|
+
<div className="grid grid-cols-1 gap-3 sm:grid-cols-3">
|
|
1095
1225
|
{archivedTasks.some((task) => task.id === selectedTask.id) ? (
|
|
1096
1226
|
<>
|
|
1097
1227
|
<Button
|
|
1098
1228
|
variant="outline"
|
|
1099
1229
|
size="sm"
|
|
1100
|
-
className="h-10 gap-2"
|
|
1230
|
+
className="h-10 gap-2 sm:col-span-2"
|
|
1101
1231
|
onClick={() => void handleRestoreTask(selectedTask.id)}
|
|
1102
1232
|
>
|
|
1103
1233
|
<ArchiveRestore className="size-3.5" />
|
|
@@ -1115,6 +1245,15 @@ export function MyProjectSummaryScreen({ projectId }: { projectId: number }) {
|
|
|
1115
1245
|
</>
|
|
1116
1246
|
) : (
|
|
1117
1247
|
<>
|
|
1248
|
+
<Button
|
|
1249
|
+
variant="outline"
|
|
1250
|
+
size="sm"
|
|
1251
|
+
className="h-10 gap-2"
|
|
1252
|
+
onClick={() => openTimesheetEntrySheet(selectedTask)}
|
|
1253
|
+
>
|
|
1254
|
+
<Send className="size-3.5" />
|
|
1255
|
+
{commonT('actions.logHours')}
|
|
1256
|
+
</Button>
|
|
1118
1257
|
<Button
|
|
1119
1258
|
variant="outline"
|
|
1120
1259
|
size="sm"
|
|
@@ -1140,13 +1279,43 @@ export function MyProjectSummaryScreen({ projectId }: { projectId: number }) {
|
|
|
1140
1279
|
}
|
|
1141
1280
|
/>
|
|
1142
1281
|
|
|
1143
|
-
<
|
|
1144
|
-
open={
|
|
1282
|
+
<TimesheetEntryCreateSheet
|
|
1283
|
+
open={isTimesheetEntrySheetOpen}
|
|
1145
1284
|
onOpenChange={(open) => {
|
|
1285
|
+
setIsTimesheetEntrySheetOpen(open);
|
|
1146
1286
|
if (!open) {
|
|
1287
|
+
setTimesheetPrefill(null);
|
|
1288
|
+
}
|
|
1289
|
+
}}
|
|
1290
|
+
project={
|
|
1291
|
+
timesheetPrefill
|
|
1292
|
+
? {
|
|
1293
|
+
id: timesheetPrefill.projectId,
|
|
1294
|
+
label: timesheetPrefill.projectLabel,
|
|
1295
|
+
projectAssignmentId: timesheetPrefill.projectAssignmentId,
|
|
1296
|
+
}
|
|
1297
|
+
: null
|
|
1298
|
+
}
|
|
1299
|
+
task={
|
|
1300
|
+
timesheetPrefill
|
|
1301
|
+
? {
|
|
1302
|
+
id: timesheetPrefill.taskId,
|
|
1303
|
+
label: timesheetPrefill.taskLabel,
|
|
1304
|
+
}
|
|
1305
|
+
: null
|
|
1306
|
+
}
|
|
1307
|
+
onCreated={() => {
|
|
1308
|
+
void refetchAll();
|
|
1309
|
+
}}
|
|
1310
|
+
/>
|
|
1311
|
+
|
|
1312
|
+
|
|
1313
|
+
<Sheet
|
|
1314
|
+
open={taskFormOpen}
|
|
1315
|
+
onOpenChange={(open) => {
|
|
1316
|
+
if (!open) {
|
|
1147
1317
|
setTaskFormOpen(false);
|
|
1148
1318
|
setEditingTaskId(null);
|
|
1149
|
-
setTaskFormData(EMPTY_TASK_FORM);
|
|
1150
1319
|
}
|
|
1151
1320
|
}}
|
|
1152
1321
|
>
|
|
@@ -1257,6 +1426,35 @@ export function MyProjectSummaryScreen({ projectId }: { projectId: number }) {
|
|
|
1257
1426
|
</div>
|
|
1258
1427
|
</div>
|
|
1259
1428
|
|
|
1429
|
+
<div className="space-y-1.5">
|
|
1430
|
+
<Label>{commonT('responsible')}</Label>
|
|
1431
|
+
<Select
|
|
1432
|
+
value={taskFormData.assigneeCollaboratorId}
|
|
1433
|
+
onValueChange={(value) =>
|
|
1434
|
+
setTaskFormData((prev) => ({
|
|
1435
|
+
...prev,
|
|
1436
|
+
assigneeCollaboratorId: value,
|
|
1437
|
+
}))
|
|
1438
|
+
}
|
|
1439
|
+
>
|
|
1440
|
+
<SelectTrigger className="w-full">
|
|
1441
|
+
<SelectValue
|
|
1442
|
+
placeholder={commonT('labels.notAssigned')}
|
|
1443
|
+
/>
|
|
1444
|
+
</SelectTrigger>
|
|
1445
|
+
<SelectContent>
|
|
1446
|
+
<SelectItem value="none">
|
|
1447
|
+
{commonT('labels.notAssigned')}
|
|
1448
|
+
</SelectItem>
|
|
1449
|
+
{taskAssigneeOptions.map((option) => (
|
|
1450
|
+
<SelectItem key={option.id} value={option.id}>
|
|
1451
|
+
{option.label}
|
|
1452
|
+
</SelectItem>
|
|
1453
|
+
))}
|
|
1454
|
+
</SelectContent>
|
|
1455
|
+
</Select>
|
|
1456
|
+
</div>
|
|
1457
|
+
|
|
1260
1458
|
<div className="grid grid-cols-2 gap-3">
|
|
1261
1459
|
<div className="space-y-1.5">
|
|
1262
1460
|
<Label htmlFor="task-due-date">
|
|
@@ -1398,10 +1596,10 @@ export function MyProjectSummaryScreen({ projectId }: { projectId: number }) {
|
|
|
1398
1596
|
<DialogContent className="sm:max-w-lg">
|
|
1399
1597
|
<DialogHeader>
|
|
1400
1598
|
<DialogTitle>{t('dialogs.deleteTitle')}</DialogTitle>
|
|
1599
|
+
<DialogDescription>
|
|
1600
|
+
{t('dialogs.deleteDescription')}
|
|
1601
|
+
</DialogDescription>
|
|
1401
1602
|
</DialogHeader>
|
|
1402
|
-
<p className="text-sm text-muted-foreground">
|
|
1403
|
-
{t('dialogs.deleteDescription')}
|
|
1404
|
-
</p>
|
|
1405
1603
|
<DialogFooter className="gap-2 sm:justify-between">
|
|
1406
1604
|
<Button variant="ghost" onClick={() => setDeletePromptTask(null)}>
|
|
1407
1605
|
{commonT('actions.cancel')}
|