@hed-hog/operations 0.0.296 → 0.0.298

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 (32) hide show
  1. package/hedhog/frontend/app/_components/collaborator-details-screen.tsx.ejs +310 -310
  2. package/hedhog/frontend/app/_components/collaborator-form-screen.tsx.ejs +631 -631
  3. package/hedhog/frontend/app/_components/contract-details-screen.tsx.ejs +132 -132
  4. package/hedhog/frontend/app/_components/contract-form-screen.tsx.ejs +558 -558
  5. package/hedhog/frontend/app/_components/project-details-screen.tsx.ejs +291 -291
  6. package/hedhog/frontend/app/_components/project-form-screen.tsx.ejs +689 -689
  7. package/hedhog/frontend/app/_lib/api.ts.ejs +32 -32
  8. package/hedhog/frontend/app/_lib/hooks/use-operations-access.ts.ejs +44 -44
  9. package/hedhog/frontend/app/_lib/types.ts.ejs +360 -360
  10. package/hedhog/frontend/app/_lib/utils/format.ts.ejs +129 -129
  11. package/hedhog/frontend/app/_lib/utils/forms.ts.ejs +14 -14
  12. package/hedhog/frontend/app/approvals/page.tsx.ejs +386 -386
  13. package/hedhog/frontend/app/collaborators/[id]/edit/page.tsx.ejs +11 -11
  14. package/hedhog/frontend/app/collaborators/[id]/page.tsx.ejs +11 -11
  15. package/hedhog/frontend/app/collaborators/new/page.tsx.ejs +5 -5
  16. package/hedhog/frontend/app/collaborators/page.tsx.ejs +261 -261
  17. package/hedhog/frontend/app/contracts/[id]/edit/page.tsx.ejs +11 -11
  18. package/hedhog/frontend/app/contracts/[id]/page.tsx.ejs +11 -11
  19. package/hedhog/frontend/app/contracts/new/page.tsx.ejs +17 -17
  20. package/hedhog/frontend/app/contracts/page.tsx.ejs +262 -262
  21. package/hedhog/frontend/app/page.tsx.ejs +319 -319
  22. package/hedhog/frontend/app/projects/[id]/edit/page.tsx.ejs +11 -11
  23. package/hedhog/frontend/app/projects/[id]/page.tsx.ejs +11 -11
  24. package/hedhog/frontend/app/projects/new/page.tsx.ejs +5 -5
  25. package/hedhog/frontend/app/projects/page.tsx.ejs +236 -236
  26. package/hedhog/frontend/app/schedule-adjustments/page.tsx.ejs +418 -418
  27. package/hedhog/frontend/app/team/page.tsx.ejs +339 -339
  28. package/hedhog/frontend/app/time-off/page.tsx.ejs +328 -328
  29. package/hedhog/frontend/app/timesheets/page.tsx.ejs +636 -636
  30. package/hedhog/frontend/messages/en.json +648 -648
  31. package/hedhog/frontend/messages/pt.json +647 -647
  32. package/package.json +2 -2
