@greatapps/common 1.1.795 → 1.1.797
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.
- package/dist/components/modals/billing/BillingDataForm.mjs +406 -0
- package/dist/components/modals/billing/BillingDataForm.mjs.map +1 -0
- package/dist/components/modals/billing/RequiredBillingDataModal.mjs +5 -405
- package/dist/components/modals/billing/RequiredBillingDataModal.mjs.map +1 -1
- package/dist/i18n/resolve-locale.mjs +1 -1
- package/dist/i18n/resolve-locale.mjs.map +1 -1
- package/dist/index.mjs +4 -0
- package/dist/index.mjs.map +1 -1
- package/dist/modules/ia-credits/types/ai-credits-offer.type.mjs +1 -0
- package/dist/modules/ia-credits/types/ai-credits-offer.type.mjs.map +1 -1
- package/dist/modules/whitelabel/actions/find-whitelabel.action.mjs +1 -5
- package/dist/modules/whitelabel/actions/find-whitelabel.action.mjs.map +1 -1
- package/dist/modules/whitelabel/constants/whitelabel.constants.mjs +9 -0
- package/dist/modules/whitelabel/constants/whitelabel.constants.mjs.map +1 -0
- package/dist/modules/whitelabel/services/whitelabel.service.mjs +85 -11
- package/dist/modules/whitelabel/services/whitelabel.service.mjs.map +1 -1
- package/dist/testing/msw/session.handlers.mjs +1 -0
- package/dist/testing/msw/session.handlers.mjs.map +1 -1
- package/package.json +10 -9
- package/src/components/modals/billing/BillingDataForm.tsx +489 -0
- package/src/components/modals/billing/RequiredBillingDataModal.tsx +3 -475
- package/src/i18n/resolve-locale.ts +1 -1
- package/src/index.ts +3 -0
- package/src/modules/ia-credits/types/ai-credits-offer.type.ts +1 -0
- package/src/modules/whitelabel/actions/find-whitelabel.action.ts +1 -7
- package/src/modules/whitelabel/constants/whitelabel.constants.ts +5 -0
- package/src/modules/whitelabel/services/whitelabel.service.ts +300 -209
- package/src/testing/msw/session.handlers.ts +1 -0
|
@@ -1,217 +1,16 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { Controller, useForm } from "react-hook-form";
|
|
5
|
-
import { zodResolver } from "@hookform/resolvers/zod";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useState } from "react";
|
|
6
4
|
import { useTranslations } from "next-intl";
|
|
7
|
-
import { toast } from "sonner";
|
|
8
|
-
import z from "zod";
|
|
9
5
|
import { IconFileInvoice } from "@tabler/icons-react";
|
|
10
6
|
import { Dialog, DialogContent, DialogHeader, DialogTitle } from "../../ui/overlay/Dialog";
|
|
11
|
-
import { Button } from "../../ui/buttons/Button";
|
|
12
|
-
import { FormField } from "../../ui/form/FormField";
|
|
13
|
-
import { SelectField } from "../../ui/form/SelectField";
|
|
14
|
-
import { Toast } from "../../ui/feedback/Toast";
|
|
15
7
|
import { useAuth } from "../../../providers/auth.provider";
|
|
16
|
-
import { useViaCep } from "../../../modules/accounts/hooks/useViaCep";
|
|
17
|
-
import { useUpdateBillingData } from "../../../modules/accounts/hooks/useAccountManagement";
|
|
18
8
|
import { useRequiredBillingData } from "../../../modules/accounts/hooks/use-required-billing-data.hook";
|
|
19
|
-
import {
|
|
20
|
-
import { readGeoCountry } from "../../../utils/geo-country";
|
|
21
|
-
import { BR_STATE_OPTIONS } from "../../../utils/constants/br-states";
|
|
22
|
-
import { formatCNPJ, formatCPF, formatPostalCode } from "../../../utils/format/masks";
|
|
23
|
-
import { isValidCNPJ, isValidCPF } from "../../../utils/validators/common";
|
|
24
|
-
const COUNTRY_OPTIONS = COUNTRIES.map((country) => ({
|
|
25
|
-
value: country.iso,
|
|
26
|
-
label: country.name
|
|
27
|
-
}));
|
|
28
|
-
const BR_REQUIRED_ADDRESS_FIELDS = [
|
|
29
|
-
"street",
|
|
30
|
-
"streetNumber",
|
|
31
|
-
"neighborhood",
|
|
32
|
-
"city",
|
|
33
|
-
"state"
|
|
34
|
-
];
|
|
35
|
-
function buildBillingDataSchema(translate) {
|
|
36
|
-
const base = z.object({
|
|
37
|
-
personType: z.enum(["pf", "pj"]),
|
|
38
|
-
document: z.string().trim(),
|
|
39
|
-
financialName: z.string().trim().min(1, translate("common.billing.requiredData.requiredField")),
|
|
40
|
-
financialEmail: z.string().trim().min(1, translate("common.billing.requiredData.requiredField")).email(translate("common.billing.requiredData.invalidEmail")),
|
|
41
|
-
cep: z.string().trim(),
|
|
42
|
-
street: z.string().trim(),
|
|
43
|
-
streetNumber: z.string().trim(),
|
|
44
|
-
complement: z.string().trim().optional(),
|
|
45
|
-
neighborhood: z.string().trim(),
|
|
46
|
-
city: z.string().trim(),
|
|
47
|
-
state: z.string().trim(),
|
|
48
|
-
country: z.string().trim().min(1, translate("common.billing.requiredData.requiredField"))
|
|
49
|
-
});
|
|
50
|
-
return base.superRefine((data, ctx) => {
|
|
51
|
-
if (data.country !== "BR") return;
|
|
52
|
-
for (const field of BR_REQUIRED_ADDRESS_FIELDS) {
|
|
53
|
-
if (!data[field]) {
|
|
54
|
-
ctx.addIssue({
|
|
55
|
-
code: "custom",
|
|
56
|
-
path: [field],
|
|
57
|
-
message: translate("common.billing.requiredData.requiredField")
|
|
58
|
-
});
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
if (data.cep.replace(/\D/g, "").length !== 8) {
|
|
62
|
-
ctx.addIssue({
|
|
63
|
-
code: "custom",
|
|
64
|
-
path: ["cep"],
|
|
65
|
-
message: translate("common.billing.requiredData.invalidCep")
|
|
66
|
-
});
|
|
67
|
-
}
|
|
68
|
-
const isCompany = data.personType === "pj";
|
|
69
|
-
const digits = data.document.replace(/\D/g, "");
|
|
70
|
-
if (digits.length !== (isCompany ? 14 : 11)) {
|
|
71
|
-
ctx.addIssue({
|
|
72
|
-
code: "custom",
|
|
73
|
-
path: ["document"],
|
|
74
|
-
message: isCompany ? translate("common.billing.requiredData.invalidCnpj") : translate("common.billing.requiredData.invalidCpf")
|
|
75
|
-
});
|
|
76
|
-
return;
|
|
77
|
-
}
|
|
78
|
-
const isValid = isCompany ? isValidCNPJ(digits) : isValidCPF(digits);
|
|
79
|
-
if (!isValid) {
|
|
80
|
-
ctx.addIssue({
|
|
81
|
-
code: "custom",
|
|
82
|
-
path: ["document"],
|
|
83
|
-
message: isCompany ? translate("common.billing.requiredData.invalidCnpjChecksum") : translate("common.billing.requiredData.invalidCpfChecksum")
|
|
84
|
-
});
|
|
85
|
-
}
|
|
86
|
-
});
|
|
87
|
-
}
|
|
88
|
-
function formatDocument(document, isCompany) {
|
|
89
|
-
if (!document) return "";
|
|
90
|
-
return isCompany ? formatCNPJ(document) : formatCPF(document);
|
|
91
|
-
}
|
|
9
|
+
import { BillingDataForm } from "./BillingDataForm";
|
|
92
10
|
function RequiredBillingDataModalContent() {
|
|
93
11
|
const translate = useTranslations();
|
|
94
|
-
const { user } = useAuth();
|
|
95
12
|
const { isRequired, account } = useRequiredBillingData();
|
|
96
|
-
const { mutateAsync: updateBillingData } = useUpdateBillingData();
|
|
97
|
-
const { mutateAsync: lookupCep } = useViaCep();
|
|
98
13
|
const [isSubmitted, setIsSubmitted] = useState(false);
|
|
99
|
-
const isPrefilled = useRef(false);
|
|
100
|
-
const schema = useMemo(
|
|
101
|
-
() => buildBillingDataSchema(translate),
|
|
102
|
-
[translate]
|
|
103
|
-
);
|
|
104
|
-
const form = useForm({
|
|
105
|
-
resolver: zodResolver(schema),
|
|
106
|
-
mode: "onChange",
|
|
107
|
-
defaultValues: {
|
|
108
|
-
personType: "pf",
|
|
109
|
-
document: "",
|
|
110
|
-
financialName: "",
|
|
111
|
-
financialEmail: "",
|
|
112
|
-
cep: "",
|
|
113
|
-
street: "",
|
|
114
|
-
streetNumber: "",
|
|
115
|
-
complement: "",
|
|
116
|
-
neighborhood: "",
|
|
117
|
-
city: "",
|
|
118
|
-
state: "",
|
|
119
|
-
country: "BR"
|
|
120
|
-
}
|
|
121
|
-
});
|
|
122
|
-
const {
|
|
123
|
-
register,
|
|
124
|
-
control,
|
|
125
|
-
handleSubmit,
|
|
126
|
-
reset,
|
|
127
|
-
setValue,
|
|
128
|
-
watch,
|
|
129
|
-
formState: { errors, isSubmitting, isValid }
|
|
130
|
-
} = form;
|
|
131
|
-
const personType = watch("personType");
|
|
132
|
-
const isCompany = personType === "pj";
|
|
133
|
-
const isBrazil = watch("country") === "BR";
|
|
134
|
-
useEffect(() => {
|
|
135
|
-
if (!account || isPrefilled.current) return;
|
|
136
|
-
isPrefilled.current = true;
|
|
137
|
-
const accountIsCompany = account.financial_document_type === 2;
|
|
138
|
-
reset({
|
|
139
|
-
personType: accountIsCompany ? "pj" : "pf",
|
|
140
|
-
document: formatDocument(account.financial_document, accountIsCompany),
|
|
141
|
-
financialName: account.financial_name ?? "",
|
|
142
|
-
financialEmail: account.financial_email || user?.email || "",
|
|
143
|
-
cep: account.zipcode ?? "",
|
|
144
|
-
street: account.address ?? "",
|
|
145
|
-
streetNumber: account.address_number ?? "",
|
|
146
|
-
complement: account.address_complement ?? "",
|
|
147
|
-
neighborhood: account.neighborhood ?? "",
|
|
148
|
-
city: account.city ?? "",
|
|
149
|
-
state: account.state ?? "",
|
|
150
|
-
country: account.country || readGeoCountry() || "BR"
|
|
151
|
-
});
|
|
152
|
-
}, [account, reset, user?.email]);
|
|
153
|
-
const handleDocumentChange = (rawValue) => {
|
|
154
|
-
setValue("document", isCompany ? formatCNPJ(rawValue) : formatCPF(rawValue), {
|
|
155
|
-
shouldValidate: true
|
|
156
|
-
});
|
|
157
|
-
};
|
|
158
|
-
const handlePersonTypeChange = (value) => {
|
|
159
|
-
if (value === personType) return;
|
|
160
|
-
setValue("document", "");
|
|
161
|
-
setValue("personType", value, { shouldValidate: true });
|
|
162
|
-
};
|
|
163
|
-
const handleCepChange = (rawValue) => {
|
|
164
|
-
setValue("cep", formatPostalCode(rawValue), { shouldValidate: true });
|
|
165
|
-
const digits = rawValue.replace(/\D/g, "");
|
|
166
|
-
if (digits.length !== 8) return;
|
|
167
|
-
lookupCep(digits).then((data) => {
|
|
168
|
-
setValue("street", data.logradouro, { shouldValidate: true });
|
|
169
|
-
setValue("neighborhood", data.bairro, { shouldValidate: true });
|
|
170
|
-
setValue("city", data.localidade, { shouldValidate: true });
|
|
171
|
-
setValue("state", data.uf, { shouldValidate: true });
|
|
172
|
-
}).catch(() => {
|
|
173
|
-
});
|
|
174
|
-
};
|
|
175
|
-
async function onSubmit(data) {
|
|
176
|
-
const payload = data.country === "BR" ? {
|
|
177
|
-
financial_document_type: data.personType === "pf" ? 1 : 2,
|
|
178
|
-
financial_document: data.document,
|
|
179
|
-
financial_name: data.financialName,
|
|
180
|
-
financial_email: data.financialEmail,
|
|
181
|
-
zipcode: data.cep,
|
|
182
|
-
address: data.street,
|
|
183
|
-
address_number: data.streetNumber,
|
|
184
|
-
address_complement: data.complement ?? "",
|
|
185
|
-
neighborhood: data.neighborhood,
|
|
186
|
-
city: data.city,
|
|
187
|
-
state: data.state,
|
|
188
|
-
country: data.country
|
|
189
|
-
} : {
|
|
190
|
-
financial_name: data.financialName,
|
|
191
|
-
financial_email: data.financialEmail,
|
|
192
|
-
country: data.country
|
|
193
|
-
};
|
|
194
|
-
try {
|
|
195
|
-
await updateBillingData(payload);
|
|
196
|
-
setIsSubmitted(true);
|
|
197
|
-
toast.custom(
|
|
198
|
-
(t) => /* @__PURE__ */ jsx(
|
|
199
|
-
Toast,
|
|
200
|
-
{
|
|
201
|
-
variant: "success",
|
|
202
|
-
message: translate("common.billing.requiredData.successToast"),
|
|
203
|
-
toastId: t
|
|
204
|
-
}
|
|
205
|
-
),
|
|
206
|
-
{ duration: 5e3 }
|
|
207
|
-
);
|
|
208
|
-
} catch (error) {
|
|
209
|
-
const message = error instanceof Error && error.message ? error.message : translate("common.billing.requiredData.errorToast");
|
|
210
|
-
toast.custom((t) => /* @__PURE__ */ jsx(Toast, { variant: "error", message, toastId: t }), {
|
|
211
|
-
duration: 5e3
|
|
212
|
-
});
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
14
|
if (!isRequired || isSubmitted) return null;
|
|
216
15
|
return /* @__PURE__ */ jsx(Dialog, { open: true, onOpenChange: () => {
|
|
217
16
|
}, children: /* @__PURE__ */ jsxs(
|
|
@@ -225,208 +24,9 @@ function RequiredBillingDataModalContent() {
|
|
|
225
24
|
children: [
|
|
226
25
|
/* @__PURE__ */ jsxs(DialogHeader, { className: "gap-3 text-left p-4 lg:p-5 border-b border-zinc-200 shrink-0", children: [
|
|
227
26
|
/* @__PURE__ */ jsx("div", { className: "flex items-center justify-center w-10 h-10 bg-zinc-50 rounded-lg", children: /* @__PURE__ */ jsx(IconFileInvoice, { size: 24, className: "text-zinc-950" }) }),
|
|
228
|
-
/* @__PURE__ */
|
|
229
|
-
/* @__PURE__ */ jsx(DialogTitle, { className: "paragraph-medium-semibold text-zinc-950", children: translate("common.billing.requiredData.title") }),
|
|
230
|
-
/* @__PURE__ */ jsx("span", { className: "paragraph-small-regular text-zinc-600", children: isBrazil ? translate("common.billing.requiredData.description") : translate("common.billing.requiredData.descriptionInternational") })
|
|
231
|
-
] })
|
|
27
|
+
/* @__PURE__ */ jsx("div", { className: "flex flex-col gap-2", children: /* @__PURE__ */ jsx(DialogTitle, { className: "paragraph-medium-semibold text-zinc-950", children: translate("common.billing.requiredData.title") }) })
|
|
232
28
|
] }),
|
|
233
|
-
/* @__PURE__ */
|
|
234
|
-
"form",
|
|
235
|
-
{
|
|
236
|
-
onSubmit: handleSubmit(onSubmit),
|
|
237
|
-
className: "flex flex-col flex-1 min-h-0",
|
|
238
|
-
noValidate: true,
|
|
239
|
-
children: [
|
|
240
|
-
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-6 p-4 lg:p-5 flex-1 overflow-y-auto", children: [
|
|
241
|
-
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-5", children: [
|
|
242
|
-
/* @__PURE__ */ jsx(
|
|
243
|
-
Controller,
|
|
244
|
-
{
|
|
245
|
-
name: "country",
|
|
246
|
-
control,
|
|
247
|
-
render: ({ field }) => /* @__PURE__ */ jsx(
|
|
248
|
-
SelectField,
|
|
249
|
-
{
|
|
250
|
-
label: translate("common.billing.requiredData.country"),
|
|
251
|
-
placeholder: translate("common.billing.requiredData.select"),
|
|
252
|
-
value: field.value || void 0,
|
|
253
|
-
onChange: (value) => setValue("country", String(value), { shouldValidate: true }),
|
|
254
|
-
options: COUNTRY_OPTIONS,
|
|
255
|
-
error: !!errors.country,
|
|
256
|
-
errorMessage: errors.country?.message
|
|
257
|
-
}
|
|
258
|
-
)
|
|
259
|
-
}
|
|
260
|
-
),
|
|
261
|
-
isBrazil && /* @__PURE__ */ jsxs("div", { className: "flex gap-4", children: [
|
|
262
|
-
/* @__PURE__ */ jsx(
|
|
263
|
-
Controller,
|
|
264
|
-
{
|
|
265
|
-
name: "personType",
|
|
266
|
-
control,
|
|
267
|
-
render: ({ field }) => /* @__PURE__ */ jsx(
|
|
268
|
-
SelectField,
|
|
269
|
-
{
|
|
270
|
-
label: translate("common.billing.requiredData.personType"),
|
|
271
|
-
placeholder: translate("common.billing.requiredData.select"),
|
|
272
|
-
value: field.value,
|
|
273
|
-
onChange: (value) => handlePersonTypeChange(value),
|
|
274
|
-
options: [
|
|
275
|
-
{
|
|
276
|
-
value: "pf",
|
|
277
|
-
label: translate("common.billing.requiredData.personTypePf")
|
|
278
|
-
},
|
|
279
|
-
{
|
|
280
|
-
value: "pj",
|
|
281
|
-
label: translate("common.billing.requiredData.personTypePj")
|
|
282
|
-
}
|
|
283
|
-
],
|
|
284
|
-
containerClassName: "flex-1"
|
|
285
|
-
}
|
|
286
|
-
)
|
|
287
|
-
}
|
|
288
|
-
),
|
|
289
|
-
/* @__PURE__ */ jsx("div", { className: "flex-1", children: /* @__PURE__ */ jsx(
|
|
290
|
-
FormField,
|
|
291
|
-
{
|
|
292
|
-
label: isCompany ? translate("common.billing.requiredData.cnpj") : translate("common.billing.requiredData.cpf"),
|
|
293
|
-
placeholder: isCompany ? "__.___.___/____-__" : "___.___.___-__",
|
|
294
|
-
error: !!errors.document,
|
|
295
|
-
errorMessage: errors.document?.message,
|
|
296
|
-
...register("document", {
|
|
297
|
-
onChange: (event) => handleDocumentChange(event.target.value)
|
|
298
|
-
})
|
|
299
|
-
}
|
|
300
|
-
) })
|
|
301
|
-
] }),
|
|
302
|
-
/* @__PURE__ */ jsx(
|
|
303
|
-
FormField,
|
|
304
|
-
{
|
|
305
|
-
label: isBrazil && isCompany ? translate("common.billing.requiredData.companyName") : translate("common.billing.requiredData.fullName"),
|
|
306
|
-
placeholder: translate("common.billing.requiredData.typeHere"),
|
|
307
|
-
error: !!errors.financialName,
|
|
308
|
-
errorMessage: errors.financialName?.message,
|
|
309
|
-
...register("financialName")
|
|
310
|
-
}
|
|
311
|
-
),
|
|
312
|
-
/* @__PURE__ */ jsx(
|
|
313
|
-
FormField,
|
|
314
|
-
{
|
|
315
|
-
label: translate("common.billing.requiredData.financialEmail"),
|
|
316
|
-
placeholder: translate("common.billing.requiredData.financialEmailPlaceholder"),
|
|
317
|
-
type: "email",
|
|
318
|
-
error: !!errors.financialEmail,
|
|
319
|
-
errorMessage: errors.financialEmail?.message,
|
|
320
|
-
...register("financialEmail")
|
|
321
|
-
}
|
|
322
|
-
)
|
|
323
|
-
] }),
|
|
324
|
-
isBrazil && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
325
|
-
/* @__PURE__ */ jsx("div", { className: "h-px bg-zinc-200" }),
|
|
326
|
-
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-5", children: [
|
|
327
|
-
/* @__PURE__ */ jsx("span", { className: "paragraph-small-semibold text-zinc-950", children: translate("common.billing.requiredData.addressHeading") }),
|
|
328
|
-
/* @__PURE__ */ jsx(
|
|
329
|
-
FormField,
|
|
330
|
-
{
|
|
331
|
-
label: translate("common.billing.requiredData.cep"),
|
|
332
|
-
placeholder: "_____-___",
|
|
333
|
-
error: !!errors.cep,
|
|
334
|
-
errorMessage: errors.cep?.message,
|
|
335
|
-
...register("cep", {
|
|
336
|
-
onChange: (event) => handleCepChange(event.target.value)
|
|
337
|
-
})
|
|
338
|
-
}
|
|
339
|
-
),
|
|
340
|
-
/* @__PURE__ */ jsxs("div", { className: "flex gap-4", children: [
|
|
341
|
-
/* @__PURE__ */ jsx("div", { className: "flex-[3]", children: /* @__PURE__ */ jsx(
|
|
342
|
-
FormField,
|
|
343
|
-
{
|
|
344
|
-
label: translate("common.billing.requiredData.street"),
|
|
345
|
-
placeholder: translate("common.billing.requiredData.typeHere"),
|
|
346
|
-
error: !!errors.street,
|
|
347
|
-
errorMessage: errors.street?.message,
|
|
348
|
-
...register("street")
|
|
349
|
-
}
|
|
350
|
-
) }),
|
|
351
|
-
/* @__PURE__ */ jsx("div", { className: "flex-1", children: /* @__PURE__ */ jsx(
|
|
352
|
-
FormField,
|
|
353
|
-
{
|
|
354
|
-
label: translate("common.billing.requiredData.streetNumber"),
|
|
355
|
-
placeholder: "000",
|
|
356
|
-
error: !!errors.streetNumber,
|
|
357
|
-
errorMessage: errors.streetNumber?.message,
|
|
358
|
-
...register("streetNumber")
|
|
359
|
-
}
|
|
360
|
-
) })
|
|
361
|
-
] }),
|
|
362
|
-
/* @__PURE__ */ jsxs("div", { className: "flex gap-4", children: [
|
|
363
|
-
/* @__PURE__ */ jsx("div", { className: "flex-1", children: /* @__PURE__ */ jsx(
|
|
364
|
-
FormField,
|
|
365
|
-
{
|
|
366
|
-
label: translate("common.billing.requiredData.neighborhood"),
|
|
367
|
-
placeholder: translate("common.billing.requiredData.typeHere"),
|
|
368
|
-
error: !!errors.neighborhood,
|
|
369
|
-
errorMessage: errors.neighborhood?.message,
|
|
370
|
-
...register("neighborhood")
|
|
371
|
-
}
|
|
372
|
-
) }),
|
|
373
|
-
/* @__PURE__ */ jsx("div", { className: "flex-1", children: /* @__PURE__ */ jsx(
|
|
374
|
-
FormField,
|
|
375
|
-
{
|
|
376
|
-
label: translate("common.billing.requiredData.complement"),
|
|
377
|
-
optional: true,
|
|
378
|
-
placeholder: translate("common.billing.requiredData.typeHere"),
|
|
379
|
-
...register("complement")
|
|
380
|
-
}
|
|
381
|
-
) })
|
|
382
|
-
] }),
|
|
383
|
-
/* @__PURE__ */ jsxs("div", { className: "flex gap-4", children: [
|
|
384
|
-
/* @__PURE__ */ jsx("div", { className: "flex-1", children: /* @__PURE__ */ jsx(
|
|
385
|
-
FormField,
|
|
386
|
-
{
|
|
387
|
-
label: translate("common.billing.requiredData.city"),
|
|
388
|
-
placeholder: translate("common.billing.requiredData.typeHere"),
|
|
389
|
-
error: !!errors.city,
|
|
390
|
-
errorMessage: errors.city?.message,
|
|
391
|
-
...register("city")
|
|
392
|
-
}
|
|
393
|
-
) }),
|
|
394
|
-
/* @__PURE__ */ jsx("div", { className: "flex-1", children: /* @__PURE__ */ jsx(
|
|
395
|
-
Controller,
|
|
396
|
-
{
|
|
397
|
-
name: "state",
|
|
398
|
-
control,
|
|
399
|
-
render: ({ field }) => /* @__PURE__ */ jsx(
|
|
400
|
-
SelectField,
|
|
401
|
-
{
|
|
402
|
-
label: translate("common.billing.requiredData.state"),
|
|
403
|
-
placeholder: translate("common.billing.requiredData.select"),
|
|
404
|
-
value: field.value || void 0,
|
|
405
|
-
onChange: (value) => setValue("state", String(value), { shouldValidate: true }),
|
|
406
|
-
options: BR_STATE_OPTIONS,
|
|
407
|
-
error: !!errors.state,
|
|
408
|
-
errorMessage: errors.state?.message
|
|
409
|
-
}
|
|
410
|
-
)
|
|
411
|
-
}
|
|
412
|
-
) })
|
|
413
|
-
] })
|
|
414
|
-
] })
|
|
415
|
-
] })
|
|
416
|
-
] }),
|
|
417
|
-
/* @__PURE__ */ jsx("div", { className: "flex items-center justify-end p-4 lg:p-5 border-t border-zinc-200 shrink-0", children: /* @__PURE__ */ jsx(
|
|
418
|
-
Button,
|
|
419
|
-
{
|
|
420
|
-
type: "submit",
|
|
421
|
-
className: "h-10! w-full lg:w-fit",
|
|
422
|
-
disabled: !isValid || isSubmitting,
|
|
423
|
-
loading: isSubmitting,
|
|
424
|
-
children: isSubmitting ? translate("common.billing.requiredData.submitting") : translate("common.billing.requiredData.submit")
|
|
425
|
-
}
|
|
426
|
-
) })
|
|
427
|
-
]
|
|
428
|
-
}
|
|
429
|
-
)
|
|
29
|
+
/* @__PURE__ */ jsx(BillingDataForm, { account, onSaved: () => setIsSubmitted(true) })
|
|
430
30
|
]
|
|
431
31
|
}
|
|
432
32
|
) });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/components/modals/billing/RequiredBillingDataModal.tsx"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-explicit-any -- o generic Translator do next-intl não é\n expressável estruturalmente; o `any` do TranslateFn é intencional e está contido neste arquivo\n (mesmo padrão de modules/plans/utils/map-api-plan-to-ui.ts). */\n'use client';\n\nimport { useEffect, useMemo, useRef, useState } from 'react';\nimport { Controller, useForm } from 'react-hook-form';\nimport { zodResolver } from '@hookform/resolvers/zod';\nimport { useTranslations } from 'next-intl';\nimport { toast } from 'sonner';\nimport z from 'zod';\nimport { IconFileInvoice } from '@tabler/icons-react';\n\nimport { Dialog, DialogContent, DialogHeader, DialogTitle } from '../../ui/overlay/Dialog';\nimport { Button } from '../../ui/buttons/Button';\nimport { FormField } from '../../ui/form/FormField';\nimport { SelectField } from '../../ui/form/SelectField';\nimport { Toast } from '../../ui/feedback/Toast';\nimport { useAuth } from '../../../providers/auth.provider';\nimport { useViaCep } from '../../../modules/accounts/hooks/useViaCep';\nimport { useUpdateBillingData } from '../../../modules/accounts/hooks/useAccountManagement';\nimport { useRequiredBillingData } from '../../../modules/accounts/hooks/use-required-billing-data.hook';\nimport { COUNTRIES } from '../../../utils/countries';\nimport { readGeoCountry } from '../../../utils/geo-country';\nimport { BR_STATE_OPTIONS } from '../../../utils/constants/br-states';\nimport { formatCNPJ, formatCPF, formatPostalCode } from '../../../utils/format/masks';\nimport { isValidCNPJ, isValidCPF } from '../../../utils/validators/common';\nimport type { UpdateBillingDataRequest } from '../../../modules/accounts/types';\n\ntype TranslateFn = (key: any, values?: Record<string, string | number>) => string;\n\ntype BillingDataFormValues = {\n personType: 'pf' | 'pj';\n document: string;\n financialName: string;\n financialEmail: string;\n cep: string;\n street: string;\n streetNumber: string;\n complement?: string;\n neighborhood: string;\n city: string;\n state: string;\n country: string;\n};\n\nconst COUNTRY_OPTIONS = COUNTRIES.map((country: { iso: string; name: string }) => ({\n value: country.iso,\n label: country.name,\n}));\n\nconst BR_REQUIRED_ADDRESS_FIELDS: readonly (keyof BillingDataFormValues)[] = [\n 'street',\n 'streetNumber',\n 'neighborhood',\n 'city',\n 'state',\n];\n\nfunction buildBillingDataSchema(translate: TranslateFn) {\n const base = z.object({\n personType: z.enum(['pf', 'pj']),\n document: z.string().trim(),\n financialName: z\n .string()\n .trim()\n .min(1, translate('common.billing.requiredData.requiredField')),\n financialEmail: z\n .string()\n .trim()\n .min(1, translate('common.billing.requiredData.requiredField'))\n .email(translate('common.billing.requiredData.invalidEmail')),\n cep: z.string().trim(),\n street: z.string().trim(),\n streetNumber: z.string().trim(),\n complement: z.string().trim().optional(),\n neighborhood: z.string().trim(),\n city: z.string().trim(),\n state: z.string().trim(),\n country: z.string().trim().min(1, translate('common.billing.requiredData.requiredField')),\n });\n\n return base.superRefine((data, ctx) => {\n if (data.country !== 'BR') return;\n\n for (const field of BR_REQUIRED_ADDRESS_FIELDS) {\n if (!data[field]) {\n ctx.addIssue({\n code: 'custom',\n path: [field],\n message: translate('common.billing.requiredData.requiredField'),\n });\n }\n }\n\n if (data.cep.replace(/\\D/g, '').length !== 8) {\n ctx.addIssue({\n code: 'custom',\n path: ['cep'],\n message: translate('common.billing.requiredData.invalidCep'),\n });\n }\n\n const isCompany = data.personType === 'pj';\n const digits = data.document.replace(/\\D/g, '');\n\n if (digits.length !== (isCompany ? 14 : 11)) {\n ctx.addIssue({\n code: 'custom',\n path: ['document'],\n message: isCompany\n ? translate('common.billing.requiredData.invalidCnpj')\n : translate('common.billing.requiredData.invalidCpf'),\n });\n return;\n }\n\n /* Dígito verificador, mesmo algoritmo do backend: sem isso 111.111.111-11 passa\n * aqui e o PUT da conta é recusado depois, sem o usuário saber o motivo. */\n const isValid = isCompany ? isValidCNPJ(digits) : isValidCPF(digits);\n if (!isValid) {\n ctx.addIssue({\n code: 'custom',\n path: ['document'],\n message: isCompany\n ? translate('common.billing.requiredData.invalidCnpjChecksum')\n : translate('common.billing.requiredData.invalidCpfChecksum'),\n });\n }\n });\n}\n\nfunction formatDocument(document: string | null | undefined, isCompany: boolean) {\n if (!document) return '';\n return isCompany ? formatCNPJ(document) : formatCPF(document);\n}\n\nfunction RequiredBillingDataModalContent() {\n const translate = useTranslations();\n const { user } = useAuth();\n const { isRequired, account } = useRequiredBillingData();\n const { mutateAsync: updateBillingData } = useUpdateBillingData();\n const { mutateAsync: lookupCep } = useViaCep();\n\n /* O modal fecha na hora do submit e não reabre enquanto o invalidate do account\n * não volta — sem isso o usuário vê o modal piscar de novo com o cache antigo. */\n const [isSubmitted, setIsSubmitted] = useState(false);\n const isPrefilled = useRef(false);\n\n const schema = useMemo(\n () => buildBillingDataSchema(translate),\n [translate],\n );\n\n const form = useForm<BillingDataFormValues>({\n resolver: zodResolver(schema),\n mode: 'onChange',\n defaultValues: {\n personType: 'pf',\n document: '',\n financialName: '',\n financialEmail: '',\n cep: '',\n street: '',\n streetNumber: '',\n complement: '',\n neighborhood: '',\n city: '',\n state: '',\n country: 'BR',\n },\n });\n\n const {\n register,\n control,\n handleSubmit,\n reset,\n setValue,\n watch,\n formState: { errors, isSubmitting, isValid },\n } = form;\n\n const personType = watch('personType');\n const isCompany = personType === 'pj';\n const isBrazil = watch('country') === 'BR';\n\n useEffect(() => {\n if (!account || isPrefilled.current) return;\n isPrefilled.current = true;\n\n const accountIsCompany = account.financial_document_type === 2;\n reset({\n personType: accountIsCompany ? 'pj' : 'pf',\n document: formatDocument(account.financial_document, accountIsCompany),\n financialName: account.financial_name ?? '',\n financialEmail: account.financial_email || user?.email || '',\n cep: account.zipcode ?? '',\n street: account.address ?? '',\n streetNumber: account.address_number ?? '',\n complement: account.address_complement ?? '',\n neighborhood: account.neighborhood ?? '',\n city: account.city ?? '',\n state: account.state ?? '',\n country: account.country || readGeoCountry() || 'BR',\n });\n }, [account, reset, user?.email]);\n\n const handleDocumentChange = (rawValue: string) => {\n setValue('document', isCompany ? formatCNPJ(rawValue) : formatCPF(rawValue), {\n shouldValidate: true,\n });\n };\n\n const handlePersonTypeChange = (value: 'pf' | 'pj') => {\n if (value === personType) return;\n setValue('document', '');\n /* shouldValidate reroda o resolver: sem isso o `isValid` fica preso no valor\n * do documento antigo e o botão continua habilitado com o campo já limpo. */\n setValue('personType', value, { shouldValidate: true });\n };\n\n const handleCepChange = (rawValue: string) => {\n setValue('cep', formatPostalCode(rawValue), { shouldValidate: true });\n\n const digits = rawValue.replace(/\\D/g, '');\n if (digits.length !== 8) return;\n\n lookupCep(digits)\n .then((data) => {\n setValue('street', data.logradouro, { shouldValidate: true });\n setValue('neighborhood', data.bairro, { shouldValidate: true });\n setValue('city', data.localidade, { shouldValidate: true });\n setValue('state', data.uf, { shouldValidate: true });\n })\n .catch(() => {\n // CEP não encontrado: o usuário preenche o endereço na mão.\n });\n };\n\n async function onSubmit(data: BillingDataFormValues) {\n const payload: UpdateBillingDataRequest =\n data.country === 'BR'\n ? {\n financial_document_type: data.personType === 'pf' ? 1 : 2,\n financial_document: data.document,\n financial_name: data.financialName,\n financial_email: data.financialEmail,\n zipcode: data.cep,\n address: data.street,\n address_number: data.streetNumber,\n address_complement: data.complement ?? '',\n neighborhood: data.neighborhood,\n city: data.city,\n state: data.state,\n country: data.country,\n }\n : {\n financial_name: data.financialName,\n financial_email: data.financialEmail,\n country: data.country,\n };\n\n try {\n await updateBillingData(payload);\n setIsSubmitted(true);\n toast.custom(\n (t) => (\n <Toast\n variant=\"success\"\n message={translate('common.billing.requiredData.successToast')}\n toastId={t}\n />\n ),\n { duration: 5000 },\n );\n } catch (error) {\n /* O backend devolve a razão exata da recusa (ex.: documento fiscal inválido).\n * Trocar por um texto genérico deixaria o usuário travado sem saber o que corrigir. */\n const message =\n error instanceof Error && error.message\n ? error.message\n : translate('common.billing.requiredData.errorToast');\n toast.custom((t) => <Toast variant=\"error\" message={message} toastId={t} />, {\n duration: 5000,\n });\n }\n }\n\n if (!isRequired || isSubmitted) return null;\n\n return (\n <Dialog open onOpenChange={() => {}}>\n <DialogContent\n showCloseButton={false}\n onEscapeKeyDown={(event: Event) => event.preventDefault()}\n onPointerDownOutside={(event: Event) => event.preventDefault()}\n onInteractOutside={(event: Event) => event.preventDefault()}\n className=\"flex flex-col p-0 gap-0 max-w-full sm:max-w-full border-0 rounded-t-2xl rounded-b-none h-dvh top-0 bottom-0 left-0 right-0 translate-x-0 translate-y-0 lg:max-w-[502px] lg:h-auto lg:max-h-[90vh] lg:rounded-lg lg:border lg:top-[50%] lg:left-[50%] lg:right-auto lg:bottom-auto lg:translate-x-[-50%] lg:translate-y-[-50%] overflow-hidden\"\n >\n <DialogHeader className=\"gap-3 text-left p-4 lg:p-5 border-b border-zinc-200 shrink-0\">\n <div className=\"flex items-center justify-center w-10 h-10 bg-zinc-50 rounded-lg\">\n <IconFileInvoice size={24} className=\"text-zinc-950\" />\n </div>\n <div className=\"flex flex-col gap-2\">\n <DialogTitle className=\"paragraph-medium-semibold text-zinc-950\">\n {translate('common.billing.requiredData.title')}\n </DialogTitle>\n <span className=\"paragraph-small-regular text-zinc-600\">\n {isBrazil\n ? translate('common.billing.requiredData.description')\n : translate('common.billing.requiredData.descriptionInternational')}\n </span>\n </div>\n </DialogHeader>\n\n <form\n onSubmit={handleSubmit(onSubmit)}\n className=\"flex flex-col flex-1 min-h-0\"\n noValidate\n >\n <div className=\"flex flex-col gap-6 p-4 lg:p-5 flex-1 overflow-y-auto\">\n <div className=\"flex flex-col gap-5\">\n <Controller\n name=\"country\"\n control={control}\n render={({ field }) => (\n <SelectField\n label={translate('common.billing.requiredData.country')}\n placeholder={translate('common.billing.requiredData.select')}\n value={field.value || undefined}\n onChange={(value) =>\n setValue('country', String(value), { shouldValidate: true })\n }\n options={COUNTRY_OPTIONS}\n error={!!errors.country}\n errorMessage={errors.country?.message}\n />\n )}\n />\n\n {isBrazil && (\n <div className=\"flex gap-4\">\n <Controller\n name=\"personType\"\n control={control}\n render={({ field }) => (\n <SelectField\n label={translate('common.billing.requiredData.personType')}\n placeholder={translate('common.billing.requiredData.select')}\n value={field.value}\n onChange={(value) => handlePersonTypeChange(value as 'pf' | 'pj')}\n options={[\n {\n value: 'pf',\n label: translate('common.billing.requiredData.personTypePf'),\n },\n {\n value: 'pj',\n label: translate('common.billing.requiredData.personTypePj'),\n },\n ]}\n containerClassName=\"flex-1\"\n />\n )}\n />\n <div className=\"flex-1\">\n <FormField\n label={\n isCompany\n ? translate('common.billing.requiredData.cnpj')\n : translate('common.billing.requiredData.cpf')\n }\n placeholder={isCompany ? '__.___.___/____-__' : '___.___.___-__'}\n error={!!errors.document}\n errorMessage={errors.document?.message}\n {...register('document', {\n onChange: (event) => handleDocumentChange(event.target.value),\n })}\n />\n </div>\n </div>\n )}\n\n <FormField\n label={\n isBrazil && isCompany\n ? translate('common.billing.requiredData.companyName')\n : translate('common.billing.requiredData.fullName')\n }\n placeholder={translate('common.billing.requiredData.typeHere')}\n error={!!errors.financialName}\n errorMessage={errors.financialName?.message}\n {...register('financialName')}\n />\n\n <FormField\n label={translate('common.billing.requiredData.financialEmail')}\n placeholder={translate('common.billing.requiredData.financialEmailPlaceholder')}\n type=\"email\"\n error={!!errors.financialEmail}\n errorMessage={errors.financialEmail?.message}\n {...register('financialEmail')}\n />\n </div>\n\n {isBrazil && (\n <>\n <div className=\"h-px bg-zinc-200\" />\n\n <div className=\"flex flex-col gap-5\">\n <span className=\"paragraph-small-semibold text-zinc-950\">\n {translate('common.billing.requiredData.addressHeading')}\n </span>\n\n <FormField\n label={translate('common.billing.requiredData.cep')}\n placeholder=\"_____-___\"\n error={!!errors.cep}\n errorMessage={errors.cep?.message}\n {...register('cep', {\n onChange: (event) => handleCepChange(event.target.value),\n })}\n />\n\n <div className=\"flex gap-4\">\n <div className=\"flex-[3]\">\n <FormField\n label={translate('common.billing.requiredData.street')}\n placeholder={translate('common.billing.requiredData.typeHere')}\n error={!!errors.street}\n errorMessage={errors.street?.message}\n {...register('street')}\n />\n </div>\n <div className=\"flex-1\">\n <FormField\n label={translate('common.billing.requiredData.streetNumber')}\n placeholder=\"000\"\n error={!!errors.streetNumber}\n errorMessage={errors.streetNumber?.message}\n {...register('streetNumber')}\n />\n </div>\n </div>\n\n <div className=\"flex gap-4\">\n <div className=\"flex-1\">\n <FormField\n label={translate('common.billing.requiredData.neighborhood')}\n placeholder={translate('common.billing.requiredData.typeHere')}\n error={!!errors.neighborhood}\n errorMessage={errors.neighborhood?.message}\n {...register('neighborhood')}\n />\n </div>\n <div className=\"flex-1\">\n <FormField\n label={translate('common.billing.requiredData.complement')}\n optional\n placeholder={translate('common.billing.requiredData.typeHere')}\n {...register('complement')}\n />\n </div>\n </div>\n\n <div className=\"flex gap-4\">\n <div className=\"flex-1\">\n <FormField\n label={translate('common.billing.requiredData.city')}\n placeholder={translate('common.billing.requiredData.typeHere')}\n error={!!errors.city}\n errorMessage={errors.city?.message}\n {...register('city')}\n />\n </div>\n <div className=\"flex-1\">\n <Controller\n name=\"state\"\n control={control}\n render={({ field }) => (\n <SelectField\n label={translate('common.billing.requiredData.state')}\n placeholder={translate('common.billing.requiredData.select')}\n value={field.value || undefined}\n onChange={(value) =>\n setValue('state', String(value), { shouldValidate: true })\n }\n options={BR_STATE_OPTIONS}\n error={!!errors.state}\n errorMessage={errors.state?.message}\n />\n )}\n />\n </div>\n </div>\n </div>\n </>\n )}\n </div>\n\n <div className=\"flex items-center justify-end p-4 lg:p-5 border-t border-zinc-200 shrink-0\">\n <Button\n type=\"submit\"\n className=\"h-10! w-full lg:w-fit\"\n disabled={!isValid || isSubmitting}\n loading={isSubmitting}\n >\n {isSubmitting\n ? translate('common.billing.requiredData.submitting')\n : translate('common.billing.requiredData.submit')}\n </Button>\n </div>\n </form>\n </DialogContent>\n </Dialog>\n );\n}\n\n/**\n * Modal bloqueante que exige o cadastro de cobrança/fiscal de contas que já\n * pagaram sem ele — sem esses dados a nota fiscal não é emitida. Monte uma vez\n * no layout raiz do app; ele mesmo decide se aparece (ver `useRequiredBillingData`).\n */\nexport default function RequiredBillingDataModal() {\n const { user, isLoading } = useAuth();\n\n /* Sem sessão não há conta nem assinatura pra consultar — evita disparar as\n * queries (e tomar 401) em /login, /register e demais rotas públicas. */\n if (isLoading || !user) return null;\n\n return <RequiredBillingDataModalContent />;\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../../src/components/modals/billing/RequiredBillingDataModal.tsx"],"sourcesContent":["'use client';\n\nimport { useState } from 'react';\nimport { useTranslations } from 'next-intl';\nimport { IconFileInvoice } from '@tabler/icons-react';\n\nimport { Dialog, DialogContent, DialogHeader, DialogTitle } from '../../ui/overlay/Dialog';\nimport { useAuth } from '../../../providers/auth.provider';\nimport { useRequiredBillingData } from '../../../modules/accounts/hooks/use-required-billing-data.hook';\nimport { BillingDataForm } from './BillingDataForm';\n\nfunction RequiredBillingDataModalContent() {\n const translate = useTranslations();\n const { isRequired, account } = useRequiredBillingData();\n\n /* O modal fecha na hora do submit e não reabre enquanto o invalidate do account\n * não volta — sem isso o usuário vê o modal piscar de novo com o cache antigo. */\n const [isSubmitted, setIsSubmitted] = useState(false);\n\n if (!isRequired || isSubmitted) return null;\n\n return (\n <Dialog open onOpenChange={() => {}}>\n <DialogContent\n showCloseButton={false}\n onEscapeKeyDown={(event: Event) => event.preventDefault()}\n onPointerDownOutside={(event: Event) => event.preventDefault()}\n onInteractOutside={(event: Event) => event.preventDefault()}\n className=\"flex flex-col p-0 gap-0 max-w-full sm:max-w-full border-0 rounded-t-2xl rounded-b-none h-dvh top-0 bottom-0 left-0 right-0 translate-x-0 translate-y-0 lg:max-w-[502px] lg:h-auto lg:max-h-[90vh] lg:rounded-lg lg:border lg:top-[50%] lg:left-[50%] lg:right-auto lg:bottom-auto lg:translate-x-[-50%] lg:translate-y-[-50%] overflow-hidden\"\n >\n <DialogHeader className=\"gap-3 text-left p-4 lg:p-5 border-b border-zinc-200 shrink-0\">\n <div className=\"flex items-center justify-center w-10 h-10 bg-zinc-50 rounded-lg\">\n <IconFileInvoice size={24} className=\"text-zinc-950\" />\n </div>\n <div className=\"flex flex-col gap-2\">\n <DialogTitle className=\"paragraph-medium-semibold text-zinc-950\">\n {translate('common.billing.requiredData.title')}\n </DialogTitle>\n </div>\n </DialogHeader>\n\n <BillingDataForm account={account} onSaved={() => setIsSubmitted(true)} />\n </DialogContent>\n </Dialog>\n );\n}\n\n/**\n * Modal bloqueante que exige o cadastro de cobrança/fiscal de contas que já\n * pagaram sem ele — sem esses dados a nota fiscal não é emitida. Monte uma vez\n * no layout raiz do app; ele mesmo decide se aparece (ver `useRequiredBillingData`).\n */\nexport default function RequiredBillingDataModal() {\n const { user, isLoading } = useAuth();\n\n /* Sem sessão não há conta nem assinatura pra consultar — evita disparar as\n * queries (e tomar 401) em /login, /register e demais rotas públicas. */\n if (isLoading || !user) return null;\n\n return <RequiredBillingDataModalContent />;\n}\n"],"mappings":";AA8BQ,SAEI,KAFJ;AA5BR,SAAS,gBAAgB;AACzB,SAAS,uBAAuB;AAChC,SAAS,uBAAuB;AAEhC,SAAS,QAAQ,eAAe,cAAc,mBAAmB;AACjE,SAAS,eAAe;AACxB,SAAS,8BAA8B;AACvC,SAAS,uBAAuB;AAEhC,SAAS,kCAAkC;AACzC,QAAM,YAAY,gBAAgB;AAClC,QAAM,EAAE,YAAY,QAAQ,IAAI,uBAAuB;AAIvD,QAAM,CAAC,aAAa,cAAc,IAAI,SAAS,KAAK;AAEpD,MAAI,CAAC,cAAc,YAAa,QAAO;AAEvC,SACE,oBAAC,UAAO,MAAI,MAAC,cAAc,MAAM;AAAA,EAAC,GAChC;AAAA,IAAC;AAAA;AAAA,MACC,iBAAiB;AAAA,MACjB,iBAAiB,CAAC,UAAiB,MAAM,eAAe;AAAA,MACxD,sBAAsB,CAAC,UAAiB,MAAM,eAAe;AAAA,MAC7D,mBAAmB,CAAC,UAAiB,MAAM,eAAe;AAAA,MAC1D,WAAU;AAAA,MAEV;AAAA,6BAAC,gBAAa,WAAU,gEACtB;AAAA,8BAAC,SAAI,WAAU,oEACb,8BAAC,mBAAgB,MAAM,IAAI,WAAU,iBAAgB,GACvD;AAAA,UACA,oBAAC,SAAI,WAAU,uBACb,8BAAC,eAAY,WAAU,2CACpB,oBAAU,mCAAmC,GAChD,GACF;AAAA,WACF;AAAA,QAEA,oBAAC,mBAAgB,SAAkB,SAAS,MAAM,eAAe,IAAI,GAAG;AAAA;AAAA;AAAA,EAC1E,GACF;AAEJ;AAOe,SAAR,2BAA4C;AACjD,QAAM,EAAE,MAAM,UAAU,IAAI,QAAQ;AAIpC,MAAI,aAAa,CAAC,KAAM,QAAO;AAE/B,SAAO,oBAAC,mCAAgC;AAC1C;","names":[]}
|
|
@@ -4,9 +4,9 @@ import { DEFAULT_LOCALE, LOCALE_COOKIE } from "./config";
|
|
|
4
4
|
import { localeFromCountry } from "./country-language";
|
|
5
5
|
import { normalizeLocale } from "./normalize";
|
|
6
6
|
import { decodeJwtPayload } from "../utils/jwt-payload";
|
|
7
|
+
import { DEFAULT_WHITELABEL_ID } from "../modules/whitelabel/constants/whitelabel.constants";
|
|
7
8
|
const AUTH_COOKIE = "greatapps";
|
|
8
9
|
const GEO_HEADER = "cf-ipcountry";
|
|
9
|
-
const DEFAULT_WHITELABEL_ID = 1;
|
|
10
10
|
function decodeJwtLocaleInfo(token) {
|
|
11
11
|
if (!token) return null;
|
|
12
12
|
try {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/i18n/resolve-locale.ts"],"sourcesContent":["import 'server-only';\n\nimport { cookies, headers } from 'next/headers';\nimport { DEFAULT_LOCALE, Locale, LOCALE_COOKIE } from './config';\nimport { localeFromCountry } from './country-language';\nimport { normalizeLocale } from './normalize';\nimport { decodeJwtPayload } from '../utils/jwt-payload';\n\nconst AUTH_COOKIE = 'greatapps';\nconst GEO_HEADER = 'cf-ipcountry';\
|
|
1
|
+
{"version":3,"sources":["../../src/i18n/resolve-locale.ts"],"sourcesContent":["import 'server-only';\n\nimport { cookies, headers } from 'next/headers';\nimport { DEFAULT_LOCALE, Locale, LOCALE_COOKIE } from './config';\nimport { localeFromCountry } from './country-language';\nimport { normalizeLocale } from './normalize';\nimport { decodeJwtPayload } from '../utils/jwt-payload';\nimport { DEFAULT_WHITELABEL_ID } from '../modules/whitelabel/constants/whitelabel.constants';\n\nconst AUTH_COOKIE = 'greatapps';\nconst GEO_HEADER = 'cf-ipcountry';\n\ninterface JwtLocaleInfo {\n id_wl?: number;\n country?: string | null;\n}\n\n/** Lê id_wl e país do JWT sem custo de rede (best-effort). */\nfunction decodeJwtLocaleInfo(token?: string | null): JwtLocaleInfo | null {\n if (!token) return null;\n try {\n const payload = decodeJwtPayload<{ id_wl?: number | string; session?: { location?: { country?: string | null } } }>(token);\n return {\n id_wl: payload?.id_wl != null ? Number(payload.id_wl) : undefined,\n country: payload?.session?.location?.country ?? null,\n };\n } catch {\n return null;\n }\n}\n\nexport interface ResolveLocaleOptions {\n /**\n * Whitelabel id já resolvido (ex.: via `findWhitelabel()`), com prioridade sobre o JWT.\n * Permite detectar domínio whitelabel mesmo para visitante não-logado.\n */\n whitelabelId?: number | null;\n /** Idioma da conta (`user.language`), quando já conhecido pelo chamador. */\n userLanguage?: string | null;\n}\n\nfunction localeFromAcceptLanguage(header: string | null): Locale | null {\n if (!header) return null;\n for (const entry of header.split(',')) {\n const locale = normalizeLocale(entry.split(';')[0].trim());\n if (locale) return locale;\n }\n return null;\n}\n\n/**\n * Resolve o locale da requisição (server-side). Ordem de prioridade:\n *\n * 1. **Whitelabel não-padrão** (`id_wl != 1`) → `pt` (por enquanto, whitelabels não são localizadas).\n * 2. **Preferência da conta** (`userLanguage`), quando fornecida.\n * 3. **Cookie `NEXT_LOCALE`** — cache da preferência ou escolha manual do visitante.\n * 4. **Header `Accept-Language`** do navegador.\n * 5. **Inferência por país** — JWT (`session.location.country`) ou header `CF-IPCountry`.\n * 6. **Fallback** → {@link DEFAULT_LOCALE}.\n */\nexport async function resolveLocale(options: ResolveLocaleOptions = {}): Promise<Locale> {\n const cookieStore = await cookies();\n const token = process.env.DUMMY_AUTH_TOKEN || cookieStore.get(AUTH_COOKIE)?.value;\n const jwt = decodeJwtLocaleInfo(token);\n\n // 1. Whitelabel não-padrão → português\n const whitelabelId = options.whitelabelId ?? jwt?.id_wl ?? null;\n if (whitelabelId != null && whitelabelId !== DEFAULT_WHITELABEL_ID) {\n return 'pt-br';\n }\n\n // 2. Preferência explícita da conta\n const fromUser = normalizeLocale(options.userLanguage);\n if (fromUser) return fromUser;\n\n // 3. Cookie persistido\n const fromCookie = normalizeLocale(cookieStore.get(LOCALE_COOKIE)?.value);\n if (fromCookie) return fromCookie;\n\n const headersList = await headers();\n\n // 4. Header Accept-Language do navegador\n const fromAcceptLanguage = localeFromAcceptLanguage(headersList.get('accept-language'));\n if (fromAcceptLanguage) return fromAcceptLanguage;\n\n // 5. Inferência por país (geo)\n const country = jwt?.country ?? headersList.get(GEO_HEADER);\n const fromGeo = localeFromCountry(country);\n if (fromGeo) return fromGeo;\n\n // 6. Fallback\n return DEFAULT_LOCALE;\n}\n"],"mappings":"AAAA,OAAO;AAEP,SAAS,SAAS,eAAe;AACjC,SAAS,gBAAwB,qBAAqB;AACtD,SAAS,yBAAyB;AAClC,SAAS,uBAAuB;AAChC,SAAS,wBAAwB;AACjC,SAAS,6BAA6B;AAEtC,MAAM,cAAc;AACpB,MAAM,aAAa;AAQnB,SAAS,oBAAoB,OAA6C;AACxE,MAAI,CAAC,MAAO,QAAO;AACnB,MAAI;AACF,UAAM,UAAU,iBAAoG,KAAK;AACzH,WAAO;AAAA,MACL,OAAO,SAAS,SAAS,OAAO,OAAO,QAAQ,KAAK,IAAI;AAAA,MACxD,SAAS,SAAS,SAAS,UAAU,WAAW;AAAA,IAClD;AAAA,EACF,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAYA,SAAS,yBAAyB,QAAsC;AACtE,MAAI,CAAC,OAAQ,QAAO;AACpB,aAAW,SAAS,OAAO,MAAM,GAAG,GAAG;AACrC,UAAM,SAAS,gBAAgB,MAAM,MAAM,GAAG,EAAE,CAAC,EAAE,KAAK,CAAC;AACzD,QAAI,OAAQ,QAAO;AAAA,EACrB;AACA,SAAO;AACT;AAYA,eAAsB,cAAc,UAAgC,CAAC,GAAoB;AACvF,QAAM,cAAc,MAAM,QAAQ;AAClC,QAAM,QAAQ,QAAQ,IAAI,oBAAoB,YAAY,IAAI,WAAW,GAAG;AAC5E,QAAM,MAAM,oBAAoB,KAAK;AAGrC,QAAM,eAAe,QAAQ,gBAAgB,KAAK,SAAS;AAC3D,MAAI,gBAAgB,QAAQ,iBAAiB,uBAAuB;AAClE,WAAO;AAAA,EACT;AAGA,QAAM,WAAW,gBAAgB,QAAQ,YAAY;AACrD,MAAI,SAAU,QAAO;AAGrB,QAAM,aAAa,gBAAgB,YAAY,IAAI,aAAa,GAAG,KAAK;AACxE,MAAI,WAAY,QAAO;AAEvB,QAAM,cAAc,MAAM,QAAQ;AAGlC,QAAM,qBAAqB,yBAAyB,YAAY,IAAI,iBAAiB,CAAC;AACtF,MAAI,mBAAoB,QAAO;AAG/B,QAAM,UAAU,KAAK,WAAW,YAAY,IAAI,UAAU;AAC1D,QAAM,UAAU,kBAAkB,OAAO;AACzC,MAAI,QAAS,QAAO;AAGpB,SAAO;AACT;","names":[]}
|
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export * from "./modules/auth/schema";
|
|
2
2
|
export * from "./modules/users/schema";
|
|
3
|
+
import { UserProfile } from "./modules/users/schema";
|
|
3
4
|
export * from "./modules/whitelabel/schema";
|
|
4
5
|
export * from "./infra/api/types";
|
|
5
6
|
export * from "./providers/query.provider";
|
|
@@ -198,6 +199,7 @@ import { default as default5 } from "./components/modals/PaidPlanRequiredModal";
|
|
|
198
199
|
import { default as default6 } from "./components/modals/AccountFrozenModal";
|
|
199
200
|
import { default as default7 } from "./components/modals/AccountDeletionWarningModal";
|
|
200
201
|
import { default as default8 } from "./components/modals/billing/RequiredBillingDataModal";
|
|
202
|
+
import { BillingDataForm } from "./components/modals/billing/BillingDataForm";
|
|
201
203
|
import { default as default9 } from "./components/modals/cards/AddCardModal";
|
|
202
204
|
import { DeleteCardModal } from "./components/modals/cards/DeleteCardModal";
|
|
203
205
|
import { CannotDeleteCardModal } from "./components/modals/cards/CannotDeleteCardModal";
|
|
@@ -572,6 +574,7 @@ export {
|
|
|
572
574
|
AppNavigation,
|
|
573
575
|
BR_STATE_OPTIONS,
|
|
574
576
|
Badge,
|
|
577
|
+
BillingDataForm,
|
|
575
578
|
Button,
|
|
576
579
|
default2 as BuyCreditsModal,
|
|
577
580
|
CARDS_QUERY_KEY,
|
|
@@ -783,6 +786,7 @@ export {
|
|
|
783
786
|
USER_QUERY_KEY,
|
|
784
787
|
UpcomingInvoiceBanner,
|
|
785
788
|
UserAvatar,
|
|
789
|
+
UserProfile,
|
|
786
790
|
UsersSelectorPopover,
|
|
787
791
|
default11 as WhitelabelCodes,
|
|
788
792
|
WorkspaceSectionType,
|