@hed-hog/finance 0.0.266 → 0.0.274

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.
@@ -37,36 +37,29 @@ import {
37
37
  SheetHeader,
38
38
  SheetTitle,
39
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, Plus, X } from 'lucide-react';
43
- import { useTranslations } from 'next-intl';
44
- import { useEffect, useRef, useState } from 'react';
45
- import { FieldValues, Path, UseFormReturn, useForm } from 'react-hook-form';
46
- import { z } from 'zod';
40
+ import { useApp, useQuery } from '@hed-hog/next-app-provider';
41
+ import { zodResolver } from '@hookform/resolvers/zod';
42
+ import { ChevronsUpDown, Plus, X } from 'lucide-react';
43
+ import { useTranslations } from 'next-intl';
44
+ import { useEffect, useMemo, useRef, useState } from 'react';
45
+ import { FieldValues, Path, UseFormReturn, useForm } from 'react-hook-form';
46
+ import { z } from 'zod';
47
47
 
48
48
  type PersonOption = {
49
49
  id: number | string;
50
50
  name: string;
51
51
  };
52
52
 
53
- const createPersonSchema = z.object({
54
- name: z.string().trim().min(2, 'Nome é obrigatório'),
55
- type: z.enum(['individual', 'company']),
56
- email: z
57
- .string()
58
- .trim()
59
- .email('E-mail inválido')
60
- .optional()
61
- .or(z.literal('')),
62
- phone: z.string().trim().optional(),
63
- document: z.string().trim().optional(),
64
- line1: z.string().optional(),
65
- city: z.string().optional(),
66
- state: z.string().optional(),
67
- });
68
-
69
- type CreatePersonValues = z.infer<typeof createPersonSchema>;
53
+ type CreatePersonValues = {
54
+ name: string;
55
+ type: 'individual' | 'company';
56
+ email?: string;
57
+ phone?: string;
58
+ document?: string;
59
+ line1?: string;
60
+ city?: string;
61
+ state?: string;
62
+ };
70
63
 
