@hook-sdk/template 0.25.0 → 0.26.0
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 +1047 -975
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +105 -331
- package/dist/index.d.ts +105 -331
- package/dist/index.js +912 -823
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// src/AppRoot.tsx
|
|
2
2
|
import { useMemo as useMemo3 } from "react";
|
|
3
3
|
import { BrowserRouter, MemoryRouter, Navigate, Route, Routes } from "react-router-dom";
|
|
4
|
-
import { useHook as
|
|
4
|
+
import { useHook as useHook7 } from "@hook-sdk/sdk";
|
|
5
5
|
|
|
6
6
|
// src/config/AppConfigContext.tsx
|
|
7
7
|
import { createContext, useContext } from "react";
|
|
@@ -31,7 +31,9 @@ var AuthFlowSchema = z.object({
|
|
|
31
31
|
requiresEmailVerify: z.boolean(),
|
|
32
32
|
googleOAuth: z.boolean(),
|
|
33
33
|
postAuthLanding: z.string().startsWith("/"),
|
|
34
|
-
preAuthRoutes: z.array(z.string().startsWith("/"))
|
|
34
|
+
preAuthRoutes: z.array(z.string().startsWith("/")),
|
|
35
|
+
// Plan-V — pay-first signup mode. See types/AppConfig.ts AuthFlowConfig.
|
|
36
|
+
signupMode: z.enum(["pre_signup", "pay_first"]).optional()
|
|
35
37
|
});
|
|
36
38
|
var PaywallNonFreeSchema = z.object({
|
|
37
39
|
mode: z.enum(["trial", "pay_first"]),
|
|
@@ -630,8 +632,8 @@ function usePaywallState() {
|
|
|
630
632
|
opening: submitting,
|
|
631
633
|
availableMethods: methods,
|
|
632
634
|
monthlyEquivalent,
|
|
633
|
-
|
|
634
|
-
|
|
635
|
+
dismissPix: () => {
|
|
636
|
+
},
|
|
635
637
|
refreshPlan: () => {
|
|
636
638
|
}
|
|
637
639
|
};
|
|
@@ -2031,53 +2033,9 @@ function SessionExpiredBanner() {
|
|
|
2031
2033
|
] });
|
|
2032
2034
|
}
|
|
2033
2035
|
|
|
2034
|
-
// src/internal/EmailVerifyBanner.tsx
|
|
2035
|
-
import { useState as useState5 } from "react";
|
|
2036
|
-
import { useHook as useHook5 } from "@hook-sdk/sdk";
|
|
2037
|
-
import { jsx as jsx18, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
2038
|
-
function EmailVerifyBanner() {
|
|
2039
|
-
const { user, auth } = useHook5();
|
|
2040
|
-
const [sending, setSending] = useState5(false);
|
|
2041
|
-
const [sent, setSent] = useState5(false);
|
|
2042
|
-
if (!user || user.emailVerified) return null;
|
|
2043
|
-
async function handleResend() {
|
|
2044
|
-
if (sending || sent) return;
|
|
2045
|
-
setSending(true);
|
|
2046
|
-
try {
|
|
2047
|
-
await auth.resendVerify();
|
|
2048
|
-
setSent(true);
|
|
2049
|
-
} catch {
|
|
2050
|
-
} finally {
|
|
2051
|
-
setSending(false);
|
|
2052
|
-
}
|
|
2053
|
-
}
|
|
2054
|
-
const label = sent ? "Enviado!" : sending ? "Enviando..." : "Reenviar link";
|
|
2055
|
-
return /* @__PURE__ */ jsxs12(
|
|
2056
|
-
"div",
|
|
2057
|
-
{
|
|
2058
|
-
role: "status",
|
|
2059
|
-
"data-testid": "email-verify-banner",
|
|
2060
|
-
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",
|
|
2061
|
-
children: [
|
|
2062
|
-
/* @__PURE__ */ jsx18("span", { children: "Confirma teu e-mail pra liberar tudo." }),
|
|
2063
|
-
/* @__PURE__ */ jsx18(
|
|
2064
|
-
"button",
|
|
2065
|
-
{
|
|
2066
|
-
type: "button",
|
|
2067
|
-
onClick: handleResend,
|
|
2068
|
-
disabled: sending || sent,
|
|
2069
|
-
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",
|
|
2070
|
-
children: label
|
|
2071
|
-
}
|
|
2072
|
-
)
|
|
2073
|
-
]
|
|
2074
|
-
}
|
|
2075
|
-
);
|
|
2076
|
-
}
|
|
2077
|
-
|
|
2078
2036
|
// src/defaults/ErrorBoundary.tsx
|
|
2079
2037
|
import { Component } from "react";
|
|
2080
|
-
import { Fragment as Fragment4, jsx as
|
|
2038
|
+
import { Fragment as Fragment4, jsx as jsx18, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
2081
2039
|
var ErrorBoundary = class extends Component {
|
|
2082
2040
|
state = { error: null };
|
|
2083
2041
|
static getDerivedStateFromError(error) {
|
|
@@ -2095,12 +2053,12 @@ var ErrorBoundary = class extends Component {
|
|
|
2095
2053
|
}
|
|
2096
2054
|
render() {
|
|
2097
2055
|
if (this.state.error) {
|
|
2098
|
-
return this.props.fallback ?? /* @__PURE__ */
|
|
2099
|
-
/* @__PURE__ */
|
|
2100
|
-
/* @__PURE__ */
|
|
2056
|
+
return this.props.fallback ?? /* @__PURE__ */ jsxs12("div", { role: "alert", style: { padding: 24, textAlign: "center" }, children: [
|
|
2057
|
+
/* @__PURE__ */ jsx18("h2", { children: "Algo deu errado" }),
|
|
2058
|
+
/* @__PURE__ */ jsx18("p", { style: { opacity: 0.7 }, children: "Recarregue a p\xE1gina pra tentar de novo." })
|
|
2101
2059
|
] });
|
|
2102
2060
|
}
|
|
2103
|
-
return /* @__PURE__ */
|
|
2061
|
+
return /* @__PURE__ */ jsx18(Fragment4, { children: this.props.children });
|
|
2104
2062
|
}
|
|
2105
2063
|
};
|
|
2106
2064
|
|
|
@@ -2109,7 +2067,7 @@ import { useEffect as useEffect7 } from "react";
|
|
|
2109
2067
|
import i18n from "i18next";
|
|
2110
2068
|
import { I18nextProvider, initReactI18next } from "react-i18next";
|
|
2111
2069
|
import { usePersistedState } from "@hook-sdk/sdk";
|
|
2112
|
-
import { jsx as
|
|
2070
|
+
import { jsx as jsx19 } from "react/jsx-runtime";
|
|
2113
2071
|
function ensureInitialized(defaultLocale, supportedLocales, resources, initialLocale) {
|
|
2114
2072
|
if (i18n.isInitialized) return;
|
|
2115
2073
|
i18n.use(initReactI18next).init({
|
|
@@ -2138,7 +2096,7 @@ function I18nProvider({
|
|
|
2138
2096
|
i18n.changeLanguage(userLocale);
|
|
2139
2097
|
}
|
|
2140
2098
|
}, [userLocale]);
|
|
2141
|
-
return /* @__PURE__ */
|
|
2099
|
+
return /* @__PURE__ */ jsx19(I18nextProvider, { i18n, children });
|
|
2142
2100
|
}
|
|
2143
2101
|
|
|
2144
2102
|
// src/dev/env.ts
|
|
@@ -2149,9 +2107,9 @@ function isDevToolsEnabled() {
|
|
|
2149
2107
|
}
|
|
2150
2108
|
|
|
2151
2109
|
// src/dev/DevSkipOnboardingFab.tsx
|
|
2152
|
-
import { useCallback as useCallback3, useRef as useRef4, useState as
|
|
2153
|
-
import { useHook as
|
|
2154
|
-
import { jsx as
|
|
2110
|
+
import { useCallback as useCallback3, useRef as useRef4, useState as useState5 } from "react";
|
|
2111
|
+
import { useHook as useHook5 } from "@hook-sdk/sdk";
|
|
2112
|
+
import { jsx as jsx20 } from "react/jsx-runtime";
|
|
2155
2113
|
var STORAGE_KEY = "hook_dev_skip_email";
|
|
2156
2114
|
var TEST_EMAIL_DOMAIN = "@hook.test";
|
|
2157
2115
|
var TEST_PASSWORD = "SkipTest!2026";
|
|
@@ -2218,10 +2176,10 @@ var STYLES = {
|
|
|
2218
2176
|
};
|
|
2219
2177
|
var CONFIRM_TIMEOUT_MS = 3e3;
|
|
2220
2178
|
function DevSkipOnboardingFab({ defaults }) {
|
|
2221
|
-
const hook =
|
|
2179
|
+
const hook = useHook5();
|
|
2222
2180
|
const { slug } = useAppConfig();
|
|
2223
|
-
const [state, setState] =
|
|
2224
|
-
const [errorMsg, setErrorMsg] =
|
|
2181
|
+
const [state, setState] = useState5("idle");
|
|
2182
|
+
const [errorMsg, setErrorMsg] = useState5(null);
|
|
2225
2183
|
const timerRef = useRef4(null);
|
|
2226
2184
|
const clearTimer = useCallback3(() => {
|
|
2227
2185
|
if (timerRef.current) {
|
|
@@ -2258,7 +2216,7 @@ function DevSkipOnboardingFab({ defaults }) {
|
|
|
2258
2216
|
...state === "confirm" || state === "error" ? STYLES.confirm : {},
|
|
2259
2217
|
...state === "busy" ? STYLES.busy : {}
|
|
2260
2218
|
};
|
|
2261
|
-
return /* @__PURE__ */
|
|
2219
|
+
return /* @__PURE__ */ jsx20(
|
|
2262
2220
|
"button",
|
|
2263
2221
|
{
|
|
2264
2222
|
type: "button",
|
|
@@ -2273,20 +2231,20 @@ function DevSkipOnboardingFab({ defaults }) {
|
|
|
2273
2231
|
}
|
|
2274
2232
|
|
|
2275
2233
|
// src/internal/PaymentReturnHandler.tsx
|
|
2276
|
-
import { useCallback as useCallback4, useEffect as useEffect8, useRef as useRef5, useState as
|
|
2277
|
-
import { useHook as
|
|
2278
|
-
import { Fragment as Fragment5, jsx as
|
|
2234
|
+
import { useCallback as useCallback4, useEffect as useEffect8, useRef as useRef5, useState as useState6 } from "react";
|
|
2235
|
+
import { useHook as useHook6 } from "@hook-sdk/sdk";
|
|
2236
|
+
import { Fragment as Fragment5, jsx as jsx21, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
2279
2237
|
var BACKOFF_MS = [2e3, 5e3, 1e4, 2e4, 4e4];
|
|
2280
2238
|
var MAX_CYCLES = 3;
|
|
2281
2239
|
var SUPPORT_MAILTO = "mailto:suporte@usehook.net?subject=Pagamento%20pendente";
|
|
2282
2240
|
function PaymentReturnHandler({ children }) {
|
|
2283
|
-
const { subscription, track: track2 } =
|
|
2241
|
+
const { subscription, track: track2 } = useHook6();
|
|
2284
2242
|
const subRef = useRef5(subscription);
|
|
2285
2243
|
subRef.current = subscription;
|
|
2286
2244
|
const runIdRef = useRef5(0);
|
|
2287
2245
|
const cyclesRef = useRef5(0);
|
|
2288
2246
|
const startMsRef = useRef5(0);
|
|
2289
|
-
const [state, setState] =
|
|
2247
|
+
const [state, setState] = useState6("idle");
|
|
2290
2248
|
const runPoll = useCallback4(() => {
|
|
2291
2249
|
const runId = ++runIdRef.current;
|
|
2292
2250
|
const isFirstRun = cyclesRef.current === 0;
|
|
@@ -2352,19 +2310,19 @@ function PaymentReturnHandler({ children }) {
|
|
|
2352
2310
|
window.location.href = cleanUrl.toString();
|
|
2353
2311
|
}, []);
|
|
2354
2312
|
if (state === "confirming") {
|
|
2355
|
-
return /* @__PURE__ */
|
|
2313
|
+
return /* @__PURE__ */ jsx21("div", { role: "status", "aria-live": "polite", style: overlayStyle2, children: "Confirmando pagamento\u2026" });
|
|
2356
2314
|
}
|
|
2357
2315
|
if (state === "waiting") {
|
|
2358
|
-
return /* @__PURE__ */
|
|
2359
|
-
/* @__PURE__ */
|
|
2360
|
-
/* @__PURE__ */
|
|
2316
|
+
return /* @__PURE__ */ jsx21("div", { role: "status", "aria-live": "polite", style: overlayStyle2, children: /* @__PURE__ */ jsxs13("div", { style: { maxWidth: 320, textAlign: "center", lineHeight: 1.5 }, children: [
|
|
2317
|
+
/* @__PURE__ */ jsx21("div", { style: { marginBottom: 16 }, children: "Pagamento aceito. Estamos confirmando com o banco \u2014 pode levar alguns minutos." }),
|
|
2318
|
+
/* @__PURE__ */ jsx21("button", { type: "button", onClick: runPoll, style: buttonStyle, children: "Atualizar" })
|
|
2361
2319
|
] }) });
|
|
2362
2320
|
}
|
|
2363
2321
|
if (state === "timeout") {
|
|
2364
|
-
return /* @__PURE__ */
|
|
2365
|
-
/* @__PURE__ */
|
|
2366
|
-
/* @__PURE__ */
|
|
2367
|
-
/* @__PURE__ */
|
|
2322
|
+
return /* @__PURE__ */ jsx21("div", { role: "alert", "aria-live": "assertive", style: overlayStyle2, children: /* @__PURE__ */ jsxs13("div", { style: { maxWidth: 360, textAlign: "center", lineHeight: 1.5 }, children: [
|
|
2323
|
+
/* @__PURE__ */ jsx21("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." }),
|
|
2324
|
+
/* @__PURE__ */ jsxs13("div", { style: { display: "flex", flexDirection: "column", gap: 8 }, children: [
|
|
2325
|
+
/* @__PURE__ */ jsx21(
|
|
2368
2326
|
"button",
|
|
2369
2327
|
{
|
|
2370
2328
|
type: "button",
|
|
@@ -2377,7 +2335,7 @@ function PaymentReturnHandler({ children }) {
|
|
|
2377
2335
|
children: "Tentar de novo"
|
|
2378
2336
|
}
|
|
2379
2337
|
),
|
|
2380
|
-
/* @__PURE__ */
|
|
2338
|
+
/* @__PURE__ */ jsx21(
|
|
2381
2339
|
"button",
|
|
2382
2340
|
{
|
|
2383
2341
|
type: "button",
|
|
@@ -2387,7 +2345,7 @@ function PaymentReturnHandler({ children }) {
|
|
|
2387
2345
|
children: "Voltar pro app"
|
|
2388
2346
|
}
|
|
2389
2347
|
),
|
|
2390
|
-
/* @__PURE__ */
|
|
2348
|
+
/* @__PURE__ */ jsx21(
|
|
2391
2349
|
"a",
|
|
2392
2350
|
{
|
|
2393
2351
|
href: SUPPORT_MAILTO,
|
|
@@ -2399,7 +2357,7 @@ function PaymentReturnHandler({ children }) {
|
|
|
2399
2357
|
] })
|
|
2400
2358
|
] }) });
|
|
2401
2359
|
}
|
|
2402
|
-
return /* @__PURE__ */
|
|
2360
|
+
return /* @__PURE__ */ jsx21(Fragment5, { children });
|
|
2403
2361
|
}
|
|
2404
2362
|
var overlayStyle2 = {
|
|
2405
2363
|
position: "fixed",
|
|
@@ -2438,7 +2396,7 @@ var linkStyle = {
|
|
|
2438
2396
|
};
|
|
2439
2397
|
|
|
2440
2398
|
// src/AppRoot.tsx
|
|
2441
|
-
import { Fragment as Fragment6, jsx as
|
|
2399
|
+
import { Fragment as Fragment6, jsx as jsx22, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
2442
2400
|
function buildLegacyConfigShim(config) {
|
|
2443
2401
|
const paywall = config.paywall;
|
|
2444
2402
|
const isFree = paywall.mode === "free";
|
|
@@ -2517,17 +2475,14 @@ function AppRoot(props) {
|
|
|
2517
2475
|
const basename = `/app/${config.slug}`;
|
|
2518
2476
|
const routerProps = testRouter === "memory" ? { basename, initialEntries: testInitialEntries } : { basename };
|
|
2519
2477
|
const position = config.install_prompt?.position ?? "post-paywall";
|
|
2520
|
-
const subscriptionGated = /* @__PURE__ */
|
|
2521
|
-
|
|
2522
|
-
|
|
2523
|
-
|
|
2524
|
-
|
|
2525
|
-
|
|
2526
|
-
|
|
2527
|
-
|
|
2528
|
-
] })
|
|
2529
|
-
] });
|
|
2530
|
-
const authGated = /* @__PURE__ */ jsx23(
|
|
2478
|
+
const subscriptionGated = /* @__PURE__ */ jsx22(SubscriptionGate, { Paywall: Paywall2 ?? FallbackPaywall, children: position === "post-paywall" ? /* @__PURE__ */ jsxs14(InstallGate, { position: "post-paywall", children: [
|
|
2479
|
+
children,
|
|
2480
|
+
/* @__PURE__ */ jsx22(PushPrompt, {})
|
|
2481
|
+
] }) : /* @__PURE__ */ jsxs14(Fragment6, { children: [
|
|
2482
|
+
children,
|
|
2483
|
+
/* @__PURE__ */ jsx22(PushPrompt, {})
|
|
2484
|
+
] }) });
|
|
2485
|
+
const authGated = /* @__PURE__ */ jsx22(
|
|
2531
2486
|
AuthGated,
|
|
2532
2487
|
{
|
|
2533
2488
|
config,
|
|
@@ -2542,13 +2497,13 @@ function AppRoot(props) {
|
|
|
2542
2497
|
children: subscriptionGated
|
|
2543
2498
|
}
|
|
2544
2499
|
);
|
|
2545
|
-
const routedTree = /* @__PURE__ */
|
|
2546
|
-
/* @__PURE__ */
|
|
2547
|
-
/* @__PURE__ */
|
|
2548
|
-
position === "pre-auth" ? /* @__PURE__ */
|
|
2549
|
-
isDevToolsEnabled() && devSkipOnboarding ? /* @__PURE__ */
|
|
2500
|
+
const routedTree = /* @__PURE__ */ jsxs14(Router, { ...routerProps, children: [
|
|
2501
|
+
/* @__PURE__ */ jsx22(DeepLinkHandler, { deepLinks: config.deepLinks }),
|
|
2502
|
+
/* @__PURE__ */ jsx22(SessionExpiredBanner, {}),
|
|
2503
|
+
position === "pre-auth" ? /* @__PURE__ */ jsx22(InstallGate, { position: "pre-auth", children: authGated }) : authGated,
|
|
2504
|
+
isDevToolsEnabled() && devSkipOnboarding ? /* @__PURE__ */ jsx22(DevSkipOnboardingFab, { defaults: devSkipOnboarding.defaults }) : null
|
|
2550
2505
|
] });
|
|
2551
|
-
return /* @__PURE__ */
|
|
2506
|
+
return /* @__PURE__ */ jsx22(ErrorBoundary, { children: /* @__PURE__ */ jsx22(AppConfigProvider, { config, children: /* @__PURE__ */ jsx22(TemplateConfigProvider, { config: legacyShim, children: /* @__PURE__ */ jsx22(ThemeProvider, { children: /* @__PURE__ */ jsx22(PersistenceRegistry, { config: config.persistedKeys, children: config.i18n ? /* @__PURE__ */ jsx22(
|
|
2552
2507
|
I18nProvider,
|
|
2553
2508
|
{
|
|
2554
2509
|
defaultLocale: config.i18n.defaultLocale,
|
|
@@ -2568,37 +2523,46 @@ function AuthGated({
|
|
|
2568
2523
|
EmailVerify,
|
|
2569
2524
|
PreAuthFlow
|
|
2570
2525
|
}) {
|
|
2571
|
-
const { authStatus } =
|
|
2526
|
+
const { authStatus } = useHook7();
|
|
2572
2527
|
if (authStatus === "loading") return null;
|
|
2573
2528
|
if (authStatus !== "authenticated") {
|
|
2529
|
+
if (config.authFlow.signupMode === "pay_first" && PreAuthFlow) {
|
|
2530
|
+
return /* @__PURE__ */ jsxs14(Routes, { children: [
|
|
2531
|
+
/* @__PURE__ */ jsx22(Route, { path: "/signin", element: /* @__PURE__ */ jsx22(Login, {}) }),
|
|
2532
|
+
/* @__PURE__ */ jsx22(Route, { path: "/forgot", element: /* @__PURE__ */ jsx22(Forgot, {}) }),
|
|
2533
|
+
/* @__PURE__ */ jsx22(Route, { path: "/reset", element: /* @__PURE__ */ jsx22(Reset, {}) }),
|
|
2534
|
+
EmailVerify ? /* @__PURE__ */ jsx22(Route, { path: "/verify", element: /* @__PURE__ */ jsx22(EmailVerify, {}) }) : null,
|
|
2535
|
+
/* @__PURE__ */ jsx22(Route, { path: "/*", element: /* @__PURE__ */ jsx22(PreAuthFlow, {}) })
|
|
2536
|
+
] });
|
|
2537
|
+
}
|
|
2574
2538
|
if (config.onboarding?.trigger === "pre_signup_custom" && PreAuthFlow) {
|
|
2575
|
-
return /* @__PURE__ */
|
|
2576
|
-
/* @__PURE__ */
|
|
2577
|
-
/* @__PURE__ */
|
|
2578
|
-
/* @__PURE__ */
|
|
2579
|
-
/* @__PURE__ */
|
|
2580
|
-
EmailVerify ? /* @__PURE__ */
|
|
2581
|
-
/* @__PURE__ */
|
|
2539
|
+
return /* @__PURE__ */ jsxs14(Routes, { children: [
|
|
2540
|
+
/* @__PURE__ */ jsx22(Route, { path: "/signin", element: /* @__PURE__ */ jsx22(Login, {}) }),
|
|
2541
|
+
/* @__PURE__ */ jsx22(Route, { path: "/signup", element: /* @__PURE__ */ jsx22(Signup, {}) }),
|
|
2542
|
+
/* @__PURE__ */ jsx22(Route, { path: "/forgot", element: /* @__PURE__ */ jsx22(Forgot, {}) }),
|
|
2543
|
+
/* @__PURE__ */ jsx22(Route, { path: "/reset", element: /* @__PURE__ */ jsx22(Reset, {}) }),
|
|
2544
|
+
EmailVerify ? /* @__PURE__ */ jsx22(Route, { path: "/verify", element: /* @__PURE__ */ jsx22(EmailVerify, {}) }) : null,
|
|
2545
|
+
/* @__PURE__ */ jsx22(Route, { path: "/*", element: /* @__PURE__ */ jsx22(PreAuthFlow, {}) })
|
|
2582
2546
|
] });
|
|
2583
2547
|
}
|
|
2584
|
-
return /* @__PURE__ */
|
|
2585
|
-
/* @__PURE__ */
|
|
2586
|
-
/* @__PURE__ */
|
|
2587
|
-
/* @__PURE__ */
|
|
2588
|
-
/* @__PURE__ */
|
|
2589
|
-
EmailVerify ? /* @__PURE__ */
|
|
2590
|
-
/* @__PURE__ */
|
|
2548
|
+
return /* @__PURE__ */ jsxs14(Routes, { children: [
|
|
2549
|
+
/* @__PURE__ */ jsx22(Route, { path: "/", element: /* @__PURE__ */ jsx22(Login, {}) }),
|
|
2550
|
+
/* @__PURE__ */ jsx22(Route, { path: "/signup", element: /* @__PURE__ */ jsx22(Signup, {}) }),
|
|
2551
|
+
/* @__PURE__ */ jsx22(Route, { path: "/forgot", element: /* @__PURE__ */ jsx22(Forgot, {}) }),
|
|
2552
|
+
/* @__PURE__ */ jsx22(Route, { path: "/reset", element: /* @__PURE__ */ jsx22(Reset, {}) }),
|
|
2553
|
+
EmailVerify ? /* @__PURE__ */ jsx22(Route, { path: "/verify", element: /* @__PURE__ */ jsx22(EmailVerify, {}) }) : null,
|
|
2554
|
+
/* @__PURE__ */ jsx22(Route, { path: "*", element: /* @__PURE__ */ jsx22(Navigate, { to: "/", replace: true }) })
|
|
2591
2555
|
] });
|
|
2592
2556
|
}
|
|
2593
|
-
return /* @__PURE__ */
|
|
2557
|
+
return /* @__PURE__ */ jsx22(Fragment6, { children });
|
|
2594
2558
|
}
|
|
2595
2559
|
function FallbackPaywall() {
|
|
2596
2560
|
return null;
|
|
2597
2561
|
}
|
|
2598
2562
|
|
|
2599
2563
|
// src/hooks/usePush.ts
|
|
2600
|
-
import { useCallback as useCallback5, useEffect as useEffect9, useState as
|
|
2601
|
-
import { useHook as
|
|
2564
|
+
import { useCallback as useCallback5, useEffect as useEffect9, useState as useState7 } from "react";
|
|
2565
|
+
import { useHook as useHook8 } from "@hook-sdk/sdk";
|
|
2602
2566
|
var DISMISS_STORAGE_KEY = "push:dismissed-until";
|
|
2603
2567
|
var DISMISS_TTL_MS2 = 7 * 24 * 60 * 60 * 1e3;
|
|
2604
2568
|
function detectIosNeedsInstall() {
|
|
@@ -2642,8 +2606,8 @@ function deriveState(push) {
|
|
|
2642
2606
|
return { kind: "prompt" };
|
|
2643
2607
|
}
|
|
2644
2608
|
function usePush() {
|
|
2645
|
-
const { push } =
|
|
2646
|
-
const [state, setState] =
|
|
2609
|
+
const { push } = useHook8();
|
|
2610
|
+
const [state, setState] = useState7(() => deriveState(push));
|
|
2647
2611
|
useEffect9(() => {
|
|
2648
2612
|
setState(deriveState(push));
|
|
2649
2613
|
}, [push]);
|
|
@@ -2681,27 +2645,27 @@ function usePush() {
|
|
|
2681
2645
|
}
|
|
2682
2646
|
|
|
2683
2647
|
// src/components/PushPrompt.tsx
|
|
2684
|
-
import { jsx as
|
|
2648
|
+
import { jsx as jsx23, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
2685
2649
|
function PushPrompt2({ texts, onSubscribed, onDeclined, onInstallRequested, className }) {
|
|
2686
2650
|
const { state, subscribe } = usePush();
|
|
2687
2651
|
if (state.kind === "denied" || state.kind === "dismissed" || state.kind === "subscribed") {
|
|
2688
2652
|
return null;
|
|
2689
2653
|
}
|
|
2690
2654
|
if (state.kind === "ios_needs_install") {
|
|
2691
|
-
return /* @__PURE__ */
|
|
2692
|
-
/* @__PURE__ */
|
|
2693
|
-
/* @__PURE__ */
|
|
2694
|
-
onInstallRequested && texts.iosInstallCta && /* @__PURE__ */
|
|
2655
|
+
return /* @__PURE__ */ jsxs15("div", { className, role: "region", "aria-label": texts.iosInstallTitle, children: [
|
|
2656
|
+
/* @__PURE__ */ jsx23("h3", { children: texts.iosInstallTitle }),
|
|
2657
|
+
/* @__PURE__ */ jsx23("p", { children: texts.iosInstallBody }),
|
|
2658
|
+
onInstallRequested && texts.iosInstallCta && /* @__PURE__ */ jsx23("button", { onClick: onInstallRequested, children: texts.iosInstallCta })
|
|
2695
2659
|
] });
|
|
2696
2660
|
}
|
|
2697
2661
|
if (state.kind === "unsupported") {
|
|
2698
|
-
return /* @__PURE__ */
|
|
2662
|
+
return /* @__PURE__ */ jsx23("div", { className, role: "region", children: /* @__PURE__ */ jsx23("p", { children: texts.unsupportedBody }) });
|
|
2699
2663
|
}
|
|
2700
2664
|
if (state.kind === "error") {
|
|
2701
|
-
return /* @__PURE__ */
|
|
2665
|
+
return /* @__PURE__ */ jsx23("div", { className, role: "region", "aria-label": "error", children: /* @__PURE__ */ jsx23("p", { children: state.message }) });
|
|
2702
2666
|
}
|
|
2703
|
-
return /* @__PURE__ */
|
|
2704
|
-
/* @__PURE__ */
|
|
2667
|
+
return /* @__PURE__ */ jsxs15("div", { className, role: "region", children: [
|
|
2668
|
+
/* @__PURE__ */ jsx23(
|
|
2705
2669
|
"button",
|
|
2706
2670
|
{
|
|
2707
2671
|
type: "button",
|
|
@@ -2715,13 +2679,13 @@ function PushPrompt2({ texts, onSubscribed, onDeclined, onInstallRequested, clas
|
|
|
2715
2679
|
children: texts.cta
|
|
2716
2680
|
}
|
|
2717
2681
|
),
|
|
2718
|
-
onDeclined && /* @__PURE__ */
|
|
2682
|
+
onDeclined && /* @__PURE__ */ jsx23("button", { type: "button", onClick: onDeclined, children: texts.declineCta })
|
|
2719
2683
|
] });
|
|
2720
2684
|
}
|
|
2721
2685
|
|
|
2722
2686
|
// src/components/LanguageSwitcher.tsx
|
|
2723
2687
|
import { usePersistedState as usePersistedState2 } from "@hook-sdk/sdk";
|
|
2724
|
-
import { jsx as
|
|
2688
|
+
import { jsx as jsx24, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
2725
2689
|
function LanguageSwitcher({ id, className, label = "Language" }) {
|
|
2726
2690
|
const config = useAppConfig();
|
|
2727
2691
|
const i18nConfig = config.i18n;
|
|
@@ -2730,43 +2694,50 @@ function LanguageSwitcher({ id, className, label = "Language" }) {
|
|
|
2730
2694
|
i18nConfig?.defaultLocale ?? "en-US"
|
|
2731
2695
|
);
|
|
2732
2696
|
if (!i18nConfig) return null;
|
|
2733
|
-
return /* @__PURE__ */
|
|
2734
|
-
label ? /* @__PURE__ */
|
|
2735
|
-
/* @__PURE__ */
|
|
2697
|
+
return /* @__PURE__ */ jsxs16("label", { className, children: [
|
|
2698
|
+
label ? /* @__PURE__ */ jsx24("span", { children: label }) : null,
|
|
2699
|
+
/* @__PURE__ */ jsx24(
|
|
2736
2700
|
"select",
|
|
2737
2701
|
{
|
|
2738
2702
|
id,
|
|
2739
2703
|
value: userLocale,
|
|
2740
2704
|
onChange: (e) => setUserLocale(e.target.value),
|
|
2741
2705
|
"data-testid": "language-switcher",
|
|
2742
|
-
children: i18nConfig.supportedLocales.map((loc) => /* @__PURE__ */
|
|
2706
|
+
children: i18nConfig.supportedLocales.map((loc) => /* @__PURE__ */ jsx24("option", { value: loc, children: loc }, loc))
|
|
2743
2707
|
}
|
|
2744
2708
|
)
|
|
2745
2709
|
] });
|
|
2746
2710
|
}
|
|
2747
2711
|
|
|
2748
2712
|
// src/defaults/LoadingState.tsx
|
|
2749
|
-
import { jsx as
|
|
2713
|
+
import { jsx as jsx25 } from "react/jsx-runtime";
|
|
2750
2714
|
function LoadingState({ message }) {
|
|
2751
|
-
return /* @__PURE__ */
|
|
2715
|
+
return /* @__PURE__ */ jsx25("div", { role: "status", "aria-live": "polite", style: { padding: 24, textAlign: "center" }, children: /* @__PURE__ */ jsx25("span", { children: message ?? "Carregando..." }) });
|
|
2752
2716
|
}
|
|
2753
2717
|
|
|
2754
2718
|
// src/defaults/EmptyState.tsx
|
|
2755
|
-
import { jsx as
|
|
2719
|
+
import { jsx as jsx26, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
2756
2720
|
function EmptyState({ title, description, action }) {
|
|
2757
|
-
return /* @__PURE__ */
|
|
2758
|
-
/* @__PURE__ */
|
|
2759
|
-
description && /* @__PURE__ */
|
|
2760
|
-
action && /* @__PURE__ */
|
|
2721
|
+
return /* @__PURE__ */ jsxs17("div", { role: "status", style: { padding: 32, textAlign: "center" }, children: [
|
|
2722
|
+
/* @__PURE__ */ jsx26("h2", { style: { marginBottom: 8 }, children: title }),
|
|
2723
|
+
description && /* @__PURE__ */ jsx26("p", { style: { opacity: 0.7 }, children: description }),
|
|
2724
|
+
action && /* @__PURE__ */ jsx26("div", { style: { marginTop: 16 }, children: action })
|
|
2761
2725
|
] });
|
|
2762
2726
|
}
|
|
2763
2727
|
|
|
2764
|
-
// src/
|
|
2765
|
-
import {
|
|
2766
|
-
import {
|
|
2728
|
+
// src/defaults/CheckoutPageDefault.tsx
|
|
2729
|
+
import { useEffect as useEffect11, useMemo as useMemo5 } from "react";
|
|
2730
|
+
import { useNavigate as useNavigate2 } from "react-router-dom";
|
|
2731
|
+
|
|
2732
|
+
// src/hooks/useCheckoutForm.ts
|
|
2733
|
+
import { useCallback as useCallback6, useEffect as useEffect10, useMemo as useMemo4, useRef as useRef6, useState as useState8 } from "react";
|
|
2734
|
+
import {
|
|
2735
|
+
useHook as useHook9,
|
|
2736
|
+
EmailTakenError
|
|
2737
|
+
} from "@hook-sdk/sdk";
|
|
2767
2738
|
|
|
2768
2739
|
// src/errors.ts
|
|
2769
|
-
import { SdkError, SdkAuthError, SdkRateLimitError
|
|
2740
|
+
import { SdkError, SdkAuthError, SdkRateLimitError } from "@hook-sdk/sdk";
|
|
2770
2741
|
function mapSdkError(err) {
|
|
2771
2742
|
if (err instanceof SdkRateLimitError) {
|
|
2772
2743
|
return {
|
|
@@ -2785,9 +2756,6 @@ function mapSdkError(err) {
|
|
|
2785
2756
|
}
|
|
2786
2757
|
return { code: "invalid_credentials", message: "E-mail ou senha inv\xE1lidos." };
|
|
2787
2758
|
}
|
|
2788
|
-
if (err instanceof SdkValidationError && err.code === "auth.email_taken") {
|
|
2789
|
-
return { code: "email_taken", message: "Esse e-mail j\xE1 tem conta." };
|
|
2790
|
-
}
|
|
2791
2759
|
if (err instanceof SdkError && err.httpStatus === 0) {
|
|
2792
2760
|
return { code: "network", message: "Sem conex\xE3o com o servidor. Verifique sua internet." };
|
|
2793
2761
|
}
|
|
@@ -2797,24 +2765,597 @@ function mapSdkError(err) {
|
|
|
2797
2765
|
return { code: "server", message: "Algo deu errado. Tente novamente em instantes." };
|
|
2798
2766
|
}
|
|
2799
2767
|
|
|
2800
|
-
// src/hooks/
|
|
2768
|
+
// src/hooks/useCheckoutForm.ts
|
|
2801
2769
|
var EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
2802
|
-
var
|
|
2803
|
-
|
|
2804
|
-
|
|
2805
|
-
const
|
|
2806
|
-
const [
|
|
2807
|
-
const [
|
|
2808
|
-
const [
|
|
2809
|
-
const [
|
|
2810
|
-
const [
|
|
2811
|
-
const [
|
|
2770
|
+
var PHONE_RE = /^[0-9()+\-\s]{8,20}$/;
|
|
2771
|
+
var CHECK_DEBOUNCE_MS = 400;
|
|
2772
|
+
function useCheckoutForm(args) {
|
|
2773
|
+
const { auth } = useHook9();
|
|
2774
|
+
const [name, setName] = useState8("");
|
|
2775
|
+
const [email, setEmail] = useState8("");
|
|
2776
|
+
const [emailConfirm, setEmailConfirm] = useState8("");
|
|
2777
|
+
const [phone, setPhone] = useState8("");
|
|
2778
|
+
const [cpf, setCpf] = useState8("");
|
|
2779
|
+
const [method, setMethod] = useState8(args.defaultMethod);
|
|
2780
|
+
const [cycle, setCycle] = useState8(args.defaultCycle);
|
|
2781
|
+
const [card, setCardState] = useState8({
|
|
2782
|
+
number: "",
|
|
2783
|
+
expiryMonth: "",
|
|
2784
|
+
expiryYear: "",
|
|
2785
|
+
ccv: "",
|
|
2786
|
+
holderName: ""
|
|
2787
|
+
});
|
|
2788
|
+
const setCard = useCallback6((patch) => {
|
|
2789
|
+
setCardState((prev) => ({ ...prev, ...patch }));
|
|
2790
|
+
}, []);
|
|
2791
|
+
const [touchedName, setTouchedName] = useState8(false);
|
|
2792
|
+
const [touchedEmail, setTouchedEmail] = useState8(false);
|
|
2793
|
+
const [touchedEmailConfirm, setTouchedEmailConfirm] = useState8(false);
|
|
2794
|
+
const [touchedPhone, setTouchedPhone] = useState8(false);
|
|
2795
|
+
const [touchedCpf, setTouchedCpf] = useState8(false);
|
|
2796
|
+
const [formSubmitAttempted, setFormSubmitAttempted] = useState8(false);
|
|
2797
|
+
const [submitting, setSubmitting] = useState8(false);
|
|
2798
|
+
const [error, setError] = useState8(null);
|
|
2799
|
+
const [emailTaken, setEmailTaken] = useState8(false);
|
|
2800
|
+
const [loginUrl, setLoginUrl] = useState8(null);
|
|
2801
|
+
const [emailStatus, setEmailStatus] = useState8("idle");
|
|
2802
|
+
const lastCheckedEmail = useRef6("");
|
|
2803
|
+
useEffect10(() => {
|
|
2804
|
+
if (!email || !EMAIL_RE.test(email)) {
|
|
2805
|
+
setEmailStatus("idle");
|
|
2806
|
+
return;
|
|
2807
|
+
}
|
|
2808
|
+
if (email === lastCheckedEmail.current) return;
|
|
2809
|
+
const timer = setTimeout(async () => {
|
|
2810
|
+
setEmailStatus("checking");
|
|
2811
|
+
try {
|
|
2812
|
+
const result = await auth.checkEmailExists({ email });
|
|
2813
|
+
lastCheckedEmail.current = email;
|
|
2814
|
+
setEmailStatus(result.exists ? "exists" : "available");
|
|
2815
|
+
} catch {
|
|
2816
|
+
setEmailStatus("idle");
|
|
2817
|
+
}
|
|
2818
|
+
}, CHECK_DEBOUNCE_MS);
|
|
2819
|
+
return () => clearTimeout(timer);
|
|
2820
|
+
}, [email, auth]);
|
|
2821
|
+
const validateName = useMemo4(() => {
|
|
2822
|
+
if (name.length === 0) return null;
|
|
2823
|
+
if (name.trim().length < 2) return "Nome muito curto.";
|
|
2824
|
+
return null;
|
|
2825
|
+
}, [name]);
|
|
2812
2826
|
const validateEmail = useMemo4(() => {
|
|
2813
2827
|
if (email.length === 0) return null;
|
|
2814
2828
|
if (!EMAIL_RE.test(email)) return "Formato de e-mail inv\xE1lido.";
|
|
2815
2829
|
return null;
|
|
2816
2830
|
}, [email]);
|
|
2817
|
-
const
|
|
2831
|
+
const validateEmailConfirm = useMemo4(() => {
|
|
2832
|
+
if (emailConfirm.length === 0) return null;
|
|
2833
|
+
if (emailConfirm !== email) return "Os e-mails n\xE3o coincidem.";
|
|
2834
|
+
return null;
|
|
2835
|
+
}, [emailConfirm, email]);
|
|
2836
|
+
const validatePhone = useMemo4(() => {
|
|
2837
|
+
if (phone.length === 0) return null;
|
|
2838
|
+
if (!PHONE_RE.test(phone)) return "Telefone inv\xE1lido.";
|
|
2839
|
+
return null;
|
|
2840
|
+
}, [phone]);
|
|
2841
|
+
const validateCpf = useMemo4(() => {
|
|
2842
|
+
if (cpf.length === 0) return null;
|
|
2843
|
+
const digits = cpf.replace(/\D/g, "");
|
|
2844
|
+
if (digits.length !== 11) return "CPF deve ter 11 d\xEDgitos.";
|
|
2845
|
+
if (/^(\d)\1+$/.test(digits)) return "CPF inv\xE1lido.";
|
|
2846
|
+
const ok = mod11(digits, 9) === digits[9] && mod11(digits, 10) === digits[10];
|
|
2847
|
+
return ok ? null : "CPF inv\xE1lido.";
|
|
2848
|
+
}, [cpf]);
|
|
2849
|
+
const nameError = touchedName || formSubmitAttempted ? validateName : null;
|
|
2850
|
+
const emailError = touchedEmail || formSubmitAttempted ? validateEmail : null;
|
|
2851
|
+
const emailConfirmError = touchedEmailConfirm || formSubmitAttempted ? validateEmailConfirm : null;
|
|
2852
|
+
const phoneError = touchedPhone || formSubmitAttempted ? validatePhone : null;
|
|
2853
|
+
const cpfError = touchedCpf || formSubmitAttempted ? validateCpf : null;
|
|
2854
|
+
const canSubmit = name.trim().length >= 2 && EMAIL_RE.test(email) && emailConfirm === email && PHONE_RE.test(phone) && 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);
|
|
2855
|
+
const submit = useCallback6(async () => {
|
|
2856
|
+
setFormSubmitAttempted(true);
|
|
2857
|
+
setError(null);
|
|
2858
|
+
setEmailTaken(false);
|
|
2859
|
+
setLoginUrl(null);
|
|
2860
|
+
if (!canSubmit) return null;
|
|
2861
|
+
setSubmitting(true);
|
|
2862
|
+
try {
|
|
2863
|
+
let args2;
|
|
2864
|
+
if (method === "card") {
|
|
2865
|
+
args2 = {
|
|
2866
|
+
method: "card",
|
|
2867
|
+
name: name.trim(),
|
|
2868
|
+
email,
|
|
2869
|
+
emailConfirm,
|
|
2870
|
+
phone,
|
|
2871
|
+
cpf: cpf.replace(/\D/g, ""),
|
|
2872
|
+
cycle,
|
|
2873
|
+
card: {
|
|
2874
|
+
number: card.number.replace(/\s/g, ""),
|
|
2875
|
+
expiryMonth: card.expiryMonth,
|
|
2876
|
+
expiryYear: card.expiryYear,
|
|
2877
|
+
ccv: card.ccv,
|
|
2878
|
+
holderName: card.holderName
|
|
2879
|
+
},
|
|
2880
|
+
cardHolderInfo: {
|
|
2881
|
+
name: card.holderName || name.trim(),
|
|
2882
|
+
email,
|
|
2883
|
+
cpfCnpj: cpf.replace(/\D/g, ""),
|
|
2884
|
+
// Empty postal/address: backend defaults if Asaas requires.
|
|
2885
|
+
// Apps that need full address should override via custom form.
|
|
2886
|
+
postalCode: "00000000",
|
|
2887
|
+
addressNumber: "0",
|
|
2888
|
+
phone
|
|
2889
|
+
}
|
|
2890
|
+
};
|
|
2891
|
+
} else {
|
|
2892
|
+
args2 = {
|
|
2893
|
+
method: "pix-auto",
|
|
2894
|
+
name: name.trim(),
|
|
2895
|
+
email,
|
|
2896
|
+
emailConfirm,
|
|
2897
|
+
phone,
|
|
2898
|
+
cpf: cpf.replace(/\D/g, ""),
|
|
2899
|
+
cycle
|
|
2900
|
+
};
|
|
2901
|
+
}
|
|
2902
|
+
const result = await auth.subscribeAnonymous(args2);
|
|
2903
|
+
return result;
|
|
2904
|
+
} catch (err) {
|
|
2905
|
+
if (err instanceof EmailTakenError) {
|
|
2906
|
+
setEmailTaken(true);
|
|
2907
|
+
setLoginUrl(err.loginUrl);
|
|
2908
|
+
setEmailStatus("exists");
|
|
2909
|
+
return null;
|
|
2910
|
+
}
|
|
2911
|
+
setError(mapSdkError(err));
|
|
2912
|
+
return null;
|
|
2913
|
+
} finally {
|
|
2914
|
+
setSubmitting(false);
|
|
2915
|
+
}
|
|
2916
|
+
}, [auth, canSubmit, method, cycle, name, email, emailConfirm, phone, cpf, card]);
|
|
2917
|
+
return {
|
|
2918
|
+
name,
|
|
2919
|
+
setName,
|
|
2920
|
+
email,
|
|
2921
|
+
setEmail,
|
|
2922
|
+
emailConfirm,
|
|
2923
|
+
setEmailConfirm,
|
|
2924
|
+
phone,
|
|
2925
|
+
setPhone,
|
|
2926
|
+
cpf,
|
|
2927
|
+
setCpf,
|
|
2928
|
+
method,
|
|
2929
|
+
setMethod,
|
|
2930
|
+
cycle,
|
|
2931
|
+
setCycle,
|
|
2932
|
+
card,
|
|
2933
|
+
setCard,
|
|
2934
|
+
nameError,
|
|
2935
|
+
emailError,
|
|
2936
|
+
emailConfirmError,
|
|
2937
|
+
phoneError,
|
|
2938
|
+
cpfError,
|
|
2939
|
+
markNameTouched: () => setTouchedName(true),
|
|
2940
|
+
markEmailTouched: () => setTouchedEmail(true),
|
|
2941
|
+
markEmailConfirmTouched: () => setTouchedEmailConfirm(true),
|
|
2942
|
+
markPhoneTouched: () => setTouchedPhone(true),
|
|
2943
|
+
markCpfTouched: () => setTouchedCpf(true),
|
|
2944
|
+
emailStatus,
|
|
2945
|
+
submit,
|
|
2946
|
+
submitting,
|
|
2947
|
+
canSubmit,
|
|
2948
|
+
formSubmitAttempted,
|
|
2949
|
+
error,
|
|
2950
|
+
emailTaken,
|
|
2951
|
+
loginUrl
|
|
2952
|
+
};
|
|
2953
|
+
}
|
|
2954
|
+
function mod11(digits, len) {
|
|
2955
|
+
let sum = 0;
|
|
2956
|
+
for (let i = 0; i < len; i++) sum += parseInt(digits.charAt(i), 10) * (len + 1 - i);
|
|
2957
|
+
const r = sum * 10 % 11;
|
|
2958
|
+
return String(r === 10 ? 0 : r);
|
|
2959
|
+
}
|
|
2960
|
+
|
|
2961
|
+
// src/hooks/usePlan.ts
|
|
2962
|
+
import { useHook as useHook10 } from "@hook-sdk/sdk";
|
|
2963
|
+
function usePlan() {
|
|
2964
|
+
const { plan } = useHook10();
|
|
2965
|
+
return plan;
|
|
2966
|
+
}
|
|
2967
|
+
|
|
2968
|
+
// src/defaults/CheckoutPageDefault.tsx
|
|
2969
|
+
import { jsx as jsx27, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
2970
|
+
var INTENT_KEY = "hook:paywall:intent";
|
|
2971
|
+
var PIX_PAYLOAD_KEY = "hook:paywall:pix-pending";
|
|
2972
|
+
function readIntent() {
|
|
2973
|
+
if (typeof window === "undefined") return {};
|
|
2974
|
+
try {
|
|
2975
|
+
const raw = sessionStorage.getItem(INTENT_KEY);
|
|
2976
|
+
if (!raw) return {};
|
|
2977
|
+
return JSON.parse(raw);
|
|
2978
|
+
} catch {
|
|
2979
|
+
return {};
|
|
2980
|
+
}
|
|
2981
|
+
}
|
|
2982
|
+
function formatBrl(cents) {
|
|
2983
|
+
return new Intl.NumberFormat("pt-BR", { style: "currency", currency: "BRL" }).format(cents / 100);
|
|
2984
|
+
}
|
|
2985
|
+
function CheckoutPageDefault() {
|
|
2986
|
+
const navigate = useNavigate2();
|
|
2987
|
+
const plan = usePlan();
|
|
2988
|
+
const intent = useMemo5(readIntent, []);
|
|
2989
|
+
const defaultMethod = intent.method === "pix-auto" ? "pix-auto" : "card";
|
|
2990
|
+
const defaultCycle = intent.cycle === "YEARLY" ? "YEARLY" : "MONTHLY";
|
|
2991
|
+
const form = useCheckoutForm({ defaultMethod, defaultCycle });
|
|
2992
|
+
useEffect11(() => {
|
|
2993
|
+
if (form.emailTaken && form.loginUrl) {
|
|
2994
|
+
const t = setTimeout(() => navigate(form.loginUrl), 1200);
|
|
2995
|
+
return () => clearTimeout(t);
|
|
2996
|
+
}
|
|
2997
|
+
}, [form.emailTaken, form.loginUrl, navigate]);
|
|
2998
|
+
const planInfo = plan.data ? {
|
|
2999
|
+
priceCents: plan.data.priceCents,
|
|
3000
|
+
yearlyPriceCents: plan.data.yearlyPriceCents,
|
|
3001
|
+
trialDays: plan.data.trialDays
|
|
3002
|
+
} : null;
|
|
3003
|
+
const cyclePrice = useMemo5(() => {
|
|
3004
|
+
if (!planInfo) return null;
|
|
3005
|
+
return form.cycle === "YEARLY" ? planInfo.yearlyPriceCents ?? planInfo.priceCents * 12 : planInfo.priceCents;
|
|
3006
|
+
}, [planInfo, form.cycle]);
|
|
3007
|
+
const submitLabel = useMemo5(() => {
|
|
3008
|
+
if (form.submitting) return "Processando\u2026";
|
|
3009
|
+
if (form.method === "card") {
|
|
3010
|
+
const trial = planInfo?.trialDays ?? 0;
|
|
3011
|
+
if (trial > 0 && cyclePrice) {
|
|
3012
|
+
return `Come\xE7ar ${trial} dias gr\xE1tis \xB7 ${formatBrl(cyclePrice)} depois`;
|
|
3013
|
+
}
|
|
3014
|
+
return cyclePrice ? `Pagar ${formatBrl(cyclePrice)}` : "Continuar";
|
|
3015
|
+
}
|
|
3016
|
+
return cyclePrice ? `Pagar ${formatBrl(cyclePrice)} via PIX` : "Continuar via PIX";
|
|
3017
|
+
}, [form.method, form.submitting, planInfo, cyclePrice]);
|
|
3018
|
+
async function onSubmit(e) {
|
|
3019
|
+
e.preventDefault();
|
|
3020
|
+
const result = await form.submit();
|
|
3021
|
+
if (!result) return;
|
|
3022
|
+
if (form.method === "pix-auto" && result.pix_qr_payload) {
|
|
3023
|
+
try {
|
|
3024
|
+
sessionStorage.setItem(
|
|
3025
|
+
PIX_PAYLOAD_KEY,
|
|
3026
|
+
JSON.stringify({
|
|
3027
|
+
payload: result.pix_qr_payload,
|
|
3028
|
+
base64: result.pix_qr_base64 ?? null,
|
|
3029
|
+
subscriptionId: result.subscription_id,
|
|
3030
|
+
pixAuthorizationId: result.pix_authorization_id ?? null
|
|
3031
|
+
})
|
|
3032
|
+
);
|
|
3033
|
+
} catch {
|
|
3034
|
+
}
|
|
3035
|
+
navigate(result.redirect.replace(/^.*\/app\/[^/]+/, ""));
|
|
3036
|
+
return;
|
|
3037
|
+
}
|
|
3038
|
+
navigate(result.redirect.replace(/^.*\/app\/[^/]+/, "") || "/");
|
|
3039
|
+
}
|
|
3040
|
+
return /* @__PURE__ */ jsx27("div", { className: "flex-1 flex flex-col bg-background min-h-0", children: /* @__PURE__ */ jsxs18("form", { onSubmit, className: "flex-1 overflow-y-auto px-5 py-6 space-y-6", children: [
|
|
3041
|
+
/* @__PURE__ */ jsxs18("header", { className: "space-y-2", children: [
|
|
3042
|
+
/* @__PURE__ */ jsx27("h1", { className: "font-display text-2xl text-foreground", children: "Finalizar assinatura" }),
|
|
3043
|
+
/* @__PURE__ */ jsx27("p", { className: "text-sm text-muted-foreground", children: "Preencha seus dados pra liberar o app. Voc\xEA j\xE1 entra com acesso na hora." })
|
|
3044
|
+
] }),
|
|
3045
|
+
form.emailTaken ? /* @__PURE__ */ jsxs18("div", { role: "alert", className: "rounded-xl bg-destructive/10 p-4 text-sm text-destructive border border-destructive/20", children: [
|
|
3046
|
+
"Esse e-mail j\xE1 tem conta nesse app.",
|
|
3047
|
+
" ",
|
|
3048
|
+
/* @__PURE__ */ jsx27("a", { href: form.loginUrl ?? "/signin", className: "underline font-medium", children: "Entrar agora" })
|
|
3049
|
+
] }) : null,
|
|
3050
|
+
form.error ? /* @__PURE__ */ jsx27("div", { role: "alert", className: "rounded-xl 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,
|
|
3051
|
+
/* @__PURE__ */ jsxs18("section", { className: "space-y-3", children: [
|
|
3052
|
+
/* @__PURE__ */ jsx27("h2", { className: "text-sm font-semibold text-foreground uppercase tracking-wide", children: "Voc\xEA" }),
|
|
3053
|
+
/* @__PURE__ */ jsx27(
|
|
3054
|
+
FieldRow,
|
|
3055
|
+
{
|
|
3056
|
+
label: "Nome completo",
|
|
3057
|
+
value: form.name,
|
|
3058
|
+
onChange: form.setName,
|
|
3059
|
+
onBlur: form.markNameTouched,
|
|
3060
|
+
error: form.nameError,
|
|
3061
|
+
autoComplete: "name"
|
|
3062
|
+
}
|
|
3063
|
+
),
|
|
3064
|
+
/* @__PURE__ */ jsx27(
|
|
3065
|
+
FieldRow,
|
|
3066
|
+
{
|
|
3067
|
+
label: "E-mail",
|
|
3068
|
+
type: "email",
|
|
3069
|
+
value: form.email,
|
|
3070
|
+
onChange: form.setEmail,
|
|
3071
|
+
onBlur: form.markEmailTouched,
|
|
3072
|
+
error: form.emailError,
|
|
3073
|
+
autoComplete: "email",
|
|
3074
|
+
autoCapitalize: "none",
|
|
3075
|
+
autoCorrect: "off",
|
|
3076
|
+
spellCheck: false,
|
|
3077
|
+
hint: form.emailStatus === "checking" ? "Verificando\u2026" : form.emailStatus === "available" ? "\u2713 Dispon\xEDvel" : form.emailStatus === "exists" ? null : null
|
|
3078
|
+
}
|
|
3079
|
+
),
|
|
3080
|
+
/* @__PURE__ */ jsx27(
|
|
3081
|
+
FieldRow,
|
|
3082
|
+
{
|
|
3083
|
+
label: "Confirme o e-mail",
|
|
3084
|
+
type: "email",
|
|
3085
|
+
value: form.emailConfirm,
|
|
3086
|
+
onChange: form.setEmailConfirm,
|
|
3087
|
+
onBlur: form.markEmailConfirmTouched,
|
|
3088
|
+
error: form.emailConfirmError,
|
|
3089
|
+
autoComplete: "email",
|
|
3090
|
+
autoCapitalize: "none",
|
|
3091
|
+
autoCorrect: "off",
|
|
3092
|
+
spellCheck: false
|
|
3093
|
+
}
|
|
3094
|
+
),
|
|
3095
|
+
/* @__PURE__ */ jsx27(
|
|
3096
|
+
FieldRow,
|
|
3097
|
+
{
|
|
3098
|
+
label: "Telefone",
|
|
3099
|
+
type: "tel",
|
|
3100
|
+
value: form.phone,
|
|
3101
|
+
onChange: form.setPhone,
|
|
3102
|
+
onBlur: form.markPhoneTouched,
|
|
3103
|
+
error: form.phoneError,
|
|
3104
|
+
autoComplete: "tel",
|
|
3105
|
+
placeholder: "(11) 99999-9999"
|
|
3106
|
+
}
|
|
3107
|
+
),
|
|
3108
|
+
/* @__PURE__ */ jsx27(
|
|
3109
|
+
FieldRow,
|
|
3110
|
+
{
|
|
3111
|
+
label: "CPF",
|
|
3112
|
+
type: "text",
|
|
3113
|
+
inputMode: "numeric",
|
|
3114
|
+
value: form.cpf,
|
|
3115
|
+
onChange: form.setCpf,
|
|
3116
|
+
onBlur: form.markCpfTouched,
|
|
3117
|
+
error: form.cpfError,
|
|
3118
|
+
autoComplete: "off",
|
|
3119
|
+
placeholder: "000.000.000-00"
|
|
3120
|
+
}
|
|
3121
|
+
)
|
|
3122
|
+
] }),
|
|
3123
|
+
/* @__PURE__ */ jsxs18("section", { className: "space-y-3", children: [
|
|
3124
|
+
/* @__PURE__ */ jsx27("h2", { className: "text-sm font-semibold text-foreground uppercase tracking-wide", children: "Pagamento" }),
|
|
3125
|
+
/* @__PURE__ */ jsxs18("div", { className: "grid grid-cols-2 gap-2", role: "tablist", children: [
|
|
3126
|
+
/* @__PURE__ */ jsx27(MethodTab, { active: form.method === "card", onClick: () => form.setMethod("card"), children: "Cart\xE3o" }),
|
|
3127
|
+
/* @__PURE__ */ jsx27(MethodTab, { active: form.method === "pix-auto", onClick: () => form.setMethod("pix-auto"), children: "PIX" })
|
|
3128
|
+
] }),
|
|
3129
|
+
/* @__PURE__ */ jsxs18("div", { className: "grid grid-cols-2 gap-2", role: "tablist", children: [
|
|
3130
|
+
/* @__PURE__ */ jsx27(MethodTab, { active: form.cycle === "MONTHLY", onClick: () => form.setCycle("MONTHLY"), children: "Mensal" }),
|
|
3131
|
+
/* @__PURE__ */ jsx27(MethodTab, { active: form.cycle === "YEARLY", onClick: () => form.setCycle("YEARLY"), children: "Anual" })
|
|
3132
|
+
] }),
|
|
3133
|
+
form.method === "card" ? /* @__PURE__ */ jsxs18("div", { className: "space-y-3 rounded-xl border border-border p-4", children: [
|
|
3134
|
+
/* @__PURE__ */ jsx27(
|
|
3135
|
+
FieldRow,
|
|
3136
|
+
{
|
|
3137
|
+
label: "Nome no cart\xE3o",
|
|
3138
|
+
value: form.card.holderName,
|
|
3139
|
+
onChange: (v) => form.setCard({ holderName: v }),
|
|
3140
|
+
autoComplete: "cc-name"
|
|
3141
|
+
}
|
|
3142
|
+
),
|
|
3143
|
+
/* @__PURE__ */ jsx27(
|
|
3144
|
+
FieldRow,
|
|
3145
|
+
{
|
|
3146
|
+
label: "N\xFAmero",
|
|
3147
|
+
value: form.card.number,
|
|
3148
|
+
onChange: (v) => form.setCard({ number: v }),
|
|
3149
|
+
autoComplete: "cc-number",
|
|
3150
|
+
inputMode: "numeric",
|
|
3151
|
+
placeholder: "0000 0000 0000 0000"
|
|
3152
|
+
}
|
|
3153
|
+
),
|
|
3154
|
+
/* @__PURE__ */ jsxs18("div", { className: "grid grid-cols-3 gap-2", children: [
|
|
3155
|
+
/* @__PURE__ */ jsx27(
|
|
3156
|
+
FieldRow,
|
|
3157
|
+
{
|
|
3158
|
+
label: "M\xEAs",
|
|
3159
|
+
value: form.card.expiryMonth,
|
|
3160
|
+
onChange: (v) => form.setCard({ expiryMonth: v }),
|
|
3161
|
+
autoComplete: "cc-exp-month",
|
|
3162
|
+
inputMode: "numeric",
|
|
3163
|
+
placeholder: "MM"
|
|
3164
|
+
}
|
|
3165
|
+
),
|
|
3166
|
+
/* @__PURE__ */ jsx27(
|
|
3167
|
+
FieldRow,
|
|
3168
|
+
{
|
|
3169
|
+
label: "Ano",
|
|
3170
|
+
value: form.card.expiryYear,
|
|
3171
|
+
onChange: (v) => form.setCard({ expiryYear: v }),
|
|
3172
|
+
autoComplete: "cc-exp-year",
|
|
3173
|
+
inputMode: "numeric",
|
|
3174
|
+
placeholder: "AA"
|
|
3175
|
+
}
|
|
3176
|
+
),
|
|
3177
|
+
/* @__PURE__ */ jsx27(
|
|
3178
|
+
FieldRow,
|
|
3179
|
+
{
|
|
3180
|
+
label: "CVV",
|
|
3181
|
+
value: form.card.ccv,
|
|
3182
|
+
onChange: (v) => form.setCard({ ccv: v }),
|
|
3183
|
+
autoComplete: "cc-csc",
|
|
3184
|
+
inputMode: "numeric",
|
|
3185
|
+
placeholder: "123"
|
|
3186
|
+
}
|
|
3187
|
+
)
|
|
3188
|
+
] })
|
|
3189
|
+
] }) : /* @__PURE__ */ jsx27("div", { className: "rounded-xl border border-border p-4 text-sm text-muted-foreground", children: "Ap\xF3s confirmar, mostraremos o QR Code PIX. Pagamento \xE0 vista." })
|
|
3190
|
+
] }),
|
|
3191
|
+
/* @__PURE__ */ jsx27(
|
|
3192
|
+
"button",
|
|
3193
|
+
{
|
|
3194
|
+
type: "submit",
|
|
3195
|
+
disabled: !form.canSubmit,
|
|
3196
|
+
className: "w-full rounded-xl bg-primary py-4 text-base font-semibold text-primary-foreground disabled:opacity-50 disabled:cursor-not-allowed",
|
|
3197
|
+
children: submitLabel
|
|
3198
|
+
}
|
|
3199
|
+
),
|
|
3200
|
+
/* @__PURE__ */ jsx27("p", { className: "text-center text-xs text-muted-foreground", children: "\u{1F512} SSL \xB7 via Asaas \xB7 Garantia 7 dias" })
|
|
3201
|
+
] }) });
|
|
3202
|
+
}
|
|
3203
|
+
function FieldRow(props) {
|
|
3204
|
+
return /* @__PURE__ */ jsxs18("label", { className: "block space-y-1", children: [
|
|
3205
|
+
/* @__PURE__ */ jsx27("span", { className: "block text-sm font-medium text-foreground", children: props.label }),
|
|
3206
|
+
/* @__PURE__ */ jsx27(
|
|
3207
|
+
"input",
|
|
3208
|
+
{
|
|
3209
|
+
type: props.type ?? "text",
|
|
3210
|
+
value: props.value,
|
|
3211
|
+
onChange: (e) => props.onChange(e.target.value),
|
|
3212
|
+
onBlur: props.onBlur,
|
|
3213
|
+
autoComplete: props.autoComplete,
|
|
3214
|
+
autoCapitalize: props.autoCapitalize,
|
|
3215
|
+
autoCorrect: props.autoCorrect,
|
|
3216
|
+
spellCheck: props.spellCheck,
|
|
3217
|
+
inputMode: props.inputMode,
|
|
3218
|
+
placeholder: props.placeholder,
|
|
3219
|
+
className: `w-full rounded-xl border bg-card px-3 py-2 text-base text-foreground outline-none focus:ring-2 focus:ring-primary ${props.error ? "border-destructive" : "border-border"}`
|
|
3220
|
+
}
|
|
3221
|
+
),
|
|
3222
|
+
props.error ? /* @__PURE__ */ jsx27("span", { className: "block text-xs text-destructive", children: props.error }) : props.hint ? /* @__PURE__ */ jsx27("span", { className: "block text-xs text-muted-foreground", children: props.hint }) : null
|
|
3223
|
+
] });
|
|
3224
|
+
}
|
|
3225
|
+
function MethodTab({ active, onClick, children }) {
|
|
3226
|
+
return /* @__PURE__ */ jsx27(
|
|
3227
|
+
"button",
|
|
3228
|
+
{
|
|
3229
|
+
type: "button",
|
|
3230
|
+
role: "tab",
|
|
3231
|
+
"aria-selected": active,
|
|
3232
|
+
onClick,
|
|
3233
|
+
className: `rounded-xl border px-4 py-2 text-sm font-medium transition ${active ? "border-primary bg-primary text-primary-foreground" : "border-border bg-card text-foreground"}`,
|
|
3234
|
+
children
|
|
3235
|
+
}
|
|
3236
|
+
);
|
|
3237
|
+
}
|
|
3238
|
+
|
|
3239
|
+
// src/defaults/PixWaitingPageDefault.tsx
|
|
3240
|
+
import { useEffect as useEffect12, useMemo as useMemo6, useState as useState9 } from "react";
|
|
3241
|
+
import { useNavigate as useNavigate3 } from "react-router-dom";
|
|
3242
|
+
import { useHook as useHook11 } from "@hook-sdk/sdk";
|
|
3243
|
+
import { jsx as jsx28, jsxs as jsxs19 } from "react/jsx-runtime";
|
|
3244
|
+
var PIX_PAYLOAD_KEY2 = "hook:paywall:pix-pending";
|
|
3245
|
+
var TIMEOUT_MS = 30 * 60 * 1e3;
|
|
3246
|
+
function readPixPayload() {
|
|
3247
|
+
if (typeof window === "undefined") return null;
|
|
3248
|
+
try {
|
|
3249
|
+
const raw = sessionStorage.getItem(PIX_PAYLOAD_KEY2);
|
|
3250
|
+
if (!raw) return null;
|
|
3251
|
+
return JSON.parse(raw);
|
|
3252
|
+
} catch {
|
|
3253
|
+
return null;
|
|
3254
|
+
}
|
|
3255
|
+
}
|
|
3256
|
+
function clearPixPayload() {
|
|
3257
|
+
if (typeof window === "undefined") return;
|
|
3258
|
+
try {
|
|
3259
|
+
sessionStorage.removeItem(PIX_PAYLOAD_KEY2);
|
|
3260
|
+
} catch {
|
|
3261
|
+
}
|
|
3262
|
+
}
|
|
3263
|
+
function PixWaitingPageDefault() {
|
|
3264
|
+
const navigate = useNavigate3();
|
|
3265
|
+
const { subscription } = useHook11();
|
|
3266
|
+
const payload = useMemo6(readPixPayload, []);
|
|
3267
|
+
const [copied, setCopied] = useState9(false);
|
|
3268
|
+
const [timedOut, setTimedOut] = useState9(false);
|
|
3269
|
+
useEffect12(() => {
|
|
3270
|
+
if (!payload) navigate("/paywall/checkout", { replace: true });
|
|
3271
|
+
}, [payload, navigate]);
|
|
3272
|
+
useEffect12(() => {
|
|
3273
|
+
const t = setTimeout(() => setTimedOut(true), TIMEOUT_MS);
|
|
3274
|
+
return () => clearTimeout(t);
|
|
3275
|
+
}, []);
|
|
3276
|
+
const hasAccess = subscription.hasAccess;
|
|
3277
|
+
useEffect12(() => {
|
|
3278
|
+
if (hasAccess) {
|
|
3279
|
+
clearPixPayload();
|
|
3280
|
+
navigate("/", { replace: true });
|
|
3281
|
+
}
|
|
3282
|
+
}, [hasAccess, navigate]);
|
|
3283
|
+
async function copyPayload() {
|
|
3284
|
+
if (!payload?.payload) return;
|
|
3285
|
+
try {
|
|
3286
|
+
await navigator.clipboard.writeText(payload.payload);
|
|
3287
|
+
setCopied(true);
|
|
3288
|
+
setTimeout(() => setCopied(false), 2e3);
|
|
3289
|
+
} catch {
|
|
3290
|
+
}
|
|
3291
|
+
}
|
|
3292
|
+
if (!payload) return null;
|
|
3293
|
+
if (timedOut) {
|
|
3294
|
+
return /* @__PURE__ */ jsxs19("div", { className: "flex-1 flex flex-col items-center justify-center px-6 py-10 text-center bg-background space-y-4", children: [
|
|
3295
|
+
/* @__PURE__ */ jsx28("h1", { className: "font-display text-2xl text-foreground", children: "PIX expirado" }),
|
|
3296
|
+
/* @__PURE__ */ jsx28("p", { className: "text-sm text-muted-foreground", children: "O tempo pra pagar acabou. Gere um novo PIX." }),
|
|
3297
|
+
/* @__PURE__ */ jsx28(
|
|
3298
|
+
"button",
|
|
3299
|
+
{
|
|
3300
|
+
onClick: () => {
|
|
3301
|
+
clearPixPayload();
|
|
3302
|
+
navigate("/paywall/checkout", { replace: true });
|
|
3303
|
+
},
|
|
3304
|
+
className: "rounded-xl bg-primary px-6 py-3 text-base font-semibold text-primary-foreground",
|
|
3305
|
+
children: "Tentar novamente"
|
|
3306
|
+
}
|
|
3307
|
+
)
|
|
3308
|
+
] });
|
|
3309
|
+
}
|
|
3310
|
+
return /* @__PURE__ */ jsxs19("div", { className: "flex-1 flex flex-col items-center px-6 py-8 bg-background space-y-6", children: [
|
|
3311
|
+
/* @__PURE__ */ jsxs19("header", { className: "text-center space-y-2", children: [
|
|
3312
|
+
/* @__PURE__ */ jsx28("h1", { className: "font-display text-2xl text-foreground", children: "Pague o PIX" }),
|
|
3313
|
+
/* @__PURE__ */ jsx28("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." })
|
|
3314
|
+
] }),
|
|
3315
|
+
payload.base64 ? /* @__PURE__ */ jsx28(
|
|
3316
|
+
"img",
|
|
3317
|
+
{
|
|
3318
|
+
src: `data:image/png;base64,${payload.base64}`,
|
|
3319
|
+
alt: "QR Code PIX",
|
|
3320
|
+
className: "w-64 h-64 rounded-2xl border border-border bg-card p-2"
|
|
3321
|
+
}
|
|
3322
|
+
) : /* @__PURE__ */ jsx28("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" }),
|
|
3323
|
+
payload.payload ? /* @__PURE__ */ jsx28(
|
|
3324
|
+
"button",
|
|
3325
|
+
{
|
|
3326
|
+
onClick: copyPayload,
|
|
3327
|
+
className: "w-full max-w-xs rounded-xl border border-border bg-card px-4 py-3 text-sm font-medium text-foreground",
|
|
3328
|
+
children: copied ? "\u2713 Copiado!" : "Copiar c\xF3digo PIX"
|
|
3329
|
+
}
|
|
3330
|
+
) : null,
|
|
3331
|
+
/* @__PURE__ */ jsxs19("div", { className: "flex items-center gap-2 text-sm text-muted-foreground", children: [
|
|
3332
|
+
/* @__PURE__ */ jsx28("span", { className: "inline-block w-2 h-2 rounded-full bg-primary animate-pulse" }),
|
|
3333
|
+
"Aguardando pagamento\u2026"
|
|
3334
|
+
] }),
|
|
3335
|
+
/* @__PURE__ */ jsx28("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." })
|
|
3336
|
+
] });
|
|
3337
|
+
}
|
|
3338
|
+
|
|
3339
|
+
// src/hooks/useLoginForm.ts
|
|
3340
|
+
import { useCallback as useCallback7, useMemo as useMemo7, useState as useState10 } from "react";
|
|
3341
|
+
import { useHook as useHook12 } from "@hook-sdk/sdk";
|
|
3342
|
+
var EMAIL_RE2 = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
3343
|
+
var MIN_PASSWORD = 8;
|
|
3344
|
+
function useLoginForm() {
|
|
3345
|
+
const { auth } = useHook12();
|
|
3346
|
+
const [email, setEmail] = useState10("");
|
|
3347
|
+
const [password, setPassword] = useState10("");
|
|
3348
|
+
const [submitting, setSubmitting] = useState10(false);
|
|
3349
|
+
const [error, setError] = useState10(null);
|
|
3350
|
+
const [touchedEmail, setTouchedEmail] = useState10(false);
|
|
3351
|
+
const [touchedPassword, setTouchedPassword] = useState10(false);
|
|
3352
|
+
const [formSubmitAttempted, setFormSubmitAttempted] = useState10(false);
|
|
3353
|
+
const validateEmail = useMemo7(() => {
|
|
3354
|
+
if (email.length === 0) return null;
|
|
3355
|
+
if (!EMAIL_RE2.test(email)) return "Formato de e-mail inv\xE1lido.";
|
|
3356
|
+
return null;
|
|
3357
|
+
}, [email]);
|
|
3358
|
+
const validatePassword = useMemo7(() => {
|
|
2818
3359
|
if (password.length === 0) return null;
|
|
2819
3360
|
if (password.length < MIN_PASSWORD) return `M\xEDnimo de ${MIN_PASSWORD} caracteres.`;
|
|
2820
3361
|
return null;
|
|
@@ -2822,7 +3363,7 @@ function useLoginForm() {
|
|
|
2822
3363
|
const emailError = touchedEmail || formSubmitAttempted ? validateEmail : null;
|
|
2823
3364
|
const passwordError = touchedPassword || formSubmitAttempted ? validatePassword : null;
|
|
2824
3365
|
const canSubmit = email.length > 0 && password.length >= MIN_PASSWORD && validateEmail === null && validatePassword === null && !submitting;
|
|
2825
|
-
const submit =
|
|
3366
|
+
const submit = useCallback7(async () => {
|
|
2826
3367
|
setFormSubmitAttempted(true);
|
|
2827
3368
|
if (!canSubmit) return false;
|
|
2828
3369
|
setSubmitting(true);
|
|
@@ -2856,32 +3397,32 @@ function useLoginForm() {
|
|
|
2856
3397
|
}
|
|
2857
3398
|
|
|
2858
3399
|
// src/hooks/useSignupForm.ts
|
|
2859
|
-
import { useCallback as
|
|
2860
|
-
import { useHook as
|
|
2861
|
-
var
|
|
3400
|
+
import { useCallback as useCallback8, useMemo as useMemo8, useState as useState11 } from "react";
|
|
3401
|
+
import { useHook as useHook13 } from "@hook-sdk/sdk";
|
|
3402
|
+
var EMAIL_RE3 = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
2862
3403
|
var MIN_PASSWORD2 = 8;
|
|
2863
3404
|
function useSignupForm() {
|
|
2864
|
-
const { auth } =
|
|
2865
|
-
const [name, setName] =
|
|
2866
|
-
const [email, setEmail] =
|
|
2867
|
-
const [password, setPassword] =
|
|
2868
|
-
const [submitting, setSubmitting] =
|
|
2869
|
-
const [error, setError] =
|
|
2870
|
-
const [touchedName, setTouchedName] =
|
|
2871
|
-
const [touchedEmail, setTouchedEmail] =
|
|
2872
|
-
const [touchedPassword, setTouchedPassword] =
|
|
2873
|
-
const [formSubmitAttempted, setFormSubmitAttempted] =
|
|
2874
|
-
const validateName =
|
|
3405
|
+
const { auth } = useHook13();
|
|
3406
|
+
const [name, setName] = useState11("");
|
|
3407
|
+
const [email, setEmail] = useState11("");
|
|
3408
|
+
const [password, setPassword] = useState11("");
|
|
3409
|
+
const [submitting, setSubmitting] = useState11(false);
|
|
3410
|
+
const [error, setError] = useState11(null);
|
|
3411
|
+
const [touchedName, setTouchedName] = useState11(false);
|
|
3412
|
+
const [touchedEmail, setTouchedEmail] = useState11(false);
|
|
3413
|
+
const [touchedPassword, setTouchedPassword] = useState11(false);
|
|
3414
|
+
const [formSubmitAttempted, setFormSubmitAttempted] = useState11(false);
|
|
3415
|
+
const validateName = useMemo8(() => {
|
|
2875
3416
|
if (name.length === 0) return null;
|
|
2876
3417
|
if (name.trim().length < 2) return "Nome muito curto.";
|
|
2877
3418
|
return null;
|
|
2878
3419
|
}, [name]);
|
|
2879
|
-
const validateEmail =
|
|
3420
|
+
const validateEmail = useMemo8(() => {
|
|
2880
3421
|
if (email.length === 0) return null;
|
|
2881
|
-
if (!
|
|
3422
|
+
if (!EMAIL_RE3.test(email)) return "Formato de e-mail inv\xE1lido.";
|
|
2882
3423
|
return null;
|
|
2883
3424
|
}, [email]);
|
|
2884
|
-
const validatePassword =
|
|
3425
|
+
const validatePassword = useMemo8(() => {
|
|
2885
3426
|
if (password.length === 0) return null;
|
|
2886
3427
|
if (password.length < MIN_PASSWORD2) return `M\xEDnimo de ${MIN_PASSWORD2} caracteres.`;
|
|
2887
3428
|
return null;
|
|
@@ -2890,7 +3431,7 @@ function useSignupForm() {
|
|
|
2890
3431
|
const emailError = touchedEmail || formSubmitAttempted ? validateEmail : null;
|
|
2891
3432
|
const passwordError = touchedPassword || formSubmitAttempted ? validatePassword : null;
|
|
2892
3433
|
const canSubmit = name.trim().length >= 2 && email.length > 0 && password.length >= MIN_PASSWORD2 && validateName === null && validateEmail === null && validatePassword === null && !submitting;
|
|
2893
|
-
const submit =
|
|
3434
|
+
const submit = useCallback8(async () => {
|
|
2894
3435
|
setFormSubmitAttempted(true);
|
|
2895
3436
|
if (!canSubmit) return false;
|
|
2896
3437
|
setSubmitting(true);
|
|
@@ -2928,25 +3469,25 @@ function useSignupForm() {
|
|
|
2928
3469
|
}
|
|
2929
3470
|
|
|
2930
3471
|
// src/hooks/useForgotForm.ts
|
|
2931
|
-
import { useCallback as
|
|
2932
|
-
import { useHook as
|
|
2933
|
-
var
|
|
3472
|
+
import { useCallback as useCallback9, useMemo as useMemo9, useState as useState12 } from "react";
|
|
3473
|
+
import { useHook as useHook14 } from "@hook-sdk/sdk";
|
|
3474
|
+
var EMAIL_RE4 = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
2934
3475
|
function useForgotForm() {
|
|
2935
|
-
const { auth } =
|
|
2936
|
-
const [email, setEmail] =
|
|
2937
|
-
const [submitting, setSubmitting] =
|
|
2938
|
-
const [sent, setSent] =
|
|
2939
|
-
const [error, setError] =
|
|
2940
|
-
const [touchedEmail, setTouchedEmail] =
|
|
2941
|
-
const [formSubmitAttempted, setFormSubmitAttempted] =
|
|
2942
|
-
const validateEmail =
|
|
3476
|
+
const { auth } = useHook14();
|
|
3477
|
+
const [email, setEmail] = useState12("");
|
|
3478
|
+
const [submitting, setSubmitting] = useState12(false);
|
|
3479
|
+
const [sent, setSent] = useState12(false);
|
|
3480
|
+
const [error, setError] = useState12(null);
|
|
3481
|
+
const [touchedEmail, setTouchedEmail] = useState12(false);
|
|
3482
|
+
const [formSubmitAttempted, setFormSubmitAttempted] = useState12(false);
|
|
3483
|
+
const validateEmail = useMemo9(() => {
|
|
2943
3484
|
if (email.length === 0) return null;
|
|
2944
|
-
if (!
|
|
3485
|
+
if (!EMAIL_RE4.test(email)) return "Formato de e-mail inv\xE1lido.";
|
|
2945
3486
|
return null;
|
|
2946
3487
|
}, [email]);
|
|
2947
3488
|
const emailError = touchedEmail || formSubmitAttempted ? validateEmail : null;
|
|
2948
3489
|
const canSubmit = email.length > 0 && validateEmail === null && !submitting;
|
|
2949
|
-
const submit =
|
|
3490
|
+
const submit = useCallback9(async () => {
|
|
2950
3491
|
setFormSubmitAttempted(true);
|
|
2951
3492
|
if (!canSubmit) return false;
|
|
2952
3493
|
setSubmitting(true);
|
|
@@ -2977,32 +3518,32 @@ function useForgotForm() {
|
|
|
2977
3518
|
}
|
|
2978
3519
|
|
|
2979
3520
|
// src/hooks/useResetForm.ts
|
|
2980
|
-
import { useCallback as
|
|
2981
|
-
import { useHook as
|
|
3521
|
+
import { useCallback as useCallback10, useEffect as useEffect13, useMemo as useMemo10, useState as useState13 } from "react";
|
|
3522
|
+
import { useHook as useHook15 } from "@hook-sdk/sdk";
|
|
2982
3523
|
var MIN_PASSWORD3 = 12;
|
|
2983
3524
|
function useResetForm() {
|
|
2984
|
-
const { auth } =
|
|
2985
|
-
const [token, setToken] =
|
|
2986
|
-
const [password, setPassword] =
|
|
2987
|
-
const [confirm, setConfirm] =
|
|
2988
|
-
const [submitting, setSubmitting] =
|
|
2989
|
-
const [done, setDone] =
|
|
2990
|
-
const [error, setError] =
|
|
2991
|
-
const [touchedPassword, setTouchedPassword] =
|
|
2992
|
-
const [touchedConfirm, setTouchedConfirm] =
|
|
2993
|
-
const [formSubmitAttempted, setFormSubmitAttempted] =
|
|
2994
|
-
|
|
3525
|
+
const { auth } = useHook15();
|
|
3526
|
+
const [token, setToken] = useState13(null);
|
|
3527
|
+
const [password, setPassword] = useState13("");
|
|
3528
|
+
const [confirm, setConfirm] = useState13("");
|
|
3529
|
+
const [submitting, setSubmitting] = useState13(false);
|
|
3530
|
+
const [done, setDone] = useState13(false);
|
|
3531
|
+
const [error, setError] = useState13(null);
|
|
3532
|
+
const [touchedPassword, setTouchedPassword] = useState13(false);
|
|
3533
|
+
const [touchedConfirm, setTouchedConfirm] = useState13(false);
|
|
3534
|
+
const [formSubmitAttempted, setFormSubmitAttempted] = useState13(false);
|
|
3535
|
+
useEffect13(() => {
|
|
2995
3536
|
if (typeof window === "undefined") return;
|
|
2996
3537
|
const params = new URLSearchParams(window.location.search);
|
|
2997
3538
|
const t = params.get("token");
|
|
2998
3539
|
setToken(t && t.length > 0 ? t : null);
|
|
2999
3540
|
}, []);
|
|
3000
|
-
const validatePassword =
|
|
3541
|
+
const validatePassword = useMemo10(() => {
|
|
3001
3542
|
if (password.length === 0) return null;
|
|
3002
3543
|
if (password.length < MIN_PASSWORD3) return `M\xEDnimo de ${MIN_PASSWORD3} caracteres.`;
|
|
3003
3544
|
return null;
|
|
3004
3545
|
}, [password]);
|
|
3005
|
-
const validateConfirm =
|
|
3546
|
+
const validateConfirm = useMemo10(() => {
|
|
3006
3547
|
if (confirm.length === 0) return null;
|
|
3007
3548
|
if (confirm !== password) return "Senhas n\xE3o coincidem.";
|
|
3008
3549
|
return null;
|
|
@@ -3010,7 +3551,7 @@ function useResetForm() {
|
|
|
3010
3551
|
const passwordError = touchedPassword || formSubmitAttempted ? validatePassword : null;
|
|
3011
3552
|
const confirmError = touchedConfirm || formSubmitAttempted ? validateConfirm : null;
|
|
3012
3553
|
const canSubmit = token !== null && password.length >= MIN_PASSWORD3 && confirm === password && validatePassword === null && validateConfirm === null && !submitting && !done;
|
|
3013
|
-
const submit =
|
|
3554
|
+
const submit = useCallback10(async () => {
|
|
3014
3555
|
setFormSubmitAttempted(true);
|
|
3015
3556
|
if (!canSubmit || token === null) return;
|
|
3016
3557
|
setSubmitting(true);
|
|
@@ -3049,13 +3590,6 @@ function useResetForm() {
|
|
|
3049
3590
|
};
|
|
3050
3591
|
}
|
|
3051
3592
|
|
|
3052
|
-
// src/hooks/usePlan.ts
|
|
3053
|
-
import { useHook as useHook14 } from "@hook-sdk/sdk";
|
|
3054
|
-
function usePlan() {
|
|
3055
|
-
const { plan } = useHook14();
|
|
3056
|
-
return plan;
|
|
3057
|
-
}
|
|
3058
|
-
|
|
3059
3593
|
// src/utils/price.ts
|
|
3060
3594
|
function formatBRL(cents) {
|
|
3061
3595
|
if (cents === null || cents === void 0) return "";
|
|
@@ -3085,12 +3619,12 @@ function discountPercent(anchorCents, realCents) {
|
|
|
3085
3619
|
}
|
|
3086
3620
|
|
|
3087
3621
|
// src/hooks/useAuthPrimitives.ts
|
|
3088
|
-
import { useEffect as
|
|
3089
|
-
import { useHook as
|
|
3622
|
+
import { useEffect as useEffect14 } from "react";
|
|
3623
|
+
import { useHook as useHook16 } from "@hook-sdk/sdk";
|
|
3090
3624
|
var warned = false;
|
|
3091
3625
|
function useAuthPrimitives() {
|
|
3092
|
-
const { auth } =
|
|
3093
|
-
|
|
3626
|
+
const { auth } = useHook16();
|
|
3627
|
+
useEffect14(() => {
|
|
3094
3628
|
if (!warned && process.env.NODE_ENV !== "production") {
|
|
3095
3629
|
warned = true;
|
|
3096
3630
|
console.warn(
|
|
@@ -3112,9 +3646,9 @@ function useAuthPrimitives() {
|
|
|
3112
3646
|
}
|
|
3113
3647
|
|
|
3114
3648
|
// src/hooks/useAuth.ts
|
|
3115
|
-
import { useHook as
|
|
3649
|
+
import { useHook as useHook17 } from "@hook-sdk/sdk";
|
|
3116
3650
|
function useAuth() {
|
|
3117
|
-
const { user, authStatus, auth } =
|
|
3651
|
+
const { user, authStatus, auth } = useHook17();
|
|
3118
3652
|
return {
|
|
3119
3653
|
user,
|
|
3120
3654
|
authStatus,
|
|
@@ -3126,23 +3660,23 @@ function useAuth() {
|
|
|
3126
3660
|
import { useTrackOnboardingStep } from "@hook-sdk/sdk";
|
|
3127
3661
|
|
|
3128
3662
|
// src/hooks/useSubscription.ts
|
|
3129
|
-
import { useHook as
|
|
3663
|
+
import { useHook as useHook18 } from "@hook-sdk/sdk";
|
|
3130
3664
|
function useSubscription() {
|
|
3131
|
-
const { subscription } =
|
|
3665
|
+
const { subscription } = useHook18();
|
|
3132
3666
|
return {
|
|
3133
3667
|
status: subscription.status()
|
|
3134
3668
|
};
|
|
3135
3669
|
}
|
|
3136
3670
|
|
|
3137
3671
|
// src/hooks/useReminders.ts
|
|
3138
|
-
import { useCallback as
|
|
3139
|
-
import { useHook as
|
|
3672
|
+
import { useCallback as useCallback11, useEffect as useEffect15, useState as useState14 } from "react";
|
|
3673
|
+
import { useHook as useHook19 } from "@hook-sdk/sdk";
|
|
3140
3674
|
function useReminders() {
|
|
3141
|
-
const { push } =
|
|
3675
|
+
const { push } = useHook19();
|
|
3142
3676
|
const r = push.reminders;
|
|
3143
|
-
const [reminders, setReminders] =
|
|
3144
|
-
const [loading, setLoading] =
|
|
3145
|
-
const reload =
|
|
3677
|
+
const [reminders, setReminders] = useState14([]);
|
|
3678
|
+
const [loading, setLoading] = useState14(true);
|
|
3679
|
+
const reload = useCallback11(async () => {
|
|
3146
3680
|
setLoading(true);
|
|
3147
3681
|
try {
|
|
3148
3682
|
const next = await r.list();
|
|
@@ -3151,38 +3685,38 @@ function useReminders() {
|
|
|
3151
3685
|
setLoading(false);
|
|
3152
3686
|
}
|
|
3153
3687
|
}, [r]);
|
|
3154
|
-
|
|
3688
|
+
useEffect15(() => {
|
|
3155
3689
|
void reload();
|
|
3156
3690
|
}, [reload]);
|
|
3157
|
-
const setReminder =
|
|
3691
|
+
const setReminder = useCallback11(async (input) => {
|
|
3158
3692
|
await r.set(input);
|
|
3159
3693
|
await reload();
|
|
3160
3694
|
}, [r, reload]);
|
|
3161
|
-
const deleteReminder =
|
|
3695
|
+
const deleteReminder = useCallback11(async (slot) => {
|
|
3162
3696
|
await r.delete(slot);
|
|
3163
3697
|
await reload();
|
|
3164
3698
|
}, [r, reload]);
|
|
3165
|
-
const schedule =
|
|
3699
|
+
const schedule = useCallback11(async (items) => {
|
|
3166
3700
|
return r.schedule(items);
|
|
3167
3701
|
}, [r]);
|
|
3168
|
-
const setFallbacks =
|
|
3702
|
+
const setFallbacks = useCallback11(async (items) => {
|
|
3169
3703
|
return r.setFallbacks(items);
|
|
3170
3704
|
}, [r]);
|
|
3171
3705
|
return { reminders, loading, setReminder, deleteReminder, schedule, setFallbacks };
|
|
3172
3706
|
}
|
|
3173
3707
|
|
|
3174
3708
|
// src/hooks/useToast.ts
|
|
3175
|
-
import { useCallback as
|
|
3709
|
+
import { useCallback as useCallback12, useState as useState15 } from "react";
|
|
3176
3710
|
function useToast() {
|
|
3177
|
-
const [items, setItems] =
|
|
3178
|
-
const show =
|
|
3711
|
+
const [items, setItems] = useState15([]);
|
|
3712
|
+
const show = useCallback12((message, kind = "info") => {
|
|
3179
3713
|
const id = `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
3180
3714
|
setItems((prev) => [...prev, { id, message, kind }]);
|
|
3181
3715
|
setTimeout(() => {
|
|
3182
3716
|
setItems((prev) => prev.filter((t) => t.id !== id));
|
|
3183
3717
|
}, 4e3);
|
|
3184
3718
|
}, []);
|
|
3185
|
-
const dismiss =
|
|
3719
|
+
const dismiss = useCallback12((id) => {
|
|
3186
3720
|
setItems((prev) => prev.filter((t) => t.id !== id));
|
|
3187
3721
|
}, []);
|
|
3188
3722
|
return { items, show, dismiss };
|
|
@@ -3190,20 +3724,20 @@ function useToast() {
|
|
|
3190
3724
|
|
|
3191
3725
|
// src/RouteBoundary.tsx
|
|
3192
3726
|
import { Routes as Routes2, Route as Route2 } from "react-router-dom";
|
|
3193
|
-
import { jsx as
|
|
3727
|
+
import { jsx as jsx29, jsxs as jsxs20 } from "react/jsx-runtime";
|
|
3194
3728
|
function RouteBoundary({ children }) {
|
|
3195
|
-
return /* @__PURE__ */
|
|
3729
|
+
return /* @__PURE__ */ jsxs20(Routes2, { children: [
|
|
3196
3730
|
children,
|
|
3197
|
-
/* @__PURE__ */
|
|
3731
|
+
/* @__PURE__ */ jsx29(Route2, { path: "*", element: /* @__PURE__ */ jsx29(DefaultNotFound, {}) })
|
|
3198
3732
|
] });
|
|
3199
3733
|
}
|
|
3200
3734
|
function DefaultNotFound() {
|
|
3201
|
-
return /* @__PURE__ */
|
|
3735
|
+
return /* @__PURE__ */ jsx29("div", { role: "alert", children: "P\xE1gina n\xE3o encontrada" });
|
|
3202
3736
|
}
|
|
3203
3737
|
|
|
3204
3738
|
// src/PreAuthShell.tsx
|
|
3205
3739
|
import { BrowserRouter as BrowserRouter2, MemoryRouter as MemoryRouter2, Routes as Routes3 } from "react-router-dom";
|
|
3206
|
-
import { jsx as
|
|
3740
|
+
import { jsx as jsx30 } from "react/jsx-runtime";
|
|
3207
3741
|
function PreAuthShell({
|
|
3208
3742
|
basename,
|
|
3209
3743
|
testRouter,
|
|
@@ -3211,14 +3745,14 @@ function PreAuthShell({
|
|
|
3211
3745
|
children
|
|
3212
3746
|
}) {
|
|
3213
3747
|
if (testRouter === "memory") {
|
|
3214
|
-
return /* @__PURE__ */
|
|
3748
|
+
return /* @__PURE__ */ jsx30(MemoryRouter2, { basename, initialEntries: testInitialEntries, children: /* @__PURE__ */ jsx30(Routes3, { children }) });
|
|
3215
3749
|
}
|
|
3216
|
-
return /* @__PURE__ */
|
|
3750
|
+
return /* @__PURE__ */ jsx30(BrowserRouter2, { basename, children: /* @__PURE__ */ jsx30(Routes3, { children }) });
|
|
3217
3751
|
}
|
|
3218
3752
|
|
|
3219
3753
|
// src/OnboardingFlow.tsx
|
|
3220
|
-
import { useCallback as
|
|
3221
|
-
import { usePersistedState as usePersistedState3, useHook as
|
|
3754
|
+
import { useCallback as useCallback13, useEffect as useEffect16, useMemo as useMemo11, useRef as useRef7 } from "react";
|
|
3755
|
+
import { usePersistedState as usePersistedState3, useHook as useHook20 } from "@hook-sdk/sdk";
|
|
3222
3756
|
|
|
3223
3757
|
// src/hooks/useOnboardingStep.ts
|
|
3224
3758
|
import { createContext as createContext3, useContext as useContext4 } from "react";
|
|
@@ -3234,7 +3768,7 @@ function useOnboardingStep() {
|
|
|
3234
3768
|
}
|
|
3235
3769
|
|
|
3236
3770
|
// src/OnboardingFlow.tsx
|
|
3237
|
-
import { jsx as
|
|
3771
|
+
import { jsx as jsx31 } from "react/jsx-runtime";
|
|
3238
3772
|
var isFilled = (v) => v != null && v !== "";
|
|
3239
3773
|
var CURRENT_STEP_FIELD = "currentStep";
|
|
3240
3774
|
function readPersistedStepIdx(draft) {
|
|
@@ -3248,11 +3782,11 @@ function OnboardingFlow({
|
|
|
3248
3782
|
persistKey
|
|
3249
3783
|
}) {
|
|
3250
3784
|
const [draft, setDraft, status] = usePersistedState3(persistKey, {});
|
|
3251
|
-
const draftRef =
|
|
3785
|
+
const draftRef = useRef7(draft);
|
|
3252
3786
|
draftRef.current = draft;
|
|
3253
3787
|
const idx = readPersistedStepIdx(draft);
|
|
3254
3788
|
const clampedIdx = Math.min(Math.max(idx, 0), Math.max(steps.length - 1, 0));
|
|
3255
|
-
const setIdx =
|
|
3789
|
+
const setIdx = useCallback13(
|
|
3256
3790
|
(n) => {
|
|
3257
3791
|
setDraft((prev) => {
|
|
3258
3792
|
const prevIdx = readPersistedStepIdx(prev);
|
|
@@ -3262,7 +3796,7 @@ function OnboardingFlow({
|
|
|
3262
3796
|
},
|
|
3263
3797
|
[setDraft]
|
|
3264
3798
|
);
|
|
3265
|
-
const setValue =
|
|
3799
|
+
const setValue = useCallback13(
|
|
3266
3800
|
(patch) => {
|
|
3267
3801
|
draftRef.current = { ...draftRef.current, ...patch };
|
|
3268
3802
|
setDraft((prev) => ({ ...prev, ...patch }));
|
|
@@ -3270,9 +3804,9 @@ function OnboardingFlow({
|
|
|
3270
3804
|
[setDraft]
|
|
3271
3805
|
);
|
|
3272
3806
|
const step = steps[clampedIdx];
|
|
3273
|
-
const hookCtx =
|
|
3807
|
+
const hookCtx = useHook20();
|
|
3274
3808
|
const track2 = typeof hookCtx.track === "function" ? hookCtx.track : void 0;
|
|
3275
|
-
|
|
3809
|
+
useEffect16(() => {
|
|
3276
3810
|
if (status.loading) return;
|
|
3277
3811
|
if (!step) return;
|
|
3278
3812
|
if (!track2) return;
|
|
@@ -3282,11 +3816,11 @@ function OnboardingFlow({
|
|
|
3282
3816
|
total_steps: steps.length
|
|
3283
3817
|
});
|
|
3284
3818
|
}, [step?.id, clampedIdx, steps.length, status.loading, track2]);
|
|
3285
|
-
const valid =
|
|
3819
|
+
const valid = useMemo11(
|
|
3286
3820
|
() => step ? (step.validates ?? []).every((field) => isFilled(draft[field])) : false,
|
|
3287
3821
|
[draft, step]
|
|
3288
3822
|
);
|
|
3289
|
-
const next =
|
|
3823
|
+
const next = useCallback13(() => {
|
|
3290
3824
|
if (!step) return;
|
|
3291
3825
|
const current = draftRef.current;
|
|
3292
3826
|
const validNow = (step.validates ?? []).every((field) => isFilled(current[field]));
|
|
@@ -3297,8 +3831,8 @@ function OnboardingFlow({
|
|
|
3297
3831
|
setIdx(clampedIdx + 1);
|
|
3298
3832
|
}
|
|
3299
3833
|
}, [clampedIdx, onComplete, step, steps.length, setIdx]);
|
|
3300
|
-
const prevStep =
|
|
3301
|
-
const ctx =
|
|
3834
|
+
const prevStep = useCallback13(() => setIdx((i) => Math.max(0, i - 1)), [setIdx]);
|
|
3835
|
+
const ctx = useMemo11(
|
|
3302
3836
|
() => ({
|
|
3303
3837
|
stepIndex: clampedIdx,
|
|
3304
3838
|
totalSteps: steps.length,
|
|
@@ -3324,7 +3858,7 @@ function OnboardingFlow({
|
|
|
3324
3858
|
`[hook-template] OnboardingFlow: missing screen component for step '${step.id}' (expected key '${step.screen}' in screens prop)`
|
|
3325
3859
|
);
|
|
3326
3860
|
}
|
|
3327
|
-
return /* @__PURE__ */
|
|
3861
|
+
return /* @__PURE__ */ jsx31(OnboardingStepContext.Provider, { value: ctx, children: /* @__PURE__ */ jsx31(Screen, {}) });
|
|
3328
3862
|
}
|
|
3329
3863
|
|
|
3330
3864
|
// src/hooks/useFeature.ts
|
|
@@ -3334,40 +3868,23 @@ function useFeature(name) {
|
|
|
3334
3868
|
}
|
|
3335
3869
|
|
|
3336
3870
|
// src/components/paywall/Paywall.tsx
|
|
3337
|
-
import { useEffect as
|
|
3338
|
-
import { useHook as
|
|
3339
|
-
|
|
3340
|
-
// src/components/paywall/PaywallProvider.tsx
|
|
3341
|
-
import { createContext as createContext4 } from "react";
|
|
3342
|
-
import { jsx as jsx31 } from "react/jsx-runtime";
|
|
3343
|
-
var PaywallContext = createContext4(null);
|
|
3344
|
-
function PaywallProvider({ children }) {
|
|
3345
|
-
const state = usePaywallState();
|
|
3346
|
-
return /* @__PURE__ */ jsx31(PaywallContext.Provider, { value: state, children });
|
|
3347
|
-
}
|
|
3348
|
-
|
|
3349
|
-
// src/components/paywall/usePaywallContext.ts
|
|
3350
|
-
import { useContext as useContext5 } from "react";
|
|
3351
|
-
function usePaywallContext() {
|
|
3352
|
-
const ctx = useContext5(PaywallContext);
|
|
3353
|
-
if (!ctx) {
|
|
3354
|
-
throw new Error("usePaywallContext must be used within <PaywallProvider>");
|
|
3355
|
-
}
|
|
3356
|
-
return ctx;
|
|
3357
|
-
}
|
|
3871
|
+
import { useEffect as useEffect17, useMemo as useMemo12 } from "react";
|
|
3872
|
+
import { useHook as useHook21 } from "@hook-sdk/sdk";
|
|
3358
3873
|
|
|
3359
3874
|
// src/components/paywall/PaywallMethodTabs.tsx
|
|
3360
3875
|
import { jsx as jsx32 } from "react/jsx-runtime";
|
|
3361
3876
|
function PaywallMethodTabs({
|
|
3877
|
+
methods,
|
|
3878
|
+
selected,
|
|
3879
|
+
onSelect,
|
|
3362
3880
|
labels,
|
|
3363
3881
|
className,
|
|
3364
3882
|
tabClassName,
|
|
3365
3883
|
tabActiveClassName
|
|
3366
3884
|
}) {
|
|
3367
|
-
const { methods, selectedMethod, selectMethod } = usePaywallContext();
|
|
3368
3885
|
if (methods.length < 2) return null;
|
|
3369
3886
|
return /* @__PURE__ */ jsx32("div", { role: "tablist", "aria-label": "M\xE9todo de pagamento", className, children: methods.map((m) => {
|
|
3370
|
-
const active = m ===
|
|
3887
|
+
const active = m === selected;
|
|
3371
3888
|
const label = labels[m] ?? m;
|
|
3372
3889
|
return /* @__PURE__ */ jsx32(
|
|
3373
3890
|
"button",
|
|
@@ -3377,7 +3894,7 @@ function PaywallMethodTabs({
|
|
|
3377
3894
|
"aria-selected": active,
|
|
3378
3895
|
"aria-controls": `paywall-tab-${m}`,
|
|
3379
3896
|
tabIndex: active ? 0 : -1,
|
|
3380
|
-
onClick: () =>
|
|
3897
|
+
onClick: () => onSelect(m),
|
|
3381
3898
|
className: [tabClassName, active ? tabActiveClassName : ""].filter(Boolean).join(" "),
|
|
3382
3899
|
children: label
|
|
3383
3900
|
},
|
|
@@ -3388,49 +3905,34 @@ function PaywallMethodTabs({
|
|
|
3388
3905
|
|
|
3389
3906
|
// src/components/paywall/PaywallMethodContent.tsx
|
|
3390
3907
|
import { jsx as jsx33 } from "react/jsx-runtime";
|
|
3391
|
-
function PaywallMethodContent({
|
|
3392
|
-
|
|
3393
|
-
|
|
3394
|
-
|
|
3395
|
-
|
|
3908
|
+
function PaywallMethodContent({
|
|
3909
|
+
method,
|
|
3910
|
+
copy,
|
|
3911
|
+
hasConsumedTrial = false,
|
|
3912
|
+
className,
|
|
3913
|
+
rowClassName
|
|
3914
|
+
}) {
|
|
3915
|
+
const useCardConsumed = method === "card" && hasConsumedTrial && copy.cardConsumedTrial;
|
|
3916
|
+
const rows = useCardConsumed ? copy.cardConsumedTrial.bodyRows : method === "pix-auto" || method === "pix-once" ? copy.pix.bodyRows : copy.card.bodyRows;
|
|
3917
|
+
return /* @__PURE__ */ jsx33("div", { role: "tabpanel", id: `paywall-tab-${method}`, className, children: rows.map((row, i) => /* @__PURE__ */ jsx33("div", { className: rowClassName, children: row }, i)) });
|
|
3396
3918
|
}
|
|
3397
3919
|
|
|
3398
3920
|
// src/components/paywall/PaywallCyclePicker.tsx
|
|
3399
|
-
import { jsx as jsx34, jsxs as
|
|
3400
|
-
var VARIANT_CLASSES = {
|
|
3401
|
-
default: { card: "", cardSelected: "" },
|
|
3402
|
-
"premium-gold": {
|
|
3403
|
-
card: "",
|
|
3404
|
-
cardSelected: "border-2 border-yellow-400/80 ring-2 ring-yellow-400/20"
|
|
3405
|
-
},
|
|
3406
|
-
"pink-pill": {
|
|
3407
|
-
card: "rounded-2xl",
|
|
3408
|
-
cardSelected: "border-2 border-pink-500"
|
|
3409
|
-
}
|
|
3410
|
-
};
|
|
3921
|
+
import { jsx as jsx34, jsxs as jsxs21 } from "react/jsx-runtime";
|
|
3411
3922
|
function PaywallCyclePicker({
|
|
3923
|
+
cycles,
|
|
3924
|
+
selected,
|
|
3925
|
+
onSelect,
|
|
3926
|
+
priceCentsByCycle,
|
|
3927
|
+
anchorCentsByCycle,
|
|
3928
|
+
monthlyEquivByCycle,
|
|
3412
3929
|
labels,
|
|
3413
3930
|
className,
|
|
3414
3931
|
cardClassName,
|
|
3415
3932
|
cardSelectedClassName,
|
|
3416
|
-
anchorClassName
|
|
3417
|
-
variant = "default",
|
|
3418
|
-
render
|
|
3933
|
+
anchorClassName
|
|
3419
3934
|
}) {
|
|
3420
|
-
const ctx = usePaywallContext();
|
|
3421
|
-
const { cycle: selected, setCycle, plan, anchorPriceCents } = ctx;
|
|
3422
|
-
const cycles = ["MONTHLY", "YEARLY"];
|
|
3423
|
-
if (render) {
|
|
3424
|
-
return /* @__PURE__ */ jsx34("div", { className, children: render({ cycles, selected, setCycle, plan, anchorPriceCents }) });
|
|
3425
|
-
}
|
|
3426
3935
|
if (cycles.length < 2) return null;
|
|
3427
|
-
const v = VARIANT_CLASSES[variant];
|
|
3428
|
-
const composedCardClassName = [v.card, cardClassName].filter(Boolean).join(" ");
|
|
3429
|
-
const composedCardSelectedClassName = [v.cardSelected, cardSelectedClassName].filter(Boolean).join(" ");
|
|
3430
|
-
const monthlyCents = plan?.monthlyCents ?? 0;
|
|
3431
|
-
const yearlyCents = plan?.yearlyCents ?? 0;
|
|
3432
|
-
const anchorMonthly = plan?.anchorMonthlyCents ?? null;
|
|
3433
|
-
const anchorYearly = plan?.anchorYearlyCents ?? null;
|
|
3434
3936
|
return /* @__PURE__ */ jsx34(
|
|
3435
3937
|
"div",
|
|
3436
3938
|
{
|
|
@@ -3441,20 +3943,16 @@ function PaywallCyclePicker({
|
|
|
3441
3943
|
const active = c === selected;
|
|
3442
3944
|
const label = c === "YEARLY" ? labels.annualLabel : labels.monthlyLabel;
|
|
3443
3945
|
const suffix = c === "YEARLY" ? labels.annualSuffix : labels.monthlySuffix;
|
|
3444
|
-
const mainCents = c === "YEARLY" ?
|
|
3445
|
-
const anchorCents = c
|
|
3446
|
-
return /* @__PURE__ */
|
|
3946
|
+
const mainCents = c === "YEARLY" ? monthlyEquivByCycle[c] : priceCentsByCycle[c];
|
|
3947
|
+
const anchorCents = anchorCentsByCycle[c];
|
|
3948
|
+
return /* @__PURE__ */ jsxs21(
|
|
3447
3949
|
"button",
|
|
3448
3950
|
{
|
|
3449
3951
|
type: "button",
|
|
3450
3952
|
role: "radio",
|
|
3451
3953
|
"aria-checked": active,
|
|
3452
|
-
onClick: () =>
|
|
3453
|
-
className: [
|
|
3454
|
-
"flex flex-col items-center gap-0.5",
|
|
3455
|
-
composedCardClassName,
|
|
3456
|
-
active ? composedCardSelectedClassName : ""
|
|
3457
|
-
].filter(Boolean).join(" "),
|
|
3954
|
+
onClick: () => onSelect(c),
|
|
3955
|
+
className: ["flex flex-col items-center gap-0.5", cardClassName, active ? cardSelectedClassName : ""].filter(Boolean).join(" "),
|
|
3458
3956
|
children: [
|
|
3459
3957
|
/* @__PURE__ */ jsx34("span", { className: "font-bold text-base leading-tight", children: formatBRL(mainCents) }),
|
|
3460
3958
|
/* @__PURE__ */ jsx34("span", { className: "text-xs opacity-70 leading-tight", children: suffix }),
|
|
@@ -3469,8 +3967,40 @@ function PaywallCyclePicker({
|
|
|
3469
3967
|
);
|
|
3470
3968
|
}
|
|
3471
3969
|
|
|
3970
|
+
// src/components/paywall/PaywallCta.tsx
|
|
3971
|
+
import { jsx as jsx35, jsxs as jsxs22 } from "react/jsx-runtime";
|
|
3972
|
+
function PaywallCta({
|
|
3973
|
+
ctaLabel,
|
|
3974
|
+
loadingLabel,
|
|
3975
|
+
switchHint,
|
|
3976
|
+
trustLine,
|
|
3977
|
+
onClick,
|
|
3978
|
+
disabled = false,
|
|
3979
|
+
loading = false,
|
|
3980
|
+
className,
|
|
3981
|
+
buttonClassName,
|
|
3982
|
+
switchHintClassName,
|
|
3983
|
+
trustClassName
|
|
3984
|
+
}) {
|
|
3985
|
+
const label = loading && loadingLabel ? loadingLabel : ctaLabel;
|
|
3986
|
+
return /* @__PURE__ */ jsxs22("div", { className, children: [
|
|
3987
|
+
/* @__PURE__ */ jsx35(
|
|
3988
|
+
"button",
|
|
3989
|
+
{
|
|
3990
|
+
type: "button",
|
|
3991
|
+
onClick,
|
|
3992
|
+
disabled: disabled || loading,
|
|
3993
|
+
className: buttonClassName,
|
|
3994
|
+
children: label
|
|
3995
|
+
}
|
|
3996
|
+
),
|
|
3997
|
+
switchHint ? /* @__PURE__ */ jsx35("p", { className: switchHintClassName, children: switchHint }) : null,
|
|
3998
|
+
/* @__PURE__ */ jsx35("p", { className: trustClassName, children: trustLine })
|
|
3999
|
+
] });
|
|
4000
|
+
}
|
|
4001
|
+
|
|
3472
4002
|
// src/components/paywall/Paywall.tsx
|
|
3473
|
-
import { jsx as
|
|
4003
|
+
import { jsx as jsx36, jsxs as jsxs23 } from "react/jsx-runtime";
|
|
3474
4004
|
var NBSP = "\xA0";
|
|
3475
4005
|
function Paywall({
|
|
3476
4006
|
copy,
|
|
@@ -3478,42 +4008,21 @@ function Paywall({
|
|
|
3478
4008
|
slots = {},
|
|
3479
4009
|
onBeforeCheckout
|
|
3480
4010
|
}) {
|
|
3481
|
-
|
|
3482
|
-
|
|
3483
|
-
{
|
|
3484
|
-
copy,
|
|
3485
|
-
themeClasses,
|
|
3486
|
-
slots,
|
|
3487
|
-
onBeforeCheckout
|
|
3488
|
-
}
|
|
3489
|
-
) });
|
|
3490
|
-
}
|
|
3491
|
-
function PaywallInner({
|
|
3492
|
-
copy,
|
|
3493
|
-
themeClasses = {},
|
|
3494
|
-
slots = {},
|
|
3495
|
-
onBeforeCheckout
|
|
3496
|
-
}) {
|
|
3497
|
-
const { track: track2 } = useHook20();
|
|
3498
|
-
const s = usePaywallContext();
|
|
4011
|
+
const { track: track2 } = useHook21();
|
|
4012
|
+
const s = usePaywallState();
|
|
3499
4013
|
const priceLabel = formatBRL(s.currentPriceCents).replace(new RegExp(NBSP, "g"), " ");
|
|
4014
|
+
const monthlyEquivLabel = formatBRL(s.currentMonthlyEquivCents).replace(new RegExp(NBSP, "g"), " ");
|
|
3500
4015
|
const trialDaysCardLabel = String(s.trialDaysCard);
|
|
3501
|
-
const ctaLabel =
|
|
4016
|
+
const ctaLabel = useMemo12(() => {
|
|
3502
4017
|
if (s.isFree) return copy.freeCta ?? "Come\xE7ar agora";
|
|
3503
4018
|
if (s.selectedMethod === "card") {
|
|
3504
4019
|
if (s.hasConsumedTrial && copy.cardConsumedTrial) {
|
|
3505
|
-
return interp(copy.cardConsumedTrial.ctaTemplate, {
|
|
3506
|
-
price: priceLabel,
|
|
3507
|
-
days: trialDaysCardLabel
|
|
3508
|
-
});
|
|
4020
|
+
return interp(copy.cardConsumedTrial.ctaTemplate, { price: priceLabel, days: trialDaysCardLabel });
|
|
3509
4021
|
}
|
|
3510
4022
|
if (s.trialDaysCard > 0) {
|
|
3511
4023
|
return interp(copy.card.ctaTemplate, { price: priceLabel, days: trialDaysCardLabel });
|
|
3512
4024
|
}
|
|
3513
|
-
return copy.cardConsumedTrial ? interp(copy.cardConsumedTrial.ctaTemplate, {
|
|
3514
|
-
price: priceLabel,
|
|
3515
|
-
days: trialDaysCardLabel
|
|
3516
|
-
}) : `Assinar por ${priceLabel}`;
|
|
4025
|
+
return copy.cardConsumedTrial ? interp(copy.cardConsumedTrial.ctaTemplate, { price: priceLabel, days: trialDaysCardLabel }) : `Assinar por ${priceLabel}`;
|
|
3517
4026
|
}
|
|
3518
4027
|
return interp(copy.pix.ctaTemplate, { price: priceLabel, days: trialDaysCardLabel });
|
|
3519
4028
|
}, [
|
|
@@ -3525,11 +4034,11 @@ function PaywallInner({
|
|
|
3525
4034
|
priceLabel,
|
|
3526
4035
|
trialDaysCardLabel
|
|
3527
4036
|
]);
|
|
3528
|
-
const switchHint =
|
|
4037
|
+
const switchHint = useMemo12(() => {
|
|
3529
4038
|
if (s.methods.length < 2) return void 0;
|
|
3530
4039
|
return s.selectedMethod === "card" ? copy.card.switchHint : copy.pix.switchHint;
|
|
3531
4040
|
}, [s.methods.length, s.selectedMethod, copy]);
|
|
3532
|
-
|
|
4041
|
+
useEffect17(() => {
|
|
3533
4042
|
if (!s.initialLoadComplete) return;
|
|
3534
4043
|
track2("paywall_view", {
|
|
3535
4044
|
default_method: s.selectedMethod,
|
|
@@ -3551,35 +4060,54 @@ function PaywallInner({
|
|
|
3551
4060
|
await s.submit();
|
|
3552
4061
|
};
|
|
3553
4062
|
const ctaTheme = s.selectedMethod === "card" ? themeClasses.ctaCard : themeClasses.ctaPix;
|
|
3554
|
-
return /* @__PURE__ */
|
|
4063
|
+
return /* @__PURE__ */ jsxs23("div", { className: themeClasses.container, children: [
|
|
3555
4064
|
slots.heroSlot,
|
|
3556
|
-
/* @__PURE__ */
|
|
3557
|
-
/* @__PURE__ */
|
|
4065
|
+
/* @__PURE__ */ jsx36("h1", { className: themeClasses.headline, children: copy.headline }),
|
|
4066
|
+
/* @__PURE__ */ jsx36("ul", { children: copy.features.map((f) => /* @__PURE__ */ jsxs23("li", { className: themeClasses.feature, children: [
|
|
3558
4067
|
"\u2713 ",
|
|
3559
|
-
/* @__PURE__ */
|
|
4068
|
+
/* @__PURE__ */ jsx36("span", { children: f })
|
|
3560
4069
|
] }, f)) }),
|
|
3561
|
-
copy.socialProof ? /* @__PURE__ */
|
|
3562
|
-
slots.cyclePickerSlot ?? /* @__PURE__ */
|
|
4070
|
+
copy.socialProof ? /* @__PURE__ */ jsx36("p", { className: themeClasses.socialProof, children: copy.socialProof }) : null,
|
|
4071
|
+
slots.cyclePickerSlot ?? /* @__PURE__ */ jsx36(
|
|
3563
4072
|
PaywallCyclePicker,
|
|
3564
4073
|
{
|
|
4074
|
+
cycles: ["MONTHLY", "YEARLY"],
|
|
4075
|
+
selected: s.cycle,
|
|
4076
|
+
onSelect: s.selectCycle,
|
|
4077
|
+
priceCentsByCycle: {
|
|
4078
|
+
MONTHLY: priceCentsForCycle(s, "MONTHLY"),
|
|
4079
|
+
YEARLY: priceCentsForCycle(s, "YEARLY")
|
|
4080
|
+
},
|
|
4081
|
+
anchorCentsByCycle: {
|
|
4082
|
+
MONTHLY: anchorForCycle(s, "MONTHLY"),
|
|
4083
|
+
YEARLY: anchorForCycle(s, "YEARLY")
|
|
4084
|
+
},
|
|
4085
|
+
monthlyEquivByCycle: {
|
|
4086
|
+
MONTHLY: priceCentsForCycle(s, "MONTHLY"),
|
|
4087
|
+
YEARLY: Math.round(priceCentsForCycle(s, "YEARLY") / 12)
|
|
4088
|
+
},
|
|
3565
4089
|
labels: copy.cycle,
|
|
3566
4090
|
cardClassName: themeClasses.cycleCard,
|
|
3567
4091
|
cardSelectedClassName: themeClasses.cycleCardSelected,
|
|
3568
4092
|
anchorClassName: themeClasses.anchorPrice
|
|
3569
4093
|
}
|
|
3570
4094
|
),
|
|
3571
|
-
/* @__PURE__ */
|
|
4095
|
+
/* @__PURE__ */ jsx36(
|
|
3572
4096
|
PaywallMethodTabs,
|
|
3573
4097
|
{
|
|
4098
|
+
methods: s.methods,
|
|
4099
|
+
selected: s.selectedMethod,
|
|
4100
|
+
onSelect: s.selectMethod,
|
|
3574
4101
|
labels: { "pix-auto": copy.pix.tabLabel, card: copy.card.tabLabel },
|
|
3575
4102
|
className: themeClasses.tabs,
|
|
3576
4103
|
tabClassName: themeClasses.tab,
|
|
3577
4104
|
tabActiveClassName: themeClasses.tabActive
|
|
3578
4105
|
}
|
|
3579
4106
|
),
|
|
3580
|
-
/* @__PURE__ */
|
|
4107
|
+
/* @__PURE__ */ jsx36(
|
|
3581
4108
|
PaywallMethodContent,
|
|
3582
4109
|
{
|
|
4110
|
+
method: s.selectedMethod,
|
|
3583
4111
|
copy: {
|
|
3584
4112
|
pix: interpolateCopy(copy.pix, priceLabel, trialDaysCardLabel),
|
|
3585
4113
|
card: interpolateCopy(copy.card, priceLabel, trialDaysCardLabel),
|
|
@@ -3590,27 +4118,27 @@ function PaywallInner({
|
|
|
3590
4118
|
ctaTemplate: copy.cardConsumedTrial.ctaTemplate
|
|
3591
4119
|
} : void 0
|
|
3592
4120
|
},
|
|
4121
|
+
hasConsumedTrial: s.hasConsumedTrial,
|
|
3593
4122
|
className: themeClasses.tabContent,
|
|
3594
4123
|
rowClassName: themeClasses.tabContentRow
|
|
3595
4124
|
}
|
|
3596
4125
|
),
|
|
3597
4126
|
slots.beforeCtaSlot,
|
|
3598
|
-
/* @__PURE__ */
|
|
3599
|
-
|
|
3600
|
-
|
|
3601
|
-
|
|
3602
|
-
|
|
3603
|
-
|
|
3604
|
-
|
|
3605
|
-
|
|
3606
|
-
|
|
3607
|
-
|
|
3608
|
-
|
|
3609
|
-
|
|
3610
|
-
|
|
3611
|
-
|
|
3612
|
-
|
|
3613
|
-
] })
|
|
4127
|
+
/* @__PURE__ */ jsx36(
|
|
4128
|
+
PaywallCta,
|
|
4129
|
+
{
|
|
4130
|
+
ctaLabel,
|
|
4131
|
+
loadingLabel: "Abrindo checkout\u2026",
|
|
4132
|
+
switchHint,
|
|
4133
|
+
trustLine: copy.trustLine,
|
|
4134
|
+
onClick: handleCta,
|
|
4135
|
+
disabled: s.submitting,
|
|
4136
|
+
loading: s.submitting,
|
|
4137
|
+
buttonClassName: ctaTheme,
|
|
4138
|
+
switchHintClassName: themeClasses.switchHint,
|
|
4139
|
+
trustClassName: themeClasses.trustLine
|
|
4140
|
+
}
|
|
4141
|
+
)
|
|
3614
4142
|
] });
|
|
3615
4143
|
}
|
|
3616
4144
|
function interp(tpl, vars) {
|
|
@@ -3624,443 +4152,19 @@ function interpolateCopy(m, price, days) {
|
|
|
3624
4152
|
switchHint: m.switchHint
|
|
3625
4153
|
};
|
|
3626
4154
|
}
|
|
3627
|
-
|
|
3628
|
-
|
|
3629
|
-
import { jsx as jsx36, jsxs as jsxs22 } from "react/jsx-runtime";
|
|
3630
|
-
function PaywallCta({
|
|
3631
|
-
ctaLabel,
|
|
3632
|
-
loadingLabel,
|
|
3633
|
-
switchHint,
|
|
3634
|
-
trustLine,
|
|
3635
|
-
className,
|
|
3636
|
-
buttonClassName,
|
|
3637
|
-
switchHintClassName,
|
|
3638
|
-
trustClassName
|
|
3639
|
-
}) {
|
|
3640
|
-
const { submit, submitting } = usePaywallContext();
|
|
3641
|
-
const label = submitting && loadingLabel ? loadingLabel : ctaLabel;
|
|
3642
|
-
return /* @__PURE__ */ jsxs22("div", { className, children: [
|
|
3643
|
-
/* @__PURE__ */ jsx36(
|
|
3644
|
-
"button",
|
|
3645
|
-
{
|
|
3646
|
-
type: "button",
|
|
3647
|
-
onClick: () => {
|
|
3648
|
-
void submit();
|
|
3649
|
-
},
|
|
3650
|
-
disabled: submitting,
|
|
3651
|
-
className: buttonClassName,
|
|
3652
|
-
children: label
|
|
3653
|
-
}
|
|
3654
|
-
),
|
|
3655
|
-
switchHint ? /* @__PURE__ */ jsx36("p", { className: switchHintClassName, children: switchHint }) : null,
|
|
3656
|
-
/* @__PURE__ */ jsx36("p", { className: trustClassName, children: trustLine })
|
|
3657
|
-
] });
|
|
3658
|
-
}
|
|
3659
|
-
|
|
3660
|
-
// src/components/paywall/blocks/PaywallEyebrow.tsx
|
|
3661
|
-
import { jsx as jsx37 } from "react/jsx-runtime";
|
|
3662
|
-
var DEFAULT_EYEBROW_CLASSES = "text-xs uppercase tracking-widest font-semibold opacity-70";
|
|
3663
|
-
function PaywallEyebrow({ text, className }) {
|
|
3664
|
-
return /* @__PURE__ */ jsx37("div", { className: [DEFAULT_EYEBROW_CLASSES, className].filter(Boolean).join(" "), children: text });
|
|
3665
|
-
}
|
|
3666
|
-
|
|
3667
|
-
// src/components/paywall/blocks/PaywallHero.tsx
|
|
3668
|
-
import { jsx as jsx38, jsxs as jsxs23 } from "react/jsx-runtime";
|
|
3669
|
-
var DEFAULT_GRADIENT = "absolute inset-0 bg-gradient-to-t from-black/70 via-black/20 to-transparent";
|
|
3670
|
-
function PaywallHero({
|
|
3671
|
-
src,
|
|
3672
|
-
alt = "",
|
|
3673
|
-
headline,
|
|
3674
|
-
aspectRatio = "16/9",
|
|
3675
|
-
gradientClassName,
|
|
3676
|
-
className,
|
|
3677
|
-
headlineClassName,
|
|
3678
|
-
imgClassName,
|
|
3679
|
-
render
|
|
3680
|
-
}) {
|
|
3681
|
-
if (render) {
|
|
3682
|
-
return /* @__PURE__ */ jsx38("div", { className, children: render({ src, headline }) });
|
|
3683
|
-
}
|
|
3684
|
-
return /* @__PURE__ */ jsxs23(
|
|
3685
|
-
"div",
|
|
3686
|
-
{
|
|
3687
|
-
className: ["relative overflow-hidden", className].filter(Boolean).join(" "),
|
|
3688
|
-
style: { aspectRatio },
|
|
3689
|
-
children: [
|
|
3690
|
-
/* @__PURE__ */ jsx38(
|
|
3691
|
-
"img",
|
|
3692
|
-
{
|
|
3693
|
-
src,
|
|
3694
|
-
alt,
|
|
3695
|
-
className: ["absolute inset-0 w-full h-full object-cover", imgClassName].filter(Boolean).join(" ")
|
|
3696
|
-
}
|
|
3697
|
-
),
|
|
3698
|
-
/* @__PURE__ */ jsx38("div", { className: gradientClassName ?? DEFAULT_GRADIENT, "aria-hidden": "true" }),
|
|
3699
|
-
headline ? /* @__PURE__ */ jsx38(
|
|
3700
|
-
"h1",
|
|
3701
|
-
{
|
|
3702
|
-
className: ["absolute bottom-0 left-0 right-0 p-4 text-white font-bold text-2xl", headlineClassName].filter(Boolean).join(" "),
|
|
3703
|
-
children: headline
|
|
3704
|
-
}
|
|
3705
|
-
) : null
|
|
3706
|
-
]
|
|
3707
|
-
}
|
|
3708
|
-
);
|
|
3709
|
-
}
|
|
3710
|
-
|
|
3711
|
-
// src/components/paywall/blocks/PaywallHeadline.tsx
|
|
3712
|
-
import { jsx as jsx39 } from "react/jsx-runtime";
|
|
3713
|
-
var DEFAULT_HEADLINE_CLASSES = "text-2xl font-bold leading-tight";
|
|
3714
|
-
function PaywallHeadline({ text, className, as = "h1" }) {
|
|
3715
|
-
const Tag = as;
|
|
3716
|
-
return /* @__PURE__ */ jsx39(Tag, { className: [DEFAULT_HEADLINE_CLASSES, className].filter(Boolean).join(" "), children: text });
|
|
3717
|
-
}
|
|
3718
|
-
|
|
3719
|
-
// src/components/paywall/blocks/PaywallPriceHeadline.tsx
|
|
3720
|
-
import { jsx as jsx40 } from "react/jsx-runtime";
|
|
3721
|
-
var DEFAULT_CLASS = "text-2xl font-bold leading-tight";
|
|
3722
|
-
var CYCLE_LABEL = {
|
|
3723
|
-
MONTHLY: "mensal",
|
|
3724
|
-
YEARLY: "anual"
|
|
3725
|
-
};
|
|
3726
|
-
function PaywallPriceHeadline({
|
|
3727
|
-
template,
|
|
3728
|
-
className,
|
|
3729
|
-
as = "h1",
|
|
3730
|
-
render
|
|
3731
|
-
}) {
|
|
3732
|
-
const { cycle, currentMonthlyEquivCents, plan } = usePaywallContext();
|
|
3733
|
-
const yearlyCents = plan?.yearlyCents ?? null;
|
|
3734
|
-
const pricePerDay = formatBRL(dailyFromYearly(yearlyCents));
|
|
3735
|
-
const monthlyEquiv = currentMonthlyEquivCents ?? 0;
|
|
3736
|
-
const cycleLabel = CYCLE_LABEL[cycle] ?? cycle.toLowerCase();
|
|
3737
|
-
const rootClasses = [DEFAULT_CLASS, className].filter(Boolean).join(" ");
|
|
3738
|
-
if (render) {
|
|
3739
|
-
const RootTag2 = as;
|
|
3740
|
-
return /* @__PURE__ */ jsx40(RootTag2, { className: [className].filter(Boolean).join(" ") || void 0, children: render({ pricePerDay, currentMonthlyEquivCents: monthlyEquiv, cycle }) });
|
|
3741
|
-
}
|
|
3742
|
-
const text = template.replaceAll("{pricePerDay}", pricePerDay).replaceAll("{currentMonthlyEquiv}", formatBRL(monthlyEquiv)).replaceAll("{cycle}", cycleLabel);
|
|
3743
|
-
const RootTag = as;
|
|
3744
|
-
return /* @__PURE__ */ jsx40(RootTag, { className: rootClasses, children: text });
|
|
3745
|
-
}
|
|
3746
|
-
|
|
3747
|
-
// src/components/paywall/blocks/PaywallCountdown.tsx
|
|
3748
|
-
import { useEffect as useEffect15, useRef as useRef7, useState as useState15 } from "react";
|
|
3749
|
-
import { jsx as jsx41 } from "react/jsx-runtime";
|
|
3750
|
-
var DEFAULT_COUNTDOWN_CLASSES = "font-mono tabular-nums";
|
|
3751
|
-
function resolveDeadlineMs(deadline) {
|
|
3752
|
-
if (deadline instanceof Date) return deadline.getTime();
|
|
3753
|
-
if (typeof deadline === "string") return new Date(deadline).getTime();
|
|
3754
|
-
const { sessionStorageKey, durationMs } = deadline;
|
|
3755
|
-
if (typeof window === "undefined" || typeof window.sessionStorage === "undefined") {
|
|
3756
|
-
return Date.now() + durationMs;
|
|
3757
|
-
}
|
|
3758
|
-
const stored = window.sessionStorage.getItem(sessionStorageKey);
|
|
3759
|
-
const parsed = stored ? Number.parseInt(stored, 10) : NaN;
|
|
3760
|
-
const now = Date.now();
|
|
3761
|
-
if (!Number.isFinite(parsed) || parsed < now) {
|
|
3762
|
-
const target = now + durationMs;
|
|
3763
|
-
window.sessionStorage.setItem(sessionStorageKey, String(target));
|
|
3764
|
-
return target;
|
|
3765
|
-
}
|
|
3766
|
-
return parsed;
|
|
3767
|
-
}
|
|
3768
|
-
function computeRemaining(deadlineMs) {
|
|
3769
|
-
const diff = Math.max(0, deadlineMs - Date.now());
|
|
3770
|
-
const totalSeconds = Math.floor(diff / 1e3);
|
|
3771
|
-
const h = Math.floor(totalSeconds / 3600);
|
|
3772
|
-
const m = Math.floor(totalSeconds % 3600 / 60);
|
|
3773
|
-
const s = totalSeconds % 60;
|
|
3774
|
-
return { h, m, s, expired: diff === 0 };
|
|
3775
|
-
}
|
|
3776
|
-
function pad(n) {
|
|
3777
|
-
return String(n).padStart(2, "0");
|
|
3778
|
-
}
|
|
3779
|
-
function PaywallCountdown({
|
|
3780
|
-
deadline,
|
|
3781
|
-
format = "h:m:s",
|
|
3782
|
-
onExpire,
|
|
3783
|
-
className,
|
|
3784
|
-
render
|
|
3785
|
-
}) {
|
|
3786
|
-
const deadlineMsRef = useRef7(null);
|
|
3787
|
-
if (deadlineMsRef.current === null) {
|
|
3788
|
-
deadlineMsRef.current = resolveDeadlineMs(deadline);
|
|
3789
|
-
}
|
|
3790
|
-
const [state, setState] = useState15(() => computeRemaining(deadlineMsRef.current));
|
|
3791
|
-
const expiredCalledRef = useRef7(false);
|
|
3792
|
-
useEffect15(() => {
|
|
3793
|
-
if (state.expired) {
|
|
3794
|
-
if (!expiredCalledRef.current) {
|
|
3795
|
-
expiredCalledRef.current = true;
|
|
3796
|
-
onExpire?.();
|
|
3797
|
-
}
|
|
3798
|
-
return;
|
|
3799
|
-
}
|
|
3800
|
-
const tick = () => {
|
|
3801
|
-
const next = computeRemaining(deadlineMsRef.current);
|
|
3802
|
-
setState(next);
|
|
3803
|
-
if (next.expired && !expiredCalledRef.current) {
|
|
3804
|
-
expiredCalledRef.current = true;
|
|
3805
|
-
onExpire?.();
|
|
3806
|
-
}
|
|
3807
|
-
};
|
|
3808
|
-
const id = setInterval(tick, 1e3);
|
|
3809
|
-
return () => clearInterval(id);
|
|
3810
|
-
}, [state.expired]);
|
|
3811
|
-
if (render) {
|
|
3812
|
-
return /* @__PURE__ */ jsx41("div", { className, children: render(state) });
|
|
3813
|
-
}
|
|
3814
|
-
const formatted = format === "h:m:s" ? `${pad(state.h)}:${pad(state.m)}:${pad(state.s)}` : `${pad(state.h * 60 + state.m)}:${pad(state.s)}`;
|
|
3815
|
-
return /* @__PURE__ */ jsx41("div", { className: [DEFAULT_COUNTDOWN_CLASSES, className].filter(Boolean).join(" "), children: formatted });
|
|
4155
|
+
function priceCentsForCycle(s, c) {
|
|
4156
|
+
return s.plan ? c === "YEARLY" ? s.plan.yearlyCents ?? 0 : s.plan.monthlyCents : 0;
|
|
3816
4157
|
}
|
|
3817
|
-
|
|
3818
|
-
|
|
3819
|
-
|
|
3820
|
-
|
|
3821
|
-
items,
|
|
3822
|
-
IconComponent,
|
|
3823
|
-
className,
|
|
3824
|
-
itemClassName,
|
|
3825
|
-
iconClassName,
|
|
3826
|
-
render,
|
|
3827
|
-
renderItem
|
|
3828
|
-
}) {
|
|
3829
|
-
if (render) {
|
|
3830
|
-
return /* @__PURE__ */ jsx42("div", { className, children: render({ items }) });
|
|
3831
|
-
}
|
|
3832
|
-
if (renderItem) {
|
|
3833
|
-
return /* @__PURE__ */ jsx42("ul", { className, children: items.map((item, idx) => /* @__PURE__ */ jsx42("li", { children: renderItem(item, idx) }, idx)) });
|
|
3834
|
-
}
|
|
3835
|
-
return /* @__PURE__ */ jsx42("ul", { className, children: items.map((item, idx) => /* @__PURE__ */ jsxs24("li", { className: itemClassName, children: [
|
|
3836
|
-
IconComponent ? /* @__PURE__ */ jsx42(IconComponent, { className: iconClassName }) : /* @__PURE__ */ jsx42("span", { className: iconClassName, "aria-hidden": "true", children: "\u2713" }),
|
|
3837
|
-
/* @__PURE__ */ jsx42("span", { children: item })
|
|
3838
|
-
] }, idx)) });
|
|
3839
|
-
}
|
|
3840
|
-
|
|
3841
|
-
// src/components/paywall/blocks/PaywallFeaturesCard.tsx
|
|
3842
|
-
import { jsx as jsx43, jsxs as jsxs25 } from "react/jsx-runtime";
|
|
3843
|
-
var DEFAULT_CARD_CLASSES = "rounded-xl border p-4";
|
|
3844
|
-
function PaywallFeaturesCard({
|
|
3845
|
-
title,
|
|
3846
|
-
items,
|
|
3847
|
-
className,
|
|
3848
|
-
cardClassName,
|
|
3849
|
-
titleClassName,
|
|
3850
|
-
itemClassName,
|
|
3851
|
-
renderItem
|
|
3852
|
-
}) {
|
|
3853
|
-
return /* @__PURE__ */ jsx43("div", { className, children: /* @__PURE__ */ jsxs25("div", { className: [DEFAULT_CARD_CLASSES, cardClassName].filter(Boolean).join(" "), children: [
|
|
3854
|
-
title ? /* @__PURE__ */ jsx43("div", { className: ["font-semibold mb-2", titleClassName].filter(Boolean).join(" "), children: title }) : null,
|
|
3855
|
-
/* @__PURE__ */ jsx43("ul", { children: items.map(
|
|
3856
|
-
(item, idx) => renderItem ? /* @__PURE__ */ jsx43("li", { children: renderItem(item, idx) }, idx) : /* @__PURE__ */ jsxs25("li", { className: itemClassName, children: [
|
|
3857
|
-
/* @__PURE__ */ jsx43("span", { "aria-hidden": "true", children: "\u2022" }),
|
|
3858
|
-
" ",
|
|
3859
|
-
/* @__PURE__ */ jsx43("span", { children: item })
|
|
3860
|
-
] }, idx)
|
|
3861
|
-
) })
|
|
3862
|
-
] }) });
|
|
3863
|
-
}
|
|
3864
|
-
|
|
3865
|
-
// src/components/paywall/blocks/PaywallTrophyBadge.tsx
|
|
3866
|
-
import { jsx as jsx44, jsxs as jsxs26 } from "react/jsx-runtime";
|
|
3867
|
-
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";
|
|
3868
|
-
var FLOATING_CLASSES = "absolute top-2 right-2 z-10 shadow-md";
|
|
3869
|
-
function PaywallTrophyBadge({
|
|
3870
|
-
text,
|
|
3871
|
-
className,
|
|
3872
|
-
iconClassName,
|
|
3873
|
-
floating = false,
|
|
3874
|
-
render
|
|
3875
|
-
}) {
|
|
3876
|
-
if (render) {
|
|
3877
|
-
return /* @__PURE__ */ jsx44("div", { className, children: render({ text }) });
|
|
3878
|
-
}
|
|
3879
|
-
const rootClasses = [
|
|
3880
|
-
DEFAULT_CHIP_CLASSES,
|
|
3881
|
-
floating ? FLOATING_CLASSES : "",
|
|
3882
|
-
className
|
|
3883
|
-
].filter(Boolean).join(" ");
|
|
3884
|
-
return /* @__PURE__ */ jsxs26("div", { className: rootClasses, children: [
|
|
3885
|
-
/* @__PURE__ */ jsx44("span", { className: iconClassName, "aria-hidden": "true", children: "\u{1F3C6}" }),
|
|
3886
|
-
/* @__PURE__ */ jsx44("span", { children: text })
|
|
3887
|
-
] });
|
|
3888
|
-
}
|
|
3889
|
-
|
|
3890
|
-
// src/components/paywall/blocks/PaywallAnchorPrice.tsx
|
|
3891
|
-
import { jsx as jsx45 } from "react/jsx-runtime";
|
|
3892
|
-
var DEFAULT_CLASS2 = "text-sm opacity-60 line-through";
|
|
3893
|
-
function PaywallAnchorPrice({
|
|
3894
|
-
className,
|
|
3895
|
-
render
|
|
3896
|
-
}) {
|
|
3897
|
-
const { anchorPriceCents, cycle } = usePaywallContext();
|
|
3898
|
-
if (anchorPriceCents === null || anchorPriceCents === void 0 || anchorPriceCents <= 0) {
|
|
3899
|
-
return null;
|
|
3900
|
-
}
|
|
3901
|
-
void cycle;
|
|
3902
|
-
const formatted = formatBRL(anchorPriceCents);
|
|
3903
|
-
const rootClasses = [DEFAULT_CLASS2, className].filter(Boolean).join(" ");
|
|
3904
|
-
if (render) {
|
|
3905
|
-
return /* @__PURE__ */ jsx45("span", { className: className || void 0, children: render({ anchorCents: anchorPriceCents, formatted }) });
|
|
3906
|
-
}
|
|
3907
|
-
return /* @__PURE__ */ jsx45("span", { className: rootClasses, children: formatted });
|
|
3908
|
-
}
|
|
3909
|
-
|
|
3910
|
-
// src/components/paywall/blocks/PaywallTestimonials.tsx
|
|
3911
|
-
import { jsx as jsx46, jsxs as jsxs27 } from "react/jsx-runtime";
|
|
3912
|
-
var DEFAULT_ROOT = "flex gap-3 overflow-x-auto snap-x snap-mandatory pb-2";
|
|
3913
|
-
var DEFAULT_CARD = "snap-start shrink-0 w-72 rounded-2xl border p-4 flex flex-col gap-2";
|
|
3914
|
-
var DEFAULT_AVATAR = "w-10 h-10 rounded-full object-cover";
|
|
3915
|
-
var DEFAULT_QUOTE = "text-sm leading-snug";
|
|
3916
|
-
var DEFAULT_NAME = "text-xs font-semibold opacity-80";
|
|
3917
|
-
var DEFAULT_STARS = "text-yellow-500 text-sm";
|
|
3918
|
-
function clampStars(n) {
|
|
3919
|
-
return Math.max(0, Math.min(5, Math.round(n)));
|
|
3920
|
-
}
|
|
3921
|
-
function PaywallTestimonials({
|
|
3922
|
-
items,
|
|
3923
|
-
className,
|
|
3924
|
-
cardClassName,
|
|
3925
|
-
avatarClassName,
|
|
3926
|
-
quoteClassName,
|
|
3927
|
-
nameClassName,
|
|
3928
|
-
starsClassName,
|
|
3929
|
-
renderItem
|
|
3930
|
-
}) {
|
|
3931
|
-
const rootClasses = [DEFAULT_ROOT, className].filter(Boolean).join(" ");
|
|
3932
|
-
const cardClasses = [DEFAULT_CARD, cardClassName].filter(Boolean).join(" ");
|
|
3933
|
-
const avatarClasses = [DEFAULT_AVATAR, avatarClassName].filter(Boolean).join(" ");
|
|
3934
|
-
const quoteClasses = [DEFAULT_QUOTE, quoteClassName].filter(Boolean).join(" ");
|
|
3935
|
-
const nameClasses = [DEFAULT_NAME, nameClassName].filter(Boolean).join(" ");
|
|
3936
|
-
const starsClasses = [DEFAULT_STARS, starsClassName].filter(Boolean).join(" ");
|
|
3937
|
-
return /* @__PURE__ */ jsx46("div", { className: rootClasses, children: items.map((item, idx) => {
|
|
3938
|
-
if (renderItem) return renderItem(item, idx);
|
|
3939
|
-
const filled = clampStars(item.stars);
|
|
3940
|
-
const empty = 5 - filled;
|
|
3941
|
-
return /* @__PURE__ */ jsxs27("div", { className: cardClasses, children: [
|
|
3942
|
-
/* @__PURE__ */ jsxs27("div", { className: "flex items-center gap-2", children: [
|
|
3943
|
-
item.avatar ? /* @__PURE__ */ jsx46(
|
|
3944
|
-
"img",
|
|
3945
|
-
{
|
|
3946
|
-
src: item.avatar,
|
|
3947
|
-
alt: "",
|
|
3948
|
-
loading: "lazy",
|
|
3949
|
-
className: avatarClasses,
|
|
3950
|
-
"aria-hidden": "true"
|
|
3951
|
-
}
|
|
3952
|
-
) : null,
|
|
3953
|
-
/* @__PURE__ */ jsx46("div", { className: nameClasses, children: item.name })
|
|
3954
|
-
] }),
|
|
3955
|
-
/* @__PURE__ */ jsxs27("div", { className: starsClasses, "aria-label": `${filled} de 5 estrelas`, children: [
|
|
3956
|
-
"\u2605".repeat(filled),
|
|
3957
|
-
"\u2606".repeat(empty)
|
|
3958
|
-
] }),
|
|
3959
|
-
/* @__PURE__ */ jsx46("p", { className: quoteClasses, children: item.quote })
|
|
3960
|
-
] }, idx);
|
|
3961
|
-
}) });
|
|
3962
|
-
}
|
|
3963
|
-
|
|
3964
|
-
// src/components/paywall/blocks/PaywallStatsRow.tsx
|
|
3965
|
-
import { jsx as jsx47, jsxs as jsxs28 } from "react/jsx-runtime";
|
|
3966
|
-
var DEFAULT_ROOT2 = "grid grid-cols-3 gap-4";
|
|
3967
|
-
var DEFAULT_CELL = "flex flex-col items-center text-center";
|
|
3968
|
-
var DEFAULT_VALUE = "text-2xl font-bold";
|
|
3969
|
-
var DEFAULT_LABEL = "text-xs opacity-70";
|
|
3970
|
-
function PaywallStatsRow({
|
|
3971
|
-
stats,
|
|
3972
|
-
className,
|
|
3973
|
-
cellClassName,
|
|
3974
|
-
valueClassName,
|
|
3975
|
-
labelClassName,
|
|
3976
|
-
renderCell
|
|
3977
|
-
}) {
|
|
3978
|
-
const rootClasses = [DEFAULT_ROOT2, className].filter(Boolean).join(" ");
|
|
3979
|
-
const cellClasses = [DEFAULT_CELL, cellClassName].filter(Boolean).join(" ");
|
|
3980
|
-
const valueClasses = [DEFAULT_VALUE, valueClassName].filter(Boolean).join(" ");
|
|
3981
|
-
const labelClasses = [DEFAULT_LABEL, labelClassName].filter(Boolean).join(" ");
|
|
3982
|
-
return /* @__PURE__ */ jsx47("div", { className: rootClasses, children: stats.map((stat, idx) => {
|
|
3983
|
-
if (renderCell) return renderCell(stat, idx);
|
|
3984
|
-
return /* @__PURE__ */ jsxs28("div", { className: cellClasses, children: [
|
|
3985
|
-
stat.icon ? /* @__PURE__ */ jsx47("div", { "aria-hidden": "true", children: stat.icon }) : null,
|
|
3986
|
-
/* @__PURE__ */ jsx47("div", { className: valueClasses, children: stat.value }),
|
|
3987
|
-
/* @__PURE__ */ jsx47("div", { className: labelClasses, children: stat.label })
|
|
3988
|
-
] }, idx);
|
|
3989
|
-
}) });
|
|
3990
|
-
}
|
|
3991
|
-
|
|
3992
|
-
// src/components/paywall/blocks/PaywallFinePrint.tsx
|
|
3993
|
-
import { jsx as jsx48 } from "react/jsx-runtime";
|
|
3994
|
-
var DEFAULT_CLASS3 = "text-xs opacity-60 leading-snug";
|
|
3995
|
-
var CYCLE_LABEL2 = {
|
|
3996
|
-
MONTHLY: "mensal",
|
|
3997
|
-
YEARLY: "anual"
|
|
3998
|
-
};
|
|
3999
|
-
function PaywallFinePrint({
|
|
4000
|
-
template,
|
|
4001
|
-
className,
|
|
4002
|
-
render
|
|
4003
|
-
}) {
|
|
4004
|
-
const {
|
|
4005
|
-
currentPriceCents,
|
|
4006
|
-
cycle,
|
|
4007
|
-
trialDaysCard,
|
|
4008
|
-
trialDaysPix,
|
|
4009
|
-
selectedMethod
|
|
4010
|
-
} = usePaywallContext();
|
|
4011
|
-
const trialDays = selectedMethod === "card" ? trialDaysCard : trialDaysPix;
|
|
4012
|
-
const cycleLabel = CYCLE_LABEL2[cycle] ?? cycle.toLowerCase();
|
|
4013
|
-
const priceFormatted = formatBRL(currentPriceCents ?? 0);
|
|
4014
|
-
const rootClasses = [DEFAULT_CLASS3, className].filter(Boolean).join(" ");
|
|
4015
|
-
if (render) {
|
|
4016
|
-
return /* @__PURE__ */ jsx48("p", { className: className || void 0, children: render({
|
|
4017
|
-
currentPriceCents: currentPriceCents ?? 0,
|
|
4018
|
-
cycle,
|
|
4019
|
-
trialDays: trialDays ?? 0,
|
|
4020
|
-
selectedMethod
|
|
4021
|
-
}) });
|
|
4022
|
-
}
|
|
4023
|
-
const text = template.replaceAll("{price}", priceFormatted).replaceAll("{trialDays}", String(trialDays ?? 0)).replaceAll("{cycle}", cycleLabel);
|
|
4024
|
-
return /* @__PURE__ */ jsx48("p", { className: rootClasses, children: text });
|
|
4025
|
-
}
|
|
4026
|
-
|
|
4027
|
-
// src/components/paywall/blocks/PaywallTrustLine.tsx
|
|
4028
|
-
import { jsx as jsx49, jsxs as jsxs29 } from "react/jsx-runtime";
|
|
4029
|
-
var DEFAULT_ROOT3 = "flex items-center gap-3";
|
|
4030
|
-
var DEFAULT_ITEM = "flex items-center gap-1.5 text-xs";
|
|
4031
|
-
function PaywallTrustLine({
|
|
4032
|
-
items,
|
|
4033
|
-
className,
|
|
4034
|
-
itemClassName,
|
|
4035
|
-
renderItem
|
|
4036
|
-
}) {
|
|
4037
|
-
const rootClasses = [DEFAULT_ROOT3, className].filter(Boolean).join(" ");
|
|
4038
|
-
const itemClasses = [DEFAULT_ITEM, itemClassName].filter(Boolean).join(" ");
|
|
4039
|
-
return /* @__PURE__ */ jsx49("div", { className: rootClasses, children: items.map((item, idx) => {
|
|
4040
|
-
if (renderItem) return renderItem(item, idx);
|
|
4041
|
-
return /* @__PURE__ */ jsxs29("span", { className: itemClasses, children: [
|
|
4042
|
-
/* @__PURE__ */ jsx49("span", { "aria-hidden": "true", children: item.icon }),
|
|
4043
|
-
/* @__PURE__ */ jsx49("span", { children: item.text })
|
|
4044
|
-
] }, idx);
|
|
4045
|
-
}) });
|
|
4046
|
-
}
|
|
4047
|
-
|
|
4048
|
-
// src/components/paywall/blocks/PaywallStickyFooter.tsx
|
|
4049
|
-
import { jsx as jsx50 } from "react/jsx-runtime";
|
|
4050
|
-
var DEFAULT_CLASSES = "sticky bottom-0 left-0 right-0 bg-background";
|
|
4051
|
-
var SAFE_AREA_CLASS = "pb-[env(safe-area-inset-bottom)]";
|
|
4052
|
-
function PaywallStickyFooter({
|
|
4053
|
-
children,
|
|
4054
|
-
className,
|
|
4055
|
-
safeAreaInsets = true
|
|
4056
|
-
}) {
|
|
4057
|
-
const classes = [DEFAULT_CLASSES, safeAreaInsets ? SAFE_AREA_CLASS : null, className].filter(Boolean).join(" ");
|
|
4058
|
-
return /* @__PURE__ */ jsx50("div", { className: classes, children });
|
|
4158
|
+
function anchorForCycle(s, c) {
|
|
4159
|
+
if (!s.plan) return null;
|
|
4160
|
+
if (c === "YEARLY") return s.plan.anchorYearlyCents ?? null;
|
|
4161
|
+
return s.plan.anchorMonthlyCents ?? null;
|
|
4059
4162
|
}
|
|
4060
4163
|
export {
|
|
4061
4164
|
AppConfigProvider,
|
|
4062
4165
|
AppConfigSchema,
|
|
4063
4166
|
AppRoot,
|
|
4167
|
+
CheckoutPageDefault,
|
|
4064
4168
|
DeepLinkHandler,
|
|
4065
4169
|
DevSkipOnboardingFab,
|
|
4066
4170
|
EmptyState,
|
|
@@ -4073,27 +4177,12 @@ export {
|
|
|
4073
4177
|
OnboardingFlow,
|
|
4074
4178
|
PaymentReturnHandler,
|
|
4075
4179
|
Paywall,
|
|
4076
|
-
PaywallAnchorPrice,
|
|
4077
|
-
PaywallContext,
|
|
4078
|
-
PaywallCountdown,
|
|
4079
4180
|
PaywallCta,
|
|
4080
4181
|
PaywallCyclePicker,
|
|
4081
|
-
PaywallEyebrow,
|
|
4082
|
-
PaywallFeatures,
|
|
4083
|
-
PaywallFeaturesCard,
|
|
4084
|
-
PaywallFinePrint,
|
|
4085
|
-
PaywallHeadline,
|
|
4086
|
-
PaywallHero,
|
|
4087
4182
|
PaywallMethodContent,
|
|
4088
4183
|
PaywallMethodTabs,
|
|
4089
|
-
PaywallPriceHeadline,
|
|
4090
|
-
PaywallProvider,
|
|
4091
|
-
PaywallStatsRow,
|
|
4092
|
-
PaywallStickyFooter,
|
|
4093
|
-
PaywallTestimonials,
|
|
4094
|
-
PaywallTrophyBadge,
|
|
4095
|
-
PaywallTrustLine,
|
|
4096
4184
|
PersistenceRegistry,
|
|
4185
|
+
PixWaitingPageDefault,
|
|
4097
4186
|
PreAuthShell,
|
|
4098
4187
|
PushPrompt2 as PushPrompt,
|
|
4099
4188
|
RouteBoundary,
|
|
@@ -4116,12 +4205,12 @@ export {
|
|
|
4116
4205
|
useAppConfig,
|
|
4117
4206
|
useAuth,
|
|
4118
4207
|
useAuthPrimitives,
|
|
4208
|
+
useCheckoutForm,
|
|
4119
4209
|
useFeature,
|
|
4120
4210
|
useForgotForm,
|
|
4121
4211
|
useInstallPrompt,
|
|
4122
4212
|
useLoginForm,
|
|
4123
4213
|
useOnboardingStep,
|
|
4124
|
-
usePaywallContext,
|
|
4125
4214
|
usePaywallState,
|
|
4126
4215
|
usePlan,
|
|
4127
4216
|
usePush,
|