@hed-hog/finance 0.0.235 → 0.0.237

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 (75) hide show
  1. package/dist/dto/create-cost-center.dto.d.ts +4 -0
  2. package/dist/dto/create-cost-center.dto.d.ts.map +1 -0
  3. package/dist/dto/create-cost-center.dto.js +24 -0
  4. package/dist/dto/create-cost-center.dto.js.map +1 -0
  5. package/dist/dto/create-finance-category.dto.d.ts +6 -0
  6. package/dist/dto/create-finance-category.dto.d.ts.map +1 -0
  7. package/dist/dto/create-finance-category.dto.js +37 -0
  8. package/dist/dto/create-finance-category.dto.js.map +1 -0
  9. package/dist/dto/create-period-close.dto.d.ts +7 -0
  10. package/dist/dto/create-period-close.dto.d.ts.map +1 -0
  11. package/dist/dto/create-period-close.dto.js +44 -0
  12. package/dist/dto/create-period-close.dto.js.map +1 -0
  13. package/dist/dto/move-finance-category.dto.d.ts +5 -0
  14. package/dist/dto/move-finance-category.dto.d.ts.map +1 -0
  15. package/dist/dto/move-finance-category.dto.js +32 -0
  16. package/dist/dto/move-finance-category.dto.js.map +1 -0
  17. package/dist/dto/update-cost-center.dto.d.ts +5 -0
  18. package/dist/dto/update-cost-center.dto.d.ts.map +1 -0
  19. package/dist/dto/update-cost-center.dto.js +32 -0
  20. package/dist/dto/update-cost-center.dto.js.map +1 -0
  21. package/dist/dto/update-finance-category.dto.d.ts +7 -0
  22. package/dist/dto/update-finance-category.dto.d.ts.map +1 -0
  23. package/dist/dto/update-finance-category.dto.js +46 -0
  24. package/dist/dto/update-finance-category.dto.js.map +1 -0
  25. package/dist/finance-audit-logs.controller.d.ts +13 -0
  26. package/dist/finance-audit-logs.controller.d.ts.map +1 -0
  27. package/dist/finance-audit-logs.controller.js +54 -0
  28. package/dist/finance-audit-logs.controller.js.map +1 -0
  29. package/dist/finance-categories.controller.d.ts +42 -0
  30. package/dist/finance-categories.controller.d.ts.map +1 -0
  31. package/dist/finance-categories.controller.js +84 -0
  32. package/dist/finance-categories.controller.js.map +1 -0
  33. package/dist/finance-cost-centers.controller.d.ts +32 -0
  34. package/dist/finance-cost-centers.controller.d.ts.map +1 -0
  35. package/dist/finance-cost-centers.controller.js +72 -0
  36. package/dist/finance-cost-centers.controller.js.map +1 -0
  37. package/dist/finance-period-close.controller.d.ts +27 -0
  38. package/dist/finance-period-close.controller.d.ts.map +1 -0
  39. package/dist/finance-period-close.controller.js +64 -0
  40. package/dist/finance-period-close.controller.js.map +1 -0
  41. package/dist/finance.module.d.ts.map +1 -1
  42. package/dist/finance.module.js +8 -0
  43. package/dist/finance.module.js.map +1 -1
  44. package/dist/finance.service.d.ts +111 -0
  45. package/dist/finance.service.d.ts.map +1 -1
  46. package/dist/finance.service.js +446 -17
  47. package/dist/finance.service.js.map +1 -1
  48. package/dist/index.d.ts +4 -0
  49. package/dist/index.d.ts.map +1 -1
  50. package/dist/index.js +4 -0
  51. package/dist/index.js.map +1 -1
  52. package/hedhog/data/route.yaml +108 -0
  53. package/hedhog/frontend/app/_components/person-field-with-create.tsx.ejs +627 -0
  54. package/hedhog/frontend/app/accounts-payable/installments/page.tsx.ejs +865 -883
  55. package/hedhog/frontend/app/accounts-receivable/installments/page.tsx.ejs +838 -861
  56. package/hedhog/frontend/app/administration/audit-logs/page.tsx.ejs +309 -0
  57. package/hedhog/frontend/app/administration/categories/page.tsx.ejs +725 -0
  58. package/hedhog/frontend/app/administration/cost-centers/page.tsx.ejs +378 -0
  59. package/hedhog/frontend/app/administration/period-close/page.tsx.ejs +502 -0
  60. package/hedhog/frontend/messages/en.json +225 -0
  61. package/hedhog/frontend/messages/pt.json +225 -0
  62. package/package.json +5 -5
  63. package/src/dto/create-cost-center.dto.ts +9 -0
  64. package/src/dto/create-finance-category.dto.ts +21 -0
  65. package/src/dto/create-period-close.dto.ts +34 -0
  66. package/src/dto/move-finance-category.dto.ts +18 -0
  67. package/src/dto/update-cost-center.dto.ts +17 -0
  68. package/src/dto/update-finance-category.dto.ts +30 -0
  69. package/src/finance-audit-logs.controller.ts +30 -0
  70. package/src/finance-categories.controller.ts +52 -0
  71. package/src/finance-cost-centers.controller.ts +43 -0
  72. package/src/finance-period-close.controller.ts +34 -0
  73. package/src/finance.module.ts +8 -0
  74. package/src/finance.service.ts +578 -9
  75. package/src/index.ts +4 -0
