@hed-hog/operations 0.0.303 → 0.0.304

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 (166) hide show
  1. package/README.md +200 -43
  2. package/dist/controllers/operations-approvals.controller.d.ts +9 -0
  3. package/dist/controllers/operations-approvals.controller.d.ts.map +1 -0
  4. package/dist/controllers/operations-approvals.controller.js +64 -0
  5. package/dist/controllers/operations-approvals.controller.js.map +1 -0
  6. package/dist/controllers/operations-collaborators.controller.d.ts +223 -0
  7. package/dist/controllers/operations-collaborators.controller.d.ts.map +1 -0
  8. package/dist/controllers/operations-collaborators.controller.js +96 -0
  9. package/dist/controllers/operations-collaborators.controller.js.map +1 -0
  10. package/dist/controllers/operations-contracts.controller.d.ts +683 -0
  11. package/dist/controllers/operations-contracts.controller.d.ts.map +1 -0
  12. package/dist/controllers/operations-contracts.controller.js +198 -0
  13. package/dist/controllers/operations-contracts.controller.js.map +1 -0
  14. package/dist/controllers/operations-org-structure.controller.d.ts +108 -0
  15. package/dist/controllers/operations-org-structure.controller.d.ts.map +1 -0
  16. package/dist/controllers/operations-org-structure.controller.js +143 -0
  17. package/dist/controllers/operations-org-structure.controller.js.map +1 -0
  18. package/dist/controllers/operations-projects.controller.d.ts +169 -0
  19. package/dist/controllers/operations-projects.controller.d.ts.map +1 -0
  20. package/dist/controllers/operations-projects.controller.js +87 -0
  21. package/dist/controllers/operations-projects.controller.js.map +1 -0
  22. package/dist/controllers/operations-tasks.controller.d.ts +54 -0
  23. package/dist/controllers/operations-tasks.controller.d.ts.map +1 -0
  24. package/dist/controllers/operations-tasks.controller.js +79 -0
  25. package/dist/controllers/operations-tasks.controller.js.map +1 -0
  26. package/dist/controllers/operations-timesheets.controller.d.ts +99 -0
  27. package/dist/controllers/operations-timesheets.controller.d.ts.map +1 -0
  28. package/dist/controllers/operations-timesheets.controller.js +154 -0
  29. package/dist/controllers/operations-timesheets.controller.js.map +1 -0
  30. package/dist/dto/create-collaborator-type.dto.d.ts +10 -0
  31. package/dist/dto/create-collaborator-type.dto.d.ts.map +1 -0
  32. package/dist/dto/create-collaborator-type.dto.js +56 -0
  33. package/dist/dto/create-collaborator-type.dto.js.map +1 -0
  34. package/dist/dto/create-collaborator.dto.d.ts +42 -0
  35. package/dist/dto/create-collaborator.dto.d.ts.map +1 -0
  36. package/dist/dto/create-collaborator.dto.js +228 -0
  37. package/dist/dto/create-collaborator.dto.js.map +1 -0
  38. package/dist/dto/create-schedule-adjustment-request.dto.d.ts +17 -0
  39. package/dist/dto/create-schedule-adjustment-request.dto.d.ts.map +1 -0
  40. package/dist/dto/create-schedule-adjustment-request.dto.js +89 -0
  41. package/dist/dto/create-schedule-adjustment-request.dto.js.map +1 -0
  42. package/dist/dto/create-task.dto.d.ts +8 -0
  43. package/dist/dto/create-task.dto.d.ts.map +1 -0
  44. package/dist/dto/create-task.dto.js +50 -0
  45. package/dist/dto/create-task.dto.js.map +1 -0
  46. package/dist/dto/create-time-off-request.dto.d.ts +9 -0
  47. package/dist/dto/create-time-off-request.dto.d.ts.map +1 -0
  48. package/dist/dto/create-time-off-request.dto.js +54 -0
  49. package/dist/dto/create-time-off-request.dto.js.map +1 -0
  50. package/dist/dto/create-timesheet-entry.dto.d.ts +12 -0
  51. package/dist/dto/create-timesheet-entry.dto.d.ts.map +1 -0
  52. package/dist/dto/create-timesheet-entry.dto.js +75 -0
  53. package/dist/dto/create-timesheet-entry.dto.js.map +1 -0
  54. package/dist/dto/list-collaborator-types.dto.d.ts +4 -0
  55. package/dist/dto/list-collaborator-types.dto.d.ts.map +1 -0
  56. package/dist/dto/list-collaborator-types.dto.js +29 -0
  57. package/dist/dto/list-collaborator-types.dto.js.map +1 -0
  58. package/dist/dto/list-collaborators.dto.d.ts +8 -0
  59. package/dist/dto/list-collaborators.dto.d.ts.map +1 -0
  60. package/dist/dto/list-collaborators.dto.js +42 -0
  61. package/dist/dto/list-collaborators.dto.js.map +1 -0
  62. package/dist/dto/list-project-options.dto.d.ts +4 -0
  63. package/dist/dto/list-project-options.dto.d.ts.map +1 -0
  64. package/dist/dto/list-project-options.dto.js +8 -0
  65. package/dist/dto/list-project-options.dto.js.map +1 -0
  66. package/dist/dto/list-tasks.dto.d.ts +7 -0
  67. package/dist/dto/list-tasks.dto.d.ts.map +1 -0
  68. package/dist/dto/list-tasks.dto.js +38 -0
  69. package/dist/dto/list-tasks.dto.js.map +1 -0
  70. package/dist/dto/list-timesheet-entries.dto.d.ts +10 -0
  71. package/dist/dto/list-timesheet-entries.dto.d.ts.map +1 -0
  72. package/dist/dto/list-timesheet-entries.dto.js +54 -0
  73. package/dist/dto/list-timesheet-entries.dto.js.map +1 -0
  74. package/dist/dto/update-collaborator-type.dto.d.ts +4 -0
  75. package/dist/dto/update-collaborator-type.dto.d.ts.map +1 -0
  76. package/dist/dto/update-collaborator-type.dto.js +8 -0
  77. package/dist/dto/update-collaborator-type.dto.js.map +1 -0
  78. package/dist/dto/update-collaborator.dto.d.ts +4 -0
  79. package/dist/dto/update-collaborator.dto.d.ts.map +1 -0
  80. package/dist/dto/update-collaborator.dto.js +8 -0
  81. package/dist/dto/update-collaborator.dto.js.map +1 -0
  82. package/dist/dto/update-task.dto.d.ts +8 -0
  83. package/dist/dto/update-task.dto.d.ts.map +1 -0
  84. package/dist/dto/update-task.dto.js +51 -0
  85. package/dist/dto/update-task.dto.js.map +1 -0
  86. package/dist/operations.controller.d.ts +0 -1045
  87. package/dist/operations.controller.d.ts.map +1 -1
  88. package/dist/operations.controller.js +0 -429
  89. package/dist/operations.controller.js.map +1 -1
  90. package/dist/operations.module.d.ts.map +1 -1
  91. package/dist/operations.module.js +23 -2
  92. package/dist/operations.module.js.map +1 -1
  93. package/dist/operations.service.d.ts +373 -8
  94. package/dist/operations.service.d.ts.map +1 -1
  95. package/dist/operations.service.js +1598 -111
  96. package/dist/operations.service.js.map +1 -1
  97. package/dist/operations.service.spec.js +315 -1
  98. package/dist/operations.service.spec.js.map +1 -1
  99. package/dist/services/shared/operations-access.service.d.ts +16 -0
  100. package/dist/services/shared/operations-access.service.d.ts.map +1 -0
  101. package/dist/services/shared/operations-access.service.js +48 -0
  102. package/dist/services/shared/operations-access.service.js.map +1 -0
  103. package/hedhog/data/dashboard.yaml +20 -0
  104. package/hedhog/data/dashboard_component.yaml +274 -0
  105. package/hedhog/data/dashboard_component_role.yaml +174 -0
  106. package/hedhog/data/dashboard_item.yaml +299 -0
  107. package/hedhog/data/dashboard_role.yaml +20 -0
  108. package/hedhog/data/menu.yaml +30 -13
  109. package/hedhog/data/operations_collaborator_type.yaml +76 -0
  110. package/hedhog/data/route.yaml +183 -0
  111. package/hedhog/frontend/app/_components/async-options-combobox.tsx.ejs +231 -0
  112. package/hedhog/frontend/app/_components/collaborator-details-screen.tsx.ejs +134 -49
  113. package/hedhog/frontend/app/_components/collaborator-form-screen.tsx.ejs +772 -93
  114. package/hedhog/frontend/app/_components/department-select-with-create.tsx.ejs +38 -16
  115. package/hedhog/frontend/app/_components/project-form-screen.tsx.ejs +875 -632
  116. package/hedhog/frontend/app/_components/timesheet-task-create-sheet.tsx.ejs +213 -0
  117. package/hedhog/frontend/app/_lib/api.ts.ejs +30 -1
  118. package/hedhog/frontend/app/_lib/types.ts.ejs +142 -39
  119. package/hedhog/frontend/app/_lib/utils/format.ts.ejs +33 -2
  120. package/hedhog/frontend/app/approvals/page.tsx.ejs +116 -98
  121. package/hedhog/frontend/app/collaborator-types/page.tsx.ejs +502 -0
  122. package/hedhog/frontend/app/collaborators/page.tsx.ejs +109 -68
  123. package/hedhog/frontend/app/contracts/templates/page.tsx.ejs +11 -9
  124. package/hedhog/frontend/app/departments/page.tsx.ejs +1 -1
  125. package/hedhog/frontend/app/projects/page.tsx.ejs +5 -1
  126. package/hedhog/frontend/app/schedule-adjustments/page.tsx.ejs +244 -120
  127. package/hedhog/frontend/app/team/page.tsx.ejs +15 -2
  128. package/hedhog/frontend/app/time-off/page.tsx.ejs +158 -82
  129. package/hedhog/frontend/app/timesheets/page.tsx.ejs +814 -357
  130. package/hedhog/frontend/messages/en.json +243 -51
  131. package/hedhog/frontend/messages/pt.json +458 -268
  132. package/hedhog/table/operations_collaborator.yaml +26 -13
  133. package/hedhog/table/operations_collaborator_equity_participation.yaml +43 -0
  134. package/hedhog/table/operations_collaborator_type.yaml +33 -0
  135. package/hedhog/table/operations_job_title.yaml +24 -0
  136. package/hedhog/table/operations_project_assignment.yaml +9 -0
  137. package/hedhog/table/operations_project_role.yaml +39 -0
  138. package/hedhog/table/operations_task.yaml +30 -0
  139. package/hedhog/table/operations_timesheet_entry.yaml +12 -0
  140. package/package.json +6 -6
  141. package/src/controllers/operations-approvals.controller.ts +24 -0
  142. package/src/controllers/operations-collaborators.controller.ts +60 -0
  143. package/src/controllers/operations-contracts.controller.ts +138 -0
  144. package/src/controllers/operations-org-structure.controller.ts +92 -0
  145. package/src/controllers/operations-projects.controller.ts +50 -0
  146. package/src/controllers/operations-tasks.controller.ts +52 -0
  147. package/src/controllers/operations-timesheets.controller.ts +100 -0
  148. package/src/dto/create-collaborator-type.dto.ts +43 -0
  149. package/src/dto/create-collaborator.dto.ts +223 -0
  150. package/src/dto/create-schedule-adjustment-request.dto.ts +91 -0
  151. package/src/dto/create-task.dto.ts +35 -0
  152. package/src/dto/create-time-off-request.dto.ts +53 -0
  153. package/src/dto/create-timesheet-entry.dto.ts +67 -0
  154. package/src/dto/list-collaborator-types.dto.ts +15 -0
  155. package/src/dto/list-collaborators.dto.ts +30 -0
  156. package/src/dto/list-project-options.dto.ts +3 -0
  157. package/src/dto/list-tasks.dto.ts +25 -0
  158. package/src/dto/list-timesheet-entries.dto.ts +40 -0
  159. package/src/dto/update-collaborator-type.dto.ts +3 -0
  160. package/src/dto/update-collaborator.dto.ts +3 -0
  161. package/src/dto/update-task.dto.ts +36 -0
  162. package/src/operations.controller.ts +1 -278
  163. package/src/operations.module.ts +23 -2
  164. package/src/operations.service.spec.ts +450 -0
  165. package/src/operations.service.ts +4641 -2163
  166. package/src/services/shared/operations-access.service.ts +52 -0
