@hook-sdk/template 0.28.2 → 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 +1944 -1887
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1912 -1855
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -105,14 +105,14 @@ __export(index_exports, {
|
|
|
105
105
|
useSignupForm: () => useSignupForm,
|
|
106
106
|
useSubscription: () => useSubscription,
|
|
107
107
|
useToast: () => useToast,
|
|
108
|
-
useTrackOnboardingStep: () =>
|
|
108
|
+
useTrackOnboardingStep: () => import_sdk26.useTrackOnboardingStep
|
|
109
109
|
});
|
|
110
110
|
module.exports = __toCommonJS(index_exports);
|
|
111
111
|
|
|
112
112
|
// src/AppRoot.tsx
|
|
113
|
-
var
|
|
113
|
+
var import_react16 = require("react");
|
|
114
114
|
var import_react_router_dom2 = require("react-router-dom");
|
|
115
|
-
var
|
|
115
|
+
var import_sdk9 = require("@hook-sdk/sdk");
|
|
116
116
|
|
|
117
117
|
// src/config/AppConfigContext.tsx
|
|
118
118
|
var import_react = require("react");
|
|
@@ -2144,10 +2144,54 @@ function SessionExpiredBanner() {
|
|
|
2144
2144
|
] });
|
|
2145
2145
|
}
|
|
2146
2146
|
|
|
2147
|
-
// src/
|
|
2147
|
+
// src/internal/EmailVerifyBanner.tsx
|
|
2148
2148
|
var import_react11 = require("react");
|
|
2149
|
+
var import_sdk5 = require("@hook-sdk/sdk");
|
|
2149
2150
|
var import_jsx_runtime18 = require("react/jsx-runtime");
|
|
2150
|
-
|
|
2151
|
+
function EmailVerifyBanner() {
|
|
2152
|
+
const { user, auth } = (0, import_sdk5.useHook)();
|
|
2153
|
+
const [sending, setSending] = (0, import_react11.useState)(false);
|
|
2154
|
+
const [sent, setSent] = (0, import_react11.useState)(false);
|
|
2155
|
+
if (!user || user.emailVerified) return null;
|
|
2156
|
+
async function handleResend() {
|
|
2157
|
+
if (sending || sent) return;
|
|
2158
|
+
setSending(true);
|
|
2159
|
+
try {
|
|
2160
|
+
await auth.resendVerify();
|
|
2161
|
+
setSent(true);
|
|
2162
|
+
} catch {
|
|
2163
|
+
} finally {
|
|
2164
|
+
setSending(false);
|
|
2165
|
+
}
|
|
2166
|
+
}
|
|
2167
|
+
const label = sent ? "Enviado!" : sending ? "Enviando..." : "Reenviar link";
|
|
2168
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
|
|
2169
|
+
"div",
|
|
2170
|
+
{
|
|
2171
|
+
role: "status",
|
|
2172
|
+
"data-testid": "email-verify-banner",
|
|
2173
|
+
className: "sticky top-0 inset-x-0 z-50 bg-yellow-100 text-yellow-900 border-b border-yellow-200 px-4 py-2 flex items-center justify-between gap-3 text-sm",
|
|
2174
|
+
children: [
|
|
2175
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { children: "Confirma teu e-mail pra liberar tudo." }),
|
|
2176
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
2177
|
+
"button",
|
|
2178
|
+
{
|
|
2179
|
+
type: "button",
|
|
2180
|
+
onClick: handleResend,
|
|
2181
|
+
disabled: sending || sent,
|
|
2182
|
+
className: "px-3 py-1 rounded text-xs font-medium bg-yellow-900 text-yellow-50 hover:bg-yellow-800 disabled:opacity-60 disabled:cursor-not-allowed",
|
|
2183
|
+
children: label
|
|
2184
|
+
}
|
|
2185
|
+
)
|
|
2186
|
+
]
|
|
2187
|
+
}
|
|
2188
|
+
);
|
|
2189
|
+
}
|
|
2190
|
+
|
|
2191
|
+
// src/defaults/ErrorBoundary.tsx
|
|
2192
|
+
var import_react12 = require("react");
|
|
2193
|
+
var import_jsx_runtime19 = require("react/jsx-runtime");
|
|
2194
|
+
var ErrorBoundary = class extends import_react12.Component {
|
|
2151
2195
|
state = { error: null };
|
|
2152
2196
|
static getDerivedStateFromError(error) {
|
|
2153
2197
|
return { error };
|
|
@@ -2164,21 +2208,21 @@ var ErrorBoundary = class extends import_react11.Component {
|
|
|
2164
2208
|
}
|
|
2165
2209
|
render() {
|
|
2166
2210
|
if (this.state.error) {
|
|
2167
|
-
return this.props.fallback ?? /* @__PURE__ */ (0,
|
|
2168
|
-
/* @__PURE__ */ (0,
|
|
2169
|
-
/* @__PURE__ */ (0,
|
|
2211
|
+
return this.props.fallback ?? /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { role: "alert", style: { padding: 24, textAlign: "center" }, children: [
|
|
2212
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("h2", { children: "Algo deu errado" }),
|
|
2213
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { style: { opacity: 0.7 }, children: "Recarregue a p\xE1gina pra tentar de novo." })
|
|
2170
2214
|
] });
|
|
2171
2215
|
}
|
|
2172
|
-
return /* @__PURE__ */ (0,
|
|
2216
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_jsx_runtime19.Fragment, { children: this.props.children });
|
|
2173
2217
|
}
|
|
2174
2218
|
};
|
|
2175
2219
|
|
|
2176
2220
|
// src/i18n/I18nProvider.tsx
|
|
2177
|
-
var
|
|
2221
|
+
var import_react13 = require("react");
|
|
2178
2222
|
var import_i18next = __toESM(require("i18next"), 1);
|
|
2179
2223
|
var import_react_i18next = require("react-i18next");
|
|
2180
|
-
var
|
|
2181
|
-
var
|
|
2224
|
+
var import_sdk6 = require("@hook-sdk/sdk");
|
|
2225
|
+
var import_jsx_runtime20 = require("react/jsx-runtime");
|
|
2182
2226
|
function ensureInitialized(defaultLocale, supportedLocales, resources, initialLocale) {
|
|
2183
2227
|
if (import_i18next.default.isInitialized) return;
|
|
2184
2228
|
import_i18next.default.use(import_react_i18next.initReactI18next).init({
|
|
@@ -2200,14 +2244,14 @@ function I18nProvider({
|
|
|
2200
2244
|
resources,
|
|
2201
2245
|
children
|
|
2202
2246
|
}) {
|
|
2203
|
-
const [userLocale] = (0,
|
|
2247
|
+
const [userLocale] = (0, import_sdk6.usePersistedState)("user-locale", defaultLocale);
|
|
2204
2248
|
ensureInitialized(defaultLocale, supportedLocales, resources, userLocale);
|
|
2205
|
-
(0,
|
|
2249
|
+
(0, import_react13.useEffect)(() => {
|
|
2206
2250
|
if (import_i18next.default.isInitialized && import_i18next.default.language !== userLocale) {
|
|
2207
2251
|
import_i18next.default.changeLanguage(userLocale);
|
|
2208
2252
|
}
|
|
2209
2253
|
}, [userLocale]);
|
|
2210
|
-
return /* @__PURE__ */ (0,
|
|
2254
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_i18next.I18nextProvider, { i18n: import_i18next.default, children });
|
|
2211
2255
|
}
|
|
2212
2256
|
|
|
2213
2257
|
// src/dev/env.ts
|
|
@@ -2218,9 +2262,9 @@ function isDevToolsEnabled() {
|
|
|
2218
2262
|
}
|
|
2219
2263
|
|
|
2220
2264
|
// src/dev/DevSkipOnboardingFab.tsx
|
|
2221
|
-
var
|
|
2222
|
-
var
|
|
2223
|
-
var
|
|
2265
|
+
var import_react14 = require("react");
|
|
2266
|
+
var import_sdk7 = require("@hook-sdk/sdk");
|
|
2267
|
+
var import_jsx_runtime21 = require("react/jsx-runtime");
|
|
2224
2268
|
var STORAGE_KEY = "hook_dev_skip_email";
|
|
2225
2269
|
var TEST_EMAIL_DOMAIN = "@hook.test";
|
|
2226
2270
|
var TEST_PASSWORD = "SkipTest!2026";
|
|
@@ -2287,25 +2331,25 @@ var STYLES = {
|
|
|
2287
2331
|
};
|
|
2288
2332
|
var CONFIRM_TIMEOUT_MS = 3e3;
|
|
2289
2333
|
function DevSkipOnboardingFab({ defaults }) {
|
|
2290
|
-
const hook = (0,
|
|
2334
|
+
const hook = (0, import_sdk7.useHook)();
|
|
2291
2335
|
const { slug } = useAppConfig();
|
|
2292
|
-
const [state, setState] = (0,
|
|
2293
|
-
const [errorMsg, setErrorMsg] = (0,
|
|
2294
|
-
const timerRef = (0,
|
|
2336
|
+
const [state, setState] = (0, import_react14.useState)("idle");
|
|
2337
|
+
const [errorMsg, setErrorMsg] = (0, import_react14.useState)(null);
|
|
2338
|
+
const timerRef = (0, import_react14.useRef)(null);
|
|
2295
2339
|
const isAuthed = hook.authStatus === "authenticated";
|
|
2296
|
-
const [onboarding] = (0,
|
|
2340
|
+
const [onboarding] = (0, import_sdk7.usePersistedState)(
|
|
2297
2341
|
"onboarding_data",
|
|
2298
2342
|
null,
|
|
2299
2343
|
{ enabled: isAuthed }
|
|
2300
2344
|
);
|
|
2301
2345
|
const onboardingCompleted = isAuthed && onboarding?.onboarding_completed === true;
|
|
2302
|
-
const clearTimer = (0,
|
|
2346
|
+
const clearTimer = (0, import_react14.useCallback)(() => {
|
|
2303
2347
|
if (timerRef.current) {
|
|
2304
2348
|
clearTimeout(timerRef.current);
|
|
2305
2349
|
timerRef.current = null;
|
|
2306
2350
|
}
|
|
2307
2351
|
}, []);
|
|
2308
|
-
const onClick = (0,
|
|
2352
|
+
const onClick = (0, import_react14.useCallback)(async () => {
|
|
2309
2353
|
if (state === "busy") return;
|
|
2310
2354
|
if (state === "idle" || state === "error") {
|
|
2311
2355
|
setState("confirm");
|
|
@@ -2335,7 +2379,7 @@ function DevSkipOnboardingFab({ defaults }) {
|
|
|
2335
2379
|
...state === "confirm" || state === "error" ? STYLES.confirm : {},
|
|
2336
2380
|
...state === "busy" ? STYLES.busy : {}
|
|
2337
2381
|
};
|
|
2338
|
-
return /* @__PURE__ */ (0,
|
|
2382
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
2339
2383
|
"button",
|
|
2340
2384
|
{
|
|
2341
2385
|
type: "button",
|
|
@@ -2350,21 +2394,21 @@ function DevSkipOnboardingFab({ defaults }) {
|
|
|
2350
2394
|
}
|
|
2351
2395
|
|
|
2352
2396
|
// src/internal/PaymentReturnHandler.tsx
|
|
2353
|
-
var
|
|
2354
|
-
var
|
|
2355
|
-
var
|
|
2397
|
+
var import_react15 = require("react");
|
|
2398
|
+
var import_sdk8 = require("@hook-sdk/sdk");
|
|
2399
|
+
var import_jsx_runtime22 = require("react/jsx-runtime");
|
|
2356
2400
|
var BACKOFF_MS = [2e3, 5e3, 1e4, 2e4, 4e4];
|
|
2357
2401
|
var MAX_CYCLES = 3;
|
|
2358
2402
|
var SUPPORT_MAILTO = "mailto:suporte@usehook.net?subject=Pagamento%20pendente";
|
|
2359
2403
|
function PaymentReturnHandler({ children }) {
|
|
2360
|
-
const { subscription, track: track2 } = (0,
|
|
2361
|
-
const subRef = (0,
|
|
2404
|
+
const { subscription, track: track2 } = (0, import_sdk8.useHook)();
|
|
2405
|
+
const subRef = (0, import_react15.useRef)(subscription);
|
|
2362
2406
|
subRef.current = subscription;
|
|
2363
|
-
const runIdRef = (0,
|
|
2364
|
-
const cyclesRef = (0,
|
|
2365
|
-
const startMsRef = (0,
|
|
2366
|
-
const [state, setState] = (0,
|
|
2367
|
-
const runPoll = (0,
|
|
2407
|
+
const runIdRef = (0, import_react15.useRef)(0);
|
|
2408
|
+
const cyclesRef = (0, import_react15.useRef)(0);
|
|
2409
|
+
const startMsRef = (0, import_react15.useRef)(0);
|
|
2410
|
+
const [state, setState] = (0, import_react15.useState)("idle");
|
|
2411
|
+
const runPoll = (0, import_react15.useCallback)(() => {
|
|
2368
2412
|
const runId = ++runIdRef.current;
|
|
2369
2413
|
const isFirstRun = cyclesRef.current === 0;
|
|
2370
2414
|
cyclesRef.current += 1;
|
|
@@ -2412,7 +2456,7 @@ function PaymentReturnHandler({ children }) {
|
|
|
2412
2456
|
};
|
|
2413
2457
|
void tick();
|
|
2414
2458
|
}, [track2]);
|
|
2415
|
-
(0,
|
|
2459
|
+
(0, import_react15.useEffect)(() => {
|
|
2416
2460
|
if (typeof window === "undefined") return;
|
|
2417
2461
|
const url = new URL(window.location.href);
|
|
2418
2462
|
if (url.searchParams.get("paymentReturn") !== "1") return;
|
|
@@ -2422,26 +2466,26 @@ function PaymentReturnHandler({ children }) {
|
|
|
2422
2466
|
runIdRef.current++;
|
|
2423
2467
|
};
|
|
2424
2468
|
}, [runPoll]);
|
|
2425
|
-
const goHome = (0,
|
|
2469
|
+
const goHome = (0, import_react15.useCallback)(() => {
|
|
2426
2470
|
const cleanUrl = new URL(window.location.href);
|
|
2427
2471
|
cleanUrl.searchParams.delete("paymentReturn");
|
|
2428
2472
|
cleanUrl.pathname = "/app/home";
|
|
2429
2473
|
window.location.href = cleanUrl.toString();
|
|
2430
2474
|
}, []);
|
|
2431
2475
|
if (state === "confirming") {
|
|
2432
|
-
return /* @__PURE__ */ (0,
|
|
2476
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { role: "status", "aria-live": "polite", style: overlayStyle2, children: "Confirmando pagamento\u2026" });
|
|
2433
2477
|
}
|
|
2434
2478
|
if (state === "waiting") {
|
|
2435
|
-
return /* @__PURE__ */ (0,
|
|
2436
|
-
/* @__PURE__ */ (0,
|
|
2437
|
-
/* @__PURE__ */ (0,
|
|
2479
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { role: "status", "aria-live": "polite", style: overlayStyle2, children: /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { style: { maxWidth: 320, textAlign: "center", lineHeight: 1.5 }, children: [
|
|
2480
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { style: { marginBottom: 16 }, children: "Pagamento aceito. Estamos confirmando com o banco \u2014 pode levar alguns minutos." }),
|
|
2481
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("button", { type: "button", onClick: runPoll, style: buttonStyle, children: "Atualizar" })
|
|
2438
2482
|
] }) });
|
|
2439
2483
|
}
|
|
2440
2484
|
if (state === "timeout") {
|
|
2441
|
-
return /* @__PURE__ */ (0,
|
|
2442
|
-
/* @__PURE__ */ (0,
|
|
2443
|
-
/* @__PURE__ */ (0,
|
|
2444
|
-
/* @__PURE__ */ (0,
|
|
2485
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { role: "alert", "aria-live": "assertive", style: overlayStyle2, children: /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { style: { maxWidth: 360, textAlign: "center", lineHeight: 1.5 }, children: [
|
|
2486
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { style: { marginBottom: 16 }, children: "Ainda n\xE3o conseguimos confirmar seu pagamento com o banco. Voc\xEA pode tentar de novo, voltar pro app, ou falar com a gente." }),
|
|
2487
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: 8 }, children: [
|
|
2488
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
2445
2489
|
"button",
|
|
2446
2490
|
{
|
|
2447
2491
|
type: "button",
|
|
@@ -2454,7 +2498,7 @@ function PaymentReturnHandler({ children }) {
|
|
|
2454
2498
|
children: "Tentar de novo"
|
|
2455
2499
|
}
|
|
2456
2500
|
),
|
|
2457
|
-
/* @__PURE__ */ (0,
|
|
2501
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
2458
2502
|
"button",
|
|
2459
2503
|
{
|
|
2460
2504
|
type: "button",
|
|
@@ -2464,7 +2508,7 @@ function PaymentReturnHandler({ children }) {
|
|
|
2464
2508
|
children: "Voltar pro app"
|
|
2465
2509
|
}
|
|
2466
2510
|
),
|
|
2467
|
-
/* @__PURE__ */ (0,
|
|
2511
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
2468
2512
|
"a",
|
|
2469
2513
|
{
|
|
2470
2514
|
href: SUPPORT_MAILTO,
|
|
@@ -2476,7 +2520,7 @@ function PaymentReturnHandler({ children }) {
|
|
|
2476
2520
|
] })
|
|
2477
2521
|
] }) });
|
|
2478
2522
|
}
|
|
2479
|
-
return /* @__PURE__ */ (0,
|
|
2523
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_jsx_runtime22.Fragment, { children });
|
|
2480
2524
|
}
|
|
2481
2525
|
var overlayStyle2 = {
|
|
2482
2526
|
position: "fixed",
|
|
@@ -2515,7 +2559,7 @@ var linkStyle = {
|
|
|
2515
2559
|
};
|
|
2516
2560
|
|
|
2517
2561
|
// src/AppRoot.tsx
|
|
2518
|
-
var
|
|
2562
|
+
var import_jsx_runtime23 = require("react/jsx-runtime");
|
|
2519
2563
|
function buildLegacyConfigShim(config) {
|
|
2520
2564
|
const paywall = config.paywall;
|
|
2521
2565
|
const isFree = paywall.mode === "free";
|
|
@@ -2589,19 +2633,22 @@ function AppRoot(props) {
|
|
|
2589
2633
|
"[hook-template] <AppRoot>: PreAuthFlow slot prop is required when config.onboarding.trigger === 'pre_signup_custom'."
|
|
2590
2634
|
);
|
|
2591
2635
|
}
|
|
2592
|
-
const legacyShim = (0,
|
|
2636
|
+
const legacyShim = (0, import_react16.useMemo)(() => buildLegacyConfigShim(config), [config]);
|
|
2593
2637
|
const Router = testRouter === "memory" ? import_react_router_dom2.MemoryRouter : import_react_router_dom2.BrowserRouter;
|
|
2594
2638
|
const basename = `/app/${config.slug}`;
|
|
2595
2639
|
const routerProps = testRouter === "memory" ? { basename, initialEntries: testInitialEntries } : { basename };
|
|
2596
2640
|
const position = config.install_prompt?.position ?? "post-paywall";
|
|
2597
|
-
const subscriptionGated = /* @__PURE__ */ (0,
|
|
2598
|
-
|
|
2599
|
-
/* @__PURE__ */ (0,
|
|
2600
|
-
|
|
2601
|
-
|
|
2602
|
-
/* @__PURE__ */ (0,
|
|
2603
|
-
|
|
2604
|
-
|
|
2641
|
+
const subscriptionGated = /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(SubscriptionGate, { Paywall: Paywall2 ?? FallbackPaywall, children: [
|
|
2642
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(EmailVerifyBanner, {}),
|
|
2643
|
+
position === "post-paywall" ? /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(InstallGate, { position: "post-paywall", children: [
|
|
2644
|
+
children,
|
|
2645
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(PushPrompt, {})
|
|
2646
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_jsx_runtime23.Fragment, { children: [
|
|
2647
|
+
children,
|
|
2648
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(PushPrompt, {})
|
|
2649
|
+
] })
|
|
2650
|
+
] });
|
|
2651
|
+
const authGated = /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
2605
2652
|
AuthGated,
|
|
2606
2653
|
{
|
|
2607
2654
|
config,
|
|
@@ -2616,13 +2663,13 @@ function AppRoot(props) {
|
|
|
2616
2663
|
children: subscriptionGated
|
|
2617
2664
|
}
|
|
2618
2665
|
);
|
|
2619
|
-
const routedTree = /* @__PURE__ */ (0,
|
|
2620
|
-
/* @__PURE__ */ (0,
|
|
2621
|
-
/* @__PURE__ */ (0,
|
|
2622
|
-
position === "pre-auth" ? /* @__PURE__ */ (0,
|
|
2623
|
-
isDevToolsEnabled() && devSkipOnboarding ? /* @__PURE__ */ (0,
|
|
2666
|
+
const routedTree = /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(Router, { ...routerProps, children: [
|
|
2667
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(DeepLinkHandler, { deepLinks: config.deepLinks }),
|
|
2668
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(SessionExpiredBanner, {}),
|
|
2669
|
+
position === "pre-auth" ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(InstallGate, { position: "pre-auth", children: authGated }) : authGated,
|
|
2670
|
+
isDevToolsEnabled() && devSkipOnboarding ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(DevSkipOnboardingFab, { defaults: devSkipOnboarding.defaults }) : null
|
|
2624
2671
|
] });
|
|
2625
|
-
return /* @__PURE__ */ (0,
|
|
2672
|
+
return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(ErrorBoundary, { children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(AppConfigProvider, { config, children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(TemplateConfigProvider, { config: legacyShim, children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(ThemeProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(PersistenceRegistry, { config: config.persistedKeys, children: config.i18n ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
2626
2673
|
I18nProvider,
|
|
2627
2674
|
{
|
|
2628
2675
|
defaultLocale: config.i18n.defaultLocale,
|
|
@@ -2642,46 +2689,46 @@ function AuthGated({
|
|
|
2642
2689
|
EmailVerify,
|
|
2643
2690
|
PreAuthFlow
|
|
2644
2691
|
}) {
|
|
2645
|
-
const { authStatus } = (0,
|
|
2692
|
+
const { authStatus } = (0, import_sdk9.useHook)();
|
|
2646
2693
|
if (authStatus === "loading") return null;
|
|
2647
2694
|
if (authStatus !== "authenticated") {
|
|
2648
2695
|
if (config.authFlow.signupMode === "pay_first" && PreAuthFlow) {
|
|
2649
|
-
return /* @__PURE__ */ (0,
|
|
2650
|
-
/* @__PURE__ */ (0,
|
|
2651
|
-
/* @__PURE__ */ (0,
|
|
2652
|
-
/* @__PURE__ */ (0,
|
|
2653
|
-
EmailVerify ? /* @__PURE__ */ (0,
|
|
2654
|
-
/* @__PURE__ */ (0,
|
|
2696
|
+
return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_react_router_dom2.Routes, { children: [
|
|
2697
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_react_router_dom2.Route, { path: "/signin", element: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(Login, {}) }),
|
|
2698
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_react_router_dom2.Route, { path: "/forgot", element: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(Forgot, {}) }),
|
|
2699
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_react_router_dom2.Route, { path: "/reset", element: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(Reset, {}) }),
|
|
2700
|
+
EmailVerify ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_react_router_dom2.Route, { path: "/verify", element: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(EmailVerify, {}) }) : null,
|
|
2701
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_react_router_dom2.Route, { path: "/*", element: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(PreAuthFlow, {}) })
|
|
2655
2702
|
] });
|
|
2656
2703
|
}
|
|
2657
2704
|
if (config.onboarding?.trigger === "pre_signup_custom" && PreAuthFlow) {
|
|
2658
|
-
return /* @__PURE__ */ (0,
|
|
2659
|
-
/* @__PURE__ */ (0,
|
|
2660
|
-
/* @__PURE__ */ (0,
|
|
2661
|
-
/* @__PURE__ */ (0,
|
|
2662
|
-
/* @__PURE__ */ (0,
|
|
2663
|
-
EmailVerify ? /* @__PURE__ */ (0,
|
|
2664
|
-
/* @__PURE__ */ (0,
|
|
2705
|
+
return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_react_router_dom2.Routes, { children: [
|
|
2706
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_react_router_dom2.Route, { path: "/signin", element: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(Login, {}) }),
|
|
2707
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_react_router_dom2.Route, { path: "/signup", element: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(Signup, {}) }),
|
|
2708
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_react_router_dom2.Route, { path: "/forgot", element: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(Forgot, {}) }),
|
|
2709
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_react_router_dom2.Route, { path: "/reset", element: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(Reset, {}) }),
|
|
2710
|
+
EmailVerify ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_react_router_dom2.Route, { path: "/verify", element: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(EmailVerify, {}) }) : null,
|
|
2711
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_react_router_dom2.Route, { path: "/*", element: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(PreAuthFlow, {}) })
|
|
2665
2712
|
] });
|
|
2666
2713
|
}
|
|
2667
|
-
return /* @__PURE__ */ (0,
|
|
2668
|
-
/* @__PURE__ */ (0,
|
|
2669
|
-
/* @__PURE__ */ (0,
|
|
2670
|
-
/* @__PURE__ */ (0,
|
|
2671
|
-
/* @__PURE__ */ (0,
|
|
2672
|
-
EmailVerify ? /* @__PURE__ */ (0,
|
|
2673
|
-
/* @__PURE__ */ (0,
|
|
2714
|
+
return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_react_router_dom2.Routes, { children: [
|
|
2715
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_react_router_dom2.Route, { path: "/", element: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(Login, {}) }),
|
|
2716
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_react_router_dom2.Route, { path: "/signup", element: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(Signup, {}) }),
|
|
2717
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_react_router_dom2.Route, { path: "/forgot", element: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(Forgot, {}) }),
|
|
2718
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_react_router_dom2.Route, { path: "/reset", element: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(Reset, {}) }),
|
|
2719
|
+
EmailVerify ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_react_router_dom2.Route, { path: "/verify", element: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(EmailVerify, {}) }) : null,
|
|
2720
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_react_router_dom2.Route, { path: "*", element: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_react_router_dom2.Navigate, { to: "/", replace: true }) })
|
|
2674
2721
|
] });
|
|
2675
2722
|
}
|
|
2676
|
-
return /* @__PURE__ */ (0,
|
|
2723
|
+
return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_jsx_runtime23.Fragment, { children });
|
|
2677
2724
|
}
|
|
2678
2725
|
function FallbackPaywall() {
|
|
2679
2726
|
return null;
|
|
2680
2727
|
}
|
|
2681
2728
|
|
|
2682
2729
|
// src/hooks/usePush.ts
|
|
2683
|
-
var
|
|
2684
|
-
var
|
|
2730
|
+
var import_react17 = require("react");
|
|
2731
|
+
var import_sdk10 = require("@hook-sdk/sdk");
|
|
2685
2732
|
var DISMISS_STORAGE_KEY = "push:dismissed-until";
|
|
2686
2733
|
var DISMISS_TTL_MS2 = 7 * 24 * 60 * 60 * 1e3;
|
|
2687
2734
|
function detectIosNeedsInstall() {
|
|
@@ -2725,12 +2772,12 @@ function deriveState(push) {
|
|
|
2725
2772
|
return { kind: "prompt" };
|
|
2726
2773
|
}
|
|
2727
2774
|
function usePush() {
|
|
2728
|
-
const { push } = (0,
|
|
2729
|
-
const [state, setState] = (0,
|
|
2730
|
-
(0,
|
|
2775
|
+
const { push } = (0, import_sdk10.useHook)();
|
|
2776
|
+
const [state, setState] = (0, import_react17.useState)(() => deriveState(push));
|
|
2777
|
+
(0, import_react17.useEffect)(() => {
|
|
2731
2778
|
setState(deriveState(push));
|
|
2732
2779
|
}, [push]);
|
|
2733
|
-
const subscribe = (0,
|
|
2780
|
+
const subscribe = (0, import_react17.useCallback)(async () => {
|
|
2734
2781
|
try {
|
|
2735
2782
|
await push.subscribe();
|
|
2736
2783
|
setState({ kind: "subscribed" });
|
|
@@ -2742,7 +2789,7 @@ function usePush() {
|
|
|
2742
2789
|
throw e;
|
|
2743
2790
|
}
|
|
2744
2791
|
}, [push]);
|
|
2745
|
-
const unsubscribe = (0,
|
|
2792
|
+
const unsubscribe = (0, import_react17.useCallback)(async () => {
|
|
2746
2793
|
try {
|
|
2747
2794
|
await push.unsubscribe();
|
|
2748
2795
|
setState({ kind: "prompt" });
|
|
@@ -2751,7 +2798,7 @@ function usePush() {
|
|
|
2751
2798
|
throw e;
|
|
2752
2799
|
}
|
|
2753
2800
|
}, [push]);
|
|
2754
|
-
const dismiss = (0,
|
|
2801
|
+
const dismiss = (0, import_react17.useCallback)(() => {
|
|
2755
2802
|
if (typeof localStorage !== "undefined") {
|
|
2756
2803
|
try {
|
|
2757
2804
|
localStorage.setItem(DISMISS_STORAGE_KEY, String(Date.now() + DISMISS_TTL_MS2));
|
|
@@ -2764,27 +2811,27 @@ function usePush() {
|
|
|
2764
2811
|
}
|
|
2765
2812
|
|
|
2766
2813
|
// src/components/PushPrompt.tsx
|
|
2767
|
-
var
|
|
2814
|
+
var import_jsx_runtime24 = require("react/jsx-runtime");
|
|
2768
2815
|
function PushPrompt2({ texts, onSubscribed, onDeclined, onInstallRequested, className }) {
|
|
2769
2816
|
const { state, subscribe } = usePush();
|
|
2770
2817
|
if (state.kind === "denied" || state.kind === "dismissed" || state.kind === "subscribed") {
|
|
2771
2818
|
return null;
|
|
2772
2819
|
}
|
|
2773
2820
|
if (state.kind === "ios_needs_install") {
|
|
2774
|
-
return /* @__PURE__ */ (0,
|
|
2775
|
-
/* @__PURE__ */ (0,
|
|
2776
|
-
/* @__PURE__ */ (0,
|
|
2777
|
-
onInstallRequested && texts.iosInstallCta && /* @__PURE__ */ (0,
|
|
2821
|
+
return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className, role: "region", "aria-label": texts.iosInstallTitle, children: [
|
|
2822
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)("h3", { children: texts.iosInstallTitle }),
|
|
2823
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)("p", { children: texts.iosInstallBody }),
|
|
2824
|
+
onInstallRequested && texts.iosInstallCta && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("button", { onClick: onInstallRequested, children: texts.iosInstallCta })
|
|
2778
2825
|
] });
|
|
2779
2826
|
}
|
|
2780
2827
|
if (state.kind === "unsupported") {
|
|
2781
|
-
return /* @__PURE__ */ (0,
|
|
2828
|
+
return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className, role: "region", children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("p", { children: texts.unsupportedBody }) });
|
|
2782
2829
|
}
|
|
2783
2830
|
if (state.kind === "error") {
|
|
2784
|
-
return /* @__PURE__ */ (0,
|
|
2831
|
+
return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className, role: "region", "aria-label": "error", children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("p", { children: state.message }) });
|
|
2785
2832
|
}
|
|
2786
|
-
return /* @__PURE__ */ (0,
|
|
2787
|
-
/* @__PURE__ */ (0,
|
|
2833
|
+
return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className, role: "region", children: [
|
|
2834
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
2788
2835
|
"button",
|
|
2789
2836
|
{
|
|
2790
2837
|
type: "button",
|
|
@@ -2798,71 +2845,71 @@ function PushPrompt2({ texts, onSubscribed, onDeclined, onInstallRequested, clas
|
|
|
2798
2845
|
children: texts.cta
|
|
2799
2846
|
}
|
|
2800
2847
|
),
|
|
2801
|
-
onDeclined && /* @__PURE__ */ (0,
|
|
2848
|
+
onDeclined && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("button", { type: "button", onClick: onDeclined, children: texts.declineCta })
|
|
2802
2849
|
] });
|
|
2803
2850
|
}
|
|
2804
2851
|
|
|
2805
2852
|
// src/components/LanguageSwitcher.tsx
|
|
2806
|
-
var
|
|
2807
|
-
var
|
|
2853
|
+
var import_sdk11 = require("@hook-sdk/sdk");
|
|
2854
|
+
var import_jsx_runtime25 = require("react/jsx-runtime");
|
|
2808
2855
|
function LanguageSwitcher({ id, className, label = "Language" }) {
|
|
2809
2856
|
const config = useAppConfig();
|
|
2810
2857
|
const i18nConfig = config.i18n;
|
|
2811
|
-
const [userLocale, setUserLocale] = (0,
|
|
2858
|
+
const [userLocale, setUserLocale] = (0, import_sdk11.usePersistedState)(
|
|
2812
2859
|
"user-locale",
|
|
2813
2860
|
i18nConfig?.defaultLocale ?? "en-US"
|
|
2814
2861
|
);
|
|
2815
2862
|
if (!i18nConfig) return null;
|
|
2816
|
-
return /* @__PURE__ */ (0,
|
|
2817
|
-
label ? /* @__PURE__ */ (0,
|
|
2818
|
-
/* @__PURE__ */ (0,
|
|
2863
|
+
return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("label", { className, children: [
|
|
2864
|
+
label ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { children: label }) : null,
|
|
2865
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
|
|
2819
2866
|
"select",
|
|
2820
2867
|
{
|
|
2821
2868
|
id,
|
|
2822
2869
|
value: userLocale,
|
|
2823
2870
|
onChange: (e) => setUserLocale(e.target.value),
|
|
2824
2871
|
"data-testid": "language-switcher",
|
|
2825
|
-
children: i18nConfig.supportedLocales.map((loc) => /* @__PURE__ */ (0,
|
|
2872
|
+
children: i18nConfig.supportedLocales.map((loc) => /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("option", { value: loc, children: loc }, loc))
|
|
2826
2873
|
}
|
|
2827
2874
|
)
|
|
2828
2875
|
] });
|
|
2829
2876
|
}
|
|
2830
2877
|
|
|
2831
2878
|
// src/defaults/LoadingState.tsx
|
|
2832
|
-
var
|
|
2879
|
+
var import_jsx_runtime26 = require("react/jsx-runtime");
|
|
2833
2880
|
function LoadingState({ message }) {
|
|
2834
|
-
return /* @__PURE__ */ (0,
|
|
2881
|
+
return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { role: "status", "aria-live": "polite", style: { padding: 24, textAlign: "center" }, children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { children: message ?? "Carregando..." }) });
|
|
2835
2882
|
}
|
|
2836
2883
|
|
|
2837
2884
|
// src/defaults/EmptyState.tsx
|
|
2838
|
-
var
|
|
2885
|
+
var import_jsx_runtime27 = require("react/jsx-runtime");
|
|
2839
2886
|
function EmptyState({ title, description, action }) {
|
|
2840
|
-
return /* @__PURE__ */ (0,
|
|
2841
|
-
/* @__PURE__ */ (0,
|
|
2842
|
-
description && /* @__PURE__ */ (0,
|
|
2843
|
-
action && /* @__PURE__ */ (0,
|
|
2887
|
+
return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { role: "status", style: { padding: 32, textAlign: "center" }, children: [
|
|
2888
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)("h2", { style: { marginBottom: 8 }, children: title }),
|
|
2889
|
+
description && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("p", { style: { opacity: 0.7 }, children: description }),
|
|
2890
|
+
action && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { style: { marginTop: 16 }, children: action })
|
|
2844
2891
|
] });
|
|
2845
2892
|
}
|
|
2846
2893
|
|
|
2847
2894
|
// src/defaults/CheckoutPageDefault.tsx
|
|
2848
|
-
var
|
|
2895
|
+
var import_react23 = require("react");
|
|
2849
2896
|
var import_react_router_dom3 = require("react-router-dom");
|
|
2850
2897
|
|
|
2851
2898
|
// src/hooks/useCheckoutForm.ts
|
|
2852
|
-
var
|
|
2853
|
-
var
|
|
2899
|
+
var import_react18 = require("react");
|
|
2900
|
+
var import_sdk13 = require("@hook-sdk/sdk");
|
|
2854
2901
|
|
|
2855
2902
|
// src/errors.ts
|
|
2856
|
-
var
|
|
2903
|
+
var import_sdk12 = require("@hook-sdk/sdk");
|
|
2857
2904
|
function mapSdkError(err) {
|
|
2858
|
-
if (err instanceof
|
|
2905
|
+
if (err instanceof import_sdk12.SdkRateLimitError) {
|
|
2859
2906
|
return {
|
|
2860
2907
|
code: "rate_limited",
|
|
2861
2908
|
message: `Aguarde ${err.retryAfter}s e tente novamente.`,
|
|
2862
2909
|
retryAfter: err.retryAfter
|
|
2863
2910
|
};
|
|
2864
2911
|
}
|
|
2865
|
-
if (err instanceof
|
|
2912
|
+
if (err instanceof import_sdk12.SdkAuthError) {
|
|
2866
2913
|
const detail = err.detail;
|
|
2867
2914
|
if (detail === "email_unverified") {
|
|
2868
2915
|
return { code: "email_unverified", message: "Confirme seu e-mail antes de entrar." };
|
|
@@ -2872,7 +2919,10 @@ function mapSdkError(err) {
|
|
|
2872
2919
|
}
|
|
2873
2920
|
return { code: "invalid_credentials", message: "E-mail ou senha inv\xE1lidos." };
|
|
2874
2921
|
}
|
|
2875
|
-
if (err instanceof
|
|
2922
|
+
if (err instanceof import_sdk12.SdkValidationError && err.code === "auth.email_taken") {
|
|
2923
|
+
return { code: "email_taken", message: "Esse e-mail j\xE1 tem conta." };
|
|
2924
|
+
}
|
|
2925
|
+
if (err instanceof import_sdk12.SdkError && err.httpStatus === 0) {
|
|
2876
2926
|
return { code: "network", message: "Sem conex\xE3o com o servidor. Verifique sua internet." };
|
|
2877
2927
|
}
|
|
2878
2928
|
if (err instanceof TypeError) {
|
|
@@ -2886,37 +2936,37 @@ var EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
|
2886
2936
|
var PHONE_RE = /^[0-9()+\-\s]{8,20}$/;
|
|
2887
2937
|
var CHECK_DEBOUNCE_MS = 400;
|
|
2888
2938
|
function useCheckoutForm(args) {
|
|
2889
|
-
const { auth } = (0,
|
|
2890
|
-
const [name, setName] = (0,
|
|
2891
|
-
const [email, setEmail] = (0,
|
|
2892
|
-
const [emailConfirm, setEmailConfirm] = (0,
|
|
2893
|
-
const [phone, setPhone] = (0,
|
|
2894
|
-
const [cpf, setCpf] = (0,
|
|
2895
|
-
const [method, setMethod] = (0,
|
|
2896
|
-
const [cycle, setCycle] = (0,
|
|
2897
|
-
const [card, setCardState] = (0,
|
|
2939
|
+
const { auth } = (0, import_sdk13.useHook)();
|
|
2940
|
+
const [name, setName] = (0, import_react18.useState)("");
|
|
2941
|
+
const [email, setEmail] = (0, import_react18.useState)("");
|
|
2942
|
+
const [emailConfirm, setEmailConfirm] = (0, import_react18.useState)("");
|
|
2943
|
+
const [phone, setPhone] = (0, import_react18.useState)("");
|
|
2944
|
+
const [cpf, setCpf] = (0, import_react18.useState)("");
|
|
2945
|
+
const [method, setMethod] = (0, import_react18.useState)(args.defaultMethod);
|
|
2946
|
+
const [cycle, setCycle] = (0, import_react18.useState)(args.defaultCycle);
|
|
2947
|
+
const [card, setCardState] = (0, import_react18.useState)({
|
|
2898
2948
|
number: "",
|
|
2899
2949
|
expiryMonth: "",
|
|
2900
2950
|
expiryYear: "",
|
|
2901
2951
|
ccv: "",
|
|
2902
2952
|
holderName: ""
|
|
2903
2953
|
});
|
|
2904
|
-
const setCard = (0,
|
|
2954
|
+
const setCard = (0, import_react18.useCallback)((patch) => {
|
|
2905
2955
|
setCardState((prev) => ({ ...prev, ...patch }));
|
|
2906
2956
|
}, []);
|
|
2907
|
-
const [touchedName, setTouchedName] = (0,
|
|
2908
|
-
const [touchedEmail, setTouchedEmail] = (0,
|
|
2909
|
-
const [touchedEmailConfirm, setTouchedEmailConfirm] = (0,
|
|
2910
|
-
const [touchedPhone, setTouchedPhone] = (0,
|
|
2911
|
-
const [touchedCpf, setTouchedCpf] = (0,
|
|
2912
|
-
const [formSubmitAttempted, setFormSubmitAttempted] = (0,
|
|
2913
|
-
const [submitting, setSubmitting] = (0,
|
|
2914
|
-
const [error, setError] = (0,
|
|
2915
|
-
const [emailTaken, setEmailTaken] = (0,
|
|
2916
|
-
const [loginUrl, setLoginUrl] = (0,
|
|
2917
|
-
const [emailStatus, setEmailStatus] = (0,
|
|
2918
|
-
const lastCheckedEmail = (0,
|
|
2919
|
-
(0,
|
|
2957
|
+
const [touchedName, setTouchedName] = (0, import_react18.useState)(false);
|
|
2958
|
+
const [touchedEmail, setTouchedEmail] = (0, import_react18.useState)(false);
|
|
2959
|
+
const [touchedEmailConfirm, setTouchedEmailConfirm] = (0, import_react18.useState)(false);
|
|
2960
|
+
const [touchedPhone, setTouchedPhone] = (0, import_react18.useState)(false);
|
|
2961
|
+
const [touchedCpf, setTouchedCpf] = (0, import_react18.useState)(false);
|
|
2962
|
+
const [formSubmitAttempted, setFormSubmitAttempted] = (0, import_react18.useState)(false);
|
|
2963
|
+
const [submitting, setSubmitting] = (0, import_react18.useState)(false);
|
|
2964
|
+
const [error, setError] = (0, import_react18.useState)(null);
|
|
2965
|
+
const [emailTaken, setEmailTaken] = (0, import_react18.useState)(false);
|
|
2966
|
+
const [loginUrl, setLoginUrl] = (0, import_react18.useState)(null);
|
|
2967
|
+
const [emailStatus, setEmailStatus] = (0, import_react18.useState)("idle");
|
|
2968
|
+
const lastCheckedEmail = (0, import_react18.useRef)("");
|
|
2969
|
+
(0, import_react18.useEffect)(() => {
|
|
2920
2970
|
if (!email || !EMAIL_RE.test(email)) {
|
|
2921
2971
|
setEmailStatus("idle");
|
|
2922
2972
|
return;
|
|
@@ -2934,27 +2984,27 @@ function useCheckoutForm(args) {
|
|
|
2934
2984
|
}, CHECK_DEBOUNCE_MS);
|
|
2935
2985
|
return () => clearTimeout(timer);
|
|
2936
2986
|
}, [email, auth]);
|
|
2937
|
-
const validateName = (0,
|
|
2987
|
+
const validateName = (0, import_react18.useMemo)(() => {
|
|
2938
2988
|
if (name.length === 0) return null;
|
|
2939
2989
|
if (name.trim().length < 2) return "Nome muito curto.";
|
|
2940
2990
|
return null;
|
|
2941
2991
|
}, [name]);
|
|
2942
|
-
const validateEmail = (0,
|
|
2992
|
+
const validateEmail = (0, import_react18.useMemo)(() => {
|
|
2943
2993
|
if (email.length === 0) return null;
|
|
2944
2994
|
if (!EMAIL_RE.test(email)) return "Formato de e-mail inv\xE1lido.";
|
|
2945
2995
|
return null;
|
|
2946
2996
|
}, [email]);
|
|
2947
|
-
const validateEmailConfirm = (0,
|
|
2997
|
+
const validateEmailConfirm = (0, import_react18.useMemo)(() => {
|
|
2948
2998
|
if (emailConfirm.length === 0) return null;
|
|
2949
2999
|
if (emailConfirm !== email) return "Os e-mails n\xE3o coincidem.";
|
|
2950
3000
|
return null;
|
|
2951
3001
|
}, [emailConfirm, email]);
|
|
2952
|
-
const validatePhone = (0,
|
|
3002
|
+
const validatePhone = (0, import_react18.useMemo)(() => {
|
|
2953
3003
|
if (phone.length === 0) return null;
|
|
2954
3004
|
if (!PHONE_RE.test(phone)) return "Telefone inv\xE1lido.";
|
|
2955
3005
|
return null;
|
|
2956
3006
|
}, [phone]);
|
|
2957
|
-
const validateCpf = (0,
|
|
3007
|
+
const validateCpf = (0, import_react18.useMemo)(() => {
|
|
2958
3008
|
if (cpf.length === 0) return null;
|
|
2959
3009
|
const digits = cpf.replace(/\D/g, "");
|
|
2960
3010
|
if (digits.length !== 11) return "CPF deve ter 11 d\xEDgitos.";
|
|
@@ -2969,7 +3019,7 @@ function useCheckoutForm(args) {
|
|
|
2969
3019
|
const cpfError = touchedCpf || formSubmitAttempted ? validateCpf : null;
|
|
2970
3020
|
const phoneOk = method === "pix-auto" ? phone === "" || PHONE_RE.test(phone) : PHONE_RE.test(phone);
|
|
2971
3021
|
const canSubmit = name.trim().length >= 2 && EMAIL_RE.test(email) && (emailConfirm === "" || emailConfirm === email) && phoneOk && validateCpf === null && cpf.replace(/\D/g, "").length === 11 && emailStatus !== "exists" && !submitting && (method !== "card" || card.number.length >= 12 && card.ccv.length >= 3 && card.expiryMonth.length >= 1 && card.expiryYear.length >= 2 && card.holderName.length >= 1);
|
|
2972
|
-
const submit = (0,
|
|
3022
|
+
const submit = (0, import_react18.useCallback)(async () => {
|
|
2973
3023
|
setFormSubmitAttempted(true);
|
|
2974
3024
|
setError(null);
|
|
2975
3025
|
setEmailTaken(false);
|
|
@@ -2998,10 +3048,16 @@ function useCheckoutForm(args) {
|
|
|
2998
3048
|
name: card.holderName || name.trim(),
|
|
2999
3049
|
email,
|
|
3000
3050
|
cpfCnpj: cpf.replace(/\D/g, ""),
|
|
3001
|
-
//
|
|
3002
|
-
//
|
|
3003
|
-
|
|
3004
|
-
|
|
3051
|
+
// Plan-V 0.28.4 — Asaas's `creditCardHolderInfo.postalCode`
|
|
3052
|
+
// rejects all-zeros with `tokenize_failed:invalid_holderInfo`
|
|
3053
|
+
// ("O CEP informado é inválido."). The default CheckoutPage
|
|
3054
|
+
// doesn't collect CEP from the user (reference design skipped
|
|
3055
|
+
// it), so ship a known-valid placeholder. Apps that need real
|
|
3056
|
+
// customer addresses must override CheckoutPageDefault and
|
|
3057
|
+
// collect CEP — see personalburn's PaywallStepPagamento for
|
|
3058
|
+
// the pattern.
|
|
3059
|
+
postalCode: "01001000",
|
|
3060
|
+
addressNumber: "100",
|
|
3005
3061
|
phone
|
|
3006
3062
|
}
|
|
3007
3063
|
};
|
|
@@ -3019,7 +3075,7 @@ function useCheckoutForm(args) {
|
|
|
3019
3075
|
const result = await auth.subscribeAnonymous(args2);
|
|
3020
3076
|
return result;
|
|
3021
3077
|
} catch (err) {
|
|
3022
|
-
if (err instanceof
|
|
3078
|
+
if (err instanceof import_sdk13.EmailTakenError) {
|
|
3023
3079
|
setEmailTaken(true);
|
|
3024
3080
|
setLoginUrl(err.loginUrl);
|
|
3025
3081
|
setEmailStatus("exists");
|
|
@@ -3076,1867 +3132,1868 @@ function mod11(digits, len) {
|
|
|
3076
3132
|
}
|
|
3077
3133
|
|
|
3078
3134
|
// src/hooks/usePlan.ts
|
|
3079
|
-
var
|
|
3135
|
+
var import_sdk14 = require("@hook-sdk/sdk");
|
|
3080
3136
|
function usePlan() {
|
|
3081
|
-
const { plan } = (0,
|
|
3137
|
+
const { plan } = (0, import_sdk14.useHook)();
|
|
3082
3138
|
return plan;
|
|
3083
3139
|
}
|
|
3084
3140
|
|
|
3085
|
-
// src/
|
|
3086
|
-
var
|
|
3087
|
-
var
|
|
3088
|
-
|
|
3089
|
-
|
|
3090
|
-
|
|
3091
|
-
|
|
3092
|
-
|
|
3093
|
-
|
|
3094
|
-
|
|
3095
|
-
|
|
3096
|
-
|
|
3097
|
-
}
|
|
3098
|
-
}
|
|
3099
|
-
function formatBrl(cents) {
|
|
3100
|
-
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);
|
|
3101
3153
|
}
|
|
3102
|
-
function
|
|
3103
|
-
|
|
3104
|
-
return
|
|
3154
|
+
function monthlyFromYearly(yearlyCents) {
|
|
3155
|
+
if (yearlyCents === null || yearlyCents === void 0) return 0;
|
|
3156
|
+
return Math.round(yearlyCents / 12);
|
|
3105
3157
|
}
|
|
3106
|
-
function
|
|
3107
|
-
|
|
3108
|
-
|
|
3109
|
-
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);
|
|
3110
3161
|
}
|
|
3111
|
-
function
|
|
3112
|
-
|
|
3113
|
-
|
|
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);
|
|
3114
3167
|
}
|
|
3115
|
-
function
|
|
3116
|
-
|
|
3117
|
-
|
|
3118
|
-
if (d.length <= 6) return d.slice(0, 3) + "." + d.slice(3);
|
|
3119
|
-
if (d.length <= 9) return d.slice(0, 3) + "." + d.slice(3, 6) + "." + d.slice(6);
|
|
3120
|
-
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);
|
|
3121
3171
|
}
|
|
3122
|
-
|
|
3123
|
-
|
|
3124
|
-
|
|
3125
|
-
|
|
3126
|
-
|
|
3127
|
-
|
|
3128
|
-
|
|
3129
|
-
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 });
|
|
3130
3180
|
}
|
|
3131
|
-
|
|
3132
|
-
|
|
3133
|
-
|
|
3134
|
-
|
|
3135
|
-
const
|
|
3136
|
-
|
|
3137
|
-
|
|
3138
|
-
const [expiryMmAa, setExpiryMmAa] = (0, import_react18.useState)("");
|
|
3139
|
-
(0, import_react18.useEffect)(() => {
|
|
3140
|
-
const { month, year } = parseExpiryMmAa(expiryMmAa);
|
|
3141
|
-
if (month !== form.card.expiryMonth || year !== form.card.expiryYear) {
|
|
3142
|
-
form.setCard({ expiryMonth: month, expiryYear: year });
|
|
3143
|
-
}
|
|
3144
|
-
}, [expiryMmAa]);
|
|
3145
|
-
(0, import_react18.useEffect)(() => {
|
|
3146
|
-
if (form.emailTaken && form.loginUrl) {
|
|
3147
|
-
const t = setTimeout(() => navigate(form.loginUrl), 1200);
|
|
3148
|
-
return () => clearTimeout(t);
|
|
3149
|
-
}
|
|
3150
|
-
}, [form.emailTaken, form.loginUrl, navigate]);
|
|
3151
|
-
const planInfo = plan.data ? {
|
|
3152
|
-
priceCents: plan.data.priceCents,
|
|
3153
|
-
yearlyPriceCents: plan.data.yearlyPriceCents,
|
|
3154
|
-
trialDays: plan.data.trialDays
|
|
3155
|
-
} : null;
|
|
3156
|
-
const annual = form.cycle === "YEARLY";
|
|
3157
|
-
const cyclePrice = (0, import_react18.useMemo)(() => {
|
|
3158
|
-
if (!planInfo) return null;
|
|
3159
|
-
return annual ? planInfo.yearlyPriceCents ?? planInfo.priceCents * 12 : planInfo.priceCents;
|
|
3160
|
-
}, [planInfo, annual]);
|
|
3161
|
-
const monthlyText = (0, import_react18.useMemo)(() => {
|
|
3162
|
-
if (!planInfo) return "";
|
|
3163
|
-
const monthly = annual && planInfo.yearlyPriceCents ? Math.round(planInfo.yearlyPriceCents / 12) : planInfo.priceCents;
|
|
3164
|
-
return formatBrl(monthly);
|
|
3165
|
-
}, [planInfo, annual]);
|
|
3166
|
-
const todayCents = (0, import_react18.useMemo)(() => {
|
|
3167
|
-
if (form.method === "pix-auto") return cyclePrice ?? 0;
|
|
3168
|
-
const trialDays2 = planInfo?.trialDays ?? 0;
|
|
3169
|
-
if (trialDays2 > 0) return 0;
|
|
3170
|
-
return cyclePrice ?? 0;
|
|
3171
|
-
}, [form.method, cyclePrice, planInfo]);
|
|
3172
|
-
const todayAmount = formatBrl(todayCents);
|
|
3173
|
-
const cyclePriceText = cyclePrice !== null ? formatBrl(cyclePrice) : "";
|
|
3174
|
-
const annualSavingsCents = (0, import_react18.useMemo)(() => {
|
|
3175
|
-
if (!planInfo || !planInfo.yearlyPriceCents) return 0;
|
|
3176
|
-
return planInfo.priceCents * 12 - planInfo.yearlyPriceCents;
|
|
3177
|
-
}, [planInfo]);
|
|
3178
|
-
const trialDays = planInfo?.trialDays ?? 7;
|
|
3179
|
-
const cardBrand = detectCardBrand(form.card.number);
|
|
3180
|
-
async function onSubmit(e) {
|
|
3181
|
-
e.preventDefault();
|
|
3182
|
-
const result = await form.submit();
|
|
3183
|
-
if (!result) return;
|
|
3184
|
-
if (form.method === "pix-auto" && result.pix_qr_payload) {
|
|
3185
|
-
try {
|
|
3186
|
-
sessionStorage.setItem(
|
|
3187
|
-
PIX_PAYLOAD_KEY,
|
|
3188
|
-
JSON.stringify({
|
|
3189
|
-
payload: result.pix_qr_payload,
|
|
3190
|
-
base64: result.pix_qr_base64 ?? null,
|
|
3191
|
-
subscriptionId: result.subscription_id,
|
|
3192
|
-
pixAuthorizationId: result.pix_authorization_id ?? null
|
|
3193
|
-
})
|
|
3194
|
-
);
|
|
3195
|
-
} catch {
|
|
3196
|
-
}
|
|
3197
|
-
navigate(result.redirect.replace(/^.*\/app\/[^/]+/, ""));
|
|
3198
|
-
return;
|
|
3199
|
-
}
|
|
3200
|
-
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>");
|
|
3201
3188
|
}
|
|
3202
|
-
return
|
|
3203
|
-
form.emailTaken ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { className: "px-5 pt-4", children: /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { role: "alert", className: "rounded-2xl bg-destructive/10 p-4 text-sm text-destructive border border-destructive/20", children: [
|
|
3204
|
-
"Esse e-mail j\xE1 tem conta nesse app.",
|
|
3205
|
-
" ",
|
|
3206
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)("a", { href: form.loginUrl ?? "/signin", className: "underline font-semibold", children: "Entrar agora" })
|
|
3207
|
-
] }) }) : null,
|
|
3208
|
-
form.error ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { className: "px-5 pt-4", children: /* @__PURE__ */ (0, import_jsx_runtime27.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,
|
|
3209
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { className: "px-5 pt-4", children: form.method === "card" ? /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "rounded-2xl bg-card border-[1.5px] border-foreground p-3.5", children: [
|
|
3210
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "flex items-center gap-2 mb-2", children: [
|
|
3211
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(ShieldIcon, { className: "w-4 h-4" }),
|
|
3212
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { className: "text-sm font-bold", children: "Voc\xEA N\xC3O ser\xE1 cobrada hoje" })
|
|
3213
|
-
] }),
|
|
3214
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "flex justify-between items-baseline text-sm text-muted-foreground", children: [
|
|
3215
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { children: "R$ 0,00 agora" }),
|
|
3216
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { className: "opacity-50", children: "\xB7" }),
|
|
3217
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("span", { children: [
|
|
3218
|
-
monthlyText,
|
|
3219
|
-
"/m\xEAs ap\xF3s ",
|
|
3220
|
-
trialDays,
|
|
3221
|
-
" dias"
|
|
3222
|
-
] })
|
|
3223
|
-
] }),
|
|
3224
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "mt-2.5 text-[11px] text-muted-foreground flex items-center gap-1.5", children: [
|
|
3225
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(BellIcon, { className: "w-2.5 h-2.5" }),
|
|
3226
|
-
"Avisamos por email 2 dias antes da primeira cobran\xE7a"
|
|
3227
|
-
] })
|
|
3228
|
-
] }) : /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "rounded-2xl p-3.5 bg-emerald-50 border-[1.5px] border-emerald-600/60", children: [
|
|
3229
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "flex items-center gap-2 mb-2 text-emerald-900", children: [
|
|
3230
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(ShieldIcon, { className: "w-4 h-4" }),
|
|
3231
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "text-sm font-bold", children: [
|
|
3232
|
-
"Garantia incondicional de ",
|
|
3233
|
-
trialDays,
|
|
3234
|
-
" dias"
|
|
3235
|
-
] })
|
|
3236
|
-
] }),
|
|
3237
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "text-sm text-emerald-900 leading-snug", children: [
|
|
3238
|
-
"Voc\xEA paga ",
|
|
3239
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)("b", { children: todayAmount }),
|
|
3240
|
-
" agora via Pix.",
|
|
3241
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)("br", {}),
|
|
3242
|
-
"N\xE3o gostou em ",
|
|
3243
|
-
trialDays,
|
|
3244
|
-
" dias? Devolvemos ",
|
|
3245
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)("b", { children: "100%" }),
|
|
3246
|
-
" sem perguntas \u2014 direto pelo app."
|
|
3247
|
-
] })
|
|
3248
|
-
] }) }),
|
|
3249
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("section", { className: "px-5 pt-5", children: [
|
|
3250
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)("h2", { className: "font-display text-2xl mb-3.5 leading-tight text-foreground", children: "Quase l\xE1." }),
|
|
3251
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(FieldLabel, { children: "Email" }),
|
|
3252
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
3253
|
-
FieldInput,
|
|
3254
|
-
{
|
|
3255
|
-
type: "email",
|
|
3256
|
-
inputMode: "email",
|
|
3257
|
-
autoComplete: "email",
|
|
3258
|
-
autoCapitalize: "none",
|
|
3259
|
-
autoCorrect: "off",
|
|
3260
|
-
spellCheck: false,
|
|
3261
|
-
placeholder: "seu@email.com",
|
|
3262
|
-
value: form.email,
|
|
3263
|
-
onChange: form.setEmail,
|
|
3264
|
-
onBlur: form.markEmailTouched,
|
|
3265
|
-
error: form.emailError,
|
|
3266
|
-
valid: form.emailStatus === "available"
|
|
3267
|
-
}
|
|
3268
|
-
),
|
|
3269
|
-
!form.emailError && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(FieldHint, { children: form.emailStatus === "checking" ? "Verificando\u2026" : form.emailStatus === "available" ? "\u2713 Dispon\xEDvel" : "Voc\xEA vai usar este email para entrar no app" }),
|
|
3270
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { className: "h-3" }),
|
|
3271
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(FieldLabel, { children: "Nome completo" }),
|
|
3272
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
3273
|
-
FieldInput,
|
|
3274
|
-
{
|
|
3275
|
-
type: "text",
|
|
3276
|
-
autoComplete: "name",
|
|
3277
|
-
placeholder: "como est\xE1 no documento",
|
|
3278
|
-
value: form.name,
|
|
3279
|
-
onChange: form.setName,
|
|
3280
|
-
onBlur: form.markNameTouched,
|
|
3281
|
-
error: form.nameError,
|
|
3282
|
-
valid: !!form.name && !form.nameError
|
|
3283
|
-
}
|
|
3284
|
-
),
|
|
3285
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { className: "h-3" }),
|
|
3286
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(FieldLabel, { children: "CPF" }),
|
|
3287
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
3288
|
-
FieldInput,
|
|
3289
|
-
{
|
|
3290
|
-
type: "text",
|
|
3291
|
-
inputMode: "numeric",
|
|
3292
|
-
placeholder: "000.000.000-00",
|
|
3293
|
-
value: form.cpf,
|
|
3294
|
-
onChange: (v) => form.setCpf(formatCpf(v)),
|
|
3295
|
-
onBlur: form.markCpfTouched,
|
|
3296
|
-
error: form.cpfError,
|
|
3297
|
-
valid: !!form.cpf && !form.cpfError
|
|
3298
|
-
}
|
|
3299
|
-
),
|
|
3300
|
-
form.method === "card" ? /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(import_jsx_runtime27.Fragment, { children: [
|
|
3301
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { className: "h-3" }),
|
|
3302
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(FieldLabel, { children: "Telefone" }),
|
|
3303
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
3304
|
-
FieldInput,
|
|
3305
|
-
{
|
|
3306
|
-
type: "tel",
|
|
3307
|
-
inputMode: "tel",
|
|
3308
|
-
autoComplete: "tel",
|
|
3309
|
-
placeholder: "(11) 99999-9999",
|
|
3310
|
-
value: form.phone,
|
|
3311
|
-
onChange: form.setPhone,
|
|
3312
|
-
onBlur: form.markPhoneTouched,
|
|
3313
|
-
error: form.phoneError,
|
|
3314
|
-
valid: !!form.phone && !form.phoneError
|
|
3315
|
-
}
|
|
3316
|
-
),
|
|
3317
|
-
!form.phoneError && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(FieldHint, { children: "Usado pra confirmar pagamento e tratar disputas." })
|
|
3318
|
-
] }) : null
|
|
3319
|
-
] }),
|
|
3320
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("section", { className: "px-5 pt-5", children: [
|
|
3321
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(FieldLabel, { children: "Forma de pagamento" }),
|
|
3322
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { role: "tablist", className: "flex gap-1.5 bg-muted p-1 rounded-xl", children: [
|
|
3323
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
3324
|
-
TabButton,
|
|
3325
|
-
{
|
|
3326
|
-
active: form.method === "card",
|
|
3327
|
-
onClick: () => form.setMethod("card"),
|
|
3328
|
-
icon: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(CardIcon, { className: "w-3.5 h-3.5" }),
|
|
3329
|
-
label: "Cart\xE3o",
|
|
3330
|
-
subtitle: trialDays > 0 ? `${trialDays} dias gr\xE1tis` : "pague hoje",
|
|
3331
|
-
subtitleActiveClass: "text-emerald-700"
|
|
3332
|
-
}
|
|
3333
|
-
),
|
|
3334
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
3335
|
-
TabButton,
|
|
3336
|
-
{
|
|
3337
|
-
active: form.method === "pix-auto",
|
|
3338
|
-
onClick: () => form.setMethod("pix-auto"),
|
|
3339
|
-
icon: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(PixIcon, { className: "w-3.5 h-3.5" }),
|
|
3340
|
-
label: "Pix",
|
|
3341
|
-
subtitle: `pague hoje \xB7 garantia ${trialDays}d`,
|
|
3342
|
-
subtitleActiveClass: "text-foreground/70"
|
|
3343
|
-
}
|
|
3344
|
-
)
|
|
3345
|
-
] })
|
|
3346
|
-
] }),
|
|
3347
|
-
form.method === "card" ? /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("section", { className: "px-5 pt-3.5", children: [
|
|
3348
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(FieldLabel, { children: "N\xFAmero do cart\xE3o" }),
|
|
3349
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "relative", children: [
|
|
3350
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
3351
|
-
FieldInput,
|
|
3352
|
-
{
|
|
3353
|
-
type: "text",
|
|
3354
|
-
inputMode: "numeric",
|
|
3355
|
-
autoComplete: "cc-number",
|
|
3356
|
-
placeholder: "0000 0000 0000 0000",
|
|
3357
|
-
value: form.card.number,
|
|
3358
|
-
onChange: (v) => form.setCard({ number: formatCardNumber(v) }),
|
|
3359
|
-
style: cardBrand ? { paddingRight: "4.5rem" } : void 0
|
|
3360
|
-
}
|
|
3361
|
-
),
|
|
3362
|
-
cardBrand && /* @__PURE__ */ (0, import_jsx_runtime27.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 })
|
|
3363
|
-
] }),
|
|
3364
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { className: "h-3" }),
|
|
3365
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "flex gap-2.5", children: [
|
|
3366
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "flex-1", children: [
|
|
3367
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(FieldLabel, { children: "Validade" }),
|
|
3368
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
3369
|
-
FieldInput,
|
|
3370
|
-
{
|
|
3371
|
-
type: "text",
|
|
3372
|
-
inputMode: "numeric",
|
|
3373
|
-
autoComplete: "cc-exp",
|
|
3374
|
-
placeholder: "MM/AA",
|
|
3375
|
-
value: expiryMmAa,
|
|
3376
|
-
onChange: (v) => setExpiryMmAa(formatExpiryMmAa(v))
|
|
3377
|
-
}
|
|
3378
|
-
)
|
|
3379
|
-
] }),
|
|
3380
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "flex-1", children: [
|
|
3381
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(FieldLabel, { children: "CVV" }),
|
|
3382
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
3383
|
-
FieldInput,
|
|
3384
|
-
{
|
|
3385
|
-
type: "text",
|
|
3386
|
-
inputMode: "numeric",
|
|
3387
|
-
autoComplete: "cc-csc",
|
|
3388
|
-
placeholder: "3 d\xEDgitos",
|
|
3389
|
-
value: form.card.ccv,
|
|
3390
|
-
onChange: (v) => form.setCard({ ccv: v.replace(/\D/g, "").slice(0, 4) })
|
|
3391
|
-
}
|
|
3392
|
-
)
|
|
3393
|
-
] })
|
|
3394
|
-
] }),
|
|
3395
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { className: "h-3" }),
|
|
3396
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(FieldLabel, { children: "Nome no cart\xE3o" }),
|
|
3397
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
3398
|
-
FieldInput,
|
|
3399
|
-
{
|
|
3400
|
-
type: "text",
|
|
3401
|
-
autoComplete: "cc-name",
|
|
3402
|
-
placeholder: "como est\xE1 no cart\xE3o",
|
|
3403
|
-
value: form.card.holderName,
|
|
3404
|
-
onChange: (v) => form.setCard({ holderName: v })
|
|
3405
|
-
}
|
|
3406
|
-
)
|
|
3407
|
-
] }) : /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("section", { className: "px-5 pt-3.5", children: /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "rounded-2xl bg-card border border-border p-3.5 flex gap-3.5 items-center", children: [
|
|
3408
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.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_runtime27.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_runtime27.jsx)(PixIcon, { className: "w-3.5 h-3.5 text-foreground" }) }) }),
|
|
3409
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "flex-1", children: [
|
|
3410
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { className: "text-xs font-bold uppercase tracking-wider text-muted-foreground", children: "pagamento em segundos" }),
|
|
3411
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "text-sm text-foreground mt-1 leading-snug", children: [
|
|
3412
|
-
"Geramos seu ",
|
|
3413
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)("b", { children: "QR Pix" }),
|
|
3414
|
-
" no pr\xF3ximo passo. Pague pelo app do banco e seu acesso libera ",
|
|
3415
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)("b", { children: "imediatamente" }),
|
|
3416
|
-
"."
|
|
3417
|
-
] })
|
|
3418
|
-
] })
|
|
3419
|
-
] }) }),
|
|
3420
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)("section", { className: "px-5 pt-5", children: /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "bg-muted rounded-2xl p-4", children: [
|
|
3421
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "flex justify-between mb-2.5", children: [
|
|
3422
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { children: [
|
|
3423
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { className: "text-sm font-semibold text-foreground", children: annual ? "Plano Anual" : "Plano Mensal" }),
|
|
3424
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { className: "text-[11px] text-muted-foreground", children: "Coach" })
|
|
3425
|
-
] }),
|
|
3426
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "text-right", children: [
|
|
3427
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "text-sm font-bold text-foreground", children: [
|
|
3428
|
-
cyclePriceText,
|
|
3429
|
-
"/",
|
|
3430
|
-
annual ? "ano" : "m\xEAs"
|
|
3431
|
-
] }),
|
|
3432
|
-
annual && annualSavingsCents > 0 && /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "text-[11px] text-emerald-700 font-semibold", children: [
|
|
3433
|
-
"economia ",
|
|
3434
|
-
formatBrl(annualSavingsCents)
|
|
3435
|
-
] })
|
|
3436
|
-
] })
|
|
3437
|
-
] }),
|
|
3438
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { className: "h-px bg-border my-3" }),
|
|
3439
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "flex justify-between items-baseline", children: [
|
|
3440
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { children: [
|
|
3441
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { className: "text-sm font-bold text-foreground", children: "Voc\xEA paga hoje" }),
|
|
3442
|
-
form.method === "card" && trialDays > 0 && /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "text-[11px] text-muted-foreground mt-0.5", children: [
|
|
3443
|
-
"cobran\xE7a inicia no dia ",
|
|
3444
|
-
trialDays
|
|
3445
|
-
] }),
|
|
3446
|
-
form.method === "pix-auto" && /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "text-[11px] text-emerald-700 mt-0.5 font-semibold", children: [
|
|
3447
|
-
"reembolso garantido at\xE9 o dia ",
|
|
3448
|
-
trialDays
|
|
3449
|
-
] })
|
|
3450
|
-
] }),
|
|
3451
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { className: "text-2xl font-bold font-display tracking-tight text-foreground", children: todayAmount })
|
|
3452
|
-
] })
|
|
3453
|
-
] }) }),
|
|
3454
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { className: "h-4" }),
|
|
3455
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "sticky bottom-0 px-5 pt-3.5 pb-6 bg-gradient-to-b from-transparent to-background", children: [
|
|
3456
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
3457
|
-
"button",
|
|
3458
|
-
{
|
|
3459
|
-
type: "submit",
|
|
3460
|
-
disabled: !form.canSubmit,
|
|
3461
|
-
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",
|
|
3462
|
-
children: form.submitting ? /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(import_jsx_runtime27.Fragment, { children: [
|
|
3463
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(Spinner2, {}),
|
|
3464
|
-
" ",
|
|
3465
|
-
form.method === "pix-auto" ? "Gerando QR\u2026" : "Confirmando\u2026"
|
|
3466
|
-
] }) : form.method === "card" ? /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(import_jsx_runtime27.Fragment, { children: [
|
|
3467
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(LockIcon, { className: "w-3.5 h-3.5" }),
|
|
3468
|
-
" Confirmar e come\xE7ar gr\xE1tis"
|
|
3469
|
-
] }) : /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(import_jsx_runtime27.Fragment, { children: [
|
|
3470
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(PixIcon, { className: "w-3.5 h-3.5" }),
|
|
3471
|
-
" Gerar QR \xB7 pagar ",
|
|
3472
|
-
todayAmount
|
|
3473
|
-
] })
|
|
3474
|
-
}
|
|
3475
|
-
),
|
|
3476
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "text-center mt-2.5 text-xs text-muted-foreground", children: [
|
|
3477
|
-
"Ao continuar, voc\xEA concorda com nossos ",
|
|
3478
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)("u", { children: "Termos" }),
|
|
3479
|
-
". Pagamento seguro Asaas."
|
|
3480
|
-
] }),
|
|
3481
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "mt-3 flex items-center justify-center gap-3.5 text-[11px] text-muted-foreground", children: [
|
|
3482
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("span", { className: "inline-flex items-center gap-1", children: [
|
|
3483
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(LockIcon, { className: "w-2.5 h-2.5 opacity-60" }),
|
|
3484
|
-
" SSL 256-bit"
|
|
3485
|
-
] }),
|
|
3486
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { className: "w-px h-2.5 bg-border" }),
|
|
3487
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { children: "Pagamento via Asaas" }),
|
|
3488
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { className: "w-px h-2.5 bg-border" }),
|
|
3489
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("span", { children: [
|
|
3490
|
-
"Garantia ",
|
|
3491
|
-
trialDays,
|
|
3492
|
-
" dias"
|
|
3493
|
-
] })
|
|
3494
|
-
] })
|
|
3495
|
-
] })
|
|
3496
|
-
] }) });
|
|
3497
|
-
}
|
|
3498
|
-
function FieldLabel({ children }) {
|
|
3499
|
-
return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { className: "text-xs font-semibold uppercase tracking-wide text-muted-foreground mb-1.5", children });
|
|
3189
|
+
return ctx;
|
|
3500
3190
|
}
|
|
3501
|
-
|
|
3502
|
-
|
|
3503
|
-
|
|
3504
|
-
|
|
3505
|
-
|
|
3506
|
-
|
|
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",
|
|
3507
3207
|
{
|
|
3508
|
-
type:
|
|
3509
|
-
|
|
3510
|
-
|
|
3511
|
-
|
|
3512
|
-
|
|
3513
|
-
|
|
3514
|
-
|
|
3515
|
-
|
|
3516
|
-
|
|
3517
|
-
|
|
3518
|
-
|
|
3519
|
-
|
|
3520
|
-
}
|
|
3521
|
-
),
|
|
3522
|
-
props.error ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { className: "mt-1.5 text-xs text-destructive font-medium", children: props.error }) : null
|
|
3523
|
-
] });
|
|
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
|
+
}) });
|
|
3524
3220
|
}
|
|
3525
|
-
|
|
3526
|
-
|
|
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)) });
|
|
3527
3229
|
}
|
|
3528
|
-
|
|
3529
|
-
|
|
3530
|
-
|
|
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",
|
|
3531
3269
|
{
|
|
3532
|
-
|
|
3533
|
-
|
|
3534
|
-
"
|
|
3535
|
-
|
|
3536
|
-
|
|
3537
|
-
|
|
3538
|
-
|
|
3539
|
-
|
|
3540
|
-
|
|
3541
|
-
|
|
3542
|
-
|
|
3543
|
-
|
|
3544
|
-
|
|
3545
|
-
|
|
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
|
+
})
|
|
3546
3301
|
}
|
|
3547
3302
|
);
|
|
3548
3303
|
}
|
|
3549
|
-
|
|
3550
|
-
|
|
3551
|
-
|
|
3552
|
-
|
|
3553
|
-
|
|
3554
|
-
|
|
3555
|
-
|
|
3556
|
-
|
|
3557
|
-
|
|
3558
|
-
|
|
3559
|
-
return /* @__PURE__ */ (0,
|
|
3560
|
-
|
|
3561
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)("path", { d: "M7.5 10V7a4.5 4.5 0 119 0v3" })
|
|
3562
|
-
] });
|
|
3563
|
-
}
|
|
3564
|
-
function ShieldIcon({ className }) {
|
|
3565
|
-
return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.8", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [
|
|
3566
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)("path", { d: "M12 2.5l8 3v6c0 5-3.5 8.5-8 10-4.5-1.5-8-5-8-10v-6l8-3z" }),
|
|
3567
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)("path", { d: "M9 12l2 2 4-4" })
|
|
3568
|
-
] });
|
|
3569
|
-
}
|
|
3570
|
-
function BellIcon({ className }) {
|
|
3571
|
-
return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.8", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [
|
|
3572
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)("path", { d: "M6 17V11a6 6 0 1112 0v6l1.5 2H4.5L6 17z" }),
|
|
3573
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)("path", { d: "M10 21a2 2 0 004 0" })
|
|
3574
|
-
] });
|
|
3575
|
-
}
|
|
3576
|
-
function Spinner2() {
|
|
3577
|
-
return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
3578
|
-
"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,
|
|
3579
3316
|
{
|
|
3580
|
-
|
|
3581
|
-
|
|
3317
|
+
copy,
|
|
3318
|
+
themeClasses,
|
|
3319
|
+
slots,
|
|
3320
|
+
onBeforeCheckout
|
|
3582
3321
|
}
|
|
3583
|
-
);
|
|
3584
|
-
}
|
|
3585
|
-
|
|
3586
|
-
// src/defaults/PixWaitingPageDefault.tsx
|
|
3587
|
-
var import_react19 = require("react");
|
|
3588
|
-
var import_react_router_dom4 = require("react-router-dom");
|
|
3589
|
-
var import_sdk14 = require("@hook-sdk/sdk");
|
|
3590
|
-
var import_jsx_runtime28 = require("react/jsx-runtime");
|
|
3591
|
-
var PIX_PAYLOAD_KEY2 = "hook:paywall:pix-pending";
|
|
3592
|
-
var TIMEOUT_MS = 30 * 60 * 1e3;
|
|
3593
|
-
function readPixPayload() {
|
|
3594
|
-
if (typeof window === "undefined") return null;
|
|
3595
|
-
try {
|
|
3596
|
-
const raw = sessionStorage.getItem(PIX_PAYLOAD_KEY2);
|
|
3597
|
-
if (!raw) return null;
|
|
3598
|
-
return JSON.parse(raw);
|
|
3599
|
-
} catch {
|
|
3600
|
-
return null;
|
|
3601
|
-
}
|
|
3322
|
+
) });
|
|
3602
3323
|
}
|
|
3603
|
-
function
|
|
3604
|
-
|
|
3605
|
-
|
|
3606
|
-
|
|
3607
|
-
|
|
3608
|
-
|
|
3609
|
-
}
|
|
3610
|
-
|
|
3611
|
-
const
|
|
3612
|
-
const
|
|
3613
|
-
const
|
|
3614
|
-
|
|
3615
|
-
|
|
3616
|
-
|
|
3617
|
-
|
|
3618
|
-
|
|
3619
|
-
|
|
3620
|
-
|
|
3621
|
-
|
|
3622
|
-
|
|
3623
|
-
|
|
3624
|
-
|
|
3625
|
-
|
|
3626
|
-
|
|
3627
|
-
|
|
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
|
+
});
|
|
3342
|
+
}
|
|
3343
|
+
if (s.trialDaysCard > 0) {
|
|
3344
|
+
return interp(copy.card.ctaTemplate, { price: priceLabel, days: trialDaysCardLabel });
|
|
3345
|
+
}
|
|
3346
|
+
return copy.cardConsumedTrial ? interp(copy.cardConsumedTrial.ctaTemplate, {
|
|
3347
|
+
price: priceLabel,
|
|
3348
|
+
days: trialDaysCardLabel
|
|
3349
|
+
}) : `Assinar por ${priceLabel}`;
|
|
3628
3350
|
}
|
|
3629
|
-
|
|
3630
|
-
|
|
3631
|
-
|
|
3632
|
-
|
|
3633
|
-
|
|
3634
|
-
|
|
3635
|
-
|
|
3636
|
-
|
|
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;
|
|
3637
3383
|
}
|
|
3638
|
-
|
|
3639
|
-
|
|
3640
|
-
|
|
3641
|
-
|
|
3642
|
-
|
|
3643
|
-
|
|
3644
|
-
|
|
3645
|
-
|
|
3646
|
-
|
|
3647
|
-
|
|
3648
|
-
|
|
3649
|
-
|
|
3650
|
-
|
|
3651
|
-
className: "rounded-xl bg-primary px-6 py-3 text-base font-semibold text-primary-foreground",
|
|
3652
|
-
children: "Tentar novamente"
|
|
3653
|
-
}
|
|
3654
|
-
)
|
|
3655
|
-
] });
|
|
3656
|
-
}
|
|
3657
|
-
return /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: "flex-1 flex flex-col items-center px-6 py-8 bg-background space-y-6", children: [
|
|
3658
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("header", { className: "text-center space-y-2", children: [
|
|
3659
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("h1", { className: "font-display text-2xl text-foreground", children: "Pague o PIX" }),
|
|
3660
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.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." })
|
|
3661
|
-
] }),
|
|
3662
|
-
payload.base64 ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
|
|
3663
|
-
"img",
|
|
3384
|
+
await s.submit();
|
|
3385
|
+
};
|
|
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,
|
|
3664
3397
|
{
|
|
3665
|
-
|
|
3666
|
-
|
|
3667
|
-
|
|
3398
|
+
labels: copy.cycle,
|
|
3399
|
+
cardClassName: themeClasses.cycleCard,
|
|
3400
|
+
cardSelectedClassName: themeClasses.cycleCardSelected,
|
|
3401
|
+
anchorClassName: themeClasses.anchorPrice
|
|
3668
3402
|
}
|
|
3669
|
-
)
|
|
3670
|
-
|
|
3671
|
-
|
|
3403
|
+
),
|
|
3404
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
|
|
3405
|
+
PaywallMethodTabs,
|
|
3672
3406
|
{
|
|
3673
|
-
|
|
3674
|
-
className:
|
|
3675
|
-
|
|
3407
|
+
labels: { "pix-auto": copy.pix.tabLabel, card: copy.card.tabLabel },
|
|
3408
|
+
className: themeClasses.tabs,
|
|
3409
|
+
tabClassName: themeClasses.tab,
|
|
3410
|
+
tabActiveClassName: themeClasses.tabActive
|
|
3676
3411
|
}
|
|
3677
|
-
)
|
|
3678
|
-
/* @__PURE__ */ (0,
|
|
3679
|
-
|
|
3680
|
-
|
|
3681
|
-
|
|
3682
|
-
|
|
3683
|
-
|
|
3684
|
-
|
|
3685
|
-
|
|
3686
|
-
|
|
3687
|
-
|
|
3688
|
-
|
|
3689
|
-
|
|
3690
|
-
|
|
3691
|
-
|
|
3692
|
-
|
|
3693
|
-
const [email, setEmail] = (0, import_react20.useState)("");
|
|
3694
|
-
const [password, setPassword] = (0, import_react20.useState)("");
|
|
3695
|
-
const [submitting, setSubmitting] = (0, import_react20.useState)(false);
|
|
3696
|
-
const [error, setError] = (0, import_react20.useState)(null);
|
|
3697
|
-
const [touchedEmail, setTouchedEmail] = (0, import_react20.useState)(false);
|
|
3698
|
-
const [touchedPassword, setTouchedPassword] = (0, import_react20.useState)(false);
|
|
3699
|
-
const [formSubmitAttempted, setFormSubmitAttempted] = (0, import_react20.useState)(false);
|
|
3700
|
-
const validateEmail = (0, import_react20.useMemo)(() => {
|
|
3701
|
-
if (email.length === 0) return null;
|
|
3702
|
-
if (!EMAIL_RE2.test(email)) return "Formato de e-mail inv\xE1lido.";
|
|
3703
|
-
return null;
|
|
3704
|
-
}, [email]);
|
|
3705
|
-
const validatePassword = (0, import_react20.useMemo)(() => {
|
|
3706
|
-
if (password.length === 0) return null;
|
|
3707
|
-
if (password.length < MIN_PASSWORD) return `M\xEDnimo de ${MIN_PASSWORD} caracteres.`;
|
|
3708
|
-
return null;
|
|
3709
|
-
}, [password]);
|
|
3710
|
-
const emailError = touchedEmail || formSubmitAttempted ? validateEmail : null;
|
|
3711
|
-
const passwordError = touchedPassword || formSubmitAttempted ? validatePassword : null;
|
|
3712
|
-
const canSubmit = email.length > 0 && password.length >= MIN_PASSWORD && validateEmail === null && validatePassword === null && !submitting;
|
|
3713
|
-
const submit = (0, import_react20.useCallback)(async () => {
|
|
3714
|
-
setFormSubmitAttempted(true);
|
|
3715
|
-
if (!canSubmit) return false;
|
|
3716
|
-
setSubmitting(true);
|
|
3717
|
-
setError(null);
|
|
3718
|
-
try {
|
|
3719
|
-
await auth.login({ email, password });
|
|
3720
|
-
return true;
|
|
3721
|
-
} catch (err) {
|
|
3722
|
-
setError(mapSdkError(err));
|
|
3723
|
-
return false;
|
|
3724
|
-
} finally {
|
|
3725
|
-
setSubmitting(false);
|
|
3726
|
-
}
|
|
3727
|
-
}, [auth, email, password, canSubmit]);
|
|
3728
|
-
return {
|
|
3729
|
-
email,
|
|
3730
|
-
setEmail,
|
|
3731
|
-
emailError,
|
|
3732
|
-
markEmailTouched: () => setTouchedEmail(true),
|
|
3733
|
-
password,
|
|
3734
|
-
setPassword,
|
|
3735
|
-
passwordError,
|
|
3736
|
-
markPasswordTouched: () => setTouchedPassword(true),
|
|
3737
|
-
formSubmitAttempted,
|
|
3738
|
-
submit,
|
|
3739
|
-
submitting,
|
|
3740
|
-
canSubmit,
|
|
3741
|
-
error,
|
|
3742
|
-
loginWithGoogle: () => auth.loginWithGoogle()
|
|
3743
|
-
};
|
|
3744
|
-
}
|
|
3745
|
-
|
|
3746
|
-
// src/hooks/useSignupForm.ts
|
|
3747
|
-
var import_react21 = require("react");
|
|
3748
|
-
var import_sdk16 = require("@hook-sdk/sdk");
|
|
3749
|
-
var EMAIL_RE3 = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
3750
|
-
var MIN_PASSWORD2 = 8;
|
|
3751
|
-
function useSignupForm() {
|
|
3752
|
-
const { auth } = (0, import_sdk16.useHook)();
|
|
3753
|
-
const [name, setName] = (0, import_react21.useState)("");
|
|
3754
|
-
const [email, setEmail] = (0, import_react21.useState)("");
|
|
3755
|
-
const [password, setPassword] = (0, import_react21.useState)("");
|
|
3756
|
-
const [submitting, setSubmitting] = (0, import_react21.useState)(false);
|
|
3757
|
-
const [error, setError] = (0, import_react21.useState)(null);
|
|
3758
|
-
const [touchedName, setTouchedName] = (0, import_react21.useState)(false);
|
|
3759
|
-
const [touchedEmail, setTouchedEmail] = (0, import_react21.useState)(false);
|
|
3760
|
-
const [touchedPassword, setTouchedPassword] = (0, import_react21.useState)(false);
|
|
3761
|
-
const [formSubmitAttempted, setFormSubmitAttempted] = (0, import_react21.useState)(false);
|
|
3762
|
-
const validateName = (0, import_react21.useMemo)(() => {
|
|
3763
|
-
if (name.length === 0) return null;
|
|
3764
|
-
if (name.trim().length < 2) return "Nome muito curto.";
|
|
3765
|
-
return null;
|
|
3766
|
-
}, [name]);
|
|
3767
|
-
const validateEmail = (0, import_react21.useMemo)(() => {
|
|
3768
|
-
if (email.length === 0) return null;
|
|
3769
|
-
if (!EMAIL_RE3.test(email)) return "Formato de e-mail inv\xE1lido.";
|
|
3770
|
-
return null;
|
|
3771
|
-
}, [email]);
|
|
3772
|
-
const validatePassword = (0, import_react21.useMemo)(() => {
|
|
3773
|
-
if (password.length === 0) return null;
|
|
3774
|
-
if (password.length < MIN_PASSWORD2) return `M\xEDnimo de ${MIN_PASSWORD2} caracteres.`;
|
|
3775
|
-
return null;
|
|
3776
|
-
}, [password]);
|
|
3777
|
-
const nameError = touchedName || formSubmitAttempted ? validateName : null;
|
|
3778
|
-
const emailError = touchedEmail || formSubmitAttempted ? validateEmail : null;
|
|
3779
|
-
const passwordError = touchedPassword || formSubmitAttempted ? validatePassword : null;
|
|
3780
|
-
const canSubmit = name.trim().length >= 2 && email.length > 0 && password.length >= MIN_PASSWORD2 && validateName === null && validateEmail === null && validatePassword === null && !submitting;
|
|
3781
|
-
const submit = (0, import_react21.useCallback)(async () => {
|
|
3782
|
-
setFormSubmitAttempted(true);
|
|
3783
|
-
if (!canSubmit) return false;
|
|
3784
|
-
setSubmitting(true);
|
|
3785
|
-
setError(null);
|
|
3786
|
-
try {
|
|
3787
|
-
await auth.signup({ name, email, password });
|
|
3788
|
-
return true;
|
|
3789
|
-
} catch (err) {
|
|
3790
|
-
setError(mapSdkError(err));
|
|
3791
|
-
return false;
|
|
3792
|
-
} finally {
|
|
3793
|
-
setSubmitting(false);
|
|
3794
|
-
}
|
|
3795
|
-
}, [auth, name, email, password, canSubmit]);
|
|
3796
|
-
return {
|
|
3797
|
-
name,
|
|
3798
|
-
setName,
|
|
3799
|
-
nameError,
|
|
3800
|
-
markNameTouched: () => setTouchedName(true),
|
|
3801
|
-
email,
|
|
3802
|
-
setEmail,
|
|
3803
|
-
emailError,
|
|
3804
|
-
markEmailTouched: () => setTouchedEmail(true),
|
|
3805
|
-
password,
|
|
3806
|
-
setPassword,
|
|
3807
|
-
passwordError,
|
|
3808
|
-
markPasswordTouched: () => setTouchedPassword(true),
|
|
3809
|
-
formSubmitAttempted,
|
|
3810
|
-
submit,
|
|
3811
|
-
submitting,
|
|
3812
|
-
canSubmit,
|
|
3813
|
-
error,
|
|
3814
|
-
loginWithGoogle: () => auth.loginWithGoogle()
|
|
3815
|
-
};
|
|
3816
|
-
}
|
|
3817
|
-
|
|
3818
|
-
// src/hooks/useForgotForm.ts
|
|
3819
|
-
var import_react22 = require("react");
|
|
3820
|
-
var import_sdk17 = require("@hook-sdk/sdk");
|
|
3821
|
-
var EMAIL_RE4 = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
3822
|
-
function useForgotForm() {
|
|
3823
|
-
const { auth } = (0, import_sdk17.useHook)();
|
|
3824
|
-
const [email, setEmail] = (0, import_react22.useState)("");
|
|
3825
|
-
const [submitting, setSubmitting] = (0, import_react22.useState)(false);
|
|
3826
|
-
const [sent, setSent] = (0, import_react22.useState)(false);
|
|
3827
|
-
const [error, setError] = (0, import_react22.useState)(null);
|
|
3828
|
-
const [touchedEmail, setTouchedEmail] = (0, import_react22.useState)(false);
|
|
3829
|
-
const [formSubmitAttempted, setFormSubmitAttempted] = (0, import_react22.useState)(false);
|
|
3830
|
-
const validateEmail = (0, import_react22.useMemo)(() => {
|
|
3831
|
-
if (email.length === 0) return null;
|
|
3832
|
-
if (!EMAIL_RE4.test(email)) return "Formato de e-mail inv\xE1lido.";
|
|
3833
|
-
return null;
|
|
3834
|
-
}, [email]);
|
|
3835
|
-
const emailError = touchedEmail || formSubmitAttempted ? validateEmail : null;
|
|
3836
|
-
const canSubmit = email.length > 0 && validateEmail === 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.forgot({ email });
|
|
3844
|
-
setSent(true);
|
|
3845
|
-
return true;
|
|
3846
|
-
} catch (err) {
|
|
3847
|
-
setError(mapSdkError(err));
|
|
3848
|
-
return false;
|
|
3849
|
-
} finally {
|
|
3850
|
-
setSubmitting(false);
|
|
3851
|
-
}
|
|
3852
|
-
}, [auth, email, canSubmit]);
|
|
3853
|
-
return {
|
|
3854
|
-
email,
|
|
3855
|
-
setEmail,
|
|
3856
|
-
emailError,
|
|
3857
|
-
markEmailTouched: () => setTouchedEmail(true),
|
|
3858
|
-
formSubmitAttempted,
|
|
3859
|
-
submit,
|
|
3860
|
-
submitting,
|
|
3861
|
-
canSubmit,
|
|
3862
|
-
sent,
|
|
3863
|
-
error
|
|
3864
|
-
};
|
|
3865
|
-
}
|
|
3866
|
-
|
|
3867
|
-
// src/hooks/useResetForm.ts
|
|
3868
|
-
var import_react23 = require("react");
|
|
3869
|
-
var import_sdk18 = require("@hook-sdk/sdk");
|
|
3870
|
-
var MIN_PASSWORD3 = 12;
|
|
3871
|
-
function useResetForm() {
|
|
3872
|
-
const { auth } = (0, import_sdk18.useHook)();
|
|
3873
|
-
const [token, setToken] = (0, import_react23.useState)(null);
|
|
3874
|
-
const [password, setPassword] = (0, import_react23.useState)("");
|
|
3875
|
-
const [confirm, setConfirm] = (0, import_react23.useState)("");
|
|
3876
|
-
const [submitting, setSubmitting] = (0, import_react23.useState)(false);
|
|
3877
|
-
const [done, setDone] = (0, import_react23.useState)(false);
|
|
3878
|
-
const [error, setError] = (0, import_react23.useState)(null);
|
|
3879
|
-
const [touchedPassword, setTouchedPassword] = (0, import_react23.useState)(false);
|
|
3880
|
-
const [touchedConfirm, setTouchedConfirm] = (0, import_react23.useState)(false);
|
|
3881
|
-
const [formSubmitAttempted, setFormSubmitAttempted] = (0, import_react23.useState)(false);
|
|
3882
|
-
(0, import_react23.useEffect)(() => {
|
|
3883
|
-
if (typeof window === "undefined") return;
|
|
3884
|
-
const params = new URLSearchParams(window.location.search);
|
|
3885
|
-
const t = params.get("token");
|
|
3886
|
-
setToken(t && t.length > 0 ? t : null);
|
|
3887
|
-
}, []);
|
|
3888
|
-
const validatePassword = (0, import_react23.useMemo)(() => {
|
|
3889
|
-
if (password.length === 0) return null;
|
|
3890
|
-
if (password.length < MIN_PASSWORD3) return `M\xEDnimo de ${MIN_PASSWORD3} caracteres.`;
|
|
3891
|
-
return null;
|
|
3892
|
-
}, [password]);
|
|
3893
|
-
const validateConfirm = (0, import_react23.useMemo)(() => {
|
|
3894
|
-
if (confirm.length === 0) return null;
|
|
3895
|
-
if (confirm !== password) return "Senhas n\xE3o coincidem.";
|
|
3896
|
-
return null;
|
|
3897
|
-
}, [confirm, password]);
|
|
3898
|
-
const passwordError = touchedPassword || formSubmitAttempted ? validatePassword : null;
|
|
3899
|
-
const confirmError = touchedConfirm || formSubmitAttempted ? validateConfirm : null;
|
|
3900
|
-
const canSubmit = token !== null && password.length >= MIN_PASSWORD3 && confirm === password && validatePassword === null && validateConfirm === null && !submitting && !done;
|
|
3901
|
-
const submit = (0, import_react23.useCallback)(async () => {
|
|
3902
|
-
setFormSubmitAttempted(true);
|
|
3903
|
-
if (!canSubmit || token === null) return;
|
|
3904
|
-
setSubmitting(true);
|
|
3905
|
-
setError(null);
|
|
3906
|
-
try {
|
|
3907
|
-
await auth.reset({ token, newPassword: password });
|
|
3908
|
-
setDone(true);
|
|
3909
|
-
if (typeof window !== "undefined") {
|
|
3910
|
-
const url = new URL(window.location.href);
|
|
3911
|
-
url.searchParams.delete("token");
|
|
3912
|
-
url.searchParams.delete("screen");
|
|
3913
|
-
window.history.replaceState({}, "", url.toString());
|
|
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
|
|
3914
3428
|
}
|
|
3915
|
-
|
|
3916
|
-
|
|
3917
|
-
|
|
3918
|
-
|
|
3919
|
-
|
|
3920
|
-
|
|
3921
|
-
|
|
3922
|
-
|
|
3923
|
-
|
|
3924
|
-
|
|
3925
|
-
|
|
3926
|
-
|
|
3927
|
-
|
|
3928
|
-
|
|
3929
|
-
|
|
3930
|
-
|
|
3931
|
-
|
|
3932
|
-
|
|
3933
|
-
|
|
3934
|
-
canSubmit,
|
|
3935
|
-
done,
|
|
3936
|
-
error
|
|
3937
|
-
};
|
|
3938
|
-
}
|
|
3939
|
-
|
|
3940
|
-
// src/utils/price.ts
|
|
3941
|
-
function formatBRL(cents) {
|
|
3942
|
-
if (cents === null || cents === void 0) return "";
|
|
3943
|
-
const reais = cents / 100;
|
|
3944
|
-
return new Intl.NumberFormat("pt-BR", {
|
|
3945
|
-
style: "currency",
|
|
3946
|
-
currency: "BRL"
|
|
3947
|
-
}).format(reais);
|
|
3948
|
-
}
|
|
3949
|
-
function monthlyFromYearly(yearlyCents) {
|
|
3950
|
-
if (yearlyCents === null || yearlyCents === void 0) return 0;
|
|
3951
|
-
return Math.round(yearlyCents / 12);
|
|
3952
|
-
}
|
|
3953
|
-
function dailyFromYearly(yearlyCents) {
|
|
3954
|
-
if (yearlyCents === null || yearlyCents === void 0) return 0;
|
|
3955
|
-
return Math.round(yearlyCents / 365);
|
|
3956
|
-
}
|
|
3957
|
-
function computeAnchorCents(baseCents, multiplier) {
|
|
3958
|
-
if (multiplier === null || multiplier === void 0) return null;
|
|
3959
|
-
if (!Number.isFinite(multiplier)) return null;
|
|
3960
|
-
if (multiplier <= 1) return null;
|
|
3961
|
-
return Math.round(baseCents * multiplier);
|
|
3962
|
-
}
|
|
3963
|
-
function discountPercent(anchorCents, realCents) {
|
|
3964
|
-
if (anchorCents <= realCents) return 0;
|
|
3965
|
-
return Math.floor((anchorCents - realCents) / anchorCents * 100);
|
|
3966
|
-
}
|
|
3967
|
-
|
|
3968
|
-
// src/hooks/useAuthPrimitives.ts
|
|
3969
|
-
var import_react24 = require("react");
|
|
3970
|
-
var import_sdk19 = require("@hook-sdk/sdk");
|
|
3971
|
-
var warned = false;
|
|
3972
|
-
function useAuthPrimitives() {
|
|
3973
|
-
const { auth } = (0, import_sdk19.useHook)();
|
|
3974
|
-
(0, import_react24.useEffect)(() => {
|
|
3975
|
-
if (!warned && process.env.NODE_ENV !== "production") {
|
|
3976
|
-
warned = true;
|
|
3977
|
-
console.warn(
|
|
3978
|
-
"[@hook-sdk/template] useAuthPrimitives() \xE9 escape hatch. Pra login/signup/forgot, use useLoginForm/useSignupForm/useForgotForm. Docs: docs/19-golden-template.md#escape-hatch"
|
|
3979
|
-
);
|
|
3980
|
-
}
|
|
3981
|
-
}, []);
|
|
3982
|
-
return {
|
|
3983
|
-
login: auth.login,
|
|
3984
|
-
signup: auth.signup,
|
|
3985
|
-
logout: auth.logout,
|
|
3986
|
-
logoutAll: auth.logoutAll,
|
|
3987
|
-
forgot: auth.forgot,
|
|
3988
|
-
resendVerify: auth.resendVerify,
|
|
3989
|
-
changePassword: auth.changePassword,
|
|
3990
|
-
changeEmail: auth.changeEmail,
|
|
3991
|
-
refresh: auth.refresh
|
|
3992
|
-
};
|
|
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
|
+
] });
|
|
3993
3448
|
}
|
|
3994
|
-
|
|
3995
|
-
|
|
3996
|
-
var import_sdk20 = require("@hook-sdk/sdk");
|
|
3997
|
-
function useAuth() {
|
|
3998
|
-
const { user, authStatus, auth } = (0, import_sdk20.useHook)();
|
|
3999
|
-
return {
|
|
4000
|
-
user,
|
|
4001
|
-
authStatus,
|
|
4002
|
-
refresh: auth.refresh
|
|
4003
|
-
};
|
|
3449
|
+
function interp(tpl, vars) {
|
|
3450
|
+
return tpl.replace(/\{(\w+)\}/g, (_m, k) => vars[k] ?? "");
|
|
4004
3451
|
}
|
|
4005
|
-
|
|
4006
|
-
// src/index.ts
|
|
4007
|
-
var import_sdk25 = require("@hook-sdk/sdk");
|
|
4008
|
-
|
|
4009
|
-
// src/hooks/useSubscription.ts
|
|
4010
|
-
var import_sdk21 = require("@hook-sdk/sdk");
|
|
4011
|
-
function useSubscription() {
|
|
4012
|
-
const { subscription } = (0, import_sdk21.useHook)();
|
|
3452
|
+
function interpolateCopy(m, price, days) {
|
|
4013
3453
|
return {
|
|
4014
|
-
|
|
3454
|
+
tabLabel: m.tabLabel,
|
|
3455
|
+
bodyRows: m.bodyRows.map((r) => interp(r, { price, days })),
|
|
3456
|
+
ctaTemplate: m.ctaTemplate,
|
|
3457
|
+
switchHint: m.switchHint
|
|
4015
3458
|
};
|
|
4016
3459
|
}
|
|
4017
3460
|
|
|
4018
|
-
// src/
|
|
4019
|
-
var
|
|
4020
|
-
|
|
4021
|
-
|
|
4022
|
-
|
|
4023
|
-
|
|
4024
|
-
|
|
4025
|
-
|
|
4026
|
-
|
|
4027
|
-
|
|
4028
|
-
|
|
4029
|
-
|
|
4030
|
-
|
|
4031
|
-
|
|
4032
|
-
|
|
4033
|
-
|
|
4034
|
-
|
|
4035
|
-
|
|
4036
|
-
|
|
4037
|
-
|
|
4038
|
-
|
|
4039
|
-
|
|
4040
|
-
|
|
4041
|
-
|
|
4042
|
-
|
|
4043
|
-
|
|
4044
|
-
|
|
4045
|
-
|
|
4046
|
-
|
|
4047
|
-
|
|
4048
|
-
}, [r]);
|
|
4049
|
-
const setFallbacks = (0, import_react25.useCallback)(async (items) => {
|
|
4050
|
-
return r.setFallbacks(items);
|
|
4051
|
-
}, [r]);
|
|
4052
|
-
return { reminders, loading, setReminder, deleteReminder, schedule, setFallbacks };
|
|
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 })
|
|
3490
|
+
] });
|
|
4053
3491
|
}
|
|
4054
3492
|
|
|
4055
|
-
// src/
|
|
4056
|
-
var
|
|
4057
|
-
|
|
4058
|
-
|
|
4059
|
-
|
|
4060
|
-
const id = `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
4061
|
-
setItems((prev) => [...prev, { id, message, kind }]);
|
|
4062
|
-
setTimeout(() => {
|
|
4063
|
-
setItems((prev) => prev.filter((t) => t.id !== id));
|
|
4064
|
-
}, 4e3);
|
|
4065
|
-
}, []);
|
|
4066
|
-
const dismiss = (0, import_react26.useCallback)((id) => {
|
|
4067
|
-
setItems((prev) => prev.filter((t) => t.id !== id));
|
|
4068
|
-
}, []);
|
|
4069
|
-
return { items, show, dismiss };
|
|
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 });
|
|
4070
3498
|
}
|
|
4071
3499
|
|
|
4072
|
-
// src/
|
|
4073
|
-
var
|
|
4074
|
-
var
|
|
4075
|
-
function
|
|
4076
|
-
|
|
4077
|
-
|
|
4078
|
-
|
|
4079
|
-
|
|
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
|
|
3513
|
+
}) {
|
|
3514
|
+
if (render) {
|
|
3515
|
+
return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("div", { className, children: render({ src, headline }) });
|
|
3516
|
+
}
|
|
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
|
+
);
|
|
4080
3542
|
}
|
|
4081
|
-
|
|
4082
|
-
|
|
3543
|
+
|
|
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 });
|
|
4083
3550
|
}
|
|
4084
3551
|
|
|
4085
|
-
// src/
|
|
4086
|
-
var
|
|
4087
|
-
var
|
|
4088
|
-
|
|
4089
|
-
|
|
4090
|
-
|
|
4091
|
-
|
|
4092
|
-
|
|
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
|
|
4093
3564
|
}) {
|
|
4094
|
-
|
|
4095
|
-
|
|
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 }) });
|
|
4096
3574
|
}
|
|
4097
|
-
|
|
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 });
|
|
4098
3578
|
}
|
|
4099
3579
|
|
|
4100
|
-
// src/
|
|
4101
|
-
var
|
|
4102
|
-
var
|
|
4103
|
-
|
|
4104
|
-
|
|
4105
|
-
|
|
4106
|
-
|
|
4107
|
-
|
|
4108
|
-
|
|
4109
|
-
|
|
4110
|
-
|
|
4111
|
-
|
|
4112
|
-
|
|
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;
|
|
3590
|
+
}
|
|
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;
|
|
3598
|
+
}
|
|
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) });
|
|
4113
3646
|
}
|
|
4114
|
-
|
|
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 });
|
|
4115
3649
|
}
|
|
4116
3650
|
|
|
4117
|
-
// src/
|
|
4118
|
-
var
|
|
4119
|
-
|
|
4120
|
-
|
|
4121
|
-
|
|
4122
|
-
|
|
4123
|
-
|
|
4124
|
-
|
|
4125
|
-
|
|
4126
|
-
|
|
4127
|
-
screens,
|
|
4128
|
-
onComplete,
|
|
4129
|
-
persistKey
|
|
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
|
|
4130
3661
|
}) {
|
|
4131
|
-
|
|
4132
|
-
|
|
4133
|
-
draftRef.current = draft;
|
|
4134
|
-
const idx = readPersistedStepIdx(draft);
|
|
4135
|
-
const clampedIdx = Math.min(Math.max(idx, 0), Math.max(steps.length - 1, 0));
|
|
4136
|
-
const setIdx = (0, import_react28.useCallback)(
|
|
4137
|
-
(n) => {
|
|
4138
|
-
setDraft((prev) => {
|
|
4139
|
-
const prevIdx = readPersistedStepIdx(prev);
|
|
4140
|
-
const nextIdx = typeof n === "function" ? n(prevIdx) : n;
|
|
4141
|
-
return { ...prev, [CURRENT_STEP_FIELD]: nextIdx };
|
|
4142
|
-
});
|
|
4143
|
-
},
|
|
4144
|
-
[setDraft]
|
|
4145
|
-
);
|
|
4146
|
-
const setValue = (0, import_react28.useCallback)(
|
|
4147
|
-
(patch) => {
|
|
4148
|
-
draftRef.current = { ...draftRef.current, ...patch };
|
|
4149
|
-
setDraft((prev) => ({ ...prev, ...patch }));
|
|
4150
|
-
},
|
|
4151
|
-
[setDraft]
|
|
4152
|
-
);
|
|
4153
|
-
const step = steps[clampedIdx];
|
|
4154
|
-
const hookCtx = (0, import_sdk23.useHook)();
|
|
4155
|
-
const track2 = typeof hookCtx.track === "function" ? hookCtx.track : void 0;
|
|
4156
|
-
(0, import_react28.useEffect)(() => {
|
|
4157
|
-
if (status.loading) return;
|
|
4158
|
-
if (!step) return;
|
|
4159
|
-
if (!track2) return;
|
|
4160
|
-
track2("onboarding_step_viewed", {
|
|
4161
|
-
step: step.id,
|
|
4162
|
-
step_index: clampedIdx,
|
|
4163
|
-
total_steps: steps.length
|
|
4164
|
-
});
|
|
4165
|
-
}, [step?.id, clampedIdx, steps.length, status.loading, track2]);
|
|
4166
|
-
const valid = (0, import_react28.useMemo)(
|
|
4167
|
-
() => step ? (step.validates ?? []).every((field) => isFilled(draft[field])) : false,
|
|
4168
|
-
[draft, step]
|
|
4169
|
-
);
|
|
4170
|
-
const next = (0, import_react28.useCallback)(() => {
|
|
4171
|
-
if (!step) return;
|
|
4172
|
-
const current = draftRef.current;
|
|
4173
|
-
const validNow = (step.validates ?? []).every((field) => isFilled(current[field]));
|
|
4174
|
-
if (!validNow) return;
|
|
4175
|
-
if (clampedIdx + 1 >= steps.length) {
|
|
4176
|
-
onComplete(current);
|
|
4177
|
-
} else {
|
|
4178
|
-
setIdx(clampedIdx + 1);
|
|
4179
|
-
}
|
|
4180
|
-
}, [clampedIdx, onComplete, step, steps.length, setIdx]);
|
|
4181
|
-
const prevStep = (0, import_react28.useCallback)(() => setIdx((i) => Math.max(0, i - 1)), [setIdx]);
|
|
4182
|
-
const ctx = (0, import_react28.useMemo)(
|
|
4183
|
-
() => ({
|
|
4184
|
-
stepIndex: clampedIdx,
|
|
4185
|
-
totalSteps: steps.length,
|
|
4186
|
-
value: draft,
|
|
4187
|
-
setValue,
|
|
4188
|
-
valid,
|
|
4189
|
-
next,
|
|
4190
|
-
prev: prevStep
|
|
4191
|
-
}),
|
|
4192
|
-
[clampedIdx, steps.length, draft, setValue, valid, next, prevStep]
|
|
4193
|
-
);
|
|
4194
|
-
if (status.loading) {
|
|
4195
|
-
return null;
|
|
4196
|
-
}
|
|
4197
|
-
if (!step) {
|
|
4198
|
-
throw new Error(
|
|
4199
|
-
`[hook-template] OnboardingFlow: step index ${clampedIdx} out of range (steps.length=${steps.length})`
|
|
4200
|
-
);
|
|
3662
|
+
if (render) {
|
|
3663
|
+
return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("div", { className, children: render({ items }) });
|
|
4201
3664
|
}
|
|
4202
|
-
|
|
4203
|
-
|
|
4204
|
-
throw new Error(
|
|
4205
|
-
`[hook-template] OnboardingFlow: missing screen component for step '${step.id}' (expected key '${step.screen}' in screens prop)`
|
|
4206
|
-
);
|
|
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)) });
|
|
4207
3667
|
}
|
|
4208
|
-
return /* @__PURE__ */ (0,
|
|
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)) });
|
|
4209
3672
|
}
|
|
4210
3673
|
|
|
4211
|
-
// src/
|
|
4212
|
-
|
|
4213
|
-
|
|
4214
|
-
|
|
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
|
+
] }) });
|
|
4215
3696
|
}
|
|
4216
3697
|
|
|
4217
|
-
// src/components/paywall/
|
|
4218
|
-
var
|
|
4219
|
-
var
|
|
4220
|
-
|
|
4221
|
-
|
|
4222
|
-
|
|
4223
|
-
|
|
4224
|
-
|
|
4225
|
-
|
|
4226
|
-
|
|
4227
|
-
|
|
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 }) });
|
|
3711
|
+
}
|
|
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
|
+
] });
|
|
4228
3721
|
}
|
|
4229
3722
|
|
|
4230
|
-
// src/components/paywall/
|
|
4231
|
-
var
|
|
4232
|
-
|
|
4233
|
-
|
|
4234
|
-
|
|
4235
|
-
|
|
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({
|
|
3727
|
+
className,
|
|
3728
|
+
render
|
|
3729
|
+
}) {
|
|
3730
|
+
const { anchorPriceCents, cycle } = usePaywallContext();
|
|
3731
|
+
if (anchorPriceCents === null || anchorPriceCents === void 0 || anchorPriceCents <= 0) {
|
|
3732
|
+
return null;
|
|
4236
3733
|
}
|
|
4237
|
-
|
|
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 });
|
|
4238
3741
|
}
|
|
4239
3742
|
|
|
4240
|
-
// src/components/paywall/
|
|
4241
|
-
var
|
|
4242
|
-
|
|
4243
|
-
|
|
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,
|
|
4244
3756
|
className,
|
|
4245
|
-
|
|
4246
|
-
|
|
3757
|
+
cardClassName,
|
|
3758
|
+
avatarClassName,
|
|
3759
|
+
quoteClassName,
|
|
3760
|
+
nameClassName,
|
|
3761
|
+
starsClassName,
|
|
3762
|
+
renderItem
|
|
4247
3763
|
}) {
|
|
4248
|
-
const
|
|
4249
|
-
|
|
4250
|
-
|
|
4251
|
-
|
|
4252
|
-
|
|
4253
|
-
|
|
4254
|
-
|
|
4255
|
-
|
|
4256
|
-
|
|
4257
|
-
|
|
4258
|
-
|
|
4259
|
-
|
|
4260
|
-
|
|
4261
|
-
|
|
4262
|
-
|
|
4263
|
-
|
|
4264
|
-
|
|
4265
|
-
|
|
4266
|
-
|
|
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);
|
|
4267
3794
|
}) });
|
|
4268
3795
|
}
|
|
4269
3796
|
|
|
4270
|
-
// src/components/paywall/
|
|
4271
|
-
var
|
|
4272
|
-
|
|
4273
|
-
|
|
4274
|
-
|
|
4275
|
-
|
|
4276
|
-
|
|
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
|
+
}) });
|
|
4277
3823
|
}
|
|
4278
3824
|
|
|
4279
|
-
// src/components/paywall/
|
|
4280
|
-
var
|
|
4281
|
-
var
|
|
4282
|
-
|
|
4283
|
-
"
|
|
4284
|
-
|
|
4285
|
-
cardSelected: "border-2 border-yellow-400/80 ring-2 ring-yellow-400/20"
|
|
4286
|
-
},
|
|
4287
|
-
"pink-pill": {
|
|
4288
|
-
card: "rounded-2xl",
|
|
4289
|
-
cardSelected: "border-2 border-pink-500"
|
|
4290
|
-
}
|
|
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"
|
|
4291
3831
|
};
|
|
4292
|
-
function
|
|
4293
|
-
|
|
3832
|
+
function PaywallFinePrint({
|
|
3833
|
+
template,
|
|
4294
3834
|
className,
|
|
4295
|
-
cardClassName,
|
|
4296
|
-
cardSelectedClassName,
|
|
4297
|
-
anchorClassName,
|
|
4298
|
-
variant = "default",
|
|
4299
3835
|
render
|
|
4300
3836
|
}) {
|
|
4301
|
-
const
|
|
4302
|
-
|
|
4303
|
-
|
|
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(" ");
|
|
4304
3848
|
if (render) {
|
|
4305
|
-
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
|
+
}) });
|
|
4306
3855
|
}
|
|
4307
|
-
|
|
4308
|
-
|
|
4309
|
-
const composedCardClassName = [v.card, cardClassName].filter(Boolean).join(" ");
|
|
4310
|
-
const composedCardSelectedClassName = [v.cardSelected, cardSelectedClassName].filter(Boolean).join(" ");
|
|
4311
|
-
const monthlyCents = plan?.monthlyCents ?? 0;
|
|
4312
|
-
const yearlyCents = plan?.yearlyCents ?? 0;
|
|
4313
|
-
const anchorMonthly = plan?.anchorMonthlyCents ?? null;
|
|
4314
|
-
const anchorYearly = plan?.anchorYearlyCents ?? null;
|
|
4315
|
-
return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
|
|
4316
|
-
"div",
|
|
4317
|
-
{
|
|
4318
|
-
role: "radiogroup",
|
|
4319
|
-
"aria-label": "Ciclo de cobran\xE7a",
|
|
4320
|
-
className: ["flex flex-row gap-2", className].filter(Boolean).join(" "),
|
|
4321
|
-
children: cycles.map((c) => {
|
|
4322
|
-
const active = c === selected;
|
|
4323
|
-
const label = c === "YEARLY" ? labels.annualLabel : labels.monthlyLabel;
|
|
4324
|
-
const suffix = c === "YEARLY" ? labels.annualSuffix : labels.monthlySuffix;
|
|
4325
|
-
const mainCents = c === "YEARLY" ? Math.round(yearlyCents / 12) : monthlyCents;
|
|
4326
|
-
const anchorCents = c === "YEARLY" ? anchorYearly : anchorMonthly;
|
|
4327
|
-
return /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)(
|
|
4328
|
-
"button",
|
|
4329
|
-
{
|
|
4330
|
-
type: "button",
|
|
4331
|
-
role: "radio",
|
|
4332
|
-
"aria-checked": active,
|
|
4333
|
-
onClick: () => setCycle(c),
|
|
4334
|
-
className: [
|
|
4335
|
-
"flex flex-col items-center gap-0.5",
|
|
4336
|
-
composedCardClassName,
|
|
4337
|
-
active ? composedCardSelectedClassName : ""
|
|
4338
|
-
].filter(Boolean).join(" "),
|
|
4339
|
-
children: [
|
|
4340
|
-
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)("span", { className: "font-bold text-base leading-tight", children: formatBRL(mainCents) }),
|
|
4341
|
-
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)("span", { className: "text-xs opacity-70 leading-tight", children: suffix }),
|
|
4342
|
-
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)("span", { className: "text-xs opacity-60 leading-tight", children: label }),
|
|
4343
|
-
anchorCents != null && anchorCents > mainCents ? /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("span", { className: anchorClassName ?? "text-xs opacity-50", children: /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("s", { children: formatBRL(anchorCents) }) }) : null
|
|
4344
|
-
]
|
|
4345
|
-
},
|
|
4346
|
-
c
|
|
4347
|
-
);
|
|
4348
|
-
})
|
|
4349
|
-
}
|
|
4350
|
-
);
|
|
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 });
|
|
4351
3858
|
}
|
|
4352
3859
|
|
|
4353
|
-
// src/components/paywall/
|
|
4354
|
-
var
|
|
4355
|
-
var
|
|
4356
|
-
|
|
4357
|
-
|
|
4358
|
-
|
|
4359
|
-
|
|
4360
|
-
|
|
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
|
|
4361
3869
|
}) {
|
|
4362
|
-
|
|
4363
|
-
|
|
4364
|
-
|
|
4365
|
-
|
|
4366
|
-
|
|
4367
|
-
|
|
4368
|
-
|
|
4369
|
-
}
|
|
4370
|
-
) });
|
|
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
|
+
}) });
|
|
4371
3879
|
}
|
|
4372
|
-
|
|
4373
|
-
|
|
4374
|
-
|
|
4375
|
-
|
|
4376
|
-
|
|
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
|
|
4377
3889
|
}) {
|
|
4378
|
-
const
|
|
4379
|
-
|
|
4380
|
-
|
|
4381
|
-
|
|
4382
|
-
|
|
4383
|
-
|
|
4384
|
-
|
|
4385
|
-
|
|
4386
|
-
|
|
4387
|
-
|
|
4388
|
-
|
|
4389
|
-
|
|
4390
|
-
|
|
4391
|
-
|
|
4392
|
-
|
|
4393
|
-
|
|
4394
|
-
|
|
4395
|
-
|
|
4396
|
-
|
|
4397
|
-
|
|
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 });
|
|
4398
3952
|
}
|
|
4399
|
-
|
|
4400
|
-
|
|
4401
|
-
|
|
4402
|
-
|
|
4403
|
-
|
|
4404
|
-
|
|
4405
|
-
|
|
4406
|
-
|
|
4407
|
-
|
|
4408
|
-
|
|
4409
|
-
|
|
4410
|
-
|
|
4411
|
-
|
|
4412
|
-
|
|
4413
|
-
|
|
4414
|
-
|
|
4415
|
-
|
|
4416
|
-
|
|
4417
|
-
|
|
4418
|
-
|
|
4419
|
-
|
|
4420
|
-
}, [
|
|
4421
|
-
const
|
|
4422
|
-
|
|
4423
|
-
|
|
4424
|
-
|
|
4425
|
-
|
|
4426
|
-
|
|
4427
|
-
|
|
4428
|
-
|
|
4429
|
-
|
|
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\/[^/]+/, ""));
|
|
4430
4007
|
return;
|
|
4431
4008
|
}
|
|
4432
|
-
|
|
4433
|
-
}
|
|
4434
|
-
|
|
4435
|
-
|
|
4436
|
-
|
|
4437
|
-
|
|
4438
|
-
|
|
4439
|
-
|
|
4440
|
-
|
|
4441
|
-
|
|
4442
|
-
|
|
4443
|
-
|
|
4444
|
-
|
|
4445
|
-
|
|
4446
|
-
|
|
4447
|
-
|
|
4448
|
-
|
|
4449
|
-
|
|
4450
|
-
|
|
4451
|
-
|
|
4452
|
-
|
|
4453
|
-
|
|
4454
|
-
|
|
4455
|
-
|
|
4456
|
-
|
|
4457
|
-
|
|
4458
|
-
|
|
4459
|
-
|
|
4460
|
-
|
|
4461
|
-
|
|
4462
|
-
|
|
4463
|
-
|
|
4464
|
-
|
|
4465
|
-
|
|
4466
|
-
|
|
4467
|
-
|
|
4468
|
-
|
|
4469
|
-
|
|
4470
|
-
|
|
4471
|
-
|
|
4472
|
-
|
|
4473
|
-
|
|
4474
|
-
|
|
4475
|
-
|
|
4476
|
-
|
|
4477
|
-
|
|
4478
|
-
|
|
4479
|
-
|
|
4480
|
-
/* @__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)(
|
|
4481
4265
|
"button",
|
|
4482
4266
|
{
|
|
4483
|
-
type: "
|
|
4484
|
-
|
|
4485
|
-
|
|
4486
|
-
|
|
4487
|
-
|
|
4488
|
-
|
|
4489
|
-
|
|
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
|
+
] })
|
|
4490
4281
|
}
|
|
4491
4282
|
),
|
|
4492
|
-
|
|
4493
|
-
|
|
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
|
+
] })
|
|
4494
4302
|
] })
|
|
4495
|
-
] });
|
|
4496
|
-
}
|
|
4497
|
-
function interp(tpl, vars) {
|
|
4498
|
-
return tpl.replace(/\{(\w+)\}/g, (_m, k) => vars[k] ?? "");
|
|
4303
|
+
] }) });
|
|
4499
4304
|
}
|
|
4500
|
-
function
|
|
4501
|
-
return {
|
|
4502
|
-
tabLabel: m.tabLabel,
|
|
4503
|
-
bodyRows: m.bodyRows.map((r) => interp(r, { price, days })),
|
|
4504
|
-
ctaTemplate: m.ctaTemplate,
|
|
4505
|
-
switchHint: m.switchHint
|
|
4506
|
-
};
|
|
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 });
|
|
4507
4307
|
}
|
|
4508
|
-
|
|
4509
|
-
|
|
4510
|
-
|
|
4511
|
-
|
|
4512
|
-
|
|
4513
|
-
|
|
4514
|
-
switchHint,
|
|
4515
|
-
trustLine,
|
|
4516
|
-
className,
|
|
4517
|
-
buttonClassName,
|
|
4518
|
-
switchHintClassName,
|
|
4519
|
-
trustClassName
|
|
4520
|
-
}) {
|
|
4521
|
-
const { submit, submitting } = usePaywallContext();
|
|
4522
|
-
const label = submitting && loadingLabel ? loadingLabel : ctaLabel;
|
|
4523
|
-
return /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("div", { className, children: [
|
|
4524
|
-
/* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
|
|
4525
|
-
"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",
|
|
4526
4314
|
{
|
|
4527
|
-
type: "
|
|
4528
|
-
|
|
4529
|
-
|
|
4530
|
-
|
|
4531
|
-
|
|
4532
|
-
|
|
4533
|
-
|
|
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}`
|
|
4534
4327
|
}
|
|
4535
4328
|
),
|
|
4536
|
-
|
|
4537
|
-
/* @__PURE__ */ (0, import_jsx_runtime37.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
|
|
4538
4330
|
] });
|
|
4539
4331
|
}
|
|
4540
|
-
|
|
4541
|
-
|
|
4542
|
-
var import_jsx_runtime38 = require("react/jsx-runtime");
|
|
4543
|
-
var DEFAULT_EYEBROW_CLASSES = "text-xs uppercase tracking-widest font-semibold opacity-70";
|
|
4544
|
-
function PaywallEyebrow({ text, className }) {
|
|
4545
|
-
return /* @__PURE__ */ (0, import_jsx_runtime38.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 });
|
|
4546
4334
|
}
|
|
4547
|
-
|
|
4548
|
-
|
|
4549
|
-
|
|
4550
|
-
var DEFAULT_GRADIENT = "absolute inset-0 bg-gradient-to-t from-black/70 via-black/20 to-transparent";
|
|
4551
|
-
function PaywallHero({
|
|
4552
|
-
src,
|
|
4553
|
-
alt = "",
|
|
4554
|
-
headline,
|
|
4555
|
-
aspectRatio = "16/9",
|
|
4556
|
-
gradientClassName,
|
|
4557
|
-
className,
|
|
4558
|
-
headlineClassName,
|
|
4559
|
-
imgClassName,
|
|
4560
|
-
render
|
|
4561
|
-
}) {
|
|
4562
|
-
if (render) {
|
|
4563
|
-
return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("div", { className, children: render({ src, headline }) });
|
|
4564
|
-
}
|
|
4565
|
-
return /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)(
|
|
4566
|
-
"div",
|
|
4335
|
+
function TabButton({ active, onClick, icon, label, subtitle, subtitleActiveClass }) {
|
|
4336
|
+
return /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)(
|
|
4337
|
+
"button",
|
|
4567
4338
|
{
|
|
4568
|
-
|
|
4569
|
-
|
|
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 },
|
|
4570
4345
|
children: [
|
|
4571
|
-
/* @__PURE__ */ (0,
|
|
4572
|
-
|
|
4573
|
-
|
|
4574
|
-
|
|
4575
|
-
|
|
4576
|
-
|
|
4577
|
-
}
|
|
4578
|
-
),
|
|
4579
|
-
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)("div", { className: gradientClassName ?? DEFAULT_GRADIENT, "aria-hidden": "true" }),
|
|
4580
|
-
headline ? /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
|
|
4581
|
-
"h1",
|
|
4582
|
-
{
|
|
4583
|
-
className: ["absolute bottom-0 left-0 right-0 p-4 text-white font-bold text-2xl", headlineClassName].filter(Boolean).join(" "),
|
|
4584
|
-
children: headline
|
|
4585
|
-
}
|
|
4586
|
-
) : null
|
|
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 })
|
|
4587
4352
|
]
|
|
4588
4353
|
}
|
|
4589
4354
|
);
|
|
4590
4355
|
}
|
|
4591
|
-
|
|
4592
|
-
|
|
4593
|
-
|
|
4594
|
-
|
|
4595
|
-
|
|
4596
|
-
|
|
4597
|
-
|
|
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",
|
|
4386
|
+
{
|
|
4387
|
+
className: "w-4 h-4 rounded-full border-2 border-white/40 border-t-white",
|
|
4388
|
+
style: { animation: "spin 0.7s linear infinite" }
|
|
4389
|
+
}
|
|
4390
|
+
);
|
|
4598
4391
|
}
|
|
4599
4392
|
|
|
4600
|
-
// src/
|
|
4601
|
-
var
|
|
4602
|
-
var
|
|
4603
|
-
var
|
|
4604
|
-
|
|
4605
|
-
|
|
4606
|
-
|
|
4607
|
-
function
|
|
4608
|
-
|
|
4609
|
-
|
|
4610
|
-
|
|
4611
|
-
|
|
4612
|
-
|
|
4613
|
-
|
|
4614
|
-
|
|
4615
|
-
const pricePerDay = formatBRL(dailyFromYearly(yearlyCents));
|
|
4616
|
-
const monthlyEquiv = currentMonthlyEquivCents ?? 0;
|
|
4617
|
-
const cycleLabel = CYCLE_LABEL[cycle] ?? cycle.toLowerCase();
|
|
4618
|
-
const rootClasses = [DEFAULT_CLASS, className].filter(Boolean).join(" ");
|
|
4619
|
-
if (render) {
|
|
4620
|
-
const RootTag2 = as;
|
|
4621
|
-
return /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(RootTag2, { className: [className].filter(Boolean).join(" ") || void 0, children: render({ pricePerDay, currentMonthlyEquivCents: monthlyEquiv, cycle }) });
|
|
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;
|
|
4622
4408
|
}
|
|
4623
|
-
const text = template.replaceAll("{pricePerDay}", pricePerDay).replaceAll("{currentMonthlyEquiv}", formatBRL(monthlyEquiv)).replaceAll("{cycle}", cycleLabel);
|
|
4624
|
-
const RootTag = as;
|
|
4625
|
-
return /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(RootTag, { className: rootClasses, children: text });
|
|
4626
4409
|
}
|
|
4627
|
-
|
|
4628
|
-
|
|
4629
|
-
|
|
4630
|
-
|
|
4631
|
-
|
|
4632
|
-
function resolveDeadlineMs(deadline) {
|
|
4633
|
-
if (deadline instanceof Date) return deadline.getTime();
|
|
4634
|
-
if (typeof deadline === "string") return new Date(deadline).getTime();
|
|
4635
|
-
const { sessionStorageKey, durationMs } = deadline;
|
|
4636
|
-
if (typeof window === "undefined" || typeof window.sessionStorage === "undefined") {
|
|
4637
|
-
return Date.now() + durationMs;
|
|
4410
|
+
function clearPixPayload() {
|
|
4411
|
+
if (typeof window === "undefined") return;
|
|
4412
|
+
try {
|
|
4413
|
+
sessionStorage.removeItem(PIX_PAYLOAD_KEY2);
|
|
4414
|
+
} catch {
|
|
4638
4415
|
}
|
|
4639
|
-
|
|
4640
|
-
|
|
4641
|
-
const
|
|
4642
|
-
|
|
4643
|
-
|
|
4644
|
-
|
|
4645
|
-
|
|
4416
|
+
}
|
|
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
|
+
}
|
|
4646
4448
|
}
|
|
4647
|
-
return
|
|
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
|
+
] });
|
|
4466
|
+
}
|
|
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
|
+
] });
|
|
4648
4494
|
}
|
|
4649
|
-
|
|
4650
|
-
|
|
4651
|
-
|
|
4652
|
-
|
|
4653
|
-
|
|
4654
|
-
|
|
4655
|
-
|
|
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
|
+
};
|
|
4656
4626
|
}
|
|
4657
|
-
|
|
4658
|
-
|
|
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
|
+
};
|
|
4659
4675
|
}
|
|
4660
|
-
|
|
4661
|
-
|
|
4662
|
-
|
|
4663
|
-
|
|
4664
|
-
|
|
4665
|
-
|
|
4666
|
-
})
|
|
4667
|
-
const
|
|
4668
|
-
|
|
4669
|
-
|
|
4670
|
-
|
|
4671
|
-
const [
|
|
4672
|
-
const
|
|
4673
|
-
(0,
|
|
4674
|
-
|
|
4675
|
-
|
|
4676
|
-
|
|
4677
|
-
|
|
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());
|
|
4678
4724
|
}
|
|
4679
|
-
|
|
4725
|
+
} catch (err) {
|
|
4726
|
+
setError(mapSdkError(err));
|
|
4727
|
+
} finally {
|
|
4728
|
+
setSubmitting(false);
|
|
4680
4729
|
}
|
|
4681
|
-
|
|
4682
|
-
|
|
4683
|
-
|
|
4684
|
-
|
|
4685
|
-
|
|
4686
|
-
|
|
4687
|
-
|
|
4688
|
-
|
|
4689
|
-
|
|
4690
|
-
|
|
4691
|
-
|
|
4692
|
-
|
|
4693
|
-
|
|
4694
|
-
|
|
4695
|
-
|
|
4696
|
-
|
|
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
|
+
};
|
|
4697
4748
|
}
|
|
4698
4749
|
|
|
4699
|
-
// src/
|
|
4700
|
-
var
|
|
4701
|
-
|
|
4702
|
-
|
|
4703
|
-
|
|
4704
|
-
|
|
4705
|
-
|
|
4706
|
-
|
|
4707
|
-
|
|
4708
|
-
|
|
4709
|
-
|
|
4710
|
-
|
|
4711
|
-
|
|
4712
|
-
}
|
|
4713
|
-
|
|
4714
|
-
|
|
4715
|
-
|
|
4716
|
-
|
|
4717
|
-
|
|
4718
|
-
|
|
4719
|
-
|
|
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
|
+
};
|
|
4720
4775
|
}
|
|
4721
4776
|
|
|
4722
|
-
// src/
|
|
4723
|
-
var
|
|
4724
|
-
|
|
4725
|
-
|
|
4726
|
-
|
|
4727
|
-
|
|
4728
|
-
|
|
4729
|
-
|
|
4730
|
-
|
|
4731
|
-
itemClassName,
|
|
4732
|
-
renderItem
|
|
4733
|
-
}) {
|
|
4734
|
-
return /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("div", { className, children: /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", { className: [DEFAULT_CARD_CLASSES, cardClassName].filter(Boolean).join(" "), children: [
|
|
4735
|
-
title ? /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("div", { className: ["font-semibold mb-2", titleClassName].filter(Boolean).join(" "), children: title }) : null,
|
|
4736
|
-
/* @__PURE__ */ (0, import_jsx_runtime44.jsx)("ul", { children: items.map(
|
|
4737
|
-
(item, idx) => renderItem ? /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("li", { children: renderItem(item, idx) }, idx) : /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("li", { className: itemClassName, children: [
|
|
4738
|
-
/* @__PURE__ */ (0, import_jsx_runtime44.jsx)("span", { "aria-hidden": "true", children: "\u2022" }),
|
|
4739
|
-
" ",
|
|
4740
|
-
/* @__PURE__ */ (0, import_jsx_runtime44.jsx)("span", { children: item })
|
|
4741
|
-
] }, idx)
|
|
4742
|
-
) })
|
|
4743
|
-
] }) });
|
|
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
|
+
};
|
|
4744
4786
|
}
|
|
4745
4787
|
|
|
4746
|
-
// src/
|
|
4747
|
-
var
|
|
4748
|
-
|
|
4749
|
-
|
|
4750
|
-
|
|
4751
|
-
|
|
4752
|
-
|
|
4753
|
-
|
|
4754
|
-
|
|
4755
|
-
|
|
4756
|
-
}) {
|
|
4757
|
-
if (render) {
|
|
4758
|
-
return /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("div", { className, children: render({ text }) });
|
|
4759
|
-
}
|
|
4760
|
-
const rootClasses = [
|
|
4761
|
-
DEFAULT_CHIP_CLASSES,
|
|
4762
|
-
floating ? FLOATING_CLASSES : "",
|
|
4763
|
-
className
|
|
4764
|
-
].filter(Boolean).join(" ");
|
|
4765
|
-
return /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: rootClasses, children: [
|
|
4766
|
-
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("span", { className: iconClassName, "aria-hidden": "true", children: "\u{1F3C6}" }),
|
|
4767
|
-
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("span", { children: text })
|
|
4768
|
-
] });
|
|
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
|
+
};
|
|
4769
4798
|
}
|
|
4770
4799
|
|
|
4771
|
-
// src/
|
|
4772
|
-
var
|
|
4773
|
-
var
|
|
4774
|
-
function
|
|
4775
|
-
|
|
4776
|
-
|
|
4777
|
-
|
|
4778
|
-
const
|
|
4779
|
-
|
|
4780
|
-
|
|
4781
|
-
|
|
4782
|
-
|
|
4783
|
-
|
|
4784
|
-
|
|
4785
|
-
|
|
4786
|
-
|
|
4787
|
-
}
|
|
4788
|
-
|
|
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 };
|
|
4789
4835
|
}
|
|
4790
4836
|
|
|
4791
|
-
// src/
|
|
4792
|
-
var
|
|
4793
|
-
|
|
4794
|
-
|
|
4795
|
-
|
|
4796
|
-
|
|
4797
|
-
|
|
4798
|
-
|
|
4799
|
-
|
|
4800
|
-
|
|
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 };
|
|
4801
4852
|
}
|
|
4802
|
-
|
|
4803
|
-
|
|
4804
|
-
|
|
4805
|
-
|
|
4806
|
-
|
|
4807
|
-
|
|
4808
|
-
|
|
4809
|
-
|
|
4810
|
-
|
|
4811
|
-
}
|
|
4812
|
-
|
|
4813
|
-
|
|
4814
|
-
const avatarClasses = [DEFAULT_AVATAR, avatarClassName].filter(Boolean).join(" ");
|
|
4815
|
-
const quoteClasses = [DEFAULT_QUOTE, quoteClassName].filter(Boolean).join(" ");
|
|
4816
|
-
const nameClasses = [DEFAULT_NAME, nameClassName].filter(Boolean).join(" ");
|
|
4817
|
-
const starsClasses = [DEFAULT_STARS, starsClassName].filter(Boolean).join(" ");
|
|
4818
|
-
return /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("div", { className: rootClasses, children: items.map((item, idx) => {
|
|
4819
|
-
if (renderItem) return renderItem(item, idx);
|
|
4820
|
-
const filled = clampStars(item.stars);
|
|
4821
|
-
const empty = 5 - filled;
|
|
4822
|
-
return /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("div", { className: cardClasses, children: [
|
|
4823
|
-
/* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
4824
|
-
item.avatar ? /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
|
|
4825
|
-
"img",
|
|
4826
|
-
{
|
|
4827
|
-
src: item.avatar,
|
|
4828
|
-
alt: "",
|
|
4829
|
-
loading: "lazy",
|
|
4830
|
-
className: avatarClasses,
|
|
4831
|
-
"aria-hidden": "true"
|
|
4832
|
-
}
|
|
4833
|
-
) : null,
|
|
4834
|
-
/* @__PURE__ */ (0, import_jsx_runtime47.jsx)("div", { className: nameClasses, children: item.name })
|
|
4835
|
-
] }),
|
|
4836
|
-
/* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("div", { className: starsClasses, "aria-label": `${filled} de 5 estrelas`, children: [
|
|
4837
|
-
"\u2605".repeat(filled),
|
|
4838
|
-
"\u2606".repeat(empty)
|
|
4839
|
-
] }),
|
|
4840
|
-
/* @__PURE__ */ (0, import_jsx_runtime47.jsx)("p", { className: quoteClasses, children: item.quote })
|
|
4841
|
-
] }, idx);
|
|
4842
|
-
}) });
|
|
4853
|
+
|
|
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" });
|
|
4843
4865
|
}
|
|
4844
4866
|
|
|
4845
|
-
// src/
|
|
4846
|
-
var
|
|
4847
|
-
var
|
|
4848
|
-
|
|
4849
|
-
|
|
4850
|
-
|
|
4851
|
-
|
|
4852
|
-
|
|
4853
|
-
className,
|
|
4854
|
-
cellClassName,
|
|
4855
|
-
valueClassName,
|
|
4856
|
-
labelClassName,
|
|
4857
|
-
renderCell
|
|
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
|
|
4858
4875
|
}) {
|
|
4859
|
-
|
|
4860
|
-
|
|
4861
|
-
|
|
4862
|
-
|
|
4863
|
-
return /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("div", { className: rootClasses, children: stats.map((stat, idx) => {
|
|
4864
|
-
if (renderCell) return renderCell(stat, idx);
|
|
4865
|
-
return /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: cellClasses, children: [
|
|
4866
|
-
stat.icon ? /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("div", { "aria-hidden": "true", children: stat.icon }) : null,
|
|
4867
|
-
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)("div", { className: valueClasses, children: stat.value }),
|
|
4868
|
-
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)("div", { className: labelClasses, children: stat.label })
|
|
4869
|
-
] }, idx);
|
|
4870
|
-
}) });
|
|
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 }) });
|
|
4878
|
+
}
|
|
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 }) });
|
|
4871
4880
|
}
|
|
4872
4881
|
|
|
4873
|
-
// src/
|
|
4874
|
-
var
|
|
4875
|
-
var
|
|
4876
|
-
|
|
4877
|
-
|
|
4878
|
-
|
|
4879
|
-
|
|
4880
|
-
function
|
|
4881
|
-
|
|
4882
|
-
|
|
4883
|
-
|
|
4884
|
-
|
|
4885
|
-
|
|
4886
|
-
currentPriceCents,
|
|
4887
|
-
cycle,
|
|
4888
|
-
trialDaysCard,
|
|
4889
|
-
trialDaysPix,
|
|
4890
|
-
selectedMethod
|
|
4891
|
-
} = usePaywallContext();
|
|
4892
|
-
const trialDays = selectedMethod === "card" ? trialDaysCard : trialDaysPix;
|
|
4893
|
-
const cycleLabel = CYCLE_LABEL2[cycle] ?? cycle.toLowerCase();
|
|
4894
|
-
const priceFormatted = formatBRL(currentPriceCents ?? 0);
|
|
4895
|
-
const rootClasses = [DEFAULT_CLASS3, className].filter(Boolean).join(" ");
|
|
4896
|
-
if (render) {
|
|
4897
|
-
return /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("p", { className: className || void 0, children: render({
|
|
4898
|
-
currentPriceCents: currentPriceCents ?? 0,
|
|
4899
|
-
cycle,
|
|
4900
|
-
trialDays: trialDays ?? 0,
|
|
4901
|
-
selectedMethod
|
|
4902
|
-
}) });
|
|
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
|
+
);
|
|
4903
4895
|
}
|
|
4904
|
-
|
|
4905
|
-
return /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("p", { className: rootClasses, children: text });
|
|
4896
|
+
return ctx;
|
|
4906
4897
|
}
|
|
4907
4898
|
|
|
4908
|
-
// src/
|
|
4909
|
-
var
|
|
4910
|
-
var
|
|
4911
|
-
var
|
|
4912
|
-
function
|
|
4913
|
-
|
|
4914
|
-
|
|
4915
|
-
|
|
4916
|
-
|
|
4899
|
+
// src/OnboardingFlow.tsx
|
|
4900
|
+
var import_jsx_runtime52 = require("react/jsx-runtime");
|
|
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
|
|
4917
4912
|
}) {
|
|
4918
|
-
const
|
|
4919
|
-
const
|
|
4920
|
-
|
|
4921
|
-
|
|
4922
|
-
|
|
4923
|
-
|
|
4924
|
-
|
|
4925
|
-
|
|
4926
|
-
|
|
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, {}) });
|
|
4927
4991
|
}
|
|
4928
4992
|
|
|
4929
|
-
// src/
|
|
4930
|
-
|
|
4931
|
-
|
|
4932
|
-
|
|
4933
|
-
function PaywallStickyFooter({
|
|
4934
|
-
children,
|
|
4935
|
-
className,
|
|
4936
|
-
safeAreaInsets = true
|
|
4937
|
-
}) {
|
|
4938
|
-
const classes = [DEFAULT_CLASSES, safeAreaInsets ? SAFE_AREA_CLASS : null, className].filter(Boolean).join(" ");
|
|
4939
|
-
return /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("div", { className: classes, children });
|
|
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);
|
|
4940
4997
|
}
|
|
4941
4998
|
// Annotate the CommonJS export names for ESM import in node:
|
|
4942
4999
|
0 && (module.exports = {
|