@hook-sdk/template 0.20.0 → 0.21.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  // src/AppRoot.tsx
2
2
  import { useMemo as useMemo3 } from "react";
3
3
  import { BrowserRouter, MemoryRouter, Navigate, Route, Routes } from "react-router-dom";
4
- import { useHook as useHook6 } from "@hook-sdk/sdk";
4
+ import { useHook as useHook7 } from "@hook-sdk/sdk";
5
5
 
6
6
  // src/config/AppConfigContext.tsx
7
7
  import { createContext, useContext } from "react";
@@ -35,7 +35,16 @@ var AuthFlowSchema = z.object({
35
35
  });
36
36
  var PaywallNonFreeSchema = z.object({
37
37
  mode: z.enum(["trial", "pay_first"]),
38
+ // Legacy flat trial — fallback when per-method fields aren't set.
38
39
  trialDays: z.number().int().nonnegative().optional(),
40
+ // Per-method trial (ADR-022 Amendment 2026-05-12 + G154). PIX Auto can't
41
+ // offer trial on Asaas today (Jornada 2 unavailable), so apps that mix
42
+ // methods must split the value to avoid bait-and-switch on PIX shoppers.
43
+ trialDaysCard: z.number().int().nonnegative().optional(),
44
+ trialDaysPix: z.number().int().nonnegative().optional(),
45
+ // Which method the paywall preselects. null/undefined = no preselection
46
+ // (user picks). Per-app override reflects audience, not Hook bias.
47
+ defaultMethod: z.enum(["card", "pix-auto", "pix-once"]).nullable().optional(),
39
48
  cycles: z.array(z.enum(["MONTHLY", "YEARLY"])).min(1),
40
49
  prices: z.object({
41
50
  monthlyCents: z.number().int().nonnegative(),
@@ -286,7 +295,8 @@ function usePaywallState() {
286
295
  () => declaredMethods.filter((m) => isMethodAvailable(availability, m)),
287
296
  [declaredMethods, availability]
288
297
  );
289
- const defaultMethod = methods[0] ?? declaredMethods[0] ?? "card";
298
+ const configDefault = !isFree && "defaultMethod" in paywall ? paywall.defaultMethod ?? null : null;
299
+ const defaultMethod = (configDefault && methods.includes(configDefault) ? configDefault : null) ?? methods[0] ?? declaredMethods[0] ?? "card";
290
300
  const [selectedMethodRaw, setSelectedMethod] = useState(defaultMethod);
291
301
  const selectedMethod = methods.includes(selectedMethodRaw) ? selectedMethodRaw : methods[0] ?? selectedMethodRaw;
292
302
  const initialCycle = isFree ? "MONTHLY" : paywall.cycles[0] ?? "MONTHLY";
@@ -307,6 +317,22 @@ function usePaywallState() {
307
317
  const [submitting, setSubmitting] = useState(false);
308
318
  const status = subscription.status();
309
319
  const daysLeftInTrial = subscription.daysLeftInTrial();
320
+ const trialDaysForMethod = useCallback(
321
+ (method) => {
322
+ if (isFree) return 0;
323
+ if (method === "card") {
324
+ if (typeof paywall.trialDaysCard === "number") return paywall.trialDaysCard;
325
+ if (typeof paywall.trialDays === "number") return paywall.trialDays;
326
+ return 7;
327
+ }
328
+ if (typeof paywall.trialDaysPix === "number") return paywall.trialDaysPix;
329
+ if (typeof paywall.trialDays === "number") return paywall.trialDays;
330
+ return 0;
331
+ },
332
+ [isFree, paywall]
333
+ );
334
+ const trialDaysCard = trialDaysForMethod("card");
335
+ const trialDaysPix = trialDaysForMethod("pix-auto");
310
336
  const initialLoadComplete = subscription.initialLoadComplete;
311
337
  const hasAccess = subscription.hasAccess;
312
338
  const pixPending = useMemo2(() => {
@@ -346,6 +372,40 @@ function usePaywallState() {
346
372
  discountPercent: discount
347
373
  };
348
374
  }, [paywall, cycle, isFree]);
375
+ const hasConsumedTrial = useMemo2(() => {
376
+ return ["active", "trialing", "past_due", "canceled", "expired"].includes(status);
377
+ }, [status]);
378
+ const currentPriceCents = useMemo2(() => {
379
+ if (isFree) return 0;
380
+ return cycle === "YEARLY" ? paywall.prices.yearlyCents : paywall.prices.monthlyCents;
381
+ }, [paywall, cycle, isFree]);
382
+ const currentMonthlyEquivCents = useMemo2(() => {
383
+ if (isFree) return 0;
384
+ if (cycle === "YEARLY") return Math.round(paywall.prices.yearlyCents / 12);
385
+ return paywall.prices.monthlyCents;
386
+ }, [paywall, cycle, isFree]);
387
+ const anchorPriceCents = useMemo2(() => {
388
+ if (isFree) return null;
389
+ const a = paywall.anchorPrices;
390
+ if (!a) return null;
391
+ return cycle === "YEARLY" ? a.yearlyCents : a.monthlyCents;
392
+ }, [paywall, cycle, isFree]);
393
+ const selectMethod = useCallback(
394
+ (next) => {
395
+ if (next === selectedMethod) return;
396
+ track2("paywall_method_tab_clicked", { method: next, from_method: selectedMethod });
397
+ setSelectedMethod(next);
398
+ },
399
+ [selectedMethod, track2]
400
+ );
401
+ const selectCycle = useCallback(
402
+ (next) => {
403
+ if (next === cycle) return;
404
+ track2("paywall_cycle_clicked", { cycle: next, from_cycle: cycle });
405
+ setCycle(next);
406
+ },
407
+ [cycle, track2]
408
+ );
349
409
  const useDefaultMessages = paywall.mode !== "free" && paywall.errorMessages === "default";
350
410
  const buildError = useCallback(
351
411
  (code, fallbackMessage) => ({
@@ -540,6 +600,20 @@ function usePaywallState() {
540
600
  methods,
541
601
  selectedMethod,
542
602
  setSelectedMethod,
603
+ // Conversion-max derivations (template 0.21)
604
+ hasConsumedTrial,
605
+ currentPriceCents,
606
+ currentMonthlyEquivCents,
607
+ anchorPriceCents,
608
+ selectMethod,
609
+ selectCycle,
610
+ isFree,
611
+ // Per-method trial (ADR-022 Amendment 2026-05-12). Use these to render
612
+ // asymmetric copy per method card on the paywall — never a global
613
+ // "free trial!" headline when both methods are visible.
614
+ trialDaysForMethod,
615
+ trialDaysCard,
616
+ trialDaysPix,
543
617
  // Form state
544
618
  cpfState,
545
619
  cardState,
@@ -571,13 +645,13 @@ var BLOCKING = /* @__PURE__ */ new Set([
571
645
  "canceled",
572
646
  "none"
573
647
  ]);
574
- function SubscriptionGate({ Paywall, children }) {
648
+ function SubscriptionGate({ Paywall: Paywall2, children }) {
575
649
  const { mode } = useTemplateConfig();
576
650
  const { status, hasAccess, initialLoadComplete } = usePaywallState();
577
651
  if (mode === "free") return /* @__PURE__ */ jsx5(Fragment2, { children });
578
652
  if (!initialLoadComplete && status === "none") return null;
579
653
  if (hasAccess === true && status !== "none") return /* @__PURE__ */ jsx5(Fragment2, { children });
580
- if (BLOCKING.has(status)) return /* @__PURE__ */ jsx5(Paywall, {});
654
+ if (BLOCKING.has(status)) return /* @__PURE__ */ jsx5(Paywall2, {});
581
655
  return /* @__PURE__ */ jsx5(Fragment2, { children });
582
656
  }
583
657
 
@@ -2023,22 +2097,155 @@ function I18nProvider({
2023
2097
  return /* @__PURE__ */ jsx19(I18nextProvider, { i18n, children });
2024
2098
  }
2025
2099
 
2026
- // src/internal/PaymentReturnHandler.tsx
2027
- import { useCallback as useCallback3, useEffect as useEffect8, useRef as useRef4, useState as useState5 } from "react";
2100
+ // src/dev/env.ts
2101
+ function isDevToolsEnabled() {
2102
+ const meta = import.meta;
2103
+ if (meta.env?.VITE_HOOK_DEV_TOOLS !== "1") return false;
2104
+ if (typeof window === "undefined") return false;
2105
+ const host = window.location.hostname;
2106
+ return host.includes(".staging.") || host === "localhost" || host === "127.0.0.1";
2107
+ }
2108
+
2109
+ // src/dev/DevSkipOnboardingFab.tsx
2110
+ import { useCallback as useCallback3, useRef as useRef4, useState as useState5 } from "react";
2028
2111
  import { useHook as useHook5 } from "@hook-sdk/sdk";
2029
- import { Fragment as Fragment5, jsx as jsx20, jsxs as jsxs13 } from "react/jsx-runtime";
2112
+ import { jsx as jsx20 } from "react/jsx-runtime";
2113
+ var STORAGE_KEY = "hook_dev_skip_email";
2114
+ var TEST_EMAIL_DOMAIN = "@hook.test";
2115
+ var TEST_PASSWORD = "SkipTest!2026";
2116
+ function makeEmail() {
2117
+ return `ryan+skip-${Date.now()}${TEST_EMAIL_DOMAIN}`;
2118
+ }
2119
+ async function ensureSignedIn(hook, maxAttempts = 3) {
2120
+ if (hook.authStatus === "authenticated") return null;
2121
+ let lastErr;
2122
+ for (let i = 0; i < maxAttempts; i += 1) {
2123
+ const email = makeEmail();
2124
+ try {
2125
+ await hook.auth.signup({ email, password: TEST_PASSWORD, name: "Ryan Test" });
2126
+ try {
2127
+ window.sessionStorage.setItem(STORAGE_KEY, email);
2128
+ } catch {
2129
+ }
2130
+ return email;
2131
+ } catch (err) {
2132
+ lastErr = err;
2133
+ await new Promise((r) => setTimeout(r, 30));
2134
+ }
2135
+ }
2136
+ throw lastErr ?? new Error("signup failed after retries");
2137
+ }
2138
+ async function skipOnboarding(hook, defaults, appSlug) {
2139
+ const { __seed, ...rest } = defaults;
2140
+ await ensureSignedIn(hook);
2141
+ await hook.appData.set("onboarding_data", {
2142
+ ...rest,
2143
+ onboarding_completed: true
2144
+ });
2145
+ if (__seed) {
2146
+ await __seed(hook);
2147
+ }
2148
+ console.info("[hook-template] dev_skip_onboarding fired", {
2149
+ app_slug: appSlug,
2150
+ hostname: window.location.hostname
2151
+ });
2152
+ window.location.assign(`/app/${appSlug}/`);
2153
+ }
2154
+ var STYLES = {
2155
+ base: {
2156
+ position: "fixed",
2157
+ bottom: "16px",
2158
+ right: "16px",
2159
+ zIndex: 2147483647,
2160
+ padding: "10px 14px",
2161
+ borderRadius: "999px",
2162
+ border: "none",
2163
+ background: "#F59E0B",
2164
+ color: "#111827",
2165
+ fontWeight: 600,
2166
+ fontSize: "13px",
2167
+ fontFamily: "system-ui, -apple-system, sans-serif",
2168
+ boxShadow: "0 4px 14px rgba(0, 0, 0, 0.25)",
2169
+ cursor: "pointer",
2170
+ display: "flex",
2171
+ alignItems: "center",
2172
+ gap: "6px"
2173
+ },
2174
+ confirm: { background: "#DC2626", color: "#FFFFFF" },
2175
+ busy: { opacity: 0.6, cursor: "wait" }
2176
+ };
2177
+ var CONFIRM_TIMEOUT_MS = 3e3;
2178
+ function DevSkipOnboardingFab({ defaults }) {
2179
+ const hook = useHook5();
2180
+ const { slug } = useAppConfig();
2181
+ const [state, setState] = useState5("idle");
2182
+ const [errorMsg, setErrorMsg] = useState5(null);
2183
+ const timerRef = useRef4(null);
2184
+ const clearTimer = useCallback3(() => {
2185
+ if (timerRef.current) {
2186
+ clearTimeout(timerRef.current);
2187
+ timerRef.current = null;
2188
+ }
2189
+ }, []);
2190
+ const onClick = useCallback3(async () => {
2191
+ if (state === "busy") return;
2192
+ if (state === "idle" || state === "error") {
2193
+ setState("confirm");
2194
+ setErrorMsg(null);
2195
+ clearTimer();
2196
+ timerRef.current = setTimeout(() => setState("idle"), CONFIRM_TIMEOUT_MS);
2197
+ return;
2198
+ }
2199
+ clearTimer();
2200
+ setState("busy");
2201
+ try {
2202
+ await skipOnboarding(hook, defaults, slug);
2203
+ } catch (err) {
2204
+ setState("error");
2205
+ setErrorMsg(err instanceof Error ? err.message : String(err));
2206
+ }
2207
+ }, [state, hook, defaults, slug, clearTimer]);
2208
+ const label = (() => {
2209
+ if (state === "busy") return "skipping\u2026";
2210
+ if (state === "confirm") return "tap again to confirm";
2211
+ if (state === "error") return `failed \u2014 tap to retry`;
2212
+ return hook.authStatus === "authenticated" ? "\u26A1 skip onboarding" : "\u26A1 skip + signup";
2213
+ })();
2214
+ const style = {
2215
+ ...STYLES.base,
2216
+ ...state === "confirm" || state === "error" ? STYLES.confirm : {},
2217
+ ...state === "busy" ? STYLES.busy : {}
2218
+ };
2219
+ return /* @__PURE__ */ jsx20(
2220
+ "button",
2221
+ {
2222
+ type: "button",
2223
+ "data-testid": "dev-skip-onboarding-fab",
2224
+ "aria-label": "Skip onboarding (staging dev only)",
2225
+ style,
2226
+ onClick,
2227
+ title: errorMsg ?? void 0,
2228
+ children: label
2229
+ }
2230
+ );
2231
+ }
2232
+
2233
+ // src/internal/PaymentReturnHandler.tsx
2234
+ import { useCallback as useCallback4, useEffect as useEffect8, useRef as useRef5, useState as useState6 } from "react";
2235
+ import { useHook as useHook6 } from "@hook-sdk/sdk";
2236
+ import { Fragment as Fragment5, jsx as jsx21, jsxs as jsxs13 } from "react/jsx-runtime";
2030
2237
  var BACKOFF_MS = [2e3, 5e3, 1e4, 2e4, 4e4];
2031
2238
  var MAX_CYCLES = 3;
2032
2239
  var SUPPORT_MAILTO = "mailto:suporte@usehook.net?subject=Pagamento%20pendente";
2033
2240
  function PaymentReturnHandler({ children }) {
2034
- const { subscription, track: track2 } = useHook5();
2035
- const subRef = useRef4(subscription);
2241
+ const { subscription, track: track2 } = useHook6();
2242
+ const subRef = useRef5(subscription);
2036
2243
  subRef.current = subscription;
2037
- const runIdRef = useRef4(0);
2038
- const cyclesRef = useRef4(0);
2039
- const startMsRef = useRef4(0);
2040
- const [state, setState] = useState5("idle");
2041
- const runPoll = useCallback3(() => {
2244
+ const runIdRef = useRef5(0);
2245
+ const cyclesRef = useRef5(0);
2246
+ const startMsRef = useRef5(0);
2247
+ const [state, setState] = useState6("idle");
2248
+ const runPoll = useCallback4(() => {
2042
2249
  const runId = ++runIdRef.current;
2043
2250
  const isFirstRun = cyclesRef.current === 0;
2044
2251
  cyclesRef.current += 1;
@@ -2096,26 +2303,26 @@ function PaymentReturnHandler({ children }) {
2096
2303
  runIdRef.current++;
2097
2304
  };
2098
2305
  }, [runPoll]);
2099
- const goHome = useCallback3(() => {
2306
+ const goHome = useCallback4(() => {
2100
2307
  const cleanUrl = new URL(window.location.href);
2101
2308
  cleanUrl.searchParams.delete("paymentReturn");
2102
2309
  cleanUrl.pathname = "/app/home";
2103
2310
  window.location.href = cleanUrl.toString();
2104
2311
  }, []);
2105
2312
  if (state === "confirming") {
2106
- return /* @__PURE__ */ jsx20("div", { role: "status", "aria-live": "polite", style: overlayStyle2, children: "Confirmando pagamento\u2026" });
2313
+ return /* @__PURE__ */ jsx21("div", { role: "status", "aria-live": "polite", style: overlayStyle2, children: "Confirmando pagamento\u2026" });
2107
2314
  }
2108
2315
  if (state === "waiting") {
2109
- return /* @__PURE__ */ jsx20("div", { role: "status", "aria-live": "polite", style: overlayStyle2, children: /* @__PURE__ */ jsxs13("div", { style: { maxWidth: 320, textAlign: "center", lineHeight: 1.5 }, children: [
2110
- /* @__PURE__ */ jsx20("div", { style: { marginBottom: 16 }, children: "Pagamento aceito. Estamos confirmando com o banco \u2014 pode levar alguns minutos." }),
2111
- /* @__PURE__ */ jsx20("button", { type: "button", onClick: runPoll, style: buttonStyle, children: "Atualizar" })
2316
+ return /* @__PURE__ */ jsx21("div", { role: "status", "aria-live": "polite", style: overlayStyle2, children: /* @__PURE__ */ jsxs13("div", { style: { maxWidth: 320, textAlign: "center", lineHeight: 1.5 }, children: [
2317
+ /* @__PURE__ */ jsx21("div", { style: { marginBottom: 16 }, children: "Pagamento aceito. Estamos confirmando com o banco \u2014 pode levar alguns minutos." }),
2318
+ /* @__PURE__ */ jsx21("button", { type: "button", onClick: runPoll, style: buttonStyle, children: "Atualizar" })
2112
2319
  ] }) });
2113
2320
  }
2114
2321
  if (state === "timeout") {
2115
- return /* @__PURE__ */ jsx20("div", { role: "alert", "aria-live": "assertive", style: overlayStyle2, children: /* @__PURE__ */ jsxs13("div", { style: { maxWidth: 360, textAlign: "center", lineHeight: 1.5 }, children: [
2116
- /* @__PURE__ */ jsx20("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." }),
2322
+ return /* @__PURE__ */ jsx21("div", { role: "alert", "aria-live": "assertive", style: overlayStyle2, children: /* @__PURE__ */ jsxs13("div", { style: { maxWidth: 360, textAlign: "center", lineHeight: 1.5 }, children: [
2323
+ /* @__PURE__ */ jsx21("div", { style: { marginBottom: 16 }, children: "Ainda n\xE3o conseguimos confirmar seu pagamento com o banco. Voc\xEA pode tentar de novo, voltar pro app, ou falar com a gente." }),
2117
2324
  /* @__PURE__ */ jsxs13("div", { style: { display: "flex", flexDirection: "column", gap: 8 }, children: [
2118
- /* @__PURE__ */ jsx20(
2325
+ /* @__PURE__ */ jsx21(
2119
2326
  "button",
2120
2327
  {
2121
2328
  type: "button",
@@ -2128,7 +2335,7 @@ function PaymentReturnHandler({ children }) {
2128
2335
  children: "Tentar de novo"
2129
2336
  }
2130
2337
  ),
2131
- /* @__PURE__ */ jsx20(
2338
+ /* @__PURE__ */ jsx21(
2132
2339
  "button",
2133
2340
  {
2134
2341
  type: "button",
@@ -2138,7 +2345,7 @@ function PaymentReturnHandler({ children }) {
2138
2345
  children: "Voltar pro app"
2139
2346
  }
2140
2347
  ),
2141
- /* @__PURE__ */ jsx20(
2348
+ /* @__PURE__ */ jsx21(
2142
2349
  "a",
2143
2350
  {
2144
2351
  href: SUPPORT_MAILTO,
@@ -2150,7 +2357,7 @@ function PaymentReturnHandler({ children }) {
2150
2357
  ] })
2151
2358
  ] }) });
2152
2359
  }
2153
- return /* @__PURE__ */ jsx20(Fragment5, { children });
2360
+ return /* @__PURE__ */ jsx21(Fragment5, { children });
2154
2361
  }
2155
2362
  var overlayStyle2 = {
2156
2363
  position: "fixed",
@@ -2189,7 +2396,7 @@ var linkStyle = {
2189
2396
  };
2190
2397
 
2191
2398
  // src/AppRoot.tsx
2192
- import { Fragment as Fragment6, jsx as jsx21, jsxs as jsxs14 } from "react/jsx-runtime";
2399
+ import { Fragment as Fragment6, jsx as jsx22, jsxs as jsxs14 } from "react/jsx-runtime";
2193
2400
  function buildLegacyConfigShim(config) {
2194
2401
  const paywall = config.paywall;
2195
2402
  const isFree = paywall.mode === "free";
@@ -2237,9 +2444,10 @@ function AppRoot(props) {
2237
2444
  Forgot,
2238
2445
  Reset,
2239
2446
  EmailVerify,
2240
- Paywall,
2447
+ Paywall: Paywall2,
2241
2448
  Onboarding,
2242
- PreAuthFlow
2449
+ PreAuthFlow,
2450
+ devSkipOnboarding
2243
2451
  } = props;
2244
2452
  if (!Login || !Signup || !Forgot || !Reset) {
2245
2453
  throw new Error(
@@ -2247,7 +2455,7 @@ function AppRoot(props) {
2247
2455
  );
2248
2456
  }
2249
2457
  const config = parseAppConfig(rawConfig);
2250
- if (config.paywall.mode !== "free" && !Paywall) {
2458
+ if (config.paywall.mode !== "free" && !Paywall2) {
2251
2459
  throw new Error(
2252
2460
  "[hook-template] <AppRoot>: Paywall slot prop is required when config.paywall.mode != 'free'."
2253
2461
  );
@@ -2267,14 +2475,14 @@ function AppRoot(props) {
2267
2475
  const basename = `/app/${config.slug}`;
2268
2476
  const routerProps = testRouter === "memory" ? { basename, initialEntries: testInitialEntries } : { basename };
2269
2477
  const position = config.install_prompt?.position ?? "post-paywall";
2270
- const subscriptionGated = /* @__PURE__ */ jsx21(SubscriptionGate, { Paywall: Paywall ?? FallbackPaywall, children: position === "post-paywall" ? /* @__PURE__ */ jsxs14(InstallGate, { position: "post-paywall", children: [
2478
+ const subscriptionGated = /* @__PURE__ */ jsx22(SubscriptionGate, { Paywall: Paywall2 ?? FallbackPaywall, children: position === "post-paywall" ? /* @__PURE__ */ jsxs14(InstallGate, { position: "post-paywall", children: [
2271
2479
  children,
2272
- /* @__PURE__ */ jsx21(PushPrompt, {})
2480
+ /* @__PURE__ */ jsx22(PushPrompt, {})
2273
2481
  ] }) : /* @__PURE__ */ jsxs14(Fragment6, { children: [
2274
2482
  children,
2275
- /* @__PURE__ */ jsx21(PushPrompt, {})
2483
+ /* @__PURE__ */ jsx22(PushPrompt, {})
2276
2484
  ] }) });
2277
- const authGated = /* @__PURE__ */ jsx21(
2485
+ const authGated = /* @__PURE__ */ jsx22(
2278
2486
  AuthGated,
2279
2487
  {
2280
2488
  config,
@@ -2283,18 +2491,19 @@ function AppRoot(props) {
2283
2491
  Forgot,
2284
2492
  Reset,
2285
2493
  EmailVerify,
2286
- Paywall,
2494
+ Paywall: Paywall2,
2287
2495
  Onboarding,
2288
2496
  PreAuthFlow,
2289
2497
  children: subscriptionGated
2290
2498
  }
2291
2499
  );
2292
2500
  const routedTree = /* @__PURE__ */ jsxs14(Router, { ...routerProps, children: [
2293
- /* @__PURE__ */ jsx21(DeepLinkHandler, { deepLinks: config.deepLinks }),
2294
- /* @__PURE__ */ jsx21(SessionExpiredBanner, {}),
2295
- position === "pre-auth" ? /* @__PURE__ */ jsx21(InstallGate, { position: "pre-auth", children: authGated }) : authGated
2501
+ /* @__PURE__ */ jsx22(DeepLinkHandler, { deepLinks: config.deepLinks }),
2502
+ /* @__PURE__ */ jsx22(SessionExpiredBanner, {}),
2503
+ position === "pre-auth" ? /* @__PURE__ */ jsx22(InstallGate, { position: "pre-auth", children: authGated }) : authGated,
2504
+ isDevToolsEnabled() && devSkipOnboarding ? /* @__PURE__ */ jsx22(DevSkipOnboardingFab, { defaults: devSkipOnboarding.defaults }) : null
2296
2505
  ] });
2297
- return /* @__PURE__ */ jsx21(ErrorBoundary, { children: /* @__PURE__ */ jsx21(AppConfigProvider, { config, children: /* @__PURE__ */ jsx21(TemplateConfigProvider, { config: legacyShim, children: /* @__PURE__ */ jsx21(ThemeProvider, { children: /* @__PURE__ */ jsx21(PersistenceRegistry, { config: config.persistedKeys, children: config.i18n ? /* @__PURE__ */ jsx21(
2506
+ return /* @__PURE__ */ jsx22(ErrorBoundary, { children: /* @__PURE__ */ jsx22(AppConfigProvider, { config, children: /* @__PURE__ */ jsx22(TemplateConfigProvider, { config: legacyShim, children: /* @__PURE__ */ jsx22(ThemeProvider, { children: /* @__PURE__ */ jsx22(PersistenceRegistry, { config: config.persistedKeys, children: config.i18n ? /* @__PURE__ */ jsx22(
2298
2507
  I18nProvider,
2299
2508
  {
2300
2509
  defaultLocale: config.i18n.defaultLocale,
@@ -2314,37 +2523,37 @@ function AuthGated({
2314
2523
  EmailVerify,
2315
2524
  PreAuthFlow
2316
2525
  }) {
2317
- const { authStatus } = useHook6();
2526
+ const { authStatus } = useHook7();
2318
2527
  if (authStatus === "loading") return null;
2319
2528
  if (authStatus !== "authenticated") {
2320
2529
  if (config.onboarding?.trigger === "pre_signup_custom" && PreAuthFlow) {
2321
2530
  return /* @__PURE__ */ jsxs14(Routes, { children: [
2322
- /* @__PURE__ */ jsx21(Route, { path: "/signin", element: /* @__PURE__ */ jsx21(Login, {}) }),
2323
- /* @__PURE__ */ jsx21(Route, { path: "/signup", element: /* @__PURE__ */ jsx21(Signup, {}) }),
2324
- /* @__PURE__ */ jsx21(Route, { path: "/forgot", element: /* @__PURE__ */ jsx21(Forgot, {}) }),
2325
- /* @__PURE__ */ jsx21(Route, { path: "/reset", element: /* @__PURE__ */ jsx21(Reset, {}) }),
2326
- EmailVerify ? /* @__PURE__ */ jsx21(Route, { path: "/verify", element: /* @__PURE__ */ jsx21(EmailVerify, {}) }) : null,
2327
- /* @__PURE__ */ jsx21(Route, { path: "/*", element: /* @__PURE__ */ jsx21(PreAuthFlow, {}) })
2531
+ /* @__PURE__ */ jsx22(Route, { path: "/signin", element: /* @__PURE__ */ jsx22(Login, {}) }),
2532
+ /* @__PURE__ */ jsx22(Route, { path: "/signup", element: /* @__PURE__ */ jsx22(Signup, {}) }),
2533
+ /* @__PURE__ */ jsx22(Route, { path: "/forgot", element: /* @__PURE__ */ jsx22(Forgot, {}) }),
2534
+ /* @__PURE__ */ jsx22(Route, { path: "/reset", element: /* @__PURE__ */ jsx22(Reset, {}) }),
2535
+ EmailVerify ? /* @__PURE__ */ jsx22(Route, { path: "/verify", element: /* @__PURE__ */ jsx22(EmailVerify, {}) }) : null,
2536
+ /* @__PURE__ */ jsx22(Route, { path: "/*", element: /* @__PURE__ */ jsx22(PreAuthFlow, {}) })
2328
2537
  ] });
2329
2538
  }
2330
2539
  return /* @__PURE__ */ jsxs14(Routes, { children: [
2331
- /* @__PURE__ */ jsx21(Route, { path: "/", element: /* @__PURE__ */ jsx21(Login, {}) }),
2332
- /* @__PURE__ */ jsx21(Route, { path: "/signup", element: /* @__PURE__ */ jsx21(Signup, {}) }),
2333
- /* @__PURE__ */ jsx21(Route, { path: "/forgot", element: /* @__PURE__ */ jsx21(Forgot, {}) }),
2334
- /* @__PURE__ */ jsx21(Route, { path: "/reset", element: /* @__PURE__ */ jsx21(Reset, {}) }),
2335
- EmailVerify ? /* @__PURE__ */ jsx21(Route, { path: "/verify", element: /* @__PURE__ */ jsx21(EmailVerify, {}) }) : null,
2336
- /* @__PURE__ */ jsx21(Route, { path: "*", element: /* @__PURE__ */ jsx21(Navigate, { to: "/", replace: true }) })
2540
+ /* @__PURE__ */ jsx22(Route, { path: "/", element: /* @__PURE__ */ jsx22(Login, {}) }),
2541
+ /* @__PURE__ */ jsx22(Route, { path: "/signup", element: /* @__PURE__ */ jsx22(Signup, {}) }),
2542
+ /* @__PURE__ */ jsx22(Route, { path: "/forgot", element: /* @__PURE__ */ jsx22(Forgot, {}) }),
2543
+ /* @__PURE__ */ jsx22(Route, { path: "/reset", element: /* @__PURE__ */ jsx22(Reset, {}) }),
2544
+ EmailVerify ? /* @__PURE__ */ jsx22(Route, { path: "/verify", element: /* @__PURE__ */ jsx22(EmailVerify, {}) }) : null,
2545
+ /* @__PURE__ */ jsx22(Route, { path: "*", element: /* @__PURE__ */ jsx22(Navigate, { to: "/", replace: true }) })
2337
2546
  ] });
2338
2547
  }
2339
- return /* @__PURE__ */ jsx21(Fragment6, { children });
2548
+ return /* @__PURE__ */ jsx22(Fragment6, { children });
2340
2549
  }
2341
2550
  function FallbackPaywall() {
2342
2551
  return null;
2343
2552
  }
2344
2553
 
2345
2554
  // src/hooks/usePush.ts
2346
- import { useCallback as useCallback4, useEffect as useEffect9, useState as useState6 } from "react";
2347
- import { useHook as useHook7 } from "@hook-sdk/sdk";
2555
+ import { useCallback as useCallback5, useEffect as useEffect9, useState as useState7 } from "react";
2556
+ import { useHook as useHook8 } from "@hook-sdk/sdk";
2348
2557
  var DISMISS_STORAGE_KEY = "push:dismissed-until";
2349
2558
  var DISMISS_TTL_MS2 = 7 * 24 * 60 * 60 * 1e3;
2350
2559
  function detectIosNeedsInstall() {
@@ -2388,12 +2597,12 @@ function deriveState(push) {
2388
2597
  return { kind: "prompt" };
2389
2598
  }
2390
2599
  function usePush() {
2391
- const { push } = useHook7();
2392
- const [state, setState] = useState6(() => deriveState(push));
2600
+ const { push } = useHook8();
2601
+ const [state, setState] = useState7(() => deriveState(push));
2393
2602
  useEffect9(() => {
2394
2603
  setState(deriveState(push));
2395
2604
  }, [push]);
2396
- const subscribe = useCallback4(async () => {
2605
+ const subscribe = useCallback5(async () => {
2397
2606
  try {
2398
2607
  await push.subscribe();
2399
2608
  setState({ kind: "subscribed" });
@@ -2405,7 +2614,7 @@ function usePush() {
2405
2614
  throw e;
2406
2615
  }
2407
2616
  }, [push]);
2408
- const unsubscribe = useCallback4(async () => {
2617
+ const unsubscribe = useCallback5(async () => {
2409
2618
  try {
2410
2619
  await push.unsubscribe();
2411
2620
  setState({ kind: "prompt" });
@@ -2414,7 +2623,7 @@ function usePush() {
2414
2623
  throw e;
2415
2624
  }
2416
2625
  }, [push]);
2417
- const dismiss = useCallback4(() => {
2626
+ const dismiss = useCallback5(() => {
2418
2627
  if (typeof localStorage !== "undefined") {
2419
2628
  try {
2420
2629
  localStorage.setItem(DISMISS_STORAGE_KEY, String(Date.now() + DISMISS_TTL_MS2));
@@ -2427,7 +2636,7 @@ function usePush() {
2427
2636
  }
2428
2637
 
2429
2638
  // src/components/PushPrompt.tsx
2430
- import { jsx as jsx22, jsxs as jsxs15 } from "react/jsx-runtime";
2639
+ import { jsx as jsx23, jsxs as jsxs15 } from "react/jsx-runtime";
2431
2640
  function PushPrompt2({ texts, onSubscribed, onDeclined, onInstallRequested, className }) {
2432
2641
  const { state, subscribe } = usePush();
2433
2642
  if (state.kind === "denied" || state.kind === "dismissed" || state.kind === "subscribed") {
@@ -2435,19 +2644,19 @@ function PushPrompt2({ texts, onSubscribed, onDeclined, onInstallRequested, clas
2435
2644
  }
2436
2645
  if (state.kind === "ios_needs_install") {
2437
2646
  return /* @__PURE__ */ jsxs15("div", { className, role: "region", "aria-label": texts.iosInstallTitle, children: [
2438
- /* @__PURE__ */ jsx22("h3", { children: texts.iosInstallTitle }),
2439
- /* @__PURE__ */ jsx22("p", { children: texts.iosInstallBody }),
2440
- onInstallRequested && texts.iosInstallCta && /* @__PURE__ */ jsx22("button", { onClick: onInstallRequested, children: texts.iosInstallCta })
2647
+ /* @__PURE__ */ jsx23("h3", { children: texts.iosInstallTitle }),
2648
+ /* @__PURE__ */ jsx23("p", { children: texts.iosInstallBody }),
2649
+ onInstallRequested && texts.iosInstallCta && /* @__PURE__ */ jsx23("button", { onClick: onInstallRequested, children: texts.iosInstallCta })
2441
2650
  ] });
2442
2651
  }
2443
2652
  if (state.kind === "unsupported") {
2444
- return /* @__PURE__ */ jsx22("div", { className, role: "region", children: /* @__PURE__ */ jsx22("p", { children: texts.unsupportedBody }) });
2653
+ return /* @__PURE__ */ jsx23("div", { className, role: "region", children: /* @__PURE__ */ jsx23("p", { children: texts.unsupportedBody }) });
2445
2654
  }
2446
2655
  if (state.kind === "error") {
2447
- return /* @__PURE__ */ jsx22("div", { className, role: "region", "aria-label": "error", children: /* @__PURE__ */ jsx22("p", { children: state.message }) });
2656
+ return /* @__PURE__ */ jsx23("div", { className, role: "region", "aria-label": "error", children: /* @__PURE__ */ jsx23("p", { children: state.message }) });
2448
2657
  }
2449
2658
  return /* @__PURE__ */ jsxs15("div", { className, role: "region", children: [
2450
- /* @__PURE__ */ jsx22(
2659
+ /* @__PURE__ */ jsx23(
2451
2660
  "button",
2452
2661
  {
2453
2662
  type: "button",
@@ -2461,13 +2670,13 @@ function PushPrompt2({ texts, onSubscribed, onDeclined, onInstallRequested, clas
2461
2670
  children: texts.cta
2462
2671
  }
2463
2672
  ),
2464
- onDeclined && /* @__PURE__ */ jsx22("button", { type: "button", onClick: onDeclined, children: texts.declineCta })
2673
+ onDeclined && /* @__PURE__ */ jsx23("button", { type: "button", onClick: onDeclined, children: texts.declineCta })
2465
2674
  ] });
2466
2675
  }
2467
2676
 
2468
2677
  // src/components/LanguageSwitcher.tsx
2469
2678
  import { usePersistedState as usePersistedState2 } from "@hook-sdk/sdk";
2470
- import { jsx as jsx23, jsxs as jsxs16 } from "react/jsx-runtime";
2679
+ import { jsx as jsx24, jsxs as jsxs16 } from "react/jsx-runtime";
2471
2680
  function LanguageSwitcher({ id, className, label = "Language" }) {
2472
2681
  const config = useAppConfig();
2473
2682
  const i18nConfig = config.i18n;
@@ -2477,39 +2686,39 @@ function LanguageSwitcher({ id, className, label = "Language" }) {
2477
2686
  );
2478
2687
  if (!i18nConfig) return null;
2479
2688
  return /* @__PURE__ */ jsxs16("label", { className, children: [
2480
- label ? /* @__PURE__ */ jsx23("span", { children: label }) : null,
2481
- /* @__PURE__ */ jsx23(
2689
+ label ? /* @__PURE__ */ jsx24("span", { children: label }) : null,
2690
+ /* @__PURE__ */ jsx24(
2482
2691
  "select",
2483
2692
  {
2484
2693
  id,
2485
2694
  value: userLocale,
2486
2695
  onChange: (e) => setUserLocale(e.target.value),
2487
2696
  "data-testid": "language-switcher",
2488
- children: i18nConfig.supportedLocales.map((loc) => /* @__PURE__ */ jsx23("option", { value: loc, children: loc }, loc))
2697
+ children: i18nConfig.supportedLocales.map((loc) => /* @__PURE__ */ jsx24("option", { value: loc, children: loc }, loc))
2489
2698
  }
2490
2699
  )
2491
2700
  ] });
2492
2701
  }
2493
2702
 
2494
2703
  // src/defaults/LoadingState.tsx
2495
- import { jsx as jsx24 } from "react/jsx-runtime";
2704
+ import { jsx as jsx25 } from "react/jsx-runtime";
2496
2705
  function LoadingState({ message }) {
2497
- return /* @__PURE__ */ jsx24("div", { role: "status", "aria-live": "polite", style: { padding: 24, textAlign: "center" }, children: /* @__PURE__ */ jsx24("span", { children: message ?? "Carregando..." }) });
2706
+ return /* @__PURE__ */ jsx25("div", { role: "status", "aria-live": "polite", style: { padding: 24, textAlign: "center" }, children: /* @__PURE__ */ jsx25("span", { children: message ?? "Carregando..." }) });
2498
2707
  }
2499
2708
 
2500
2709
  // src/defaults/EmptyState.tsx
2501
- import { jsx as jsx25, jsxs as jsxs17 } from "react/jsx-runtime";
2710
+ import { jsx as jsx26, jsxs as jsxs17 } from "react/jsx-runtime";
2502
2711
  function EmptyState({ title, description, action }) {
2503
2712
  return /* @__PURE__ */ jsxs17("div", { role: "status", style: { padding: 32, textAlign: "center" }, children: [
2504
- /* @__PURE__ */ jsx25("h2", { style: { marginBottom: 8 }, children: title }),
2505
- description && /* @__PURE__ */ jsx25("p", { style: { opacity: 0.7 }, children: description }),
2506
- action && /* @__PURE__ */ jsx25("div", { style: { marginTop: 16 }, children: action })
2713
+ /* @__PURE__ */ jsx26("h2", { style: { marginBottom: 8 }, children: title }),
2714
+ description && /* @__PURE__ */ jsx26("p", { style: { opacity: 0.7 }, children: description }),
2715
+ action && /* @__PURE__ */ jsx26("div", { style: { marginTop: 16 }, children: action })
2507
2716
  ] });
2508
2717
  }
2509
2718
 
2510
2719
  // src/hooks/useLoginForm.ts
2511
- import { useCallback as useCallback5, useMemo as useMemo4, useState as useState7 } from "react";
2512
- import { useHook as useHook8 } from "@hook-sdk/sdk";
2720
+ import { useCallback as useCallback6, useMemo as useMemo4, useState as useState8 } from "react";
2721
+ import { useHook as useHook9 } from "@hook-sdk/sdk";
2513
2722
 
2514
2723
  // src/errors.ts
2515
2724
  import { SdkError, SdkAuthError, SdkRateLimitError } from "@hook-sdk/sdk";
@@ -2544,14 +2753,14 @@ function mapSdkError(err) {
2544
2753
  var EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
2545
2754
  var MIN_PASSWORD = 8;
2546
2755
  function useLoginForm() {
2547
- const { auth } = useHook8();
2548
- const [email, setEmail] = useState7("");
2549
- const [password, setPassword] = useState7("");
2550
- const [submitting, setSubmitting] = useState7(false);
2551
- const [error, setError] = useState7(null);
2552
- const [touchedEmail, setTouchedEmail] = useState7(false);
2553
- const [touchedPassword, setTouchedPassword] = useState7(false);
2554
- const [formSubmitAttempted, setFormSubmitAttempted] = useState7(false);
2756
+ const { auth } = useHook9();
2757
+ const [email, setEmail] = useState8("");
2758
+ const [password, setPassword] = useState8("");
2759
+ const [submitting, setSubmitting] = useState8(false);
2760
+ const [error, setError] = useState8(null);
2761
+ const [touchedEmail, setTouchedEmail] = useState8(false);
2762
+ const [touchedPassword, setTouchedPassword] = useState8(false);
2763
+ const [formSubmitAttempted, setFormSubmitAttempted] = useState8(false);
2555
2764
  const validateEmail = useMemo4(() => {
2556
2765
  if (email.length === 0) return null;
2557
2766
  if (!EMAIL_RE.test(email)) return "Formato de e-mail inv\xE1lido.";
@@ -2565,7 +2774,7 @@ function useLoginForm() {
2565
2774
  const emailError = touchedEmail || formSubmitAttempted ? validateEmail : null;
2566
2775
  const passwordError = touchedPassword || formSubmitAttempted ? validatePassword : null;
2567
2776
  const canSubmit = email.length > 0 && password.length >= MIN_PASSWORD && validateEmail === null && validatePassword === null && !submitting;
2568
- const submit = useCallback5(async () => {
2777
+ const submit = useCallback6(async () => {
2569
2778
  setFormSubmitAttempted(true);
2570
2779
  if (!canSubmit) return false;
2571
2780
  setSubmitting(true);
@@ -2599,21 +2808,21 @@ function useLoginForm() {
2599
2808
  }
2600
2809
 
2601
2810
  // src/hooks/useSignupForm.ts
2602
- import { useCallback as useCallback6, useMemo as useMemo5, useState as useState8 } from "react";
2603
- import { useHook as useHook9 } from "@hook-sdk/sdk";
2811
+ import { useCallback as useCallback7, useMemo as useMemo5, useState as useState9 } from "react";
2812
+ import { useHook as useHook10 } from "@hook-sdk/sdk";
2604
2813
  var EMAIL_RE2 = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
2605
2814
  var MIN_PASSWORD2 = 8;
2606
2815
  function useSignupForm() {
2607
- const { auth } = useHook9();
2608
- const [name, setName] = useState8("");
2609
- const [email, setEmail] = useState8("");
2610
- const [password, setPassword] = useState8("");
2611
- const [submitting, setSubmitting] = useState8(false);
2612
- const [error, setError] = useState8(null);
2613
- const [touchedName, setTouchedName] = useState8(false);
2614
- const [touchedEmail, setTouchedEmail] = useState8(false);
2615
- const [touchedPassword, setTouchedPassword] = useState8(false);
2616
- const [formSubmitAttempted, setFormSubmitAttempted] = useState8(false);
2816
+ const { auth } = useHook10();
2817
+ const [name, setName] = useState9("");
2818
+ const [email, setEmail] = useState9("");
2819
+ const [password, setPassword] = useState9("");
2820
+ const [submitting, setSubmitting] = useState9(false);
2821
+ const [error, setError] = useState9(null);
2822
+ const [touchedName, setTouchedName] = useState9(false);
2823
+ const [touchedEmail, setTouchedEmail] = useState9(false);
2824
+ const [touchedPassword, setTouchedPassword] = useState9(false);
2825
+ const [formSubmitAttempted, setFormSubmitAttempted] = useState9(false);
2617
2826
  const validateName = useMemo5(() => {
2618
2827
  if (name.length === 0) return null;
2619
2828
  if (name.trim().length < 2) return "Nome muito curto.";
@@ -2633,7 +2842,7 @@ function useSignupForm() {
2633
2842
  const emailError = touchedEmail || formSubmitAttempted ? validateEmail : null;
2634
2843
  const passwordError = touchedPassword || formSubmitAttempted ? validatePassword : null;
2635
2844
  const canSubmit = name.trim().length >= 2 && email.length > 0 && password.length >= MIN_PASSWORD2 && validateName === null && validateEmail === null && validatePassword === null && !submitting;
2636
- const submit = useCallback6(async () => {
2845
+ const submit = useCallback7(async () => {
2637
2846
  setFormSubmitAttempted(true);
2638
2847
  if (!canSubmit) return false;
2639
2848
  setSubmitting(true);
@@ -2671,17 +2880,17 @@ function useSignupForm() {
2671
2880
  }
2672
2881
 
2673
2882
  // src/hooks/useForgotForm.ts
2674
- import { useCallback as useCallback7, useMemo as useMemo6, useState as useState9 } from "react";
2675
- import { useHook as useHook10 } from "@hook-sdk/sdk";
2883
+ import { useCallback as useCallback8, useMemo as useMemo6, useState as useState10 } from "react";
2884
+ import { useHook as useHook11 } from "@hook-sdk/sdk";
2676
2885
  var EMAIL_RE3 = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
2677
2886
  function useForgotForm() {
2678
- const { auth } = useHook10();
2679
- const [email, setEmail] = useState9("");
2680
- const [submitting, setSubmitting] = useState9(false);
2681
- const [sent, setSent] = useState9(false);
2682
- const [error, setError] = useState9(null);
2683
- const [touchedEmail, setTouchedEmail] = useState9(false);
2684
- const [formSubmitAttempted, setFormSubmitAttempted] = useState9(false);
2887
+ const { auth } = useHook11();
2888
+ const [email, setEmail] = useState10("");
2889
+ const [submitting, setSubmitting] = useState10(false);
2890
+ const [sent, setSent] = useState10(false);
2891
+ const [error, setError] = useState10(null);
2892
+ const [touchedEmail, setTouchedEmail] = useState10(false);
2893
+ const [formSubmitAttempted, setFormSubmitAttempted] = useState10(false);
2685
2894
  const validateEmail = useMemo6(() => {
2686
2895
  if (email.length === 0) return null;
2687
2896
  if (!EMAIL_RE3.test(email)) return "Formato de e-mail inv\xE1lido.";
@@ -2689,7 +2898,7 @@ function useForgotForm() {
2689
2898
  }, [email]);
2690
2899
  const emailError = touchedEmail || formSubmitAttempted ? validateEmail : null;
2691
2900
  const canSubmit = email.length > 0 && validateEmail === null && !submitting;
2692
- const submit = useCallback7(async () => {
2901
+ const submit = useCallback8(async () => {
2693
2902
  setFormSubmitAttempted(true);
2694
2903
  if (!canSubmit) return false;
2695
2904
  setSubmitting(true);
@@ -2720,20 +2929,20 @@ function useForgotForm() {
2720
2929
  }
2721
2930
 
2722
2931
  // src/hooks/useResetForm.ts
2723
- import { useCallback as useCallback8, useEffect as useEffect10, useMemo as useMemo7, useState as useState10 } from "react";
2724
- import { useHook as useHook11 } from "@hook-sdk/sdk";
2932
+ import { useCallback as useCallback9, useEffect as useEffect10, useMemo as useMemo7, useState as useState11 } from "react";
2933
+ import { useHook as useHook12 } from "@hook-sdk/sdk";
2725
2934
  var MIN_PASSWORD3 = 12;
2726
2935
  function useResetForm() {
2727
- const { auth } = useHook11();
2728
- const [token, setToken] = useState10(null);
2729
- const [password, setPassword] = useState10("");
2730
- const [confirm, setConfirm] = useState10("");
2731
- const [submitting, setSubmitting] = useState10(false);
2732
- const [done, setDone] = useState10(false);
2733
- const [error, setError] = useState10(null);
2734
- const [touchedPassword, setTouchedPassword] = useState10(false);
2735
- const [touchedConfirm, setTouchedConfirm] = useState10(false);
2736
- const [formSubmitAttempted, setFormSubmitAttempted] = useState10(false);
2936
+ const { auth } = useHook12();
2937
+ const [token, setToken] = useState11(null);
2938
+ const [password, setPassword] = useState11("");
2939
+ const [confirm, setConfirm] = useState11("");
2940
+ const [submitting, setSubmitting] = useState11(false);
2941
+ const [done, setDone] = useState11(false);
2942
+ const [error, setError] = useState11(null);
2943
+ const [touchedPassword, setTouchedPassword] = useState11(false);
2944
+ const [touchedConfirm, setTouchedConfirm] = useState11(false);
2945
+ const [formSubmitAttempted, setFormSubmitAttempted] = useState11(false);
2737
2946
  useEffect10(() => {
2738
2947
  if (typeof window === "undefined") return;
2739
2948
  const params = new URLSearchParams(window.location.search);
@@ -2753,7 +2962,7 @@ function useResetForm() {
2753
2962
  const passwordError = touchedPassword || formSubmitAttempted ? validatePassword : null;
2754
2963
  const confirmError = touchedConfirm || formSubmitAttempted ? validateConfirm : null;
2755
2964
  const canSubmit = token !== null && password.length >= MIN_PASSWORD3 && confirm === password && validatePassword === null && validateConfirm === null && !submitting && !done;
2756
- const submit = useCallback8(async () => {
2965
+ const submit = useCallback9(async () => {
2757
2966
  setFormSubmitAttempted(true);
2758
2967
  if (!canSubmit || token === null) return;
2759
2968
  setSubmitting(true);
@@ -2793,9 +3002,9 @@ function useResetForm() {
2793
3002
  }
2794
3003
 
2795
3004
  // src/hooks/usePlan.ts
2796
- import { useHook as useHook12 } from "@hook-sdk/sdk";
3005
+ import { useHook as useHook13 } from "@hook-sdk/sdk";
2797
3006
  function usePlan() {
2798
- const { plan } = useHook12();
3007
+ const { plan } = useHook13();
2799
3008
  return plan;
2800
3009
  }
2801
3010
 
@@ -2829,10 +3038,10 @@ function discountPercent(anchorCents, realCents) {
2829
3038
 
2830
3039
  // src/hooks/useAuthPrimitives.ts
2831
3040
  import { useEffect as useEffect11 } from "react";
2832
- import { useHook as useHook13 } from "@hook-sdk/sdk";
3041
+ import { useHook as useHook14 } from "@hook-sdk/sdk";
2833
3042
  var warned = false;
2834
3043
  function useAuthPrimitives() {
2835
- const { auth } = useHook13();
3044
+ const { auth } = useHook14();
2836
3045
  useEffect11(() => {
2837
3046
  if (!warned && process.env.NODE_ENV !== "production") {
2838
3047
  warned = true;
@@ -2855,9 +3064,9 @@ function useAuthPrimitives() {
2855
3064
  }
2856
3065
 
2857
3066
  // src/hooks/useAuth.ts
2858
- import { useHook as useHook14 } from "@hook-sdk/sdk";
3067
+ import { useHook as useHook15 } from "@hook-sdk/sdk";
2859
3068
  function useAuth() {
2860
- const { user, authStatus, auth } = useHook14();
3069
+ const { user, authStatus, auth } = useHook15();
2861
3070
  return {
2862
3071
  user,
2863
3072
  authStatus,
@@ -2869,23 +3078,23 @@ function useAuth() {
2869
3078
  import { useTrackOnboardingStep } from "@hook-sdk/sdk";
2870
3079
 
2871
3080
  // src/hooks/useSubscription.ts
2872
- import { useHook as useHook15 } from "@hook-sdk/sdk";
3081
+ import { useHook as useHook16 } from "@hook-sdk/sdk";
2873
3082
  function useSubscription() {
2874
- const { subscription } = useHook15();
3083
+ const { subscription } = useHook16();
2875
3084
  return {
2876
3085
  status: subscription.status()
2877
3086
  };
2878
3087
  }
2879
3088
 
2880
3089
  // src/hooks/useReminders.ts
2881
- import { useCallback as useCallback9, useEffect as useEffect12, useState as useState11 } from "react";
2882
- import { useHook as useHook16 } from "@hook-sdk/sdk";
3090
+ import { useCallback as useCallback10, useEffect as useEffect12, useState as useState12 } from "react";
3091
+ import { useHook as useHook17 } from "@hook-sdk/sdk";
2883
3092
  function useReminders() {
2884
- const { push } = useHook16();
3093
+ const { push } = useHook17();
2885
3094
  const r = push.reminders;
2886
- const [reminders, setReminders] = useState11([]);
2887
- const [loading, setLoading] = useState11(true);
2888
- const reload = useCallback9(async () => {
3095
+ const [reminders, setReminders] = useState12([]);
3096
+ const [loading, setLoading] = useState12(true);
3097
+ const reload = useCallback10(async () => {
2889
3098
  setLoading(true);
2890
3099
  try {
2891
3100
  const next = await r.list();
@@ -2897,35 +3106,35 @@ function useReminders() {
2897
3106
  useEffect12(() => {
2898
3107
  void reload();
2899
3108
  }, [reload]);
2900
- const setReminder = useCallback9(async (input) => {
3109
+ const setReminder = useCallback10(async (input) => {
2901
3110
  await r.set(input);
2902
3111
  await reload();
2903
3112
  }, [r, reload]);
2904
- const deleteReminder = useCallback9(async (slot) => {
3113
+ const deleteReminder = useCallback10(async (slot) => {
2905
3114
  await r.delete(slot);
2906
3115
  await reload();
2907
3116
  }, [r, reload]);
2908
- const schedule = useCallback9(async (items) => {
3117
+ const schedule = useCallback10(async (items) => {
2909
3118
  return r.schedule(items);
2910
3119
  }, [r]);
2911
- const setFallbacks = useCallback9(async (items) => {
3120
+ const setFallbacks = useCallback10(async (items) => {
2912
3121
  return r.setFallbacks(items);
2913
3122
  }, [r]);
2914
3123
  return { reminders, loading, setReminder, deleteReminder, schedule, setFallbacks };
2915
3124
  }
2916
3125
 
2917
3126
  // src/hooks/useToast.ts
2918
- import { useCallback as useCallback10, useState as useState12 } from "react";
3127
+ import { useCallback as useCallback11, useState as useState13 } from "react";
2919
3128
  function useToast() {
2920
- const [items, setItems] = useState12([]);
2921
- const show = useCallback10((message, kind = "info") => {
3129
+ const [items, setItems] = useState13([]);
3130
+ const show = useCallback11((message, kind = "info") => {
2922
3131
  const id = `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
2923
3132
  setItems((prev) => [...prev, { id, message, kind }]);
2924
3133
  setTimeout(() => {
2925
3134
  setItems((prev) => prev.filter((t) => t.id !== id));
2926
3135
  }, 4e3);
2927
3136
  }, []);
2928
- const dismiss = useCallback10((id) => {
3137
+ const dismiss = useCallback11((id) => {
2929
3138
  setItems((prev) => prev.filter((t) => t.id !== id));
2930
3139
  }, []);
2931
3140
  return { items, show, dismiss };
@@ -2933,20 +3142,20 @@ function useToast() {
2933
3142
 
2934
3143
  // src/RouteBoundary.tsx
2935
3144
  import { Routes as Routes2, Route as Route2 } from "react-router-dom";
2936
- import { jsx as jsx26, jsxs as jsxs18 } from "react/jsx-runtime";
3145
+ import { jsx as jsx27, jsxs as jsxs18 } from "react/jsx-runtime";
2937
3146
  function RouteBoundary({ children }) {
2938
3147
  return /* @__PURE__ */ jsxs18(Routes2, { children: [
2939
3148
  children,
2940
- /* @__PURE__ */ jsx26(Route2, { path: "*", element: /* @__PURE__ */ jsx26(DefaultNotFound, {}) })
3149
+ /* @__PURE__ */ jsx27(Route2, { path: "*", element: /* @__PURE__ */ jsx27(DefaultNotFound, {}) })
2941
3150
  ] });
2942
3151
  }
2943
3152
  function DefaultNotFound() {
2944
- return /* @__PURE__ */ jsx26("div", { role: "alert", children: "P\xE1gina n\xE3o encontrada" });
3153
+ return /* @__PURE__ */ jsx27("div", { role: "alert", children: "P\xE1gina n\xE3o encontrada" });
2945
3154
  }
2946
3155
 
2947
3156
  // src/PreAuthShell.tsx
2948
3157
  import { BrowserRouter as BrowserRouter2, MemoryRouter as MemoryRouter2, Routes as Routes3 } from "react-router-dom";
2949
- import { jsx as jsx27 } from "react/jsx-runtime";
3158
+ import { jsx as jsx28 } from "react/jsx-runtime";
2950
3159
  function PreAuthShell({
2951
3160
  basename,
2952
3161
  testRouter,
@@ -2954,14 +3163,14 @@ function PreAuthShell({
2954
3163
  children
2955
3164
  }) {
2956
3165
  if (testRouter === "memory") {
2957
- return /* @__PURE__ */ jsx27(MemoryRouter2, { basename, initialEntries: testInitialEntries, children: /* @__PURE__ */ jsx27(Routes3, { children }) });
3166
+ return /* @__PURE__ */ jsx28(MemoryRouter2, { basename, initialEntries: testInitialEntries, children: /* @__PURE__ */ jsx28(Routes3, { children }) });
2958
3167
  }
2959
- return /* @__PURE__ */ jsx27(BrowserRouter2, { basename, children: /* @__PURE__ */ jsx27(Routes3, { children }) });
3168
+ return /* @__PURE__ */ jsx28(BrowserRouter2, { basename, children: /* @__PURE__ */ jsx28(Routes3, { children }) });
2960
3169
  }
2961
3170
 
2962
3171
  // src/OnboardingFlow.tsx
2963
- import { useCallback as useCallback11, useEffect as useEffect13, useMemo as useMemo8, useRef as useRef5 } from "react";
2964
- import { usePersistedState as usePersistedState3, useHook as useHook17 } from "@hook-sdk/sdk";
3172
+ import { useCallback as useCallback12, useEffect as useEffect13, useMemo as useMemo8, useRef as useRef6 } from "react";
3173
+ import { usePersistedState as usePersistedState3, useHook as useHook18 } from "@hook-sdk/sdk";
2965
3174
 
2966
3175
  // src/hooks/useOnboardingStep.ts
2967
3176
  import { createContext as createContext3, useContext as useContext4 } from "react";
@@ -2977,7 +3186,7 @@ function useOnboardingStep() {
2977
3186
  }
2978
3187
 
2979
3188
  // src/OnboardingFlow.tsx
2980
- import { jsx as jsx28 } from "react/jsx-runtime";
3189
+ import { jsx as jsx29 } from "react/jsx-runtime";
2981
3190
  var isFilled = (v) => v != null && v !== "";
2982
3191
  var CURRENT_STEP_FIELD = "currentStep";
2983
3192
  function readPersistedStepIdx(draft) {
@@ -2991,11 +3200,11 @@ function OnboardingFlow({
2991
3200
  persistKey
2992
3201
  }) {
2993
3202
  const [draft, setDraft, status] = usePersistedState3(persistKey, {});
2994
- const draftRef = useRef5(draft);
3203
+ const draftRef = useRef6(draft);
2995
3204
  draftRef.current = draft;
2996
3205
  const idx = readPersistedStepIdx(draft);
2997
3206
  const clampedIdx = Math.min(Math.max(idx, 0), Math.max(steps.length - 1, 0));
2998
- const setIdx = useCallback11(
3207
+ const setIdx = useCallback12(
2999
3208
  (n) => {
3000
3209
  setDraft((prev) => {
3001
3210
  const prevIdx = readPersistedStepIdx(prev);
@@ -3005,7 +3214,7 @@ function OnboardingFlow({
3005
3214
  },
3006
3215
  [setDraft]
3007
3216
  );
3008
- const setValue = useCallback11(
3217
+ const setValue = useCallback12(
3009
3218
  (patch) => {
3010
3219
  draftRef.current = { ...draftRef.current, ...patch };
3011
3220
  setDraft((prev) => ({ ...prev, ...patch }));
@@ -3013,7 +3222,7 @@ function OnboardingFlow({
3013
3222
  [setDraft]
3014
3223
  );
3015
3224
  const step = steps[clampedIdx];
3016
- const hookCtx = useHook17();
3225
+ const hookCtx = useHook18();
3017
3226
  const track2 = typeof hookCtx.track === "function" ? hookCtx.track : void 0;
3018
3227
  useEffect13(() => {
3019
3228
  if (status.loading) return;
@@ -3029,7 +3238,7 @@ function OnboardingFlow({
3029
3238
  () => step ? (step.validates ?? []).every((field) => isFilled(draft[field])) : false,
3030
3239
  [draft, step]
3031
3240
  );
3032
- const next = useCallback11(() => {
3241
+ const next = useCallback12(() => {
3033
3242
  if (!step) return;
3034
3243
  const current = draftRef.current;
3035
3244
  const validNow = (step.validates ?? []).every((field) => isFilled(current[field]));
@@ -3040,7 +3249,7 @@ function OnboardingFlow({
3040
3249
  setIdx(clampedIdx + 1);
3041
3250
  }
3042
3251
  }, [clampedIdx, onComplete, step, steps.length, setIdx]);
3043
- const prevStep = useCallback11(() => setIdx((i) => Math.max(0, i - 1)), [setIdx]);
3252
+ const prevStep = useCallback12(() => setIdx((i) => Math.max(0, i - 1)), [setIdx]);
3044
3253
  const ctx = useMemo8(
3045
3254
  () => ({
3046
3255
  stepIndex: clampedIdx,
@@ -3067,7 +3276,7 @@ function OnboardingFlow({
3067
3276
  `[hook-template] OnboardingFlow: missing screen component for step '${step.id}' (expected key '${step.screen}' in screens prop)`
3068
3277
  );
3069
3278
  }
3070
- return /* @__PURE__ */ jsx28(OnboardingStepContext.Provider, { value: ctx, children: /* @__PURE__ */ jsx28(Screen, {}) });
3279
+ return /* @__PURE__ */ jsx29(OnboardingStepContext.Provider, { value: ctx, children: /* @__PURE__ */ jsx29(Screen, {}) });
3071
3280
  }
3072
3281
 
3073
3282
  // src/hooks/useFeature.ts
@@ -3075,11 +3284,298 @@ function useFeature(name) {
3075
3284
  const config = useAppConfig();
3076
3285
  return Array.isArray(config.features_enabled) && config.features_enabled.includes(name);
3077
3286
  }
3287
+
3288
+ // src/components/paywall/Paywall.tsx
3289
+ import { useEffect as useEffect14, useMemo as useMemo9 } from "react";
3290
+ import { useHook as useHook19 } from "@hook-sdk/sdk";
3291
+
3292
+ // src/components/paywall/PaywallMethodTabs.tsx
3293
+ import { jsx as jsx30 } from "react/jsx-runtime";
3294
+ function PaywallMethodTabs({
3295
+ methods,
3296
+ selected,
3297
+ onSelect,
3298
+ labels,
3299
+ className,
3300
+ tabClassName,
3301
+ tabActiveClassName
3302
+ }) {
3303
+ if (methods.length < 2) return null;
3304
+ return /* @__PURE__ */ jsx30("div", { role: "tablist", "aria-label": "M\xE9todo de pagamento", className, children: methods.map((m) => {
3305
+ const active = m === selected;
3306
+ const label = labels[m] ?? m;
3307
+ return /* @__PURE__ */ jsx30(
3308
+ "button",
3309
+ {
3310
+ type: "button",
3311
+ role: "tab",
3312
+ "aria-selected": active,
3313
+ "aria-controls": `paywall-tab-${m}`,
3314
+ tabIndex: active ? 0 : -1,
3315
+ onClick: () => onSelect(m),
3316
+ className: [tabClassName, active ? tabActiveClassName : ""].filter(Boolean).join(" "),
3317
+ children: label
3318
+ },
3319
+ m
3320
+ );
3321
+ }) });
3322
+ }
3323
+
3324
+ // src/components/paywall/PaywallMethodContent.tsx
3325
+ import { jsx as jsx31 } from "react/jsx-runtime";
3326
+ function PaywallMethodContent({
3327
+ method,
3328
+ copy,
3329
+ hasConsumedTrial = false,
3330
+ className,
3331
+ rowClassName
3332
+ }) {
3333
+ const useCardConsumed = method === "card" && hasConsumedTrial && copy.cardConsumedTrial;
3334
+ const rows = useCardConsumed ? copy.cardConsumedTrial.bodyRows : method === "pix-auto" || method === "pix-once" ? copy.pix.bodyRows : copy.card.bodyRows;
3335
+ return /* @__PURE__ */ jsx31("div", { role: "tabpanel", id: `paywall-tab-${method}`, className, children: rows.map((row, i) => /* @__PURE__ */ jsx31("div", { className: rowClassName, children: row }, i)) });
3336
+ }
3337
+
3338
+ // src/components/paywall/PaywallCyclePicker.tsx
3339
+ import { jsx as jsx32, jsxs as jsxs19 } from "react/jsx-runtime";
3340
+ function PaywallCyclePicker({
3341
+ cycles,
3342
+ selected,
3343
+ onSelect,
3344
+ priceCentsByCycle,
3345
+ anchorCentsByCycle,
3346
+ monthlyEquivByCycle,
3347
+ labels,
3348
+ className,
3349
+ cardClassName,
3350
+ cardSelectedClassName,
3351
+ anchorClassName
3352
+ }) {
3353
+ if (cycles.length < 2) return null;
3354
+ return /* @__PURE__ */ jsx32("div", { role: "radiogroup", "aria-label": "Ciclo de cobran\xE7a", className, children: cycles.map((c) => {
3355
+ const active = c === selected;
3356
+ const label = c === "YEARLY" ? labels.annualLabel : labels.monthlyLabel;
3357
+ const suffix = c === "YEARLY" ? labels.annualSuffix : labels.monthlySuffix;
3358
+ const mainCents = c === "YEARLY" ? monthlyEquivByCycle[c] : priceCentsByCycle[c];
3359
+ const anchorCents = anchorCentsByCycle[c];
3360
+ return /* @__PURE__ */ jsxs19(
3361
+ "button",
3362
+ {
3363
+ type: "button",
3364
+ role: "radio",
3365
+ "aria-checked": active,
3366
+ onClick: () => onSelect(c),
3367
+ className: [cardClassName, active ? cardSelectedClassName : ""].filter(Boolean).join(" "),
3368
+ children: [
3369
+ /* @__PURE__ */ jsx32("strong", { children: formatBRL(mainCents) }),
3370
+ /* @__PURE__ */ jsx32("span", { children: suffix }),
3371
+ /* @__PURE__ */ jsx32("span", { children: label }),
3372
+ anchorCents != null && anchorCents > mainCents ? /* @__PURE__ */ jsx32("span", { className: anchorClassName, children: /* @__PURE__ */ jsx32("s", { children: formatBRL(anchorCents) }) }) : null
3373
+ ]
3374
+ },
3375
+ c
3376
+ );
3377
+ }) });
3378
+ }
3379
+
3380
+ // src/components/paywall/PaywallCta.tsx
3381
+ import { jsx as jsx33, jsxs as jsxs20 } from "react/jsx-runtime";
3382
+ function PaywallCta({
3383
+ ctaLabel,
3384
+ loadingLabel,
3385
+ switchHint,
3386
+ trustLine,
3387
+ onClick,
3388
+ disabled = false,
3389
+ loading = false,
3390
+ className,
3391
+ buttonClassName,
3392
+ switchHintClassName,
3393
+ trustClassName
3394
+ }) {
3395
+ const label = loading && loadingLabel ? loadingLabel : ctaLabel;
3396
+ return /* @__PURE__ */ jsxs20("div", { className, children: [
3397
+ /* @__PURE__ */ jsx33(
3398
+ "button",
3399
+ {
3400
+ type: "button",
3401
+ onClick,
3402
+ disabled: disabled || loading,
3403
+ className: buttonClassName,
3404
+ children: label
3405
+ }
3406
+ ),
3407
+ switchHint ? /* @__PURE__ */ jsx33("p", { className: switchHintClassName, children: switchHint }) : null,
3408
+ /* @__PURE__ */ jsx33("p", { className: trustClassName, children: trustLine })
3409
+ ] });
3410
+ }
3411
+
3412
+ // src/components/paywall/Paywall.tsx
3413
+ import { jsx as jsx34, jsxs as jsxs21 } from "react/jsx-runtime";
3414
+ var NBSP = "\xA0";
3415
+ function Paywall({
3416
+ copy,
3417
+ themeClasses = {},
3418
+ slots = {},
3419
+ onBeforeCheckout
3420
+ }) {
3421
+ const { track: track2 } = useHook19();
3422
+ const s = usePaywallState();
3423
+ const priceLabel = formatBRL(s.currentPriceCents).replace(new RegExp(NBSP, "g"), " ");
3424
+ const monthlyEquivLabel = formatBRL(s.currentMonthlyEquivCents).replace(new RegExp(NBSP, "g"), " ");
3425
+ const trialDaysCardLabel = String(s.trialDaysCard);
3426
+ const ctaLabel = useMemo9(() => {
3427
+ if (s.isFree) return copy.freeCta ?? "Come\xE7ar agora";
3428
+ if (s.selectedMethod === "card") {
3429
+ if (s.hasConsumedTrial && copy.cardConsumedTrial) {
3430
+ return interp(copy.cardConsumedTrial.ctaTemplate, { price: priceLabel, days: trialDaysCardLabel });
3431
+ }
3432
+ if (s.trialDaysCard > 0) {
3433
+ return interp(copy.card.ctaTemplate, { price: priceLabel, days: trialDaysCardLabel });
3434
+ }
3435
+ return copy.cardConsumedTrial ? interp(copy.cardConsumedTrial.ctaTemplate, { price: priceLabel, days: trialDaysCardLabel }) : `Assinar por ${priceLabel}`;
3436
+ }
3437
+ return interp(copy.pix.ctaTemplate, { price: priceLabel, days: trialDaysCardLabel });
3438
+ }, [
3439
+ s.isFree,
3440
+ s.selectedMethod,
3441
+ s.hasConsumedTrial,
3442
+ s.trialDaysCard,
3443
+ copy,
3444
+ priceLabel,
3445
+ trialDaysCardLabel
3446
+ ]);
3447
+ const switchHint = useMemo9(() => {
3448
+ if (s.methods.length < 2) return void 0;
3449
+ return s.selectedMethod === "card" ? copy.card.switchHint : copy.pix.switchHint;
3450
+ }, [s.methods.length, s.selectedMethod, copy]);
3451
+ useEffect14(() => {
3452
+ if (!s.initialLoadComplete) return;
3453
+ track2("paywall_view", {
3454
+ default_method: s.selectedMethod,
3455
+ default_cycle: s.cycle,
3456
+ available_methods: s.methods
3457
+ });
3458
+ }, [s.initialLoadComplete]);
3459
+ const handleCta = async () => {
3460
+ track2("paywall_cta_clicked", {
3461
+ method: s.selectedMethod,
3462
+ cycle: s.cycle,
3463
+ price_cents: s.currentPriceCents,
3464
+ had_consumed_trial: s.hasConsumedTrial
3465
+ });
3466
+ if (onBeforeCheckout) {
3467
+ await onBeforeCheckout(s.selectedMethod, s.cycle);
3468
+ return;
3469
+ }
3470
+ await s.submit();
3471
+ };
3472
+ const ctaTheme = s.selectedMethod === "card" ? themeClasses.ctaCard : themeClasses.ctaPix;
3473
+ return /* @__PURE__ */ jsxs21("div", { className: themeClasses.container, children: [
3474
+ slots.heroSlot,
3475
+ /* @__PURE__ */ jsx34("h1", { className: themeClasses.headline, children: copy.headline }),
3476
+ /* @__PURE__ */ jsx34("ul", { children: copy.features.map((f) => /* @__PURE__ */ jsxs21("li", { className: themeClasses.feature, children: [
3477
+ "\u2713 ",
3478
+ /* @__PURE__ */ jsx34("span", { children: f })
3479
+ ] }, f)) }),
3480
+ copy.socialProof ? /* @__PURE__ */ jsx34("p", { className: themeClasses.socialProof, children: copy.socialProof }) : null,
3481
+ slots.cyclePickerSlot ?? /* @__PURE__ */ jsx34(
3482
+ PaywallCyclePicker,
3483
+ {
3484
+ cycles: ["MONTHLY", "YEARLY"],
3485
+ selected: s.cycle,
3486
+ onSelect: s.selectCycle,
3487
+ priceCentsByCycle: {
3488
+ MONTHLY: priceCentsForCycle(s, "MONTHLY"),
3489
+ YEARLY: priceCentsForCycle(s, "YEARLY")
3490
+ },
3491
+ anchorCentsByCycle: {
3492
+ MONTHLY: anchorForCycle(s, "MONTHLY"),
3493
+ YEARLY: anchorForCycle(s, "YEARLY")
3494
+ },
3495
+ monthlyEquivByCycle: {
3496
+ MONTHLY: priceCentsForCycle(s, "MONTHLY"),
3497
+ YEARLY: Math.round(priceCentsForCycle(s, "YEARLY") / 12)
3498
+ },
3499
+ labels: copy.cycle,
3500
+ cardClassName: themeClasses.cycleCard,
3501
+ cardSelectedClassName: themeClasses.cycleCardSelected,
3502
+ anchorClassName: themeClasses.anchorPrice
3503
+ }
3504
+ ),
3505
+ /* @__PURE__ */ jsx34(
3506
+ PaywallMethodTabs,
3507
+ {
3508
+ methods: s.methods,
3509
+ selected: s.selectedMethod,
3510
+ onSelect: s.selectMethod,
3511
+ labels: { "pix-auto": copy.pix.tabLabel, card: copy.card.tabLabel },
3512
+ className: themeClasses.tabs,
3513
+ tabClassName: themeClasses.tab,
3514
+ tabActiveClassName: themeClasses.tabActive
3515
+ }
3516
+ ),
3517
+ /* @__PURE__ */ jsx34(
3518
+ PaywallMethodContent,
3519
+ {
3520
+ method: s.selectedMethod,
3521
+ copy: {
3522
+ pix: interpolateCopy(copy.pix, priceLabel, trialDaysCardLabel),
3523
+ card: interpolateCopy(copy.card, priceLabel, trialDaysCardLabel),
3524
+ cardConsumedTrial: copy.cardConsumedTrial ? {
3525
+ bodyRows: copy.cardConsumedTrial.bodyRows.map(
3526
+ (r) => interp(r, { price: priceLabel, days: trialDaysCardLabel })
3527
+ ),
3528
+ ctaTemplate: copy.cardConsumedTrial.ctaTemplate
3529
+ } : void 0
3530
+ },
3531
+ hasConsumedTrial: s.hasConsumedTrial,
3532
+ className: themeClasses.tabContent,
3533
+ rowClassName: themeClasses.tabContentRow
3534
+ }
3535
+ ),
3536
+ slots.beforeCtaSlot,
3537
+ /* @__PURE__ */ jsx34(
3538
+ PaywallCta,
3539
+ {
3540
+ ctaLabel,
3541
+ loadingLabel: "Abrindo checkout\u2026",
3542
+ switchHint,
3543
+ trustLine: copy.trustLine,
3544
+ onClick: handleCta,
3545
+ disabled: !s.initialLoadComplete,
3546
+ loading: s.submitting,
3547
+ buttonClassName: ctaTheme,
3548
+ switchHintClassName: themeClasses.switchHint,
3549
+ trustClassName: themeClasses.trustLine
3550
+ }
3551
+ )
3552
+ ] });
3553
+ }
3554
+ function interp(tpl, vars) {
3555
+ return tpl.replace(/\{(\w+)\}/g, (_m, k) => vars[k] ?? "");
3556
+ }
3557
+ function interpolateCopy(m, price, days) {
3558
+ return {
3559
+ tabLabel: m.tabLabel,
3560
+ bodyRows: m.bodyRows.map((r) => interp(r, { price, days })),
3561
+ ctaTemplate: m.ctaTemplate,
3562
+ switchHint: m.switchHint
3563
+ };
3564
+ }
3565
+ function priceCentsForCycle(s, c) {
3566
+ return s.plan ? c === "YEARLY" ? s.plan.yearlyCents ?? 0 : s.plan.monthlyCents : 0;
3567
+ }
3568
+ function anchorForCycle(s, c) {
3569
+ if (!s.plan) return null;
3570
+ if (c === "YEARLY") return s.plan.anchorYearlyCents ?? null;
3571
+ return s.plan.anchorMonthlyCents ?? null;
3572
+ }
3078
3573
  export {
3079
3574
  AppConfigProvider,
3080
3575
  AppConfigSchema,
3081
3576
  AppRoot,
3082
3577
  DeepLinkHandler,
3578
+ DevSkipOnboardingFab,
3083
3579
  EmptyState,
3084
3580
  ErrorBoundary,
3085
3581
  I18nProvider,
@@ -3089,6 +3585,11 @@ export {
3089
3585
  LoadingState,
3090
3586
  OnboardingFlow,
3091
3587
  PaymentReturnHandler,
3588
+ Paywall,
3589
+ PaywallCta,
3590
+ PaywallCyclePicker,
3591
+ PaywallMethodContent,
3592
+ PaywallMethodTabs,
3092
3593
  PersistenceRegistry,
3093
3594
  PreAuthShell,
3094
3595
  PushPrompt2 as PushPrompt,
@@ -3103,10 +3604,12 @@ export {
3103
3604
  detectStandalone,
3104
3605
  discountPercent,
3105
3606
  formatBRL,
3607
+ isDevToolsEnabled,
3106
3608
  monthlyFromYearly,
3107
3609
  parseAppConfig,
3108
3610
  shouldBlockInstall,
3109
3611
  shouldShowPermanentOption,
3612
+ skipOnboarding,
3110
3613
  useAppConfig,
3111
3614
  useAuth,
3112
3615
  useAuthPrimitives,