@hed-hog/operations 0.0.300 → 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.
Files changed (73) hide show
  1. package/dist/operations.controller.d.ts +713 -31
  2. package/dist/operations.controller.d.ts.map +1 -1
  3. package/dist/operations.controller.js +157 -0
  4. package/dist/operations.controller.js.map +1 -1
  5. package/dist/operations.module.d.ts.map +1 -1
  6. package/dist/operations.module.js +5 -1
  7. package/dist/operations.module.js.map +1 -1
  8. package/dist/operations.proposal.subscriber.d.ts +11 -0
  9. package/dist/operations.proposal.subscriber.d.ts.map +1 -0
  10. package/dist/operations.proposal.subscriber.js +80 -0
  11. package/dist/operations.proposal.subscriber.js.map +1 -0
  12. package/dist/operations.proposal.subscriber.spec.d.ts +2 -0
  13. package/dist/operations.proposal.subscriber.spec.d.ts.map +1 -0
  14. package/dist/operations.proposal.subscriber.spec.js +88 -0
  15. package/dist/operations.proposal.subscriber.spec.js.map +1 -0
  16. package/dist/operations.service.d.ts +490 -46
  17. package/dist/operations.service.d.ts.map +1 -1
  18. package/dist/operations.service.js +2442 -119
  19. package/dist/operations.service.js.map +1 -1
  20. package/dist/operations.service.spec.d.ts +2 -0
  21. package/dist/operations.service.spec.d.ts.map +1 -0
  22. package/dist/operations.service.spec.js +159 -0
  23. package/dist/operations.service.spec.js.map +1 -0
  24. package/hedhog/data/menu.yaml +34 -0
  25. package/hedhog/data/role_route.yaml +39 -0
  26. package/hedhog/data/route.yaml +130 -0
  27. package/hedhog/frontend/app/_components/collaborator-details-screen.tsx.ejs +8 -6
  28. package/hedhog/frontend/app/_components/collaborator-form-screen.tsx.ejs +1163 -327
  29. package/hedhog/frontend/app/_components/collaborator-select-with-create.tsx.ejs +256 -0
  30. package/hedhog/frontend/app/_components/contract-content-editor.tsx.ejs +258 -0
  31. package/hedhog/frontend/app/_components/contract-creation-wizard.tsx.ejs +631 -0
  32. package/hedhog/frontend/app/_components/contract-details-screen.tsx.ejs +353 -27
  33. package/hedhog/frontend/app/_components/contract-form-screen.tsx.ejs +1926 -87
  34. package/hedhog/frontend/app/_components/contract-template-form-screen.tsx.ejs +526 -0
  35. package/hedhog/frontend/app/_components/contract-template-select-with-create.tsx.ejs +247 -0
  36. package/hedhog/frontend/app/_components/contract-wizard-sheet.tsx.ejs +3520 -0
  37. package/hedhog/frontend/app/_components/department-select-with-create.tsx.ejs +370 -0
  38. package/hedhog/frontend/app/_components/person-select-with-create.tsx.ejs +826 -0
  39. package/hedhog/frontend/app/_components/project-form-screen.tsx.ejs +1251 -364
  40. package/hedhog/frontend/app/_components/section-card.tsx.ejs +48 -13
  41. package/hedhog/frontend/app/_lib/api.ts.ejs +2 -5
  42. package/hedhog/frontend/app/_lib/types.ts.ejs +76 -33
  43. package/hedhog/frontend/app/_lib/utils/format.ts.ejs +85 -8
  44. package/hedhog/frontend/app/approvals/page.tsx.ejs +90 -54
  45. package/hedhog/frontend/app/collaborators/[id]/edit/page.tsx.ejs +2 -2
  46. package/hedhog/frontend/app/collaborators/[id]/page.tsx.ejs +2 -2
  47. package/hedhog/frontend/app/collaborators/page.tsx.ejs +597 -140
  48. package/hedhog/frontend/app/contracts/[id]/edit/page.tsx.ejs +2 -2
  49. package/hedhog/frontend/app/contracts/[id]/page.tsx.ejs +2 -2
  50. package/hedhog/frontend/app/contracts/page.tsx.ejs +941 -262
  51. package/hedhog/frontend/app/contracts/templates/page.tsx.ejs +384 -0
  52. package/hedhog/frontend/app/departments/page.tsx.ejs +442 -0
  53. package/hedhog/frontend/app/page.tsx.ejs +36 -12
  54. package/hedhog/frontend/app/projects/[id]/edit/page.tsx.ejs +2 -2
  55. package/hedhog/frontend/app/projects/new/page.tsx.ejs +2 -2
  56. package/hedhog/frontend/app/projects/page.tsx.ejs +264 -102
  57. package/hedhog/frontend/app/schedule-adjustments/page.tsx.ejs +50 -28
  58. package/hedhog/frontend/app/time-off/page.tsx.ejs +57 -31
  59. package/hedhog/frontend/app/timesheets/page.tsx.ejs +85 -42
  60. package/hedhog/frontend/messages/en.json +473 -12
  61. package/hedhog/frontend/messages/pt.json +528 -66
  62. package/hedhog/table/operations_collaborator.yaml +20 -0
  63. package/hedhog/table/operations_contract.yaml +22 -1
  64. package/hedhog/table/operations_contract_document.yaml +33 -16
  65. package/hedhog/table/operations_contract_template.yaml +58 -0
  66. package/hedhog/table/operations_department.yaml +24 -0
  67. package/package.json +6 -4
  68. package/src/operations.controller.ts +122 -0
  69. package/src/operations.module.ts +6 -2
  70. package/src/operations.proposal.subscriber.spec.ts +121 -0
  71. package/src/operations.proposal.subscriber.ts +86 -0
  72. package/src/operations.service.spec.ts +210 -0
  73. package/src/operations.service.ts +3934 -212