@@ -0,0 +1,213 @@
1
+ 'use client';
2
+
3
+ import {
4
+ Form,
5
+ FormControl,
6
+ FormField,
7
+ FormItem,
8
+ FormLabel,
9
+ FormMessage,
10
+ } from '@/components/ui/form';
11
+ import { FormActions } from '@/components/ui/form-actions';
12
+ import { Input } from '@/components/ui/input';
13
+ import {
14
+ Sheet,
15
+ SheetContent,
16
+ SheetDescription,
17
+ SheetHeader,
18
+ SheetTitle,
19
+ } from '@/components/ui/sheet';
20
+ import { Textarea } from '@/components/ui/textarea';
21
+ import { useApp } from '@hed-hog/next-app-provider';
22
+ import { zodResolver } from '@hookform/resolvers/zod';
23
+ import { Layers3 } from 'lucide-react';
24
+ import { useTranslations } from 'next-intl';
25
+ import { useEffect, useMemo } from 'react';
26
+ import { useForm } from 'react-hook-form';
27
+ import { z } from 'zod';
28
+
29
+ import { getOperationsErrorMessage, mutateOperations } from '../_lib/api';
30
+ import type {
31
+ OperationsProjectOption,
32
+ OperationsTaskOption,
33
+ } from '../_lib/types';
34
+ import { trimToNull } from '../_lib/utils/forms';
35
+
36
+ type TimesheetTaskCreateSheetProps = {
37
+ open: boolean;
38
+ onOpenChange: (open: boolean) => void;
39
+ project: OperationsProjectOption | null;
40
+ onCreated: (task: OperationsTaskOption) => void;
41
+ };
42
+
43
+ type TaskFormValues = {
44
+ name: string;
45
+ description: string;
46
+ };
47
+
48
+ export function TimesheetTaskCreateSheet({
49
+ open,
50
+ onOpenChange,
51
+ project,
52
+ onCreated,
53
+ }: TimesheetTaskCreateSheetProps) {
54
+ const t = useTranslations('operations.TimesheetsPage');
55
+ const commonT = useTranslations('operations.Common');
56
+ const { request, showToastHandler } = useApp();
57
+
58
+ const taskSchema = useMemo(
59
+ () =>
60
+ z.object({
61
+ name: z
62
+ .string()
63
+ .trim()
64
+ .min(2, t('sheet.task.validation.nameMinLength')),
65
+ description: z
66
+ .string()
67
+ .trim()
68
+ .max(500, t('sheet.task.validation.descriptionMaxLength'))
69
+ .optional()
70
+ .or(z.literal('')),
71
+ }),
72
+ [t]
73
+ );
74
+
75
+ const form = useForm<TaskFormValues>({
76
+ resolver: zodResolver(taskSchema),
77
+ defaultValues: {
78
+ name: '',
79
+ description: '',
80
+ },
81
+ });
82
+
83
+ useEffect(() => {
84
+ if (!open) {
85
+ form.reset({
86
+ name: '',
87
+ description: '',
88
+ });
89
+ }
90
+ }, [form, open]);
91
+
92
+ const handleSubmit = async (values: TaskFormValues) => {
93
+ if (!project?.id) {
94
+ showToastHandler?.('error', t('messages.selectProjectFirst'));
95
+ return;
96
+ }
97
+
98
+ try {
99
+ const createdTask = await mutateOperations<OperationsTaskOption>(
100
+ request,
101
+ '/operations/tasks',
102
+ 'POST',
103
+ {
104
+ projectId: project.id,
105
+ name: values.name.trim(),
106
+ description: trimToNull(values.description),
107
+ }
108
+ );
109
+
110
+ onCreated(createdTask);
111
+ form.reset({
112
+ name: '',
113
+ description: '',
114
+ });
115
+ onOpenChange(false);
116
+ showToastHandler?.('success', t('messages.taskCreateSuccess'));
117
+ } catch (error) {
118
+ showToastHandler?.(
119
+ 'error',
120
+ getOperationsErrorMessage(error, t('messages.taskCreateError'))
121
+ );
122
+ }
123
+ };
124
+
125
+ const handleOpenChange = (nextOpen: boolean) => {
126
+ if (form.formState.isSubmitting && !nextOpen) {
127
+ return;
128
+ }
129
+
130
+ onOpenChange(nextOpen);
131
+ };
132
+
133
+ return (
134
+ <Sheet open={open} onOpenChange={handleOpenChange}>
135
+ <SheetContent className="flex h-full w-full flex-col gap-0 overflow-hidden p-0 sm:max-w-lg">
136
+ <SheetHeader className="border-b px-4 py-4 text-left">
137
+ <div className="flex items-start gap-3">
138
+ <div className="flex h-10 w-10 shrink-0 items-center justify-center rounded-xl bg-violet-500/10 text-violet-600">
139
+ <Layers3 className="size-5" />
140
+ </div>
141
+
142
+ <div className="space-y-1">
143
+ <SheetTitle>{t('sheet.task.title')}</SheetTitle>
144
+ <SheetDescription>{t('sheet.task.description')}</SheetDescription>
145
+ </div>
146
+ </div>
147
+ </SheetHeader>
148
+
149
+ <Form {...form}>
150
+ <form
151
+ onSubmit={form.handleSubmit(handleSubmit)}
152
+ className="flex min-h-0 flex-1 flex-col"
153
+ >
154
+ <div className="flex-1 space-y-4 overflow-y-auto px-4 py-4">
155
+ <div className="rounded-lg border bg-muted/30 p-3">
156
+ <div className="text-xs font-medium uppercase tracking-wide text-muted-foreground">
157
+ {t('sheet.task.projectLabel')}
158
+ </div>
159
+ <div className="mt-1 text-sm font-medium text-foreground">
160
+ {project?.label ?? commonT('labels.notAssigned')}
161
+ </div>
162
+ </div>
163
+
164
+ <FormField
165
+ control={form.control}
166
+ name="name"
167
+ render={({ field }) => (
168
+ <FormItem>
169
+ <FormLabel>{t('sheet.task.name')}</FormLabel>
170
+ <FormControl>
171
+ <Input
172
+ {...field}
173
+ placeholder={t('sheet.task.placeholders.name')}
174
+ />
175
+ </FormControl>
176
+ <FormMessage />
177
+ </FormItem>
178
+ )}
179
+ />
180
+
181
+ <FormField
182
+ control={form.control}
183
+ name="description"
184
+ render={({ field }) => (
185
+ <FormItem>
186
+ <FormLabel>{t('sheet.task.descriptionLabel')}</FormLabel>
187
+ <FormControl>
188
+ <Textarea
189
+ {...field}
190
+ rows={4}
191
+ placeholder={t('sheet.task.placeholders.description')}
192
+ />
193
+ </FormControl>
194
+ <FormMessage />
195
+ </FormItem>
196
+ )}
197
+ />
198
+ </div>
199
+
200
+ <FormActions
201
+ sheet
202
+ onCancel={() => onOpenChange(false)}
203
+ cancelLabel={commonT('actions.cancel')}
204
+ submitType="submit"
205
+ submitLabel={t('sheet.task.submit')}
206
+ submitDisabled={form.formState.isSubmitting || !project}
207
+ />
208
+ </form>
209
+ </Form>
210
+ </SheetContent>
211
+ </Sheet>
212
+ );
213
+ }
@@ -4,6 +4,35 @@ type RequestFn = (input: {
4
4
  data?: unknown;
5
5
  }) => Promise<{ data: unknown }>;
