@greatapps/common 1.1.740 → 1.1.742
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/BuyCreditsModal.mjs +42 -30
- package/dist/components/modals/BuyCreditsModal.mjs.map +1 -1
- package/dist/components/modals/cards/AddCardModal.mjs +2 -1
- package/dist/components/modals/cards/AddCardModal.mjs.map +1 -1
- package/dist/index.mjs +25 -9
- package/dist/index.mjs.map +1 -1
- package/dist/modules/accounts/hooks/use-currency-formatter.hook.mjs +3 -1
- package/dist/modules/accounts/hooks/use-currency-formatter.hook.mjs.map +1 -1
- package/dist/modules/accounts/hooks/use-required-billing-data.hook.mjs +3 -2
- package/dist/modules/accounts/hooks/use-required-billing-data.hook.mjs.map +1 -1
- package/dist/modules/accounts/utils/billing-data.mjs +3 -9
- package/dist/modules/accounts/utils/billing-data.mjs.map +1 -1
- package/dist/modules/plans/types/plan.type.mjs +15 -0
- package/dist/modules/plans/types/plan.type.mjs.map +1 -1
- package/dist/modules/plans/utils/map-api-plan-to-ui.mjs +10 -2
- package/dist/modules/plans/utils/map-api-plan-to-ui.mjs.map +1 -1
- package/dist/modules/subscriptions/constants/addons.constants.mjs +15 -2
- package/dist/modules/subscriptions/constants/addons.constants.mjs.map +1 -1
- package/dist/utils/format/currency.mjs +4 -1
- package/dist/utils/format/currency.mjs.map +1 -1
- package/dist/utils/format/gateway.mjs +18 -0
- package/dist/utils/format/gateway.mjs.map +1 -0
- package/package.json +1 -1
- package/src/components/modals/BuyCreditsModal.tsx +48 -32
- package/src/components/modals/cards/AddCardModal.tsx +2 -1
- package/src/index.ts +14 -5
- package/src/modules/accounts/hooks/use-currency-formatter.hook.tsx +3 -0
- package/src/modules/accounts/hooks/use-required-billing-data.hook.ts +3 -2
- package/src/modules/accounts/utils/billing-data.ts +11 -15
- package/src/modules/plans/types/plan.type.ts +17 -0
- package/src/modules/plans/utils/map-api-plan-to-ui.ts +12 -4
- package/src/modules/subscriptions/constants/addons.constants.ts +41 -28
- package/src/utils/format/currency.ts +5 -29
- package/src/utils/format/gateway.ts +22 -0
|
@@ -12,14 +12,16 @@ import { Toast } from "../ui/feedback/Toast";
|
|
|
12
12
|
import { SelectField } from "../ui/form/SelectField";
|
|
13
13
|
import { Skeleton } from "../ui/feedback/Skeleton";
|
|
14
14
|
import { PaymentInfoCard } from "../ui/data-display/PaymentInfoCard";
|
|
15
|
-
import { ADDON_IDS } from "../../modules/subscriptions/constants/addons.constants";
|
|
16
15
|
import {
|
|
17
|
-
|
|
18
|
-
AI_CREDIT_VALUES
|
|
16
|
+
ADDON_IDS,
|
|
17
|
+
AI_CREDIT_VALUES,
|
|
18
|
+
buildAiCreditOptions
|
|
19
19
|
} from "../../modules/subscriptions/constants/addons.constants";
|
|
20
20
|
import { useBuyCreditsModal } from "../../store/useBuyCreditsModal";
|
|
21
21
|
import { useModalManager } from "../../store/useModalManager";
|
|
22
22
|
import { useCards } from "../../modules/cards/hooks/cards.hook";
|
|
23
|
+
import { useCurrencyFormatter } from "../../modules/accounts/hooks/use-currency-formatter.hook";
|
|
24
|
+
import { usePlanById } from "../../modules/plans/hooks/use-plan-by-id.hook";
|
|
23
25
|
import { useActiveSubscription } from "../../modules/subscriptions/hooks/find-active-subscription.hook";
|
|
24
26
|
import { useCalculateSubscription } from "../../modules/subscriptions/hooks/calculate-subscription.hook";
|
|
25
27
|
import { useUpdateSubscriptionPlan } from "../../modules/subscriptions/hooks/update-subscription-plan.hook";
|
|
@@ -45,6 +47,7 @@ function BuyCreditsModal() {
|
|
|
45
47
|
const isDefaultWl = useIsDefaultWhitelabel();
|
|
46
48
|
const { isExternalContracting, redirectToExternal } = useExternalContracting();
|
|
47
49
|
const { data: cardsData } = useCards();
|
|
50
|
+
const { locale, formatCurrencyNumber } = useCurrencyFormatter();
|
|
48
51
|
const { data: subscriptionData } = useActiveSubscription();
|
|
49
52
|
const subscription = subscriptionData?.data?.[0] ?? null;
|
|
50
53
|
const defaultCardId = cardsData?.data?.find((card) => card.is_default)?.id?.toString() ?? cardsData?.data?.[0]?.id?.toString() ?? "";
|
|
@@ -63,9 +66,17 @@ function BuyCreditsModal() {
|
|
|
63
66
|
const currentCredits = aiItem?.quantity ?? 0;
|
|
64
67
|
const subscriptionId = subscription?.id;
|
|
65
68
|
const planId = subscription?.id_plan;
|
|
69
|
+
const { data: planData } = usePlanById(planId);
|
|
70
|
+
const perCreditPrice = useMemo(() => {
|
|
71
|
+
const planAiItem = planData?.data?.items?.find(
|
|
72
|
+
(item) => item.id_addon === ADDON_IDS.AI && (item.value ?? 0) > 0
|
|
73
|
+
);
|
|
74
|
+
return planAiItem?.value ?? aiItem?.value ?? 0;
|
|
75
|
+
}, [planData, aiItem]);
|
|
76
|
+
const hasPerCreditPrice = perCreditPrice > 0;
|
|
77
|
+
const aiCreditOptions = useMemo(() => buildAiCreditOptions(perCreditPrice), [perCreditPrice]);
|
|
66
78
|
const buildPlanExtras = useCallback(
|
|
67
79
|
(aiQuantity) => {
|
|
68
|
-
const aiOption = AI_CREDIT_OPTIONS.find((opt) => opt.credits === aiQuantity);
|
|
69
80
|
return [
|
|
70
81
|
...(subscription?.items ?? []).filter((item) => item.id_addon != null && item.id_addon !== ADDON_IDS.AI).map((item) => ({
|
|
71
82
|
id_addon: Number(item.id_addon),
|
|
@@ -75,8 +86,7 @@ function BuyCreditsModal() {
|
|
|
75
86
|
})),
|
|
76
87
|
{
|
|
77
88
|
id_addon: ADDON_IDS.AI,
|
|
78
|
-
quantity: aiQuantity
|
|
79
|
-
value: aiOption?.price ?? 0
|
|
89
|
+
quantity: aiQuantity
|
|
80
90
|
}
|
|
81
91
|
];
|
|
82
92
|
},
|
|
@@ -134,13 +144,12 @@ function BuyCreditsModal() {
|
|
|
134
144
|
shouldValidate: true,
|
|
135
145
|
shouldDirty: true
|
|
136
146
|
});
|
|
137
|
-
|
|
138
|
-
if (!option) return;
|
|
147
|
+
if (!AI_CREDIT_VALUES.has(credits)) return;
|
|
139
148
|
calculate({
|
|
140
149
|
id_product: 1,
|
|
141
150
|
...planId != null && { id_plan: planId },
|
|
142
151
|
...subscriptionId != null && { id_subscription: subscriptionId },
|
|
143
|
-
plan_extras: buildPlanExtras(
|
|
152
|
+
plan_extras: buildPlanExtras(credits)
|
|
144
153
|
});
|
|
145
154
|
},
|
|
146
155
|
[form, subscriptionId, planId, calculate, buildPlanExtras]
|
|
@@ -153,13 +162,7 @@ function BuyCreditsModal() {
|
|
|
153
162
|
if (!calculatedData) return null;
|
|
154
163
|
return getPriceFromCalculatedData(calculatedData, subscription?.periodicity);
|
|
155
164
|
}, [calculatedData, subscription]);
|
|
156
|
-
const
|
|
157
|
-
return price.toLocaleString("pt-BR", {
|
|
158
|
-
style: "currency",
|
|
159
|
-
currency: "BRL"
|
|
160
|
-
});
|
|
161
|
-
}, []);
|
|
162
|
-
const isConfirmDisabled = !isDirty || !isValid || isCalculatePending || isSubmitting;
|
|
165
|
+
const isConfirmDisabled = !isDirty || !isValid || isCalculatePending || isSubmitting || !hasPerCreditPrice;
|
|
163
166
|
const handleClose = useCallback(() => {
|
|
164
167
|
form.reset();
|
|
165
168
|
closeModal();
|
|
@@ -168,48 +171,57 @@ function BuyCreditsModal() {
|
|
|
168
171
|
openModal("addCardModal");
|
|
169
172
|
}, [openModal]);
|
|
170
173
|
const selectOptions = useMemo(() => {
|
|
171
|
-
return
|
|
174
|
+
return aiCreditOptions.map((opt) => ({
|
|
172
175
|
value: opt.credits,
|
|
173
176
|
label: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-2 w-full", children: [
|
|
174
|
-
/* @__PURE__ */ jsx("span", { className: "paragraph-small-medium text-zinc-950 flex-1", children: translate("common.credits.buy.creditsOptionLabel", { credits: opt.credits.toLocaleString(
|
|
175
|
-
/* @__PURE__ */ jsx("span", { className: "paragraph-small-medium text-zinc-500 opacity-70", children: opt.
|
|
177
|
+
/* @__PURE__ */ jsx("span", { className: "paragraph-small-medium text-zinc-950 flex-1", children: translate("common.credits.buy.creditsOptionLabel", { credits: opt.credits.toLocaleString(locale) }) }),
|
|
178
|
+
hasPerCreditPrice && /* @__PURE__ */ jsx("span", { className: "paragraph-small-medium text-zinc-500 opacity-70", children: formatCurrencyNumber(opt.price) })
|
|
176
179
|
] }),
|
|
177
|
-
displayValue: translate("common.credits.buy.creditsOptionDisplayValue", { credits: opt.credits.toLocaleString(
|
|
180
|
+
displayValue: translate("common.credits.buy.creditsOptionDisplayValue", { credits: opt.credits.toLocaleString(locale) })
|
|
178
181
|
}));
|
|
179
|
-
}, [translate]);
|
|
182
|
+
}, [aiCreditOptions, translate, locale, formatCurrencyNumber, hasPerCreditPrice]);
|
|
180
183
|
const onSubmit = useCallback(
|
|
181
184
|
async (data) => {
|
|
182
185
|
if (!subscriptionId) return;
|
|
183
|
-
|
|
184
|
-
if (!
|
|
186
|
+
if (!hasPerCreditPrice) return;
|
|
187
|
+
if (!AI_CREDIT_VALUES.has(data.creditOption)) return;
|
|
185
188
|
await updatePlanMutation.mutateAsync({
|
|
186
189
|
subscriptionId,
|
|
187
190
|
data: {
|
|
188
|
-
plan_extras: buildPlanExtras(
|
|
191
|
+
plan_extras: buildPlanExtras(data.creditOption)
|
|
189
192
|
}
|
|
190
193
|
});
|
|
191
194
|
toast.custom((t) => /* @__PURE__ */ jsx(
|
|
192
195
|
Toast,
|
|
193
196
|
{
|
|
194
197
|
variant: "success",
|
|
195
|
-
message: translate("common.credits.buy.creditsChangedToast", { credits: data.creditOption.toLocaleString(
|
|
198
|
+
message: translate("common.credits.buy.creditsChangedToast", { credits: data.creditOption.toLocaleString(locale) }),
|
|
196
199
|
toastId: t
|
|
197
200
|
}
|
|
198
201
|
));
|
|
199
202
|
form.reset();
|
|
200
203
|
closeModal();
|
|
201
204
|
},
|
|
202
|
-
[
|
|
205
|
+
[
|
|
206
|
+
subscriptionId,
|
|
207
|
+
hasPerCreditPrice,
|
|
208
|
+
updatePlanMutation,
|
|
209
|
+
form,
|
|
210
|
+
closeModal,
|
|
211
|
+
buildPlanExtras,
|
|
212
|
+
translate,
|
|
213
|
+
locale
|
|
214
|
+
]
|
|
203
215
|
);
|
|
204
216
|
const renderPriceDisplay = useCallback(() => {
|
|
205
217
|
if (isCalculatePending) {
|
|
206
218
|
return /* @__PURE__ */ jsx(Skeleton, { className: "h-7 w-24" });
|
|
207
219
|
}
|
|
208
220
|
if (totalPrice !== null) {
|
|
209
|
-
return /* @__PURE__ */ jsx("span", { className: "paragraph-xlarge-semibold text-zinc-950", children: totalPrice === 0 ? translate("common.credits.buy.defaultPrice") :
|
|
221
|
+
return /* @__PURE__ */ jsx("span", { className: "paragraph-xlarge-semibold text-zinc-950", children: totalPrice === 0 ? translate("common.credits.buy.defaultPrice") : formatCurrencyNumber(totalPrice) });
|
|
210
222
|
}
|
|
211
223
|
return /* @__PURE__ */ jsx("span", { className: "paragraph-xlarge-semibold text-zinc-400", children: "--" });
|
|
212
|
-
}, [isCalculatePending, totalPrice,
|
|
224
|
+
}, [isCalculatePending, totalPrice, formatCurrencyNumber, translate]);
|
|
213
225
|
if (isExternalContracting) {
|
|
214
226
|
return /* @__PURE__ */ jsx(Dialog, { open, onOpenChange: handleClose, children: /* @__PURE__ */ jsxs(DialogContent, { className: "flex flex-col p-0 gap-0 w-full md:w-[410px] lg:w-[410px]", children: [
|
|
215
227
|
/* @__PURE__ */ jsxs(DialogHeader, { className: "gap-3 text-left p-5", children: [
|
|
@@ -284,7 +296,7 @@ function BuyCreditsModal() {
|
|
|
284
296
|
/* @__PURE__ */ jsxs("div", { className: "hidden lg:flex flex-col gap-2", children: [
|
|
285
297
|
immediateChargeTotal !== null && immediateChargeTotal > 0 && /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
|
|
286
298
|
/* @__PURE__ */ jsx("span", { className: "paragraph-xsmall-medium text-zinc-500", children: translate("common.credits.buy.immediateCharge") }),
|
|
287
|
-
isCalculatePending ? /* @__PURE__ */ jsx(Skeleton, { className: "h-5 w-20" }) : /* @__PURE__ */ jsx("span", { className: "paragraph-small-semibold text-zinc-950", children:
|
|
299
|
+
isCalculatePending ? /* @__PURE__ */ jsx(Skeleton, { className: "h-5 w-20" }) : /* @__PURE__ */ jsx("span", { className: "paragraph-small-semibold text-zinc-950", children: formatCurrencyNumber(immediateChargeTotal) })
|
|
288
300
|
] }),
|
|
289
301
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
|
|
290
302
|
/* @__PURE__ */ jsx("span", { className: "paragraph-small-medium text-zinc-500", children: translate("common.credits.buy.totalPlanValue") }),
|
|
@@ -308,7 +320,7 @@ function BuyCreditsModal() {
|
|
|
308
320
|
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
|
|
309
321
|
immediateChargeTotal !== null && immediateChargeTotal > 0 && /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
|
|
310
322
|
/* @__PURE__ */ jsx("span", { className: "paragraph-xsmall-medium text-zinc-500", children: translate("common.credits.buy.immediateCharge") }),
|
|
311
|
-
isCalculatePending ? /* @__PURE__ */ jsx(Skeleton, { className: "h-5 w-20" }) : /* @__PURE__ */ jsx("span", { className: "paragraph-small-semibold text-zinc-950", children:
|
|
323
|
+
isCalculatePending ? /* @__PURE__ */ jsx(Skeleton, { className: "h-5 w-20" }) : /* @__PURE__ */ jsx("span", { className: "paragraph-small-semibold text-zinc-950", children: formatCurrencyNumber(immediateChargeTotal) })
|
|
312
324
|
] }),
|
|
313
325
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
|
|
314
326
|
/* @__PURE__ */ jsx("span", { className: "paragraph-small-medium text-zinc-500", children: translate("common.credits.buy.totalPlanValue") }),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/modals/BuyCreditsModal.tsx"],"sourcesContent":["'use client';\n\nimport {\n Dialog,\n DialogContent,\n DialogHeader,\n DialogTitle,\n} from '../ui/overlay/Dialog';\nimport { Button } from '../ui/buttons/Button';\nimport { Separator } from '../ui/data-display/Separator';\nimport { Toast } from '../ui/feedback/Toast';\nimport { SelectField } from '../ui/form/SelectField';\nimport { Skeleton } from '../ui/feedback/Skeleton';\nimport { PaymentInfoCard } from '../ui/data-display/PaymentInfoCard';\nimport { ADDON_IDS } from '../../modules/subscriptions/constants/addons.constants';\nimport {\n AI_CREDIT_OPTIONS,\n AI_CREDIT_VALUES,\n} from '../../modules/subscriptions/constants/addons.constants';\nimport { useBuyCreditsModal } from '../../store/useBuyCreditsModal';\nimport { useModalManager } from '../../store/useModalManager';\nimport { useCards } from '../../modules/cards/hooks/cards.hook';\nimport { useActiveSubscription } from '../../modules/subscriptions/hooks/find-active-subscription.hook';\nimport { useCalculateSubscription } from '../../modules/subscriptions/hooks/calculate-subscription.hook';\nimport { useUpdateSubscriptionPlan } from '../../modules/subscriptions/hooks/update-subscription-plan.hook';\nimport { getPriceFromCalculatedData } from '../../modules/subscriptions/utils/periodicity';\nimport { useIsDefaultWhitelabel, useExternalContracting } from '../../providers/whitelabel.provider';\nimport { IconInfoCircle, IconX, IconLoader2, IconSparkles } from '@tabler/icons-react';\nimport { useTranslations } from 'next-intl';\nimport { useCallback, useEffect, useMemo, useRef } from 'react';\nimport { useForm } from 'react-hook-form';\nimport { zodResolver } from '@hookform/resolvers/zod';\nimport z from 'zod';\nimport { toast } from 'sonner';\n\nconst buyCreditSchema = z.object({\n creditOption: z.number().refine((val) => AI_CREDIT_VALUES.has(val), {\n message: 'Selecione uma opção de créditos',\n }),\n selectedCardId: z.string().min(1, 'Selecione um cartão'),\n});\n\ntype BuyCreditFormData = z.infer<typeof buyCreditSchema>;\n\nexport default function BuyCreditsModal() {\n const translate = useTranslations();\n const { open, closeModal } = useBuyCreditsModal();\n const { openModal } = useModalManager();\n const isDefaultWl = useIsDefaultWhitelabel();\n const { isExternalContracting, redirectToExternal } = useExternalContracting();\n const { data: cardsData } = useCards();\n const { data: subscriptionData } = useActiveSubscription();\n const subscription = subscriptionData?.data?.[0] ?? null;\n const defaultCardId =\n cardsData?.data?.find((card) => card.is_default)?.id?.toString() ??\n cardsData?.data?.[0]?.id?.toString() ??\n '';\n\n const {\n mutate: calculate,\n isPending: isCalculatePending,\n data: calculateData,\n } = useCalculateSubscription();\n const updatePlanMutation = useUpdateSubscriptionPlan();\n\n const aiItem = useMemo(\n () =>\n subscription?.items?.find(\n (item) => item.id_addon === ADDON_IDS.AI && (item.value ?? 0) > 0\n ),\n [subscription]\n );\n\n const currentCredits = aiItem?.quantity ?? 0;\n const subscriptionId = subscription?.id;\n const planId = subscription?.id_plan;\n\n const buildPlanExtras = useCallback(\n (aiQuantity: number) => {\n const aiOption = AI_CREDIT_OPTIONS.find(opt => opt.credits === aiQuantity);\n return [\n ...(subscription?.items ?? [])\n .filter((item) => item.id_addon != null && item.id_addon !== ADDON_IDS.AI)\n .map((item: any) => ({ \n id_addon: Number(item.id_addon), \n quantity: item.quantity ?? 0,\n value: Number(item.value ?? 0),\n price: item.price,\n })),\n { \n id_addon: ADDON_IDS.AI, \n quantity: aiQuantity,\n value: aiOption?.price ?? 0 \n },\n ];\n },\n [subscription]\n );\n\n const form = useForm<BuyCreditFormData>({\n resolver: zodResolver(buyCreditSchema),\n mode: 'onChange',\n defaultValues: {\n creditOption: currentCredits,\n selectedCardId: defaultCardId,\n },\n });\n\n const hasInitialized = useRef(false);\n\n useEffect(() => {\n if (!open) {\n hasInitialized.current = false;\n return;\n }\n\n if (hasInitialized.current || !subscription) return;\n hasInitialized.current = true;\n\n form.reset({\n creditOption: currentCredits,\n selectedCardId: defaultCardId,\n });\n\n calculate({\n id_product: 1,\n ...(planId != null && { id_plan: planId }),\n ...(subscriptionId != null && { id_subscription: subscriptionId }),\n plan_extras: buildPlanExtras(currentCredits),\n });\n }, [\n open,\n subscription,\n currentCredits,\n defaultCardId,\n form,\n calculate,\n planId,\n subscriptionId,\n buildPlanExtras,\n ]);\n\n // Sync selectedCardId when cards load after modal opened\n useEffect(() => {\n if (open && defaultCardId && !form.getValues('selectedCardId')) {\n form.setValue('selectedCardId', defaultCardId, { shouldValidate: true });\n }\n }, [open, defaultCardId, form]);\n\n const creditOption = form.watch('creditOption');\n const selectedCardId = form.watch('selectedCardId');\n const { isDirty, isSubmitting, isValid } = form.formState;\n\n\n const handleCreditOptionChange = useCallback(\n (value: string | number | boolean) => {\n const credits = Number(value);\n\n form.setValue('creditOption', credits, {\n shouldValidate: true,\n shouldDirty: true,\n });\n\n const option = AI_CREDIT_OPTIONS.find((opt) => opt.credits === credits);\n if (!option) return;\n\n calculate({\n id_product: 1,\n ...(planId != null && { id_plan: planId }),\n ...(subscriptionId != null && { id_subscription: subscriptionId }),\n plan_extras: buildPlanExtras(option.credits),\n });\n },\n [form, subscriptionId, planId, calculate, buildPlanExtras]\n );\n\n const calculatedData = calculateData?.data ?? null;\n\n const isIncreasingCredits = creditOption > currentCredits;\n const hasChanged = creditOption !== currentCredits;\n\n const immediateChargeTotal = calculatedData?.target?.immediate_charge?.total ?? null;\n\n const totalPrice = useMemo(() => {\n if (!calculatedData) return null;\n return getPriceFromCalculatedData(calculatedData, subscription?.periodicity);\n }, [calculatedData, subscription]);\n\n const formatPrice = useCallback((price: number) => {\n return price.toLocaleString('pt-BR', {\n style: 'currency',\n currency: 'BRL',\n });\n }, []);\n\n const isConfirmDisabled = !isDirty || !isValid || isCalculatePending || isSubmitting;\n\n const handleClose = useCallback(() => {\n form.reset();\n closeModal();\n }, [form, closeModal]);\n\n const handleOpenAddCardModal = useCallback(() => {\n openModal('addCardModal');\n }, [openModal]);\n\n const selectOptions = useMemo(() => {\n return AI_CREDIT_OPTIONS.map((opt) => ({\n value: opt.credits,\n label: (\n <div className=\"flex items-center justify-between gap-2 w-full\">\n <span className=\"paragraph-small-medium text-zinc-950 flex-1\">\n {translate('common.credits.buy.creditsOptionLabel', { credits: opt.credits.toLocaleString('pt-BR') })}\n </span>\n <span className=\"paragraph-small-medium text-zinc-500 opacity-70\">{opt.priceLabel}</span>\n </div>\n ),\n displayValue: translate('common.credits.buy.creditsOptionDisplayValue', { credits: opt.credits.toLocaleString('pt-BR') }),\n }));\n }, [translate]);\n\n const onSubmit = useCallback(\n async (data: BuyCreditFormData) => {\n if (!subscriptionId) return;\n\n const option = AI_CREDIT_OPTIONS.find((opt) => opt.credits === data.creditOption);\n if (!option) return;\n\n await updatePlanMutation.mutateAsync({\n subscriptionId,\n data: {\n plan_extras: buildPlanExtras(option.credits),\n },\n });\n\n toast.custom((t) => (\n <Toast\n variant=\"success\"\n message={translate('common.credits.buy.creditsChangedToast', { credits: data.creditOption.toLocaleString('pt-BR') })}\n toastId={t}\n />\n ));\n form.reset();\n closeModal();\n },\n [subscriptionId, updatePlanMutation, form, closeModal, buildPlanExtras]\n );\n\n const renderPriceDisplay = useCallback(() => {\n if (isCalculatePending) {\n return <Skeleton className=\"h-7 w-24\" />;\n }\n if (totalPrice !== null) {\n return (\n <span className=\"paragraph-xlarge-semibold text-zinc-950\">\n {totalPrice === 0 ? translate('common.credits.buy.defaultPrice') : formatPrice(totalPrice)}\n </span>\n );\n }\n return <span className=\"paragraph-xlarge-semibold text-zinc-400\">--</span>;\n }, [isCalculatePending, totalPrice, formatPrice]);\n\n if (isExternalContracting) {\n return (\n <Dialog open={open} onOpenChange={handleClose}>\n <DialogContent className=\"flex flex-col p-0 gap-0 w-full md:w-[410px] lg:w-[410px]\">\n <DialogHeader className=\"gap-3 text-left p-5\">\n <div className=\"flex items-center justify-center w-10 h-10 bg-zinc-50 rounded-lg\">\n <IconSparkles 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.credits.buy.externalTitle')}\n </DialogTitle>\n <span className=\"paragraph-small-regular text-zinc-600\">\n {translate('common.credits.buy.externalDescription')}\n </span>\n </div>\n </DialogHeader>\n <div className=\"flex items-center gap-2 p-5 border-t border-zinc-200\">\n <Button\n className=\"w-fit h-10!\"\n onClick={() => {\n closeModal();\n redirectToExternal('contracting');\n }}\n >\n {translate('common.credits.buy.externalButton')}\n </Button>\n </div>\n </DialogContent>\n </Dialog>\n );\n }\n\n return (\n <Dialog open={open} onOpenChange={handleClose}>\n <DialogContent\n showCloseButton={false}\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-[433px] 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 lg:overflow-y-auto\"\n >\n <DialogHeader className=\"px-4 py-3 border-b border-zinc-200 shrink-0 relative\">\n <DialogTitle className=\"paragraph-medium-semibold text-zinc-950 text-center\">\n {translate('common.credits.buy.title')}\n </DialogTitle>\n <button\n type=\"button\"\n onClick={handleClose}\n className=\"absolute right-3 top-1/2 -translate-y-1/2 size-8 flex items-center justify-center rounded-lg cursor-pointer hover:bg-zinc-100 transition-colors\"\n >\n <IconX size={18} className=\"text-zinc-400\" />\n </button>\n </DialogHeader>\n\n <form\n onSubmit={form.handleSubmit(onSubmit)}\n className=\"flex flex-col flex-1 lg:flex-none overflow-hidden\"\n >\n <div className=\"flex flex-col gap-6 lg:gap-8 p-4 lg:p-5 flex-1 lg:flex-none overflow-y-auto\">\n <div className=\"flex flex-col gap-4\">\n <SelectField\n options={selectOptions}\n value={creditOption}\n onChange={handleCreditOptionChange}\n className=\"h-12!\"\n />\n\n <PaymentInfoCard\n selectedCardId={selectedCardId}\n onCardSelect={(cardId) =>\n form.setValue('selectedCardId', cardId, { shouldValidate: true })\n }\n onOpenAddCard={handleOpenAddCardModal}\n />\n\n {hasChanged && (\n <div className={`flex items-center gap-3 p-4 rounded-lg ${isDefaultWl ? 'bg-cyan-50' : 'bg-zinc-50'}`}>\n <IconInfoCircle className=\"size-4 text-zinc-950 shrink-0\" />\n <span className=\"paragraph-small-regular text-zinc-950\">\n {isIncreasingCredits\n ? translate('common.credits.buy.paymentOnConfirm')\n : translate('common.credits.buy.nextInvoiceChanges')}\n </span>\n </div>\n )}\n </div>\n\n <Separator className=\"bg-zinc-200 hidden lg:block\" />\n\n <div className=\"hidden lg:flex flex-col gap-2\">\n {immediateChargeTotal !== null && immediateChargeTotal > 0 && (\n <div className=\"flex items-center justify-between\">\n <span className=\"paragraph-xsmall-medium text-zinc-500\">{translate('common.credits.buy.immediateCharge')}</span>\n {isCalculatePending ? (\n <Skeleton className=\"h-5 w-20\" />\n ) : (\n <span className=\"paragraph-small-semibold text-zinc-950\">\n {formatPrice(immediateChargeTotal)}\n </span>\n )}\n </div>\n )}\n <div className=\"flex items-center justify-between\">\n <span className=\"paragraph-small-medium text-zinc-500\">{translate('common.credits.buy.totalPlanValue')}</span>\n {renderPriceDisplay()}\n </div>\n </div>\n\n <Button\n type=\"submit\"\n disabled={isConfirmDisabled}\n className=\"w-full hidden lg:inline-flex\"\n >\n {isSubmitting && <IconLoader2 className=\"size-4 animate-spin\" />}\n {translate('common.credits.buy.confirmAndPay')}\n </Button>\n </div>\n\n <div className=\"flex flex-col gap-4 p-4 border-t border-zinc-200 shrink-0 lg:hidden\">\n <div className=\"flex flex-col gap-2\">\n {immediateChargeTotal !== null && immediateChargeTotal > 0 && (\n <div className=\"flex items-center justify-between\">\n <span className=\"paragraph-xsmall-medium text-zinc-500\">{translate('common.credits.buy.immediateCharge')}</span>\n {isCalculatePending ? (\n <Skeleton className=\"h-5 w-20\" />\n ) : (\n <span className=\"paragraph-small-semibold text-zinc-950\">\n {formatPrice(immediateChargeTotal)}\n </span>\n )}\n </div>\n )}\n <div className=\"flex items-center justify-between\">\n <span className=\"paragraph-small-medium text-zinc-500\">{translate('common.credits.buy.totalPlanValue')}</span>\n {renderPriceDisplay()}\n </div>\n </div>\n <Button type=\"submit\" disabled={isConfirmDisabled} className=\"w-full\">\n {isSubmitting && <IconLoader2 className=\"size-4 animate-spin\" />}\n {translate('common.credits.buy.confirmAndPay')}\n </Button>\n </div>\n </form>\n </DialogContent>\n </Dialog>\n );\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../src/components/modals/BuyCreditsModal.tsx"],"sourcesContent":["'use client';\n\nimport {\n Dialog,\n DialogContent,\n DialogHeader,\n DialogTitle,\n} from '../ui/overlay/Dialog';\nimport { Button } from '../ui/buttons/Button';\nimport { Separator } from '../ui/data-display/Separator';\nimport { Toast } from '../ui/feedback/Toast';\nimport { SelectField } from '../ui/form/SelectField';\nimport { Skeleton } from '../ui/feedback/Skeleton';\nimport { PaymentInfoCard } from '../ui/data-display/PaymentInfoCard';\nimport {\n ADDON_IDS,\n AI_CREDIT_VALUES,\n buildAiCreditOptions,\n} from '../../modules/subscriptions/constants/addons.constants';\nimport { useBuyCreditsModal } from '../../store/useBuyCreditsModal';\nimport { useModalManager } from '../../store/useModalManager';\nimport { useCards } from '../../modules/cards/hooks/cards.hook';\nimport { useCurrencyFormatter } from '../../modules/accounts/hooks/use-currency-formatter.hook';\nimport { usePlanById } from '../../modules/plans/hooks/use-plan-by-id.hook';\nimport { useActiveSubscription } from '../../modules/subscriptions/hooks/find-active-subscription.hook';\nimport { useCalculateSubscription } from '../../modules/subscriptions/hooks/calculate-subscription.hook';\nimport { useUpdateSubscriptionPlan } from '../../modules/subscriptions/hooks/update-subscription-plan.hook';\nimport { getPriceFromCalculatedData } from '../../modules/subscriptions/utils/periodicity';\nimport { useIsDefaultWhitelabel, useExternalContracting } from '../../providers/whitelabel.provider';\nimport { IconInfoCircle, IconX, IconLoader2, IconSparkles } from '@tabler/icons-react';\nimport { useTranslations } from 'next-intl';\nimport { useCallback, useEffect, useMemo, useRef } from 'react';\nimport { useForm } from 'react-hook-form';\nimport { zodResolver } from '@hookform/resolvers/zod';\nimport z from 'zod';\nimport { toast } from 'sonner';\n\nconst buyCreditSchema = z.object({\n creditOption: z.number().refine((val) => AI_CREDIT_VALUES.has(val), {\n message: 'Selecione uma opção de créditos',\n }),\n selectedCardId: z.string().min(1, 'Selecione um cartão'),\n});\n\ntype BuyCreditFormData = z.infer<typeof buyCreditSchema>;\n\nexport default function BuyCreditsModal() {\n const translate = useTranslations();\n const { open, closeModal } = useBuyCreditsModal();\n const { openModal } = useModalManager();\n const isDefaultWl = useIsDefaultWhitelabel();\n const { isExternalContracting, redirectToExternal } = useExternalContracting();\n const { data: cardsData } = useCards();\n const { locale, formatCurrencyNumber } = useCurrencyFormatter();\n const { data: subscriptionData } = useActiveSubscription();\n const subscription = subscriptionData?.data?.[0] ?? null;\n const defaultCardId =\n cardsData?.data?.find((card) => card.is_default)?.id?.toString() ??\n cardsData?.data?.[0]?.id?.toString() ??\n '';\n\n const {\n mutate: calculate,\n isPending: isCalculatePending,\n data: calculateData,\n } = useCalculateSubscription();\n const updatePlanMutation = useUpdateSubscriptionPlan();\n\n const aiItem = useMemo(\n () =>\n subscription?.items?.find(\n (item) => item.id_addon === ADDON_IDS.AI && (item.value ?? 0) > 0\n ),\n [subscription]\n );\n\n const currentCredits = aiItem?.quantity ?? 0;\n const subscriptionId = subscription?.id;\n const planId = subscription?.id_plan;\n\n const { data: planData } = usePlanById(planId);\n const perCreditPrice = useMemo(() => {\n const planAiItem = planData?.data?.items?.find(\n (item) => item.id_addon === ADDON_IDS.AI && (item.value ?? 0) > 0\n );\n return planAiItem?.value ?? aiItem?.value ?? 0;\n }, [planData, aiItem]);\n\n const hasPerCreditPrice = perCreditPrice > 0;\n\n const aiCreditOptions = useMemo(() => buildAiCreditOptions(perCreditPrice), [perCreditPrice]);\n\n const buildPlanExtras = useCallback(\n (aiQuantity: number) => {\n return [\n ...(subscription?.items ?? [])\n .filter((item) => item.id_addon != null && item.id_addon !== ADDON_IDS.AI)\n .map((item: any) => ({ \n id_addon: Number(item.id_addon), \n quantity: item.quantity ?? 0,\n value: Number(item.value ?? 0),\n price: item.price,\n })),\n {\n id_addon: ADDON_IDS.AI,\n quantity: aiQuantity,\n },\n ];\n },\n [subscription]\n );\n\n const form = useForm<BuyCreditFormData>({\n resolver: zodResolver(buyCreditSchema),\n mode: 'onChange',\n defaultValues: {\n creditOption: currentCredits,\n selectedCardId: defaultCardId,\n },\n });\n\n const hasInitialized = useRef(false);\n\n useEffect(() => {\n if (!open) {\n hasInitialized.current = false;\n return;\n }\n\n if (hasInitialized.current || !subscription) return;\n hasInitialized.current = true;\n\n form.reset({\n creditOption: currentCredits,\n selectedCardId: defaultCardId,\n });\n\n calculate({\n id_product: 1,\n ...(planId != null && { id_plan: planId }),\n ...(subscriptionId != null && { id_subscription: subscriptionId }),\n plan_extras: buildPlanExtras(currentCredits),\n });\n }, [\n open,\n subscription,\n currentCredits,\n defaultCardId,\n form,\n calculate,\n planId,\n subscriptionId,\n buildPlanExtras,\n ]);\n\n // Sync selectedCardId when cards load after modal opened\n useEffect(() => {\n if (open && defaultCardId && !form.getValues('selectedCardId')) {\n form.setValue('selectedCardId', defaultCardId, { shouldValidate: true });\n }\n }, [open, defaultCardId, form]);\n\n const creditOption = form.watch('creditOption');\n const selectedCardId = form.watch('selectedCardId');\n const { isDirty, isSubmitting, isValid } = form.formState;\n\n\n const handleCreditOptionChange = useCallback(\n (value: string | number | boolean) => {\n const credits = Number(value);\n\n form.setValue('creditOption', credits, {\n shouldValidate: true,\n shouldDirty: true,\n });\n\n if (!AI_CREDIT_VALUES.has(credits)) return;\n\n calculate({\n id_product: 1,\n ...(planId != null && { id_plan: planId }),\n ...(subscriptionId != null && { id_subscription: subscriptionId }),\n plan_extras: buildPlanExtras(credits),\n });\n },\n [form, subscriptionId, planId, calculate, buildPlanExtras]\n );\n\n const calculatedData = calculateData?.data ?? null;\n\n const isIncreasingCredits = creditOption > currentCredits;\n const hasChanged = creditOption !== currentCredits;\n\n const immediateChargeTotal = calculatedData?.target?.immediate_charge?.total ?? null;\n\n const totalPrice = useMemo(() => {\n if (!calculatedData) return null;\n return getPriceFromCalculatedData(calculatedData, subscription?.periodicity);\n }, [calculatedData, subscription]);\n\n const isConfirmDisabled =\n !isDirty || !isValid || isCalculatePending || isSubmitting || !hasPerCreditPrice;\n\n const handleClose = useCallback(() => {\n form.reset();\n closeModal();\n }, [form, closeModal]);\n\n const handleOpenAddCardModal = useCallback(() => {\n openModal('addCardModal');\n }, [openModal]);\n\n const selectOptions = useMemo(() => {\n return aiCreditOptions.map((opt) => ({\n value: opt.credits,\n label: (\n <div className=\"flex items-center justify-between gap-2 w-full\">\n <span className=\"paragraph-small-medium text-zinc-950 flex-1\">\n {translate('common.credits.buy.creditsOptionLabel', { credits: opt.credits.toLocaleString(locale) })}\n </span>\n {hasPerCreditPrice && (\n <span className=\"paragraph-small-medium text-zinc-500 opacity-70\">{formatCurrencyNumber(opt.price)}</span>\n )}\n </div>\n ),\n displayValue: translate('common.credits.buy.creditsOptionDisplayValue', { credits: opt.credits.toLocaleString(locale) }),\n }));\n }, [aiCreditOptions, translate, locale, formatCurrencyNumber, hasPerCreditPrice]);\n\n const onSubmit = useCallback(\n async (data: BuyCreditFormData) => {\n if (!subscriptionId) return;\n if (!hasPerCreditPrice) return;\n if (!AI_CREDIT_VALUES.has(data.creditOption)) return;\n\n await updatePlanMutation.mutateAsync({\n subscriptionId,\n data: {\n plan_extras: buildPlanExtras(data.creditOption),\n },\n });\n\n toast.custom((t) => (\n <Toast\n variant=\"success\"\n message={translate('common.credits.buy.creditsChangedToast', { credits: data.creditOption.toLocaleString(locale) })}\n toastId={t}\n />\n ));\n form.reset();\n closeModal();\n },\n [\n subscriptionId,\n hasPerCreditPrice,\n updatePlanMutation,\n form,\n closeModal,\n buildPlanExtras,\n translate,\n locale,\n ]\n );\n\n const renderPriceDisplay = useCallback(() => {\n if (isCalculatePending) {\n return <Skeleton className=\"h-7 w-24\" />;\n }\n if (totalPrice !== null) {\n return (\n <span className=\"paragraph-xlarge-semibold text-zinc-950\">\n {totalPrice === 0 ? translate('common.credits.buy.defaultPrice') : formatCurrencyNumber(totalPrice)}\n </span>\n );\n }\n return <span className=\"paragraph-xlarge-semibold text-zinc-400\">--</span>;\n }, [isCalculatePending, totalPrice, formatCurrencyNumber, translate]);\n\n if (isExternalContracting) {\n return (\n <Dialog open={open} onOpenChange={handleClose}>\n <DialogContent className=\"flex flex-col p-0 gap-0 w-full md:w-[410px] lg:w-[410px]\">\n <DialogHeader className=\"gap-3 text-left p-5\">\n <div className=\"flex items-center justify-center w-10 h-10 bg-zinc-50 rounded-lg\">\n <IconSparkles 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.credits.buy.externalTitle')}\n </DialogTitle>\n <span className=\"paragraph-small-regular text-zinc-600\">\n {translate('common.credits.buy.externalDescription')}\n </span>\n </div>\n </DialogHeader>\n <div className=\"flex items-center gap-2 p-5 border-t border-zinc-200\">\n <Button\n className=\"w-fit h-10!\"\n onClick={() => {\n closeModal();\n redirectToExternal('contracting');\n }}\n >\n {translate('common.credits.buy.externalButton')}\n </Button>\n </div>\n </DialogContent>\n </Dialog>\n );\n }\n\n return (\n <Dialog open={open} onOpenChange={handleClose}>\n <DialogContent\n showCloseButton={false}\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-[433px] 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 lg:overflow-y-auto\"\n >\n <DialogHeader className=\"px-4 py-3 border-b border-zinc-200 shrink-0 relative\">\n <DialogTitle className=\"paragraph-medium-semibold text-zinc-950 text-center\">\n {translate('common.credits.buy.title')}\n </DialogTitle>\n <button\n type=\"button\"\n onClick={handleClose}\n className=\"absolute right-3 top-1/2 -translate-y-1/2 size-8 flex items-center justify-center rounded-lg cursor-pointer hover:bg-zinc-100 transition-colors\"\n >\n <IconX size={18} className=\"text-zinc-400\" />\n </button>\n </DialogHeader>\n\n <form\n onSubmit={form.handleSubmit(onSubmit)}\n className=\"flex flex-col flex-1 lg:flex-none overflow-hidden\"\n >\n <div className=\"flex flex-col gap-6 lg:gap-8 p-4 lg:p-5 flex-1 lg:flex-none overflow-y-auto\">\n <div className=\"flex flex-col gap-4\">\n <SelectField\n options={selectOptions}\n value={creditOption}\n onChange={handleCreditOptionChange}\n className=\"h-12!\"\n />\n\n <PaymentInfoCard\n selectedCardId={selectedCardId}\n onCardSelect={(cardId) =>\n form.setValue('selectedCardId', cardId, { shouldValidate: true })\n }\n onOpenAddCard={handleOpenAddCardModal}\n />\n\n {hasChanged && (\n <div className={`flex items-center gap-3 p-4 rounded-lg ${isDefaultWl ? 'bg-cyan-50' : 'bg-zinc-50'}`}>\n <IconInfoCircle className=\"size-4 text-zinc-950 shrink-0\" />\n <span className=\"paragraph-small-regular text-zinc-950\">\n {isIncreasingCredits\n ? translate('common.credits.buy.paymentOnConfirm')\n : translate('common.credits.buy.nextInvoiceChanges')}\n </span>\n </div>\n )}\n </div>\n\n <Separator className=\"bg-zinc-200 hidden lg:block\" />\n\n <div className=\"hidden lg:flex flex-col gap-2\">\n {immediateChargeTotal !== null && immediateChargeTotal > 0 && (\n <div className=\"flex items-center justify-between\">\n <span className=\"paragraph-xsmall-medium text-zinc-500\">{translate('common.credits.buy.immediateCharge')}</span>\n {isCalculatePending ? (\n <Skeleton className=\"h-5 w-20\" />\n ) : (\n <span className=\"paragraph-small-semibold text-zinc-950\">\n {formatCurrencyNumber(immediateChargeTotal)}\n </span>\n )}\n </div>\n )}\n <div className=\"flex items-center justify-between\">\n <span className=\"paragraph-small-medium text-zinc-500\">{translate('common.credits.buy.totalPlanValue')}</span>\n {renderPriceDisplay()}\n </div>\n </div>\n\n <Button\n type=\"submit\"\n disabled={isConfirmDisabled}\n className=\"w-full hidden lg:inline-flex\"\n >\n {isSubmitting && <IconLoader2 className=\"size-4 animate-spin\" />}\n {translate('common.credits.buy.confirmAndPay')}\n </Button>\n </div>\n\n <div className=\"flex flex-col gap-4 p-4 border-t border-zinc-200 shrink-0 lg:hidden\">\n <div className=\"flex flex-col gap-2\">\n {immediateChargeTotal !== null && immediateChargeTotal > 0 && (\n <div className=\"flex items-center justify-between\">\n <span className=\"paragraph-xsmall-medium text-zinc-500\">{translate('common.credits.buy.immediateCharge')}</span>\n {isCalculatePending ? (\n <Skeleton className=\"h-5 w-20\" />\n ) : (\n <span className=\"paragraph-small-semibold text-zinc-950\">\n {formatCurrencyNumber(immediateChargeTotal)}\n </span>\n )}\n </div>\n )}\n <div className=\"flex items-center justify-between\">\n <span className=\"paragraph-small-medium text-zinc-500\">{translate('common.credits.buy.totalPlanValue')}</span>\n {renderPriceDisplay()}\n </div>\n </div>\n <Button type=\"submit\" disabled={isConfirmDisabled} className=\"w-full\">\n {isSubmitting && <IconLoader2 className=\"size-4 animate-spin\" />}\n {translate('common.credits.buy.confirmAndPay')}\n </Button>\n </div>\n </form>\n </DialogContent>\n </Dialog>\n );\n}\n"],"mappings":"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","names":[]}
|
|
@@ -9,6 +9,7 @@ import { useCreateCard } from "../../../modules/cards/hooks/create-card.hook";
|
|
|
9
9
|
import { useCreateSetupIntent } from "../../../modules/cards/hooks/create-setup-intent.hook";
|
|
10
10
|
import { useCurrentAccount } from "../../../modules/accounts/hooks/current-account.hook";
|
|
11
11
|
import { isValidTaxId } from "../../../utils/validators/common";
|
|
12
|
+
import { isUsdAccount } from "../../../utils/format/gateway";
|
|
12
13
|
import { useExternalContracting } from "../../../providers/whitelabel.provider";
|
|
13
14
|
import { CardFormFields, BillingFormFields, buildCardFormSchema } from "./CardFormFields";
|
|
14
15
|
import { IconX, IconCreditCard, IconCheck, IconChevronRight } from "@tabler/icons-react";
|
|
@@ -67,7 +68,7 @@ function AddCardModal() {
|
|
|
67
68
|
const isOpen = activeModal === "addCardModal";
|
|
68
69
|
const { isExternalContracting, redirectToExternal } = useExternalContracting();
|
|
69
70
|
const { data: account } = useCurrentAccount();
|
|
70
|
-
const isInternational = account
|
|
71
|
+
const isInternational = isUsdAccount(account);
|
|
71
72
|
const [currentStep, setCurrentStep] = useState(1);
|
|
72
73
|
const [stripeStatus, setStripeStatus] = useState(INITIAL_STRIPE_STATUS);
|
|
73
74
|
const [stripeErrors, setStripeErrors] = useState({});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/components/modals/cards/AddCardModal.tsx"],"sourcesContent":["'use client';\n\nimport { useCallback, useState, useEffect } from 'react';\nimport { Dialog, DialogContent, DialogHeader, DialogTitle } from '../../ui/overlay/Dialog';\nimport { Button } from '../../ui/buttons/Button';\nimport { Toast } from '../../ui/feedback/Toast';\nimport { useModalManager } from '../../../store/useModalManager';\nimport { useCreateCard } from '../../../modules/cards/hooks/create-card.hook';\nimport { useCreateSetupIntent } from '../../../modules/cards/hooks/create-setup-intent.hook';\nimport { useCurrentAccount } from '../../../modules/accounts/hooks/current-account.hook';\nimport { isValidTaxId } from '../../../utils/validators/common';\nimport { useExternalContracting } from '../../../providers/whitelabel.provider';\nimport { CardFormFields, BillingFormFields, buildCardFormSchema } from './CardFormFields';\nimport type { CardFormData, StripeElementsStatus } from './CardFormFields';\nimport { IconX, IconCreditCard, IconCheck, IconChevronRight } from '@tabler/icons-react';\nimport { cn } from '../../../infra/utils/clsx';\nimport { useForm } from 'react-hook-form';\nimport { zodResolver } from '@hookform/resolvers/zod';\nimport { CardNumberElement, useElements, useStripe } from '@stripe/react-stripe-js';\nimport { toast } from 'sonner';\nimport { useTranslations } from 'next-intl';\n\nconst INITIAL_STRIPE_STATUS: StripeElementsStatus = {\n cardNumber: false,\n cardExpiry: false,\n cardCvc: false,\n};\n\nfunction CardStepper({ currentStep }: { readonly currentStep: number }) {\n const translate = useTranslations();\n const steps = [\n { number: 1, label: translate('common.cards.add.stepBilling') },\n { number: 2, label: translate('common.cards.add.stepCard') },\n ];\n return (\n <div className=\"flex items-center justify-start gap-2 px-4 py-3 bg-zinc-50 border-b border-zinc-200 lg:border-b-0\">\n {steps.map((step, idx) => {\n const isCompleted = currentStep > step.number;\n const isCurrent = currentStep === step.number;\n const isPending = !isCompleted && !isCurrent;\n return (\n <div key={step.number} className=\"flex items-center gap-2\">\n <div\n className={cn(\n 'flex items-center justify-center size-6 rounded-full paragraph-xsmall-semibold',\n isCompleted && 'bg-green-50 text-green-600 border border-green-200',\n isCurrent && 'bg-primary text-zinc-950',\n isPending && 'border border-zinc-200 text-zinc-400',\n )}\n >\n {isCompleted ? (\n <IconCheck size={14} stroke={3} />\n ) : (\n step.number\n )}\n </div>\n <span\n className={cn(\n 'paragraph-xsmall-semibold',\n (isCompleted || isCurrent) && 'text-zinc-950',\n isPending && 'text-zinc-400',\n )}\n >\n {step.label}\n </span>\n {idx < steps.length - 1 && (\n <IconChevronRight size={16} className=\"text-zinc-300 ml-1\" />\n )}\n </div>\n );\n })}\n </div>\n );\n}\n\nexport default function AddCardModal() {\n const translate = useTranslations();\n const { activeModal, modalData, closeModal } = useModalManager();\n const isOpen = activeModal === 'addCardModal';\n const { isExternalContracting, redirectToExternal } = useExternalContracting();\n const { data: account } = useCurrentAccount();\n const isInternational = account?.gateway === 'stripe_usd';\n const [currentStep, setCurrentStep] = useState(1);\n const [stripeStatus, setStripeStatus] = useState<StripeElementsStatus>(INITIAL_STRIPE_STATUS);\n const [stripeErrors, setStripeErrors] = useState<Record<string, string | undefined>>({});\n const [isAuthenticating, setIsAuthenticating] = useState(false);\n\n const onCardAdded = modalData.onCardAdded as ((cardId: string) => void) | undefined;\n\n const createSetupIntentMutation = useCreateSetupIntent();\n const createCardMutation = useCreateCard();\n const elements = useElements();\n const stripe = useStripe();\n\n const form = useForm<CardFormData>({\n resolver: zodResolver(buildCardFormSchema(isInternational)),\n mode: 'onSubmit',\n reValidateMode: 'onChange',\n defaultValues: {\n country: 'BR',\n personType: 'pf',\n },\n });\n\n useEffect(() => {\n if (isInternational) {\n form.setValue('country', 'US');\n }\n }, [isInternational, form]);\n\n const handleClose = useCallback(() => {\n form.reset();\n setCurrentStep(1);\n setStripeStatus(INITIAL_STRIPE_STATUS);\n setStripeErrors({});\n setIsAuthenticating(false);\n closeModal();\n }, [form, closeModal]);\n\n const handleStripeChange = useCallback(\n (field: keyof StripeElementsStatus, complete: boolean) => {\n setStripeStatus((prev) => ({ ...prev, [field]: complete }));\n if (complete) {\n setStripeErrors((prev) => ({ ...prev, [field]: undefined }));\n }\n },\n []\n );\n\n const handleContinue = useCallback(async () => {\n const fields: (keyof CardFormData)[] = isInternational\n ? ['fullName', 'cep', 'street', 'city', 'state']\n : ['fullName', 'cep', 'street', 'streetNumber', 'neighborhood', 'city', 'state'];\n const isValid = await form.trigger(fields);\n if (!isValid) return;\n setCurrentStep(2);\n }, [form, isInternational]);\n\n const handleBack = useCallback(() => {\n setCurrentStep(1);\n }, []);\n\n async function handleSubmit(data: CardFormData) {\n const newStripeErrors: Record<string, string | undefined> = {};\n if (!stripeStatus.cardNumber) newStripeErrors.cardNumber = translate('common.cards.form.cardNumberRequired');\n if (!stripeStatus.cardExpiry) newStripeErrors.cardExpiry = translate('common.cards.form.cardExpiryRequired');\n if (!stripeStatus.cardCvc) newStripeErrors.cardCvc = translate('common.cards.form.cardCvcRequired');\n setStripeErrors(newStripeErrors);\n\n const stripeValid =\n stripeStatus.cardNumber && stripeStatus.cardExpiry && stripeStatus.cardCvc;\n if (!stripeValid) return;\n if (!stripe || !elements) return;\n\n const cardElement = elements.getElement(CardNumberElement);\n if (!cardElement) return;\n\n setIsAuthenticating(true);\n try {\n const intentResult = await createSetupIntentMutation.mutateAsync();\n const intent = intentResult?.data;\n if (!intent?.client_secret || !intent?.setup_intent_id) {\n toast.custom(\n (t) => (\n <Toast\n variant=\"error\"\n message={translate('common.cards.add.errorInitAuth')}\n toastId={t}\n />\n ),\n { duration: 5000 }\n );\n return;\n }\n\n const billingDetails = isInternational\n ? {\n name: data.name,\n address: {\n line1: data.street,\n line2: data.complement || undefined,\n city: data.city,\n state: data.state,\n postal_code: data.cep,\n country: data.country,\n },\n }\n : { name: data.name };\n\n const { setupIntent, error } = await stripe.confirmCardSetup(intent.client_secret, {\n payment_method: {\n card: cardElement,\n billing_details: billingDetails,\n },\n });\n\n if (error) {\n toast.custom(\n (t) => (\n <Toast\n variant=\"error\"\n message={error.message || translate('common.cards.add.errorAuth')}\n toastId={t}\n />\n ),\n { duration: 5000 }\n );\n return;\n }\n\n if (setupIntent?.status !== 'succeeded') {\n toast.custom(\n (t) => (\n <Toast\n variant=\"error\"\n message={translate('common.cards.add.errorAuthStatus', { status: setupIntent?.status ?? translate('common.cards.add.statusUnknown') })}\n toastId={t}\n />\n ),\n { duration: 5000 }\n );\n return;\n }\n\n /* Chamada ÚNICA: os dados fiscais vão no mesmo request do cartão. O backend atualiza a\n * conta ANTES de registrar o cartão, fail-closed — fiscal rejeitado (CPF inválido etc.)\n * = cartão não registra e o erro chega com a mensagem específica no catch abaixo.\n * Substitui o Promise.all de createCard + updateAccount, que não tinha garantia entre as\n * pernas: quando o PUT de conta falhava, o cartão ficava salvo e a conta sem NENHUM dado\n * fiscal — e as faturas seguintes falhavam a emissão de nota em silêncio. */\n const cardResult = await createCardMutation.mutateAsync({\n setup_intent_id: intent.setup_intent_id,\n name: data.name,\n set_default: true,\n ...(isInternational\n ? {}\n : {\n financial_document_type: data.personType === 'pf' ? 1 : 2,\n financial_document: data.personType === 'pf' ? data.cpf : data.cnpj,\n }),\n financial_name: data.fullName,\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 if (cardResult.success && cardResult.data?.id != null) {\n onCardAdded?.(cardResult.data.id.toString());\n }\n\n toast.custom(\n (t) => <Toast variant=\"success\" message={translate('common.cards.add.successToast')} toastId={t} />,\n { duration: 5000 }\n );\n handleClose();\n } catch (error) {\n /* O backend fail-closed devolve a razão exata da recusa (ex.: \"CPF do pagador inválido —\n * confira os dígitos verificadores\"), e o withAction relança como Error com essa mensagem.\n * Engolir num texto genérico deixaria o usuário sem saber o que corrigir. */\n const backendMessage = error instanceof Error && error.message ? error.message : null;\n toast.custom(\n (t) => (\n <Toast\n variant=\"error\"\n message={backendMessage || translate('common.cards.add.errorSave')}\n toastId={t}\n />\n ),\n { duration: 5000 }\n );\n } finally {\n setIsAuthenticating(false);\n }\n }\n\n const isSubmitting =\n createCardMutation.isPending ||\n form.formState.isSubmitting;\n\n const watchedValues = form.watch(['name', 'country', 'personType', 'cpf', 'cnpj', 'fullName', 'cep', 'street', 'streetNumber', 'neighborhood', 'city', 'state']);\n const [name, country, personType, cpf, cnpj, fullName, cep, street, streetNumber, neighborhood, city, state] = watchedValues;\n const isBillingValid = isInternational\n ? !!fullName && !!cep && !!street && !!city && !!state\n : !!fullName &&\n !!cep && cep.length >= 9 &&\n !!street &&\n !!streetNumber &&\n !!neighborhood &&\n !!city &&\n !!state;\n const isCardValid = isInternational\n ? !!name && !!country && stripeStatus.cardNumber && stripeStatus.cardExpiry && stripeStatus.cardCvc\n : !!name &&\n !!country &&\n !!personType &&\n /* Dígito verificador, em sincronia com o schema (buildCardFormSchema) e com a validação\n * do backend — a regra antiga de tamanho deixava 111.111.111-11 habilitar o botão. */\n (personType === 'pf' ? isValidTaxId(cpf, 'cpf') : isValidTaxId(cnpj, 'cnpj')) &&\n stripeStatus.cardNumber &&\n stripeStatus.cardExpiry &&\n stripeStatus.cardCvc;\n\n if (isExternalContracting) {\n return (\n <Dialog open={isOpen} onOpenChange={handleClose}>\n <DialogContent className=\"flex flex-col p-0 gap-0 w-full md:w-[410px] lg:w-[410px]\">\n <DialogHeader className=\"gap-3 text-left p-5\">\n <div className=\"flex items-center justify-center w-10 h-10 bg-zinc-50 rounded-lg\">\n <IconCreditCard 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.cards.add.externalTitle')}\n </DialogTitle>\n <span className=\"paragraph-small-regular text-zinc-600\">\n {translate('common.cards.add.externalDescription')}\n </span>\n </div>\n </DialogHeader>\n <div className=\"flex items-center gap-2 p-5 border-t border-zinc-200\">\n <Button\n className=\"w-fit h-10!\"\n onClick={() => {\n handleClose();\n redirectToExternal('contracting');\n }}\n >\n {translate('common.cards.add.externalButton')}\n </Button>\n </div>\n </DialogContent>\n </Dialog>\n );\n }\n\n return (\n <Dialog open={isOpen} onOpenChange={handleClose}>\n <DialogContent\n showCloseButton={false}\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-y-auto\"\n >\n <DialogHeader className=\"p-0\">\n <div className=\"flex items-center justify-center px-4 py-3 relative border-b border-zinc-200 lg:border-b-0\">\n <DialogTitle className=\"paragraph-medium-semibold text-zinc-950 text-center\">\n {translate('common.cards.add.title')}\n </DialogTitle>\n <Button\n type=\"button\"\n variant=\"ghost\"\n className=\"size-8! p-0 absolute right-4\"\n onClick={handleClose}\n >\n <IconX size={18} />\n </Button>\n </div>\n </DialogHeader>\n\n <CardStepper currentStep={currentStep} />\n\n <form\n onSubmit={form.handleSubmit(handleSubmit)}\n className=\"flex flex-col flex-1 lg:flex-none\"\n >\n <div className={`flex flex-col gap-6 lg:gap-8 p-4 lg:p-5 flex-1 lg:flex-none ${currentStep !== 1 ? 'hidden' : ''}`}>\n <h2 className=\"font-[family-name:var(--font-outfit)] text-[18px] leading-tight font-semibold text-zinc-950\">\n {translate('common.cards.add.billingHeading')}\n </h2>\n <BillingFormFields form={form} isInternational={isInternational} />\n </div>\n <div className={`flex flex-col gap-6 lg:gap-8 p-4 lg:p-5 flex-1 lg:flex-none ${currentStep !== 2 ? 'hidden' : ''}`}>\n <h2 className=\"font-[family-name:var(--font-outfit)] text-[18px] leading-tight font-semibold text-zinc-950\">\n {translate('common.cards.add.cardHeading')}\n </h2>\n <CardFormFields\n form={form}\n onStripeChange={handleStripeChange}\n stripeErrors={stripeErrors}\n isInternational={isInternational}\n />\n </div>\n\n <div className=\"flex justify-between items-center p-4 lg:p-5 border-t border-zinc-200 gap-2 mt-auto lg:mt-0\">\n {currentStep === 1 ? (\n <>\n <Button variant=\"secondary\" type=\"button\" onClick={handleClose} className=\"h-10!\">\n {translate('common.actions.cancel')}\n </Button>\n <Button\n type=\"button\"\n className=\"h-10!\"\n onClick={handleContinue}\n disabled={!isBillingValid}\n >\n {translate('common.actions.continue')}\n </Button>\n </>\n ) : (\n <>\n <Button variant=\"secondary\" type=\"button\" onClick={handleBack} className=\"h-10!\">\n {translate('common.actions.back')}\n </Button>\n <Button\n type=\"submit\"\n className=\"h-10!\"\n disabled={isSubmitting || isAuthenticating || !isCardValid}\n loading={isAuthenticating || isSubmitting}\n >\n {isAuthenticating\n ? translate('common.cards.add.authenticating')\n : isSubmitting\n ? translate('common.cards.add.submitting')\n : translate('common.cards.add.submit')}\n </Button>\n </>\n )}\n </div>\n </form>\n </DialogContent>\n </Dialog>\n );\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../../src/components/modals/cards/AddCardModal.tsx"],"sourcesContent":["'use client';\n\nimport { useCallback, useState, useEffect } from 'react';\nimport { Dialog, DialogContent, DialogHeader, DialogTitle } from '../../ui/overlay/Dialog';\nimport { Button } from '../../ui/buttons/Button';\nimport { Toast } from '../../ui/feedback/Toast';\nimport { useModalManager } from '../../../store/useModalManager';\nimport { useCreateCard } from '../../../modules/cards/hooks/create-card.hook';\nimport { useCreateSetupIntent } from '../../../modules/cards/hooks/create-setup-intent.hook';\nimport { useCurrentAccount } from '../../../modules/accounts/hooks/current-account.hook';\nimport { isValidTaxId } from '../../../utils/validators/common';\nimport { isUsdAccount } from '../../../utils/format/gateway';\nimport { useExternalContracting } from '../../../providers/whitelabel.provider';\nimport { CardFormFields, BillingFormFields, buildCardFormSchema } from './CardFormFields';\nimport type { CardFormData, StripeElementsStatus } from './CardFormFields';\nimport { IconX, IconCreditCard, IconCheck, IconChevronRight } from '@tabler/icons-react';\nimport { cn } from '../../../infra/utils/clsx';\nimport { useForm } from 'react-hook-form';\nimport { zodResolver } from '@hookform/resolvers/zod';\nimport { CardNumberElement, useElements, useStripe } from '@stripe/react-stripe-js';\nimport { toast } from 'sonner';\nimport { useTranslations } from 'next-intl';\n\nconst INITIAL_STRIPE_STATUS: StripeElementsStatus = {\n cardNumber: false,\n cardExpiry: false,\n cardCvc: false,\n};\n\nfunction CardStepper({ currentStep }: { readonly currentStep: number }) {\n const translate = useTranslations();\n const steps = [\n { number: 1, label: translate('common.cards.add.stepBilling') },\n { number: 2, label: translate('common.cards.add.stepCard') },\n ];\n return (\n <div className=\"flex items-center justify-start gap-2 px-4 py-3 bg-zinc-50 border-b border-zinc-200 lg:border-b-0\">\n {steps.map((step, idx) => {\n const isCompleted = currentStep > step.number;\n const isCurrent = currentStep === step.number;\n const isPending = !isCompleted && !isCurrent;\n return (\n <div key={step.number} className=\"flex items-center gap-2\">\n <div\n className={cn(\n 'flex items-center justify-center size-6 rounded-full paragraph-xsmall-semibold',\n isCompleted && 'bg-green-50 text-green-600 border border-green-200',\n isCurrent && 'bg-primary text-zinc-950',\n isPending && 'border border-zinc-200 text-zinc-400',\n )}\n >\n {isCompleted ? (\n <IconCheck size={14} stroke={3} />\n ) : (\n step.number\n )}\n </div>\n <span\n className={cn(\n 'paragraph-xsmall-semibold',\n (isCompleted || isCurrent) && 'text-zinc-950',\n isPending && 'text-zinc-400',\n )}\n >\n {step.label}\n </span>\n {idx < steps.length - 1 && (\n <IconChevronRight size={16} className=\"text-zinc-300 ml-1\" />\n )}\n </div>\n );\n })}\n </div>\n );\n}\n\nexport default function AddCardModal() {\n const translate = useTranslations();\n const { activeModal, modalData, closeModal } = useModalManager();\n const isOpen = activeModal === 'addCardModal';\n const { isExternalContracting, redirectToExternal } = useExternalContracting();\n const { data: account } = useCurrentAccount();\n const isInternational = isUsdAccount(account);\n const [currentStep, setCurrentStep] = useState(1);\n const [stripeStatus, setStripeStatus] = useState<StripeElementsStatus>(INITIAL_STRIPE_STATUS);\n const [stripeErrors, setStripeErrors] = useState<Record<string, string | undefined>>({});\n const [isAuthenticating, setIsAuthenticating] = useState(false);\n\n const onCardAdded = modalData.onCardAdded as ((cardId: string) => void) | undefined;\n\n const createSetupIntentMutation = useCreateSetupIntent();\n const createCardMutation = useCreateCard();\n const elements = useElements();\n const stripe = useStripe();\n\n const form = useForm<CardFormData>({\n resolver: zodResolver(buildCardFormSchema(isInternational)),\n mode: 'onSubmit',\n reValidateMode: 'onChange',\n defaultValues: {\n country: 'BR',\n personType: 'pf',\n },\n });\n\n useEffect(() => {\n if (isInternational) {\n form.setValue('country', 'US');\n }\n }, [isInternational, form]);\n\n const handleClose = useCallback(() => {\n form.reset();\n setCurrentStep(1);\n setStripeStatus(INITIAL_STRIPE_STATUS);\n setStripeErrors({});\n setIsAuthenticating(false);\n closeModal();\n }, [form, closeModal]);\n\n const handleStripeChange = useCallback(\n (field: keyof StripeElementsStatus, complete: boolean) => {\n setStripeStatus((prev) => ({ ...prev, [field]: complete }));\n if (complete) {\n setStripeErrors((prev) => ({ ...prev, [field]: undefined }));\n }\n },\n []\n );\n\n const handleContinue = useCallback(async () => {\n const fields: (keyof CardFormData)[] = isInternational\n ? ['fullName', 'cep', 'street', 'city', 'state']\n : ['fullName', 'cep', 'street', 'streetNumber', 'neighborhood', 'city', 'state'];\n const isValid = await form.trigger(fields);\n if (!isValid) return;\n setCurrentStep(2);\n }, [form, isInternational]);\n\n const handleBack = useCallback(() => {\n setCurrentStep(1);\n }, []);\n\n async function handleSubmit(data: CardFormData) {\n const newStripeErrors: Record<string, string | undefined> = {};\n if (!stripeStatus.cardNumber) newStripeErrors.cardNumber = translate('common.cards.form.cardNumberRequired');\n if (!stripeStatus.cardExpiry) newStripeErrors.cardExpiry = translate('common.cards.form.cardExpiryRequired');\n if (!stripeStatus.cardCvc) newStripeErrors.cardCvc = translate('common.cards.form.cardCvcRequired');\n setStripeErrors(newStripeErrors);\n\n const stripeValid =\n stripeStatus.cardNumber && stripeStatus.cardExpiry && stripeStatus.cardCvc;\n if (!stripeValid) return;\n if (!stripe || !elements) return;\n\n const cardElement = elements.getElement(CardNumberElement);\n if (!cardElement) return;\n\n setIsAuthenticating(true);\n try {\n const intentResult = await createSetupIntentMutation.mutateAsync();\n const intent = intentResult?.data;\n if (!intent?.client_secret || !intent?.setup_intent_id) {\n toast.custom(\n (t) => (\n <Toast\n variant=\"error\"\n message={translate('common.cards.add.errorInitAuth')}\n toastId={t}\n />\n ),\n { duration: 5000 }\n );\n return;\n }\n\n const billingDetails = isInternational\n ? {\n name: data.name,\n address: {\n line1: data.street,\n line2: data.complement || undefined,\n city: data.city,\n state: data.state,\n postal_code: data.cep,\n country: data.country,\n },\n }\n : { name: data.name };\n\n const { setupIntent, error } = await stripe.confirmCardSetup(intent.client_secret, {\n payment_method: {\n card: cardElement,\n billing_details: billingDetails,\n },\n });\n\n if (error) {\n toast.custom(\n (t) => (\n <Toast\n variant=\"error\"\n message={error.message || translate('common.cards.add.errorAuth')}\n toastId={t}\n />\n ),\n { duration: 5000 }\n );\n return;\n }\n\n if (setupIntent?.status !== 'succeeded') {\n toast.custom(\n (t) => (\n <Toast\n variant=\"error\"\n message={translate('common.cards.add.errorAuthStatus', { status: setupIntent?.status ?? translate('common.cards.add.statusUnknown') })}\n toastId={t}\n />\n ),\n { duration: 5000 }\n );\n return;\n }\n\n /* Chamada ÚNICA: os dados fiscais vão no mesmo request do cartão. O backend atualiza a\n * conta ANTES de registrar o cartão, fail-closed — fiscal rejeitado (CPF inválido etc.)\n * = cartão não registra e o erro chega com a mensagem específica no catch abaixo.\n * Substitui o Promise.all de createCard + updateAccount, que não tinha garantia entre as\n * pernas: quando o PUT de conta falhava, o cartão ficava salvo e a conta sem NENHUM dado\n * fiscal — e as faturas seguintes falhavam a emissão de nota em silêncio. */\n const cardResult = await createCardMutation.mutateAsync({\n setup_intent_id: intent.setup_intent_id,\n name: data.name,\n set_default: true,\n ...(isInternational\n ? {}\n : {\n financial_document_type: data.personType === 'pf' ? 1 : 2,\n financial_document: data.personType === 'pf' ? data.cpf : data.cnpj,\n }),\n financial_name: data.fullName,\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 if (cardResult.success && cardResult.data?.id != null) {\n onCardAdded?.(cardResult.data.id.toString());\n }\n\n toast.custom(\n (t) => <Toast variant=\"success\" message={translate('common.cards.add.successToast')} toastId={t} />,\n { duration: 5000 }\n );\n handleClose();\n } catch (error) {\n /* O backend fail-closed devolve a razão exata da recusa (ex.: \"CPF do pagador inválido —\n * confira os dígitos verificadores\"), e o withAction relança como Error com essa mensagem.\n * Engolir num texto genérico deixaria o usuário sem saber o que corrigir. */\n const backendMessage = error instanceof Error && error.message ? error.message : null;\n toast.custom(\n (t) => (\n <Toast\n variant=\"error\"\n message={backendMessage || translate('common.cards.add.errorSave')}\n toastId={t}\n />\n ),\n { duration: 5000 }\n );\n } finally {\n setIsAuthenticating(false);\n }\n }\n\n const isSubmitting =\n createCardMutation.isPending ||\n form.formState.isSubmitting;\n\n const watchedValues = form.watch(['name', 'country', 'personType', 'cpf', 'cnpj', 'fullName', 'cep', 'street', 'streetNumber', 'neighborhood', 'city', 'state']);\n const [name, country, personType, cpf, cnpj, fullName, cep, street, streetNumber, neighborhood, city, state] = watchedValues;\n const isBillingValid = isInternational\n ? !!fullName && !!cep && !!street && !!city && !!state\n : !!fullName &&\n !!cep && cep.length >= 9 &&\n !!street &&\n !!streetNumber &&\n !!neighborhood &&\n !!city &&\n !!state;\n const isCardValid = isInternational\n ? !!name && !!country && stripeStatus.cardNumber && stripeStatus.cardExpiry && stripeStatus.cardCvc\n : !!name &&\n !!country &&\n !!personType &&\n /* Dígito verificador, em sincronia com o schema (buildCardFormSchema) e com a validação\n * do backend — a regra antiga de tamanho deixava 111.111.111-11 habilitar o botão. */\n (personType === 'pf' ? isValidTaxId(cpf, 'cpf') : isValidTaxId(cnpj, 'cnpj')) &&\n stripeStatus.cardNumber &&\n stripeStatus.cardExpiry &&\n stripeStatus.cardCvc;\n\n if (isExternalContracting) {\n return (\n <Dialog open={isOpen} onOpenChange={handleClose}>\n <DialogContent className=\"flex flex-col p-0 gap-0 w-full md:w-[410px] lg:w-[410px]\">\n <DialogHeader className=\"gap-3 text-left p-5\">\n <div className=\"flex items-center justify-center w-10 h-10 bg-zinc-50 rounded-lg\">\n <IconCreditCard 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.cards.add.externalTitle')}\n </DialogTitle>\n <span className=\"paragraph-small-regular text-zinc-600\">\n {translate('common.cards.add.externalDescription')}\n </span>\n </div>\n </DialogHeader>\n <div className=\"flex items-center gap-2 p-5 border-t border-zinc-200\">\n <Button\n className=\"w-fit h-10!\"\n onClick={() => {\n handleClose();\n redirectToExternal('contracting');\n }}\n >\n {translate('common.cards.add.externalButton')}\n </Button>\n </div>\n </DialogContent>\n </Dialog>\n );\n }\n\n return (\n <Dialog open={isOpen} onOpenChange={handleClose}>\n <DialogContent\n showCloseButton={false}\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-y-auto\"\n >\n <DialogHeader className=\"p-0\">\n <div className=\"flex items-center justify-center px-4 py-3 relative border-b border-zinc-200 lg:border-b-0\">\n <DialogTitle className=\"paragraph-medium-semibold text-zinc-950 text-center\">\n {translate('common.cards.add.title')}\n </DialogTitle>\n <Button\n type=\"button\"\n variant=\"ghost\"\n className=\"size-8! p-0 absolute right-4\"\n onClick={handleClose}\n >\n <IconX size={18} />\n </Button>\n </div>\n </DialogHeader>\n\n <CardStepper currentStep={currentStep} />\n\n <form\n onSubmit={form.handleSubmit(handleSubmit)}\n className=\"flex flex-col flex-1 lg:flex-none\"\n >\n <div className={`flex flex-col gap-6 lg:gap-8 p-4 lg:p-5 flex-1 lg:flex-none ${currentStep !== 1 ? 'hidden' : ''}`}>\n <h2 className=\"font-[family-name:var(--font-outfit)] text-[18px] leading-tight font-semibold text-zinc-950\">\n {translate('common.cards.add.billingHeading')}\n </h2>\n <BillingFormFields form={form} isInternational={isInternational} />\n </div>\n <div className={`flex flex-col gap-6 lg:gap-8 p-4 lg:p-5 flex-1 lg:flex-none ${currentStep !== 2 ? 'hidden' : ''}`}>\n <h2 className=\"font-[family-name:var(--font-outfit)] text-[18px] leading-tight font-semibold text-zinc-950\">\n {translate('common.cards.add.cardHeading')}\n </h2>\n <CardFormFields\n form={form}\n onStripeChange={handleStripeChange}\n stripeErrors={stripeErrors}\n isInternational={isInternational}\n />\n </div>\n\n <div className=\"flex justify-between items-center p-4 lg:p-5 border-t border-zinc-200 gap-2 mt-auto lg:mt-0\">\n {currentStep === 1 ? (\n <>\n <Button variant=\"secondary\" type=\"button\" onClick={handleClose} className=\"h-10!\">\n {translate('common.actions.cancel')}\n </Button>\n <Button\n type=\"button\"\n className=\"h-10!\"\n onClick={handleContinue}\n disabled={!isBillingValid}\n >\n {translate('common.actions.continue')}\n </Button>\n </>\n ) : (\n <>\n <Button variant=\"secondary\" type=\"button\" onClick={handleBack} className=\"h-10!\">\n {translate('common.actions.back')}\n </Button>\n <Button\n type=\"submit\"\n className=\"h-10!\"\n disabled={isSubmitting || isAuthenticating || !isCardValid}\n loading={isAuthenticating || isSubmitting}\n >\n {isAuthenticating\n ? translate('common.cards.add.authenticating')\n : isSubmitting\n ? translate('common.cards.add.submitting')\n : translate('common.cards.add.submit')}\n </Button>\n </>\n )}\n </div>\n </form>\n </DialogContent>\n </Dialog>\n );\n}\n"],"mappings":"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","names":[]}
|
package/dist/index.mjs
CHANGED
|
@@ -89,7 +89,10 @@ import {
|
|
|
89
89
|
import {
|
|
90
90
|
ADDON_IDS,
|
|
91
91
|
AI_CREDIT_OPTIONS,
|
|
92
|
-
|
|
92
|
+
AI_CREDIT_SIZES,
|
|
93
|
+
AI_CREDIT_VALUES,
|
|
94
|
+
buildAiCreditOptions,
|
|
95
|
+
resolveAiCreditPrice
|
|
93
96
|
} from "./modules/subscriptions/constants/addons.constants";
|
|
94
97
|
import { PlanSchema, PlanItemSchema } from "./modules/plans/types/plan.type";
|
|
95
98
|
import {
|
|
@@ -360,8 +363,17 @@ import {
|
|
|
360
363
|
formatCurrency,
|
|
361
364
|
formatCurrencyNumber,
|
|
362
365
|
parseCurrencyToNumber,
|
|
363
|
-
getCurrencyForGateway
|
|
366
|
+
getCurrencyForGateway,
|
|
367
|
+
getLocaleForCurrency
|
|
364
368
|
} from "./utils/format/currency";
|
|
369
|
+
import {
|
|
370
|
+
USD_GATEWAY,
|
|
371
|
+
isUsdGateway,
|
|
372
|
+
isUsdAccount,
|
|
373
|
+
allowedPaymentMethods,
|
|
374
|
+
isPaymentMethodAllowed,
|
|
375
|
+
canBuyStandaloneAiCredits
|
|
376
|
+
} from "./utils/format/gateway";
|
|
365
377
|
import { isValidCPF, isValidCNPJ, isValidTaxId } from "./utils/validators/common";
|
|
366
378
|
import { BR_STATE_OPTIONS } from "./utils/constants/br-states";
|
|
367
379
|
import {
|
|
@@ -392,11 +404,7 @@ import {
|
|
|
392
404
|
import { useViaCep } from "./modules/accounts/hooks/useViaCep";
|
|
393
405
|
import { useAccountToken } from "./modules/accounts/hooks/use-account-token.hook";
|
|
394
406
|
import { useRequiredBillingData } from "./modules/accounts/hooks/use-required-billing-data.hook";
|
|
395
|
-
import {
|
|
396
|
-
hasCompleteBillingData,
|
|
397
|
-
isInternationalAccount,
|
|
398
|
-
INTERNATIONAL_GATEWAY
|
|
399
|
-
} from "./modules/accounts/utils/billing-data";
|
|
407
|
+
import { hasCompleteBillingData } from "./modules/accounts/utils/billing-data";
|
|
400
408
|
import { default as default19 } from "./components/account/AccountModals";
|
|
401
409
|
import { useAccountModals } from "./store/useAccountModals";
|
|
402
410
|
import { ModalManager } from "./components/modals/ModalManager";
|
|
@@ -446,6 +454,7 @@ export {
|
|
|
446
454
|
ACCOUNT_USERS_QUERY_KEY,
|
|
447
455
|
ADDON_IDS,
|
|
448
456
|
AI_CREDIT_OPTIONS,
|
|
457
|
+
AI_CREDIT_SIZES,
|
|
449
458
|
AI_CREDIT_VALUES,
|
|
450
459
|
Accordion,
|
|
451
460
|
AccordionContent,
|
|
@@ -526,7 +535,6 @@ export {
|
|
|
526
535
|
FrillEmbed,
|
|
527
536
|
GENDER_OPTIONS,
|
|
528
537
|
INFINITE_PROJECTS_QUERY_KEY,
|
|
529
|
-
INTERNATIONAL_GATEWAY,
|
|
530
538
|
ImageCropModal,
|
|
531
539
|
ImageTooSmallModal,
|
|
532
540
|
ImageUpload,
|
|
@@ -650,19 +658,23 @@ export {
|
|
|
650
658
|
TooltipTrigger,
|
|
651
659
|
TrialBanner,
|
|
652
660
|
default20 as TwoFactorAuthModal,
|
|
661
|
+
USD_GATEWAY,
|
|
653
662
|
USER_QUERY_KEY,
|
|
654
663
|
UpcomingInvoiceBanner,
|
|
655
664
|
UserAvatar,
|
|
656
665
|
UsersSelectorPopover,
|
|
657
666
|
default9 as WhitelabelCodes,
|
|
667
|
+
allowedPaymentMethods,
|
|
658
668
|
badgeVariants,
|
|
659
669
|
base64ToFile,
|
|
670
|
+
buildAiCreditOptions,
|
|
660
671
|
buildCardFormSchema,
|
|
661
672
|
buildLocaleOptions,
|
|
662
673
|
buildPlanExtras,
|
|
663
674
|
buildQueryParams,
|
|
664
675
|
buttonVariants,
|
|
665
676
|
calendarDateSchema,
|
|
677
|
+
canBuyStandaloneAiCredits,
|
|
666
678
|
cardFormSchema,
|
|
667
679
|
cn,
|
|
668
680
|
compressImage,
|
|
@@ -687,6 +699,7 @@ export {
|
|
|
687
699
|
formatTimer,
|
|
688
700
|
getCurrencyForGateway,
|
|
689
701
|
getImageDimensions,
|
|
702
|
+
getLocaleForCurrency,
|
|
690
703
|
getOriginalPriceFromCalculatedData,
|
|
691
704
|
getPriceFromCalculatedData,
|
|
692
705
|
getSubscriptionCancellationState,
|
|
@@ -695,8 +708,10 @@ export {
|
|
|
695
708
|
hasPaidSubscription,
|
|
696
709
|
hasSubscriptionExpired,
|
|
697
710
|
hideCrisp,
|
|
698
|
-
|
|
711
|
+
isPaymentMethodAllowed,
|
|
699
712
|
isSubscriptionPendingPixResponse,
|
|
713
|
+
isUsdAccount,
|
|
714
|
+
isUsdGateway,
|
|
700
715
|
isValidCNPJ,
|
|
701
716
|
isValidCPF,
|
|
702
717
|
isValidTaxId,
|
|
@@ -710,6 +725,7 @@ export {
|
|
|
710
725
|
periodicityToBillingPeriod,
|
|
711
726
|
readFromClipboard,
|
|
712
727
|
redirect,
|
|
728
|
+
resolveAiCreditPrice,
|
|
713
729
|
resolveSafeRedirect,
|
|
714
730
|
sameHostOr,
|
|
715
731
|
showCrisp,
|