@hed-hog/operations 0.0.295 → 0.0.296

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.
Files changed (126) hide show
  1. package/dist/operations.controller.d.ts +415 -0
  2. package/dist/operations.controller.d.ts.map +1 -0
  3. package/dist/operations.controller.js +333 -0
  4. package/dist/operations.controller.js.map +1 -0
  5. package/dist/operations.module.d.ts.map +1 -1
  6. package/dist/operations.module.js +4 -3
  7. package/dist/operations.module.js.map +1 -1
  8. package/dist/operations.service.d.ts +589 -153
  9. package/dist/operations.service.d.ts.map +1 -1
  10. package/dist/operations.service.js +2229 -100
  11. package/dist/operations.service.js.map +1 -1
  12. package/hedhog/data/menu.yaml +198 -251
  13. package/hedhog/data/role.yaml +23 -14
  14. package/hedhog/data/route.yaml +317 -143
  15. package/hedhog/frontend/app/_components/collaborator-details-screen.tsx.ejs +310 -0
  16. package/hedhog/frontend/app/_components/collaborator-form-screen.tsx.ejs +631 -0
  17. package/hedhog/frontend/app/_components/contract-details-screen.tsx.ejs +132 -0
  18. package/hedhog/frontend/app/_components/contract-form-screen.tsx.ejs +558 -0
  19. package/hedhog/frontend/app/_components/project-details-screen.tsx.ejs +291 -0
  20. package/hedhog/frontend/app/_components/project-form-screen.tsx.ejs +689 -0
  21. package/hedhog/frontend/app/_lib/api.ts.ejs +32 -0
  22. package/hedhog/frontend/app/_lib/hooks/use-operations-access.ts.ejs +44 -0
  23. package/hedhog/frontend/app/_lib/types.ts.ejs +360 -0
  24. package/hedhog/frontend/app/_lib/utils/format.ts.ejs +129 -25
  25. package/hedhog/frontend/app/_lib/utils/forms.ts.ejs +14 -0
  26. package/hedhog/frontend/app/approvals/page.tsx.ejs +386 -147
  27. package/hedhog/frontend/app/collaborators/[id]/edit/page.tsx.ejs +11 -0
  28. package/hedhog/frontend/app/collaborators/[id]/page.tsx.ejs +11 -0
  29. package/hedhog/frontend/app/collaborators/new/page.tsx.ejs +5 -0
  30. package/hedhog/frontend/app/collaborators/page.tsx.ejs +261 -0
  31. package/hedhog/frontend/app/contracts/[id]/edit/page.tsx.ejs +11 -0
  32. package/hedhog/frontend/app/contracts/[id]/page.tsx.ejs +11 -108
  33. package/hedhog/frontend/app/contracts/new/page.tsx.ejs +17 -0
  34. package/hedhog/frontend/app/contracts/page.tsx.ejs +262 -181
  35. package/hedhog/frontend/app/page.tsx.ejs +319 -177
  36. package/hedhog/frontend/app/projects/[id]/edit/page.tsx.ejs +11 -0
  37. package/hedhog/frontend/app/projects/[id]/page.tsx.ejs +11 -936
  38. package/hedhog/frontend/app/projects/new/page.tsx.ejs +5 -0
  39. package/hedhog/frontend/app/projects/page.tsx.ejs +236 -1074
  40. package/hedhog/frontend/app/schedule-adjustments/page.tsx.ejs +418 -0
  41. package/hedhog/frontend/app/team/page.tsx.ejs +339 -0
  42. package/hedhog/frontend/app/time-off/page.tsx.ejs +328 -0
  43. package/hedhog/frontend/app/timesheets/page.tsx.ejs +636 -126
  44. package/hedhog/frontend/messages/en.json +648 -454
  45. package/hedhog/frontend/messages/pt.json +647 -454
  46. package/hedhog/table/operations_approval.yaml +49 -0
  47. package/hedhog/table/operations_approval_history.yaml +29 -0
  48. package/hedhog/table/{operations_employee.yaml → operations_collaborator.yaml} +67 -64
  49. package/hedhog/table/operations_collaborator_schedule_day.yaml +34 -0
  50. package/hedhog/table/operations_contract.yaml +100 -48
  51. package/hedhog/table/operations_contract_document.yaml +39 -0
  52. package/hedhog/table/operations_contract_financial_term.yaml +40 -0
  53. package/hedhog/table/operations_contract_history.yaml +27 -0
  54. package/hedhog/table/operations_contract_party.yaml +46 -0
  55. package/hedhog/table/operations_contract_revision.yaml +38 -0
  56. package/hedhog/table/operations_contract_signature.yaml +38 -0
  57. package/hedhog/table/operations_project.yaml +54 -50
  58. package/hedhog/table/{operations_allocation.yaml → operations_project_assignment.yaml} +55 -52
  59. package/hedhog/table/operations_schedule_adjustment_day.yaml +34 -0
  60. package/hedhog/table/operations_schedule_adjustment_request.yaml +53 -0
  61. package/hedhog/table/operations_time_off_request.yaml +57 -0
  62. package/hedhog/table/operations_timesheet.yaml +41 -36
  63. package/hedhog/table/operations_timesheet_entry.yaml +40 -50
  64. package/package.json +8 -7
  65. package/src/operations.controller.ts +182 -0
  66. package/src/operations.module.ts +22 -21
  67. package/src/operations.service.ts +3595 -137
  68. package/hedhog/data/operations_career_level.yaml +0 -102
  69. package/hedhog/data/operations_career_track.yaml +0 -8
  70. package/hedhog/data/operations_certification.yaml +0 -38
  71. package/hedhog/data/operations_evaluation_cycle.yaml +0 -18
  72. package/hedhog/data/operations_performance_criterion.yaml +0 -48
  73. package/hedhog/frontend/app/_components/allocation-calendar.tsx.ejs +0 -56
  74. package/hedhog/frontend/app/_components/kanban-board.tsx.ejs +0 -626
  75. package/hedhog/frontend/app/_components/timesheet-entry-dialog.tsx.ejs +0 -142
  76. package/hedhog/frontend/app/_lib/hooks/use-operations-data.ts.ejs +0 -41
  77. package/hedhog/frontend/app/_lib/hooks/use-operations-growth-data.ts.ejs +0 -63
  78. package/hedhog/frontend/app/_lib/mocks/allocations.mock.ts.ejs +0 -74
  79. package/hedhog/frontend/app/_lib/mocks/contracts.mock.ts.ejs +0 -74
  80. package/hedhog/frontend/app/_lib/mocks/operations-growth.mock.ts.ejs +0 -824
  81. package/hedhog/frontend/app/_lib/mocks/projects.mock.ts.ejs +0 -455
  82. package/hedhog/frontend/app/_lib/mocks/tasks.mock.ts.ejs +0 -117
  83. package/hedhog/frontend/app/_lib/mocks/timesheets.mock.ts.ejs +0 -84
  84. package/hedhog/frontend/app/_lib/mocks/users.mock.ts.ejs +0 -67
  85. package/hedhog/frontend/app/_lib/services/contracts.service.ts.ejs +0 -10
  86. package/hedhog/frontend/app/_lib/services/operations-growth.service.ts.ejs +0 -31
  87. package/hedhog/frontend/app/_lib/services/projects.service.ts.ejs +0 -10
  88. package/hedhog/frontend/app/_lib/services/tasks.service.ts.ejs +0 -10
  89. package/hedhog/frontend/app/_lib/services/timesheets.service.ts.ejs +0 -10
  90. package/hedhog/frontend/app/_lib/types/operations-growth.ts.ejs +0 -209
  91. package/hedhog/frontend/app/_lib/types/operations.ts.ejs +0 -156
  92. package/hedhog/frontend/app/_lib/utils/growth.ts.ejs +0 -62
  93. package/hedhog/frontend/app/_lib/utils/metrics.ts.ejs +0 -103
  94. package/hedhog/frontend/app/_lib/utils/status.ts.ejs +0 -80
  95. package/hedhog/frontend/app/allocations/page.tsx.ejs +0 -155
  96. package/hedhog/frontend/app/career/page.tsx.ejs +0 -143
  97. package/hedhog/frontend/app/certifications/page.tsx.ejs +0 -202
  98. package/hedhog/frontend/app/evaluations/page.tsx.ejs +0 -278
  99. package/hedhog/frontend/app/goals/page.tsx.ejs +0 -171
  100. package/hedhog/frontend/app/growth/page.tsx.ejs +0 -288
  101. package/hedhog/frontend/app/manager/page.tsx.ejs +0 -175
  102. package/hedhog/frontend/app/rewards/page.tsx.ejs +0 -196
  103. package/hedhog/frontend/app/tasks/page.tsx.ejs +0 -999
  104. package/hedhog/table/operations_calibration_item.yaml +0 -61
  105. package/hedhog/table/operations_calibration_session.yaml +0 -25
  106. package/hedhog/table/operations_career_level.yaml +0 -75
  107. package/hedhog/table/operations_career_track.yaml +0 -21
  108. package/hedhog/table/operations_certification.yaml +0 -48
  109. package/hedhog/table/operations_employee_certification.yaml +0 -43
  110. package/hedhog/table/operations_employee_connect.yaml +0 -61
  111. package/hedhog/table/operations_employee_evaluation.yaml +0 -113
  112. package/hedhog/table/operations_employee_evaluation_item.yaml +0 -39
  113. package/hedhog/table/operations_employee_profile.yaml +0 -80
  114. package/hedhog/table/operations_employee_skill_matrix.yaml +0 -30
  115. package/hedhog/table/operations_evaluation_cycle.yaml +0 -31
  116. package/hedhog/table/operations_goal.yaml +0 -67
  117. package/hedhog/table/operations_goal_progress.yaml +0 -31
  118. package/hedhog/table/operations_performance_criterion.yaml +0 -29
  119. package/hedhog/table/operations_promotion_readiness.yaml +0 -49
  120. package/hedhog/table/operations_promotion_recommendation.yaml +0 -63
  121. package/hedhog/table/operations_public_recognition.yaml +0 -46
  122. package/hedhog/table/operations_reward.yaml +0 -100
  123. package/hedhog/table/operations_score_event.yaml +0 -81
  124. package/hedhog/table/operations_task.yaml +0 -60
  125. package/src/operations-data.controller.ts +0 -54
  126. package/src/operations-growth.controller.ts +0 -44
