@hed-hog/operations 0.0.303 → 0.0.305

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 (178) 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 +184 -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 +85 -0
  23. package/dist/controllers/operations-tasks.controller.d.ts.map +1 -0
  24. package/dist/controllers/operations-tasks.controller.js +90 -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 +14 -0
  43. package/dist/dto/create-task.dto.d.ts.map +1 -0
  44. package/dist/dto/create-task.dto.js +83 -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 +14 -0
  83. package/dist/dto/update-task.dto.d.ts.map +1 -0
  84. package/dist/dto/update-task.dto.js +84 -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 +429 -8
  94. package/dist/operations.service.d.ts.map +1 -1
  95. package/dist/operations.service.js +1931 -165
  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 +196 -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 +125 -40
  113. package/hedhog/frontend/app/_components/collaborator-form-screen.tsx.ejs +740 -106
  114. package/hedhog/frontend/app/_components/collaborator-select-with-create.tsx.ejs +256 -256
  115. package/hedhog/frontend/app/_components/contract-form-screen.tsx.ejs +7 -7
  116. package/hedhog/frontend/app/_components/contract-template-form-screen.tsx.ejs +306 -306
  117. package/hedhog/frontend/app/_components/contract-template-select-with-create.tsx.ejs +247 -247
  118. package/hedhog/frontend/app/_components/contract-wizard-sheet.tsx.ejs +3520 -3520
  119. package/hedhog/frontend/app/_components/department-select-with-create.tsx.ejs +38 -16
  120. package/hedhog/frontend/app/_components/project-details-screen.tsx.ejs +1504 -52
  121. package/hedhog/frontend/app/_components/project-form-screen.tsx.ejs +1017 -649
  122. package/hedhog/frontend/app/_components/section-card.tsx.ejs +25 -18
  123. package/hedhog/frontend/app/_components/system-user-select-with-create.tsx.ejs +609 -0
  124. package/hedhog/frontend/app/_components/timesheet-task-create-sheet.tsx.ejs +213 -0
  125. package/hedhog/frontend/app/_lib/api.ts.ejs +30 -1
  126. package/hedhog/frontend/app/_lib/types.ts.ejs +147 -39
  127. package/hedhog/frontend/app/_lib/utils/format.ts.ejs +40 -9
  128. package/hedhog/frontend/app/_lib/utils/forms.ts.ejs +48 -1
  129. package/hedhog/frontend/app/approvals/page.tsx.ejs +116 -98
  130. package/hedhog/frontend/app/collaborator-types/page.tsx.ejs +502 -0
  131. package/hedhog/frontend/app/collaborators/page.tsx.ejs +116 -72
  132. package/hedhog/frontend/app/contracts/page.tsx.ejs +938 -938
  133. package/hedhog/frontend/app/contracts/templates/page.tsx.ejs +11 -9
  134. package/hedhog/frontend/app/departments/page.tsx.ejs +1 -1
  135. package/hedhog/frontend/app/projects/[id]/edit/page.tsx.ejs +1 -1
  136. package/hedhog/frontend/app/projects/page.tsx.ejs +364 -133
  137. package/hedhog/frontend/app/schedule-adjustments/page.tsx.ejs +244 -120
  138. package/hedhog/frontend/app/team/page.tsx.ejs +15 -2
  139. package/hedhog/frontend/app/time-off/page.tsx.ejs +158 -82
  140. package/hedhog/frontend/app/timesheets/page.tsx.ejs +814 -357
  141. package/hedhog/frontend/messages/en.json +268 -53
  142. package/hedhog/frontend/messages/pt.json +484 -271
  143. package/hedhog/table/operations_collaborator.yaml +26 -13
  144. package/hedhog/table/operations_collaborator_equity_participation.yaml +43 -0
  145. package/hedhog/table/operations_collaborator_type.yaml +33 -0
  146. package/hedhog/table/operations_job_title.yaml +24 -0
  147. package/hedhog/table/operations_project.yaml +9 -0
  148. package/hedhog/table/operations_project_assignment.yaml +9 -0
  149. package/hedhog/table/operations_project_role.yaml +39 -0
  150. package/hedhog/table/operations_task.yaml +69 -0
  151. package/hedhog/table/operations_timesheet_entry.yaml +12 -0
  152. package/package.json +6 -6
  153. package/src/controllers/operations-approvals.controller.ts +24 -0
  154. package/src/controllers/operations-collaborators.controller.ts +60 -0
  155. package/src/controllers/operations-contracts.controller.ts +138 -0
  156. package/src/controllers/operations-org-structure.controller.ts +92 -0
  157. package/src/controllers/operations-projects.controller.ts +50 -0
  158. package/src/controllers/operations-tasks.controller.ts +63 -0
  159. package/src/controllers/operations-timesheets.controller.ts +100 -0
  160. package/src/dto/create-collaborator-type.dto.ts +43 -0
  161. package/src/dto/create-collaborator.dto.ts +223 -0
  162. package/src/dto/create-schedule-adjustment-request.dto.ts +91 -0
  163. package/src/dto/create-task.dto.ts +75 -0
  164. package/src/dto/create-time-off-request.dto.ts +53 -0
  165. package/src/dto/create-timesheet-entry.dto.ts +67 -0
  166. package/src/dto/list-collaborator-types.dto.ts +15 -0
  167. package/src/dto/list-collaborators.dto.ts +30 -0
  168. package/src/dto/list-project-options.dto.ts +3 -0
  169. package/src/dto/list-tasks.dto.ts +25 -0
  170. package/src/dto/list-timesheet-entries.dto.ts +40 -0
  171. package/src/dto/update-collaborator-type.dto.ts +3 -0
  172. package/src/dto/update-collaborator.dto.ts +3 -0
  173. package/src/dto/update-task.dto.ts +76 -0
  174. package/src/operations.controller.ts +1 -278
  175. package/src/operations.module.ts +23 -2
  176. package/src/operations.service.spec.ts +450 -0
  177. package/src/operations.service.ts +4507 -1561
  178. package/src/services/shared/operations-access.service.ts +52 -0