6
6
 
7
+ export function getOperationsErrorMessage(error: unknown, fallback: string) {
8
+ if (error && typeof error === 'object') {
9
+ const requestError = error as {
10
+ message?: string;
11
+ response?: {
12
+ data?: {
13
+ message?: string | string[];
14
+ };
15
+ };
16
+ };
17
+
18
+ const message =
19
+ requestError.response?.data?.message ?? requestError.message;
20
+
21
+ if (Array.isArray(message)) {
22
+ const combined = message.filter(Boolean).join(' ');
23
+ if (combined.trim()) {
24
+ return combined;
25
+ }
26
+ }
27
+
28
+ if (typeof message === 'string' && message.trim()) {
29
+ return message;
30
+ }
31
+ }
32
+
33
+ return fallback;
34
+ }
35
+
7
36
  export async function fetchOperations<T>(request: RequestFn, url: string) {
8
37
  const response = await request({
9
38
  url,
@@ -16,7 +45,7 @@ export async function fetchOperations<T>(request: RequestFn, url: string) {
16
45
  export async function mutateOperations<T>(
17
46
  request: RequestFn,
18
47
  url: string,
19
- method: 'POST' | 'PATCH',
48
+ method: 'POST' | 'PATCH' | 'DELETE',
20
49
  data?: unknown
21
50
  ) {
22
51
  const response = await request({
@@ -1,3 +1,13 @@
1
+ export type PaginatedResponse<T> = {
2
+ total: number;
3
+ lastPage: number;
4
+ page: number;
5
+ pageSize: number;
6
+ prev?: number | null;
7
+ next?: number | null;
8
+ data: T[];
9
+ };
10
+
1
11
  export type OperationsDashboard = {
2
12
  actor: {
3
13
  roleScope: 'self' | 'team' | 'full';
@@ -31,13 +41,18 @@ export type OperationsCollaborator = {
31
41
  personName?: string | null;
32
42
  personAvatarId?: number | null;
33
43
  code: string;
34
- collaboratorType?: string;
44
+ collaboratorTypeId?: number | null;
45
+ collaboratorTypeSlug?: string | null;
46
+ collaboratorType?: string | null;
47
+ collaboratorTypeName?: string | null;
35
48
  displayName: string;
36
49
  departmentId?: number | null;
37
50
  department?: string | null;
51
+ jobTitleId?: number | null;
38
52
  title?: string | null;
39
53
  levelLabel?: string | null;
40
54
  weeklyCapacityHours?: number | null;
55
+ compensationAmount?: number | null;
41
56
  status: string;
42
57
  joinedAt?: string | null;
43
58
  leftAt?: string | null;
@@ -64,6 +79,70 @@ export type OperationsDepartment = {
64
79
  updatedAt?: string | null;
65
80
  };
66
81
 
82
+ export type OperationsJobTitle = {
83
+ id: number;
84
+ slug: string;
85
+ code?: string | null;
86
+ name: string;
87
+ description?: string | null;
88
+ status: 'active' | 'inactive';
89
+ collaboratorCount?: number;
90
+ createdAt?: string | null;
91
+ updatedAt?: string | null;
92
+ };
93
+
94
+ export type OperationsCollaboratorType = {
95
+ id: number;
96
+ slug: string;
97
+ name: string;
98
+ description?: string | null;
99
+ category?: string | null;
100
+ isActive?: boolean;
101
+ sortOrder?: number | null;
102
+ status: 'active' | 'inactive';
103
+ collaboratorCount?: number;
104
+ createdAt?: string | null;
105
+ updatedAt?: string | null;
106
+ };
107
+
108
+ export type OperationsProjectRole = {
109
+ id: number;
110
+ slug: string;
111
+ code?: string | null;
112
+ name: string;
113
+ description?: string | null;
114
+ isActive?: boolean;
115
+ sortOrder?: number;
116
+ createdAt?: string | null;
117
+ updatedAt?: string | null;
118
+ };
119
+
120
+ export type OperationsProjectOption = {
121
+ id: number;
122
+ label: string;
123
+ name: string;
124
+ code?: string | null;
125
+ clientName?: string | null;
126
+ projectAssignmentId?: number | null;
127
+ roleLabel?: string | null;
128
+ status: string;
129
+ startDate?: string | null;
130
+ endDate?: string | null;
131
+ };
132
+
133
+ export type OperationsTaskOption = {
134
+ id: number;
135
+ label: string;
136
+ name: string;
137
+ description?: string | null;
138
+ status: string;
139
+ projectId: number;
140
+ projectAssignmentId: number;
141
+ projectName: string;
142
+ projectCode?: string | null;
143
+ createdAt?: string | null;
144
+ };
145
+
67
146
  export type OperationsProject = {
68
147
  id: number;
69
148
  contractId?: number | null;
@@ -87,16 +166,16 @@ export type OperationsProject = {
87
166
  teamSize?: number;
88
167
  };
89
168
 
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;
169
+ export type OperationsContract = {
170
+ id: number;
171
+ code: string;
172
+ name?: string | null;
173
+ contractCategory?: string;
174
+ contractType?: string;
175
+ clientName?: string | null;
176
+ signatureStatus?: string;
177
+ isActive?: boolean;
178
+ billingModel: string;
100
179
  accountManagerCollaboratorId?: number | null;
101
180
  accountManagerName?: string | null;
102
181
  relatedCollaboratorId?: number | null;
@@ -104,26 +183,26 @@ export type OperationsContract = {
104
183
  contractTemplateId?: number | null;
105
184
  contractTemplateName?: string | null;
106
185
  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;
186
+ contractTemplateCode?: string | null;
187
+ mainRelatedPartyName?: string | null;
188
+ originType?: string | null;
189
+ originId?: number | null;
190
+ startDate?: string | null;
191
+ endDate?: string | null;
192
+ signedAt?: string | null;
193
+ effectiveDate?: string | null;
115
194
  budgetAmount?: number | null;
116
195
  monthlyHourCap?: number | null;
117
196
  valueAmount?: number | null;
118
197
  paymentAmount?: number | null;
119
198
  revenueAmount?: number | null;
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;
199
+ fineAmount?: number | null;
200
+ status: string;
201
+ creationMode?: 'blank' | 'template' | 'upload' | 'duplicate' | null;
202
+ wizardStep?: number | null;
203
+ description?: string | null;
204
+ contentHtml?: string | null;
205
+ projectCount?: number;
127
206
  currentPdfFileName?: string | null;
128
207
  scheduleSummary?: OperationsWeeklyScheduleDay[];
129
208
  };
@@ -154,14 +233,35 @@ export type OperationsWeeklyScheduleDay = {
154
233
  breakMinutes?: number | null;
155
234
  };
156
235
 
236
+ export type OperationsCollaboratorEquityParticipation = {
237
+ participationType: string;
238
+ percentage?: number | null;
239
+ votingPower?: number | null;
240
+ startDate?: string | null;
241
+ endDate?: string | null;
242
+ notes?: string | null;
243
+ };
244
+
157
245
  export type OperationsTimesheetEntry = {
158
246
  id: number;
247
+ timesheetId?: number | null;
248
+ collaboratorId?: number | null;
249
+ collaboratorName?: string | null;
159
250
  projectAssignmentId?: number | null;
160
251
  projectId?: number | null;
252
+ projectCode?: string | null;
161
253
  projectName?: string | null;
162
254
  roleLabel?: string | null;
255
+ taskId?: number | null;
256
+ taskName?: string | null;
163
257
  activityLabel?: string | null;
258
+ label?: string | null;
259
+ status?: string | null;
260
+ weekStartDate?: string | null;
261
+ weekEndDate?: string | null;
262
+ createdAt?: string | null;
164
263
  workDate: string;
264
+ durationMinutes?: number | null;
165
265
  hours: number;
166
266
  description?: string | null;
167
267
  };
@@ -282,6 +382,7 @@ export type OperationsCollaboratorDetails = OperationsCollaborator & {
282
382
  code: string;
283
383
  name: string;
284
384
  status: string;
385
+ projectRoleId?: number | null;
285
386
  roleLabel?: string | null;
286
387
  allocationPercent?: number | null;
287
388
  weeklyHours?: number | null;
@@ -290,6 +391,7 @@ export type OperationsCollaboratorDetails = OperationsCollaborator & {
290
391
  }>;
291
392
  relatedContracts: OperationsContract[];
292
393
  weeklySchedule: OperationsWeeklyScheduleDay[];
394
+ equityParticipation?: OperationsCollaboratorEquityParticipation | null;
293
395
  timesheetSummary: {
294
396
  totalTimesheets: number;
295
397
  pendingTimesheets: number;
@@ -315,6 +417,7 @@ export type OperationsProjectDetails = OperationsProject & {
315
417
  id: number;
316
418
  collaboratorId: number;
317
419
  collaboratorName: string;
420
+ projectRoleId?: number | null;
318
421
  roleLabel?: string | null;
319
422
  allocationPercent?: number | null;
320
423
  weeklyHours?: number | null;
@@ -371,19 +474,19 @@ export type OperationsContractDetails = OperationsContract & {
371
474
  dueDay?: number | null;
372
475
  notes?: string | null;
373
476
  }>;
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
- }>;
477
+ documents: Array<{
478
+ id: number;
479
+ documentType: string;
480
+ fileId?: number | null;
481
+ fileName: string;
482
+ mimeType: string;
483
+ fileContentBase64?: string | null;
484
+ isCurrent: boolean;
485
+ extractionStatus?: string | null;
486
+ extractionSummary?: string | null;
487
+ notes?: string | null;
488
+ createdAt: string;
489
+ }>;
387
490
  revisions: Array<{
388
491
  id: number;
389
492
  revisionType: string;
@@ -135,6 +135,36 @@ export function formatEnumLabel(value?: string | null) {
135
135
  .replace(/\b\w/g, (match) => match.toUpperCase());
136
136
  }
137
137
 
138
+ const weekdayLabels: Record<
139
+ string,
140
+ {
141
+ 'pt-BR': string;
142
+ 'en-US': string;
143
+ }
144
+ > = {
145
+ monday: { 'pt-BR': 'Segunda-feira', 'en-US': 'Monday' },
146
+ tuesday: { 'pt-BR': 'Terça-feira', 'en-US': 'Tuesday' },
147
+ wednesday: { 'pt-BR': 'Quarta-feira', 'en-US': 'Wednesday' },
148
+ thursday: { 'pt-BR': 'Quinta-feira', 'en-US': 'Thursday' },
149
+ friday: { 'pt-BR': 'Sexta-feira', 'en-US': 'Friday' },
150
+ saturday: { 'pt-BR': 'Sábado', 'en-US': 'Saturday' },
151
+ sunday: { 'pt-BR': 'Domingo', 'en-US': 'Sunday' },
152
+ };
153
+
154
+ export function formatWeekdayLabel(
155
+ value?: string | null,
156
+ currentLocaleCode = 'en-US'
157
+ ) {
158
+ if (!value) {
159
+ return '-';
160
+ }
161
+
162
+ const locale = resolveLocale(currentLocaleCode) as 'pt-BR' | 'en-US';
163
+ const normalizedValue = String(value).trim().toLowerCase();
164
+
165
+ return weekdayLabels[normalizedValue]?.[locale] ?? formatEnumLabel(value);
166
+ }
167
+
138
168
  export function formatDateRange(
139
169
  startDate?: string | null,
140
170
  endDate?: string | null,
@@ -186,7 +216,8 @@ export function summarizeScheduleDays(
186
216
  isWorkingDay: boolean;
187
217
  startTime?: string | null;
188
218
  endTime?: string | null;
189
- }>
219
+ }>,
220
+ currentLocaleCode = 'en-US'
190
221
  ) {
191
222
  if (!days.length) {
192
223
  return '-';
@@ -195,7 +226,7 @@ export function summarizeScheduleDays(
195
226
  return days
196
227
  .filter((day) => day.isWorkingDay)
197
228
  .map((day) => {
198
- const label = formatEnumLabel(day.weekday);
229
+ const label = formatWeekdayLabel(day.weekday, currentLocaleCode);
199
230
  if (day.startTime && day.endTime) {
200
231
  return `${label}: ${formatTimeValue(day.startTime)}-${formatTimeValue(day.endTime)}`;
201
232
  }