@@ -0,0 +1,247 @@
1
+ 'use client';
2
+
3
+ import { Button } from '@/components/ui/button';
4
+ import {
5
+ Command,
6
+ CommandEmpty,
7
+ CommandGroup,
8
+ CommandInput,
9
+ CommandItem,
10
+ CommandList,
11
+ } from '@/components/ui/command';
12
+ import {
13
+ Popover,
14
+ PopoverContent,
15
+ PopoverTrigger,
16
+ } from '@/components/ui/popover';
17
+ import {
18
+ Sheet,
19
+ SheetContent,
20
+ SheetDescription,
21
+ SheetHeader,
22
+ SheetTitle,
23
+ } from '@/components/ui/sheet';
24
+ import { useApp, useQuery } from '@hed-hog/next-app-provider';
25
+ import { Check, ChevronsUpDown, Plus, X } from 'lucide-react';
26
+ import { useEffect, useRef, useState } from 'react';
27
+ import { fetchOperations } from '../_lib/api';
28
+ import type { OperationsContractTemplate } from '../_lib/types';
29
+ import { ContractTemplateFormScreen } from './contract-template-form-screen';
30
+
31
+ type ContractTemplateSelectWithCreateProps = {
32
+ label: string;
33
+ value?: number | null;
34
+ initialSelectedLabel?: string;
35
+ placeholder: string;
36
+ disabled?: boolean;
37
+ onChange: (option: OperationsContractTemplate | null) => void;
38
+ };
39
+
40
+ export function ContractTemplateSelectWithCreate({
41
+ label,
42
+ value,
43
+ initialSelectedLabel = '',
44
+ placeholder,
45
+ disabled = false,
46
+ onChange,
47
+ }: ContractTemplateSelectWithCreateProps) {
48
+ const { request, currentLocaleCode } = useApp();
49
+ const [open, setOpen] = useState(false);
50
+ const [search, setSearch] = useState('');
51
+ const [createOpen, setCreateOpen] = useState(false);
52
+ const [selectedLabel, setSelectedLabel] = useState(initialSelectedLabel);
53
+ const parentScrollContainerRef = useRef<HTMLElement | null>(null);
54
+ const parentScrollTopRef = useRef(0);
55
+
56
+ const { data: templates = [] } = useQuery<OperationsContractTemplate[]>({
57
+ queryKey: ['operations-inline-contract-templates', currentLocaleCode],
58
+ queryFn: () =>
59
+ fetchOperations<OperationsContractTemplate[]>(
60
+ request,
61
+ '/operations/contract-templates'
62
+ ),
63
+ placeholderData: (old) => old ?? [],
64
+ });
65
+
66
+ useEffect(() => {
67
+ setSelectedLabel(initialSelectedLabel);
68
+ }, [initialSelectedLabel]);
69
+
70
+ useEffect(() => {
71
+ if (value == null) {
72
+ setSelectedLabel('');
73
+ return;
74
+ }
75
+
76
+ const option = templates.find((item) => item.id === value);
77
+ if (option) {
78
+ setSelectedLabel(option.name);
79
+ }
80
+ }, [templates, value]);
81
+
82
+ const filteredOptions = templates.filter((item) => {
83
+ const haystack = [item.name, item.code, item.description]
84
+ .filter(Boolean)
85
+ .join(' ')
86
+ .toLowerCase();
87
+ return haystack.includes(search.trim().toLowerCase());
88
+ });
89
+
90
+ const captureParentScrollPosition = (trigger: HTMLElement) => {
91
+ const parentSheetContent = trigger.closest(
92
+ '[data-radix-dialog-content]'
93
+ ) as HTMLElement | null;
94
+
95
+ if (!parentSheetContent) {
96
+ parentScrollContainerRef.current = null;
97
+ parentScrollTopRef.current = 0;
98
+ return;
99
+ }
100
+
101
+ parentScrollContainerRef.current = parentSheetContent;
102
+ parentScrollTopRef.current = parentSheetContent.scrollTop;
103
+ };
104
+
105
+ const restoreParentScrollPosition = () => {
106
+ const container =
107
+ parentScrollContainerRef.current &&
108
+ document.body.contains(parentScrollContainerRef.current)
109
+ ? parentScrollContainerRef.current
110
+ : null;
111
+
112
+ if (!container) {
113
+ return;
114
+ }
115
+
116
+ const restore = () => {
117
+ container.scrollTop = parentScrollTopRef.current;
118
+ };
119
+
120
+ requestAnimationFrame(restore);
121
+ setTimeout(restore, 0);
122
+ setTimeout(restore, 120);
123
+ };
124
+
125
+ return (
126
+ <div className="space-y-1.5">
127
+ <label className="text-xs font-medium text-muted-foreground">
128
+ {label}
129
+ </label>
130
+
131
+ <div className="flex gap-2">
132
+ <Popover open={open} onOpenChange={setOpen}>
133
+ <PopoverTrigger asChild>
134
+ <Button
135
+ type="button"
136
+ variant="outline"
137
+ role="combobox"
138
+ disabled={disabled}
139
+ className="h-9 flex-1 justify-between overflow-hidden"
140
+ >
141
+ <span className="truncate text-left">
142
+ {selectedLabel || placeholder}
143
+ </span>
144
+ <ChevronsUpDown className="size-4 shrink-0 opacity-50" />
145
+ </Button>
146
+ </PopoverTrigger>
147
+ <PopoverContent className="w-[var(--radix-popover-trigger-width)] p-0">
148
+ <Command shouldFilter={false}>
149
+ <CommandInput
150
+ value={search}
151
+ onValueChange={setSearch}
152
+ placeholder="Buscar template..."
153
+ />
154
+ <CommandList>
155
+ <CommandEmpty>Nenhum template encontrado.</CommandEmpty>
156
+ <CommandGroup>
157
+ {filteredOptions.map((option) => (
158
+ <CommandItem
159
+ key={option.id}
160
+ value={String(option.id)}
161
+ onSelect={() => {
162
+ onChange(option);
163
+ setSelectedLabel(option.name);
164
+ setOpen(false);
165
+ }}
166
+ >
167
+ <Check
168
+ className={`mr-2 size-4 ${
169
+ value === option.id ? 'opacity-100' : 'opacity-0'
170
+ }`}
171
+ />
172
+ <div className="min-w-0">
173
+ <div className="truncate">{option.name}</div>
174
+ <div className="truncate text-xs text-muted-foreground">
175
+ {[option.code, option.contractType]
176
+ .filter(Boolean)
177
+ .join(' • ')}
178
+ </div>
179
+ </div>
180
+ </CommandItem>
181
+ ))}
182
+ </CommandGroup>
183
+ </CommandList>
184
+ </Command>
185
+ </PopoverContent>
186
+ </Popover>
187
+
188
+ {value ? (
189
+ <Button
190
+ type="button"
191
+ variant="outline"
192
+ size="icon"
193
+ className="h-9 w-9 shrink-0 cursor-pointer"
194
+ onClick={() => {
195
+ onChange(null);
196
+ setSelectedLabel('');
197
+ }}
198
+ >
199
+ <X className="size-4" />
200
+ </Button>
201
+ ) : null}
202
+
203
+ <Button
204
+ type="button"
205
+ variant="outline"
206
+ size="icon"
207
+ className="h-9 w-9 shrink-0 cursor-pointer"
208
+ disabled={disabled}
209
+ onClick={(event) => {
210
+ captureParentScrollPosition(event.currentTarget);
211
+ setCreateOpen(true);
212
+ }}
213
+ aria-label={`Criar ${label.toLowerCase()}`}
214
+ >
215
+ <Plus className="size-4" />
216
+ </Button>
217
+ </div>
218
+
219
+ <Sheet
220
+ open={createOpen}
221
+ onOpenChange={(nextOpen) => {
222
+ setCreateOpen(nextOpen);
223
+ if (!nextOpen) {
224
+ restoreParentScrollPosition();
225
+ }
226
+ }}
227
+ >
228
+ <SheetContent className="w-full overflow-y-auto sm:max-w-[min(92vw,72rem)]">
229
+ <SheetHeader>
230
+ <SheetTitle>Novo template</SheetTitle>
231
+ <SheetDescription>
232
+ Crie um template sem sair do wizard do contrato.
233
+ </SheetDescription>
234
+ </SheetHeader>
235
+ <ContractTemplateFormScreen
236
+ onCancel={() => setCreateOpen(false)}
237
+ onSaved={async (template) => {
238
+ onChange(template);
239
+ setSelectedLabel(template.name);
240
+ setCreateOpen(false);
241
+ }}
242
+ />
243
+ </SheetContent>
244
+ </Sheet>
245
+ </div>
246
+ );
247
+ }