@hed-hog/operations 0.0.306 → 0.0.310
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-approvals.controller.d.ts +114 -1
- package/dist/controllers/operations-approvals.controller.d.ts.map +1 -1
- package/dist/controllers/operations-approvals.controller.js +16 -3
- package/dist/controllers/operations-approvals.controller.js.map +1 -1
- package/dist/controllers/operations-collaborators.controller.d.ts +16 -1
- package/dist/controllers/operations-collaborators.controller.d.ts.map +1 -1
- package/dist/controllers/operations-collaborators.controller.js +16 -3
- package/dist/controllers/operations-collaborators.controller.js.map +1 -1
- package/dist/controllers/operations-contracts.controller.d.ts +14 -453
- package/dist/controllers/operations-contracts.controller.d.ts.map +1 -1
- package/dist/controllers/operations-contracts.controller.js +11 -112
- package/dist/controllers/operations-contracts.controller.js.map +1 -1
- package/dist/controllers/operations-org-structure.controller.d.ts +65 -2
- package/dist/controllers/operations-org-structure.controller.d.ts.map +1 -1
- package/dist/controllers/operations-org-structure.controller.js +18 -5
- package/dist/controllers/operations-org-structure.controller.js.map +1 -1
- package/dist/controllers/operations-projects.controller.d.ts +28 -4
- package/dist/controllers/operations-projects.controller.d.ts.map +1 -1
- package/dist/controllers/operations-projects.controller.js +17 -5
- package/dist/controllers/operations-projects.controller.js.map +1 -1
- package/dist/controllers/operations-timesheets.controller.d.ts +31 -4
- package/dist/controllers/operations-timesheets.controller.d.ts.map +1 -1
- package/dist/controllers/operations-timesheets.controller.js +16 -11
- package/dist/controllers/operations-timesheets.controller.js.map +1 -1
- package/dist/dto/list-approvals.dto.d.ts +6 -0
- package/dist/dto/list-approvals.dto.d.ts.map +1 -0
- package/dist/dto/list-approvals.dto.js +28 -0
- package/dist/dto/list-approvals.dto.js.map +1 -0
- package/dist/dto/list-collaborator-types.dto.d.ts +3 -1
- package/dist/dto/list-collaborator-types.dto.d.ts.map +1 -1
- package/dist/dto/list-collaborator-types.dto.js +7 -1
- package/dist/dto/list-collaborator-types.dto.js.map +1 -1
- package/dist/dto/list-collaborators.dto.d.ts +1 -0
- package/dist/dto/list-collaborators.dto.d.ts.map +1 -1
- package/dist/dto/list-collaborators.dto.js +5 -0
- package/dist/dto/list-collaborators.dto.js.map +1 -1
- package/dist/dto/list-contracts.dto.d.ts +8 -0
- package/dist/dto/list-contracts.dto.d.ts.map +1 -0
- package/dist/dto/list-contracts.dto.js +38 -0
- package/dist/dto/list-contracts.dto.js.map +1 -0
- package/dist/dto/list-departments.dto.d.ts +5 -0
- package/dist/dto/list-departments.dto.d.ts.map +1 -0
- package/dist/dto/list-departments.dto.js +23 -0
- package/dist/dto/list-departments.dto.js.map +1 -0
- package/dist/dto/list-projects.dto.d.ts +5 -0
- package/dist/dto/list-projects.dto.d.ts.map +1 -0
- package/dist/dto/list-projects.dto.js +23 -0
- package/dist/dto/list-projects.dto.js.map +1 -0
- package/dist/dto/list-schedule-adjustments.dto.d.ts +5 -0
- package/dist/dto/list-schedule-adjustments.dto.d.ts.map +1 -0
- package/dist/dto/list-schedule-adjustments.dto.js +23 -0
- package/dist/dto/list-schedule-adjustments.dto.js.map +1 -0
- package/dist/dto/list-time-off-requests.dto.d.ts +5 -0
- package/dist/dto/list-time-off-requests.dto.d.ts.map +1 -0
- package/dist/dto/list-time-off-requests.dto.js +23 -0
- package/dist/dto/list-time-off-requests.dto.js.map +1 -0
- package/dist/dto/list-timesheets.dto.d.ts +5 -0
- package/dist/dto/list-timesheets.dto.d.ts.map +1 -0
- package/dist/dto/list-timesheets.dto.js +23 -0
- package/dist/dto/list-timesheets.dto.js.map +1 -0
- package/dist/dto/reorder-collaborator-types.dto.d.ts +4 -0
- package/dist/dto/reorder-collaborator-types.dto.d.ts.map +1 -0
- package/dist/dto/reorder-collaborator-types.dto.js +25 -0
- package/dist/dto/reorder-collaborator-types.dto.js.map +1 -0
- package/dist/operations.service.d.ts +340 -271
- package/dist/operations.service.d.ts.map +1 -1
- package/dist/operations.service.js +1007 -1043
- package/dist/operations.service.js.map +1 -1
- package/dist/operations.service.spec.js +0 -22
- package/dist/operations.service.spec.js.map +1 -1
- package/hedhog/data/menu.yaml +0 -36
- package/hedhog/data/route.yaml +42 -73
- package/hedhog/frontend/app/_components/collaborator-form-screen.tsx.ejs +8 -1
- package/hedhog/frontend/app/_components/collaborator-select-with-create.tsx.ejs +15 -10
- package/hedhog/frontend/app/_components/contract-details-screen.tsx.ejs +108 -213
- package/hedhog/frontend/app/_components/contract-form-screen.tsx.ejs +251 -2039
- package/hedhog/frontend/app/_components/project-details-screen.tsx.ejs +167 -60
- package/hedhog/frontend/app/_components/project-form-screen.tsx.ejs +70 -301
- package/hedhog/frontend/app/_components/system-user-select-with-create.tsx.ejs +102 -51
- package/hedhog/frontend/app/_lib/types.ts.ejs +19 -24
- package/hedhog/frontend/app/_lib/utils/format.ts.ejs +14 -9
- package/hedhog/frontend/app/approvals/page.tsx.ejs +842 -150
- package/hedhog/frontend/app/collaborator-types/page.tsx.ejs +445 -153
- package/hedhog/frontend/app/collaborators/page.tsx.ejs +118 -49
- package/hedhog/frontend/app/contracts/[id]/page.tsx.ejs +2 -2
- package/hedhog/frontend/app/contracts/page.tsx.ejs +215 -617
- package/hedhog/frontend/app/departments/page.tsx.ejs +257 -113
- package/hedhog/frontend/app/projects/page.tsx.ejs +90 -51
- package/hedhog/frontend/app/schedule-adjustments/page.tsx.ejs +412 -147
- package/hedhog/frontend/app/time-off/page.tsx.ejs +400 -123
- package/hedhog/frontend/app/timesheets/page.tsx.ejs +460 -365
- package/hedhog/frontend/messages/en.json +143 -14
- package/hedhog/frontend/messages/pt.json +192 -54
- package/hedhog/table/operations_contract.yaml +0 -9
- package/package.json +4 -4
- package/src/controllers/operations-approvals.controller.ts +9 -3
- package/src/controllers/operations-collaborators.controller.ts +15 -2
- package/src/controllers/operations-contracts.controller.ts +8 -92
- package/src/controllers/operations-org-structure.controller.ts +17 -4
- package/src/controllers/operations-projects.controller.ts +10 -4
- package/src/controllers/operations-timesheets.controller.ts +17 -8
- package/src/dto/list-approvals.dto.ts +12 -0
- package/src/dto/list-collaborator-types.dto.ts +7 -2
- package/src/dto/list-collaborators.dto.ts +4 -0
- package/src/dto/list-contracts.dto.ts +20 -0
- package/src/dto/list-departments.dto.ts +8 -0
- package/src/dto/list-projects.dto.ts +8 -0
- package/src/dto/list-schedule-adjustments.dto.ts +8 -0
- package/src/dto/list-time-off-requests.dto.ts +8 -0
- package/src/dto/list-timesheets.dto.ts +8 -0
- package/src/dto/reorder-collaborator-types.dto.ts +10 -0
- package/src/operations.service.spec.ts +0 -30
- package/src/operations.service.ts +1557 -1806
- package/hedhog/frontend/app/_components/contract-creation-wizard.tsx.ejs +0 -631
- package/hedhog/frontend/app/_components/contract-template-form-screen.tsx.ejs +0 -526
- package/hedhog/frontend/app/_components/contract-template-select-with-create.tsx.ejs +0 -247
- package/hedhog/frontend/app/_components/contract-wizard-sheet.tsx.ejs +0 -3520
- package/hedhog/frontend/app/contracts/templates/page.tsx.ejs +0 -380
- package/hedhog/frontend/app/team/page.tsx.ejs +0 -352
- package/hedhog/table/operations_contract_financial_term.yaml +0 -40
- package/hedhog/table/operations_contract_revision.yaml +0 -38
- package/hedhog/table/operations_contract_signature.yaml +0 -38
- package/hedhog/table/operations_contract_template.yaml +0 -58
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
+
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar';
|
|
3
4
|
import { Button } from '@/components/ui/button';
|
|
4
5
|
import {
|
|
5
6
|
Command,
|
|
@@ -26,11 +27,12 @@ import {
|
|
|
26
27
|
import { useApp } from '@hed-hog/next-app-provider';
|
|
27
28
|
import { Check, ChevronsUpDown, Plus, X } from 'lucide-react';
|
|
28
29
|
import { useTranslations } from 'next-intl';
|
|
29
|
-
import { useEffect, useMemo, useRef, useState } from 'react';
|
|
30
|
+
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
30
31
|
|
|
31
32
|
export type SystemUserOption = {
|
|
32
33
|
id: number;
|
|
33
34
|
name: string;
|
|
35
|
+
photoId?: number | null;
|
|
34
36
|
};
|
|
35
37
|
|
|
36
38
|
type SystemUserSelectWithCreateProps = {
|
|
@@ -50,7 +52,7 @@ type SystemUserSelectWithCreateProps = {
|
|
|
50
52
|
|
|
51
53
|
type UserListPayload = {
|
|
52
54
|
paginate: {
|
|
53
|
-
data: Array<{ id: number; name: string | null }>;
|
|
55
|
+
data: Array<{ id: number; name: string | null; photo_id?: number | null }>;
|
|
54
56
|
total: number;
|
|
55
57
|
lastPage: number;
|
|
56
58
|
page: number;
|
|
@@ -83,12 +85,36 @@ function parseUserListResponse(payload: UserListPayload): {
|
|
|
83
85
|
hasMore: boolean;
|
|
84
86
|
} {
|
|
85
87
|
const raw = payload?.paginate?.data ?? [];
|
|
86
|
-
const items = raw.map((u) => ({
|
|
88
|
+
const items = raw.map((u) => ({
|
|
89
|
+
id: u.id,
|
|
90
|
+
name: u.name || `#${u.id}`,
|
|
91
|
+
photoId: u.photo_id ?? null,
|
|
92
|
+
}));
|
|
87
93
|
const hasMore =
|
|
88
94
|
(payload?.paginate?.page ?? 1) < (payload?.paginate?.lastPage ?? 1);
|
|
89
95
|
return { items, hasMore };
|
|
90
96
|
}
|
|
91
97
|
|
|
98
|
+
function getUserPhotoUrl(photoId?: number | null) {
|
|
99
|
+
return typeof photoId === 'number' && photoId > 0
|
|
100
|
+
? `${process.env.NEXT_PUBLIC_API_BASE_URL}/file/open/${photoId}`
|
|
101
|
+
: undefined;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function getInitials(value?: string | null) {
|
|
105
|
+
const parts = String(value ?? '')
|
|
106
|
+
.trim()
|
|
107
|
+
.split(/\s+/)
|
|
108
|
+
.filter(Boolean)
|
|
109
|
+
.slice(0, 2);
|
|
110
|
+
|
|
111
|
+
if (!parts.length) {
|
|
112
|
+
return '??';
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return parts.map((part) => part[0]?.toUpperCase() ?? '').join('');
|
|
116
|
+
}
|
|
117
|
+
|
|
92
118
|
export function SystemUserSelectWithCreate({
|
|
93
119
|
label,
|
|
94
120
|
value,
|
|
@@ -132,56 +158,55 @@ export function SystemUserSelectWithCreate({
|
|
|
132
158
|
return () => clearTimeout(timeout);
|
|
133
159
|
}, [search]);
|
|
134
160
|
|
|
135
|
-
const loadOwnerOptions =
|
|
136
|
-
page: number,
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
) => {
|
|
140
|
-
const requestId = requestIdRef.current + 1;
|
|
141
|
-
requestIdRef.current = requestId;
|
|
142
|
-
|
|
143
|
-
if (reset) {
|
|
144
|
-
setIsLoadingOptions(true);
|
|
145
|
-
} else {
|
|
146
|
-
setIsLoadingMoreOptions(true);
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
try {
|
|
150
|
-
const params = new URLSearchParams();
|
|
151
|
-
params.set('page', String(page));
|
|
152
|
-
params.set('pageSize', String(PAGE_SIZE));
|
|
161
|
+
const loadOwnerOptions = useCallback(
|
|
162
|
+
async (page: number, searchTerm: string, reset: boolean) => {
|
|
163
|
+
const requestId = requestIdRef.current + 1;
|
|
164
|
+
requestIdRef.current = requestId;
|
|
153
165
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
166
|
+
if (reset) {
|
|
167
|
+
setIsLoadingOptions(true);
|
|
168
|
+
} else {
|
|
169
|
+
setIsLoadingMoreOptions(true);
|
|
157
170
|
}
|
|
158
171
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
172
|
+
try {
|
|
173
|
+
const params = new URLSearchParams();
|
|
174
|
+
params.set('page', String(page));
|
|
175
|
+
params.set('pageSize', String(PAGE_SIZE));
|
|
163
176
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
177
|
+
const normalizedSearch = searchTerm.trim();
|
|
178
|
+
if (normalizedSearch) {
|
|
179
|
+
params.set('search', normalizedSearch);
|
|
180
|
+
}
|
|
167
181
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
182
|
+
const response = await request<UserListPayload>({
|
|
183
|
+
url: `/user?${params.toString()}`,
|
|
184
|
+
method: 'GET',
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
if (requestIdRef.current !== requestId) {
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
const parsed = parseUserListResponse(response.data);
|
|
192
|
+
setCurrentPage(page);
|
|
193
|
+
setHasMore(parsed.hasMore);
|
|
194
|
+
setRemoteOptions((current) =>
|
|
195
|
+
reset ? parsed.items : mergeOptions(current, parsed.items)
|
|
196
|
+
);
|
|
197
|
+
} finally {
|
|
198
|
+
if (requestIdRef.current === requestId) {
|
|
199
|
+
setIsLoadingOptions(false);
|
|
200
|
+
setIsLoadingMoreOptions(false);
|
|
201
|
+
}
|
|
178
202
|
}
|
|
179
|
-
}
|
|
180
|
-
|
|
203
|
+
},
|
|
204
|
+
[request]
|
|
205
|
+
);
|
|
181
206
|
|
|
182
207
|
useEffect(() => {
|
|
183
208
|
void loadOwnerOptions(1, debouncedSearch, true);
|
|
184
|
-
}, [debouncedSearch]);
|
|
209
|
+
}, [debouncedSearch, loadOwnerOptions]);
|
|
185
210
|
|
|
186
211
|
useEffect(() => {
|
|
187
212
|
const normalizedValue = value.trim();
|
|
@@ -213,13 +238,14 @@ export function SystemUserSelectWithCreate({
|
|
|
213
238
|
}
|
|
214
239
|
|
|
215
240
|
const rawUser = response.data as
|
|
216
|
-
| { id?: number; name?: string | null }
|
|
241
|
+
| { id?: number; name?: string | null; photo_id?: number | null }
|
|
217
242
|
| undefined;
|
|
218
243
|
const resolvedOption =
|
|
219
244
|
rawUser?.id && String(rawUser.id) === normalizedValue
|
|
220
245
|
? {
|
|
221
246
|
id: rawUser.id,
|
|
222
247
|
name: rawUser.name || `#${rawUser.id}`,
|
|
248
|
+
photoId: rawUser.photo_id ?? null,
|
|
223
249
|
}
|
|
224
250
|
: null;
|
|
225
251
|
|
|
@@ -232,6 +258,7 @@ export function SystemUserSelectWithCreate({
|
|
|
232
258
|
setSelectedValueOption({
|
|
233
259
|
id: Number(normalizedValue),
|
|
234
260
|
name: `#${normalizedValue}`,
|
|
261
|
+
photoId: null,
|
|
235
262
|
});
|
|
236
263
|
})
|
|
237
264
|
.catch(() => {
|
|
@@ -239,6 +266,7 @@ export function SystemUserSelectWithCreate({
|
|
|
239
266
|
setSelectedValueOption({
|
|
240
267
|
id: Number(normalizedValue),
|
|
241
268
|
name: `#${normalizedValue}`,
|
|
269
|
+
photoId: null,
|
|
242
270
|
});
|
|
243
271
|
}
|
|
244
272
|
});
|
|
@@ -371,13 +399,26 @@ export function SystemUserSelectWithCreate({
|
|
|
371
399
|
type="button"
|
|
372
400
|
variant="outline"
|
|
373
401
|
role="combobox"
|
|
374
|
-
className="h-10 min-w-0 flex-1 justify-between overflow-hidden"
|
|
402
|
+
className="h-10 min-w-0 flex-1 justify-between gap-2 overflow-hidden"
|
|
375
403
|
>
|
|
376
|
-
<
|
|
377
|
-
{selectedOption
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
404
|
+
<div className="flex min-w-0 items-center gap-2">
|
|
405
|
+
{selectedOption ? (
|
|
406
|
+
<Avatar className="h-7 w-7 shrink-0 border border-border/60 bg-muted">
|
|
407
|
+
<AvatarImage
|
|
408
|
+
src={getUserPhotoUrl(selectedOption.photoId)}
|
|
409
|
+
alt={selectedOption.name}
|
|
410
|
+
/>
|
|
411
|
+
<AvatarFallback className="bg-muted text-[11px] font-semibold text-foreground">
|
|
412
|
+
{getInitials(selectedOption.name)}
|
|
413
|
+
</AvatarFallback>
|
|
414
|
+
</Avatar>
|
|
415
|
+
) : null}
|
|
416
|
+
<span className="truncate text-left">
|
|
417
|
+
{selectedOption
|
|
418
|
+
? `${selectedOption.name} (#${selectedOption.id})`
|
|
419
|
+
: emptyLabel}
|
|
420
|
+
</span>
|
|
421
|
+
</div>
|
|
381
422
|
<ChevronsUpDown className="ml-2 h-4 w-4 shrink-0 opacity-50" />
|
|
382
423
|
</Button>
|
|
383
424
|
</PopoverTrigger>
|
|
@@ -433,6 +474,7 @@ export function SystemUserSelectWithCreate({
|
|
|
433
474
|
<CommandItem
|
|
434
475
|
key={option.id}
|
|
435
476
|
value={`${option.name} #${option.id}`}
|
|
477
|
+
className="gap-2"
|
|
436
478
|
onSelect={() => {
|
|
437
479
|
onChange(String(option.id));
|
|
438
480
|
setOpen(false);
|
|
@@ -443,6 +485,15 @@ export function SystemUserSelectWithCreate({
|
|
|
443
485
|
) : (
|
|
444
486
|
<span className="mr-2 h-4 w-4" />
|
|
445
487
|
)}
|
|
488
|
+
<Avatar className="h-7 w-7 shrink-0 border border-border/60 bg-muted">
|
|
489
|
+
<AvatarImage
|
|
490
|
+
src={getUserPhotoUrl(option.photoId)}
|
|
491
|
+
alt={option.name}
|
|
492
|
+
/>
|
|
493
|
+
<AvatarFallback className="bg-muted text-[11px] font-semibold text-foreground">
|
|
494
|
+
{getInitials(option.name)}
|
|
495
|
+
</AvatarFallback>
|
|
496
|
+
</Avatar>
|
|
446
497
|
<div className="min-w-0">
|
|
447
498
|
<div className="truncate">{option.name}</div>
|
|
448
499
|
<div className="truncate text-xs text-muted-foreground">
|
|
@@ -67,6 +67,20 @@ export type OperationsCollaborator = {
|
|
|
67
67
|
pendingScheduleAdjustmentRequests?: number;
|
|
68
68
|
};
|
|
69
69
|
|
|
70
|
+
export type OperationsCollaboratorStats = {
|
|
71
|
+
total: number;
|
|
72
|
+
active: number;
|
|
73
|
+
onLeave: number;
|
|
74
|
+
withContracts: number;
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
export type OperationsContractStats = {
|
|
78
|
+
total: number;
|
|
79
|
+
active: number;
|
|
80
|
+
inactive: number;
|
|
81
|
+
withFile: number;
|
|
82
|
+
};
|
|
83
|
+
|
|
70
84
|
export type OperationsDepartment = {
|
|
71
85
|
id: number;
|
|
72
86
|
slug: string;
|
|
@@ -182,10 +196,6 @@ export type OperationsContract = {
|
|
|
182
196
|
accountManagerName?: string | null;
|
|
183
197
|
relatedCollaboratorId?: number | null;
|
|
184
198
|
relatedCollaboratorName?: string | null;
|
|
185
|
-
contractTemplateId?: number | null;
|
|
186
|
-
contractTemplateName?: string | null;
|
|
187
|
-
contractTemplateSlug?: string | null;
|
|
188
|
-
contractTemplateCode?: string | null;
|
|
189
199
|
mainRelatedPartyName?: string | null;
|
|
190
200
|
originType?: string | null;
|
|
191
201
|
originId?: number | null;
|
|
@@ -209,24 +219,6 @@ export type OperationsContract = {
|
|
|
209
219
|
scheduleSummary?: OperationsWeeklyScheduleDay[];
|
|
210
220
|
};
|
|
211
221
|
|
|
212
|
-
export type OperationsContractTemplate = {
|
|
213
|
-
id: number;
|
|
214
|
-
slug: string;
|
|
215
|
-
code?: string | null;
|
|
216
|
-
name: string;
|
|
217
|
-
description?: string | null;
|
|
218
|
-
contractCategory?: string | null;
|
|
219
|
-
contractType?: string | null;
|
|
220
|
-
billingModel?: string | null;
|
|
221
|
-
signatureStatus?: string | null;
|
|
222
|
-
isActive?: boolean;
|
|
223
|
-
status: string;
|
|
224
|
-
contentHtml?: string | null;
|
|
225
|
-
usageCount?: number;
|
|
226
|
-
createdAt?: string | null;
|
|
227
|
-
updatedAt?: string | null;
|
|
228
|
-
};
|
|
229
|
-
|
|
230
222
|
export type OperationsWeeklyScheduleDay = {
|
|
231
223
|
weekday: string;
|
|
232
224
|
isWorkingDay: boolean;
|
|
@@ -353,6 +345,10 @@ export type OperationsApproval = {
|
|
|
353
345
|
scheduleStartDate?: string | null;
|
|
354
346
|
scheduleEndDate?: string | null;
|
|
355
347
|
scheduleReason?: string | null;
|
|
348
|
+
// enriched detail (returned by GET /operations/approvals/:id)
|
|
349
|
+
entries?: OperationsTimesheetEntry[];
|
|
350
|
+
days?: OperationsScheduleAdjustmentDay[];
|
|
351
|
+
currentSchedule?: OperationsWeeklyScheduleDay[];
|
|
356
352
|
};
|
|
357
353
|
|
|
358
354
|
export type OperationsTeamOverview = {
|
|
@@ -426,7 +422,6 @@ export type OperationsProjectDetails = OperationsProject & {
|
|
|
426
422
|
roleLabel?: string | null;
|
|
427
423
|
allocationPercent?: number | null;
|
|
428
424
|
weeklyHours?: number | null;
|
|
429
|
-
isBillable?: boolean;
|
|
430
425
|
startDate?: string | null;
|
|
431
426
|
endDate?: string | null;
|
|
432
427
|
status: string;
|
|
@@ -439,7 +434,7 @@ export type OperationsProjectDetails = OperationsProject & {
|
|
|
439
434
|
};
|
|
440
435
|
operationalIndicators: {
|
|
441
436
|
activeAssignments: number;
|
|
442
|
-
|
|
437
|
+
completedAssignments: number;
|
|
443
438
|
averageAllocation: number;
|
|
444
439
|
totalWeeklyHours: number;
|
|
445
440
|
};
|
|
@@ -3,14 +3,19 @@ import {
|
|
|
3
3
|
formatDate as formatDateWithSettings,
|
|
4
4
|
} from '@/lib/format-date';
|
|
5
5
|
|
|
6
|
-
export
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
6
|
+
export function formatCurrency(
|
|
7
|
+
value: number,
|
|
8
|
+
getSettingValue?: ((key: string) => unknown) | null,
|
|
9
|
+
currentLocaleCode = 'pt-BR'
|
|
10
|
+
) {
|
|
11
|
+
const currency =
|
|
12
|
+
(getSettingValue?.('currency') as string | undefined) || 'BRL';
|
|
13
|
+
const locale = resolveLocale(currentLocaleCode);
|
|
14
|
+
return new Intl.NumberFormat(locale, {
|
|
15
|
+
style: 'currency',
|
|
16
|
+
currency,
|
|
17
|
+
maximumFractionDigits: 2,
|
|
18
|
+
}).format(value);
|
|
14
19
|
}
|
|
15
20
|
|
|
16
21
|
function resolveLocale(currentLocaleCode: string) {
|
|
@@ -179,7 +184,7 @@ export function formatDateRange(
|
|
|
179
184
|
return formatDate(startDate, getSettingValue, currentLocaleCode);
|
|
180
185
|
}
|
|
181
186
|
|
|
182
|
-
return `${formatDate(startDate, getSettingValue, currentLocaleCode)}
|
|
187
|
+
return `${formatDate(startDate, getSettingValue, currentLocaleCode)} - ${formatDate(endDate, getSettingValue, currentLocaleCode)}`;
|
|
183
188
|
}
|
|
184
189
|
|
|
185
190
|
export function getStatusBadgeClass(value?: string | null) {
|