@@ -1,8 +1,8 @@
1
1
  'use client';
2
2
 
3
- import { EmptyState, Page } from '@/components/entity-list';
4
- import { Button } from '@/components/ui/button';
5
- import { FormActions } from '@/components/ui/form-actions';
3
+ import { EmptyState, Page } from '@/components/entity-list';
4
+ import { Button } from '@/components/ui/button';
5
+ import { FormActions } from '@/components/ui/form-actions';
6
6
  import { Input } from '@/components/ui/input';
7
7
  import { Label } from '@/components/ui/label';
8
8
  import {
@@ -21,12 +21,12 @@ import Link from 'next/link';
21
21
  import { useRouter } from 'next/navigation';
22
22
  import { useEffect, useState } from 'react';
23
23
  import { fetchOperations, mutateOperations } from '../_lib/api';
24
- import { useOperationsAccess } from '../_lib/hooks/use-operations-access';
25
- import type { OperationsContractTemplate } from '../_lib/types';
26
- import { formatEnumLabel } from '../_lib/utils/format';
27
- import { trimToNull } from '../_lib/utils/forms';
28
- import { ContractContentEditor } from './contract-content-editor';
29
- import { OperationsHeader } from './operations-header';
24
+ import { useOperationsAccess } from '../_lib/hooks/use-operations-access';
25
+ import type { OperationsContractTemplate } from '../_lib/types';
26
+ import { formatEnumLabel } from '../_lib/utils/format';
27
+ import { trimToNull } from '../_lib/utils/forms';
28
+ import { ContractContentEditor } from './contract-content-editor';
29
+ import { OperationsHeader } from './operations-header';
30
30
 
31
31
  type ContractTemplateFormState = {
32
32
  code: string;
@@ -86,15 +86,15 @@ export function ContractTemplateFormScreen({
86
86
  }: ContractTemplateFormScreenProps) {
87
87
  const t = useTranslations('operations.ContractTemplateFormPage');
88
88
  const commonT = useTranslations('operations.Common');
89
- const { request, showToastHandler, currentLocaleCode } = useApp();
90
- const access = useOperationsAccess();
91
- const router = useRouter();
92
- const [form, setForm] = useState<ContractTemplateFormState>(buildEmptyForm());
93
- const isSheetMode = Boolean(onCancel);
94
- const [sheetStep, setSheetStep] = useState(0);
95
- const nextLabel = currentLocaleCode?.toLowerCase().startsWith('pt')
96
- ? 'Proximo'
97
- : 'Next';
89
+ const { request, showToastHandler, currentLocaleCode } = useApp();
90
+ const access = useOperationsAccess();
91
+ const router = useRouter();
92
+ const [form, setForm] = useState<ContractTemplateFormState>(buildEmptyForm());
93
+ const isSheetMode = Boolean(onCancel);
94
+ const [sheetStep, setSheetStep] = useState(0);
95
+ const nextLabel = currentLocaleCode?.toLowerCase().startsWith('pt')
96
+ ? 'Proximo'
97
+ : 'Next';
98
98
 
99
99
  const { data: template, isLoading } = useQuery<OperationsContractTemplate>({
100
100
  queryKey: [
@@ -110,31 +110,31 @@ export function ContractTemplateFormScreen({
110
110
  ),
111
111
  });
112
112
 
113
- useEffect(() => {
114
- if (template) {
115
- // eslint-disable-next-line react-hooks/set-state-in-effect
116
- setForm(toFormState(template));
117
- return;
113
+ useEffect(() => {
114
+ if (template) {
115
+ // eslint-disable-next-line react-hooks/set-state-in-effect
116
+ setForm(toFormState(template));
117
+ return;
118
118
  }
119
119
 
120
120
  if (!templateId) {
121
- setForm(buildEmptyForm());
122
- }
123
- }, [template, templateId]);
124
-
125
- useEffect(() => {
126
- if (!isSheetMode) return;
127
- setSheetStep(0);
128
- }, [isSheetMode, templateId]);
129
-
130
- const validateOverviewStep = () => {
131
- if (!form.name.trim()) {
132
- showToastHandler?.('error', t('messages.requiredFields'));
133
- return false;
134
- }
135
-
136
- return true;
137
- };
121
+ setForm(buildEmptyForm());
122
+ }
123
+ }, [template, templateId]);
124
+
125
+ useEffect(() => {
126
+ if (!isSheetMode) return;
127
+ setSheetStep(0);
128
+ }, [isSheetMode, templateId]);
129
+
130
+ const validateOverviewStep = () => {
131
+ if (!form.name.trim()) {
132
+ showToastHandler?.('error', t('messages.requiredFields'));
133
+ return false;
134
+ }
135
+
136
+ return true;
137
+ };
138
138
 
139
139
  const onSubmit = async () => {
140
140
  if (!form.name.trim()) {
@@ -224,272 +224,272 @@ export function ContractTemplateFormScreen({
224
224
  );
225
225
  }
226
226
 
227
- const overviewSection = (
228
- <section className="space-y-6">
229
- <div className="space-y-1">
230
- <h2 className="text-xl font-semibold">{t('sections.overview')}</h2>
231
- <p className="text-sm text-muted-foreground">
232
- {t('sections.overviewDescription')}
233
- </p>
234
- </div>
235
-
236
- <div className="grid gap-4 md:grid-cols-12">
237
- <div className="space-y-2 md:col-span-3">
238
- <Label htmlFor="contract-template-code">{t('fields.code')}</Label>
239
- <Input
240
- id="contract-template-code"
241
- value={form.code}
242
- placeholder={t('placeholders.code')}
243
- onChange={(event) =>
244
- setForm((current) => ({ ...current, code: event.target.value }))
245
- }
246
- />
247
- </div>
248
- <div className="space-y-2 md:col-span-6">
249
- <Label htmlFor="contract-template-name">{t('fields.name')}</Label>
250
- <Input
251
- id="contract-template-name"
252
- value={form.name}
253
- placeholder={t('placeholders.name')}
254
- onChange={(event) =>
255
- setForm((current) => ({ ...current, name: event.target.value }))
256
- }
257
- />
258
- </div>
259
- <div className="space-y-2 md:col-span-3">
260
- <Label>{commonT('labels.status')}</Label>
261
- <Select
262
- value={form.status}
263
- onValueChange={(value) =>
264
- setForm((current) => ({ ...current, status: value }))
265
- }
266
- >
267
- <SelectTrigger className="w-full">
268
- <SelectValue />
269
- </SelectTrigger>
270
- <SelectContent>
271
- {['active', 'draft', 'inactive', 'archived'].map((value) => (
272
- <SelectItem key={value} value={value}>
273
- {formatEnumLabel(value)}
274
- </SelectItem>
275
- ))}
276
- </SelectContent>
277
- </Select>
278
- </div>
279
-
280
- <div className="space-y-2 md:col-span-3">
281
- <Label>{t('fields.contractCategory')}</Label>
282
- <Select
283
- value={form.contractCategory}
284
- onValueChange={(value) =>
285
- setForm((current) => ({ ...current, contractCategory: value }))
286
- }
287
- >
288
- <SelectTrigger className="w-full">
289
- <SelectValue />
290
- </SelectTrigger>
291
- <SelectContent>
292
- {[
293
- 'employee',
294
- 'contractor',
295
- 'client',
296
- 'supplier',
297
- 'vendor',
298
- 'partner',
299
- 'internal',
300
- 'other',
301
- ].map((value) => (
302
- <SelectItem key={value} value={value}>
303
- {formatEnumLabel(value)}
304
- </SelectItem>
305
- ))}
306
- </SelectContent>
307
- </Select>
308
- </div>
309
- <div className="space-y-2 md:col-span-3">
310
- <Label>{t('fields.contractType')}</Label>
311
- <Select
312
- value={form.contractType}
313
- onValueChange={(value) =>
314
- setForm((current) => ({ ...current, contractType: value }))
315
- }
316
- >
317
- <SelectTrigger className="w-full">
318
- <SelectValue />
319
- </SelectTrigger>
320
- <SelectContent>
321
- {[
322
- 'clt',
323
- 'pj',
324
- 'freelancer_agreement',
325
- 'service_agreement',
326
- 'fixed_term',
327
- 'recurring_service',
328
- 'nda',
329
- 'amendment',
330
- 'addendum',
331
- 'other',
332
- ].map((value) => (
333
- <SelectItem key={value} value={value}>
334
- {formatEnumLabel(value)}
335
- </SelectItem>
336
- ))}
337
- </SelectContent>
338
- </Select>
339
- </div>
340
- <div className="space-y-2 md:col-span-3">
341
- <Label>{commonT('labels.billingModel')}</Label>
342
- <Select
343
- value={form.billingModel}
344
- onValueChange={(value) =>
345
- setForm((current) => ({ ...current, billingModel: value }))
346
- }
347
- >
348
- <SelectTrigger className="w-full">
349
- <SelectValue />
350
- </SelectTrigger>
351
- <SelectContent>
352
- {['time_and_material', 'monthly_retainer', 'fixed_price'].map(
353
- (value) => (
354
- <SelectItem key={value} value={value}>
355
- {formatEnumLabel(value)}
356
- </SelectItem>
357
- )
358
- )}
359
- </SelectContent>
360
- </Select>
361
- </div>
362
- <div className="space-y-2 md:col-span-3">
363
- <Label>{t('fields.signatureStatus')}</Label>
364
- <Select
365
- value={form.signatureStatus}
366
- onValueChange={(value) =>
367
- setForm((current) => ({ ...current, signatureStatus: value }))
368
- }
369
- >
370
- <SelectTrigger className="w-full">
371
- <SelectValue />
372
- </SelectTrigger>
373
- <SelectContent>
374
- {[
375
- 'not_started',
376
- 'pending',
377
- 'partially_signed',
378
- 'signed',
379
- 'expired',
380
- ].map((value) => (
381
- <SelectItem key={value} value={value}>
382
- {formatEnumLabel(value)}
383
- </SelectItem>
384
- ))}
385
- </SelectContent>
386
- </Select>
387
- </div>
388
-
389
- <div className="space-y-2 md:col-span-12">
390
- <Label htmlFor="contract-template-description">
391
- {t('fields.description')}
392
- </Label>
393
- <Textarea
394
- id="contract-template-description"
395
- rows={3}
396
- value={form.description}
397
- placeholder={t('placeholders.description')}
398
- onChange={(event) =>
399
- setForm((current) => ({
400
- ...current,
401
- description: event.target.value,
402
- }))
403
- }
404
- />
405
- </div>
406
-
407
- <div className="flex items-center justify-between rounded-lg border px-4 py-4 md:col-span-12">
408
- <div className="space-y-1">
409
- <div className="text-sm font-medium">{t('fields.isActive')}</div>
410
- <div className="text-xs text-muted-foreground">
411
- {t('fields.isActiveDescription')}
412
- </div>
413
- </div>
414
- <Switch
415
- checked={form.isActive}
416
- onCheckedChange={(checked) =>
417
- setForm((current) => ({ ...current, isActive: checked }))
418
- }
419
- />
420
- </div>
421
- </div>
422
- </section>
423
- );
424
-
425
- const contentSection = (
426
- <section className="space-y-6">
427
- <ContractContentEditor
428
- value={form.contentHtml}
429
- onChange={(value) =>
430
- setForm((current) => ({ ...current, contentHtml: value }))
431
- }
432
- editorTitle={t('sections.editor')}
433
- editorDescription={t('sections.editorDescription')}
434
- previewTitle={t('sections.preview')}
435
- previewDescription={t('sections.previewDescription')}
436
- promptContext={{
437
- name: form.name,
438
- code: form.code,
439
- description: form.description,
440
- contract_type: form.contractType,
441
- billing_model: form.billingModel,
442
- }}
443
- showPreview={false}
444
- chrome="plain"
445
- />
446
- </section>
447
- );
448
-
449
- const formBody = isSheetMode ? (
450
- <div className="space-y-6">
451
- {sheetStep === 0 ? overviewSection : contentSection}
452
- {templateId && isLoading ? (
453
- <div className="text-sm text-muted-foreground">{t('loading')}</div>
454
- ) : null}
455
- </div>
456
- ) : (
457
- <div className="space-y-8">
458
- {overviewSection}
459
- {contentSection}
460
- {templateId && isLoading ? (
461
- <div className="text-sm text-muted-foreground">{t('loading')}</div>
462
- ) : null}
463
- </div>
464
- );
465
-
466
- if (isSheetMode) {
467
- return (
468
- <div className="mt-4 space-y-6 pb-6">
469
- {formBody}
470
-
471
- <FormActions
472
- sheet
473
- cancelLabel={
474
- sheetStep === 0 ? commonT('actions.cancel') : commonT('actions.back')
475
- }
476
- onCancel={
477
- sheetStep === 0 ? onCancel : () => setSheetStep((current) => current - 1)
478
- }
479
- onSubmit={() => {
480
- if (sheetStep === 0) {
481
- if (!validateOverviewStep()) return;
482
- setSheetStep(1);
483
- return;
484
- }
485
-
486
- void onSubmit();
487
- }}
488
- submitIcon={sheetStep === 0 ? undefined : <Save className="size-4" />}
489
- submitLabel={sheetStep === 0 ? nextLabel : commonT('actions.save')}
490
- submitSize="lg"
491
- />
492
- </div>
227
+ const overviewSection = (
228
+ <section className="space-y-6">
229
+ <div className="space-y-1">
230
+ <h2 className="text-xl font-semibold">{t('sections.overview')}</h2>
231
+ <p className="text-sm text-muted-foreground">
232
+ {t('sections.overviewDescription')}
233
+ </p>
234
+ </div>
235
+
236
+ <div className="grid gap-4 md:grid-cols-12">
237
+ <div className="space-y-2 md:col-span-3">
238
+ <Label htmlFor="contract-template-code">{t('fields.code')}</Label>
239
+ <Input
240
+ id="contract-template-code"
241
+ value={form.code}
242
+ placeholder={t('placeholders.code')}
243
+ onChange={(event) =>
244
+ setForm((current) => ({ ...current, code: event.target.value }))
245
+ }
246
+ />
247
+ </div>
248
+ <div className="space-y-2 md:col-span-6">
249
+ <Label htmlFor="contract-template-name">{t('fields.name')}</Label>
250
+ <Input
251
+ id="contract-template-name"
252
+ value={form.name}
253
+ placeholder={t('placeholders.name')}
254
+ onChange={(event) =>
255
+ setForm((current) => ({ ...current, name: event.target.value }))
256
+ }
257
+ />
258
+ </div>
259
+ <div className="space-y-2 md:col-span-3">
260
+ <Label>{commonT('labels.status')}</Label>
261
+ <Select
262
+ value={form.status}
263
+ onValueChange={(value) =>
264
+ setForm((current) => ({ ...current, status: value }))
265
+ }
266
+ >
267
+ <SelectTrigger className="w-full">
268
+ <SelectValue />
269
+ </SelectTrigger>
270
+ <SelectContent>
271
+ {['active', 'draft', 'inactive', 'archived'].map((value) => (
272
+ <SelectItem key={value} value={value}>
273
+ {formatEnumLabel(value)}
274
+ </SelectItem>
275
+ ))}
276
+ </SelectContent>
277
+ </Select>
278
+ </div>
279
+
280
+ <div className="space-y-2 md:col-span-3">
281
+ <Label>{t('fields.contractCategory')}</Label>
282
+ <Select
283
+ value={form.contractCategory}
284
+ onValueChange={(value) =>
285
+ setForm((current) => ({ ...current, contractCategory: value }))
286
+ }
287
+ >
288
+ <SelectTrigger className="w-full">
289
+ <SelectValue />
290
+ </SelectTrigger>
291
+ <SelectContent>
292
+ {[
293
+ 'employee',
294
+ 'contractor',
295
+ 'client',
296
+ 'supplier',
297
+ 'vendor',
298
+ 'partner',
299
+ 'internal',
300
+ 'other',
301
+ ].map((value) => (
302
+ <SelectItem key={value} value={value}>
303
+ {formatEnumLabel(value)}
304
+ </SelectItem>
305
+ ))}
306
+ </SelectContent>
307
+ </Select>
308
+ </div>
309
+ <div className="space-y-2 md:col-span-3">
310
+ <Label>{t('fields.contractType')}</Label>
311
+ <Select
312
+ value={form.contractType}
313
+ onValueChange={(value) =>
314
+ setForm((current) => ({ ...current, contractType: value }))
315
+ }
316
+ >
317
+ <SelectTrigger className="w-full">
318
+ <SelectValue />
319
+ </SelectTrigger>
320
+ <SelectContent>
321
+ {[
322
+ 'clt',
323
+ 'pj',
324
+ 'freelancer_agreement',
325
+ 'service_agreement',
326
+ 'fixed_term',
327
+ 'recurring_service',
328
+ 'nda',
329
+ 'amendment',
330
+ 'addendum',
331
+ 'other',
332
+ ].map((value) => (
333
+ <SelectItem key={value} value={value}>
334
+ {formatEnumLabel(value)}
335
+ </SelectItem>
336
+ ))}
337
+ </SelectContent>
338
+ </Select>
339
+ </div>
340
+ <div className="space-y-2 md:col-span-3">
341
+ <Label>{commonT('labels.billingModel')}</Label>
342
+ <Select
343
+ value={form.billingModel}
344
+ onValueChange={(value) =>
345
+ setForm((current) => ({ ...current, billingModel: value }))
346
+ }
347
+ >
348
+ <SelectTrigger className="w-full">
349
+ <SelectValue />
350
+ </SelectTrigger>
351
+ <SelectContent>
352
+ {['time_and_material', 'monthly_retainer', 'fixed_price'].map(
353
+ (value) => (
354
+ <SelectItem key={value} value={value}>
355
+ {formatEnumLabel(value)}
356
+ </SelectItem>
357
+ )
358
+ )}
359
+ </SelectContent>
360
+ </Select>
361
+ </div>
362
+ <div className="space-y-2 md:col-span-3">
363
+ <Label>{t('fields.signatureStatus')}</Label>
364
+ <Select
365
+ value={form.signatureStatus}
366
+ onValueChange={(value) =>
367
+ setForm((current) => ({ ...current, signatureStatus: value }))
368
+ }
369
+ >
370
+ <SelectTrigger className="w-full">
371
+ <SelectValue />
372
+ </SelectTrigger>
373
+ <SelectContent>
374
+ {[
375
+ 'not_started',
376
+ 'pending',
377
+ 'partially_signed',
378
+ 'signed',
379
+ 'expired',
380
+ ].map((value) => (
381
+ <SelectItem key={value} value={value}>
382
+ {formatEnumLabel(value)}
383
+ </SelectItem>
384
+ ))}
385
+ </SelectContent>
386
+ </Select>
387
+ </div>
388
+
389
+ <div className="space-y-2 md:col-span-12">
390
+ <Label htmlFor="contract-template-description">
391
+ {t('fields.description')}
392
+ </Label>
393
+ <Textarea
394
+ id="contract-template-description"
395
+ rows={3}
396
+ value={form.description}
397
+ placeholder={t('placeholders.description')}
398
+ onChange={(event) =>
399
+ setForm((current) => ({
400
+ ...current,
401
+ description: event.target.value,
402
+ }))
403
+ }
404
+ />
405
+ </div>
406
+
407
+ <div className="flex items-center justify-between rounded-lg border px-4 py-4 md:col-span-12">
408
+ <div className="space-y-1">
409
+ <div className="text-sm font-medium">{t('fields.isActive')}</div>
410
+ <div className="text-xs text-muted-foreground">
411
+ {t('fields.isActiveDescription')}
412
+ </div>
413
+ </div>
414
+ <Switch
415
+ checked={form.isActive}
416
+ onCheckedChange={(checked) =>
417
+ setForm((current) => ({ ...current, isActive: checked }))
418
+ }
419
+ />
420
+ </div>
421
+ </div>
422
+ </section>
423
+ );
424
+
425
+ const contentSection = (
426
+ <section className="space-y-6">
427
+ <ContractContentEditor
428
+ value={form.contentHtml}
429
+ onChange={(value) =>
430
+ setForm((current) => ({ ...current, contentHtml: value }))
431
+ }
432
+ editorTitle={t('sections.editor')}
433
+ editorDescription={t('sections.editorDescription')}
434
+ previewTitle={t('sections.preview')}
435
+ previewDescription={t('sections.previewDescription')}
436
+ promptContext={{
437
+ name: form.name,
438
+ code: form.code,
439
+ description: form.description,
440
+ contract_type: form.contractType,
441
+ billing_model: form.billingModel,
442
+ }}
443
+ showPreview={false}
444
+ chrome="plain"
445
+ />
446
+ </section>
447
+ );
448
+
449
+ const formBody = isSheetMode ? (
450
+ <div className="space-y-6">
451
+ {sheetStep === 0 ? overviewSection : contentSection}
452
+ {templateId && isLoading ? (
453
+ <div className="text-sm text-muted-foreground">{t('loading')}</div>
454
+ ) : null}
455
+ </div>
456
+ ) : (
457
+ <div className="space-y-8">
458
+ {overviewSection}
459
+ {contentSection}
460
+ {templateId && isLoading ? (
461
+ <div className="text-sm text-muted-foreground">{t('loading')}</div>
462
+ ) : null}
463
+ </div>
464
+ );
465
+
466
+ if (isSheetMode) {
467
+ return (
468
+ <div className="mt-4 space-y-6 pb-6">
469
+ {formBody}
470
+
471
+ <FormActions
472
+ sheet
473
+ cancelLabel={
474
+ sheetStep === 0 ? commonT('actions.cancel') : commonT('actions.back')
475
+ }
476
+ onCancel={
477
+ sheetStep === 0 ? onCancel : () => setSheetStep((current) => current - 1)
478
+ }
479
+ onSubmit={() => {
480
+ if (sheetStep === 0) {
481
+ if (!validateOverviewStep()) return;
482
+ setSheetStep(1);
483
+ return;
484
+ }
485
+
486
+ void onSubmit();
487
+ }}
488
+ submitIcon={sheetStep === 0 ? undefined : <Save className="size-4" />}
489
+ submitLabel={sheetStep === 0 ? nextLabel : commonT('actions.save')}
490
+ submitSize="lg"
491
+ />
492
+ </div>
493
493
  );
494
494
  }
495
495