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