@@ -1,310 +1,310 @@
1
- 'use client';
2
-
3
- import { EmptyState, Page } from '@/components/entity-list';
4
- import { Button } from '@/components/ui/button';
5
- import { KpiCardsGrid } from '@/components/ui/kpi-cards-grid';
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 { Pencil, UserRound } 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 type { OperationsCollaboratorDetails } from '../_lib/types';
23
- import {
24
- formatDate,
25
- formatDateRange,
26
- formatEnumLabel,
27
- formatHours,
28
- getStatusBadgeClass,
29
- summarizeScheduleDays,
30
- } from '../_lib/utils/format';
31
- import { useOperationsAccess } from '../_lib/hooks/use-operations-access';
32
-
33
- export function CollaboratorDetailsScreen({
34
- collaboratorId,
35
- }: {
36
- collaboratorId: number;
37
- }) {
38
- const t = useTranslations('operations.CollaboratorDetailsPage');
39
- const commonT = useTranslations('operations.Common');
40
- const { request, currentLocaleCode } = useApp();
41
- const access = useOperationsAccess();
42
-
43
- const { data: collaborator, refetch } = useQuery<OperationsCollaboratorDetails>({
44
- queryKey: ['operations-collaborator-details', currentLocaleCode, collaboratorId],
45
- queryFn: () =>
46
- fetchOperations<OperationsCollaboratorDetails>(
47
- request,
48
- `/operations/collaborators/${collaboratorId}`
49
- ),
50
- });
51
-
52
- if (!collaborator) {
53
- return (
54
- <Page>
55
- <OperationsHeader
56
- title={t('title')}
57
- description={t('description')}
58
- current={t('breadcrumb')}
59
- />
60
- <EmptyState
61
- icon={<UserRound className="size-12" />}
62
- title={commonT('states.emptyTitle')}
63
- description={t('notFound')}
64
- actionLabel={commonT('actions.refresh')}
65
- onAction={() => void refetch()}
66
- />
67
- </Page>
68
- );
69
- }
70
-
71
- const summaryCards = [
72
- {
73
- key: 'timesheets',
74
- title: t('cards.timesheets'),
75
- value: collaborator.timesheetSummary.totalTimesheets,
76
- description: t('cards.timesheetsDescription', {
77
- pending: collaborator.timesheetSummary.pendingTimesheets,
78
- }),
79
- },
80
- {
81
- key: 'hours',
82
- title: t('cards.loggedHours'),
83
- value: formatHours(collaborator.timesheetSummary.totalHours),
84
- description: t('cards.loggedHoursDescription'),
85
- },
86
- {
87
- key: 'timeOff',
88
- title: t('cards.timeOff'),
89
- value: collaborator.timeOffSummary.totalRequests,
90
- description: t('cards.timeOffDescription', {
91
- pending: collaborator.timeOffSummary.pendingRequests,
92
- }),
93
- },
94
- {
95
- key: 'assignments',
96
- title: t('cards.assignments'),
97
- value: collaborator.assignedProjects.length,
98
- description: t('cards.assignmentsDescription'),
99
- },
100
- ];
101
-
102
- return (
103
- <Page>
104
- <OperationsHeader
105
- title={collaborator.displayName}
106
- description={t('description')}
107
- current={t('breadcrumb')}
108
- actions={
109
- access.isDirector ? (
110
- <Button size="sm" asChild>
111
- <Link href={`/operations/collaborators/${collaborator.id}/edit`}>
112
- <Pencil className="size-4" />
113
- {commonT('actions.edit')}
114
- </Link>
115
- </Button>
116
- ) : undefined
117
- }
118
- />
119
-
120
- <div className="grid gap-4 xl:grid-cols-4">
121
- <SectionCard title={t('sections.profile')} className="xl:col-span-2">
122
- <dl className="grid gap-3 md:grid-cols-2 text-sm">
123
- <div>
124
- <dt className="text-muted-foreground">{commonT('labels.collaborator')}</dt>
125
- <dd className="font-medium">{collaborator.displayName}</dd>
126
- </div>
127
- <div>
128
- <dt className="text-muted-foreground">{commonT('labels.collaboratorType')}</dt>
129
- <dd className="font-medium">
130
- {formatEnumLabel(collaborator.collaboratorType)}
131
- </dd>
132
- </div>
133
- <div>
134
- <dt className="text-muted-foreground">{commonT('labels.department')}</dt>
135
- <dd className="font-medium">
136
- {collaborator.department || commonT('labels.notAvailable')}
137
- </dd>
138
- </div>
139
- <div>
140
- <dt className="text-muted-foreground">{commonT('labels.title')}</dt>
141
- <dd className="font-medium">
142
- {collaborator.title || commonT('labels.notAvailable')}
143
- </dd>
144
- </div>
145
- <div>
146
- <dt className="text-muted-foreground">{commonT('labels.supervisor')}</dt>
147
- <dd className="font-medium">
148
- {collaborator.supervisorName || commonT('labels.notAssigned')}
149
- </dd>
150
- </div>
151
- <div>
152
- <dt className="text-muted-foreground">{commonT('labels.weeklyCapacity')}</dt>
153
- <dd className="font-medium">
154
- {formatHours(collaborator.weeklyCapacityHours)}
155
- </dd>
156
- </div>
157
- <div>
158
- <dt className="text-muted-foreground">{commonT('labels.startDate')}</dt>
159
- <dd className="font-medium">{formatDate(collaborator.joinedAt)}</dd>
160
- </div>
161
- <div>
162
- <dt className="text-muted-foreground">{commonT('labels.status')}</dt>
163
- <dd className="font-medium">
164
- <StatusBadge
165
- label={formatEnumLabel(collaborator.status)}
166
- className={getStatusBadgeClass(collaborator.status)}
167
- />
168
- </dd>
169
- </div>
170
- </dl>
171
- </SectionCard>
172
-
173
- <SectionCard title={t('sections.primaryContract')} className="xl:col-span-2">
174
- {collaborator.relatedContracts.length > 0 ? (
175
- <div className="space-y-3">
176
- {collaborator.relatedContracts.slice(0, 2).map((contract) => (
177
- <div
178
- key={contract.id}
179
- className="flex items-center justify-between rounded-lg border px-4 py-3"
180
- >
181
- <div>
182
- <div className="font-medium">{contract.name}</div>
183
- <div className="text-sm text-muted-foreground">
184
- {contract.code} • {formatEnumLabel(contract.contractCategory)}
185
- </div>
186
- </div>
187
- <div className="flex items-center gap-2">
188
- <StatusBadge
189
- label={formatEnumLabel(contract.status)}
190
- className={getStatusBadgeClass(contract.status)}
191
- />
192
- <Button variant="outline" size="sm" asChild>
193
- <Link href={`/operations/contracts?edit=${contract.id}`}>
194
- {commonT('actions.openContract')}
195
- </Link>
196
- </Button>
197
- </div>
198
- </div>
199
- ))}
200
- </div>
201
- ) : (
202
- <p className="text-sm text-muted-foreground">{t('noContracts')}</p>
203
- )}
204
- </SectionCard>
205
- </div>
206
-
207
- <KpiCardsGrid items={summaryCards} />
208
-
209
- <div className="grid gap-4 xl:grid-cols-2">
210
- <SectionCard title={t('sections.projects')} description={t('sections.projectsDescription')}>
211
- {collaborator.assignedProjects.length > 0 ? (
212
- <div className="overflow-x-auto rounded-md border">
213
- <Table>
214
- <TableHeader>
215
- <TableRow>
216
- <TableHead>{commonT('labels.project')}</TableHead>
217
- <TableHead>{commonT('labels.role')}</TableHead>
218
- <TableHead>{commonT('labels.timeline')}</TableHead>
219
- <TableHead>{commonT('labels.status')}</TableHead>
220
- </TableRow>
221
- </TableHeader>
222
- <TableBody>
223
- {collaborator.assignedProjects.map((project) => (
224
- <TableRow key={project.id}>
225
- <TableCell>
226
- <div className="font-medium">{project.name}</div>
227
- <div className="text-xs text-muted-foreground">
228
- {project.code}
229
- </div>
230
- </TableCell>
231
- <TableCell>{project.roleLabel || commonT('labels.notAssigned')}</TableCell>
232
- <TableCell>{formatDateRange(project.startDate, project.endDate)}</TableCell>
233
- <TableCell>
234
- <StatusBadge
235
- label={formatEnumLabel(project.status)}
236
- className={getStatusBadgeClass(project.status)}
237
- />
238
- </TableCell>
239
- </TableRow>
240
- ))}
241
- </TableBody>
242
- </Table>
243
- </div>
244
- ) : (
245
- <p className="text-sm text-muted-foreground">{t('noProjects')}</p>
246
- )}
247
- </SectionCard>
248
-
249
- <SectionCard title={t('sections.schedule')} description={t('sections.scheduleDescription')}>
250
- <p className="text-sm">
251
- {summarizeScheduleDays(collaborator.weeklySchedule)}
252
- </p>
253
- </SectionCard>
254
- </div>
255
-
256
- <div className="grid gap-4 xl:grid-cols-2">
257
- <SectionCard title={t('sections.timeOff')} description={t('sections.timeOffDescription')}>
258
- <dl className="grid gap-3 md:grid-cols-3 text-sm">
259
- <div>
260
- <dt className="text-muted-foreground">{commonT('labels.total')}</dt>
261
- <dd className="font-medium">{collaborator.timeOffSummary.totalRequests}</dd>
262
- </div>
263
- <div>
264
- <dt className="text-muted-foreground">{commonT('labels.pending')}</dt>
265
- <dd className="font-medium">{collaborator.timeOffSummary.pendingRequests}</dd>
266
- </div>
267
- <div>
268
- <dt className="text-muted-foreground">{commonT('labels.approved')}</dt>
269
- <dd className="font-medium">{collaborator.timeOffSummary.approvedRequests}</dd>
270
- </div>
271
- </dl>
272
- </SectionCard>
273
-
274
- <SectionCard
275
- title={t('sections.scheduleAdjustments')}
276
- description={t('sections.scheduleAdjustmentsDescription')}
277
- >
278
- {collaborator.scheduleAdjustmentRequests.length > 0 ? (
279
- <div className="space-y-2">
280
- {collaborator.scheduleAdjustmentRequests.map((request) => (
281
- <div
282
- key={request.id}
283
- className="flex items-center justify-between rounded-lg border px-4 py-3 text-sm"
284
- >
285
- <div>
286
- <div className="font-medium">
287
- {formatEnumLabel(request.requestScope)}
288
- </div>
289
- <div className="text-muted-foreground">
290
- {formatDateRange(
291
- request.effectiveStartDate,
292
- request.effectiveEndDate
293
- )}
294
- </div>
295
- </div>
296
- <StatusBadge
297
- label={formatEnumLabel(request.status)}
298
- className={getStatusBadgeClass(request.status)}
299
- />
300
- </div>
301
- ))}
302
- </div>
303
- ) : (
304
- <p className="text-sm text-muted-foreground">{t('noScheduleAdjustments')}</p>
305
- )}
306
- </SectionCard>
307
- </div>
308
- </Page>
309
- );
310
- }
1
+ 'use client';
2
+
3
+ import { EmptyState, Page } from '@/components/entity-list';
4
+ import { Button } from '@/components/ui/button';
5
+ import { KpiCardsGrid } from '@/components/ui/kpi-cards-grid';
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 { Pencil, UserRound } 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 type { OperationsCollaboratorDetails } from '../_lib/types';
23
+ import {
24
+ formatDate,
25
+ formatDateRange,
26
+ formatEnumLabel,
27
+ formatHours,
28
+ getStatusBadgeClass,
29
+ summarizeScheduleDays,
30
+ } from '../_lib/utils/format';
31
+ import { useOperationsAccess } from '../_lib/hooks/use-operations-access';
32
+
33
+ export function CollaboratorDetailsScreen({
34
+ collaboratorId,
35
+ }: {
36
+ collaboratorId: number;
37
+ }) {
38
+ const t = useTranslations('operations.CollaboratorDetailsPage');
39
+ const commonT = useTranslations('operations.Common');
40
+ const { request, currentLocaleCode } = useApp();
41
+ const access = useOperationsAccess();
42
+
43
+ const { data: collaborator, refetch } = useQuery<OperationsCollaboratorDetails>({
44
+ queryKey: ['operations-collaborator-details', currentLocaleCode, collaboratorId],
45
+ queryFn: () =>
46
+ fetchOperations<OperationsCollaboratorDetails>(
47
+ request,
48
+ `/operations/collaborators/${collaboratorId}`
49
+ ),
50
+ });
51
+
52
+ if (!collaborator) {
53
+ return (
54
+ <Page>
55
+ <OperationsHeader
56
+ title={t('title')}
57
+ description={t('description')}
58
+ current={t('breadcrumb')}
59
+ />
60
+ <EmptyState
61
+ icon={<UserRound className="size-12" />}
62
+ title={commonT('states.emptyTitle')}
63
+ description={t('notFound')}
64
+ actionLabel={commonT('actions.refresh')}
65
+ onAction={() => void refetch()}
66
+ />
67
+ </Page>
68
+ );
69
+ }
70
+
71
+ const summaryCards = [
72
+ {
73
+ key: 'timesheets',
74
+ title: t('cards.timesheets'),
75
+ value: collaborator.timesheetSummary.totalTimesheets,
76
+ description: t('cards.timesheetsDescription', {
77
+ pending: collaborator.timesheetSummary.pendingTimesheets,
78
+ }),
79
+ },
80
+ {
81
+ key: 'hours',
82
+ title: t('cards.loggedHours'),
83
+ value: formatHours(collaborator.timesheetSummary.totalHours),
84
+ description: t('cards.loggedHoursDescription'),
85
+ },
86
+ {
87
+ key: 'timeOff',
88
+ title: t('cards.timeOff'),
89
+ value: collaborator.timeOffSummary.totalRequests,
90
+ description: t('cards.timeOffDescription', {
91
+ pending: collaborator.timeOffSummary.pendingRequests,
92
+ }),
93
+ },
94
+ {
95
+ key: 'assignments',
96
+ title: t('cards.assignments'),
97
+ value: collaborator.assignedProjects.length,
98
+ description: t('cards.assignmentsDescription'),
99
+ },
100
+ ];
101
+
102
+ return (
103
+ <Page>
104
+ <OperationsHeader
105
+ title={collaborator.displayName}
106
+ description={t('description')}
107
+ current={t('breadcrumb')}
108
+ actions={
109
+ access.isDirector ? (
110
+ <Button size="sm" asChild>
111
+ <Link href={`/operations/collaborators/${collaborator.id}/edit`}>
112
+ <Pencil className="size-4" />
113
+ {commonT('actions.edit')}
114
+ </Link>
115
+ </Button>
116
+ ) : undefined
117
+ }
118
+ />
119
+
120
+ <div className="grid gap-4 xl:grid-cols-4">
121
+ <SectionCard title={t('sections.profile')} className="xl:col-span-2">
122
+ <dl className="grid gap-3 md:grid-cols-2 text-sm">
123
+ <div>
124
+ <dt className="text-muted-foreground">{commonT('labels.collaborator')}</dt>
125
+ <dd className="font-medium">{collaborator.displayName}</dd>
126
+ </div>
127
+ <div>
128
+ <dt className="text-muted-foreground">{commonT('labels.collaboratorType')}</dt>
129
+ <dd className="font-medium">
130
+ {formatEnumLabel(collaborator.collaboratorType)}
131
+ </dd>
132
+ </div>
133
+ <div>
134
+ <dt className="text-muted-foreground">{commonT('labels.department')}</dt>
135
+ <dd className="font-medium">
136
+ {collaborator.department || commonT('labels.notAvailable')}
137
+ </dd>
138
+ </div>
139
+ <div>
140
+ <dt className="text-muted-foreground">{commonT('labels.title')}</dt>
141
+ <dd className="font-medium">
142
+ {collaborator.title || commonT('labels.notAvailable')}
143
+ </dd>
144
+ </div>
145
+ <div>
146
+ <dt className="text-muted-foreground">{commonT('labels.supervisor')}</dt>
147
+ <dd className="font-medium">
148
+ {collaborator.supervisorName || commonT('labels.notAssigned')}
149
+ </dd>
150
+ </div>
151
+ <div>
152
+ <dt className="text-muted-foreground">{commonT('labels.weeklyCapacity')}</dt>
153
+ <dd className="font-medium">
154
+ {formatHours(collaborator.weeklyCapacityHours)}
155
+ </dd>
156
+ </div>
157
+ <div>
158
+ <dt className="text-muted-foreground">{commonT('labels.startDate')}</dt>
159
+ <dd className="font-medium">{formatDate(collaborator.joinedAt)}</dd>
160
+ </div>
161
+ <div>
162
+ <dt className="text-muted-foreground">{commonT('labels.status')}</dt>
163
+ <dd className="font-medium">
164
+ <StatusBadge
165
+ label={formatEnumLabel(collaborator.status)}
166
+ className={getStatusBadgeClass(collaborator.status)}
167
+ />
168
+ </dd>
169
+ </div>
170
+ </dl>
171
+ </SectionCard>
172
+
173
+ <SectionCard title={t('sections.primaryContract')} className="xl:col-span-2">
174
+ {collaborator.relatedContracts.length > 0 ? (
175
+ <div className="space-y-3">
176
+ {collaborator.relatedContracts.slice(0, 2).map((contract) => (
177
+ <div
178
+ key={contract.id}
179
+ className="flex items-center justify-between rounded-lg border px-4 py-3"
180
+ >
181
+ <div>
182
+ <div className="font-medium">{contract.name}</div>
183
+ <div className="text-sm text-muted-foreground">
184
+ {contract.code} • {formatEnumLabel(contract.contractCategory)}
185
+ </div>
186
+ </div>
187
+ <div className="flex items-center gap-2">
188
+ <StatusBadge
189
+ label={formatEnumLabel(contract.status)}
190
+ className={getStatusBadgeClass(contract.status)}
191
+ />
192
+ <Button variant="outline" size="sm" asChild>
193
+ <Link href={`/operations/contracts?edit=${contract.id}`}>
194
+ {commonT('actions.openContract')}
195
+ </Link>
196
+ </Button>
197
+ </div>
198
+ </div>
199
+ ))}
200
+ </div>
201
+ ) : (
202
+ <p className="text-sm text-muted-foreground">{t('noContracts')}</p>
203
+ )}
204
+ </SectionCard>
205
+ </div>
206
+
207
+ <KpiCardsGrid items={summaryCards} />
208
+
209
+ <div className="grid gap-4 xl:grid-cols-2">
210
+ <SectionCard title={t('sections.projects')} description={t('sections.projectsDescription')}>
211
+ {collaborator.assignedProjects.length > 0 ? (
212
+ <div className="overflow-x-auto rounded-md border">
213
+ <Table>
214
+ <TableHeader>
215
+ <TableRow>
216
+ <TableHead>{commonT('labels.project')}</TableHead>
217
+ <TableHead>{commonT('labels.role')}</TableHead>
218
+ <TableHead>{commonT('labels.timeline')}</TableHead>
219
+ <TableHead>{commonT('labels.status')}</TableHead>
220
+ </TableRow>
221
+ </TableHeader>
222
+ <TableBody>
223
+ {collaborator.assignedProjects.map((project) => (
224
+ <TableRow key={project.id}>
225
+ <TableCell>
226
+ <div className="font-medium">{project.name}</div>
227
+ <div className="text-xs text-muted-foreground">
228
+ {project.code}
229
+ </div>
230
+ </TableCell>
231
+ <TableCell>{project.roleLabel || commonT('labels.notAssigned')}</TableCell>
232
+ <TableCell>{formatDateRange(project.startDate, project.endDate)}</TableCell>
233
+ <TableCell>
234
+ <StatusBadge
235
+ label={formatEnumLabel(project.status)}
236
+ className={getStatusBadgeClass(project.status)}
237
+ />
238
+ </TableCell>
239
+ </TableRow>
240
+ ))}
241
+ </TableBody>
242
+ </Table>
243
+ </div>
244
+ ) : (
245
+ <p className="text-sm text-muted-foreground">{t('noProjects')}</p>
246
+ )}
247
+ </SectionCard>
248
+
249
+ <SectionCard title={t('sections.schedule')} description={t('sections.scheduleDescription')}>
250
+ <p className="text-sm">
251
+ {summarizeScheduleDays(collaborator.weeklySchedule)}
252
+ </p>
253
+ </SectionCard>
254
+ </div>
255
+
256
+ <div className="grid gap-4 xl:grid-cols-2">
257
+ <SectionCard title={t('sections.timeOff')} description={t('sections.timeOffDescription')}>
258
+ <dl className="grid gap-3 md:grid-cols-3 text-sm">
259
+ <div>
260
+ <dt className="text-muted-foreground">{commonT('labels.total')}</dt>
261
+ <dd className="font-medium">{collaborator.timeOffSummary.totalRequests}</dd>
262
+ </div>
263
+ <div>
264
+ <dt className="text-muted-foreground">{commonT('labels.pending')}</dt>
265
+ <dd className="font-medium">{collaborator.timeOffSummary.pendingRequests}</dd>
266
+ </div>
267
+ <div>
268
+ <dt className="text-muted-foreground">{commonT('labels.approved')}</dt>
269
+ <dd className="font-medium">{collaborator.timeOffSummary.approvedRequests}</dd>
270
+ </div>
271
+ </dl>
272
+ </SectionCard>
273
+
274
+ <SectionCard
275
+ title={t('sections.scheduleAdjustments')}
276
+ description={t('sections.scheduleAdjustmentsDescription')}
277
+ >
278
+ {collaborator.scheduleAdjustmentRequests.length > 0 ? (
279
+ <div className="space-y-2">
280
+ {collaborator.scheduleAdjustmentRequests.map((request) => (
281
+ <div
282
+ key={request.id}
283
+ className="flex items-center justify-between rounded-lg border px-4 py-3 text-sm"
284
+ >
285
+ <div>
286
+ <div className="font-medium">
287
+ {formatEnumLabel(request.requestScope)}
288
+ </div>
289
+ <div className="text-muted-foreground">
290
+ {formatDateRange(
291
+ request.effectiveStartDate,
292
+ request.effectiveEndDate
293
+ )}
294
+ </div>
295
+ </div>
296
+ <StatusBadge
297
+ label={formatEnumLabel(request.status)}
298
+ className={getStatusBadgeClass(request.status)}
299
+ />
300
+ </div>
301
+ ))}
302
+ </div>
303
+ ) : (
304
+ <p className="text-sm text-muted-foreground">{t('noScheduleAdjustments')}</p>
305
+ )}
306
+ </SectionCard>
307
+ </div>
308
+ </Page>
309
+ );
310
+ }