71
64
  function CreatePersonSheet({
72
65
  open,
@@ -79,8 +72,33 @@ function CreatePersonSheet({
79
72
  onCreated: (person: PersonOption) => void;
80
73
  entityLabel: string;
81
74
  }) {
82
- const { request, showToastHandler, currentLocaleCode } = useApp();
83
- const t = useTranslations('finance.PersonFieldWithCreate');
75
+ const { request, showToastHandler, currentLocaleCode, getSettingValue } =
76
+ useApp();
77
+ const t = useTranslations('finance.PersonFieldWithCreate');
78
+ const allowCompanyRegistration =
79
+ getSettingValue('contact-allow-company-registration') !== false;
80
+
81
+ const createPersonSchema = useMemo(
82
+ () =>
83
+ z.object({
84
+ name: z.string().trim().min(2, 'Nome é obrigatório'),
85
+ type: allowCompanyRegistration
86
+ ? z.enum(['individual', 'company'])
87
+ : z.literal('individual'),
88
+ email: z
89
+ .string()
90
+ .trim()
91
+ .email('E-mail inválido')
92
+ .optional()
93
+ .or(z.literal('')),
94
+ phone: z.string().trim().optional(),
95
+ document: z.string().trim().optional(),
96
+ line1: z.string().optional(),
97
+ city: z.string().optional(),
98
+ state: z.string().optional(),
99
+ }),
100
+ [allowCompanyRegistration]
101
+ );
84
102
 
85
103
  const form = useForm<CreatePersonValues>({
86
104
  resolver: zodResolver(createPersonSchema),
@@ -96,7 +114,13 @@ function CreatePersonSheet({
96
114
  },
97
115
  });
98
116
 
99
- const selectedType = form.watch('type');
117
+ const selectedType = allowCompanyRegistration ? form.watch('type') : 'individual';
118
+
119
+ useEffect(() => {
120
+ if (!allowCompanyRegistration) {
121
+ form.setValue('type', 'individual');
122
+ }
123
+ }, [allowCompanyRegistration, form]);
100
124
 
101
125
  const { data: contactTypes = [] } = useQuery<any[]>({
102
126
  queryKey: ['person-field-contact-types', currentLocaleCode],
@@ -110,19 +134,7 @@ function CreatePersonSheet({
110
134
  placeholderData: (old) => old ?? [],
111
135
  });
112
136
 
113
- const { data: addressTypes = [] } = useQuery<any[]>({
114
- queryKey: ['person-field-address-types', currentLocaleCode],
115
- queryFn: async () => {
116
- const response = await request<any>({
117
- url: '/person-address-type?pageSize=100',
118
- method: 'GET',
119
- });
120
- return response?.data?.data || [];
121
- },
122
- placeholderData: (old) => old ?? [],
123
- });
124
-
125
- const { data: documentTypes = [] } = useQuery<any[]>({
137
+ const { data: documentTypes = [] } = useQuery<any[]>({
126
138
  queryKey: ['person-field-document-types', currentLocaleCode],
127
139
  queryFn: async () => {
128
140
  const response = await request<any>({
@@ -150,24 +162,21 @@ function CreatePersonSheet({
150
162
  return found?.document_type_id || documentTypes[0]?.document_type_id;
151
163
  };
152
164
 
153
- const resolveAddressTypeId = () => {
154
- const home = addressTypes.find(
155
- (item) => String(item.code).toUpperCase() === 'HOME'
156
- );
157
- return home?.address_type_id || addressTypes[0]?.address_type_id;
158
- };
159
-
160
- const handleSubmit = async (values: CreatePersonValues) => {
161
- try {
162
- const createResponse = await request<any>({
163
- url: '/person',
164
- method: 'POST',
165
- data: {
166
- name: values.name,
167
- type: values.type,
168
- status: 'active',
169
- },
170
- });
165
+ const resolveAddressType = () => 'residential';
166
+
167
+ const handleSubmit = async (values: CreatePersonValues) => {
168
+ try {
169
+ const normalizedType = allowCompanyRegistration ? values.type : 'individual';
170
+
171
+ const createResponse = await request<any>({
172
+ url: '/person',
173
+ method: 'POST',
174
+ data: {
175
+ name: values.name,
176
+ type: normalizedType,
177
+ status: 'active',
178
+ },
179
+ });
171
180
 
172
181
  const personId = Number(
173
182
  createResponse?.data?.id ?? createResponse?.data?.data?.id
@@ -178,12 +187,12 @@ function CreatePersonSheet({
178
187
  }
179
188
 
180
189
  const emailTypeId = resolveContactTypeId('EMAIL', 0);
181
- const phoneTypeId =
182
- resolveContactTypeId('PHONE', 1) || resolveContactTypeId('MOBILE', 1);
183
- const documentTypeId = resolveDocumentTypeId(
184
- values.type === 'individual' ? 'CPF' : 'CNPJ'
185
- );
186
- const addressTypeId = resolveAddressTypeId();
190
+ const phoneTypeId =
191
+ resolveContactTypeId('PHONE', 1) || resolveContactTypeId('MOBILE', 1);
192
+ const documentTypeId = resolveDocumentTypeId(
193
+ normalizedType === 'individual' ? 'CPF' : 'CNPJ'
194
+ );
195
+ const addressType = resolveAddressType();
187
196
 
188
197
  const contacts = [
189
198
  values.email && emailTypeId
@@ -211,28 +220,28 @@ function CreatePersonSheet({
211
220
  ]
212
221
  : [];
213
222
 
214
- const addresses =
215
- values.line1 && values.city && values.state && addressTypeId
216
- ? [
217
- {
218
- line1: values.line1.trim(),
219
- city: values.city.trim(),
220
- state: values.state.trim(),
221
- is_primary: true,
222
- address_type_id: addressTypeId,
223
- },
224
- ]
225
- : [];
223
+ const addresses =
224
+ values.line1 && values.city && values.state
225
+ ? [
226
+ {
227
+ line1: values.line1.trim(),
228
+ city: values.city.trim(),
229
+ state: values.state.trim(),
230
+ is_primary: true,
231
+ address_type: addressType,
232
+ },
233
+ ]
234
+ : [];
226
235
 
227
236
  await request({
228
237
  url: `/person/${personId}`,
229
238
  method: 'PATCH',
230
- data: {
231
- name: values.name,
232
- type: values.type,
233
- status: 'active',
234
- contacts,
235
- documents,
239
+ data: {
240
+ name: values.name,
241
+ type: normalizedType,
242
+ status: 'active',
243
+ contacts,
244
+ documents,
236
245
  addresses,
237
246
  },
238
247
  });
@@ -263,10 +272,14 @@ function CreatePersonSheet({
263
272
  className="w-full overflow-y-auto sm:max-w-xl"
264
273
  onCloseAutoFocus={(event) => event.preventDefault()}
265
274
  >
266
- <SheetHeader>
267
- <SheetTitle>{t('sheet.title', { entityLabel })}</SheetTitle>
268
- <SheetDescription>{t('sheet.description')}</SheetDescription>
269
- </SheetHeader>
275
+ <SheetHeader>
276
+ <SheetTitle>{t('sheet.title', { entityLabel })}</SheetTitle>
277
+ <SheetDescription>
278
+ {allowCompanyRegistration
279
+ ? t('sheet.description')
280
+ : t('sheet.descriptionIndividualOnly')}
281
+ </SheetDescription>
282
+ </SheetHeader>
270
283
 
271
284
  <Form {...form}>
272
285
  <div className="space-y-4 p-4">
@@ -287,31 +300,33 @@ function CreatePersonSheet({
287
300
  )}
288
301
  />
289
302
 
290
- <FormField
291
- control={form.control}
292
- name="type"
293
- render={({ field }) => (
294
- <FormItem>
295
- <FormLabel>{t('fields.type')}</FormLabel>
296
- <Select value={field.value} onValueChange={field.onChange}>
297
- <FormControl>
298
- <SelectTrigger>
299
- <SelectValue placeholder={t('common.select')} />
300
- </SelectTrigger>
301
- </FormControl>
302
- <SelectContent>
303
- <SelectItem value="individual">
304
- {t('types.individual')}
305
- </SelectItem>
306
- <SelectItem value="company">
307
- {t('types.company')}
308
- </SelectItem>
309
- </SelectContent>
310
- </Select>
311
- <FormMessage />
312
- </FormItem>
313
- )}
314
- />
303
+ {allowCompanyRegistration ? (
304
+ <FormField
305
+ control={form.control}
306
+ name="type"
307
+ render={({ field }) => (
308
+ <FormItem>
309
+ <FormLabel>{t('fields.type')}</FormLabel>
310
+ <Select value={field.value} onValueChange={field.onChange}>
311
+ <FormControl>
312
+ <SelectTrigger>
313
+ <SelectValue placeholder={t('common.select')} />
314
+ </SelectTrigger>
315
+ </FormControl>
316
+ <SelectContent>
317
+ <SelectItem value="individual">
318
+ {t('types.individual')}
319
+ </SelectItem>
320
+ <SelectItem value="company">
321
+ {t('types.company')}
322
+ </SelectItem>
323
+ </SelectContent>
324
+ </Select>
325
+ <FormMessage />
326
+ </FormItem>
327
+ )}
328
+ />
329
+ ) : null}
315
330
 
316
331
  <div className="grid grid-cols-1 gap-4 sm:grid-cols-2">
317
332
  <FormField
@@ -5,7 +5,7 @@ import {
5
5
  CostCenterFieldWithCreate,
6
6
  } from '@/app/(app)/(libraries)/finance/_components/finance-entity-field-with-create';
7
7
  import { FinanceTitleActionsMenu } from '@/app/(app)/(libraries)/finance/_components/finance-title-actions-menu';
8
- import { PersonFieldWithCreate } from '@/app/(app)/(libraries)/finance/_components/person-field-with-create';
8
+ import { PersonFieldWithCreate } from '@/app/(app)/(libraries)/contact/person/_components/person-field-with-create';
9
9
  import { Page, PageHeader } from '@/components/entity-list';
10
10
  import { Button } from '@/components/ui/button';
11
11
  import { Checkbox } from '@/components/ui/checkbox';
@@ -4,7 +4,7 @@ import {
4
4
  CategoryFieldWithCreate,
5
5
  CostCenterFieldWithCreate,
6
6
  } from '@/app/(app)/(libraries)/finance/_components/finance-entity-field-with-create';
7
- import { PersonFieldWithCreate } from '@/app/(app)/(libraries)/finance/_components/person-field-with-create';
7
+ import { PersonFieldWithCreate } from '@/app/(app)/(libraries)/contact/person/_components/person-field-with-create';
8
8
  import { Page, PageHeader } from '@/components/entity-list';
9
9
  import { Badge } from '@/components/ui/badge';
10
10
  import { Button } from '@/components/ui/button';
@@ -100,10 +100,11 @@
100
100
  }
101
101
  },
102
102
  "PersonFieldWithCreate": {
103
- "sheet": {
104
- "title": "New {entityLabel}",
105
- "description": "Only name and type are required. You can complete the remaining fields now or later."
106
- },
103
+ "sheet": {
104
+ "title": "New {entityLabel}",
105
+ "description": "Only name and type are required. You can complete the remaining fields now or later.",
106
+ "descriptionIndividualOnly": "Only name is required. You can complete the remaining fields now or later."
107
+ },
107
108
  "common": {
108
109
  "select": "Select"
109
110
  },
@@ -100,10 +100,11 @@
100
100
  }
101
101
  },
102
102
  "PersonFieldWithCreate": {
103
- "sheet": {
104
- "title": "Novo {entityLabel}",
105
- "description": "Apenas nome e tipo são obrigatórios. Você pode completar os demais dados agora ou depois."
106
- },
103
+ "sheet": {
104
+ "title": "Novo {entityLabel}",
105
+ "description": "Apenas nome e tipo são obrigatórios. Você pode completar os demais dados agora ou depois.",
106
+ "descriptionIndividualOnly": "Apenas nome é obrigatório. Você pode completar os demais dados agora ou depois."
107
+ },
107
108
  "common": {
108
109
  "select": "Selecione"
109
110
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hed-hog/finance",
3
- "version": "0.0.266",
3
+ "version": "0.0.274",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "dependencies": {
@@ -9,14 +9,14 @@
9
9
  "@nestjs/core": "^11",
10
10
  "@nestjs/jwt": "^11",
11
11
  "@nestjs/mapped-types": "*",
12
- "@hed-hog/api-pagination": "0.0.6",
13
- "@hed-hog/contact": "0.0.266",
12
+ "@hed-hog/contact": "0.0.274",
14
13
  "@hed-hog/api-prisma": "0.0.5",
15
- "@hed-hog/api-locale": "0.0.13",
16
- "@hed-hog/tag": "0.0.266",
14
+ "@hed-hog/api-pagination": "0.0.6",
15
+ "@hed-hog/api": "0.0.4",
17
16
  "@hed-hog/api-types": "0.0.1",
18
- "@hed-hog/core": "0.0.266",
19
- "@hed-hog/api": "0.0.4"
17
+ "@hed-hog/tag": "0.0.274",
18
+ "@hed-hog/api-locale": "0.0.13",
19
+ "@hed-hog/core": "0.0.274"
20
20
  },
21
21
  "exports": {
22
22
  ".": {