@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.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 useHook8 } from "@hook-sdk/sdk";
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
- // G154 fix (template 0.24.0 + SDK 0.26.0): wired to SDK action.
634
- dismissPix: subscription.clearPixPending,
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 jsx19, jsxs as jsxs13 } from "react/jsx-runtime";
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__ */ jsxs13("div", { role: "alert", style: { padding: 24, textAlign: "center" }, children: [
2099
- /* @__PURE__ */ jsx19("h2", { children: "Algo deu errado" }),
2100
- /* @__PURE__ */ jsx19("p", { style: { opacity: 0.7 }, children: "Recarregue a p\xE1gina pra tentar de novo." })
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__ */ jsx19(Fragment4, { children: this.props.children });
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 jsx20 } from "react/jsx-runtime";
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__ */ jsx20(I18nextProvider, { i18n, children });
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 useState6 } from "react";
2153
- import { useHook as useHook6 } from "@hook-sdk/sdk";
2154
- import { jsx as jsx21 } from "react/jsx-runtime";
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 = useHook6();
2179
+ const hook = useHook5();
2222
2180
  const { slug } = useAppConfig();
2223
- const [state, setState] = useState6("idle");
2224
- const [errorMsg, setErrorMsg] = useState6(null);
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__ */ jsx21(
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 useState7 } from "react";
2277
- import { useHook as useHook7 } from "@hook-sdk/sdk";
2278
- import { Fragment as Fragment5, jsx as jsx22, jsxs as jsxs14 } from "react/jsx-runtime";
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 } = useHook7();
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] = useState7("idle");
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__ */ jsx22("div", { role: "status", "aria-live": "polite", style: overlayStyle2, children: "Confirmando pagamento\u2026" });
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__ */ jsx22("div", { role: "status", "aria-live": "polite", style: overlayStyle2, children: /* @__PURE__ */ jsxs14("div", { style: { maxWidth: 320, textAlign: "center", lineHeight: 1.5 }, children: [
2359
- /* @__PURE__ */ jsx22("div", { style: { marginBottom: 16 }, children: "Pagamento aceito. Estamos confirmando com o banco \u2014 pode levar alguns minutos." }),
2360
- /* @__PURE__ */ jsx22("button", { type: "button", onClick: runPoll, style: buttonStyle, children: "Atualizar" })
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__ */ jsx22("div", { role: "alert", "aria-live": "assertive", style: overlayStyle2, children: /* @__PURE__ */ jsxs14("div", { style: { maxWidth: 360, textAlign: "center", lineHeight: 1.5 }, children: [
2365
- /* @__PURE__ */ jsx22("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." }),
2366
- /* @__PURE__ */ jsxs14("div", { style: { display: "flex", flexDirection: "column", gap: 8 }, children: [
2367
- /* @__PURE__ */ jsx22(
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__ */ jsx22(
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__ */ jsx22(
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__ */ jsx22(Fragment5, { children });
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 jsx23, jsxs as jsxs15 } from "react/jsx-runtime";
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__ */ jsxs15(SubscriptionGate, { Paywall: Paywall2 ?? FallbackPaywall, children: [
2521
- /* @__PURE__ */ jsx23(EmailVerifyBanner, {}),
2522
- position === "post-paywall" ? /* @__PURE__ */ jsxs15(InstallGate, { position: "post-paywall", children: [
2523
- children,
2524
- /* @__PURE__ */ jsx23(PushPrompt, {})
2525
- ] }) : /* @__PURE__ */ jsxs15(Fragment6, { children: [
2526
- children,
2527
- /* @__PURE__ */ jsx23(PushPrompt, {})
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__ */ jsxs15(Router, { ...routerProps, children: [
2546
- /* @__PURE__ */ jsx23(DeepLinkHandler, { deepLinks: config.deepLinks }),
2547
- /* @__PURE__ */ jsx23(SessionExpiredBanner, {}),
2548
- position === "pre-auth" ? /* @__PURE__ */ jsx23(InstallGate, { position: "pre-auth", children: authGated }) : authGated,
2549
- isDevToolsEnabled() && devSkipOnboarding ? /* @__PURE__ */ jsx23(DevSkipOnboardingFab, { defaults: devSkipOnboarding.defaults }) : null
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__ */ jsx23(ErrorBoundary, { children: /* @__PURE__ */ jsx23(AppConfigProvider, { config, children: /* @__PURE__ */ jsx23(TemplateConfigProvider, { config: legacyShim, children: /* @__PURE__ */ jsx23(ThemeProvider, { children: /* @__PURE__ */ jsx23(PersistenceRegistry, { config: config.persistedKeys, children: config.i18n ? /* @__PURE__ */ jsx23(
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 } = useHook8();
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__ */ jsxs15(Routes, { children: [
2576
- /* @__PURE__ */ jsx23(Route, { path: "/signin", element: /* @__PURE__ */ jsx23(Login, {}) }),
2577
- /* @__PURE__ */ jsx23(Route, { path: "/signup", element: /* @__PURE__ */ jsx23(Signup, {}) }),
2578
- /* @__PURE__ */ jsx23(Route, { path: "/forgot", element: /* @__PURE__ */ jsx23(Forgot, {}) }),
2579
- /* @__PURE__ */ jsx23(Route, { path: "/reset", element: /* @__PURE__ */ jsx23(Reset, {}) }),
2580
- EmailVerify ? /* @__PURE__ */ jsx23(Route, { path: "/verify", element: /* @__PURE__ */ jsx23(EmailVerify, {}) }) : null,
2581
- /* @__PURE__ */ jsx23(Route, { path: "/*", element: /* @__PURE__ */ jsx23(PreAuthFlow, {}) })
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__ */ jsxs15(Routes, { children: [
2585
- /* @__PURE__ */ jsx23(Route, { path: "/", element: /* @__PURE__ */ jsx23(Login, {}) }),
2586
- /* @__PURE__ */ jsx23(Route, { path: "/signup", element: /* @__PURE__ */ jsx23(Signup, {}) }),
2587
- /* @__PURE__ */ jsx23(Route, { path: "/forgot", element: /* @__PURE__ */ jsx23(Forgot, {}) }),
2588
- /* @__PURE__ */ jsx23(Route, { path: "/reset", element: /* @__PURE__ */ jsx23(Reset, {}) }),
2589
- EmailVerify ? /* @__PURE__ */ jsx23(Route, { path: "/verify", element: /* @__PURE__ */ jsx23(EmailVerify, {}) }) : null,
2590
- /* @__PURE__ */ jsx23(Route, { path: "*", element: /* @__PURE__ */ jsx23(Navigate, { to: "/", replace: true }) })
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__ */ jsx23(Fragment6, { children });
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 useState8 } from "react";
2601
- import { useHook as useHook9 } from "@hook-sdk/sdk";
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 } = useHook9();
2646
- const [state, setState] = useState8(() => deriveState(push));
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 jsx24, jsxs as jsxs16 } from "react/jsx-runtime";
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__ */ jsxs16("div", { className, role: "region", "aria-label": texts.iosInstallTitle, children: [
2692
- /* @__PURE__ */ jsx24("h3", { children: texts.iosInstallTitle }),
2693
- /* @__PURE__ */ jsx24("p", { children: texts.iosInstallBody }),
2694
- onInstallRequested && texts.iosInstallCta && /* @__PURE__ */ jsx24("button", { onClick: onInstallRequested, children: texts.iosInstallCta })
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__ */ jsx24("div", { className, role: "region", children: /* @__PURE__ */ jsx24("p", { children: texts.unsupportedBody }) });
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__ */ jsx24("div", { className, role: "region", "aria-label": "error", children: /* @__PURE__ */ jsx24("p", { children: state.message }) });
2665
+ return /* @__PURE__ */ jsx23("div", { className, role: "region", "aria-label": "error", children: /* @__PURE__ */ jsx23("p", { children: state.message }) });
2702
2666
  }
2703
- return /* @__PURE__ */ jsxs16("div", { className, role: "region", children: [
2704
- /* @__PURE__ */ jsx24(
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__ */ jsx24("button", { type: "button", onClick: onDeclined, children: texts.declineCta })
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 jsx25, jsxs as jsxs17 } from "react/jsx-runtime";
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__ */ jsxs17("label", { className, children: [
2734
- label ? /* @__PURE__ */ jsx25("span", { children: label }) : null,
2735
- /* @__PURE__ */ jsx25(
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__ */ jsx25("option", { value: loc, children: loc }, loc))
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 jsx26 } from "react/jsx-runtime";
2713
+ import { jsx as jsx25 } from "react/jsx-runtime";
2750
2714
  function LoadingState({ message }) {
2751
- return /* @__PURE__ */ jsx26("div", { role: "status", "aria-live": "polite", style: { padding: 24, textAlign: "center" }, children: /* @__PURE__ */ jsx26("span", { children: message ?? "Carregando..." }) });
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 jsx27, jsxs as jsxs18 } from "react/jsx-runtime";
2719
+ import { jsx as jsx26, jsxs as jsxs17 } from "react/jsx-runtime";
2756
2720
  function EmptyState({ title, description, action }) {
2757
- return /* @__PURE__ */ jsxs18("div", { role: "status", style: { padding: 32, textAlign: "center" }, children: [
2758
- /* @__PURE__ */ jsx27("h2", { style: { marginBottom: 8 }, children: title }),
2759
- description && /* @__PURE__ */ jsx27("p", { style: { opacity: 0.7 }, children: description }),
2760
- action && /* @__PURE__ */ jsx27("div", { style: { marginTop: 16 }, children: action })
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/hooks/useLoginForm.ts
2765
- import { useCallback as useCallback6, useMemo as useMemo4, useState as useState9 } from "react";
2766
- import { useHook as useHook10 } from "@hook-sdk/sdk";
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, SdkValidationError } from "@hook-sdk/sdk";
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/useLoginForm.ts
2768
+ // src/hooks/useCheckoutForm.ts
2801
2769
  var EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
2802
- var MIN_PASSWORD = 8;
2803
- function useLoginForm() {
2804
- const { auth } = useHook10();
2805
- const [email, setEmail] = useState9("");
2806
- const [password, setPassword] = useState9("");
2807
- const [submitting, setSubmitting] = useState9(false);
2808
- const [error, setError] = useState9(null);
2809
- const [touchedEmail, setTouchedEmail] = useState9(false);
2810
- const [touchedPassword, setTouchedPassword] = useState9(false);
2811
- const [formSubmitAttempted, setFormSubmitAttempted] = useState9(false);
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 validatePassword = useMemo4(() => {
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 = useCallback6(async () => {
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 useCallback7, useMemo as useMemo5, useState as useState10 } from "react";
2860
- import { useHook as useHook11 } from "@hook-sdk/sdk";
2861
- var EMAIL_RE2 = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
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 } = useHook11();
2865
- const [name, setName] = useState10("");
2866
- const [email, setEmail] = useState10("");
2867
- const [password, setPassword] = useState10("");
2868
- const [submitting, setSubmitting] = useState10(false);
2869
- const [error, setError] = useState10(null);
2870
- const [touchedName, setTouchedName] = useState10(false);
2871
- const [touchedEmail, setTouchedEmail] = useState10(false);
2872
- const [touchedPassword, setTouchedPassword] = useState10(false);
2873
- const [formSubmitAttempted, setFormSubmitAttempted] = useState10(false);
2874
- const validateName = useMemo5(() => {
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 = useMemo5(() => {
3420
+ const validateEmail = useMemo8(() => {
2880
3421
  if (email.length === 0) return null;
2881
- if (!EMAIL_RE2.test(email)) return "Formato de e-mail inv\xE1lido.";
3422
+ if (!EMAIL_RE3.test(email)) return "Formato de e-mail inv\xE1lido.";
2882
3423
  return null;
2883
3424
  }, [email]);
2884
- const validatePassword = useMemo5(() => {
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 = useCallback7(async () => {
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 useCallback8, useMemo as useMemo6, useState as useState11 } from "react";
2932
- import { useHook as useHook12 } from "@hook-sdk/sdk";
2933
- var EMAIL_RE3 = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
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 } = useHook12();
2936
- const [email, setEmail] = useState11("");
2937
- const [submitting, setSubmitting] = useState11(false);
2938
- const [sent, setSent] = useState11(false);
2939
- const [error, setError] = useState11(null);
2940
- const [touchedEmail, setTouchedEmail] = useState11(false);
2941
- const [formSubmitAttempted, setFormSubmitAttempted] = useState11(false);
2942
- const validateEmail = useMemo6(() => {
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 (!EMAIL_RE3.test(email)) return "Formato de e-mail inv\xE1lido.";
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 = useCallback8(async () => {
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 useCallback9, useEffect as useEffect10, useMemo as useMemo7, useState as useState12 } from "react";
2981
- import { useHook as useHook13 } from "@hook-sdk/sdk";
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 } = useHook13();
2985
- const [token, setToken] = useState12(null);
2986
- const [password, setPassword] = useState12("");
2987
- const [confirm, setConfirm] = useState12("");
2988
- const [submitting, setSubmitting] = useState12(false);
2989
- const [done, setDone] = useState12(false);
2990
- const [error, setError] = useState12(null);
2991
- const [touchedPassword, setTouchedPassword] = useState12(false);
2992
- const [touchedConfirm, setTouchedConfirm] = useState12(false);
2993
- const [formSubmitAttempted, setFormSubmitAttempted] = useState12(false);
2994
- useEffect10(() => {
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 = useMemo7(() => {
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 = useMemo7(() => {
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 = useCallback9(async () => {
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 useEffect11 } from "react";
3089
- import { useHook as useHook15 } from "@hook-sdk/sdk";
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 } = useHook15();
3093
- useEffect11(() => {
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 useHook16 } from "@hook-sdk/sdk";
3649
+ import { useHook as useHook17 } from "@hook-sdk/sdk";
3116
3650
  function useAuth() {
3117
- const { user, authStatus, auth } = useHook16();
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 useHook17 } from "@hook-sdk/sdk";
3663
+ import { useHook as useHook18 } from "@hook-sdk/sdk";
3130
3664
  function useSubscription() {
3131
- const { subscription } = useHook17();
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 useCallback10, useEffect as useEffect12, useState as useState13 } from "react";
3139
- import { useHook as useHook18 } from "@hook-sdk/sdk";
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 } = useHook18();
3675
+ const { push } = useHook19();
3142
3676
  const r = push.reminders;
3143
- const [reminders, setReminders] = useState13([]);
3144
- const [loading, setLoading] = useState13(true);
3145
- const reload = useCallback10(async () => {
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
- useEffect12(() => {
3688
+ useEffect15(() => {
3155
3689
  void reload();
3156
3690
  }, [reload]);
3157
- const setReminder = useCallback10(async (input) => {
3691
+ const setReminder = useCallback11(async (input) => {
3158
3692
  await r.set(input);
3159
3693
  await reload();
3160
3694
  }, [r, reload]);
3161
- const deleteReminder = useCallback10(async (slot) => {
3695
+ const deleteReminder = useCallback11(async (slot) => {
3162
3696
  await r.delete(slot);
3163
3697
  await reload();
3164
3698
  }, [r, reload]);
3165
- const schedule = useCallback10(async (items) => {
3699
+ const schedule = useCallback11(async (items) => {
3166
3700
  return r.schedule(items);
3167
3701
  }, [r]);
3168
- const setFallbacks = useCallback10(async (items) => {
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 useCallback11, useState as useState14 } from "react";
3709
+ import { useCallback as useCallback12, useState as useState15 } from "react";
3176
3710
  function useToast() {
3177
- const [items, setItems] = useState14([]);
3178
- const show = useCallback11((message, kind = "info") => {
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 = useCallback11((id) => {
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 jsx28, jsxs as jsxs19 } from "react/jsx-runtime";
3727
+ import { jsx as jsx29, jsxs as jsxs20 } from "react/jsx-runtime";
3194
3728
  function RouteBoundary({ children }) {
3195
- return /* @__PURE__ */ jsxs19(Routes2, { children: [
3729
+ return /* @__PURE__ */ jsxs20(Routes2, { children: [
3196
3730
  children,
3197
- /* @__PURE__ */ jsx28(Route2, { path: "*", element: /* @__PURE__ */ jsx28(DefaultNotFound, {}) })
3731
+ /* @__PURE__ */ jsx29(Route2, { path: "*", element: /* @__PURE__ */ jsx29(DefaultNotFound, {}) })
3198
3732
  ] });
3199
3733
  }
3200
3734
  function DefaultNotFound() {
3201
- return /* @__PURE__ */ jsx28("div", { role: "alert", children: "P\xE1gina n\xE3o encontrada" });
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 jsx29 } from "react/jsx-runtime";
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__ */ jsx29(MemoryRouter2, { basename, initialEntries: testInitialEntries, children: /* @__PURE__ */ jsx29(Routes3, { children }) });
3748
+ return /* @__PURE__ */ jsx30(MemoryRouter2, { basename, initialEntries: testInitialEntries, children: /* @__PURE__ */ jsx30(Routes3, { children }) });
3215
3749
  }
3216
- return /* @__PURE__ */ jsx29(BrowserRouter2, { basename, children: /* @__PURE__ */ jsx29(Routes3, { children }) });
3750
+ return /* @__PURE__ */ jsx30(BrowserRouter2, { basename, children: /* @__PURE__ */ jsx30(Routes3, { children }) });
3217
3751
  }
3218
3752
 
3219
3753
  // src/OnboardingFlow.tsx
3220
- import { useCallback as useCallback12, useEffect as useEffect13, useMemo as useMemo8, useRef as useRef6 } from "react";
3221
- import { usePersistedState as usePersistedState3, useHook as useHook19 } from "@hook-sdk/sdk";
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 jsx30 } from "react/jsx-runtime";
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 = useRef6(draft);
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 = useCallback12(
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 = useCallback12(
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 = useHook19();
3807
+ const hookCtx = useHook20();
3274
3808
  const track2 = typeof hookCtx.track === "function" ? hookCtx.track : void 0;
3275
- useEffect13(() => {
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 = useMemo8(
3819
+ const valid = useMemo11(
3286
3820
  () => step ? (step.validates ?? []).every((field) => isFilled(draft[field])) : false,
3287
3821
  [draft, step]
3288
3822
  );
3289
- const next = useCallback12(() => {
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 = useCallback12(() => setIdx((i) => Math.max(0, i - 1)), [setIdx]);
3301
- const ctx = useMemo8(
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__ */ jsx30(OnboardingStepContext.Provider, { value: ctx, children: /* @__PURE__ */ jsx30(Screen, {}) });
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 useEffect14, useMemo as useMemo9 } from "react";
3338
- import { useHook as useHook20 } from "@hook-sdk/sdk";
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 === selectedMethod;
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: () => selectMethod(m),
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({ copy, className, rowClassName }) {
3392
- const { selectedMethod, hasConsumedTrial } = usePaywallContext();
3393
- const useCardConsumed = selectedMethod === "card" && hasConsumedTrial && copy.cardConsumedTrial;
3394
- const rows = useCardConsumed ? copy.cardConsumedTrial.bodyRows : selectedMethod === "pix-auto" || selectedMethod === "pix-once" ? copy.pix.bodyRows : copy.card.bodyRows;
3395
- return /* @__PURE__ */ jsx33("div", { role: "tabpanel", id: `paywall-tab-${selectedMethod}`, className, children: rows.map((row, i) => /* @__PURE__ */ jsx33("div", { className: rowClassName, children: row }, i)) });
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 jsxs20 } from "react/jsx-runtime";
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" ? Math.round(yearlyCents / 12) : monthlyCents;
3445
- const anchorCents = c === "YEARLY" ? anchorYearly : anchorMonthly;
3446
- return /* @__PURE__ */ jsxs20(
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: () => setCycle(c),
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 jsx35, jsxs as jsxs21 } from "react/jsx-runtime";
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
- return /* @__PURE__ */ jsx35(PaywallProvider, { children: /* @__PURE__ */ jsx35(
3482
- PaywallInner,
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 = useMemo9(() => {
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 = useMemo9(() => {
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
- useEffect14(() => {
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__ */ jsxs21("div", { className: themeClasses.container, children: [
4063
+ return /* @__PURE__ */ jsxs23("div", { className: themeClasses.container, children: [
3555
4064
  slots.heroSlot,
3556
- /* @__PURE__ */ jsx35("h1", { className: themeClasses.headline, children: copy.headline }),
3557
- /* @__PURE__ */ jsx35("ul", { children: copy.features.map((f) => /* @__PURE__ */ jsxs21("li", { className: themeClasses.feature, children: [
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__ */ jsx35("span", { children: f })
4068
+ /* @__PURE__ */ jsx36("span", { children: f })
3560
4069
  ] }, f)) }),
3561
- copy.socialProof ? /* @__PURE__ */ jsx35("p", { className: themeClasses.socialProof, children: copy.socialProof }) : null,
3562
- slots.cyclePickerSlot ?? /* @__PURE__ */ jsx35(
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__ */ jsx35(
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__ */ jsx35(
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__ */ jsxs21("div", { children: [
3599
- /* @__PURE__ */ jsx35(
3600
- "button",
3601
- {
3602
- type: "button",
3603
- onClick: () => {
3604
- void handleCta();
3605
- },
3606
- disabled: s.submitting,
3607
- className: ctaTheme,
3608
- children: s.submitting ? "Abrindo checkout\u2026" : ctaLabel
3609
- }
3610
- ),
3611
- switchHint ? /* @__PURE__ */ jsx35("p", { className: themeClasses.switchHint, children: switchHint }) : null,
3612
- /* @__PURE__ */ jsx35("p", { className: themeClasses.trustLine, children: copy.trustLine })
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
- // src/components/paywall/PaywallCta.tsx
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
- // src/components/paywall/blocks/PaywallFeatures.tsx
3819
- import { jsx as jsx42, jsxs as jsxs24 } from "react/jsx-runtime";
3820
- function PaywallFeatures({
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,