@hed-hog/operations 0.0.319 → 0.0.322
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 +22 -0
- package/dist/controllers/operations-tasks.controller.d.ts.map +1 -1
- package/dist/controllers/operations-tasks.controller.js +37 -0
- package/dist/controllers/operations-tasks.controller.js.map +1 -1
- package/dist/dto/create-task.dto.d.ts.map +1 -1
- package/dist/dto/create-task.dto.js +0 -1
- package/dist/dto/create-task.dto.js.map +1 -1
- package/dist/dto/update-task.dto.d.ts.map +1 -1
- package/dist/dto/update-task.dto.js +0 -1
- package/dist/dto/update-task.dto.js.map +1 -1
- package/dist/operations.service.d.ts +22 -0
- package/dist/operations.service.d.ts.map +1 -1
- package/dist/operations.service.js +187 -132
- package/dist/operations.service.js.map +1 -1
- package/hedhog/data/operations_cost_type.yaml +95 -95
- package/hedhog/data/route.yaml +39 -0
- package/hedhog/frontend/app/_components/collaborator-costs-section.tsx.ejs +884 -884
- package/hedhog/frontend/app/_components/collaborator-details-screen.tsx.ejs +23 -23
- package/hedhog/frontend/app/_components/person-select-with-create.tsx.ejs +49 -22
- package/hedhog/frontend/app/_components/project-details-screen.tsx.ejs +2968 -624
- package/hedhog/frontend/app/_components/project-form-screen.tsx.ejs +62 -68
- package/hedhog/frontend/app/_components/task-file-attachments.tsx.ejs +388 -0
- package/hedhog/frontend/app/_lib/types.ts.ejs +179 -178
- package/hedhog/frontend/app/my-tasks/page.tsx.ejs +121 -11
- package/hedhog/frontend/app/projects/page.tsx.ejs +105 -22
- package/hedhog/frontend/app/reports/collaborators/page.tsx.ejs +771 -771
- package/hedhog/frontend/app/reports/projects/page.tsx.ejs +809 -809
- package/hedhog/frontend/messages/en.json +143 -2
- package/hedhog/frontend/messages/pt.json +143 -2
- package/hedhog/table/operations_task_file.yaml +23 -0
- package/package.json +5 -5
- package/src/controllers/operations-reports.controller.ts +32 -32
- package/src/controllers/operations-tasks.controller.ts +43 -9
- package/src/dto/create-task.dto.ts +0 -1
- package/src/dto/list-reports.dto.ts +51 -51
- package/src/dto/update-task.dto.ts +0 -1
- package/src/operations.module.ts +5 -5
- package/src/operations.service.ts +754 -632
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
PaginationFooter,
|
|
7
7
|
SearchBar,
|
|
8
8
|
} from '@/components/entity-list';
|
|
9
|
+
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar';
|
|
9
10
|
import { Button } from '@/components/ui/button';
|
|
10
11
|
import { Card, CardContent } from '@/components/ui/card';
|
|
11
12
|
import { KpiCardsGrid } from '@/components/ui/kpi-cards-grid';
|
|
@@ -27,6 +28,8 @@ import {
|
|
|
27
28
|
import { ToggleGroup, ToggleGroupItem } from '@/components/ui/toggle-group';
|
|
28
29
|
import { useApp, useQuery } from '@hed-hog/next-app-provider';
|
|
29
30
|
import {
|
|
31
|
+
Archive,
|
|
32
|
+
ArchiveRestore,
|
|
30
33
|
CalendarDays,
|
|
31
34
|
Eye,
|
|
32
35
|
FileText,
|
|
@@ -53,6 +56,22 @@ const PROJECT_VIEW_STORAGE_KEY = 'operations-projects-view-mode';
|
|
|
53
56
|
|
|
54
57
|
type ProjectViewMode = 'table' | 'cards';
|
|
55
58
|
|
|
59
|
+
function getPersonAvatarUrl(avatarId?: number | null): string {
|
|
60
|
+
return typeof avatarId === 'number' && avatarId > 0
|
|
61
|
+
? `${process.env.NEXT_PUBLIC_API_BASE_URL}/person/avatar/${avatarId}`
|
|
62
|
+
: '/placeholder.png';
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function getInitials(value?: string | null): string {
|
|
66
|
+
if (!value) return '?';
|
|
67
|
+
return value
|
|
68
|
+
.split(' ')
|
|
69
|
+
.filter(Boolean)
|
|
70
|
+
.slice(0, 2)
|
|
71
|
+
.map((w) => w[0]!.toUpperCase())
|
|
72
|
+
.join('');
|
|
73
|
+
}
|
|
74
|
+
|
|
56
75
|
function parseEditProjectId(value: string | null) {
|
|
57
76
|
const parsed = Number(value);
|
|
58
77
|
return Number.isInteger(parsed) && parsed > 0 ? parsed : null;
|
|
@@ -335,6 +354,9 @@ export default function OperationsProjectsPage() {
|
|
|
335
354
|
<Card
|
|
336
355
|
key={project.id}
|
|
337
356
|
className="cursor-pointer overflow-hidden border-border/60 py-0 shadow-sm transition-all hover:-translate-y-0.5 hover:shadow-md"
|
|
357
|
+
onDoubleClick={() =>
|
|
358
|
+
router.push(`/operations/projects/${project.id}`)
|
|
359
|
+
}
|
|
338
360
|
>
|
|
339
361
|
<CardContent className="space-y-4 p-4">
|
|
340
362
|
<div className="flex flex-col gap-3 sm:flex-row sm:items-start sm:justify-between">
|
|
@@ -359,17 +381,39 @@ export default function OperationsProjectsPage() {
|
|
|
359
381
|
</div>
|
|
360
382
|
|
|
361
383
|
<div className="grid gap-2 text-sm text-muted-foreground lg:grid-cols-2">
|
|
362
|
-
<div>
|
|
363
|
-
<span className="font-medium text-foreground">
|
|
384
|
+
<div className="flex flex-wrap items-center gap-1.5">
|
|
385
|
+
<span className="shrink-0 font-medium text-foreground">
|
|
364
386
|
{commonT('labels.client')}:
|
|
365
|
-
</span>
|
|
366
|
-
|
|
387
|
+
</span>
|
|
388
|
+
<Avatar className="h-5 w-5 shrink-0">
|
|
389
|
+
<AvatarImage
|
|
390
|
+
src={getPersonAvatarUrl(project.clientAvatarId)}
|
|
391
|
+
alt={project.clientName ?? ''}
|
|
392
|
+
/>
|
|
393
|
+
<AvatarFallback className="text-[9px] font-medium">
|
|
394
|
+
{getInitials(project.clientName)}
|
|
395
|
+
</AvatarFallback>
|
|
396
|
+
</Avatar>
|
|
397
|
+
<span className="truncate">
|
|
398
|
+
{project.clientName || commonT('labels.notAvailable')}
|
|
399
|
+
</span>
|
|
367
400
|
</div>
|
|
368
|
-
<div>
|
|
369
|
-
<span className="font-medium text-foreground">
|
|
401
|
+
<div className="flex flex-wrap items-center gap-1.5">
|
|
402
|
+
<span className="shrink-0 font-medium text-foreground">
|
|
370
403
|
{commonT('labels.manager')}:
|
|
371
|
-
</span>
|
|
372
|
-
|
|
404
|
+
</span>
|
|
405
|
+
<Avatar className="h-5 w-5 shrink-0">
|
|
406
|
+
<AvatarImage
|
|
407
|
+
src={getPersonAvatarUrl(project.managerAvatarId)}
|
|
408
|
+
alt={project.managerName ?? ''}
|
|
409
|
+
/>
|
|
410
|
+
<AvatarFallback className="text-[9px] font-medium">
|
|
411
|
+
{getInitials(project.managerName)}
|
|
412
|
+
</AvatarFallback>
|
|
413
|
+
</Avatar>
|
|
414
|
+
<span className="truncate">
|
|
415
|
+
{project.managerName || commonT('labels.notAssigned')}
|
|
416
|
+
</span>
|
|
373
417
|
</div>
|
|
374
418
|
<div>
|
|
375
419
|
<span className="font-medium text-foreground">
|
|
@@ -414,7 +458,7 @@ export default function OperationsProjectsPage() {
|
|
|
414
458
|
</div>
|
|
415
459
|
</div>
|
|
416
460
|
|
|
417
|
-
<div className="flex
|
|
461
|
+
<div className="flex items-center justify-end gap-2 border-t border-border/60 pt-3">
|
|
418
462
|
<Button variant="outline" size="icon" asChild>
|
|
419
463
|
<Link href={`/operations/projects/${project.id}`}>
|
|
420
464
|
<Eye className="size-4" />
|
|
@@ -451,13 +495,20 @@ export default function OperationsProjectsPage() {
|
|
|
451
495
|
{access.isDirector ? (
|
|
452
496
|
<Button
|
|
453
497
|
variant="outline"
|
|
454
|
-
size="
|
|
498
|
+
size="icon"
|
|
455
499
|
className="cursor-pointer"
|
|
500
|
+
title={
|
|
501
|
+
project.status === 'archived'
|
|
502
|
+
? commonT('actions.activate')
|
|
503
|
+
: t('actions.archive')
|
|
504
|
+
}
|
|
456
505
|
onClick={() => void toggleArchived(project)}
|
|
457
506
|
>
|
|
458
|
-
{project.status === 'archived'
|
|
459
|
-
|
|
460
|
-
|
|
507
|
+
{project.status === 'archived' ? (
|
|
508
|
+
<ArchiveRestore className="size-4" />
|
|
509
|
+
) : (
|
|
510
|
+
<Archive className="size-4" />
|
|
511
|
+
)}
|
|
461
512
|
</Button>
|
|
462
513
|
) : null}
|
|
463
514
|
</div>
|
|
@@ -500,6 +551,9 @@ export default function OperationsProjectsPage() {
|
|
|
500
551
|
<TableRow
|
|
501
552
|
key={project.id}
|
|
502
553
|
className="cursor-pointer hover:bg-muted/30"
|
|
554
|
+
onDoubleClick={() =>
|
|
555
|
+
router.push(`/operations/projects/${project.id}`)
|
|
556
|
+
}
|
|
503
557
|
>
|
|
504
558
|
<TableCell>
|
|
505
559
|
<div className="min-w-0">
|
|
@@ -518,8 +572,19 @@ export default function OperationsProjectsPage() {
|
|
|
518
572
|
</div>
|
|
519
573
|
</TableCell>
|
|
520
574
|
<TableCell>
|
|
521
|
-
<div className="
|
|
522
|
-
|
|
575
|
+
<div className="flex min-w-0 items-center gap-1.5">
|
|
576
|
+
<Avatar className="h-6 w-6 shrink-0">
|
|
577
|
+
<AvatarImage
|
|
578
|
+
src={getPersonAvatarUrl(project.clientAvatarId)}
|
|
579
|
+
alt={project.clientName ?? ''}
|
|
580
|
+
/>
|
|
581
|
+
<AvatarFallback className="text-[9px] font-medium">
|
|
582
|
+
{getInitials(project.clientName)}
|
|
583
|
+
</AvatarFallback>
|
|
584
|
+
</Avatar>
|
|
585
|
+
<span className="truncate">
|
|
586
|
+
{project.clientName || commonT('labels.notAvailable')}
|
|
587
|
+
</span>
|
|
523
588
|
</div>
|
|
524
589
|
</TableCell>
|
|
525
590
|
<TableCell>
|
|
@@ -529,8 +594,19 @@ export default function OperationsProjectsPage() {
|
|
|
529
594
|
/>
|
|
530
595
|
</TableCell>
|
|
531
596
|
<TableCell className="hidden lg:table-cell">
|
|
532
|
-
<div className="
|
|
533
|
-
|
|
597
|
+
<div className="flex min-w-0 items-center gap-1.5">
|
|
598
|
+
<Avatar className="h-6 w-6 shrink-0">
|
|
599
|
+
<AvatarImage
|
|
600
|
+
src={getPersonAvatarUrl(project.managerAvatarId)}
|
|
601
|
+
alt={project.managerName ?? ''}
|
|
602
|
+
/>
|
|
603
|
+
<AvatarFallback className="text-[9px] font-medium">
|
|
604
|
+
{getInitials(project.managerName)}
|
|
605
|
+
</AvatarFallback>
|
|
606
|
+
</Avatar>
|
|
607
|
+
<span className="truncate">
|
|
608
|
+
{project.managerName || commonT('labels.notAssigned')}
|
|
609
|
+
</span>
|
|
534
610
|
</div>
|
|
535
611
|
</TableCell>
|
|
536
612
|
<TableCell className="hidden md:table-cell">
|
|
@@ -563,7 +639,7 @@ export default function OperationsProjectsPage() {
|
|
|
563
639
|
)}
|
|
564
640
|
</TableCell>
|
|
565
641
|
<TableCell>
|
|
566
|
-
<div className="flex
|
|
642
|
+
<div className="flex items-center justify-end gap-1.5">
|
|
567
643
|
<Button variant="outline" size="icon" asChild>
|
|
568
644
|
<Link href={`/operations/projects/${project.id}`}>
|
|
569
645
|
<Eye className="size-4" />
|
|
@@ -600,13 +676,20 @@ export default function OperationsProjectsPage() {
|
|
|
600
676
|
{access.isDirector ? (
|
|
601
677
|
<Button
|
|
602
678
|
variant="outline"
|
|
603
|
-
size="
|
|
679
|
+
size="icon"
|
|
604
680
|
className="cursor-pointer"
|
|
681
|
+
title={
|
|
682
|
+
project.status === 'archived'
|
|
683
|
+
? commonT('actions.activate')
|
|
684
|
+
: t('actions.archive')
|
|
685
|
+
}
|
|
605
686
|
onClick={() => void toggleArchived(project)}
|
|
606
687
|
>
|
|
607
|
-
{project.status === 'archived'
|
|
608
|
-
|
|
609
|
-
|
|
688
|
+
{project.status === 'archived' ? (
|
|
689
|
+
<ArchiveRestore className="size-4" />
|
|
690
|
+
) : (
|
|
691
|
+
<Archive className="size-4" />
|
|
692
|
+
)}
|
|
610
693
|
</Button>
|
|
611
694
|
) : null}
|
|
612
695
|
</div>
|