@greatapps/common 1.1.290 → 1.1.292

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.
@@ -3,7 +3,7 @@
3
3
  import { UseFormReturn } from 'react-hook-form';
4
4
  import { FormField } from '../../ui/form/FormField';
5
5
  import { SelectField } from '../../ui/form/SelectField';
6
- import { formatCPF, formatPostalCode } from '../../../utils/format/masks';
6
+ import { formatCPF, formatCNPJ, formatPostalCode } from '../../../utils/format/masks';
7
7
  import z from 'zod';
8
8
  import { CardCvcElement, CardExpiryElement, CardNumberElement } from '@stripe/react-stripe-js';
9
9
 
@@ -20,18 +20,39 @@ const stripeElementOptions = {
20
20
  },
21
21
  };
22
22
 
23
- export const cardFormSchema = z.object({
24
- name: z.string().min(1, 'Nome é obrigatório'),
25
- number: z.string().min(1, 'Número do cartão é obrigatório'),
26
- expiry: z.string().min(1, 'Data de validade é obrigatória'),
27
- cvv: z.string().min(1, 'Código de segurança é obrigatório'),
28
- country: z.string().min(1, 'País é obrigatório'),
29
- postalCode: z.string().optional(),
30
- cpf: z.string().min(14, 'CPF é obrigatório'),
31
- });
23
+ export const cardFormSchema = z
24
+ .object({
25
+ name: z.string().min(1, 'Nome é obrigatório'),
26
+ number: z.string().min(1, 'Número do cartão é obrigatório'),
27
+ expiry: z.string().min(1, 'Data de validade é obrigatória'),
28
+ cvv: z.string().min(1, 'Código de segurança é obrigatório'),
29
+ country: z.string().min(1, 'País é obrigatório'),
30
+ personType: z.enum(['pf', 'pj']),
31
+ cpf: z.string().optional(),
32
+ cnpj: z.string().optional(),
33
+ fullName: z.string().min(1, 'Nome completo é obrigatório'),
34
+ cep: z.string().min(9, 'CEP é obrigatório'),
35
+ street: z.string().min(1, 'Endereço é obrigatório'),
36
+ streetNumber: z.string().min(1, 'Número é obrigatório'),
37
+ city: z.string().min(1, 'Cidade é obrigatória'),
38
+ state: z.string().min(1, 'UF é obrigatório'),
39
+ complement: z.string().optional(),
40
+ })
41
+ .refine(
42
+ (data) => {
43
+ if (data.personType === 'pf') return !!data.cpf && data.cpf.length >= 14;
44
+ return !!data.cnpj && data.cnpj.length >= 18;
45
+ },
46
+ {
47
+ message: 'Documento é obrigatório',
48
+ path: ['cpf'],
49
+ }
50
+ );
32
51
 
33
52
  export type CardFormData = z.infer<typeof cardFormSchema>;
34
53
 
54
+ export const STEP1_FIELDS = ['name', 'number', 'expiry', 'cvv', 'country', 'personType', 'cpf', 'cnpj'] as const;
55
+
35
56
  type CardFormFieldsProps = {
36
57
  readonly form: UseFormReturn<CardFormData>;
37
58
  };
@@ -44,6 +65,8 @@ export function CardFormFields({ form }: CardFormFieldsProps) {
44
65
  formState: { errors },
45
66
  } = form;
46
67
 
