@hook-sdk/template 0.25.1 → 0.26.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -33,6 +33,7 @@ __export(index_exports, {
33
33
  AppConfigProvider: () => AppConfigProvider,
34
34
  AppConfigSchema: () => AppConfigSchema,
35
35
  AppRoot: () => AppRoot,
36
+ CheckoutPageDefault: () => CheckoutPageDefault,
36
37
  DeepLinkHandler: () => DeepLinkHandler,
37
38
  DevSkipOnboardingFab: () => DevSkipOnboardingFab,
38
39
  EmptyState: () => EmptyState,
@@ -45,27 +46,12 @@ __export(index_exports, {
45
46
  OnboardingFlow: () => OnboardingFlow,
46
47
  PaymentReturnHandler: () => PaymentReturnHandler,
47
48
  Paywall: () => Paywall,
48
- PaywallAnchorPrice: () => PaywallAnchorPrice,
49
- PaywallContext: () => PaywallContext,
50
- PaywallCountdown: () => PaywallCountdown,
51
49
  PaywallCta: () => PaywallCta,
52
50
  PaywallCyclePicker: () => PaywallCyclePicker,
53
- PaywallEyebrow: () => PaywallEyebrow,
54
- PaywallFeatures: () => PaywallFeatures,
55
- PaywallFeaturesCard: () => PaywallFeaturesCard,
56
- PaywallFinePrint: () => PaywallFinePrint,
57
- PaywallHeadline: () => PaywallHeadline,
58
- PaywallHero: () => PaywallHero,
59
51
  PaywallMethodContent: () => PaywallMethodContent,
60
52
  PaywallMethodTabs: () => PaywallMethodTabs,
61
- PaywallPriceHeadline: () => PaywallPriceHeadline,
62
- PaywallProvider: () => PaywallProvider,
63
- PaywallStatsRow: () => PaywallStatsRow,
64
- PaywallStickyFooter: () => PaywallStickyFooter,
65
- PaywallTestimonials: () => PaywallTestimonials,
66
- PaywallTrophyBadge: () => PaywallTrophyBadge,
67
- PaywallTrustLine: () => PaywallTrustLine,
68
53
  PersistenceRegistry: () => PersistenceRegistry,
54
+ PixWaitingPageDefault: () => PixWaitingPageDefault,
69
55
  PreAuthShell: () => PreAuthShell,
70
56
  PushPrompt: () => PushPrompt2,
71
57
  RouteBoundary: () => RouteBoundary,
@@ -88,12 +74,12 @@ __export(index_exports, {
88
74
  useAppConfig: () => useAppConfig,
89
75
  useAuth: () => useAuth,
90
76
  useAuthPrimitives: () => useAuthPrimitives,
77
+ useCheckoutForm: () => useCheckoutForm,
91
78
  useFeature: () => useFeature,
92
79
  useForgotForm: () => useForgotForm,
93
80
  useInstallPrompt: () => useInstallPrompt,
94
81
  useLoginForm: () => useLoginForm,
95
82
  useOnboardingStep: () => useOnboardingStep,
96
- usePaywallContext: () => usePaywallContext,
97
83
  usePaywallState: () => usePaywallState,
98
84
  usePlan: () => usePlan,
99
85
  usePush: () => usePush,
@@ -102,14 +88,14 @@ __export(index_exports, {
102
88
  useSignupForm: () => useSignupForm,
103
89
  useSubscription: () => useSubscription,
104
90
  useToast: () => useToast,
105
- useTrackOnboardingStep: () => import_sdk24.useTrackOnboardingStep
91
+ useTrackOnboardingStep: () => import_sdk25.useTrackOnboardingStep
106
92
  });
107
93
  module.exports = __toCommonJS(index_exports);
108
94
 
109
95
  // src/AppRoot.tsx
110
- var import_react16 = require("react");
96
+ var import_react15 = require("react");
111
97
  var import_react_router_dom2 = require("react-router-dom");
112
- var import_sdk9 = require("@hook-sdk/sdk");
98
+ var import_sdk8 = require("@hook-sdk/sdk");
113
99
 
114
100
  // src/config/AppConfigContext.tsx
115
101
  var import_react = require("react");
@@ -139,7 +125,9 @@ var AuthFlowSchema = import_zod.z.object({
139
125
  requiresEmailVerify: import_zod.z.boolean(),
140
126
  googleOAuth: import_zod.z.boolean(),
141
127
  postAuthLanding: import_zod.z.string().startsWith("/"),
142
- preAuthRoutes: import_zod.z.array(import_zod.z.string().startsWith("/"))
128
+ preAuthRoutes: import_zod.z.array(import_zod.z.string().startsWith("/")),
129
+ // Plan-V — pay-first signup mode. See types/AppConfig.ts AuthFlowConfig.
130
+ signupMode: import_zod.z.enum(["pre_signup", "pay_first"]).optional()
143
131
  });
144
132
  var PaywallNonFreeSchema = import_zod.z.object({
145
133
  mode: import_zod.z.enum(["trial", "pay_first"]),
@@ -738,8 +726,8 @@ function usePaywallState() {
738
726
  opening: submitting,
739
727
  availableMethods: methods,
740
728
  monthlyEquivalent,
741
- // G154 fix (template 0.24.0 + SDK 0.26.0): wired to SDK action.
742
- dismissPix: subscription.clearPixPending,
729
+ dismissPix: () => {
730
+ },
743
731
  refreshPlan: () => {
744
732
  }
745
733
  };
@@ -2139,54 +2127,10 @@ function SessionExpiredBanner() {
2139
2127
  ] });
2140
2128
  }
2141
2129
 
2142
- // src/internal/EmailVerifyBanner.tsx
2130
+ // src/defaults/ErrorBoundary.tsx
2143
2131
  var import_react11 = require("react");
2144
- var import_sdk5 = require("@hook-sdk/sdk");
2145
2132
  var import_jsx_runtime18 = require("react/jsx-runtime");
2146
- function EmailVerifyBanner() {
2147
- const { user, auth } = (0, import_sdk5.useHook)();
2148
- const [sending, setSending] = (0, import_react11.useState)(false);
2149
- const [sent, setSent] = (0, import_react11.useState)(false);
2150
- if (!user || user.emailVerified) return null;
2151
- async function handleResend() {
2152
- if (sending || sent) return;
2153
- setSending(true);
2154
- try {
2155
- await auth.resendVerify();
2156
- setSent(true);
2157
- } catch {
2158
- } finally {
2159
- setSending(false);
2160
- }
2161
- }
2162
- const label = sent ? "Enviado!" : sending ? "Enviando..." : "Reenviar link";
2163
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
2164
- "div",
2165
- {
2166
- role: "status",
2167
- "data-testid": "email-verify-banner",
2168
- 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",
2169
- children: [
2170
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { children: "Confirma teu e-mail pra liberar tudo." }),
2171
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
2172
- "button",
2173
- {
2174
- type: "button",
2175
- onClick: handleResend,
2176
- disabled: sending || sent,
2177
- 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",
2178
- children: label
2179
- }
2180
- )
2181
- ]
2182
- }
2183
- );
2184
- }
2185
-
2186
- // src/defaults/ErrorBoundary.tsx
2187
- var import_react12 = require("react");
2188
- var import_jsx_runtime19 = require("react/jsx-runtime");
2189
- var ErrorBoundary = class extends import_react12.Component {
2133
+ var ErrorBoundary = class extends import_react11.Component {
2190
2134
  state = { error: null };
2191
2135
  static getDerivedStateFromError(error) {
2192
2136
  return { error };
@@ -2203,21 +2147,21 @@ var ErrorBoundary = class extends import_react12.Component {
2203
2147
  }
2204
2148
  render() {
2205
2149
  if (this.state.error) {
2206
- return this.props.fallback ?? /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { role: "alert", style: { padding: 24, textAlign: "center" }, children: [
2207
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("h2", { children: "Algo deu errado" }),
2208
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { style: { opacity: 0.7 }, children: "Recarregue a p\xE1gina pra tentar de novo." })
2150
+ return this.props.fallback ?? /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { role: "alert", style: { padding: 24, textAlign: "center" }, children: [
2151
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("h2", { children: "Algo deu errado" }),
2152
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("p", { style: { opacity: 0.7 }, children: "Recarregue a p\xE1gina pra tentar de novo." })
2209
2153
  ] });
2210
2154
  }
2211
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_jsx_runtime19.Fragment, { children: this.props.children });
2155
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_jsx_runtime18.Fragment, { children: this.props.children });
2212
2156
  }
2213
2157
  };
2214
2158
 
2215
2159
  // src/i18n/I18nProvider.tsx
2216
- var import_react13 = require("react");
2160
+ var import_react12 = require("react");
2217
2161
  var import_i18next = __toESM(require("i18next"), 1);
2218
2162
  var import_react_i18next = require("react-i18next");
2219
- var import_sdk6 = require("@hook-sdk/sdk");
2220
- var import_jsx_runtime20 = require("react/jsx-runtime");
2163
+ var import_sdk5 = require("@hook-sdk/sdk");
2164
+ var import_jsx_runtime19 = require("react/jsx-runtime");
2221
2165
  function ensureInitialized(defaultLocale, supportedLocales, resources, initialLocale) {
2222
2166
  if (import_i18next.default.isInitialized) return;
2223
2167
  import_i18next.default.use(import_react_i18next.initReactI18next).init({
@@ -2239,14 +2183,14 @@ function I18nProvider({
2239
2183
  resources,
2240
2184
  children
2241
2185
  }) {
2242
- const [userLocale] = (0, import_sdk6.usePersistedState)("user-locale", defaultLocale);
2186
+ const [userLocale] = (0, import_sdk5.usePersistedState)("user-locale", defaultLocale);
2243
2187
  ensureInitialized(defaultLocale, supportedLocales, resources, userLocale);
2244
- (0, import_react13.useEffect)(() => {
2188
+ (0, import_react12.useEffect)(() => {
2245
2189
  if (import_i18next.default.isInitialized && import_i18next.default.language !== userLocale) {
2246
2190
  import_i18next.default.changeLanguage(userLocale);
2247
2191
  }
2248
2192
  }, [userLocale]);
2249
- return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_i18next.I18nextProvider, { i18n: import_i18next.default, children });
2193
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_react_i18next.I18nextProvider, { i18n: import_i18next.default, children });
2250
2194
  }
2251
2195
 
2252
2196
  // src/dev/env.ts
@@ -2257,9 +2201,9 @@ function isDevToolsEnabled() {
2257
2201
  }
2258
2202
 
2259
2203
  // src/dev/DevSkipOnboardingFab.tsx
2260
- var import_react14 = require("react");
2261
- var import_sdk7 = require("@hook-sdk/sdk");
2262
- var import_jsx_runtime21 = require("react/jsx-runtime");
2204
+ var import_react13 = require("react");
2205
+ var import_sdk6 = require("@hook-sdk/sdk");
2206
+ var import_jsx_runtime20 = require("react/jsx-runtime");
2263
2207
  var STORAGE_KEY = "hook_dev_skip_email";
2264
2208
  var TEST_EMAIL_DOMAIN = "@hook.test";
2265
2209
  var TEST_PASSWORD = "SkipTest!2026";
@@ -2326,18 +2270,18 @@ var STYLES = {
2326
2270
  };
2327
2271
  var CONFIRM_TIMEOUT_MS = 3e3;
2328
2272
  function DevSkipOnboardingFab({ defaults }) {
2329
- const hook = (0, import_sdk7.useHook)();
2273
+ const hook = (0, import_sdk6.useHook)();
2330
2274
  const { slug } = useAppConfig();
2331
- const [state, setState] = (0, import_react14.useState)("idle");
2332
- const [errorMsg, setErrorMsg] = (0, import_react14.useState)(null);
2333
- const timerRef = (0, import_react14.useRef)(null);
2334
- const clearTimer = (0, import_react14.useCallback)(() => {
2275
+ const [state, setState] = (0, import_react13.useState)("idle");
2276
+ const [errorMsg, setErrorMsg] = (0, import_react13.useState)(null);
2277
+ const timerRef = (0, import_react13.useRef)(null);
2278
+ const clearTimer = (0, import_react13.useCallback)(() => {
2335
2279
  if (timerRef.current) {
2336
2280
  clearTimeout(timerRef.current);
2337
2281
  timerRef.current = null;
2338
2282
  }
2339
2283
  }, []);
2340
- const onClick = (0, import_react14.useCallback)(async () => {
2284
+ const onClick = (0, import_react13.useCallback)(async () => {
2341
2285
  if (state === "busy") return;
2342
2286
  if (state === "idle" || state === "error") {
2343
2287
  setState("confirm");
@@ -2366,7 +2310,7 @@ function DevSkipOnboardingFab({ defaults }) {
2366
2310
  ...state === "confirm" || state === "error" ? STYLES.confirm : {},
2367
2311
  ...state === "busy" ? STYLES.busy : {}
2368
2312
  };
2369
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
2313
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
2370
2314
  "button",
2371
2315
  {
2372
2316
  type: "button",
@@ -2381,21 +2325,21 @@ function DevSkipOnboardingFab({ defaults }) {
2381
2325
  }
2382
2326
 
2383
2327
  // src/internal/PaymentReturnHandler.tsx
2384
- var import_react15 = require("react");
2385
- var import_sdk8 = require("@hook-sdk/sdk");
2386
- var import_jsx_runtime22 = require("react/jsx-runtime");
2328
+ var import_react14 = require("react");
2329
+ var import_sdk7 = require("@hook-sdk/sdk");
2330
+ var import_jsx_runtime21 = require("react/jsx-runtime");
2387
2331
  var BACKOFF_MS = [2e3, 5e3, 1e4, 2e4, 4e4];
2388
2332
  var MAX_CYCLES = 3;
2389
2333
  var SUPPORT_MAILTO = "mailto:suporte@usehook.net?subject=Pagamento%20pendente";
2390
2334
  function PaymentReturnHandler({ children }) {
2391
- const { subscription, track: track2 } = (0, import_sdk8.useHook)();
2392
- const subRef = (0, import_react15.useRef)(subscription);
2335
+ const { subscription, track: track2 } = (0, import_sdk7.useHook)();
2336
+ const subRef = (0, import_react14.useRef)(subscription);
2393
2337
  subRef.current = subscription;
2394
- const runIdRef = (0, import_react15.useRef)(0);
2395
- const cyclesRef = (0, import_react15.useRef)(0);
2396
- const startMsRef = (0, import_react15.useRef)(0);
2397
- const [state, setState] = (0, import_react15.useState)("idle");
2398
- const runPoll = (0, import_react15.useCallback)(() => {
2338
+ const runIdRef = (0, import_react14.useRef)(0);
2339
+ const cyclesRef = (0, import_react14.useRef)(0);
2340
+ const startMsRef = (0, import_react14.useRef)(0);
2341
+ const [state, setState] = (0, import_react14.useState)("idle");
2342
+ const runPoll = (0, import_react14.useCallback)(() => {
2399
2343
  const runId = ++runIdRef.current;
2400
2344
  const isFirstRun = cyclesRef.current === 0;
2401
2345
  cyclesRef.current += 1;
@@ -2443,7 +2387,7 @@ function PaymentReturnHandler({ children }) {
2443
2387
  };
2444
2388
  void tick();
2445
2389
  }, [track2]);
2446
- (0, import_react15.useEffect)(() => {
2390
+ (0, import_react14.useEffect)(() => {
2447
2391
  if (typeof window === "undefined") return;
2448
2392
  const url = new URL(window.location.href);
2449
2393
  if (url.searchParams.get("paymentReturn") !== "1") return;
@@ -2453,26 +2397,26 @@ function PaymentReturnHandler({ children }) {
2453
2397
  runIdRef.current++;
2454
2398
  };
2455
2399
  }, [runPoll]);
2456
- const goHome = (0, import_react15.useCallback)(() => {
2400
+ const goHome = (0, import_react14.useCallback)(() => {
2457
2401
  const cleanUrl = new URL(window.location.href);
2458
2402
  cleanUrl.searchParams.delete("paymentReturn");
2459
2403
  cleanUrl.pathname = "/app/home";
2460
2404
  window.location.href = cleanUrl.toString();
2461
2405
  }, []);
2462
2406
  if (state === "confirming") {
2463
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { role: "status", "aria-live": "polite", style: overlayStyle2, children: "Confirmando pagamento\u2026" });
2407
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { role: "status", "aria-live": "polite", style: overlayStyle2, children: "Confirmando pagamento\u2026" });
2464
2408
  }
2465
2409
  if (state === "waiting") {
2466
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { role: "status", "aria-live": "polite", style: overlayStyle2, children: /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { style: { maxWidth: 320, textAlign: "center", lineHeight: 1.5 }, children: [
2467
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { style: { marginBottom: 16 }, children: "Pagamento aceito. Estamos confirmando com o banco \u2014 pode levar alguns minutos." }),
2468
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("button", { type: "button", onClick: runPoll, style: buttonStyle, children: "Atualizar" })
2410
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { role: "status", "aria-live": "polite", style: overlayStyle2, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { style: { maxWidth: 320, textAlign: "center", lineHeight: 1.5 }, children: [
2411
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { style: { marginBottom: 16 }, children: "Pagamento aceito. Estamos confirmando com o banco \u2014 pode levar alguns minutos." }),
2412
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("button", { type: "button", onClick: runPoll, style: buttonStyle, children: "Atualizar" })
2469
2413
  ] }) });
2470
2414
  }
2471
2415
  if (state === "timeout") {
2472
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { role: "alert", "aria-live": "assertive", style: overlayStyle2, children: /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { style: { maxWidth: 360, textAlign: "center", lineHeight: 1.5 }, children: [
2473
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { style: { marginBottom: 16 }, children: "Ainda n\xE3o conseguimos confirmar seu pagamento com o banco. Voc\xEA pode tentar de novo, voltar pro app, ou falar com a gente." }),
2474
- /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: 8 }, children: [
2475
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
2416
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { role: "alert", "aria-live": "assertive", style: overlayStyle2, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { style: { maxWidth: 360, textAlign: "center", lineHeight: 1.5 }, children: [
2417
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { style: { marginBottom: 16 }, children: "Ainda n\xE3o conseguimos confirmar seu pagamento com o banco. Voc\xEA pode tentar de novo, voltar pro app, ou falar com a gente." }),
2418
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: 8 }, children: [
2419
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
2476
2420
  "button",
2477
2421
  {
2478
2422
  type: "button",
@@ -2485,7 +2429,7 @@ function PaymentReturnHandler({ children }) {
2485
2429
  children: "Tentar de novo"
2486
2430
  }
2487
2431
  ),
2488
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
2432
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
2489
2433
  "button",
2490
2434
  {
2491
2435
  type: "button",
@@ -2495,7 +2439,7 @@ function PaymentReturnHandler({ children }) {
2495
2439
  children: "Voltar pro app"
2496
2440
  }
2497
2441
  ),
2498
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
2442
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
2499
2443
  "a",
2500
2444
  {
2501
2445
  href: SUPPORT_MAILTO,
@@ -2507,7 +2451,7 @@ function PaymentReturnHandler({ children }) {
2507
2451
  ] })
2508
2452
  ] }) });
2509
2453
  }
2510
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_jsx_runtime22.Fragment, { children });
2454
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_jsx_runtime21.Fragment, { children });
2511
2455
  }
2512
2456
  var overlayStyle2 = {
2513
2457
  position: "fixed",
@@ -2546,7 +2490,7 @@ var linkStyle = {
2546
2490
  };
2547
2491
 
2548
2492
  // src/AppRoot.tsx
2549
- var import_jsx_runtime23 = require("react/jsx-runtime");
2493
+ var import_jsx_runtime22 = require("react/jsx-runtime");
2550
2494
  function buildLegacyConfigShim(config) {
2551
2495
  const paywall = config.paywall;
2552
2496
  const isFree = paywall.mode === "free";
@@ -2620,22 +2564,19 @@ function AppRoot(props) {
2620
2564
  "[hook-template] <AppRoot>: PreAuthFlow slot prop is required when config.onboarding.trigger === 'pre_signup_custom'."
2621
2565
  );
2622
2566
  }
2623
- const legacyShim = (0, import_react16.useMemo)(() => buildLegacyConfigShim(config), [config]);
2567
+ const legacyShim = (0, import_react15.useMemo)(() => buildLegacyConfigShim(config), [config]);
2624
2568
  const Router = testRouter === "memory" ? import_react_router_dom2.MemoryRouter : import_react_router_dom2.BrowserRouter;
2625
2569
  const basename = `/app/${config.slug}`;
2626
2570
  const routerProps = testRouter === "memory" ? { basename, initialEntries: testInitialEntries } : { basename };
2627
2571
  const position = config.install_prompt?.position ?? "post-paywall";
2628
- const subscriptionGated = /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(SubscriptionGate, { Paywall: Paywall2 ?? FallbackPaywall, children: [
2629
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(EmailVerifyBanner, {}),
2630
- position === "post-paywall" ? /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(InstallGate, { position: "post-paywall", children: [
2631
- children,
2632
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(PushPrompt, {})
2633
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_jsx_runtime23.Fragment, { children: [
2634
- children,
2635
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(PushPrompt, {})
2636
- ] })
2637
- ] });
2638
- const authGated = /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
2572
+ const subscriptionGated = /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(SubscriptionGate, { Paywall: Paywall2 ?? FallbackPaywall, children: position === "post-paywall" ? /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(InstallGate, { position: "post-paywall", children: [
2573
+ children,
2574
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(PushPrompt, {})
2575
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_jsx_runtime22.Fragment, { children: [
2576
+ children,
2577
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(PushPrompt, {})
2578
+ ] }) });
2579
+ const authGated = /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
2639
2580
  AuthGated,
2640
2581
  {
2641
2582
  config,
@@ -2650,13 +2591,13 @@ function AppRoot(props) {
2650
2591
  children: subscriptionGated
2651
2592
  }
2652
2593
  );
2653
- const routedTree = /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(Router, { ...routerProps, children: [
2654
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(DeepLinkHandler, { deepLinks: config.deepLinks }),
2655
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(SessionExpiredBanner, {}),
2656
- position === "pre-auth" ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(InstallGate, { position: "pre-auth", children: authGated }) : authGated,
2657
- isDevToolsEnabled() && devSkipOnboarding ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(DevSkipOnboardingFab, { defaults: devSkipOnboarding.defaults }) : null
2594
+ const routedTree = /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(Router, { ...routerProps, children: [
2595
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(DeepLinkHandler, { deepLinks: config.deepLinks }),
2596
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(SessionExpiredBanner, {}),
2597
+ position === "pre-auth" ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(InstallGate, { position: "pre-auth", children: authGated }) : authGated,
2598
+ isDevToolsEnabled() && devSkipOnboarding ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(DevSkipOnboardingFab, { defaults: devSkipOnboarding.defaults }) : null
2658
2599
  ] });
2659
- return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(ErrorBoundary, { children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(AppConfigProvider, { config, children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(TemplateConfigProvider, { config: legacyShim, children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(ThemeProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(PersistenceRegistry, { config: config.persistedKeys, children: config.i18n ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
2600
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ErrorBoundary, { children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(AppConfigProvider, { config, children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(TemplateConfigProvider, { config: legacyShim, children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ThemeProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(PersistenceRegistry, { config: config.persistedKeys, children: config.i18n ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
2660
2601
  I18nProvider,
2661
2602
  {
2662
2603
  defaultLocale: config.i18n.defaultLocale,
@@ -2676,37 +2617,46 @@ function AuthGated({
2676
2617
  EmailVerify,
2677
2618
  PreAuthFlow
2678
2619
  }) {
2679
- const { authStatus } = (0, import_sdk9.useHook)();
2620
+ const { authStatus } = (0, import_sdk8.useHook)();
2680
2621
  if (authStatus === "loading") return null;
2681
2622
  if (authStatus !== "authenticated") {
2623
+ if (config.authFlow.signupMode === "pay_first" && PreAuthFlow) {
2624
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_react_router_dom2.Routes, { children: [
2625
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_react_router_dom2.Route, { path: "/signin", element: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(Login, {}) }),
2626
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_react_router_dom2.Route, { path: "/forgot", element: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(Forgot, {}) }),
2627
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_react_router_dom2.Route, { path: "/reset", element: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(Reset, {}) }),
2628
+ EmailVerify ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_react_router_dom2.Route, { path: "/verify", element: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(EmailVerify, {}) }) : null,
2629
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_react_router_dom2.Route, { path: "/*", element: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(PreAuthFlow, {}) })
2630
+ ] });
2631
+ }
2682
2632
  if (config.onboarding?.trigger === "pre_signup_custom" && PreAuthFlow) {
2683
- return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_react_router_dom2.Routes, { children: [
2684
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_react_router_dom2.Route, { path: "/signin", element: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(Login, {}) }),
2685
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_react_router_dom2.Route, { path: "/signup", element: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(Signup, {}) }),
2686
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_react_router_dom2.Route, { path: "/forgot", element: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(Forgot, {}) }),
2687
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_react_router_dom2.Route, { path: "/reset", element: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(Reset, {}) }),
2688
- EmailVerify ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_react_router_dom2.Route, { path: "/verify", element: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(EmailVerify, {}) }) : null,
2689
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_react_router_dom2.Route, { path: "/*", element: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(PreAuthFlow, {}) })
2633
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_react_router_dom2.Routes, { children: [
2634
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_react_router_dom2.Route, { path: "/signin", element: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(Login, {}) }),
2635
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_react_router_dom2.Route, { path: "/signup", element: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(Signup, {}) }),
2636
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_react_router_dom2.Route, { path: "/forgot", element: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(Forgot, {}) }),
2637
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_react_router_dom2.Route, { path: "/reset", element: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(Reset, {}) }),
2638
+ EmailVerify ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_react_router_dom2.Route, { path: "/verify", element: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(EmailVerify, {}) }) : null,
2639
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_react_router_dom2.Route, { path: "/*", element: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(PreAuthFlow, {}) })
2690
2640
  ] });
2691
2641
  }
2692
- return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_react_router_dom2.Routes, { children: [
2693
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_react_router_dom2.Route, { path: "/", element: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(Login, {}) }),
2694
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_react_router_dom2.Route, { path: "/signup", element: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(Signup, {}) }),
2695
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_react_router_dom2.Route, { path: "/forgot", element: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(Forgot, {}) }),
2696
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_react_router_dom2.Route, { path: "/reset", element: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(Reset, {}) }),
2697
- EmailVerify ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_react_router_dom2.Route, { path: "/verify", element: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(EmailVerify, {}) }) : null,
2698
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_react_router_dom2.Route, { path: "*", element: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_react_router_dom2.Navigate, { to: "/", replace: true }) })
2642
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_react_router_dom2.Routes, { children: [
2643
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_react_router_dom2.Route, { path: "/", element: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(Login, {}) }),
2644
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_react_router_dom2.Route, { path: "/signup", element: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(Signup, {}) }),
2645
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_react_router_dom2.Route, { path: "/forgot", element: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(Forgot, {}) }),
2646
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_react_router_dom2.Route, { path: "/reset", element: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(Reset, {}) }),
2647
+ EmailVerify ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_react_router_dom2.Route, { path: "/verify", element: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(EmailVerify, {}) }) : null,
2648
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_react_router_dom2.Route, { path: "*", element: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_react_router_dom2.Navigate, { to: "/", replace: true }) })
2699
2649
  ] });
2700
2650
  }
2701
- return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_jsx_runtime23.Fragment, { children });
2651
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_jsx_runtime22.Fragment, { children });
2702
2652
  }
2703
2653
  function FallbackPaywall() {
2704
2654
  return null;
2705
2655
  }
2706
2656
 
2707
2657
  // src/hooks/usePush.ts
2708
- var import_react17 = require("react");
2709
- var import_sdk10 = require("@hook-sdk/sdk");
2658
+ var import_react16 = require("react");
2659
+ var import_sdk9 = require("@hook-sdk/sdk");
2710
2660
  var DISMISS_STORAGE_KEY = "push:dismissed-until";
2711
2661
  var DISMISS_TTL_MS2 = 7 * 24 * 60 * 60 * 1e3;
2712
2662
  function detectIosNeedsInstall() {
@@ -2750,12 +2700,12 @@ function deriveState(push) {
2750
2700
  return { kind: "prompt" };
2751
2701
  }
2752
2702
  function usePush() {
2753
- const { push } = (0, import_sdk10.useHook)();
2754
- const [state, setState] = (0, import_react17.useState)(() => deriveState(push));
2755
- (0, import_react17.useEffect)(() => {
2703
+ const { push } = (0, import_sdk9.useHook)();
2704
+ const [state, setState] = (0, import_react16.useState)(() => deriveState(push));
2705
+ (0, import_react16.useEffect)(() => {
2756
2706
  setState(deriveState(push));
2757
2707
  }, [push]);
2758
- const subscribe = (0, import_react17.useCallback)(async () => {
2708
+ const subscribe = (0, import_react16.useCallback)(async () => {
2759
2709
  try {
2760
2710
  await push.subscribe();
2761
2711
  setState({ kind: "subscribed" });
@@ -2767,7 +2717,7 @@ function usePush() {
2767
2717
  throw e;
2768
2718
  }
2769
2719
  }, [push]);
2770
- const unsubscribe = (0, import_react17.useCallback)(async () => {
2720
+ const unsubscribe = (0, import_react16.useCallback)(async () => {
2771
2721
  try {
2772
2722
  await push.unsubscribe();
2773
2723
  setState({ kind: "prompt" });
@@ -2776,7 +2726,7 @@ function usePush() {
2776
2726
  throw e;
2777
2727
  }
2778
2728
  }, [push]);
2779
- const dismiss = (0, import_react17.useCallback)(() => {
2729
+ const dismiss = (0, import_react16.useCallback)(() => {
2780
2730
  if (typeof localStorage !== "undefined") {
2781
2731
  try {
2782
2732
  localStorage.setItem(DISMISS_STORAGE_KEY, String(Date.now() + DISMISS_TTL_MS2));
@@ -2789,27 +2739,27 @@ function usePush() {
2789
2739
  }
2790
2740
 
2791
2741
  // src/components/PushPrompt.tsx
2792
- var import_jsx_runtime24 = require("react/jsx-runtime");
2742
+ var import_jsx_runtime23 = require("react/jsx-runtime");
2793
2743
  function PushPrompt2({ texts, onSubscribed, onDeclined, onInstallRequested, className }) {
2794
2744
  const { state, subscribe } = usePush();
2795
2745
  if (state.kind === "denied" || state.kind === "dismissed" || state.kind === "subscribed") {
2796
2746
  return null;
2797
2747
  }
2798
2748
  if (state.kind === "ios_needs_install") {
2799
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className, role: "region", "aria-label": texts.iosInstallTitle, children: [
2800
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("h3", { children: texts.iosInstallTitle }),
2801
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("p", { children: texts.iosInstallBody }),
2802
- onInstallRequested && texts.iosInstallCta && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("button", { onClick: onInstallRequested, children: texts.iosInstallCta })
2749
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className, role: "region", "aria-label": texts.iosInstallTitle, children: [
2750
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("h3", { children: texts.iosInstallTitle }),
2751
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("p", { children: texts.iosInstallBody }),
2752
+ onInstallRequested && texts.iosInstallCta && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("button", { onClick: onInstallRequested, children: texts.iosInstallCta })
2803
2753
  ] });
2804
2754
  }
2805
2755
  if (state.kind === "unsupported") {
2806
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className, role: "region", children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("p", { children: texts.unsupportedBody }) });
2756
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className, role: "region", children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("p", { children: texts.unsupportedBody }) });
2807
2757
  }
2808
2758
  if (state.kind === "error") {
2809
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className, role: "region", "aria-label": "error", children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("p", { children: state.message }) });
2759
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className, role: "region", "aria-label": "error", children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("p", { children: state.message }) });
2810
2760
  }
2811
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className, role: "region", children: [
2812
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
2761
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className, role: "region", children: [
2762
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
2813
2763
  "button",
2814
2764
  {
2815
2765
  type: "button",
@@ -2823,67 +2773,71 @@ function PushPrompt2({ texts, onSubscribed, onDeclined, onInstallRequested, clas
2823
2773
  children: texts.cta
2824
2774
  }
2825
2775
  ),
2826
- onDeclined && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("button", { type: "button", onClick: onDeclined, children: texts.declineCta })
2776
+ onDeclined && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("button", { type: "button", onClick: onDeclined, children: texts.declineCta })
2827
2777
  ] });
2828
2778
  }
2829
2779
 
2830
2780
  // src/components/LanguageSwitcher.tsx
2831
- var import_sdk11 = require("@hook-sdk/sdk");
2832
- var import_jsx_runtime25 = require("react/jsx-runtime");
2781
+ var import_sdk10 = require("@hook-sdk/sdk");
2782
+ var import_jsx_runtime24 = require("react/jsx-runtime");
2833
2783
  function LanguageSwitcher({ id, className, label = "Language" }) {
2834
2784
  const config = useAppConfig();
2835
2785
  const i18nConfig = config.i18n;
2836
- const [userLocale, setUserLocale] = (0, import_sdk11.usePersistedState)(
2786
+ const [userLocale, setUserLocale] = (0, import_sdk10.usePersistedState)(
2837
2787
  "user-locale",
2838
2788
  i18nConfig?.defaultLocale ?? "en-US"
2839
2789
  );
2840
2790
  if (!i18nConfig) return null;
2841
- return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("label", { className, children: [
2842
- label ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { children: label }) : null,
2843
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
2791
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("label", { className, children: [
2792
+ label ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { children: label }) : null,
2793
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
2844
2794
  "select",
2845
2795
  {
2846
2796
  id,
2847
2797
  value: userLocale,
2848
2798
  onChange: (e) => setUserLocale(e.target.value),
2849
2799
  "data-testid": "language-switcher",
2850
- children: i18nConfig.supportedLocales.map((loc) => /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("option", { value: loc, children: loc }, loc))
2800
+ children: i18nConfig.supportedLocales.map((loc) => /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("option", { value: loc, children: loc }, loc))
2851
2801
  }
2852
2802
  )
2853
2803
  ] });
2854
2804
  }
2855
2805
 
2856
2806
  // src/defaults/LoadingState.tsx
2857
- var import_jsx_runtime26 = require("react/jsx-runtime");
2807
+ var import_jsx_runtime25 = require("react/jsx-runtime");
2858
2808
  function LoadingState({ message }) {
2859
- return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { role: "status", "aria-live": "polite", style: { padding: 24, textAlign: "center" }, children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { children: message ?? "Carregando..." }) });
2809
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { role: "status", "aria-live": "polite", style: { padding: 24, textAlign: "center" }, children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { children: message ?? "Carregando..." }) });
2860
2810
  }
2861
2811
 
2862
2812
  // src/defaults/EmptyState.tsx
2863
- var import_jsx_runtime27 = require("react/jsx-runtime");
2813
+ var import_jsx_runtime26 = require("react/jsx-runtime");
2864
2814
  function EmptyState({ title, description, action }) {
2865
- return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { role: "status", style: { padding: 32, textAlign: "center" }, children: [
2866
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("h2", { style: { marginBottom: 8 }, children: title }),
2867
- description && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("p", { style: { opacity: 0.7 }, children: description }),
2868
- action && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { style: { marginTop: 16 }, children: action })
2815
+ return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { role: "status", style: { padding: 32, textAlign: "center" }, children: [
2816
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("h2", { style: { marginBottom: 8 }, children: title }),
2817
+ description && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("p", { style: { opacity: 0.7 }, children: description }),
2818
+ action && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { style: { marginTop: 16 }, children: action })
2869
2819
  ] });
2870
2820
  }
2871
2821
 
2872
- // src/hooks/useLoginForm.ts
2822
+ // src/defaults/CheckoutPageDefault.tsx
2873
2823
  var import_react18 = require("react");
2874
- var import_sdk13 = require("@hook-sdk/sdk");
2824
+ var import_react_router_dom3 = require("react-router-dom");
2875
2825
 
2876
- // src/errors.ts
2826
+ // src/hooks/useCheckoutForm.ts
2827
+ var import_react17 = require("react");
2877
2828
  var import_sdk12 = require("@hook-sdk/sdk");
2829
+
2830
+ // src/errors.ts
2831
+ var import_sdk11 = require("@hook-sdk/sdk");
2878
2832
  function mapSdkError(err) {
2879
- if (err instanceof import_sdk12.SdkRateLimitError) {
2833
+ if (err instanceof import_sdk11.SdkRateLimitError) {
2880
2834
  return {
2881
2835
  code: "rate_limited",
2882
2836
  message: `Aguarde ${err.retryAfter}s e tente novamente.`,
2883
2837
  retryAfter: err.retryAfter
2884
2838
  };
2885
2839
  }
2886
- if (err instanceof import_sdk12.SdkAuthError) {
2840
+ if (err instanceof import_sdk11.SdkAuthError) {
2887
2841
  const detail = err.detail;
2888
2842
  if (detail === "email_unverified") {
2889
2843
  return { code: "email_unverified", message: "Confirme seu e-mail antes de entrar." };
@@ -2893,10 +2847,7 @@ function mapSdkError(err) {
2893
2847
  }
2894
2848
  return { code: "invalid_credentials", message: "E-mail ou senha inv\xE1lidos." };
2895
2849
  }
2896
- if (err instanceof import_sdk12.SdkValidationError && err.code === "auth.email_taken") {
2897
- return { code: "email_taken", message: "Esse e-mail j\xE1 tem conta." };
2898
- }
2899
- if (err instanceof import_sdk12.SdkError && err.httpStatus === 0) {
2850
+ if (err instanceof import_sdk11.SdkError && err.httpStatus === 0) {
2900
2851
  return { code: "network", message: "Sem conex\xE3o com o servidor. Verifique sua internet." };
2901
2852
  }
2902
2853
  if (err instanceof TypeError) {
@@ -2905,212 +2856,785 @@ function mapSdkError(err) {
2905
2856
  return { code: "server", message: "Algo deu errado. Tente novamente em instantes." };
2906
2857
  }
2907
2858
 
2908
- // src/hooks/useLoginForm.ts
2859
+ // src/hooks/useCheckoutForm.ts
2909
2860
  var EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
2910
- var MIN_PASSWORD = 8;
2911
- function useLoginForm() {
2912
- const { auth } = (0, import_sdk13.useHook)();
2913
- const [email, setEmail] = (0, import_react18.useState)("");
2914
- const [password, setPassword] = (0, import_react18.useState)("");
2915
- const [submitting, setSubmitting] = (0, import_react18.useState)(false);
2916
- const [error, setError] = (0, import_react18.useState)(null);
2917
- const [touchedEmail, setTouchedEmail] = (0, import_react18.useState)(false);
2918
- const [touchedPassword, setTouchedPassword] = (0, import_react18.useState)(false);
2919
- const [formSubmitAttempted, setFormSubmitAttempted] = (0, import_react18.useState)(false);
2920
- const validateEmail = (0, import_react18.useMemo)(() => {
2921
- if (email.length === 0) return null;
2922
- if (!EMAIL_RE.test(email)) return "Formato de e-mail inv\xE1lido.";
2923
- return null;
2924
- }, [email]);
2925
- const validatePassword = (0, import_react18.useMemo)(() => {
2926
- if (password.length === 0) return null;
2927
- if (password.length < MIN_PASSWORD) return `M\xEDnimo de ${MIN_PASSWORD} caracteres.`;
2928
- return null;
2929
- }, [password]);
2930
- const emailError = touchedEmail || formSubmitAttempted ? validateEmail : null;
2931
- const passwordError = touchedPassword || formSubmitAttempted ? validatePassword : null;
2932
- const canSubmit = email.length > 0 && password.length >= MIN_PASSWORD && validateEmail === null && validatePassword === null && !submitting;
2933
- const submit = (0, import_react18.useCallback)(async () => {
2934
- setFormSubmitAttempted(true);
2935
- if (!canSubmit) return false;
2936
- setSubmitting(true);
2937
- setError(null);
2938
- try {
2939
- await auth.login({ email, password });
2940
- return true;
2941
- } catch (err) {
2942
- setError(mapSdkError(err));
2943
- return false;
2944
- } finally {
2945
- setSubmitting(false);
2861
+ var PHONE_RE = /^[0-9()+\-\s]{8,20}$/;
2862
+ var CHECK_DEBOUNCE_MS = 400;
2863
+ function useCheckoutForm(args) {
2864
+ const { auth } = (0, import_sdk12.useHook)();
2865
+ const [name, setName] = (0, import_react17.useState)("");
2866
+ const [email, setEmail] = (0, import_react17.useState)("");
2867
+ const [emailConfirm, setEmailConfirm] = (0, import_react17.useState)("");
2868
+ const [phone, setPhone] = (0, import_react17.useState)("");
2869
+ const [cpf, setCpf] = (0, import_react17.useState)("");
2870
+ const [method, setMethod] = (0, import_react17.useState)(args.defaultMethod);
2871
+ const [cycle, setCycle] = (0, import_react17.useState)(args.defaultCycle);
2872
+ const [card, setCardState] = (0, import_react17.useState)({
2873
+ number: "",
2874
+ expiryMonth: "",
2875
+ expiryYear: "",
2876
+ ccv: "",
2877
+ holderName: ""
2878
+ });
2879
+ const setCard = (0, import_react17.useCallback)((patch) => {
2880
+ setCardState((prev) => ({ ...prev, ...patch }));
2881
+ }, []);
2882
+ const [touchedName, setTouchedName] = (0, import_react17.useState)(false);
2883
+ const [touchedEmail, setTouchedEmail] = (0, import_react17.useState)(false);
2884
+ const [touchedEmailConfirm, setTouchedEmailConfirm] = (0, import_react17.useState)(false);
2885
+ const [touchedPhone, setTouchedPhone] = (0, import_react17.useState)(false);
2886
+ const [touchedCpf, setTouchedCpf] = (0, import_react17.useState)(false);
2887
+ const [formSubmitAttempted, setFormSubmitAttempted] = (0, import_react17.useState)(false);
2888
+ const [submitting, setSubmitting] = (0, import_react17.useState)(false);
2889
+ const [error, setError] = (0, import_react17.useState)(null);
2890
+ const [emailTaken, setEmailTaken] = (0, import_react17.useState)(false);
2891
+ const [loginUrl, setLoginUrl] = (0, import_react17.useState)(null);
2892
+ const [emailStatus, setEmailStatus] = (0, import_react17.useState)("idle");
2893
+ const lastCheckedEmail = (0, import_react17.useRef)("");
2894
+ (0, import_react17.useEffect)(() => {
2895
+ if (!email || !EMAIL_RE.test(email)) {
2896
+ setEmailStatus("idle");
2897
+ return;
2946
2898
  }
2947
- }, [auth, email, password, canSubmit]);
2948
- return {
2949
- email,
2950
- setEmail,
2951
- emailError,
2952
- markEmailTouched: () => setTouchedEmail(true),
2953
- password,
2954
- setPassword,
2955
- passwordError,
2956
- markPasswordTouched: () => setTouchedPassword(true),
2957
- formSubmitAttempted,
2958
- submit,
2959
- submitting,
2960
- canSubmit,
2961
- error,
2962
- loginWithGoogle: () => auth.loginWithGoogle()
2963
- };
2964
- }
2965
-
2966
- // src/hooks/useSignupForm.ts
2967
- var import_react19 = require("react");
2968
- var import_sdk14 = require("@hook-sdk/sdk");
2969
- var EMAIL_RE2 = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
2970
- var MIN_PASSWORD2 = 8;
2971
- function useSignupForm() {
2972
- const { auth } = (0, import_sdk14.useHook)();
2973
- const [name, setName] = (0, import_react19.useState)("");
2974
- const [email, setEmail] = (0, import_react19.useState)("");
2975
- const [password, setPassword] = (0, import_react19.useState)("");
2976
- const [submitting, setSubmitting] = (0, import_react19.useState)(false);
2977
- const [error, setError] = (0, import_react19.useState)(null);
2978
- const [touchedName, setTouchedName] = (0, import_react19.useState)(false);
2979
- const [touchedEmail, setTouchedEmail] = (0, import_react19.useState)(false);
2980
- const [touchedPassword, setTouchedPassword] = (0, import_react19.useState)(false);
2981
- const [formSubmitAttempted, setFormSubmitAttempted] = (0, import_react19.useState)(false);
2982
- const validateName = (0, import_react19.useMemo)(() => {
2899
+ if (email === lastCheckedEmail.current) return;
2900
+ const timer = setTimeout(async () => {
2901
+ setEmailStatus("checking");
2902
+ try {
2903
+ const result = await auth.checkEmailExists({ email });
2904
+ lastCheckedEmail.current = email;
2905
+ setEmailStatus(result.exists ? "exists" : "available");
2906
+ } catch {
2907
+ setEmailStatus("idle");
2908
+ }
2909
+ }, CHECK_DEBOUNCE_MS);
2910
+ return () => clearTimeout(timer);
2911
+ }, [email, auth]);
2912
+ const validateName = (0, import_react17.useMemo)(() => {
2983
2913
  if (name.length === 0) return null;
2984
2914
  if (name.trim().length < 2) return "Nome muito curto.";
2985
2915
  return null;
2986
2916
  }, [name]);
2987
- const validateEmail = (0, import_react19.useMemo)(() => {
2917
+ const validateEmail = (0, import_react17.useMemo)(() => {
2988
2918
  if (email.length === 0) return null;
2989
- if (!EMAIL_RE2.test(email)) return "Formato de e-mail inv\xE1lido.";
2919
+ if (!EMAIL_RE.test(email)) return "Formato de e-mail inv\xE1lido.";
2990
2920
  return null;
2991
2921
  }, [email]);
2992
- const validatePassword = (0, import_react19.useMemo)(() => {
2993
- if (password.length === 0) return null;
2994
- if (password.length < MIN_PASSWORD2) return `M\xEDnimo de ${MIN_PASSWORD2} caracteres.`;
2922
+ const validateEmailConfirm = (0, import_react17.useMemo)(() => {
2923
+ if (emailConfirm.length === 0) return null;
2924
+ if (emailConfirm !== email) return "Os e-mails n\xE3o coincidem.";
2995
2925
  return null;
2996
- }, [password]);
2926
+ }, [emailConfirm, email]);
2927
+ const validatePhone = (0, import_react17.useMemo)(() => {
2928
+ if (phone.length === 0) return null;
2929
+ if (!PHONE_RE.test(phone)) return "Telefone inv\xE1lido.";
2930
+ return null;
2931
+ }, [phone]);
2932
+ const validateCpf = (0, import_react17.useMemo)(() => {
2933
+ if (cpf.length === 0) return null;
2934
+ const digits = cpf.replace(/\D/g, "");
2935
+ if (digits.length !== 11) return "CPF deve ter 11 d\xEDgitos.";
2936
+ if (/^(\d)\1+$/.test(digits)) return "CPF inv\xE1lido.";
2937
+ const ok = mod11(digits, 9) === digits[9] && mod11(digits, 10) === digits[10];
2938
+ return ok ? null : "CPF inv\xE1lido.";
2939
+ }, [cpf]);
2997
2940
  const nameError = touchedName || formSubmitAttempted ? validateName : null;
2998
2941
  const emailError = touchedEmail || formSubmitAttempted ? validateEmail : null;
2999
- const passwordError = touchedPassword || formSubmitAttempted ? validatePassword : null;
3000
- const canSubmit = name.trim().length >= 2 && email.length > 0 && password.length >= MIN_PASSWORD2 && validateName === null && validateEmail === null && validatePassword === null && !submitting;
3001
- const submit = (0, import_react19.useCallback)(async () => {
2942
+ const emailConfirmError = touchedEmailConfirm || formSubmitAttempted ? validateEmailConfirm : null;
2943
+ const phoneError = touchedPhone || formSubmitAttempted ? validatePhone : null;
2944
+ const cpfError = touchedCpf || formSubmitAttempted ? validateCpf : null;
2945
+ 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);
2946
+ const submit = (0, import_react17.useCallback)(async () => {
3002
2947
  setFormSubmitAttempted(true);
3003
- if (!canSubmit) return false;
3004
- setSubmitting(true);
3005
2948
  setError(null);
2949
+ setEmailTaken(false);
2950
+ setLoginUrl(null);
2951
+ if (!canSubmit) return null;
2952
+ setSubmitting(true);
3006
2953
  try {
3007
- await auth.signup({ name, email, password });
3008
- return true;
2954
+ let args2;
2955
+ if (method === "card") {
2956
+ args2 = {
2957
+ method: "card",
2958
+ name: name.trim(),
2959
+ email,
2960
+ emailConfirm,
2961
+ phone,
2962
+ cpf: cpf.replace(/\D/g, ""),
2963
+ cycle,
2964
+ card: {
2965
+ number: card.number.replace(/\s/g, ""),
2966
+ expiryMonth: card.expiryMonth,
2967
+ expiryYear: card.expiryYear,
2968
+ ccv: card.ccv,
2969
+ holderName: card.holderName
2970
+ },
2971
+ cardHolderInfo: {
2972
+ name: card.holderName || name.trim(),
2973
+ email,
2974
+ cpfCnpj: cpf.replace(/\D/g, ""),
2975
+ // Empty postal/address: backend defaults if Asaas requires.
2976
+ // Apps that need full address should override via custom form.
2977
+ postalCode: "00000000",
2978
+ addressNumber: "0",
2979
+ phone
2980
+ }
2981
+ };
2982
+ } else {
2983
+ args2 = {
2984
+ method: "pix-auto",
2985
+ name: name.trim(),
2986
+ email,
2987
+ emailConfirm,
2988
+ phone,
2989
+ cpf: cpf.replace(/\D/g, ""),
2990
+ cycle
2991
+ };
2992
+ }
2993
+ const result = await auth.subscribeAnonymous(args2);
2994
+ return result;
3009
2995
  } catch (err) {
2996
+ if (err instanceof import_sdk12.EmailTakenError) {
2997
+ setEmailTaken(true);
2998
+ setLoginUrl(err.loginUrl);
2999
+ setEmailStatus("exists");
3000
+ return null;
3001
+ }
3010
3002
  setError(mapSdkError(err));
3011
- return false;
3003
+ return null;
3012
3004
  } finally {
3013
3005
  setSubmitting(false);
3014
3006
  }
3015
- }, [auth, name, email, password, canSubmit]);
3007
+ }, [auth, canSubmit, method, cycle, name, email, emailConfirm, phone, cpf, card]);
3016
3008
  return {
3017
3009
  name,
3018
3010
  setName,
3019
- nameError,
3020
- markNameTouched: () => setTouchedName(true),
3021
3011
  email,
3022
3012
  setEmail,
3013
+ emailConfirm,
3014
+ setEmailConfirm,
3015
+ phone,
3016
+ setPhone,
3017
+ cpf,
3018
+ setCpf,
3019
+ method,
3020
+ setMethod,
3021
+ cycle,
3022
+ setCycle,
3023
+ card,
3024
+ setCard,
3025
+ nameError,
3023
3026
  emailError,
3027
+ emailConfirmError,
3028
+ phoneError,
3029
+ cpfError,
3030
+ markNameTouched: () => setTouchedName(true),
3024
3031
  markEmailTouched: () => setTouchedEmail(true),
3025
- password,
3026
- setPassword,
3027
- passwordError,
3028
- markPasswordTouched: () => setTouchedPassword(true),
3029
- formSubmitAttempted,
3032
+ markEmailConfirmTouched: () => setTouchedEmailConfirm(true),
3033
+ markPhoneTouched: () => setTouchedPhone(true),
3034
+ markCpfTouched: () => setTouchedCpf(true),
3035
+ emailStatus,
3030
3036
  submit,
3031
3037
  submitting,
3032
3038
  canSubmit,
3039
+ formSubmitAttempted,
3033
3040
  error,
3034
- loginWithGoogle: () => auth.loginWithGoogle()
3041
+ emailTaken,
3042
+ loginUrl
3035
3043
  };
3036
3044
  }
3045
+ function mod11(digits, len) {
3046
+ let sum = 0;
3047
+ for (let i = 0; i < len; i++) sum += parseInt(digits.charAt(i), 10) * (len + 1 - i);
3048
+ const r = sum * 10 % 11;
3049
+ return String(r === 10 ? 0 : r);
3050
+ }
3037
3051
 
3038
- // src/hooks/useForgotForm.ts
3039
- var import_react20 = require("react");
3040
- var import_sdk15 = require("@hook-sdk/sdk");
3041
- var EMAIL_RE3 = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
3042
- function useForgotForm() {
3043
- const { auth } = (0, import_sdk15.useHook)();
3044
- const [email, setEmail] = (0, import_react20.useState)("");
3045
- const [submitting, setSubmitting] = (0, import_react20.useState)(false);
3046
- const [sent, setSent] = (0, import_react20.useState)(false);
3047
- const [error, setError] = (0, import_react20.useState)(null);
3048
- const [touchedEmail, setTouchedEmail] = (0, import_react20.useState)(false);
3049
- const [formSubmitAttempted, setFormSubmitAttempted] = (0, import_react20.useState)(false);
3050
- const validateEmail = (0, import_react20.useMemo)(() => {
3051
- if (email.length === 0) return null;
3052
- if (!EMAIL_RE3.test(email)) return "Formato de e-mail inv\xE1lido.";
3053
- return null;
3054
- }, [email]);
3055
- const emailError = touchedEmail || formSubmitAttempted ? validateEmail : null;
3056
- const canSubmit = email.length > 0 && validateEmail === null && !submitting;
3057
- const submit = (0, import_react20.useCallback)(async () => {
3058
- setFormSubmitAttempted(true);
3059
- if (!canSubmit) return false;
3060
- setSubmitting(true);
3061
- setError(null);
3062
- try {
3063
- await auth.forgot({ email });
3064
- setSent(true);
3065
- return true;
3066
- } catch (err) {
3067
- setError(mapSdkError(err));
3068
- return false;
3069
- } finally {
3070
- setSubmitting(false);
3071
- }
3072
- }, [auth, email, canSubmit]);
3073
- return {
3074
- email,
3075
- setEmail,
3076
- emailError,
3077
- markEmailTouched: () => setTouchedEmail(true),
3078
- formSubmitAttempted,
3079
- submit,
3080
- submitting,
3081
- canSubmit,
3082
- sent,
3083
- error
3084
- };
3052
+ // src/hooks/usePlan.ts
3053
+ var import_sdk13 = require("@hook-sdk/sdk");
3054
+ function usePlan() {
3055
+ const { plan } = (0, import_sdk13.useHook)();
3056
+ return plan;
3085
3057
  }
3086
3058
 
3087
- // src/hooks/useResetForm.ts
3088
- var import_react21 = require("react");
3089
- var import_sdk16 = require("@hook-sdk/sdk");
3090
- var MIN_PASSWORD3 = 8;
3091
- function useResetForm() {
3092
- const { auth } = (0, import_sdk16.useHook)();
3093
- const [token, setToken] = (0, import_react21.useState)(null);
3094
- const [password, setPassword] = (0, import_react21.useState)("");
3095
- const [confirm, setConfirm] = (0, import_react21.useState)("");
3096
- const [submitting, setSubmitting] = (0, import_react21.useState)(false);
3097
- const [done, setDone] = (0, import_react21.useState)(false);
3098
- const [error, setError] = (0, import_react21.useState)(null);
3099
- const [touchedPassword, setTouchedPassword] = (0, import_react21.useState)(false);
3100
- const [touchedConfirm, setTouchedConfirm] = (0, import_react21.useState)(false);
3101
- const [formSubmitAttempted, setFormSubmitAttempted] = (0, import_react21.useState)(false);
3102
- (0, import_react21.useEffect)(() => {
3103
- if (typeof window === "undefined") return;
3104
- const params = new URLSearchParams(window.location.search);
3105
- const t = params.get("token");
3106
- setToken(t && t.length > 0 ? t : null);
3107
- }, []);
3108
- const validatePassword = (0, import_react21.useMemo)(() => {
3109
- if (password.length === 0) return null;
3110
- if (password.length < MIN_PASSWORD3) return `M\xEDnimo de ${MIN_PASSWORD3} caracteres.`;
3059
+ // src/defaults/CheckoutPageDefault.tsx
3060
+ var import_jsx_runtime27 = require("react/jsx-runtime");
3061
+ var INTENT_KEY = "hook:paywall:intent";
3062
+ var PIX_PAYLOAD_KEY = "hook:paywall:pix-pending";
3063
+ function readIntent() {
3064
+ if (typeof window === "undefined") return {};
3065
+ try {
3066
+ const raw = sessionStorage.getItem(INTENT_KEY);
3067
+ if (!raw) return {};
3068
+ return JSON.parse(raw);
3069
+ } catch {
3070
+ return {};
3071
+ }
3072
+ }
3073
+ function formatBrl(cents) {
3074
+ return new Intl.NumberFormat("pt-BR", { style: "currency", currency: "BRL" }).format(cents / 100);
3075
+ }
3076
+ function CheckoutPageDefault() {
3077
+ const navigate = (0, import_react_router_dom3.useNavigate)();
3078
+ const plan = usePlan();
3079
+ const intent = (0, import_react18.useMemo)(readIntent, []);
3080
+ const defaultMethod = intent.method === "pix-auto" ? "pix-auto" : "card";
3081
+ const defaultCycle = intent.cycle === "YEARLY" ? "YEARLY" : "MONTHLY";
3082
+ const form = useCheckoutForm({ defaultMethod, defaultCycle });
3083
+ (0, import_react18.useEffect)(() => {
3084
+ if (form.emailTaken && form.loginUrl) {
3085
+ const t = setTimeout(() => navigate(form.loginUrl), 1200);
3086
+ return () => clearTimeout(t);
3087
+ }
3088
+ }, [form.emailTaken, form.loginUrl, navigate]);
3089
+ const planInfo = plan.data ? {
3090
+ priceCents: plan.data.priceCents,
3091
+ yearlyPriceCents: plan.data.yearlyPriceCents,
3092
+ trialDays: plan.data.trialDays
3093
+ } : null;
3094
+ const cyclePrice = (0, import_react18.useMemo)(() => {
3095
+ if (!planInfo) return null;
3096
+ return form.cycle === "YEARLY" ? planInfo.yearlyPriceCents ?? planInfo.priceCents * 12 : planInfo.priceCents;
3097
+ }, [planInfo, form.cycle]);
3098
+ const submitLabel = (0, import_react18.useMemo)(() => {
3099
+ if (form.submitting) return "Processando\u2026";
3100
+ if (form.method === "card") {
3101
+ const trial = planInfo?.trialDays ?? 0;
3102
+ if (trial > 0 && cyclePrice) {
3103
+ return `Come\xE7ar ${trial} dias gr\xE1tis \xB7 ${formatBrl(cyclePrice)} depois`;
3104
+ }
3105
+ return cyclePrice ? `Pagar ${formatBrl(cyclePrice)}` : "Continuar";
3106
+ }
3107
+ return cyclePrice ? `Pagar ${formatBrl(cyclePrice)} via PIX` : "Continuar via PIX";
3108
+ }, [form.method, form.submitting, planInfo, cyclePrice]);
3109
+ async function onSubmit(e) {
3110
+ e.preventDefault();
3111
+ const result = await form.submit();
3112
+ if (!result) return;
3113
+ if (form.method === "pix-auto" && result.pix_qr_payload) {
3114
+ try {
3115
+ sessionStorage.setItem(
3116
+ PIX_PAYLOAD_KEY,
3117
+ JSON.stringify({
3118
+ payload: result.pix_qr_payload,
3119
+ base64: result.pix_qr_base64 ?? null,
3120
+ subscriptionId: result.subscription_id,
3121
+ pixAuthorizationId: result.pix_authorization_id ?? null
3122
+ })
3123
+ );
3124
+ } catch {
3125
+ }
3126
+ navigate(result.redirect.replace(/^.*\/app\/[^/]+/, ""));
3127
+ return;
3128
+ }
3129
+ navigate(result.redirect.replace(/^.*\/app\/[^/]+/, "") || "/");
3130
+ }
3131
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { className: "flex-1 flex flex-col bg-background min-h-0", children: /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("form", { onSubmit, className: "flex-1 overflow-y-auto px-5 py-6 space-y-6", children: [
3132
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("header", { className: "space-y-2", children: [
3133
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("h1", { className: "font-display text-2xl text-foreground", children: "Finalizar assinatura" }),
3134
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("p", { className: "text-sm text-muted-foreground", children: "Preencha seus dados pra liberar o app. Voc\xEA j\xE1 entra com acesso na hora." })
3135
+ ] }),
3136
+ form.emailTaken ? /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { role: "alert", className: "rounded-xl bg-destructive/10 p-4 text-sm text-destructive border border-destructive/20", children: [
3137
+ "Esse e-mail j\xE1 tem conta nesse app.",
3138
+ " ",
3139
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("a", { href: form.loginUrl ?? "/signin", className: "underline font-medium", children: "Entrar agora" })
3140
+ ] }) : null,
3141
+ form.error ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("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,
3142
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("section", { className: "space-y-3", children: [
3143
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("h2", { className: "text-sm font-semibold text-foreground uppercase tracking-wide", children: "Voc\xEA" }),
3144
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
3145
+ FieldRow,
3146
+ {
3147
+ label: "Nome completo",
3148
+ value: form.name,
3149
+ onChange: form.setName,
3150
+ onBlur: form.markNameTouched,
3151
+ error: form.nameError,
3152
+ autoComplete: "name"
3153
+ }
3154
+ ),
3155
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
3156
+ FieldRow,
3157
+ {
3158
+ label: "E-mail",
3159
+ type: "email",
3160
+ value: form.email,
3161
+ onChange: form.setEmail,
3162
+ onBlur: form.markEmailTouched,
3163
+ error: form.emailError,
3164
+ autoComplete: "email",
3165
+ autoCapitalize: "none",
3166
+ autoCorrect: "off",
3167
+ spellCheck: false,
3168
+ hint: form.emailStatus === "checking" ? "Verificando\u2026" : form.emailStatus === "available" ? "\u2713 Dispon\xEDvel" : form.emailStatus === "exists" ? null : null
3169
+ }
3170
+ ),
3171
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
3172
+ FieldRow,
3173
+ {
3174
+ label: "Confirme o e-mail",
3175
+ type: "email",
3176
+ value: form.emailConfirm,
3177
+ onChange: form.setEmailConfirm,
3178
+ onBlur: form.markEmailConfirmTouched,
3179
+ error: form.emailConfirmError,
3180
+ autoComplete: "email",
3181
+ autoCapitalize: "none",
3182
+ autoCorrect: "off",
3183
+ spellCheck: false
3184
+ }
3185
+ ),
3186
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
3187
+ FieldRow,
3188
+ {
3189
+ label: "Telefone",
3190
+ type: "tel",
3191
+ value: form.phone,
3192
+ onChange: form.setPhone,
3193
+ onBlur: form.markPhoneTouched,
3194
+ error: form.phoneError,
3195
+ autoComplete: "tel",
3196
+ placeholder: "(11) 99999-9999"
3197
+ }
3198
+ ),
3199
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
3200
+ FieldRow,
3201
+ {
3202
+ label: "CPF",
3203
+ type: "text",
3204
+ inputMode: "numeric",
3205
+ value: form.cpf,
3206
+ onChange: form.setCpf,
3207
+ onBlur: form.markCpfTouched,
3208
+ error: form.cpfError,
3209
+ autoComplete: "off",
3210
+ placeholder: "000.000.000-00"
3211
+ }
3212
+ )
3213
+ ] }),
3214
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("section", { className: "space-y-3", children: [
3215
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("h2", { className: "text-sm font-semibold text-foreground uppercase tracking-wide", children: "Pagamento" }),
3216
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "grid grid-cols-2 gap-2", role: "tablist", children: [
3217
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(MethodTab, { active: form.method === "card", onClick: () => form.setMethod("card"), children: "Cart\xE3o" }),
3218
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(MethodTab, { active: form.method === "pix-auto", onClick: () => form.setMethod("pix-auto"), children: "PIX" })
3219
+ ] }),
3220
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "grid grid-cols-2 gap-2", role: "tablist", children: [
3221
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(MethodTab, { active: form.cycle === "MONTHLY", onClick: () => form.setCycle("MONTHLY"), children: "Mensal" }),
3222
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(MethodTab, { active: form.cycle === "YEARLY", onClick: () => form.setCycle("YEARLY"), children: "Anual" })
3223
+ ] }),
3224
+ form.method === "card" ? /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "space-y-3 rounded-xl border border-border p-4", children: [
3225
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
3226
+ FieldRow,
3227
+ {
3228
+ label: "Nome no cart\xE3o",
3229
+ value: form.card.holderName,
3230
+ onChange: (v) => form.setCard({ holderName: v }),
3231
+ autoComplete: "cc-name"
3232
+ }
3233
+ ),
3234
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
3235
+ FieldRow,
3236
+ {
3237
+ label: "N\xFAmero",
3238
+ value: form.card.number,
3239
+ onChange: (v) => form.setCard({ number: v }),
3240
+ autoComplete: "cc-number",
3241
+ inputMode: "numeric",
3242
+ placeholder: "0000 0000 0000 0000"
3243
+ }
3244
+ ),
3245
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "grid grid-cols-3 gap-2", children: [
3246
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
3247
+ FieldRow,
3248
+ {
3249
+ label: "M\xEAs",
3250
+ value: form.card.expiryMonth,
3251
+ onChange: (v) => form.setCard({ expiryMonth: v }),
3252
+ autoComplete: "cc-exp-month",
3253
+ inputMode: "numeric",
3254
+ placeholder: "MM"
3255
+ }
3256
+ ),
3257
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
3258
+ FieldRow,
3259
+ {
3260
+ label: "Ano",
3261
+ value: form.card.expiryYear,
3262
+ onChange: (v) => form.setCard({ expiryYear: v }),
3263
+ autoComplete: "cc-exp-year",
3264
+ inputMode: "numeric",
3265
+ placeholder: "AA"
3266
+ }
3267
+ ),
3268
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
3269
+ FieldRow,
3270
+ {
3271
+ label: "CVV",
3272
+ value: form.card.ccv,
3273
+ onChange: (v) => form.setCard({ ccv: v }),
3274
+ autoComplete: "cc-csc",
3275
+ inputMode: "numeric",
3276
+ placeholder: "123"
3277
+ }
3278
+ )
3279
+ ] })
3280
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("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." })
3281
+ ] }),
3282
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
3283
+ "button",
3284
+ {
3285
+ type: "submit",
3286
+ disabled: !form.canSubmit,
3287
+ className: "w-full rounded-xl bg-primary py-4 text-base font-semibold text-primary-foreground disabled:opacity-50 disabled:cursor-not-allowed",
3288
+ children: submitLabel
3289
+ }
3290
+ ),
3291
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("p", { className: "text-center text-xs text-muted-foreground", children: "\u{1F512} SSL \xB7 via Asaas \xB7 Garantia 7 dias" })
3292
+ ] }) });
3293
+ }
3294
+ function FieldRow(props) {
3295
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("label", { className: "block space-y-1", children: [
3296
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { className: "block text-sm font-medium text-foreground", children: props.label }),
3297
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
3298
+ "input",
3299
+ {
3300
+ type: props.type ?? "text",
3301
+ value: props.value,
3302
+ onChange: (e) => props.onChange(e.target.value),
3303
+ onBlur: props.onBlur,
3304
+ autoComplete: props.autoComplete,
3305
+ autoCapitalize: props.autoCapitalize,
3306
+ autoCorrect: props.autoCorrect,
3307
+ spellCheck: props.spellCheck,
3308
+ inputMode: props.inputMode,
3309
+ placeholder: props.placeholder,
3310
+ 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"}`
3311
+ }
3312
+ ),
3313
+ props.error ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { className: "block text-xs text-destructive", children: props.error }) : props.hint ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { className: "block text-xs text-muted-foreground", children: props.hint }) : null
3314
+ ] });
3315
+ }
3316
+ function MethodTab({ active, onClick, children }) {
3317
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
3318
+ "button",
3319
+ {
3320
+ type: "button",
3321
+ role: "tab",
3322
+ "aria-selected": active,
3323
+ onClick,
3324
+ 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"}`,
3325
+ children
3326
+ }
3327
+ );
3328
+ }
3329
+
3330
+ // src/defaults/PixWaitingPageDefault.tsx
3331
+ var import_react19 = require("react");
3332
+ var import_react_router_dom4 = require("react-router-dom");
3333
+ var import_sdk14 = require("@hook-sdk/sdk");
3334
+ var import_jsx_runtime28 = require("react/jsx-runtime");
3335
+ var PIX_PAYLOAD_KEY2 = "hook:paywall:pix-pending";
3336
+ var TIMEOUT_MS = 30 * 60 * 1e3;
3337
+ function readPixPayload() {
3338
+ if (typeof window === "undefined") return null;
3339
+ try {
3340
+ const raw = sessionStorage.getItem(PIX_PAYLOAD_KEY2);
3341
+ if (!raw) return null;
3342
+ return JSON.parse(raw);
3343
+ } catch {
3344
+ return null;
3345
+ }
3346
+ }
3347
+ function clearPixPayload() {
3348
+ if (typeof window === "undefined") return;
3349
+ try {
3350
+ sessionStorage.removeItem(PIX_PAYLOAD_KEY2);
3351
+ } catch {
3352
+ }
3353
+ }
3354
+ function PixWaitingPageDefault() {
3355
+ const navigate = (0, import_react_router_dom4.useNavigate)();
3356
+ const { subscription } = (0, import_sdk14.useHook)();
3357
+ const payload = (0, import_react19.useMemo)(readPixPayload, []);
3358
+ const [copied, setCopied] = (0, import_react19.useState)(false);
3359
+ const [timedOut, setTimedOut] = (0, import_react19.useState)(false);
3360
+ (0, import_react19.useEffect)(() => {
3361
+ if (!payload) navigate("/paywall/checkout", { replace: true });
3362
+ }, [payload, navigate]);
3363
+ (0, import_react19.useEffect)(() => {
3364
+ const t = setTimeout(() => setTimedOut(true), TIMEOUT_MS);
3365
+ return () => clearTimeout(t);
3366
+ }, []);
3367
+ const hasAccess = subscription.hasAccess;
3368
+ (0, import_react19.useEffect)(() => {
3369
+ if (hasAccess) {
3370
+ clearPixPayload();
3371
+ navigate("/", { replace: true });
3372
+ }
3373
+ }, [hasAccess, navigate]);
3374
+ async function copyPayload() {
3375
+ if (!payload?.payload) return;
3376
+ try {
3377
+ await navigator.clipboard.writeText(payload.payload);
3378
+ setCopied(true);
3379
+ setTimeout(() => setCopied(false), 2e3);
3380
+ } catch {
3381
+ }
3382
+ }
3383
+ if (!payload) return null;
3384
+ if (timedOut) {
3385
+ return /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: "flex-1 flex flex-col items-center justify-center px-6 py-10 text-center bg-background space-y-4", children: [
3386
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("h1", { className: "font-display text-2xl text-foreground", children: "PIX expirado" }),
3387
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("p", { className: "text-sm text-muted-foreground", children: "O tempo pra pagar acabou. Gere um novo PIX." }),
3388
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
3389
+ "button",
3390
+ {
3391
+ onClick: () => {
3392
+ clearPixPayload();
3393
+ navigate("/paywall/checkout", { replace: true });
3394
+ },
3395
+ className: "rounded-xl bg-primary px-6 py-3 text-base font-semibold text-primary-foreground",
3396
+ children: "Tentar novamente"
3397
+ }
3398
+ )
3399
+ ] });
3400
+ }
3401
+ return /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: "flex-1 flex flex-col items-center px-6 py-8 bg-background space-y-6", children: [
3402
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("header", { className: "text-center space-y-2", children: [
3403
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("h1", { className: "font-display text-2xl text-foreground", children: "Pague o PIX" }),
3404
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("p", { className: "text-sm text-muted-foreground", children: "Escaneie o QR Code no app do seu banco. O acesso libera assim que confirmarmos o pagamento." })
3405
+ ] }),
3406
+ payload.base64 ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
3407
+ "img",
3408
+ {
3409
+ src: `data:image/png;base64,${payload.base64}`,
3410
+ alt: "QR Code PIX",
3411
+ className: "w-64 h-64 rounded-2xl border border-border bg-card p-2"
3412
+ }
3413
+ ) : /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("div", { className: "w-64 h-64 rounded-2xl border border-border bg-card flex items-center justify-center text-sm text-muted-foreground", children: "QR indispon\xEDvel" }),
3414
+ payload.payload ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
3415
+ "button",
3416
+ {
3417
+ onClick: copyPayload,
3418
+ className: "w-full max-w-xs rounded-xl border border-border bg-card px-4 py-3 text-sm font-medium text-foreground",
3419
+ children: copied ? "\u2713 Copiado!" : "Copiar c\xF3digo PIX"
3420
+ }
3421
+ ) : null,
3422
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: "flex items-center gap-2 text-sm text-muted-foreground", children: [
3423
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { className: "inline-block w-2 h-2 rounded-full bg-primary animate-pulse" }),
3424
+ "Aguardando pagamento\u2026"
3425
+ ] }),
3426
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("p", { className: "text-center text-xs text-muted-foreground", children: "Pode fechar essa janela \u2014 tamb\xE9m enviamos um link de acesso pro seu e-mail." })
3427
+ ] });
3428
+ }
3429
+
3430
+ // src/hooks/useLoginForm.ts
3431
+ var import_react20 = require("react");
3432
+ var import_sdk15 = require("@hook-sdk/sdk");
3433
+ var EMAIL_RE2 = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
3434
+ var MIN_PASSWORD = 8;
3435
+ function useLoginForm() {
3436
+ const { auth } = (0, import_sdk15.useHook)();
3437
+ const [email, setEmail] = (0, import_react20.useState)("");
3438
+ const [password, setPassword] = (0, import_react20.useState)("");
3439
+ const [submitting, setSubmitting] = (0, import_react20.useState)(false);
3440
+ const [error, setError] = (0, import_react20.useState)(null);
3441
+ const [touchedEmail, setTouchedEmail] = (0, import_react20.useState)(false);
3442
+ const [touchedPassword, setTouchedPassword] = (0, import_react20.useState)(false);
3443
+ const [formSubmitAttempted, setFormSubmitAttempted] = (0, import_react20.useState)(false);
3444
+ const validateEmail = (0, import_react20.useMemo)(() => {
3445
+ if (email.length === 0) return null;
3446
+ if (!EMAIL_RE2.test(email)) return "Formato de e-mail inv\xE1lido.";
3447
+ return null;
3448
+ }, [email]);
3449
+ const validatePassword = (0, import_react20.useMemo)(() => {
3450
+ if (password.length === 0) return null;
3451
+ if (password.length < MIN_PASSWORD) return `M\xEDnimo de ${MIN_PASSWORD} caracteres.`;
3452
+ return null;
3453
+ }, [password]);
3454
+ const emailError = touchedEmail || formSubmitAttempted ? validateEmail : null;
3455
+ const passwordError = touchedPassword || formSubmitAttempted ? validatePassword : null;
3456
+ const canSubmit = email.length > 0 && password.length >= MIN_PASSWORD && validateEmail === null && validatePassword === null && !submitting;
3457
+ const submit = (0, import_react20.useCallback)(async () => {
3458
+ setFormSubmitAttempted(true);
3459
+ if (!canSubmit) return false;
3460
+ setSubmitting(true);
3461
+ setError(null);
3462
+ try {
3463
+ await auth.login({ email, password });
3464
+ return true;
3465
+ } catch (err) {
3466
+ setError(mapSdkError(err));
3467
+ return false;
3468
+ } finally {
3469
+ setSubmitting(false);
3470
+ }
3471
+ }, [auth, email, password, canSubmit]);
3472
+ return {
3473
+ email,
3474
+ setEmail,
3475
+ emailError,
3476
+ markEmailTouched: () => setTouchedEmail(true),
3477
+ password,
3478
+ setPassword,
3479
+ passwordError,
3480
+ markPasswordTouched: () => setTouchedPassword(true),
3481
+ formSubmitAttempted,
3482
+ submit,
3483
+ submitting,
3484
+ canSubmit,
3485
+ error,
3486
+ loginWithGoogle: () => auth.loginWithGoogle()
3487
+ };
3488
+ }
3489
+
3490
+ // src/hooks/useSignupForm.ts
3491
+ var import_react21 = require("react");
3492
+ var import_sdk16 = require("@hook-sdk/sdk");
3493
+ var EMAIL_RE3 = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
3494
+ var MIN_PASSWORD2 = 8;
3495
+ function useSignupForm() {
3496
+ const { auth } = (0, import_sdk16.useHook)();
3497
+ const [name, setName] = (0, import_react21.useState)("");
3498
+ const [email, setEmail] = (0, import_react21.useState)("");
3499
+ const [password, setPassword] = (0, import_react21.useState)("");
3500
+ const [submitting, setSubmitting] = (0, import_react21.useState)(false);
3501
+ const [error, setError] = (0, import_react21.useState)(null);
3502
+ const [touchedName, setTouchedName] = (0, import_react21.useState)(false);
3503
+ const [touchedEmail, setTouchedEmail] = (0, import_react21.useState)(false);
3504
+ const [touchedPassword, setTouchedPassword] = (0, import_react21.useState)(false);
3505
+ const [formSubmitAttempted, setFormSubmitAttempted] = (0, import_react21.useState)(false);
3506
+ const validateName = (0, import_react21.useMemo)(() => {
3507
+ if (name.length === 0) return null;
3508
+ if (name.trim().length < 2) return "Nome muito curto.";
3509
+ return null;
3510
+ }, [name]);
3511
+ const validateEmail = (0, import_react21.useMemo)(() => {
3512
+ if (email.length === 0) return null;
3513
+ if (!EMAIL_RE3.test(email)) return "Formato de e-mail inv\xE1lido.";
3514
+ return null;
3515
+ }, [email]);
3516
+ const validatePassword = (0, import_react21.useMemo)(() => {
3517
+ if (password.length === 0) return null;
3518
+ if (password.length < MIN_PASSWORD2) return `M\xEDnimo de ${MIN_PASSWORD2} caracteres.`;
3519
+ return null;
3520
+ }, [password]);
3521
+ const nameError = touchedName || formSubmitAttempted ? validateName : null;
3522
+ const emailError = touchedEmail || formSubmitAttempted ? validateEmail : null;
3523
+ const passwordError = touchedPassword || formSubmitAttempted ? validatePassword : null;
3524
+ const canSubmit = name.trim().length >= 2 && email.length > 0 && password.length >= MIN_PASSWORD2 && validateName === null && validateEmail === null && validatePassword === null && !submitting;
3525
+ const submit = (0, import_react21.useCallback)(async () => {
3526
+ setFormSubmitAttempted(true);
3527
+ if (!canSubmit) return false;
3528
+ setSubmitting(true);
3529
+ setError(null);
3530
+ try {
3531
+ await auth.signup({ name, email, password });
3532
+ return true;
3533
+ } catch (err) {
3534
+ setError(mapSdkError(err));
3535
+ return false;
3536
+ } finally {
3537
+ setSubmitting(false);
3538
+ }
3539
+ }, [auth, name, email, password, canSubmit]);
3540
+ return {
3541
+ name,
3542
+ setName,
3543
+ nameError,
3544
+ markNameTouched: () => setTouchedName(true),
3545
+ email,
3546
+ setEmail,
3547
+ emailError,
3548
+ markEmailTouched: () => setTouchedEmail(true),
3549
+ password,
3550
+ setPassword,
3551
+ passwordError,
3552
+ markPasswordTouched: () => setTouchedPassword(true),
3553
+ formSubmitAttempted,
3554
+ submit,
3555
+ submitting,
3556
+ canSubmit,
3557
+ error,
3558
+ loginWithGoogle: () => auth.loginWithGoogle()
3559
+ };
3560
+ }
3561
+
3562
+ // src/hooks/useForgotForm.ts
3563
+ var import_react22 = require("react");
3564
+ var import_sdk17 = require("@hook-sdk/sdk");
3565
+ var EMAIL_RE4 = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
3566
+ function useForgotForm() {
3567
+ const { auth } = (0, import_sdk17.useHook)();
3568
+ const [email, setEmail] = (0, import_react22.useState)("");
3569
+ const [submitting, setSubmitting] = (0, import_react22.useState)(false);
3570
+ const [sent, setSent] = (0, import_react22.useState)(false);
3571
+ const [error, setError] = (0, import_react22.useState)(null);
3572
+ const [touchedEmail, setTouchedEmail] = (0, import_react22.useState)(false);
3573
+ const [formSubmitAttempted, setFormSubmitAttempted] = (0, import_react22.useState)(false);
3574
+ const validateEmail = (0, import_react22.useMemo)(() => {
3575
+ if (email.length === 0) return null;
3576
+ if (!EMAIL_RE4.test(email)) return "Formato de e-mail inv\xE1lido.";
3577
+ return null;
3578
+ }, [email]);
3579
+ const emailError = touchedEmail || formSubmitAttempted ? validateEmail : null;
3580
+ const canSubmit = email.length > 0 && validateEmail === null && !submitting;
3581
+ const submit = (0, import_react22.useCallback)(async () => {
3582
+ setFormSubmitAttempted(true);
3583
+ if (!canSubmit) return false;
3584
+ setSubmitting(true);
3585
+ setError(null);
3586
+ try {
3587
+ await auth.forgot({ email });
3588
+ setSent(true);
3589
+ return true;
3590
+ } catch (err) {
3591
+ setError(mapSdkError(err));
3592
+ return false;
3593
+ } finally {
3594
+ setSubmitting(false);
3595
+ }
3596
+ }, [auth, email, canSubmit]);
3597
+ return {
3598
+ email,
3599
+ setEmail,
3600
+ emailError,
3601
+ markEmailTouched: () => setTouchedEmail(true),
3602
+ formSubmitAttempted,
3603
+ submit,
3604
+ submitting,
3605
+ canSubmit,
3606
+ sent,
3607
+ error
3608
+ };
3609
+ }
3610
+
3611
+ // src/hooks/useResetForm.ts
3612
+ var import_react23 = require("react");
3613
+ var import_sdk18 = require("@hook-sdk/sdk");
3614
+ var MIN_PASSWORD3 = 12;
3615
+ function useResetForm() {
3616
+ const { auth } = (0, import_sdk18.useHook)();
3617
+ const [token, setToken] = (0, import_react23.useState)(null);
3618
+ const [password, setPassword] = (0, import_react23.useState)("");
3619
+ const [confirm, setConfirm] = (0, import_react23.useState)("");
3620
+ const [submitting, setSubmitting] = (0, import_react23.useState)(false);
3621
+ const [done, setDone] = (0, import_react23.useState)(false);
3622
+ const [error, setError] = (0, import_react23.useState)(null);
3623
+ const [touchedPassword, setTouchedPassword] = (0, import_react23.useState)(false);
3624
+ const [touchedConfirm, setTouchedConfirm] = (0, import_react23.useState)(false);
3625
+ const [formSubmitAttempted, setFormSubmitAttempted] = (0, import_react23.useState)(false);
3626
+ (0, import_react23.useEffect)(() => {
3627
+ if (typeof window === "undefined") return;
3628
+ const params = new URLSearchParams(window.location.search);
3629
+ const t = params.get("token");
3630
+ setToken(t && t.length > 0 ? t : null);
3631
+ }, []);
3632
+ const validatePassword = (0, import_react23.useMemo)(() => {
3633
+ if (password.length === 0) return null;
3634
+ if (password.length < MIN_PASSWORD3) return `M\xEDnimo de ${MIN_PASSWORD3} caracteres.`;
3111
3635
  return null;
3112
3636
  }, [password]);
3113
- const validateConfirm = (0, import_react21.useMemo)(() => {
3637
+ const validateConfirm = (0, import_react23.useMemo)(() => {
3114
3638
  if (confirm.length === 0) return null;
3115
3639
  if (confirm !== password) return "Senhas n\xE3o coincidem.";
3116
3640
  return null;
@@ -3118,7 +3642,7 @@ function useResetForm() {
3118
3642
  const passwordError = touchedPassword || formSubmitAttempted ? validatePassword : null;
3119
3643
  const confirmError = touchedConfirm || formSubmitAttempted ? validateConfirm : null;
3120
3644
  const canSubmit = token !== null && password.length >= MIN_PASSWORD3 && confirm === password && validatePassword === null && validateConfirm === null && !submitting && !done;
3121
- const submit = (0, import_react21.useCallback)(async () => {
3645
+ const submit = (0, import_react23.useCallback)(async () => {
3122
3646
  setFormSubmitAttempted(true);
3123
3647
  if (!canSubmit || token === null) return;
3124
3648
  setSubmitting(true);
@@ -3157,13 +3681,6 @@ function useResetForm() {
3157
3681
  };
3158
3682
  }
3159
3683
 
3160
- // src/hooks/usePlan.ts
3161
- var import_sdk17 = require("@hook-sdk/sdk");
3162
- function usePlan() {
3163
- const { plan } = (0, import_sdk17.useHook)();
3164
- return plan;
3165
- }
3166
-
3167
3684
  // src/utils/price.ts
3168
3685
  function formatBRL(cents) {
3169
3686
  if (cents === null || cents === void 0) return "";
@@ -3193,12 +3710,12 @@ function discountPercent(anchorCents, realCents) {
3193
3710
  }
3194
3711
 
3195
3712
  // src/hooks/useAuthPrimitives.ts
3196
- var import_react22 = require("react");
3197
- var import_sdk18 = require("@hook-sdk/sdk");
3713
+ var import_react24 = require("react");
3714
+ var import_sdk19 = require("@hook-sdk/sdk");
3198
3715
  var warned = false;
3199
3716
  function useAuthPrimitives() {
3200
- const { auth } = (0, import_sdk18.useHook)();
3201
- (0, import_react22.useEffect)(() => {
3717
+ const { auth } = (0, import_sdk19.useHook)();
3718
+ (0, import_react24.useEffect)(() => {
3202
3719
  if (!warned && process.env.NODE_ENV !== "production") {
3203
3720
  warned = true;
3204
3721
  console.warn(
@@ -3220,9 +3737,9 @@ function useAuthPrimitives() {
3220
3737
  }
3221
3738
 
3222
3739
  // src/hooks/useAuth.ts
3223
- var import_sdk19 = require("@hook-sdk/sdk");
3740
+ var import_sdk20 = require("@hook-sdk/sdk");
3224
3741
  function useAuth() {
3225
- const { user, authStatus, auth } = (0, import_sdk19.useHook)();
3742
+ const { user, authStatus, auth } = (0, import_sdk20.useHook)();
3226
3743
  return {
3227
3744
  user,
3228
3745
  authStatus,
@@ -3231,26 +3748,26 @@ function useAuth() {
3231
3748
  }
3232
3749
 
3233
3750
  // src/index.ts
3234
- var import_sdk24 = require("@hook-sdk/sdk");
3751
+ var import_sdk25 = require("@hook-sdk/sdk");
3235
3752
 
3236
3753
  // src/hooks/useSubscription.ts
3237
- var import_sdk20 = require("@hook-sdk/sdk");
3754
+ var import_sdk21 = require("@hook-sdk/sdk");
3238
3755
  function useSubscription() {
3239
- const { subscription } = (0, import_sdk20.useHook)();
3756
+ const { subscription } = (0, import_sdk21.useHook)();
3240
3757
  return {
3241
3758
  status: subscription.status()
3242
3759
  };
3243
3760
  }
3244
3761
 
3245
3762
  // src/hooks/useReminders.ts
3246
- var import_react23 = require("react");
3247
- var import_sdk21 = require("@hook-sdk/sdk");
3763
+ var import_react25 = require("react");
3764
+ var import_sdk22 = require("@hook-sdk/sdk");
3248
3765
  function useReminders() {
3249
- const { push } = (0, import_sdk21.useHook)();
3766
+ const { push } = (0, import_sdk22.useHook)();
3250
3767
  const r = push.reminders;
3251
- const [reminders, setReminders] = (0, import_react23.useState)([]);
3252
- const [loading, setLoading] = (0, import_react23.useState)(true);
3253
- const reload = (0, import_react23.useCallback)(async () => {
3768
+ const [reminders, setReminders] = (0, import_react25.useState)([]);
3769
+ const [loading, setLoading] = (0, import_react25.useState)(true);
3770
+ const reload = (0, import_react25.useCallback)(async () => {
3254
3771
  setLoading(true);
3255
3772
  try {
3256
3773
  const next = await r.list();
@@ -3259,59 +3776,59 @@ function useReminders() {
3259
3776
  setLoading(false);
3260
3777
  }
3261
3778
  }, [r]);
3262
- (0, import_react23.useEffect)(() => {
3779
+ (0, import_react25.useEffect)(() => {
3263
3780
  void reload();
3264
3781
  }, [reload]);
3265
- const setReminder = (0, import_react23.useCallback)(async (input) => {
3782
+ const setReminder = (0, import_react25.useCallback)(async (input) => {
3266
3783
  await r.set(input);
3267
3784
  await reload();
3268
3785
  }, [r, reload]);
3269
- const deleteReminder = (0, import_react23.useCallback)(async (slot) => {
3786
+ const deleteReminder = (0, import_react25.useCallback)(async (slot) => {
3270
3787
  await r.delete(slot);
3271
3788
  await reload();
3272
3789
  }, [r, reload]);
3273
- const schedule = (0, import_react23.useCallback)(async (items) => {
3790
+ const schedule = (0, import_react25.useCallback)(async (items) => {
3274
3791
  return r.schedule(items);
3275
3792
  }, [r]);
3276
- const setFallbacks = (0, import_react23.useCallback)(async (items) => {
3793
+ const setFallbacks = (0, import_react25.useCallback)(async (items) => {
3277
3794
  return r.setFallbacks(items);
3278
3795
  }, [r]);
3279
3796
  return { reminders, loading, setReminder, deleteReminder, schedule, setFallbacks };
3280
3797
  }
3281
3798
 
3282
3799
  // src/hooks/useToast.ts
3283
- var import_react24 = require("react");
3800
+ var import_react26 = require("react");
3284
3801
  function useToast() {
3285
- const [items, setItems] = (0, import_react24.useState)([]);
3286
- const show = (0, import_react24.useCallback)((message, kind = "info") => {
3802
+ const [items, setItems] = (0, import_react26.useState)([]);
3803
+ const show = (0, import_react26.useCallback)((message, kind = "info") => {
3287
3804
  const id = `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
3288
3805
  setItems((prev) => [...prev, { id, message, kind }]);
3289
3806
  setTimeout(() => {
3290
3807
  setItems((prev) => prev.filter((t) => t.id !== id));
3291
3808
  }, 4e3);
3292
3809
  }, []);
3293
- const dismiss = (0, import_react24.useCallback)((id) => {
3810
+ const dismiss = (0, import_react26.useCallback)((id) => {
3294
3811
  setItems((prev) => prev.filter((t) => t.id !== id));
3295
3812
  }, []);
3296
3813
  return { items, show, dismiss };
3297
3814
  }
3298
3815
 
3299
3816
  // src/RouteBoundary.tsx
3300
- var import_react_router_dom3 = require("react-router-dom");
3301
- var import_jsx_runtime28 = require("react/jsx-runtime");
3817
+ var import_react_router_dom5 = require("react-router-dom");
3818
+ var import_jsx_runtime29 = require("react/jsx-runtime");
3302
3819
  function RouteBoundary({ children }) {
3303
- return /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(import_react_router_dom3.Routes, { children: [
3820
+ return /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(import_react_router_dom5.Routes, { children: [
3304
3821
  children,
3305
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_react_router_dom3.Route, { path: "*", element: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(DefaultNotFound, {}) })
3822
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_react_router_dom5.Route, { path: "*", element: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(DefaultNotFound, {}) })
3306
3823
  ] });
3307
3824
  }
3308
3825
  function DefaultNotFound() {
3309
- return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("div", { role: "alert", children: "P\xE1gina n\xE3o encontrada" });
3826
+ return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("div", { role: "alert", children: "P\xE1gina n\xE3o encontrada" });
3310
3827
  }
3311
3828
 
3312
3829
  // src/PreAuthShell.tsx
3313
- var import_react_router_dom4 = require("react-router-dom");
3314
- var import_jsx_runtime29 = require("react/jsx-runtime");
3830
+ var import_react_router_dom6 = require("react-router-dom");
3831
+ var import_jsx_runtime30 = require("react/jsx-runtime");
3315
3832
  function PreAuthShell({
3316
3833
  basename,
3317
3834
  testRouter,
@@ -3319,20 +3836,20 @@ function PreAuthShell({
3319
3836
  children
3320
3837
  }) {
3321
3838
  if (testRouter === "memory") {
3322
- return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_react_router_dom4.MemoryRouter, { basename, initialEntries: testInitialEntries, children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_react_router_dom4.Routes, { children }) });
3839
+ return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_react_router_dom6.MemoryRouter, { basename, initialEntries: testInitialEntries, children: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_react_router_dom6.Routes, { children }) });
3323
3840
  }
3324
- return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_react_router_dom4.BrowserRouter, { basename, children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_react_router_dom4.Routes, { children }) });
3841
+ return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_react_router_dom6.BrowserRouter, { basename, children: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_react_router_dom6.Routes, { children }) });
3325
3842
  }
3326
3843
 
3327
3844
  // src/OnboardingFlow.tsx
3328
- var import_react26 = require("react");
3329
- var import_sdk22 = require("@hook-sdk/sdk");
3845
+ var import_react28 = require("react");
3846
+ var import_sdk23 = require("@hook-sdk/sdk");
3330
3847
 
3331
3848
  // src/hooks/useOnboardingStep.ts
3332
- var import_react25 = require("react");
3333
- var OnboardingStepContext = (0, import_react25.createContext)(null);
3849
+ var import_react27 = require("react");
3850
+ var OnboardingStepContext = (0, import_react27.createContext)(null);
3334
3851
  function useOnboardingStep() {
3335
- const ctx = (0, import_react25.useContext)(OnboardingStepContext);
3852
+ const ctx = (0, import_react27.useContext)(OnboardingStepContext);
3336
3853
  if (!ctx) {
3337
3854
  throw new Error(
3338
3855
  "[hook-template] useOnboardingStep must be used inside <OnboardingFlow>. (G75)"
@@ -3342,7 +3859,7 @@ function useOnboardingStep() {
3342
3859
  }
3343
3860
 
3344
3861
  // src/OnboardingFlow.tsx
3345
- var import_jsx_runtime30 = require("react/jsx-runtime");
3862
+ var import_jsx_runtime31 = require("react/jsx-runtime");
3346
3863
  var isFilled = (v) => v != null && v !== "";
3347
3864
  var CURRENT_STEP_FIELD = "currentStep";
3348
3865
  function readPersistedStepIdx(draft) {
@@ -3355,12 +3872,12 @@ function OnboardingFlow({
3355
3872
  onComplete,
3356
3873
  persistKey
3357
3874
  }) {
3358
- const [draft, setDraft, status] = (0, import_sdk22.usePersistedState)(persistKey, {});
3359
- const draftRef = (0, import_react26.useRef)(draft);
3875
+ const [draft, setDraft, status] = (0, import_sdk23.usePersistedState)(persistKey, {});
3876
+ const draftRef = (0, import_react28.useRef)(draft);
3360
3877
  draftRef.current = draft;
3361
3878
  const idx = readPersistedStepIdx(draft);
3362
3879
  const clampedIdx = Math.min(Math.max(idx, 0), Math.max(steps.length - 1, 0));
3363
- const setIdx = (0, import_react26.useCallback)(
3880
+ const setIdx = (0, import_react28.useCallback)(
3364
3881
  (n) => {
3365
3882
  setDraft((prev) => {
3366
3883
  const prevIdx = readPersistedStepIdx(prev);
@@ -3370,7 +3887,7 @@ function OnboardingFlow({
3370
3887
  },
3371
3888
  [setDraft]
3372
3889
  );
3373
- const setValue = (0, import_react26.useCallback)(
3890
+ const setValue = (0, import_react28.useCallback)(
3374
3891
  (patch) => {
3375
3892
  draftRef.current = { ...draftRef.current, ...patch };
3376
3893
  setDraft((prev) => ({ ...prev, ...patch }));
@@ -3378,9 +3895,9 @@ function OnboardingFlow({
3378
3895
  [setDraft]
3379
3896
  );
3380
3897
  const step = steps[clampedIdx];
3381
- const hookCtx = (0, import_sdk22.useHook)();
3898
+ const hookCtx = (0, import_sdk23.useHook)();
3382
3899
  const track2 = typeof hookCtx.track === "function" ? hookCtx.track : void 0;
3383
- (0, import_react26.useEffect)(() => {
3900
+ (0, import_react28.useEffect)(() => {
3384
3901
  if (status.loading) return;
3385
3902
  if (!step) return;
3386
3903
  if (!track2) return;
@@ -3390,11 +3907,11 @@ function OnboardingFlow({
3390
3907
  total_steps: steps.length
3391
3908
  });
3392
3909
  }, [step?.id, clampedIdx, steps.length, status.loading, track2]);
3393
- const valid = (0, import_react26.useMemo)(
3910
+ const valid = (0, import_react28.useMemo)(
3394
3911
  () => step ? (step.validates ?? []).every((field) => isFilled(draft[field])) : false,
3395
3912
  [draft, step]
3396
3913
  );
3397
- const next = (0, import_react26.useCallback)(() => {
3914
+ const next = (0, import_react28.useCallback)(() => {
3398
3915
  if (!step) return;
3399
3916
  const current = draftRef.current;
3400
3917
  const validNow = (step.validates ?? []).every((field) => isFilled(current[field]));
@@ -3405,8 +3922,8 @@ function OnboardingFlow({
3405
3922
  setIdx(clampedIdx + 1);
3406
3923
  }
3407
3924
  }, [clampedIdx, onComplete, step, steps.length, setIdx]);
3408
- const prevStep = (0, import_react26.useCallback)(() => setIdx((i) => Math.max(0, i - 1)), [setIdx]);
3409
- const ctx = (0, import_react26.useMemo)(
3925
+ const prevStep = (0, import_react28.useCallback)(() => setIdx((i) => Math.max(0, i - 1)), [setIdx]);
3926
+ const ctx = (0, import_react28.useMemo)(
3410
3927
  () => ({
3411
3928
  stepIndex: clampedIdx,
3412
3929
  totalSteps: steps.length,
@@ -3432,7 +3949,7 @@ function OnboardingFlow({
3432
3949
  `[hook-template] OnboardingFlow: missing screen component for step '${step.id}' (expected key '${step.screen}' in screens prop)`
3433
3950
  );
3434
3951
  }
3435
- return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(OnboardingStepContext.Provider, { value: ctx, children: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(Screen, {}) });
3952
+ return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(OnboardingStepContext.Provider, { value: ctx, children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(Screen, {}) });
3436
3953
  }
3437
3954
 
3438
3955
  // src/hooks/useFeature.ts
@@ -3443,39 +3960,22 @@ function useFeature(name) {
3443
3960
 
3444
3961
  // src/components/paywall/Paywall.tsx
3445
3962
  var import_react29 = require("react");
3446
- var import_sdk23 = require("@hook-sdk/sdk");
3447
-
3448
- // src/components/paywall/PaywallProvider.tsx
3449
- var import_react27 = require("react");
3450
- var import_jsx_runtime31 = require("react/jsx-runtime");
3451
- var PaywallContext = (0, import_react27.createContext)(null);
3452
- function PaywallProvider({ children }) {
3453
- const state = usePaywallState();
3454
- return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(PaywallContext.Provider, { value: state, children });
3455
- }
3456
-
3457
- // src/components/paywall/usePaywallContext.ts
3458
- var import_react28 = require("react");
3459
- function usePaywallContext() {
3460
- const ctx = (0, import_react28.useContext)(PaywallContext);
3461
- if (!ctx) {
3462
- throw new Error("usePaywallContext must be used within <PaywallProvider>");
3463
- }
3464
- return ctx;
3465
- }
3963
+ var import_sdk24 = require("@hook-sdk/sdk");
3466
3964
 
3467
3965
  // src/components/paywall/PaywallMethodTabs.tsx
3468
3966
  var import_jsx_runtime32 = require("react/jsx-runtime");
3469
3967
  function PaywallMethodTabs({
3968
+ methods,
3969
+ selected,
3970
+ onSelect,
3470
3971
  labels,
3471
3972
  className,
3472
3973
  tabClassName,
3473
3974
  tabActiveClassName
3474
3975
  }) {
3475
- const { methods, selectedMethod, selectMethod } = usePaywallContext();
3476
3976
  if (methods.length < 2) return null;
3477
3977
  return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("div", { role: "tablist", "aria-label": "M\xE9todo de pagamento", className, children: methods.map((m) => {
3478
- const active = m === selectedMethod;
3978
+ const active = m === selected;
3479
3979
  const label = labels[m] ?? m;
3480
3980
  return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
3481
3981
  "button",
@@ -3485,7 +3985,7 @@ function PaywallMethodTabs({
3485
3985
  "aria-selected": active,
3486
3986
  "aria-controls": `paywall-tab-${m}`,
3487
3987
  tabIndex: active ? 0 : -1,
3488
- onClick: () => selectMethod(m),
3988
+ onClick: () => onSelect(m),
3489
3989
  className: [tabClassName, active ? tabActiveClassName : ""].filter(Boolean).join(" "),
3490
3990
  children: label
3491
3991
  },
@@ -3496,49 +3996,34 @@ function PaywallMethodTabs({
3496
3996
 
3497
3997
  // src/components/paywall/PaywallMethodContent.tsx
3498
3998
  var import_jsx_runtime33 = require("react/jsx-runtime");
3499
- function PaywallMethodContent({ copy, className, rowClassName }) {
3500
- const { selectedMethod, hasConsumedTrial } = usePaywallContext();
3501
- const useCardConsumed = selectedMethod === "card" && hasConsumedTrial && copy.cardConsumedTrial;
3502
- const rows = useCardConsumed ? copy.cardConsumedTrial.bodyRows : selectedMethod === "pix-auto" || selectedMethod === "pix-once" ? copy.pix.bodyRows : copy.card.bodyRows;
3503
- return /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { role: "tabpanel", id: `paywall-tab-${selectedMethod}`, className, children: rows.map((row, i) => /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: rowClassName, children: row }, i)) });
3999
+ function PaywallMethodContent({
4000
+ method,
4001
+ copy,
4002
+ hasConsumedTrial = false,
4003
+ className,
4004
+ rowClassName
4005
+ }) {
4006
+ const useCardConsumed = method === "card" && hasConsumedTrial && copy.cardConsumedTrial;
4007
+ const rows = useCardConsumed ? copy.cardConsumedTrial.bodyRows : method === "pix-auto" || method === "pix-once" ? copy.pix.bodyRows : copy.card.bodyRows;
4008
+ return /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { role: "tabpanel", id: `paywall-tab-${method}`, className, children: rows.map((row, i) => /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: rowClassName, children: row }, i)) });
3504
4009
  }
3505
4010
 
3506
4011
  // src/components/paywall/PaywallCyclePicker.tsx
3507
4012
  var import_jsx_runtime34 = require("react/jsx-runtime");
3508
- var VARIANT_CLASSES = {
3509
- default: { card: "", cardSelected: "" },
3510
- "premium-gold": {
3511
- card: "",
3512
- cardSelected: "border-2 border-yellow-400/80 ring-2 ring-yellow-400/20"
3513
- },
3514
- "pink-pill": {
3515
- card: "rounded-2xl",
3516
- cardSelected: "border-2 border-pink-500"
3517
- }
3518
- };
3519
4013
  function PaywallCyclePicker({
4014
+ cycles,
4015
+ selected,
4016
+ onSelect,
4017
+ priceCentsByCycle,
4018
+ anchorCentsByCycle,
4019
+ monthlyEquivByCycle,
3520
4020
  labels,
3521
4021
  className,
3522
4022
  cardClassName,
3523
4023
  cardSelectedClassName,
3524
- anchorClassName,
3525
- variant = "default",
3526
- render
4024
+ anchorClassName
3527
4025
  }) {
3528
- const ctx = usePaywallContext();
3529
- const { cycle: selected, setCycle, plan, anchorPriceCents } = ctx;
3530
- const cycles = ["MONTHLY", "YEARLY"];
3531
- if (render) {
3532
- return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("div", { className, children: render({ cycles, selected, setCycle, plan, anchorPriceCents }) });
3533
- }
3534
4026
  if (cycles.length < 2) return null;
3535
- const v = VARIANT_CLASSES[variant];
3536
- const composedCardClassName = [v.card, cardClassName].filter(Boolean).join(" ");
3537
- const composedCardSelectedClassName = [v.cardSelected, cardSelectedClassName].filter(Boolean).join(" ");
3538
- const monthlyCents = plan?.monthlyCents ?? 0;
3539
- const yearlyCents = plan?.yearlyCents ?? 0;
3540
- const anchorMonthly = plan?.anchorMonthlyCents ?? null;
3541
- const anchorYearly = plan?.anchorYearlyCents ?? null;
3542
4027
  return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
3543
4028
  "div",
3544
4029
  {
@@ -3549,20 +4034,16 @@ function PaywallCyclePicker({
3549
4034
  const active = c === selected;
3550
4035
  const label = c === "YEARLY" ? labels.annualLabel : labels.monthlyLabel;
3551
4036
  const suffix = c === "YEARLY" ? labels.annualSuffix : labels.monthlySuffix;
3552
- const mainCents = c === "YEARLY" ? Math.round(yearlyCents / 12) : monthlyCents;
3553
- const anchorCents = c === "YEARLY" ? anchorYearly : anchorMonthly;
4037
+ const mainCents = c === "YEARLY" ? monthlyEquivByCycle[c] : priceCentsByCycle[c];
4038
+ const anchorCents = anchorCentsByCycle[c];
3554
4039
  return /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(
3555
4040
  "button",
3556
4041
  {
3557
4042
  type: "button",
3558
4043
  role: "radio",
3559
4044
  "aria-checked": active,
3560
- onClick: () => setCycle(c),
3561
- className: [
3562
- "flex flex-col items-center gap-0.5",
3563
- composedCardClassName,
3564
- active ? composedCardSelectedClassName : ""
3565
- ].filter(Boolean).join(" "),
4045
+ onClick: () => onSelect(c),
4046
+ className: ["flex flex-col items-center gap-0.5", cardClassName, active ? cardSelectedClassName : ""].filter(Boolean).join(" "),
3566
4047
  children: [
3567
4048
  /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { className: "font-bold text-base leading-tight", children: formatBRL(mainCents) }),
3568
4049
  /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { className: "text-xs opacity-70 leading-tight", children: suffix }),
@@ -3577,51 +4058,62 @@ function PaywallCyclePicker({
3577
4058
  );
3578
4059
  }
3579
4060
 
3580
- // src/components/paywall/Paywall.tsx
4061
+ // src/components/paywall/PaywallCta.tsx
3581
4062
  var import_jsx_runtime35 = require("react/jsx-runtime");
3582
- var NBSP = "\xA0";
3583
- function Paywall({
3584
- copy,
3585
- themeClasses = {},
3586
- slots = {},
3587
- onBeforeCheckout
4063
+ function PaywallCta({
4064
+ ctaLabel,
4065
+ loadingLabel,
4066
+ switchHint,
4067
+ trustLine,
4068
+ onClick,
4069
+ disabled = false,
4070
+ loading = false,
4071
+ className,
4072
+ buttonClassName,
4073
+ switchHintClassName,
4074
+ trustClassName
3588
4075
  }) {
3589
- return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(PaywallProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
3590
- PaywallInner,
3591
- {
3592
- copy,
3593
- themeClasses,
3594
- slots,
3595
- onBeforeCheckout
3596
- }
3597
- ) });
4076
+ const label = loading && loadingLabel ? loadingLabel : ctaLabel;
4077
+ return /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("div", { className, children: [
4078
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
4079
+ "button",
4080
+ {
4081
+ type: "button",
4082
+ onClick,
4083
+ disabled: disabled || loading,
4084
+ className: buttonClassName,
4085
+ children: label
4086
+ }
4087
+ ),
4088
+ switchHint ? /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("p", { className: switchHintClassName, children: switchHint }) : null,
4089
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("p", { className: trustClassName, children: trustLine })
4090
+ ] });
3598
4091
  }
3599
- function PaywallInner({
4092
+
4093
+ // src/components/paywall/Paywall.tsx
4094
+ var import_jsx_runtime36 = require("react/jsx-runtime");
4095
+ var NBSP = "\xA0";
4096
+ function Paywall({
3600
4097
  copy,
3601
4098
  themeClasses = {},
3602
4099
  slots = {},
3603
4100
  onBeforeCheckout
3604
4101
  }) {
3605
- const { track: track2 } = (0, import_sdk23.useHook)();
3606
- const s = usePaywallContext();
4102
+ const { track: track2 } = (0, import_sdk24.useHook)();
4103
+ const s = usePaywallState();
3607
4104
  const priceLabel = formatBRL(s.currentPriceCents).replace(new RegExp(NBSP, "g"), " ");
4105
+ const monthlyEquivLabel = formatBRL(s.currentMonthlyEquivCents).replace(new RegExp(NBSP, "g"), " ");
3608
4106
  const trialDaysCardLabel = String(s.trialDaysCard);
3609
4107
  const ctaLabel = (0, import_react29.useMemo)(() => {
3610
4108
  if (s.isFree) return copy.freeCta ?? "Come\xE7ar agora";
3611
4109
  if (s.selectedMethod === "card") {
3612
4110
  if (s.hasConsumedTrial && copy.cardConsumedTrial) {
3613
- return interp(copy.cardConsumedTrial.ctaTemplate, {
3614
- price: priceLabel,
3615
- days: trialDaysCardLabel
3616
- });
4111
+ return interp(copy.cardConsumedTrial.ctaTemplate, { price: priceLabel, days: trialDaysCardLabel });
3617
4112
  }
3618
4113
  if (s.trialDaysCard > 0) {
3619
4114
  return interp(copy.card.ctaTemplate, { price: priceLabel, days: trialDaysCardLabel });
3620
4115
  }
3621
- return copy.cardConsumedTrial ? interp(copy.cardConsumedTrial.ctaTemplate, {
3622
- price: priceLabel,
3623
- days: trialDaysCardLabel
3624
- }) : `Assinar por ${priceLabel}`;
4116
+ return copy.cardConsumedTrial ? interp(copy.cardConsumedTrial.ctaTemplate, { price: priceLabel, days: trialDaysCardLabel }) : `Assinar por ${priceLabel}`;
3625
4117
  }
3626
4118
  return interp(copy.pix.ctaTemplate, { price: priceLabel, days: trialDaysCardLabel });
3627
4119
  }, [
@@ -3659,35 +4151,54 @@ function PaywallInner({
3659
4151
  await s.submit();
3660
4152
  };
3661
4153
  const ctaTheme = s.selectedMethod === "card" ? themeClasses.ctaCard : themeClasses.ctaPix;
3662
- return /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("div", { className: themeClasses.container, children: [
4154
+ return /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("div", { className: themeClasses.container, children: [
3663
4155
  slots.heroSlot,
3664
- /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("h1", { className: themeClasses.headline, children: copy.headline }),
3665
- /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("ul", { children: copy.features.map((f) => /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("li", { className: themeClasses.feature, children: [
4156
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("h1", { className: themeClasses.headline, children: copy.headline }),
4157
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("ul", { children: copy.features.map((f) => /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("li", { className: themeClasses.feature, children: [
3666
4158
  "\u2713 ",
3667
- /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("span", { children: f })
4159
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("span", { children: f })
3668
4160
  ] }, f)) }),
3669
- copy.socialProof ? /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("p", { className: themeClasses.socialProof, children: copy.socialProof }) : null,
3670
- slots.cyclePickerSlot ?? /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
4161
+ copy.socialProof ? /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("p", { className: themeClasses.socialProof, children: copy.socialProof }) : null,
4162
+ slots.cyclePickerSlot ?? /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
3671
4163
  PaywallCyclePicker,
3672
4164
  {
4165
+ cycles: ["MONTHLY", "YEARLY"],
4166
+ selected: s.cycle,
4167
+ onSelect: s.selectCycle,
4168
+ priceCentsByCycle: {
4169
+ MONTHLY: priceCentsForCycle(s, "MONTHLY"),
4170
+ YEARLY: priceCentsForCycle(s, "YEARLY")
4171
+ },
4172
+ anchorCentsByCycle: {
4173
+ MONTHLY: anchorForCycle(s, "MONTHLY"),
4174
+ YEARLY: anchorForCycle(s, "YEARLY")
4175
+ },
4176
+ monthlyEquivByCycle: {
4177
+ MONTHLY: priceCentsForCycle(s, "MONTHLY"),
4178
+ YEARLY: Math.round(priceCentsForCycle(s, "YEARLY") / 12)
4179
+ },
3673
4180
  labels: copy.cycle,
3674
4181
  cardClassName: themeClasses.cycleCard,
3675
4182
  cardSelectedClassName: themeClasses.cycleCardSelected,
3676
4183
  anchorClassName: themeClasses.anchorPrice
3677
4184
  }
3678
4185
  ),
3679
- /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
4186
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
3680
4187
  PaywallMethodTabs,
3681
4188
  {
4189
+ methods: s.methods,
4190
+ selected: s.selectedMethod,
4191
+ onSelect: s.selectMethod,
3682
4192
  labels: { "pix-auto": copy.pix.tabLabel, card: copy.card.tabLabel },
3683
4193
  className: themeClasses.tabs,
3684
4194
  tabClassName: themeClasses.tab,
3685
4195
  tabActiveClassName: themeClasses.tabActive
3686
4196
  }
3687
4197
  ),
3688
- /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
4198
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
3689
4199
  PaywallMethodContent,
3690
4200
  {
4201
+ method: s.selectedMethod,
3691
4202
  copy: {
3692
4203
  pix: interpolateCopy(copy.pix, priceLabel, trialDaysCardLabel),
3693
4204
  card: interpolateCopy(copy.card, priceLabel, trialDaysCardLabel),
@@ -3698,27 +4209,27 @@ function PaywallInner({
3698
4209
  ctaTemplate: copy.cardConsumedTrial.ctaTemplate
3699
4210
  } : void 0
3700
4211
  },
4212
+ hasConsumedTrial: s.hasConsumedTrial,
3701
4213
  className: themeClasses.tabContent,
3702
4214
  rowClassName: themeClasses.tabContentRow
3703
4215
  }
3704
4216
  ),
3705
4217
  slots.beforeCtaSlot,
3706
- /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("div", { children: [
3707
- /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
3708
- "button",
3709
- {
3710
- type: "button",
3711
- onClick: () => {
3712
- void handleCta();
3713
- },
3714
- disabled: s.submitting,
3715
- className: ctaTheme,
3716
- children: s.submitting ? "Abrindo checkout\u2026" : ctaLabel
3717
- }
3718
- ),
3719
- switchHint ? /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("p", { className: themeClasses.switchHint, children: switchHint }) : null,
3720
- /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("p", { className: themeClasses.trustLine, children: copy.trustLine })
3721
- ] })
4218
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
4219
+ PaywallCta,
4220
+ {
4221
+ ctaLabel,
4222
+ loadingLabel: "Abrindo checkout\u2026",
4223
+ switchHint,
4224
+ trustLine: copy.trustLine,
4225
+ onClick: handleCta,
4226
+ disabled: s.submitting,
4227
+ loading: s.submitting,
4228
+ buttonClassName: ctaTheme,
4229
+ switchHintClassName: themeClasses.switchHint,
4230
+ trustClassName: themeClasses.trustLine
4231
+ }
4232
+ )
3722
4233
  ] });
3723
4234
  }
3724
4235
  function interp(tpl, vars) {
@@ -3732,444 +4243,20 @@ function interpolateCopy(m, price, days) {
3732
4243
  switchHint: m.switchHint
3733
4244
  };
3734
4245
  }
3735
-
3736
- // src/components/paywall/PaywallCta.tsx
3737
- var import_jsx_runtime36 = require("react/jsx-runtime");
3738
- function PaywallCta({
3739
- ctaLabel,
3740
- loadingLabel,
3741
- switchHint,
3742
- trustLine,
3743
- className,
3744
- buttonClassName,
3745
- switchHintClassName,
3746
- trustClassName
3747
- }) {
3748
- const { submit, submitting } = usePaywallContext();
3749
- const label = submitting && loadingLabel ? loadingLabel : ctaLabel;
3750
- return /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("div", { className, children: [
3751
- /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
3752
- "button",
3753
- {
3754
- type: "button",
3755
- onClick: () => {
3756
- void submit();
3757
- },
3758
- disabled: submitting,
3759
- className: buttonClassName,
3760
- children: label
3761
- }
3762
- ),
3763
- switchHint ? /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("p", { className: switchHintClassName, children: switchHint }) : null,
3764
- /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("p", { className: trustClassName, children: trustLine })
3765
- ] });
3766
- }
3767
-
3768
- // src/components/paywall/blocks/PaywallEyebrow.tsx
3769
- var import_jsx_runtime37 = require("react/jsx-runtime");
3770
- var DEFAULT_EYEBROW_CLASSES = "text-xs uppercase tracking-widest font-semibold opacity-70";
3771
- function PaywallEyebrow({ text, className }) {
3772
- return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("div", { className: [DEFAULT_EYEBROW_CLASSES, className].filter(Boolean).join(" "), children: text });
3773
- }
3774
-
3775
- // src/components/paywall/blocks/PaywallHero.tsx
3776
- var import_jsx_runtime38 = require("react/jsx-runtime");
3777
- var DEFAULT_GRADIENT = "absolute inset-0 bg-gradient-to-t from-black/70 via-black/20 to-transparent";
3778
- function PaywallHero({
3779
- src,
3780
- alt = "",
3781
- headline,
3782
- aspectRatio = "16/9",
3783
- gradientClassName,
3784
- className,
3785
- headlineClassName,
3786
- imgClassName,
3787
- render
3788
- }) {
3789
- if (render) {
3790
- return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("div", { className, children: render({ src, headline }) });
3791
- }
3792
- return /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(
3793
- "div",
3794
- {
3795
- className: ["relative overflow-hidden", className].filter(Boolean).join(" "),
3796
- style: { aspectRatio },
3797
- children: [
3798
- /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
3799
- "img",
3800
- {
3801
- src,
3802
- alt,
3803
- className: ["absolute inset-0 w-full h-full object-cover", imgClassName].filter(Boolean).join(" ")
3804
- }
3805
- ),
3806
- /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("div", { className: gradientClassName ?? DEFAULT_GRADIENT, "aria-hidden": "true" }),
3807
- headline ? /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
3808
- "h1",
3809
- {
3810
- className: ["absolute bottom-0 left-0 right-0 p-4 text-white font-bold text-2xl", headlineClassName].filter(Boolean).join(" "),
3811
- children: headline
3812
- }
3813
- ) : null
3814
- ]
3815
- }
3816
- );
3817
- }
3818
-
3819
- // src/components/paywall/blocks/PaywallHeadline.tsx
3820
- var import_jsx_runtime39 = require("react/jsx-runtime");
3821
- var DEFAULT_HEADLINE_CLASSES = "text-2xl font-bold leading-tight";
3822
- function PaywallHeadline({ text, className, as = "h1" }) {
3823
- const Tag = as;
3824
- return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(Tag, { className: [DEFAULT_HEADLINE_CLASSES, className].filter(Boolean).join(" "), children: text });
3825
- }
3826
-
3827
- // src/components/paywall/blocks/PaywallPriceHeadline.tsx
3828
- var import_jsx_runtime40 = require("react/jsx-runtime");
3829
- var DEFAULT_CLASS = "text-2xl font-bold leading-tight";
3830
- var CYCLE_LABEL = {
3831
- MONTHLY: "mensal",
3832
- YEARLY: "anual"
3833
- };
3834
- function PaywallPriceHeadline({
3835
- template,
3836
- className,
3837
- as = "h1",
3838
- render
3839
- }) {
3840
- const { cycle, currentMonthlyEquivCents, plan } = usePaywallContext();
3841
- const yearlyCents = plan?.yearlyCents ?? null;
3842
- const pricePerDay = formatBRL(dailyFromYearly(yearlyCents));
3843
- const monthlyEquiv = currentMonthlyEquivCents ?? 0;
3844
- const cycleLabel = CYCLE_LABEL[cycle] ?? cycle.toLowerCase();
3845
- const rootClasses = [DEFAULT_CLASS, className].filter(Boolean).join(" ");
3846
- if (render) {
3847
- const RootTag2 = as;
3848
- return /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(RootTag2, { className: [className].filter(Boolean).join(" ") || void 0, children: render({ pricePerDay, currentMonthlyEquivCents: monthlyEquiv, cycle }) });
3849
- }
3850
- const text = template.replaceAll("{pricePerDay}", pricePerDay).replaceAll("{currentMonthlyEquiv}", formatBRL(monthlyEquiv)).replaceAll("{cycle}", cycleLabel);
3851
- const RootTag = as;
3852
- return /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(RootTag, { className: rootClasses, children: text });
3853
- }
3854
-
3855
- // src/components/paywall/blocks/PaywallCountdown.tsx
3856
- var import_react30 = require("react");
3857
- var import_jsx_runtime41 = require("react/jsx-runtime");
3858
- var DEFAULT_COUNTDOWN_CLASSES = "font-mono tabular-nums";
3859
- function resolveDeadlineMs(deadline) {
3860
- if (deadline instanceof Date) return deadline.getTime();
3861
- if (typeof deadline === "string") return new Date(deadline).getTime();
3862
- const { sessionStorageKey, durationMs } = deadline;
3863
- if (typeof window === "undefined" || typeof window.sessionStorage === "undefined") {
3864
- return Date.now() + durationMs;
3865
- }
3866
- const stored = window.sessionStorage.getItem(sessionStorageKey);
3867
- const parsed = stored ? Number.parseInt(stored, 10) : NaN;
3868
- const now = Date.now();
3869
- if (!Number.isFinite(parsed) || parsed < now) {
3870
- const target = now + durationMs;
3871
- window.sessionStorage.setItem(sessionStorageKey, String(target));
3872
- return target;
3873
- }
3874
- return parsed;
3875
- }
3876
- function computeRemaining(deadlineMs) {
3877
- const diff = Math.max(0, deadlineMs - Date.now());
3878
- const totalSeconds = Math.floor(diff / 1e3);
3879
- const h = Math.floor(totalSeconds / 3600);
3880
- const m = Math.floor(totalSeconds % 3600 / 60);
3881
- const s = totalSeconds % 60;
3882
- return { h, m, s, expired: diff === 0 };
3883
- }
3884
- function pad(n) {
3885
- return String(n).padStart(2, "0");
3886
- }
3887
- function PaywallCountdown({
3888
- deadline,
3889
- format = "h:m:s",
3890
- onExpire,
3891
- className,
3892
- render
3893
- }) {
3894
- const deadlineMsRef = (0, import_react30.useRef)(null);
3895
- if (deadlineMsRef.current === null) {
3896
- deadlineMsRef.current = resolveDeadlineMs(deadline);
3897
- }
3898
- const [state, setState] = (0, import_react30.useState)(() => computeRemaining(deadlineMsRef.current));
3899
- const expiredCalledRef = (0, import_react30.useRef)(false);
3900
- (0, import_react30.useEffect)(() => {
3901
- if (state.expired) {
3902
- if (!expiredCalledRef.current) {
3903
- expiredCalledRef.current = true;
3904
- onExpire?.();
3905
- }
3906
- return;
3907
- }
3908
- const tick = () => {
3909
- const next = computeRemaining(deadlineMsRef.current);
3910
- setState(next);
3911
- if (next.expired && !expiredCalledRef.current) {
3912
- expiredCalledRef.current = true;
3913
- onExpire?.();
3914
- }
3915
- };
3916
- const id = setInterval(tick, 1e3);
3917
- return () => clearInterval(id);
3918
- }, [state.expired]);
3919
- if (render) {
3920
- return /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("div", { className, children: render(state) });
3921
- }
3922
- const formatted = format === "h:m:s" ? `${pad(state.h)}:${pad(state.m)}:${pad(state.s)}` : `${pad(state.h * 60 + state.m)}:${pad(state.s)}`;
3923
- return /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("div", { className: [DEFAULT_COUNTDOWN_CLASSES, className].filter(Boolean).join(" "), children: formatted });
3924
- }
3925
-
3926
- // src/components/paywall/blocks/PaywallFeatures.tsx
3927
- var import_jsx_runtime42 = require("react/jsx-runtime");
3928
- function PaywallFeatures({
3929
- items,
3930
- IconComponent,
3931
- className,
3932
- itemClassName,
3933
- iconClassName,
3934
- render,
3935
- renderItem
3936
- }) {
3937
- if (render) {
3938
- return /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("div", { className, children: render({ items }) });
3939
- }
3940
- if (renderItem) {
3941
- return /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("ul", { className, children: items.map((item, idx) => /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("li", { children: renderItem(item, idx) }, idx)) });
3942
- }
3943
- return /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("ul", { className, children: items.map((item, idx) => /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("li", { className: itemClassName, children: [
3944
- IconComponent ? /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(IconComponent, { className: iconClassName }) : /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: iconClassName, "aria-hidden": "true", children: "\u2713" }),
3945
- /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { children: item })
3946
- ] }, idx)) });
3947
- }
3948
-
3949
- // src/components/paywall/blocks/PaywallFeaturesCard.tsx
3950
- var import_jsx_runtime43 = require("react/jsx-runtime");
3951
- var DEFAULT_CARD_CLASSES = "rounded-xl border p-4";
3952
- function PaywallFeaturesCard({
3953
- title,
3954
- items,
3955
- className,
3956
- cardClassName,
3957
- titleClassName,
3958
- itemClassName,
3959
- renderItem
3960
- }) {
3961
- return /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("div", { className, children: /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", { className: [DEFAULT_CARD_CLASSES, cardClassName].filter(Boolean).join(" "), children: [
3962
- title ? /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("div", { className: ["font-semibold mb-2", titleClassName].filter(Boolean).join(" "), children: title }) : null,
3963
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("ul", { children: items.map(
3964
- (item, idx) => renderItem ? /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("li", { children: renderItem(item, idx) }, idx) : /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("li", { className: itemClassName, children: [
3965
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("span", { "aria-hidden": "true", children: "\u2022" }),
3966
- " ",
3967
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("span", { children: item })
3968
- ] }, idx)
3969
- ) })
3970
- ] }) });
3971
- }
3972
-
3973
- // src/components/paywall/blocks/PaywallTrophyBadge.tsx
3974
- var import_jsx_runtime44 = require("react/jsx-runtime");
3975
- 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";
3976
- var FLOATING_CLASSES = "absolute top-2 right-2 z-10 shadow-md";
3977
- function PaywallTrophyBadge({
3978
- text,
3979
- className,
3980
- iconClassName,
3981
- floating = false,
3982
- render
3983
- }) {
3984
- if (render) {
3985
- return /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("div", { className, children: render({ text }) });
3986
- }
3987
- const rootClasses = [
3988
- DEFAULT_CHIP_CLASSES,
3989
- floating ? FLOATING_CLASSES : "",
3990
- className
3991
- ].filter(Boolean).join(" ");
3992
- return /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", { className: rootClasses, children: [
3993
- /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("span", { className: iconClassName, "aria-hidden": "true", children: "\u{1F3C6}" }),
3994
- /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("span", { children: text })
3995
- ] });
3996
- }
3997
-
3998
- // src/components/paywall/blocks/PaywallAnchorPrice.tsx
3999
- var import_jsx_runtime45 = require("react/jsx-runtime");
4000
- var DEFAULT_CLASS2 = "text-sm opacity-60 line-through";
4001
- function PaywallAnchorPrice({
4002
- className,
4003
- render
4004
- }) {
4005
- const { anchorPriceCents, cycle } = usePaywallContext();
4006
- if (anchorPriceCents === null || anchorPriceCents === void 0 || anchorPriceCents <= 0) {
4007
- return null;
4008
- }
4009
- void cycle;
4010
- const formatted = formatBRL(anchorPriceCents);
4011
- const rootClasses = [DEFAULT_CLASS2, className].filter(Boolean).join(" ");
4012
- if (render) {
4013
- return /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("span", { className: className || void 0, children: render({ anchorCents: anchorPriceCents, formatted }) });
4014
- }
4015
- return /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("span", { className: rootClasses, children: formatted });
4016
- }
4017
-
4018
- // src/components/paywall/blocks/PaywallTestimonials.tsx
4019
- var import_jsx_runtime46 = require("react/jsx-runtime");
4020
- var DEFAULT_ROOT = "flex gap-3 overflow-x-auto snap-x snap-mandatory pb-2";
4021
- var DEFAULT_CARD = "snap-start shrink-0 w-72 rounded-2xl border p-4 flex flex-col gap-2";
4022
- var DEFAULT_AVATAR = "w-10 h-10 rounded-full object-cover";
4023
- var DEFAULT_QUOTE = "text-sm leading-snug";
4024
- var DEFAULT_NAME = "text-xs font-semibold opacity-80";
4025
- var DEFAULT_STARS = "text-yellow-500 text-sm";
4026
- function clampStars(n) {
4027
- return Math.max(0, Math.min(5, Math.round(n)));
4028
- }
4029
- function PaywallTestimonials({
4030
- items,
4031
- className,
4032
- cardClassName,
4033
- avatarClassName,
4034
- quoteClassName,
4035
- nameClassName,
4036
- starsClassName,
4037
- renderItem
4038
- }) {
4039
- const rootClasses = [DEFAULT_ROOT, className].filter(Boolean).join(" ");
4040
- const cardClasses = [DEFAULT_CARD, cardClassName].filter(Boolean).join(" ");
4041
- const avatarClasses = [DEFAULT_AVATAR, avatarClassName].filter(Boolean).join(" ");
4042
- const quoteClasses = [DEFAULT_QUOTE, quoteClassName].filter(Boolean).join(" ");
4043
- const nameClasses = [DEFAULT_NAME, nameClassName].filter(Boolean).join(" ");
4044
- const starsClasses = [DEFAULT_STARS, starsClassName].filter(Boolean).join(" ");
4045
- return /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("div", { className: rootClasses, children: items.map((item, idx) => {
4046
- if (renderItem) return renderItem(item, idx);
4047
- const filled = clampStars(item.stars);
4048
- const empty = 5 - filled;
4049
- return /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: cardClasses, children: [
4050
- /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: "flex items-center gap-2", children: [
4051
- item.avatar ? /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
4052
- "img",
4053
- {
4054
- src: item.avatar,
4055
- alt: "",
4056
- loading: "lazy",
4057
- className: avatarClasses,
4058
- "aria-hidden": "true"
4059
- }
4060
- ) : null,
4061
- /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("div", { className: nameClasses, children: item.name })
4062
- ] }),
4063
- /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: starsClasses, "aria-label": `${filled} de 5 estrelas`, children: [
4064
- "\u2605".repeat(filled),
4065
- "\u2606".repeat(empty)
4066
- ] }),
4067
- /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("p", { className: quoteClasses, children: item.quote })
4068
- ] }, idx);
4069
- }) });
4070
- }
4071
-
4072
- // src/components/paywall/blocks/PaywallStatsRow.tsx
4073
- var import_jsx_runtime47 = require("react/jsx-runtime");
4074
- var DEFAULT_ROOT2 = "grid grid-cols-3 gap-4";
4075
- var DEFAULT_CELL = "flex flex-col items-center text-center";
4076
- var DEFAULT_VALUE = "text-2xl font-bold";
4077
- var DEFAULT_LABEL = "text-xs opacity-70";
4078
- function PaywallStatsRow({
4079
- stats,
4080
- className,
4081
- cellClassName,
4082
- valueClassName,
4083
- labelClassName,
4084
- renderCell
4085
- }) {
4086
- const rootClasses = [DEFAULT_ROOT2, className].filter(Boolean).join(" ");
4087
- const cellClasses = [DEFAULT_CELL, cellClassName].filter(Boolean).join(" ");
4088
- const valueClasses = [DEFAULT_VALUE, valueClassName].filter(Boolean).join(" ");
4089
- const labelClasses = [DEFAULT_LABEL, labelClassName].filter(Boolean).join(" ");
4090
- return /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("div", { className: rootClasses, children: stats.map((stat, idx) => {
4091
- if (renderCell) return renderCell(stat, idx);
4092
- return /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("div", { className: cellClasses, children: [
4093
- stat.icon ? /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("div", { "aria-hidden": "true", children: stat.icon }) : null,
4094
- /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("div", { className: valueClasses, children: stat.value }),
4095
- /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("div", { className: labelClasses, children: stat.label })
4096
- ] }, idx);
4097
- }) });
4098
- }
4099
-
4100
- // src/components/paywall/blocks/PaywallFinePrint.tsx
4101
- var import_jsx_runtime48 = require("react/jsx-runtime");
4102
- var DEFAULT_CLASS3 = "text-xs opacity-60 leading-snug";
4103
- var CYCLE_LABEL2 = {
4104
- MONTHLY: "mensal",
4105
- YEARLY: "anual"
4106
- };
4107
- function PaywallFinePrint({
4108
- template,
4109
- className,
4110
- render
4111
- }) {
4112
- const {
4113
- currentPriceCents,
4114
- cycle,
4115
- trialDaysCard,
4116
- trialDaysPix,
4117
- selectedMethod
4118
- } = usePaywallContext();
4119
- const trialDays = selectedMethod === "card" ? trialDaysCard : trialDaysPix;
4120
- const cycleLabel = CYCLE_LABEL2[cycle] ?? cycle.toLowerCase();
4121
- const priceFormatted = formatBRL(currentPriceCents ?? 0);
4122
- const rootClasses = [DEFAULT_CLASS3, className].filter(Boolean).join(" ");
4123
- if (render) {
4124
- return /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("p", { className: className || void 0, children: render({
4125
- currentPriceCents: currentPriceCents ?? 0,
4126
- cycle,
4127
- trialDays: trialDays ?? 0,
4128
- selectedMethod
4129
- }) });
4130
- }
4131
- const text = template.replaceAll("{price}", priceFormatted).replaceAll("{trialDays}", String(trialDays ?? 0)).replaceAll("{cycle}", cycleLabel);
4132
- return /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("p", { className: rootClasses, children: text });
4133
- }
4134
-
4135
- // src/components/paywall/blocks/PaywallTrustLine.tsx
4136
- var import_jsx_runtime49 = require("react/jsx-runtime");
4137
- var DEFAULT_ROOT3 = "flex items-center gap-3";
4138
- var DEFAULT_ITEM = "flex items-center gap-1.5 text-xs";
4139
- function PaywallTrustLine({
4140
- items,
4141
- className,
4142
- itemClassName,
4143
- renderItem
4144
- }) {
4145
- const rootClasses = [DEFAULT_ROOT3, className].filter(Boolean).join(" ");
4146
- const itemClasses = [DEFAULT_ITEM, itemClassName].filter(Boolean).join(" ");
4147
- return /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("div", { className: rootClasses, children: items.map((item, idx) => {
4148
- if (renderItem) return renderItem(item, idx);
4149
- return /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("span", { className: itemClasses, children: [
4150
- /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("span", { "aria-hidden": "true", children: item.icon }),
4151
- /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("span", { children: item.text })
4152
- ] }, idx);
4153
- }) });
4246
+ function priceCentsForCycle(s, c) {
4247
+ return s.plan ? c === "YEARLY" ? s.plan.yearlyCents ?? 0 : s.plan.monthlyCents : 0;
4154
4248
  }
4155
-
4156
- // src/components/paywall/blocks/PaywallStickyFooter.tsx
4157
- var import_jsx_runtime50 = require("react/jsx-runtime");
4158
- var DEFAULT_CLASSES = "sticky bottom-0 left-0 right-0 bg-background";
4159
- var SAFE_AREA_CLASS = "pb-[env(safe-area-inset-bottom)]";
4160
- function PaywallStickyFooter({
4161
- children,
4162
- className,
4163
- safeAreaInsets = true
4164
- }) {
4165
- const classes = [DEFAULT_CLASSES, safeAreaInsets ? SAFE_AREA_CLASS : null, className].filter(Boolean).join(" ");
4166
- return /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("div", { className: classes, children });
4249
+ function anchorForCycle(s, c) {
4250
+ if (!s.plan) return null;
4251
+ if (c === "YEARLY") return s.plan.anchorYearlyCents ?? null;
4252
+ return s.plan.anchorMonthlyCents ?? null;
4167
4253
  }
4168
4254
  // Annotate the CommonJS export names for ESM import in node:
4169
4255
  0 && (module.exports = {
4170
4256
  AppConfigProvider,
4171
4257
  AppConfigSchema,
4172
4258
  AppRoot,
4259
+ CheckoutPageDefault,
4173
4260
  DeepLinkHandler,
4174
4261
  DevSkipOnboardingFab,
4175
4262
  EmptyState,
@@ -4182,27 +4269,12 @@ function PaywallStickyFooter({
4182
4269
  OnboardingFlow,
4183
4270
  PaymentReturnHandler,
4184
4271
  Paywall,
4185
- PaywallAnchorPrice,
4186
- PaywallContext,
4187
- PaywallCountdown,
4188
4272
  PaywallCta,
4189
4273
  PaywallCyclePicker,
4190
- PaywallEyebrow,
4191
- PaywallFeatures,
4192
- PaywallFeaturesCard,
4193
- PaywallFinePrint,
4194
- PaywallHeadline,
4195
- PaywallHero,
4196
4274
  PaywallMethodContent,
4197
4275
  PaywallMethodTabs,
4198
- PaywallPriceHeadline,
4199
- PaywallProvider,
4200
- PaywallStatsRow,
4201
- PaywallStickyFooter,
4202
- PaywallTestimonials,
4203
- PaywallTrophyBadge,
4204
- PaywallTrustLine,
4205
4276
  PersistenceRegistry,
4277
+ PixWaitingPageDefault,
4206
4278
  PreAuthShell,
4207
4279
  PushPrompt,
4208
4280
  RouteBoundary,
@@ -4225,12 +4297,12 @@ function PaywallStickyFooter({
4225
4297
  useAppConfig,
4226
4298
  useAuth,
4227
4299
  useAuthPrimitives,
4300
+ useCheckoutForm,
4228
4301
  useFeature,
4229
4302
  useForgotForm,
4230
4303
  useInstallPrompt,
4231
4304
  useLoginForm,
4232
4305
  useOnboardingStep,
4233
- usePaywallContext,
4234
4306
  usePaywallState,
4235
4307
  usePlan,
4236
4308
  usePush,