@hed-hog/operations 0.0.299 → 0.0.301
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/operations.controller.d.ts +713 -31
- package/dist/operations.controller.d.ts.map +1 -1
- package/dist/operations.controller.js +157 -0
- package/dist/operations.controller.js.map +1 -1
- package/dist/operations.module.d.ts.map +1 -1
- package/dist/operations.module.js +5 -1
- package/dist/operations.module.js.map +1 -1
- package/dist/operations.proposal.subscriber.d.ts +11 -0
- package/dist/operations.proposal.subscriber.d.ts.map +1 -0
- package/dist/operations.proposal.subscriber.js +80 -0
- package/dist/operations.proposal.subscriber.js.map +1 -0
- package/dist/operations.proposal.subscriber.spec.d.ts +2 -0
- package/dist/operations.proposal.subscriber.spec.d.ts.map +1 -0
- package/dist/operations.proposal.subscriber.spec.js +88 -0
- package/dist/operations.proposal.subscriber.spec.js.map +1 -0
- package/dist/operations.service.d.ts +490 -46
- package/dist/operations.service.d.ts.map +1 -1
- package/dist/operations.service.js +3590 -1267
- package/dist/operations.service.js.map +1 -1
- package/dist/operations.service.spec.d.ts +2 -0
- package/dist/operations.service.spec.d.ts.map +1 -0
- package/dist/operations.service.spec.js +159 -0
- package/dist/operations.service.spec.js.map +1 -0
- package/hedhog/data/menu.yaml +232 -198
- package/hedhog/data/role.yaml +23 -23
- package/hedhog/data/role_route.yaml +39 -0
- package/hedhog/data/route.yaml +447 -317
- package/hedhog/frontend/app/_components/collaborator-details-screen.tsx.ejs +8 -6
- package/hedhog/frontend/app/_components/collaborator-form-screen.tsx.ejs +1163 -327
- package/hedhog/frontend/app/_components/collaborator-select-with-create.tsx.ejs +256 -0
- package/hedhog/frontend/app/_components/contract-content-editor.tsx.ejs +258 -0
- package/hedhog/frontend/app/_components/contract-creation-wizard.tsx.ejs +631 -0
- package/hedhog/frontend/app/_components/contract-details-screen.tsx.ejs +353 -27
- package/hedhog/frontend/app/_components/contract-form-screen.tsx.ejs +1926 -87
- package/hedhog/frontend/app/_components/contract-template-form-screen.tsx.ejs +526 -0
- package/hedhog/frontend/app/_components/contract-template-select-with-create.tsx.ejs +247 -0
- package/hedhog/frontend/app/_components/contract-wizard-sheet.tsx.ejs +3520 -0
- package/hedhog/frontend/app/_components/department-select-with-create.tsx.ejs +370 -0
- package/hedhog/frontend/app/_components/person-select-with-create.tsx.ejs +826 -0
- package/hedhog/frontend/app/_components/project-form-screen.tsx.ejs +1251 -364
- package/hedhog/frontend/app/_components/section-card.tsx.ejs +48 -13
- package/hedhog/frontend/app/_lib/api.ts.ejs +2 -5
- package/hedhog/frontend/app/_lib/types.ts.ejs +76 -33
- package/hedhog/frontend/app/_lib/utils/format.ts.ejs +85 -8
- package/hedhog/frontend/app/approvals/page.tsx.ejs +90 -54
- package/hedhog/frontend/app/collaborators/[id]/edit/page.tsx.ejs +2 -2
- package/hedhog/frontend/app/collaborators/[id]/page.tsx.ejs +2 -2
- package/hedhog/frontend/app/collaborators/page.tsx.ejs +597 -140
- package/hedhog/frontend/app/contracts/[id]/edit/page.tsx.ejs +2 -2
- package/hedhog/frontend/app/contracts/[id]/page.tsx.ejs +2 -2
- package/hedhog/frontend/app/contracts/page.tsx.ejs +941 -262
- package/hedhog/frontend/app/contracts/templates/page.tsx.ejs +384 -0
- package/hedhog/frontend/app/departments/page.tsx.ejs +442 -0
- package/hedhog/frontend/app/page.tsx.ejs +36 -12
- package/hedhog/frontend/app/projects/[id]/edit/page.tsx.ejs +2 -2
- package/hedhog/frontend/app/projects/new/page.tsx.ejs +2 -2
- package/hedhog/frontend/app/projects/page.tsx.ejs +264 -102
- package/hedhog/frontend/app/schedule-adjustments/page.tsx.ejs +50 -28
- package/hedhog/frontend/app/time-off/page.tsx.ejs +57 -31
- package/hedhog/frontend/app/timesheets/page.tsx.ejs +85 -42
- package/hedhog/frontend/messages/en.json +473 -12
- package/hedhog/frontend/messages/pt.json +528 -66
- package/hedhog/table/operations_approval.yaml +49 -49
- package/hedhog/table/operations_approval_history.yaml +29 -29
- package/hedhog/table/operations_collaborator.yaml +87 -67
- package/hedhog/table/operations_collaborator_schedule_day.yaml +34 -34
- package/hedhog/table/operations_contract.yaml +121 -100
- package/hedhog/table/operations_contract_document.yaml +40 -23
- package/hedhog/table/operations_contract_financial_term.yaml +40 -40
- package/hedhog/table/operations_contract_history.yaml +27 -27
- package/hedhog/table/operations_contract_party.yaml +46 -46
- package/hedhog/table/operations_contract_revision.yaml +38 -38
- package/hedhog/table/operations_contract_signature.yaml +38 -38
- package/hedhog/table/operations_contract_template.yaml +58 -0
- package/hedhog/table/operations_department.yaml +24 -0
- package/hedhog/table/operations_project.yaml +54 -54
- package/hedhog/table/operations_project_assignment.yaml +55 -55
- package/hedhog/table/operations_schedule_adjustment_day.yaml +34 -34
- package/hedhog/table/operations_schedule_adjustment_request.yaml +53 -53
- package/hedhog/table/operations_time_off_request.yaml +57 -57
- package/hedhog/table/operations_timesheet.yaml +41 -41
- package/hedhog/table/operations_timesheet_entry.yaml +40 -40
- package/package.json +5 -3
- package/src/operations.controller.ts +304 -182
- package/src/operations.module.ts +26 -22
- package/src/operations.proposal.subscriber.spec.ts +121 -0
- package/src/operations.proposal.subscriber.ts +86 -0
- package/src/operations.service.spec.ts +210 -0
- package/src/operations.service.ts +7317 -3595
- package/dist/operations-data.controller.d.ts +0 -139
- package/dist/operations-data.controller.d.ts.map +0 -1
- package/dist/operations-data.controller.js +0 -113
- package/dist/operations-data.controller.js.map +0 -1
- package/dist/operations-growth.controller.d.ts +0 -48
- package/dist/operations-growth.controller.d.ts.map +0 -1
- package/dist/operations-growth.controller.js +0 -90
- package/dist/operations-growth.controller.js.map +0 -1
|
@@ -59,15 +59,33 @@ const emptyForm: TimeOffFormState = {
|
|
|
59
59
|
reason: '',
|
|
60
60
|
};
|
|
61
61
|
|
|
62
|
-
export default function OperationsTimeOffPage() {
|
|
63
|
-
const t = useTranslations('operations.TimeOffPage');
|
|
64
|
-
const commonT = useTranslations('operations.Common');
|
|
65
|
-
const { request, showToastHandler, currentLocaleCode } = useApp();
|
|
66
|
-
const access = useOperationsAccess();
|
|
67
|
-
const [search, setSearch] = useState('');
|
|
68
|
-
const [statusFilter, setStatusFilter] = useState('all');
|
|
69
|
-
const [isSheetOpen, setIsSheetOpen] = useState(false);
|
|
70
|
-
const [form, setForm] = useState<TimeOffFormState>(emptyForm);
|
|
62
|
+
export default function OperationsTimeOffPage() {
|
|
63
|
+
const t = useTranslations('operations.TimeOffPage');
|
|
64
|
+
const commonT = useTranslations('operations.Common');
|
|
65
|
+
const { request, showToastHandler, currentLocaleCode } = useApp();
|
|
66
|
+
const access = useOperationsAccess();
|
|
67
|
+
const [search, setSearch] = useState('');
|
|
68
|
+
const [statusFilter, setStatusFilter] = useState('all');
|
|
69
|
+
const [isSheetOpen, setIsSheetOpen] = useState(false);
|
|
70
|
+
const [form, setForm] = useState<TimeOffFormState>(emptyForm);
|
|
71
|
+
|
|
72
|
+
const getRequestTypeLabel = (value?: string | null) => {
|
|
73
|
+
if (!value) {
|
|
74
|
+
return '-';
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const key = `options.requestTypes.${value}`;
|
|
78
|
+
return t.has(key) ? t(key) : formatEnumLabel(value);
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
const getStatusLabel = (value?: string | null) => {
|
|
82
|
+
if (!value) {
|
|
83
|
+
return '-';
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const key = `options.statuses.${value}`;
|
|
87
|
+
return t.has(key) ? t(key) : formatEnumLabel(value);
|
|
88
|
+
};
|
|
71
89
|
|
|
72
90
|
const { data: requests = [], refetch } = useQuery<OperationsTimeOffRequest[]>({
|
|
73
91
|
queryKey: ['operations-time-off', currentLocaleCode],
|
|
@@ -166,12 +184,12 @@ export default function OperationsTimeOffPage() {
|
|
|
166
184
|
value: statusFilter,
|
|
167
185
|
onChange: setStatusFilter,
|
|
168
186
|
placeholder: commonT('labels.status'),
|
|
169
|
-
options: [
|
|
170
|
-
{ value: 'all', label: commonT('filters.allStatuses') },
|
|
171
|
-
{ value: 'submitted', label:
|
|
172
|
-
{ value: 'approved', label:
|
|
173
|
-
{ value: 'rejected', label:
|
|
174
|
-
],
|
|
187
|
+
options: [
|
|
188
|
+
{ value: 'all', label: commonT('filters.allStatuses') },
|
|
189
|
+
{ value: 'submitted', label: getStatusLabel('submitted') },
|
|
190
|
+
{ value: 'approved', label: getStatusLabel('approved') },
|
|
191
|
+
{ value: 'rejected', label: getStatusLabel('rejected') },
|
|
192
|
+
],
|
|
175
193
|
},
|
|
176
194
|
]}
|
|
177
195
|
/>
|
|
@@ -196,7 +214,7 @@ export default function OperationsTimeOffPage() {
|
|
|
196
214
|
{filteredRows.map((requestItem) => (
|
|
197
215
|
<TableRow key={requestItem.id}>
|
|
198
216
|
<TableCell>{requestItem.collaboratorName}</TableCell>
|
|
199
|
-
<TableCell>{
|
|
217
|
+
<TableCell>{getRequestTypeLabel(requestItem.requestType)}</TableCell>
|
|
200
218
|
<TableCell>
|
|
201
219
|
<div>
|
|
202
220
|
{formatDateRange(requestItem.startDate, requestItem.endDate)}
|
|
@@ -209,10 +227,10 @@ export default function OperationsTimeOffPage() {
|
|
|
209
227
|
{requestItem.approverName || commonT('labels.notAssigned')}
|
|
210
228
|
</TableCell>
|
|
211
229
|
<TableCell>
|
|
212
|
-
<StatusBadge
|
|
213
|
-
label={
|
|
214
|
-
className={getStatusBadgeClass(requestItem.status)}
|
|
215
|
-
/>
|
|
230
|
+
<StatusBadge
|
|
231
|
+
label={getStatusLabel(requestItem.status)}
|
|
232
|
+
className={getStatusBadgeClass(requestItem.status)}
|
|
233
|
+
/>
|
|
216
234
|
</TableCell>
|
|
217
235
|
<TableCell>
|
|
218
236
|
{requestItem.reason || commonT('labels.noNotes')}
|
|
@@ -251,17 +269,25 @@ export default function OperationsTimeOffPage() {
|
|
|
251
269
|
setForm((current) => ({ ...current, requestType: value }))
|
|
252
270
|
}
|
|
253
271
|
>
|
|
254
|
-
<SelectTrigger>
|
|
255
|
-
<SelectValue />
|
|
256
|
-
</SelectTrigger>
|
|
257
|
-
<SelectContent>
|
|
258
|
-
<SelectItem value="vacation">
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
<SelectItem value="
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
272
|
+
<SelectTrigger>
|
|
273
|
+
<SelectValue />
|
|
274
|
+
</SelectTrigger>
|
|
275
|
+
<SelectContent>
|
|
276
|
+
<SelectItem value="vacation">
|
|
277
|
+
{getRequestTypeLabel('vacation')}
|
|
278
|
+
</SelectItem>
|
|
279
|
+
<SelectItem value="personal_time">
|
|
280
|
+
{getRequestTypeLabel('personal_time')}
|
|
281
|
+
</SelectItem>
|
|
282
|
+
<SelectItem value="sick_leave">
|
|
283
|
+
{getRequestTypeLabel('sick_leave')}
|
|
284
|
+
</SelectItem>
|
|
285
|
+
<SelectItem value="unpaid_leave">
|
|
286
|
+
{getRequestTypeLabel('unpaid_leave')}
|
|
287
|
+
</SelectItem>
|
|
288
|
+
<SelectItem value="other">{getRequestTypeLabel('other')}</SelectItem>
|
|
289
|
+
</SelectContent>
|
|
290
|
+
</Select>
|
|
265
291
|
</div>
|
|
266
292
|
|
|
267
293
|
<div className="grid gap-4 md:grid-cols-2">
|
|
@@ -78,7 +78,9 @@ const emptyForm: TimesheetFormState = {
|
|
|
78
78
|
entries: [createEmptyEntry()],
|
|
79
79
|
};
|
|
80
80
|
|
|
81
|
-
function toFormState(
|
|
81
|
+
function toFormState(
|
|
82
|
+
timesheet?: OperationsTimesheet | null
|
|
83
|
+
): TimesheetFormState {
|
|
82
84
|
if (!timesheet) {
|
|
83
85
|
return emptyForm;
|
|
84
86
|
}
|
|
@@ -87,21 +89,20 @@ function toFormState(timesheet?: OperationsTimesheet | null): TimesheetFormState
|
|
|
87
89
|
weekStartDate: timesheet.weekStartDate ?? '',
|
|
88
90
|
weekEndDate: timesheet.weekEndDate ?? '',
|
|
89
91
|
notes: timesheet.notes ?? '',
|
|
90
|
-
entries:
|
|
91
|
-
timesheet.entries
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
hours
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
: [createEmptyEntry()],
|
|
92
|
+
entries: timesheet.entries?.length
|
|
93
|
+
? timesheet.entries.map((entry) => ({
|
|
94
|
+
projectAssignmentId: entry.projectAssignmentId
|
|
95
|
+
? String(entry.projectAssignmentId)
|
|
96
|
+
: 'none',
|
|
97
|
+
activityLabel: entry.activityLabel ?? '',
|
|
98
|
+
workDate: entry.workDate ?? '',
|
|
99
|
+
hours:
|
|
100
|
+
entry.hours !== null && entry.hours !== undefined
|
|
101
|
+
? String(entry.hours)
|
|
102
|
+
: '',
|
|
103
|
+
description: entry.description ?? '',
|
|
104
|
+
}))
|
|
105
|
+
: [createEmptyEntry()],
|
|
105
106
|
};
|
|
106
107
|
}
|
|
107
108
|
|
|
@@ -113,9 +114,8 @@ export default function OperationsTimesheetsPage() {
|
|
|
113
114
|
const [search, setSearch] = useState('');
|
|
114
115
|
const [statusFilter, setStatusFilter] = useState('all');
|
|
115
116
|
const [isSheetOpen, setIsSheetOpen] = useState(false);
|
|
116
|
-
const [editingTimesheet, setEditingTimesheet] =
|
|
117
|
-
null
|
|
118
|
-
);
|
|
117
|
+
const [editingTimesheet, setEditingTimesheet] =
|
|
118
|
+
useState<OperationsTimesheet | null>(null);
|
|
119
119
|
const [form, setForm] = useState<TimesheetFormState>(emptyForm);
|
|
120
120
|
|
|
121
121
|
const { data: timesheets = [], refetch } = useQuery<OperationsTimesheet[]>({
|
|
@@ -128,13 +128,17 @@ export default function OperationsTimesheetsPage() {
|
|
|
128
128
|
queryKey: ['operations-timesheets-me', currentLocaleCode],
|
|
129
129
|
enabled: access.isCollaborator,
|
|
130
130
|
queryFn: () =>
|
|
131
|
-
fetchOperations<OperationsCollaborator>(
|
|
131
|
+
fetchOperations<OperationsCollaborator>(
|
|
132
|
+
request,
|
|
133
|
+
'/operations/collaborators/me'
|
|
134
|
+
),
|
|
132
135
|
});
|
|
133
136
|
|
|
134
137
|
const { data: projects = [] } = useQuery<OperationsProject[]>({
|
|
135
138
|
queryKey: ['operations-timesheet-project-options', currentLocaleCode],
|
|
136
139
|
enabled: access.isCollaborator,
|
|
137
|
-
queryFn: () =>
|
|
140
|
+
queryFn: () =>
|
|
141
|
+
fetchOperations<OperationsProject[]>(request, '/operations/projects'),
|
|
138
142
|
});
|
|
139
143
|
|
|
140
144
|
const projectOptions = useMemo(
|
|
@@ -143,7 +147,9 @@ export default function OperationsTimesheetsPage() {
|
|
|
143
147
|
.filter((project) => project.myAssignmentId)
|
|
144
148
|
.map((project) => ({
|
|
145
149
|
value: String(project.myAssignmentId),
|
|
146
|
-
label: [project.name, project.myRoleLabel]
|
|
150
|
+
label: [project.name, project.myRoleLabel]
|
|
151
|
+
.filter(Boolean)
|
|
152
|
+
.join(' • '),
|
|
147
153
|
})),
|
|
148
154
|
[projects]
|
|
149
155
|
);
|
|
@@ -164,7 +170,9 @@ export default function OperationsTimesheetsPage() {
|
|
|
164
170
|
]
|
|
165
171
|
.filter(Boolean)
|
|
166
172
|
.some((value) =>
|
|
167
|
-
String(value)
|
|
173
|
+
String(value)
|
|
174
|
+
.toLowerCase()
|
|
175
|
+
.includes(search.trim().toLowerCase())
|
|
168
176
|
);
|
|
169
177
|
const matchesStatus =
|
|
170
178
|
statusFilter === 'all' ? true : item.status === statusFilter;
|
|
@@ -211,8 +219,8 @@ export default function OperationsTimesheetsPage() {
|
|
|
211
219
|
const canManageRow = (timesheet: OperationsTimesheet) => {
|
|
212
220
|
return Boolean(
|
|
213
221
|
me?.id &&
|
|
214
|
-
|
|
215
|
-
|
|
222
|
+
timesheet.collaboratorId === me.id &&
|
|
223
|
+
['draft', 'rejected'].includes(timesheet.status)
|
|
216
224
|
);
|
|
217
225
|
};
|
|
218
226
|
|
|
@@ -283,7 +291,12 @@ export default function OperationsTimesheetsPage() {
|
|
|
283
291
|
payload
|
|
284
292
|
);
|
|
285
293
|
} else {
|
|
286
|
-
await mutateOperations(
|
|
294
|
+
await mutateOperations(
|
|
295
|
+
request,
|
|
296
|
+
'/operations/timesheets',
|
|
297
|
+
'POST',
|
|
298
|
+
payload
|
|
299
|
+
);
|
|
287
300
|
}
|
|
288
301
|
|
|
289
302
|
showToastHandler?.('success', t('messages.saveSuccess'));
|
|
@@ -369,7 +382,9 @@ export default function OperationsTimesheetsPage() {
|
|
|
369
382
|
{filteredRows.map((timesheet) => (
|
|
370
383
|
<TableRow key={timesheet.id}>
|
|
371
384
|
<TableCell>
|
|
372
|
-
<div className="font-medium">
|
|
385
|
+
<div className="font-medium">
|
|
386
|
+
{timesheet.collaboratorName}
|
|
387
|
+
</div>
|
|
373
388
|
<div className="text-xs text-muted-foreground">
|
|
374
389
|
{timesheet.notes || commonT('labels.noNotes')}
|
|
375
390
|
</div>
|
|
@@ -387,10 +402,11 @@ export default function OperationsTimesheetsPage() {
|
|
|
387
402
|
<div className="text-xs text-muted-foreground">
|
|
388
403
|
{(timesheet.entries ?? [])
|
|
389
404
|
.slice(0, 2)
|
|
390
|
-
.map(
|
|
391
|
-
|
|
392
|
-
.
|
|
393
|
-
|
|
405
|
+
.map(
|
|
406
|
+
(entry) =>
|
|
407
|
+
[entry.projectName, entry.activityLabel]
|
|
408
|
+
.filter(Boolean)
|
|
409
|
+
.join(' • ') || commonT('labels.unassigned')
|
|
394
410
|
)
|
|
395
411
|
.join(', ') || commonT('labels.unassigned')}
|
|
396
412
|
</div>
|
|
@@ -400,7 +416,12 @@ export default function OperationsTimesheetsPage() {
|
|
|
400
416
|
{timesheet.approverName || commonT('labels.notAssigned')}
|
|
401
417
|
</TableCell>
|
|
402
418
|
<TableCell>
|
|
403
|
-
<div>
|
|
419
|
+
<div>
|
|
420
|
+
{formatDateRange(
|
|
421
|
+
timesheet.weekStartDate,
|
|
422
|
+
timesheet.weekEndDate
|
|
423
|
+
)}
|
|
424
|
+
</div>
|
|
404
425
|
<div className="text-xs text-muted-foreground">
|
|
405
426
|
{timesheet.decisionNote || commonT('labels.noNotes')}
|
|
406
427
|
</div>
|
|
@@ -446,7 +467,11 @@ export default function OperationsTimesheetsPage() {
|
|
|
446
467
|
icon={<ClipboardList className="size-12" />}
|
|
447
468
|
title={commonT('states.emptyTitle')}
|
|
448
469
|
description={t('emptyDescription')}
|
|
449
|
-
actionLabel={
|
|
470
|
+
actionLabel={
|
|
471
|
+
access.isCollaborator
|
|
472
|
+
? commonT('actions.create')
|
|
473
|
+
: commonT('actions.refresh')
|
|
474
|
+
}
|
|
450
475
|
onAction={access.isCollaborator ? openCreate : () => void refetch()}
|
|
451
476
|
/>
|
|
452
477
|
)}
|
|
@@ -469,10 +494,12 @@ export default function OperationsTimesheetsPage() {
|
|
|
469
494
|
<SheetDescription>{t('sheet.description')}</SheetDescription>
|
|
470
495
|
</SheetHeader>
|
|
471
496
|
|
|
472
|
-
<div className="mt-6 grid gap-4">
|
|
497
|
+
<div className="mt-6 grid gap-4 px-4">
|
|
473
498
|
<div className="grid gap-4 md:grid-cols-2">
|
|
474
499
|
<div className="space-y-2">
|
|
475
|
-
<label className="text-sm font-medium">
|
|
500
|
+
<label className="text-sm font-medium">
|
|
501
|
+
{commonT('labels.weekStart')}
|
|
502
|
+
</label>
|
|
476
503
|
<Input
|
|
477
504
|
type="date"
|
|
478
505
|
value={form.weekStartDate}
|
|
@@ -485,7 +512,9 @@ export default function OperationsTimesheetsPage() {
|
|
|
485
512
|
/>
|
|
486
513
|
</div>
|
|
487
514
|
<div className="space-y-2">
|
|
488
|
-
<label className="text-sm font-medium">
|
|
515
|
+
<label className="text-sm font-medium">
|
|
516
|
+
{commonT('labels.weekEnd')}
|
|
517
|
+
</label>
|
|
489
518
|
<Input
|
|
490
519
|
type="date"
|
|
491
520
|
value={form.weekEndDate}
|
|
@@ -500,12 +529,17 @@ export default function OperationsTimesheetsPage() {
|
|
|
500
529
|
</div>
|
|
501
530
|
|
|
502
531
|
<div className="space-y-2">
|
|
503
|
-
<label className="text-sm font-medium">
|
|
532
|
+
<label className="text-sm font-medium">
|
|
533
|
+
{commonT('labels.notes')}
|
|
534
|
+
</label>
|
|
504
535
|
<Textarea
|
|
505
536
|
rows={3}
|
|
506
537
|
value={form.notes}
|
|
507
538
|
onChange={(event) =>
|
|
508
|
-
setForm((current) => ({
|
|
539
|
+
setForm((current) => ({
|
|
540
|
+
...current,
|
|
541
|
+
notes: event.target.value,
|
|
542
|
+
}))
|
|
509
543
|
}
|
|
510
544
|
/>
|
|
511
545
|
</div>
|
|
@@ -513,7 +547,9 @@ export default function OperationsTimesheetsPage() {
|
|
|
513
547
|
<div className="space-y-3">
|
|
514
548
|
<div className="flex items-center justify-between">
|
|
515
549
|
<div>
|
|
516
|
-
<div className="text-sm font-medium">
|
|
550
|
+
<div className="text-sm font-medium">
|
|
551
|
+
{t('entries.title')}
|
|
552
|
+
</div>
|
|
517
553
|
<div className="text-xs text-muted-foreground">
|
|
518
554
|
{projectOptions.length > 0
|
|
519
555
|
? t('entries.description')
|
|
@@ -551,7 +587,10 @@ export default function OperationsTimesheetsPage() {
|
|
|
551
587
|
{commonT('labels.unassigned')}
|
|
552
588
|
</SelectItem>
|
|
553
589
|
{projectOptions.map((option) => (
|
|
554
|
-
<SelectItem
|
|
590
|
+
<SelectItem
|
|
591
|
+
key={option.value}
|
|
592
|
+
value={option.value}
|
|
593
|
+
>
|
|
555
594
|
{option.label}
|
|
556
595
|
</SelectItem>
|
|
557
596
|
))}
|
|
@@ -566,7 +605,9 @@ export default function OperationsTimesheetsPage() {
|
|
|
566
605
|
<Input
|
|
567
606
|
value={entry.activityLabel}
|
|
568
607
|
onChange={(event) =>
|
|
569
|
-
updateEntry(index, {
|
|
608
|
+
updateEntry(index, {
|
|
609
|
+
activityLabel: event.target.value,
|
|
610
|
+
})
|
|
570
611
|
}
|
|
571
612
|
placeholder={t('entries.activityPlaceholder')}
|
|
572
613
|
/>
|
|
@@ -580,7 +621,9 @@ export default function OperationsTimesheetsPage() {
|
|
|
580
621
|
rows={2}
|
|
581
622
|
value={entry.description}
|
|
582
623
|
onChange={(event) =>
|
|
583
|
-
updateEntry(index, {
|
|
624
|
+
updateEntry(index, {
|
|
625
|
+
description: event.target.value,
|
|
626
|
+
})
|
|
584
627
|
}
|
|
585
628
|
/>
|
|
586
629
|
</div>
|