68
+ const personType = watch('personType');
69
+
47
70
  return (
48
71
  <div className="flex flex-col gap-5">
49
72
  <FormField
@@ -55,9 +78,7 @@ export function CardFormFields({ form }: CardFormFieldsProps) {
55
78
  />
56
79
 
57
80
  <div className="flex flex-col gap-1.5">
58
- <label className="paragraph-xsmall-semibold text-zinc-600">
59
- Número do cartão
60
- </label>
81
+ <label className="paragraph-xsmall-semibold text-zinc-600">Número do cartão</label>
61
82
  <div className="h-10 px-3 flex items-center w-full border border-zinc-200 rounded-lg bg-white transition-colors focus-within:border-zinc-400 relative">
62
83
  <div className="w-full">
63
84
  <CardNumberElement
@@ -75,9 +96,7 @@ export function CardFormFields({ form }: CardFormFieldsProps) {
75
96
 
76
97
  <div className="flex gap-4">
77
98
  <div className="flex-1 flex flex-col gap-1.5">
78
- <label className="paragraph-xsmall-semibold text-zinc-600">
79
- Data de validade
80
- </label>
99
+ <label className="paragraph-xsmall-semibold text-zinc-600">Data de validade</label>
81
100
  <div className="h-10 px-3 flex items-center w-full border border-zinc-200 rounded-lg bg-white transition-colors focus-within:border-zinc-400">
82
101
  <div className="w-full">
83
102
  <CardExpiryElement
@@ -94,9 +113,7 @@ export function CardFormFields({ form }: CardFormFieldsProps) {
94
113
  </div>
95
114
 
96
115
  <div className="flex-1 flex flex-col gap-1.5">
97
- <label className="paragraph-xsmall-semibold text-zinc-600">
98
- CVC
99
- </label>
116
+ <label className="paragraph-xsmall-semibold text-zinc-600">CVC</label>
100
117
  <div className="h-10 px-3 flex items-center w-full border border-zinc-200 rounded-lg bg-white transition-colors focus-within:border-zinc-400">
101
118
  <div className="w-full">
102
119
  <CardCvcElement
@@ -113,45 +130,148 @@ export function CardFormFields({ form }: CardFormFieldsProps) {
113
130
  </div>
114
131
  </div>
115
132
 
133
+ <SelectField
134
+ label="País"
135
+ placeholder="Selecione"
136
+ value={watch('country')}
137
+ onChange={(value) => setValue('country', value as string)}
138
+ options={[
139
+ { value: 'BR', label: 'Brasil' },
140
+ { value: 'ES', label: 'Espanha' },
141
+ { value: 'US', label: 'Estados Unidos' },
142
+ ]}
143
+ />
144
+
116
145
  <div className="flex gap-4">
117
146
  <SelectField
118
- label="País"
147
+ label="Tipo de pessoa"
119
148
  placeholder="Selecione"
120
- value={watch('country')}
121
- onChange={(value) => setValue('country', value as string)}
149
+ value={personType}
150
+ onChange={(value) => {
151
+ setValue('personType', value as 'pf' | 'pj');
152
+ setValue('cpf', '');
153
+ setValue('cnpj', '');
154
+ }}
122
155
  options={[
123
- { value: 'BR', label: 'Brasil' },
124
- { value: 'ES', label: 'Espanha' },
125
- { value: 'US', label: 'Estados Unidos' },
156
+ { value: 'pf', label: 'Pessoa física' },
157
+ { value: 'pj', label: 'Pessoa jurídica' },
126
158
  ]}
127
159
  containerClassName="flex-1"
128
160
  />
129
161
  <div className="flex-1">
130
- <FormField
131
- label="Código postal"
132
- optional
133
- placeholder=""
134
- {...register('postalCode', {
135
- onChange: (e) => {
136
- setValue('postalCode', formatPostalCode(e.target.value));
137
- },
138
- })}
139
- error={!!errors.postalCode}
140
- errorMessage={errors.postalCode?.message}
141
- />
162
+ {personType === 'pj' ? (
163
+ <FormField
164
+ label="CNPJ"
165
+ placeholder="__.___.___/____-__"
166
+ {...register('cnpj', {
167
+ onChange: (e) => {
168
+ setValue('cnpj', formatCNPJ(e.target.value));
169
+ },
170
+ })}
171
+ error={!!errors.cpf}
172
+ errorMessage={errors.cpf?.message}
173
+ />
174
+ ) : (
175
+ <FormField
176
+ label="CPF"
177
+ placeholder="___.___.___-__"
178
+ {...register('cpf', {
179
+ onChange: (e) => {
180
+ setValue('cpf', formatCPF(e.target.value));
181
+ },
182
+ })}
183
+ error={!!errors.cpf}
184
+ errorMessage={errors.cpf?.message}
185
+ />
186
+ )}
142
187
  </div>
143
188
  </div>
189
+ </div>
190
+ );
191
+ }
192
+
193
+ type BillingFormFieldsProps = {
194
+ readonly form: UseFormReturn<CardFormData>;
195
+ };
196
+
197
+ export function BillingFormFields({ form }: BillingFormFieldsProps) {
198
+ const {
199
+ register,
200
+ setValue,
201
+ formState: { errors },
202
+ } = form;
203
+
204
+ return (
205
+ <div className="flex flex-col gap-5">
206
+ <FormField
207
+ label="Nome completo"
208
+ placeholder="Digite aqui"
209
+ {...register('fullName')}
210
+ error={!!errors.fullName}
211
+ errorMessage={errors.fullName?.message}
212
+ />
144
213
 
145
214
  <FormField
146
- label="CPF"
147
- placeholder="___.___.___-__"
148
- {...register('cpf', {
215
+ label="CEP"
216
+ placeholder="_____-___"
217
+ {...register('cep', {
149
218
  onChange: (e) => {
150
- setValue('cpf', formatCPF(e.target.value));
219
+ setValue('cep', formatPostalCode(e.target.value));
151
220
  },
152
221
  })}
153
- error={!!errors.cpf}
154
- errorMessage={errors.cpf?.message}
222
+ error={!!errors.cep}
223
+ errorMessage={errors.cep?.message}
224
+ />
225
+
226
+ <div className="flex gap-4">
227
+ <div className="flex-[2]">
228
+ <FormField
229
+ label="Endereço"
230
+ placeholder=""
231
+ {...register('street')}
232
+ error={!!errors.street}
233
+ errorMessage={errors.street?.message}
234
+ />
235
+ </div>
236
+ <div className="flex-1">
237
+ <FormField
238
+ label="Número"
239
+ placeholder=""
240
+ {...register('streetNumber')}
241
+ error={!!errors.streetNumber}
242
+ errorMessage={errors.streetNumber?.message}
243
+ />
244
+ </div>
245
+ </div>
246
+
247
+ <div className="flex gap-4">
248
+ <div className="flex-1">
249
+ <FormField
250
+ label="Cidade"
251
+ placeholder=""
252
+ {...register('city')}
253
+ error={!!errors.city}
254
+ errorMessage={errors.city?.message}
255
+ />
256
+ </div>
257
+ <div className="flex-1">
258
+ <FormField
259
+ label="UF"
260
+ placeholder=""
261
+ {...register('state')}
262
+ error={!!errors.state}
263
+ errorMessage={errors.state?.message}
264
+ />
265
+ </div>
266
+ </div>
267
+
268
+ <FormField
269
+ label="Complemento"
270
+ optional
271
+ placeholder=""
272
+ {...register('complement')}
273
+ error={!!errors.complement}
274
+ errorMessage={errors.complement?.message}
155
275
  />
156
276
  </div>
157
277
  );
package/src/index.ts CHANGED
@@ -312,8 +312,10 @@ export {
312
312
  formatTimer,
313
313
  formatFullName,
314
314
  formatCPF,
315
+ formatCNPJ,
315
316
  formatCardNumber,
316
317
  } from "./utils/format/masks";
318
+ export { BR_STATE_OPTIONS } from "./utils/constants/br-states";
317
319
  export type { TimezoneOption } from "./modules/accounts/services/timezone.service";
318
320
  export {
319
321
  buildLocaleOptions,
@@ -146,6 +146,16 @@ export interface UpdateAccountRequest {
146
146
  currency?: string;
147
147
  timezone?: string;
148
148
  bussiness_type?: number;
149
+ financial_document_type?: number;
150
+ financial_document?: string;
151
+ financial_name?: string;
152
+ zipcode?: string;
153
+ address?: string;
154
+ address_number?: string;
155
+ address_complement?: string;
156
+ neighborhood?: string;
157
+ city?: string;
158
+ state?: string;
149
159
  }
150
160
 
151
161
  export interface UpdateAccountResponse {
@@ -0,0 +1,29 @@
1
+ export const BR_STATE_OPTIONS = [
2
+ { value: 'AC', label: 'AC' },
3
+ { value: 'AL', label: 'AL' },
4
+ { value: 'AP', label: 'AP' },
5
+ { value: 'AM', label: 'AM' },
6
+ { value: 'BA', label: 'BA' },
7
+ { value: 'CE', label: 'CE' },
8
+ { value: 'DF', label: 'DF' },
9
+ { value: 'ES', label: 'ES' },
10
+ { value: 'GO', label: 'GO' },
11
+ { value: 'MA', label: 'MA' },
12
+ { value: 'MT', label: 'MT' },
13
+ { value: 'MS', label: 'MS' },
14
+ { value: 'MG', label: 'MG' },
15
+ { value: 'PA', label: 'PA' },
16
+ { value: 'PB', label: 'PB' },
17
+ { value: 'PR', label: 'PR' },
18
+ { value: 'PE', label: 'PE' },
19
+ { value: 'PI', label: 'PI' },
20
+ { value: 'RJ', label: 'RJ' },
21
+ { value: 'RN', label: 'RN' },
22
+ { value: 'RS', label: 'RS' },
23
+ { value: 'RO', label: 'RO' },
24
+ { value: 'RR', label: 'RR' },
25
+ { value: 'SC', label: 'SC' },
26
+ { value: 'SP', label: 'SP' },
27
+ { value: 'SE', label: 'SE' },
28
+ { value: 'TO', label: 'TO' },
29
+ ];
@@ -32,6 +32,17 @@ export function formatPostalCode(value: string): string {
32
32
  return `${numbers.slice(0, 5)}-${numbers.slice(5, 8)}`;
33
33
  }
34
34
 
35
+ export function formatCNPJ(value: string): string {
36
+ const numbers = value.replace(/\D/g, '');
37
+ if (numbers.length <= 2) return numbers;
38
+ if (numbers.length <= 5) return `${numbers.slice(0, 2)}.${numbers.slice(2)}`;
39
+ if (numbers.length <= 8)
40
+ return `${numbers.slice(0, 2)}.${numbers.slice(2, 5)}.${numbers.slice(5)}`;
41
+ if (numbers.length <= 12)
42
+ return `${numbers.slice(0, 2)}.${numbers.slice(2, 5)}.${numbers.slice(5, 8)}/${numbers.slice(8)}`;
43
+ return `${numbers.slice(0, 2)}.${numbers.slice(2, 5)}.${numbers.slice(5, 8)}/${numbers.slice(8, 12)}-${numbers.slice(12, 14)}`;
44
+ }
45
+
35
46
  export function formatPhone(value: string): string {
36
47
  const numbers = value.replace(/\D/g, '').substring(0, 11);
37
48
  if (numbers.length <= 2) return numbers;