@@ -0,0 +1,627 @@
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
+ Form,
14
+ FormControl,
15
+ FormField,
16
+ FormItem,
17
+ FormLabel,
18
+ FormMessage,
19
+ } from '@/components/ui/form';
20
+ import { Input } from '@/components/ui/input';
21
+ import {
22
+ Popover,
23
+ PopoverContent,
24
+ PopoverTrigger,
25
+ } from '@/components/ui/popover';
26
+ import {
27
+ Select,
28
+ SelectContent,
29
+ SelectItem,
30
+ SelectTrigger,
31
+ SelectValue,
32
+ } from '@/components/ui/select';
33
+ import {
34
+ Sheet,
35
+ SheetContent,
36
+ SheetDescription,
37
+ SheetHeader,
38
+ SheetTitle,
39
+ } from '@/components/ui/sheet';
40
+ import { useApp, useQuery } from '@hed-hog/next-app-provider';
41
+ import { zodResolver } from '@hookform/resolvers/zod';
42
+ import { ChevronsUpDown, X } from 'lucide-react';
43
+ import { useEffect, useState } from 'react';
44
+ import { FieldValues, Path, UseFormReturn, useForm } from 'react-hook-form';
45
+ import { z } from 'zod';
46
+
47
+ type PersonOption = {
48
+ id: number | string;
49
+ name: string;
50
+ };
51
+
52
+ const createPersonSchema = z.object({
53
+ name: z.string().trim().min(2, 'Nome é obrigatório'),
54
+ type: z.enum(['individual', 'company']),
55
+ email: z
56
+ .string()
57
+ .trim()
58
+ .email('E-mail inválido')
59
+ .optional()
60
+ .or(z.literal('')),
61
+ phone: z.string().trim().optional(),
62
+ document: z.string().trim().optional(),
63
+ line1: z.string().optional(),
64
+ city: z.string().optional(),
65
+ state: z.string().optional(),
66
+ });
67
+
68
+ type CreatePersonValues = z.infer<typeof createPersonSchema>;
69
+
70
+ function CreatePersonSheet({
71
+ open,
72
+ onOpenChange,
73
+ onCreated,
74
+ entityLabel,
75
+ }: {
76
+ open: boolean;
77
+ onOpenChange: (open: boolean) => void;
78
+ onCreated: (person: PersonOption) => void;
79
+ entityLabel: string;
80
+ }) {
81
+ const { request, showToastHandler, currentLocaleCode } = useApp();
82
+
83
+ const form = useForm<CreatePersonValues>({
84
+ resolver: zodResolver(createPersonSchema),
85
+ defaultValues: {
86
+ name: '',
87
+ type: 'individual',
88
+ email: '',
89
+ phone: '',
90
+ document: '',
91
+ line1: '',
92
+ city: '',
93
+ state: '',
94
+ },
95
+ });
96
+
97
+ const selectedType = form.watch('type');
98
+
99
+ const { data: contactTypes = [] } = useQuery<any[]>({
100
+ queryKey: ['person-field-contact-types', currentLocaleCode],
101
+ queryFn: async () => {
102
+ const response = await request<any>({
103
+ url: '/person-contact-type?pageSize=100',
104
+ method: 'GET',
105
+ });
106
+ return response?.data?.data || [];
107
+ },
108
+ placeholderData: (old) => old ?? [],
109
+ });
110
+
111
+ const { data: addressTypes = [] } = useQuery<any[]>({
112
+ queryKey: ['person-field-address-types', currentLocaleCode],
113
+ queryFn: async () => {
114
+ const response = await request<any>({
115
+ url: '/person-address-type?pageSize=100',
116
+ method: 'GET',
117
+ });
118
+ return response?.data?.data || [];
119
+ },
120
+ placeholderData: (old) => old ?? [],
121
+ });
122
+
123
+ const { data: documentTypes = [] } = useQuery<any[]>({
124
+ queryKey: ['person-field-document-types', currentLocaleCode],
125
+ queryFn: async () => {
126
+ const response = await request<any>({
127
+ url: '/person-document-type?pageSize=100',
128
+ method: 'GET',
129
+ });
130
+ return response?.data?.data || [];
131
+ },
132
+ placeholderData: (old) => old ?? [],
133
+ });
134
+
135
+ const resolveContactTypeId = (code: string, fallbackIndex = 0) => {
136
+ const found = contactTypes.find(
137
+ (item) => String(item.code).toUpperCase() === code
138
+ );
139
+ return (
140
+ found?.contact_type_id || contactTypes[fallbackIndex]?.contact_type_id
141
+ );
142
+ };
143
+
144
+ const resolveDocumentTypeId = (code: string) => {
145
+ const found = documentTypes.find(
146
+ (item) => String(item.code).toUpperCase() === code
147
+ );
148
+ return found?.document_type_id || documentTypes[0]?.document_type_id;
149
+ };
150
+
151
+ const resolveAddressTypeId = () => {
152
+ const home = addressTypes.find(
153
+ (item) => String(item.code).toUpperCase() === 'HOME'
154
+ );
155
+ return home?.address_type_id || addressTypes[0]?.address_type_id;
156
+ };
157
+
158
+ const handleSubmit = async (values: CreatePersonValues) => {
159
+ try {
160
+ const createResponse = await request<any>({
161
+ url: '/person',
162
+ method: 'POST',
163
+ data: {
164
+ name: values.name,
165
+ type: values.type,
166
+ status: 'active',
167
+ },
168
+ });
169
+
170
+ const personId = Number(
171
+ createResponse?.data?.id ?? createResponse?.data?.data?.id
172
+ );
173
+
174
+ if (!personId) {
175
+ throw new Error('Não foi possível identificar o cadastro criado');
176
+ }
177
+
178
+ const emailTypeId = resolveContactTypeId('EMAIL', 0);
179
+ const phoneTypeId =
180
+ resolveContactTypeId('PHONE', 1) || resolveContactTypeId('MOBILE', 1);
181
+ const documentTypeId = resolveDocumentTypeId(
182
+ values.type === 'individual' ? 'CPF' : 'CNPJ'
183
+ );
184
+ const addressTypeId = resolveAddressTypeId();
185
+
186
+ const contacts = [
187
+ values.email && emailTypeId
188
+ ? {
189
+ value: values.email.trim(),
190
+ is_primary: true,
191
+ contact_type_id: emailTypeId,
192
+ }
193
+ : null,
194
+ values.phone && phoneTypeId
195
+ ? {
196
+ value: values.phone.trim(),
197
+ is_primary: true,
198
+ contact_type_id: phoneTypeId,
199
+ }
200
+ : null,
201
+ ].filter(Boolean);
202
+
203
+ const documents = values.document?.trim()
204
+ ? [
205
+ {
206
+ value: values.document.trim(),
207
+ document_type_id: documentTypeId,
208
+ },
209
+ ]
210
+ : [];
211
+
212
+ const addresses =
213
+ values.line1 && values.city && values.state && addressTypeId
214
+ ? [
215
+ {
216
+ line1: values.line1.trim(),
217
+ city: values.city.trim(),
218
+ state: values.state.trim(),
219
+ is_primary: true,
220
+ address_type_id: addressTypeId,
221
+ },
222
+ ]
223
+ : [];
224
+
225
+ await request({
226
+ url: `/person/${personId}`,
227
+ method: 'PATCH',
228
+ data: {
229
+ name: values.name,
230
+ type: values.type,
231
+ status: 'active',
232
+ contacts,
233
+ documents,
234
+ addresses,
235
+ },
236
+ });
237
+
238
+ onCreated({ id: personId, name: values.name });
239
+ form.reset();
240
+ onOpenChange(false);
241
+ showToastHandler?.('success', `${entityLabel} criado com sucesso`);
242
+ } catch {
243
+ showToastHandler?.('error', `Não foi possível criar ${entityLabel}`);
244
+ }
245
+ };
246
+
247
+ return (
248
+ <Sheet
249
+ open={open}
250
+ onOpenChange={(nextOpen) => {
251
+ onOpenChange(nextOpen);
252
+ if (!nextOpen) {
253
+ form.reset();
254
+ }
255
+ }}
256
+ >
257
+ <SheetContent className="w-full overflow-y-auto sm:max-w-xl">
258
+ <SheetHeader>
259
+ <SheetTitle>Novo {entityLabel}</SheetTitle>
260
+ <SheetDescription>
261
+ Apenas nome e tipo são obrigatórios. Você pode completar os demais
262
+ dados agora ou depois.
263
+ </SheetDescription>
264
+ </SheetHeader>
265
+
266
+ <Form {...form}>
267
+ <form
268
+ className="space-y-4 p-4"
269
+ onSubmit={form.handleSubmit(handleSubmit)}
270
+ >
271
+ <FormField
272
+ control={form.control}
273
+ name="name"
274
+ render={({ field }) => (
275
+ <FormItem>
276
+ <FormLabel>Nome</FormLabel>
277
+ <FormControl>
278
+ <Input placeholder={`Nome do ${entityLabel}`} {...field} />
279
+ </FormControl>
280
+ <FormMessage />
281
+ </FormItem>
282
+ )}
283
+ />
284
+
285
+ <FormField
286
+ control={form.control}
287
+ name="type"
288
+ render={({ field }) => (
289
+ <FormItem>
290
+ <FormLabel>Tipo</FormLabel>
291
+ <Select value={field.value} onValueChange={field.onChange}>
292
+ <FormControl>
293
+ <SelectTrigger>
294
+ <SelectValue placeholder="Selecione" />
295
+ </SelectTrigger>
296
+ </FormControl>
297
+ <SelectContent>
298
+ <SelectItem value="individual">Pessoa Física</SelectItem>
299
+ <SelectItem value="company">Pessoa Jurídica</SelectItem>
300
+ </SelectContent>
301
+ </Select>
302
+ <FormMessage />
303
+ </FormItem>
304
+ )}
305
+ />
306
+
307
+ <div className="grid grid-cols-1 gap-4 sm:grid-cols-2">
308
+ <FormField
309
+ control={form.control}
310
+ name="document"
311
+ render={({ field }) => (
312
+ <FormItem>
313
+ <FormLabel>
314
+ {selectedType === 'individual'
315
+ ? 'CPF (opcional)'
316
+ : 'CNPJ (opcional)'}
317
+ </FormLabel>
318
+ <FormControl>
319
+ <Input
320
+ placeholder={
321
+ selectedType === 'individual'
322
+ ? '000.000.000-00'
323
+ : '00.000.000/0000-00'
324
+ }
325
+ {...field}
326
+ value={field.value || ''}
327
+ />
328
+ </FormControl>
329
+ <FormMessage />
330
+ </FormItem>
331
+ )}
332
+ />
333
+
334
+ <FormField
335
+ control={form.control}
336
+ name="email"
337
+ render={({ field }) => (
338
+ <FormItem>
339
+ <FormLabel>E-mail (opcional)</FormLabel>
340
+ <FormControl>
341
+ <Input
342
+ placeholder={`${entityLabel}@empresa.com`}
343
+ {...field}
344
+ value={field.value || ''}
345
+ />
346
+ </FormControl>
347
+ <FormMessage />
348
+ </FormItem>
349
+ )}
350
+ />
351
+ </div>
352
+
353
+ <FormField
354
+ control={form.control}
355
+ name="phone"
356
+ render={({ field }) => (
357
+ <FormItem>
358
+ <FormLabel>Telefone (opcional)</FormLabel>
359
+ <FormControl>
360
+ <Input
361
+ placeholder="(11) 99999-9999"
362
+ {...field}
363
+ value={field.value || ''}
364
+ />
365
+ </FormControl>
366
+ <FormMessage />
367
+ </FormItem>
368
+ )}
369
+ />
370
+
371
+ <div className="rounded-md border p-3">
372
+ <p className="mb-3 text-sm font-medium">Endereço (opcional)</p>
373
+ <div className="grid grid-cols-1 gap-3 sm:grid-cols-2">
374
+ <FormField
375
+ control={form.control}
376
+ name="line1"
377
+ render={({ field }) => (
378
+ <FormItem className="sm:col-span-2">
379
+ <FormControl>
380
+ <Input
381
+ placeholder="Rua, número, complemento"
382
+ {...field}
383
+ value={field.value || ''}
384
+ />
385
+ </FormControl>
386
+ <FormMessage />
387
+ </FormItem>
388
+ )}
389
+ />
390
+
391
+ <FormField
392
+ control={form.control}
393
+ name="city"
394
+ render={({ field }) => (
395
+ <FormItem>
396
+ <FormControl>
397
+ <Input
398
+ placeholder="Cidade"
399
+ {...field}
400
+ value={field.value || ''}
401
+ />
402
+ </FormControl>
403
+ <FormMessage />
404
+ </FormItem>
405
+ )}
406
+ />
407
+
408
+ <FormField
409
+ control={form.control}
410
+ name="state"
411
+ render={({ field }) => (
412
+ <FormItem>
413
+ <FormControl>
414
+ <Input
415
+ placeholder="UF"
416
+ {...field}
417
+ value={field.value || ''}
418
+ />
419
+ </FormControl>
420
+ <FormMessage />
421
+ </FormItem>
422
+ )}
423
+ />
424
+ </div>
425
+ </div>
426
+
427
+ <div className="flex justify-end gap-2">
428
+ <Button
429
+ type="button"
430
+ variant="outline"
431
+ onClick={() => onOpenChange(false)}
432
+ >
433
+ Cancelar
434
+ </Button>
435
+ <Button type="submit" disabled={form.formState.isSubmitting}>
436
+ Salvar {entityLabel}
437
+ </Button>
438
+ </div>
439
+ </form>
440
+ </Form>
441
+ </SheetContent>
442
+ </Sheet>
443
+ );
444
+ }
445
+
446
+ export function PersonFieldWithCreate<TFieldValues extends FieldValues>({
447
+ form,
448
+ name,
449
+ label,
450
+ entityLabel,
451
+ selectPlaceholder,
452
+ }: {
453
+ form: UseFormReturn<TFieldValues>;
454
+ name: Path<TFieldValues>;
455
+ label: string;
456
+ entityLabel: string;
457
+ selectPlaceholder: string;
458
+ }) {
459
+ const { request } = useApp();
460
+ const [personOpen, setPersonOpen] = useState(false);
461
+ const [personSearch, setPersonSearch] = useState('');
462
+ const [debouncedPersonSearch, setDebouncedPersonSearch] = useState('');
463
+ const [createPersonOpen, setCreatePersonOpen] = useState(false);
464
+ const [selectedPersonLabel, setSelectedPersonLabel] = useState('');
465
+
466
+ useEffect(() => {
467
+ const timeout = setTimeout(() => {
468
+ setDebouncedPersonSearch(personSearch);
469
+ }, 300);
470
+
471
+ return () => clearTimeout(timeout);
472
+ }, [personSearch]);
473
+
474
+ const { data: personOptionsData = [], isLoading: isLoadingPersons } =
475
+ useQuery<PersonOption[]>({
476
+ queryKey: [
477
+ 'person-autocomplete-generic',
478
+ entityLabel,
479
+ debouncedPersonSearch,
480
+ ],
481
+ queryFn: async () => {
482
+ const params = new URLSearchParams();
483
+ params.set('page', '1');
484
+ params.set('pageSize', '20');
485
+ if (debouncedPersonSearch.trim()) {
486
+ params.set('search', debouncedPersonSearch.trim());
487
+ }
488
+
489
+ const response = await request<any>({
490
+ url: `/person?${params.toString()}`,
491
+ method: 'GET',
492
+ });
493
+
494
+ const payload = response?.data;
495
+ if (Array.isArray(payload?.data)) {
496
+ return payload.data as PersonOption[];
497
+ }
498
+
499
+ if (Array.isArray(payload)) {
500
+ return payload as PersonOption[];
501
+ }
502
+
503
+ return [];
504
+ },
505
+ placeholderData: (old) => old ?? [],
506
+ });
507
+
508
+ return (
509
+ <>
510
+ <FormField
511
+ control={form.control}
512
+ name={name}
513
+ render={({ field }) => (
514
+ <FormItem>
515
+ <FormLabel>{label}</FormLabel>
516
+ <div className="flex items-center gap-2">
517
+ <Popover open={personOpen} onOpenChange={setPersonOpen}>
518
+ <PopoverTrigger asChild>
519
+ <FormControl>
520
+ <Button
521
+ type="button"
522
+ variant="outline"
523
+ role="combobox"
524
+ className="w-full justify-between"
525
+ >
526
+ {field.value
527
+ ? (personOptionsData.find(
528
+ (person) =>
529
+ String(person.id) === String(field.value)
530
+ )?.name ??
531
+ selectedPersonLabel ??
532
+ `ID #${String(field.value)}`)
533
+ : selectPlaceholder}
534
+ <ChevronsUpDown className="ml-2 h-4 w-4 shrink-0 opacity-50" />
535
+ </Button>
536
+ </FormControl>
537
+ </PopoverTrigger>
538
+ <PopoverContent
539
+ className="p-0"
540
+ style={{ width: 'var(--radix-popover-trigger-width)' }}
541
+ >
542
+ <Command shouldFilter={false}>
543
+ <CommandInput
544
+ placeholder="Digite para buscar pessoa..."
545
+ value={personSearch}
546
+ onValueChange={setPersonSearch}
547
+ />
548
+ <CommandList>
549
+ <CommandEmpty>
550
+ {isLoadingPersons ? (
551
+ 'Buscando pessoas...'
552
+ ) : (
553
+ <div className="space-y-2 p-2 text-center">
554
+ <p className="text-sm text-muted-foreground">
555
+ Nenhuma pessoa encontrada
556
+ </p>
557
+ <Button
558
+ type="button"
559
+ variant="outline"
560
+ className="w-full"
561
+ onClick={() => {
562
+ setPersonOpen(false);
563
+ setCreatePersonOpen(true);
564
+ }}
565
+ >
566
+ Criar novo cadastro
567
+ </Button>
568
+ </div>
569
+ )}
570
+ </CommandEmpty>
571
+ <CommandGroup>
572
+ {personOptionsData.map((person) => (
573
+ <CommandItem
574
+ key={String(person.id)}
575
+ value={`${person.name}-${person.id}`}
576
+ onSelect={() => {
577
+ field.onChange(String(person.id));
578
+ setSelectedPersonLabel(person.name);
579
+ setPersonOpen(false);
580
+ }}
581
+ >
582
+ {person.name}
583
+ </CommandItem>
584
+ ))}
585
+ </CommandGroup>
586
+ </CommandList>
587
+ </Command>
588
+ </PopoverContent>
589
+ </Popover>
590
+
591
+ {field.value ? (
592
+ <Button
593
+ type="button"
594
+ variant="outline"
595
+ size="icon"
596
+ onClick={() => {
597
+ field.onChange('');
598
+ setPersonSearch('');
599
+ setSelectedPersonLabel('');
600
+ setPersonOpen(false);
601
+ }}
602
+ >
603
+ <X className="h-4 w-4" />
604
+ </Button>
605
+ ) : null}
606
+ </div>
607
+ <FormMessage />
608
+ </FormItem>
609
+ )}
610
+ />
611
+
612
+ <CreatePersonSheet
613
+ open={createPersonOpen}
614
+ onOpenChange={setCreatePersonOpen}
615
+ entityLabel={entityLabel}
616
+ onCreated={(person) => {
617
+ form.setValue(name, String(person.id) as any, {
618
+ shouldValidate: true,
619
+ });
620
+ setSelectedPersonLabel(person.name);
621
+ setPersonSearch(person.name);
622
+ setCreatePersonOpen(false);
623
+ }}
624
+ />
625
+ </>
626
+ );
627
+ }