@hed-hog/operations 0.0.332 → 0.0.338
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-collaborators.controller.d.ts +0 -54
- package/dist/controllers/operations-collaborators.controller.d.ts.map +1 -1
- package/dist/controllers/operations-collaborators.controller.js +0 -100
- package/dist/controllers/operations-collaborators.controller.js.map +1 -1
- package/dist/controllers/operations-contracts.controller.d.ts +12 -12
- package/dist/operations.service.d.ts +0 -76
- package/dist/operations.service.d.ts.map +1 -1
- package/dist/operations.service.js +7 -230
- package/dist/operations.service.js.map +1 -1
- package/dist/operations.service.spec.js +6 -0
- package/dist/operations.service.spec.js.map +1 -1
- package/hedhog/data/menu.yaml +8 -27
- package/hedhog/data/route.yaml +0 -72
- package/hedhog/frontend/app/_components/collaborator-details-screen.tsx.ejs +476 -0
- package/hedhog/frontend/app/_components/collaborator-form-screen.tsx.ejs +3 -39
- package/hedhog/frontend/app/_components/collaborator-select-with-create.tsx.ejs +261 -0
- package/hedhog/frontend/app/_components/collaborator-tasks-tab.tsx.ejs +358 -358
- package/hedhog/frontend/app/_components/collaborator-timesheets-tab.tsx.ejs +6 -6
- package/hedhog/frontend/app/_components/contract-content-editor.tsx.ejs +258 -0
- package/hedhog/frontend/app/_components/my-project-summary-screen.tsx.ejs +5 -4
- package/hedhog/frontend/app/_components/person-select-with-create.tsx.ejs +1 -0
- package/hedhog/frontend/app/_components/project-assignments-tab.tsx.ejs +10 -218
- package/hedhog/frontend/app/_components/project-cost-report-screen.tsx.ejs +23 -23
- package/hedhog/frontend/app/_components/project-details-screen.tsx.ejs +24 -708
- package/hedhog/frontend/app/_components/project-form-screen.tsx.ejs +38 -158
- package/hedhog/frontend/app/_components/task-detail-sheet.tsx.ejs +1 -5
- package/hedhog/frontend/app/_components/task-form-sheet.tsx.ejs +629 -629
- package/hedhog/frontend/app/_lib/api.ts.ejs +0 -151
- package/hedhog/frontend/app/_lib/types.ts.ejs +0 -1
- package/hedhog/frontend/app/_lib/utils/task-ui.ts.ejs +0 -18
- package/hedhog/frontend/app/my-projects/page.tsx.ejs +2 -16
- package/hedhog/frontend/app/my-tasks/page.tsx.ejs +86 -24
- package/hedhog/frontend/app/projects/page.tsx.ejs +6 -42
- package/hedhog/frontend/messages/en.json +2 -96
- package/hedhog/frontend/messages/operations/operations/en.json +2100 -0
- package/hedhog/frontend/messages/operations/operations/pt.json +2111 -0
- package/hedhog/frontend/messages/pt.json +2 -96
- package/hedhog/frontend/widgets/capacity-distribution.tsx.ejs +16 -16
- package/hedhog/frontend/widgets/effort-by-project.tsx.ejs +16 -16
- package/hedhog/frontend/widgets/headcount-by-area.tsx.ejs +16 -16
- package/hedhog/frontend/widgets/index.ts.ejs +25 -25
- package/hedhog/frontend/widgets/managed-projects-status.tsx.ejs +16 -16
- package/hedhog/frontend/widgets/my-hours-period-kpi.tsx.ejs +16 -16
- package/hedhog/frontend/widgets/my-open-requests-kpi.tsx.ejs +16 -16
- package/hedhog/frontend/widgets/my-pending-requests-list.tsx.ejs +16 -16
- package/hedhog/frontend/widgets/my-project-allocations-kpi.tsx.ejs +16 -16
- package/hedhog/frontend/widgets/my-quick-actions.tsx.ejs +16 -16
- package/hedhog/frontend/widgets/my-relevant-deadlines.tsx.ejs +16 -16
- package/hedhog/frontend/widgets/my-timesheet-status-kpi.tsx.ejs +16 -16
- package/hedhog/frontend/widgets/my-weekly-journey.tsx.ejs +16 -16
- package/hedhog/frontend/widgets/portfolio-costs-kpi.tsx.ejs +16 -16
- package/hedhog/frontend/widgets/portfolio-effort-kpi.tsx.ejs +16 -16
- package/hedhog/frontend/widgets/portfolio-projects-kpi.tsx.ejs +16 -16
- package/hedhog/frontend/widgets/portfolio-risk-kpi.tsx.ejs +16 -16
- package/hedhog/frontend/widgets/project-status-overview.tsx.ejs +16 -16
- package/hedhog/frontend/widgets/shared-operations-widget.tsx.ejs +169 -169
- package/hedhog/frontend/widgets/strategic-deadlines.tsx.ejs +16 -16
- package/hedhog/frontend/widgets/team-approval-queue.tsx.ejs +16 -16
- package/hedhog/frontend/widgets/team-capacity-kpi.tsx.ejs +16 -16
- package/hedhog/frontend/widgets/team-headcount-kpi.tsx.ejs +16 -16
- package/hedhog/frontend/widgets/team-hours-kpi.tsx.ejs +16 -16
- package/hedhog/frontend/widgets/team-pending-approvals-kpi.tsx.ejs +16 -16
- package/hedhog/frontend/widgets/team-utilization-overview.tsx.ejs +16 -16
- package/hedhog/frontend/widgets/team-workload-alerts.tsx.ejs +16 -16
- package/hedhog/table/operations_collaborator.yaml +8 -8
- package/hedhog/table/operations_task.yaml +76 -76
- package/hedhog/table/operations_task_activity.yaml +51 -51
- package/package.json +6 -6
- package/src/controllers/operations-collaborators.controller.ts +8 -117
- package/src/controllers/operations-tasks.controller.ts +156 -156
- package/src/dashboard/widgets/MyQuickActions.tsx +22 -22
- package/src/dto/create-collaborator.dto.ts +4 -4
- package/src/operations.service.spec.ts +1006 -988
- package/src/operations.service.ts +7 -323
- package/dist/dto/create-collaborator-invoice.dto.d.ts +0 -11
- package/dist/dto/create-collaborator-invoice.dto.d.ts.map +0 -1
- package/dist/dto/create-collaborator-invoice.dto.js +0 -55
- package/dist/dto/create-collaborator-invoice.dto.js.map +0 -1
- package/dist/dto/create-collaborator-payment.dto.d.ts +0 -10
- package/dist/dto/create-collaborator-payment.dto.d.ts.map +0 -1
- package/dist/dto/create-collaborator-payment.dto.js +0 -50
- package/dist/dto/create-collaborator-payment.dto.js.map +0 -1
- package/dist/dto/list-collaborator-invoice.dto.d.ts +0 -4
- package/dist/dto/list-collaborator-invoice.dto.d.ts.map +0 -1
- package/dist/dto/list-collaborator-invoice.dto.js +0 -8
- package/dist/dto/list-collaborator-invoice.dto.js.map +0 -1
- package/dist/dto/list-collaborator-payment.dto.d.ts +0 -4
- package/dist/dto/list-collaborator-payment.dto.d.ts.map +0 -1
- package/dist/dto/list-collaborator-payment.dto.js +0 -8
- package/dist/dto/list-collaborator-payment.dto.js.map +0 -1
- package/dist/dto/update-collaborator-invoice.dto.d.ts +0 -6
- package/dist/dto/update-collaborator-invoice.dto.d.ts.map +0 -1
- package/dist/dto/update-collaborator-invoice.dto.js +0 -9
- package/dist/dto/update-collaborator-invoice.dto.js.map +0 -1
- package/dist/dto/update-collaborator-payment.dto.d.ts +0 -6
- package/dist/dto/update-collaborator-payment.dto.d.ts.map +0 -1
- package/dist/dto/update-collaborator-payment.dto.js +0 -9
- package/dist/dto/update-collaborator-payment.dto.js.map +0 -1
- package/hedhog/frontend/app/_components/collaborator-invoices-tab.tsx.ejs +0 -443
- package/hedhog/frontend/app/_components/collaborator-payment-history-tab.tsx.ejs +0 -429
- package/hedhog/frontend/app/tasks-gantt/page.tsx.ejs +0 -953
- package/hedhog/table/operations_collaborator_invoice.yaml +0 -35
- package/hedhog/table/operations_collaborator_payment.yaml +0 -32
- package/src/dto/create-collaborator-invoice.dto.ts +0 -39
- package/src/dto/create-collaborator-payment.dto.ts +0 -35
- package/src/dto/list-collaborator-invoice.dto.ts +0 -3
- package/src/dto/list-collaborator-payment.dto.ts +0 -3
- package/src/dto/update-collaborator-invoice.dto.ts +0 -6
- package/src/dto/update-collaborator-payment.dto.ts +0 -6
|
@@ -478,154 +478,3 @@ export function deleteTaskComment(
|
|
|
478
478
|
'DELETE'
|
|
479
479
|
);
|
|
480
480
|
}
|
|
481
|
-
|
|
482
|
-
// ─── Collaborator Payments ────────────────────────────────────────────────────
|
|
483
|
-
|
|
484
|
-
export type CollaboratorPayment = {
|
|
485
|
-
id: number;
|
|
486
|
-
collaboratorId: number;
|
|
487
|
-
amount: string;
|
|
488
|
-
paymentDate: string;
|
|
489
|
-
referenceMonth: string | null;
|
|
490
|
-
paymentMethod: string;
|
|
491
|
-
notes: string | null;
|
|
492
|
-
createdAt: string;
|
|
493
|
-
};
|
|
494
|
-
|
|
495
|
-
export function fetchCollaboratorPayments(
|
|
496
|
-
request: RequestFn,
|
|
497
|
-
collaboratorId: number
|
|
498
|
-
) {
|
|
499
|
-
return fetchOperations<CollaboratorPayment[]>(
|
|
500
|
-
request,
|
|
501
|
-
`/operations/collaborators/${collaboratorId}/payment-history`
|
|
502
|
-
);
|
|
503
|
-
}
|
|
504
|
-
|
|
505
|
-
export function createCollaboratorPayment(
|
|
506
|
-
request: RequestFn,
|
|
507
|
-
collaboratorId: number,
|
|
508
|
-
data: {
|
|
509
|
-
amount: number;
|
|
510
|
-
paymentDate: string;
|
|
511
|
-
referenceMonth?: string | null;
|
|
512
|
-
paymentMethod?: string;
|
|
513
|
-
notes?: string | null;
|
|
514
|
-
}
|
|
515
|
-
) {
|
|
516
|
-
return mutateOperations<CollaboratorPayment>(
|
|
517
|
-
request,
|
|
518
|
-
`/operations/collaborators/${collaboratorId}/payment-history`,
|
|
519
|
-
'POST',
|
|
520
|
-
data
|
|
521
|
-
);
|
|
522
|
-
}
|
|
523
|
-
|
|
524
|
-
export function updateCollaboratorPayment(
|
|
525
|
-
request: RequestFn,
|
|
526
|
-
collaboratorId: number,
|
|
527
|
-
paymentId: number,
|
|
528
|
-
data: Partial<{
|
|
529
|
-
amount: number;
|
|
530
|
-
paymentDate: string;
|
|
531
|
-
referenceMonth: string | null;
|
|
532
|
-
paymentMethod: string;
|
|
533
|
-
notes: string | null;
|
|
534
|
-
}>
|
|
535
|
-
) {
|
|
536
|
-
return mutateOperations<CollaboratorPayment>(
|
|
537
|
-
request,
|
|
538
|
-
`/operations/collaborators/${collaboratorId}/payment-history/${paymentId}`,
|
|
539
|
-
'PATCH',
|
|
540
|
-
data
|
|
541
|
-
);
|
|
542
|
-
}
|
|
543
|
-
|
|
544
|
-
export function deleteCollaboratorPayment(
|
|
545
|
-
request: RequestFn,
|
|
546
|
-
collaboratorId: number,
|
|
547
|
-
paymentId: number
|
|
548
|
-
) {
|
|
549
|
-
return mutateOperations<{ success: boolean }>(
|
|
550
|
-
request,
|
|
551
|
-
`/operations/collaborators/${collaboratorId}/payment-history/${paymentId}`,
|
|
552
|
-
'DELETE'
|
|
553
|
-
);
|
|
554
|
-
}
|
|
555
|
-
|
|
556
|
-
// ─── Collaborator Invoices ────────────────────────────────────────────────────
|
|
557
|
-
|
|
558
|
-
export type CollaboratorInvoice = {
|
|
559
|
-
id: number;
|
|
560
|
-
collaboratorId: number;
|
|
561
|
-
invoiceNumber: string | null;
|
|
562
|
-
amount: string;
|
|
563
|
-
issueDate: string;
|
|
564
|
-
dueDate: string | null;
|
|
565
|
-
status: string;
|
|
566
|
-
description: string | null;
|
|
567
|
-
createdAt: string;
|
|
568
|
-
};
|
|
569
|
-
|
|
570
|
-
export function fetchCollaboratorInvoices(
|
|
571
|
-
request: RequestFn,
|
|
572
|
-
collaboratorId: number
|
|
573
|
-
) {
|
|
574
|
-
return fetchOperations<CollaboratorInvoice[]>(
|
|
575
|
-
request,
|
|
576
|
-
`/operations/collaborators/${collaboratorId}/invoices`
|
|
577
|
-
);
|
|
578
|
-
}
|
|
579
|
-
|
|
580
|
-
export function createCollaboratorInvoice(
|
|
581
|
-
request: RequestFn,
|
|
582
|
-
collaboratorId: number,
|
|
583
|
-
data: {
|
|
584
|
-
invoiceNumber?: string | null;
|
|
585
|
-
amount: number;
|
|
586
|
-
issueDate: string;
|
|
587
|
-
dueDate?: string | null;
|
|
588
|
-
status?: string;
|
|
589
|
-
description?: string | null;
|
|
590
|
-
}
|
|
591
|
-
) {
|
|
592
|
-
return mutateOperations<CollaboratorInvoice>(
|
|
593
|
-
request,
|
|
594
|
-
`/operations/collaborators/${collaboratorId}/invoices`,
|
|
595
|
-
'POST',
|
|
596
|
-
data
|
|
597
|
-
);
|
|
598
|
-
}
|
|
599
|
-
|
|
600
|
-
export function updateCollaboratorInvoice(
|
|
601
|
-
request: RequestFn,
|
|
602
|
-
collaboratorId: number,
|
|
603
|
-
invoiceId: number,
|
|
604
|
-
data: Partial<{
|
|
605
|
-
invoiceNumber: string | null;
|
|
606
|
-
amount: number;
|
|
607
|
-
issueDate: string;
|
|
608
|
-
dueDate: string | null;
|
|
609
|
-
status: string;
|
|
610
|
-
description: string | null;
|
|
611
|
-
}>
|
|
612
|
-
) {
|
|
613
|
-
return mutateOperations<CollaboratorInvoice>(
|
|
614
|
-
request,
|
|
615
|
-
`/operations/collaborators/${collaboratorId}/invoices/${invoiceId}`,
|
|
616
|
-
'PATCH',
|
|
617
|
-
data
|
|
618
|
-
);
|
|
619
|
-
}
|
|
620
|
-
|
|
621
|
-
export function deleteCollaboratorInvoice(
|
|
622
|
-
request: RequestFn,
|
|
623
|
-
collaboratorId: number,
|
|
624
|
-
invoiceId: number
|
|
625
|
-
) {
|
|
626
|
-
return mutateOperations<{ success: boolean }>(
|
|
627
|
-
request,
|
|
628
|
-
`/operations/collaborators/${collaboratorId}/invoices/${invoiceId}`,
|
|
629
|
-
'DELETE'
|
|
630
|
-
);
|
|
631
|
-
}
|
|
@@ -435,7 +435,6 @@ export type OperationsProject = {
|
|
|
435
435
|
managerCollaboratorId?: number | null;
|
|
436
436
|
clientPersonId?: number | null;
|
|
437
437
|
clientAvatarId?: number | null;
|
|
438
|
-
clientUserPhotoId?: number | null;
|
|
439
438
|
code: string;
|
|
440
439
|
name: string;
|
|
441
440
|
clientName?: string | null;
|
|
@@ -41,21 +41,3 @@ export function formatDurationMinutes(minutes?: number | null) {
|
|
|
41
41
|
if (remainingMinutes <= 0) return `${hours}h`;
|
|
42
42
|
return `${hours}h ${remainingMinutes}min`;
|
|
43
43
|
}
|
|
44
|
-
|
|
45
|
-
export function getTaskDescriptionPreview(value?: string | null) {
|
|
46
|
-
if (!value) return '';
|
|
47
|
-
|
|
48
|
-
return String(value)
|
|
49
|
-
.replace(/<br\s*\/?>/gi, ' ')
|
|
50
|
-
.replace(/<\/(p|div|li|ul|ol|h1|h2|h3|h4|h5|h6)>/gi, ' ')
|
|
51
|
-
.replace(/<li[^>]*>/gi, ' ')
|
|
52
|
-
.replace(/<[^>]*>/g, '')
|
|
53
|
-
.replace(/ /gi, ' ')
|
|
54
|
-
.replace(/&/gi, '&')
|
|
55
|
-
.replace(/</gi, '<')
|
|
56
|
-
.replace(/>/gi, '>')
|
|
57
|
-
.replace(/'/gi, "'")
|
|
58
|
-
.replace(/"/gi, '"')
|
|
59
|
-
.replace(/\s+/g, ' ')
|
|
60
|
-
.trim();
|
|
61
|
-
}
|
|
@@ -49,12 +49,6 @@ function getPersonAvatarUrl(avatarId?: number | null): string {
|
|
|
49
49
|
: '/placeholder.png';
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
-
function getUserPhotoUrl(photoId?: number | null): string {
|
|
53
|
-
return typeof photoId === 'number' && photoId > 0
|
|
54
|
-
? `${process.env.NEXT_PUBLIC_API_BASE_URL}/user/avatar/${photoId}`
|
|
55
|
-
: '/placeholder.png';
|
|
56
|
-
}
|
|
57
|
-
|
|
58
52
|
function getInitials(value?: string | null): string {
|
|
59
53
|
if (!value) return '?';
|
|
60
54
|
return value
|
|
@@ -299,11 +293,7 @@ export default function OperationsMyProjectsPage() {
|
|
|
299
293
|
</span>
|
|
300
294
|
<Avatar className="h-5 w-5 shrink-0">
|
|
301
295
|
<AvatarImage
|
|
302
|
-
src={
|
|
303
|
-
project.clientUserPhotoId
|
|
304
|
-
? getUserPhotoUrl(project.clientUserPhotoId)
|
|
305
|
-
: getPersonAvatarUrl(project.clientAvatarId)
|
|
306
|
-
}
|
|
296
|
+
src={getPersonAvatarUrl(project.clientAvatarId)}
|
|
307
297
|
alt={project.clientName ?? ''}
|
|
308
298
|
/>
|
|
309
299
|
<AvatarFallback className="text-[9px] font-medium">
|
|
@@ -412,11 +402,7 @@ export default function OperationsMyProjectsPage() {
|
|
|
412
402
|
<div className="flex min-w-0 items-center gap-1.5">
|
|
413
403
|
<Avatar className="h-6 w-6 shrink-0">
|
|
414
404
|
<AvatarImage
|
|
415
|
-
src={
|
|
416
|
-
project.clientUserPhotoId
|
|
417
|
-
? getUserPhotoUrl(project.clientUserPhotoId)
|
|
418
|
-
: getPersonAvatarUrl(project.clientAvatarId)
|
|
419
|
-
}
|
|
405
|
+
src={getPersonAvatarUrl(project.clientAvatarId)}
|
|
420
406
|
alt={project.clientName ?? ''}
|
|
421
407
|
/>
|
|
422
408
|
<AvatarFallback className="text-[9px] font-medium">
|
|
@@ -6,7 +6,6 @@ import {
|
|
|
6
6
|
PaginationFooter,
|
|
7
7
|
SearchBar,
|
|
8
8
|
} from '@/components/entity-list';
|
|
9
|
-
import { RichTextEditor } from '@/components/rich-text-editor';
|
|
10
9
|
import { Button } from '@/components/ui/button';
|
|
11
10
|
import { Card, CardContent } from '@/components/ui/card';
|
|
12
11
|
import {
|
|
@@ -44,7 +43,7 @@ import {
|
|
|
44
43
|
} from '@/components/ui/table';
|
|
45
44
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
|
|
46
45
|
import { ToggleGroup, ToggleGroupItem } from '@/components/ui/toggle-group';
|
|
47
|
-
import {
|
|
46
|
+
import { RichTextEditor } from '@/components/rich-text-editor';
|
|
48
47
|
import {
|
|
49
48
|
closestCenter,
|
|
50
49
|
DndContext,
|
|
@@ -87,14 +86,15 @@ import { useCallback, useMemo, useState } from 'react';
|
|
|
87
86
|
import { OperationsHeader } from '../_components/operations-header';
|
|
88
87
|
import { StatusBadge } from '../_components/status-badge';
|
|
89
88
|
import {
|
|
90
|
-
TaskCommentsSection,
|
|
91
89
|
TaskDetailSheet,
|
|
90
|
+
TaskCommentsSection,
|
|
92
91
|
type TaskDetailSheetData,
|
|
93
92
|
} from '../_components/task-detail-sheet';
|
|
94
93
|
import { TaskFileAttachments } from '../_components/task-file-attachments';
|
|
95
94
|
import { TimesheetEntryCreateSheet } from '../_components/timesheet-entry-create-sheet';
|
|
96
95
|
import { fetchOperations, mutateOperations } from '../_lib/api';
|
|
97
96
|
import { useMentionItems } from '../_lib/hooks/use-mention-items';
|
|
97
|
+
import { usePersistedPageSize } from '@/hooks/use-persisted-page-size';
|
|
98
98
|
import type {
|
|
99
99
|
OperationsCollaborator,
|
|
100
100
|
OperationsProjectOption,
|
|
@@ -102,7 +102,6 @@ import type {
|
|
|
102
102
|
PaginatedResponse,
|
|
103
103
|
} from '../_lib/types';
|
|
104
104
|
import { formatDate, getStatusBadgeClass } from '../_lib/utils/format';
|
|
105
|
-
import { getTaskDescriptionPreview } from '../_lib/utils/task-ui';
|
|
106
105
|
|
|
107
106
|
type TaskViewMode = 'table' | 'cards' | 'board';
|
|
108
107
|
|
|
@@ -706,13 +705,9 @@ export default function OperationsMyTasksPage() {
|
|
|
706
705
|
[inlineCreateName, request, refetchBoard]
|
|
707
706
|
);
|
|
708
707
|
|
|
709
|
-
const openCreateTaskForm = useCallback((
|
|
708
|
+
const openCreateTaskForm = useCallback(() => {
|
|
710
709
|
setEditingTaskId(null);
|
|
711
710
|
setSelectedTask(null);
|
|
712
|
-
setTaskFormData((prev) => ({
|
|
713
|
-
...EMPTY_TASK_FORM,
|
|
714
|
-
...(status ? { status } : { status: prev.status }),
|
|
715
|
-
}));
|
|
716
711
|
setTaskFormOpen(true);
|
|
717
712
|
}, []);
|
|
718
713
|
|
|
@@ -938,7 +933,7 @@ export default function OperationsMyTasksPage() {
|
|
|
938
933
|
{(isOver) => (
|
|
939
934
|
<div
|
|
940
935
|
className={[
|
|
941
|
-
'flex min-h-
|
|
936
|
+
'flex min-h-128 flex-col overflow-hidden rounded-3xl border bg-linear-to-b p-3 transition-all',
|
|
942
937
|
getColumnClassName(column.id),
|
|
943
938
|
isOver
|
|
944
939
|
? 'border-primary shadow-lg ring-2 ring-primary/15'
|
|
@@ -968,14 +963,17 @@ export default function OperationsMyTasksPage() {
|
|
|
968
963
|
<button
|
|
969
964
|
type="button"
|
|
970
965
|
className="flex size-5 cursor-pointer items-center justify-center rounded-full text-muted-foreground transition hover:bg-muted hover:text-foreground"
|
|
971
|
-
onClick={() =>
|
|
966
|
+
onClick={() => {
|
|
967
|
+
setInlineCreateColumn(column.id);
|
|
968
|
+
setInlineCreateName('');
|
|
969
|
+
}}
|
|
972
970
|
>
|
|
973
971
|
<Plus className="size-3.5" />
|
|
974
972
|
</button>
|
|
975
973
|
</div>
|
|
976
974
|
</div>
|
|
977
975
|
|
|
978
|
-
<div className="flex
|
|
976
|
+
<div className="flex flex-1 flex-col gap-2">
|
|
979
977
|
<AnimatePresence initial={false}>
|
|
980
978
|
{boardColumns[column.id].map((task) => {
|
|
981
979
|
const taskTags = task.tags
|
|
@@ -1027,8 +1025,9 @@ export default function OperationsMyTasksPage() {
|
|
|
1027
1025
|
</p>
|
|
1028
1026
|
{task.description ? (
|
|
1029
1027
|
<p className="line-clamp-2 text-xs leading-5 text-muted-foreground">
|
|
1030
|
-
{
|
|
1031
|
-
|
|
1028
|
+
{task.description.replace(
|
|
1029
|
+
/<[^>]*>/g,
|
|
1030
|
+
''
|
|
1032
1031
|
)}
|
|
1033
1032
|
</p>
|
|
1034
1033
|
) : null}
|
|
@@ -1152,14 +1151,76 @@ export default function OperationsMyTasksPage() {
|
|
|
1152
1151
|
</AnimatePresence>
|
|
1153
1152
|
</div>
|
|
1154
1153
|
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1154
|
+
{inlineCreateColumn === column.id ? (
|
|
1155
|
+
<div className="space-y-1.5 rounded-lg border bg-card p-2">
|
|
1156
|
+
<Input
|
|
1157
|
+
autoFocus
|
|
1158
|
+
placeholder={detailT('taskForm.namePlaceholder')}
|
|
1159
|
+
value={inlineCreateName}
|
|
1160
|
+
onChange={(e) =>
|
|
1161
|
+
setInlineCreateName(e.target.value)
|
|
1162
|
+
}
|
|
1163
|
+
onKeyDown={(e) => {
|
|
1164
|
+
if (e.key === 'Enter') {
|
|
1165
|
+
e.preventDefault();
|
|
1166
|
+
void handleInlineCreateTask(column.id);
|
|
1167
|
+
} else if (e.key === 'Escape') {
|
|
1168
|
+
setInlineCreateColumn(null);
|
|
1169
|
+
setInlineCreateName('');
|
|
1170
|
+
}
|
|
1171
|
+
}}
|
|
1172
|
+
onBlur={() => {
|
|
1173
|
+
if (!inlineCreateName.trim()) {
|
|
1174
|
+
setInlineCreateColumn(null);
|
|
1175
|
+
setInlineCreateName('');
|
|
1176
|
+
}
|
|
1177
|
+
}}
|
|
1178
|
+
disabled={inlineCreateLoading}
|
|
1179
|
+
className="h-8 text-sm"
|
|
1180
|
+
/>
|
|
1181
|
+
<div className="flex gap-1">
|
|
1182
|
+
<Button
|
|
1183
|
+
type="button"
|
|
1184
|
+
size="sm"
|
|
1185
|
+
className="h-7 px-2 text-xs"
|
|
1186
|
+
disabled={
|
|
1187
|
+
!inlineCreateName.trim() || inlineCreateLoading
|
|
1188
|
+
}
|
|
1189
|
+
onMouseDown={(e) => e.preventDefault()}
|
|
1190
|
+
onClick={() =>
|
|
1191
|
+
void handleInlineCreateTask(column.id)
|
|
1192
|
+
}
|
|
1193
|
+
>
|
|
1194
|
+
{t('actions.create')}
|
|
1195
|
+
</Button>
|
|
1196
|
+
<Button
|
|
1197
|
+
type="button"
|
|
1198
|
+
variant="ghost"
|
|
1199
|
+
size="sm"
|
|
1200
|
+
className="h-7 px-2 text-xs"
|
|
1201
|
+
onMouseDown={(e) => e.preventDefault()}
|
|
1202
|
+
onClick={() => {
|
|
1203
|
+
setInlineCreateColumn(null);
|
|
1204
|
+
setInlineCreateName('');
|
|
1205
|
+
}}
|
|
1206
|
+
>
|
|
1207
|
+
{commonT('actions.cancel')}
|
|
1208
|
+
</Button>
|
|
1209
|
+
</div>
|
|
1210
|
+
</div>
|
|
1211
|
+
) : (
|
|
1212
|
+
<button
|
|
1213
|
+
type="button"
|
|
1214
|
+
className="flex w-full cursor-pointer items-center gap-1 rounded-md px-1 py-1 text-xs text-muted-foreground transition hover:bg-muted hover:text-foreground"
|
|
1215
|
+
onClick={() => {
|
|
1216
|
+
setInlineCreateColumn(column.id);
|
|
1217
|
+
setInlineCreateName('');
|
|
1218
|
+
}}
|
|
1219
|
+
>
|
|
1220
|
+
<Plus className="size-3" />
|
|
1221
|
+
{t('actions.create')}
|
|
1222
|
+
</button>
|
|
1223
|
+
)}
|
|
1163
1224
|
</div>
|
|
1164
1225
|
)}
|
|
1165
1226
|
</DroppableColumn>
|
|
@@ -1215,7 +1276,7 @@ export default function OperationsMyTasksPage() {
|
|
|
1215
1276
|
|
|
1216
1277
|
{task.description ? (
|
|
1217
1278
|
<p className="line-clamp-3 text-sm text-muted-foreground">
|
|
1218
|
-
{
|
|
1279
|
+
{task.description}
|
|
1219
1280
|
</p>
|
|
1220
1281
|
) : null}
|
|
1221
1282
|
|
|
@@ -1264,7 +1325,7 @@ export default function OperationsMyTasksPage() {
|
|
|
1264
1325
|
<div className="truncate font-medium">{task.name}</div>
|
|
1265
1326
|
{task.description ? (
|
|
1266
1327
|
<div className="truncate text-xs text-muted-foreground">
|
|
1267
|
-
{
|
|
1328
|
+
{task.description}
|
|
1268
1329
|
</div>
|
|
1269
1330
|
) : null}
|
|
1270
1331
|
</div>
|
|
@@ -1465,6 +1526,7 @@ export default function OperationsMyTasksPage() {
|
|
|
1465
1526
|
</DialogContent>
|
|
1466
1527
|
</Dialog>
|
|
1467
1528
|
|
|
1529
|
+
|
|
1468
1530
|
<Sheet
|
|
1469
1531
|
open={taskFormOpen}
|
|
1470
1532
|
onOpenChange={(open) => {
|
|
@@ -194,15 +194,9 @@ function DroppableProjectColumn({
|
|
|
194
194
|
return <div ref={setNodeRef}>{children(isOver)}</div>;
|
|
195
195
|
}
|
|
196
196
|
|
|
197
|
-
function getPersonAvatarUrl(avatarId?: number | null) {
|
|
197
|
+
function getPersonAvatarUrl(avatarId?: number | null): string {
|
|
198
198
|
return typeof avatarId === 'number' && avatarId > 0
|
|
199
199
|
? `${process.env.NEXT_PUBLIC_API_BASE_URL}/person/avatar/${avatarId}`
|
|
200
|
-
: undefined;
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
function getUserPhotoUrl(photoId?: number | null) {
|
|
204
|
-
return typeof photoId === 'number' && photoId > 0
|
|
205
|
-
? `${process.env.NEXT_PUBLIC_API_BASE_URL}/user/avatar/${photoId}`
|
|
206
200
|
: '/placeholder.png';
|
|
207
201
|
}
|
|
208
202
|
|
|
@@ -512,31 +506,9 @@ export default function OperationsProjectsPage() {
|
|
|
512
506
|
>
|
|
513
507
|
<CardContent className="space-y-2 p-3">
|
|
514
508
|
<div className="truncate text-sm font-semibold">{project.name}</div>
|
|
515
|
-
<div className="
|
|
516
|
-
{project.clientName
|
|
517
|
-
|
|
518
|
-
<span className="truncate">{project.code || '—'}</span>
|
|
519
|
-
<span>•</span>
|
|
520
|
-
<Avatar className="h-4 w-4 shrink-0">
|
|
521
|
-
<AvatarImage
|
|
522
|
-
src={
|
|
523
|
-
project.clientUserPhotoId
|
|
524
|
-
? getUserPhotoUrl(project.clientUserPhotoId)
|
|
525
|
-
: getPersonAvatarUrl(project.clientAvatarId)
|
|
526
|
-
}
|
|
527
|
-
alt={project.clientName}
|
|
528
|
-
/>
|
|
529
|
-
<AvatarFallback className="text-[8px] font-medium">
|
|
530
|
-
{getInitials(project.clientName)}
|
|
531
|
-
</AvatarFallback>
|
|
532
|
-
</Avatar>
|
|
533
|
-
<span className="truncate">{project.clientName}</span>
|
|
534
|
-
</>
|
|
535
|
-
) : (
|
|
536
|
-
<span className="truncate">
|
|
537
|
-
{project.code || commonT('labels.notAvailable')}
|
|
538
|
-
</span>
|
|
539
|
-
)}
|
|
509
|
+
<div className="truncate text-xs text-muted-foreground">
|
|
510
|
+
{[project.code, project.clientName].filter(Boolean).join(' • ') ||
|
|
511
|
+
commonT('labels.notAvailable')}
|
|
540
512
|
</div>
|
|
541
513
|
<div className="flex items-center justify-between gap-2 pt-1">
|
|
542
514
|
<StatusBadge
|
|
@@ -786,11 +758,7 @@ export default function OperationsProjectsPage() {
|
|
|
786
758
|
</span>
|
|
787
759
|
<Avatar className="h-5 w-5 shrink-0">
|
|
788
760
|
<AvatarImage
|
|
789
|
-
src={
|
|
790
|
-
project.clientUserPhotoId
|
|
791
|
-
? getUserPhotoUrl(project.clientUserPhotoId)
|
|
792
|
-
: getPersonAvatarUrl(project.clientAvatarId)
|
|
793
|
-
}
|
|
761
|
+
src={getPersonAvatarUrl(project.clientAvatarId)}
|
|
794
762
|
alt={project.clientName ?? ''}
|
|
795
763
|
/>
|
|
796
764
|
<AvatarFallback className="text-[9px] font-medium">
|
|
@@ -995,11 +963,7 @@ export default function OperationsProjectsPage() {
|
|
|
995
963
|
<div className="flex min-w-0 items-center gap-1.5">
|
|
996
964
|
<Avatar className="h-6 w-6 shrink-0">
|
|
997
965
|
<AvatarImage
|
|
998
|
-
src={
|
|
999
|
-
project.clientUserPhotoId
|
|
1000
|
-
? getUserPhotoUrl(project.clientUserPhotoId)
|
|
1001
|
-
: getPersonAvatarUrl(project.clientAvatarId)
|
|
1002
|
-
}
|
|
966
|
+
src={getPersonAvatarUrl(project.clientAvatarId)}
|
|
1003
967
|
alt={project.clientName ?? ''}
|
|
1004
968
|
/>
|
|
1005
969
|
<AvatarFallback className="text-[9px] font-medium">
|
|
@@ -306,11 +306,7 @@
|
|
|
306
306
|
"projects": "Projects",
|
|
307
307
|
"tasks": "Tasks",
|
|
308
308
|
"timesheets": "Timesheets",
|
|
309
|
-
"salary": "Compensation"
|
|
310
|
-
"paymentHistory": "Payment History",
|
|
311
|
-
"paymentHistoryEmpty": "No payment records found for this collaborator.",
|
|
312
|
-
"invoices": "Invoices",
|
|
313
|
-
"invoicesEmpty": "No invoices have been submitted by this collaborator yet."
|
|
309
|
+
"salary": "Compensation"
|
|
314
310
|
},
|
|
315
311
|
"sections": {
|
|
316
312
|
"basicInfo": "Basic info",
|
|
@@ -345,7 +341,6 @@
|
|
|
345
341
|
"collaboratorType": "Relationship type",
|
|
346
342
|
"collaboratorTypeDescription": "Select the nature of the relationship with the company. Role and equity participation stay separate.",
|
|
347
343
|
"weeklyCapacityHours": "Weekly workload",
|
|
348
|
-
"hourlyRate": "Hourly rate",
|
|
349
344
|
"compensationAmount": "Compensation amount",
|
|
350
345
|
"contract": "Contract",
|
|
351
346
|
"contractPlaceholder": "Search or select a contract…",
|
|
@@ -422,49 +417,7 @@
|
|
|
422
417
|
"createSuccess": "Collaborator created successfully.",
|
|
423
418
|
"createError": "Unable to create the collaborator.",
|
|
424
419
|
"updateSuccess": "Collaborator updated successfully.",
|
|
425
|
-
"updateError": "Unable to update the collaborator."
|
|
426
|
-
"saveSuccess": "Saved successfully.",
|
|
427
|
-
"saveError": "Unable to save. Please try again.",
|
|
428
|
-
"deleteSuccess": "Deleted successfully.",
|
|
429
|
-
"deleteError": "Unable to delete. Please try again."
|
|
430
|
-
},
|
|
431
|
-
"paymentHistory": {
|
|
432
|
-
"add": "Add payment",
|
|
433
|
-
"editTitle": "Edit payment",
|
|
434
|
-
"deleteConfirm": "Are you sure you want to delete this payment?",
|
|
435
|
-
"amount": "Amount",
|
|
436
|
-
"paymentDate": "Payment date",
|
|
437
|
-
"referenceMonth": "Reference month",
|
|
438
|
-
"paymentMethod": "Payment method",
|
|
439
|
-
"notes": "Notes",
|
|
440
|
-
"methodBankTransfer": "Bank transfer",
|
|
441
|
-
"methodPix": "Pix",
|
|
442
|
-
"methodCheck": "Check",
|
|
443
|
-
"methodOther": "Other"
|
|
444
|
-
},
|
|
445
|
-
"invoices": {
|
|
446
|
-
"add": "Add invoice",
|
|
447
|
-
"editTitle": "Edit invoice",
|
|
448
|
-
"deleteConfirm": "Are you sure you want to delete this invoice?",
|
|
449
|
-
"invoiceNumber": "Invoice number",
|
|
450
|
-
"amount": "Amount",
|
|
451
|
-
"issueDate": "Issue date",
|
|
452
|
-
"dueDate": "Due date",
|
|
453
|
-
"status": "Status",
|
|
454
|
-
"description": "Description",
|
|
455
|
-
"statusPending": "Pending",
|
|
456
|
-
"statusPaid": "Paid",
|
|
457
|
-
"statusCancelled": "Cancelled",
|
|
458
|
-
"statusOverdue": "Overdue"
|
|
459
|
-
},
|
|
460
|
-
"projectAllocation": {
|
|
461
|
-
"total": "Total allocation",
|
|
462
|
-
"idle": "Idle capacity",
|
|
463
|
-
"overloaded": "Overloaded",
|
|
464
|
-
"distributeEqually": "Distribute equally",
|
|
465
|
-
"autoRebalance": "Auto-rebalance",
|
|
466
|
-
"autoRebalanceDescription": "Automatically adjust other projects when editing allocation",
|
|
467
|
-
"distributing": "Distributing..."
|
|
420
|
+
"updateError": "Unable to update the collaborator."
|
|
468
421
|
},
|
|
469
422
|
"chart": {
|
|
470
423
|
"salaryHistory": "Salary history",
|
|
@@ -692,47 +645,6 @@
|
|
|
692
645
|
"done": "Done"
|
|
693
646
|
}
|
|
694
647
|
},
|
|
695
|
-
"TasksGanttPage": {
|
|
696
|
-
"title": "Tasks Gantt",
|
|
697
|
-
"description": "Track tasks from every active project on a single timeline.",
|
|
698
|
-
"breadcrumb": "Tasks Gantt",
|
|
699
|
-
"searchPlaceholder": "Search task, project, or assignee...",
|
|
700
|
-
"viewDescription": "Tasks from active projects grouped by project.",
|
|
701
|
-
"loading": "Building Gantt view...",
|
|
702
|
-
"emptyDescription": "No tasks were found for active projects with the current filters.",
|
|
703
|
-
"loadErrorDescription": "We couldn't load the schedule right now. Refresh to try again.",
|
|
704
|
-
"noAccessDescription": "The consolidated Gantt view is available only to supervisors and directors.",
|
|
705
|
-
"actions": {
|
|
706
|
-
"openProject": "Open project"
|
|
707
|
-
},
|
|
708
|
-
"filters": {
|
|
709
|
-
"allProjects": "All projects",
|
|
710
|
-
"allStatuses": "All statuses",
|
|
711
|
-
"clearDateRange": "Clear date range"
|
|
712
|
-
},
|
|
713
|
-
"cards": {
|
|
714
|
-
"activeProjects": "Active projects",
|
|
715
|
-
"activeProjectsDescription": "Active projects with tasks on the schedule.",
|
|
716
|
-
"tasks": "Scheduled tasks",
|
|
717
|
-
"tasksDescription": "Items shown with the current filters.",
|
|
718
|
-
"doing": "In progress",
|
|
719
|
-
"doingDescription": "Tasks currently being executed.",
|
|
720
|
-
"overdue": "Overdue",
|
|
721
|
-
"overdueDescription": "Open tasks with an expired due date."
|
|
722
|
-
},
|
|
723
|
-
"labels": {
|
|
724
|
-
"projectTask": "Project and task",
|
|
725
|
-
"range": "{from} through {to}",
|
|
726
|
-
"tasksCount": "{count} task(s)"
|
|
727
|
-
},
|
|
728
|
-
"legend": {
|
|
729
|
-
"todo": "To do",
|
|
730
|
-
"doing": "In progress",
|
|
731
|
-
"review": "In review",
|
|
732
|
-
"done": "Done",
|
|
733
|
-
"overdue": "Overdue"
|
|
734
|
-
}
|
|
735
|
-
},
|
|
736
648
|
"ProjectFormPage": {
|
|
737
649
|
"newTitle": "New Project",
|
|
738
650
|
"editTitle": "Edit Project",
|
|
@@ -1038,12 +950,6 @@
|
|
|
1038
950
|
"usedHours": "Used hours",
|
|
1039
951
|
"availability": "Availability",
|
|
1040
952
|
"overloadWarning": "{value}% above recommended capacity.",
|
|
1041
|
-
"addCollaborator": "Add collaborator",
|
|
1042
|
-
"addTitle": "Add collaborator",
|
|
1043
|
-
"editTitle": "Edit allocation",
|
|
1044
|
-
"formDescription": "Configure the collaborator's allocation data for this project.",
|
|
1045
|
-
"removeTitle": "Remove collaborator",
|
|
1046
|
-
"removeDescription": "Are you sure you want to remove this collaborator from the project?",
|
|
1047
953
|
"status": {
|
|
1048
954
|
"available": "Available",
|
|
1049
955
|
"high": "High load",
|