@hook-sdk/template 0.20.0 → 0.22.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 +714 -202
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +242 -2
- package/dist/index.d.ts +242 -2
- package/dist/index.js +666 -163
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -34,6 +34,7 @@ __export(index_exports, {
|
|
|
34
34
|
AppConfigSchema: () => AppConfigSchema,
|
|
35
35
|
AppRoot: () => AppRoot,
|
|
36
36
|
DeepLinkHandler: () => DeepLinkHandler,
|
|
37
|
+
DevSkipOnboardingFab: () => DevSkipOnboardingFab,
|
|
37
38
|
EmptyState: () => EmptyState,
|
|
38
39
|
ErrorBoundary: () => ErrorBoundary,
|
|
39
40
|
I18nProvider: () => I18nProvider,
|
|
@@ -43,6 +44,11 @@ __export(index_exports, {
|
|
|
43
44
|
LoadingState: () => LoadingState,
|
|
44
45
|
OnboardingFlow: () => OnboardingFlow,
|
|
45
46
|
PaymentReturnHandler: () => PaymentReturnHandler,
|
|
47
|
+
Paywall: () => Paywall,
|
|
48
|
+
PaywallCta: () => PaywallCta,
|
|
49
|
+
PaywallCyclePicker: () => PaywallCyclePicker,
|
|
50
|
+
PaywallMethodContent: () => PaywallMethodContent,
|
|
51
|
+
PaywallMethodTabs: () => PaywallMethodTabs,
|
|
46
52
|
PersistenceRegistry: () => PersistenceRegistry,
|
|
47
53
|
PreAuthShell: () => PreAuthShell,
|
|
48
54
|
PushPrompt: () => PushPrompt2,
|
|
@@ -57,10 +63,12 @@ __export(index_exports, {
|
|
|
57
63
|
detectStandalone: () => detectStandalone,
|
|
58
64
|
discountPercent: () => discountPercent,
|
|
59
65
|
formatBRL: () => formatBRL,
|
|
66
|
+
isDevToolsEnabled: () => isDevToolsEnabled,
|
|
60
67
|
monthlyFromYearly: () => monthlyFromYearly,
|
|
61
68
|
parseAppConfig: () => parseAppConfig,
|
|
62
69
|
shouldBlockInstall: () => shouldBlockInstall,
|
|
63
70
|
shouldShowPermanentOption: () => shouldShowPermanentOption,
|
|
71
|
+
skipOnboarding: () => skipOnboarding,
|
|
64
72
|
useAppConfig: () => useAppConfig,
|
|
65
73
|
useAuth: () => useAuth,
|
|
66
74
|
useAuthPrimitives: () => useAuthPrimitives,
|
|
@@ -77,14 +85,14 @@ __export(index_exports, {
|
|
|
77
85
|
useSignupForm: () => useSignupForm,
|
|
78
86
|
useSubscription: () => useSubscription,
|
|
79
87
|
useToast: () => useToast,
|
|
80
|
-
useTrackOnboardingStep: () =>
|
|
88
|
+
useTrackOnboardingStep: () => import_sdk23.useTrackOnboardingStep
|
|
81
89
|
});
|
|
82
90
|
module.exports = __toCommonJS(index_exports);
|
|
83
91
|
|
|
84
92
|
// src/AppRoot.tsx
|
|
85
|
-
var
|
|
93
|
+
var import_react15 = require("react");
|
|
86
94
|
var import_react_router_dom2 = require("react-router-dom");
|
|
87
|
-
var
|
|
95
|
+
var import_sdk8 = require("@hook-sdk/sdk");
|
|
88
96
|
|
|
89
97
|
// src/config/AppConfigContext.tsx
|
|
90
98
|
var import_react = require("react");
|
|
@@ -118,7 +126,16 @@ var AuthFlowSchema = import_zod.z.object({
|
|
|
118
126
|
});
|
|
119
127
|
var PaywallNonFreeSchema = import_zod.z.object({
|
|
120
128
|
mode: import_zod.z.enum(["trial", "pay_first"]),
|
|
129
|
+
// Legacy flat trial — fallback when per-method fields aren't set.
|
|
121
130
|
trialDays: import_zod.z.number().int().nonnegative().optional(),
|
|
131
|
+
// Per-method trial (ADR-022 Amendment 2026-05-12 + G154). PIX Auto can't
|
|
132
|
+
// offer trial on Asaas today (Jornada 2 unavailable), so apps that mix
|
|
133
|
+
// methods must split the value to avoid bait-and-switch on PIX shoppers.
|
|
134
|
+
trialDaysCard: import_zod.z.number().int().nonnegative().optional(),
|
|
135
|
+
trialDaysPix: import_zod.z.number().int().nonnegative().optional(),
|
|
136
|
+
// Which method the paywall preselects. null/undefined = no preselection
|
|
137
|
+
// (user picks). Per-app override reflects audience, not Hook bias.
|
|
138
|
+
defaultMethod: import_zod.z.enum(["card", "pix-auto", "pix-once"]).nullable().optional(),
|
|
122
139
|
cycles: import_zod.z.array(import_zod.z.enum(["MONTHLY", "YEARLY"])).min(1),
|
|
123
140
|
prices: import_zod.z.object({
|
|
124
141
|
monthlyCents: import_zod.z.number().int().nonnegative(),
|
|
@@ -369,10 +386,11 @@ function usePaywallState() {
|
|
|
369
386
|
() => declaredMethods.filter((m) => isMethodAvailable(availability, m)),
|
|
370
387
|
[declaredMethods, availability]
|
|
371
388
|
);
|
|
372
|
-
const
|
|
389
|
+
const configDefault = !isFree && "defaultMethod" in paywall ? paywall.defaultMethod ?? null : null;
|
|
390
|
+
const defaultMethod = (configDefault && methods.includes(configDefault) ? configDefault : null) ?? methods[0] ?? declaredMethods[0] ?? "card";
|
|
373
391
|
const [selectedMethodRaw, setSelectedMethod] = (0, import_react6.useState)(defaultMethod);
|
|
374
392
|
const selectedMethod = methods.includes(selectedMethodRaw) ? selectedMethodRaw : methods[0] ?? selectedMethodRaw;
|
|
375
|
-
const initialCycle = isFree ? "MONTHLY" : paywall.cycles[0] ?? "MONTHLY";
|
|
393
|
+
const initialCycle = isFree ? "MONTHLY" : paywall.cycles.includes("YEARLY") ? "YEARLY" : paywall.cycles[0] ?? "MONTHLY";
|
|
376
394
|
const [cycle, setCycle] = (0, import_react6.useState)(initialCycle);
|
|
377
395
|
const cpfRequired = !isFree && paywall.requiresCpf;
|
|
378
396
|
const [cpf, setCpf] = (0, import_react6.useState)("");
|
|
@@ -390,6 +408,22 @@ function usePaywallState() {
|
|
|
390
408
|
const [submitting, setSubmitting] = (0, import_react6.useState)(false);
|
|
391
409
|
const status = subscription.status();
|
|
392
410
|
const daysLeftInTrial = subscription.daysLeftInTrial();
|
|
411
|
+
const trialDaysForMethod = (0, import_react6.useCallback)(
|
|
412
|
+
(method) => {
|
|
413
|
+
if (isFree) return 0;
|
|
414
|
+
if (method === "card") {
|
|
415
|
+
if (typeof paywall.trialDaysCard === "number") return paywall.trialDaysCard;
|
|
416
|
+
if (typeof paywall.trialDays === "number") return paywall.trialDays;
|
|
417
|
+
return 7;
|
|
418
|
+
}
|
|
419
|
+
if (typeof paywall.trialDaysPix === "number") return paywall.trialDaysPix;
|
|
420
|
+
if (typeof paywall.trialDays === "number") return paywall.trialDays;
|
|
421
|
+
return 0;
|
|
422
|
+
},
|
|
423
|
+
[isFree, paywall]
|
|
424
|
+
);
|
|
425
|
+
const trialDaysCard = trialDaysForMethod("card");
|
|
426
|
+
const trialDaysPix = trialDaysForMethod("pix-auto");
|
|
393
427
|
const initialLoadComplete = subscription.initialLoadComplete;
|
|
394
428
|
const hasAccess = subscription.hasAccess;
|
|
395
429
|
const pixPending = (0, import_react6.useMemo)(() => {
|
|
@@ -429,6 +463,40 @@ function usePaywallState() {
|
|
|
429
463
|
discountPercent: discount
|
|
430
464
|
};
|
|
431
465
|
}, [paywall, cycle, isFree]);
|
|
466
|
+
const hasConsumedTrial = (0, import_react6.useMemo)(() => {
|
|
467
|
+
return ["active", "trialing", "past_due", "canceled", "expired"].includes(status);
|
|
468
|
+
}, [status]);
|
|
469
|
+
const currentPriceCents = (0, import_react6.useMemo)(() => {
|
|
470
|
+
if (isFree) return 0;
|
|
471
|
+
return cycle === "YEARLY" ? paywall.prices.yearlyCents : paywall.prices.monthlyCents;
|
|
472
|
+
}, [paywall, cycle, isFree]);
|
|
473
|
+
const currentMonthlyEquivCents = (0, import_react6.useMemo)(() => {
|
|
474
|
+
if (isFree) return 0;
|
|
475
|
+
if (cycle === "YEARLY") return Math.round(paywall.prices.yearlyCents / 12);
|
|
476
|
+
return paywall.prices.monthlyCents;
|
|
477
|
+
}, [paywall, cycle, isFree]);
|
|
478
|
+
const anchorPriceCents = (0, import_react6.useMemo)(() => {
|
|
479
|
+
if (isFree) return null;
|
|
480
|
+
const a = paywall.anchorPrices;
|
|
481
|
+
if (!a) return null;
|
|
482
|
+
return cycle === "YEARLY" ? a.yearlyCents : a.monthlyCents;
|
|
483
|
+
}, [paywall, cycle, isFree]);
|
|
484
|
+
const selectMethod = (0, import_react6.useCallback)(
|
|
485
|
+
(next) => {
|
|
486
|
+
if (next === selectedMethod) return;
|
|
487
|
+
track2("paywall_method_tab_clicked", { method: next, from_method: selectedMethod });
|
|
488
|
+
setSelectedMethod(next);
|
|
489
|
+
},
|
|
490
|
+
[selectedMethod, track2]
|
|
491
|
+
);
|
|
492
|
+
const selectCycle = (0, import_react6.useCallback)(
|
|
493
|
+
(next) => {
|
|
494
|
+
if (next === cycle) return;
|
|
495
|
+
track2("paywall_cycle_clicked", { cycle: next, from_cycle: cycle });
|
|
496
|
+
setCycle(next);
|
|
497
|
+
},
|
|
498
|
+
[cycle, track2]
|
|
499
|
+
);
|
|
432
500
|
const useDefaultMessages = paywall.mode !== "free" && paywall.errorMessages === "default";
|
|
433
501
|
const buildError = (0, import_react6.useCallback)(
|
|
434
502
|
(code, fallbackMessage) => ({
|
|
@@ -623,6 +691,20 @@ function usePaywallState() {
|
|
|
623
691
|
methods,
|
|
624
692
|
selectedMethod,
|
|
625
693
|
setSelectedMethod,
|
|
694
|
+
// Conversion-max derivations (template 0.21)
|
|
695
|
+
hasConsumedTrial,
|
|
696
|
+
currentPriceCents,
|
|
697
|
+
currentMonthlyEquivCents,
|
|
698
|
+
anchorPriceCents,
|
|
699
|
+
selectMethod,
|
|
700
|
+
selectCycle,
|
|
701
|
+
isFree,
|
|
702
|
+
// Per-method trial (ADR-022 Amendment 2026-05-12). Use these to render
|
|
703
|
+
// asymmetric copy per method card on the paywall — never a global
|
|
704
|
+
// "free trial!" headline when both methods are visible.
|
|
705
|
+
trialDaysForMethod,
|
|
706
|
+
trialDaysCard,
|
|
707
|
+
trialDaysPix,
|
|
626
708
|
// Form state
|
|
627
709
|
cpfState,
|
|
628
710
|
cardState,
|
|
@@ -654,13 +736,13 @@ var BLOCKING = /* @__PURE__ */ new Set([
|
|
|
654
736
|
"canceled",
|
|
655
737
|
"none"
|
|
656
738
|
]);
|
|
657
|
-
function SubscriptionGate({ Paywall, children }) {
|
|
739
|
+
function SubscriptionGate({ Paywall: Paywall2, children }) {
|
|
658
740
|
const { mode } = useTemplateConfig();
|
|
659
741
|
const { status, hasAccess, initialLoadComplete } = usePaywallState();
|
|
660
742
|
if (mode === "free") return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_jsx_runtime5.Fragment, { children });
|
|
661
743
|
if (!initialLoadComplete && status === "none") return null;
|
|
662
744
|
if (hasAccess === true && status !== "none") return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_jsx_runtime5.Fragment, { children });
|
|
663
|
-
if (BLOCKING.has(status)) return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
745
|
+
if (BLOCKING.has(status)) return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Paywall2, {});
|
|
664
746
|
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_jsx_runtime5.Fragment, { children });
|
|
665
747
|
}
|
|
666
748
|
|
|
@@ -2106,22 +2188,156 @@ function I18nProvider({
|
|
|
2106
2188
|
return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_react_i18next.I18nextProvider, { i18n: import_i18next.default, children });
|
|
2107
2189
|
}
|
|
2108
2190
|
|
|
2109
|
-
// src/
|
|
2191
|
+
// src/dev/env.ts
|
|
2192
|
+
var import_meta = {};
|
|
2193
|
+
function isDevToolsEnabled() {
|
|
2194
|
+
const meta = import_meta;
|
|
2195
|
+
if (meta.env?.VITE_HOOK_DEV_TOOLS !== "1") return false;
|
|
2196
|
+
if (typeof window === "undefined") return false;
|
|
2197
|
+
const host = window.location.hostname;
|
|
2198
|
+
return host.includes(".staging.") || host === "localhost" || host === "127.0.0.1";
|
|
2199
|
+
}
|
|
2200
|
+
|
|
2201
|
+
// src/dev/DevSkipOnboardingFab.tsx
|
|
2110
2202
|
var import_react13 = require("react");
|
|
2111
2203
|
var import_sdk6 = require("@hook-sdk/sdk");
|
|
2112
2204
|
var import_jsx_runtime20 = require("react/jsx-runtime");
|
|
2205
|
+
var STORAGE_KEY = "hook_dev_skip_email";
|
|
2206
|
+
var TEST_EMAIL_DOMAIN = "@hook.test";
|
|
2207
|
+
var TEST_PASSWORD = "SkipTest!2026";
|
|
2208
|
+
function makeEmail() {
|
|
2209
|
+
return `ryan+skip-${Date.now()}${TEST_EMAIL_DOMAIN}`;
|
|
2210
|
+
}
|
|
2211
|
+
async function ensureSignedIn(hook, maxAttempts = 3) {
|
|
2212
|
+
if (hook.authStatus === "authenticated") return null;
|
|
2213
|
+
let lastErr;
|
|
2214
|
+
for (let i = 0; i < maxAttempts; i += 1) {
|
|
2215
|
+
const email = makeEmail();
|
|
2216
|
+
try {
|
|
2217
|
+
await hook.auth.signup({ email, password: TEST_PASSWORD, name: "Ryan Test" });
|
|
2218
|
+
try {
|
|
2219
|
+
window.sessionStorage.setItem(STORAGE_KEY, email);
|
|
2220
|
+
} catch {
|
|
2221
|
+
}
|
|
2222
|
+
return email;
|
|
2223
|
+
} catch (err) {
|
|
2224
|
+
lastErr = err;
|
|
2225
|
+
await new Promise((r) => setTimeout(r, 30));
|
|
2226
|
+
}
|
|
2227
|
+
}
|
|
2228
|
+
throw lastErr ?? new Error("signup failed after retries");
|
|
2229
|
+
}
|
|
2230
|
+
async function skipOnboarding(hook, defaults, appSlug) {
|
|
2231
|
+
const { __seed, ...rest } = defaults;
|
|
2232
|
+
await ensureSignedIn(hook);
|
|
2233
|
+
await hook.appData.set("onboarding_data", {
|
|
2234
|
+
...rest,
|
|
2235
|
+
onboarding_completed: true
|
|
2236
|
+
});
|
|
2237
|
+
if (__seed) {
|
|
2238
|
+
await __seed(hook);
|
|
2239
|
+
}
|
|
2240
|
+
console.info("[hook-template] dev_skip_onboarding fired", {
|
|
2241
|
+
app_slug: appSlug,
|
|
2242
|
+
hostname: window.location.hostname
|
|
2243
|
+
});
|
|
2244
|
+
window.location.assign(`/app/${appSlug}/`);
|
|
2245
|
+
}
|
|
2246
|
+
var STYLES = {
|
|
2247
|
+
base: {
|
|
2248
|
+
position: "fixed",
|
|
2249
|
+
bottom: "16px",
|
|
2250
|
+
right: "16px",
|
|
2251
|
+
zIndex: 2147483647,
|
|
2252
|
+
padding: "10px 14px",
|
|
2253
|
+
borderRadius: "999px",
|
|
2254
|
+
border: "none",
|
|
2255
|
+
background: "#F59E0B",
|
|
2256
|
+
color: "#111827",
|
|
2257
|
+
fontWeight: 600,
|
|
2258
|
+
fontSize: "13px",
|
|
2259
|
+
fontFamily: "system-ui, -apple-system, sans-serif",
|
|
2260
|
+
boxShadow: "0 4px 14px rgba(0, 0, 0, 0.25)",
|
|
2261
|
+
cursor: "pointer",
|
|
2262
|
+
display: "flex",
|
|
2263
|
+
alignItems: "center",
|
|
2264
|
+
gap: "6px"
|
|
2265
|
+
},
|
|
2266
|
+
confirm: { background: "#DC2626", color: "#FFFFFF" },
|
|
2267
|
+
busy: { opacity: 0.6, cursor: "wait" }
|
|
2268
|
+
};
|
|
2269
|
+
var CONFIRM_TIMEOUT_MS = 3e3;
|
|
2270
|
+
function DevSkipOnboardingFab({ defaults }) {
|
|
2271
|
+
const hook = (0, import_sdk6.useHook)();
|
|
2272
|
+
const { slug } = useAppConfig();
|
|
2273
|
+
const [state, setState] = (0, import_react13.useState)("idle");
|
|
2274
|
+
const [errorMsg, setErrorMsg] = (0, import_react13.useState)(null);
|
|
2275
|
+
const timerRef = (0, import_react13.useRef)(null);
|
|
2276
|
+
const clearTimer = (0, import_react13.useCallback)(() => {
|
|
2277
|
+
if (timerRef.current) {
|
|
2278
|
+
clearTimeout(timerRef.current);
|
|
2279
|
+
timerRef.current = null;
|
|
2280
|
+
}
|
|
2281
|
+
}, []);
|
|
2282
|
+
const onClick = (0, import_react13.useCallback)(async () => {
|
|
2283
|
+
if (state === "busy") return;
|
|
2284
|
+
if (state === "idle" || state === "error") {
|
|
2285
|
+
setState("confirm");
|
|
2286
|
+
setErrorMsg(null);
|
|
2287
|
+
clearTimer();
|
|
2288
|
+
timerRef.current = setTimeout(() => setState("idle"), CONFIRM_TIMEOUT_MS);
|
|
2289
|
+
return;
|
|
2290
|
+
}
|
|
2291
|
+
clearTimer();
|
|
2292
|
+
setState("busy");
|
|
2293
|
+
try {
|
|
2294
|
+
await skipOnboarding(hook, defaults, slug);
|
|
2295
|
+
} catch (err) {
|
|
2296
|
+
setState("error");
|
|
2297
|
+
setErrorMsg(err instanceof Error ? err.message : String(err));
|
|
2298
|
+
}
|
|
2299
|
+
}, [state, hook, defaults, slug, clearTimer]);
|
|
2300
|
+
const label = (() => {
|
|
2301
|
+
if (state === "busy") return "skipping\u2026";
|
|
2302
|
+
if (state === "confirm") return "tap again to confirm";
|
|
2303
|
+
if (state === "error") return `failed \u2014 tap to retry`;
|
|
2304
|
+
return hook.authStatus === "authenticated" ? "\u26A1 skip onboarding" : "\u26A1 skip + signup";
|
|
2305
|
+
})();
|
|
2306
|
+
const style = {
|
|
2307
|
+
...STYLES.base,
|
|
2308
|
+
...state === "confirm" || state === "error" ? STYLES.confirm : {},
|
|
2309
|
+
...state === "busy" ? STYLES.busy : {}
|
|
2310
|
+
};
|
|
2311
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
2312
|
+
"button",
|
|
2313
|
+
{
|
|
2314
|
+
type: "button",
|
|
2315
|
+
"data-testid": "dev-skip-onboarding-fab",
|
|
2316
|
+
"aria-label": "Skip onboarding (staging dev only)",
|
|
2317
|
+
style,
|
|
2318
|
+
onClick,
|
|
2319
|
+
title: errorMsg ?? void 0,
|
|
2320
|
+
children: label
|
|
2321
|
+
}
|
|
2322
|
+
);
|
|
2323
|
+
}
|
|
2324
|
+
|
|
2325
|
+
// src/internal/PaymentReturnHandler.tsx
|
|
2326
|
+
var import_react14 = require("react");
|
|
2327
|
+
var import_sdk7 = require("@hook-sdk/sdk");
|
|
2328
|
+
var import_jsx_runtime21 = require("react/jsx-runtime");
|
|
2113
2329
|
var BACKOFF_MS = [2e3, 5e3, 1e4, 2e4, 4e4];
|
|
2114
2330
|
var MAX_CYCLES = 3;
|
|
2115
2331
|
var SUPPORT_MAILTO = "mailto:suporte@usehook.net?subject=Pagamento%20pendente";
|
|
2116
2332
|
function PaymentReturnHandler({ children }) {
|
|
2117
|
-
const { subscription, track: track2 } = (0,
|
|
2118
|
-
const subRef = (0,
|
|
2333
|
+
const { subscription, track: track2 } = (0, import_sdk7.useHook)();
|
|
2334
|
+
const subRef = (0, import_react14.useRef)(subscription);
|
|
2119
2335
|
subRef.current = subscription;
|
|
2120
|
-
const runIdRef = (0,
|
|
2121
|
-
const cyclesRef = (0,
|
|
2122
|
-
const startMsRef = (0,
|
|
2123
|
-
const [state, setState] = (0,
|
|
2124
|
-
const runPoll = (0,
|
|
2336
|
+
const runIdRef = (0, import_react14.useRef)(0);
|
|
2337
|
+
const cyclesRef = (0, import_react14.useRef)(0);
|
|
2338
|
+
const startMsRef = (0, import_react14.useRef)(0);
|
|
2339
|
+
const [state, setState] = (0, import_react14.useState)("idle");
|
|
2340
|
+
const runPoll = (0, import_react14.useCallback)(() => {
|
|
2125
2341
|
const runId = ++runIdRef.current;
|
|
2126
2342
|
const isFirstRun = cyclesRef.current === 0;
|
|
2127
2343
|
cyclesRef.current += 1;
|
|
@@ -2169,7 +2385,7 @@ function PaymentReturnHandler({ children }) {
|
|
|
2169
2385
|
};
|
|
2170
2386
|
void tick();
|
|
2171
2387
|
}, [track2]);
|
|
2172
|
-
(0,
|
|
2388
|
+
(0, import_react14.useEffect)(() => {
|
|
2173
2389
|
if (typeof window === "undefined") return;
|
|
2174
2390
|
const url = new URL(window.location.href);
|
|
2175
2391
|
if (url.searchParams.get("paymentReturn") !== "1") return;
|
|
@@ -2179,26 +2395,26 @@ function PaymentReturnHandler({ children }) {
|
|
|
2179
2395
|
runIdRef.current++;
|
|
2180
2396
|
};
|
|
2181
2397
|
}, [runPoll]);
|
|
2182
|
-
const goHome = (0,
|
|
2398
|
+
const goHome = (0, import_react14.useCallback)(() => {
|
|
2183
2399
|
const cleanUrl = new URL(window.location.href);
|
|
2184
2400
|
cleanUrl.searchParams.delete("paymentReturn");
|
|
2185
2401
|
cleanUrl.pathname = "/app/home";
|
|
2186
2402
|
window.location.href = cleanUrl.toString();
|
|
2187
2403
|
}, []);
|
|
2188
2404
|
if (state === "confirming") {
|
|
2189
|
-
return /* @__PURE__ */ (0,
|
|
2405
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { role: "status", "aria-live": "polite", style: overlayStyle2, children: "Confirmando pagamento\u2026" });
|
|
2190
2406
|
}
|
|
2191
2407
|
if (state === "waiting") {
|
|
2192
|
-
return /* @__PURE__ */ (0,
|
|
2193
|
-
/* @__PURE__ */ (0,
|
|
2194
|
-
/* @__PURE__ */ (0,
|
|
2408
|
+
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: [
|
|
2409
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { style: { marginBottom: 16 }, children: "Pagamento aceito. Estamos confirmando com o banco \u2014 pode levar alguns minutos." }),
|
|
2410
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("button", { type: "button", onClick: runPoll, style: buttonStyle, children: "Atualizar" })
|
|
2195
2411
|
] }) });
|
|
2196
2412
|
}
|
|
2197
2413
|
if (state === "timeout") {
|
|
2198
|
-
return /* @__PURE__ */ (0,
|
|
2199
|
-
/* @__PURE__ */ (0,
|
|
2200
|
-
/* @__PURE__ */ (0,
|
|
2201
|
-
/* @__PURE__ */ (0,
|
|
2414
|
+
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: [
|
|
2415
|
+
/* @__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." }),
|
|
2416
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: 8 }, children: [
|
|
2417
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
2202
2418
|
"button",
|
|
2203
2419
|
{
|
|
2204
2420
|
type: "button",
|
|
@@ -2211,7 +2427,7 @@ function PaymentReturnHandler({ children }) {
|
|
|
2211
2427
|
children: "Tentar de novo"
|
|
2212
2428
|
}
|
|
2213
2429
|
),
|
|
2214
|
-
/* @__PURE__ */ (0,
|
|
2430
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
2215
2431
|
"button",
|
|
2216
2432
|
{
|
|
2217
2433
|
type: "button",
|
|
@@ -2221,7 +2437,7 @@ function PaymentReturnHandler({ children }) {
|
|
|
2221
2437
|
children: "Voltar pro app"
|
|
2222
2438
|
}
|
|
2223
2439
|
),
|
|
2224
|
-
/* @__PURE__ */ (0,
|
|
2440
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
2225
2441
|
"a",
|
|
2226
2442
|
{
|
|
2227
2443
|
href: SUPPORT_MAILTO,
|
|
@@ -2233,7 +2449,7 @@ function PaymentReturnHandler({ children }) {
|
|
|
2233
2449
|
] })
|
|
2234
2450
|
] }) });
|
|
2235
2451
|
}
|
|
2236
|
-
return /* @__PURE__ */ (0,
|
|
2452
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_jsx_runtime21.Fragment, { children });
|
|
2237
2453
|
}
|
|
2238
2454
|
var overlayStyle2 = {
|
|
2239
2455
|
position: "fixed",
|
|
@@ -2272,7 +2488,7 @@ var linkStyle = {
|
|
|
2272
2488
|
};
|
|
2273
2489
|
|
|
2274
2490
|
// src/AppRoot.tsx
|
|
2275
|
-
var
|
|
2491
|
+
var import_jsx_runtime22 = require("react/jsx-runtime");
|
|
2276
2492
|
function buildLegacyConfigShim(config) {
|
|
2277
2493
|
const paywall = config.paywall;
|
|
2278
2494
|
const isFree = paywall.mode === "free";
|
|
@@ -2320,9 +2536,10 @@ function AppRoot(props) {
|
|
|
2320
2536
|
Forgot,
|
|
2321
2537
|
Reset,
|
|
2322
2538
|
EmailVerify,
|
|
2323
|
-
Paywall,
|
|
2539
|
+
Paywall: Paywall2,
|
|
2324
2540
|
Onboarding,
|
|
2325
|
-
PreAuthFlow
|
|
2541
|
+
PreAuthFlow,
|
|
2542
|
+
devSkipOnboarding
|
|
2326
2543
|
} = props;
|
|
2327
2544
|
if (!Login || !Signup || !Forgot || !Reset) {
|
|
2328
2545
|
throw new Error(
|
|
@@ -2330,7 +2547,7 @@ function AppRoot(props) {
|
|
|
2330
2547
|
);
|
|
2331
2548
|
}
|
|
2332
2549
|
const config = parseAppConfig(rawConfig);
|
|
2333
|
-
if (config.paywall.mode !== "free" && !
|
|
2550
|
+
if (config.paywall.mode !== "free" && !Paywall2) {
|
|
2334
2551
|
throw new Error(
|
|
2335
2552
|
"[hook-template] <AppRoot>: Paywall slot prop is required when config.paywall.mode != 'free'."
|
|
2336
2553
|
);
|
|
@@ -2345,19 +2562,19 @@ function AppRoot(props) {
|
|
|
2345
2562
|
"[hook-template] <AppRoot>: PreAuthFlow slot prop is required when config.onboarding.trigger === 'pre_signup_custom'."
|
|
2346
2563
|
);
|
|
2347
2564
|
}
|
|
2348
|
-
const legacyShim = (0,
|
|
2565
|
+
const legacyShim = (0, import_react15.useMemo)(() => buildLegacyConfigShim(config), [config]);
|
|
2349
2566
|
const Router = testRouter === "memory" ? import_react_router_dom2.MemoryRouter : import_react_router_dom2.BrowserRouter;
|
|
2350
2567
|
const basename = `/app/${config.slug}`;
|
|
2351
2568
|
const routerProps = testRouter === "memory" ? { basename, initialEntries: testInitialEntries } : { basename };
|
|
2352
2569
|
const position = config.install_prompt?.position ?? "post-paywall";
|
|
2353
|
-
const subscriptionGated = /* @__PURE__ */ (0,
|
|
2570
|
+
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: [
|
|
2354
2571
|
children,
|
|
2355
|
-
/* @__PURE__ */ (0,
|
|
2356
|
-
] }) : /* @__PURE__ */ (0,
|
|
2572
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(PushPrompt, {})
|
|
2573
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_jsx_runtime22.Fragment, { children: [
|
|
2357
2574
|
children,
|
|
2358
|
-
/* @__PURE__ */ (0,
|
|
2575
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(PushPrompt, {})
|
|
2359
2576
|
] }) });
|
|
2360
|
-
const authGated = /* @__PURE__ */ (0,
|
|
2577
|
+
const authGated = /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
2361
2578
|
AuthGated,
|
|
2362
2579
|
{
|
|
2363
2580
|
config,
|
|
@@ -2366,18 +2583,19 @@ function AppRoot(props) {
|
|
|
2366
2583
|
Forgot,
|
|
2367
2584
|
Reset,
|
|
2368
2585
|
EmailVerify,
|
|
2369
|
-
Paywall,
|
|
2586
|
+
Paywall: Paywall2,
|
|
2370
2587
|
Onboarding,
|
|
2371
2588
|
PreAuthFlow,
|
|
2372
2589
|
children: subscriptionGated
|
|
2373
2590
|
}
|
|
2374
2591
|
);
|
|
2375
|
-
const routedTree = /* @__PURE__ */ (0,
|
|
2376
|
-
/* @__PURE__ */ (0,
|
|
2377
|
-
/* @__PURE__ */ (0,
|
|
2378
|
-
position === "pre-auth" ? /* @__PURE__ */ (0,
|
|
2592
|
+
const routedTree = /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(Router, { ...routerProps, children: [
|
|
2593
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(DeepLinkHandler, { deepLinks: config.deepLinks }),
|
|
2594
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(SessionExpiredBanner, {}),
|
|
2595
|
+
position === "pre-auth" ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(InstallGate, { position: "pre-auth", children: authGated }) : authGated,
|
|
2596
|
+
isDevToolsEnabled() && devSkipOnboarding ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(DevSkipOnboardingFab, { defaults: devSkipOnboarding.defaults }) : null
|
|
2379
2597
|
] });
|
|
2380
|
-
return /* @__PURE__ */ (0,
|
|
2598
|
+
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)(
|
|
2381
2599
|
I18nProvider,
|
|
2382
2600
|
{
|
|
2383
2601
|
defaultLocale: config.i18n.defaultLocale,
|
|
@@ -2397,37 +2615,37 @@ function AuthGated({
|
|
|
2397
2615
|
EmailVerify,
|
|
2398
2616
|
PreAuthFlow
|
|
2399
2617
|
}) {
|
|
2400
|
-
const { authStatus } = (0,
|
|
2618
|
+
const { authStatus } = (0, import_sdk8.useHook)();
|
|
2401
2619
|
if (authStatus === "loading") return null;
|
|
2402
2620
|
if (authStatus !== "authenticated") {
|
|
2403
2621
|
if (config.onboarding?.trigger === "pre_signup_custom" && PreAuthFlow) {
|
|
2404
|
-
return /* @__PURE__ */ (0,
|
|
2405
|
-
/* @__PURE__ */ (0,
|
|
2406
|
-
/* @__PURE__ */ (0,
|
|
2407
|
-
/* @__PURE__ */ (0,
|
|
2408
|
-
/* @__PURE__ */ (0,
|
|
2409
|
-
EmailVerify ? /* @__PURE__ */ (0,
|
|
2410
|
-
/* @__PURE__ */ (0,
|
|
2622
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_react_router_dom2.Routes, { children: [
|
|
2623
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_react_router_dom2.Route, { path: "/signin", element: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(Login, {}) }),
|
|
2624
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_react_router_dom2.Route, { path: "/signup", element: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(Signup, {}) }),
|
|
2625
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_react_router_dom2.Route, { path: "/forgot", element: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(Forgot, {}) }),
|
|
2626
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_react_router_dom2.Route, { path: "/reset", element: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(Reset, {}) }),
|
|
2627
|
+
EmailVerify ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_react_router_dom2.Route, { path: "/verify", element: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(EmailVerify, {}) }) : null,
|
|
2628
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_react_router_dom2.Route, { path: "/*", element: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(PreAuthFlow, {}) })
|
|
2411
2629
|
] });
|
|
2412
2630
|
}
|
|
2413
|
-
return /* @__PURE__ */ (0,
|
|
2414
|
-
/* @__PURE__ */ (0,
|
|
2415
|
-
/* @__PURE__ */ (0,
|
|
2416
|
-
/* @__PURE__ */ (0,
|
|
2417
|
-
/* @__PURE__ */ (0,
|
|
2418
|
-
EmailVerify ? /* @__PURE__ */ (0,
|
|
2419
|
-
/* @__PURE__ */ (0,
|
|
2631
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_react_router_dom2.Routes, { children: [
|
|
2632
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_react_router_dom2.Route, { path: "/", element: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(Login, {}) }),
|
|
2633
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_react_router_dom2.Route, { path: "/signup", element: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(Signup, {}) }),
|
|
2634
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_react_router_dom2.Route, { path: "/forgot", element: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(Forgot, {}) }),
|
|
2635
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_react_router_dom2.Route, { path: "/reset", element: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(Reset, {}) }),
|
|
2636
|
+
EmailVerify ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_react_router_dom2.Route, { path: "/verify", element: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(EmailVerify, {}) }) : null,
|
|
2637
|
+
/* @__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 }) })
|
|
2420
2638
|
] });
|
|
2421
2639
|
}
|
|
2422
|
-
return /* @__PURE__ */ (0,
|
|
2640
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_jsx_runtime22.Fragment, { children });
|
|
2423
2641
|
}
|
|
2424
2642
|
function FallbackPaywall() {
|
|
2425
2643
|
return null;
|
|
2426
2644
|
}
|
|
2427
2645
|
|
|
2428
2646
|
// src/hooks/usePush.ts
|
|
2429
|
-
var
|
|
2430
|
-
var
|
|
2647
|
+
var import_react16 = require("react");
|
|
2648
|
+
var import_sdk9 = require("@hook-sdk/sdk");
|
|
2431
2649
|
var DISMISS_STORAGE_KEY = "push:dismissed-until";
|
|
2432
2650
|
var DISMISS_TTL_MS2 = 7 * 24 * 60 * 60 * 1e3;
|
|
2433
2651
|
function detectIosNeedsInstall() {
|
|
@@ -2471,12 +2689,12 @@ function deriveState(push) {
|
|
|
2471
2689
|
return { kind: "prompt" };
|
|
2472
2690
|
}
|
|
2473
2691
|
function usePush() {
|
|
2474
|
-
const { push } = (0,
|
|
2475
|
-
const [state, setState] = (0,
|
|
2476
|
-
(0,
|
|
2692
|
+
const { push } = (0, import_sdk9.useHook)();
|
|
2693
|
+
const [state, setState] = (0, import_react16.useState)(() => deriveState(push));
|
|
2694
|
+
(0, import_react16.useEffect)(() => {
|
|
2477
2695
|
setState(deriveState(push));
|
|
2478
2696
|
}, [push]);
|
|
2479
|
-
const subscribe = (0,
|
|
2697
|
+
const subscribe = (0, import_react16.useCallback)(async () => {
|
|
2480
2698
|
try {
|
|
2481
2699
|
await push.subscribe();
|
|
2482
2700
|
setState({ kind: "subscribed" });
|
|
@@ -2488,7 +2706,7 @@ function usePush() {
|
|
|
2488
2706
|
throw e;
|
|
2489
2707
|
}
|
|
2490
2708
|
}, [push]);
|
|
2491
|
-
const unsubscribe = (0,
|
|
2709
|
+
const unsubscribe = (0, import_react16.useCallback)(async () => {
|
|
2492
2710
|
try {
|
|
2493
2711
|
await push.unsubscribe();
|
|
2494
2712
|
setState({ kind: "prompt" });
|
|
@@ -2497,7 +2715,7 @@ function usePush() {
|
|
|
2497
2715
|
throw e;
|
|
2498
2716
|
}
|
|
2499
2717
|
}, [push]);
|
|
2500
|
-
const dismiss = (0,
|
|
2718
|
+
const dismiss = (0, import_react16.useCallback)(() => {
|
|
2501
2719
|
if (typeof localStorage !== "undefined") {
|
|
2502
2720
|
try {
|
|
2503
2721
|
localStorage.setItem(DISMISS_STORAGE_KEY, String(Date.now() + DISMISS_TTL_MS2));
|
|
@@ -2510,27 +2728,27 @@ function usePush() {
|
|
|
2510
2728
|
}
|
|
2511
2729
|
|
|
2512
2730
|
// src/components/PushPrompt.tsx
|
|
2513
|
-
var
|
|
2731
|
+
var import_jsx_runtime23 = require("react/jsx-runtime");
|
|
2514
2732
|
function PushPrompt2({ texts, onSubscribed, onDeclined, onInstallRequested, className }) {
|
|
2515
2733
|
const { state, subscribe } = usePush();
|
|
2516
2734
|
if (state.kind === "denied" || state.kind === "dismissed" || state.kind === "subscribed") {
|
|
2517
2735
|
return null;
|
|
2518
2736
|
}
|
|
2519
2737
|
if (state.kind === "ios_needs_install") {
|
|
2520
|
-
return /* @__PURE__ */ (0,
|
|
2521
|
-
/* @__PURE__ */ (0,
|
|
2522
|
-
/* @__PURE__ */ (0,
|
|
2523
|
-
onInstallRequested && texts.iosInstallCta && /* @__PURE__ */ (0,
|
|
2738
|
+
return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className, role: "region", "aria-label": texts.iosInstallTitle, children: [
|
|
2739
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)("h3", { children: texts.iosInstallTitle }),
|
|
2740
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)("p", { children: texts.iosInstallBody }),
|
|
2741
|
+
onInstallRequested && texts.iosInstallCta && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("button", { onClick: onInstallRequested, children: texts.iosInstallCta })
|
|
2524
2742
|
] });
|
|
2525
2743
|
}
|
|
2526
2744
|
if (state.kind === "unsupported") {
|
|
2527
|
-
return /* @__PURE__ */ (0,
|
|
2745
|
+
return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className, role: "region", children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("p", { children: texts.unsupportedBody }) });
|
|
2528
2746
|
}
|
|
2529
2747
|
if (state.kind === "error") {
|
|
2530
|
-
return /* @__PURE__ */ (0,
|
|
2748
|
+
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 }) });
|
|
2531
2749
|
}
|
|
2532
|
-
return /* @__PURE__ */ (0,
|
|
2533
|
-
/* @__PURE__ */ (0,
|
|
2750
|
+
return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className, role: "region", children: [
|
|
2751
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
2534
2752
|
"button",
|
|
2535
2753
|
{
|
|
2536
2754
|
type: "button",
|
|
@@ -2544,67 +2762,67 @@ function PushPrompt2({ texts, onSubscribed, onDeclined, onInstallRequested, clas
|
|
|
2544
2762
|
children: texts.cta
|
|
2545
2763
|
}
|
|
2546
2764
|
),
|
|
2547
|
-
onDeclined && /* @__PURE__ */ (0,
|
|
2765
|
+
onDeclined && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("button", { type: "button", onClick: onDeclined, children: texts.declineCta })
|
|
2548
2766
|
] });
|
|
2549
2767
|
}
|
|
2550
2768
|
|
|
2551
2769
|
// src/components/LanguageSwitcher.tsx
|
|
2552
|
-
var
|
|
2553
|
-
var
|
|
2770
|
+
var import_sdk10 = require("@hook-sdk/sdk");
|
|
2771
|
+
var import_jsx_runtime24 = require("react/jsx-runtime");
|
|
2554
2772
|
function LanguageSwitcher({ id, className, label = "Language" }) {
|
|
2555
2773
|
const config = useAppConfig();
|
|
2556
2774
|
const i18nConfig = config.i18n;
|
|
2557
|
-
const [userLocale, setUserLocale] = (0,
|
|
2775
|
+
const [userLocale, setUserLocale] = (0, import_sdk10.usePersistedState)(
|
|
2558
2776
|
"user-locale",
|
|
2559
2777
|
i18nConfig?.defaultLocale ?? "en-US"
|
|
2560
2778
|
);
|
|
2561
2779
|
if (!i18nConfig) return null;
|
|
2562
|
-
return /* @__PURE__ */ (0,
|
|
2563
|
-
label ? /* @__PURE__ */ (0,
|
|
2564
|
-
/* @__PURE__ */ (0,
|
|
2780
|
+
return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("label", { className, children: [
|
|
2781
|
+
label ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { children: label }) : null,
|
|
2782
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
2565
2783
|
"select",
|
|
2566
2784
|
{
|
|
2567
2785
|
id,
|
|
2568
2786
|
value: userLocale,
|
|
2569
2787
|
onChange: (e) => setUserLocale(e.target.value),
|
|
2570
2788
|
"data-testid": "language-switcher",
|
|
2571
|
-
children: i18nConfig.supportedLocales.map((loc) => /* @__PURE__ */ (0,
|
|
2789
|
+
children: i18nConfig.supportedLocales.map((loc) => /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("option", { value: loc, children: loc }, loc))
|
|
2572
2790
|
}
|
|
2573
2791
|
)
|
|
2574
2792
|
] });
|
|
2575
2793
|
}
|
|
2576
2794
|
|
|
2577
2795
|
// src/defaults/LoadingState.tsx
|
|
2578
|
-
var
|
|
2796
|
+
var import_jsx_runtime25 = require("react/jsx-runtime");
|
|
2579
2797
|
function LoadingState({ message }) {
|
|
2580
|
-
return /* @__PURE__ */ (0,
|
|
2798
|
+
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..." }) });
|
|
2581
2799
|
}
|
|
2582
2800
|
|
|
2583
2801
|
// src/defaults/EmptyState.tsx
|
|
2584
|
-
var
|
|
2802
|
+
var import_jsx_runtime26 = require("react/jsx-runtime");
|
|
2585
2803
|
function EmptyState({ title, description, action }) {
|
|
2586
|
-
return /* @__PURE__ */ (0,
|
|
2587
|
-
/* @__PURE__ */ (0,
|
|
2588
|
-
description && /* @__PURE__ */ (0,
|
|
2589
|
-
action && /* @__PURE__ */ (0,
|
|
2804
|
+
return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { role: "status", style: { padding: 32, textAlign: "center" }, children: [
|
|
2805
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)("h2", { style: { marginBottom: 8 }, children: title }),
|
|
2806
|
+
description && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("p", { style: { opacity: 0.7 }, children: description }),
|
|
2807
|
+
action && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { style: { marginTop: 16 }, children: action })
|
|
2590
2808
|
] });
|
|
2591
2809
|
}
|
|
2592
2810
|
|
|
2593
2811
|
// src/hooks/useLoginForm.ts
|
|
2594
|
-
var
|
|
2595
|
-
var
|
|
2812
|
+
var import_react17 = require("react");
|
|
2813
|
+
var import_sdk12 = require("@hook-sdk/sdk");
|
|
2596
2814
|
|
|
2597
2815
|
// src/errors.ts
|
|
2598
|
-
var
|
|
2816
|
+
var import_sdk11 = require("@hook-sdk/sdk");
|
|
2599
2817
|
function mapSdkError(err) {
|
|
2600
|
-
if (err instanceof
|
|
2818
|
+
if (err instanceof import_sdk11.SdkRateLimitError) {
|
|
2601
2819
|
return {
|
|
2602
2820
|
code: "rate_limited",
|
|
2603
2821
|
message: `Aguarde ${err.retryAfter}s e tente novamente.`,
|
|
2604
2822
|
retryAfter: err.retryAfter
|
|
2605
2823
|
};
|
|
2606
2824
|
}
|
|
2607
|
-
if (err instanceof
|
|
2825
|
+
if (err instanceof import_sdk11.SdkAuthError) {
|
|
2608
2826
|
const detail = err.detail;
|
|
2609
2827
|
if (detail === "email_unverified") {
|
|
2610
2828
|
return { code: "email_unverified", message: "Confirme seu e-mail antes de entrar." };
|
|
@@ -2614,7 +2832,7 @@ function mapSdkError(err) {
|
|
|
2614
2832
|
}
|
|
2615
2833
|
return { code: "invalid_credentials", message: "E-mail ou senha inv\xE1lidos." };
|
|
2616
2834
|
}
|
|
2617
|
-
if (err instanceof
|
|
2835
|
+
if (err instanceof import_sdk11.SdkError && err.httpStatus === 0) {
|
|
2618
2836
|
return { code: "network", message: "Sem conex\xE3o com o servidor. Verifique sua internet." };
|
|
2619
2837
|
}
|
|
2620
2838
|
if (err instanceof TypeError) {
|
|
@@ -2627,20 +2845,20 @@ function mapSdkError(err) {
|
|
|
2627
2845
|
var EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
2628
2846
|
var MIN_PASSWORD = 8;
|
|
2629
2847
|
function useLoginForm() {
|
|
2630
|
-
const { auth } = (0,
|
|
2631
|
-
const [email, setEmail] = (0,
|
|
2632
|
-
const [password, setPassword] = (0,
|
|
2633
|
-
const [submitting, setSubmitting] = (0,
|
|
2634
|
-
const [error, setError] = (0,
|
|
2635
|
-
const [touchedEmail, setTouchedEmail] = (0,
|
|
2636
|
-
const [touchedPassword, setTouchedPassword] = (0,
|
|
2637
|
-
const [formSubmitAttempted, setFormSubmitAttempted] = (0,
|
|
2638
|
-
const validateEmail = (0,
|
|
2848
|
+
const { auth } = (0, import_sdk12.useHook)();
|
|
2849
|
+
const [email, setEmail] = (0, import_react17.useState)("");
|
|
2850
|
+
const [password, setPassword] = (0, import_react17.useState)("");
|
|
2851
|
+
const [submitting, setSubmitting] = (0, import_react17.useState)(false);
|
|
2852
|
+
const [error, setError] = (0, import_react17.useState)(null);
|
|
2853
|
+
const [touchedEmail, setTouchedEmail] = (0, import_react17.useState)(false);
|
|
2854
|
+
const [touchedPassword, setTouchedPassword] = (0, import_react17.useState)(false);
|
|
2855
|
+
const [formSubmitAttempted, setFormSubmitAttempted] = (0, import_react17.useState)(false);
|
|
2856
|
+
const validateEmail = (0, import_react17.useMemo)(() => {
|
|
2639
2857
|
if (email.length === 0) return null;
|
|
2640
2858
|
if (!EMAIL_RE.test(email)) return "Formato de e-mail inv\xE1lido.";
|
|
2641
2859
|
return null;
|
|
2642
2860
|
}, [email]);
|
|
2643
|
-
const validatePassword = (0,
|
|
2861
|
+
const validatePassword = (0, import_react17.useMemo)(() => {
|
|
2644
2862
|
if (password.length === 0) return null;
|
|
2645
2863
|
if (password.length < MIN_PASSWORD) return `M\xEDnimo de ${MIN_PASSWORD} caracteres.`;
|
|
2646
2864
|
return null;
|
|
@@ -2648,7 +2866,7 @@ function useLoginForm() {
|
|
|
2648
2866
|
const emailError = touchedEmail || formSubmitAttempted ? validateEmail : null;
|
|
2649
2867
|
const passwordError = touchedPassword || formSubmitAttempted ? validatePassword : null;
|
|
2650
2868
|
const canSubmit = email.length > 0 && password.length >= MIN_PASSWORD && validateEmail === null && validatePassword === null && !submitting;
|
|
2651
|
-
const submit = (0,
|
|
2869
|
+
const submit = (0, import_react17.useCallback)(async () => {
|
|
2652
2870
|
setFormSubmitAttempted(true);
|
|
2653
2871
|
if (!canSubmit) return false;
|
|
2654
2872
|
setSubmitting(true);
|
|
@@ -2682,32 +2900,32 @@ function useLoginForm() {
|
|
|
2682
2900
|
}
|
|
2683
2901
|
|
|
2684
2902
|
// src/hooks/useSignupForm.ts
|
|
2685
|
-
var
|
|
2686
|
-
var
|
|
2903
|
+
var import_react18 = require("react");
|
|
2904
|
+
var import_sdk13 = require("@hook-sdk/sdk");
|
|
2687
2905
|
var EMAIL_RE2 = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
2688
2906
|
var MIN_PASSWORD2 = 8;
|
|
2689
2907
|
function useSignupForm() {
|
|
2690
|
-
const { auth } = (0,
|
|
2691
|
-
const [name, setName] = (0,
|
|
2692
|
-
const [email, setEmail] = (0,
|
|
2693
|
-
const [password, setPassword] = (0,
|
|
2694
|
-
const [submitting, setSubmitting] = (0,
|
|
2695
|
-
const [error, setError] = (0,
|
|
2696
|
-
const [touchedName, setTouchedName] = (0,
|
|
2697
|
-
const [touchedEmail, setTouchedEmail] = (0,
|
|
2698
|
-
const [touchedPassword, setTouchedPassword] = (0,
|
|
2699
|
-
const [formSubmitAttempted, setFormSubmitAttempted] = (0,
|
|
2700
|
-
const validateName = (0,
|
|
2908
|
+
const { auth } = (0, import_sdk13.useHook)();
|
|
2909
|
+
const [name, setName] = (0, import_react18.useState)("");
|
|
2910
|
+
const [email, setEmail] = (0, import_react18.useState)("");
|
|
2911
|
+
const [password, setPassword] = (0, import_react18.useState)("");
|
|
2912
|
+
const [submitting, setSubmitting] = (0, import_react18.useState)(false);
|
|
2913
|
+
const [error, setError] = (0, import_react18.useState)(null);
|
|
2914
|
+
const [touchedName, setTouchedName] = (0, import_react18.useState)(false);
|
|
2915
|
+
const [touchedEmail, setTouchedEmail] = (0, import_react18.useState)(false);
|
|
2916
|
+
const [touchedPassword, setTouchedPassword] = (0, import_react18.useState)(false);
|
|
2917
|
+
const [formSubmitAttempted, setFormSubmitAttempted] = (0, import_react18.useState)(false);
|
|
2918
|
+
const validateName = (0, import_react18.useMemo)(() => {
|
|
2701
2919
|
if (name.length === 0) return null;
|
|
2702
2920
|
if (name.trim().length < 2) return "Nome muito curto.";
|
|
2703
2921
|
return null;
|
|
2704
2922
|
}, [name]);
|
|
2705
|
-
const validateEmail = (0,
|
|
2923
|
+
const validateEmail = (0, import_react18.useMemo)(() => {
|
|
2706
2924
|
if (email.length === 0) return null;
|
|
2707
2925
|
if (!EMAIL_RE2.test(email)) return "Formato de e-mail inv\xE1lido.";
|
|
2708
2926
|
return null;
|
|
2709
2927
|
}, [email]);
|
|
2710
|
-
const validatePassword = (0,
|
|
2928
|
+
const validatePassword = (0, import_react18.useMemo)(() => {
|
|
2711
2929
|
if (password.length === 0) return null;
|
|
2712
2930
|
if (password.length < MIN_PASSWORD2) return `M\xEDnimo de ${MIN_PASSWORD2} caracteres.`;
|
|
2713
2931
|
return null;
|
|
@@ -2716,7 +2934,7 @@ function useSignupForm() {
|
|
|
2716
2934
|
const emailError = touchedEmail || formSubmitAttempted ? validateEmail : null;
|
|
2717
2935
|
const passwordError = touchedPassword || formSubmitAttempted ? validatePassword : null;
|
|
2718
2936
|
const canSubmit = name.trim().length >= 2 && email.length > 0 && password.length >= MIN_PASSWORD2 && validateName === null && validateEmail === null && validatePassword === null && !submitting;
|
|
2719
|
-
const submit = (0,
|
|
2937
|
+
const submit = (0, import_react18.useCallback)(async () => {
|
|
2720
2938
|
setFormSubmitAttempted(true);
|
|
2721
2939
|
if (!canSubmit) return false;
|
|
2722
2940
|
setSubmitting(true);
|
|
@@ -2754,25 +2972,25 @@ function useSignupForm() {
|
|
|
2754
2972
|
}
|
|
2755
2973
|
|
|
2756
2974
|
// src/hooks/useForgotForm.ts
|
|
2757
|
-
var
|
|
2758
|
-
var
|
|
2975
|
+
var import_react19 = require("react");
|
|
2976
|
+
var import_sdk14 = require("@hook-sdk/sdk");
|
|
2759
2977
|
var EMAIL_RE3 = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
2760
2978
|
function useForgotForm() {
|
|
2761
|
-
const { auth } = (0,
|
|
2762
|
-
const [email, setEmail] = (0,
|
|
2763
|
-
const [submitting, setSubmitting] = (0,
|
|
2764
|
-
const [sent, setSent] = (0,
|
|
2765
|
-
const [error, setError] = (0,
|
|
2766
|
-
const [touchedEmail, setTouchedEmail] = (0,
|
|
2767
|
-
const [formSubmitAttempted, setFormSubmitAttempted] = (0,
|
|
2768
|
-
const validateEmail = (0,
|
|
2979
|
+
const { auth } = (0, import_sdk14.useHook)();
|
|
2980
|
+
const [email, setEmail] = (0, import_react19.useState)("");
|
|
2981
|
+
const [submitting, setSubmitting] = (0, import_react19.useState)(false);
|
|
2982
|
+
const [sent, setSent] = (0, import_react19.useState)(false);
|
|
2983
|
+
const [error, setError] = (0, import_react19.useState)(null);
|
|
2984
|
+
const [touchedEmail, setTouchedEmail] = (0, import_react19.useState)(false);
|
|
2985
|
+
const [formSubmitAttempted, setFormSubmitAttempted] = (0, import_react19.useState)(false);
|
|
2986
|
+
const validateEmail = (0, import_react19.useMemo)(() => {
|
|
2769
2987
|
if (email.length === 0) return null;
|
|
2770
2988
|
if (!EMAIL_RE3.test(email)) return "Formato de e-mail inv\xE1lido.";
|
|
2771
2989
|
return null;
|
|
2772
2990
|
}, [email]);
|
|
2773
2991
|
const emailError = touchedEmail || formSubmitAttempted ? validateEmail : null;
|
|
2774
2992
|
const canSubmit = email.length > 0 && validateEmail === null && !submitting;
|
|
2775
|
-
const submit = (0,
|
|
2993
|
+
const submit = (0, import_react19.useCallback)(async () => {
|
|
2776
2994
|
setFormSubmitAttempted(true);
|
|
2777
2995
|
if (!canSubmit) return false;
|
|
2778
2996
|
setSubmitting(true);
|
|
@@ -2803,32 +3021,32 @@ function useForgotForm() {
|
|
|
2803
3021
|
}
|
|
2804
3022
|
|
|
2805
3023
|
// src/hooks/useResetForm.ts
|
|
2806
|
-
var
|
|
2807
|
-
var
|
|
3024
|
+
var import_react20 = require("react");
|
|
3025
|
+
var import_sdk15 = require("@hook-sdk/sdk");
|
|
2808
3026
|
var MIN_PASSWORD3 = 12;
|
|
2809
3027
|
function useResetForm() {
|
|
2810
|
-
const { auth } = (0,
|
|
2811
|
-
const [token, setToken] = (0,
|
|
2812
|
-
const [password, setPassword] = (0,
|
|
2813
|
-
const [confirm, setConfirm] = (0,
|
|
2814
|
-
const [submitting, setSubmitting] = (0,
|
|
2815
|
-
const [done, setDone] = (0,
|
|
2816
|
-
const [error, setError] = (0,
|
|
2817
|
-
const [touchedPassword, setTouchedPassword] = (0,
|
|
2818
|
-
const [touchedConfirm, setTouchedConfirm] = (0,
|
|
2819
|
-
const [formSubmitAttempted, setFormSubmitAttempted] = (0,
|
|
2820
|
-
(0,
|
|
3028
|
+
const { auth } = (0, import_sdk15.useHook)();
|
|
3029
|
+
const [token, setToken] = (0, import_react20.useState)(null);
|
|
3030
|
+
const [password, setPassword] = (0, import_react20.useState)("");
|
|
3031
|
+
const [confirm, setConfirm] = (0, import_react20.useState)("");
|
|
3032
|
+
const [submitting, setSubmitting] = (0, import_react20.useState)(false);
|
|
3033
|
+
const [done, setDone] = (0, import_react20.useState)(false);
|
|
3034
|
+
const [error, setError] = (0, import_react20.useState)(null);
|
|
3035
|
+
const [touchedPassword, setTouchedPassword] = (0, import_react20.useState)(false);
|
|
3036
|
+
const [touchedConfirm, setTouchedConfirm] = (0, import_react20.useState)(false);
|
|
3037
|
+
const [formSubmitAttempted, setFormSubmitAttempted] = (0, import_react20.useState)(false);
|
|
3038
|
+
(0, import_react20.useEffect)(() => {
|
|
2821
3039
|
if (typeof window === "undefined") return;
|
|
2822
3040
|
const params = new URLSearchParams(window.location.search);
|
|
2823
3041
|
const t = params.get("token");
|
|
2824
3042
|
setToken(t && t.length > 0 ? t : null);
|
|
2825
3043
|
}, []);
|
|
2826
|
-
const validatePassword = (0,
|
|
3044
|
+
const validatePassword = (0, import_react20.useMemo)(() => {
|
|
2827
3045
|
if (password.length === 0) return null;
|
|
2828
3046
|
if (password.length < MIN_PASSWORD3) return `M\xEDnimo de ${MIN_PASSWORD3} caracteres.`;
|
|
2829
3047
|
return null;
|
|
2830
3048
|
}, [password]);
|
|
2831
|
-
const validateConfirm = (0,
|
|
3049
|
+
const validateConfirm = (0, import_react20.useMemo)(() => {
|
|
2832
3050
|
if (confirm.length === 0) return null;
|
|
2833
3051
|
if (confirm !== password) return "Senhas n\xE3o coincidem.";
|
|
2834
3052
|
return null;
|
|
@@ -2836,7 +3054,7 @@ function useResetForm() {
|
|
|
2836
3054
|
const passwordError = touchedPassword || formSubmitAttempted ? validatePassword : null;
|
|
2837
3055
|
const confirmError = touchedConfirm || formSubmitAttempted ? validateConfirm : null;
|
|
2838
3056
|
const canSubmit = token !== null && password.length >= MIN_PASSWORD3 && confirm === password && validatePassword === null && validateConfirm === null && !submitting && !done;
|
|
2839
|
-
const submit = (0,
|
|
3057
|
+
const submit = (0, import_react20.useCallback)(async () => {
|
|
2840
3058
|
setFormSubmitAttempted(true);
|
|
2841
3059
|
if (!canSubmit || token === null) return;
|
|
2842
3060
|
setSubmitting(true);
|
|
@@ -2876,9 +3094,9 @@ function useResetForm() {
|
|
|
2876
3094
|
}
|
|
2877
3095
|
|
|
2878
3096
|
// src/hooks/usePlan.ts
|
|
2879
|
-
var
|
|
3097
|
+
var import_sdk16 = require("@hook-sdk/sdk");
|
|
2880
3098
|
function usePlan() {
|
|
2881
|
-
const { plan } = (0,
|
|
3099
|
+
const { plan } = (0, import_sdk16.useHook)();
|
|
2882
3100
|
return plan;
|
|
2883
3101
|
}
|
|
2884
3102
|
|
|
@@ -2911,12 +3129,12 @@ function discountPercent(anchorCents, realCents) {
|
|
|
2911
3129
|
}
|
|
2912
3130
|
|
|
2913
3131
|
// src/hooks/useAuthPrimitives.ts
|
|
2914
|
-
var
|
|
2915
|
-
var
|
|
3132
|
+
var import_react21 = require("react");
|
|
3133
|
+
var import_sdk17 = require("@hook-sdk/sdk");
|
|
2916
3134
|
var warned = false;
|
|
2917
3135
|
function useAuthPrimitives() {
|
|
2918
|
-
const { auth } = (0,
|
|
2919
|
-
(0,
|
|
3136
|
+
const { auth } = (0, import_sdk17.useHook)();
|
|
3137
|
+
(0, import_react21.useEffect)(() => {
|
|
2920
3138
|
if (!warned && process.env.NODE_ENV !== "production") {
|
|
2921
3139
|
warned = true;
|
|
2922
3140
|
console.warn(
|
|
@@ -2938,9 +3156,9 @@ function useAuthPrimitives() {
|
|
|
2938
3156
|
}
|
|
2939
3157
|
|
|
2940
3158
|
// src/hooks/useAuth.ts
|
|
2941
|
-
var
|
|
3159
|
+
var import_sdk18 = require("@hook-sdk/sdk");
|
|
2942
3160
|
function useAuth() {
|
|
2943
|
-
const { user, authStatus, auth } = (0,
|
|
3161
|
+
const { user, authStatus, auth } = (0, import_sdk18.useHook)();
|
|
2944
3162
|
return {
|
|
2945
3163
|
user,
|
|
2946
3164
|
authStatus,
|
|
@@ -2949,26 +3167,26 @@ function useAuth() {
|
|
|
2949
3167
|
}
|
|
2950
3168
|
|
|
2951
3169
|
// src/index.ts
|
|
2952
|
-
var
|
|
3170
|
+
var import_sdk23 = require("@hook-sdk/sdk");
|
|
2953
3171
|
|
|
2954
3172
|
// src/hooks/useSubscription.ts
|
|
2955
|
-
var
|
|
3173
|
+
var import_sdk19 = require("@hook-sdk/sdk");
|
|
2956
3174
|
function useSubscription() {
|
|
2957
|
-
const { subscription } = (0,
|
|
3175
|
+
const { subscription } = (0, import_sdk19.useHook)();
|
|
2958
3176
|
return {
|
|
2959
3177
|
status: subscription.status()
|
|
2960
3178
|
};
|
|
2961
3179
|
}
|
|
2962
3180
|
|
|
2963
3181
|
// src/hooks/useReminders.ts
|
|
2964
|
-
var
|
|
2965
|
-
var
|
|
3182
|
+
var import_react22 = require("react");
|
|
3183
|
+
var import_sdk20 = require("@hook-sdk/sdk");
|
|
2966
3184
|
function useReminders() {
|
|
2967
|
-
const { push } = (0,
|
|
3185
|
+
const { push } = (0, import_sdk20.useHook)();
|
|
2968
3186
|
const r = push.reminders;
|
|
2969
|
-
const [reminders, setReminders] = (0,
|
|
2970
|
-
const [loading, setLoading] = (0,
|
|
2971
|
-
const reload = (0,
|
|
3187
|
+
const [reminders, setReminders] = (0, import_react22.useState)([]);
|
|
3188
|
+
const [loading, setLoading] = (0, import_react22.useState)(true);
|
|
3189
|
+
const reload = (0, import_react22.useCallback)(async () => {
|
|
2972
3190
|
setLoading(true);
|
|
2973
3191
|
try {
|
|
2974
3192
|
const next = await r.list();
|
|
@@ -2977,38 +3195,38 @@ function useReminders() {
|
|
|
2977
3195
|
setLoading(false);
|
|
2978
3196
|
}
|
|
2979
3197
|
}, [r]);
|
|
2980
|
-
(0,
|
|
3198
|
+
(0, import_react22.useEffect)(() => {
|
|
2981
3199
|
void reload();
|
|
2982
3200
|
}, [reload]);
|
|
2983
|
-
const setReminder = (0,
|
|
3201
|
+
const setReminder = (0, import_react22.useCallback)(async (input) => {
|
|
2984
3202
|
await r.set(input);
|
|
2985
3203
|
await reload();
|
|
2986
3204
|
}, [r, reload]);
|
|
2987
|
-
const deleteReminder = (0,
|
|
3205
|
+
const deleteReminder = (0, import_react22.useCallback)(async (slot) => {
|
|
2988
3206
|
await r.delete(slot);
|
|
2989
3207
|
await reload();
|
|
2990
3208
|
}, [r, reload]);
|
|
2991
|
-
const schedule = (0,
|
|
3209
|
+
const schedule = (0, import_react22.useCallback)(async (items) => {
|
|
2992
3210
|
return r.schedule(items);
|
|
2993
3211
|
}, [r]);
|
|
2994
|
-
const setFallbacks = (0,
|
|
3212
|
+
const setFallbacks = (0, import_react22.useCallback)(async (items) => {
|
|
2995
3213
|
return r.setFallbacks(items);
|
|
2996
3214
|
}, [r]);
|
|
2997
3215
|
return { reminders, loading, setReminder, deleteReminder, schedule, setFallbacks };
|
|
2998
3216
|
}
|
|
2999
3217
|
|
|
3000
3218
|
// src/hooks/useToast.ts
|
|
3001
|
-
var
|
|
3219
|
+
var import_react23 = require("react");
|
|
3002
3220
|
function useToast() {
|
|
3003
|
-
const [items, setItems] = (0,
|
|
3004
|
-
const show = (0,
|
|
3221
|
+
const [items, setItems] = (0, import_react23.useState)([]);
|
|
3222
|
+
const show = (0, import_react23.useCallback)((message, kind = "info") => {
|
|
3005
3223
|
const id = `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
3006
3224
|
setItems((prev) => [...prev, { id, message, kind }]);
|
|
3007
3225
|
setTimeout(() => {
|
|
3008
3226
|
setItems((prev) => prev.filter((t) => t.id !== id));
|
|
3009
3227
|
}, 4e3);
|
|
3010
3228
|
}, []);
|
|
3011
|
-
const dismiss = (0,
|
|
3229
|
+
const dismiss = (0, import_react23.useCallback)((id) => {
|
|
3012
3230
|
setItems((prev) => prev.filter((t) => t.id !== id));
|
|
3013
3231
|
}, []);
|
|
3014
3232
|
return { items, show, dismiss };
|
|
@@ -3016,20 +3234,20 @@ function useToast() {
|
|
|
3016
3234
|
|
|
3017
3235
|
// src/RouteBoundary.tsx
|
|
3018
3236
|
var import_react_router_dom3 = require("react-router-dom");
|
|
3019
|
-
var
|
|
3237
|
+
var import_jsx_runtime27 = require("react/jsx-runtime");
|
|
3020
3238
|
function RouteBoundary({ children }) {
|
|
3021
|
-
return /* @__PURE__ */ (0,
|
|
3239
|
+
return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(import_react_router_dom3.Routes, { children: [
|
|
3022
3240
|
children,
|
|
3023
|
-
/* @__PURE__ */ (0,
|
|
3241
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_react_router_dom3.Route, { path: "*", element: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(DefaultNotFound, {}) })
|
|
3024
3242
|
] });
|
|
3025
3243
|
}
|
|
3026
3244
|
function DefaultNotFound() {
|
|
3027
|
-
return /* @__PURE__ */ (0,
|
|
3245
|
+
return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { role: "alert", children: "P\xE1gina n\xE3o encontrada" });
|
|
3028
3246
|
}
|
|
3029
3247
|
|
|
3030
3248
|
// src/PreAuthShell.tsx
|
|
3031
3249
|
var import_react_router_dom4 = require("react-router-dom");
|
|
3032
|
-
var
|
|
3250
|
+
var import_jsx_runtime28 = require("react/jsx-runtime");
|
|
3033
3251
|
function PreAuthShell({
|
|
3034
3252
|
basename,
|
|
3035
3253
|
testRouter,
|
|
@@ -3037,20 +3255,20 @@ function PreAuthShell({
|
|
|
3037
3255
|
children
|
|
3038
3256
|
}) {
|
|
3039
3257
|
if (testRouter === "memory") {
|
|
3040
|
-
return /* @__PURE__ */ (0,
|
|
3258
|
+
return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_react_router_dom4.MemoryRouter, { basename, initialEntries: testInitialEntries, children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_react_router_dom4.Routes, { children }) });
|
|
3041
3259
|
}
|
|
3042
|
-
return /* @__PURE__ */ (0,
|
|
3260
|
+
return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_react_router_dom4.BrowserRouter, { basename, children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_react_router_dom4.Routes, { children }) });
|
|
3043
3261
|
}
|
|
3044
3262
|
|
|
3045
3263
|
// src/OnboardingFlow.tsx
|
|
3046
|
-
var
|
|
3047
|
-
var
|
|
3264
|
+
var import_react25 = require("react");
|
|
3265
|
+
var import_sdk21 = require("@hook-sdk/sdk");
|
|
3048
3266
|
|
|
3049
3267
|
// src/hooks/useOnboardingStep.ts
|
|
3050
|
-
var
|
|
3051
|
-
var OnboardingStepContext = (0,
|
|
3268
|
+
var import_react24 = require("react");
|
|
3269
|
+
var OnboardingStepContext = (0, import_react24.createContext)(null);
|
|
3052
3270
|
function useOnboardingStep() {
|
|
3053
|
-
const ctx = (0,
|
|
3271
|
+
const ctx = (0, import_react24.useContext)(OnboardingStepContext);
|
|
3054
3272
|
if (!ctx) {
|
|
3055
3273
|
throw new Error(
|
|
3056
3274
|
"[hook-template] useOnboardingStep must be used inside <OnboardingFlow>. (G75)"
|
|
@@ -3060,7 +3278,7 @@ function useOnboardingStep() {
|
|
|
3060
3278
|
}
|
|
3061
3279
|
|
|
3062
3280
|
// src/OnboardingFlow.tsx
|
|
3063
|
-
var
|
|
3281
|
+
var import_jsx_runtime29 = require("react/jsx-runtime");
|
|
3064
3282
|
var isFilled = (v) => v != null && v !== "";
|
|
3065
3283
|
var CURRENT_STEP_FIELD = "currentStep";
|
|
3066
3284
|
function readPersistedStepIdx(draft) {
|
|
@@ -3073,12 +3291,12 @@ function OnboardingFlow({
|
|
|
3073
3291
|
onComplete,
|
|
3074
3292
|
persistKey
|
|
3075
3293
|
}) {
|
|
3076
|
-
const [draft, setDraft, status] = (0,
|
|
3077
|
-
const draftRef = (0,
|
|
3294
|
+
const [draft, setDraft, status] = (0, import_sdk21.usePersistedState)(persistKey, {});
|
|
3295
|
+
const draftRef = (0, import_react25.useRef)(draft);
|
|
3078
3296
|
draftRef.current = draft;
|
|
3079
3297
|
const idx = readPersistedStepIdx(draft);
|
|
3080
3298
|
const clampedIdx = Math.min(Math.max(idx, 0), Math.max(steps.length - 1, 0));
|
|
3081
|
-
const setIdx = (0,
|
|
3299
|
+
const setIdx = (0, import_react25.useCallback)(
|
|
3082
3300
|
(n) => {
|
|
3083
3301
|
setDraft((prev) => {
|
|
3084
3302
|
const prevIdx = readPersistedStepIdx(prev);
|
|
@@ -3088,7 +3306,7 @@ function OnboardingFlow({
|
|
|
3088
3306
|
},
|
|
3089
3307
|
[setDraft]
|
|
3090
3308
|
);
|
|
3091
|
-
const setValue = (0,
|
|
3309
|
+
const setValue = (0, import_react25.useCallback)(
|
|
3092
3310
|
(patch) => {
|
|
3093
3311
|
draftRef.current = { ...draftRef.current, ...patch };
|
|
3094
3312
|
setDraft((prev) => ({ ...prev, ...patch }));
|
|
@@ -3096,9 +3314,9 @@ function OnboardingFlow({
|
|
|
3096
3314
|
[setDraft]
|
|
3097
3315
|
);
|
|
3098
3316
|
const step = steps[clampedIdx];
|
|
3099
|
-
const hookCtx = (0,
|
|
3317
|
+
const hookCtx = (0, import_sdk21.useHook)();
|
|
3100
3318
|
const track2 = typeof hookCtx.track === "function" ? hookCtx.track : void 0;
|
|
3101
|
-
(0,
|
|
3319
|
+
(0, import_react25.useEffect)(() => {
|
|
3102
3320
|
if (status.loading) return;
|
|
3103
3321
|
if (!step) return;
|
|
3104
3322
|
if (!track2) return;
|
|
@@ -3108,11 +3326,11 @@ function OnboardingFlow({
|
|
|
3108
3326
|
total_steps: steps.length
|
|
3109
3327
|
});
|
|
3110
3328
|
}, [step?.id, clampedIdx, steps.length, status.loading, track2]);
|
|
3111
|
-
const valid = (0,
|
|
3329
|
+
const valid = (0, import_react25.useMemo)(
|
|
3112
3330
|
() => step ? (step.validates ?? []).every((field) => isFilled(draft[field])) : false,
|
|
3113
3331
|
[draft, step]
|
|
3114
3332
|
);
|
|
3115
|
-
const next = (0,
|
|
3333
|
+
const next = (0, import_react25.useCallback)(() => {
|
|
3116
3334
|
if (!step) return;
|
|
3117
3335
|
const current = draftRef.current;
|
|
3118
3336
|
const validNow = (step.validates ?? []).every((field) => isFilled(current[field]));
|
|
@@ -3123,8 +3341,8 @@ function OnboardingFlow({
|
|
|
3123
3341
|
setIdx(clampedIdx + 1);
|
|
3124
3342
|
}
|
|
3125
3343
|
}, [clampedIdx, onComplete, step, steps.length, setIdx]);
|
|
3126
|
-
const prevStep = (0,
|
|
3127
|
-
const ctx = (0,
|
|
3344
|
+
const prevStep = (0, import_react25.useCallback)(() => setIdx((i) => Math.max(0, i - 1)), [setIdx]);
|
|
3345
|
+
const ctx = (0, import_react25.useMemo)(
|
|
3128
3346
|
() => ({
|
|
3129
3347
|
stepIndex: clampedIdx,
|
|
3130
3348
|
totalSteps: steps.length,
|
|
@@ -3150,7 +3368,7 @@ function OnboardingFlow({
|
|
|
3150
3368
|
`[hook-template] OnboardingFlow: missing screen component for step '${step.id}' (expected key '${step.screen}' in screens prop)`
|
|
3151
3369
|
);
|
|
3152
3370
|
}
|
|
3153
|
-
return /* @__PURE__ */ (0,
|
|
3371
|
+
return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(OnboardingStepContext.Provider, { value: ctx, children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(Screen, {}) });
|
|
3154
3372
|
}
|
|
3155
3373
|
|
|
3156
3374
|
// src/hooks/useFeature.ts
|
|
@@ -3158,12 +3376,299 @@ function useFeature(name) {
|
|
|
3158
3376
|
const config = useAppConfig();
|
|
3159
3377
|
return Array.isArray(config.features_enabled) && config.features_enabled.includes(name);
|
|
3160
3378
|
}
|
|
3379
|
+
|
|
3380
|
+
// src/components/paywall/Paywall.tsx
|
|
3381
|
+
var import_react26 = require("react");
|
|
3382
|
+
var import_sdk22 = require("@hook-sdk/sdk");
|
|
3383
|
+
|
|
3384
|
+
// src/components/paywall/PaywallMethodTabs.tsx
|
|
3385
|
+
var import_jsx_runtime30 = require("react/jsx-runtime");
|
|
3386
|
+
function PaywallMethodTabs({
|
|
3387
|
+
methods,
|
|
3388
|
+
selected,
|
|
3389
|
+
onSelect,
|
|
3390
|
+
labels,
|
|
3391
|
+
className,
|
|
3392
|
+
tabClassName,
|
|
3393
|
+
tabActiveClassName
|
|
3394
|
+
}) {
|
|
3395
|
+
if (methods.length < 2) return null;
|
|
3396
|
+
return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("div", { role: "tablist", "aria-label": "M\xE9todo de pagamento", className, children: methods.map((m) => {
|
|
3397
|
+
const active = m === selected;
|
|
3398
|
+
const label = labels[m] ?? m;
|
|
3399
|
+
return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
|
|
3400
|
+
"button",
|
|
3401
|
+
{
|
|
3402
|
+
type: "button",
|
|
3403
|
+
role: "tab",
|
|
3404
|
+
"aria-selected": active,
|
|
3405
|
+
"aria-controls": `paywall-tab-${m}`,
|
|
3406
|
+
tabIndex: active ? 0 : -1,
|
|
3407
|
+
onClick: () => onSelect(m),
|
|
3408
|
+
className: [tabClassName, active ? tabActiveClassName : ""].filter(Boolean).join(" "),
|
|
3409
|
+
children: label
|
|
3410
|
+
},
|
|
3411
|
+
m
|
|
3412
|
+
);
|
|
3413
|
+
}) });
|
|
3414
|
+
}
|
|
3415
|
+
|
|
3416
|
+
// src/components/paywall/PaywallMethodContent.tsx
|
|
3417
|
+
var import_jsx_runtime31 = require("react/jsx-runtime");
|
|
3418
|
+
function PaywallMethodContent({
|
|
3419
|
+
method,
|
|
3420
|
+
copy,
|
|
3421
|
+
hasConsumedTrial = false,
|
|
3422
|
+
className,
|
|
3423
|
+
rowClassName
|
|
3424
|
+
}) {
|
|
3425
|
+
const useCardConsumed = method === "card" && hasConsumedTrial && copy.cardConsumedTrial;
|
|
3426
|
+
const rows = useCardConsumed ? copy.cardConsumedTrial.bodyRows : method === "pix-auto" || method === "pix-once" ? copy.pix.bodyRows : copy.card.bodyRows;
|
|
3427
|
+
return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("div", { role: "tabpanel", id: `paywall-tab-${method}`, className, children: rows.map((row, i) => /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("div", { className: rowClassName, children: row }, i)) });
|
|
3428
|
+
}
|
|
3429
|
+
|
|
3430
|
+
// src/components/paywall/PaywallCyclePicker.tsx
|
|
3431
|
+
var import_jsx_runtime32 = require("react/jsx-runtime");
|
|
3432
|
+
function PaywallCyclePicker({
|
|
3433
|
+
cycles,
|
|
3434
|
+
selected,
|
|
3435
|
+
onSelect,
|
|
3436
|
+
priceCentsByCycle,
|
|
3437
|
+
anchorCentsByCycle,
|
|
3438
|
+
monthlyEquivByCycle,
|
|
3439
|
+
labels,
|
|
3440
|
+
className,
|
|
3441
|
+
cardClassName,
|
|
3442
|
+
cardSelectedClassName,
|
|
3443
|
+
anchorClassName
|
|
3444
|
+
}) {
|
|
3445
|
+
if (cycles.length < 2) return null;
|
|
3446
|
+
return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("div", { role: "radiogroup", "aria-label": "Ciclo de cobran\xE7a", className, children: cycles.map((c) => {
|
|
3447
|
+
const active = c === selected;
|
|
3448
|
+
const label = c === "YEARLY" ? labels.annualLabel : labels.monthlyLabel;
|
|
3449
|
+
const suffix = c === "YEARLY" ? labels.annualSuffix : labels.monthlySuffix;
|
|
3450
|
+
const mainCents = c === "YEARLY" ? monthlyEquivByCycle[c] : priceCentsByCycle[c];
|
|
3451
|
+
const anchorCents = anchorCentsByCycle[c];
|
|
3452
|
+
return /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(
|
|
3453
|
+
"button",
|
|
3454
|
+
{
|
|
3455
|
+
type: "button",
|
|
3456
|
+
role: "radio",
|
|
3457
|
+
"aria-checked": active,
|
|
3458
|
+
onClick: () => onSelect(c),
|
|
3459
|
+
className: ["flex flex-col items-center gap-0.5", cardClassName, active ? cardSelectedClassName : ""].filter(Boolean).join(" "),
|
|
3460
|
+
children: [
|
|
3461
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)("span", { className: "font-bold text-base leading-tight", children: formatBRL(mainCents) }),
|
|
3462
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)("span", { className: "text-xs opacity-70 leading-tight", children: suffix }),
|
|
3463
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)("span", { className: "text-xs opacity-60 leading-tight", children: label }),
|
|
3464
|
+
anchorCents != null && anchorCents > mainCents ? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("span", { className: anchorClassName ?? "text-xs opacity-50", children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("s", { children: formatBRL(anchorCents) }) }) : null
|
|
3465
|
+
]
|
|
3466
|
+
},
|
|
3467
|
+
c
|
|
3468
|
+
);
|
|
3469
|
+
}) });
|
|
3470
|
+
}
|
|
3471
|
+
|
|
3472
|
+
// src/components/paywall/PaywallCta.tsx
|
|
3473
|
+
var import_jsx_runtime33 = require("react/jsx-runtime");
|
|
3474
|
+
function PaywallCta({
|
|
3475
|
+
ctaLabel,
|
|
3476
|
+
loadingLabel,
|
|
3477
|
+
switchHint,
|
|
3478
|
+
trustLine,
|
|
3479
|
+
onClick,
|
|
3480
|
+
disabled = false,
|
|
3481
|
+
loading = false,
|
|
3482
|
+
className,
|
|
3483
|
+
buttonClassName,
|
|
3484
|
+
switchHintClassName,
|
|
3485
|
+
trustClassName
|
|
3486
|
+
}) {
|
|
3487
|
+
const label = loading && loadingLabel ? loadingLabel : ctaLabel;
|
|
3488
|
+
return /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("div", { className, children: [
|
|
3489
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
|
|
3490
|
+
"button",
|
|
3491
|
+
{
|
|
3492
|
+
type: "button",
|
|
3493
|
+
onClick,
|
|
3494
|
+
disabled: disabled || loading,
|
|
3495
|
+
className: buttonClassName,
|
|
3496
|
+
children: label
|
|
3497
|
+
}
|
|
3498
|
+
),
|
|
3499
|
+
switchHint ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("p", { className: switchHintClassName, children: switchHint }) : null,
|
|
3500
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)("p", { className: trustClassName, children: trustLine })
|
|
3501
|
+
] });
|
|
3502
|
+
}
|
|
3503
|
+
|
|
3504
|
+
// src/components/paywall/Paywall.tsx
|
|
3505
|
+
var import_jsx_runtime34 = require("react/jsx-runtime");
|
|
3506
|
+
var NBSP = "\xA0";
|
|
3507
|
+
function Paywall({
|
|
3508
|
+
copy,
|
|
3509
|
+
themeClasses = {},
|
|
3510
|
+
slots = {},
|
|
3511
|
+
onBeforeCheckout
|
|
3512
|
+
}) {
|
|
3513
|
+
const { track: track2 } = (0, import_sdk22.useHook)();
|
|
3514
|
+
const s = usePaywallState();
|
|
3515
|
+
const priceLabel = formatBRL(s.currentPriceCents).replace(new RegExp(NBSP, "g"), " ");
|
|
3516
|
+
const monthlyEquivLabel = formatBRL(s.currentMonthlyEquivCents).replace(new RegExp(NBSP, "g"), " ");
|
|
3517
|
+
const trialDaysCardLabel = String(s.trialDaysCard);
|
|
3518
|
+
const ctaLabel = (0, import_react26.useMemo)(() => {
|
|
3519
|
+
if (s.isFree) return copy.freeCta ?? "Come\xE7ar agora";
|
|
3520
|
+
if (s.selectedMethod === "card") {
|
|
3521
|
+
if (s.hasConsumedTrial && copy.cardConsumedTrial) {
|
|
3522
|
+
return interp(copy.cardConsumedTrial.ctaTemplate, { price: priceLabel, days: trialDaysCardLabel });
|
|
3523
|
+
}
|
|
3524
|
+
if (s.trialDaysCard > 0) {
|
|
3525
|
+
return interp(copy.card.ctaTemplate, { price: priceLabel, days: trialDaysCardLabel });
|
|
3526
|
+
}
|
|
3527
|
+
return copy.cardConsumedTrial ? interp(copy.cardConsumedTrial.ctaTemplate, { price: priceLabel, days: trialDaysCardLabel }) : `Assinar por ${priceLabel}`;
|
|
3528
|
+
}
|
|
3529
|
+
return interp(copy.pix.ctaTemplate, { price: priceLabel, days: trialDaysCardLabel });
|
|
3530
|
+
}, [
|
|
3531
|
+
s.isFree,
|
|
3532
|
+
s.selectedMethod,
|
|
3533
|
+
s.hasConsumedTrial,
|
|
3534
|
+
s.trialDaysCard,
|
|
3535
|
+
copy,
|
|
3536
|
+
priceLabel,
|
|
3537
|
+
trialDaysCardLabel
|
|
3538
|
+
]);
|
|
3539
|
+
const switchHint = (0, import_react26.useMemo)(() => {
|
|
3540
|
+
if (s.methods.length < 2) return void 0;
|
|
3541
|
+
return s.selectedMethod === "card" ? copy.card.switchHint : copy.pix.switchHint;
|
|
3542
|
+
}, [s.methods.length, s.selectedMethod, copy]);
|
|
3543
|
+
(0, import_react26.useEffect)(() => {
|
|
3544
|
+
if (!s.initialLoadComplete) return;
|
|
3545
|
+
track2("paywall_view", {
|
|
3546
|
+
default_method: s.selectedMethod,
|
|
3547
|
+
default_cycle: s.cycle,
|
|
3548
|
+
available_methods: s.methods
|
|
3549
|
+
});
|
|
3550
|
+
}, [s.initialLoadComplete]);
|
|
3551
|
+
const handleCta = async () => {
|
|
3552
|
+
track2("paywall_cta_clicked", {
|
|
3553
|
+
method: s.selectedMethod,
|
|
3554
|
+
cycle: s.cycle,
|
|
3555
|
+
price_cents: s.currentPriceCents,
|
|
3556
|
+
had_consumed_trial: s.hasConsumedTrial
|
|
3557
|
+
});
|
|
3558
|
+
if (onBeforeCheckout) {
|
|
3559
|
+
await onBeforeCheckout(s.selectedMethod, s.cycle);
|
|
3560
|
+
return;
|
|
3561
|
+
}
|
|
3562
|
+
await s.submit();
|
|
3563
|
+
};
|
|
3564
|
+
const ctaTheme = s.selectedMethod === "card" ? themeClasses.ctaCard : themeClasses.ctaPix;
|
|
3565
|
+
return /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("div", { className: themeClasses.container, children: [
|
|
3566
|
+
slots.heroSlot,
|
|
3567
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)("h1", { className: themeClasses.headline, children: copy.headline }),
|
|
3568
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)("ul", { children: copy.features.map((f) => /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("li", { className: themeClasses.feature, children: [
|
|
3569
|
+
"\u2713 ",
|
|
3570
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { children: f })
|
|
3571
|
+
] }, f)) }),
|
|
3572
|
+
copy.socialProof ? /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("p", { className: themeClasses.socialProof, children: copy.socialProof }) : null,
|
|
3573
|
+
slots.cyclePickerSlot ?? /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
|
|
3574
|
+
PaywallCyclePicker,
|
|
3575
|
+
{
|
|
3576
|
+
cycles: ["MONTHLY", "YEARLY"],
|
|
3577
|
+
selected: s.cycle,
|
|
3578
|
+
onSelect: s.selectCycle,
|
|
3579
|
+
priceCentsByCycle: {
|
|
3580
|
+
MONTHLY: priceCentsForCycle(s, "MONTHLY"),
|
|
3581
|
+
YEARLY: priceCentsForCycle(s, "YEARLY")
|
|
3582
|
+
},
|
|
3583
|
+
anchorCentsByCycle: {
|
|
3584
|
+
MONTHLY: anchorForCycle(s, "MONTHLY"),
|
|
3585
|
+
YEARLY: anchorForCycle(s, "YEARLY")
|
|
3586
|
+
},
|
|
3587
|
+
monthlyEquivByCycle: {
|
|
3588
|
+
MONTHLY: priceCentsForCycle(s, "MONTHLY"),
|
|
3589
|
+
YEARLY: Math.round(priceCentsForCycle(s, "YEARLY") / 12)
|
|
3590
|
+
},
|
|
3591
|
+
labels: copy.cycle,
|
|
3592
|
+
cardClassName: themeClasses.cycleCard,
|
|
3593
|
+
cardSelectedClassName: themeClasses.cycleCardSelected,
|
|
3594
|
+
anchorClassName: themeClasses.anchorPrice
|
|
3595
|
+
}
|
|
3596
|
+
),
|
|
3597
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
|
|
3598
|
+
PaywallMethodTabs,
|
|
3599
|
+
{
|
|
3600
|
+
methods: s.methods,
|
|
3601
|
+
selected: s.selectedMethod,
|
|
3602
|
+
onSelect: s.selectMethod,
|
|
3603
|
+
labels: { "pix-auto": copy.pix.tabLabel, card: copy.card.tabLabel },
|
|
3604
|
+
className: themeClasses.tabs,
|
|
3605
|
+
tabClassName: themeClasses.tab,
|
|
3606
|
+
tabActiveClassName: themeClasses.tabActive
|
|
3607
|
+
}
|
|
3608
|
+
),
|
|
3609
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
|
|
3610
|
+
PaywallMethodContent,
|
|
3611
|
+
{
|
|
3612
|
+
method: s.selectedMethod,
|
|
3613
|
+
copy: {
|
|
3614
|
+
pix: interpolateCopy(copy.pix, priceLabel, trialDaysCardLabel),
|
|
3615
|
+
card: interpolateCopy(copy.card, priceLabel, trialDaysCardLabel),
|
|
3616
|
+
cardConsumedTrial: copy.cardConsumedTrial ? {
|
|
3617
|
+
bodyRows: copy.cardConsumedTrial.bodyRows.map(
|
|
3618
|
+
(r) => interp(r, { price: priceLabel, days: trialDaysCardLabel })
|
|
3619
|
+
),
|
|
3620
|
+
ctaTemplate: copy.cardConsumedTrial.ctaTemplate
|
|
3621
|
+
} : void 0
|
|
3622
|
+
},
|
|
3623
|
+
hasConsumedTrial: s.hasConsumedTrial,
|
|
3624
|
+
className: themeClasses.tabContent,
|
|
3625
|
+
rowClassName: themeClasses.tabContentRow
|
|
3626
|
+
}
|
|
3627
|
+
),
|
|
3628
|
+
slots.beforeCtaSlot,
|
|
3629
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
|
|
3630
|
+
PaywallCta,
|
|
3631
|
+
{
|
|
3632
|
+
ctaLabel,
|
|
3633
|
+
loadingLabel: "Abrindo checkout\u2026",
|
|
3634
|
+
switchHint,
|
|
3635
|
+
trustLine: copy.trustLine,
|
|
3636
|
+
onClick: handleCta,
|
|
3637
|
+
disabled: s.submitting,
|
|
3638
|
+
loading: s.submitting,
|
|
3639
|
+
buttonClassName: ctaTheme,
|
|
3640
|
+
switchHintClassName: themeClasses.switchHint,
|
|
3641
|
+
trustClassName: themeClasses.trustLine
|
|
3642
|
+
}
|
|
3643
|
+
)
|
|
3644
|
+
] });
|
|
3645
|
+
}
|
|
3646
|
+
function interp(tpl, vars) {
|
|
3647
|
+
return tpl.replace(/\{(\w+)\}/g, (_m, k) => vars[k] ?? "");
|
|
3648
|
+
}
|
|
3649
|
+
function interpolateCopy(m, price, days) {
|
|
3650
|
+
return {
|
|
3651
|
+
tabLabel: m.tabLabel,
|
|
3652
|
+
bodyRows: m.bodyRows.map((r) => interp(r, { price, days })),
|
|
3653
|
+
ctaTemplate: m.ctaTemplate,
|
|
3654
|
+
switchHint: m.switchHint
|
|
3655
|
+
};
|
|
3656
|
+
}
|
|
3657
|
+
function priceCentsForCycle(s, c) {
|
|
3658
|
+
return s.plan ? c === "YEARLY" ? s.plan.yearlyCents ?? 0 : s.plan.monthlyCents : 0;
|
|
3659
|
+
}
|
|
3660
|
+
function anchorForCycle(s, c) {
|
|
3661
|
+
if (!s.plan) return null;
|
|
3662
|
+
if (c === "YEARLY") return s.plan.anchorYearlyCents ?? null;
|
|
3663
|
+
return s.plan.anchorMonthlyCents ?? null;
|
|
3664
|
+
}
|
|
3161
3665
|
// Annotate the CommonJS export names for ESM import in node:
|
|
3162
3666
|
0 && (module.exports = {
|
|
3163
3667
|
AppConfigProvider,
|
|
3164
3668
|
AppConfigSchema,
|
|
3165
3669
|
AppRoot,
|
|
3166
3670
|
DeepLinkHandler,
|
|
3671
|
+
DevSkipOnboardingFab,
|
|
3167
3672
|
EmptyState,
|
|
3168
3673
|
ErrorBoundary,
|
|
3169
3674
|
I18nProvider,
|
|
@@ -3173,6 +3678,11 @@ function useFeature(name) {
|
|
|
3173
3678
|
LoadingState,
|
|
3174
3679
|
OnboardingFlow,
|
|
3175
3680
|
PaymentReturnHandler,
|
|
3681
|
+
Paywall,
|
|
3682
|
+
PaywallCta,
|
|
3683
|
+
PaywallCyclePicker,
|
|
3684
|
+
PaywallMethodContent,
|
|
3685
|
+
PaywallMethodTabs,
|
|
3176
3686
|
PersistenceRegistry,
|
|
3177
3687
|
PreAuthShell,
|
|
3178
3688
|
PushPrompt,
|
|
@@ -3187,10 +3697,12 @@ function useFeature(name) {
|
|
|
3187
3697
|
detectStandalone,
|
|
3188
3698
|
discountPercent,
|
|
3189
3699
|
formatBRL,
|
|
3700
|
+
isDevToolsEnabled,
|
|
3190
3701
|
monthlyFromYearly,
|
|
3191
3702
|
parseAppConfig,
|
|
3192
3703
|
shouldBlockInstall,
|
|
3193
3704
|
shouldShowPermanentOption,
|
|
3705
|
+
skipOnboarding,
|
|
3194
3706
|
useAppConfig,
|
|
3195
3707
|
useAuth,
|
|
3196
3708
|
useAuthPrimitives,
|