@hed-hog/operations 0.0.300 → 0.0.302

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 (73) hide show
  1. package/dist/operations.controller.d.ts +713 -31
  2. package/dist/operations.controller.d.ts.map +1 -1
  3. package/dist/operations.controller.js +157 -0
  4. package/dist/operations.controller.js.map +1 -1
  5. package/dist/operations.module.d.ts.map +1 -1
  6. package/dist/operations.module.js +5 -1
  7. package/dist/operations.module.js.map +1 -1
  8. package/dist/operations.proposal.subscriber.d.ts +11 -0
  9. package/dist/operations.proposal.subscriber.d.ts.map +1 -0
  10. package/dist/operations.proposal.subscriber.js +80 -0
  11. package/dist/operations.proposal.subscriber.js.map +1 -0
  12. package/dist/operations.proposal.subscriber.spec.d.ts +2 -0
  13. package/dist/operations.proposal.subscriber.spec.d.ts.map +1 -0
  14. package/dist/operations.proposal.subscriber.spec.js +88 -0
  15. package/dist/operations.proposal.subscriber.spec.js.map +1 -0
  16. package/dist/operations.service.d.ts +491 -46
  17. package/dist/operations.service.d.ts.map +1 -1
  18. package/dist/operations.service.js +2484 -121
  19. package/dist/operations.service.js.map +1 -1
  20. package/dist/operations.service.spec.d.ts +2 -0
  21. package/dist/operations.service.spec.d.ts.map +1 -0
  22. package/dist/operations.service.spec.js +159 -0
  23. package/dist/operations.service.spec.js.map +1 -0
  24. package/hedhog/data/menu.yaml +35 -22
  25. package/hedhog/data/role_route.yaml +39 -0
  26. package/hedhog/data/route.yaml +130 -0
  27. package/hedhog/frontend/app/_components/collaborator-details-screen.tsx.ejs +8 -6
  28. package/hedhog/frontend/app/_components/collaborator-form-screen.tsx.ejs +1163 -327
  29. package/hedhog/frontend/app/_components/collaborator-select-with-create.tsx.ejs +256 -0
  30. package/hedhog/frontend/app/_components/contract-content-editor.tsx.ejs +258 -0
  31. package/hedhog/frontend/app/_components/contract-creation-wizard.tsx.ejs +631 -0
  32. package/hedhog/frontend/app/_components/contract-details-screen.tsx.ejs +353 -27
  33. package/hedhog/frontend/app/_components/contract-form-screen.tsx.ejs +1926 -87
  34. package/hedhog/frontend/app/_components/contract-template-form-screen.tsx.ejs +526 -0
  35. package/hedhog/frontend/app/_components/contract-template-select-with-create.tsx.ejs +247 -0
  36. package/hedhog/frontend/app/_components/contract-wizard-sheet.tsx.ejs +3520 -0
  37. package/hedhog/frontend/app/_components/department-select-with-create.tsx.ejs +370 -0
  38. package/hedhog/frontend/app/_components/person-select-with-create.tsx.ejs +826 -0
  39. package/hedhog/frontend/app/_components/project-form-screen.tsx.ejs +1251 -364
  40. package/hedhog/frontend/app/_components/section-card.tsx.ejs +48 -13
  41. package/hedhog/frontend/app/_lib/api.ts.ejs +2 -5
  42. package/hedhog/frontend/app/_lib/types.ts.ejs +76 -33
  43. package/hedhog/frontend/app/_lib/utils/format.ts.ejs +85 -8
  44. package/hedhog/frontend/app/approvals/page.tsx.ejs +90 -54
  45. package/hedhog/frontend/app/collaborators/[id]/edit/page.tsx.ejs +2 -2
  46. package/hedhog/frontend/app/collaborators/[id]/page.tsx.ejs +2 -2
  47. package/hedhog/frontend/app/collaborators/page.tsx.ejs +597 -140
  48. package/hedhog/frontend/app/contracts/[id]/edit/page.tsx.ejs +2 -2
  49. package/hedhog/frontend/app/contracts/[id]/page.tsx.ejs +2 -2
  50. package/hedhog/frontend/app/contracts/page.tsx.ejs +941 -262
  51. package/hedhog/frontend/app/contracts/templates/page.tsx.ejs +384 -0
  52. package/hedhog/frontend/app/departments/page.tsx.ejs +442 -0
  53. package/hedhog/frontend/app/page.tsx.ejs +3 -317
  54. package/hedhog/frontend/app/projects/[id]/edit/page.tsx.ejs +2 -2
  55. package/hedhog/frontend/app/projects/new/page.tsx.ejs +2 -2
  56. package/hedhog/frontend/app/projects/page.tsx.ejs +264 -102
  57. package/hedhog/frontend/app/schedule-adjustments/page.tsx.ejs +50 -28
  58. package/hedhog/frontend/app/time-off/page.tsx.ejs +57 -31
  59. package/hedhog/frontend/app/timesheets/page.tsx.ejs +85 -42
  60. package/hedhog/frontend/messages/en.json +473 -12
  61. package/hedhog/frontend/messages/pt.json +528 -66
  62. package/hedhog/table/operations_collaborator.yaml +20 -0
  63. package/hedhog/table/operations_contract.yaml +22 -1
  64. package/hedhog/table/operations_contract_document.yaml +33 -16
  65. package/hedhog/table/operations_contract_template.yaml +58 -0
  66. package/hedhog/table/operations_department.yaml +24 -0
  67. package/package.json +7 -5
  68. package/src/operations.controller.ts +122 -0
  69. package/src/operations.module.ts +6 -2
  70. package/src/operations.proposal.subscriber.spec.ts +121 -0
  71. package/src/operations.proposal.subscriber.ts +86 -0
  72. package/src/operations.service.spec.ts +210 -0
  73. package/src/operations.service.ts +4026 -241
