@hook-sdk/template 0.28.4 → 0.28.5
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/index.cjs +1734 -1733
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1723 -1722
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -2892,7 +2892,7 @@ function EmptyState({ title, description, action }) {
|
|
|
2892
2892
|
}
|
|
2893
2893
|
|
|
2894
2894
|
// src/defaults/CheckoutPageDefault.tsx
|
|
2895
|
-
var
|
|
2895
|
+
var import_react23 = require("react");
|
|
2896
2896
|
var import_react_router_dom3 = require("react-router-dom");
|
|
2897
2897
|
|
|
2898
2898
|
// src/hooks/useCheckoutForm.ts
|
|
@@ -3138,1861 +3138,1862 @@ function usePlan() {
|
|
|
3138
3138
|
return plan;
|
|
3139
3139
|
}
|
|
3140
3140
|
|
|
3141
|
-
// src/
|
|
3142
|
-
var
|
|
3143
|
-
var
|
|
3144
|
-
|
|
3145
|
-
|
|
3146
|
-
|
|
3147
|
-
|
|
3148
|
-
|
|
3149
|
-
|
|
3150
|
-
|
|
3151
|
-
|
|
3152
|
-
|
|
3153
|
-
}
|
|
3154
|
-
}
|
|
3155
|
-
function formatBrl(cents) {
|
|
3156
|
-
return new Intl.NumberFormat("pt-BR", { style: "currency", currency: "BRL" }).format(cents / 100);
|
|
3141
|
+
// src/components/paywall/Paywall.tsx
|
|
3142
|
+
var import_react21 = require("react");
|
|
3143
|
+
var import_sdk15 = require("@hook-sdk/sdk");
|
|
3144
|
+
|
|
3145
|
+
// src/utils/price.ts
|
|
3146
|
+
function formatBRL(cents) {
|
|
3147
|
+
if (cents === null || cents === void 0) return "";
|
|
3148
|
+
const reais = cents / 100;
|
|
3149
|
+
return new Intl.NumberFormat("pt-BR", {
|
|
3150
|
+
style: "currency",
|
|
3151
|
+
currency: "BRL"
|
|
3152
|
+
}).format(reais);
|
|
3157
3153
|
}
|
|
3158
|
-
function
|
|
3159
|
-
|
|
3160
|
-
return
|
|
3154
|
+
function monthlyFromYearly(yearlyCents) {
|
|
3155
|
+
if (yearlyCents === null || yearlyCents === void 0) return 0;
|
|
3156
|
+
return Math.round(yearlyCents / 12);
|
|
3161
3157
|
}
|
|
3162
|
-
function
|
|
3163
|
-
|
|
3164
|
-
|
|
3165
|
-
return d.slice(0, 2) + "/" + d.slice(2);
|
|
3158
|
+
function dailyFromYearly(yearlyCents) {
|
|
3159
|
+
if (yearlyCents === null || yearlyCents === void 0) return 0;
|
|
3160
|
+
return Math.round(yearlyCents / 365);
|
|
3166
3161
|
}
|
|
3167
|
-
function
|
|
3168
|
-
|
|
3169
|
-
|
|
3162
|
+
function computeAnchorCents(baseCents, multiplier) {
|
|
3163
|
+
if (multiplier === null || multiplier === void 0) return null;
|
|
3164
|
+
if (!Number.isFinite(multiplier)) return null;
|
|
3165
|
+
if (multiplier <= 1) return null;
|
|
3166
|
+
return Math.round(baseCents * multiplier);
|
|
3170
3167
|
}
|
|
3171
|
-
function
|
|
3172
|
-
|
|
3173
|
-
|
|
3174
|
-
if (d.length <= 6) return d.slice(0, 3) + "." + d.slice(3);
|
|
3175
|
-
if (d.length <= 9) return d.slice(0, 3) + "." + d.slice(3, 6) + "." + d.slice(6);
|
|
3176
|
-
return d.slice(0, 3) + "." + d.slice(3, 6) + "." + d.slice(6, 9) + "-" + d.slice(9);
|
|
3168
|
+
function discountPercent(anchorCents, realCents) {
|
|
3169
|
+
if (anchorCents <= realCents) return 0;
|
|
3170
|
+
return Math.floor((anchorCents - realCents) / anchorCents * 100);
|
|
3177
3171
|
}
|
|
3178
|
-
|
|
3179
|
-
|
|
3180
|
-
|
|
3181
|
-
|
|
3182
|
-
|
|
3183
|
-
|
|
3184
|
-
|
|
3185
|
-
return
|
|
3172
|
+
|
|
3173
|
+
// src/components/paywall/PaywallProvider.tsx
|
|
3174
|
+
var import_react19 = require("react");
|
|
3175
|
+
var import_jsx_runtime28 = require("react/jsx-runtime");
|
|
3176
|
+
var PaywallContext = (0, import_react19.createContext)(null);
|
|
3177
|
+
function PaywallProvider({ children }) {
|
|
3178
|
+
const state = usePaywallState();
|
|
3179
|
+
return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(PaywallContext.Provider, { value: state, children });
|
|
3186
3180
|
}
|
|
3187
|
-
|
|
3188
|
-
|
|
3189
|
-
|
|
3190
|
-
|
|
3191
|
-
const
|
|
3192
|
-
|
|
3193
|
-
|
|
3194
|
-
const [expiryMmAa, setExpiryMmAa] = (0, import_react19.useState)("");
|
|
3195
|
-
(0, import_react19.useEffect)(() => {
|
|
3196
|
-
const { month, year } = parseExpiryMmAa(expiryMmAa);
|
|
3197
|
-
if (month !== form.card.expiryMonth || year !== form.card.expiryYear) {
|
|
3198
|
-
form.setCard({ expiryMonth: month, expiryYear: year });
|
|
3199
|
-
}
|
|
3200
|
-
}, [expiryMmAa]);
|
|
3201
|
-
(0, import_react19.useEffect)(() => {
|
|
3202
|
-
if (form.emailTaken && form.loginUrl) {
|
|
3203
|
-
const t = setTimeout(() => navigate(form.loginUrl), 1200);
|
|
3204
|
-
return () => clearTimeout(t);
|
|
3205
|
-
}
|
|
3206
|
-
}, [form.emailTaken, form.loginUrl, navigate]);
|
|
3207
|
-
const planInfo = plan.data ? {
|
|
3208
|
-
priceCents: plan.data.priceCents,
|
|
3209
|
-
yearlyPriceCents: plan.data.yearlyPriceCents,
|
|
3210
|
-
trialDays: plan.data.trialDays
|
|
3211
|
-
} : null;
|
|
3212
|
-
const annual = form.cycle === "YEARLY";
|
|
3213
|
-
const cyclePrice = (0, import_react19.useMemo)(() => {
|
|
3214
|
-
if (!planInfo) return null;
|
|
3215
|
-
return annual ? planInfo.yearlyPriceCents ?? planInfo.priceCents * 12 : planInfo.priceCents;
|
|
3216
|
-
}, [planInfo, annual]);
|
|
3217
|
-
const monthlyText = (0, import_react19.useMemo)(() => {
|
|
3218
|
-
if (!planInfo) return "";
|
|
3219
|
-
const monthly = annual && planInfo.yearlyPriceCents ? Math.round(planInfo.yearlyPriceCents / 12) : planInfo.priceCents;
|
|
3220
|
-
return formatBrl(monthly);
|
|
3221
|
-
}, [planInfo, annual]);
|
|
3222
|
-
const todayCents = (0, import_react19.useMemo)(() => {
|
|
3223
|
-
if (form.method === "pix-auto") return cyclePrice ?? 0;
|
|
3224
|
-
const trialDays2 = planInfo?.trialDays ?? 0;
|
|
3225
|
-
if (trialDays2 > 0) return 0;
|
|
3226
|
-
return cyclePrice ?? 0;
|
|
3227
|
-
}, [form.method, cyclePrice, planInfo]);
|
|
3228
|
-
const todayAmount = formatBrl(todayCents);
|
|
3229
|
-
const cyclePriceText = cyclePrice !== null ? formatBrl(cyclePrice) : "";
|
|
3230
|
-
const annualSavingsCents = (0, import_react19.useMemo)(() => {
|
|
3231
|
-
if (!planInfo || !planInfo.yearlyPriceCents) return 0;
|
|
3232
|
-
return planInfo.priceCents * 12 - planInfo.yearlyPriceCents;
|
|
3233
|
-
}, [planInfo]);
|
|
3234
|
-
const trialDays = planInfo?.trialDays ?? 7;
|
|
3235
|
-
const cardBrand = detectCardBrand(form.card.number);
|
|
3236
|
-
async function onSubmit(e) {
|
|
3237
|
-
e.preventDefault();
|
|
3238
|
-
const result = await form.submit();
|
|
3239
|
-
if (!result) return;
|
|
3240
|
-
if (form.method === "pix-auto" && result.pix_qr_payload) {
|
|
3241
|
-
try {
|
|
3242
|
-
sessionStorage.setItem(
|
|
3243
|
-
PIX_PAYLOAD_KEY,
|
|
3244
|
-
JSON.stringify({
|
|
3245
|
-
payload: result.pix_qr_payload,
|
|
3246
|
-
base64: result.pix_qr_base64 ?? null,
|
|
3247
|
-
subscriptionId: result.subscription_id,
|
|
3248
|
-
pixAuthorizationId: result.pix_authorization_id ?? null
|
|
3249
|
-
})
|
|
3250
|
-
);
|
|
3251
|
-
} catch {
|
|
3252
|
-
}
|
|
3253
|
-
navigate(result.redirect.replace(/^.*\/app\/[^/]+/, ""));
|
|
3254
|
-
return;
|
|
3255
|
-
}
|
|
3256
|
-
navigate(result.redirect.replace(/^.*\/app\/[^/]+/, "") || "/");
|
|
3181
|
+
|
|
3182
|
+
// src/components/paywall/usePaywallContext.ts
|
|
3183
|
+
var import_react20 = require("react");
|
|
3184
|
+
function usePaywallContext() {
|
|
3185
|
+
const ctx = (0, import_react20.useContext)(PaywallContext);
|
|
3186
|
+
if (!ctx) {
|
|
3187
|
+
throw new Error("usePaywallContext must be used within <PaywallProvider>");
|
|
3257
3188
|
}
|
|
3258
|
-
return
|
|
3259
|
-
form.emailTaken ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("div", { className: "px-5 pt-4", children: /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { role: "alert", className: "rounded-2xl bg-destructive/10 p-4 text-sm text-destructive border border-destructive/20", children: [
|
|
3260
|
-
"Esse e-mail j\xE1 tem conta nesse app.",
|
|
3261
|
-
" ",
|
|
3262
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("a", { href: form.loginUrl ?? "/signin", className: "underline font-semibold", children: "Entrar agora" })
|
|
3263
|
-
] }) }) : null,
|
|
3264
|
-
form.error ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("div", { className: "px-5 pt-4", children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("div", { role: "alert", className: "rounded-2xl bg-destructive/10 p-4 text-sm text-destructive border border-destructive/20", children: form.error.message || "N\xE3o foi poss\xEDvel concluir o pagamento. Tente novamente." }) }) : null,
|
|
3265
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("div", { className: "px-5 pt-4", children: form.method === "card" ? /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: "rounded-2xl bg-card border-[1.5px] border-foreground p-3.5", children: [
|
|
3266
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: "flex items-center gap-2 mb-2", children: [
|
|
3267
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(ShieldIcon, { className: "w-4 h-4" }),
|
|
3268
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("div", { className: "text-sm font-bold", children: "Voc\xEA N\xC3O ser\xE1 cobrada hoje" })
|
|
3269
|
-
] }),
|
|
3270
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: "flex justify-between items-baseline text-sm text-muted-foreground", children: [
|
|
3271
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { children: "R$ 0,00 agora" }),
|
|
3272
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { className: "opacity-50", children: "\xB7" }),
|
|
3273
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("span", { children: [
|
|
3274
|
-
monthlyText,
|
|
3275
|
-
"/m\xEAs ap\xF3s ",
|
|
3276
|
-
trialDays,
|
|
3277
|
-
" dias"
|
|
3278
|
-
] })
|
|
3279
|
-
] }),
|
|
3280
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: "mt-2.5 text-[11px] text-muted-foreground flex items-center gap-1.5", children: [
|
|
3281
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(BellIcon, { className: "w-2.5 h-2.5" }),
|
|
3282
|
-
"Avisamos por email 2 dias antes da primeira cobran\xE7a"
|
|
3283
|
-
] })
|
|
3284
|
-
] }) : /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: "rounded-2xl p-3.5 bg-emerald-50 border-[1.5px] border-emerald-600/60", children: [
|
|
3285
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: "flex items-center gap-2 mb-2 text-emerald-900", children: [
|
|
3286
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(ShieldIcon, { className: "w-4 h-4" }),
|
|
3287
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: "text-sm font-bold", children: [
|
|
3288
|
-
"Garantia incondicional de ",
|
|
3289
|
-
trialDays,
|
|
3290
|
-
" dias"
|
|
3291
|
-
] })
|
|
3292
|
-
] }),
|
|
3293
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: "text-sm text-emerald-900 leading-snug", children: [
|
|
3294
|
-
"Voc\xEA paga ",
|
|
3295
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("b", { children: todayAmount }),
|
|
3296
|
-
" agora via Pix.",
|
|
3297
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("br", {}),
|
|
3298
|
-
"N\xE3o gostou em ",
|
|
3299
|
-
trialDays,
|
|
3300
|
-
" dias? Devolvemos ",
|
|
3301
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("b", { children: "100%" }),
|
|
3302
|
-
" sem perguntas \u2014 direto pelo app."
|
|
3303
|
-
] })
|
|
3304
|
-
] }) }),
|
|
3305
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("section", { className: "px-5 pt-5", children: [
|
|
3306
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("h2", { className: "font-display text-2xl mb-3.5 leading-tight text-foreground", children: "Quase l\xE1." }),
|
|
3307
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(FieldLabel, { children: "Email" }),
|
|
3308
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
|
|
3309
|
-
FieldInput,
|
|
3310
|
-
{
|
|
3311
|
-
type: "email",
|
|
3312
|
-
inputMode: "email",
|
|
3313
|
-
autoComplete: "email",
|
|
3314
|
-
autoCapitalize: "none",
|
|
3315
|
-
autoCorrect: "off",
|
|
3316
|
-
spellCheck: false,
|
|
3317
|
-
placeholder: "seu@email.com",
|
|
3318
|
-
value: form.email,
|
|
3319
|
-
onChange: form.setEmail,
|
|
3320
|
-
onBlur: form.markEmailTouched,
|
|
3321
|
-
error: form.emailError,
|
|
3322
|
-
valid: form.emailStatus === "available"
|
|
3323
|
-
}
|
|
3324
|
-
),
|
|
3325
|
-
!form.emailError && /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(FieldHint, { children: form.emailStatus === "checking" ? "Verificando\u2026" : form.emailStatus === "available" ? "\u2713 Dispon\xEDvel" : "Voc\xEA vai usar este email para entrar no app" }),
|
|
3326
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("div", { className: "h-3" }),
|
|
3327
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(FieldLabel, { children: "Nome completo" }),
|
|
3328
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
|
|
3329
|
-
FieldInput,
|
|
3330
|
-
{
|
|
3331
|
-
type: "text",
|
|
3332
|
-
autoComplete: "name",
|
|
3333
|
-
placeholder: "como est\xE1 no documento",
|
|
3334
|
-
value: form.name,
|
|
3335
|
-
onChange: form.setName,
|
|
3336
|
-
onBlur: form.markNameTouched,
|
|
3337
|
-
error: form.nameError,
|
|
3338
|
-
valid: !!form.name && !form.nameError
|
|
3339
|
-
}
|
|
3340
|
-
),
|
|
3341
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("div", { className: "h-3" }),
|
|
3342
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(FieldLabel, { children: "CPF" }),
|
|
3343
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
|
|
3344
|
-
FieldInput,
|
|
3345
|
-
{
|
|
3346
|
-
type: "text",
|
|
3347
|
-
inputMode: "numeric",
|
|
3348
|
-
placeholder: "000.000.000-00",
|
|
3349
|
-
value: form.cpf,
|
|
3350
|
-
onChange: (v) => form.setCpf(formatCpf(v)),
|
|
3351
|
-
onBlur: form.markCpfTouched,
|
|
3352
|
-
error: form.cpfError,
|
|
3353
|
-
valid: !!form.cpf && !form.cpfError
|
|
3354
|
-
}
|
|
3355
|
-
),
|
|
3356
|
-
form.method === "card" ? /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(import_jsx_runtime28.Fragment, { children: [
|
|
3357
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("div", { className: "h-3" }),
|
|
3358
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(FieldLabel, { children: "Telefone" }),
|
|
3359
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
|
|
3360
|
-
FieldInput,
|
|
3361
|
-
{
|
|
3362
|
-
type: "tel",
|
|
3363
|
-
inputMode: "tel",
|
|
3364
|
-
autoComplete: "tel",
|
|
3365
|
-
placeholder: "(11) 99999-9999",
|
|
3366
|
-
value: form.phone,
|
|
3367
|
-
onChange: form.setPhone,
|
|
3368
|
-
onBlur: form.markPhoneTouched,
|
|
3369
|
-
error: form.phoneError,
|
|
3370
|
-
valid: !!form.phone && !form.phoneError
|
|
3371
|
-
}
|
|
3372
|
-
),
|
|
3373
|
-
!form.phoneError && /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(FieldHint, { children: "Usado pra confirmar pagamento e tratar disputas." })
|
|
3374
|
-
] }) : null
|
|
3375
|
-
] }),
|
|
3376
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("section", { className: "px-5 pt-5", children: [
|
|
3377
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(FieldLabel, { children: "Forma de pagamento" }),
|
|
3378
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { role: "tablist", className: "flex gap-1.5 bg-muted p-1 rounded-xl", children: [
|
|
3379
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
|
|
3380
|
-
TabButton,
|
|
3381
|
-
{
|
|
3382
|
-
active: form.method === "card",
|
|
3383
|
-
onClick: () => form.setMethod("card"),
|
|
3384
|
-
icon: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(CardIcon, { className: "w-3.5 h-3.5" }),
|
|
3385
|
-
label: "Cart\xE3o",
|
|
3386
|
-
subtitle: trialDays > 0 ? `${trialDays} dias gr\xE1tis` : "pague hoje",
|
|
3387
|
-
subtitleActiveClass: "text-emerald-700"
|
|
3388
|
-
}
|
|
3389
|
-
),
|
|
3390
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
|
|
3391
|
-
TabButton,
|
|
3392
|
-
{
|
|
3393
|
-
active: form.method === "pix-auto",
|
|
3394
|
-
onClick: () => form.setMethod("pix-auto"),
|
|
3395
|
-
icon: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(PixIcon, { className: "w-3.5 h-3.5" }),
|
|
3396
|
-
label: "Pix",
|
|
3397
|
-
subtitle: `pague hoje \xB7 garantia ${trialDays}d`,
|
|
3398
|
-
subtitleActiveClass: "text-foreground/70"
|
|
3399
|
-
}
|
|
3400
|
-
)
|
|
3401
|
-
] })
|
|
3402
|
-
] }),
|
|
3403
|
-
form.method === "card" ? /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("section", { className: "px-5 pt-3.5", children: [
|
|
3404
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(FieldLabel, { children: "N\xFAmero do cart\xE3o" }),
|
|
3405
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: "relative", children: [
|
|
3406
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
|
|
3407
|
-
FieldInput,
|
|
3408
|
-
{
|
|
3409
|
-
type: "text",
|
|
3410
|
-
inputMode: "numeric",
|
|
3411
|
-
autoComplete: "cc-number",
|
|
3412
|
-
placeholder: "0000 0000 0000 0000",
|
|
3413
|
-
value: form.card.number,
|
|
3414
|
-
onChange: (v) => form.setCard({ number: formatCardNumber(v) }),
|
|
3415
|
-
style: cardBrand ? { paddingRight: "4.5rem" } : void 0
|
|
3416
|
-
}
|
|
3417
|
-
),
|
|
3418
|
-
cardBrand && /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { className: "absolute right-3 top-1/2 -translate-y-1/2 text-[10px] font-bold tracking-wide px-1.5 py-0.5 rounded bg-muted text-muted-foreground", children: cardBrand })
|
|
3419
|
-
] }),
|
|
3420
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("div", { className: "h-3" }),
|
|
3421
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: "flex gap-2.5", children: [
|
|
3422
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: "flex-1", children: [
|
|
3423
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(FieldLabel, { children: "Validade" }),
|
|
3424
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
|
|
3425
|
-
FieldInput,
|
|
3426
|
-
{
|
|
3427
|
-
type: "text",
|
|
3428
|
-
inputMode: "numeric",
|
|
3429
|
-
autoComplete: "cc-exp",
|
|
3430
|
-
placeholder: "MM/AA",
|
|
3431
|
-
value: expiryMmAa,
|
|
3432
|
-
onChange: (v) => setExpiryMmAa(formatExpiryMmAa(v))
|
|
3433
|
-
}
|
|
3434
|
-
)
|
|
3435
|
-
] }),
|
|
3436
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: "flex-1", children: [
|
|
3437
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(FieldLabel, { children: "CVV" }),
|
|
3438
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
|
|
3439
|
-
FieldInput,
|
|
3440
|
-
{
|
|
3441
|
-
type: "text",
|
|
3442
|
-
inputMode: "numeric",
|
|
3443
|
-
autoComplete: "cc-csc",
|
|
3444
|
-
placeholder: "3 d\xEDgitos",
|
|
3445
|
-
value: form.card.ccv,
|
|
3446
|
-
onChange: (v) => form.setCard({ ccv: v.replace(/\D/g, "").slice(0, 4) })
|
|
3447
|
-
}
|
|
3448
|
-
)
|
|
3449
|
-
] })
|
|
3450
|
-
] }),
|
|
3451
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("div", { className: "h-3" }),
|
|
3452
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(FieldLabel, { children: "Nome no cart\xE3o" }),
|
|
3453
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
|
|
3454
|
-
FieldInput,
|
|
3455
|
-
{
|
|
3456
|
-
type: "text",
|
|
3457
|
-
autoComplete: "cc-name",
|
|
3458
|
-
placeholder: "como est\xE1 no cart\xE3o",
|
|
3459
|
-
value: form.card.holderName,
|
|
3460
|
-
onChange: (v) => form.setCard({ holderName: v })
|
|
3461
|
-
}
|
|
3462
|
-
)
|
|
3463
|
-
] }) : /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("section", { className: "px-5 pt-3.5", children: /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: "rounded-2xl bg-card border border-border p-3.5 flex gap-3.5 items-center", children: [
|
|
3464
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("div", { className: "w-[72px] h-[72px] rounded-xl shrink-0 border-2 border-foreground relative overflow-hidden bg-muted", children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("div", { className: "absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 w-[22px] h-[22px] bg-background flex items-center justify-center", children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(PixIcon, { className: "w-3.5 h-3.5 text-foreground" }) }) }),
|
|
3465
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: "flex-1", children: [
|
|
3466
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("div", { className: "text-xs font-bold uppercase tracking-wider text-muted-foreground", children: "pagamento em segundos" }),
|
|
3467
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: "text-sm text-foreground mt-1 leading-snug", children: [
|
|
3468
|
-
"Geramos seu ",
|
|
3469
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("b", { children: "QR Pix" }),
|
|
3470
|
-
" no pr\xF3ximo passo. Pague pelo app do banco e seu acesso libera ",
|
|
3471
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("b", { children: "imediatamente" }),
|
|
3472
|
-
"."
|
|
3473
|
-
] })
|
|
3474
|
-
] })
|
|
3475
|
-
] }) }),
|
|
3476
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("section", { className: "px-5 pt-5", children: /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: "bg-muted rounded-2xl p-4", children: [
|
|
3477
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: "flex justify-between mb-2.5", children: [
|
|
3478
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { children: [
|
|
3479
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("div", { className: "text-sm font-semibold text-foreground", children: annual ? "Plano Anual" : "Plano Mensal" }),
|
|
3480
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("div", { className: "text-[11px] text-muted-foreground", children: "Coach" })
|
|
3481
|
-
] }),
|
|
3482
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: "text-right", children: [
|
|
3483
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: "text-sm font-bold text-foreground", children: [
|
|
3484
|
-
cyclePriceText,
|
|
3485
|
-
"/",
|
|
3486
|
-
annual ? "ano" : "m\xEAs"
|
|
3487
|
-
] }),
|
|
3488
|
-
annual && annualSavingsCents > 0 && /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: "text-[11px] text-emerald-700 font-semibold", children: [
|
|
3489
|
-
"economia ",
|
|
3490
|
-
formatBrl(annualSavingsCents)
|
|
3491
|
-
] })
|
|
3492
|
-
] })
|
|
3493
|
-
] }),
|
|
3494
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("div", { className: "h-px bg-border my-3" }),
|
|
3495
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: "flex justify-between items-baseline", children: [
|
|
3496
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { children: [
|
|
3497
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("div", { className: "text-sm font-bold text-foreground", children: "Voc\xEA paga hoje" }),
|
|
3498
|
-
form.method === "card" && trialDays > 0 && /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: "text-[11px] text-muted-foreground mt-0.5", children: [
|
|
3499
|
-
"cobran\xE7a inicia no dia ",
|
|
3500
|
-
trialDays
|
|
3501
|
-
] }),
|
|
3502
|
-
form.method === "pix-auto" && /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: "text-[11px] text-emerald-700 mt-0.5 font-semibold", children: [
|
|
3503
|
-
"reembolso garantido at\xE9 o dia ",
|
|
3504
|
-
trialDays
|
|
3505
|
-
] })
|
|
3506
|
-
] }),
|
|
3507
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("div", { className: "text-2xl font-bold font-display tracking-tight text-foreground", children: todayAmount })
|
|
3508
|
-
] })
|
|
3509
|
-
] }) }),
|
|
3510
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("div", { className: "h-4" }),
|
|
3511
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: "sticky bottom-0 px-5 pt-3.5 pb-6 bg-gradient-to-b from-transparent to-background", children: [
|
|
3512
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
|
|
3513
|
-
"button",
|
|
3514
|
-
{
|
|
3515
|
-
type: "submit",
|
|
3516
|
-
disabled: !form.canSubmit,
|
|
3517
|
-
className: "w-full rounded-full bg-primary text-primary-foreground min-h-14 px-5 text-base font-bold inline-flex items-center justify-center gap-2 disabled:opacity-50 disabled:cursor-not-allowed shadow-lg",
|
|
3518
|
-
children: form.submitting ? /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(import_jsx_runtime28.Fragment, { children: [
|
|
3519
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(Spinner2, {}),
|
|
3520
|
-
" ",
|
|
3521
|
-
form.method === "pix-auto" ? "Gerando QR\u2026" : "Confirmando\u2026"
|
|
3522
|
-
] }) : form.method === "card" ? /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(import_jsx_runtime28.Fragment, { children: [
|
|
3523
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(LockIcon, { className: "w-3.5 h-3.5" }),
|
|
3524
|
-
" Confirmar e come\xE7ar gr\xE1tis"
|
|
3525
|
-
] }) : /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(import_jsx_runtime28.Fragment, { children: [
|
|
3526
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(PixIcon, { className: "w-3.5 h-3.5" }),
|
|
3527
|
-
" Gerar QR \xB7 pagar ",
|
|
3528
|
-
todayAmount
|
|
3529
|
-
] })
|
|
3530
|
-
}
|
|
3531
|
-
),
|
|
3532
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: "text-center mt-2.5 text-xs text-muted-foreground", children: [
|
|
3533
|
-
"Ao continuar, voc\xEA concorda com nossos ",
|
|
3534
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("u", { children: "Termos" }),
|
|
3535
|
-
". Pagamento seguro Asaas."
|
|
3536
|
-
] }),
|
|
3537
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: "mt-3 flex items-center justify-center gap-3.5 text-[11px] text-muted-foreground", children: [
|
|
3538
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("span", { className: "inline-flex items-center gap-1", children: [
|
|
3539
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(LockIcon, { className: "w-2.5 h-2.5 opacity-60" }),
|
|
3540
|
-
" SSL 256-bit"
|
|
3541
|
-
] }),
|
|
3542
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { className: "w-px h-2.5 bg-border" }),
|
|
3543
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { children: "Pagamento via Asaas" }),
|
|
3544
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { className: "w-px h-2.5 bg-border" }),
|
|
3545
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("span", { children: [
|
|
3546
|
-
"Garantia ",
|
|
3547
|
-
trialDays,
|
|
3548
|
-
" dias"
|
|
3549
|
-
] })
|
|
3550
|
-
] })
|
|
3551
|
-
] })
|
|
3552
|
-
] }) });
|
|
3553
|
-
}
|
|
3554
|
-
function FieldLabel({ children }) {
|
|
3555
|
-
return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("div", { className: "text-xs font-semibold uppercase tracking-wide text-muted-foreground mb-1.5", children });
|
|
3189
|
+
return ctx;
|
|
3556
3190
|
}
|
|
3557
|
-
|
|
3558
|
-
|
|
3559
|
-
|
|
3560
|
-
|
|
3561
|
-
|
|
3562
|
-
|
|
3191
|
+
|
|
3192
|
+
// src/components/paywall/PaywallMethodTabs.tsx
|
|
3193
|
+
var import_jsx_runtime29 = require("react/jsx-runtime");
|
|
3194
|
+
function PaywallMethodTabs({
|
|
3195
|
+
labels,
|
|
3196
|
+
className,
|
|
3197
|
+
tabClassName,
|
|
3198
|
+
tabActiveClassName
|
|
3199
|
+
}) {
|
|
3200
|
+
const { methods, selectedMethod, selectMethod } = usePaywallContext();
|
|
3201
|
+
if (methods.length < 2) return null;
|
|
3202
|
+
return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("div", { role: "tablist", "aria-label": "M\xE9todo de pagamento", className, children: methods.map((m) => {
|
|
3203
|
+
const active = m === selectedMethod;
|
|
3204
|
+
const label = labels[m] ?? m;
|
|
3205
|
+
return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
|
|
3206
|
+
"button",
|
|
3563
3207
|
{
|
|
3564
|
-
type:
|
|
3565
|
-
|
|
3566
|
-
|
|
3567
|
-
|
|
3568
|
-
|
|
3569
|
-
|
|
3570
|
-
|
|
3571
|
-
|
|
3572
|
-
|
|
3573
|
-
|
|
3574
|
-
|
|
3575
|
-
|
|
3576
|
-
}
|
|
3577
|
-
),
|
|
3578
|
-
props.error ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("div", { className: "mt-1.5 text-xs text-destructive font-medium", children: props.error }) : null
|
|
3579
|
-
] });
|
|
3208
|
+
type: "button",
|
|
3209
|
+
role: "tab",
|
|
3210
|
+
"aria-selected": active,
|
|
3211
|
+
"aria-controls": `paywall-tab-${m}`,
|
|
3212
|
+
tabIndex: active ? 0 : -1,
|
|
3213
|
+
onClick: () => selectMethod(m),
|
|
3214
|
+
className: [tabClassName, active ? tabActiveClassName : ""].filter(Boolean).join(" "),
|
|
3215
|
+
children: label
|
|
3216
|
+
},
|
|
3217
|
+
m
|
|
3218
|
+
);
|
|
3219
|
+
}) });
|
|
3580
3220
|
}
|
|
3581
|
-
|
|
3582
|
-
|
|
3221
|
+
|
|
3222
|
+
// src/components/paywall/PaywallMethodContent.tsx
|
|
3223
|
+
var import_jsx_runtime30 = require("react/jsx-runtime");
|
|
3224
|
+
function PaywallMethodContent({ copy, className, rowClassName }) {
|
|
3225
|
+
const { selectedMethod, hasConsumedTrial } = usePaywallContext();
|
|
3226
|
+
const useCardConsumed = selectedMethod === "card" && hasConsumedTrial && copy.cardConsumedTrial;
|
|
3227
|
+
const rows = useCardConsumed ? copy.cardConsumedTrial.bodyRows : selectedMethod === "pix-auto" || selectedMethod === "pix-once" ? copy.pix.bodyRows : copy.card.bodyRows;
|
|
3228
|
+
return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("div", { role: "tabpanel", id: `paywall-tab-${selectedMethod}`, className, children: rows.map((row, i) => /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("div", { className: rowClassName, children: row }, i)) });
|
|
3583
3229
|
}
|
|
3584
|
-
|
|
3585
|
-
|
|
3586
|
-
|
|
3230
|
+
|
|
3231
|
+
// src/components/paywall/PaywallCyclePicker.tsx
|
|
3232
|
+
var import_jsx_runtime31 = require("react/jsx-runtime");
|
|
3233
|
+
var VARIANT_CLASSES = {
|
|
3234
|
+
default: { card: "", cardSelected: "" },
|
|
3235
|
+
"premium-gold": {
|
|
3236
|
+
card: "",
|
|
3237
|
+
cardSelected: "border-2 border-yellow-400/80 ring-2 ring-yellow-400/20"
|
|
3238
|
+
},
|
|
3239
|
+
"pink-pill": {
|
|
3240
|
+
card: "rounded-2xl",
|
|
3241
|
+
cardSelected: "border-2 border-pink-500"
|
|
3242
|
+
}
|
|
3243
|
+
};
|
|
3244
|
+
function PaywallCyclePicker({
|
|
3245
|
+
labels,
|
|
3246
|
+
className,
|
|
3247
|
+
cardClassName,
|
|
3248
|
+
cardSelectedClassName,
|
|
3249
|
+
anchorClassName,
|
|
3250
|
+
variant = "default",
|
|
3251
|
+
render
|
|
3252
|
+
}) {
|
|
3253
|
+
const ctx = usePaywallContext();
|
|
3254
|
+
const { cycle: selected, setCycle, plan, anchorPriceCents } = ctx;
|
|
3255
|
+
const cycles = ["MONTHLY", "YEARLY"];
|
|
3256
|
+
if (render) {
|
|
3257
|
+
return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("div", { className, children: render({ cycles, selected, setCycle, plan, anchorPriceCents }) });
|
|
3258
|
+
}
|
|
3259
|
+
if (cycles.length < 2) return null;
|
|
3260
|
+
const v = VARIANT_CLASSES[variant];
|
|
3261
|
+
const composedCardClassName = [v.card, cardClassName].filter(Boolean).join(" ");
|
|
3262
|
+
const composedCardSelectedClassName = [v.cardSelected, cardSelectedClassName].filter(Boolean).join(" ");
|
|
3263
|
+
const monthlyCents = plan?.monthlyCents ?? 0;
|
|
3264
|
+
const yearlyCents = plan?.yearlyCents ?? 0;
|
|
3265
|
+
const anchorMonthly = plan?.anchorMonthlyCents ?? null;
|
|
3266
|
+
const anchorYearly = plan?.anchorYearlyCents ?? null;
|
|
3267
|
+
return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
|
|
3268
|
+
"div",
|
|
3587
3269
|
{
|
|
3588
|
-
|
|
3589
|
-
|
|
3590
|
-
"
|
|
3591
|
-
|
|
3592
|
-
|
|
3593
|
-
|
|
3594
|
-
|
|
3595
|
-
|
|
3596
|
-
|
|
3597
|
-
|
|
3598
|
-
|
|
3599
|
-
|
|
3600
|
-
|
|
3601
|
-
|
|
3270
|
+
role: "radiogroup",
|
|
3271
|
+
"aria-label": "Ciclo de cobran\xE7a",
|
|
3272
|
+
className: ["flex flex-row gap-2", className].filter(Boolean).join(" "),
|
|
3273
|
+
children: cycles.map((c) => {
|
|
3274
|
+
const active = c === selected;
|
|
3275
|
+
const label = c === "YEARLY" ? labels.annualLabel : labels.monthlyLabel;
|
|
3276
|
+
const suffix = c === "YEARLY" ? labels.annualSuffix : labels.monthlySuffix;
|
|
3277
|
+
const mainCents = c === "YEARLY" ? Math.round(yearlyCents / 12) : monthlyCents;
|
|
3278
|
+
const anchorCents = c === "YEARLY" ? anchorYearly : anchorMonthly;
|
|
3279
|
+
return /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(
|
|
3280
|
+
"button",
|
|
3281
|
+
{
|
|
3282
|
+
type: "button",
|
|
3283
|
+
role: "radio",
|
|
3284
|
+
"aria-checked": active,
|
|
3285
|
+
onClick: () => setCycle(c),
|
|
3286
|
+
className: [
|
|
3287
|
+
"flex flex-col items-center gap-0.5",
|
|
3288
|
+
composedCardClassName,
|
|
3289
|
+
active ? composedCardSelectedClassName : ""
|
|
3290
|
+
].filter(Boolean).join(" "),
|
|
3291
|
+
children: [
|
|
3292
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsx)("span", { className: "font-bold text-base leading-tight", children: formatBRL(mainCents) }),
|
|
3293
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsx)("span", { className: "text-xs opacity-70 leading-tight", children: suffix }),
|
|
3294
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsx)("span", { className: "text-xs opacity-60 leading-tight", children: label }),
|
|
3295
|
+
anchorCents != null && anchorCents > mainCents ? /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("span", { className: anchorClassName ?? "text-xs opacity-50", children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("s", { children: formatBRL(anchorCents) }) }) : null
|
|
3296
|
+
]
|
|
3297
|
+
},
|
|
3298
|
+
c
|
|
3299
|
+
);
|
|
3300
|
+
})
|
|
3602
3301
|
}
|
|
3603
3302
|
);
|
|
3604
3303
|
}
|
|
3605
|
-
|
|
3606
|
-
|
|
3607
|
-
|
|
3608
|
-
|
|
3609
|
-
|
|
3610
|
-
|
|
3611
|
-
|
|
3612
|
-
|
|
3613
|
-
|
|
3614
|
-
|
|
3615
|
-
return /* @__PURE__ */ (0,
|
|
3616
|
-
|
|
3617
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("path", { d: "M7.5 10V7a4.5 4.5 0 119 0v3" })
|
|
3618
|
-
] });
|
|
3619
|
-
}
|
|
3620
|
-
function ShieldIcon({ className }) {
|
|
3621
|
-
return /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.8", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [
|
|
3622
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("path", { d: "M12 2.5l8 3v6c0 5-3.5 8.5-8 10-4.5-1.5-8-5-8-10v-6l8-3z" }),
|
|
3623
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("path", { d: "M9 12l2 2 4-4" })
|
|
3624
|
-
] });
|
|
3625
|
-
}
|
|
3626
|
-
function BellIcon({ className }) {
|
|
3627
|
-
return /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.8", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [
|
|
3628
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("path", { d: "M6 17V11a6 6 0 1112 0v6l1.5 2H4.5L6 17z" }),
|
|
3629
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("path", { d: "M10 21a2 2 0 004 0" })
|
|
3630
|
-
] });
|
|
3631
|
-
}
|
|
3632
|
-
function Spinner2() {
|
|
3633
|
-
return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
|
|
3634
|
-
"span",
|
|
3304
|
+
|
|
3305
|
+
// src/components/paywall/Paywall.tsx
|
|
3306
|
+
var import_jsx_runtime32 = require("react/jsx-runtime");
|
|
3307
|
+
var NBSP = "\xA0";
|
|
3308
|
+
function Paywall({
|
|
3309
|
+
copy,
|
|
3310
|
+
themeClasses = {},
|
|
3311
|
+
slots = {},
|
|
3312
|
+
onBeforeCheckout
|
|
3313
|
+
}) {
|
|
3314
|
+
return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(PaywallProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
|
|
3315
|
+
PaywallInner,
|
|
3635
3316
|
{
|
|
3636
|
-
|
|
3637
|
-
|
|
3317
|
+
copy,
|
|
3318
|
+
themeClasses,
|
|
3319
|
+
slots,
|
|
3320
|
+
onBeforeCheckout
|
|
3638
3321
|
}
|
|
3639
|
-
);
|
|
3640
|
-
}
|
|
3641
|
-
|
|
3642
|
-
// src/defaults/PixWaitingPageDefault.tsx
|
|
3643
|
-
var import_react20 = require("react");
|
|
3644
|
-
var import_react_router_dom4 = require("react-router-dom");
|
|
3645
|
-
var import_sdk15 = require("@hook-sdk/sdk");
|
|
3646
|
-
var import_jsx_runtime29 = require("react/jsx-runtime");
|
|
3647
|
-
var PIX_PAYLOAD_KEY2 = "hook:paywall:pix-pending";
|
|
3648
|
-
var TIMEOUT_MS = 30 * 60 * 1e3;
|
|
3649
|
-
function readPixPayload() {
|
|
3650
|
-
if (typeof window === "undefined") return null;
|
|
3651
|
-
try {
|
|
3652
|
-
const raw = sessionStorage.getItem(PIX_PAYLOAD_KEY2);
|
|
3653
|
-
if (!raw) return null;
|
|
3654
|
-
return JSON.parse(raw);
|
|
3655
|
-
} catch {
|
|
3656
|
-
return null;
|
|
3657
|
-
}
|
|
3658
|
-
}
|
|
3659
|
-
function clearPixPayload() {
|
|
3660
|
-
if (typeof window === "undefined") return;
|
|
3661
|
-
try {
|
|
3662
|
-
sessionStorage.removeItem(PIX_PAYLOAD_KEY2);
|
|
3663
|
-
} catch {
|
|
3664
|
-
}
|
|
3322
|
+
) });
|
|
3665
3323
|
}
|
|
3666
|
-
function
|
|
3667
|
-
|
|
3668
|
-
|
|
3669
|
-
|
|
3670
|
-
|
|
3671
|
-
|
|
3672
|
-
(0,
|
|
3673
|
-
|
|
3674
|
-
|
|
3675
|
-
(
|
|
3676
|
-
|
|
3677
|
-
|
|
3678
|
-
|
|
3679
|
-
|
|
3680
|
-
|
|
3681
|
-
|
|
3682
|
-
|
|
3683
|
-
|
|
3684
|
-
}
|
|
3685
|
-
}, [hasAccess, navigate]);
|
|
3686
|
-
async function copyPayload() {
|
|
3687
|
-
if (!payload?.payload) return;
|
|
3688
|
-
try {
|
|
3689
|
-
await navigator.clipboard.writeText(payload.payload);
|
|
3690
|
-
setCopied(true);
|
|
3691
|
-
setTimeout(() => setCopied(false), 2e3);
|
|
3692
|
-
} catch {
|
|
3693
|
-
}
|
|
3694
|
-
}
|
|
3695
|
-
if (!payload) return null;
|
|
3696
|
-
if (timedOut) {
|
|
3697
|
-
return /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "flex-1 flex flex-col items-center justify-center px-6 py-10 text-center bg-background space-y-4", children: [
|
|
3698
|
-
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)("h1", { className: "font-display text-2xl text-foreground", children: "PIX expirado" }),
|
|
3699
|
-
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)("p", { className: "text-sm text-muted-foreground", children: "O tempo pra pagar acabou. Gere um novo PIX." }),
|
|
3700
|
-
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
|
|
3701
|
-
"button",
|
|
3702
|
-
{
|
|
3703
|
-
onClick: () => {
|
|
3704
|
-
clearPixPayload();
|
|
3705
|
-
navigate("/paywall/checkout", { replace: true });
|
|
3706
|
-
},
|
|
3707
|
-
className: "rounded-xl bg-primary px-6 py-3 text-base font-semibold text-primary-foreground",
|
|
3708
|
-
children: "Tentar novamente"
|
|
3709
|
-
}
|
|
3710
|
-
)
|
|
3711
|
-
] });
|
|
3712
|
-
}
|
|
3713
|
-
return /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "flex-1 flex flex-col items-center px-6 py-8 bg-background space-y-6", children: [
|
|
3714
|
-
/* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("header", { className: "text-center space-y-2", children: [
|
|
3715
|
-
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)("h1", { className: "font-display text-2xl text-foreground", children: "Pague o PIX" }),
|
|
3716
|
-
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)("p", { className: "text-sm text-muted-foreground", children: "Escaneie o QR Code no app do seu banco. O acesso libera assim que confirmarmos o pagamento." })
|
|
3717
|
-
] }),
|
|
3718
|
-
payload.base64 ? /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
|
|
3719
|
-
"img",
|
|
3720
|
-
{
|
|
3721
|
-
src: `data:image/png;base64,${payload.base64}`,
|
|
3722
|
-
alt: "QR Code PIX",
|
|
3723
|
-
className: "w-64 h-64 rounded-2xl border border-border bg-card p-2"
|
|
3324
|
+
function PaywallInner({
|
|
3325
|
+
copy,
|
|
3326
|
+
themeClasses = {},
|
|
3327
|
+
slots = {},
|
|
3328
|
+
onBeforeCheckout
|
|
3329
|
+
}) {
|
|
3330
|
+
const { track: track2 } = (0, import_sdk15.useHook)();
|
|
3331
|
+
const s = usePaywallContext();
|
|
3332
|
+
const priceLabel = formatBRL(s.currentPriceCents).replace(new RegExp(NBSP, "g"), " ");
|
|
3333
|
+
const trialDaysCardLabel = String(s.trialDaysCard);
|
|
3334
|
+
const ctaLabel = (0, import_react21.useMemo)(() => {
|
|
3335
|
+
if (s.isFree) return copy.freeCta ?? "Come\xE7ar agora";
|
|
3336
|
+
if (s.selectedMethod === "card") {
|
|
3337
|
+
if (s.hasConsumedTrial && copy.cardConsumedTrial) {
|
|
3338
|
+
return interp(copy.cardConsumedTrial.ctaTemplate, {
|
|
3339
|
+
price: priceLabel,
|
|
3340
|
+
days: trialDaysCardLabel
|
|
3341
|
+
});
|
|
3724
3342
|
}
|
|
3725
|
-
|
|
3726
|
-
|
|
3727
|
-
"button",
|
|
3728
|
-
{
|
|
3729
|
-
onClick: copyPayload,
|
|
3730
|
-
className: "w-full max-w-xs rounded-xl border border-border bg-card px-4 py-3 text-sm font-medium text-foreground",
|
|
3731
|
-
children: copied ? "\u2713 Copiado!" : "Copiar c\xF3digo PIX"
|
|
3343
|
+
if (s.trialDaysCard > 0) {
|
|
3344
|
+
return interp(copy.card.ctaTemplate, { price: priceLabel, days: trialDaysCardLabel });
|
|
3732
3345
|
}
|
|
3733
|
-
|
|
3734
|
-
|
|
3735
|
-
|
|
3736
|
-
|
|
3737
|
-
] }),
|
|
3738
|
-
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)("p", { className: "text-center text-xs text-muted-foreground", children: "Pode fechar essa janela \u2014 tamb\xE9m enviamos um link de acesso pro seu e-mail." })
|
|
3739
|
-
] });
|
|
3740
|
-
}
|
|
3741
|
-
|
|
3742
|
-
// src/hooks/useLoginForm.ts
|
|
3743
|
-
var import_react21 = require("react");
|
|
3744
|
-
var import_sdk16 = require("@hook-sdk/sdk");
|
|
3745
|
-
var EMAIL_RE2 = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
3746
|
-
var MIN_PASSWORD = 8;
|
|
3747
|
-
function useLoginForm() {
|
|
3748
|
-
const { auth } = (0, import_sdk16.useHook)();
|
|
3749
|
-
const [email, setEmail] = (0, import_react21.useState)("");
|
|
3750
|
-
const [password, setPassword] = (0, import_react21.useState)("");
|
|
3751
|
-
const [submitting, setSubmitting] = (0, import_react21.useState)(false);
|
|
3752
|
-
const [error, setError] = (0, import_react21.useState)(null);
|
|
3753
|
-
const [touchedEmail, setTouchedEmail] = (0, import_react21.useState)(false);
|
|
3754
|
-
const [touchedPassword, setTouchedPassword] = (0, import_react21.useState)(false);
|
|
3755
|
-
const [formSubmitAttempted, setFormSubmitAttempted] = (0, import_react21.useState)(false);
|
|
3756
|
-
const validateEmail = (0, import_react21.useMemo)(() => {
|
|
3757
|
-
if (email.length === 0) return null;
|
|
3758
|
-
if (!EMAIL_RE2.test(email)) return "Formato de e-mail inv\xE1lido.";
|
|
3759
|
-
return null;
|
|
3760
|
-
}, [email]);
|
|
3761
|
-
const validatePassword = (0, import_react21.useMemo)(() => {
|
|
3762
|
-
if (password.length === 0) return null;
|
|
3763
|
-
if (password.length < MIN_PASSWORD) return `M\xEDnimo de ${MIN_PASSWORD} caracteres.`;
|
|
3764
|
-
return null;
|
|
3765
|
-
}, [password]);
|
|
3766
|
-
const emailError = touchedEmail || formSubmitAttempted ? validateEmail : null;
|
|
3767
|
-
const passwordError = touchedPassword || formSubmitAttempted ? validatePassword : null;
|
|
3768
|
-
const canSubmit = email.length > 0 && password.length >= MIN_PASSWORD && validateEmail === null && validatePassword === null && !submitting;
|
|
3769
|
-
const submit = (0, import_react21.useCallback)(async () => {
|
|
3770
|
-
setFormSubmitAttempted(true);
|
|
3771
|
-
if (!canSubmit) return false;
|
|
3772
|
-
setSubmitting(true);
|
|
3773
|
-
setError(null);
|
|
3774
|
-
try {
|
|
3775
|
-
await auth.login({ email, password });
|
|
3776
|
-
return true;
|
|
3777
|
-
} catch (err) {
|
|
3778
|
-
setError(mapSdkError(err));
|
|
3779
|
-
return false;
|
|
3780
|
-
} finally {
|
|
3781
|
-
setSubmitting(false);
|
|
3782
|
-
}
|
|
3783
|
-
}, [auth, email, password, canSubmit]);
|
|
3784
|
-
return {
|
|
3785
|
-
email,
|
|
3786
|
-
setEmail,
|
|
3787
|
-
emailError,
|
|
3788
|
-
markEmailTouched: () => setTouchedEmail(true),
|
|
3789
|
-
password,
|
|
3790
|
-
setPassword,
|
|
3791
|
-
passwordError,
|
|
3792
|
-
markPasswordTouched: () => setTouchedPassword(true),
|
|
3793
|
-
formSubmitAttempted,
|
|
3794
|
-
submit,
|
|
3795
|
-
submitting,
|
|
3796
|
-
canSubmit,
|
|
3797
|
-
error,
|
|
3798
|
-
loginWithGoogle: () => auth.loginWithGoogle()
|
|
3799
|
-
};
|
|
3800
|
-
}
|
|
3801
|
-
|
|
3802
|
-
// src/hooks/useSignupForm.ts
|
|
3803
|
-
var import_react22 = require("react");
|
|
3804
|
-
var import_sdk17 = require("@hook-sdk/sdk");
|
|
3805
|
-
var EMAIL_RE3 = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
3806
|
-
var MIN_PASSWORD2 = 8;
|
|
3807
|
-
function useSignupForm() {
|
|
3808
|
-
const { auth } = (0, import_sdk17.useHook)();
|
|
3809
|
-
const [name, setName] = (0, import_react22.useState)("");
|
|
3810
|
-
const [email, setEmail] = (0, import_react22.useState)("");
|
|
3811
|
-
const [password, setPassword] = (0, import_react22.useState)("");
|
|
3812
|
-
const [submitting, setSubmitting] = (0, import_react22.useState)(false);
|
|
3813
|
-
const [error, setError] = (0, import_react22.useState)(null);
|
|
3814
|
-
const [touchedName, setTouchedName] = (0, import_react22.useState)(false);
|
|
3815
|
-
const [touchedEmail, setTouchedEmail] = (0, import_react22.useState)(false);
|
|
3816
|
-
const [touchedPassword, setTouchedPassword] = (0, import_react22.useState)(false);
|
|
3817
|
-
const [formSubmitAttempted, setFormSubmitAttempted] = (0, import_react22.useState)(false);
|
|
3818
|
-
const validateName = (0, import_react22.useMemo)(() => {
|
|
3819
|
-
if (name.length === 0) return null;
|
|
3820
|
-
if (name.trim().length < 2) return "Nome muito curto.";
|
|
3821
|
-
return null;
|
|
3822
|
-
}, [name]);
|
|
3823
|
-
const validateEmail = (0, import_react22.useMemo)(() => {
|
|
3824
|
-
if (email.length === 0) return null;
|
|
3825
|
-
if (!EMAIL_RE3.test(email)) return "Formato de e-mail inv\xE1lido.";
|
|
3826
|
-
return null;
|
|
3827
|
-
}, [email]);
|
|
3828
|
-
const validatePassword = (0, import_react22.useMemo)(() => {
|
|
3829
|
-
if (password.length === 0) return null;
|
|
3830
|
-
if (password.length < MIN_PASSWORD2) return `M\xEDnimo de ${MIN_PASSWORD2} caracteres.`;
|
|
3831
|
-
return null;
|
|
3832
|
-
}, [password]);
|
|
3833
|
-
const nameError = touchedName || formSubmitAttempted ? validateName : null;
|
|
3834
|
-
const emailError = touchedEmail || formSubmitAttempted ? validateEmail : null;
|
|
3835
|
-
const passwordError = touchedPassword || formSubmitAttempted ? validatePassword : null;
|
|
3836
|
-
const canSubmit = name.trim().length >= 2 && email.length > 0 && password.length >= MIN_PASSWORD2 && validateName === null && validateEmail === null && validatePassword === null && !submitting;
|
|
3837
|
-
const submit = (0, import_react22.useCallback)(async () => {
|
|
3838
|
-
setFormSubmitAttempted(true);
|
|
3839
|
-
if (!canSubmit) return false;
|
|
3840
|
-
setSubmitting(true);
|
|
3841
|
-
setError(null);
|
|
3842
|
-
try {
|
|
3843
|
-
await auth.signup({ name, email, password });
|
|
3844
|
-
return true;
|
|
3845
|
-
} catch (err) {
|
|
3846
|
-
setError(mapSdkError(err));
|
|
3847
|
-
return false;
|
|
3848
|
-
} finally {
|
|
3849
|
-
setSubmitting(false);
|
|
3346
|
+
return copy.cardConsumedTrial ? interp(copy.cardConsumedTrial.ctaTemplate, {
|
|
3347
|
+
price: priceLabel,
|
|
3348
|
+
days: trialDaysCardLabel
|
|
3349
|
+
}) : `Assinar por ${priceLabel}`;
|
|
3850
3350
|
}
|
|
3851
|
-
|
|
3852
|
-
|
|
3853
|
-
|
|
3854
|
-
|
|
3855
|
-
|
|
3856
|
-
|
|
3857
|
-
|
|
3858
|
-
|
|
3859
|
-
|
|
3860
|
-
|
|
3861
|
-
|
|
3862
|
-
|
|
3863
|
-
|
|
3864
|
-
|
|
3865
|
-
|
|
3866
|
-
|
|
3867
|
-
|
|
3868
|
-
|
|
3869
|
-
|
|
3870
|
-
|
|
3871
|
-
|
|
3872
|
-
}
|
|
3873
|
-
|
|
3874
|
-
|
|
3875
|
-
|
|
3876
|
-
|
|
3877
|
-
|
|
3878
|
-
|
|
3879
|
-
|
|
3880
|
-
|
|
3881
|
-
|
|
3882
|
-
|
|
3883
|
-
const [error, setError] = (0, import_react23.useState)(null);
|
|
3884
|
-
const [touchedEmail, setTouchedEmail] = (0, import_react23.useState)(false);
|
|
3885
|
-
const [formSubmitAttempted, setFormSubmitAttempted] = (0, import_react23.useState)(false);
|
|
3886
|
-
const validateEmail = (0, import_react23.useMemo)(() => {
|
|
3887
|
-
if (email.length === 0) return null;
|
|
3888
|
-
if (!EMAIL_RE4.test(email)) return "Formato de e-mail inv\xE1lido.";
|
|
3889
|
-
return null;
|
|
3890
|
-
}, [email]);
|
|
3891
|
-
const emailError = touchedEmail || formSubmitAttempted ? validateEmail : null;
|
|
3892
|
-
const canSubmit = email.length > 0 && validateEmail === null && !submitting;
|
|
3893
|
-
const submit = (0, import_react23.useCallback)(async () => {
|
|
3894
|
-
setFormSubmitAttempted(true);
|
|
3895
|
-
if (!canSubmit) return false;
|
|
3896
|
-
setSubmitting(true);
|
|
3897
|
-
setError(null);
|
|
3898
|
-
try {
|
|
3899
|
-
await auth.forgot({ email });
|
|
3900
|
-
setSent(true);
|
|
3901
|
-
return true;
|
|
3902
|
-
} catch (err) {
|
|
3903
|
-
setError(mapSdkError(err));
|
|
3904
|
-
return false;
|
|
3905
|
-
} finally {
|
|
3906
|
-
setSubmitting(false);
|
|
3351
|
+
return interp(copy.pix.ctaTemplate, { price: priceLabel, days: trialDaysCardLabel });
|
|
3352
|
+
}, [
|
|
3353
|
+
s.isFree,
|
|
3354
|
+
s.selectedMethod,
|
|
3355
|
+
s.hasConsumedTrial,
|
|
3356
|
+
s.trialDaysCard,
|
|
3357
|
+
copy,
|
|
3358
|
+
priceLabel,
|
|
3359
|
+
trialDaysCardLabel
|
|
3360
|
+
]);
|
|
3361
|
+
const switchHint = (0, import_react21.useMemo)(() => {
|
|
3362
|
+
if (s.methods.length < 2) return void 0;
|
|
3363
|
+
return s.selectedMethod === "card" ? copy.card.switchHint : copy.pix.switchHint;
|
|
3364
|
+
}, [s.methods.length, s.selectedMethod, copy]);
|
|
3365
|
+
(0, import_react21.useEffect)(() => {
|
|
3366
|
+
if (!s.initialLoadComplete) return;
|
|
3367
|
+
track2("paywall_view", {
|
|
3368
|
+
default_method: s.selectedMethod,
|
|
3369
|
+
default_cycle: s.cycle,
|
|
3370
|
+
available_methods: s.methods
|
|
3371
|
+
});
|
|
3372
|
+
}, [s.initialLoadComplete]);
|
|
3373
|
+
const handleCta = async () => {
|
|
3374
|
+
track2("paywall_cta_clicked", {
|
|
3375
|
+
method: s.selectedMethod,
|
|
3376
|
+
cycle: s.cycle,
|
|
3377
|
+
price_cents: s.currentPriceCents,
|
|
3378
|
+
had_consumed_trial: s.hasConsumedTrial
|
|
3379
|
+
});
|
|
3380
|
+
if (onBeforeCheckout) {
|
|
3381
|
+
await onBeforeCheckout(s.selectedMethod, s.cycle);
|
|
3382
|
+
return;
|
|
3907
3383
|
}
|
|
3908
|
-
|
|
3909
|
-
return {
|
|
3910
|
-
email,
|
|
3911
|
-
setEmail,
|
|
3912
|
-
emailError,
|
|
3913
|
-
markEmailTouched: () => setTouchedEmail(true),
|
|
3914
|
-
formSubmitAttempted,
|
|
3915
|
-
submit,
|
|
3916
|
-
submitting,
|
|
3917
|
-
canSubmit,
|
|
3918
|
-
sent,
|
|
3919
|
-
error
|
|
3384
|
+
await s.submit();
|
|
3920
3385
|
};
|
|
3921
|
-
|
|
3922
|
-
|
|
3923
|
-
|
|
3924
|
-
|
|
3925
|
-
|
|
3926
|
-
|
|
3927
|
-
|
|
3928
|
-
|
|
3929
|
-
|
|
3930
|
-
|
|
3931
|
-
|
|
3932
|
-
|
|
3933
|
-
|
|
3934
|
-
|
|
3935
|
-
|
|
3936
|
-
|
|
3937
|
-
const [formSubmitAttempted, setFormSubmitAttempted] = (0, import_react24.useState)(false);
|
|
3938
|
-
(0, import_react24.useEffect)(() => {
|
|
3939
|
-
if (typeof window === "undefined") return;
|
|
3940
|
-
const params = new URLSearchParams(window.location.search);
|
|
3941
|
-
const t = params.get("token");
|
|
3942
|
-
setToken(t && t.length > 0 ? t : null);
|
|
3943
|
-
}, []);
|
|
3944
|
-
const validatePassword = (0, import_react24.useMemo)(() => {
|
|
3945
|
-
if (password.length === 0) return null;
|
|
3946
|
-
if (password.length < MIN_PASSWORD3) return `M\xEDnimo de ${MIN_PASSWORD3} caracteres.`;
|
|
3947
|
-
return null;
|
|
3948
|
-
}, [password]);
|
|
3949
|
-
const validateConfirm = (0, import_react24.useMemo)(() => {
|
|
3950
|
-
if (confirm.length === 0) return null;
|
|
3951
|
-
if (confirm !== password) return "Senhas n\xE3o coincidem.";
|
|
3952
|
-
return null;
|
|
3953
|
-
}, [confirm, password]);
|
|
3954
|
-
const passwordError = touchedPassword || formSubmitAttempted ? validatePassword : null;
|
|
3955
|
-
const confirmError = touchedConfirm || formSubmitAttempted ? validateConfirm : null;
|
|
3956
|
-
const canSubmit = token !== null && password.length >= MIN_PASSWORD3 && confirm === password && validatePassword === null && validateConfirm === null && !submitting && !done;
|
|
3957
|
-
const submit = (0, import_react24.useCallback)(async () => {
|
|
3958
|
-
setFormSubmitAttempted(true);
|
|
3959
|
-
if (!canSubmit || token === null) return;
|
|
3960
|
-
setSubmitting(true);
|
|
3961
|
-
setError(null);
|
|
3962
|
-
try {
|
|
3963
|
-
await auth.reset({ token, newPassword: password });
|
|
3964
|
-
setDone(true);
|
|
3965
|
-
if (typeof window !== "undefined") {
|
|
3966
|
-
const url = new URL(window.location.href);
|
|
3967
|
-
url.searchParams.delete("token");
|
|
3968
|
-
url.searchParams.delete("screen");
|
|
3969
|
-
window.history.replaceState({}, "", url.toString());
|
|
3386
|
+
const ctaTheme = s.selectedMethod === "card" ? themeClasses.ctaCard : themeClasses.ctaPix;
|
|
3387
|
+
return /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("div", { className: themeClasses.container, children: [
|
|
3388
|
+
slots.heroSlot,
|
|
3389
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)("h1", { className: themeClasses.headline, children: copy.headline }),
|
|
3390
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)("ul", { children: copy.features.map((f) => /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("li", { className: themeClasses.feature, children: [
|
|
3391
|
+
"\u2713 ",
|
|
3392
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)("span", { children: f })
|
|
3393
|
+
] }, f)) }),
|
|
3394
|
+
copy.socialProof ? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("p", { className: themeClasses.socialProof, children: copy.socialProof }) : null,
|
|
3395
|
+
slots.cyclePickerSlot ?? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
|
|
3396
|
+
PaywallCyclePicker,
|
|
3397
|
+
{
|
|
3398
|
+
labels: copy.cycle,
|
|
3399
|
+
cardClassName: themeClasses.cycleCard,
|
|
3400
|
+
cardSelectedClassName: themeClasses.cycleCardSelected,
|
|
3401
|
+
anchorClassName: themeClasses.anchorPrice
|
|
3970
3402
|
}
|
|
3971
|
-
|
|
3972
|
-
|
|
3973
|
-
|
|
3974
|
-
|
|
3975
|
-
|
|
3976
|
-
|
|
3977
|
-
|
|
3978
|
-
|
|
3979
|
-
|
|
3980
|
-
|
|
3981
|
-
|
|
3982
|
-
|
|
3983
|
-
|
|
3984
|
-
|
|
3985
|
-
|
|
3986
|
-
|
|
3987
|
-
|
|
3988
|
-
|
|
3989
|
-
|
|
3990
|
-
|
|
3991
|
-
|
|
3992
|
-
|
|
3993
|
-
|
|
3994
|
-
|
|
3995
|
-
|
|
3996
|
-
|
|
3997
|
-
|
|
3998
|
-
|
|
3999
|
-
|
|
4000
|
-
|
|
4001
|
-
|
|
4002
|
-
|
|
4003
|
-
|
|
4004
|
-
|
|
4005
|
-
|
|
4006
|
-
|
|
4007
|
-
|
|
4008
|
-
|
|
4009
|
-
|
|
4010
|
-
|
|
4011
|
-
|
|
4012
|
-
}
|
|
4013
|
-
|
|
4014
|
-
|
|
4015
|
-
|
|
4016
|
-
if (multiplier <= 1) return null;
|
|
4017
|
-
return Math.round(baseCents * multiplier);
|
|
4018
|
-
}
|
|
4019
|
-
function discountPercent(anchorCents, realCents) {
|
|
4020
|
-
if (anchorCents <= realCents) return 0;
|
|
4021
|
-
return Math.floor((anchorCents - realCents) / anchorCents * 100);
|
|
4022
|
-
}
|
|
4023
|
-
|
|
4024
|
-
// src/hooks/useAuthPrimitives.ts
|
|
4025
|
-
var import_react25 = require("react");
|
|
4026
|
-
var import_sdk20 = require("@hook-sdk/sdk");
|
|
4027
|
-
var warned = false;
|
|
4028
|
-
function useAuthPrimitives() {
|
|
4029
|
-
const { auth } = (0, import_sdk20.useHook)();
|
|
4030
|
-
(0, import_react25.useEffect)(() => {
|
|
4031
|
-
if (!warned && process.env.NODE_ENV !== "production") {
|
|
4032
|
-
warned = true;
|
|
4033
|
-
console.warn(
|
|
4034
|
-
"[@hook-sdk/template] useAuthPrimitives() \xE9 escape hatch. Pra login/signup/forgot, use useLoginForm/useSignupForm/useForgotForm. Docs: docs/19-golden-template.md#escape-hatch"
|
|
4035
|
-
);
|
|
4036
|
-
}
|
|
4037
|
-
}, []);
|
|
4038
|
-
return {
|
|
4039
|
-
login: auth.login,
|
|
4040
|
-
signup: auth.signup,
|
|
4041
|
-
logout: auth.logout,
|
|
4042
|
-
logoutAll: auth.logoutAll,
|
|
4043
|
-
forgot: auth.forgot,
|
|
4044
|
-
resendVerify: auth.resendVerify,
|
|
4045
|
-
changePassword: auth.changePassword,
|
|
4046
|
-
changeEmail: auth.changeEmail,
|
|
4047
|
-
refresh: auth.refresh
|
|
4048
|
-
};
|
|
4049
|
-
}
|
|
4050
|
-
|
|
4051
|
-
// src/hooks/useAuth.ts
|
|
4052
|
-
var import_sdk21 = require("@hook-sdk/sdk");
|
|
4053
|
-
function useAuth() {
|
|
4054
|
-
const { user, authStatus, auth } = (0, import_sdk21.useHook)();
|
|
4055
|
-
return {
|
|
4056
|
-
user,
|
|
4057
|
-
authStatus,
|
|
4058
|
-
refresh: auth.refresh
|
|
4059
|
-
};
|
|
3403
|
+
),
|
|
3404
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
|
|
3405
|
+
PaywallMethodTabs,
|
|
3406
|
+
{
|
|
3407
|
+
labels: { "pix-auto": copy.pix.tabLabel, card: copy.card.tabLabel },
|
|
3408
|
+
className: themeClasses.tabs,
|
|
3409
|
+
tabClassName: themeClasses.tab,
|
|
3410
|
+
tabActiveClassName: themeClasses.tabActive
|
|
3411
|
+
}
|
|
3412
|
+
),
|
|
3413
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
|
|
3414
|
+
PaywallMethodContent,
|
|
3415
|
+
{
|
|
3416
|
+
copy: {
|
|
3417
|
+
pix: interpolateCopy(copy.pix, priceLabel, trialDaysCardLabel),
|
|
3418
|
+
card: interpolateCopy(copy.card, priceLabel, trialDaysCardLabel),
|
|
3419
|
+
cardConsumedTrial: copy.cardConsumedTrial ? {
|
|
3420
|
+
bodyRows: copy.cardConsumedTrial.bodyRows.map(
|
|
3421
|
+
(r) => interp(r, { price: priceLabel, days: trialDaysCardLabel })
|
|
3422
|
+
),
|
|
3423
|
+
ctaTemplate: copy.cardConsumedTrial.ctaTemplate
|
|
3424
|
+
} : void 0
|
|
3425
|
+
},
|
|
3426
|
+
className: themeClasses.tabContent,
|
|
3427
|
+
rowClassName: themeClasses.tabContentRow
|
|
3428
|
+
}
|
|
3429
|
+
),
|
|
3430
|
+
slots.beforeCtaSlot,
|
|
3431
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("div", { children: [
|
|
3432
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
|
|
3433
|
+
"button",
|
|
3434
|
+
{
|
|
3435
|
+
type: "button",
|
|
3436
|
+
onClick: () => {
|
|
3437
|
+
void handleCta();
|
|
3438
|
+
},
|
|
3439
|
+
disabled: s.submitting,
|
|
3440
|
+
className: ctaTheme,
|
|
3441
|
+
children: s.submitting ? "Abrindo checkout\u2026" : ctaLabel
|
|
3442
|
+
}
|
|
3443
|
+
),
|
|
3444
|
+
switchHint ? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("p", { className: themeClasses.switchHint, children: switchHint }) : null,
|
|
3445
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)("p", { className: themeClasses.trustLine, children: copy.trustLine })
|
|
3446
|
+
] })
|
|
3447
|
+
] });
|
|
4060
3448
|
}
|
|
4061
|
-
|
|
4062
|
-
|
|
4063
|
-
|
|
4064
|
-
|
|
4065
|
-
// src/hooks/useSubscription.ts
|
|
4066
|
-
var import_sdk22 = require("@hook-sdk/sdk");
|
|
4067
|
-
function useSubscription() {
|
|
4068
|
-
const { subscription } = (0, import_sdk22.useHook)();
|
|
3449
|
+
function interp(tpl, vars) {
|
|
3450
|
+
return tpl.replace(/\{(\w+)\}/g, (_m, k) => vars[k] ?? "");
|
|
3451
|
+
}
|
|
3452
|
+
function interpolateCopy(m, price, days) {
|
|
4069
3453
|
return {
|
|
4070
|
-
|
|
3454
|
+
tabLabel: m.tabLabel,
|
|
3455
|
+
bodyRows: m.bodyRows.map((r) => interp(r, { price, days })),
|
|
3456
|
+
ctaTemplate: m.ctaTemplate,
|
|
3457
|
+
switchHint: m.switchHint
|
|
4071
3458
|
};
|
|
4072
3459
|
}
|
|
4073
3460
|
|
|
4074
|
-
// src/
|
|
4075
|
-
var
|
|
4076
|
-
|
|
4077
|
-
|
|
4078
|
-
|
|
4079
|
-
|
|
4080
|
-
|
|
4081
|
-
|
|
4082
|
-
|
|
4083
|
-
|
|
4084
|
-
|
|
4085
|
-
|
|
4086
|
-
|
|
4087
|
-
|
|
4088
|
-
|
|
4089
|
-
|
|
4090
|
-
|
|
4091
|
-
|
|
4092
|
-
|
|
4093
|
-
|
|
4094
|
-
|
|
4095
|
-
|
|
4096
|
-
|
|
4097
|
-
|
|
4098
|
-
|
|
4099
|
-
|
|
4100
|
-
|
|
4101
|
-
|
|
4102
|
-
|
|
4103
|
-
return r.schedule(items);
|
|
4104
|
-
}, [r]);
|
|
4105
|
-
const setFallbacks = (0, import_react26.useCallback)(async (items) => {
|
|
4106
|
-
return r.setFallbacks(items);
|
|
4107
|
-
}, [r]);
|
|
4108
|
-
return { reminders, loading, setReminder, deleteReminder, schedule, setFallbacks };
|
|
4109
|
-
}
|
|
4110
|
-
|
|
4111
|
-
// src/hooks/useToast.ts
|
|
4112
|
-
var import_react27 = require("react");
|
|
4113
|
-
function useToast() {
|
|
4114
|
-
const [items, setItems] = (0, import_react27.useState)([]);
|
|
4115
|
-
const show = (0, import_react27.useCallback)((message, kind = "info") => {
|
|
4116
|
-
const id = `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
4117
|
-
setItems((prev) => [...prev, { id, message, kind }]);
|
|
4118
|
-
setTimeout(() => {
|
|
4119
|
-
setItems((prev) => prev.filter((t) => t.id !== id));
|
|
4120
|
-
}, 4e3);
|
|
4121
|
-
}, []);
|
|
4122
|
-
const dismiss = (0, import_react27.useCallback)((id) => {
|
|
4123
|
-
setItems((prev) => prev.filter((t) => t.id !== id));
|
|
4124
|
-
}, []);
|
|
4125
|
-
return { items, show, dismiss };
|
|
4126
|
-
}
|
|
4127
|
-
|
|
4128
|
-
// src/RouteBoundary.tsx
|
|
4129
|
-
var import_react_router_dom5 = require("react-router-dom");
|
|
4130
|
-
var import_jsx_runtime30 = require("react/jsx-runtime");
|
|
4131
|
-
function RouteBoundary({ children }) {
|
|
4132
|
-
return /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(import_react_router_dom5.Routes, { children: [
|
|
4133
|
-
children,
|
|
4134
|
-
/* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_react_router_dom5.Route, { path: "*", element: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(DefaultNotFound, {}) })
|
|
3461
|
+
// src/components/paywall/PaywallCta.tsx
|
|
3462
|
+
var import_jsx_runtime33 = require("react/jsx-runtime");
|
|
3463
|
+
function PaywallCta({
|
|
3464
|
+
ctaLabel,
|
|
3465
|
+
loadingLabel,
|
|
3466
|
+
switchHint,
|
|
3467
|
+
trustLine,
|
|
3468
|
+
className,
|
|
3469
|
+
buttonClassName,
|
|
3470
|
+
switchHintClassName,
|
|
3471
|
+
trustClassName
|
|
3472
|
+
}) {
|
|
3473
|
+
const { submit, submitting } = usePaywallContext();
|
|
3474
|
+
const label = submitting && loadingLabel ? loadingLabel : ctaLabel;
|
|
3475
|
+
return /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("div", { className, children: [
|
|
3476
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
|
|
3477
|
+
"button",
|
|
3478
|
+
{
|
|
3479
|
+
type: "button",
|
|
3480
|
+
onClick: () => {
|
|
3481
|
+
void submit();
|
|
3482
|
+
},
|
|
3483
|
+
disabled: submitting,
|
|
3484
|
+
className: buttonClassName,
|
|
3485
|
+
children: label
|
|
3486
|
+
}
|
|
3487
|
+
),
|
|
3488
|
+
switchHint ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("p", { className: switchHintClassName, children: switchHint }) : null,
|
|
3489
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)("p", { className: trustClassName, children: trustLine })
|
|
4135
3490
|
] });
|
|
4136
3491
|
}
|
|
4137
|
-
|
|
4138
|
-
|
|
3492
|
+
|
|
3493
|
+
// src/components/paywall/blocks/PaywallEyebrow.tsx
|
|
3494
|
+
var import_jsx_runtime34 = require("react/jsx-runtime");
|
|
3495
|
+
var DEFAULT_EYEBROW_CLASSES = "text-xs uppercase tracking-widest font-semibold opacity-70";
|
|
3496
|
+
function PaywallEyebrow({ text, className }) {
|
|
3497
|
+
return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("div", { className: [DEFAULT_EYEBROW_CLASSES, className].filter(Boolean).join(" "), children: text });
|
|
4139
3498
|
}
|
|
4140
3499
|
|
|
4141
|
-
// src/
|
|
4142
|
-
var
|
|
4143
|
-
var
|
|
4144
|
-
function
|
|
4145
|
-
|
|
4146
|
-
|
|
4147
|
-
|
|
4148
|
-
|
|
3500
|
+
// src/components/paywall/blocks/PaywallHero.tsx
|
|
3501
|
+
var import_jsx_runtime35 = require("react/jsx-runtime");
|
|
3502
|
+
var DEFAULT_GRADIENT = "absolute inset-0 bg-gradient-to-t from-black/70 via-black/20 to-transparent";
|
|
3503
|
+
function PaywallHero({
|
|
3504
|
+
src,
|
|
3505
|
+
alt = "",
|
|
3506
|
+
headline,
|
|
3507
|
+
aspectRatio = "16/9",
|
|
3508
|
+
gradientClassName,
|
|
3509
|
+
className,
|
|
3510
|
+
headlineClassName,
|
|
3511
|
+
imgClassName,
|
|
3512
|
+
render
|
|
4149
3513
|
}) {
|
|
4150
|
-
if (
|
|
4151
|
-
return /* @__PURE__ */ (0,
|
|
3514
|
+
if (render) {
|
|
3515
|
+
return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("div", { className, children: render({ src, headline }) });
|
|
4152
3516
|
}
|
|
4153
|
-
return /* @__PURE__ */ (0,
|
|
3517
|
+
return /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)(
|
|
3518
|
+
"div",
|
|
3519
|
+
{
|
|
3520
|
+
className: ["relative overflow-hidden", className].filter(Boolean).join(" "),
|
|
3521
|
+
style: { aspectRatio },
|
|
3522
|
+
children: [
|
|
3523
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
|
|
3524
|
+
"img",
|
|
3525
|
+
{
|
|
3526
|
+
src,
|
|
3527
|
+
alt,
|
|
3528
|
+
className: ["absolute inset-0 w-full h-full object-cover", imgClassName].filter(Boolean).join(" ")
|
|
3529
|
+
}
|
|
3530
|
+
),
|
|
3531
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)("div", { className: gradientClassName ?? DEFAULT_GRADIENT, "aria-hidden": "true" }),
|
|
3532
|
+
headline ? /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
|
|
3533
|
+
"h1",
|
|
3534
|
+
{
|
|
3535
|
+
className: ["absolute bottom-0 left-0 right-0 p-4 text-white font-bold text-2xl", headlineClassName].filter(Boolean).join(" "),
|
|
3536
|
+
children: headline
|
|
3537
|
+
}
|
|
3538
|
+
) : null
|
|
3539
|
+
]
|
|
3540
|
+
}
|
|
3541
|
+
);
|
|
4154
3542
|
}
|
|
4155
3543
|
|
|
4156
|
-
// src/
|
|
4157
|
-
var
|
|
4158
|
-
var
|
|
3544
|
+
// src/components/paywall/blocks/PaywallHeadline.tsx
|
|
3545
|
+
var import_jsx_runtime36 = require("react/jsx-runtime");
|
|
3546
|
+
var DEFAULT_HEADLINE_CLASSES = "text-2xl font-bold leading-tight";
|
|
3547
|
+
function PaywallHeadline({ text, className, as = "h1" }) {
|
|
3548
|
+
const Tag = as;
|
|
3549
|
+
return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(Tag, { className: [DEFAULT_HEADLINE_CLASSES, className].filter(Boolean).join(" "), children: text });
|
|
3550
|
+
}
|
|
4159
3551
|
|
|
4160
|
-
// src/
|
|
4161
|
-
var
|
|
4162
|
-
var
|
|
4163
|
-
|
|
4164
|
-
|
|
4165
|
-
|
|
4166
|
-
|
|
4167
|
-
|
|
4168
|
-
|
|
3552
|
+
// src/components/paywall/blocks/PaywallPriceHeadline.tsx
|
|
3553
|
+
var import_jsx_runtime37 = require("react/jsx-runtime");
|
|
3554
|
+
var DEFAULT_CLASS = "text-2xl font-bold leading-tight";
|
|
3555
|
+
var CYCLE_LABEL = {
|
|
3556
|
+
MONTHLY: "mensal",
|
|
3557
|
+
YEARLY: "anual"
|
|
3558
|
+
};
|
|
3559
|
+
function PaywallPriceHeadline({
|
|
3560
|
+
template,
|
|
3561
|
+
className,
|
|
3562
|
+
as = "h1",
|
|
3563
|
+
render
|
|
3564
|
+
}) {
|
|
3565
|
+
const { cycle, currentMonthlyEquivCents, plan } = usePaywallContext();
|
|
3566
|
+
const yearlyCents = plan?.yearlyCents ?? null;
|
|
3567
|
+
const pricePerDay = formatBRL(dailyFromYearly(yearlyCents));
|
|
3568
|
+
const monthlyEquiv = currentMonthlyEquivCents ?? 0;
|
|
3569
|
+
const cycleLabel = CYCLE_LABEL[cycle] ?? cycle.toLowerCase();
|
|
3570
|
+
const rootClasses = [DEFAULT_CLASS, className].filter(Boolean).join(" ");
|
|
3571
|
+
if (render) {
|
|
3572
|
+
const RootTag2 = as;
|
|
3573
|
+
return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(RootTag2, { className: [className].filter(Boolean).join(" ") || void 0, children: render({ pricePerDay, currentMonthlyEquivCents: monthlyEquiv, cycle }) });
|
|
4169
3574
|
}
|
|
4170
|
-
|
|
3575
|
+
const text = template.replaceAll("{pricePerDay}", pricePerDay).replaceAll("{currentMonthlyEquiv}", formatBRL(monthlyEquiv)).replaceAll("{cycle}", cycleLabel);
|
|
3576
|
+
const RootTag = as;
|
|
3577
|
+
return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(RootTag, { className: rootClasses, children: text });
|
|
4171
3578
|
}
|
|
4172
3579
|
|
|
4173
|
-
// src/
|
|
4174
|
-
var
|
|
4175
|
-
var
|
|
4176
|
-
var
|
|
4177
|
-
function
|
|
4178
|
-
|
|
4179
|
-
|
|
4180
|
-
}
|
|
4181
|
-
|
|
4182
|
-
|
|
4183
|
-
screens,
|
|
4184
|
-
onComplete,
|
|
4185
|
-
persistKey
|
|
4186
|
-
}) {
|
|
4187
|
-
const [draft, setDraft, status] = (0, import_sdk24.usePersistedState)(persistKey, {});
|
|
4188
|
-
const draftRef = (0, import_react29.useRef)(draft);
|
|
4189
|
-
draftRef.current = draft;
|
|
4190
|
-
const idx = readPersistedStepIdx(draft);
|
|
4191
|
-
const clampedIdx = Math.min(Math.max(idx, 0), Math.max(steps.length - 1, 0));
|
|
4192
|
-
const setIdx = (0, import_react29.useCallback)(
|
|
4193
|
-
(n) => {
|
|
4194
|
-
setDraft((prev) => {
|
|
4195
|
-
const prevIdx = readPersistedStepIdx(prev);
|
|
4196
|
-
const nextIdx = typeof n === "function" ? n(prevIdx) : n;
|
|
4197
|
-
return { ...prev, [CURRENT_STEP_FIELD]: nextIdx };
|
|
4198
|
-
});
|
|
4199
|
-
},
|
|
4200
|
-
[setDraft]
|
|
4201
|
-
);
|
|
4202
|
-
const setValue = (0, import_react29.useCallback)(
|
|
4203
|
-
(patch) => {
|
|
4204
|
-
draftRef.current = { ...draftRef.current, ...patch };
|
|
4205
|
-
setDraft((prev) => ({ ...prev, ...patch }));
|
|
4206
|
-
},
|
|
4207
|
-
[setDraft]
|
|
4208
|
-
);
|
|
4209
|
-
const step = steps[clampedIdx];
|
|
4210
|
-
const hookCtx = (0, import_sdk24.useHook)();
|
|
4211
|
-
const track2 = typeof hookCtx.track === "function" ? hookCtx.track : void 0;
|
|
4212
|
-
(0, import_react29.useEffect)(() => {
|
|
4213
|
-
if (status.loading) return;
|
|
4214
|
-
if (!step) return;
|
|
4215
|
-
if (!track2) return;
|
|
4216
|
-
track2("onboarding_step_viewed", {
|
|
4217
|
-
step: step.id,
|
|
4218
|
-
step_index: clampedIdx,
|
|
4219
|
-
total_steps: steps.length
|
|
4220
|
-
});
|
|
4221
|
-
}, [step?.id, clampedIdx, steps.length, status.loading, track2]);
|
|
4222
|
-
const valid = (0, import_react29.useMemo)(
|
|
4223
|
-
() => step ? (step.validates ?? []).every((field) => isFilled(draft[field])) : false,
|
|
4224
|
-
[draft, step]
|
|
4225
|
-
);
|
|
4226
|
-
const next = (0, import_react29.useCallback)(() => {
|
|
4227
|
-
if (!step) return;
|
|
4228
|
-
const current = draftRef.current;
|
|
4229
|
-
const validNow = (step.validates ?? []).every((field) => isFilled(current[field]));
|
|
4230
|
-
if (!validNow) return;
|
|
4231
|
-
if (clampedIdx + 1 >= steps.length) {
|
|
4232
|
-
onComplete(current);
|
|
4233
|
-
} else {
|
|
4234
|
-
setIdx(clampedIdx + 1);
|
|
4235
|
-
}
|
|
4236
|
-
}, [clampedIdx, onComplete, step, steps.length, setIdx]);
|
|
4237
|
-
const prevStep = (0, import_react29.useCallback)(() => setIdx((i) => Math.max(0, i - 1)), [setIdx]);
|
|
4238
|
-
const ctx = (0, import_react29.useMemo)(
|
|
4239
|
-
() => ({
|
|
4240
|
-
stepIndex: clampedIdx,
|
|
4241
|
-
totalSteps: steps.length,
|
|
4242
|
-
value: draft,
|
|
4243
|
-
setValue,
|
|
4244
|
-
valid,
|
|
4245
|
-
next,
|
|
4246
|
-
prev: prevStep
|
|
4247
|
-
}),
|
|
4248
|
-
[clampedIdx, steps.length, draft, setValue, valid, next, prevStep]
|
|
4249
|
-
);
|
|
4250
|
-
if (status.loading) {
|
|
4251
|
-
return null;
|
|
3580
|
+
// src/components/paywall/blocks/PaywallCountdown.tsx
|
|
3581
|
+
var import_react22 = require("react");
|
|
3582
|
+
var import_jsx_runtime38 = require("react/jsx-runtime");
|
|
3583
|
+
var DEFAULT_COUNTDOWN_CLASSES = "font-mono tabular-nums";
|
|
3584
|
+
function resolveDeadlineMs(deadline) {
|
|
3585
|
+
if (deadline instanceof Date) return deadline.getTime();
|
|
3586
|
+
if (typeof deadline === "string") return new Date(deadline).getTime();
|
|
3587
|
+
const { sessionStorageKey, durationMs } = deadline;
|
|
3588
|
+
if (typeof window === "undefined" || typeof window.sessionStorage === "undefined") {
|
|
3589
|
+
return Date.now() + durationMs;
|
|
4252
3590
|
}
|
|
4253
|
-
|
|
4254
|
-
|
|
4255
|
-
|
|
4256
|
-
|
|
3591
|
+
const stored = window.sessionStorage.getItem(sessionStorageKey);
|
|
3592
|
+
const parsed = stored ? Number.parseInt(stored, 10) : NaN;
|
|
3593
|
+
const now = Date.now();
|
|
3594
|
+
if (!Number.isFinite(parsed) || parsed < now) {
|
|
3595
|
+
const target = now + durationMs;
|
|
3596
|
+
window.sessionStorage.setItem(sessionStorageKey, String(target));
|
|
3597
|
+
return target;
|
|
4257
3598
|
}
|
|
4258
|
-
|
|
4259
|
-
|
|
4260
|
-
|
|
4261
|
-
|
|
4262
|
-
|
|
3599
|
+
return parsed;
|
|
3600
|
+
}
|
|
3601
|
+
function computeRemaining(deadlineMs) {
|
|
3602
|
+
const diff = Math.max(0, deadlineMs - Date.now());
|
|
3603
|
+
const totalSeconds = Math.floor(diff / 1e3);
|
|
3604
|
+
const h = Math.floor(totalSeconds / 3600);
|
|
3605
|
+
const m = Math.floor(totalSeconds % 3600 / 60);
|
|
3606
|
+
const s = totalSeconds % 60;
|
|
3607
|
+
return { h, m, s, expired: diff === 0 };
|
|
3608
|
+
}
|
|
3609
|
+
function pad(n) {
|
|
3610
|
+
return String(n).padStart(2, "0");
|
|
3611
|
+
}
|
|
3612
|
+
function PaywallCountdown({
|
|
3613
|
+
deadline,
|
|
3614
|
+
format = "h:m:s",
|
|
3615
|
+
onExpire,
|
|
3616
|
+
className,
|
|
3617
|
+
render
|
|
3618
|
+
}) {
|
|
3619
|
+
const deadlineMsRef = (0, import_react22.useRef)(null);
|
|
3620
|
+
if (deadlineMsRef.current === null) {
|
|
3621
|
+
deadlineMsRef.current = resolveDeadlineMs(deadline);
|
|
3622
|
+
}
|
|
3623
|
+
const [state, setState] = (0, import_react22.useState)(() => computeRemaining(deadlineMsRef.current));
|
|
3624
|
+
const expiredCalledRef = (0, import_react22.useRef)(false);
|
|
3625
|
+
(0, import_react22.useEffect)(() => {
|
|
3626
|
+
if (state.expired) {
|
|
3627
|
+
if (!expiredCalledRef.current) {
|
|
3628
|
+
expiredCalledRef.current = true;
|
|
3629
|
+
onExpire?.();
|
|
3630
|
+
}
|
|
3631
|
+
return;
|
|
3632
|
+
}
|
|
3633
|
+
const tick = () => {
|
|
3634
|
+
const next = computeRemaining(deadlineMsRef.current);
|
|
3635
|
+
setState(next);
|
|
3636
|
+
if (next.expired && !expiredCalledRef.current) {
|
|
3637
|
+
expiredCalledRef.current = true;
|
|
3638
|
+
onExpire?.();
|
|
3639
|
+
}
|
|
3640
|
+
};
|
|
3641
|
+
const id = setInterval(tick, 1e3);
|
|
3642
|
+
return () => clearInterval(id);
|
|
3643
|
+
}, [state.expired]);
|
|
3644
|
+
if (render) {
|
|
3645
|
+
return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("div", { className, children: render(state) });
|
|
4263
3646
|
}
|
|
4264
|
-
|
|
3647
|
+
const formatted = format === "h:m:s" ? `${pad(state.h)}:${pad(state.m)}:${pad(state.s)}` : `${pad(state.h * 60 + state.m)}:${pad(state.s)}`;
|
|
3648
|
+
return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("div", { className: [DEFAULT_COUNTDOWN_CLASSES, className].filter(Boolean).join(" "), children: formatted });
|
|
4265
3649
|
}
|
|
4266
3650
|
|
|
4267
|
-
// src/
|
|
4268
|
-
|
|
4269
|
-
|
|
4270
|
-
|
|
3651
|
+
// src/components/paywall/blocks/PaywallFeatures.tsx
|
|
3652
|
+
var import_jsx_runtime39 = require("react/jsx-runtime");
|
|
3653
|
+
function PaywallFeatures({
|
|
3654
|
+
items,
|
|
3655
|
+
IconComponent,
|
|
3656
|
+
className,
|
|
3657
|
+
itemClassName,
|
|
3658
|
+
iconClassName,
|
|
3659
|
+
render,
|
|
3660
|
+
renderItem
|
|
3661
|
+
}) {
|
|
3662
|
+
if (render) {
|
|
3663
|
+
return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("div", { className, children: render({ items }) });
|
|
3664
|
+
}
|
|
3665
|
+
if (renderItem) {
|
|
3666
|
+
return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("ul", { className, children: items.map((item, idx) => /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("li", { children: renderItem(item, idx) }, idx)) });
|
|
3667
|
+
}
|
|
3668
|
+
return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("ul", { className, children: items.map((item, idx) => /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("li", { className: itemClassName, children: [
|
|
3669
|
+
IconComponent ? /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(IconComponent, { className: iconClassName }) : /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("span", { className: iconClassName, "aria-hidden": "true", children: "\u2713" }),
|
|
3670
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)("span", { children: item })
|
|
3671
|
+
] }, idx)) });
|
|
4271
3672
|
}
|
|
4272
3673
|
|
|
4273
|
-
// src/components/paywall/
|
|
4274
|
-
var
|
|
4275
|
-
var
|
|
4276
|
-
|
|
4277
|
-
|
|
4278
|
-
|
|
4279
|
-
|
|
4280
|
-
|
|
4281
|
-
|
|
4282
|
-
|
|
4283
|
-
|
|
3674
|
+
// src/components/paywall/blocks/PaywallFeaturesCard.tsx
|
|
3675
|
+
var import_jsx_runtime40 = require("react/jsx-runtime");
|
|
3676
|
+
var DEFAULT_CARD_CLASSES = "rounded-xl border p-4";
|
|
3677
|
+
function PaywallFeaturesCard({
|
|
3678
|
+
title,
|
|
3679
|
+
items,
|
|
3680
|
+
className,
|
|
3681
|
+
cardClassName,
|
|
3682
|
+
titleClassName,
|
|
3683
|
+
itemClassName,
|
|
3684
|
+
renderItem
|
|
3685
|
+
}) {
|
|
3686
|
+
return /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("div", { className, children: /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("div", { className: [DEFAULT_CARD_CLASSES, cardClassName].filter(Boolean).join(" "), children: [
|
|
3687
|
+
title ? /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("div", { className: ["font-semibold mb-2", titleClassName].filter(Boolean).join(" "), children: title }) : null,
|
|
3688
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)("ul", { children: items.map(
|
|
3689
|
+
(item, idx) => renderItem ? /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("li", { children: renderItem(item, idx) }, idx) : /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("li", { className: itemClassName, children: [
|
|
3690
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)("span", { "aria-hidden": "true", children: "\u2022" }),
|
|
3691
|
+
" ",
|
|
3692
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)("span", { children: item })
|
|
3693
|
+
] }, idx)
|
|
3694
|
+
) })
|
|
3695
|
+
] }) });
|
|
4284
3696
|
}
|
|
4285
3697
|
|
|
4286
|
-
// src/components/paywall/
|
|
4287
|
-
var
|
|
4288
|
-
|
|
4289
|
-
|
|
4290
|
-
|
|
4291
|
-
|
|
3698
|
+
// src/components/paywall/blocks/PaywallTrophyBadge.tsx
|
|
3699
|
+
var import_jsx_runtime41 = require("react/jsx-runtime");
|
|
3700
|
+
var DEFAULT_CHIP_CLASSES = "inline-flex items-center gap-1 px-3 py-1 rounded-full bg-yellow-100 text-yellow-900 text-sm font-medium";
|
|
3701
|
+
var FLOATING_CLASSES = "absolute top-2 right-2 z-10 shadow-md";
|
|
3702
|
+
function PaywallTrophyBadge({
|
|
3703
|
+
text,
|
|
3704
|
+
className,
|
|
3705
|
+
iconClassName,
|
|
3706
|
+
floating = false,
|
|
3707
|
+
render
|
|
3708
|
+
}) {
|
|
3709
|
+
if (render) {
|
|
3710
|
+
return /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("div", { className, children: render({ text }) });
|
|
4292
3711
|
}
|
|
4293
|
-
|
|
3712
|
+
const rootClasses = [
|
|
3713
|
+
DEFAULT_CHIP_CLASSES,
|
|
3714
|
+
floating ? FLOATING_CLASSES : "",
|
|
3715
|
+
className
|
|
3716
|
+
].filter(Boolean).join(" ");
|
|
3717
|
+
return /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: rootClasses, children: [
|
|
3718
|
+
/* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { className: iconClassName, "aria-hidden": "true", children: "\u{1F3C6}" }),
|
|
3719
|
+
/* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { children: text })
|
|
3720
|
+
] });
|
|
4294
3721
|
}
|
|
4295
3722
|
|
|
4296
|
-
// src/components/paywall/
|
|
4297
|
-
var
|
|
4298
|
-
|
|
4299
|
-
|
|
3723
|
+
// src/components/paywall/blocks/PaywallAnchorPrice.tsx
|
|
3724
|
+
var import_jsx_runtime42 = require("react/jsx-runtime");
|
|
3725
|
+
var DEFAULT_CLASS2 = "text-sm opacity-60 line-through";
|
|
3726
|
+
function PaywallAnchorPrice({
|
|
4300
3727
|
className,
|
|
4301
|
-
|
|
4302
|
-
tabActiveClassName
|
|
3728
|
+
render
|
|
4303
3729
|
}) {
|
|
4304
|
-
const {
|
|
4305
|
-
if (
|
|
4306
|
-
|
|
4307
|
-
|
|
4308
|
-
|
|
4309
|
-
|
|
4310
|
-
|
|
4311
|
-
|
|
4312
|
-
|
|
4313
|
-
|
|
4314
|
-
|
|
4315
|
-
"aria-controls": `paywall-tab-${m}`,
|
|
4316
|
-
tabIndex: active ? 0 : -1,
|
|
4317
|
-
onClick: () => selectMethod(m),
|
|
4318
|
-
className: [tabClassName, active ? tabActiveClassName : ""].filter(Boolean).join(" "),
|
|
4319
|
-
children: label
|
|
4320
|
-
},
|
|
4321
|
-
m
|
|
4322
|
-
);
|
|
4323
|
-
}) });
|
|
3730
|
+
const { anchorPriceCents, cycle } = usePaywallContext();
|
|
3731
|
+
if (anchorPriceCents === null || anchorPriceCents === void 0 || anchorPriceCents <= 0) {
|
|
3732
|
+
return null;
|
|
3733
|
+
}
|
|
3734
|
+
void cycle;
|
|
3735
|
+
const formatted = formatBRL(anchorPriceCents);
|
|
3736
|
+
const rootClasses = [DEFAULT_CLASS2, className].filter(Boolean).join(" ");
|
|
3737
|
+
if (render) {
|
|
3738
|
+
return /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: className || void 0, children: render({ anchorCents: anchorPriceCents, formatted }) });
|
|
3739
|
+
}
|
|
3740
|
+
return /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: rootClasses, children: formatted });
|
|
4324
3741
|
}
|
|
4325
3742
|
|
|
4326
|
-
// src/components/paywall/
|
|
4327
|
-
var
|
|
4328
|
-
|
|
4329
|
-
|
|
4330
|
-
|
|
4331
|
-
|
|
4332
|
-
|
|
3743
|
+
// src/components/paywall/blocks/PaywallTestimonials.tsx
|
|
3744
|
+
var import_jsx_runtime43 = require("react/jsx-runtime");
|
|
3745
|
+
var DEFAULT_ROOT = "flex gap-3 overflow-x-auto snap-x snap-mandatory pb-2";
|
|
3746
|
+
var DEFAULT_CARD = "snap-start shrink-0 w-72 rounded-2xl border p-4 flex flex-col gap-2";
|
|
3747
|
+
var DEFAULT_AVATAR = "w-10 h-10 rounded-full object-cover";
|
|
3748
|
+
var DEFAULT_QUOTE = "text-sm leading-snug";
|
|
3749
|
+
var DEFAULT_NAME = "text-xs font-semibold opacity-80";
|
|
3750
|
+
var DEFAULT_STARS = "text-yellow-500 text-sm";
|
|
3751
|
+
function clampStars(n) {
|
|
3752
|
+
return Math.max(0, Math.min(5, Math.round(n)));
|
|
3753
|
+
}
|
|
3754
|
+
function PaywallTestimonials({
|
|
3755
|
+
items,
|
|
3756
|
+
className,
|
|
3757
|
+
cardClassName,
|
|
3758
|
+
avatarClassName,
|
|
3759
|
+
quoteClassName,
|
|
3760
|
+
nameClassName,
|
|
3761
|
+
starsClassName,
|
|
3762
|
+
renderItem
|
|
3763
|
+
}) {
|
|
3764
|
+
const rootClasses = [DEFAULT_ROOT, className].filter(Boolean).join(" ");
|
|
3765
|
+
const cardClasses = [DEFAULT_CARD, cardClassName].filter(Boolean).join(" ");
|
|
3766
|
+
const avatarClasses = [DEFAULT_AVATAR, avatarClassName].filter(Boolean).join(" ");
|
|
3767
|
+
const quoteClasses = [DEFAULT_QUOTE, quoteClassName].filter(Boolean).join(" ");
|
|
3768
|
+
const nameClasses = [DEFAULT_NAME, nameClassName].filter(Boolean).join(" ");
|
|
3769
|
+
const starsClasses = [DEFAULT_STARS, starsClassName].filter(Boolean).join(" ");
|
|
3770
|
+
return /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("div", { className: rootClasses, children: items.map((item, idx) => {
|
|
3771
|
+
if (renderItem) return renderItem(item, idx);
|
|
3772
|
+
const filled = clampStars(item.stars);
|
|
3773
|
+
const empty = 5 - filled;
|
|
3774
|
+
return /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", { className: cardClasses, children: [
|
|
3775
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
3776
|
+
item.avatar ? /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
|
|
3777
|
+
"img",
|
|
3778
|
+
{
|
|
3779
|
+
src: item.avatar,
|
|
3780
|
+
alt: "",
|
|
3781
|
+
loading: "lazy",
|
|
3782
|
+
className: avatarClasses,
|
|
3783
|
+
"aria-hidden": "true"
|
|
3784
|
+
}
|
|
3785
|
+
) : null,
|
|
3786
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsx)("div", { className: nameClasses, children: item.name })
|
|
3787
|
+
] }),
|
|
3788
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", { className: starsClasses, "aria-label": `${filled} de 5 estrelas`, children: [
|
|
3789
|
+
"\u2605".repeat(filled),
|
|
3790
|
+
"\u2606".repeat(empty)
|
|
3791
|
+
] }),
|
|
3792
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsx)("p", { className: quoteClasses, children: item.quote })
|
|
3793
|
+
] }, idx);
|
|
3794
|
+
}) });
|
|
4333
3795
|
}
|
|
4334
3796
|
|
|
4335
|
-
// src/components/paywall/
|
|
4336
|
-
var
|
|
4337
|
-
var
|
|
4338
|
-
|
|
4339
|
-
|
|
4340
|
-
|
|
4341
|
-
|
|
4342
|
-
|
|
4343
|
-
|
|
4344
|
-
|
|
4345
|
-
|
|
4346
|
-
|
|
3797
|
+
// src/components/paywall/blocks/PaywallStatsRow.tsx
|
|
3798
|
+
var import_jsx_runtime44 = require("react/jsx-runtime");
|
|
3799
|
+
var DEFAULT_ROOT2 = "grid grid-cols-3 gap-4";
|
|
3800
|
+
var DEFAULT_CELL = "flex flex-col items-center text-center";
|
|
3801
|
+
var DEFAULT_VALUE = "text-2xl font-bold";
|
|
3802
|
+
var DEFAULT_LABEL = "text-xs opacity-70";
|
|
3803
|
+
function PaywallStatsRow({
|
|
3804
|
+
stats,
|
|
3805
|
+
className,
|
|
3806
|
+
cellClassName,
|
|
3807
|
+
valueClassName,
|
|
3808
|
+
labelClassName,
|
|
3809
|
+
renderCell
|
|
3810
|
+
}) {
|
|
3811
|
+
const rootClasses = [DEFAULT_ROOT2, className].filter(Boolean).join(" ");
|
|
3812
|
+
const cellClasses = [DEFAULT_CELL, cellClassName].filter(Boolean).join(" ");
|
|
3813
|
+
const valueClasses = [DEFAULT_VALUE, valueClassName].filter(Boolean).join(" ");
|
|
3814
|
+
const labelClasses = [DEFAULT_LABEL, labelClassName].filter(Boolean).join(" ");
|
|
3815
|
+
return /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("div", { className: rootClasses, children: stats.map((stat, idx) => {
|
|
3816
|
+
if (renderCell) return renderCell(stat, idx);
|
|
3817
|
+
return /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", { className: cellClasses, children: [
|
|
3818
|
+
stat.icon ? /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("div", { "aria-hidden": "true", children: stat.icon }) : null,
|
|
3819
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsx)("div", { className: valueClasses, children: stat.value }),
|
|
3820
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsx)("div", { className: labelClasses, children: stat.label })
|
|
3821
|
+
] }, idx);
|
|
3822
|
+
}) });
|
|
3823
|
+
}
|
|
3824
|
+
|
|
3825
|
+
// src/components/paywall/blocks/PaywallFinePrint.tsx
|
|
3826
|
+
var import_jsx_runtime45 = require("react/jsx-runtime");
|
|
3827
|
+
var DEFAULT_CLASS3 = "text-xs opacity-60 leading-snug";
|
|
3828
|
+
var CYCLE_LABEL2 = {
|
|
3829
|
+
MONTHLY: "mensal",
|
|
3830
|
+
YEARLY: "anual"
|
|
4347
3831
|
};
|
|
4348
|
-
function
|
|
4349
|
-
|
|
3832
|
+
function PaywallFinePrint({
|
|
3833
|
+
template,
|
|
4350
3834
|
className,
|
|
4351
|
-
cardClassName,
|
|
4352
|
-
cardSelectedClassName,
|
|
4353
|
-
anchorClassName,
|
|
4354
|
-
variant = "default",
|
|
4355
3835
|
render
|
|
4356
3836
|
}) {
|
|
4357
|
-
const
|
|
4358
|
-
|
|
4359
|
-
|
|
3837
|
+
const {
|
|
3838
|
+
currentPriceCents,
|
|
3839
|
+
cycle,
|
|
3840
|
+
trialDaysCard,
|
|
3841
|
+
trialDaysPix,
|
|
3842
|
+
selectedMethod
|
|
3843
|
+
} = usePaywallContext();
|
|
3844
|
+
const trialDays = selectedMethod === "card" ? trialDaysCard : trialDaysPix;
|
|
3845
|
+
const cycleLabel = CYCLE_LABEL2[cycle] ?? cycle.toLowerCase();
|
|
3846
|
+
const priceFormatted = formatBRL(currentPriceCents ?? 0);
|
|
3847
|
+
const rootClasses = [DEFAULT_CLASS3, className].filter(Boolean).join(" ");
|
|
4360
3848
|
if (render) {
|
|
4361
|
-
return /* @__PURE__ */ (0,
|
|
3849
|
+
return /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("p", { className: className || void 0, children: render({
|
|
3850
|
+
currentPriceCents: currentPriceCents ?? 0,
|
|
3851
|
+
cycle,
|
|
3852
|
+
trialDays: trialDays ?? 0,
|
|
3853
|
+
selectedMethod
|
|
3854
|
+
}) });
|
|
4362
3855
|
}
|
|
4363
|
-
|
|
4364
|
-
|
|
4365
|
-
const composedCardClassName = [v.card, cardClassName].filter(Boolean).join(" ");
|
|
4366
|
-
const composedCardSelectedClassName = [v.cardSelected, cardSelectedClassName].filter(Boolean).join(" ");
|
|
4367
|
-
const monthlyCents = plan?.monthlyCents ?? 0;
|
|
4368
|
-
const yearlyCents = plan?.yearlyCents ?? 0;
|
|
4369
|
-
const anchorMonthly = plan?.anchorMonthlyCents ?? null;
|
|
4370
|
-
const anchorYearly = plan?.anchorYearlyCents ?? null;
|
|
4371
|
-
return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
4372
|
-
"div",
|
|
4373
|
-
{
|
|
4374
|
-
role: "radiogroup",
|
|
4375
|
-
"aria-label": "Ciclo de cobran\xE7a",
|
|
4376
|
-
className: ["flex flex-row gap-2", className].filter(Boolean).join(" "),
|
|
4377
|
-
children: cycles.map((c) => {
|
|
4378
|
-
const active = c === selected;
|
|
4379
|
-
const label = c === "YEARLY" ? labels.annualLabel : labels.monthlyLabel;
|
|
4380
|
-
const suffix = c === "YEARLY" ? labels.annualSuffix : labels.monthlySuffix;
|
|
4381
|
-
const mainCents = c === "YEARLY" ? Math.round(yearlyCents / 12) : monthlyCents;
|
|
4382
|
-
const anchorCents = c === "YEARLY" ? anchorYearly : anchorMonthly;
|
|
4383
|
-
return /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(
|
|
4384
|
-
"button",
|
|
4385
|
-
{
|
|
4386
|
-
type: "button",
|
|
4387
|
-
role: "radio",
|
|
4388
|
-
"aria-checked": active,
|
|
4389
|
-
onClick: () => setCycle(c),
|
|
4390
|
-
className: [
|
|
4391
|
-
"flex flex-col items-center gap-0.5",
|
|
4392
|
-
composedCardClassName,
|
|
4393
|
-
active ? composedCardSelectedClassName : ""
|
|
4394
|
-
].filter(Boolean).join(" "),
|
|
4395
|
-
children: [
|
|
4396
|
-
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)("span", { className: "font-bold text-base leading-tight", children: formatBRL(mainCents) }),
|
|
4397
|
-
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)("span", { className: "text-xs opacity-70 leading-tight", children: suffix }),
|
|
4398
|
-
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)("span", { className: "text-xs opacity-60 leading-tight", children: label }),
|
|
4399
|
-
anchorCents != null && anchorCents > mainCents ? /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("span", { className: anchorClassName ?? "text-xs opacity-50", children: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("s", { children: formatBRL(anchorCents) }) }) : null
|
|
4400
|
-
]
|
|
4401
|
-
},
|
|
4402
|
-
c
|
|
4403
|
-
);
|
|
4404
|
-
})
|
|
4405
|
-
}
|
|
4406
|
-
);
|
|
3856
|
+
const text = template.replaceAll("{price}", priceFormatted).replaceAll("{trialDays}", String(trialDays ?? 0)).replaceAll("{cycle}", cycleLabel);
|
|
3857
|
+
return /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("p", { className: rootClasses, children: text });
|
|
4407
3858
|
}
|
|
4408
3859
|
|
|
4409
|
-
// src/components/paywall/
|
|
4410
|
-
var
|
|
4411
|
-
var
|
|
4412
|
-
|
|
4413
|
-
|
|
4414
|
-
|
|
4415
|
-
|
|
4416
|
-
|
|
3860
|
+
// src/components/paywall/blocks/PaywallTrustLine.tsx
|
|
3861
|
+
var import_jsx_runtime46 = require("react/jsx-runtime");
|
|
3862
|
+
var DEFAULT_ROOT3 = "flex items-center gap-3";
|
|
3863
|
+
var DEFAULT_ITEM = "flex items-center gap-1.5 text-xs";
|
|
3864
|
+
function PaywallTrustLine({
|
|
3865
|
+
items,
|
|
3866
|
+
className,
|
|
3867
|
+
itemClassName,
|
|
3868
|
+
renderItem
|
|
4417
3869
|
}) {
|
|
4418
|
-
|
|
4419
|
-
|
|
4420
|
-
|
|
4421
|
-
|
|
4422
|
-
|
|
4423
|
-
|
|
4424
|
-
|
|
4425
|
-
}
|
|
4426
|
-
) });
|
|
3870
|
+
const rootClasses = [DEFAULT_ROOT3, className].filter(Boolean).join(" ");
|
|
3871
|
+
const itemClasses = [DEFAULT_ITEM, itemClassName].filter(Boolean).join(" ");
|
|
3872
|
+
return /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("div", { className: rootClasses, children: items.map((item, idx) => {
|
|
3873
|
+
if (renderItem) return renderItem(item, idx);
|
|
3874
|
+
return /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("span", { className: itemClasses, children: [
|
|
3875
|
+
/* @__PURE__ */ (0, import_jsx_runtime46.jsx)("span", { "aria-hidden": "true", children: item.icon }),
|
|
3876
|
+
/* @__PURE__ */ (0, import_jsx_runtime46.jsx)("span", { children: item.text })
|
|
3877
|
+
] }, idx);
|
|
3878
|
+
}) });
|
|
4427
3879
|
}
|
|
4428
|
-
|
|
4429
|
-
|
|
4430
|
-
|
|
4431
|
-
|
|
4432
|
-
|
|
3880
|
+
|
|
3881
|
+
// src/components/paywall/blocks/PaywallStickyFooter.tsx
|
|
3882
|
+
var import_jsx_runtime47 = require("react/jsx-runtime");
|
|
3883
|
+
var DEFAULT_CLASSES = "sticky bottom-0 left-0 right-0 bg-background";
|
|
3884
|
+
var SAFE_AREA_CLASS = "pb-[env(safe-area-inset-bottom)]";
|
|
3885
|
+
function PaywallStickyFooter({
|
|
3886
|
+
children,
|
|
3887
|
+
className,
|
|
3888
|
+
safeAreaInsets = true
|
|
4433
3889
|
}) {
|
|
4434
|
-
const
|
|
4435
|
-
|
|
4436
|
-
|
|
4437
|
-
|
|
4438
|
-
|
|
4439
|
-
|
|
4440
|
-
|
|
4441
|
-
|
|
4442
|
-
|
|
4443
|
-
|
|
4444
|
-
|
|
4445
|
-
|
|
4446
|
-
|
|
4447
|
-
|
|
4448
|
-
|
|
4449
|
-
|
|
4450
|
-
|
|
4451
|
-
|
|
4452
|
-
|
|
4453
|
-
|
|
3890
|
+
const classes = [DEFAULT_CLASSES, safeAreaInsets ? SAFE_AREA_CLASS : null, className].filter(Boolean).join(" ");
|
|
3891
|
+
return /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("div", { className: classes, children });
|
|
3892
|
+
}
|
|
3893
|
+
|
|
3894
|
+
// src/defaults/CheckoutPageDefault.tsx
|
|
3895
|
+
var import_jsx_runtime48 = require("react/jsx-runtime");
|
|
3896
|
+
var INTENT_KEY = "hook:paywall:intent";
|
|
3897
|
+
var PIX_PAYLOAD_KEY = "hook:paywall:pix-pending";
|
|
3898
|
+
function readIntent() {
|
|
3899
|
+
if (typeof window === "undefined") return {};
|
|
3900
|
+
try {
|
|
3901
|
+
const raw = sessionStorage.getItem(INTENT_KEY);
|
|
3902
|
+
if (!raw) return {};
|
|
3903
|
+
return JSON.parse(raw);
|
|
3904
|
+
} catch {
|
|
3905
|
+
return {};
|
|
3906
|
+
}
|
|
3907
|
+
}
|
|
3908
|
+
function formatBrl(cents) {
|
|
3909
|
+
return new Intl.NumberFormat("pt-BR", { style: "currency", currency: "BRL" }).format(cents / 100);
|
|
3910
|
+
}
|
|
3911
|
+
function formatCardNumber(v) {
|
|
3912
|
+
const digits = v.replace(/\D/g, "").slice(0, 16);
|
|
3913
|
+
return digits.replace(/(.{4})/g, "$1 ").trim();
|
|
3914
|
+
}
|
|
3915
|
+
function formatExpiryMmAa(v) {
|
|
3916
|
+
const d = v.replace(/\D/g, "").slice(0, 4);
|
|
3917
|
+
if (d.length < 3) return d;
|
|
3918
|
+
return d.slice(0, 2) + "/" + d.slice(2);
|
|
3919
|
+
}
|
|
3920
|
+
function parseExpiryMmAa(v) {
|
|
3921
|
+
const d = v.replace(/\D/g, "");
|
|
3922
|
+
return { month: d.slice(0, 2), year: d.slice(2, 4) };
|
|
3923
|
+
}
|
|
3924
|
+
function formatCpf(v) {
|
|
3925
|
+
const d = v.replace(/\D/g, "").slice(0, 11);
|
|
3926
|
+
if (d.length <= 3) return d;
|
|
3927
|
+
if (d.length <= 6) return d.slice(0, 3) + "." + d.slice(3);
|
|
3928
|
+
if (d.length <= 9) return d.slice(0, 3) + "." + d.slice(3, 6) + "." + d.slice(6);
|
|
3929
|
+
return d.slice(0, 3) + "." + d.slice(3, 6) + "." + d.slice(6, 9) + "-" + d.slice(9);
|
|
3930
|
+
}
|
|
3931
|
+
function detectCardBrand(num) {
|
|
3932
|
+
const n = num.replace(/\s/g, "");
|
|
3933
|
+
if (/^4/.test(n)) return "VISA";
|
|
3934
|
+
if (/^(5[1-5]|2[2-7])/.test(n)) return "MASTER";
|
|
3935
|
+
if (/^3[47]/.test(n)) return "AMEX";
|
|
3936
|
+
if (/^(4011|4312|4389|4514|6011|6362|6363)/.test(n)) return "ELO";
|
|
3937
|
+
if (/^(606282|3841)/.test(n)) return "HIPER";
|
|
3938
|
+
return "";
|
|
3939
|
+
}
|
|
3940
|
+
function CheckoutPageDefault() {
|
|
3941
|
+
const navigate = (0, import_react_router_dom3.useNavigate)();
|
|
3942
|
+
const plan = usePlan();
|
|
3943
|
+
const intent = (0, import_react23.useMemo)(readIntent, []);
|
|
3944
|
+
const defaultMethod = intent.method === "pix-auto" ? "pix-auto" : "card";
|
|
3945
|
+
const defaultCycle = intent.cycle === "MONTHLY" ? "MONTHLY" : "YEARLY";
|
|
3946
|
+
const form = useCheckoutForm({ defaultMethod, defaultCycle });
|
|
3947
|
+
const [expiryMmAa, setExpiryMmAa] = (0, import_react23.useState)("");
|
|
3948
|
+
(0, import_react23.useEffect)(() => {
|
|
3949
|
+
const { month, year } = parseExpiryMmAa(expiryMmAa);
|
|
3950
|
+
if (month !== form.card.expiryMonth || year !== form.card.expiryYear) {
|
|
3951
|
+
form.setCard({ expiryMonth: month, expiryYear: year });
|
|
4454
3952
|
}
|
|
4455
|
-
|
|
4456
|
-
|
|
4457
|
-
|
|
4458
|
-
|
|
4459
|
-
|
|
4460
|
-
|
|
4461
|
-
|
|
4462
|
-
|
|
4463
|
-
|
|
4464
|
-
|
|
4465
|
-
|
|
4466
|
-
|
|
4467
|
-
|
|
4468
|
-
|
|
4469
|
-
|
|
4470
|
-
|
|
4471
|
-
|
|
4472
|
-
|
|
4473
|
-
|
|
4474
|
-
|
|
4475
|
-
|
|
4476
|
-
}, [
|
|
4477
|
-
const
|
|
4478
|
-
|
|
4479
|
-
|
|
4480
|
-
|
|
4481
|
-
|
|
4482
|
-
|
|
4483
|
-
|
|
4484
|
-
|
|
4485
|
-
|
|
3953
|
+
}, [expiryMmAa]);
|
|
3954
|
+
(0, import_react23.useEffect)(() => {
|
|
3955
|
+
if (form.emailTaken && form.loginUrl) {
|
|
3956
|
+
const t = setTimeout(() => navigate(form.loginUrl), 1200);
|
|
3957
|
+
return () => clearTimeout(t);
|
|
3958
|
+
}
|
|
3959
|
+
}, [form.emailTaken, form.loginUrl, navigate]);
|
|
3960
|
+
const planInfo = plan.data ? {
|
|
3961
|
+
priceCents: plan.data.priceCents,
|
|
3962
|
+
yearlyPriceCents: plan.data.yearlyPriceCents,
|
|
3963
|
+
trialDays: plan.data.trialDays
|
|
3964
|
+
} : null;
|
|
3965
|
+
const annual = form.cycle === "YEARLY";
|
|
3966
|
+
const cyclePrice = (0, import_react23.useMemo)(() => {
|
|
3967
|
+
if (!planInfo) return null;
|
|
3968
|
+
return annual ? planInfo.yearlyPriceCents ?? planInfo.priceCents * 12 : planInfo.priceCents;
|
|
3969
|
+
}, [planInfo, annual]);
|
|
3970
|
+
const monthlyText = (0, import_react23.useMemo)(() => {
|
|
3971
|
+
if (!planInfo) return "";
|
|
3972
|
+
const monthly = annual && planInfo.yearlyPriceCents ? Math.round(planInfo.yearlyPriceCents / 12) : planInfo.priceCents;
|
|
3973
|
+
return formatBrl(monthly);
|
|
3974
|
+
}, [planInfo, annual]);
|
|
3975
|
+
const todayCents = (0, import_react23.useMemo)(() => {
|
|
3976
|
+
if (form.method === "pix-auto") return cyclePrice ?? 0;
|
|
3977
|
+
const trialDays2 = planInfo?.trialDays ?? 0;
|
|
3978
|
+
if (trialDays2 > 0) return 0;
|
|
3979
|
+
return cyclePrice ?? 0;
|
|
3980
|
+
}, [form.method, cyclePrice, planInfo]);
|
|
3981
|
+
const todayAmount = formatBrl(todayCents);
|
|
3982
|
+
const cyclePriceText = cyclePrice !== null ? formatBrl(cyclePrice) : "";
|
|
3983
|
+
const annualSavingsCents = (0, import_react23.useMemo)(() => {
|
|
3984
|
+
if (!planInfo || !planInfo.yearlyPriceCents) return 0;
|
|
3985
|
+
return planInfo.priceCents * 12 - planInfo.yearlyPriceCents;
|
|
3986
|
+
}, [planInfo]);
|
|
3987
|
+
const trialDays = planInfo?.trialDays ?? 7;
|
|
3988
|
+
const cardBrand = detectCardBrand(form.card.number);
|
|
3989
|
+
async function onSubmit(e) {
|
|
3990
|
+
e.preventDefault();
|
|
3991
|
+
const result = await form.submit();
|
|
3992
|
+
if (!result) return;
|
|
3993
|
+
if (form.method === "pix-auto" && result.pix_qr_payload) {
|
|
3994
|
+
try {
|
|
3995
|
+
sessionStorage.setItem(
|
|
3996
|
+
PIX_PAYLOAD_KEY,
|
|
3997
|
+
JSON.stringify({
|
|
3998
|
+
payload: result.pix_qr_payload,
|
|
3999
|
+
base64: result.pix_qr_base64 ?? null,
|
|
4000
|
+
subscriptionId: result.subscription_id,
|
|
4001
|
+
pixAuthorizationId: result.pix_authorization_id ?? null
|
|
4002
|
+
})
|
|
4003
|
+
);
|
|
4004
|
+
} catch {
|
|
4005
|
+
}
|
|
4006
|
+
navigate(result.redirect.replace(/^.*\/app\/[^/]+/, ""));
|
|
4486
4007
|
return;
|
|
4487
4008
|
}
|
|
4488
|
-
|
|
4489
|
-
}
|
|
4490
|
-
|
|
4491
|
-
|
|
4492
|
-
|
|
4493
|
-
|
|
4494
|
-
|
|
4495
|
-
|
|
4496
|
-
|
|
4497
|
-
|
|
4498
|
-
|
|
4499
|
-
|
|
4500
|
-
|
|
4501
|
-
|
|
4502
|
-
|
|
4503
|
-
|
|
4504
|
-
|
|
4505
|
-
|
|
4506
|
-
|
|
4507
|
-
|
|
4508
|
-
|
|
4509
|
-
|
|
4510
|
-
|
|
4511
|
-
|
|
4512
|
-
|
|
4513
|
-
|
|
4514
|
-
|
|
4515
|
-
|
|
4516
|
-
|
|
4517
|
-
|
|
4518
|
-
|
|
4519
|
-
|
|
4520
|
-
|
|
4521
|
-
|
|
4522
|
-
|
|
4523
|
-
|
|
4524
|
-
|
|
4525
|
-
|
|
4526
|
-
|
|
4527
|
-
|
|
4528
|
-
|
|
4529
|
-
|
|
4530
|
-
|
|
4531
|
-
|
|
4532
|
-
|
|
4533
|
-
|
|
4534
|
-
|
|
4535
|
-
|
|
4536
|
-
/* @__PURE__ */ (0,
|
|
4009
|
+
navigate(result.redirect.replace(/^.*\/app\/[^/]+/, "") || "/");
|
|
4010
|
+
}
|
|
4011
|
+
return /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("div", { className: "flex-1 flex flex-col bg-background min-h-0", children: /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("form", { onSubmit, className: "flex-1 flex flex-col min-h-0", children: [
|
|
4012
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: "flex-1 overflow-y-auto pb-4", children: [
|
|
4013
|
+
form.emailTaken ? /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("div", { className: "px-5 pt-4", children: /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { role: "alert", className: "rounded-2xl bg-destructive/10 p-4 text-sm text-destructive border border-destructive/20", children: [
|
|
4014
|
+
"Esse e-mail j\xE1 tem conta nesse app.",
|
|
4015
|
+
" ",
|
|
4016
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)("a", { href: form.loginUrl ?? "/signin", className: "underline font-semibold", children: "Entrar agora" })
|
|
4017
|
+
] }) }) : null,
|
|
4018
|
+
form.error ? /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("div", { className: "px-5 pt-4", children: /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("div", { role: "alert", className: "rounded-2xl bg-destructive/10 p-4 text-sm text-destructive border border-destructive/20", children: form.error.message || "N\xE3o foi poss\xEDvel concluir o pagamento. Tente novamente." }) }) : null,
|
|
4019
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)("div", { className: "px-5 pt-4", children: form.method === "card" ? /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: "rounded-2xl bg-card border-[1.5px] border-foreground p-3.5", children: [
|
|
4020
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: "flex items-center gap-2 mb-2", children: [
|
|
4021
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(ShieldIcon, { className: "w-4 h-4" }),
|
|
4022
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)("div", { className: "text-sm font-bold", children: "Voc\xEA N\xC3O ser\xE1 cobrada hoje" })
|
|
4023
|
+
] }),
|
|
4024
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: "flex justify-between items-baseline text-sm text-muted-foreground", children: [
|
|
4025
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)("span", { children: "R$ 0,00 agora" }),
|
|
4026
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)("span", { className: "opacity-50", children: "\xB7" }),
|
|
4027
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("span", { children: [
|
|
4028
|
+
monthlyText,
|
|
4029
|
+
"/m\xEAs ap\xF3s ",
|
|
4030
|
+
trialDays,
|
|
4031
|
+
" dias"
|
|
4032
|
+
] })
|
|
4033
|
+
] }),
|
|
4034
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: "mt-2.5 text-[11px] text-muted-foreground flex items-center gap-1.5", children: [
|
|
4035
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(BellIcon, { className: "w-2.5 h-2.5" }),
|
|
4036
|
+
"Avisamos por email 2 dias antes da primeira cobran\xE7a"
|
|
4037
|
+
] })
|
|
4038
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: "rounded-2xl p-3.5 bg-emerald-50 border-[1.5px] border-emerald-600/60", children: [
|
|
4039
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: "flex items-center gap-2 mb-2 text-emerald-900", children: [
|
|
4040
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(ShieldIcon, { className: "w-4 h-4" }),
|
|
4041
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: "text-sm font-bold", children: [
|
|
4042
|
+
"Garantia incondicional de ",
|
|
4043
|
+
trialDays,
|
|
4044
|
+
" dias"
|
|
4045
|
+
] })
|
|
4046
|
+
] }),
|
|
4047
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: "text-sm text-emerald-900 leading-snug", children: [
|
|
4048
|
+
"Voc\xEA paga hoje via Pix.",
|
|
4049
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)("br", {}),
|
|
4050
|
+
"N\xE3o gostou em ",
|
|
4051
|
+
trialDays,
|
|
4052
|
+
" dias? Devolvemos ",
|
|
4053
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)("b", { children: "100%" }),
|
|
4054
|
+
" sem perguntas \u2014 direto pelo app."
|
|
4055
|
+
] })
|
|
4056
|
+
] }) }),
|
|
4057
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("section", { className: "px-5 pt-5", children: [
|
|
4058
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)("h2", { className: "font-display text-2xl mb-3.5 leading-tight text-foreground", children: "Quase l\xE1." }),
|
|
4059
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(FieldLabel, { children: "Email" }),
|
|
4060
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
|
|
4061
|
+
FieldInput,
|
|
4062
|
+
{
|
|
4063
|
+
type: "email",
|
|
4064
|
+
inputMode: "email",
|
|
4065
|
+
autoComplete: "email",
|
|
4066
|
+
autoCapitalize: "none",
|
|
4067
|
+
autoCorrect: "off",
|
|
4068
|
+
spellCheck: false,
|
|
4069
|
+
placeholder: "seu@email.com",
|
|
4070
|
+
value: form.email,
|
|
4071
|
+
onChange: form.setEmail,
|
|
4072
|
+
onBlur: form.markEmailTouched,
|
|
4073
|
+
error: form.emailError,
|
|
4074
|
+
valid: form.emailStatus === "available"
|
|
4075
|
+
}
|
|
4076
|
+
),
|
|
4077
|
+
!form.emailError && /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(FieldHint, { children: form.emailStatus === "checking" ? "Verificando\u2026" : form.emailStatus === "available" ? "\u2713 Dispon\xEDvel" : "Voc\xEA vai usar este email para entrar no app" }),
|
|
4078
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)("div", { className: "h-3" }),
|
|
4079
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(FieldLabel, { children: "Nome completo" }),
|
|
4080
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
|
|
4081
|
+
FieldInput,
|
|
4082
|
+
{
|
|
4083
|
+
type: "text",
|
|
4084
|
+
autoComplete: "name",
|
|
4085
|
+
placeholder: "como est\xE1 no documento",
|
|
4086
|
+
value: form.name,
|
|
4087
|
+
onChange: form.setName,
|
|
4088
|
+
onBlur: form.markNameTouched,
|
|
4089
|
+
error: form.nameError,
|
|
4090
|
+
valid: !!form.name && !form.nameError
|
|
4091
|
+
}
|
|
4092
|
+
),
|
|
4093
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)("div", { className: "h-3" }),
|
|
4094
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(FieldLabel, { children: "CPF" }),
|
|
4095
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
|
|
4096
|
+
FieldInput,
|
|
4097
|
+
{
|
|
4098
|
+
type: "text",
|
|
4099
|
+
inputMode: "numeric",
|
|
4100
|
+
placeholder: "000.000.000-00",
|
|
4101
|
+
value: form.cpf,
|
|
4102
|
+
onChange: (v) => form.setCpf(formatCpf(v)),
|
|
4103
|
+
onBlur: form.markCpfTouched,
|
|
4104
|
+
error: form.cpfError,
|
|
4105
|
+
valid: !!form.cpf && !form.cpfError
|
|
4106
|
+
}
|
|
4107
|
+
),
|
|
4108
|
+
form.method === "card" ? /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)(import_jsx_runtime48.Fragment, { children: [
|
|
4109
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)("div", { className: "h-3" }),
|
|
4110
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(FieldLabel, { children: "Telefone" }),
|
|
4111
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
|
|
4112
|
+
FieldInput,
|
|
4113
|
+
{
|
|
4114
|
+
type: "tel",
|
|
4115
|
+
inputMode: "tel",
|
|
4116
|
+
autoComplete: "tel",
|
|
4117
|
+
placeholder: "(11) 99999-9999",
|
|
4118
|
+
value: form.phone,
|
|
4119
|
+
onChange: form.setPhone,
|
|
4120
|
+
onBlur: form.markPhoneTouched,
|
|
4121
|
+
error: form.phoneError,
|
|
4122
|
+
valid: !!form.phone && !form.phoneError
|
|
4123
|
+
}
|
|
4124
|
+
),
|
|
4125
|
+
!form.phoneError && /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(FieldHint, { children: "Usado pra confirmar pagamento e tratar disputas." })
|
|
4126
|
+
] }) : null
|
|
4127
|
+
] }),
|
|
4128
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("section", { className: "px-5 pt-5", children: [
|
|
4129
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(FieldLabel, { children: "Forma de pagamento" }),
|
|
4130
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { role: "tablist", className: "flex gap-1.5 bg-muted p-1 rounded-xl", children: [
|
|
4131
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
|
|
4132
|
+
TabButton,
|
|
4133
|
+
{
|
|
4134
|
+
active: form.method === "card",
|
|
4135
|
+
onClick: () => form.setMethod("card"),
|
|
4136
|
+
icon: /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(CardIcon, { className: "w-3.5 h-3.5" }),
|
|
4137
|
+
label: "Cart\xE3o",
|
|
4138
|
+
subtitle: trialDays > 0 ? `${trialDays} dias gr\xE1tis` : "pague hoje",
|
|
4139
|
+
subtitleActiveClass: "text-emerald-700"
|
|
4140
|
+
}
|
|
4141
|
+
),
|
|
4142
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
|
|
4143
|
+
TabButton,
|
|
4144
|
+
{
|
|
4145
|
+
active: form.method === "pix-auto",
|
|
4146
|
+
onClick: () => form.setMethod("pix-auto"),
|
|
4147
|
+
icon: /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(PixIcon, { className: "w-3.5 h-3.5" }),
|
|
4148
|
+
label: "Pix",
|
|
4149
|
+
subtitle: `pague hoje \xB7 garantia ${trialDays}d`,
|
|
4150
|
+
subtitleActiveClass: "text-foreground/70"
|
|
4151
|
+
}
|
|
4152
|
+
)
|
|
4153
|
+
] })
|
|
4154
|
+
] }),
|
|
4155
|
+
form.method === "card" ? /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("section", { className: "px-5 pt-3.5", children: [
|
|
4156
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(FieldLabel, { children: "N\xFAmero do cart\xE3o" }),
|
|
4157
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: "relative", children: [
|
|
4158
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
|
|
4159
|
+
FieldInput,
|
|
4160
|
+
{
|
|
4161
|
+
type: "text",
|
|
4162
|
+
inputMode: "numeric",
|
|
4163
|
+
autoComplete: "cc-number",
|
|
4164
|
+
placeholder: "0000 0000 0000 0000",
|
|
4165
|
+
value: form.card.number,
|
|
4166
|
+
onChange: (v) => form.setCard({ number: formatCardNumber(v) }),
|
|
4167
|
+
style: cardBrand ? { paddingRight: "4.5rem" } : void 0
|
|
4168
|
+
}
|
|
4169
|
+
),
|
|
4170
|
+
cardBrand && /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("span", { className: "absolute right-3 top-1/2 -translate-y-1/2 text-[10px] font-bold tracking-wide px-1.5 py-0.5 rounded bg-muted text-muted-foreground", children: cardBrand })
|
|
4171
|
+
] }),
|
|
4172
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)("div", { className: "h-3" }),
|
|
4173
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: "flex gap-2.5", children: [
|
|
4174
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: "flex-1", children: [
|
|
4175
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(FieldLabel, { children: "Validade" }),
|
|
4176
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
|
|
4177
|
+
FieldInput,
|
|
4178
|
+
{
|
|
4179
|
+
type: "text",
|
|
4180
|
+
inputMode: "numeric",
|
|
4181
|
+
autoComplete: "cc-exp",
|
|
4182
|
+
placeholder: "MM/AA",
|
|
4183
|
+
value: expiryMmAa,
|
|
4184
|
+
onChange: (v) => setExpiryMmAa(formatExpiryMmAa(v))
|
|
4185
|
+
}
|
|
4186
|
+
)
|
|
4187
|
+
] }),
|
|
4188
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: "flex-1", children: [
|
|
4189
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(FieldLabel, { children: "CVV" }),
|
|
4190
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
|
|
4191
|
+
FieldInput,
|
|
4192
|
+
{
|
|
4193
|
+
type: "text",
|
|
4194
|
+
inputMode: "numeric",
|
|
4195
|
+
autoComplete: "cc-csc",
|
|
4196
|
+
placeholder: "3 d\xEDgitos",
|
|
4197
|
+
value: form.card.ccv,
|
|
4198
|
+
onChange: (v) => form.setCard({ ccv: v.replace(/\D/g, "").slice(0, 4) })
|
|
4199
|
+
}
|
|
4200
|
+
)
|
|
4201
|
+
] })
|
|
4202
|
+
] }),
|
|
4203
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)("div", { className: "h-3" }),
|
|
4204
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(FieldLabel, { children: "Nome no cart\xE3o" }),
|
|
4205
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
|
|
4206
|
+
FieldInput,
|
|
4207
|
+
{
|
|
4208
|
+
type: "text",
|
|
4209
|
+
autoComplete: "cc-name",
|
|
4210
|
+
placeholder: "como est\xE1 no cart\xE3o",
|
|
4211
|
+
value: form.card.holderName,
|
|
4212
|
+
onChange: (v) => form.setCard({ holderName: v })
|
|
4213
|
+
}
|
|
4214
|
+
)
|
|
4215
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("section", { className: "px-5 pt-3.5", children: /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: "rounded-2xl bg-card border border-border p-3.5 flex gap-3.5 items-center", children: [
|
|
4216
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)("div", { className: "w-[72px] h-[72px] rounded-xl shrink-0 border-2 border-foreground relative overflow-hidden bg-muted", children: /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("div", { className: "absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 w-[22px] h-[22px] bg-background flex items-center justify-center", children: /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(PixIcon, { className: "w-3.5 h-3.5 text-foreground" }) }) }),
|
|
4217
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: "flex-1", children: [
|
|
4218
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)("div", { className: "text-xs font-bold uppercase tracking-wider text-muted-foreground", children: "pagamento em segundos" }),
|
|
4219
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: "text-sm text-foreground mt-1 leading-snug", children: [
|
|
4220
|
+
"Geramos seu ",
|
|
4221
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)("b", { children: "QR Pix" }),
|
|
4222
|
+
" no pr\xF3ximo passo. Pague pelo app do banco e seu acesso libera ",
|
|
4223
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)("b", { children: "imediatamente" }),
|
|
4224
|
+
"."
|
|
4225
|
+
] })
|
|
4226
|
+
] })
|
|
4227
|
+
] }) }),
|
|
4228
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)("section", { className: "px-5 pt-5", children: /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: "bg-muted rounded-2xl p-4", children: [
|
|
4229
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: "flex justify-between mb-2.5", children: [
|
|
4230
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { children: [
|
|
4231
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)("div", { className: "text-sm font-semibold text-foreground", children: annual ? "Plano Anual" : "Plano Mensal" }),
|
|
4232
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)("div", { className: "text-[11px] text-muted-foreground", children: "Coach" })
|
|
4233
|
+
] }),
|
|
4234
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: "text-right", children: [
|
|
4235
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: "text-sm font-bold text-foreground", children: [
|
|
4236
|
+
cyclePriceText,
|
|
4237
|
+
"/",
|
|
4238
|
+
annual ? "ano" : "m\xEAs"
|
|
4239
|
+
] }),
|
|
4240
|
+
annual && annualSavingsCents > 0 && /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: "text-[11px] text-emerald-700 font-semibold", children: [
|
|
4241
|
+
"economia ",
|
|
4242
|
+
formatBrl(annualSavingsCents)
|
|
4243
|
+
] })
|
|
4244
|
+
] })
|
|
4245
|
+
] }),
|
|
4246
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)("div", { className: "h-px bg-border my-3" }),
|
|
4247
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: "flex justify-between items-baseline", children: [
|
|
4248
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { children: [
|
|
4249
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)("div", { className: "text-sm font-bold text-foreground", children: "Voc\xEA paga hoje" }),
|
|
4250
|
+
form.method === "card" && trialDays > 0 && /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: "text-[11px] text-muted-foreground mt-0.5", children: [
|
|
4251
|
+
"cobran\xE7a inicia no dia ",
|
|
4252
|
+
trialDays
|
|
4253
|
+
] }),
|
|
4254
|
+
form.method === "pix-auto" && /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: "text-[11px] text-emerald-700 mt-0.5 font-semibold", children: [
|
|
4255
|
+
"reembolso garantido at\xE9 o dia ",
|
|
4256
|
+
trialDays
|
|
4257
|
+
] })
|
|
4258
|
+
] }),
|
|
4259
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)("div", { className: "text-2xl font-bold font-display tracking-tight text-foreground", children: todayAmount })
|
|
4260
|
+
] })
|
|
4261
|
+
] }) })
|
|
4262
|
+
] }),
|
|
4263
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsxs)(PaywallStickyFooter, { className: "px-5 pt-3.5 pb-5 border-t border-border", children: [
|
|
4264
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
|
|
4537
4265
|
"button",
|
|
4538
4266
|
{
|
|
4539
|
-
type: "
|
|
4540
|
-
|
|
4541
|
-
|
|
4542
|
-
|
|
4543
|
-
|
|
4544
|
-
|
|
4545
|
-
|
|
4267
|
+
type: "submit",
|
|
4268
|
+
disabled: !form.canSubmit,
|
|
4269
|
+
className: "w-full rounded-full bg-primary text-primary-foreground min-h-14 px-5 text-base font-bold inline-flex items-center justify-center gap-2 disabled:opacity-50 disabled:cursor-not-allowed shadow-lg",
|
|
4270
|
+
children: form.submitting ? /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)(import_jsx_runtime48.Fragment, { children: [
|
|
4271
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(Spinner2, {}),
|
|
4272
|
+
" ",
|
|
4273
|
+
form.method === "pix-auto" ? "Gerando QR\u2026" : "Confirmando\u2026"
|
|
4274
|
+
] }) : form.method === "card" ? /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)(import_jsx_runtime48.Fragment, { children: [
|
|
4275
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(LockIcon, { className: "w-3.5 h-3.5" }),
|
|
4276
|
+
" Confirmar e come\xE7ar gr\xE1tis"
|
|
4277
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)(import_jsx_runtime48.Fragment, { children: [
|
|
4278
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(PixIcon, { className: "w-3.5 h-3.5" }),
|
|
4279
|
+
" Gerar QR Pix"
|
|
4280
|
+
] })
|
|
4546
4281
|
}
|
|
4547
4282
|
),
|
|
4548
|
-
|
|
4549
|
-
|
|
4283
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: "text-center mt-2.5 text-xs text-muted-foreground", children: [
|
|
4284
|
+
"Ao continuar, voc\xEA concorda com nossos ",
|
|
4285
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)("u", { children: "Termos" }),
|
|
4286
|
+
". Pagamento seguro Asaas."
|
|
4287
|
+
] }),
|
|
4288
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: "mt-3 flex items-center justify-center gap-3.5 text-[11px] text-muted-foreground", children: [
|
|
4289
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("span", { className: "inline-flex items-center gap-1", children: [
|
|
4290
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(LockIcon, { className: "w-2.5 h-2.5 opacity-60" }),
|
|
4291
|
+
" SSL 256-bit"
|
|
4292
|
+
] }),
|
|
4293
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)("span", { className: "w-px h-2.5 bg-border" }),
|
|
4294
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)("span", { children: "Pagamento via Asaas" }),
|
|
4295
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)("span", { className: "w-px h-2.5 bg-border" }),
|
|
4296
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("span", { children: [
|
|
4297
|
+
"Garantia ",
|
|
4298
|
+
trialDays,
|
|
4299
|
+
" dias"
|
|
4300
|
+
] })
|
|
4301
|
+
] })
|
|
4550
4302
|
] })
|
|
4551
|
-
] });
|
|
4552
|
-
}
|
|
4553
|
-
function interp(tpl, vars) {
|
|
4554
|
-
return tpl.replace(/\{(\w+)\}/g, (_m, k) => vars[k] ?? "");
|
|
4303
|
+
] }) });
|
|
4555
4304
|
}
|
|
4556
|
-
function
|
|
4557
|
-
return {
|
|
4558
|
-
tabLabel: m.tabLabel,
|
|
4559
|
-
bodyRows: m.bodyRows.map((r) => interp(r, { price, days })),
|
|
4560
|
-
ctaTemplate: m.ctaTemplate,
|
|
4561
|
-
switchHint: m.switchHint
|
|
4562
|
-
};
|
|
4305
|
+
function FieldLabel({ children }) {
|
|
4306
|
+
return /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("div", { className: "text-xs font-semibold uppercase tracking-wide text-muted-foreground mb-1.5", children });
|
|
4563
4307
|
}
|
|
4564
|
-
|
|
4565
|
-
|
|
4566
|
-
|
|
4567
|
-
|
|
4568
|
-
|
|
4569
|
-
|
|
4570
|
-
switchHint,
|
|
4571
|
-
trustLine,
|
|
4572
|
-
className,
|
|
4573
|
-
buttonClassName,
|
|
4574
|
-
switchHintClassName,
|
|
4575
|
-
trustClassName
|
|
4576
|
-
}) {
|
|
4577
|
-
const { submit, submitting } = usePaywallContext();
|
|
4578
|
-
const label = submitting && loadingLabel ? loadingLabel : ctaLabel;
|
|
4579
|
-
return /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("div", { className, children: [
|
|
4580
|
-
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
|
|
4581
|
-
"button",
|
|
4308
|
+
function FieldInput(props) {
|
|
4309
|
+
const baseClass = "w-full px-4 rounded-xl bg-card text-base text-foreground outline-none border-[1.5px] transition-colors";
|
|
4310
|
+
const stateClass = props.error ? "border-destructive focus:border-destructive" : props.valid ? "border-emerald-600 focus:border-emerald-700" : "border-border focus:border-foreground";
|
|
4311
|
+
return /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)(import_jsx_runtime48.Fragment, { children: [
|
|
4312
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
|
|
4313
|
+
"input",
|
|
4582
4314
|
{
|
|
4583
|
-
type: "
|
|
4584
|
-
|
|
4585
|
-
|
|
4586
|
-
|
|
4587
|
-
|
|
4588
|
-
|
|
4589
|
-
|
|
4315
|
+
type: props.type ?? "text",
|
|
4316
|
+
inputMode: props.inputMode,
|
|
4317
|
+
autoComplete: props.autoComplete,
|
|
4318
|
+
autoCapitalize: props.autoCapitalize,
|
|
4319
|
+
autoCorrect: props.autoCorrect,
|
|
4320
|
+
spellCheck: props.spellCheck,
|
|
4321
|
+
placeholder: props.placeholder,
|
|
4322
|
+
value: props.value,
|
|
4323
|
+
onChange: (e) => props.onChange(e.target.value),
|
|
4324
|
+
onBlur: props.onBlur,
|
|
4325
|
+
style: { height: "52px", ...props.style },
|
|
4326
|
+
className: `${baseClass} ${stateClass}`
|
|
4590
4327
|
}
|
|
4591
4328
|
),
|
|
4592
|
-
|
|
4593
|
-
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)("p", { className: trustClassName, children: trustLine })
|
|
4329
|
+
props.error ? /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("div", { className: "mt-1.5 text-xs text-destructive font-medium", children: props.error }) : null
|
|
4594
4330
|
] });
|
|
4595
4331
|
}
|
|
4596
|
-
|
|
4597
|
-
|
|
4598
|
-
var import_jsx_runtime39 = require("react/jsx-runtime");
|
|
4599
|
-
var DEFAULT_EYEBROW_CLASSES = "text-xs uppercase tracking-widest font-semibold opacity-70";
|
|
4600
|
-
function PaywallEyebrow({ text, className }) {
|
|
4601
|
-
return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("div", { className: [DEFAULT_EYEBROW_CLASSES, className].filter(Boolean).join(" "), children: text });
|
|
4332
|
+
function FieldHint({ children }) {
|
|
4333
|
+
return /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("div", { className: "mt-1.5 text-xs text-muted-foreground", children });
|
|
4602
4334
|
}
|
|
4603
|
-
|
|
4604
|
-
|
|
4605
|
-
|
|
4606
|
-
|
|
4607
|
-
|
|
4608
|
-
|
|
4609
|
-
|
|
4610
|
-
|
|
4611
|
-
|
|
4612
|
-
|
|
4613
|
-
|
|
4614
|
-
|
|
4615
|
-
|
|
4616
|
-
|
|
4617
|
-
|
|
4618
|
-
|
|
4619
|
-
|
|
4620
|
-
|
|
4621
|
-
|
|
4622
|
-
|
|
4335
|
+
function TabButton({ active, onClick, icon, label, subtitle, subtitleActiveClass }) {
|
|
4336
|
+
return /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)(
|
|
4337
|
+
"button",
|
|
4338
|
+
{
|
|
4339
|
+
type: "button",
|
|
4340
|
+
role: "tab",
|
|
4341
|
+
"aria-selected": active,
|
|
4342
|
+
onClick,
|
|
4343
|
+
className: `flex-1 flex flex-col items-center justify-center gap-0.5 py-2.5 px-1.5 rounded-lg text-sm font-semibold transition-colors ${active ? "bg-card text-foreground shadow-sm" : "bg-transparent text-muted-foreground"}`,
|
|
4344
|
+
style: { minHeight: 56 },
|
|
4345
|
+
children: [
|
|
4346
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("span", { className: "inline-flex items-center gap-1.5", children: [
|
|
4347
|
+
icon,
|
|
4348
|
+
" ",
|
|
4349
|
+
label
|
|
4350
|
+
] }),
|
|
4351
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)("span", { className: `text-[10px] font-medium ${active ? subtitleActiveClass : "text-muted-foreground/70"}`, children: subtitle })
|
|
4352
|
+
]
|
|
4353
|
+
}
|
|
4354
|
+
);
|
|
4355
|
+
}
|
|
4356
|
+
function CardIcon({ className }) {
|
|
4357
|
+
return /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.8", strokeLinejoin: "round", "aria-hidden": "true", children: [
|
|
4358
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)("rect", { x: "2.5", y: "5.5", width: "19", height: "13", rx: "2.5" }),
|
|
4359
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)("path", { d: "M2.5 10h19" })
|
|
4360
|
+
] });
|
|
4361
|
+
}
|
|
4362
|
+
function PixIcon({ className }) {
|
|
4363
|
+
return /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("svg", { className, viewBox: "0 0 24 24", fill: "currentColor", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("path", { d: "M12 2L2 12l10 10 10-10L12 2zm0 4.83L17.17 12 12 17.17 6.83 12 12 6.83z" }) });
|
|
4364
|
+
}
|
|
4365
|
+
function LockIcon({ className }) {
|
|
4366
|
+
return /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.8", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [
|
|
4367
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)("rect", { x: "4", y: "10", width: "16", height: "11", rx: "2.5" }),
|
|
4368
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)("path", { d: "M7.5 10V7a4.5 4.5 0 119 0v3" })
|
|
4369
|
+
] });
|
|
4370
|
+
}
|
|
4371
|
+
function ShieldIcon({ className }) {
|
|
4372
|
+
return /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.8", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [
|
|
4373
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)("path", { d: "M12 2.5l8 3v6c0 5-3.5 8.5-8 10-4.5-1.5-8-5-8-10v-6l8-3z" }),
|
|
4374
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)("path", { d: "M9 12l2 2 4-4" })
|
|
4375
|
+
] });
|
|
4376
|
+
}
|
|
4377
|
+
function BellIcon({ className }) {
|
|
4378
|
+
return /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.8", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [
|
|
4379
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)("path", { d: "M6 17V11a6 6 0 1112 0v6l1.5 2H4.5L6 17z" }),
|
|
4380
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)("path", { d: "M10 21a2 2 0 004 0" })
|
|
4381
|
+
] });
|
|
4382
|
+
}
|
|
4383
|
+
function Spinner2() {
|
|
4384
|
+
return /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
|
|
4385
|
+
"span",
|
|
4623
4386
|
{
|
|
4624
|
-
className:
|
|
4625
|
-
style: {
|
|
4626
|
-
children: [
|
|
4627
|
-
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
|
|
4628
|
-
"img",
|
|
4629
|
-
{
|
|
4630
|
-
src,
|
|
4631
|
-
alt,
|
|
4632
|
-
className: ["absolute inset-0 w-full h-full object-cover", imgClassName].filter(Boolean).join(" ")
|
|
4633
|
-
}
|
|
4634
|
-
),
|
|
4635
|
-
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)("div", { className: gradientClassName ?? DEFAULT_GRADIENT, "aria-hidden": "true" }),
|
|
4636
|
-
headline ? /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
|
|
4637
|
-
"h1",
|
|
4638
|
-
{
|
|
4639
|
-
className: ["absolute bottom-0 left-0 right-0 p-4 text-white font-bold text-2xl", headlineClassName].filter(Boolean).join(" "),
|
|
4640
|
-
children: headline
|
|
4641
|
-
}
|
|
4642
|
-
) : null
|
|
4643
|
-
]
|
|
4387
|
+
className: "w-4 h-4 rounded-full border-2 border-white/40 border-t-white",
|
|
4388
|
+
style: { animation: "spin 0.7s linear infinite" }
|
|
4644
4389
|
}
|
|
4645
4390
|
);
|
|
4646
4391
|
}
|
|
4647
4392
|
|
|
4648
|
-
// src/
|
|
4649
|
-
var
|
|
4650
|
-
var
|
|
4651
|
-
|
|
4652
|
-
|
|
4653
|
-
|
|
4393
|
+
// src/defaults/PixWaitingPageDefault.tsx
|
|
4394
|
+
var import_react24 = require("react");
|
|
4395
|
+
var import_react_router_dom4 = require("react-router-dom");
|
|
4396
|
+
var import_sdk16 = require("@hook-sdk/sdk");
|
|
4397
|
+
var import_jsx_runtime49 = require("react/jsx-runtime");
|
|
4398
|
+
var PIX_PAYLOAD_KEY2 = "hook:paywall:pix-pending";
|
|
4399
|
+
var TIMEOUT_MS = 30 * 60 * 1e3;
|
|
4400
|
+
function readPixPayload() {
|
|
4401
|
+
if (typeof window === "undefined") return null;
|
|
4402
|
+
try {
|
|
4403
|
+
const raw = sessionStorage.getItem(PIX_PAYLOAD_KEY2);
|
|
4404
|
+
if (!raw) return null;
|
|
4405
|
+
return JSON.parse(raw);
|
|
4406
|
+
} catch {
|
|
4407
|
+
return null;
|
|
4408
|
+
}
|
|
4654
4409
|
}
|
|
4655
|
-
|
|
4656
|
-
|
|
4657
|
-
|
|
4658
|
-
|
|
4659
|
-
|
|
4660
|
-
MONTHLY: "mensal",
|
|
4661
|
-
YEARLY: "anual"
|
|
4662
|
-
};
|
|
4663
|
-
function PaywallPriceHeadline({
|
|
4664
|
-
template,
|
|
4665
|
-
className,
|
|
4666
|
-
as = "h1",
|
|
4667
|
-
render
|
|
4668
|
-
}) {
|
|
4669
|
-
const { cycle, currentMonthlyEquivCents, plan } = usePaywallContext();
|
|
4670
|
-
const yearlyCents = plan?.yearlyCents ?? null;
|
|
4671
|
-
const pricePerDay = formatBRL(dailyFromYearly(yearlyCents));
|
|
4672
|
-
const monthlyEquiv = currentMonthlyEquivCents ?? 0;
|
|
4673
|
-
const cycleLabel = CYCLE_LABEL[cycle] ?? cycle.toLowerCase();
|
|
4674
|
-
const rootClasses = [DEFAULT_CLASS, className].filter(Boolean).join(" ");
|
|
4675
|
-
if (render) {
|
|
4676
|
-
const RootTag2 = as;
|
|
4677
|
-
return /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(RootTag2, { className: [className].filter(Boolean).join(" ") || void 0, children: render({ pricePerDay, currentMonthlyEquivCents: monthlyEquiv, cycle }) });
|
|
4410
|
+
function clearPixPayload() {
|
|
4411
|
+
if (typeof window === "undefined") return;
|
|
4412
|
+
try {
|
|
4413
|
+
sessionStorage.removeItem(PIX_PAYLOAD_KEY2);
|
|
4414
|
+
} catch {
|
|
4678
4415
|
}
|
|
4679
|
-
const text = template.replaceAll("{pricePerDay}", pricePerDay).replaceAll("{currentMonthlyEquiv}", formatBRL(monthlyEquiv)).replaceAll("{cycle}", cycleLabel);
|
|
4680
|
-
const RootTag = as;
|
|
4681
|
-
return /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(RootTag, { className: rootClasses, children: text });
|
|
4682
4416
|
}
|
|
4683
|
-
|
|
4684
|
-
|
|
4685
|
-
|
|
4686
|
-
|
|
4687
|
-
|
|
4688
|
-
|
|
4689
|
-
|
|
4690
|
-
|
|
4691
|
-
|
|
4692
|
-
|
|
4693
|
-
|
|
4417
|
+
function PixWaitingPageDefault() {
|
|
4418
|
+
const navigate = (0, import_react_router_dom4.useNavigate)();
|
|
4419
|
+
const { subscription } = (0, import_sdk16.useHook)();
|
|
4420
|
+
const payload = (0, import_react24.useMemo)(readPixPayload, []);
|
|
4421
|
+
const [copied, setCopied] = (0, import_react24.useState)(false);
|
|
4422
|
+
const [timedOut, setTimedOut] = (0, import_react24.useState)(false);
|
|
4423
|
+
(0, import_react24.useEffect)(() => {
|
|
4424
|
+
if (!payload) navigate("/paywall/checkout", { replace: true });
|
|
4425
|
+
}, [payload, navigate]);
|
|
4426
|
+
(0, import_react24.useEffect)(() => {
|
|
4427
|
+
window.scrollTo(0, 0);
|
|
4428
|
+
}, []);
|
|
4429
|
+
(0, import_react24.useEffect)(() => {
|
|
4430
|
+
const t = setTimeout(() => setTimedOut(true), TIMEOUT_MS);
|
|
4431
|
+
return () => clearTimeout(t);
|
|
4432
|
+
}, []);
|
|
4433
|
+
const hasAccess = subscription.hasAccess;
|
|
4434
|
+
(0, import_react24.useEffect)(() => {
|
|
4435
|
+
if (hasAccess) {
|
|
4436
|
+
clearPixPayload();
|
|
4437
|
+
navigate("/", { replace: true });
|
|
4438
|
+
}
|
|
4439
|
+
}, [hasAccess, navigate]);
|
|
4440
|
+
async function copyPayload() {
|
|
4441
|
+
if (!payload?.payload) return;
|
|
4442
|
+
try {
|
|
4443
|
+
await navigator.clipboard.writeText(payload.payload);
|
|
4444
|
+
setCopied(true);
|
|
4445
|
+
setTimeout(() => setCopied(false), 2e3);
|
|
4446
|
+
} catch {
|
|
4447
|
+
}
|
|
4694
4448
|
}
|
|
4695
|
-
|
|
4696
|
-
|
|
4697
|
-
|
|
4698
|
-
|
|
4699
|
-
|
|
4700
|
-
|
|
4701
|
-
|
|
4449
|
+
if (!payload) return null;
|
|
4450
|
+
if (timedOut) {
|
|
4451
|
+
return /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("div", { className: "flex-1 flex flex-col items-center justify-center px-6 py-10 text-center bg-background space-y-4", children: [
|
|
4452
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)("h1", { className: "font-display text-2xl text-foreground", children: "PIX expirado" }),
|
|
4453
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)("p", { className: "text-sm text-muted-foreground", children: "O tempo pra pagar acabou. Gere um novo PIX." }),
|
|
4454
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
|
|
4455
|
+
"button",
|
|
4456
|
+
{
|
|
4457
|
+
onClick: () => {
|
|
4458
|
+
clearPixPayload();
|
|
4459
|
+
navigate("/paywall/checkout", { replace: true });
|
|
4460
|
+
},
|
|
4461
|
+
className: "rounded-xl bg-primary px-6 py-3 text-base font-semibold text-primary-foreground",
|
|
4462
|
+
children: "Tentar novamente"
|
|
4463
|
+
}
|
|
4464
|
+
)
|
|
4465
|
+
] });
|
|
4702
4466
|
}
|
|
4703
|
-
return
|
|
4467
|
+
return /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("div", { className: "flex-1 flex flex-col items-center px-6 py-8 bg-background space-y-6", children: [
|
|
4468
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("header", { className: "text-center space-y-2", children: [
|
|
4469
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)("h1", { className: "font-display text-2xl text-foreground", children: "Pague o PIX" }),
|
|
4470
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)("p", { className: "text-sm text-muted-foreground", children: "Escaneie o QR Code no app do seu banco. O acesso libera assim que confirmarmos o pagamento." })
|
|
4471
|
+
] }),
|
|
4472
|
+
payload.base64 ? /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
|
|
4473
|
+
"img",
|
|
4474
|
+
{
|
|
4475
|
+
src: `data:image/png;base64,${payload.base64}`,
|
|
4476
|
+
alt: "QR Code PIX",
|
|
4477
|
+
className: "w-64 h-64 rounded-2xl border border-border bg-card p-2"
|
|
4478
|
+
}
|
|
4479
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("div", { className: "w-64 h-64 rounded-2xl border border-border bg-card flex items-center justify-center text-sm text-muted-foreground", children: "QR indispon\xEDvel" }),
|
|
4480
|
+
payload.payload ? /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
|
|
4481
|
+
"button",
|
|
4482
|
+
{
|
|
4483
|
+
onClick: copyPayload,
|
|
4484
|
+
className: "w-full max-w-xs rounded-xl border border-border bg-card px-4 py-3 text-sm font-medium text-foreground",
|
|
4485
|
+
children: copied ? "\u2713 Copiado!" : "Copiar c\xF3digo PIX"
|
|
4486
|
+
}
|
|
4487
|
+
) : null,
|
|
4488
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("div", { className: "flex items-center gap-2 text-sm text-muted-foreground", children: [
|
|
4489
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)("span", { className: "inline-block w-2 h-2 rounded-full bg-primary animate-pulse" }),
|
|
4490
|
+
"Aguardando pagamento\u2026"
|
|
4491
|
+
] }),
|
|
4492
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)("p", { className: "text-center text-xs text-muted-foreground", children: "Pode fechar essa janela \u2014 tamb\xE9m enviamos um link de acesso pro seu e-mail." })
|
|
4493
|
+
] });
|
|
4704
4494
|
}
|
|
4705
|
-
|
|
4706
|
-
|
|
4707
|
-
|
|
4708
|
-
|
|
4709
|
-
|
|
4710
|
-
|
|
4711
|
-
|
|
4495
|
+
|
|
4496
|
+
// src/hooks/useLoginForm.ts
|
|
4497
|
+
var import_react25 = require("react");
|
|
4498
|
+
var import_sdk17 = require("@hook-sdk/sdk");
|
|
4499
|
+
var EMAIL_RE2 = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
4500
|
+
var MIN_PASSWORD = 8;
|
|
4501
|
+
function useLoginForm() {
|
|
4502
|
+
const { auth } = (0, import_sdk17.useHook)();
|
|
4503
|
+
const [email, setEmail] = (0, import_react25.useState)("");
|
|
4504
|
+
const [password, setPassword] = (0, import_react25.useState)("");
|
|
4505
|
+
const [submitting, setSubmitting] = (0, import_react25.useState)(false);
|
|
4506
|
+
const [error, setError] = (0, import_react25.useState)(null);
|
|
4507
|
+
const [touchedEmail, setTouchedEmail] = (0, import_react25.useState)(false);
|
|
4508
|
+
const [touchedPassword, setTouchedPassword] = (0, import_react25.useState)(false);
|
|
4509
|
+
const [formSubmitAttempted, setFormSubmitAttempted] = (0, import_react25.useState)(false);
|
|
4510
|
+
const validateEmail = (0, import_react25.useMemo)(() => {
|
|
4511
|
+
if (email.length === 0) return null;
|
|
4512
|
+
if (!EMAIL_RE2.test(email)) return "Formato de e-mail inv\xE1lido.";
|
|
4513
|
+
return null;
|
|
4514
|
+
}, [email]);
|
|
4515
|
+
const validatePassword = (0, import_react25.useMemo)(() => {
|
|
4516
|
+
if (password.length === 0) return null;
|
|
4517
|
+
if (password.length < MIN_PASSWORD) return `M\xEDnimo de ${MIN_PASSWORD} caracteres.`;
|
|
4518
|
+
return null;
|
|
4519
|
+
}, [password]);
|
|
4520
|
+
const emailError = touchedEmail || formSubmitAttempted ? validateEmail : null;
|
|
4521
|
+
const passwordError = touchedPassword || formSubmitAttempted ? validatePassword : null;
|
|
4522
|
+
const canSubmit = email.length > 0 && password.length >= MIN_PASSWORD && validateEmail === null && validatePassword === null && !submitting;
|
|
4523
|
+
const submit = (0, import_react25.useCallback)(async () => {
|
|
4524
|
+
setFormSubmitAttempted(true);
|
|
4525
|
+
if (!canSubmit) return false;
|
|
4526
|
+
setSubmitting(true);
|
|
4527
|
+
setError(null);
|
|
4528
|
+
try {
|
|
4529
|
+
await auth.login({ email, password });
|
|
4530
|
+
return true;
|
|
4531
|
+
} catch (err) {
|
|
4532
|
+
setError(mapSdkError(err));
|
|
4533
|
+
return false;
|
|
4534
|
+
} finally {
|
|
4535
|
+
setSubmitting(false);
|
|
4536
|
+
}
|
|
4537
|
+
}, [auth, email, password, canSubmit]);
|
|
4538
|
+
return {
|
|
4539
|
+
email,
|
|
4540
|
+
setEmail,
|
|
4541
|
+
emailError,
|
|
4542
|
+
markEmailTouched: () => setTouchedEmail(true),
|
|
4543
|
+
password,
|
|
4544
|
+
setPassword,
|
|
4545
|
+
passwordError,
|
|
4546
|
+
markPasswordTouched: () => setTouchedPassword(true),
|
|
4547
|
+
formSubmitAttempted,
|
|
4548
|
+
submit,
|
|
4549
|
+
submitting,
|
|
4550
|
+
canSubmit,
|
|
4551
|
+
error,
|
|
4552
|
+
loginWithGoogle: () => auth.loginWithGoogle()
|
|
4553
|
+
};
|
|
4554
|
+
}
|
|
4555
|
+
|
|
4556
|
+
// src/hooks/useSignupForm.ts
|
|
4557
|
+
var import_react26 = require("react");
|
|
4558
|
+
var import_sdk18 = require("@hook-sdk/sdk");
|
|
4559
|
+
var EMAIL_RE3 = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
4560
|
+
var MIN_PASSWORD2 = 8;
|
|
4561
|
+
function useSignupForm() {
|
|
4562
|
+
const { auth } = (0, import_sdk18.useHook)();
|
|
4563
|
+
const [name, setName] = (0, import_react26.useState)("");
|
|
4564
|
+
const [email, setEmail] = (0, import_react26.useState)("");
|
|
4565
|
+
const [password, setPassword] = (0, import_react26.useState)("");
|
|
4566
|
+
const [submitting, setSubmitting] = (0, import_react26.useState)(false);
|
|
4567
|
+
const [error, setError] = (0, import_react26.useState)(null);
|
|
4568
|
+
const [touchedName, setTouchedName] = (0, import_react26.useState)(false);
|
|
4569
|
+
const [touchedEmail, setTouchedEmail] = (0, import_react26.useState)(false);
|
|
4570
|
+
const [touchedPassword, setTouchedPassword] = (0, import_react26.useState)(false);
|
|
4571
|
+
const [formSubmitAttempted, setFormSubmitAttempted] = (0, import_react26.useState)(false);
|
|
4572
|
+
const validateName = (0, import_react26.useMemo)(() => {
|
|
4573
|
+
if (name.length === 0) return null;
|
|
4574
|
+
if (name.trim().length < 2) return "Nome muito curto.";
|
|
4575
|
+
return null;
|
|
4576
|
+
}, [name]);
|
|
4577
|
+
const validateEmail = (0, import_react26.useMemo)(() => {
|
|
4578
|
+
if (email.length === 0) return null;
|
|
4579
|
+
if (!EMAIL_RE3.test(email)) return "Formato de e-mail inv\xE1lido.";
|
|
4580
|
+
return null;
|
|
4581
|
+
}, [email]);
|
|
4582
|
+
const validatePassword = (0, import_react26.useMemo)(() => {
|
|
4583
|
+
if (password.length === 0) return null;
|
|
4584
|
+
if (password.length < MIN_PASSWORD2) return `M\xEDnimo de ${MIN_PASSWORD2} caracteres.`;
|
|
4585
|
+
return null;
|
|
4586
|
+
}, [password]);
|
|
4587
|
+
const nameError = touchedName || formSubmitAttempted ? validateName : null;
|
|
4588
|
+
const emailError = touchedEmail || formSubmitAttempted ? validateEmail : null;
|
|
4589
|
+
const passwordError = touchedPassword || formSubmitAttempted ? validatePassword : null;
|
|
4590
|
+
const canSubmit = name.trim().length >= 2 && email.length > 0 && password.length >= MIN_PASSWORD2 && validateName === null && validateEmail === null && validatePassword === null && !submitting;
|
|
4591
|
+
const submit = (0, import_react26.useCallback)(async () => {
|
|
4592
|
+
setFormSubmitAttempted(true);
|
|
4593
|
+
if (!canSubmit) return false;
|
|
4594
|
+
setSubmitting(true);
|
|
4595
|
+
setError(null);
|
|
4596
|
+
try {
|
|
4597
|
+
await auth.signup({ name, email, password });
|
|
4598
|
+
return true;
|
|
4599
|
+
} catch (err) {
|
|
4600
|
+
setError(mapSdkError(err));
|
|
4601
|
+
return false;
|
|
4602
|
+
} finally {
|
|
4603
|
+
setSubmitting(false);
|
|
4604
|
+
}
|
|
4605
|
+
}, [auth, name, email, password, canSubmit]);
|
|
4606
|
+
return {
|
|
4607
|
+
name,
|
|
4608
|
+
setName,
|
|
4609
|
+
nameError,
|
|
4610
|
+
markNameTouched: () => setTouchedName(true),
|
|
4611
|
+
email,
|
|
4612
|
+
setEmail,
|
|
4613
|
+
emailError,
|
|
4614
|
+
markEmailTouched: () => setTouchedEmail(true),
|
|
4615
|
+
password,
|
|
4616
|
+
setPassword,
|
|
4617
|
+
passwordError,
|
|
4618
|
+
markPasswordTouched: () => setTouchedPassword(true),
|
|
4619
|
+
formSubmitAttempted,
|
|
4620
|
+
submit,
|
|
4621
|
+
submitting,
|
|
4622
|
+
canSubmit,
|
|
4623
|
+
error,
|
|
4624
|
+
loginWithGoogle: () => auth.loginWithGoogle()
|
|
4625
|
+
};
|
|
4712
4626
|
}
|
|
4713
|
-
|
|
4714
|
-
|
|
4627
|
+
|
|
4628
|
+
// src/hooks/useForgotForm.ts
|
|
4629
|
+
var import_react27 = require("react");
|
|
4630
|
+
var import_sdk19 = require("@hook-sdk/sdk");
|
|
4631
|
+
var EMAIL_RE4 = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
4632
|
+
function useForgotForm() {
|
|
4633
|
+
const { auth } = (0, import_sdk19.useHook)();
|
|
4634
|
+
const [email, setEmail] = (0, import_react27.useState)("");
|
|
4635
|
+
const [submitting, setSubmitting] = (0, import_react27.useState)(false);
|
|
4636
|
+
const [sent, setSent] = (0, import_react27.useState)(false);
|
|
4637
|
+
const [error, setError] = (0, import_react27.useState)(null);
|
|
4638
|
+
const [touchedEmail, setTouchedEmail] = (0, import_react27.useState)(false);
|
|
4639
|
+
const [formSubmitAttempted, setFormSubmitAttempted] = (0, import_react27.useState)(false);
|
|
4640
|
+
const validateEmail = (0, import_react27.useMemo)(() => {
|
|
4641
|
+
if (email.length === 0) return null;
|
|
4642
|
+
if (!EMAIL_RE4.test(email)) return "Formato de e-mail inv\xE1lido.";
|
|
4643
|
+
return null;
|
|
4644
|
+
}, [email]);
|
|
4645
|
+
const emailError = touchedEmail || formSubmitAttempted ? validateEmail : null;
|
|
4646
|
+
const canSubmit = email.length > 0 && validateEmail === null && !submitting;
|
|
4647
|
+
const submit = (0, import_react27.useCallback)(async () => {
|
|
4648
|
+
setFormSubmitAttempted(true);
|
|
4649
|
+
if (!canSubmit) return false;
|
|
4650
|
+
setSubmitting(true);
|
|
4651
|
+
setError(null);
|
|
4652
|
+
try {
|
|
4653
|
+
await auth.forgot({ email });
|
|
4654
|
+
setSent(true);
|
|
4655
|
+
return true;
|
|
4656
|
+
} catch (err) {
|
|
4657
|
+
setError(mapSdkError(err));
|
|
4658
|
+
return false;
|
|
4659
|
+
} finally {
|
|
4660
|
+
setSubmitting(false);
|
|
4661
|
+
}
|
|
4662
|
+
}, [auth, email, canSubmit]);
|
|
4663
|
+
return {
|
|
4664
|
+
email,
|
|
4665
|
+
setEmail,
|
|
4666
|
+
emailError,
|
|
4667
|
+
markEmailTouched: () => setTouchedEmail(true),
|
|
4668
|
+
formSubmitAttempted,
|
|
4669
|
+
submit,
|
|
4670
|
+
submitting,
|
|
4671
|
+
canSubmit,
|
|
4672
|
+
sent,
|
|
4673
|
+
error
|
|
4674
|
+
};
|
|
4715
4675
|
}
|
|
4716
|
-
|
|
4717
|
-
|
|
4718
|
-
|
|
4719
|
-
|
|
4720
|
-
|
|
4721
|
-
|
|
4722
|
-
})
|
|
4723
|
-
const
|
|
4724
|
-
|
|
4725
|
-
|
|
4726
|
-
|
|
4727
|
-
const [
|
|
4728
|
-
const
|
|
4729
|
-
(0,
|
|
4730
|
-
|
|
4731
|
-
|
|
4732
|
-
|
|
4733
|
-
|
|
4676
|
+
|
|
4677
|
+
// src/hooks/useResetForm.ts
|
|
4678
|
+
var import_react28 = require("react");
|
|
4679
|
+
var import_sdk20 = require("@hook-sdk/sdk");
|
|
4680
|
+
var MIN_PASSWORD3 = 8;
|
|
4681
|
+
function useResetForm() {
|
|
4682
|
+
const { auth } = (0, import_sdk20.useHook)();
|
|
4683
|
+
const [token, setToken] = (0, import_react28.useState)(null);
|
|
4684
|
+
const [password, setPassword] = (0, import_react28.useState)("");
|
|
4685
|
+
const [confirm, setConfirm] = (0, import_react28.useState)("");
|
|
4686
|
+
const [submitting, setSubmitting] = (0, import_react28.useState)(false);
|
|
4687
|
+
const [done, setDone] = (0, import_react28.useState)(false);
|
|
4688
|
+
const [error, setError] = (0, import_react28.useState)(null);
|
|
4689
|
+
const [touchedPassword, setTouchedPassword] = (0, import_react28.useState)(false);
|
|
4690
|
+
const [touchedConfirm, setTouchedConfirm] = (0, import_react28.useState)(false);
|
|
4691
|
+
const [formSubmitAttempted, setFormSubmitAttempted] = (0, import_react28.useState)(false);
|
|
4692
|
+
(0, import_react28.useEffect)(() => {
|
|
4693
|
+
if (typeof window === "undefined") return;
|
|
4694
|
+
const params = new URLSearchParams(window.location.search);
|
|
4695
|
+
const t = params.get("token");
|
|
4696
|
+
setToken(t && t.length > 0 ? t : null);
|
|
4697
|
+
}, []);
|
|
4698
|
+
const validatePassword = (0, import_react28.useMemo)(() => {
|
|
4699
|
+
if (password.length === 0) return null;
|
|
4700
|
+
if (password.length < MIN_PASSWORD3) return `M\xEDnimo de ${MIN_PASSWORD3} caracteres.`;
|
|
4701
|
+
return null;
|
|
4702
|
+
}, [password]);
|
|
4703
|
+
const validateConfirm = (0, import_react28.useMemo)(() => {
|
|
4704
|
+
if (confirm.length === 0) return null;
|
|
4705
|
+
if (confirm !== password) return "Senhas n\xE3o coincidem.";
|
|
4706
|
+
return null;
|
|
4707
|
+
}, [confirm, password]);
|
|
4708
|
+
const passwordError = touchedPassword || formSubmitAttempted ? validatePassword : null;
|
|
4709
|
+
const confirmError = touchedConfirm || formSubmitAttempted ? validateConfirm : null;
|
|
4710
|
+
const canSubmit = token !== null && password.length >= MIN_PASSWORD3 && confirm === password && validatePassword === null && validateConfirm === null && !submitting && !done;
|
|
4711
|
+
const submit = (0, import_react28.useCallback)(async () => {
|
|
4712
|
+
setFormSubmitAttempted(true);
|
|
4713
|
+
if (!canSubmit || token === null) return;
|
|
4714
|
+
setSubmitting(true);
|
|
4715
|
+
setError(null);
|
|
4716
|
+
try {
|
|
4717
|
+
await auth.reset({ token, newPassword: password });
|
|
4718
|
+
setDone(true);
|
|
4719
|
+
if (typeof window !== "undefined") {
|
|
4720
|
+
const url = new URL(window.location.href);
|
|
4721
|
+
url.searchParams.delete("token");
|
|
4722
|
+
url.searchParams.delete("screen");
|
|
4723
|
+
window.history.replaceState({}, "", url.toString());
|
|
4734
4724
|
}
|
|
4735
|
-
|
|
4725
|
+
} catch (err) {
|
|
4726
|
+
setError(mapSdkError(err));
|
|
4727
|
+
} finally {
|
|
4728
|
+
setSubmitting(false);
|
|
4736
4729
|
}
|
|
4737
|
-
|
|
4738
|
-
|
|
4739
|
-
|
|
4740
|
-
|
|
4741
|
-
|
|
4742
|
-
|
|
4743
|
-
|
|
4744
|
-
|
|
4745
|
-
|
|
4746
|
-
|
|
4747
|
-
|
|
4748
|
-
|
|
4749
|
-
|
|
4750
|
-
|
|
4751
|
-
|
|
4752
|
-
|
|
4730
|
+
}, [auth, token, password, canSubmit]);
|
|
4731
|
+
return {
|
|
4732
|
+
token,
|
|
4733
|
+
password,
|
|
4734
|
+
setPassword,
|
|
4735
|
+
passwordError,
|
|
4736
|
+
markPasswordTouched: () => setTouchedPassword(true),
|
|
4737
|
+
confirm,
|
|
4738
|
+
setConfirm,
|
|
4739
|
+
confirmError,
|
|
4740
|
+
markConfirmTouched: () => setTouchedConfirm(true),
|
|
4741
|
+
formSubmitAttempted,
|
|
4742
|
+
submit,
|
|
4743
|
+
submitting,
|
|
4744
|
+
canSubmit,
|
|
4745
|
+
done,
|
|
4746
|
+
error
|
|
4747
|
+
};
|
|
4753
4748
|
}
|
|
4754
4749
|
|
|
4755
|
-
// src/
|
|
4756
|
-
var
|
|
4757
|
-
|
|
4758
|
-
|
|
4759
|
-
|
|
4760
|
-
|
|
4761
|
-
|
|
4762
|
-
|
|
4763
|
-
|
|
4764
|
-
|
|
4765
|
-
|
|
4766
|
-
|
|
4767
|
-
|
|
4768
|
-
}
|
|
4769
|
-
|
|
4770
|
-
|
|
4771
|
-
|
|
4772
|
-
|
|
4773
|
-
|
|
4774
|
-
|
|
4775
|
-
|
|
4750
|
+
// src/hooks/useAuthPrimitives.ts
|
|
4751
|
+
var import_react29 = require("react");
|
|
4752
|
+
var import_sdk21 = require("@hook-sdk/sdk");
|
|
4753
|
+
var warned = false;
|
|
4754
|
+
function useAuthPrimitives() {
|
|
4755
|
+
const { auth } = (0, import_sdk21.useHook)();
|
|
4756
|
+
(0, import_react29.useEffect)(() => {
|
|
4757
|
+
if (!warned && process.env.NODE_ENV !== "production") {
|
|
4758
|
+
warned = true;
|
|
4759
|
+
console.warn(
|
|
4760
|
+
"[@hook-sdk/template] useAuthPrimitives() \xE9 escape hatch. Pra login/signup/forgot, use useLoginForm/useSignupForm/useForgotForm. Docs: docs/19-golden-template.md#escape-hatch"
|
|
4761
|
+
);
|
|
4762
|
+
}
|
|
4763
|
+
}, []);
|
|
4764
|
+
return {
|
|
4765
|
+
login: auth.login,
|
|
4766
|
+
signup: auth.signup,
|
|
4767
|
+
logout: auth.logout,
|
|
4768
|
+
logoutAll: auth.logoutAll,
|
|
4769
|
+
forgot: auth.forgot,
|
|
4770
|
+
resendVerify: auth.resendVerify,
|
|
4771
|
+
changePassword: auth.changePassword,
|
|
4772
|
+
changeEmail: auth.changeEmail,
|
|
4773
|
+
refresh: auth.refresh
|
|
4774
|
+
};
|
|
4776
4775
|
}
|
|
4777
4776
|
|
|
4778
|
-
// src/
|
|
4779
|
-
var
|
|
4780
|
-
|
|
4781
|
-
|
|
4782
|
-
|
|
4783
|
-
|
|
4784
|
-
|
|
4785
|
-
|
|
4786
|
-
|
|
4787
|
-
itemClassName,
|
|
4788
|
-
renderItem
|
|
4789
|
-
}) {
|
|
4790
|
-
return /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("div", { className, children: /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: [DEFAULT_CARD_CLASSES, cardClassName].filter(Boolean).join(" "), children: [
|
|
4791
|
-
title ? /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("div", { className: ["font-semibold mb-2", titleClassName].filter(Boolean).join(" "), children: title }) : null,
|
|
4792
|
-
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("ul", { children: items.map(
|
|
4793
|
-
(item, idx) => renderItem ? /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("li", { children: renderItem(item, idx) }, idx) : /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("li", { className: itemClassName, children: [
|
|
4794
|
-
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("span", { "aria-hidden": "true", children: "\u2022" }),
|
|
4795
|
-
" ",
|
|
4796
|
-
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("span", { children: item })
|
|
4797
|
-
] }, idx)
|
|
4798
|
-
) })
|
|
4799
|
-
] }) });
|
|
4777
|
+
// src/hooks/useAuth.ts
|
|
4778
|
+
var import_sdk22 = require("@hook-sdk/sdk");
|
|
4779
|
+
function useAuth() {
|
|
4780
|
+
const { user, authStatus, auth } = (0, import_sdk22.useHook)();
|
|
4781
|
+
return {
|
|
4782
|
+
user,
|
|
4783
|
+
authStatus,
|
|
4784
|
+
refresh: auth.refresh
|
|
4785
|
+
};
|
|
4800
4786
|
}
|
|
4801
4787
|
|
|
4802
|
-
// src/
|
|
4803
|
-
var
|
|
4804
|
-
|
|
4805
|
-
|
|
4806
|
-
|
|
4807
|
-
|
|
4808
|
-
|
|
4809
|
-
|
|
4810
|
-
|
|
4811
|
-
|
|
4812
|
-
}) {
|
|
4813
|
-
if (render) {
|
|
4814
|
-
return /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("div", { className, children: render({ text }) });
|
|
4815
|
-
}
|
|
4816
|
-
const rootClasses = [
|
|
4817
|
-
DEFAULT_CHIP_CLASSES,
|
|
4818
|
-
floating ? FLOATING_CLASSES : "",
|
|
4819
|
-
className
|
|
4820
|
-
].filter(Boolean).join(" ");
|
|
4821
|
-
return /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: rootClasses, children: [
|
|
4822
|
-
/* @__PURE__ */ (0, import_jsx_runtime46.jsx)("span", { className: iconClassName, "aria-hidden": "true", children: "\u{1F3C6}" }),
|
|
4823
|
-
/* @__PURE__ */ (0, import_jsx_runtime46.jsx)("span", { children: text })
|
|
4824
|
-
] });
|
|
4788
|
+
// src/index.ts
|
|
4789
|
+
var import_sdk26 = require("@hook-sdk/sdk");
|
|
4790
|
+
|
|
4791
|
+
// src/hooks/useSubscription.ts
|
|
4792
|
+
var import_sdk23 = require("@hook-sdk/sdk");
|
|
4793
|
+
function useSubscription() {
|
|
4794
|
+
const { subscription } = (0, import_sdk23.useHook)();
|
|
4795
|
+
return {
|
|
4796
|
+
status: subscription.status()
|
|
4797
|
+
};
|
|
4825
4798
|
}
|
|
4826
4799
|
|
|
4827
|
-
// src/
|
|
4828
|
-
var
|
|
4829
|
-
var
|
|
4830
|
-
function
|
|
4831
|
-
|
|
4832
|
-
|
|
4833
|
-
|
|
4834
|
-
const
|
|
4835
|
-
|
|
4836
|
-
|
|
4837
|
-
|
|
4838
|
-
|
|
4839
|
-
|
|
4840
|
-
|
|
4841
|
-
|
|
4842
|
-
|
|
4843
|
-
}
|
|
4844
|
-
|
|
4800
|
+
// src/hooks/useReminders.ts
|
|
4801
|
+
var import_react30 = require("react");
|
|
4802
|
+
var import_sdk24 = require("@hook-sdk/sdk");
|
|
4803
|
+
function useReminders() {
|
|
4804
|
+
const { push } = (0, import_sdk24.useHook)();
|
|
4805
|
+
const r = push.reminders;
|
|
4806
|
+
const [reminders, setReminders] = (0, import_react30.useState)([]);
|
|
4807
|
+
const [loading, setLoading] = (0, import_react30.useState)(true);
|
|
4808
|
+
const reload = (0, import_react30.useCallback)(async () => {
|
|
4809
|
+
setLoading(true);
|
|
4810
|
+
try {
|
|
4811
|
+
const next = await r.list();
|
|
4812
|
+
setReminders(next);
|
|
4813
|
+
} finally {
|
|
4814
|
+
setLoading(false);
|
|
4815
|
+
}
|
|
4816
|
+
}, [r]);
|
|
4817
|
+
(0, import_react30.useEffect)(() => {
|
|
4818
|
+
void reload();
|
|
4819
|
+
}, [reload]);
|
|
4820
|
+
const setReminder = (0, import_react30.useCallback)(async (input) => {
|
|
4821
|
+
await r.set(input);
|
|
4822
|
+
await reload();
|
|
4823
|
+
}, [r, reload]);
|
|
4824
|
+
const deleteReminder = (0, import_react30.useCallback)(async (slot) => {
|
|
4825
|
+
await r.delete(slot);
|
|
4826
|
+
await reload();
|
|
4827
|
+
}, [r, reload]);
|
|
4828
|
+
const schedule = (0, import_react30.useCallback)(async (items) => {
|
|
4829
|
+
return r.schedule(items);
|
|
4830
|
+
}, [r]);
|
|
4831
|
+
const setFallbacks = (0, import_react30.useCallback)(async (items) => {
|
|
4832
|
+
return r.setFallbacks(items);
|
|
4833
|
+
}, [r]);
|
|
4834
|
+
return { reminders, loading, setReminder, deleteReminder, schedule, setFallbacks };
|
|
4845
4835
|
}
|
|
4846
4836
|
|
|
4847
|
-
// src/
|
|
4848
|
-
var
|
|
4849
|
-
|
|
4850
|
-
|
|
4851
|
-
|
|
4852
|
-
|
|
4853
|
-
|
|
4854
|
-
|
|
4855
|
-
|
|
4856
|
-
|
|
4857
|
-
}
|
|
4858
|
-
|
|
4859
|
-
|
|
4860
|
-
|
|
4861
|
-
|
|
4862
|
-
avatarClassName,
|
|
4863
|
-
quoteClassName,
|
|
4864
|
-
nameClassName,
|
|
4865
|
-
starsClassName,
|
|
4866
|
-
renderItem
|
|
4867
|
-
}) {
|
|
4868
|
-
const rootClasses = [DEFAULT_ROOT, className].filter(Boolean).join(" ");
|
|
4869
|
-
const cardClasses = [DEFAULT_CARD, cardClassName].filter(Boolean).join(" ");
|
|
4870
|
-
const avatarClasses = [DEFAULT_AVATAR, avatarClassName].filter(Boolean).join(" ");
|
|
4871
|
-
const quoteClasses = [DEFAULT_QUOTE, quoteClassName].filter(Boolean).join(" ");
|
|
4872
|
-
const nameClasses = [DEFAULT_NAME, nameClassName].filter(Boolean).join(" ");
|
|
4873
|
-
const starsClasses = [DEFAULT_STARS, starsClassName].filter(Boolean).join(" ");
|
|
4874
|
-
return /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("div", { className: rootClasses, children: items.map((item, idx) => {
|
|
4875
|
-
if (renderItem) return renderItem(item, idx);
|
|
4876
|
-
const filled = clampStars(item.stars);
|
|
4877
|
-
const empty = 5 - filled;
|
|
4878
|
-
return /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: cardClasses, children: [
|
|
4879
|
-
/* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
4880
|
-
item.avatar ? /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
|
|
4881
|
-
"img",
|
|
4882
|
-
{
|
|
4883
|
-
src: item.avatar,
|
|
4884
|
-
alt: "",
|
|
4885
|
-
loading: "lazy",
|
|
4886
|
-
className: avatarClasses,
|
|
4887
|
-
"aria-hidden": "true"
|
|
4888
|
-
}
|
|
4889
|
-
) : null,
|
|
4890
|
-
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)("div", { className: nameClasses, children: item.name })
|
|
4891
|
-
] }),
|
|
4892
|
-
/* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: starsClasses, "aria-label": `${filled} de 5 estrelas`, children: [
|
|
4893
|
-
"\u2605".repeat(filled),
|
|
4894
|
-
"\u2606".repeat(empty)
|
|
4895
|
-
] }),
|
|
4896
|
-
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)("p", { className: quoteClasses, children: item.quote })
|
|
4897
|
-
] }, idx);
|
|
4898
|
-
}) });
|
|
4837
|
+
// src/hooks/useToast.ts
|
|
4838
|
+
var import_react31 = require("react");
|
|
4839
|
+
function useToast() {
|
|
4840
|
+
const [items, setItems] = (0, import_react31.useState)([]);
|
|
4841
|
+
const show = (0, import_react31.useCallback)((message, kind = "info") => {
|
|
4842
|
+
const id = `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
4843
|
+
setItems((prev) => [...prev, { id, message, kind }]);
|
|
4844
|
+
setTimeout(() => {
|
|
4845
|
+
setItems((prev) => prev.filter((t) => t.id !== id));
|
|
4846
|
+
}, 4e3);
|
|
4847
|
+
}, []);
|
|
4848
|
+
const dismiss = (0, import_react31.useCallback)((id) => {
|
|
4849
|
+
setItems((prev) => prev.filter((t) => t.id !== id));
|
|
4850
|
+
}, []);
|
|
4851
|
+
return { items, show, dismiss };
|
|
4899
4852
|
}
|
|
4900
4853
|
|
|
4901
|
-
// src/
|
|
4902
|
-
var
|
|
4903
|
-
var
|
|
4904
|
-
|
|
4905
|
-
|
|
4906
|
-
|
|
4907
|
-
|
|
4908
|
-
|
|
4909
|
-
|
|
4910
|
-
|
|
4911
|
-
|
|
4912
|
-
labelClassName,
|
|
4913
|
-
renderCell
|
|
4914
|
-
}) {
|
|
4915
|
-
const rootClasses = [DEFAULT_ROOT2, className].filter(Boolean).join(" ");
|
|
4916
|
-
const cellClasses = [DEFAULT_CELL, cellClassName].filter(Boolean).join(" ");
|
|
4917
|
-
const valueClasses = [DEFAULT_VALUE, valueClassName].filter(Boolean).join(" ");
|
|
4918
|
-
const labelClasses = [DEFAULT_LABEL, labelClassName].filter(Boolean).join(" ");
|
|
4919
|
-
return /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("div", { className: rootClasses, children: stats.map((stat, idx) => {
|
|
4920
|
-
if (renderCell) return renderCell(stat, idx);
|
|
4921
|
-
return /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("div", { className: cellClasses, children: [
|
|
4922
|
-
stat.icon ? /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("div", { "aria-hidden": "true", children: stat.icon }) : null,
|
|
4923
|
-
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)("div", { className: valueClasses, children: stat.value }),
|
|
4924
|
-
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)("div", { className: labelClasses, children: stat.label })
|
|
4925
|
-
] }, idx);
|
|
4926
|
-
}) });
|
|
4854
|
+
// src/RouteBoundary.tsx
|
|
4855
|
+
var import_react_router_dom5 = require("react-router-dom");
|
|
4856
|
+
var import_jsx_runtime50 = require("react/jsx-runtime");
|
|
4857
|
+
function RouteBoundary({ children }) {
|
|
4858
|
+
return /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)(import_react_router_dom5.Routes, { children: [
|
|
4859
|
+
children,
|
|
4860
|
+
/* @__PURE__ */ (0, import_jsx_runtime50.jsx)(import_react_router_dom5.Route, { path: "*", element: /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(DefaultNotFound, {}) })
|
|
4861
|
+
] });
|
|
4862
|
+
}
|
|
4863
|
+
function DefaultNotFound() {
|
|
4864
|
+
return /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("div", { role: "alert", children: "P\xE1gina n\xE3o encontrada" });
|
|
4927
4865
|
}
|
|
4928
4866
|
|
|
4929
|
-
// src/
|
|
4930
|
-
var
|
|
4931
|
-
var
|
|
4932
|
-
|
|
4933
|
-
|
|
4934
|
-
|
|
4935
|
-
|
|
4936
|
-
|
|
4937
|
-
template,
|
|
4938
|
-
className,
|
|
4939
|
-
render
|
|
4867
|
+
// src/PreAuthShell.tsx
|
|
4868
|
+
var import_react_router_dom6 = require("react-router-dom");
|
|
4869
|
+
var import_jsx_runtime51 = require("react/jsx-runtime");
|
|
4870
|
+
function PreAuthShell({
|
|
4871
|
+
basename,
|
|
4872
|
+
testRouter,
|
|
4873
|
+
testInitialEntries,
|
|
4874
|
+
children
|
|
4940
4875
|
}) {
|
|
4941
|
-
|
|
4942
|
-
|
|
4943
|
-
cycle,
|
|
4944
|
-
trialDaysCard,
|
|
4945
|
-
trialDaysPix,
|
|
4946
|
-
selectedMethod
|
|
4947
|
-
} = usePaywallContext();
|
|
4948
|
-
const trialDays = selectedMethod === "card" ? trialDaysCard : trialDaysPix;
|
|
4949
|
-
const cycleLabel = CYCLE_LABEL2[cycle] ?? cycle.toLowerCase();
|
|
4950
|
-
const priceFormatted = formatBRL(currentPriceCents ?? 0);
|
|
4951
|
-
const rootClasses = [DEFAULT_CLASS3, className].filter(Boolean).join(" ");
|
|
4952
|
-
if (render) {
|
|
4953
|
-
return /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("p", { className: className || void 0, children: render({
|
|
4954
|
-
currentPriceCents: currentPriceCents ?? 0,
|
|
4955
|
-
cycle,
|
|
4956
|
-
trialDays: trialDays ?? 0,
|
|
4957
|
-
selectedMethod
|
|
4958
|
-
}) });
|
|
4876
|
+
if (testRouter === "memory") {
|
|
4877
|
+
return /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(import_react_router_dom6.MemoryRouter, { basename, initialEntries: testInitialEntries, children: /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(import_react_router_dom6.Routes, { children }) });
|
|
4959
4878
|
}
|
|
4960
|
-
|
|
4961
|
-
return /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("p", { className: rootClasses, children: text });
|
|
4879
|
+
return /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(import_react_router_dom6.BrowserRouter, { basename, children: /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(import_react_router_dom6.Routes, { children }) });
|
|
4962
4880
|
}
|
|
4963
4881
|
|
|
4964
|
-
// src/
|
|
4965
|
-
var
|
|
4966
|
-
var
|
|
4967
|
-
|
|
4968
|
-
|
|
4969
|
-
|
|
4970
|
-
|
|
4971
|
-
|
|
4972
|
-
|
|
4973
|
-
|
|
4974
|
-
|
|
4975
|
-
|
|
4976
|
-
|
|
4977
|
-
|
|
4978
|
-
|
|
4979
|
-
/* @__PURE__ */ (0, import_jsx_runtime51.jsx)("span", { "aria-hidden": "true", children: item.icon }),
|
|
4980
|
-
/* @__PURE__ */ (0, import_jsx_runtime51.jsx)("span", { children: item.text })
|
|
4981
|
-
] }, idx);
|
|
4982
|
-
}) });
|
|
4882
|
+
// src/OnboardingFlow.tsx
|
|
4883
|
+
var import_react33 = require("react");
|
|
4884
|
+
var import_sdk25 = require("@hook-sdk/sdk");
|
|
4885
|
+
|
|
4886
|
+
// src/hooks/useOnboardingStep.ts
|
|
4887
|
+
var import_react32 = require("react");
|
|
4888
|
+
var OnboardingStepContext = (0, import_react32.createContext)(null);
|
|
4889
|
+
function useOnboardingStep() {
|
|
4890
|
+
const ctx = (0, import_react32.useContext)(OnboardingStepContext);
|
|
4891
|
+
if (!ctx) {
|
|
4892
|
+
throw new Error(
|
|
4893
|
+
"[hook-template] useOnboardingStep must be used inside <OnboardingFlow>. (G75)"
|
|
4894
|
+
);
|
|
4895
|
+
}
|
|
4896
|
+
return ctx;
|
|
4983
4897
|
}
|
|
4984
4898
|
|
|
4985
|
-
// src/
|
|
4899
|
+
// src/OnboardingFlow.tsx
|
|
4986
4900
|
var import_jsx_runtime52 = require("react/jsx-runtime");
|
|
4987
|
-
var
|
|
4988
|
-
var
|
|
4989
|
-
function
|
|
4990
|
-
|
|
4991
|
-
|
|
4992
|
-
|
|
4901
|
+
var isFilled = (v) => v != null && v !== "";
|
|
4902
|
+
var CURRENT_STEP_FIELD = "currentStep";
|
|
4903
|
+
function readPersistedStepIdx(draft) {
|
|
4904
|
+
const raw = draft[CURRENT_STEP_FIELD];
|
|
4905
|
+
return typeof raw === "number" && Number.isFinite(raw) && raw >= 0 ? raw : 0;
|
|
4906
|
+
}
|
|
4907
|
+
function OnboardingFlow({
|
|
4908
|
+
steps,
|
|
4909
|
+
screens,
|
|
4910
|
+
onComplete,
|
|
4911
|
+
persistKey
|
|
4993
4912
|
}) {
|
|
4994
|
-
const
|
|
4995
|
-
|
|
4913
|
+
const [draft, setDraft, status] = (0, import_sdk25.usePersistedState)(persistKey, {});
|
|
4914
|
+
const draftRef = (0, import_react33.useRef)(draft);
|
|
4915
|
+
draftRef.current = draft;
|
|
4916
|
+
const idx = readPersistedStepIdx(draft);
|
|
4917
|
+
const clampedIdx = Math.min(Math.max(idx, 0), Math.max(steps.length - 1, 0));
|
|
4918
|
+
const setIdx = (0, import_react33.useCallback)(
|
|
4919
|
+
(n) => {
|
|
4920
|
+
setDraft((prev) => {
|
|
4921
|
+
const prevIdx = readPersistedStepIdx(prev);
|
|
4922
|
+
const nextIdx = typeof n === "function" ? n(prevIdx) : n;
|
|
4923
|
+
return { ...prev, [CURRENT_STEP_FIELD]: nextIdx };
|
|
4924
|
+
});
|
|
4925
|
+
},
|
|
4926
|
+
[setDraft]
|
|
4927
|
+
);
|
|
4928
|
+
const setValue = (0, import_react33.useCallback)(
|
|
4929
|
+
(patch) => {
|
|
4930
|
+
draftRef.current = { ...draftRef.current, ...patch };
|
|
4931
|
+
setDraft((prev) => ({ ...prev, ...patch }));
|
|
4932
|
+
},
|
|
4933
|
+
[setDraft]
|
|
4934
|
+
);
|
|
4935
|
+
const step = steps[clampedIdx];
|
|
4936
|
+
const hookCtx = (0, import_sdk25.useHook)();
|
|
4937
|
+
const track2 = typeof hookCtx.track === "function" ? hookCtx.track : void 0;
|
|
4938
|
+
(0, import_react33.useEffect)(() => {
|
|
4939
|
+
if (status.loading) return;
|
|
4940
|
+
if (!step) return;
|
|
4941
|
+
if (!track2) return;
|
|
4942
|
+
track2("onboarding_step_viewed", {
|
|
4943
|
+
step: step.id,
|
|
4944
|
+
step_index: clampedIdx,
|
|
4945
|
+
total_steps: steps.length
|
|
4946
|
+
});
|
|
4947
|
+
}, [step?.id, clampedIdx, steps.length, status.loading, track2]);
|
|
4948
|
+
const valid = (0, import_react33.useMemo)(
|
|
4949
|
+
() => step ? (step.validates ?? []).every((field) => isFilled(draft[field])) : false,
|
|
4950
|
+
[draft, step]
|
|
4951
|
+
);
|
|
4952
|
+
const next = (0, import_react33.useCallback)(() => {
|
|
4953
|
+
if (!step) return;
|
|
4954
|
+
const current = draftRef.current;
|
|
4955
|
+
const validNow = (step.validates ?? []).every((field) => isFilled(current[field]));
|
|
4956
|
+
if (!validNow) return;
|
|
4957
|
+
if (clampedIdx + 1 >= steps.length) {
|
|
4958
|
+
onComplete(current);
|
|
4959
|
+
} else {
|
|
4960
|
+
setIdx(clampedIdx + 1);
|
|
4961
|
+
}
|
|
4962
|
+
}, [clampedIdx, onComplete, step, steps.length, setIdx]);
|
|
4963
|
+
const prevStep = (0, import_react33.useCallback)(() => setIdx((i) => Math.max(0, i - 1)), [setIdx]);
|
|
4964
|
+
const ctx = (0, import_react33.useMemo)(
|
|
4965
|
+
() => ({
|
|
4966
|
+
stepIndex: clampedIdx,
|
|
4967
|
+
totalSteps: steps.length,
|
|
4968
|
+
value: draft,
|
|
4969
|
+
setValue,
|
|
4970
|
+
valid,
|
|
4971
|
+
next,
|
|
4972
|
+
prev: prevStep
|
|
4973
|
+
}),
|
|
4974
|
+
[clampedIdx, steps.length, draft, setValue, valid, next, prevStep]
|
|
4975
|
+
);
|
|
4976
|
+
if (status.loading) {
|
|
4977
|
+
return null;
|
|
4978
|
+
}
|
|
4979
|
+
if (!step) {
|
|
4980
|
+
throw new Error(
|
|
4981
|
+
`[hook-template] OnboardingFlow: step index ${clampedIdx} out of range (steps.length=${steps.length})`
|
|
4982
|
+
);
|
|
4983
|
+
}
|
|
4984
|
+
const Screen = screens[step.screen];
|
|
4985
|
+
if (!Screen) {
|
|
4986
|
+
throw new Error(
|
|
4987
|
+
`[hook-template] OnboardingFlow: missing screen component for step '${step.id}' (expected key '${step.screen}' in screens prop)`
|
|
4988
|
+
);
|
|
4989
|
+
}
|
|
4990
|
+
return /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(OnboardingStepContext.Provider, { value: ctx, children: /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(Screen, {}) });
|
|
4991
|
+
}
|
|
4992
|
+
|
|
4993
|
+
// src/hooks/useFeature.ts
|
|
4994
|
+
function useFeature(name) {
|
|
4995
|
+
const config = useAppConfig();
|
|
4996
|
+
return Array.isArray(config.features_enabled) && config.features_enabled.includes(name);
|
|
4996
4997
|
}
|
|
4997
4998
|
// Annotate the CommonJS export names for ESM import in node:
|
|
4998
4999
|
0 && (module.exports = {
|