@hed-hog/operations 0.0.328 → 0.0.329
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/dist/controllers/operations-tasks.controller.d.ts +3 -3
- package/dist/operations.service.d.ts +3 -3
- package/hedhog/frontend/app/_components/collaborator-form-screen.tsx.ejs +7 -7
- package/hedhog/frontend/app/_components/department-picker.tsx.ejs +125 -0
- package/hedhog/frontend/app/_components/department-select-with-create.tsx.ejs +64 -325
- package/hedhog/frontend/app/_components/project-form-screen.tsx.ejs +16 -16
- package/hedhog/frontend/app/_components/system-user-picker.tsx.ejs +198 -0
- package/hedhog/frontend/app/_components/system-user-select-with-create.tsx.ejs +107 -569
- package/hedhog/frontend/messages/en.json +79 -10
- package/hedhog/frontend/messages/operations/en.json +67 -3
- package/hedhog/frontend/messages/operations/pt.json +67 -3
- package/hedhog/frontend/messages/pt.json +77 -8
- package/package.json +6 -6
- package/hedhog/frontend/app/_components/collaborator-details-screen.tsx.ejs +0 -476
- package/hedhog/frontend/app/_components/collaborator-select-with-create.tsx.ejs +0 -261
- package/hedhog/frontend/app/_components/contract-content-editor.tsx.ejs +0 -258
- package/hedhog/frontend/app/_components/person-select-with-create.tsx.ejs +0 -1
- package/hedhog/frontend/messages/en.json.ejs +0 -2060
- package/hedhog/frontend/messages/operations/operations/en.json +0 -2102
- package/hedhog/frontend/messages/operations/operations/pt.json +0 -2111
- package/hedhog/frontend/messages/pt.json.ejs +0 -2067
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/async-options-combobox.d.ts +0 -29
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/async-options-combobox.d.ts.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/async-options-combobox.js +0 -95
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/async-options-combobox.js.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/async-options-combobox.tsx +0 -233
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/collaborator-costs-section.d.ts +0 -10
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/collaborator-costs-section.d.ts.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/collaborator-costs-section.js +0 -577
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/collaborator-costs-section.js.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/collaborator-costs-section.tsx +0 -868
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/collaborator-details-screen.d.ts +0 -4
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/collaborator-details-screen.d.ts.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/collaborator-details-screen.js +0 -337
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/collaborator-details-screen.js.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/collaborator-details-screen.tsx +0 -476
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/collaborator-form-screen.d.ts +0 -9
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/collaborator-form-screen.d.ts.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/collaborator-form-screen.js +0 -1348
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/collaborator-form-screen.js.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/collaborator-form-screen.tsx +0 -2233
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/collaborator-select-with-create.d.ts +0 -12
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/collaborator-select-with-create.d.ts.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/collaborator-select-with-create.js +0 -162
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/collaborator-select-with-create.js.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/collaborator-select-with-create.tsx +0 -261
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/contract-content-editor.d.ts +0 -18
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/contract-content-editor.d.ts.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/contract-content-editor.js +0 -145
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/contract-content-editor.js.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/contract-content-editor.tsx +0 -258
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/contract-details-screen.d.ts +0 -4
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/contract-details-screen.d.ts.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/contract-details-screen.js +0 -223
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/contract-details-screen.js.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/contract-details-screen.tsx +0 -342
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/contract-form-screen.d.ts +0 -58
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/contract-form-screen.d.ts.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/contract-form-screen.js +0 -438
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/contract-form-screen.js.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/contract-form-screen.tsx +0 -698
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/department-select-with-create.d.ts +0 -20
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/department-select-with-create.d.ts.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/department-select-with-create.js +0 -233
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/department-select-with-create.js.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/department-select-with-create.tsx +0 -392
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/my-project-summary-screen.d.ts +0 -4
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/my-project-summary-screen.d.ts.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/my-project-summary-screen.js +0 -814
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/my-project-summary-screen.js.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/my-project-summary-screen.tsx +0 -1288
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/operations-calendar-view.d.ts +0 -21
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/operations-calendar-view.d.ts.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/operations-calendar-view.js +0 -174
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/operations-calendar-view.js.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/operations-calendar-view.tsx +0 -306
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/operations-header.d.ts +0 -10
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/operations-header.d.ts.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/operations-header.js +0 -12
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/operations-header.js.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/operations-header.tsx +0 -29
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/person-select-with-create.d.ts +0 -15
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/person-select-with-create.d.ts.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/person-select-with-create.js +0 -501
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/person-select-with-create.js.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/person-select-with-create.tsx +0 -853
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/project-costs-section.d.ts +0 -6
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/project-costs-section.d.ts.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/project-costs-section.js +0 -847
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/project-costs-section.js.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/project-costs-section.tsx +0 -1340
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/project-details-screen.d.ts +0 -4
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/project-details-screen.d.ts.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/project-details-screen.js +0 -2930
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/project-details-screen.js.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/project-details-screen.tsx +0 -4378
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/project-form-screen.d.ts +0 -9
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/project-form-screen.d.ts.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/project-form-screen.js +0 -1013
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/project-form-screen.js.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/project-form-screen.tsx +0 -1745
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/section-card.d.ts +0 -13
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/section-card.d.ts.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/section-card.js +0 -38
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/section-card.js.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/section-card.tsx +0 -74
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/status-badge.d.ts +0 -7
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/status-badge.d.ts.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/status-badge.js +0 -11
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/status-badge.js.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/status-badge.tsx +0 -15
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/system-user-select-with-create.d.ts +0 -18
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/system-user-select-with-create.d.ts.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/system-user-select-with-create.js +0 -406
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/system-user-select-with-create.js.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/system-user-select-with-create.tsx +0 -660
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/task-detail-sheet.d.ts +0 -26
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/task-detail-sheet.d.ts.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/task-detail-sheet.js +0 -332
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/task-detail-sheet.js.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/task-detail-sheet.tsx +0 -518
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/task-file-attachments.d.ts +0 -6
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/task-file-attachments.d.ts.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/task-file-attachments.js +0 -255
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/task-file-attachments.js.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/task-file-attachments.tsx +0 -388
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/timesheet-task-create-sheet.d.ts +0 -10
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/timesheet-task-create-sheet.d.ts.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/timesheet-task-create-sheet.js +0 -131
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/timesheet-task-create-sheet.js.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/timesheet-task-create-sheet.tsx +0 -214
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_lib/api.d.ts +0 -108
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_lib/api.d.ts.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_lib/api.js +0 -162
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_lib/api.js.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_lib/api.ts +0 -428
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_lib/hooks/use-operations-access.d.ts +0 -8
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_lib/hooks/use-operations-access.d.ts.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_lib/hooks/use-operations-access.js +0 -36
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_lib/hooks/use-operations-access.js.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_lib/hooks/use-operations-access.ts +0 -44
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_lib/types.d.ts +0 -837
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_lib/types.d.ts.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_lib/types.js +0 -3
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_lib/types.js.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_lib/types.ts +0 -861
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_lib/utils/format.d.ts +0 -16
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_lib/utils/format.d.ts.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_lib/utils/format.js +0 -182
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_lib/utils/format.js.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_lib/utils/format.ts +0 -250
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_lib/utils/forms.d.ts +0 -4
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_lib/utils/forms.d.ts.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_lib/utils/forms.js +0 -51
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_lib/utils/forms.js.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_lib/utils/forms.ts +0 -61
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/approvals/page.d.ts +0 -2
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/approvals/page.d.ts.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/approvals/page.js +0 -954
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/approvals/page.js.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/approvals/page.tsx +0 -1277
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/collaborator-types/page.d.ts +0 -2
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/collaborator-types/page.d.ts.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/collaborator-types/page.js +0 -488
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/collaborator-types/page.js.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/collaborator-types/page.tsx +0 -805
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/collaborators/[id]/edit/page.d.ts +0 -6
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/collaborators/[id]/edit/page.d.ts.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/collaborators/[id]/edit/page.js +0 -9
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/collaborators/[id]/edit/page.js.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/collaborators/[id]/edit/page.tsx +0 -11
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/collaborators/[id]/page.d.ts +0 -6
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/collaborators/[id]/page.d.ts.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/collaborators/[id]/page.js +0 -9
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/collaborators/[id]/page.js.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/collaborators/[id]/page.tsx +0 -11
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/collaborators/new/page.d.ts +0 -2
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/collaborators/new/page.d.ts.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/collaborators/new/page.js +0 -8
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/collaborators/new/page.js.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/collaborators/new/page.tsx +0 -5
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/collaborators/page.d.ts +0 -2
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/collaborators/page.d.ts.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/collaborators/page.js +0 -612
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/collaborators/page.js.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/collaborators/page.tsx +0 -939
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/contracts/[id]/edit/page.d.ts +0 -6
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/contracts/[id]/edit/page.d.ts.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/contracts/[id]/edit/page.js +0 -9
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/contracts/[id]/edit/page.js.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/contracts/[id]/edit/page.tsx +0 -11
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/contracts/[id]/page.d.ts +0 -6
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/contracts/[id]/page.d.ts.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/contracts/[id]/page.js +0 -9
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/contracts/[id]/page.js.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/contracts/[id]/page.tsx +0 -11
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/contracts/new/page.d.ts +0 -6
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/contracts/new/page.d.ts.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/contracts/new/page.js +0 -9
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/contracts/new/page.js.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/contracts/new/page.tsx +0 -17
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/contracts/page.d.ts +0 -2
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/contracts/page.d.ts.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/contracts/page.js +0 -348
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/contracts/page.js.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/contracts/page.tsx +0 -536
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/departments/page.d.ts +0 -2
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/departments/page.d.ts.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/departments/page.js +0 -401
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/departments/page.js.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/departments/page.tsx +0 -607
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/layout.d.ts +0 -5
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/layout.d.ts.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/layout.js +0 -7
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/layout.js.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/layout.tsx +0 -9
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/my-projects/[id]/page.d.ts +0 -6
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/my-projects/[id]/page.d.ts.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/my-projects/[id]/page.js +0 -9
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/my-projects/[id]/page.js.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/my-projects/[id]/page.tsx +0 -11
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/my-projects/page.d.ts +0 -2
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/my-projects/page.d.ts.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/my-projects/page.js +0 -321
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/my-projects/page.js.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/my-projects/page.tsx +0 -440
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/my-tasks/page.d.ts +0 -2
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/my-tasks/page.d.ts.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/my-tasks/page.js +0 -939
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/my-tasks/page.js.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/my-tasks/page.tsx +0 -1499
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/async-options-combobox.d.ts +0 -29
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/async-options-combobox.d.ts.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/async-options-combobox.js +0 -95
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/async-options-combobox.js.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/async-options-combobox.tsx +0 -233
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/collaborator-costs-section.d.ts +0 -10
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/collaborator-costs-section.d.ts.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/collaborator-costs-section.js +0 -577
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/collaborator-costs-section.js.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/collaborator-costs-section.tsx +0 -868
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/collaborator-details-screen.d.ts +0 -4
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/collaborator-details-screen.d.ts.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/collaborator-details-screen.js +0 -337
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/collaborator-details-screen.js.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/collaborator-details-screen.tsx +0 -476
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/collaborator-form-screen.d.ts +0 -9
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/collaborator-form-screen.d.ts.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/collaborator-form-screen.js +0 -1348
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/collaborator-form-screen.js.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/collaborator-form-screen.tsx +0 -2233
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/collaborator-select-with-create.d.ts +0 -12
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/collaborator-select-with-create.d.ts.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/collaborator-select-with-create.js +0 -162
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/collaborator-select-with-create.js.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/collaborator-select-with-create.tsx +0 -261
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/contract-content-editor.d.ts +0 -18
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/contract-content-editor.d.ts.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/contract-content-editor.js +0 -145
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/contract-content-editor.js.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/contract-content-editor.tsx +0 -258
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/contract-details-screen.d.ts +0 -4
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/contract-details-screen.d.ts.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/contract-details-screen.js +0 -223
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/contract-details-screen.js.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/contract-details-screen.tsx +0 -342
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/contract-form-screen.d.ts +0 -58
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/contract-form-screen.d.ts.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/contract-form-screen.js +0 -438
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/contract-form-screen.js.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/contract-form-screen.tsx +0 -698
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/department-select-with-create.d.ts +0 -20
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/department-select-with-create.d.ts.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/department-select-with-create.js +0 -233
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/department-select-with-create.js.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/department-select-with-create.tsx +0 -392
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/my-project-summary-screen.d.ts +0 -4
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/my-project-summary-screen.d.ts.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/my-project-summary-screen.js +0 -814
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/my-project-summary-screen.js.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/my-project-summary-screen.tsx +0 -1288
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/operations-calendar-view.d.ts +0 -21
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/operations-calendar-view.d.ts.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/operations-calendar-view.js +0 -174
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/operations-calendar-view.js.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/operations-calendar-view.tsx +0 -306
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/operations-header.d.ts +0 -10
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/operations-header.d.ts.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/operations-header.js +0 -12
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/operations-header.js.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/operations-header.tsx +0 -29
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/person-select-with-create.d.ts +0 -15
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/person-select-with-create.d.ts.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/person-select-with-create.js +0 -501
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/person-select-with-create.js.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/person-select-with-create.tsx +0 -853
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/project-cost-report-screen.d.ts +0 -6
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/project-cost-report-screen.d.ts.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/project-cost-report-screen.js +0 -459
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/project-cost-report-screen.js.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/project-cost-report-screen.tsx +0 -598
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/project-costs-section.d.ts +0 -6
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/project-costs-section.d.ts.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/project-costs-section.js +0 -876
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/project-costs-section.js.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/project-costs-section.tsx +0 -1368
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/project-details-screen.d.ts +0 -4
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/project-details-screen.d.ts.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/project-details-screen.js +0 -2930
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/project-details-screen.js.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/project-details-screen.tsx +0 -4378
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/project-form-screen.d.ts +0 -9
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/project-form-screen.d.ts.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/project-form-screen.js +0 -1013
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/project-form-screen.js.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/project-form-screen.tsx +0 -1745
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/section-card.d.ts +0 -13
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/section-card.d.ts.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/section-card.js +0 -38
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/section-card.js.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/section-card.tsx +0 -74
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/status-badge.d.ts +0 -7
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/status-badge.d.ts.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/status-badge.js +0 -11
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/status-badge.js.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/status-badge.tsx +0 -15
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/system-user-select-with-create.d.ts +0 -18
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/system-user-select-with-create.d.ts.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/system-user-select-with-create.js +0 -406
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/system-user-select-with-create.js.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/system-user-select-with-create.tsx +0 -660
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/task-detail-sheet.d.ts +0 -26
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/task-detail-sheet.d.ts.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/task-detail-sheet.js +0 -332
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/task-detail-sheet.js.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/task-detail-sheet.tsx +0 -518
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/task-file-attachments.d.ts +0 -6
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/task-file-attachments.d.ts.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/task-file-attachments.js +0 -255
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/task-file-attachments.js.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/task-file-attachments.tsx +0 -388
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/timesheet-task-create-sheet.d.ts +0 -10
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/timesheet-task-create-sheet.d.ts.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/timesheet-task-create-sheet.js +0 -131
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/timesheet-task-create-sheet.js.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/timesheet-task-create-sheet.tsx +0 -214
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_lib/api.d.ts +0 -108
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_lib/api.d.ts.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_lib/api.js +0 -162
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_lib/api.js.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_lib/api.ts +0 -428
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_lib/hooks/use-operations-access.d.ts +0 -8
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_lib/hooks/use-operations-access.d.ts.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_lib/hooks/use-operations-access.js +0 -36
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_lib/hooks/use-operations-access.js.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_lib/hooks/use-operations-access.ts +0 -44
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_lib/types.d.ts +0 -837
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_lib/types.d.ts.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_lib/types.js +0 -3
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_lib/types.js.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_lib/types.ts +0 -861
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_lib/utils/format.d.ts +0 -16
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_lib/utils/format.d.ts.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_lib/utils/format.js +0 -182
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_lib/utils/format.js.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_lib/utils/format.ts +0 -250
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_lib/utils/forms.d.ts +0 -4
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_lib/utils/forms.d.ts.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_lib/utils/forms.js +0 -51
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_lib/utils/forms.js.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_lib/utils/forms.ts +0 -61
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/approvals/page.d.ts +0 -2
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/approvals/page.d.ts.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/approvals/page.js +0 -954
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/approvals/page.js.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/approvals/page.tsx +0 -1277
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/collaborator-types/page.d.ts +0 -2
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/collaborator-types/page.d.ts.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/collaborator-types/page.js +0 -488
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/collaborator-types/page.js.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/collaborator-types/page.tsx +0 -805
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/collaborators/[id]/edit/page.d.ts +0 -6
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/collaborators/[id]/edit/page.d.ts.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/collaborators/[id]/edit/page.js +0 -9
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/collaborators/[id]/edit/page.js.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/collaborators/[id]/edit/page.tsx +0 -11
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/collaborators/[id]/page.d.ts +0 -6
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/collaborators/[id]/page.d.ts.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/collaborators/[id]/page.js +0 -9
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/collaborators/[id]/page.js.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/collaborators/[id]/page.tsx +0 -11
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/collaborators/new/page.d.ts +0 -2
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/collaborators/new/page.d.ts.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/collaborators/new/page.js +0 -8
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/collaborators/new/page.js.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/collaborators/new/page.tsx +0 -5
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/collaborators/page.d.ts +0 -2
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/collaborators/page.d.ts.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/collaborators/page.js +0 -612
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/collaborators/page.js.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/collaborators/page.tsx +0 -939
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/contracts/[id]/edit/page.d.ts +0 -6
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/contracts/[id]/edit/page.d.ts.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/contracts/[id]/edit/page.js +0 -9
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/contracts/[id]/edit/page.js.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/contracts/[id]/edit/page.tsx +0 -11
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/contracts/[id]/page.d.ts +0 -6
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/contracts/[id]/page.d.ts.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/contracts/[id]/page.js +0 -9
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/contracts/[id]/page.js.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/contracts/[id]/page.tsx +0 -11
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/contracts/new/page.d.ts +0 -6
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/contracts/new/page.d.ts.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/contracts/new/page.js +0 -9
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/contracts/new/page.js.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/contracts/new/page.tsx +0 -17
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/contracts/page.d.ts +0 -2
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/contracts/page.d.ts.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/contracts/page.js +0 -348
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/contracts/page.js.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/contracts/page.tsx +0 -536
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/departments/page.d.ts +0 -2
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/departments/page.d.ts.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/departments/page.js +0 -401
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/departments/page.js.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/departments/page.tsx +0 -607
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/layout.d.ts +0 -5
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/layout.d.ts.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/layout.js +0 -7
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/layout.js.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/layout.tsx +0 -9
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/my-projects/[id]/page.d.ts +0 -6
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/my-projects/[id]/page.d.ts.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/my-projects/[id]/page.js +0 -9
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/my-projects/[id]/page.js.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/my-projects/[id]/page.tsx +0 -11
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/my-projects/page.d.ts +0 -2
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/my-projects/page.d.ts.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/my-projects/page.js +0 -321
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/my-projects/page.js.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/my-projects/page.tsx +0 -440
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/my-tasks/page.d.ts +0 -2
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/my-tasks/page.d.ts.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/my-tasks/page.js +0 -939
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/my-tasks/page.js.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/my-tasks/page.tsx +0 -1499
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/page.d.ts +0 -2
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/page.d.ts.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/page.js +0 -8
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/page.js.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/page.tsx +0 -5
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/project-cost-categories/page.d.ts +0 -2
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/project-cost-categories/page.d.ts.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/project-cost-categories/page.js +0 -436
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/project-cost-categories/page.js.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/project-cost-categories/page.tsx +0 -675
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/project-cost-types/page.d.ts +0 -2
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/project-cost-types/page.d.ts.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/project-cost-types/page.js +0 -563
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/project-cost-types/page.js.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/project-cost-types/page.tsx +0 -846
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/projects/[id]/costs-report/page.d.ts +0 -6
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/projects/[id]/costs-report/page.d.ts.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/projects/[id]/costs-report/page.js +0 -9
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/projects/[id]/costs-report/page.js.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/projects/[id]/costs-report/page.tsx +0 -10
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/projects/[id]/edit/page.d.ts +0 -6
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/projects/[id]/edit/page.d.ts.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/projects/[id]/edit/page.js +0 -9
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/projects/[id]/edit/page.js.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/projects/[id]/edit/page.tsx +0 -11
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/projects/[id]/page.d.ts +0 -6
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/projects/[id]/page.d.ts.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/projects/[id]/page.js +0 -9
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/projects/[id]/page.js.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/projects/[id]/page.tsx +0 -11
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/projects/new/page.d.ts +0 -2
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/projects/new/page.d.ts.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/projects/new/page.js +0 -8
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/projects/new/page.js.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/projects/new/page.tsx +0 -5
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/projects/page.d.ts +0 -2
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/projects/page.d.ts.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/projects/page.js +0 -492
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/projects/page.js.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/projects/page.tsx +0 -757
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/reports/collaborators/page.d.ts +0 -2
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/reports/collaborators/page.d.ts.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/reports/collaborators/page.js +0 -342
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/reports/collaborators/page.js.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/reports/collaborators/page.tsx +0 -430
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/reports/projects/page.d.ts +0 -2
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/reports/projects/page.d.ts.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/reports/projects/page.js +0 -338
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/reports/projects/page.js.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/reports/projects/page.tsx +0 -428
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/schedule-adjustments/page.d.ts +0 -2
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/schedule-adjustments/page.d.ts.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/schedule-adjustments/page.js +0 -660
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/schedule-adjustments/page.js.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/schedule-adjustments/page.tsx +0 -992
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/time-off/page.d.ts +0 -2
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/time-off/page.d.ts.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/time-off/page.js +0 -515
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/time-off/page.js.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/time-off/page.tsx +0 -707
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/timesheets/page.d.ts +0 -2
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/timesheets/page.d.ts.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/timesheets/page.js +0 -1141
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/timesheets/page.js.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/timesheets/page.tsx +0 -1705
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/page.d.ts +0 -2
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/page.d.ts.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/page.js +0 -8
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/page.js.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/page.tsx +0 -5
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/project-cost-categories/page.d.ts +0 -2
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/project-cost-categories/page.d.ts.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/project-cost-categories/page.js +0 -436
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/project-cost-categories/page.js.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/project-cost-categories/page.tsx +0 -675
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/project-cost-types/page.d.ts +0 -2
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/project-cost-types/page.d.ts.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/project-cost-types/page.js +0 -563
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/project-cost-types/page.js.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/project-cost-types/page.tsx +0 -846
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/projects/[id]/edit/page.d.ts +0 -6
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/projects/[id]/edit/page.d.ts.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/projects/[id]/edit/page.js +0 -9
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/projects/[id]/edit/page.js.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/projects/[id]/edit/page.tsx +0 -11
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/projects/[id]/page.d.ts +0 -6
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/projects/[id]/page.d.ts.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/projects/[id]/page.js +0 -9
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/projects/[id]/page.js.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/projects/[id]/page.tsx +0 -11
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/projects/new/page.d.ts +0 -2
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/projects/new/page.d.ts.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/projects/new/page.js +0 -8
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/projects/new/page.js.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/projects/new/page.tsx +0 -5
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/projects/page.d.ts +0 -2
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/projects/page.d.ts.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/projects/page.js +0 -492
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/projects/page.js.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/projects/page.tsx +0 -757
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/reports/collaborators/page.d.ts +0 -2
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/reports/collaborators/page.d.ts.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/reports/collaborators/page.js +0 -342
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/reports/collaborators/page.js.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/reports/collaborators/page.tsx +0 -430
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/reports/projects/page.d.ts +0 -2
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/reports/projects/page.d.ts.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/reports/projects/page.js +0 -338
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/reports/projects/page.js.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/reports/projects/page.tsx +0 -428
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/schedule-adjustments/page.d.ts +0 -2
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/schedule-adjustments/page.d.ts.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/schedule-adjustments/page.js +0 -660
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/schedule-adjustments/page.js.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/schedule-adjustments/page.tsx +0 -992
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/time-off/page.d.ts +0 -2
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/time-off/page.d.ts.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/time-off/page.js +0 -515
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/time-off/page.js.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/time-off/page.tsx +0 -707
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/timesheets/page.d.ts +0 -2
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/timesheets/page.d.ts.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/timesheets/page.js +0 -1141
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/timesheets/page.js.map +0 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/timesheets/page.tsx +0 -1705
|
@@ -1,2930 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
'use client';
|
|
3
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
4
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
5
|
-
};
|
|
6
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
-
exports.ProjectDetailsScreen = ProjectDetailsScreen;
|
|
8
|
-
const entity_list_1 = require("@/components/entity-list");
|
|
9
|
-
const rich_text_editor_1 = require("@/components/rich-text-editor");
|
|
10
|
-
const avatar_1 = require("@/components/ui/avatar");
|
|
11
|
-
const button_1 = require("@/components/ui/button");
|
|
12
|
-
const card_1 = require("@/components/ui/card");
|
|
13
|
-
const chart_1 = require("@/components/ui/chart");
|
|
14
|
-
const dialog_1 = require("@/components/ui/dialog");
|
|
15
|
-
const dropdown_menu_1 = require("@/components/ui/dropdown-menu");
|
|
16
|
-
const input_1 = require("@/components/ui/input");
|
|
17
|
-
const label_1 = require("@/components/ui/label");
|
|
18
|
-
const progress_1 = require("@/components/ui/progress");
|
|
19
|
-
const select_1 = require("@/components/ui/select");
|
|
20
|
-
const sheet_1 = require("@/components/ui/sheet");
|
|
21
|
-
const skeleton_1 = require("@/components/ui/skeleton");
|
|
22
|
-
const table_1 = require("@/components/ui/table");
|
|
23
|
-
const tooltip_1 = require("@/components/ui/tooltip");
|
|
24
|
-
const core_1 = require("@dnd-kit/core");
|
|
25
|
-
const utilities_1 = require("@dnd-kit/utilities");
|
|
26
|
-
const next_app_provider_1 = require("@hed-hog/next-app-provider");
|
|
27
|
-
const framer_motion_1 = require("framer-motion");
|
|
28
|
-
const lucide_react_1 = require("lucide-react");
|
|
29
|
-
const next_intl_1 = require("next-intl");
|
|
30
|
-
const link_1 = __importDefault(require("next/link"));
|
|
31
|
-
const navigation_1 = require("next/navigation");
|
|
32
|
-
const react_1 = require("react");
|
|
33
|
-
const recharts_1 = require("recharts");
|
|
34
|
-
const api_1 = require("../_lib/api");
|
|
35
|
-
const use_operations_access_1 = require("../_lib/hooks/use-operations-access");
|
|
36
|
-
const format_1 = require("../_lib/utils/format");
|
|
37
|
-
const operations_header_1 = require("./operations-header");
|
|
38
|
-
const project_costs_section_1 = require("./project-costs-section");
|
|
39
|
-
const project_form_screen_1 = require("./project-form-screen");
|
|
40
|
-
const section_card_1 = require("./section-card");
|
|
41
|
-
const status_badge_1 = require("./status-badge");
|
|
42
|
-
const task_detail_sheet_1 = require("./task-detail-sheet");
|
|
43
|
-
const task_file_attachments_1 = require("./task-file-attachments");
|
|
44
|
-
const EMPTY_TASK_FORM = {
|
|
45
|
-
name: '',
|
|
46
|
-
description: '',
|
|
47
|
-
priority: 'medium',
|
|
48
|
-
status: 'todo',
|
|
49
|
-
assigneeCollaboratorId: 'none',
|
|
50
|
-
dueDate: '',
|
|
51
|
-
estimateHours: '',
|
|
52
|
-
tags: '',
|
|
53
|
-
};
|
|
54
|
-
const KANBAN_COLUMNS = [
|
|
55
|
-
{ id: 'todo', label: 'Backlog' },
|
|
56
|
-
{ id: 'doing', label: 'Em execução' },
|
|
57
|
-
{ id: 'review', label: 'Revisão' },
|
|
58
|
-
{ id: 'done', label: 'Concluído' },
|
|
59
|
-
];
|
|
60
|
-
// Prefer pointer-within so any column the cursor enters triggers a drop target.
|
|
61
|
-
// Falls back to closestCenter for the gap between columns.
|
|
62
|
-
const kanbanCollision = (args) => {
|
|
63
|
-
const within = (0, core_1.pointerWithin)(args);
|
|
64
|
-
if (within.length > 0)
|
|
65
|
-
return within;
|
|
66
|
-
return (0, core_1.closestCenter)(args);
|
|
67
|
-
};
|
|
68
|
-
function apiTaskToBoardTask(row) {
|
|
69
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o;
|
|
70
|
-
const status = KANBAN_COLUMNS.some((c) => c.id === row.status)
|
|
71
|
-
? row.status
|
|
72
|
-
: 'todo';
|
|
73
|
-
return {
|
|
74
|
-
id: row.id,
|
|
75
|
-
name: row.name,
|
|
76
|
-
description: (_a = row.description) !== null && _a !== void 0 ? _a : null,
|
|
77
|
-
status,
|
|
78
|
-
priority: (_b = row.priority) !== null && _b !== void 0 ? _b : 'medium',
|
|
79
|
-
dueDate: (_c = row.dueDate) !== null && _c !== void 0 ? _c : null,
|
|
80
|
-
estimateHours: (_d = row.estimateHours) !== null && _d !== void 0 ? _d : null,
|
|
81
|
-
tags: (_e = row.tags) !== null && _e !== void 0 ? _e : null,
|
|
82
|
-
assigneeCollaboratorId: (_f = row.assigneeCollaboratorId) !== null && _f !== void 0 ? _f : null,
|
|
83
|
-
assigneeName: (_g = row.assigneeName) !== null && _g !== void 0 ? _g : null,
|
|
84
|
-
assigneeUserPhotoId: (_h = row.assigneeUserPhotoId) !== null && _h !== void 0 ? _h : null,
|
|
85
|
-
assigneePersonAvatarId: (_j = row.assigneePersonAvatarId) !== null && _j !== void 0 ? _j : null,
|
|
86
|
-
projectAssignmentId: (_k = row.projectAssignmentId) !== null && _k !== void 0 ? _k : null,
|
|
87
|
-
createdAt: (_l = row.createdAt) !== null && _l !== void 0 ? _l : null,
|
|
88
|
-
commentCount: (_m = row.commentCount) !== null && _m !== void 0 ? _m : 0,
|
|
89
|
-
fileCount: (_o = row.fileCount) !== null && _o !== void 0 ? _o : 0,
|
|
90
|
-
};
|
|
91
|
-
}
|
|
92
|
-
function splitTasksByColumn(tasks) {
|
|
93
|
-
return {
|
|
94
|
-
todo: tasks.filter((t) => t.status === 'todo'),
|
|
95
|
-
doing: tasks.filter((t) => t.status === 'doing'),
|
|
96
|
-
review: tasks.filter((t) => t.status === 'review'),
|
|
97
|
-
done: tasks.filter((t) => t.status === 'done'),
|
|
98
|
-
};
|
|
99
|
-
}
|
|
100
|
-
const boardChartConfig = {
|
|
101
|
-
allocation: { label: 'Alocacao', color: 'hsl(201 96% 32%)' },
|
|
102
|
-
loggedHours: { label: 'Horas', color: 'hsl(166 72% 28%)' },
|
|
103
|
-
progress: { label: 'Progresso', color: 'hsl(262 83% 58%)' },
|
|
104
|
-
planned: { label: 'Planejado', color: 'hsl(215 16% 47%)' },
|
|
105
|
-
todo: { label: 'Backlog', color: 'hsl(215 16% 47%)' },
|
|
106
|
-
doing: { label: 'Em execucao', color: 'hsl(201 96% 32%)' },
|
|
107
|
-
review: { label: 'Revisao', color: 'hsl(38 92% 50%)' },
|
|
108
|
-
done: { label: 'Concluido', color: 'hsl(166 72% 28%)' },
|
|
109
|
-
health: { label: 'Saude', color: 'hsl(166 72% 28%)' },
|
|
110
|
-
};
|
|
111
|
-
function taskDragId(taskId) {
|
|
112
|
-
return `task-${taskId}`;
|
|
113
|
-
}
|
|
114
|
-
function columnDropId(columnId) {
|
|
115
|
-
return `col-${columnId}`;
|
|
116
|
-
}
|
|
117
|
-
function parseTaskId(value) {
|
|
118
|
-
if (!value) {
|
|
119
|
-
return null;
|
|
120
|
-
}
|
|
121
|
-
const id = String(value);
|
|
122
|
-
if (!id.startsWith('task-')) {
|
|
123
|
-
return null;
|
|
124
|
-
}
|
|
125
|
-
const parsed = Number(id.slice(5));
|
|
126
|
-
return Number.isFinite(parsed) ? parsed : null;
|
|
127
|
-
}
|
|
128
|
-
function parseColumnId(value) {
|
|
129
|
-
if (!value) {
|
|
130
|
-
return null;
|
|
131
|
-
}
|
|
132
|
-
const id = String(value);
|
|
133
|
-
if (!id.startsWith('col-')) {
|
|
134
|
-
return null;
|
|
135
|
-
}
|
|
136
|
-
const column = id.slice(4);
|
|
137
|
-
return KANBAN_COLUMNS.some((item) => item.id === column)
|
|
138
|
-
? column
|
|
139
|
-
: null;
|
|
140
|
-
}
|
|
141
|
-
function DroppableColumn({ columnId, children, }) {
|
|
142
|
-
const { isOver, setNodeRef } = (0, core_1.useDroppable)({ id: columnDropId(columnId) });
|
|
143
|
-
return <div ref={setNodeRef}>{children(isOver)}</div>;
|
|
144
|
-
}
|
|
145
|
-
function DraggableTaskCard({ task, disabled = false, children, }) {
|
|
146
|
-
const { attributes, listeners, setNodeRef, transform, isDragging } = (0, core_1.useDraggable)({ id: taskDragId(task.id), disabled });
|
|
147
|
-
return (<div ref={setNodeRef} style={{ transform: utilities_1.CSS.Translate.toString(transform) }} {...(disabled ? {} : listeners)} {...(disabled ? {} : attributes)} className={isDragging ? 'z-20' : undefined}>
|
|
148
|
-
{children(disabled ? false : isDragging)}
|
|
149
|
-
</div>);
|
|
150
|
-
}
|
|
151
|
-
function shouldOpenEditSheet(value, projectId) {
|
|
152
|
-
if (!value) {
|
|
153
|
-
return false;
|
|
154
|
-
}
|
|
155
|
-
return value === '1' || value === 'true' || value === String(projectId);
|
|
156
|
-
}
|
|
157
|
-
function getInitials(value) {
|
|
158
|
-
const parts = String(value !== null && value !== void 0 ? value : '')
|
|
159
|
-
.trim()
|
|
160
|
-
.split(/\s+/)
|
|
161
|
-
.filter(Boolean)
|
|
162
|
-
.slice(0, 2);
|
|
163
|
-
if (!parts.length) {
|
|
164
|
-
return '??';
|
|
165
|
-
}
|
|
166
|
-
return parts.map((part) => { var _a, _b; return (_b = (_a = part[0]) === null || _a === void 0 ? void 0 : _a.toUpperCase()) !== null && _b !== void 0 ? _b : ''; }).join('');
|
|
167
|
-
}
|
|
168
|
-
function getPersonAvatarUrl(avatarId) {
|
|
169
|
-
return typeof avatarId === 'number' && avatarId > 0
|
|
170
|
-
? `${process.env.NEXT_PUBLIC_API_BASE_URL}/person/avatar/${avatarId}`
|
|
171
|
-
: '/placeholder.png';
|
|
172
|
-
}
|
|
173
|
-
function getUserPhotoUrl(photoId) {
|
|
174
|
-
return typeof photoId === 'number' && photoId > 0
|
|
175
|
-
? `${process.env.NEXT_PUBLIC_API_BASE_URL}/file/open/${photoId}`
|
|
176
|
-
: null;
|
|
177
|
-
}
|
|
178
|
-
function normalizeDateInputValue(value) {
|
|
179
|
-
if (!value) {
|
|
180
|
-
return '';
|
|
181
|
-
}
|
|
182
|
-
const normalizedValue = String(value).trim();
|
|
183
|
-
const directMatch = normalizedValue.match(/^\d{4}-\d{2}-\d{2}/);
|
|
184
|
-
if (directMatch === null || directMatch === void 0 ? void 0 : directMatch[0]) {
|
|
185
|
-
return directMatch[0];
|
|
186
|
-
}
|
|
187
|
-
const parsedDate = new Date(normalizedValue);
|
|
188
|
-
if (Number.isNaN(parsedDate.getTime())) {
|
|
189
|
-
return '';
|
|
190
|
-
}
|
|
191
|
-
return parsedDate.toISOString().slice(0, 10);
|
|
192
|
-
}
|
|
193
|
-
function clampPercent(value) {
|
|
194
|
-
if (typeof value !== 'number' || Number.isNaN(value)) {
|
|
195
|
-
return 0;
|
|
196
|
-
}
|
|
197
|
-
return Math.max(0, Math.min(100, Math.round(value)));
|
|
198
|
-
}
|
|
199
|
-
function isPastDue(value) {
|
|
200
|
-
if (!value) {
|
|
201
|
-
return false;
|
|
202
|
-
}
|
|
203
|
-
const date = new Date(value);
|
|
204
|
-
if (Number.isNaN(date.getTime())) {
|
|
205
|
-
return false;
|
|
206
|
-
}
|
|
207
|
-
const today = new Date();
|
|
208
|
-
today.setHours(0, 0, 0, 0);
|
|
209
|
-
date.setHours(0, 0, 0, 0);
|
|
210
|
-
return date < today;
|
|
211
|
-
}
|
|
212
|
-
function getTaskProgress(status) {
|
|
213
|
-
const progressByStatus = {
|
|
214
|
-
todo: 12,
|
|
215
|
-
doing: 48,
|
|
216
|
-
review: 76,
|
|
217
|
-
done: 100,
|
|
218
|
-
};
|
|
219
|
-
return progressByStatus[status];
|
|
220
|
-
}
|
|
221
|
-
function getPriorityClassName(priority) {
|
|
222
|
-
if (priority === 'high') {
|
|
223
|
-
return 'border-rose-500/30 bg-rose-500/10 text-rose-700 dark:text-rose-300';
|
|
224
|
-
}
|
|
225
|
-
if (priority === 'medium') {
|
|
226
|
-
return 'border-amber-500/30 bg-amber-500/10 text-amber-700 dark:text-amber-300';
|
|
227
|
-
}
|
|
228
|
-
return 'border-emerald-500/30 bg-emerald-500/10 text-emerald-700 dark:text-emerald-300';
|
|
229
|
-
}
|
|
230
|
-
function getColumnClassName(columnId) {
|
|
231
|
-
const styles = {
|
|
232
|
-
todo: 'from-slate-500/20 via-slate-500/5 to-transparent',
|
|
233
|
-
doing: 'from-sky-500/20 via-cyan-500/5 to-transparent',
|
|
234
|
-
review: 'from-amber-500/20 via-yellow-500/5 to-transparent',
|
|
235
|
-
done: 'from-emerald-500/20 via-green-500/5 to-transparent',
|
|
236
|
-
};
|
|
237
|
-
return styles[columnId];
|
|
238
|
-
}
|
|
239
|
-
function getColumnDotClassName(columnId) {
|
|
240
|
-
const styles = {
|
|
241
|
-
todo: 'bg-slate-500',
|
|
242
|
-
doing: 'bg-sky-500',
|
|
243
|
-
review: 'bg-amber-500',
|
|
244
|
-
done: 'bg-emerald-500',
|
|
245
|
-
};
|
|
246
|
-
return styles[columnId];
|
|
247
|
-
}
|
|
248
|
-
function getTaskTags(task) {
|
|
249
|
-
var _a;
|
|
250
|
-
return String((_a = task.tags) !== null && _a !== void 0 ? _a : '')
|
|
251
|
-
.split(',')
|
|
252
|
-
.map((tag) => tag.trim())
|
|
253
|
-
.filter(Boolean);
|
|
254
|
-
}
|
|
255
|
-
function getTaskCommentCount(task) {
|
|
256
|
-
var _a;
|
|
257
|
-
return (_a = task.commentCount) !== null && _a !== void 0 ? _a : 0;
|
|
258
|
-
}
|
|
259
|
-
function getTaskAttachmentCount(task) {
|
|
260
|
-
var _a;
|
|
261
|
-
return (_a = task.fileCount) !== null && _a !== void 0 ? _a : 0;
|
|
262
|
-
}
|
|
263
|
-
function getAllocationTone(allocation) {
|
|
264
|
-
if (allocation > 100) {
|
|
265
|
-
return {
|
|
266
|
-
labelKey: 'overload',
|
|
267
|
-
text: 'text-rose-700 dark:text-rose-300',
|
|
268
|
-
border: 'border-rose-500/30',
|
|
269
|
-
bg: 'bg-rose-500/10',
|
|
270
|
-
progress: '[&>div]:bg-rose-500',
|
|
271
|
-
icon: lucide_react_1.AlertTriangle,
|
|
272
|
-
};
|
|
273
|
-
}
|
|
274
|
-
if (allocation >= 85) {
|
|
275
|
-
return {
|
|
276
|
-
labelKey: 'high',
|
|
277
|
-
text: 'text-amber-700 dark:text-amber-300',
|
|
278
|
-
border: 'border-amber-500/30',
|
|
279
|
-
bg: 'bg-amber-500/10',
|
|
280
|
-
progress: '[&>div]:bg-amber-500',
|
|
281
|
-
icon: lucide_react_1.Gauge,
|
|
282
|
-
};
|
|
283
|
-
}
|
|
284
|
-
return {
|
|
285
|
-
labelKey: 'available',
|
|
286
|
-
text: 'text-emerald-700 dark:text-emerald-300',
|
|
287
|
-
border: 'border-emerald-500/30',
|
|
288
|
-
bg: 'bg-emerald-500/10',
|
|
289
|
-
progress: '[&>div]:bg-emerald-500',
|
|
290
|
-
icon: lucide_react_1.CheckCircle2,
|
|
291
|
-
};
|
|
292
|
-
}
|
|
293
|
-
function getValidTimestamp(value) {
|
|
294
|
-
if (!value) {
|
|
295
|
-
return null;
|
|
296
|
-
}
|
|
297
|
-
const date = new Date(value);
|
|
298
|
-
if (Number.isNaN(date.getTime())) {
|
|
299
|
-
return null;
|
|
300
|
-
}
|
|
301
|
-
return date.toISOString();
|
|
302
|
-
}
|
|
303
|
-
function formatRelativeTime(value, locale) {
|
|
304
|
-
const date = new Date(value);
|
|
305
|
-
if (Number.isNaN(date.getTime())) {
|
|
306
|
-
return '';
|
|
307
|
-
}
|
|
308
|
-
const diffSeconds = Math.round((date.getTime() - Date.now()) / 1000);
|
|
309
|
-
const units = [
|
|
310
|
-
['year', 60 * 60 * 24 * 365],
|
|
311
|
-
['month', 60 * 60 * 24 * 30],
|
|
312
|
-
['day', 60 * 60 * 24],
|
|
313
|
-
['hour', 60 * 60],
|
|
314
|
-
['minute', 60],
|
|
315
|
-
];
|
|
316
|
-
const formatter = new Intl.RelativeTimeFormat(locale, { numeric: 'auto' });
|
|
317
|
-
for (const [unit, seconds] of units) {
|
|
318
|
-
if (Math.abs(diffSeconds) >= seconds) {
|
|
319
|
-
return formatter.format(Math.round(diffSeconds / seconds), unit);
|
|
320
|
-
}
|
|
321
|
-
}
|
|
322
|
-
return formatter.format(diffSeconds, 'second');
|
|
323
|
-
}
|
|
324
|
-
function getTimelineDayKey(value) {
|
|
325
|
-
const date = new Date(value);
|
|
326
|
-
if (Number.isNaN(date.getTime())) {
|
|
327
|
-
return value;
|
|
328
|
-
}
|
|
329
|
-
return date.toISOString().slice(0, 10);
|
|
330
|
-
}
|
|
331
|
-
function getProjectHealthScore({ progress, averageAllocation, overdueTasks, pendingTimesheets, }) {
|
|
332
|
-
const progressScore = clampPercent(progress);
|
|
333
|
-
const allocation = typeof averageAllocation === 'number' && !Number.isNaN(averageAllocation)
|
|
334
|
-
? Math.round(averageAllocation)
|
|
335
|
-
: 0;
|
|
336
|
-
const allocationPenalty = allocation > 100 ? 16 : allocation > 85 ? 6 : 0;
|
|
337
|
-
const overduePenalty = Math.min(overdueTasks * 9, 32);
|
|
338
|
-
const timesheetPenalty = Math.min(pendingTimesheets * 4, 20);
|
|
339
|
-
const value = clampPercent(72 +
|
|
340
|
-
progressScore * 0.18 -
|
|
341
|
-
allocationPenalty -
|
|
342
|
-
overduePenalty -
|
|
343
|
-
timesheetPenalty);
|
|
344
|
-
if (value >= 75) {
|
|
345
|
-
return { value, labelKey: 'good', tone: 'good' };
|
|
346
|
-
}
|
|
347
|
-
if (value >= 50) {
|
|
348
|
-
return { value, labelKey: 'warning', tone: 'warning' };
|
|
349
|
-
}
|
|
350
|
-
return { value, labelKey: 'danger', tone: 'danger' };
|
|
351
|
-
}
|
|
352
|
-
const kpiToneStyles = {
|
|
353
|
-
positive: {
|
|
354
|
-
accent: 'from-emerald-500/25 via-teal-500/10 to-transparent',
|
|
355
|
-
icon: 'bg-emerald-500/10 text-emerald-700 dark:text-emerald-300',
|
|
356
|
-
value: 'text-emerald-700 dark:text-emerald-300',
|
|
357
|
-
indicator: 'bg-emerald-500',
|
|
358
|
-
trend: 'text-emerald-700 dark:text-emerald-300',
|
|
359
|
-
},
|
|
360
|
-
warning: {
|
|
361
|
-
accent: 'from-amber-500/25 via-yellow-500/10 to-transparent',
|
|
362
|
-
icon: 'bg-amber-500/10 text-amber-700 dark:text-amber-300',
|
|
363
|
-
value: 'text-amber-700 dark:text-amber-300',
|
|
364
|
-
indicator: 'bg-amber-500',
|
|
365
|
-
trend: 'text-amber-700 dark:text-amber-300',
|
|
366
|
-
},
|
|
367
|
-
critical: {
|
|
368
|
-
accent: 'from-rose-500/25 via-red-500/10 to-transparent',
|
|
369
|
-
icon: 'bg-rose-500/10 text-rose-700 dark:text-rose-300',
|
|
370
|
-
value: 'text-rose-700 dark:text-rose-300',
|
|
371
|
-
indicator: 'bg-rose-500',
|
|
372
|
-
trend: 'text-rose-700 dark:text-rose-300',
|
|
373
|
-
},
|
|
374
|
-
info: {
|
|
375
|
-
accent: 'from-sky-500/25 via-cyan-500/10 to-transparent',
|
|
376
|
-
icon: 'bg-sky-500/10 text-sky-700 dark:text-sky-300',
|
|
377
|
-
value: 'text-sky-700 dark:text-sky-300',
|
|
378
|
-
indicator: 'bg-sky-500',
|
|
379
|
-
trend: 'text-sky-700 dark:text-sky-300',
|
|
380
|
-
},
|
|
381
|
-
neutral: {
|
|
382
|
-
accent: 'from-violet-500/25 via-indigo-500/10 to-transparent',
|
|
383
|
-
icon: 'bg-violet-500/10 text-violet-700 dark:text-violet-300',
|
|
384
|
-
value: 'text-foreground',
|
|
385
|
-
indicator: 'bg-violet-500',
|
|
386
|
-
trend: 'text-muted-foreground',
|
|
387
|
-
},
|
|
388
|
-
};
|
|
389
|
-
function ProjectKpiWidget({ item, indicatorLabel, index = 0, }) {
|
|
390
|
-
const Icon = item.icon;
|
|
391
|
-
const tone = kpiToneStyles[item.tone];
|
|
392
|
-
return (<framer_motion_1.motion.div initial={{ opacity: 0, y: 12 }} animate={{ opacity: 1, y: 0 }} transition={{
|
|
393
|
-
type: 'spring',
|
|
394
|
-
stiffness: 340,
|
|
395
|
-
damping: 26,
|
|
396
|
-
delay: index * 0.07,
|
|
397
|
-
}} whileHover={{ y: -4 }} className="min-w-0">
|
|
398
|
-
<card_1.Card className="group relative h-full overflow-hidden border-border/70 bg-card py-0 shadow-xs transition-shadow hover:shadow-md">
|
|
399
|
-
<div className={[
|
|
400
|
-
'absolute inset-x-0 top-0 h-20 bg-linear-to-br',
|
|
401
|
-
tone.accent,
|
|
402
|
-
].join(' ')}/>
|
|
403
|
-
<card_1.CardContent className="relative flex h-full flex-col gap-5 p-4">
|
|
404
|
-
<div className="flex items-start justify-between gap-3">
|
|
405
|
-
<div className={[
|
|
406
|
-
'flex size-10 items-center justify-center rounded-2xl transition-transform group-hover:scale-105',
|
|
407
|
-
tone.icon,
|
|
408
|
-
].join(' ')}>
|
|
409
|
-
<Icon className="size-5"/>
|
|
410
|
-
</div>
|
|
411
|
-
<span className={[
|
|
412
|
-
'rounded-full border bg-background/80 px-2 py-0.5 text-[11px] font-medium',
|
|
413
|
-
tone.trend,
|
|
414
|
-
].join(' ')}>
|
|
415
|
-
{item.trend}
|
|
416
|
-
</span>
|
|
417
|
-
</div>
|
|
418
|
-
|
|
419
|
-
<div className="min-w-0">
|
|
420
|
-
<div className={[
|
|
421
|
-
'truncate text-3xl font-semibold tracking-tight tabular-nums',
|
|
422
|
-
tone.value,
|
|
423
|
-
].join(' ')}>
|
|
424
|
-
{item.value}
|
|
425
|
-
</div>
|
|
426
|
-
<div className="mt-1 text-sm font-medium text-foreground">
|
|
427
|
-
{item.title}
|
|
428
|
-
</div>
|
|
429
|
-
<div className="mt-1 line-clamp-2 text-xs leading-5 text-muted-foreground">
|
|
430
|
-
{item.subtitle}
|
|
431
|
-
</div>
|
|
432
|
-
</div>
|
|
433
|
-
|
|
434
|
-
<div className="mt-auto space-y-2">
|
|
435
|
-
<div className="flex items-center justify-between text-[11px] text-muted-foreground">
|
|
436
|
-
<span>{indicatorLabel}</span>
|
|
437
|
-
<span>{clampPercent(item.indicator)}%</span>
|
|
438
|
-
</div>
|
|
439
|
-
<div className="h-1.5 overflow-hidden rounded-full bg-muted">
|
|
440
|
-
<div className={[
|
|
441
|
-
'h-full rounded-full transition-all duration-500',
|
|
442
|
-
tone.indicator,
|
|
443
|
-
].join(' ')} style={{ width: `${clampPercent(item.indicator)}%` }}/>
|
|
444
|
-
</div>
|
|
445
|
-
</div>
|
|
446
|
-
</card_1.CardContent>
|
|
447
|
-
</card_1.Card>
|
|
448
|
-
</framer_motion_1.motion.div>);
|
|
449
|
-
}
|
|
450
|
-
function ChartEmptyState({ icon: Icon, title, description, }) {
|
|
451
|
-
return (<div className="flex h-72 flex-col items-center justify-center rounded-xl border border-dashed bg-muted/10 p-6 text-center">
|
|
452
|
-
<div className="flex size-11 items-center justify-center rounded-2xl bg-muted text-muted-foreground">
|
|
453
|
-
<Icon className="size-5"/>
|
|
454
|
-
</div>
|
|
455
|
-
<div className="mt-3 text-sm font-medium">{title}</div>
|
|
456
|
-
<div className="mt-1 max-w-xs text-xs leading-5 text-muted-foreground">
|
|
457
|
-
{description}
|
|
458
|
-
</div>
|
|
459
|
-
</div>);
|
|
460
|
-
}
|
|
461
|
-
function ProjectChartCard({ title, description, icon: Icon, metric, children, className, isLoading = false, }) {
|
|
462
|
-
return (<framer_motion_1.motion.div initial={{ opacity: 0, y: 8 }} animate={{ opacity: 1, y: 0 }} transition={{ duration: 0.22 }} className={className}>
|
|
463
|
-
<card_1.Card className="h-full overflow-hidden border-border/70 bg-card py-0 shadow-sm">
|
|
464
|
-
<card_1.CardContent className="flex h-full flex-col gap-4 p-4">
|
|
465
|
-
<div className="flex items-start justify-between gap-4">
|
|
466
|
-
<div className="flex min-w-0 items-start gap-3">
|
|
467
|
-
<div className="flex size-10 shrink-0 items-center justify-center rounded-2xl bg-muted text-foreground">
|
|
468
|
-
<Icon className="size-5"/>
|
|
469
|
-
</div>
|
|
470
|
-
<div className="min-w-0">
|
|
471
|
-
<div className="text-sm font-semibold">{title}</div>
|
|
472
|
-
{description ? (<div className="mt-1 text-xs leading-5 text-muted-foreground">
|
|
473
|
-
{description}
|
|
474
|
-
</div>) : null}
|
|
475
|
-
</div>
|
|
476
|
-
</div>
|
|
477
|
-
{metric ? (<div className="shrink-0 rounded-full border bg-background px-3 py-1 text-xs font-medium text-muted-foreground">
|
|
478
|
-
{metric}
|
|
479
|
-
</div>) : null}
|
|
480
|
-
</div>
|
|
481
|
-
{isLoading ? <skeleton_1.Skeleton className="h-72 rounded-xl"/> : children}
|
|
482
|
-
</card_1.CardContent>
|
|
483
|
-
</card_1.Card>
|
|
484
|
-
</framer_motion_1.motion.div>);
|
|
485
|
-
}
|
|
486
|
-
function ProjectDetailsSkeleton() {
|
|
487
|
-
return (<entity_list_1.Page>
|
|
488
|
-
<div className="space-y-6">
|
|
489
|
-
{/* Hero header */}
|
|
490
|
-
<div className="overflow-hidden rounded-3xl border bg-card shadow-sm">
|
|
491
|
-
<div className="border-b p-5 sm:p-6">
|
|
492
|
-
<div className="space-y-4">
|
|
493
|
-
{/* Breadcrumb */}
|
|
494
|
-
<div className="flex items-center gap-2">
|
|
495
|
-
<skeleton_1.Skeleton className="h-4 w-20 rounded-full"/>
|
|
496
|
-
<skeleton_1.Skeleton className="h-3 w-3 rounded-full"/>
|
|
497
|
-
<skeleton_1.Skeleton className="h-4 w-16 rounded-full"/>
|
|
498
|
-
<skeleton_1.Skeleton className="h-3 w-3 rounded-full"/>
|
|
499
|
-
<skeleton_1.Skeleton className="h-4 w-32 rounded-full"/>
|
|
500
|
-
</div>
|
|
501
|
-
{/* Title row */}
|
|
502
|
-
<div className="flex items-start gap-4">
|
|
503
|
-
<skeleton_1.Skeleton className="size-14 shrink-0 rounded-2xl"/>
|
|
504
|
-
<div className="flex-1 space-y-2">
|
|
505
|
-
<div className="flex gap-2">
|
|
506
|
-
<skeleton_1.Skeleton className="h-6 w-20 rounded-full"/>
|
|
507
|
-
<skeleton_1.Skeleton className="h-6 w-16 rounded-full"/>
|
|
508
|
-
</div>
|
|
509
|
-
<skeleton_1.Skeleton className="h-8 w-72"/>
|
|
510
|
-
<skeleton_1.Skeleton className="h-4 w-full max-w-md"/>
|
|
511
|
-
</div>
|
|
512
|
-
<div className="hidden flex-shrink-0 gap-2 lg:flex">
|
|
513
|
-
<skeleton_1.Skeleton className="h-9 w-20 rounded-lg"/>
|
|
514
|
-
<skeleton_1.Skeleton className="h-9 w-28 rounded-lg"/>
|
|
515
|
-
<skeleton_1.Skeleton className="h-9 w-9 rounded-lg"/>
|
|
516
|
-
</div>
|
|
517
|
-
</div>
|
|
518
|
-
{/* Meta grid */}
|
|
519
|
-
<div className="grid gap-3 md:grid-cols-2 xl:grid-cols-7">
|
|
520
|
-
<skeleton_1.Skeleton className="h-16 rounded-xl xl:col-span-2"/>
|
|
521
|
-
<skeleton_1.Skeleton className="h-16 rounded-xl"/>
|
|
522
|
-
<skeleton_1.Skeleton className="h-16 rounded-xl"/>
|
|
523
|
-
<skeleton_1.Skeleton className="h-16 rounded-xl"/>
|
|
524
|
-
<skeleton_1.Skeleton className="h-16 rounded-xl"/>
|
|
525
|
-
<skeleton_1.Skeleton className="h-16 rounded-xl"/>
|
|
526
|
-
</div>
|
|
527
|
-
{/* Team row */}
|
|
528
|
-
<div className="rounded-2xl border p-4">
|
|
529
|
-
<div className="flex items-center justify-between gap-4">
|
|
530
|
-
<div className="flex items-center gap-3">
|
|
531
|
-
<div className="space-y-1">
|
|
532
|
-
<skeleton_1.Skeleton className="h-3 w-12"/>
|
|
533
|
-
<skeleton_1.Skeleton className="h-5 w-24"/>
|
|
534
|
-
</div>
|
|
535
|
-
<div className="flex -space-x-2">
|
|
536
|
-
{Array.from({ length: 4 }).map((_, i) => (<skeleton_1.Skeleton key={i} className="size-10 rounded-full border-2 border-background"/>))}
|
|
537
|
-
</div>
|
|
538
|
-
</div>
|
|
539
|
-
<div className="grid grid-cols-3 gap-3">
|
|
540
|
-
<skeleton_1.Skeleton className="h-16 w-28 rounded-xl"/>
|
|
541
|
-
<skeleton_1.Skeleton className="h-16 w-28 rounded-xl"/>
|
|
542
|
-
<skeleton_1.Skeleton className="h-16 w-28 rounded-xl"/>
|
|
543
|
-
</div>
|
|
544
|
-
</div>
|
|
545
|
-
</div>
|
|
546
|
-
</div>
|
|
547
|
-
</div>
|
|
548
|
-
</div>
|
|
549
|
-
|
|
550
|
-
{/* KPI row */}
|
|
551
|
-
<div className="rounded-3xl border p-3 sm:p-4">
|
|
552
|
-
<div className="grid gap-3 sm:grid-cols-2 lg:grid-cols-3 2xl:grid-cols-6">
|
|
553
|
-
{Array.from({ length: 6 }).map((_, i) => (<div key={i} className="overflow-hidden rounded-xl border p-4">
|
|
554
|
-
<div className="flex items-start justify-between gap-3">
|
|
555
|
-
<skeleton_1.Skeleton className="size-10 rounded-2xl"/>
|
|
556
|
-
<skeleton_1.Skeleton className="h-5 w-16 rounded-full"/>
|
|
557
|
-
</div>
|
|
558
|
-
<div className="mt-5 space-y-2">
|
|
559
|
-
<skeleton_1.Skeleton className="h-8 w-24"/>
|
|
560
|
-
<skeleton_1.Skeleton className="h-4 w-32"/>
|
|
561
|
-
<skeleton_1.Skeleton className="h-3 w-full"/>
|
|
562
|
-
</div>
|
|
563
|
-
<div className="mt-auto pt-4 space-y-2">
|
|
564
|
-
<div className="flex justify-between">
|
|
565
|
-
<skeleton_1.Skeleton className="h-3 w-16"/>
|
|
566
|
-
<skeleton_1.Skeleton className="h-3 w-8"/>
|
|
567
|
-
</div>
|
|
568
|
-
<skeleton_1.Skeleton className="h-1.5 w-full rounded-full"/>
|
|
569
|
-
</div>
|
|
570
|
-
</div>))}
|
|
571
|
-
</div>
|
|
572
|
-
</div>
|
|
573
|
-
|
|
574
|
-
{/* Overview */}
|
|
575
|
-
<div className="rounded-xl border p-4">
|
|
576
|
-
<skeleton_1.Skeleton className="mb-4 h-5 w-28"/>
|
|
577
|
-
<div className="grid gap-3 sm:grid-cols-2 xl:grid-cols-3">
|
|
578
|
-
{Array.from({ length: 9 }).map((_, i) => (<div key={i} className="space-y-1.5">
|
|
579
|
-
<skeleton_1.Skeleton className="h-3 w-20"/>
|
|
580
|
-
<skeleton_1.Skeleton className="h-5 w-32"/>
|
|
581
|
-
</div>))}
|
|
582
|
-
</div>
|
|
583
|
-
<div className="mt-6 space-y-1.5">
|
|
584
|
-
<skeleton_1.Skeleton className="h-3 w-16"/>
|
|
585
|
-
<div className="grid gap-3 sm:grid-cols-2 xl:grid-cols-3">
|
|
586
|
-
{Array.from({ length: 4 }).map((_, i) => (<div key={i} className="space-y-1.5">
|
|
587
|
-
<skeleton_1.Skeleton className="h-3 w-24"/>
|
|
588
|
-
<skeleton_1.Skeleton className="h-5 w-36"/>
|
|
589
|
-
</div>))}
|
|
590
|
-
</div>
|
|
591
|
-
</div>
|
|
592
|
-
</div>
|
|
593
|
-
|
|
594
|
-
{/* Charts */}
|
|
595
|
-
<div className="rounded-3xl border p-4">
|
|
596
|
-
<skeleton_1.Skeleton className="mb-4 h-5 w-36"/>
|
|
597
|
-
<div className="grid gap-4 xl:grid-cols-12">
|
|
598
|
-
<skeleton_1.Skeleton className="h-80 rounded-xl xl:col-span-8"/>
|
|
599
|
-
<skeleton_1.Skeleton className="h-80 rounded-xl xl:col-span-4"/>
|
|
600
|
-
<skeleton_1.Skeleton className="h-72 rounded-xl xl:col-span-5"/>
|
|
601
|
-
<skeleton_1.Skeleton className="h-72 rounded-xl xl:col-span-4"/>
|
|
602
|
-
<skeleton_1.Skeleton className="h-72 rounded-xl xl:col-span-3"/>
|
|
603
|
-
</div>
|
|
604
|
-
</div>
|
|
605
|
-
|
|
606
|
-
{/* Kanban */}
|
|
607
|
-
<div className="rounded-3xl border p-4">
|
|
608
|
-
<div className="mb-4 flex items-center justify-between">
|
|
609
|
-
<skeleton_1.Skeleton className="h-5 w-28"/>
|
|
610
|
-
<skeleton_1.Skeleton className="h-9 w-28 rounded-lg"/>
|
|
611
|
-
</div>
|
|
612
|
-
<div className="mb-4 rounded-2xl border p-3">
|
|
613
|
-
<div className="flex gap-3">
|
|
614
|
-
<skeleton_1.Skeleton className="h-10 flex-1 rounded-lg"/>
|
|
615
|
-
<skeleton_1.Skeleton className="h-10 w-44 rounded-lg"/>
|
|
616
|
-
<skeleton_1.Skeleton className="h-10 w-44 rounded-lg"/>
|
|
617
|
-
</div>
|
|
618
|
-
</div>
|
|
619
|
-
<div className="grid gap-4 xl:grid-cols-4">
|
|
620
|
-
{Array.from({ length: 4 }).map((_, col) => (<div key={col} className="min-h-48 rounded-3xl border p-3 space-y-3">
|
|
621
|
-
<div className="rounded-2xl border bg-background/85 p-3 flex items-center justify-between">
|
|
622
|
-
<div className="space-y-1">
|
|
623
|
-
<div className="flex items-center gap-2">
|
|
624
|
-
<skeleton_1.Skeleton className="size-2.5 rounded-full"/>
|
|
625
|
-
<skeleton_1.Skeleton className="h-4 w-20"/>
|
|
626
|
-
</div>
|
|
627
|
-
<skeleton_1.Skeleton className="h-3 w-12"/>
|
|
628
|
-
</div>
|
|
629
|
-
<skeleton_1.Skeleton className="size-5 rounded-full"/>
|
|
630
|
-
</div>
|
|
631
|
-
{Array.from({ length: col === 0 ? 3 : col === 1 ? 2 : 1 }).map((_, card) => (<div key={card} className="rounded-2xl border bg-card p-3 space-y-3">
|
|
632
|
-
<div className="flex items-start justify-between gap-2">
|
|
633
|
-
<div className="flex-1 space-y-1">
|
|
634
|
-
<skeleton_1.Skeleton className="h-4 w-full"/>
|
|
635
|
-
<skeleton_1.Skeleton className="h-3 w-3/4"/>
|
|
636
|
-
</div>
|
|
637
|
-
<skeleton_1.Skeleton className="h-5 w-12 rounded-full"/>
|
|
638
|
-
</div>
|
|
639
|
-
<div className="grid grid-cols-2 gap-2">
|
|
640
|
-
<skeleton_1.Skeleton className="h-8 rounded-xl"/>
|
|
641
|
-
<skeleton_1.Skeleton className="h-8 rounded-xl"/>
|
|
642
|
-
</div>
|
|
643
|
-
<div className="space-y-1.5">
|
|
644
|
-
<skeleton_1.Skeleton className="h-1.5 w-full rounded-full"/>
|
|
645
|
-
</div>
|
|
646
|
-
<div className="flex items-center justify-between border-t pt-3">
|
|
647
|
-
<div className="flex items-center gap-2">
|
|
648
|
-
<skeleton_1.Skeleton className="size-7 rounded-full"/>
|
|
649
|
-
<skeleton_1.Skeleton className="h-3 w-20"/>
|
|
650
|
-
</div>
|
|
651
|
-
<div className="flex gap-2">
|
|
652
|
-
<skeleton_1.Skeleton className="h-3 w-6"/>
|
|
653
|
-
<skeleton_1.Skeleton className="h-3 w-6"/>
|
|
654
|
-
</div>
|
|
655
|
-
</div>
|
|
656
|
-
</div>))}
|
|
657
|
-
</div>))}
|
|
658
|
-
</div>
|
|
659
|
-
</div>
|
|
660
|
-
|
|
661
|
-
{/* Timeline */}
|
|
662
|
-
<div className="rounded-3xl border p-4">
|
|
663
|
-
<skeleton_1.Skeleton className="mb-4 h-5 w-24"/>
|
|
664
|
-
<div className="rounded-3xl border p-4 space-y-6">
|
|
665
|
-
{Array.from({ length: 3 }).map((_, group) => (<div key={group} className="space-y-3">
|
|
666
|
-
<skeleton_1.Skeleton className="h-6 w-28 rounded-full"/>
|
|
667
|
-
{Array.from({ length: 2 }).map((_, event) => (<div key={event} className="grid grid-cols-[2rem_1fr] gap-3">
|
|
668
|
-
<div className="flex flex-col items-center">
|
|
669
|
-
<skeleton_1.Skeleton className="size-8 rounded-full"/>
|
|
670
|
-
{event === 0 ? (<div className="w-px flex-1 bg-border mt-1"/>) : null}
|
|
671
|
-
</div>
|
|
672
|
-
<div className="pb-5">
|
|
673
|
-
<div className="rounded-2xl border p-4 space-y-3">
|
|
674
|
-
<div className="flex justify-between">
|
|
675
|
-
<div className="space-y-1.5">
|
|
676
|
-
<skeleton_1.Skeleton className="h-4 w-40"/>
|
|
677
|
-
<skeleton_1.Skeleton className="h-3 w-56"/>
|
|
678
|
-
</div>
|
|
679
|
-
<skeleton_1.Skeleton className="h-3 w-16"/>
|
|
680
|
-
</div>
|
|
681
|
-
<div className="flex items-center gap-2 border-t pt-3">
|
|
682
|
-
<skeleton_1.Skeleton className="size-7 rounded-full"/>
|
|
683
|
-
<skeleton_1.Skeleton className="h-3 w-24"/>
|
|
684
|
-
</div>
|
|
685
|
-
</div>
|
|
686
|
-
</div>
|
|
687
|
-
</div>))}
|
|
688
|
-
</div>))}
|
|
689
|
-
</div>
|
|
690
|
-
</div>
|
|
691
|
-
</div>
|
|
692
|
-
</entity_list_1.Page>);
|
|
693
|
-
}
|
|
694
|
-
function ProjectDetailsScreen({ projectId }) {
|
|
695
|
-
var _a, _b, _c, _d, _e;
|
|
696
|
-
const t = (0, next_intl_1.useTranslations)('operations.ProjectDetailsPage');
|
|
697
|
-
const commonT = (0, next_intl_1.useTranslations)('operations.Common');
|
|
698
|
-
const formT = (0, next_intl_1.useTranslations)('operations.ProjectFormPage');
|
|
699
|
-
const contractT = (0, next_intl_1.useTranslations)('operations.ContractFormPage');
|
|
700
|
-
const { request, currentLocaleCode, getSettingValue } = (0, next_app_provider_1.useApp)();
|
|
701
|
-
const access = (0, use_operations_access_1.useOperationsAccess)();
|
|
702
|
-
const isLimitedView = !access.isDirector && !access.isSupervisor;
|
|
703
|
-
const router = (0, navigation_1.useRouter)();
|
|
704
|
-
const pathname = (0, navigation_1.usePathname)();
|
|
705
|
-
const searchParams = (0, navigation_1.useSearchParams)();
|
|
706
|
-
const getProjectStatusLabel = (value) => {
|
|
707
|
-
if (!value)
|
|
708
|
-
return commonT('labels.notAvailable');
|
|
709
|
-
try {
|
|
710
|
-
return formT(`options.statuses.${value}`);
|
|
711
|
-
}
|
|
712
|
-
catch (_a) {
|
|
713
|
-
return (0, format_1.formatEnumLabel)(value);
|
|
714
|
-
}
|
|
715
|
-
};
|
|
716
|
-
const getContractStatusLabel = (value) => {
|
|
717
|
-
if (!value)
|
|
718
|
-
return commonT('labels.notAvailable');
|
|
719
|
-
try {
|
|
720
|
-
return contractT(`options.statuses.${value}`);
|
|
721
|
-
}
|
|
722
|
-
catch (_a) {
|
|
723
|
-
return (0, format_1.formatEnumLabel)(value);
|
|
724
|
-
}
|
|
725
|
-
};
|
|
726
|
-
const getContractCategoryLabel = (value) => {
|
|
727
|
-
if (!value)
|
|
728
|
-
return commonT('labels.notAvailable');
|
|
729
|
-
try {
|
|
730
|
-
return contractT(`options.contractCategories.${value}`);
|
|
731
|
-
}
|
|
732
|
-
catch (_a) {
|
|
733
|
-
return (0, format_1.formatEnumLabel)(value);
|
|
734
|
-
}
|
|
735
|
-
};
|
|
736
|
-
const getContractTypeLabel = (value) => {
|
|
737
|
-
if (!value)
|
|
738
|
-
return commonT('labels.notAvailable');
|
|
739
|
-
try {
|
|
740
|
-
return contractT(`options.contractTypes.${value}`);
|
|
741
|
-
}
|
|
742
|
-
catch (_a) {
|
|
743
|
-
return (0, format_1.formatEnumLabel)(value);
|
|
744
|
-
}
|
|
745
|
-
};
|
|
746
|
-
const getSignatureStatusLabel = (value) => {
|
|
747
|
-
if (!value)
|
|
748
|
-
return commonT('labels.notAvailable');
|
|
749
|
-
try {
|
|
750
|
-
return contractT(`options.signatureStatuses.${value}`);
|
|
751
|
-
}
|
|
752
|
-
catch (_a) {
|
|
753
|
-
return (0, format_1.formatEnumLabel)(value);
|
|
754
|
-
}
|
|
755
|
-
};
|
|
756
|
-
const isEditSheetOpen = (0, react_1.useMemo)(() => !isLimitedView &&
|
|
757
|
-
shouldOpenEditSheet(searchParams.get('edit'), projectId), [isLimitedView, projectId, searchParams]);
|
|
758
|
-
const updateSheetQuery = (open) => {
|
|
759
|
-
const params = new URLSearchParams(searchParams.toString());
|
|
760
|
-
if (open) {
|
|
761
|
-
params.set('edit', '1');
|
|
762
|
-
}
|
|
763
|
-
else {
|
|
764
|
-
params.delete('edit');
|
|
765
|
-
}
|
|
766
|
-
const query = params.toString();
|
|
767
|
-
router.replace(query ? `${pathname}?${query}` : pathname, {
|
|
768
|
-
scroll: false,
|
|
769
|
-
});
|
|
770
|
-
};
|
|
771
|
-
const openEditSheet = () => {
|
|
772
|
-
updateSheetQuery(true);
|
|
773
|
-
};
|
|
774
|
-
const closeEditSheet = () => {
|
|
775
|
-
updateSheetQuery(false);
|
|
776
|
-
};
|
|
777
|
-
const getDeliveryModelLabel = (value) => {
|
|
778
|
-
if (!value) {
|
|
779
|
-
return commonT('labels.notAvailable');
|
|
780
|
-
}
|
|
781
|
-
try {
|
|
782
|
-
return formT(`options.deliveryModels.${value}`);
|
|
783
|
-
}
|
|
784
|
-
catch (_a) {
|
|
785
|
-
return (0, format_1.formatEnumLabel)(value);
|
|
786
|
-
}
|
|
787
|
-
};
|
|
788
|
-
const getBillingModelLabel = (value) => {
|
|
789
|
-
if (!value) {
|
|
790
|
-
return commonT('labels.notAvailable');
|
|
791
|
-
}
|
|
792
|
-
try {
|
|
793
|
-
return formT(`options.billingModels.${value}`);
|
|
794
|
-
}
|
|
795
|
-
catch (_a) {
|
|
796
|
-
return (0, format_1.formatEnumLabel)(value);
|
|
797
|
-
}
|
|
798
|
-
};
|
|
799
|
-
const getTaskPriorityLabel = (value) => {
|
|
800
|
-
var _a;
|
|
801
|
-
const labels = currentLocaleCode.startsWith('pt')
|
|
802
|
-
? { low: 'Baixa', medium: 'Média', high: 'Alta' }
|
|
803
|
-
: { low: 'Low', medium: 'Medium', high: 'High' };
|
|
804
|
-
return (_a = labels[value]) !== null && _a !== void 0 ? _a : (0, format_1.formatEnumLabel)(value);
|
|
805
|
-
};
|
|
806
|
-
const { data: project, refetch, isLoading: isProjectLoading, } = (0, next_app_provider_1.useQuery)({
|
|
807
|
-
queryKey: ['operations-project-details', currentLocaleCode, projectId],
|
|
808
|
-
queryFn: () => (0, api_1.fetchOperations)(request, `/operations/projects/${projectId}`),
|
|
809
|
-
});
|
|
810
|
-
const { data: rawTasks = [], refetch: refetchTasks, isLoading: isTasksLoading, } = (0, next_app_provider_1.useQuery)({
|
|
811
|
-
queryKey: ['operations-project-board-tasks', projectId],
|
|
812
|
-
queryFn: () => (0, api_1.fetchOperations)(request, `/operations/projects/${projectId}/tasks`),
|
|
813
|
-
enabled: Boolean(project),
|
|
814
|
-
});
|
|
815
|
-
const { data: archivedTasksResponse, refetch: refetchArchivedTasks } = (0, next_app_provider_1.useQuery)({
|
|
816
|
-
queryKey: ['operations-project-archived-tasks', projectId],
|
|
817
|
-
queryFn: () => (0, api_1.fetchOperations)(request, `/operations/tasks?projectId=${projectId}&pageSize=100&sortField=createdAt&sortOrder=desc&archived=true`),
|
|
818
|
-
enabled: Boolean(project),
|
|
819
|
-
});
|
|
820
|
-
const { data: projectStats, isLoading: isProjectStatsLoading } = (0, next_app_provider_1.useQuery)({
|
|
821
|
-
queryKey: ['operations-project-stats', projectId],
|
|
822
|
-
queryFn: () => (0, api_1.fetchOperations)(request, `/operations/projects/${projectId}/stats`),
|
|
823
|
-
enabled: Boolean(project) && !isLimitedView,
|
|
824
|
-
});
|
|
825
|
-
const [boardState, setBoardState] = (0, react_1.useState)(null);
|
|
826
|
-
const [selectedTask, setSelectedTask] = (0, react_1.useState)(null);
|
|
827
|
-
const [taskFormOpen, setTaskFormOpen] = (0, react_1.useState)(false);
|
|
828
|
-
const [editingTaskId, setEditingTaskId] = (0, react_1.useState)(null);
|
|
829
|
-
const [taskFormData, setTaskFormData] = (0, react_1.useState)(EMPTY_TASK_FORM);
|
|
830
|
-
const [taskFormLoading, setTaskFormLoading] = (0, react_1.useState)(false);
|
|
831
|
-
const [deletePromptTask, setDeletePromptTask] = (0, react_1.useState)(null);
|
|
832
|
-
const [inlineCreateColumn, setInlineCreateColumn] = (0, react_1.useState)(null);
|
|
833
|
-
const [inlineCreateName, setInlineCreateName] = (0, react_1.useState)('');
|
|
834
|
-
const [inlineCreateLoading, setInlineCreateLoading] = (0, react_1.useState)(false);
|
|
835
|
-
const [boardSearch, setBoardSearch] = (0, react_1.useState)('');
|
|
836
|
-
const [boardPriorityFilter, setBoardPriorityFilter] = (0, react_1.useState)('all');
|
|
837
|
-
const [boardGroupMode, setBoardGroupMode] = (0, react_1.useState)('status');
|
|
838
|
-
const [timelineTypeFilter, setTimelineTypeFilter] = (0, react_1.useState)('all');
|
|
839
|
-
const [timelineVisibleCount, setTimelineVisibleCount] = (0, react_1.useState)(8);
|
|
840
|
-
const [archivingTaskId, setArchivingTaskId] = (0, react_1.useState)(null);
|
|
841
|
-
const [restoringTaskId, setRestoringTaskId] = (0, react_1.useState)(null);
|
|
842
|
-
const [deletingTaskId, setDeletingTaskId] = (0, react_1.useState)(null);
|
|
843
|
-
const [activeDragTask, setActiveDragTask] = (0, react_1.useState)(null);
|
|
844
|
-
const apiTasks = (0, react_1.useMemo)(() => rawTasks.map(apiTaskToBoardTask), [rawTasks]);
|
|
845
|
-
const archivedTasks = (0, react_1.useMemo)(() => {
|
|
846
|
-
var _a;
|
|
847
|
-
return ((_a = archivedTasksResponse === null || archivedTasksResponse === void 0 ? void 0 : archivedTasksResponse.data) !== null && _a !== void 0 ? _a : []).filter((task) => Boolean(task.deletedAt));
|
|
848
|
-
}, [archivedTasksResponse]);
|
|
849
|
-
const taskColumns = (0, react_1.useMemo)(() => {
|
|
850
|
-
if (project && (boardState === null || boardState === void 0 ? void 0 : boardState.projectId) === project.id) {
|
|
851
|
-
return boardState.columns;
|
|
852
|
-
}
|
|
853
|
-
return splitTasksByColumn(apiTasks);
|
|
854
|
-
}, [project, boardState, apiTasks]);
|
|
855
|
-
const filteredTaskColumns = (0, react_1.useMemo)(() => {
|
|
856
|
-
const normalizedSearch = boardSearch.trim().toLocaleLowerCase();
|
|
857
|
-
const filterTask = (task) => {
|
|
858
|
-
const matchesSearch = !normalizedSearch ||
|
|
859
|
-
[
|
|
860
|
-
task.name,
|
|
861
|
-
task.description,
|
|
862
|
-
task.assigneeName,
|
|
863
|
-
task.tags,
|
|
864
|
-
task.priority,
|
|
865
|
-
]
|
|
866
|
-
.filter(Boolean)
|
|
867
|
-
.some((value) => String(value).toLocaleLowerCase().includes(normalizedSearch));
|
|
868
|
-
const matchesPriority = boardPriorityFilter === 'all' || task.priority === boardPriorityFilter;
|
|
869
|
-
return matchesSearch && matchesPriority;
|
|
870
|
-
};
|
|
871
|
-
return {
|
|
872
|
-
todo: taskColumns.todo.filter(filterTask),
|
|
873
|
-
doing: taskColumns.doing.filter(filterTask),
|
|
874
|
-
review: taskColumns.review.filter(filterTask),
|
|
875
|
-
done: taskColumns.done.filter(filterTask),
|
|
876
|
-
};
|
|
877
|
-
}, [boardPriorityFilter, boardSearch, taskColumns]);
|
|
878
|
-
const taskAssigneeOptions = (0, react_1.useMemo)(() => {
|
|
879
|
-
var _a;
|
|
880
|
-
const seen = new Set();
|
|
881
|
-
return ((_a = project === null || project === void 0 ? void 0 : project.assignments.filter((assignment) => {
|
|
882
|
-
if (!assignment.collaboratorId ||
|
|
883
|
-
seen.has(assignment.collaboratorId)) {
|
|
884
|
-
return false;
|
|
885
|
-
}
|
|
886
|
-
seen.add(assignment.collaboratorId);
|
|
887
|
-
return true;
|
|
888
|
-
}).map((assignment) => ({
|
|
889
|
-
id: String(assignment.collaboratorId),
|
|
890
|
-
label: assignment.collaboratorName,
|
|
891
|
-
}))) !== null && _a !== void 0 ? _a : []);
|
|
892
|
-
}, [project]);
|
|
893
|
-
const openCreateTaskForm = (0, react_1.useCallback)((defaultStatus = 'todo') => {
|
|
894
|
-
setEditingTaskId(null);
|
|
895
|
-
setTaskFormData(Object.assign(Object.assign({}, EMPTY_TASK_FORM), { status: defaultStatus }));
|
|
896
|
-
setTaskFormOpen(true);
|
|
897
|
-
}, []);
|
|
898
|
-
const openEditTaskForm = (0, react_1.useCallback)((task) => {
|
|
899
|
-
var _a, _b;
|
|
900
|
-
setEditingTaskId(task.id);
|
|
901
|
-
setTaskFormData({
|
|
902
|
-
name: task.name,
|
|
903
|
-
description: (_a = task.description) !== null && _a !== void 0 ? _a : '',
|
|
904
|
-
priority: task.priority,
|
|
905
|
-
status: task.status,
|
|
906
|
-
assigneeCollaboratorId: task.assigneeCollaboratorId
|
|
907
|
-
? String(task.assigneeCollaboratorId)
|
|
908
|
-
: 'none',
|
|
909
|
-
dueDate: normalizeDateInputValue(task.dueDate),
|
|
910
|
-
estimateHours: task.estimateHours != null ? String(task.estimateHours) : '',
|
|
911
|
-
tags: (_b = task.tags) !== null && _b !== void 0 ? _b : '',
|
|
912
|
-
});
|
|
913
|
-
setSelectedTask(null);
|
|
914
|
-
setTaskFormOpen(true);
|
|
915
|
-
}, []);
|
|
916
|
-
const handleTaskFormSubmit = (0, react_1.useCallback)(async () => {
|
|
917
|
-
if (!taskFormData.name.trim())
|
|
918
|
-
return;
|
|
919
|
-
setTaskFormLoading(true);
|
|
920
|
-
try {
|
|
921
|
-
const payload = {
|
|
922
|
-
name: taskFormData.name.trim(),
|
|
923
|
-
description: taskFormData.description || null,
|
|
924
|
-
priority: taskFormData.priority,
|
|
925
|
-
status: taskFormData.status,
|
|
926
|
-
assigneeCollaboratorId: taskFormData.assigneeCollaboratorId !== 'none'
|
|
927
|
-
? Number(taskFormData.assigneeCollaboratorId)
|
|
928
|
-
: null,
|
|
929
|
-
dueDate: taskFormData.dueDate || null,
|
|
930
|
-
estimateHours: taskFormData.estimateHours
|
|
931
|
-
? Number(taskFormData.estimateHours)
|
|
932
|
-
: null,
|
|
933
|
-
tags: taskFormData.tags || null,
|
|
934
|
-
};
|
|
935
|
-
if (editingTaskId) {
|
|
936
|
-
await (0, api_1.mutateOperations)(request, `/operations/tasks/${editingTaskId}`, 'PATCH', payload);
|
|
937
|
-
}
|
|
938
|
-
else {
|
|
939
|
-
await (0, api_1.mutateOperations)(request, '/operations/tasks', 'POST', Object.assign({ projectId }, payload));
|
|
940
|
-
}
|
|
941
|
-
setBoardState(null);
|
|
942
|
-
await refetchTasks();
|
|
943
|
-
await refetchArchivedTasks();
|
|
944
|
-
setTaskFormOpen(false);
|
|
945
|
-
setEditingTaskId(null);
|
|
946
|
-
setTaskFormData(EMPTY_TASK_FORM);
|
|
947
|
-
}
|
|
948
|
-
finally {
|
|
949
|
-
setTaskFormLoading(false);
|
|
950
|
-
}
|
|
951
|
-
}, [
|
|
952
|
-
taskFormData,
|
|
953
|
-
editingTaskId,
|
|
954
|
-
projectId,
|
|
955
|
-
request,
|
|
956
|
-
refetchTasks,
|
|
957
|
-
refetchArchivedTasks,
|
|
958
|
-
]);
|
|
959
|
-
const handleArchiveTask = (0, react_1.useCallback)(async (taskId) => {
|
|
960
|
-
setArchivingTaskId(taskId);
|
|
961
|
-
try {
|
|
962
|
-
await (0, api_1.mutateOperations)(request, `/operations/tasks/${taskId}`, 'PATCH', {
|
|
963
|
-
archived: true,
|
|
964
|
-
});
|
|
965
|
-
setBoardState(null);
|
|
966
|
-
setSelectedTask(null);
|
|
967
|
-
await refetchTasks();
|
|
968
|
-
await refetchArchivedTasks();
|
|
969
|
-
}
|
|
970
|
-
catch (_a) {
|
|
971
|
-
// ignore
|
|
972
|
-
}
|
|
973
|
-
finally {
|
|
974
|
-
setArchivingTaskId(null);
|
|
975
|
-
}
|
|
976
|
-
}, [request, refetchTasks, refetchArchivedTasks]);
|
|
977
|
-
const handleRestoreTask = (0, react_1.useCallback)(async (taskId) => {
|
|
978
|
-
setRestoringTaskId(taskId);
|
|
979
|
-
try {
|
|
980
|
-
await (0, api_1.mutateOperations)(request, `/operations/tasks/${taskId}`, 'PATCH', {
|
|
981
|
-
archived: false,
|
|
982
|
-
});
|
|
983
|
-
setSelectedTask(null);
|
|
984
|
-
await refetchTasks();
|
|
985
|
-
await refetchArchivedTasks();
|
|
986
|
-
}
|
|
987
|
-
catch (_a) {
|
|
988
|
-
// ignore
|
|
989
|
-
}
|
|
990
|
-
finally {
|
|
991
|
-
setRestoringTaskId(null);
|
|
992
|
-
}
|
|
993
|
-
}, [request, refetchTasks, refetchArchivedTasks]);
|
|
994
|
-
const handleInlineCreateTask = (0, react_1.useCallback)(async (column, name) => {
|
|
995
|
-
const trimmed = name.trim();
|
|
996
|
-
if (!trimmed) {
|
|
997
|
-
setInlineCreateColumn(null);
|
|
998
|
-
setInlineCreateName('');
|
|
999
|
-
return;
|
|
1000
|
-
}
|
|
1001
|
-
setInlineCreateLoading(true);
|
|
1002
|
-
try {
|
|
1003
|
-
await (0, api_1.mutateOperations)(request, '/operations/tasks', 'POST', {
|
|
1004
|
-
projectId,
|
|
1005
|
-
name: trimmed,
|
|
1006
|
-
status: column,
|
|
1007
|
-
priority: 'medium',
|
|
1008
|
-
});
|
|
1009
|
-
setBoardState(null);
|
|
1010
|
-
setInlineCreateColumn(null);
|
|
1011
|
-
setInlineCreateName('');
|
|
1012
|
-
await refetchTasks();
|
|
1013
|
-
}
|
|
1014
|
-
finally {
|
|
1015
|
-
setInlineCreateLoading(false);
|
|
1016
|
-
}
|
|
1017
|
-
}, [projectId, request, refetchTasks]);
|
|
1018
|
-
const handleDeleteTask = (0, react_1.useCallback)(async (taskId) => {
|
|
1019
|
-
setDeletingTaskId(taskId);
|
|
1020
|
-
try {
|
|
1021
|
-
await (0, api_1.mutateOperations)(request, `/operations/tasks/${taskId}?permanent=true`, 'DELETE');
|
|
1022
|
-
setBoardState(null);
|
|
1023
|
-
setSelectedTask(null);
|
|
1024
|
-
setDeletePromptTask(null);
|
|
1025
|
-
await refetchTasks();
|
|
1026
|
-
await refetchArchivedTasks();
|
|
1027
|
-
}
|
|
1028
|
-
catch (_a) {
|
|
1029
|
-
// ignore
|
|
1030
|
-
}
|
|
1031
|
-
finally {
|
|
1032
|
-
setDeletingTaskId(null);
|
|
1033
|
-
}
|
|
1034
|
-
}, [request, refetchTasks, refetchArchivedTasks]);
|
|
1035
|
-
const allocationChartData = (0, react_1.useMemo)(() => {
|
|
1036
|
-
var _a;
|
|
1037
|
-
if ((_a = projectStats === null || projectStats === void 0 ? void 0 : projectStats.allocationByCollaborator) === null || _a === void 0 ? void 0 : _a.length) {
|
|
1038
|
-
return projectStats.allocationByCollaborator;
|
|
1039
|
-
}
|
|
1040
|
-
if (!project) {
|
|
1041
|
-
return [];
|
|
1042
|
-
}
|
|
1043
|
-
return project.assignments.slice(0, 6).map((assignment) => ({
|
|
1044
|
-
name: getInitials(assignment.collaboratorName),
|
|
1045
|
-
allocation: typeof assignment.allocationPercent === 'number'
|
|
1046
|
-
? Math.round(assignment.allocationPercent)
|
|
1047
|
-
: 0,
|
|
1048
|
-
}));
|
|
1049
|
-
}, [project, projectStats]);
|
|
1050
|
-
const sensors = (0, core_1.useSensors)((0, core_1.useSensor)(core_1.PointerSensor, {
|
|
1051
|
-
activationConstraint: { distance: 6 },
|
|
1052
|
-
}));
|
|
1053
|
-
const velocityChartData = (0, react_1.useMemo)(() => {
|
|
1054
|
-
var _a;
|
|
1055
|
-
if ((_a = projectStats === null || projectStats === void 0 ? void 0 : projectStats.weeklyVelocity) === null || _a === void 0 ? void 0 : _a.length) {
|
|
1056
|
-
return projectStats.weeklyVelocity.map((row) => ({
|
|
1057
|
-
week: row.weekLabel,
|
|
1058
|
-
loggedHours: row.loggedHours,
|
|
1059
|
-
completedTasks: 0,
|
|
1060
|
-
}));
|
|
1061
|
-
}
|
|
1062
|
-
return [];
|
|
1063
|
-
}, [projectStats]);
|
|
1064
|
-
const findColumnByTask = (0, react_1.useCallback)((taskId) => {
|
|
1065
|
-
var _a;
|
|
1066
|
-
const match = KANBAN_COLUMNS.find((column) => taskColumns[column.id].some((task) => task.id === taskId));
|
|
1067
|
-
return (_a = match === null || match === void 0 ? void 0 : match.id) !== null && _a !== void 0 ? _a : null;
|
|
1068
|
-
}, [taskColumns]);
|
|
1069
|
-
const moveTaskToColumn = (0, react_1.useCallback)((taskId, targetColumn) => {
|
|
1070
|
-
const originColumn = findColumnByTask(taskId);
|
|
1071
|
-
if (!originColumn || originColumn === targetColumn) {
|
|
1072
|
-
return;
|
|
1073
|
-
}
|
|
1074
|
-
const sourceTask = taskColumns[originColumn].find((task) => task.id === taskId);
|
|
1075
|
-
if (!sourceTask || !project) {
|
|
1076
|
-
return;
|
|
1077
|
-
}
|
|
1078
|
-
// Optimistic update
|
|
1079
|
-
setBoardState({
|
|
1080
|
-
projectId: project.id,
|
|
1081
|
-
columns: Object.assign(Object.assign({}, taskColumns), { [originColumn]: taskColumns[originColumn].filter((task) => task.id !== taskId), [targetColumn]: [
|
|
1082
|
-
Object.assign(Object.assign({}, sourceTask), { status: targetColumn }),
|
|
1083
|
-
...taskColumns[targetColumn],
|
|
1084
|
-
] }),
|
|
1085
|
-
});
|
|
1086
|
-
// Persist to API
|
|
1087
|
-
(0, api_1.mutateOperations)(request, `/operations/tasks/${taskId}`, 'PATCH', {
|
|
1088
|
-
status: targetColumn,
|
|
1089
|
-
}).catch(() => {
|
|
1090
|
-
// Rollback optimistic update on error
|
|
1091
|
-
setBoardState(null);
|
|
1092
|
-
void refetchTasks();
|
|
1093
|
-
});
|
|
1094
|
-
}, [findColumnByTask, taskColumns, project, request, refetchTasks]);
|
|
1095
|
-
const onBoardDragStart = (event) => {
|
|
1096
|
-
var _a;
|
|
1097
|
-
const taskId = parseTaskId(event.active.id);
|
|
1098
|
-
if (!taskId)
|
|
1099
|
-
return;
|
|
1100
|
-
const col = findColumnByTask(taskId);
|
|
1101
|
-
if (!col)
|
|
1102
|
-
return;
|
|
1103
|
-
const task = (_a = taskColumns[col].find((t) => t.id === taskId)) !== null && _a !== void 0 ? _a : null;
|
|
1104
|
-
setActiveDragTask(task);
|
|
1105
|
-
};
|
|
1106
|
-
const onBoardDragEnd = (event) => {
|
|
1107
|
-
var _a;
|
|
1108
|
-
setActiveDragTask(null);
|
|
1109
|
-
const taskId = parseTaskId(event.active.id);
|
|
1110
|
-
const targetColumn = parseColumnId((_a = event.over) === null || _a === void 0 ? void 0 : _a.id);
|
|
1111
|
-
if (!taskId || !targetColumn) {
|
|
1112
|
-
return;
|
|
1113
|
-
}
|
|
1114
|
-
moveTaskToColumn(taskId, targetColumn);
|
|
1115
|
-
};
|
|
1116
|
-
const timelineEvents = (0, react_1.useMemo)(() => {
|
|
1117
|
-
if (!project) {
|
|
1118
|
-
return [];
|
|
1119
|
-
}
|
|
1120
|
-
const events = [];
|
|
1121
|
-
const projectStart = getValidTimestamp(project.startDate);
|
|
1122
|
-
const projectEnd = getValidTimestamp(project.endDate);
|
|
1123
|
-
if (projectStart) {
|
|
1124
|
-
events.push({
|
|
1125
|
-
id: `project-start-${project.id}`,
|
|
1126
|
-
type: 'status',
|
|
1127
|
-
title: t('timeline.projectStarted'),
|
|
1128
|
-
description: t('timeline.projectStartedDescription', {
|
|
1129
|
-
project: project.name,
|
|
1130
|
-
}),
|
|
1131
|
-
timestamp: projectStart,
|
|
1132
|
-
actorName: project.managerName,
|
|
1133
|
-
actorAvatarId: project.managerAvatarId,
|
|
1134
|
-
icon: lucide_react_1.Rocket,
|
|
1135
|
-
toneClassName: 'bg-sky-500 text-white',
|
|
1136
|
-
});
|
|
1137
|
-
}
|
|
1138
|
-
if (projectEnd) {
|
|
1139
|
-
events.push({
|
|
1140
|
-
id: `project-deadline-${project.id}`,
|
|
1141
|
-
type: 'status',
|
|
1142
|
-
title: t('timeline.targetDate'),
|
|
1143
|
-
description: t('timeline.targetDateDescription'),
|
|
1144
|
-
timestamp: projectEnd,
|
|
1145
|
-
actorName: project.managerName,
|
|
1146
|
-
actorAvatarId: project.managerAvatarId,
|
|
1147
|
-
icon: lucide_react_1.CalendarClock,
|
|
1148
|
-
toneClassName: isPastDue(project.endDate)
|
|
1149
|
-
? 'bg-rose-500 text-white'
|
|
1150
|
-
: 'bg-violet-500 text-white',
|
|
1151
|
-
});
|
|
1152
|
-
}
|
|
1153
|
-
apiTasks.forEach((task) => {
|
|
1154
|
-
var _a, _b, _c, _d;
|
|
1155
|
-
const taskCreatedAt = (_b = (_a = getValidTimestamp(task.createdAt)) !== null && _a !== void 0 ? _a : getValidTimestamp(task.dueDate)) !== null && _b !== void 0 ? _b : projectStart;
|
|
1156
|
-
const actorName = task.assigneeName || project.managerName;
|
|
1157
|
-
if (taskCreatedAt) {
|
|
1158
|
-
events.push({
|
|
1159
|
-
id: `task-created-${task.id}`,
|
|
1160
|
-
type: 'task',
|
|
1161
|
-
title: t('timeline.taskCreated'),
|
|
1162
|
-
description: task.name,
|
|
1163
|
-
timestamp: taskCreatedAt,
|
|
1164
|
-
actorName,
|
|
1165
|
-
actorAvatarId: task.assigneePersonAvatarId,
|
|
1166
|
-
actorUserPhotoId: task.assigneeUserPhotoId,
|
|
1167
|
-
icon: lucide_react_1.Plus,
|
|
1168
|
-
toneClassName: 'bg-slate-500 text-white',
|
|
1169
|
-
});
|
|
1170
|
-
}
|
|
1171
|
-
if (task.status === 'done') {
|
|
1172
|
-
events.push({
|
|
1173
|
-
id: `task-done-${task.id}`,
|
|
1174
|
-
type: 'status',
|
|
1175
|
-
title: t('timeline.taskCompleted'),
|
|
1176
|
-
description: task.name,
|
|
1177
|
-
timestamp: (_d = (_c = getValidTimestamp(task.dueDate)) !== null && _c !== void 0 ? _c : taskCreatedAt) !== null && _d !== void 0 ? _d : new Date().toISOString(),
|
|
1178
|
-
actorName,
|
|
1179
|
-
actorAvatarId: task.assigneePersonAvatarId,
|
|
1180
|
-
actorUserPhotoId: task.assigneeUserPhotoId,
|
|
1181
|
-
icon: lucide_react_1.CheckCircle2,
|
|
1182
|
-
toneClassName: 'bg-emerald-500 text-white',
|
|
1183
|
-
});
|
|
1184
|
-
}
|
|
1185
|
-
if (task.description) {
|
|
1186
|
-
events.push({
|
|
1187
|
-
id: `task-comment-${task.id}`,
|
|
1188
|
-
type: 'comment',
|
|
1189
|
-
title: t('timeline.commentAdded'),
|
|
1190
|
-
description: task.name,
|
|
1191
|
-
timestamp: taskCreatedAt !== null && taskCreatedAt !== void 0 ? taskCreatedAt : new Date().toISOString(),
|
|
1192
|
-
actorName,
|
|
1193
|
-
actorAvatarId: task.assigneePersonAvatarId,
|
|
1194
|
-
actorUserPhotoId: task.assigneeUserPhotoId,
|
|
1195
|
-
icon: lucide_react_1.MessageSquare,
|
|
1196
|
-
toneClassName: 'bg-indigo-500 text-white',
|
|
1197
|
-
});
|
|
1198
|
-
}
|
|
1199
|
-
});
|
|
1200
|
-
if (project.timesheetSummary.totalTimesheets > 0) {
|
|
1201
|
-
events.push({
|
|
1202
|
-
id: `timesheets-${project.id}`,
|
|
1203
|
-
type: 'timesheet',
|
|
1204
|
-
title: t('timeline.timesheetLogged'),
|
|
1205
|
-
description: t('timeline.timesheetLoggedDescription', {
|
|
1206
|
-
count: project.timesheetSummary.totalTimesheets,
|
|
1207
|
-
hours: (0, format_1.formatHours)(project.timesheetSummary.totalHours),
|
|
1208
|
-
}),
|
|
1209
|
-
timestamp: new Date().toISOString(),
|
|
1210
|
-
actorName: project.managerName,
|
|
1211
|
-
actorAvatarId: project.managerAvatarId,
|
|
1212
|
-
icon: lucide_react_1.Timer,
|
|
1213
|
-
toneClassName: 'bg-cyan-500 text-white',
|
|
1214
|
-
});
|
|
1215
|
-
}
|
|
1216
|
-
if (project.timesheetSummary.pendingTimesheets > 0) {
|
|
1217
|
-
events.push({
|
|
1218
|
-
id: `approvals-${project.id}`,
|
|
1219
|
-
type: 'approval',
|
|
1220
|
-
title: t('timeline.approvalPending'),
|
|
1221
|
-
description: t('timeline.approvalPendingDescription', {
|
|
1222
|
-
count: project.timesheetSummary.pendingTimesheets,
|
|
1223
|
-
}),
|
|
1224
|
-
timestamp: new Date().toISOString(),
|
|
1225
|
-
actorName: project.managerName,
|
|
1226
|
-
actorAvatarId: project.managerAvatarId,
|
|
1227
|
-
icon: lucide_react_1.GitCommitHorizontal,
|
|
1228
|
-
toneClassName: 'bg-amber-500 text-white',
|
|
1229
|
-
});
|
|
1230
|
-
}
|
|
1231
|
-
return events.sort((a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime());
|
|
1232
|
-
}, [apiTasks, project, t]);
|
|
1233
|
-
if (isProjectLoading) {
|
|
1234
|
-
return <ProjectDetailsSkeleton />;
|
|
1235
|
-
}
|
|
1236
|
-
if (!project) {
|
|
1237
|
-
return (<entity_list_1.Page>
|
|
1238
|
-
<operations_header_1.OperationsHeader title={t('title')} description={t('description')} current={t('breadcrumb')}/>
|
|
1239
|
-
<entity_list_1.EmptyState icon={<lucide_react_1.FolderKanban className="size-12"/>} title={commonT('states.emptyTitle')} description={t('notFound')} actionLabel={commonT('actions.refresh')} onAction={() => void refetch()}/>
|
|
1240
|
-
</entity_list_1.Page>);
|
|
1241
|
-
}
|
|
1242
|
-
const totalTasks = apiTasks.length;
|
|
1243
|
-
const completedTasks = taskColumns.done.length;
|
|
1244
|
-
const pendingTasks = totalTasks - completedTasks;
|
|
1245
|
-
const activeCollaborators = project.operationalIndicators.activeAssignments ||
|
|
1246
|
-
project.assignments.filter((assignment) => assignment.status === 'active')
|
|
1247
|
-
.length ||
|
|
1248
|
-
project.assignments.length;
|
|
1249
|
-
const overdueTasks = apiTasks.filter((task) => task.status !== 'done' && isPastDue(task.dueDate)).length;
|
|
1250
|
-
const projectProgress = clampPercent(project.progressPercent);
|
|
1251
|
-
const taskProgress = totalTasks > 0 ? Math.round((completedTasks / totalTasks) * 100) : 0;
|
|
1252
|
-
const displayedProgress = projectProgress || taskProgress;
|
|
1253
|
-
const averageAllocation = clampPercent(project.operationalIndicators.averageAllocation);
|
|
1254
|
-
const weeklyVelocity = (_e = (_c = (_b = (_a = projectStats === null || projectStats === void 0 ? void 0 : projectStats.weeklyVelocity) === null || _a === void 0 ? void 0 : _a.at(-1)) === null || _b === void 0 ? void 0 : _b.loggedHours) !== null && _c !== void 0 ? _c : (_d = projectStats === null || projectStats === void 0 ? void 0 : projectStats.quickRadar) === null || _d === void 0 ? void 0 : _d.totalWeeklyHours) !== null && _e !== void 0 ? _e : project.operationalIndicators.totalWeeklyHours;
|
|
1255
|
-
const projectHealth = getProjectHealthScore({
|
|
1256
|
-
progress: displayedProgress,
|
|
1257
|
-
averageAllocation,
|
|
1258
|
-
overdueTasks,
|
|
1259
|
-
pendingTimesheets: project.timesheetSummary.pendingTimesheets,
|
|
1260
|
-
});
|
|
1261
|
-
const projectHealthLabel = projectHealth.labelKey === 'good'
|
|
1262
|
-
? t('health.good')
|
|
1263
|
-
: projectHealth.labelKey === 'warning'
|
|
1264
|
-
? t('health.warning')
|
|
1265
|
-
: t('health.danger');
|
|
1266
|
-
const projectHealthTrend = projectHealth.labelKey === 'good'
|
|
1267
|
-
? t('kpi.trends.health.good')
|
|
1268
|
-
: projectHealth.labelKey === 'warning'
|
|
1269
|
-
? t('kpi.trends.health.warning')
|
|
1270
|
-
: t('kpi.trends.health.danger');
|
|
1271
|
-
const teamPreview = project.assignments.slice(0, 5);
|
|
1272
|
-
const hiddenTeamCount = Math.max(project.assignments.length - teamPreview.length, 0);
|
|
1273
|
-
const overloadedAssignments = project.assignments.filter((assignment) => { var _a; return ((_a = assignment.allocationPercent) !== null && _a !== void 0 ? _a : 0) > 100; }).length;
|
|
1274
|
-
const highAllocationAssignments = project.assignments.filter((assignment) => {
|
|
1275
|
-
var _a;
|
|
1276
|
-
const allocation = (_a = assignment.allocationPercent) !== null && _a !== void 0 ? _a : 0;
|
|
1277
|
-
return allocation >= 85 && allocation <= 100;
|
|
1278
|
-
}).length;
|
|
1279
|
-
const availableAssignments = project.assignments.filter((assignment) => { var _a; return ((_a = assignment.allocationPercent) !== null && _a !== void 0 ? _a : 0) < 85; }).length;
|
|
1280
|
-
const burnupChartData = velocityChartData.length > 0
|
|
1281
|
-
? velocityChartData.reduce((items, row, index) => {
|
|
1282
|
-
var _a, _b, _c;
|
|
1283
|
-
const previous = (_b = (_a = items[index - 1]) === null || _a === void 0 ? void 0 : _a.loggedHours) !== null && _b !== void 0 ? _b : 0;
|
|
1284
|
-
const loggedHours = previous + Number((_c = row.loggedHours) !== null && _c !== void 0 ? _c : 0);
|
|
1285
|
-
const planned = project.operationalIndicators.totalWeeklyHours > 0
|
|
1286
|
-
? project.operationalIndicators.totalWeeklyHours * (index + 1)
|
|
1287
|
-
: loggedHours;
|
|
1288
|
-
items.push({ week: row.week, loggedHours, planned });
|
|
1289
|
-
return items;
|
|
1290
|
-
}, [])
|
|
1291
|
-
: [
|
|
1292
|
-
{ week: t('charts.start'), loggedHours: 0, planned: 0 },
|
|
1293
|
-
{
|
|
1294
|
-
week: t('charts.current'),
|
|
1295
|
-
loggedHours: project.timesheetSummary.totalHours,
|
|
1296
|
-
planned: project.operationalIndicators.totalWeeklyHours ||
|
|
1297
|
-
project.timesheetSummary.totalHours,
|
|
1298
|
-
},
|
|
1299
|
-
];
|
|
1300
|
-
const taskDistributionData = KANBAN_COLUMNS.map((column) => ({
|
|
1301
|
-
key: column.id,
|
|
1302
|
-
name: column.label,
|
|
1303
|
-
value: taskColumns[column.id].length,
|
|
1304
|
-
fill: `var(--color-${column.id})`,
|
|
1305
|
-
})).filter((item) => item.value > 0);
|
|
1306
|
-
const healthChartData = [
|
|
1307
|
-
{
|
|
1308
|
-
name: t('charts.healthScore'),
|
|
1309
|
-
value: projectHealth.value,
|
|
1310
|
-
fill: projectHealth.tone === 'danger'
|
|
1311
|
-
? 'hsl(0 84% 60%)'
|
|
1312
|
-
: projectHealth.tone === 'warning'
|
|
1313
|
-
? 'hsl(38 92% 50%)'
|
|
1314
|
-
: 'var(--color-health)',
|
|
1315
|
-
},
|
|
1316
|
-
];
|
|
1317
|
-
const chartDashboardLoading = isProjectStatsLoading || isTasksLoading;
|
|
1318
|
-
const filteredTimelineEvents = timelineEvents.filter((event) => timelineTypeFilter === 'all' || event.type === timelineTypeFilter);
|
|
1319
|
-
const visibleTimelineEvents = filteredTimelineEvents.slice(0, timelineVisibleCount);
|
|
1320
|
-
const groupedTimelineEvents = visibleTimelineEvents.reduce((groups, event) => {
|
|
1321
|
-
const dayKey = getTimelineDayKey(event.timestamp);
|
|
1322
|
-
const currentGroup = groups[groups.length - 1];
|
|
1323
|
-
if ((currentGroup === null || currentGroup === void 0 ? void 0 : currentGroup.dayKey) === dayKey) {
|
|
1324
|
-
currentGroup.events.push(event);
|
|
1325
|
-
}
|
|
1326
|
-
else {
|
|
1327
|
-
groups.push({ dayKey, events: [event] });
|
|
1328
|
-
}
|
|
1329
|
-
return groups;
|
|
1330
|
-
}, []);
|
|
1331
|
-
const allocationTone = project.operationalIndicators.averageAllocation > 100
|
|
1332
|
-
? 'critical'
|
|
1333
|
-
: project.operationalIndicators.averageAllocation > 85
|
|
1334
|
-
? 'warning'
|
|
1335
|
-
: 'positive';
|
|
1336
|
-
const pendingTasksTone = overdueTasks > 0 ? 'critical' : pendingTasks > 0 ? 'warning' : 'positive';
|
|
1337
|
-
const velocityTone = weeklyVelocity > 0 ? 'positive' : 'info';
|
|
1338
|
-
const kpiWidgets = [
|
|
1339
|
-
{
|
|
1340
|
-
key: 'hours',
|
|
1341
|
-
title: t('cards.loggedHours'),
|
|
1342
|
-
value: (0, format_1.formatHours)(project.timesheetSummary.totalHours),
|
|
1343
|
-
subtitle: t('cards.loggedHoursDescription'),
|
|
1344
|
-
trend: t('kpi.trends.hours', {
|
|
1345
|
-
count: project.timesheetSummary.totalTimesheets,
|
|
1346
|
-
}),
|
|
1347
|
-
indicator: Math.min(project.timesheetSummary.totalHours, 100),
|
|
1348
|
-
icon: lucide_react_1.Timer,
|
|
1349
|
-
tone: 'info',
|
|
1350
|
-
},
|
|
1351
|
-
{
|
|
1352
|
-
key: 'health',
|
|
1353
|
-
title: t('cards.projectHealth'),
|
|
1354
|
-
value: projectHealthLabel,
|
|
1355
|
-
subtitle: t('kpi.subtitles.health'),
|
|
1356
|
-
trend: projectHealthTrend,
|
|
1357
|
-
indicator: projectHealth.value,
|
|
1358
|
-
icon: lucide_react_1.HeartPulse,
|
|
1359
|
-
tone: projectHealth.tone === 'danger'
|
|
1360
|
-
? 'critical'
|
|
1361
|
-
: projectHealth.tone === 'warning'
|
|
1362
|
-
? 'warning'
|
|
1363
|
-
: 'positive',
|
|
1364
|
-
},
|
|
1365
|
-
{
|
|
1366
|
-
key: 'velocity',
|
|
1367
|
-
title: t('cards.weeklyVelocity'),
|
|
1368
|
-
value: (0, format_1.formatHours)(weeklyVelocity),
|
|
1369
|
-
subtitle: t('cards.weeklyVelocityDescription'),
|
|
1370
|
-
trend: weeklyVelocity > 0
|
|
1371
|
-
? t('kpi.trends.velocity.active')
|
|
1372
|
-
: t('kpi.trends.velocity.empty'),
|
|
1373
|
-
indicator: Math.min(weeklyVelocity, 100),
|
|
1374
|
-
icon: lucide_react_1.TrendingUp,
|
|
1375
|
-
tone: velocityTone,
|
|
1376
|
-
},
|
|
1377
|
-
{
|
|
1378
|
-
key: 'allocation',
|
|
1379
|
-
title: t('cards.allocation'),
|
|
1380
|
-
value: (0, format_1.formatPercent)(project.operationalIndicators.averageAllocation),
|
|
1381
|
-
subtitle: t('cards.allocationDescription'),
|
|
1382
|
-
trend: allocationTone === 'critical'
|
|
1383
|
-
? t('kpi.trends.allocation.critical')
|
|
1384
|
-
: allocationTone === 'warning'
|
|
1385
|
-
? t('kpi.trends.allocation.warning')
|
|
1386
|
-
: t('kpi.trends.allocation.good'),
|
|
1387
|
-
indicator: averageAllocation,
|
|
1388
|
-
icon: lucide_react_1.Gauge,
|
|
1389
|
-
tone: allocationTone,
|
|
1390
|
-
},
|
|
1391
|
-
{
|
|
1392
|
-
key: 'pendingTasks',
|
|
1393
|
-
title: t('cards.pendingTasks'),
|
|
1394
|
-
value: pendingTasks,
|
|
1395
|
-
subtitle: t('cards.pendingTasksDescription', { overdue: overdueTasks }),
|
|
1396
|
-
trend: pendingTasksTone === 'critical'
|
|
1397
|
-
? t('kpi.trends.tasks.critical', { count: overdueTasks })
|
|
1398
|
-
: pendingTasksTone === 'warning'
|
|
1399
|
-
? t('kpi.trends.tasks.warning')
|
|
1400
|
-
: t('kpi.trends.tasks.good'),
|
|
1401
|
-
indicator: totalTasks > 0 ? Math.round((pendingTasks / totalTasks) * 100) : 0,
|
|
1402
|
-
icon: lucide_react_1.ClipboardList,
|
|
1403
|
-
tone: pendingTasksTone,
|
|
1404
|
-
},
|
|
1405
|
-
{
|
|
1406
|
-
key: 'activeCollaborators',
|
|
1407
|
-
title: t('cards.activeCollaborators'),
|
|
1408
|
-
value: activeCollaborators,
|
|
1409
|
-
subtitle: t('cards.activeCollaboratorsDescription'),
|
|
1410
|
-
trend: activeCollaborators > 0
|
|
1411
|
-
? t('kpi.trends.collaborators.active')
|
|
1412
|
-
: t('kpi.trends.collaborators.empty'),
|
|
1413
|
-
indicator: project.assignments.length > 0
|
|
1414
|
-
? Math.round((activeCollaborators / project.assignments.length) * 100)
|
|
1415
|
-
: 0,
|
|
1416
|
-
icon: lucide_react_1.Users,
|
|
1417
|
-
tone: activeCollaborators > 0 ? 'positive' : 'warning',
|
|
1418
|
-
},
|
|
1419
|
-
];
|
|
1420
|
-
return (<entity_list_1.Page>
|
|
1421
|
-
<framer_motion_1.motion.section initial={{ opacity: 0, y: 10 }} animate={{ opacity: 1, y: 0 }} transition={{ duration: 0.25 }} className="overflow-hidden rounded-3xl border bg-card shadow-sm">
|
|
1422
|
-
<div className="relative overflow-hidden border-b bg-linear-to-br from-muted/70 via-background to-background p-5 sm:p-6">
|
|
1423
|
-
<div className="absolute inset-x-0 top-0 h-px bg-linear-to-r from-transparent via-primary/40 to-transparent"/>
|
|
1424
|
-
<div className="flex flex-col gap-6">
|
|
1425
|
-
<div className="flex flex-col gap-4 lg:flex-row lg:items-start lg:justify-between">
|
|
1426
|
-
<div className="min-w-0 space-y-4">
|
|
1427
|
-
<nav aria-label="Breadcrumb" className="flex min-w-0 flex-wrap items-center gap-1.5 text-xs text-muted-foreground">
|
|
1428
|
-
<link_1.default href="/operations/projects" className="transition hover:text-foreground">
|
|
1429
|
-
{t('breadcrumbTrail.operations')}
|
|
1430
|
-
</link_1.default>
|
|
1431
|
-
<lucide_react_1.ChevronRight className="size-3.5"/>
|
|
1432
|
-
<link_1.default href="/operations/projects" className="transition hover:text-foreground">
|
|
1433
|
-
{t('breadcrumbTrail.projects')}
|
|
1434
|
-
</link_1.default>
|
|
1435
|
-
<lucide_react_1.ChevronRight className="size-3.5"/>
|
|
1436
|
-
<span className="max-w-[12rem] truncate font-medium text-foreground sm:max-w-md">
|
|
1437
|
-
{project.code || project.name}
|
|
1438
|
-
</span>
|
|
1439
|
-
</nav>
|
|
1440
|
-
|
|
1441
|
-
<div className="flex min-w-0 items-start gap-4">
|
|
1442
|
-
<div className="flex size-14 shrink-0 items-center justify-center rounded-2xl border bg-background shadow-xs">
|
|
1443
|
-
<lucide_react_1.FolderKanban className="size-7 text-primary"/>
|
|
1444
|
-
</div>
|
|
1445
|
-
<div className="min-w-0 space-y-2">
|
|
1446
|
-
<div className="flex flex-wrap items-center gap-2">
|
|
1447
|
-
<span className="rounded-full border bg-background px-3 py-1 text-xs font-medium text-muted-foreground">
|
|
1448
|
-
{project.code || commonT('labels.notAvailable')}
|
|
1449
|
-
</span>
|
|
1450
|
-
<status_badge_1.StatusBadge label={getProjectStatusLabel(project.status)} className={(0, format_1.getStatusBadgeClass)(project.status)}/>
|
|
1451
|
-
</div>
|
|
1452
|
-
<div className="space-y-1.5">
|
|
1453
|
-
<h1 className="max-w-5xl text-2xl font-semibold tracking-tight text-foreground sm:text-3xl">
|
|
1454
|
-
{project.name}
|
|
1455
|
-
</h1>
|
|
1456
|
-
<p className="max-w-3xl text-sm leading-6 text-muted-foreground">
|
|
1457
|
-
{project.summary || t('executive.fallbackDescription')}
|
|
1458
|
-
</p>
|
|
1459
|
-
</div>
|
|
1460
|
-
</div>
|
|
1461
|
-
</div>
|
|
1462
|
-
</div>
|
|
1463
|
-
|
|
1464
|
-
<div className="flex flex-wrap gap-2 lg:justify-end">
|
|
1465
|
-
{access.isDirector ? (<button_1.Button size="sm" onClick={openEditSheet} className="cursor-pointer gap-2">
|
|
1466
|
-
<lucide_react_1.Pencil className="size-4"/>
|
|
1467
|
-
{commonT('actions.edit')}
|
|
1468
|
-
</button_1.Button>) : null}
|
|
1469
|
-
{!isLimitedView ? (<button_1.Button variant="outline" size="sm" onClick={() => openCreateTaskForm()} className="cursor-pointer gap-2">
|
|
1470
|
-
<lucide_react_1.Plus className="size-4"/>
|
|
1471
|
-
{t('taskForm.titleNew')}
|
|
1472
|
-
</button_1.Button>) : null}
|
|
1473
|
-
<button_1.Button variant="outline" size="sm" asChild>
|
|
1474
|
-
<link_1.default href="/operations/timesheets">
|
|
1475
|
-
<lucide_react_1.Timer className="size-4"/>
|
|
1476
|
-
{t('quickActions.timesheet')}
|
|
1477
|
-
</link_1.default>
|
|
1478
|
-
</button_1.Button>
|
|
1479
|
-
<dropdown_menu_1.DropdownMenu>
|
|
1480
|
-
<dropdown_menu_1.DropdownMenuTrigger asChild>
|
|
1481
|
-
<button_1.Button variant="outline" size="icon" className="size-9 cursor-pointer" aria-label={t('quickActions.more')}>
|
|
1482
|
-
<lucide_react_1.MoreHorizontal className="size-4"/>
|
|
1483
|
-
</button_1.Button>
|
|
1484
|
-
</dropdown_menu_1.DropdownMenuTrigger>
|
|
1485
|
-
<dropdown_menu_1.DropdownMenuContent align="end" className="w-56">
|
|
1486
|
-
<dropdown_menu_1.DropdownMenuItem asChild>
|
|
1487
|
-
<link_1.default href="/operations/reports/projects">
|
|
1488
|
-
<lucide_react_1.BarChart2 className="size-4"/>
|
|
1489
|
-
{t('quickActions.reports')}
|
|
1490
|
-
</link_1.default>
|
|
1491
|
-
</dropdown_menu_1.DropdownMenuItem>
|
|
1492
|
-
{project.contractId ? (<dropdown_menu_1.DropdownMenuItem asChild>
|
|
1493
|
-
<link_1.default href={`/operations/contracts?edit=${project.contractId}`}>
|
|
1494
|
-
<lucide_react_1.FileText className="size-4"/>
|
|
1495
|
-
{commonT('actions.openContract')}
|
|
1496
|
-
</link_1.default>
|
|
1497
|
-
</dropdown_menu_1.DropdownMenuItem>) : null}
|
|
1498
|
-
<dropdown_menu_1.DropdownMenuSeparator />
|
|
1499
|
-
<dropdown_menu_1.DropdownMenuItem asChild>
|
|
1500
|
-
<link_1.default href="/operations/projects">
|
|
1501
|
-
<lucide_react_1.FolderKanban className="size-4"/>
|
|
1502
|
-
{t('breadcrumbTrail.projects')}
|
|
1503
|
-
</link_1.default>
|
|
1504
|
-
</dropdown_menu_1.DropdownMenuItem>
|
|
1505
|
-
</dropdown_menu_1.DropdownMenuContent>
|
|
1506
|
-
</dropdown_menu_1.DropdownMenu>
|
|
1507
|
-
</div>
|
|
1508
|
-
</div>
|
|
1509
|
-
|
|
1510
|
-
<div className="grid gap-3 text-sm md:grid-cols-2 xl:grid-cols-7">
|
|
1511
|
-
<div className="rounded-xl border bg-background/70 p-3 xl:col-span-2">
|
|
1512
|
-
<div className="flex items-center gap-2 text-muted-foreground">
|
|
1513
|
-
<lucide_react_1.Users className="size-4"/>
|
|
1514
|
-
{commonT('labels.client')}
|
|
1515
|
-
</div>
|
|
1516
|
-
<div className="mt-2 flex items-center gap-2 font-medium">
|
|
1517
|
-
<avatar_1.Avatar className="size-7 border bg-muted">
|
|
1518
|
-
<avatar_1.AvatarImage src={getPersonAvatarUrl(project.clientAvatarId)} alt={project.clientName || commonT('labels.client')}/>
|
|
1519
|
-
<avatar_1.AvatarFallback className="text-[10px]">
|
|
1520
|
-
{getInitials(project.clientName)}
|
|
1521
|
-
</avatar_1.AvatarFallback>
|
|
1522
|
-
</avatar_1.Avatar>
|
|
1523
|
-
<span className="truncate">
|
|
1524
|
-
{project.clientName || commonT('labels.notAvailable')}
|
|
1525
|
-
</span>
|
|
1526
|
-
</div>
|
|
1527
|
-
</div>
|
|
1528
|
-
<div className="rounded-xl border bg-background/70 p-3">
|
|
1529
|
-
<div className="flex items-center gap-2 text-muted-foreground">
|
|
1530
|
-
<lucide_react_1.Rocket className="size-4"/>
|
|
1531
|
-
{commonT('labels.deliveryModel')}
|
|
1532
|
-
</div>
|
|
1533
|
-
<div className="mt-2 truncate font-medium">
|
|
1534
|
-
{project.deliveryModel
|
|
1535
|
-
? getDeliveryModelLabel(project.deliveryModel)
|
|
1536
|
-
: commonT('labels.notAvailable')}
|
|
1537
|
-
</div>
|
|
1538
|
-
</div>
|
|
1539
|
-
<div className="rounded-xl border bg-background/70 p-3">
|
|
1540
|
-
<div className="flex items-center gap-2 text-muted-foreground">
|
|
1541
|
-
<lucide_react_1.Users className="size-4"/>
|
|
1542
|
-
{commonT('labels.manager')}
|
|
1543
|
-
</div>
|
|
1544
|
-
<div className="mt-2 truncate font-medium">
|
|
1545
|
-
{project.managerName || commonT('labels.notAssigned')}
|
|
1546
|
-
</div>
|
|
1547
|
-
</div>
|
|
1548
|
-
<div className="rounded-xl border bg-background/70 p-3">
|
|
1549
|
-
<div className="flex items-center gap-2 text-muted-foreground">
|
|
1550
|
-
<lucide_react_1.CalendarDays className="size-4"/>
|
|
1551
|
-
{commonT('labels.startDate')}
|
|
1552
|
-
</div>
|
|
1553
|
-
<div className="mt-2 font-medium">
|
|
1554
|
-
{(0, format_1.formatDate)(project.startDate, getSettingValue, currentLocaleCode)}
|
|
1555
|
-
</div>
|
|
1556
|
-
</div>
|
|
1557
|
-
<div className="rounded-xl border bg-background/70 p-3">
|
|
1558
|
-
<div className="flex items-center gap-2 text-muted-foreground">
|
|
1559
|
-
<lucide_react_1.CalendarClock className="size-4"/>
|
|
1560
|
-
{commonT('labels.endDate')}
|
|
1561
|
-
</div>
|
|
1562
|
-
<div className="mt-2 font-medium">
|
|
1563
|
-
{(0, format_1.formatDate)(project.endDate, getSettingValue, currentLocaleCode)}
|
|
1564
|
-
</div>
|
|
1565
|
-
</div>
|
|
1566
|
-
<div className="rounded-xl border bg-background/70 p-3">
|
|
1567
|
-
<div className="flex items-center gap-2 text-muted-foreground">
|
|
1568
|
-
<lucide_react_1.Gauge className="size-4"/>
|
|
1569
|
-
{commonT('labels.progress')}
|
|
1570
|
-
</div>
|
|
1571
|
-
<div className="mt-2 flex items-center gap-3">
|
|
1572
|
-
<progress_1.Progress value={displayedProgress} className="h-2"/>
|
|
1573
|
-
<span className="text-sm font-semibold tabular-nums">
|
|
1574
|
-
{displayedProgress}%
|
|
1575
|
-
</span>
|
|
1576
|
-
</div>
|
|
1577
|
-
</div>
|
|
1578
|
-
</div>
|
|
1579
|
-
|
|
1580
|
-
<div className="flex flex-col gap-4 rounded-2xl border bg-background/75 p-4 sm:flex-row sm:items-center sm:justify-between">
|
|
1581
|
-
<div className="flex items-center gap-3">
|
|
1582
|
-
<div>
|
|
1583
|
-
<div className="flex items-center gap-2 text-muted-foreground">
|
|
1584
|
-
<lucide_react_1.Users className="size-4"/>
|
|
1585
|
-
<span className="text-xs font-medium uppercase tracking-[0.18em]">
|
|
1586
|
-
{t('executive.team')}
|
|
1587
|
-
</span>
|
|
1588
|
-
</div>
|
|
1589
|
-
<div className="mt-1 text-sm font-semibold">
|
|
1590
|
-
{t('executive.membersCount', {
|
|
1591
|
-
count: project.assignments.length,
|
|
1592
|
-
})}
|
|
1593
|
-
</div>
|
|
1594
|
-
</div>
|
|
1595
|
-
<div className="flex -space-x-2">
|
|
1596
|
-
{teamPreview.map((assignment) => (<tooltip_1.Tooltip key={assignment.id}>
|
|
1597
|
-
<tooltip_1.TooltipTrigger asChild>
|
|
1598
|
-
<avatar_1.Avatar className="size-10 cursor-default border-2 border-background bg-muted transition-transform hover:z-10 hover:scale-110">
|
|
1599
|
-
<avatar_1.AvatarImage src={getUserPhotoUrl(assignment.userPhotoId) ||
|
|
1600
|
-
getPersonAvatarUrl(assignment.personAvatarId)} alt={assignment.collaboratorName}/>
|
|
1601
|
-
<avatar_1.AvatarFallback className="text-xs">
|
|
1602
|
-
{getInitials(assignment.collaboratorName)}
|
|
1603
|
-
</avatar_1.AvatarFallback>
|
|
1604
|
-
</avatar_1.Avatar>
|
|
1605
|
-
</tooltip_1.TooltipTrigger>
|
|
1606
|
-
<tooltip_1.TooltipContent side="bottom" className="text-xs">
|
|
1607
|
-
<p className="font-medium">
|
|
1608
|
-
{assignment.collaboratorName}
|
|
1609
|
-
</p>
|
|
1610
|
-
{assignment.roleLabel ? (<p className="text-muted-foreground">
|
|
1611
|
-
{assignment.roleLabel}
|
|
1612
|
-
</p>) : null}
|
|
1613
|
-
</tooltip_1.TooltipContent>
|
|
1614
|
-
</tooltip_1.Tooltip>))}
|
|
1615
|
-
{hiddenTeamCount > 0 ? (<div className="flex size-10 items-center justify-center rounded-full border-2 border-background bg-muted text-xs font-semibold text-muted-foreground">
|
|
1616
|
-
+{hiddenTeamCount}
|
|
1617
|
-
</div>) : null}
|
|
1618
|
-
</div>
|
|
1619
|
-
</div>
|
|
1620
|
-
|
|
1621
|
-
<div className="grid grid-cols-3 gap-3 text-sm sm:min-w-80">
|
|
1622
|
-
<div className="rounded-xl border bg-muted/20 p-3">
|
|
1623
|
-
<div className="text-muted-foreground">
|
|
1624
|
-
{commonT('labels.status')}
|
|
1625
|
-
</div>
|
|
1626
|
-
<div className="mt-1">
|
|
1627
|
-
<status_badge_1.StatusBadge label={getProjectStatusLabel(project.status)} className={(0, format_1.getStatusBadgeClass)(project.status)}/>
|
|
1628
|
-
</div>
|
|
1629
|
-
</div>
|
|
1630
|
-
<div className="rounded-xl border bg-muted/20 p-3">
|
|
1631
|
-
<div className="text-muted-foreground">
|
|
1632
|
-
{t('cards.projectHealth')}
|
|
1633
|
-
</div>
|
|
1634
|
-
<div className="mt-1 font-semibold">{projectHealthLabel}</div>
|
|
1635
|
-
</div>
|
|
1636
|
-
<div className="rounded-xl border bg-muted/20 p-3">
|
|
1637
|
-
<div className="text-muted-foreground">
|
|
1638
|
-
{t('executive.completedTasks')}
|
|
1639
|
-
</div>
|
|
1640
|
-
<div className="mt-1 font-semibold">
|
|
1641
|
-
{completedTasks}/{totalTasks}
|
|
1642
|
-
</div>
|
|
1643
|
-
</div>
|
|
1644
|
-
</div>
|
|
1645
|
-
</div>
|
|
1646
|
-
</div>
|
|
1647
|
-
</div>
|
|
1648
|
-
</framer_motion_1.motion.section>
|
|
1649
|
-
|
|
1650
|
-
{!isLimitedView ? (<>
|
|
1651
|
-
<div className="rounded-3xl border bg-linear-to-b from-muted/50 to-background p-3 shadow-sm sm:p-4">
|
|
1652
|
-
<div className="grid gap-3 sm:grid-cols-2 lg:grid-cols-3 2xl:grid-cols-6">
|
|
1653
|
-
{kpiWidgets.map((item, index) => (<ProjectKpiWidget key={item.key} item={item} index={index} indicatorLabel={t('kpi.indicator')}/>))}
|
|
1654
|
-
</div>
|
|
1655
|
-
</div>
|
|
1656
|
-
|
|
1657
|
-
<div className="grid gap-4 xl:grid-cols-12">
|
|
1658
|
-
<section_card_1.SectionCard title={t('sections.overview')} className="rounded-xl border bg-card p-4 shadow-sm xl:col-span-12">
|
|
1659
|
-
<dl className="grid gap-3 text-sm sm:grid-cols-2 xl:grid-cols-3">
|
|
1660
|
-
<div>
|
|
1661
|
-
<dt className="text-muted-foreground">
|
|
1662
|
-
{commonT('labels.project')}
|
|
1663
|
-
</dt>
|
|
1664
|
-
<dd className="font-medium">{project.name}</dd>
|
|
1665
|
-
</div>
|
|
1666
|
-
<div>
|
|
1667
|
-
<dt className="text-muted-foreground">
|
|
1668
|
-
{commonT('labels.code')}
|
|
1669
|
-
</dt>
|
|
1670
|
-
<dd className="font-medium">
|
|
1671
|
-
{project.code || commonT('labels.notAvailable')}
|
|
1672
|
-
</dd>
|
|
1673
|
-
</div>
|
|
1674
|
-
<div>
|
|
1675
|
-
<dt className="text-muted-foreground">
|
|
1676
|
-
{commonT('labels.client')}
|
|
1677
|
-
</dt>
|
|
1678
|
-
<dd className="font-medium">
|
|
1679
|
-
<div className="flex items-center gap-2">
|
|
1680
|
-
<avatar_1.Avatar className="h-8 w-8 border border-border/60 bg-muted">
|
|
1681
|
-
<avatar_1.AvatarImage src={getPersonAvatarUrl(project.clientAvatarId)} alt={project.clientName || commonT('labels.client')}/>
|
|
1682
|
-
<avatar_1.AvatarFallback className="bg-muted text-xs font-semibold text-foreground">
|
|
1683
|
-
{getInitials(project.clientName || commonT('labels.client'))}
|
|
1684
|
-
</avatar_1.AvatarFallback>
|
|
1685
|
-
</avatar_1.Avatar>
|
|
1686
|
-
<span>
|
|
1687
|
-
{project.clientName || commonT('labels.notAvailable')}
|
|
1688
|
-
</span>
|
|
1689
|
-
</div>
|
|
1690
|
-
</dd>
|
|
1691
|
-
</div>
|
|
1692
|
-
<div>
|
|
1693
|
-
<dt className="text-muted-foreground">
|
|
1694
|
-
{commonT('labels.manager')}
|
|
1695
|
-
</dt>
|
|
1696
|
-
<dd className="font-medium">
|
|
1697
|
-
{project.managerName || commonT('labels.notAssigned')}
|
|
1698
|
-
</dd>
|
|
1699
|
-
</div>
|
|
1700
|
-
<div>
|
|
1701
|
-
<dt className="text-muted-foreground">
|
|
1702
|
-
{commonT('labels.status')}
|
|
1703
|
-
</dt>
|
|
1704
|
-
<dd className="font-medium">
|
|
1705
|
-
<status_badge_1.StatusBadge label={getProjectStatusLabel(project.status)} className={(0, format_1.getStatusBadgeClass)(project.status)}/>
|
|
1706
|
-
</dd>
|
|
1707
|
-
</div>
|
|
1708
|
-
<div>
|
|
1709
|
-
<dt className="text-muted-foreground">
|
|
1710
|
-
{commonT('labels.deliveryModel')}
|
|
1711
|
-
</dt>
|
|
1712
|
-
<dd className="font-medium">
|
|
1713
|
-
{project.deliveryModel
|
|
1714
|
-
? getDeliveryModelLabel(project.deliveryModel)
|
|
1715
|
-
: commonT('labels.notAvailable')}
|
|
1716
|
-
</dd>
|
|
1717
|
-
</div>
|
|
1718
|
-
<div>
|
|
1719
|
-
<dt className="text-muted-foreground">
|
|
1720
|
-
{commonT('labels.startDate')}
|
|
1721
|
-
</dt>
|
|
1722
|
-
<dd className="font-medium">
|
|
1723
|
-
{(0, format_1.formatDate)(project.startDate, getSettingValue, currentLocaleCode)}
|
|
1724
|
-
</dd>
|
|
1725
|
-
</div>
|
|
1726
|
-
<div>
|
|
1727
|
-
<dt className="text-muted-foreground">
|
|
1728
|
-
{commonT('labels.endDate')}
|
|
1729
|
-
</dt>
|
|
1730
|
-
<dd className="font-medium">
|
|
1731
|
-
{(0, format_1.formatDate)(project.endDate, getSettingValue, currentLocaleCode)}
|
|
1732
|
-
</dd>
|
|
1733
|
-
</div>
|
|
1734
|
-
<div>
|
|
1735
|
-
<dt className="text-muted-foreground">
|
|
1736
|
-
{commonT('labels.budget')}
|
|
1737
|
-
</dt>
|
|
1738
|
-
<dd className="font-medium">
|
|
1739
|
-
{project.budgetAmount
|
|
1740
|
-
? (0, format_1.formatCurrency)(project.budgetAmount, getSettingValue, currentLocaleCode)
|
|
1741
|
-
: commonT('labels.notAvailable')}
|
|
1742
|
-
</dd>
|
|
1743
|
-
</div>
|
|
1744
|
-
<div>
|
|
1745
|
-
<dt className="text-muted-foreground">
|
|
1746
|
-
{commonT('labels.progress')}
|
|
1747
|
-
</dt>
|
|
1748
|
-
<dd className="font-medium">
|
|
1749
|
-
{(0, format_1.formatPercent)(project.progressPercent)}
|
|
1750
|
-
</dd>
|
|
1751
|
-
</div>
|
|
1752
|
-
<div>
|
|
1753
|
-
<dt className="text-muted-foreground">
|
|
1754
|
-
{commonT('labels.timeline')}
|
|
1755
|
-
</dt>
|
|
1756
|
-
<dd className="font-medium">
|
|
1757
|
-
{(0, format_1.formatDateRange)(project.startDate, project.endDate, getSettingValue, currentLocaleCode)}
|
|
1758
|
-
</dd>
|
|
1759
|
-
</div>
|
|
1760
|
-
<div>
|
|
1761
|
-
<dt className="text-muted-foreground">
|
|
1762
|
-
{commonT('labels.contractStatus')}
|
|
1763
|
-
</dt>
|
|
1764
|
-
<dd className="font-medium">
|
|
1765
|
-
{project.contractStatus ? (<status_badge_1.StatusBadge label={getContractStatusLabel(project.contractStatus)} className={(0, format_1.getStatusBadgeClass)(project.contractStatus)}/>) : (commonT('labels.notAssigned'))}
|
|
1766
|
-
</dd>
|
|
1767
|
-
</div>
|
|
1768
|
-
</dl>
|
|
1769
|
-
{project.summary ? (<div className="mt-4 rounded-lg border border-border/70 bg-muted/30 p-3 text-sm text-muted-foreground">
|
|
1770
|
-
{project.summary}
|
|
1771
|
-
</div>) : null}
|
|
1772
|
-
|
|
1773
|
-
{/* Contrato vinculado */}
|
|
1774
|
-
<div className="mt-6 border-t pt-6">
|
|
1775
|
-
<div className="mb-4 flex items-center gap-2 text-sm font-semibold">
|
|
1776
|
-
<lucide_react_1.FileText className="size-4 text-muted-foreground"/>
|
|
1777
|
-
{t('sections.contract')}
|
|
1778
|
-
</div>
|
|
1779
|
-
{project.relatedContract ? (<div className="space-y-4">
|
|
1780
|
-
<div className="flex flex-col gap-3 rounded-xl border bg-muted/20 px-4 py-3 sm:flex-row sm:items-center sm:justify-between">
|
|
1781
|
-
<div>
|
|
1782
|
-
<div className="font-medium">
|
|
1783
|
-
{project.relatedContract.name}
|
|
1784
|
-
</div>
|
|
1785
|
-
<div className="text-sm text-muted-foreground">
|
|
1786
|
-
{[
|
|
1787
|
-
project.relatedContract.code,
|
|
1788
|
-
project.relatedContract.clientName,
|
|
1789
|
-
]
|
|
1790
|
-
.filter(Boolean)
|
|
1791
|
-
.join(' • ') || commonT('labels.notAvailable')}
|
|
1792
|
-
</div>
|
|
1793
|
-
</div>
|
|
1794
|
-
<div className="flex items-center gap-3">
|
|
1795
|
-
<status_badge_1.StatusBadge label={getContractStatusLabel(project.relatedContract.status)} className={(0, format_1.getStatusBadgeClass)(project.relatedContract.status)}/>
|
|
1796
|
-
<button_1.Button variant="outline" size="sm" asChild className="shrink-0">
|
|
1797
|
-
<link_1.default href={`/operations/contracts?edit=${project.relatedContract.id}`}>
|
|
1798
|
-
<lucide_react_1.FileText className="size-4"/>
|
|
1799
|
-
{commonT('actions.openContract')}
|
|
1800
|
-
</link_1.default>
|
|
1801
|
-
</button_1.Button>
|
|
1802
|
-
</div>
|
|
1803
|
-
</div>
|
|
1804
|
-
<dl className="grid gap-3 text-sm sm:grid-cols-2 xl:grid-cols-3">
|
|
1805
|
-
<div>
|
|
1806
|
-
<dt className="text-muted-foreground">
|
|
1807
|
-
{commonT('labels.contractCategory')}
|
|
1808
|
-
</dt>
|
|
1809
|
-
<dd className="font-medium">
|
|
1810
|
-
{project.relatedContract.contractCategory
|
|
1811
|
-
? getContractCategoryLabel(project.relatedContract.contractCategory)
|
|
1812
|
-
: commonT('labels.notAvailable')}
|
|
1813
|
-
</dd>
|
|
1814
|
-
</div>
|
|
1815
|
-
<div>
|
|
1816
|
-
<dt className="text-muted-foreground">
|
|
1817
|
-
{commonT('labels.contractType')}
|
|
1818
|
-
</dt>
|
|
1819
|
-
<dd className="font-medium">
|
|
1820
|
-
{project.relatedContract.contractType
|
|
1821
|
-
? getContractTypeLabel(project.relatedContract.contractType)
|
|
1822
|
-
: commonT('labels.notAvailable')}
|
|
1823
|
-
</dd>
|
|
1824
|
-
</div>
|
|
1825
|
-
<div>
|
|
1826
|
-
<dt className="text-muted-foreground">
|
|
1827
|
-
{commonT('labels.billingModel')}
|
|
1828
|
-
</dt>
|
|
1829
|
-
<dd className="font-medium">
|
|
1830
|
-
{getBillingModelLabel(project.relatedContract.billingModel)}
|
|
1831
|
-
</dd>
|
|
1832
|
-
</div>
|
|
1833
|
-
<div>
|
|
1834
|
-
<dt className="text-muted-foreground">
|
|
1835
|
-
{commonT('labels.timeline')}
|
|
1836
|
-
</dt>
|
|
1837
|
-
<dd className="font-medium">
|
|
1838
|
-
{(0, format_1.formatDateRange)(project.relatedContract.startDate, project.relatedContract.endDate, getSettingValue, currentLocaleCode)}
|
|
1839
|
-
</dd>
|
|
1840
|
-
</div>
|
|
1841
|
-
<div>
|
|
1842
|
-
<dt className="text-muted-foreground">
|
|
1843
|
-
{commonT('labels.signatureStatus')}
|
|
1844
|
-
</dt>
|
|
1845
|
-
<dd className="font-medium">
|
|
1846
|
-
{project.relatedContract.signatureStatus
|
|
1847
|
-
? getSignatureStatusLabel(project.relatedContract.signatureStatus)
|
|
1848
|
-
: commonT('labels.notAvailable')}
|
|
1849
|
-
</dd>
|
|
1850
|
-
</div>
|
|
1851
|
-
<div>
|
|
1852
|
-
<dt className="text-muted-foreground">
|
|
1853
|
-
{commonT('labels.budget')}
|
|
1854
|
-
</dt>
|
|
1855
|
-
<dd className="font-medium">
|
|
1856
|
-
{project.relatedContract.budgetAmount
|
|
1857
|
-
? (0, format_1.formatCurrency)(project.relatedContract.budgetAmount, getSettingValue, currentLocaleCode)
|
|
1858
|
-
: commonT('labels.notAvailable')}
|
|
1859
|
-
</dd>
|
|
1860
|
-
</div>
|
|
1861
|
-
</dl>
|
|
1862
|
-
</div>) : (<p className="text-sm text-muted-foreground">
|
|
1863
|
-
{t('noContract')}
|
|
1864
|
-
</p>)}
|
|
1865
|
-
</div>
|
|
1866
|
-
</section_card_1.SectionCard>
|
|
1867
|
-
</div>
|
|
1868
|
-
|
|
1869
|
-
<section_card_1.SectionCard title={t('sections.deliveryHealth')} description={t('sections.deliveryHealthDescription')} className="rounded-3xl border bg-card p-4 shadow-sm">
|
|
1870
|
-
<div className="grid gap-4 xl:grid-cols-12">
|
|
1871
|
-
<ProjectChartCard title={t('charts.burnup')} description={t('charts.burnupDescription')} icon={lucide_react_1.LineChart} metric={(0, format_1.formatPercent)(displayedProgress)} className="xl:col-span-8" isLoading={chartDashboardLoading}>
|
|
1872
|
-
{burnupChartData.length > 1 ? (<chart_1.ChartContainer className="h-80 w-full" config={boardChartConfig}>
|
|
1873
|
-
<recharts_1.AreaChart data={burnupChartData}>
|
|
1874
|
-
<defs>
|
|
1875
|
-
<linearGradient id="burnupLogged" x1="0" y1="0" x2="0" y2="1">
|
|
1876
|
-
<stop offset="5%" stopColor="var(--color-loggedHours)" stopOpacity={0.26}/>
|
|
1877
|
-
<stop offset="95%" stopColor="var(--color-loggedHours)" stopOpacity={0.02}/>
|
|
1878
|
-
</linearGradient>
|
|
1879
|
-
</defs>
|
|
1880
|
-
<recharts_1.CartesianGrid vertical={false} strokeDasharray="3 3"/>
|
|
1881
|
-
<recharts_1.XAxis dataKey="week" tickLine={false} axisLine={false}/>
|
|
1882
|
-
<recharts_1.YAxis tickLine={false} axisLine={false} width={36}/>
|
|
1883
|
-
<chart_1.ChartTooltip content={<chart_1.ChartTooltipContent />}/>
|
|
1884
|
-
<recharts_1.Area type="monotone" dataKey="planned" stroke="var(--color-planned)" strokeDasharray="4 4" strokeWidth={2} fill="transparent"/>
|
|
1885
|
-
<recharts_1.Area type="monotone" dataKey="loggedHours" stroke="var(--color-loggedHours)" strokeWidth={2.5} fill="url(#burnupLogged)"/>
|
|
1886
|
-
</recharts_1.AreaChart>
|
|
1887
|
-
</chart_1.ChartContainer>) : (<ChartEmptyState icon={lucide_react_1.LineChart} title={t('charts.emptyTitle')} description={t('charts.emptyBurnup')}/>)}
|
|
1888
|
-
</ProjectChartCard>
|
|
1889
|
-
|
|
1890
|
-
<ProjectChartCard title={t('charts.weeklyVelocity')} description={t('charts.weeklyVelocityDescription')} icon={lucide_react_1.Rocket} metric={(0, format_1.formatHours)(weeklyVelocity)} className="xl:col-span-4" isLoading={isProjectStatsLoading}>
|
|
1891
|
-
{velocityChartData.length > 0 ? (<chart_1.ChartContainer className="h-80 w-full" config={boardChartConfig}>
|
|
1892
|
-
<recharts_1.LineChart data={velocityChartData}>
|
|
1893
|
-
<recharts_1.CartesianGrid vertical={false} strokeDasharray="3 3"/>
|
|
1894
|
-
<recharts_1.XAxis dataKey="week" tickLine={false} axisLine={false}/>
|
|
1895
|
-
<recharts_1.YAxis tickLine={false} axisLine={false} width={30}/>
|
|
1896
|
-
<chart_1.ChartTooltip content={<chart_1.ChartTooltipContent />}/>
|
|
1897
|
-
<recharts_1.Line type="monotone" dataKey="loggedHours" stroke="var(--color-loggedHours)" strokeWidth={2.5} dot={{ r: 3 }} activeDot={{ r: 5 }}/>
|
|
1898
|
-
</recharts_1.LineChart>
|
|
1899
|
-
</chart_1.ChartContainer>) : (<ChartEmptyState icon={lucide_react_1.Rocket} title={t('charts.emptyTitle')} description={t('charts.emptyVelocity')}/>)}
|
|
1900
|
-
</ProjectChartCard>
|
|
1901
|
-
|
|
1902
|
-
<ProjectChartCard title={t('charts.allocationByCollaborator')} description={t('charts.allocationDescription')} icon={lucide_react_1.BarChart3} metric={(0, format_1.formatPercent)(project.operationalIndicators.averageAllocation)} className="xl:col-span-5" isLoading={chartDashboardLoading}>
|
|
1903
|
-
{allocationChartData.length > 0 ? (<chart_1.ChartContainer className="h-72 w-full" config={boardChartConfig}>
|
|
1904
|
-
<recharts_1.BarChart data={allocationChartData}>
|
|
1905
|
-
<recharts_1.CartesianGrid vertical={false} strokeDasharray="3 3"/>
|
|
1906
|
-
<recharts_1.XAxis dataKey="name" tickLine={false} axisLine={false}/>
|
|
1907
|
-
<recharts_1.YAxis tickLine={false} axisLine={false} width={32}/>
|
|
1908
|
-
<chart_1.ChartTooltip content={<chart_1.ChartTooltipContent hideLabel/>}/>
|
|
1909
|
-
<recharts_1.Bar dataKey="allocation" radius={[8, 8, 3, 3]} fill="var(--color-allocation)"/>
|
|
1910
|
-
</recharts_1.BarChart>
|
|
1911
|
-
</chart_1.ChartContainer>) : (<ChartEmptyState icon={lucide_react_1.BarChart3} title={t('charts.emptyTitle')} description={t('charts.emptyAllocation')}/>)}
|
|
1912
|
-
</ProjectChartCard>
|
|
1913
|
-
|
|
1914
|
-
<ProjectChartCard title={t('charts.taskDistribution')} description={t('charts.taskDistributionDescription')} icon={lucide_react_1.ClipboardList} metric={`${totalTasks} ${t('kanban.items')}`} className="xl:col-span-4" isLoading={isTasksLoading}>
|
|
1915
|
-
{taskDistributionData.length > 0 ? (<div className="grid gap-4 md:grid-cols-[1fr_11rem]">
|
|
1916
|
-
<chart_1.ChartContainer className="h-72 w-full" config={boardChartConfig}>
|
|
1917
|
-
<recharts_1.PieChart>
|
|
1918
|
-
<chart_1.ChartTooltip content={<chart_1.ChartTooltipContent hideLabel/>}/>
|
|
1919
|
-
<recharts_1.Pie data={taskDistributionData} dataKey="value" nameKey="name" innerRadius={58} outerRadius={92} paddingAngle={4}>
|
|
1920
|
-
{taskDistributionData.map((entry) => (<recharts_1.Cell key={entry.key} fill={entry.fill}/>))}
|
|
1921
|
-
</recharts_1.Pie>
|
|
1922
|
-
</recharts_1.PieChart>
|
|
1923
|
-
</chart_1.ChartContainer>
|
|
1924
|
-
<div className="flex flex-col justify-center gap-2">
|
|
1925
|
-
{taskDistributionData.map((item) => (<div key={item.key} className="flex items-center justify-between gap-3 rounded-lg border bg-muted/10 px-3 py-2 text-xs">
|
|
1926
|
-
<span className="flex min-w-0 items-center gap-2">
|
|
1927
|
-
<span className="size-2.5 shrink-0 rounded-full" style={{ backgroundColor: item.fill }}/>
|
|
1928
|
-
<span className="truncate">{item.name}</span>
|
|
1929
|
-
</span>
|
|
1930
|
-
<span className="font-semibold">{item.value}</span>
|
|
1931
|
-
</div>))}
|
|
1932
|
-
</div>
|
|
1933
|
-
</div>) : (<ChartEmptyState icon={lucide_react_1.ClipboardList} title={t('charts.emptyTitle')} description={t('charts.emptyTasks')}/>)}
|
|
1934
|
-
</ProjectChartCard>
|
|
1935
|
-
|
|
1936
|
-
<ProjectChartCard title={t('charts.operationalHealth')} description={t('charts.operationalHealthDescription')} icon={lucide_react_1.HeartPulse} metric={projectHealthLabel} className="xl:col-span-3" isLoading={chartDashboardLoading}>
|
|
1937
|
-
<div className="grid h-72 place-items-center">
|
|
1938
|
-
<chart_1.ChartContainer className="h-56 w-full" config={boardChartConfig}>
|
|
1939
|
-
<recharts_1.RadialBarChart data={healthChartData} innerRadius="72%" outerRadius="100%" startAngle={180} endAngle={0}>
|
|
1940
|
-
<recharts_1.PolarAngleAxis type="number" domain={[0, 100]} tick={false}/>
|
|
1941
|
-
<recharts_1.RadialBar dataKey="value" cornerRadius={12} background={{ fill: 'hsl(var(--muted))' }}/>
|
|
1942
|
-
<chart_1.ChartTooltip content={<chart_1.ChartTooltipContent hideLabel/>}/>
|
|
1943
|
-
</recharts_1.RadialBarChart>
|
|
1944
|
-
</chart_1.ChartContainer>
|
|
1945
|
-
<div className="-mt-20 text-center">
|
|
1946
|
-
<div className="text-3xl font-semibold tabular-nums">
|
|
1947
|
-
{projectHealth.value}%
|
|
1948
|
-
</div>
|
|
1949
|
-
<div className="mt-1 text-xs text-muted-foreground">
|
|
1950
|
-
{t('charts.healthScore')}
|
|
1951
|
-
</div>
|
|
1952
|
-
</div>
|
|
1953
|
-
</div>
|
|
1954
|
-
</ProjectChartCard>
|
|
1955
|
-
</div>
|
|
1956
|
-
</section_card_1.SectionCard>
|
|
1957
|
-
</>) : null}
|
|
1958
|
-
|
|
1959
|
-
<section_card_1.SectionCard title={t('sections.taskBoard')} description={t('sections.taskBoardDescription')} className="rounded-3xl border bg-card p-4 shadow-sm" actions={!isLimitedView ? (<button_1.Button size="sm" variant="default" className="gap-2" onClick={() => openCreateTaskForm()}>
|
|
1960
|
-
<lucide_react_1.Plus className="size-4"/>
|
|
1961
|
-
{t('taskForm.titleNew')}
|
|
1962
|
-
</button_1.Button>) : undefined}>
|
|
1963
|
-
<div className="mb-4 flex flex-col gap-3 rounded-2xl border bg-muted/20 p-3 lg:flex-row lg:items-center lg:justify-between">
|
|
1964
|
-
<div className="relative min-w-0 flex-1">
|
|
1965
|
-
<lucide_react_1.Search className="pointer-events-none absolute left-3 top-1/2 size-4 -translate-y-1/2 text-muted-foreground"/>
|
|
1966
|
-
<input_1.Input value={boardSearch} onChange={(event) => setBoardSearch(event.target.value)} placeholder={t('kanban.searchPlaceholder')} className="h-10 bg-background pl-9"/>
|
|
1967
|
-
</div>
|
|
1968
|
-
<div className="flex flex-col gap-2 sm:flex-row sm:items-center">
|
|
1969
|
-
<div className="flex items-center gap-2 rounded-xl border bg-background px-3 py-2 text-xs text-muted-foreground">
|
|
1970
|
-
<lucide_react_1.SlidersHorizontal className="size-4"/>
|
|
1971
|
-
{t('kanban.filters')}
|
|
1972
|
-
</div>
|
|
1973
|
-
<select_1.Select value={boardPriorityFilter} onValueChange={(value) => setBoardPriorityFilter(value)}>
|
|
1974
|
-
<select_1.SelectTrigger className="h-10 w-full bg-background sm:w-44">
|
|
1975
|
-
<select_1.SelectValue />
|
|
1976
|
-
</select_1.SelectTrigger>
|
|
1977
|
-
<select_1.SelectContent>
|
|
1978
|
-
<select_1.SelectItem value="all">{t('kanban.allPriorities')}</select_1.SelectItem>
|
|
1979
|
-
<select_1.SelectItem value="high">
|
|
1980
|
-
{getTaskPriorityLabel('high')}
|
|
1981
|
-
</select_1.SelectItem>
|
|
1982
|
-
<select_1.SelectItem value="medium">
|
|
1983
|
-
{getTaskPriorityLabel('medium')}
|
|
1984
|
-
</select_1.SelectItem>
|
|
1985
|
-
<select_1.SelectItem value="low">
|
|
1986
|
-
{getTaskPriorityLabel('low')}
|
|
1987
|
-
</select_1.SelectItem>
|
|
1988
|
-
</select_1.SelectContent>
|
|
1989
|
-
</select_1.Select>
|
|
1990
|
-
<select_1.Select value={boardGroupMode} onValueChange={setBoardGroupMode}>
|
|
1991
|
-
<select_1.SelectTrigger className="h-10 w-full bg-background sm:w-44">
|
|
1992
|
-
<select_1.SelectValue />
|
|
1993
|
-
</select_1.SelectTrigger>
|
|
1994
|
-
<select_1.SelectContent>
|
|
1995
|
-
<select_1.SelectItem value="status">
|
|
1996
|
-
{t('kanban.groupStatus')}
|
|
1997
|
-
</select_1.SelectItem>
|
|
1998
|
-
</select_1.SelectContent>
|
|
1999
|
-
</select_1.Select>
|
|
2000
|
-
</div>
|
|
2001
|
-
</div>
|
|
2002
|
-
|
|
2003
|
-
<core_1.DndContext sensors={sensors} collisionDetection={kanbanCollision} onDragStart={onBoardDragStart} onDragCancel={() => setActiveDragTask(null)} onDragEnd={onBoardDragEnd}>
|
|
2004
|
-
<div className="relative">
|
|
2005
|
-
<div className="grid auto-cols-[minmax(19rem,1fr)] grid-flow-col gap-4 overflow-x-auto pb-2 xl:grid-flow-row xl:grid-cols-4 xl:overflow-visible xl:pb-0">
|
|
2006
|
-
{KANBAN_COLUMNS.map((column) => (<DroppableColumn key={column.id} columnId={column.id}>
|
|
2007
|
-
{(isOver) => (<div className={[
|
|
2008
|
-
'flex min-h-[32rem] flex-col overflow-hidden rounded-3xl border bg-linear-to-b p-3 transition-all',
|
|
2009
|
-
getColumnClassName(column.id),
|
|
2010
|
-
isOver
|
|
2011
|
-
? 'border-primary shadow-lg ring-2 ring-primary/15'
|
|
2012
|
-
: 'border-border',
|
|
2013
|
-
].join(' ')}>
|
|
2014
|
-
<div className="mb-3 flex items-center justify-between gap-3 rounded-2xl border bg-background/85 p-3 shadow-xs">
|
|
2015
|
-
<div className="min-w-0">
|
|
2016
|
-
<div className="flex items-center gap-2 text-sm font-semibold">
|
|
2017
|
-
<span className={[
|
|
2018
|
-
'size-2.5 rounded-full',
|
|
2019
|
-
getColumnDotClassName(column.id),
|
|
2020
|
-
].join(' ')}/>
|
|
2021
|
-
{column.label}
|
|
2022
|
-
</div>
|
|
2023
|
-
<div className="mt-1 text-xs text-muted-foreground">
|
|
2024
|
-
{filteredTaskColumns[column.id].length}/
|
|
2025
|
-
{taskColumns[column.id].length} {t('kanban.items')}
|
|
2026
|
-
</div>
|
|
2027
|
-
</div>
|
|
2028
|
-
<div className="flex items-center gap-1">
|
|
2029
|
-
<span className="rounded-full border bg-background px-2 py-0.5 text-xs font-medium text-muted-foreground">
|
|
2030
|
-
{filteredTaskColumns[column.id].length}
|
|
2031
|
-
</span>
|
|
2032
|
-
{!isLimitedView ? (<button type="button" className="flex size-5 cursor-pointer items-center justify-center rounded-full text-muted-foreground transition hover:bg-muted hover:text-foreground" onClick={() => {
|
|
2033
|
-
setInlineCreateColumn(column.id);
|
|
2034
|
-
setInlineCreateName('');
|
|
2035
|
-
}}>
|
|
2036
|
-
<lucide_react_1.Plus className="size-3.5"/>
|
|
2037
|
-
</button>) : null}
|
|
2038
|
-
</div>
|
|
2039
|
-
</div>
|
|
2040
|
-
|
|
2041
|
-
<div className="flex flex-1 flex-col gap-2">
|
|
2042
|
-
<framer_motion_1.AnimatePresence initial={false}>
|
|
2043
|
-
{filteredTaskColumns[column.id].map((task) => {
|
|
2044
|
-
const tags = getTaskTags(task);
|
|
2045
|
-
const comments = getTaskCommentCount(task);
|
|
2046
|
-
const attachments = getTaskAttachmentCount(task);
|
|
2047
|
-
return (<DraggableTaskCard key={task.id} task={task} disabled={false}>
|
|
2048
|
-
{(isDragging) => (<framer_motion_1.motion.div initial={{ opacity: 0, scale: 0.96 }} animate={{ opacity: 1, scale: 1 }} exit={{ opacity: 0, scale: 0.95, y: -4 }} transition={{ duration: 0.18 }} role="button" tabIndex={0} className={[
|
|
2049
|
-
'group w-full cursor-pointer rounded-2xl border bg-card p-3 text-left shadow-xs transition',
|
|
2050
|
-
isDragging
|
|
2051
|
-
? 'opacity-0'
|
|
2052
|
-
: 'hover:border-primary/40 hover:shadow-lg',
|
|
2053
|
-
].join(' ')} onClick={() => setSelectedTask(Object.assign(Object.assign({}, task), { projectName: project === null || project === void 0 ? void 0 : project.name, projectCode: project === null || project === void 0 ? void 0 : project.code }))} onKeyDown={(event) => {
|
|
2054
|
-
if (event.key === 'Enter' ||
|
|
2055
|
-
event.key === ' ') {
|
|
2056
|
-
event.preventDefault();
|
|
2057
|
-
setSelectedTask(Object.assign(Object.assign({}, task), { projectName: project === null || project === void 0 ? void 0 : project.name, projectCode: project === null || project === void 0 ? void 0 : project.code }));
|
|
2058
|
-
}
|
|
2059
|
-
}}>
|
|
2060
|
-
<div className="mb-3 flex items-start justify-between gap-2">
|
|
2061
|
-
<div className="min-w-0 space-y-1">
|
|
2062
|
-
<p className="line-clamp-2 text-sm font-semibold leading-snug">
|
|
2063
|
-
{task.name}
|
|
2064
|
-
</p>
|
|
2065
|
-
{task.description ? (<p className="line-clamp-2 text-xs leading-5 text-muted-foreground">
|
|
2066
|
-
{task.description.replace(/<[^>]*>/g, '')}
|
|
2067
|
-
</p>) : null}
|
|
2068
|
-
</div>
|
|
2069
|
-
<div className="flex items-start gap-2">
|
|
2070
|
-
<span className={[
|
|
2071
|
-
'shrink-0 rounded-full border px-2 py-0.5 text-[10px] font-semibold uppercase tracking-wide',
|
|
2072
|
-
getPriorityClassName(task.priority),
|
|
2073
|
-
].join(' ')}>
|
|
2074
|
-
{getTaskPriorityLabel(task.priority)}
|
|
2075
|
-
</span>
|
|
2076
|
-
<button_1.Button type="button" variant="ghost" size="icon" className="size-7 shrink-0 rounded-full opacity-0 transition group-hover:opacity-100" onPointerDown={(event) => event.stopPropagation()} onClick={(event) => {
|
|
2077
|
-
event.stopPropagation();
|
|
2078
|
-
openEditTaskForm(task);
|
|
2079
|
-
}}>
|
|
2080
|
-
<lucide_react_1.Pencil className="size-3.5"/>
|
|
2081
|
-
</button_1.Button>
|
|
2082
|
-
</div>
|
|
2083
|
-
</div>
|
|
2084
|
-
|
|
2085
|
-
{tags.length > 0 ? (<div className="mb-3 flex flex-wrap gap-1">
|
|
2086
|
-
{tags.slice(0, 4).map((tag) => (<span key={`${task.id}-${tag}`} className="rounded-full border bg-muted/60 px-2 py-0.5 text-[10px] font-medium text-muted-foreground">
|
|
2087
|
-
{tag}
|
|
2088
|
-
</span>))}
|
|
2089
|
-
{tags.length > 4 ? (<span className="rounded-full border bg-muted/60 px-2 py-0.5 text-[10px] font-medium text-muted-foreground">
|
|
2090
|
-
+{tags.length - 4}
|
|
2091
|
-
</span>) : null}
|
|
2092
|
-
</div>) : null}
|
|
2093
|
-
|
|
2094
|
-
<div className="grid grid-cols-2 gap-2 text-xs">
|
|
2095
|
-
<div className={[
|
|
2096
|
-
'rounded-xl border bg-muted/20 px-2 py-1.5',
|
|
2097
|
-
isPastDue(task.dueDate) &&
|
|
2098
|
-
task.status !== 'done'
|
|
2099
|
-
? 'border-rose-500/30 bg-rose-500/10 text-rose-700 dark:text-rose-300'
|
|
2100
|
-
: 'text-muted-foreground',
|
|
2101
|
-
].join(' ')}>
|
|
2102
|
-
<span className="flex items-center gap-1">
|
|
2103
|
-
<lucide_react_1.AlarmClock className="size-3.5"/>
|
|
2104
|
-
{(0, format_1.formatDate)(task.dueDate, getSettingValue, currentLocaleCode)}
|
|
2105
|
-
</span>
|
|
2106
|
-
</div>
|
|
2107
|
-
<div className="rounded-xl border bg-muted/20 px-2 py-1.5 text-muted-foreground">
|
|
2108
|
-
<span className="flex items-center gap-1">
|
|
2109
|
-
<lucide_react_1.Timer className="size-3.5"/>
|
|
2110
|
-
{task.estimateHours != null
|
|
2111
|
-
? `${task.estimateHours}h`
|
|
2112
|
-
: t('kanban.noEstimate')}
|
|
2113
|
-
</span>
|
|
2114
|
-
</div>
|
|
2115
|
-
</div>
|
|
2116
|
-
|
|
2117
|
-
<div className="mt-3 space-y-1.5">
|
|
2118
|
-
<div className="flex items-center justify-between text-[11px] text-muted-foreground">
|
|
2119
|
-
<span>{t('kanban.progress')}</span>
|
|
2120
|
-
<span>
|
|
2121
|
-
{getTaskProgress(task.status)}%
|
|
2122
|
-
</span>
|
|
2123
|
-
</div>
|
|
2124
|
-
<progress_1.Progress value={getTaskProgress(task.status)} className="h-1.5"/>
|
|
2125
|
-
</div>
|
|
2126
|
-
|
|
2127
|
-
<div className="mt-3 flex items-center justify-between gap-3 border-t pt-3">
|
|
2128
|
-
<div className="flex min-w-0 items-center gap-2">
|
|
2129
|
-
<div className="flex size-7 shrink-0 items-center justify-center overflow-hidden rounded-full bg-muted text-[10px] font-semibold uppercase text-muted-foreground ring-1 ring-border">
|
|
2130
|
-
{(() => {
|
|
2131
|
-
const photoUrl = getUserPhotoUrl(task.assigneeUserPhotoId);
|
|
2132
|
-
const avatarUrl = task.assigneePersonAvatarId
|
|
2133
|
-
? getPersonAvatarUrl(task.assigneePersonAvatarId)
|
|
2134
|
-
: null;
|
|
2135
|
-
const imgSrc = photoUrl !== null && photoUrl !== void 0 ? photoUrl : avatarUrl;
|
|
2136
|
-
return imgSrc ? (
|
|
2137
|
-
// eslint-disable-next-line @next/next/no-img-element
|
|
2138
|
-
<img src={imgSrc} alt={task.assigneeName ||
|
|
2139
|
-
commonT('labels.notAssigned')} className="size-full object-cover"/>) : (getInitials(task.assigneeName));
|
|
2140
|
-
})()}
|
|
2141
|
-
</div>
|
|
2142
|
-
<span className="truncate text-[11px] text-muted-foreground">
|
|
2143
|
-
{task.assigneeName ||
|
|
2144
|
-
commonT('labels.notAssigned')}
|
|
2145
|
-
</span>
|
|
2146
|
-
</div>
|
|
2147
|
-
<div className="flex shrink-0 items-center gap-2 text-[11px] text-muted-foreground">
|
|
2148
|
-
<span className="inline-flex items-center gap-1">
|
|
2149
|
-
<lucide_react_1.MessageSquare className="size-3.5"/>
|
|
2150
|
-
{comments}
|
|
2151
|
-
</span>
|
|
2152
|
-
<span className="inline-flex items-center gap-1">
|
|
2153
|
-
<lucide_react_1.Paperclip className="size-3.5"/>
|
|
2154
|
-
{attachments}
|
|
2155
|
-
</span>
|
|
2156
|
-
</div>
|
|
2157
|
-
</div>
|
|
2158
|
-
</framer_motion_1.motion.div>)}
|
|
2159
|
-
</DraggableTaskCard>);
|
|
2160
|
-
})}
|
|
2161
|
-
</framer_motion_1.AnimatePresence>
|
|
2162
|
-
{filteredTaskColumns[column.id].length === 0 ? (<div className="rounded-2xl border border-dashed bg-background/70 p-4 text-center text-xs text-muted-foreground">
|
|
2163
|
-
{boardSearch || boardPriorityFilter !== 'all'
|
|
2164
|
-
? t('kanban.noFilteredTasks')
|
|
2165
|
-
: t('kanban.emptyColumn')}
|
|
2166
|
-
</div>) : null}
|
|
2167
|
-
{!isLimitedView && inlineCreateColumn === column.id ? (<div className="space-y-1.5 rounded-2xl border bg-card p-2 shadow-sm">
|
|
2168
|
-
<input_1.Input autoFocus placeholder={t('taskForm.namePlaceholder')} value={inlineCreateName} onChange={(e) => setInlineCreateName(e.target.value)} onKeyDown={(e) => {
|
|
2169
|
-
if (e.key === 'Enter') {
|
|
2170
|
-
e.preventDefault();
|
|
2171
|
-
void handleInlineCreateTask(column.id, inlineCreateName);
|
|
2172
|
-
}
|
|
2173
|
-
else if (e.key === 'Escape') {
|
|
2174
|
-
setInlineCreateColumn(null);
|
|
2175
|
-
setInlineCreateName('');
|
|
2176
|
-
}
|
|
2177
|
-
}} onBlur={() => {
|
|
2178
|
-
if (!inlineCreateName.trim()) {
|
|
2179
|
-
setInlineCreateColumn(null);
|
|
2180
|
-
setInlineCreateName('');
|
|
2181
|
-
}
|
|
2182
|
-
}} disabled={inlineCreateLoading} className="h-8 text-sm"/>
|
|
2183
|
-
<div className="flex gap-1">
|
|
2184
|
-
<button_1.Button type="button" size="sm" className="h-7 px-2 text-xs" disabled={!inlineCreateName.trim() ||
|
|
2185
|
-
inlineCreateLoading} onMouseDown={(e) => e.preventDefault()} onClick={() => void handleInlineCreateTask(column.id, inlineCreateName)}>
|
|
2186
|
-
{t('taskForm.titleNew')}
|
|
2187
|
-
</button_1.Button>
|
|
2188
|
-
<button_1.Button type="button" variant="ghost" size="sm" className="h-7 px-2 text-xs" onMouseDown={(e) => e.preventDefault()} onClick={() => {
|
|
2189
|
-
setInlineCreateColumn(null);
|
|
2190
|
-
setInlineCreateName('');
|
|
2191
|
-
}}>
|
|
2192
|
-
{commonT('actions.cancel')}
|
|
2193
|
-
</button_1.Button>
|
|
2194
|
-
</div>
|
|
2195
|
-
</div>) : !isLimitedView ? (<button type="button" className="mt-auto flex w-full cursor-pointer items-center justify-center gap-1 rounded-2xl border border-dashed bg-background/70 px-3 py-2 text-xs text-muted-foreground transition hover:border-primary/40 hover:bg-primary/5 hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/50" onClick={() => {
|
|
2196
|
-
setInlineCreateColumn(column.id);
|
|
2197
|
-
setInlineCreateName('');
|
|
2198
|
-
}}>
|
|
2199
|
-
<lucide_react_1.Plus className="size-3"/>
|
|
2200
|
-
{t('taskForm.titleNew')}
|
|
2201
|
-
</button>) : null}
|
|
2202
|
-
</div>
|
|
2203
|
-
</div>)}
|
|
2204
|
-
</DroppableColumn>))}
|
|
2205
|
-
</div>
|
|
2206
|
-
{/* Scroll fade overlay — visible only on mobile/tablet */}
|
|
2207
|
-
<div aria-hidden className="pointer-events-none absolute inset-y-0 right-0 w-16 bg-linear-to-l from-background/80 to-transparent xl:hidden"/>
|
|
2208
|
-
</div>
|
|
2209
|
-
{/* DragOverlay renders the floating card following the pointer */}
|
|
2210
|
-
<core_1.DragOverlay dropAnimation={{ duration: 160, easing: 'ease' }}>
|
|
2211
|
-
{activeDragTask
|
|
2212
|
-
? (() => {
|
|
2213
|
-
const overlayTask = activeDragTask;
|
|
2214
|
-
const overlayTags = getTaskTags(overlayTask);
|
|
2215
|
-
const overlayComments = getTaskCommentCount(overlayTask);
|
|
2216
|
-
const overlayAttachments = getTaskAttachmentCount(overlayTask);
|
|
2217
|
-
return (<div className="w-76 cursor-grabbing rounded-2xl border border-primary/60 bg-card p-3 shadow-2xl ring-2 ring-primary/20 opacity-95">
|
|
2218
|
-
<div className="mb-3 flex items-start justify-between gap-2">
|
|
2219
|
-
<div className="min-w-0 space-y-1">
|
|
2220
|
-
<p className="line-clamp-2 text-sm font-semibold leading-snug">
|
|
2221
|
-
{overlayTask.name}
|
|
2222
|
-
</p>
|
|
2223
|
-
{overlayTask.description ? (<p className="line-clamp-2 text-xs leading-5 text-muted-foreground">
|
|
2224
|
-
{overlayTask.description.replace(/<[^>]*>/g, '')}
|
|
2225
|
-
</p>) : null}
|
|
2226
|
-
</div>
|
|
2227
|
-
<span className={[
|
|
2228
|
-
'shrink-0 rounded-full border px-2 py-0.5 text-[10px] font-semibold uppercase tracking-wide',
|
|
2229
|
-
getPriorityClassName(overlayTask.priority),
|
|
2230
|
-
].join(' ')}>
|
|
2231
|
-
{getTaskPriorityLabel(overlayTask.priority)}
|
|
2232
|
-
</span>
|
|
2233
|
-
</div>
|
|
2234
|
-
|
|
2235
|
-
{overlayTags.length > 0 ? (<div className="mb-3 flex flex-wrap gap-1">
|
|
2236
|
-
{overlayTags.slice(0, 4).map((tag) => (<span key={tag} className="rounded-full border bg-muted/60 px-2 py-0.5 text-[10px] font-medium text-muted-foreground">
|
|
2237
|
-
{tag}
|
|
2238
|
-
</span>))}
|
|
2239
|
-
{overlayTags.length > 4 ? (<span className="rounded-full border bg-muted/60 px-2 py-0.5 text-[10px] font-medium text-muted-foreground">
|
|
2240
|
-
+{overlayTags.length - 4}
|
|
2241
|
-
</span>) : null}
|
|
2242
|
-
</div>) : null}
|
|
2243
|
-
|
|
2244
|
-
<div className="grid grid-cols-2 gap-2 text-xs">
|
|
2245
|
-
<div className={[
|
|
2246
|
-
'rounded-xl border bg-muted/20 px-2 py-1.5',
|
|
2247
|
-
isPastDue(overlayTask.dueDate) &&
|
|
2248
|
-
overlayTask.status !== 'done'
|
|
2249
|
-
? 'border-rose-500/30 bg-rose-500/10 text-rose-700 dark:text-rose-300'
|
|
2250
|
-
: 'text-muted-foreground',
|
|
2251
|
-
].join(' ')}>
|
|
2252
|
-
<span className="flex items-center gap-1">
|
|
2253
|
-
<lucide_react_1.AlarmClock className="size-3.5"/>
|
|
2254
|
-
{(0, format_1.formatDate)(overlayTask.dueDate, getSettingValue, currentLocaleCode)}
|
|
2255
|
-
</span>
|
|
2256
|
-
</div>
|
|
2257
|
-
<div className="rounded-xl border bg-muted/20 px-2 py-1.5 text-muted-foreground">
|
|
2258
|
-
<span className="flex items-center gap-1">
|
|
2259
|
-
<lucide_react_1.Timer className="size-3.5"/>
|
|
2260
|
-
{overlayTask.estimateHours != null
|
|
2261
|
-
? `${overlayTask.estimateHours}h`
|
|
2262
|
-
: t('kanban.noEstimate')}
|
|
2263
|
-
</span>
|
|
2264
|
-
</div>
|
|
2265
|
-
</div>
|
|
2266
|
-
|
|
2267
|
-
<div className="mt-3 space-y-1.5">
|
|
2268
|
-
<div className="flex items-center justify-between text-[11px] text-muted-foreground">
|
|
2269
|
-
<span>{t('kanban.progress')}</span>
|
|
2270
|
-
<span>{getTaskProgress(overlayTask.status)}%</span>
|
|
2271
|
-
</div>
|
|
2272
|
-
<progress_1.Progress value={getTaskProgress(overlayTask.status)} className="h-1.5"/>
|
|
2273
|
-
</div>
|
|
2274
|
-
|
|
2275
|
-
<div className="mt-3 flex items-center justify-between gap-3 border-t pt-3">
|
|
2276
|
-
<div className="flex min-w-0 items-center gap-2">
|
|
2277
|
-
<div className="flex size-7 shrink-0 items-center justify-center overflow-hidden rounded-full bg-muted text-[10px] font-semibold uppercase text-muted-foreground ring-1 ring-border">
|
|
2278
|
-
{(() => {
|
|
2279
|
-
const photoUrl = getUserPhotoUrl(overlayTask.assigneeUserPhotoId);
|
|
2280
|
-
const avatarUrl = overlayTask.assigneePersonAvatarId
|
|
2281
|
-
? getPersonAvatarUrl(overlayTask.assigneePersonAvatarId)
|
|
2282
|
-
: null;
|
|
2283
|
-
const imgSrc = photoUrl !== null && photoUrl !== void 0 ? photoUrl : avatarUrl;
|
|
2284
|
-
return imgSrc ? (
|
|
2285
|
-
// eslint-disable-next-line @next/next/no-img-element
|
|
2286
|
-
<img src={imgSrc} alt={overlayTask.assigneeName ||
|
|
2287
|
-
commonT('labels.notAssigned')} className="size-full object-cover"/>) : (getInitials(overlayTask.assigneeName));
|
|
2288
|
-
})()}
|
|
2289
|
-
</div>
|
|
2290
|
-
<span className="truncate text-[11px] text-muted-foreground">
|
|
2291
|
-
{overlayTask.assigneeName ||
|
|
2292
|
-
commonT('labels.notAssigned')}
|
|
2293
|
-
</span>
|
|
2294
|
-
</div>
|
|
2295
|
-
<div className="flex shrink-0 items-center gap-2 text-[11px] text-muted-foreground">
|
|
2296
|
-
<span className="inline-flex items-center gap-1">
|
|
2297
|
-
<lucide_react_1.MessageSquare className="size-3.5"/>
|
|
2298
|
-
{overlayComments}
|
|
2299
|
-
</span>
|
|
2300
|
-
<span className="inline-flex items-center gap-1">
|
|
2301
|
-
<lucide_react_1.Paperclip className="size-3.5"/>
|
|
2302
|
-
{overlayAttachments}
|
|
2303
|
-
</span>
|
|
2304
|
-
</div>
|
|
2305
|
-
</div>
|
|
2306
|
-
</div>);
|
|
2307
|
-
})()
|
|
2308
|
-
: null}
|
|
2309
|
-
</core_1.DragOverlay>
|
|
2310
|
-
</core_1.DndContext>
|
|
2311
|
-
</section_card_1.SectionCard>
|
|
2312
|
-
|
|
2313
|
-
<section_card_1.SectionCard title={t('sections.timeline')} description={t('sections.timelineDescription')} className="rounded-3xl border bg-card p-4 shadow-sm" actions={<div className="flex flex-wrap items-center gap-2">
|
|
2314
|
-
<select_1.Select value={timelineTypeFilter} onValueChange={(value) => {
|
|
2315
|
-
setTimelineTypeFilter(value);
|
|
2316
|
-
setTimelineVisibleCount(8);
|
|
2317
|
-
}}>
|
|
2318
|
-
<select_1.SelectTrigger className="h-9 w-44 bg-background">
|
|
2319
|
-
<select_1.SelectValue />
|
|
2320
|
-
</select_1.SelectTrigger>
|
|
2321
|
-
<select_1.SelectContent>
|
|
2322
|
-
<select_1.SelectItem value="all">{t('timeline.filters.all')}</select_1.SelectItem>
|
|
2323
|
-
<select_1.SelectItem value="task">
|
|
2324
|
-
{t('timeline.filters.task')}
|
|
2325
|
-
</select_1.SelectItem>
|
|
2326
|
-
<select_1.SelectItem value="status">
|
|
2327
|
-
{t('timeline.filters.status')}
|
|
2328
|
-
</select_1.SelectItem>
|
|
2329
|
-
<select_1.SelectItem value="timesheet">
|
|
2330
|
-
{t('timeline.filters.timesheet')}
|
|
2331
|
-
</select_1.SelectItem>
|
|
2332
|
-
<select_1.SelectItem value="approval">
|
|
2333
|
-
{t('timeline.filters.approval')}
|
|
2334
|
-
</select_1.SelectItem>
|
|
2335
|
-
<select_1.SelectItem value="comment">
|
|
2336
|
-
{t('timeline.filters.comment')}
|
|
2337
|
-
</select_1.SelectItem>
|
|
2338
|
-
</select_1.SelectContent>
|
|
2339
|
-
</select_1.Select>
|
|
2340
|
-
</div>}>
|
|
2341
|
-
<div className="rounded-3xl border bg-linear-to-b from-muted/30 to-background p-4">
|
|
2342
|
-
{groupedTimelineEvents.length > 0 ? (<div className="space-y-6">
|
|
2343
|
-
{groupedTimelineEvents.map((group) => (<div key={group.dayKey} className="space-y-3">
|
|
2344
|
-
<div className="sticky top-0 z-10 w-fit rounded-full border bg-background px-3 py-1 text-xs font-medium text-muted-foreground shadow-xs">
|
|
2345
|
-
{(0, format_1.formatDate)(group.dayKey, getSettingValue, currentLocaleCode)}
|
|
2346
|
-
</div>
|
|
2347
|
-
<div className="space-y-0">
|
|
2348
|
-
{group.events.map((event, index) => {
|
|
2349
|
-
const Icon = event.icon;
|
|
2350
|
-
return (<framer_motion_1.motion.div key={event.id} initial={{ opacity: 0, y: 8 }} animate={{ opacity: 1, y: 0 }} transition={{ duration: 0.18 }} className="grid grid-cols-[2rem_1fr] gap-3">
|
|
2351
|
-
<div className="flex flex-col items-center">
|
|
2352
|
-
<div className={[
|
|
2353
|
-
'flex size-8 items-center justify-center rounded-full shadow-sm',
|
|
2354
|
-
event.toneClassName,
|
|
2355
|
-
].join(' ')}>
|
|
2356
|
-
<Icon className="size-4"/>
|
|
2357
|
-
</div>
|
|
2358
|
-
{index < group.events.length - 1 ? (<div className="w-px flex-1 bg-border"/>) : null}
|
|
2359
|
-
</div>
|
|
2360
|
-
<div className="pb-5">
|
|
2361
|
-
<div className="rounded-2xl border bg-card p-4 shadow-xs transition hover:shadow-sm">
|
|
2362
|
-
<div className="flex flex-col gap-3 sm:flex-row sm:items-start sm:justify-between">
|
|
2363
|
-
<div className="min-w-0">
|
|
2364
|
-
<div className="flex flex-wrap items-center gap-2">
|
|
2365
|
-
<span className="text-sm font-semibold">
|
|
2366
|
-
{event.title}
|
|
2367
|
-
</span>
|
|
2368
|
-
<span className="rounded-full border bg-muted/40 px-2 py-0.5 text-[10px] font-medium text-muted-foreground">
|
|
2369
|
-
{t(`timeline.types.${event.type}`)}
|
|
2370
|
-
</span>
|
|
2371
|
-
</div>
|
|
2372
|
-
<p className="mt-1 line-clamp-2 text-sm text-muted-foreground">
|
|
2373
|
-
{event.description}
|
|
2374
|
-
</p>
|
|
2375
|
-
</div>
|
|
2376
|
-
<div className="shrink-0 text-xs text-muted-foreground">
|
|
2377
|
-
{formatRelativeTime(event.timestamp, currentLocaleCode)}
|
|
2378
|
-
</div>
|
|
2379
|
-
</div>
|
|
2380
|
-
<div className="mt-3 flex items-center gap-2 border-t pt-3">
|
|
2381
|
-
<avatar_1.Avatar className="size-7 border bg-muted">
|
|
2382
|
-
<avatar_1.AvatarImage src={getUserPhotoUrl(event.actorUserPhotoId) ||
|
|
2383
|
-
getPersonAvatarUrl(event.actorAvatarId)} alt={event.actorName ||
|
|
2384
|
-
commonT('labels.notAssigned')}/>
|
|
2385
|
-
<avatar_1.AvatarFallback className="text-[10px]">
|
|
2386
|
-
{getInitials(event.actorName)}
|
|
2387
|
-
</avatar_1.AvatarFallback>
|
|
2388
|
-
</avatar_1.Avatar>
|
|
2389
|
-
<span className="truncate text-xs text-muted-foreground">
|
|
2390
|
-
{event.actorName ||
|
|
2391
|
-
commonT('labels.notAssigned')}
|
|
2392
|
-
</span>
|
|
2393
|
-
</div>
|
|
2394
|
-
</div>
|
|
2395
|
-
</div>
|
|
2396
|
-
</framer_motion_1.motion.div>);
|
|
2397
|
-
})}
|
|
2398
|
-
</div>
|
|
2399
|
-
</div>))}
|
|
2400
|
-
{visibleTimelineEvents.length < filteredTimelineEvents.length ? (<div className="flex justify-center">
|
|
2401
|
-
<button_1.Button type="button" variant="outline" size="sm" onClick={() => setTimelineVisibleCount((current) => current + 8)}>
|
|
2402
|
-
{t('timeline.loadMore')}
|
|
2403
|
-
</button_1.Button>
|
|
2404
|
-
</div>) : null}
|
|
2405
|
-
</div>) : (<div className="flex min-h-56 flex-col items-center justify-center rounded-2xl border border-dashed bg-background p-6 text-center">
|
|
2406
|
-
<div className="flex size-12 items-center justify-center rounded-2xl bg-muted text-muted-foreground">
|
|
2407
|
-
<lucide_react_1.GitCommitHorizontal className="size-6"/>
|
|
2408
|
-
</div>
|
|
2409
|
-
<div className="mt-3 text-sm font-medium">
|
|
2410
|
-
{t('timeline.emptyTitle')}
|
|
2411
|
-
</div>
|
|
2412
|
-
<p className="mt-1 max-w-sm text-xs leading-5 text-muted-foreground">
|
|
2413
|
-
{t('timeline.empty')}
|
|
2414
|
-
</p>
|
|
2415
|
-
</div>)}
|
|
2416
|
-
</div>
|
|
2417
|
-
</section_card_1.SectionCard>
|
|
2418
|
-
|
|
2419
|
-
<section_card_1.SectionCard title={t('sections.archivedTasks')} description={t('sections.archivedTasksDescription')} className="rounded-xl border bg-card p-4 shadow-sm">
|
|
2420
|
-
{archivedTasks.length > 0 ? (<div className="overflow-x-auto rounded-lg border bg-muted/10">
|
|
2421
|
-
<table_1.Table>
|
|
2422
|
-
<table_1.TableHeader>
|
|
2423
|
-
<table_1.TableRow>
|
|
2424
|
-
<table_1.TableHead>{commonT('labels.task')}</table_1.TableHead>
|
|
2425
|
-
<table_1.TableHead>{commonT('labels.status')}</table_1.TableHead>
|
|
2426
|
-
<table_1.TableHead>{t('taskForm.deadlineLabel')}</table_1.TableHead>
|
|
2427
|
-
<table_1.TableHead className="text-right">
|
|
2428
|
-
{commonT('labels.actions')}
|
|
2429
|
-
</table_1.TableHead>
|
|
2430
|
-
</table_1.TableRow>
|
|
2431
|
-
</table_1.TableHeader>
|
|
2432
|
-
<table_1.TableBody>
|
|
2433
|
-
{archivedTasks.map((task) => {
|
|
2434
|
-
var _a, _b;
|
|
2435
|
-
return (<table_1.TableRow key={task.id} className="cursor-pointer hover:bg-muted/30" onClick={() => setSelectedTask(task)}>
|
|
2436
|
-
<table_1.TableCell>
|
|
2437
|
-
<div className="min-w-0">
|
|
2438
|
-
<div className="truncate font-medium">{task.name}</div>
|
|
2439
|
-
{task.description ? (<div className="truncate text-xs text-muted-foreground">
|
|
2440
|
-
{task.description}
|
|
2441
|
-
</div>) : null}
|
|
2442
|
-
</div>
|
|
2443
|
-
</table_1.TableCell>
|
|
2444
|
-
<table_1.TableCell>
|
|
2445
|
-
<status_badge_1.StatusBadge label={(_b = (_a = KANBAN_COLUMNS.find((column) => column.id === task.status)) === null || _a === void 0 ? void 0 : _a.label) !== null && _b !== void 0 ? _b : (0, format_1.formatEnumLabel)(task.status)} className={(0, format_1.getStatusBadgeClass)(task.status)}/>
|
|
2446
|
-
</table_1.TableCell>
|
|
2447
|
-
<table_1.TableCell>
|
|
2448
|
-
{(0, format_1.formatDate)(task.dueDate, getSettingValue, currentLocaleCode)}
|
|
2449
|
-
</table_1.TableCell>
|
|
2450
|
-
<table_1.TableCell>
|
|
2451
|
-
<div className="flex justify-end gap-2">
|
|
2452
|
-
<button_1.Button variant="outline" size="sm" className="gap-2" disabled={restoringTaskId === task.id} onClick={(event) => {
|
|
2453
|
-
event.stopPropagation();
|
|
2454
|
-
void handleRestoreTask(task.id);
|
|
2455
|
-
}}>
|
|
2456
|
-
{restoringTaskId === task.id ? (<lucide_react_1.Loader2 className="size-4 animate-spin"/>) : (<lucide_react_1.ArchiveRestore className="size-4"/>)}
|
|
2457
|
-
{commonT('actions.unarchive')}
|
|
2458
|
-
</button_1.Button>
|
|
2459
|
-
<button_1.Button variant="destructive" size="sm" className="gap-2" onClick={(event) => {
|
|
2460
|
-
event.stopPropagation();
|
|
2461
|
-
setDeletePromptTask(task);
|
|
2462
|
-
}}>
|
|
2463
|
-
<lucide_react_1.Trash2 className="size-4"/>
|
|
2464
|
-
{commonT('actions.delete')}
|
|
2465
|
-
</button_1.Button>
|
|
2466
|
-
</div>
|
|
2467
|
-
</table_1.TableCell>
|
|
2468
|
-
</table_1.TableRow>);
|
|
2469
|
-
})}
|
|
2470
|
-
</table_1.TableBody>
|
|
2471
|
-
</table_1.Table>
|
|
2472
|
-
</div>) : (<ChartEmptyState icon={lucide_react_1.Archive} title={commonT('states.emptyTitle')} description={t('emptyArchivedDescription')}/>)}
|
|
2473
|
-
</section_card_1.SectionCard>
|
|
2474
|
-
|
|
2475
|
-
<div className="grid gap-4 xl:grid-cols-12">
|
|
2476
|
-
<section_card_1.SectionCard title={t('sections.team')} description={t('sections.teamDescription')} className={[
|
|
2477
|
-
'rounded-2xl border bg-card p-4 shadow-sm',
|
|
2478
|
-
isLimitedView ? 'xl:col-span-12' : 'xl:col-span-8',
|
|
2479
|
-
].join(' ')}>
|
|
2480
|
-
{project.assignments.length > 0 ? (<div className="space-y-4">
|
|
2481
|
-
<div className="grid gap-3 sm:grid-cols-3">
|
|
2482
|
-
<div className="rounded-2xl border bg-emerald-500/10 p-3">
|
|
2483
|
-
<div className="text-xs text-muted-foreground">
|
|
2484
|
-
{t('teamPanel.available')}
|
|
2485
|
-
</div>
|
|
2486
|
-
<div className="mt-1 text-2xl font-semibold text-emerald-700 dark:text-emerald-300">
|
|
2487
|
-
{availableAssignments}
|
|
2488
|
-
</div>
|
|
2489
|
-
</div>
|
|
2490
|
-
<div className="rounded-2xl border bg-amber-500/10 p-3">
|
|
2491
|
-
<div className="text-xs text-muted-foreground">
|
|
2492
|
-
{t('teamPanel.highAllocation')}
|
|
2493
|
-
</div>
|
|
2494
|
-
<div className="mt-1 text-2xl font-semibold text-amber-700 dark:text-amber-300">
|
|
2495
|
-
{highAllocationAssignments}
|
|
2496
|
-
</div>
|
|
2497
|
-
</div>
|
|
2498
|
-
<div className="rounded-2xl border bg-rose-500/10 p-3">
|
|
2499
|
-
<div className="text-xs text-muted-foreground">
|
|
2500
|
-
{t('teamPanel.overload')}
|
|
2501
|
-
</div>
|
|
2502
|
-
<div className="mt-1 text-2xl font-semibold text-rose-700 dark:text-rose-300">
|
|
2503
|
-
{overloadedAssignments}
|
|
2504
|
-
</div>
|
|
2505
|
-
</div>
|
|
2506
|
-
</div>
|
|
2507
|
-
|
|
2508
|
-
<div className="grid gap-3 md:grid-cols-2">
|
|
2509
|
-
{project.assignments.map((assignment) => {
|
|
2510
|
-
var _a;
|
|
2511
|
-
const allocationValue = typeof assignment.allocationPercent === 'number'
|
|
2512
|
-
? Math.round(assignment.allocationPercent)
|
|
2513
|
-
: 0;
|
|
2514
|
-
const allocation = clampPercent(allocationValue);
|
|
2515
|
-
const weeklyHours = (_a = assignment.weeklyHours) !== null && _a !== void 0 ? _a : 0;
|
|
2516
|
-
const usedHours = weeklyHours > 0
|
|
2517
|
-
? (weeklyHours * Math.max(allocationValue, 0)) / 100
|
|
2518
|
-
: 0;
|
|
2519
|
-
const availablePercent = Math.max(0, 100 - allocationValue);
|
|
2520
|
-
const availabilityHours = weeklyHours > 0 ? Math.max(0, weeklyHours - usedHours) : 0;
|
|
2521
|
-
const tone = getAllocationTone(allocationValue);
|
|
2522
|
-
const ToneIcon = tone.icon;
|
|
2523
|
-
return (<framer_motion_1.motion.div key={assignment.id} whileHover={{ y: -2 }} className={[
|
|
2524
|
-
'overflow-hidden rounded-2xl border bg-background shadow-xs transition hover:shadow-md',
|
|
2525
|
-
tone.border,
|
|
2526
|
-
].join(' ')}>
|
|
2527
|
-
<div className="border-b bg-linear-to-br from-muted/50 to-background p-4">
|
|
2528
|
-
<div className="flex items-start justify-between gap-3">
|
|
2529
|
-
<div className="flex min-w-0 items-center gap-3">
|
|
2530
|
-
<avatar_1.Avatar className="size-12 border bg-muted">
|
|
2531
|
-
<avatar_1.AvatarImage src={getUserPhotoUrl(assignment.userPhotoId) ||
|
|
2532
|
-
getPersonAvatarUrl(assignment.personAvatarId)} alt={assignment.collaboratorName}/>
|
|
2533
|
-
<avatar_1.AvatarFallback className="text-xs font-semibold">
|
|
2534
|
-
{getInitials(assignment.collaboratorName)}
|
|
2535
|
-
</avatar_1.AvatarFallback>
|
|
2536
|
-
</avatar_1.Avatar>
|
|
2537
|
-
<div className="min-w-0">
|
|
2538
|
-
<div className="truncate text-sm font-semibold">
|
|
2539
|
-
{assignment.collaboratorName}
|
|
2540
|
-
</div>
|
|
2541
|
-
<div className="truncate text-xs text-muted-foreground">
|
|
2542
|
-
{assignment.roleLabel ||
|
|
2543
|
-
commonT('labels.notAssigned')}
|
|
2544
|
-
</div>
|
|
2545
|
-
</div>
|
|
2546
|
-
</div>
|
|
2547
|
-
<div className="flex shrink-0 flex-col items-end gap-2">
|
|
2548
|
-
<status_badge_1.StatusBadge label={(0, format_1.formatEnumLabel)(assignment.status)} className={(0, format_1.getStatusBadgeClass)(assignment.status)}/>
|
|
2549
|
-
<span className={[
|
|
2550
|
-
'inline-flex items-center gap-1 rounded-full border px-2 py-0.5 text-[10px] font-semibold',
|
|
2551
|
-
tone.border,
|
|
2552
|
-
tone.bg,
|
|
2553
|
-
tone.text,
|
|
2554
|
-
].join(' ')}>
|
|
2555
|
-
<ToneIcon className="size-3"/>
|
|
2556
|
-
{t(`teamPanel.status.${tone.labelKey}`)}
|
|
2557
|
-
</span>
|
|
2558
|
-
</div>
|
|
2559
|
-
</div>
|
|
2560
|
-
</div>
|
|
2561
|
-
|
|
2562
|
-
<div className="space-y-4 p-4">
|
|
2563
|
-
<div className="space-y-2">
|
|
2564
|
-
<div className="flex items-center justify-between text-xs">
|
|
2565
|
-
<span className="text-muted-foreground">
|
|
2566
|
-
{commonT('labels.allocationPercent')}
|
|
2567
|
-
</span>
|
|
2568
|
-
<span className={['font-semibold', tone.text].join(' ')}>
|
|
2569
|
-
{(0, format_1.formatPercent)(assignment.allocationPercent)}
|
|
2570
|
-
</span>
|
|
2571
|
-
</div>
|
|
2572
|
-
<progress_1.Progress value={allocation} className={['h-2.5', tone.progress].join(' ')}/>
|
|
2573
|
-
{allocationValue > 100 ? (<div className="flex items-center gap-1 text-xs text-rose-700 dark:text-rose-300">
|
|
2574
|
-
<lucide_react_1.AlertTriangle className="size-3.5"/>
|
|
2575
|
-
{t('teamPanel.overloadWarning', {
|
|
2576
|
-
value: allocationValue - 100,
|
|
2577
|
-
})}
|
|
2578
|
-
</div>) : null}
|
|
2579
|
-
</div>
|
|
2580
|
-
|
|
2581
|
-
<div className="grid grid-cols-2 gap-3 text-xs xl:grid-cols-4">
|
|
2582
|
-
<div className="rounded-xl border bg-muted/20 p-2">
|
|
2583
|
-
<div className="text-muted-foreground">
|
|
2584
|
-
{commonT('labels.weeklyCapacity')}
|
|
2585
|
-
</div>
|
|
2586
|
-
<div className="mt-1 font-semibold">
|
|
2587
|
-
{weeklyHours
|
|
2588
|
-
? (0, format_1.formatHours)(weeklyHours)
|
|
2589
|
-
: commonT('labels.notAvailable')}
|
|
2590
|
-
</div>
|
|
2591
|
-
</div>
|
|
2592
|
-
<div className="rounded-xl border bg-muted/20 p-2">
|
|
2593
|
-
<div className="text-muted-foreground">
|
|
2594
|
-
{t('teamPanel.usedHours')}
|
|
2595
|
-
</div>
|
|
2596
|
-
<div className="mt-1 font-semibold">
|
|
2597
|
-
{weeklyHours
|
|
2598
|
-
? (0, format_1.formatHours)(usedHours)
|
|
2599
|
-
: commonT('labels.notAvailable')}
|
|
2600
|
-
</div>
|
|
2601
|
-
</div>
|
|
2602
|
-
<div className="rounded-xl border bg-muted/20 p-2">
|
|
2603
|
-
<div className="text-muted-foreground">
|
|
2604
|
-
{t('teamPanel.availability')}
|
|
2605
|
-
</div>
|
|
2606
|
-
<div className="mt-1 font-semibold">
|
|
2607
|
-
{weeklyHours
|
|
2608
|
-
? (0, format_1.formatHours)(availabilityHours)
|
|
2609
|
-
: `${clampPercent(availablePercent)}%`}
|
|
2610
|
-
</div>
|
|
2611
|
-
</div>
|
|
2612
|
-
<div className="rounded-xl border bg-muted/20 p-2">
|
|
2613
|
-
<div className="text-muted-foreground">
|
|
2614
|
-
{commonT('labels.timeline')}
|
|
2615
|
-
</div>
|
|
2616
|
-
<div className="mt-1 truncate font-semibold">
|
|
2617
|
-
{(0, format_1.formatDateRange)(assignment.startDate, assignment.endDate, getSettingValue, currentLocaleCode)}
|
|
2618
|
-
</div>
|
|
2619
|
-
</div>
|
|
2620
|
-
</div>
|
|
2621
|
-
</div>
|
|
2622
|
-
</framer_motion_1.motion.div>);
|
|
2623
|
-
})}
|
|
2624
|
-
</div>
|
|
2625
|
-
</div>) : (<ChartEmptyState icon={lucide_react_1.Users} title={commonT('states.emptyTitle')} description={t('noAssignments')}/>)}
|
|
2626
|
-
</section_card_1.SectionCard>
|
|
2627
|
-
|
|
2628
|
-
{!isLimitedView ? (<section_card_1.SectionCard title={t('sections.indicators')} description={t('sections.indicatorsDescription')} className="rounded-xl border bg-card p-4 shadow-sm xl:col-span-4">
|
|
2629
|
-
<div className="grid gap-3 sm:grid-cols-2 xl:grid-cols-1">
|
|
2630
|
-
{[
|
|
2631
|
-
{
|
|
2632
|
-
icon: lucide_react_1.Users,
|
|
2633
|
-
label: t('indicators.activeAssignments'),
|
|
2634
|
-
value: project.operationalIndicators.activeAssignments,
|
|
2635
|
-
tone: 'text-sky-700 dark:text-sky-300',
|
|
2636
|
-
bg: 'bg-sky-500/10',
|
|
2637
|
-
},
|
|
2638
|
-
{
|
|
2639
|
-
icon: lucide_react_1.CheckCircle2,
|
|
2640
|
-
label: t('indicators.completedAssignments'),
|
|
2641
|
-
value: project.operationalIndicators.completedAssignments,
|
|
2642
|
-
tone: 'text-emerald-700 dark:text-emerald-300',
|
|
2643
|
-
bg: 'bg-emerald-500/10',
|
|
2644
|
-
},
|
|
2645
|
-
{
|
|
2646
|
-
icon: lucide_react_1.Gauge,
|
|
2647
|
-
label: t('indicators.averageAllocation'),
|
|
2648
|
-
value: (0, format_1.formatPercent)(project.operationalIndicators.averageAllocation),
|
|
2649
|
-
tone: averageAllocation > 100
|
|
2650
|
-
? 'text-rose-700 dark:text-rose-300'
|
|
2651
|
-
: averageAllocation > 85
|
|
2652
|
-
? 'text-amber-700 dark:text-amber-300'
|
|
2653
|
-
: 'text-emerald-700 dark:text-emerald-300',
|
|
2654
|
-
bg: averageAllocation > 100
|
|
2655
|
-
? 'bg-rose-500/10'
|
|
2656
|
-
: averageAllocation > 85
|
|
2657
|
-
? 'bg-amber-500/10'
|
|
2658
|
-
: 'bg-emerald-500/10',
|
|
2659
|
-
},
|
|
2660
|
-
{
|
|
2661
|
-
icon: lucide_react_1.Timer,
|
|
2662
|
-
label: t('indicators.totalWeeklyHours'),
|
|
2663
|
-
value: (0, format_1.formatHours)(project.operationalIndicators.totalWeeklyHours),
|
|
2664
|
-
tone: 'text-violet-700 dark:text-violet-300',
|
|
2665
|
-
bg: 'bg-violet-500/10',
|
|
2666
|
-
},
|
|
2667
|
-
{
|
|
2668
|
-
icon: lucide_react_1.ClipboardList,
|
|
2669
|
-
label: t('cards.timesheets'),
|
|
2670
|
-
value: project.timesheetSummary.totalTimesheets,
|
|
2671
|
-
tone: 'text-foreground',
|
|
2672
|
-
bg: 'bg-muted/40',
|
|
2673
|
-
},
|
|
2674
|
-
{
|
|
2675
|
-
icon: lucide_react_1.AlarmClock,
|
|
2676
|
-
label: commonT('labels.pending'),
|
|
2677
|
-
value: project.timesheetSummary.pendingTimesheets,
|
|
2678
|
-
tone: project.timesheetSummary.pendingTimesheets > 0
|
|
2679
|
-
? 'text-amber-700 dark:text-amber-300'
|
|
2680
|
-
: 'text-foreground',
|
|
2681
|
-
bg: project.timesheetSummary.pendingTimesheets > 0
|
|
2682
|
-
? 'bg-amber-500/10'
|
|
2683
|
-
: 'bg-muted/40',
|
|
2684
|
-
},
|
|
2685
|
-
{
|
|
2686
|
-
icon: lucide_react_1.BarChart2,
|
|
2687
|
-
label: t('cards.loggedHours'),
|
|
2688
|
-
value: (0, format_1.formatHours)(project.timesheetSummary.totalHours),
|
|
2689
|
-
tone: 'text-sky-700 dark:text-sky-300',
|
|
2690
|
-
bg: 'bg-sky-500/10',
|
|
2691
|
-
},
|
|
2692
|
-
].map(({ icon: Icon, label, value, tone, bg }) => (<div key={label} className="flex items-center gap-3 rounded-xl border bg-card p-3 transition-shadow hover:shadow-sm">
|
|
2693
|
-
<div className={[
|
|
2694
|
-
'flex size-9 shrink-0 items-center justify-center rounded-xl',
|
|
2695
|
-
bg,
|
|
2696
|
-
].join(' ')}>
|
|
2697
|
-
<Icon className={['size-4', tone].join(' ')}/>
|
|
2698
|
-
</div>
|
|
2699
|
-
<div className="min-w-0 flex-1">
|
|
2700
|
-
<div className="truncate text-xs text-muted-foreground">
|
|
2701
|
-
{label}
|
|
2702
|
-
</div>
|
|
2703
|
-
<div className={[
|
|
2704
|
-
'mt-0.5 text-sm font-semibold tabular-nums',
|
|
2705
|
-
tone,
|
|
2706
|
-
].join(' ')}>
|
|
2707
|
-
{value}
|
|
2708
|
-
</div>
|
|
2709
|
-
</div>
|
|
2710
|
-
</div>))}
|
|
2711
|
-
</div>
|
|
2712
|
-
</section_card_1.SectionCard>) : null}
|
|
2713
|
-
</div>
|
|
2714
|
-
|
|
2715
|
-
<section_card_1.SectionCard title={t('sections.costs')} description={t('sections.costsDescription')} className="rounded-2xl border bg-card p-4 shadow-sm">
|
|
2716
|
-
<project_costs_section_1.ProjectCostsSection projectId={projectId}/>
|
|
2717
|
-
</section_card_1.SectionCard>
|
|
2718
|
-
|
|
2719
|
-
<task_detail_sheet_1.TaskDetailSheet task={selectedTask} open={selectedTask !== null} onOpenChange={(open) => {
|
|
2720
|
-
if (!open) {
|
|
2721
|
-
setSelectedTask(null);
|
|
2722
|
-
}
|
|
2723
|
-
}} statusLabel={(status) => { var _a, _b; return (_b = (_a = KANBAN_COLUMNS.find((column) => column.id === status)) === null || _a === void 0 ? void 0 : _a.label) !== null && _b !== void 0 ? _b : status; }} footer={selectedTask && !isLimitedView ? (<div className="grid grid-cols-2 gap-3">
|
|
2724
|
-
{archivedTasks.some((task) => task.id === selectedTask.id) ? (<>
|
|
2725
|
-
<button_1.Button variant="outline" size="sm" className="h-10 gap-2" disabled={restoringTaskId === selectedTask.id} onClick={() => void handleRestoreTask(selectedTask.id)}>
|
|
2726
|
-
{restoringTaskId === selectedTask.id ? (<lucide_react_1.Loader2 className="size-3.5 animate-spin"/>) : (<lucide_react_1.ArchiveRestore className="size-3.5"/>)}
|
|
2727
|
-
{commonT('actions.unarchive')}
|
|
2728
|
-
</button_1.Button>
|
|
2729
|
-
<button_1.Button variant="destructive" size="sm" className="h-10 gap-2" onClick={() => setDeletePromptTask(selectedTask)}>
|
|
2730
|
-
<lucide_react_1.Trash2 className="size-3.5"/>
|
|
2731
|
-
{commonT('actions.delete')}
|
|
2732
|
-
</button_1.Button>
|
|
2733
|
-
</>) : (<button_1.Button variant="outline" size="sm" className="col-span-2 h-10 gap-2" disabled={archivingTaskId === selectedTask.id} onClick={() => void handleArchiveTask(selectedTask.id)}>
|
|
2734
|
-
{archivingTaskId === selectedTask.id ? (<lucide_react_1.Loader2 className="size-3.5 animate-spin"/>) : (<lucide_react_1.Archive className="size-3.5"/>)}
|
|
2735
|
-
{commonT('actions.archive')}
|
|
2736
|
-
</button_1.Button>)}
|
|
2737
|
-
</div>) : null}/>
|
|
2738
|
-
|
|
2739
|
-
{!isLimitedView ? (<sheet_1.Sheet open={isEditSheetOpen} onOpenChange={(open) => {
|
|
2740
|
-
if (!open) {
|
|
2741
|
-
closeEditSheet();
|
|
2742
|
-
}
|
|
2743
|
-
}}>
|
|
2744
|
-
<sheet_1.SheetContent className="w-full overflow-x-hidden overflow-y-auto sm:max-w-[min(92vw,64rem)]">
|
|
2745
|
-
<sheet_1.SheetHeader>
|
|
2746
|
-
<sheet_1.SheetTitle>{formT('editTitle')}</sheet_1.SheetTitle>
|
|
2747
|
-
<sheet_1.SheetDescription>{formT('description')}</sheet_1.SheetDescription>
|
|
2748
|
-
</sheet_1.SheetHeader>
|
|
2749
|
-
|
|
2750
|
-
<project_form_screen_1.ProjectFormScreen projectId={projectId} onCancel={closeEditSheet} onSaved={async () => {
|
|
2751
|
-
closeEditSheet();
|
|
2752
|
-
await refetch();
|
|
2753
|
-
}}/>
|
|
2754
|
-
</sheet_1.SheetContent>
|
|
2755
|
-
</sheet_1.Sheet>) : null}
|
|
2756
|
-
|
|
2757
|
-
{!isLimitedView ? (<sheet_1.Sheet open={taskFormOpen} onOpenChange={(open) => {
|
|
2758
|
-
if (!open) {
|
|
2759
|
-
setTaskFormOpen(false);
|
|
2760
|
-
setEditingTaskId(null);
|
|
2761
|
-
setTaskFormData(EMPTY_TASK_FORM);
|
|
2762
|
-
}
|
|
2763
|
-
}}>
|
|
2764
|
-
<sheet_1.SheetContent className="flex w-full flex-col overflow-hidden sm:max-w-xl">
|
|
2765
|
-
<sheet_1.SheetHeader>
|
|
2766
|
-
<sheet_1.SheetTitle>
|
|
2767
|
-
{editingTaskId
|
|
2768
|
-
? t('taskForm.titleEdit')
|
|
2769
|
-
: t('taskForm.titleNew')}
|
|
2770
|
-
</sheet_1.SheetTitle>
|
|
2771
|
-
</sheet_1.SheetHeader>
|
|
2772
|
-
|
|
2773
|
-
<div className="flex-1 space-y-4 overflow-y-auto px-4 py-2">
|
|
2774
|
-
<div className="space-y-1.5">
|
|
2775
|
-
<label_1.Label htmlFor="task-name">{t('taskForm.nameLabel')} *</label_1.Label>
|
|
2776
|
-
<input_1.Input id="task-name" placeholder={t('taskForm.namePlaceholder')} value={taskFormData.name} onChange={(e) => setTaskFormData((prev) => (Object.assign(Object.assign({}, prev), { name: e.target.value })))}/>
|
|
2777
|
-
</div>
|
|
2778
|
-
|
|
2779
|
-
<div className="space-y-1.5">
|
|
2780
|
-
<label_1.Label htmlFor="task-description">
|
|
2781
|
-
{t('taskForm.descriptionLabel')}
|
|
2782
|
-
</label_1.Label>
|
|
2783
|
-
<rich_text_editor_1.RichTextEditor value={taskFormData.description} onChange={(val) => setTaskFormData((prev) => (Object.assign(Object.assign({}, prev), { description: val })))}/>
|
|
2784
|
-
</div>
|
|
2785
|
-
|
|
2786
|
-
<div className="grid grid-cols-2 gap-3">
|
|
2787
|
-
<div className="space-y-1.5">
|
|
2788
|
-
<label_1.Label>{t('taskForm.priorityLabel')}</label_1.Label>
|
|
2789
|
-
<select_1.Select value={taskFormData.priority} onValueChange={(v) => setTaskFormData((prev) => (Object.assign(Object.assign({}, prev), { priority: v })))}>
|
|
2790
|
-
<select_1.SelectTrigger className="w-full">
|
|
2791
|
-
<select_1.SelectValue />
|
|
2792
|
-
</select_1.SelectTrigger>
|
|
2793
|
-
<select_1.SelectContent>
|
|
2794
|
-
<select_1.SelectItem value="low">
|
|
2795
|
-
{getTaskPriorityLabel('low')}
|
|
2796
|
-
</select_1.SelectItem>
|
|
2797
|
-
<select_1.SelectItem value="medium">
|
|
2798
|
-
{getTaskPriorityLabel('medium')}
|
|
2799
|
-
</select_1.SelectItem>
|
|
2800
|
-
<select_1.SelectItem value="high">
|
|
2801
|
-
{getTaskPriorityLabel('high')}
|
|
2802
|
-
</select_1.SelectItem>
|
|
2803
|
-
</select_1.SelectContent>
|
|
2804
|
-
</select_1.Select>
|
|
2805
|
-
</div>
|
|
2806
|
-
|
|
2807
|
-
<div className="space-y-1.5">
|
|
2808
|
-
<label_1.Label>{t('taskForm.columnLabel')}</label_1.Label>
|
|
2809
|
-
<select_1.Select value={taskFormData.status} onValueChange={(v) => setTaskFormData((prev) => (Object.assign(Object.assign({}, prev), { status: v })))}>
|
|
2810
|
-
<select_1.SelectTrigger className="w-full">
|
|
2811
|
-
<select_1.SelectValue />
|
|
2812
|
-
</select_1.SelectTrigger>
|
|
2813
|
-
<select_1.SelectContent>
|
|
2814
|
-
{KANBAN_COLUMNS.map((col) => (<select_1.SelectItem key={col.id} value={col.id}>
|
|
2815
|
-
{col.label}
|
|
2816
|
-
</select_1.SelectItem>))}
|
|
2817
|
-
</select_1.SelectContent>
|
|
2818
|
-
</select_1.Select>
|
|
2819
|
-
</div>
|
|
2820
|
-
</div>
|
|
2821
|
-
|
|
2822
|
-
<div className="space-y-1.5">
|
|
2823
|
-
<label_1.Label>Responsável</label_1.Label>
|
|
2824
|
-
<select_1.Select value={taskFormData.assigneeCollaboratorId} onValueChange={(value) => setTaskFormData((prev) => (Object.assign(Object.assign({}, prev), { assigneeCollaboratorId: value })))}>
|
|
2825
|
-
<select_1.SelectTrigger className="w-full">
|
|
2826
|
-
<select_1.SelectValue placeholder={commonT('labels.notAssigned')}/>
|
|
2827
|
-
</select_1.SelectTrigger>
|
|
2828
|
-
<select_1.SelectContent>
|
|
2829
|
-
<select_1.SelectItem value="none">
|
|
2830
|
-
{commonT('labels.notAssigned')}
|
|
2831
|
-
</select_1.SelectItem>
|
|
2832
|
-
{taskAssigneeOptions.map((option) => (<select_1.SelectItem key={option.id} value={option.id}>
|
|
2833
|
-
{option.label}
|
|
2834
|
-
</select_1.SelectItem>))}
|
|
2835
|
-
</select_1.SelectContent>
|
|
2836
|
-
</select_1.Select>
|
|
2837
|
-
</div>
|
|
2838
|
-
|
|
2839
|
-
<div className="grid grid-cols-2 gap-3">
|
|
2840
|
-
<div className="space-y-1.5">
|
|
2841
|
-
<label_1.Label htmlFor="task-due-date">
|
|
2842
|
-
{t('taskForm.deadlineLabel')}
|
|
2843
|
-
</label_1.Label>
|
|
2844
|
-
<input_1.Input id="task-due-date" type="date" value={taskFormData.dueDate} onChange={(e) => setTaskFormData((prev) => (Object.assign(Object.assign({}, prev), { dueDate: e.target.value })))}/>
|
|
2845
|
-
</div>
|
|
2846
|
-
|
|
2847
|
-
<div className="space-y-1.5">
|
|
2848
|
-
<label_1.Label htmlFor="task-estimate">
|
|
2849
|
-
{t('taskForm.estimateLabel')}
|
|
2850
|
-
</label_1.Label>
|
|
2851
|
-
<input_1.Input id="task-estimate" type="number" min="0" step="0.5" placeholder="0" value={taskFormData.estimateHours} onChange={(e) => setTaskFormData((prev) => (Object.assign(Object.assign({}, prev), { estimateHours: e.target.value })))}/>
|
|
2852
|
-
</div>
|
|
2853
|
-
</div>
|
|
2854
|
-
|
|
2855
|
-
<div className="space-y-1.5">
|
|
2856
|
-
<label_1.Label htmlFor="task-tags">{t('taskForm.tagsLabel')}</label_1.Label>
|
|
2857
|
-
<input_1.Input id="task-tags" placeholder={t('taskForm.tagsPlaceholder')} value={taskFormData.tags} onChange={(e) => setTaskFormData((prev) => (Object.assign(Object.assign({}, prev), { tags: e.target.value })))}/>
|
|
2858
|
-
</div>
|
|
2859
|
-
|
|
2860
|
-
{editingTaskId ? (<div className="space-y-1.5">
|
|
2861
|
-
<label_1.Label className="flex items-center gap-1.5">
|
|
2862
|
-
<lucide_react_1.Paperclip className="size-3.5"/>
|
|
2863
|
-
{t('taskForm.attachmentsLabel')}
|
|
2864
|
-
</label_1.Label>
|
|
2865
|
-
<task_file_attachments_1.TaskFileAttachments taskId={editingTaskId}/>
|
|
2866
|
-
</div>) : null}
|
|
2867
|
-
</div>
|
|
2868
|
-
|
|
2869
|
-
<div className="mt-4 flex flex-wrap items-center justify-between gap-2 border-t px-4 pb-4 pt-4">
|
|
2870
|
-
<div className="flex gap-2">
|
|
2871
|
-
{editingTaskId ? (<button_1.Button type="button" variant="outline" disabled={taskFormLoading || archivingTaskId === editingTaskId} onClick={() => {
|
|
2872
|
-
if (!editingTaskId)
|
|
2873
|
-
return;
|
|
2874
|
-
const id = editingTaskId;
|
|
2875
|
-
setTaskFormOpen(false);
|
|
2876
|
-
setEditingTaskId(null);
|
|
2877
|
-
setTaskFormData(EMPTY_TASK_FORM);
|
|
2878
|
-
void handleArchiveTask(id);
|
|
2879
|
-
}}>
|
|
2880
|
-
{archivingTaskId === editingTaskId ? (<lucide_react_1.Loader2 className="mr-2 size-4 animate-spin"/>) : (<lucide_react_1.Archive className="mr-2 size-4"/>)}
|
|
2881
|
-
{commonT('actions.archive')}
|
|
2882
|
-
</button_1.Button>) : null}
|
|
2883
|
-
</div>
|
|
2884
|
-
<div className="flex gap-2">
|
|
2885
|
-
<button_1.Button variant="outline" onClick={() => {
|
|
2886
|
-
setTaskFormOpen(false);
|
|
2887
|
-
setEditingTaskId(null);
|
|
2888
|
-
setTaskFormData(EMPTY_TASK_FORM);
|
|
2889
|
-
}} disabled={taskFormLoading}>
|
|
2890
|
-
{commonT('actions.cancel')}
|
|
2891
|
-
</button_1.Button>
|
|
2892
|
-
<button_1.Button onClick={() => void handleTaskFormSubmit()} disabled={taskFormLoading || !taskFormData.name.trim()}>
|
|
2893
|
-
{taskFormLoading
|
|
2894
|
-
? t('taskForm.saving')
|
|
2895
|
-
: editingTaskId
|
|
2896
|
-
? commonT('actions.save')
|
|
2897
|
-
: commonT('actions.create')}
|
|
2898
|
-
</button_1.Button>
|
|
2899
|
-
</div>
|
|
2900
|
-
</div>
|
|
2901
|
-
</sheet_1.SheetContent>
|
|
2902
|
-
</sheet_1.Sheet>) : null}
|
|
2903
|
-
|
|
2904
|
-
{!isLimitedView ? (<>
|
|
2905
|
-
<dialog_1.Dialog open={deletePromptTask !== null} onOpenChange={(open) => {
|
|
2906
|
-
if (!open)
|
|
2907
|
-
setDeletePromptTask(null);
|
|
2908
|
-
}}>
|
|
2909
|
-
<dialog_1.DialogContent className="sm:max-w-sm">
|
|
2910
|
-
<dialog_1.DialogHeader>
|
|
2911
|
-
<dialog_1.DialogTitle>{t('dialogs.deleteTitle')}</dialog_1.DialogTitle>
|
|
2912
|
-
</dialog_1.DialogHeader>
|
|
2913
|
-
<p className="text-sm text-muted-foreground">
|
|
2914
|
-
{t('dialogs.deleteDescription')}
|
|
2915
|
-
</p>
|
|
2916
|
-
<dialog_1.DialogFooter className="mt-4">
|
|
2917
|
-
<button_1.Button variant="outline" onClick={() => setDeletePromptTask(null)}>
|
|
2918
|
-
{commonT('actions.cancel')}
|
|
2919
|
-
</button_1.Button>
|
|
2920
|
-
{deletePromptTask ? (<button_1.Button variant="destructive" disabled={deletingTaskId === deletePromptTask.id} onClick={() => void handleDeleteTask(deletePromptTask.id)}>
|
|
2921
|
-
{deletingTaskId === deletePromptTask.id ? (<lucide_react_1.Loader2 className="mr-2 size-3.5 animate-spin"/>) : null}
|
|
2922
|
-
{commonT('actions.delete')}
|
|
2923
|
-
</button_1.Button>) : null}
|
|
2924
|
-
</dialog_1.DialogFooter>
|
|
2925
|
-
</dialog_1.DialogContent>
|
|
2926
|
-
</dialog_1.Dialog>
|
|
2927
|
-
</>) : null}
|
|
2928
|
-
</entity_list_1.Page>);
|
|
2929
|
-
}
|
|
2930
|
-
//# sourceMappingURL=project-details-screen.js.map
|