@@ -1,10 +1,11 @@
1
+ import { CardDescription, CardTitle } from '@/components/ui/card';
1
2
  import {
2
- Card,
3
- CardContent,
4
- CardDescription,
5
- CardHeader,
6
- CardTitle,
7
- } from '@/components/ui/card';
3
+ Tooltip,
4
+ TooltipContent,
5
+ TooltipTrigger,
6
+ } from '@/components/ui/tooltip';
7
+ import { cn } from '@/lib/utils';
8
+ import { Info } from 'lucide-react';
8
9
  import { ReactNode } from 'react';
9
10
 
10
11
  interface SectionCardProps {
@@ -12,6 +13,8 @@ interface SectionCardProps {
12
13
  description?: string;
13
14
  children: ReactNode;
14
15
  className?: string;
16
+ compact?: boolean;
17
+ descriptionMode?: 'inline' | 'tooltip';
15
18
  }
16
19
 
17
20
  export function SectionCard({
@@ -19,14 +22,46 @@ export function SectionCard({
19
22
  description,
20
23
  children,
21
24
  className,
25
+ compact = false,
26
+ descriptionMode = 'inline',
22
27
  }: SectionCardProps) {
23
28
  return (
24
- <Card className={className}>
25
- <CardHeader>
26
- <CardTitle>{title}</CardTitle>
27
- {description ? <CardDescription>{description}</CardDescription> : null}
28
- </CardHeader>
29
- <CardContent>{children}</CardContent>
30
- </Card>
29
+ <div className={cn(className, '')}>
30
+ <div className={compact ? 'space-y-1 px-0 py-2.5' : undefined}>
31
+ <div className="flex items-start justify-between gap-2">
32
+ <div className="flex items-center gap-2">
33
+ <CardTitle
34
+ className={compact ? 'text-sm font-semibold' : undefined}
35
+ >
36
+ {title}
37
+ </CardTitle>
38
+ {description && descriptionMode === 'tooltip' ? (
39
+ <Tooltip>
40
+ <TooltipTrigger asChild>
41
+ <button
42
+ type="button"
43
+ className="cursor-help text-muted-foreground transition-colors hover:text-foreground"
44
+ aria-label={description}
45
+ >
46
+ <Info className="size-4" />
47
+ </button>
48
+ </TooltipTrigger>
49
+ <TooltipContent className="max-w-xs text-sm leading-relaxed">
50
+ {description}
51
+ </TooltipContent>
52
+ </Tooltip>
53
+ ) : null}
54
+ </div>
55
+ </div>
56
+ {description && descriptionMode !== 'tooltip' ? (
57
+ <CardDescription
58
+ className={compact ? 'text-[11px] leading-relaxed' : undefined}
59
+ >
60
+ {description}
61
+ </CardDescription>
62
+ ) : null}
63
+ </div>
64
+ <div className={compact ? 'px-0 pb-3 pt-0' : undefined}>{children}</div>
65
+ </div>
31
66
  );
32
67
  }
@@ -2,12 +2,9 @@ type RequestFn = (input: {
2
2
  url: string;
3
3
  method: string;
4
4
  data?: unknown;
5
- }) => Promise<{ data: any }>;
5
+ }) => Promise<{ data: unknown }>;
6
6
 
7
- export async function fetchOperations<T>(
8
- request: RequestFn,
9
- url: string
10
- ) {
7
+ export async function fetchOperations<T>(request: RequestFn, url: string) {
11
8
  const response = await request({
12
9
  url,
13
10
  method: 'GET',
@@ -26,10 +26,14 @@ export type OperationsDashboard = {
26
26
 
27
27
  export type OperationsCollaborator = {
28
28
  id: number;
29
- userId?: number;
29
+ userId?: number | null;
30
+ personId?: number | null;
31
+ personName?: string | null;
32
+ personAvatarId?: number | null;
30
33
  code: string;
31
34
  collaboratorType?: string;
32
35
  displayName: string;
36
+ departmentId?: number | null;
33
37
  department?: string | null;
34
38
  title?: string | null;
35
39
  levelLabel?: string | null;
@@ -48,6 +52,18 @@ export type OperationsCollaborator = {
48
52
  pendingScheduleAdjustmentRequests?: number;
49
53
  };
50
54
 
55
+ export type OperationsDepartment = {
56
+ id: number;
57
+ slug: string;
58
+ code?: string | null;
59
+ name: string;
60
+ description?: string | null;
61
+ status: 'active' | 'inactive';
62
+ collaboratorCount?: number;
63
+ createdAt?: string | null;
64
+ updatedAt?: string | null;
65
+ };
66
+
51
67
  export type OperationsProject = {
52
68
  id: number;
53
69
  contractId?: number | null;
@@ -71,41 +87,65 @@ export type OperationsProject = {
71
87
  teamSize?: number;
72
88
  };
73
89
 
74
- export type OperationsContract = {
75
- id: number;
76
- code: string;
77
- name: string;
78
- contractCategory?: string;
79
- contractType?: string;
80
- clientName: string;
81
- signatureStatus?: string;
82
- isActive?: boolean;
83
- billingModel: string;
90
+ export type OperationsContract = {
91
+ id: number;
92
+ code: string;
93
+ name?: string | null;
94
+ contractCategory?: string;
95
+ contractType?: string;
96
+ clientName?: string | null;
97
+ signatureStatus?: string;
98
+ isActive?: boolean;
99
+ billingModel: string;
84
100
  accountManagerCollaboratorId?: number | null;
85
101
  accountManagerName?: string | null;
86
102
  relatedCollaboratorId?: number | null;
87
103
  relatedCollaboratorName?: string | null;
88
- mainRelatedPartyName?: string | null;
89
- originType?: string | null;
90
- originId?: number | null;
91
- startDate: string;
92
- endDate?: string | null;
93
- signedAt?: string | null;
94
- effectiveDate?: string | null;
104
+ contractTemplateId?: number | null;
105
+ contractTemplateName?: string | null;
106
+ contractTemplateSlug?: string | null;
107
+ contractTemplateCode?: string | null;
108
+ mainRelatedPartyName?: string | null;
109
+ originType?: string | null;
110
+ originId?: number | null;
111
+ startDate?: string | null;
112
+ endDate?: string | null;
113
+ signedAt?: string | null;
114
+ effectiveDate?: string | null;
95
115
  budgetAmount?: number | null;
96
116
  monthlyHourCap?: number | null;
97
117
  valueAmount?: number | null;
98
118
  paymentAmount?: number | null;
99
119
  revenueAmount?: number | null;
100
- fineAmount?: number | null;
101
- status: string;
102
- description?: string | null;
103
- contentHtml?: string | null;
104
- projectCount?: number;
120
+ fineAmount?: number | null;
121
+ status: string;
122
+ creationMode?: 'blank' | 'template' | 'upload' | 'duplicate' | null;
123
+ wizardStep?: number | null;
124
+ description?: string | null;
125
+ contentHtml?: string | null;
126
+ projectCount?: number;
105
127
  currentPdfFileName?: string | null;
106
128
  scheduleSummary?: OperationsWeeklyScheduleDay[];
107
129
  };
108
130
 
131
+ export type OperationsContractTemplate = {
132
+ id: number;
133
+ slug: string;
134
+ code?: string | null;
135
+ name: string;
136
+ description?: string | null;
137
+ contractCategory?: string | null;
138
+ contractType?: string | null;
139
+ billingModel?: string | null;
140
+ signatureStatus?: string | null;
141
+ isActive?: boolean;
142
+ status: string;
143
+ contentHtml?: string | null;
144
+ usageCount?: number;
145
+ createdAt?: string | null;
146
+ updatedAt?: string | null;
147
+ };
148
+
109
149
  export type OperationsWeeklyScheduleDay = {
110
150
  weekday: string;
111
151
  isWorkingDay: boolean;
@@ -331,16 +371,19 @@ export type OperationsContractDetails = OperationsContract & {
331
371
  dueDay?: number | null;
332
372
  notes?: string | null;
333
373
  }>;
334
- documents: Array<{
335
- id: number;
336
- documentType: string;
337
- fileName: string;
338
- mimeType: string;
339
- fileContentBase64?: string | null;
340
- isCurrent: boolean;
341
- notes?: string | null;
342
- createdAt: string;
343
- }>;
374
+ documents: Array<{
375
+ id: number;
376
+ documentType: string;
377
+ fileId?: number | null;
378
+ fileName: string;
379
+ mimeType: string;
380
+ fileContentBase64?: string | null;
381
+ isCurrent: boolean;
382
+ extractionStatus?: string | null;
383
+ extractionSummary?: string | null;
384
+ notes?: string | null;
385
+ createdAt: string;
386
+ }>;
344
387
  revisions: Array<{
345
388
  id: number;
346
389
  revisionType: string;
@@ -1,3 +1,8 @@
1
+ import {
2
+ formatDateTime as formatDateTimeWithSettings,
3
+ formatDate as formatDateWithSettings,
4
+ } from '@/lib/format-date';
5
+
1
6
  export const operationsCurrency = new Intl.NumberFormat('en-US', {
2
7
  style: 'currency',
3
8
  currency: 'USD',
@@ -8,24 +13,74 @@ export function formatCurrency(value: number) {
8
13
  return operationsCurrency.format(value);
9
14
  }
10
15
 
11
- export function formatDate(value?: string | null) {
16
+ function resolveLocale(currentLocaleCode: string) {
17
+ return currentLocaleCode.startsWith('pt') ? 'pt-BR' : 'en-US';
18
+ }
19
+
20
+ export function formatDate(
21
+ value?: string | null,
22
+ getSettingValue?: ((key: string) => unknown) | null,
23
+ currentLocaleCode = 'en-US'
24
+ ) {
12
25
  if (!value) {
13
26
  return '-';
14
27
  }
15
28
 
16
- return new Date(`${value}T00:00:00`).toLocaleDateString('en-US', {
29
+ const parsedDate = new Date(
30
+ value.includes('T') ? value : `${value}T00:00:00`
31
+ );
32
+
33
+ if (Number.isNaN(parsedDate.getTime())) {
34
+ return '-';
35
+ }
36
+
37
+ if (getSettingValue) {
38
+ try {
39
+ return formatDateWithSettings(
40
+ parsedDate,
41
+ getSettingValue,
42
+ currentLocaleCode
43
+ );
44
+ } catch {
45
+ // Fall back to a locale-based format below.
46
+ }
47
+ }
48
+
49
+ return parsedDate.toLocaleDateString(resolveLocale(currentLocaleCode), {
17
50
  month: 'short',
18
51
  day: 'numeric',
19
52
  year: 'numeric',
20
53
  });
21
54
  }
22
55
 
23
- export function formatDateTime(value?: string | null) {
56
+ export function formatDateTime(
57
+ value?: string | null,
58
+ getSettingValue?: ((key: string) => unknown) | null,
59
+ currentLocaleCode = 'en-US'
60
+ ) {
24
61
  if (!value) {
25
62
  return '-';
26
63
  }
27
64
 
28
- return new Date(value).toLocaleString('en-US', {
65
+ const parsedDate = new Date(value);
66
+
67
+ if (Number.isNaN(parsedDate.getTime())) {
68
+ return '-';
69
+ }
70
+
71
+ if (getSettingValue) {
72
+ try {
73
+ return formatDateTimeWithSettings(
74
+ parsedDate,
75
+ getSettingValue,
76
+ currentLocaleCode
77
+ );
78
+ } catch {
79
+ // Fall back to a locale-based format below.
80
+ }
81
+ }
82
+
83
+ return parsedDate.toLocaleString(resolveLocale(currentLocaleCode), {
29
84
  month: 'short',
30
85
  day: 'numeric',
31
86
  year: 'numeric',
@@ -50,6 +105,26 @@ export function formatHours(value?: number | null) {
50
105
  return `${Number(value).toFixed(1)}h`;
51
106
  }
52
107
 
108
+ function formatTimeValue(value?: string | null) {
109
+ if (!value) {
110
+ return '-';
111
+ }
112
+
113
+ const directMatch = String(value).match(/(\d{2}:\d{2})(?::\d{2})?/);
114
+
115
+ if (directMatch?.[1]) {
116
+ return directMatch[1];
117
+ }
118
+
119
+ const parsedDate = new Date(value);
120
+
121
+ if (!Number.isNaN(parsedDate.getTime())) {
122
+ return parsedDate.toISOString().slice(11, 16);
123
+ }
124
+
125
+ return String(value);
126
+ }
127
+
53
128
  export function formatEnumLabel(value?: string | null) {
54
129
  if (!value) {
55
130
  return '-';
@@ -62,17 +137,19 @@ export function formatEnumLabel(value?: string | null) {
62
137
 
63
138
  export function formatDateRange(
64
139
  startDate?: string | null,
65
- endDate?: string | null
140
+ endDate?: string | null,
141
+ getSettingValue?: ((key: string) => unknown) | null,
142
+ currentLocaleCode = 'en-US'
66
143
  ) {
67
144
  if (!startDate && !endDate) {
68
145
  return '-';
69
146
  }
70
147
 
71
148
  if (!endDate || startDate === endDate) {
72
- return formatDate(startDate);
149
+ return formatDate(startDate, getSettingValue, currentLocaleCode);
73
150
  }
74
151
 
75
- return `${formatDate(startDate)} to ${formatDate(endDate)}`;
152
+ return `${formatDate(startDate, getSettingValue, currentLocaleCode)} to ${formatDate(endDate, getSettingValue, currentLocaleCode)}`;
76
153
  }
77
154
 
78
155
  export function getStatusBadgeClass(value?: string | null) {
@@ -120,7 +197,7 @@ export function summarizeScheduleDays(
120
197
  .map((day) => {
121
198
  const label = formatEnumLabel(day.weekday);
122
199
  if (day.startTime && day.endTime) {
123
- return `${label}: ${day.startTime}-${day.endTime}`;
200
+ return `${label}: ${formatTimeValue(day.startTime)}-${formatTimeValue(day.endTime)}`;
124
201
  }
125
202
 
126
203
  return label;
@@ -37,34 +37,12 @@ import {
37
37
  getStatusBadgeClass,
38
38
  } from '../_lib/utils/format';
39
39
 
40
- type PendingDecision = {
41
- approval: OperationsApproval;
42
- action: 'approve' | 'reject';
43
- };
44
-
45
- function getTargetLabel(approval: OperationsApproval) {
46
- switch (approval.targetType) {
47
- case 'timesheet':
48
- return `Timesheet ${formatDateRange(
49
- approval.timesheetWeekStartDate,
50
- approval.timesheetWeekEndDate
51
- )}`;
52
- case 'time_off_request':
53
- return `${formatEnumLabel(approval.timeOffType)} ${formatDateRange(
54
- approval.timeOffStartDate,
55
- approval.timeOffEndDate
56
- )}`;
57
- case 'schedule_adjustment_request':
58
- return `${formatEnumLabel(approval.scheduleRequestScope)} ${formatDateRange(
59
- approval.scheduleStartDate,
60
- approval.scheduleEndDate
61
- )}`;
62
- default:
63
- return formatEnumLabel(approval.targetType);
64
- }
65
- }
66
-
67
- export default function OperationsApprovalsPage() {
40
+ type PendingDecision = {
41
+ approval: OperationsApproval;
42
+ action: 'approve' | 'reject';
43
+ };
44
+
45
+ export default function OperationsApprovalsPage() {
68
46
  const t = useTranslations('operations.ApprovalsPage');
69
47
  const commonT = useTranslations('operations.Common');
70
48
  const { request, showToastHandler, currentLocaleCode } = useApp();
@@ -72,10 +50,68 @@ export default function OperationsApprovalsPage() {
72
50
  const [search, setSearch] = useState('');
73
51
  const [statusFilter, setStatusFilter] = useState('all');
74
52
  const [targetFilter, setTargetFilter] = useState('all');
75
- const [decisionNote, setDecisionNote] = useState('');
76
- const [pendingDecision, setPendingDecision] = useState<PendingDecision | null>(
77
- null
78
- );
53
+ const [decisionNote, setDecisionNote] = useState('');
54
+ const [pendingDecision, setPendingDecision] = useState<PendingDecision | null>(
55
+ null
56
+ );
57
+
58
+ const getStatusLabel = (value?: string | null) => {
59
+ if (!value) {
60
+ return '-';
61
+ }
62
+
63
+ const key = `options.statuses.${value}`;
64
+ return t.has(key) ? t(key) : formatEnumLabel(value);
65
+ };
66
+
67
+ const getTargetTypeLabel = (value?: string | null) => {
68
+ if (!value) {
69
+ return '-';
70
+ }
71
+
72
+ const key = `options.targetTypes.${value}`;
73
+ return t.has(key) ? t(key) : formatEnumLabel(value);
74
+ };
75
+
76
+ const getTimeOffTypeLabel = (value?: string | null) => {
77
+ if (!value) {
78
+ return '-';
79
+ }
80
+
81
+ const key = `options.timeOffTypes.${value}`;
82
+ return t.has(key) ? t(key) : formatEnumLabel(value);
83
+ };
84
+
85
+ const getScheduleScopeLabel = (value?: string | null) => {
86
+ if (!value) {
87
+ return '-';
88
+ }
89
+
90
+ const key = `options.scheduleScopes.${value}`;
91
+ return t.has(key) ? t(key) : formatEnumLabel(value);
92
+ };
93
+
94
+ const getTargetLabel = (approval: OperationsApproval) => {
95
+ switch (approval.targetType) {
96
+ case 'timesheet':
97
+ return `${getTargetTypeLabel('timesheet')} ${formatDateRange(
98
+ approval.timesheetWeekStartDate,
99
+ approval.timesheetWeekEndDate
100
+ )}`;
101
+ case 'time_off_request':
102
+ return `${getTimeOffTypeLabel(approval.timeOffType)} ${formatDateRange(
103
+ approval.timeOffStartDate,
104
+ approval.timeOffEndDate
105
+ )}`;
106
+ case 'schedule_adjustment_request':
107
+ return `${getScheduleScopeLabel(approval.scheduleRequestScope)} ${formatDateRange(
108
+ approval.scheduleStartDate,
109
+ approval.scheduleEndDate
110
+ )}`;
111
+ default:
112
+ return getTargetTypeLabel(approval.targetType);
113
+ }
114
+ };
79
115
 
80
116
  const { data: approvals = [], refetch } = useQuery<OperationsApproval[]>({
81
117
  queryKey: ['operations-approvals', currentLocaleCode],
@@ -194,12 +230,12 @@ export default function OperationsApprovalsPage() {
194
230
  value: statusFilter,
195
231
  onChange: setStatusFilter,
196
232
  placeholder: commonT('labels.status'),
197
- options: [
198
- { value: 'all', label: commonT('filters.allStatuses') },
199
- { value: 'pending', label: formatEnumLabel('pending') },
200
- { value: 'approved', label: formatEnumLabel('approved') },
201
- { value: 'rejected', label: formatEnumLabel('rejected') },
202
- ],
233
+ options: [
234
+ { value: 'all', label: commonT('filters.allStatuses') },
235
+ { value: 'pending', label: getStatusLabel('pending') },
236
+ { value: 'approved', label: getStatusLabel('approved') },
237
+ { value: 'rejected', label: getStatusLabel('rejected') },
238
+ ],
203
239
  },
204
240
  {
205
241
  id: 'target',
@@ -207,18 +243,18 @@ export default function OperationsApprovalsPage() {
207
243
  value: targetFilter,
208
244
  onChange: setTargetFilter,
209
245
  placeholder: commonT('labels.requestType'),
210
- options: [
211
- { value: 'all', label: commonT('filters.allTypes') },
212
- { value: 'timesheet', label: formatEnumLabel('timesheet') },
213
- {
214
- value: 'time_off_request',
215
- label: formatEnumLabel('time_off_request'),
216
- },
217
- {
218
- value: 'schedule_adjustment_request',
219
- label: formatEnumLabel('schedule_adjustment_request'),
220
- },
221
- ],
246
+ options: [
247
+ { value: 'all', label: commonT('filters.allTypes') },
248
+ { value: 'timesheet', label: getTargetTypeLabel('timesheet') },
249
+ {
250
+ value: 'time_off_request',
251
+ label: getTargetTypeLabel('time_off_request'),
252
+ },
253
+ {
254
+ value: 'schedule_adjustment_request',
255
+ label: getTargetTypeLabel('schedule_adjustment_request'),
256
+ },
257
+ ],
222
258
  },
223
259
  ]}
224
260
  />
@@ -272,10 +308,10 @@ export default function OperationsApprovalsPage() {
272
308
  </div>
273
309
  </TableCell>
274
310
  <TableCell>
275
- <StatusBadge
276
- label={formatEnumLabel(approval.status)}
277
- className={getStatusBadgeClass(approval.status)}
278
- />
311
+ <StatusBadge
312
+ label={getStatusLabel(approval.status)}
313
+ className={getStatusBadgeClass(approval.status)}
314
+ />
279
315
  </TableCell>
280
316
  <TableCell>
281
317
  {approval.status === 'pending' ? (
@@ -1,4 +1,4 @@
1
- import { CollaboratorFormScreen } from '../../../_components/collaborator-form-screen';
1
+ import { redirect } from 'next/navigation';
2
2
 
3
3
  export default async function EditCollaboratorPage({
4
4
  params,
@@ -7,5 +7,5 @@ export default async function EditCollaboratorPage({
7
7
  }) {
8
8
  const { id } = await params;
9
9
 
10
- return <CollaboratorFormScreen collaboratorId={Number(id)} />;
10
+ redirect(`/operations/collaborators?edit=${id}`);
11
11
  }
@@ -1,4 +1,4 @@
1
- import { CollaboratorDetailsScreen } from '../../_components/collaborator-details-screen';
1
+ import { redirect } from 'next/navigation';
2
2
 
3
3
  export default async function CollaboratorDetailsPage({
4
4
  params,
@@ -7,5 +7,5 @@ export default async function CollaboratorDetailsPage({
7
7
  }) {
8
8
  const { id } = await params;
9
9
 
10
- return <CollaboratorDetailsScreen collaboratorId={Number(id)} />;
10
+ redirect(`/operations/collaborators?edit=${id}`);
11
11
  }