@@ -0,0 +1,132 @@
1
+ 'use client';
2
+
3
+ import { EmptyState, Page } from '@/components/entity-list';
4
+ import { Button } from '@/components/ui/button';
5
+ import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
6
+ import {
7
+ Table,
8
+ TableBody,
9
+ TableCell,
10
+ TableHead,
11
+ TableHeader,
12
+ TableRow,
13
+ } from '@/components/ui/table';
14
+ import { useApp, useQuery } from '@hed-hog/next-app-provider';
15
+ import { Download, FileText, Pencil } from 'lucide-react';
16
+ import Link from 'next/link';
17
+ import { useTranslations } from 'next-intl';
18
+ import { OperationsHeader } from './operations-header';
19
+ import { SectionCard } from './section-card';
20
+ import { StatusBadge } from './status-badge';
21
+ import { fetchOperations } from '../_lib/api';
22
+ import { useOperationsAccess } from '../_lib/hooks/use-operations-access';
23
+ import type { OperationsContractDetails } from '../_lib/types';
24
+ import {
25
+ formatCurrency,
26
+ formatDate,
27
+ formatDateTime,
28
+ formatEnumLabel,
29
+ getStatusBadgeClass,
30
+ } from '../_lib/utils/format';
31
+
32
+ function downloadBase64File(fileName: string, mimeType: string, base64: string) {
33
+ const href = `data:${mimeType};base64,${base64}`;
34
+ const link = document.createElement('a');
35
+ link.href = href;
36
+ link.download = fileName;
37
+ link.click();
38
+ }
39
+
40
+ export function ContractDetailsScreen({ contractId }: { contractId: number }) {
41
+ const t = useTranslations('operations.ContractDetailsPage');
42
+ const commonT = useTranslations('operations.Common');
43
+ const { request, currentLocaleCode } = useApp();
44
+ const access = useOperationsAccess();
45
+
46
+ const { data: contract, refetch } = useQuery<OperationsContractDetails>({
47
+ queryKey: ['operations-contract-details', currentLocaleCode, contractId],
48
+ queryFn: () =>
49
+ fetchOperations<OperationsContractDetails>(request, `/operations/contracts/${contractId}`),
50
+ });
51
+
52
+ if (!contract) {
53
+ return (
54
+ <Page>
55
+ <OperationsHeader title={t('title')} description={t('description')} current={t('breadcrumb')} />
56
+ <EmptyState
57
+ icon={<FileText className="size-12" />}
58
+ title={commonT('states.emptyTitle')}
59
+ description={t('notFound')}
60
+ actionLabel={commonT('actions.refresh')}
61
+ onAction={() => void refetch()}
62
+ />
63
+ </Page>
64
+ );
65
+ }
66
+
67
+ const currentPdf = contract.documents.find((document) => document.isCurrent);
68
+
69
+ return (
70
+ <Page>
71
+ <OperationsHeader
72
+ title={contract.name}
73
+ description={t('description')}
74
+ current={t('breadcrumb')}
75
+ actions={
76
+ <div className="flex gap-2">
77
+ {currentPdf?.fileContentBase64 ? (
78
+ <Button variant="outline" size="sm" onClick={() => downloadBase64File(currentPdf.fileName, currentPdf.mimeType, currentPdf.fileContentBase64 || '')}>
79
+ <Download className="size-4" />
80
+ {t('actions.downloadPdf')}
81
+ </Button>
82
+ ) : null}
83
+ {access.isDirector ? (
84
+ <Button size="sm" asChild>
85
+ <Link href={`/operations/contracts/${contract.id}/edit`}>
86
+ <Pencil className="size-4" />
87
+ {commonT('actions.edit')}
88
+ </Link>
89
+ </Button>
90
+ ) : null}
91
+ </div>
92
+ }
93
+ />
94
+
95
+ <Tabs defaultValue="overview">
96
+ <TabsList className="flex-wrap">
97
+ <TabsTrigger value="overview">{t('tabs.overview')}</TabsTrigger>
98
+ <TabsTrigger value="parties">{t('tabs.parties')}</TabsTrigger>
99
+ <TabsTrigger value="signatures">{t('tabs.signatures')}</TabsTrigger>
100
+ <TabsTrigger value="financials">{t('tabs.financials')}</TabsTrigger>
101
+ <TabsTrigger value="documents">{t('tabs.documents')}</TabsTrigger>
102
+ <TabsTrigger value="revisions">{t('tabs.revisions')}</TabsTrigger>
103
+ <TabsTrigger value="history">{t('tabs.history')}</TabsTrigger>
104
+ </TabsList>
105
+
106
+ <TabsContent value="overview">
107
+ <SectionCard title={t('sections.overview')}>
108
+ <dl className="grid gap-3 text-sm md:grid-cols-3">
109
+ <div><dt className="text-muted-foreground">{commonT('labels.contract')}</dt><dd className="font-medium">{contract.name}</dd></div>
110
+ <div><dt className="text-muted-foreground">{t('labels.origin')}</dt><dd className="font-medium">{formatEnumLabel(contract.originType)}</dd></div>
111
+ <div><dt className="text-muted-foreground">{t('labels.mainParty')}</dt><dd className="font-medium">{contract.mainRelatedPartyName || commonT('labels.notAvailable')}</dd></div>
112
+ <div><dt className="text-muted-foreground">{t('labels.contractType')}</dt><dd className="font-medium">{formatEnumLabel(contract.contractType)}</dd></div>
113
+ <div><dt className="text-muted-foreground">{t('labels.signatureStatus')}</dt><dd className="font-medium"><StatusBadge label={formatEnumLabel(contract.signatureStatus)} className={getStatusBadgeClass(contract.signatureStatus)} /></dd></div>
114
+ <div><dt className="text-muted-foreground">{t('labels.activeState')}</dt><dd className="font-medium">{contract.isActive ? t('labels.active') : t('labels.inactive')}</dd></div>
115
+ <div><dt className="text-muted-foreground">{commonT('labels.startDate')}</dt><dd className="font-medium">{formatDate(contract.startDate)}</dd></div>
116
+ <div><dt className="text-muted-foreground">{commonT('labels.endDate')}</dt><dd className="font-medium">{formatDate(contract.endDate)}</dd></div>
117
+ <div><dt className="text-muted-foreground">{commonT('labels.status')}</dt><dd className="font-medium"><StatusBadge label={formatEnumLabel(contract.status)} className={getStatusBadgeClass(contract.status)} /></dd></div>
118
+ </dl>
119
+ {contract.contentHtml ? <div className="prose prose-sm mt-4 max-w-none rounded-lg border p-4" dangerouslySetInnerHTML={{ __html: contract.contentHtml }} /> : null}
120
+ </SectionCard>
121
+ </TabsContent>
122
+
123
+ <TabsContent value="parties"><SectionCard title={t('sections.parties')}>{contract.parties.length ? <div className="overflow-x-auto rounded-md border"><Table><TableHeader><TableRow><TableHead>{t('labels.mainParty')}</TableHead><TableHead>{t('labels.partyRole')}</TableHead><TableHead>{t('labels.partyType')}</TableHead><TableHead>{t('labels.documentNumber')}</TableHead></TableRow></TableHeader><TableBody>{contract.parties.map((party) => <TableRow key={party.id}><TableCell>{party.displayName}</TableCell><TableCell>{formatEnumLabel(party.partyRole)}</TableCell><TableCell>{formatEnumLabel(party.partyType)}</TableCell><TableCell>{party.documentNumber || commonT('labels.notAvailable')}</TableCell></TableRow>)}</TableBody></Table></div> : <p className="text-sm text-muted-foreground">{t('states.noParties')}</p>}</SectionCard></TabsContent>
124
+ <TabsContent value="signatures"><SectionCard title={t('sections.signatures')}>{contract.signatures.length ? <div className="overflow-x-auto rounded-md border"><Table><TableHeader><TableRow><TableHead>{t('labels.signer')}</TableHead><TableHead>{commonT('labels.status')}</TableHead><TableHead>{t('labels.signedAt')}</TableHead></TableRow></TableHeader><TableBody>{contract.signatures.map((signature) => <TableRow key={signature.id}><TableCell>{signature.signerName}</TableCell><TableCell><StatusBadge label={formatEnumLabel(signature.status)} className={getStatusBadgeClass(signature.status)} /></TableCell><TableCell>{formatDate(signature.signedAt)}</TableCell></TableRow>)}</TableBody></Table></div> : <p className="text-sm text-muted-foreground">{t('states.noSignatures')}</p>}</SectionCard></TabsContent>
125
+ <TabsContent value="financials"><SectionCard title={t('sections.financials')}><dl className="grid gap-3 text-sm md:grid-cols-4"><div><dt className="text-muted-foreground">{t('labels.value')}</dt><dd className="font-medium">{formatCurrency(contract.valueAmount ?? 0)}</dd></div><div><dt className="text-muted-foreground">{t('labels.payment')}</dt><dd className="font-medium">{formatCurrency(contract.paymentAmount ?? 0)}</dd></div><div><dt className="text-muted-foreground">{t('labels.revenue')}</dt><dd className="font-medium">{formatCurrency(contract.revenueAmount ?? 0)}</dd></div><div><dt className="text-muted-foreground">{t('labels.fine')}</dt><dd className="font-medium">{formatCurrency(contract.fineAmount ?? 0)}</dd></div></dl></SectionCard></TabsContent>
126
+ <TabsContent value="documents"><SectionCard title={t('sections.documents')}>{contract.documents.length ? <div className="space-y-3">{contract.documents.map((document) => <div key={document.id} className="flex items-center justify-between rounded-lg border px-4 py-3"><div><div className="font-medium">{document.fileName}</div><div className="text-xs text-muted-foreground">{formatEnumLabel(document.documentType)} • {formatDateTime(document.createdAt)}</div></div>{document.fileContentBase64 ? <Button variant="outline" size="sm" onClick={() => downloadBase64File(document.fileName, document.mimeType, document.fileContentBase64 || '')}><Download className="size-4" />{t('actions.download')}</Button> : null}</div>)}</div> : <p className="text-sm text-muted-foreground">{t('states.noDocuments')}</p>}</SectionCard></TabsContent>
127
+ <TabsContent value="revisions"><SectionCard title={t('sections.revisions')}>{contract.revisions.length ? <div className="overflow-x-auto rounded-md border"><Table><TableHeader><TableRow><TableHead>{t('labels.revision')}</TableHead><TableHead>{commonT('labels.status')}</TableHead><TableHead>{commonT('labels.startDate')}</TableHead></TableRow></TableHeader><TableBody>{contract.revisions.map((revision) => <TableRow key={revision.id}><TableCell>{revision.title}</TableCell><TableCell><StatusBadge label={formatEnumLabel(revision.status)} className={getStatusBadgeClass(revision.status)} /></TableCell><TableCell>{formatDate(revision.effectiveDate)}</TableCell></TableRow>)}</TableBody></Table></div> : <p className="text-sm text-muted-foreground">{t('states.noRevisions')}</p>}</SectionCard></TabsContent>
128
+ <TabsContent value="history"><SectionCard title={t('sections.history')}>{contract.history.length ? <div className="space-y-3">{contract.history.map((item) => <div key={item.id} className="rounded-lg border px-4 py-3 text-sm"><div className="font-medium">{formatEnumLabel(item.action)}</div><div className="text-muted-foreground">{formatDateTime(item.createdAt)}</div><div>{item.note || commonT('labels.noNotes')}</div></div>)}</div> : <p className="text-sm text-muted-foreground">{t('states.noHistory')}</p>}</SectionCard></TabsContent>
129
+ </Tabs>
130
+ </Page>
131
+ );
132
+ }