@hook-sdk/template 0.9.1 → 0.10.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 +1229 -1690
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +323 -128
- package/dist/index.d.ts +323 -128
- package/dist/index.js +1183 -1652
- package/dist/index.js.map +1 -1
- package/package.json +6 -3
package/dist/index.cjs
CHANGED
|
@@ -20,18 +20,22 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
// src/index.ts
|
|
21
21
|
var index_exports = {};
|
|
22
22
|
__export(index_exports, {
|
|
23
|
+
AppConfigProvider: () => AppConfigProvider,
|
|
24
|
+
AppConfigSchema: () => AppConfigSchema,
|
|
23
25
|
AppRoot: () => AppRoot,
|
|
24
|
-
|
|
25
|
-
DefaultLoginScreen: () => DefaultLoginScreen,
|
|
26
|
-
DefaultPaywall: () => DefaultPaywall,
|
|
27
|
-
DefaultResetScreen: () => DefaultResetScreen,
|
|
28
|
-
DefaultSignupScreen: () => DefaultSignupScreen,
|
|
26
|
+
DeepLinkHandler: () => DeepLinkHandler,
|
|
29
27
|
EmptyState: () => EmptyState,
|
|
30
28
|
ErrorBoundary: () => ErrorBoundary,
|
|
31
29
|
InstallGate: () => InstallGate,
|
|
32
30
|
InstallSplash: () => InstallSplash,
|
|
33
31
|
LoadingState: () => LoadingState,
|
|
32
|
+
OnboardingFlow: () => OnboardingFlow,
|
|
33
|
+
PaymentReturnHandler: () => PaymentReturnHandler,
|
|
34
|
+
PersistenceRegistry: () => PersistenceRegistry,
|
|
35
|
+
PreAuthShell: () => PreAuthShell,
|
|
34
36
|
PushPrompt: () => PushPrompt2,
|
|
37
|
+
RouteBoundary: () => RouteBoundary,
|
|
38
|
+
asaasErrorMessage: () => asaasErrorMessage,
|
|
35
39
|
computeAnchorCents: () => computeAnchorCents,
|
|
36
40
|
dailyFromYearly: () => dailyFromYearly,
|
|
37
41
|
detectAndroidBrowser: () => detectAndroidBrowser,
|
|
@@ -42,13 +46,17 @@ __export(index_exports, {
|
|
|
42
46
|
discountPercent: () => discountPercent,
|
|
43
47
|
formatBRL: () => formatBRL,
|
|
44
48
|
monthlyFromYearly: () => monthlyFromYearly,
|
|
49
|
+
parseAppConfig: () => parseAppConfig,
|
|
45
50
|
shouldBlockInstall: () => shouldBlockInstall,
|
|
46
51
|
shouldShowPermanentOption: () => shouldShowPermanentOption,
|
|
52
|
+
useAppConfig: () => useAppConfig,
|
|
47
53
|
useAuth: () => useAuth,
|
|
48
54
|
useAuthPrimitives: () => useAuthPrimitives,
|
|
55
|
+
useFeature: () => useFeature,
|
|
49
56
|
useForgotForm: () => useForgotForm,
|
|
50
57
|
useInstallPrompt: () => useInstallPrompt,
|
|
51
58
|
useLoginForm: () => useLoginForm,
|
|
59
|
+
useOnboardingStep: () => useOnboardingStep,
|
|
52
60
|
usePaywallState: () => usePaywallState,
|
|
53
61
|
usePlan: () => usePlan,
|
|
54
62
|
usePush: () => usePush,
|
|
@@ -61,25 +69,156 @@ __export(index_exports, {
|
|
|
61
69
|
module.exports = __toCommonJS(index_exports);
|
|
62
70
|
|
|
63
71
|
// src/AppRoot.tsx
|
|
64
|
-
var
|
|
65
|
-
var
|
|
72
|
+
var import_react11 = require("react");
|
|
73
|
+
var import_react_router_dom2 = require("react-router-dom");
|
|
74
|
+
var import_sdk4 = require("@hook-sdk/sdk");
|
|
66
75
|
|
|
67
|
-
// src/
|
|
76
|
+
// src/config/AppConfigContext.tsx
|
|
68
77
|
var import_react = require("react");
|
|
69
78
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
70
|
-
var
|
|
79
|
+
var AppConfigContext = (0, import_react.createContext)(null);
|
|
80
|
+
function AppConfigProvider({
|
|
81
|
+
config,
|
|
82
|
+
children
|
|
83
|
+
}) {
|
|
84
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(AppConfigContext.Provider, { value: config, children });
|
|
85
|
+
}
|
|
86
|
+
function useAppConfig() {
|
|
87
|
+
const v = (0, import_react.useContext)(AppConfigContext);
|
|
88
|
+
if (!v) {
|
|
89
|
+
throw new Error(
|
|
90
|
+
"[hook-template] useAppConfig: AppConfigProvider missing \u2014 wrap your app in <AppRoot>"
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
return v;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// src/config/schema.ts
|
|
97
|
+
var import_zod = require("zod");
|
|
98
|
+
var SnakeKeyRE = /^[a-z0-9][a-z0-9_.-]{0,127}$/;
|
|
99
|
+
var AuthFlowSchema = import_zod.z.object({
|
|
100
|
+
minPassword: import_zod.z.number().int().min(6).max(64),
|
|
101
|
+
requiresEmailVerify: import_zod.z.boolean(),
|
|
102
|
+
googleOAuth: import_zod.z.boolean(),
|
|
103
|
+
postAuthLanding: import_zod.z.string().startsWith("/"),
|
|
104
|
+
preAuthRoutes: import_zod.z.array(import_zod.z.string().startsWith("/"))
|
|
105
|
+
});
|
|
106
|
+
var PaywallNonFreeSchema = import_zod.z.object({
|
|
107
|
+
mode: import_zod.z.enum(["trial", "pay_first"]),
|
|
108
|
+
trialDays: import_zod.z.number().int().nonnegative().optional(),
|
|
109
|
+
cycles: import_zod.z.array(import_zod.z.enum(["MONTHLY", "YEARLY"])).min(1),
|
|
110
|
+
prices: import_zod.z.object({
|
|
111
|
+
monthlyCents: import_zod.z.number().int().nonnegative(),
|
|
112
|
+
yearlyCents: import_zod.z.number().int().nonnegative()
|
|
113
|
+
}),
|
|
114
|
+
anchorPrices: import_zod.z.object({
|
|
115
|
+
monthlyCents: import_zod.z.number().int().nonnegative(),
|
|
116
|
+
yearlyCents: import_zod.z.number().int().nonnegative()
|
|
117
|
+
}).optional(),
|
|
118
|
+
checkoutMethods: import_zod.z.array(import_zod.z.enum(["card", "pix-auto", "pix-once"])).min(1),
|
|
119
|
+
requiresCpf: import_zod.z.boolean(),
|
|
120
|
+
cancelWindowDays: import_zod.z.number().int().nonnegative().optional(),
|
|
121
|
+
errorMessages: import_zod.z.enum(["default", "custom"])
|
|
122
|
+
});
|
|
123
|
+
var PaywallFreeSchema = import_zod.z.object({ mode: import_zod.z.literal("free") });
|
|
124
|
+
var PaywallSchema = import_zod.z.discriminatedUnion("mode", [PaywallNonFreeSchema, PaywallFreeSchema]);
|
|
125
|
+
var PersistedKeySchema = import_zod.z.object({
|
|
126
|
+
key: import_zod.z.string().regex(SnakeKeyRE, "key must be snake_case (matches /^[a-z0-9][a-z0-9_.-]{0,127}$/)"),
|
|
127
|
+
default: import_zod.z.unknown(),
|
|
128
|
+
guardRegen: import_zod.z.boolean().optional(),
|
|
129
|
+
debounceMs: import_zod.z.number().int().positive().optional()
|
|
130
|
+
});
|
|
131
|
+
var OnboardingSchema = import_zod.z.object({
|
|
132
|
+
trigger: import_zod.z.enum(["pre_signup", "post_signup", "pre_signup_custom", "optional"]),
|
|
133
|
+
steps: import_zod.z.array(
|
|
134
|
+
import_zod.z.object({
|
|
135
|
+
id: import_zod.z.string().regex(SnakeKeyRE),
|
|
136
|
+
screen: import_zod.z.string(),
|
|
137
|
+
validates: import_zod.z.array(import_zod.z.string()).optional()
|
|
138
|
+
})
|
|
139
|
+
).min(1),
|
|
140
|
+
persistTo: import_zod.z.literal("appData"),
|
|
141
|
+
persistKey: import_zod.z.string().regex(SnakeKeyRE)
|
|
142
|
+
});
|
|
143
|
+
var DeepLinksSchema = import_zod.z.object({
|
|
144
|
+
passwordReset: import_zod.z.string().startsWith("/").optional(),
|
|
145
|
+
emailVerify: import_zod.z.string().startsWith("/").optional()
|
|
146
|
+
}).strict();
|
|
147
|
+
var AppConfigSchema = import_zod.z.object({
|
|
148
|
+
slug: import_zod.z.string().regex(/^[a-z0-9-]+$/),
|
|
149
|
+
name: import_zod.z.string().min(1),
|
|
150
|
+
branding: import_zod.z.object({ primaryColor: import_zod.z.string(), logoUrl: import_zod.z.string().url() }),
|
|
151
|
+
authFlow: AuthFlowSchema,
|
|
152
|
+
paywall: PaywallSchema,
|
|
153
|
+
persistedKeys: import_zod.z.array(PersistedKeySchema),
|
|
154
|
+
onboarding: OnboardingSchema.optional(),
|
|
155
|
+
deepLinks: DeepLinksSchema.optional(),
|
|
156
|
+
features_enabled: import_zod.z.array(import_zod.z.string()).optional()
|
|
157
|
+
}).strict();
|
|
158
|
+
function parseAppConfig(input) {
|
|
159
|
+
const r = AppConfigSchema.safeParse(input);
|
|
160
|
+
if (!r.success) {
|
|
161
|
+
const messages = r.error.issues.map((i) => `[${i.path.join(".")}] ${i.message}`).join("\n");
|
|
162
|
+
throw new Error(`Invalid app.config.json:
|
|
163
|
+
${messages}`);
|
|
164
|
+
}
|
|
165
|
+
return r.data;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// src/PersistenceRegistry.tsx
|
|
169
|
+
var import_react2 = require("react");
|
|
170
|
+
var import_sdk = require("@hook-sdk/sdk");
|
|
171
|
+
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
172
|
+
function PersistenceRegistry({ config, children }) {
|
|
173
|
+
const { appData } = (0, import_sdk.useHook)();
|
|
174
|
+
(0, import_react2.useEffect)(() => {
|
|
175
|
+
if (config.length === 0) return;
|
|
176
|
+
const keys = config.map((c) => c.key);
|
|
177
|
+
const bulk = appData.bulkRead;
|
|
178
|
+
bulk?.(keys).catch(() => {
|
|
179
|
+
});
|
|
180
|
+
}, [config, appData]);
|
|
181
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_jsx_runtime2.Fragment, { children });
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// src/DeepLinkHandler.tsx
|
|
185
|
+
var import_react3 = require("react");
|
|
186
|
+
var import_react_router_dom = require("react-router-dom");
|
|
187
|
+
function DeepLinkHandler({ deepLinks }) {
|
|
188
|
+
const nav = (0, import_react_router_dom.useNavigate)();
|
|
189
|
+
const loc = (0, import_react_router_dom.useLocation)();
|
|
190
|
+
(0, import_react3.useEffect)(() => {
|
|
191
|
+
if (!deepLinks) return;
|
|
192
|
+
const params = new URLSearchParams(loc.search);
|
|
193
|
+
const token = params.get("token");
|
|
194
|
+
if (!token) return;
|
|
195
|
+
if (deepLinks.passwordReset && deepLinks.passwordReset.includes(":token") && loc.pathname === "/") {
|
|
196
|
+
nav(deepLinks.passwordReset.replace(":token", token));
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
if (deepLinks.emailVerify && deepLinks.emailVerify.includes(":token") && loc.pathname === "/") {
|
|
200
|
+
nav(deepLinks.emailVerify.replace(":token", token));
|
|
201
|
+
}
|
|
202
|
+
}, [deepLinks, loc, nav]);
|
|
203
|
+
return null;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// src/internal/TemplateConfigContext.tsx
|
|
207
|
+
var import_react4 = require("react");
|
|
208
|
+
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
209
|
+
var TemplateConfigContext = (0, import_react4.createContext)(null);
|
|
71
210
|
function TemplateConfigProvider({
|
|
72
211
|
config,
|
|
73
212
|
children
|
|
74
213
|
}) {
|
|
75
|
-
const value = (0,
|
|
214
|
+
const value = (0, import_react4.useMemo)(() => ({
|
|
76
215
|
...config,
|
|
77
216
|
mode: config.subscription?.mode ?? "trial"
|
|
78
217
|
}), [config]);
|
|
79
|
-
return /* @__PURE__ */ (0,
|
|
218
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(TemplateConfigContext.Provider, { value, children });
|
|
80
219
|
}
|
|
81
220
|
function useTemplateConfig() {
|
|
82
|
-
const ctx = (0,
|
|
221
|
+
const ctx = (0, import_react4.useContext)(TemplateConfigContext);
|
|
83
222
|
if (ctx === null) {
|
|
84
223
|
throw new Error("useTemplateConfig must be used inside <TemplateConfigProvider>");
|
|
85
224
|
}
|
|
@@ -87,7 +226,7 @@ function useTemplateConfig() {
|
|
|
87
226
|
}
|
|
88
227
|
|
|
89
228
|
// src/internal/ThemeProvider.tsx
|
|
90
|
-
var
|
|
229
|
+
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
91
230
|
function ThemeProvider({ children }) {
|
|
92
231
|
const config = useTemplateConfig();
|
|
93
232
|
const style = {
|
|
@@ -96,182 +235,308 @@ function ThemeProvider({ children }) {
|
|
|
96
235
|
"--hook-color-background": config.theme.background_color
|
|
97
236
|
}
|
|
98
237
|
};
|
|
99
|
-
return /* @__PURE__ */ (0,
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
// src/internal/AuthGate.tsx
|
|
103
|
-
var import_react2 = require("react");
|
|
104
|
-
|
|
105
|
-
// src/hooks/useAuth.ts
|
|
106
|
-
var import_sdk = require("@hook-sdk/sdk");
|
|
107
|
-
function useAuth() {
|
|
108
|
-
const { user, authStatus, auth } = (0, import_sdk.useHook)();
|
|
109
|
-
return {
|
|
110
|
-
user,
|
|
111
|
-
authStatus,
|
|
112
|
-
refresh: auth.refresh
|
|
113
|
-
};
|
|
238
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style, children });
|
|
114
239
|
}
|
|
115
240
|
|
|
116
|
-
// src/
|
|
117
|
-
var
|
|
118
|
-
|
|
119
|
-
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { role: "status", "aria-live": "polite", style: { padding: 24, textAlign: "center" }, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: message ?? "Carregando..." }) });
|
|
120
|
-
}
|
|
241
|
+
// src/hooks/usePaywallState.ts
|
|
242
|
+
var import_react5 = require("react");
|
|
243
|
+
var import_sdk2 = require("@hook-sdk/sdk");
|
|
121
244
|
|
|
122
|
-
// src/
|
|
123
|
-
var
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
(0, import_react2.useEffect)(() => {
|
|
140
|
-
const onPop = () => {
|
|
141
|
-
if (detectResetFromUrl()) setScreen("reset");
|
|
142
|
-
};
|
|
143
|
-
window.addEventListener("popstate", onPop);
|
|
144
|
-
return () => window.removeEventListener("popstate", onPop);
|
|
145
|
-
}, []);
|
|
146
|
-
if (authStatus === "loading") return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(LoadingState, {});
|
|
147
|
-
if (!user) {
|
|
148
|
-
if (screen === "reset") return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Reset, { onNavigate: setScreen });
|
|
149
|
-
if (screen === "signup") return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Signup, { onNavigate: setScreen });
|
|
150
|
-
if (screen === "forgot") return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Forgot, { onNavigate: setScreen });
|
|
151
|
-
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Login, { onNavigate: setScreen });
|
|
152
|
-
}
|
|
153
|
-
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_jsx_runtime4.Fragment, { children });
|
|
245
|
+
// src/errors/asaas-pt-br.ts
|
|
246
|
+
var MAP = {
|
|
247
|
+
invalid_cpf: "CPF inv\xE1lido. Confira os n\xFAmeros e tente novamente.",
|
|
248
|
+
cpf_required: "Por favor, informe seu CPF para continuar.",
|
|
249
|
+
card_declined: "Cart\xE3o recusado pela operadora. Tente outro cart\xE3o ou m\xE9todo.",
|
|
250
|
+
insufficient_funds: "Saldo insuficiente no cart\xE3o. Tente outro m\xE9todo.",
|
|
251
|
+
card_expired: "Cart\xE3o expirado. Use um cart\xE3o v\xE1lido.",
|
|
252
|
+
invalid_card_number: "N\xFAmero de cart\xE3o inv\xE1lido.",
|
|
253
|
+
invalid_cvv: "C\xF3digo de seguran\xE7a (CVV) inv\xE1lido.",
|
|
254
|
+
invalid_expiration: "Data de validade inv\xE1lida.",
|
|
255
|
+
generic_decline: "Pagamento recusado. Tente novamente em instantes ou use outro m\xE9todo.",
|
|
256
|
+
webhook_unverified: "N\xE3o conseguimos confirmar seu pagamento. Atualize a p\xE1gina em alguns segundos.",
|
|
257
|
+
pix_expired: "QR Code do PIX expirou. Gere um novo.",
|
|
258
|
+
pix_not_paid_yet: "PIX ainda n\xE3o foi pago. Aguardando confirma\xE7\xE3o."
|
|
259
|
+
};
|
|
260
|
+
function asaasErrorMessage(code) {
|
|
261
|
+
return MAP[code] ?? "Ocorreu um erro inesperado. Tente novamente em instantes.";
|
|
154
262
|
}
|
|
155
263
|
|
|
156
264
|
// src/hooks/usePaywallState.ts
|
|
157
|
-
|
|
158
|
-
|
|
265
|
+
function isCheckoutFailure(r) {
|
|
266
|
+
return "ok" in r && r.ok === false;
|
|
267
|
+
}
|
|
268
|
+
var FALLBACK_PAYWALL = {
|
|
269
|
+
mode: "pay_first",
|
|
270
|
+
cycles: ["MONTHLY"],
|
|
271
|
+
prices: { monthlyCents: 0, yearlyCents: 0 },
|
|
272
|
+
checkoutMethods: ["card", "pix-auto"],
|
|
273
|
+
requiresCpf: true,
|
|
274
|
+
errorMessages: "default"
|
|
275
|
+
};
|
|
276
|
+
var isMethodAvailable = (availability, method) => availability[method] !== false;
|
|
159
277
|
function usePaywallState() {
|
|
160
278
|
const { subscription, plan } = (0, import_sdk2.useHook)();
|
|
161
|
-
const
|
|
162
|
-
const
|
|
163
|
-
const
|
|
279
|
+
const configFromCtx = (0, import_react5.useContext)(AppConfigContext);
|
|
280
|
+
const paywall = configFromCtx?.paywall ?? FALLBACK_PAYWALL;
|
|
281
|
+
const isFree = paywall.mode === "free";
|
|
282
|
+
const declaredMethods = (0, import_react5.useMemo)(
|
|
283
|
+
() => isFree ? [] : paywall.checkoutMethods,
|
|
284
|
+
[isFree, paywall]
|
|
285
|
+
);
|
|
286
|
+
const availability = subscription.methodAvailability ?? {
|
|
287
|
+
card: null,
|
|
288
|
+
"pix-auto": null,
|
|
289
|
+
"pix-once": null
|
|
290
|
+
};
|
|
291
|
+
const methods = (0, import_react5.useMemo)(
|
|
292
|
+
() => declaredMethods.filter((m) => isMethodAvailable(availability, m)),
|
|
293
|
+
[declaredMethods, availability]
|
|
294
|
+
);
|
|
295
|
+
const defaultMethod = methods[0] ?? declaredMethods[0] ?? "card";
|
|
296
|
+
const [selectedMethodRaw, setSelectedMethod] = (0, import_react5.useState)(defaultMethod);
|
|
297
|
+
const selectedMethod = methods.includes(selectedMethodRaw) ? selectedMethodRaw : methods[0] ?? selectedMethodRaw;
|
|
298
|
+
const initialCycle = isFree ? "MONTHLY" : paywall.cycles[0] ?? "MONTHLY";
|
|
299
|
+
const [cycle, setCycle] = (0, import_react5.useState)(initialCycle);
|
|
300
|
+
const cpfRequired = !isFree && paywall.requiresCpf;
|
|
301
|
+
const [cpf, setCpf] = (0, import_react5.useState)("");
|
|
302
|
+
const cpfValid = (0, import_react5.useMemo)(() => /^[0-9]{11}$/.test(cpf), [cpf]);
|
|
303
|
+
const [card, setCardState] = (0, import_react5.useState)({
|
|
304
|
+
number: "",
|
|
305
|
+
cvv: "",
|
|
306
|
+
expiry: "",
|
|
307
|
+
holder: ""
|
|
308
|
+
});
|
|
309
|
+
const setCard = (0, import_react5.useCallback)((patch) => {
|
|
310
|
+
setCardState((prev) => ({ ...prev, ...patch }));
|
|
311
|
+
}, []);
|
|
312
|
+
const [error, setError] = (0, import_react5.useState)(null);
|
|
313
|
+
const [submitting, setSubmitting] = (0, import_react5.useState)(false);
|
|
164
314
|
const status = subscription.status();
|
|
165
315
|
const daysLeftInTrial = subscription.daysLeftInTrial();
|
|
166
316
|
const initialLoadComplete = subscription.initialLoadComplete;
|
|
167
|
-
const
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
317
|
+
const pixPending = (0, import_react5.useMemo)(() => {
|
|
318
|
+
const sdkPix = subscription.pixPending;
|
|
319
|
+
if (!sdkPix) return null;
|
|
320
|
+
const liveStatus = subscription.current?.status;
|
|
321
|
+
const paid = liveStatus === "ACTIVE" || liveStatus === "TRIAL";
|
|
322
|
+
return {
|
|
323
|
+
method: sdkPix.method,
|
|
324
|
+
qrCodePayload: sdkPix.qrCodePayload,
|
|
325
|
+
qrCodeBase64: sdkPix.qrCodeBase64,
|
|
326
|
+
expiresAt: null,
|
|
327
|
+
paid
|
|
328
|
+
};
|
|
329
|
+
}, [subscription.pixPending, subscription.current]);
|
|
330
|
+
const monthlyEquivalent = (0, import_react5.useCallback)(
|
|
331
|
+
(c) => {
|
|
332
|
+
const monthlyCents = plan.data?.priceCents ?? (isFree ? 0 : paywall.prices.monthlyCents);
|
|
333
|
+
const yearlyCents = plan.data?.yearlyPriceCents ?? (isFree ? null : paywall.prices.yearlyCents);
|
|
334
|
+
if (c === "YEARLY" && yearlyCents) return Math.round(yearlyCents / 12);
|
|
335
|
+
return monthlyCents;
|
|
179
336
|
},
|
|
180
|
-
[
|
|
337
|
+
[plan, paywall, isFree]
|
|
181
338
|
);
|
|
182
|
-
const
|
|
339
|
+
const planDerived = (0, import_react5.useMemo)(() => {
|
|
340
|
+
if (isFree) return null;
|
|
341
|
+
const monthlyCents = paywall.prices.monthlyCents;
|
|
342
|
+
const yearlyCents = paywall.prices.yearlyCents;
|
|
343
|
+
const anchor = paywall.anchorPrices;
|
|
344
|
+
const discount = anchor && anchor.yearlyCents > 0 ? Math.round((1 - paywall.prices.yearlyCents / anchor.yearlyCents) * 100) : 0;
|
|
345
|
+
return {
|
|
346
|
+
monthlyCents,
|
|
347
|
+
yearlyCents,
|
|
348
|
+
anchorMonthlyCents: anchor?.monthlyCents,
|
|
349
|
+
anchorYearlyCents: anchor?.yearlyCents,
|
|
350
|
+
monthlyEquivalent: cycle === "YEARLY" ? Math.round(yearlyCents / 12) : monthlyCents,
|
|
351
|
+
discountPercent: discount
|
|
352
|
+
};
|
|
353
|
+
}, [paywall, cycle, isFree]);
|
|
354
|
+
const useDefaultMessages = paywall.mode !== "free" && paywall.errorMessages === "default";
|
|
355
|
+
const buildError = (0, import_react5.useCallback)(
|
|
356
|
+
(code, fallbackMessage) => ({
|
|
357
|
+
code,
|
|
358
|
+
message: fallbackMessage,
|
|
359
|
+
userMessage: useDefaultMessages ? asaasErrorMessage(code) : fallbackMessage
|
|
360
|
+
}),
|
|
361
|
+
[useDefaultMessages]
|
|
362
|
+
);
|
|
363
|
+
const submit = (0, import_react5.useCallback)(async () => {
|
|
364
|
+
setSubmitting(true);
|
|
365
|
+
setError(null);
|
|
366
|
+
const methodToUse = selectedMethod;
|
|
367
|
+
if (!isMethodAvailable(availability, methodToUse)) {
|
|
368
|
+
const code = "method_unavailable";
|
|
369
|
+
setError(buildError(code, `method ${methodToUse} unavailable`));
|
|
370
|
+
setSubmitting(false);
|
|
371
|
+
return {
|
|
372
|
+
ok: false,
|
|
373
|
+
code: "method_unavailable",
|
|
374
|
+
method: methodToUse,
|
|
375
|
+
reason: "pre_flight_unavailable"
|
|
376
|
+
};
|
|
377
|
+
}
|
|
378
|
+
try {
|
|
379
|
+
let result;
|
|
380
|
+
if (methodToUse === "card") {
|
|
381
|
+
const [expMonthRaw = "", expYearRaw = ""] = card.expiry.split("/");
|
|
382
|
+
const expYearTrimmed = expYearRaw.trim();
|
|
383
|
+
const cardData = {
|
|
384
|
+
number: card.number,
|
|
385
|
+
holderName: card.holder,
|
|
386
|
+
expiryMonth: expMonthRaw.trim(),
|
|
387
|
+
expiryYear: expYearTrimmed.length === 2 ? `20${expYearTrimmed}` : expYearTrimmed,
|
|
388
|
+
ccv: card.cvv
|
|
389
|
+
};
|
|
390
|
+
const holderInfo = {
|
|
391
|
+
name: card.holder,
|
|
392
|
+
email: "",
|
|
393
|
+
cpfCnpj: cpf,
|
|
394
|
+
postalCode: "",
|
|
395
|
+
addressNumber: ""
|
|
396
|
+
};
|
|
397
|
+
result = await subscription.checkout({
|
|
398
|
+
method: "card",
|
|
399
|
+
cycle,
|
|
400
|
+
cpf,
|
|
401
|
+
card: cardData,
|
|
402
|
+
holderInfo
|
|
403
|
+
});
|
|
404
|
+
} else if (methodToUse === "pix-auto") {
|
|
405
|
+
result = await subscription.checkout({ method: "pix-auto", cycle, cpf });
|
|
406
|
+
} else {
|
|
407
|
+
result = await subscription.checkout({ method: "pix-once", cycle, cpf });
|
|
408
|
+
}
|
|
409
|
+
if (isCheckoutFailure(result)) {
|
|
410
|
+
setError(buildError(result.code, `${result.code}: ${result.reason}`));
|
|
411
|
+
setSubmitting(false);
|
|
412
|
+
return result;
|
|
413
|
+
}
|
|
414
|
+
await subscription.refresh();
|
|
415
|
+
setSubmitting(false);
|
|
416
|
+
return result;
|
|
417
|
+
} catch (err) {
|
|
418
|
+
const code = err?.code ?? "generic_decline";
|
|
419
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
420
|
+
setError(buildError(code, message));
|
|
421
|
+
setSubmitting(false);
|
|
422
|
+
return void 0;
|
|
423
|
+
}
|
|
424
|
+
}, [selectedMethod, availability, subscription, cycle, cpf, card, buildError]);
|
|
425
|
+
const checkout = (0, import_react5.useCallback)(
|
|
183
426
|
async (args) => {
|
|
184
|
-
|
|
427
|
+
setSubmitting(true);
|
|
185
428
|
setError(null);
|
|
186
|
-
setPixPending(null);
|
|
187
429
|
try {
|
|
188
430
|
if (args.method === "card") {
|
|
189
431
|
if (!args.card || !args.holderInfo) {
|
|
190
|
-
throw
|
|
432
|
+
throw Object.assign(
|
|
433
|
+
new Error('card and holderInfo are required when method is "card"'),
|
|
434
|
+
{ code: "validation" }
|
|
435
|
+
);
|
|
191
436
|
}
|
|
192
|
-
|
|
437
|
+
const sdkArgs = {
|
|
193
438
|
method: "card",
|
|
194
439
|
cycle: args.cycle,
|
|
195
440
|
cpf: args.cpf,
|
|
196
441
|
card: args.card,
|
|
197
442
|
holderInfo: args.holderInfo,
|
|
198
443
|
...args.remoteIp ? { remoteIp: args.remoteIp } : {}
|
|
199
|
-
}
|
|
444
|
+
};
|
|
445
|
+
const result2 = await subscription.checkout(sdkArgs);
|
|
446
|
+
if (isCheckoutFailure(result2)) {
|
|
447
|
+
setError(buildError(result2.code, `${result2.code}: ${result2.reason}`));
|
|
448
|
+
setSubmitting(false);
|
|
449
|
+
return;
|
|
450
|
+
}
|
|
200
451
|
await subscription.refresh();
|
|
201
|
-
|
|
452
|
+
setSubmitting(false);
|
|
453
|
+
return;
|
|
454
|
+
}
|
|
455
|
+
if (args.method === "pix-auto") {
|
|
456
|
+
const result2 = await subscription.checkout({
|
|
457
|
+
method: "pix-auto",
|
|
458
|
+
cycle: args.cycle,
|
|
459
|
+
cpf: args.cpf
|
|
460
|
+
});
|
|
461
|
+
if (isCheckoutFailure(result2)) {
|
|
462
|
+
setError(buildError(result2.code, `${result2.code}: ${result2.reason}`));
|
|
463
|
+
setSubmitting(false);
|
|
464
|
+
return;
|
|
465
|
+
}
|
|
466
|
+
setSubmitting(false);
|
|
202
467
|
return;
|
|
203
468
|
}
|
|
204
469
|
const result = await subscription.checkout({
|
|
205
|
-
method: "pix-
|
|
470
|
+
method: "pix-once",
|
|
206
471
|
cycle: args.cycle,
|
|
207
472
|
cpf: args.cpf
|
|
208
473
|
});
|
|
209
|
-
if (result
|
|
210
|
-
|
|
474
|
+
if (isCheckoutFailure(result)) {
|
|
475
|
+
setError(buildError(result.code, `${result.code}: ${result.reason}`));
|
|
476
|
+
setSubmitting(false);
|
|
477
|
+
return;
|
|
211
478
|
}
|
|
212
|
-
|
|
213
|
-
method: "pix-auto",
|
|
214
|
-
qrCodePayload: result.qrCodePayload,
|
|
215
|
-
qrCodeBase64: result.qrCodeBase64,
|
|
216
|
-
expiresAt: null,
|
|
217
|
-
paid: false
|
|
218
|
-
});
|
|
219
|
-
setOpening(false);
|
|
479
|
+
setSubmitting(false);
|
|
220
480
|
} catch (err) {
|
|
221
|
-
|
|
222
|
-
|
|
481
|
+
const code = err?.code ?? "generic_decline";
|
|
482
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
483
|
+
setError(buildError(code, message));
|
|
484
|
+
setSubmitting(false);
|
|
223
485
|
}
|
|
224
486
|
},
|
|
225
|
-
[subscription]
|
|
487
|
+
[subscription, buildError]
|
|
226
488
|
);
|
|
227
|
-
const cancel = (0,
|
|
489
|
+
const cancel = (0, import_react5.useCallback)(async () => {
|
|
228
490
|
try {
|
|
229
491
|
await subscription.cancel();
|
|
230
492
|
await subscription.refresh();
|
|
231
493
|
} catch (err) {
|
|
232
|
-
|
|
494
|
+
const code = err?.code ?? "generic_decline";
|
|
495
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
496
|
+
setError(buildError(code, message));
|
|
233
497
|
}
|
|
234
|
-
}, [subscription]);
|
|
235
|
-
const
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
const tick = async () => {
|
|
244
|
-
if (cancelled || attempts >= MAX_ATTEMPTS) return;
|
|
245
|
-
attempts++;
|
|
246
|
-
try {
|
|
247
|
-
await subRef.current.refresh();
|
|
248
|
-
if (cancelled) return;
|
|
249
|
-
const s = subRef.current.status();
|
|
250
|
-
if (s === "active" || s === "trialing") {
|
|
251
|
-
setPixPending((prev) => prev ? { ...prev, paid: true } : prev);
|
|
252
|
-
return;
|
|
253
|
-
}
|
|
254
|
-
} catch {
|
|
255
|
-
}
|
|
256
|
-
if (!cancelled) setTimeout(tick, 3e3);
|
|
257
|
-
};
|
|
258
|
-
setTimeout(tick, 3e3);
|
|
259
|
-
return () => {
|
|
260
|
-
cancelled = true;
|
|
261
|
-
};
|
|
262
|
-
}, [pixPending]);
|
|
498
|
+
}, [subscription, buildError]);
|
|
499
|
+
const cardState = (0, import_react5.useMemo)(
|
|
500
|
+
() => ({ ...card, set: setCard }),
|
|
501
|
+
[card, setCard]
|
|
502
|
+
);
|
|
503
|
+
const cpfState = (0, import_react5.useMemo)(
|
|
504
|
+
() => ({ required: cpfRequired, value: cpf, set: setCpf, valid: cpfValid }),
|
|
505
|
+
[cpfRequired, cpf, cpfValid]
|
|
506
|
+
);
|
|
263
507
|
return {
|
|
508
|
+
// Subscription status (reactive, proxied from SDK)
|
|
264
509
|
status,
|
|
265
510
|
daysLeftInTrial,
|
|
266
511
|
initialLoadComplete,
|
|
512
|
+
// Plan derivation from config (sync, no fetch)
|
|
513
|
+
plan: planDerived,
|
|
514
|
+
// Cycle + method selection
|
|
515
|
+
cycle,
|
|
516
|
+
setCycle,
|
|
517
|
+
methods,
|
|
518
|
+
selectedMethod,
|
|
519
|
+
setSelectedMethod,
|
|
520
|
+
// Form state
|
|
521
|
+
cpfState,
|
|
522
|
+
cardState,
|
|
523
|
+
// High-level + legacy actions
|
|
524
|
+
submit,
|
|
267
525
|
checkout,
|
|
268
526
|
cancel,
|
|
269
|
-
|
|
270
|
-
error,
|
|
527
|
+
// PIX state (proxied from SDK; legacy `paid`/`expiresAt` derived)
|
|
271
528
|
pixPending,
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
529
|
+
// Error + submit progress
|
|
530
|
+
error,
|
|
531
|
+
submitting,
|
|
532
|
+
// Backward-compat aliases (deprecated; remove in template 0.11)
|
|
533
|
+
opening: submitting,
|
|
534
|
+
availableMethods: methods,
|
|
535
|
+
monthlyEquivalent,
|
|
536
|
+
dismissPix: () => {
|
|
537
|
+
},
|
|
538
|
+
refreshPlan: () => {
|
|
539
|
+
}
|
|
275
540
|
};
|
|
276
541
|
}
|
|
277
542
|
|
|
@@ -292,51 +557,11 @@ function SubscriptionGate({ Paywall, children }) {
|
|
|
292
557
|
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_jsx_runtime5.Fragment, { children });
|
|
293
558
|
}
|
|
294
559
|
|
|
295
|
-
// src/internal/PersistedKeysPrefetch.tsx
|
|
296
|
-
var import_react4 = require("react");
|
|
297
|
-
var import_sdk3 = require("@hook-sdk/sdk");
|
|
298
|
-
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
299
|
-
var SAFETY_TIMEOUT_MS = 3e3;
|
|
300
|
-
function PersistedKeysPrefetch({ children }) {
|
|
301
|
-
const { appData } = (0, import_sdk3.useHook)();
|
|
302
|
-
const config = useTemplateConfig();
|
|
303
|
-
const hasKeys = !!config.persistedKeys && config.persistedKeys.length > 0;
|
|
304
|
-
const [ready, setReady] = (0, import_react4.useState)(!hasKeys);
|
|
305
|
-
(0, import_react4.useEffect)(() => {
|
|
306
|
-
const keys = config.persistedKeys;
|
|
307
|
-
if (!keys || keys.length === 0) {
|
|
308
|
-
setReady(true);
|
|
309
|
-
return;
|
|
310
|
-
}
|
|
311
|
-
let cancelled = false;
|
|
312
|
-
appData.cache.startPrefetch(keys, (ks) => appData.bulkRead(ks));
|
|
313
|
-
void appData.cache.waitForPrimed(SAFETY_TIMEOUT_MS).then((result) => {
|
|
314
|
-
if (cancelled) return;
|
|
315
|
-
if (result === "timeout") {
|
|
316
|
-
console.warn(
|
|
317
|
-
`[@hook-sdk/template] PersistedKeysPrefetch: bulk-read n\xE3o completou em ${SAFETY_TIMEOUT_MS}ms. Liberando render mesmo assim \u2014 usePersistedState pode expor defaultValue at\xE9 o fetch terminar (G77).`
|
|
318
|
-
);
|
|
319
|
-
}
|
|
320
|
-
setReady(true);
|
|
321
|
-
});
|
|
322
|
-
return () => {
|
|
323
|
-
cancelled = true;
|
|
324
|
-
};
|
|
325
|
-
}, [appData, config.persistedKeys]);
|
|
326
|
-
if (!ready) return null;
|
|
327
|
-
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_jsx_runtime6.Fragment, { children });
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
// src/internal/PushPrompt.tsx
|
|
331
|
-
function PushPrompt() {
|
|
332
|
-
return null;
|
|
333
|
-
}
|
|
334
|
-
|
|
335
560
|
// src/components/InstallGate/InstallGate.tsx
|
|
336
|
-
var
|
|
561
|
+
var import_react8 = require("react");
|
|
337
562
|
|
|
338
563
|
// src/hooks/useInstallPrompt.ts
|
|
339
|
-
var
|
|
564
|
+
var import_react6 = require("react");
|
|
340
565
|
var IOS_RE = /iPad|iPhone|iPod/;
|
|
341
566
|
var IOS_NON_SAFARI_RE = /CriOS|FxiOS|EdgiOS/;
|
|
342
567
|
var ANDROID_RE = /Android/;
|
|
@@ -469,18 +694,18 @@ function useInstallPrompt(slug) {
|
|
|
469
694
|
const iosBrowser = detectIOSBrowser(ua);
|
|
470
695
|
const androidBrowser = detectAndroidBrowser(ua);
|
|
471
696
|
const inAppApp = detectInAppApp(ua);
|
|
472
|
-
const [isInstallable, setIsInstallable] = (0,
|
|
697
|
+
const [isInstallable, setIsInstallable] = (0, import_react6.useState)(() => {
|
|
473
698
|
if (typeof window === "undefined") return false;
|
|
474
699
|
return window.__pwaInstallPrompt != null;
|
|
475
700
|
});
|
|
476
|
-
const [isInstalled, setIsInstalled] = (0,
|
|
701
|
+
const [isInstalled, setIsInstalled] = (0, import_react6.useState)(() => {
|
|
477
702
|
const { installed } = detectStandalone();
|
|
478
703
|
return installed || readInstalledMarker(slug);
|
|
479
704
|
});
|
|
480
|
-
const [isDismissedSession, setIsDismissedSession] = (0,
|
|
481
|
-
const [isDismissedPermanent, setIsDismissedPermanent] = (0,
|
|
482
|
-
const [skipCount, setSkipCount] = (0,
|
|
483
|
-
(0,
|
|
705
|
+
const [isDismissedSession, setIsDismissedSession] = (0, import_react6.useState)(() => readSessionSkip(slug));
|
|
706
|
+
const [isDismissedPermanent, setIsDismissedPermanent] = (0, import_react6.useState)(() => readPermanentDismiss(slug).dismissed);
|
|
707
|
+
const [skipCount, setSkipCount] = (0, import_react6.useState)(() => readSkipCount(slug));
|
|
708
|
+
(0, import_react6.useEffect)(() => {
|
|
484
709
|
if (typeof window === "undefined") return;
|
|
485
710
|
if (window.__pwaInstallPrompt) {
|
|
486
711
|
setIsInstallable(true);
|
|
@@ -504,7 +729,7 @@ function useInstallPrompt(slug) {
|
|
|
504
729
|
window.removeEventListener("appinstalled", onInstalled);
|
|
505
730
|
};
|
|
506
731
|
}, [slug]);
|
|
507
|
-
(0,
|
|
732
|
+
(0, import_react6.useEffect)(() => {
|
|
508
733
|
if (typeof window === "undefined") return;
|
|
509
734
|
const mq = window.matchMedia?.("(display-mode: standalone)");
|
|
510
735
|
if (!mq) return;
|
|
@@ -528,7 +753,7 @@ function useInstallPrompt(slug) {
|
|
|
528
753
|
isDismissedPermanent,
|
|
529
754
|
skipCount
|
|
530
755
|
});
|
|
531
|
-
const promptInstall = (0,
|
|
756
|
+
const promptInstall = (0, import_react6.useCallback)(async () => {
|
|
532
757
|
if (typeof window === "undefined") return false;
|
|
533
758
|
const prompt = window.__pwaInstallPrompt;
|
|
534
759
|
if (!prompt) return false;
|
|
@@ -550,7 +775,7 @@ function useInstallPrompt(slug) {
|
|
|
550
775
|
return false;
|
|
551
776
|
}
|
|
552
777
|
}, [slug]);
|
|
553
|
-
const dismissSession = (0,
|
|
778
|
+
const dismissSession = (0, import_react6.useCallback)(() => {
|
|
554
779
|
if (typeof sessionStorage !== "undefined") {
|
|
555
780
|
try {
|
|
556
781
|
sessionStorage.setItem(storageKey.sessionSkip(slug), "true");
|
|
@@ -564,20 +789,20 @@ function useInstallPrompt(slug) {
|
|
|
564
789
|
setIsDismissedSession(true);
|
|
565
790
|
track("pwa_install_session_skip", { slug, platform, skip_count: newCount });
|
|
566
791
|
}, [slug, skipCount, platform]);
|
|
567
|
-
const dismissPermanent = (0,
|
|
792
|
+
const dismissPermanent = (0, import_react6.useCallback)(() => {
|
|
568
793
|
const storage = safeStorage();
|
|
569
794
|
if (storage) storage.setItem(storageKey.dismissedAt(slug), (/* @__PURE__ */ new Date()).toISOString());
|
|
570
795
|
setIsDismissedPermanent(true);
|
|
571
796
|
track("pwa_install_permanent_dismiss", { slug, platform, prior_skip_count: skipCount });
|
|
572
797
|
}, [slug, platform, skipCount]);
|
|
573
|
-
const copyLink = (0,
|
|
798
|
+
const copyLink = (0, import_react6.useCallback)(async () => {
|
|
574
799
|
if (typeof navigator === "undefined" || typeof location === "undefined") return;
|
|
575
800
|
try {
|
|
576
801
|
await navigator.clipboard?.writeText?.(location.href);
|
|
577
802
|
} catch {
|
|
578
803
|
}
|
|
579
804
|
}, []);
|
|
580
|
-
const reset = (0,
|
|
805
|
+
const reset = (0, import_react6.useCallback)(() => {
|
|
581
806
|
const storage = safeStorage();
|
|
582
807
|
if (storage) {
|
|
583
808
|
storage.removeItem(storageKey.dismissedAt(slug));
|
|
@@ -759,11 +984,11 @@ var INSTALL_COPY = {
|
|
|
759
984
|
};
|
|
760
985
|
|
|
761
986
|
// src/components/InstallGate/InstallSplash.tsx
|
|
762
|
-
var
|
|
987
|
+
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
763
988
|
function InstallSplash({ children, title, subtitle }) {
|
|
764
989
|
const { name, theme } = useTemplateConfig();
|
|
765
990
|
const iconUrl = theme.icon_url || theme.logo_url || null;
|
|
766
|
-
return /* @__PURE__ */ (0,
|
|
991
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
767
992
|
"div",
|
|
768
993
|
{
|
|
769
994
|
role: "dialog",
|
|
@@ -771,15 +996,15 @@ function InstallSplash({ children, title, subtitle }) {
|
|
|
771
996
|
"aria-labelledby": "install-splash-title",
|
|
772
997
|
"aria-describedby": subtitle ? "install-splash-subtitle" : void 0,
|
|
773
998
|
style: overlayStyle,
|
|
774
|
-
children: /* @__PURE__ */ (0,
|
|
775
|
-
/* @__PURE__ */ (0,
|
|
999
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: cardStyle, children: [
|
|
1000
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: { display: "flex", justifyContent: "center", marginBottom: 16 }, children: iconUrl ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
776
1001
|
"img",
|
|
777
1002
|
{
|
|
778
1003
|
src: iconUrl,
|
|
779
1004
|
alt: `\xCDcone de ${name}`,
|
|
780
1005
|
style: { width: 80, height: 80, borderRadius: 20, objectFit: "cover" }
|
|
781
1006
|
}
|
|
782
|
-
) : /* @__PURE__ */ (0,
|
|
1007
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
783
1008
|
"div",
|
|
784
1009
|
{
|
|
785
1010
|
style: {
|
|
@@ -797,10 +1022,10 @@ function InstallSplash({ children, title, subtitle }) {
|
|
|
797
1022
|
children: name.charAt(0).toUpperCase()
|
|
798
1023
|
}
|
|
799
1024
|
) }),
|
|
800
|
-
/* @__PURE__ */ (0,
|
|
801
|
-
subtitle && /* @__PURE__ */ (0,
|
|
802
|
-
/* @__PURE__ */ (0,
|
|
803
|
-
/* @__PURE__ */ (0,
|
|
1025
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("h1", { id: "install-splash-title", style: titleStyle, children: title }),
|
|
1026
|
+
subtitle && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { id: "install-splash-subtitle", style: subtitleStyle, children: subtitle }),
|
|
1027
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: { marginTop: 24 }, children }),
|
|
1028
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { style: footerStyle, children: "por Hook" })
|
|
804
1029
|
] })
|
|
805
1030
|
}
|
|
806
1031
|
);
|
|
@@ -874,7 +1099,7 @@ var footerStyle = {
|
|
|
874
1099
|
};
|
|
875
1100
|
|
|
876
1101
|
// src/components/InstallGate/icons.tsx
|
|
877
|
-
var
|
|
1102
|
+
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
878
1103
|
var defaultSvgProps = (size) => ({
|
|
879
1104
|
width: size,
|
|
880
1105
|
height: size,
|
|
@@ -886,64 +1111,64 @@ var defaultSvgProps = (size) => ({
|
|
|
886
1111
|
strokeLinejoin: "round"
|
|
887
1112
|
});
|
|
888
1113
|
function ShareIconIOS({ size = 24, style, className }) {
|
|
889
|
-
return /* @__PURE__ */ (0,
|
|
890
|
-
/* @__PURE__ */ (0,
|
|
891
|
-
/* @__PURE__ */ (0,
|
|
892
|
-
/* @__PURE__ */ (0,
|
|
1114
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("svg", { ...defaultSvgProps(size), style, className, "aria-hidden": "true", children: [
|
|
1115
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("path", { d: "M12 2L12 15" }),
|
|
1116
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("path", { d: "M8 6L12 2L16 6" }),
|
|
1117
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("path", { d: "M4 11v9a2 2 0 002 2h12a2 2 0 002-2v-9" })
|
|
893
1118
|
] });
|
|
894
1119
|
}
|
|
895
1120
|
function MenuDotsVerticalIcon({ size = 24, style, className }) {
|
|
896
|
-
return /* @__PURE__ */ (0,
|
|
897
|
-
/* @__PURE__ */ (0,
|
|
898
|
-
/* @__PURE__ */ (0,
|
|
899
|
-
/* @__PURE__ */ (0,
|
|
1121
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("svg", { ...defaultSvgProps(size), style, className, "aria-hidden": "true", children: [
|
|
1122
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("circle", { cx: "12", cy: "5", r: "1.5" }),
|
|
1123
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("circle", { cx: "12", cy: "12", r: "1.5" }),
|
|
1124
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("circle", { cx: "12", cy: "19", r: "1.5" })
|
|
900
1125
|
] });
|
|
901
1126
|
}
|
|
902
1127
|
function MenuDotsHorizontalIcon({ size = 24, style, className }) {
|
|
903
|
-
return /* @__PURE__ */ (0,
|
|
904
|
-
/* @__PURE__ */ (0,
|
|
905
|
-
/* @__PURE__ */ (0,
|
|
906
|
-
/* @__PURE__ */ (0,
|
|
1128
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("svg", { ...defaultSvgProps(size), style, className, "aria-hidden": "true", children: [
|
|
1129
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("circle", { cx: "5", cy: "12", r: "1.5" }),
|
|
1130
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("circle", { cx: "12", cy: "12", r: "1.5" }),
|
|
1131
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("circle", { cx: "19", cy: "12", r: "1.5" })
|
|
907
1132
|
] });
|
|
908
1133
|
}
|
|
909
1134
|
function SquarePlusIcon({ size = 24, style, className }) {
|
|
910
|
-
return /* @__PURE__ */ (0,
|
|
911
|
-
/* @__PURE__ */ (0,
|
|
912
|
-
/* @__PURE__ */ (0,
|
|
913
|
-
/* @__PURE__ */ (0,
|
|
1135
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("svg", { ...defaultSvgProps(size), style, className, "aria-hidden": "true", children: [
|
|
1136
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("rect", { x: "3", y: "3", width: "18", height: "18", rx: "2" }),
|
|
1137
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("path", { d: "M12 8v8" }),
|
|
1138
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("path", { d: "M8 12h8" })
|
|
914
1139
|
] });
|
|
915
1140
|
}
|
|
916
1141
|
function DownloadIcon({ size = 24, style, className }) {
|
|
917
|
-
return /* @__PURE__ */ (0,
|
|
918
|
-
/* @__PURE__ */ (0,
|
|
919
|
-
/* @__PURE__ */ (0,
|
|
920
|
-
/* @__PURE__ */ (0,
|
|
1142
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("svg", { ...defaultSvgProps(size), style, className, "aria-hidden": "true", children: [
|
|
1143
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("path", { d: "M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4" }),
|
|
1144
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("polyline", { points: "7 10 12 15 17 10" }),
|
|
1145
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("line", { x1: "12", y1: "15", x2: "12", y2: "3" })
|
|
921
1146
|
] });
|
|
922
1147
|
}
|
|
923
1148
|
function ExternalLinkIcon({ size = 24, style, className }) {
|
|
924
|
-
return /* @__PURE__ */ (0,
|
|
925
|
-
/* @__PURE__ */ (0,
|
|
926
|
-
/* @__PURE__ */ (0,
|
|
927
|
-
/* @__PURE__ */ (0,
|
|
1149
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("svg", { ...defaultSvgProps(size), style, className, "aria-hidden": "true", children: [
|
|
1150
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("path", { d: "M18 13v6a2 2 0 01-2 2H5a2 2 0 01-2-2V8a2 2 0 012-2h6" }),
|
|
1151
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("polyline", { points: "15 3 21 3 21 9" }),
|
|
1152
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("line", { x1: "10", y1: "14", x2: "21", y2: "3" })
|
|
928
1153
|
] });
|
|
929
1154
|
}
|
|
930
1155
|
function XIcon({ size = 20, style, className }) {
|
|
931
|
-
return /* @__PURE__ */ (0,
|
|
932
|
-
/* @__PURE__ */ (0,
|
|
933
|
-
/* @__PURE__ */ (0,
|
|
1156
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("svg", { ...defaultSvgProps(size), style, className, "aria-hidden": "true", children: [
|
|
1157
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
|
|
1158
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
|
|
934
1159
|
] });
|
|
935
1160
|
}
|
|
936
1161
|
|
|
937
1162
|
// src/components/InstallGate/variants/AndroidNativeVariant.tsx
|
|
938
|
-
var
|
|
1163
|
+
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
939
1164
|
function AndroidNativeVariant({
|
|
940
1165
|
state,
|
|
941
1166
|
actions
|
|
942
1167
|
}) {
|
|
943
1168
|
const copy = INSTALL_COPY.android.native;
|
|
944
1169
|
const showPermanent = shouldShowPermanentOption(state);
|
|
945
|
-
return /* @__PURE__ */ (0,
|
|
946
|
-
/* @__PURE__ */ (0,
|
|
1170
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(InstallSplash, { title: copy.title, subtitle: copy.subtitle, children: [
|
|
1171
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
|
|
947
1172
|
"button",
|
|
948
1173
|
{
|
|
949
1174
|
"data-testid": "install-prompt-cta-android-native",
|
|
@@ -951,12 +1176,12 @@ function AndroidNativeVariant({
|
|
|
951
1176
|
onClick: () => void actions.promptInstall(),
|
|
952
1177
|
style: { ...primaryButtonStyle, display: "inline-flex", alignItems: "center", justifyContent: "center", gap: 8 },
|
|
953
1178
|
children: [
|
|
954
|
-
/* @__PURE__ */ (0,
|
|
1179
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(DownloadIcon, { size: 18 }),
|
|
955
1180
|
copy.cta
|
|
956
1181
|
]
|
|
957
1182
|
}
|
|
958
1183
|
),
|
|
959
|
-
/* @__PURE__ */ (0,
|
|
1184
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
960
1185
|
"button",
|
|
961
1186
|
{
|
|
962
1187
|
"data-testid": "install-prompt-skip-session",
|
|
@@ -966,7 +1191,7 @@ function AndroidNativeVariant({
|
|
|
966
1191
|
children: copy.skip
|
|
967
1192
|
}
|
|
968
1193
|
),
|
|
969
|
-
showPermanent && /* @__PURE__ */ (0,
|
|
1194
|
+
showPermanent && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
970
1195
|
"button",
|
|
971
1196
|
{
|
|
972
1197
|
"data-testid": "install-prompt-skip-permanent",
|
|
@@ -980,17 +1205,17 @@ function AndroidNativeVariant({
|
|
|
980
1205
|
}
|
|
981
1206
|
|
|
982
1207
|
// src/components/InstallGate/variants/AndroidManualVariant.tsx
|
|
983
|
-
var
|
|
1208
|
+
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
984
1209
|
function AndroidManualVariant({
|
|
985
1210
|
state,
|
|
986
1211
|
actions
|
|
987
1212
|
}) {
|
|
988
1213
|
const copy = INSTALL_COPY.android.manual;
|
|
989
1214
|
const showPermanent = shouldShowPermanentOption(state);
|
|
990
|
-
return /* @__PURE__ */ (0,
|
|
991
|
-
/* @__PURE__ */ (0,
|
|
992
|
-
/* @__PURE__ */ (0,
|
|
993
|
-
/* @__PURE__ */ (0,
|
|
1215
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(InstallSplash, { title: copy.title, children: [
|
|
1216
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Step, { n: 1, icon: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(MenuDotsVerticalIcon, { size: 20 }), children: copy.step1 }),
|
|
1217
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Step, { n: 2, icon: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(DownloadIcon, { size: 18 }), children: copy.step2 }),
|
|
1218
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
994
1219
|
"button",
|
|
995
1220
|
{
|
|
996
1221
|
"data-testid": "install-prompt-cta-android-manual",
|
|
@@ -1000,7 +1225,7 @@ function AndroidManualVariant({
|
|
|
1000
1225
|
children: copy.cta
|
|
1001
1226
|
}
|
|
1002
1227
|
),
|
|
1003
|
-
/* @__PURE__ */ (0,
|
|
1228
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1004
1229
|
"button",
|
|
1005
1230
|
{
|
|
1006
1231
|
"data-testid": "install-prompt-skip-session",
|
|
@@ -1010,7 +1235,7 @@ function AndroidManualVariant({
|
|
|
1010
1235
|
children: copy.skip
|
|
1011
1236
|
}
|
|
1012
1237
|
),
|
|
1013
|
-
showPermanent && /* @__PURE__ */ (0,
|
|
1238
|
+
showPermanent && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1014
1239
|
"button",
|
|
1015
1240
|
{
|
|
1016
1241
|
"data-testid": "install-prompt-skip-permanent",
|
|
@@ -1023,7 +1248,7 @@ function AndroidManualVariant({
|
|
|
1023
1248
|
] });
|
|
1024
1249
|
}
|
|
1025
1250
|
function Step({ n, icon, children }) {
|
|
1026
|
-
return /* @__PURE__ */ (0,
|
|
1251
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
|
|
1027
1252
|
"div",
|
|
1028
1253
|
{
|
|
1029
1254
|
style: {
|
|
@@ -1037,7 +1262,7 @@ function Step({ n, icon, children }) {
|
|
|
1037
1262
|
textAlign: "left"
|
|
1038
1263
|
},
|
|
1039
1264
|
children: [
|
|
1040
|
-
/* @__PURE__ */ (0,
|
|
1265
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1041
1266
|
"div",
|
|
1042
1267
|
{
|
|
1043
1268
|
style: {
|
|
@@ -1056,22 +1281,22 @@ function Step({ n, icon, children }) {
|
|
|
1056
1281
|
children: n
|
|
1057
1282
|
}
|
|
1058
1283
|
),
|
|
1059
|
-
/* @__PURE__ */ (0,
|
|
1060
|
-
/* @__PURE__ */ (0,
|
|
1284
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { style: { flex: 1, fontSize: 15, color: "#333" }, children }),
|
|
1285
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { style: { color: "#888", flexShrink: 0 }, children: icon })
|
|
1061
1286
|
]
|
|
1062
1287
|
}
|
|
1063
1288
|
);
|
|
1064
1289
|
}
|
|
1065
1290
|
|
|
1066
1291
|
// src/components/InstallGate/Step.tsx
|
|
1067
|
-
var
|
|
1292
|
+
var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
1068
1293
|
function Step2({
|
|
1069
1294
|
n,
|
|
1070
1295
|
title,
|
|
1071
1296
|
subtitle,
|
|
1072
1297
|
visual
|
|
1073
1298
|
}) {
|
|
1074
|
-
return /* @__PURE__ */ (0,
|
|
1299
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
|
|
1075
1300
|
"div",
|
|
1076
1301
|
{
|
|
1077
1302
|
style: {
|
|
@@ -1082,7 +1307,7 @@ function Step2({
|
|
|
1082
1307
|
textAlign: "left"
|
|
1083
1308
|
},
|
|
1084
1309
|
children: [
|
|
1085
|
-
/* @__PURE__ */ (0,
|
|
1310
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
1086
1311
|
"div",
|
|
1087
1312
|
{
|
|
1088
1313
|
style: {
|
|
@@ -1101,9 +1326,9 @@ function Step2({
|
|
|
1101
1326
|
children: n
|
|
1102
1327
|
}
|
|
1103
1328
|
),
|
|
1104
|
-
/* @__PURE__ */ (0,
|
|
1105
|
-
/* @__PURE__ */ (0,
|
|
1106
|
-
subtitle && /* @__PURE__ */ (0,
|
|
1329
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { style: { flex: 1 }, children: [
|
|
1330
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { style: { margin: 0, fontSize: 15, fontWeight: 500, color: "#111", lineHeight: 1.3 }, children: title }),
|
|
1331
|
+
subtitle && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { style: { margin: "4px 0 0 0", fontSize: 13, color: "#777" }, children: subtitle }),
|
|
1107
1332
|
visual
|
|
1108
1333
|
] })
|
|
1109
1334
|
]
|
|
@@ -1112,21 +1337,21 @@ function Step2({
|
|
|
1112
1337
|
}
|
|
1113
1338
|
|
|
1114
1339
|
// src/components/InstallGate/variants/IOSafariVariant.tsx
|
|
1115
|
-
var
|
|
1340
|
+
var import_jsx_runtime11 = require("react/jsx-runtime");
|
|
1116
1341
|
function IOSafariVariant({
|
|
1117
1342
|
state,
|
|
1118
1343
|
actions
|
|
1119
1344
|
}) {
|
|
1120
1345
|
const copy = INSTALL_COPY.iosSafari;
|
|
1121
1346
|
const showPermanent = shouldShowPermanentOption(state);
|
|
1122
|
-
return /* @__PURE__ */ (0,
|
|
1123
|
-
/* @__PURE__ */ (0,
|
|
1347
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(InstallSplash, { title: copy.title, subtitle: copy.subtitle, children: [
|
|
1348
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
1124
1349
|
Step2,
|
|
1125
1350
|
{
|
|
1126
1351
|
n: 1,
|
|
1127
1352
|
title: copy.step1.title,
|
|
1128
1353
|
subtitle: copy.step1.subtitle,
|
|
1129
|
-
visual: /* @__PURE__ */ (0,
|
|
1354
|
+
visual: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
1130
1355
|
"div",
|
|
1131
1356
|
{
|
|
1132
1357
|
style: {
|
|
@@ -1138,17 +1363,17 @@ function IOSafariVariant({
|
|
|
1138
1363
|
padding: "12px 0",
|
|
1139
1364
|
marginTop: 8
|
|
1140
1365
|
},
|
|
1141
|
-
children: /* @__PURE__ */ (0,
|
|
1366
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(ShareIconIOS, { size: 32, style: { color: "var(--hook-color-primary)" } })
|
|
1142
1367
|
}
|
|
1143
1368
|
)
|
|
1144
1369
|
}
|
|
1145
1370
|
),
|
|
1146
|
-
/* @__PURE__ */ (0,
|
|
1371
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
1147
1372
|
Step2,
|
|
1148
1373
|
{
|
|
1149
1374
|
n: 2,
|
|
1150
1375
|
title: copy.step2.title,
|
|
1151
|
-
visual: /* @__PURE__ */ (0,
|
|
1376
|
+
visual: /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
|
|
1152
1377
|
"div",
|
|
1153
1378
|
{
|
|
1154
1379
|
style: {
|
|
@@ -1161,19 +1386,19 @@ function IOSafariVariant({
|
|
|
1161
1386
|
marginTop: 8
|
|
1162
1387
|
},
|
|
1163
1388
|
children: [
|
|
1164
|
-
/* @__PURE__ */ (0,
|
|
1165
|
-
/* @__PURE__ */ (0,
|
|
1389
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(SquarePlusIcon, { size: 22, style: { color: "#555" } }),
|
|
1390
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { style: { fontSize: 14, color: "#333" }, children: copy.step2.iconLabel })
|
|
1166
1391
|
]
|
|
1167
1392
|
}
|
|
1168
1393
|
)
|
|
1169
1394
|
}
|
|
1170
1395
|
),
|
|
1171
|
-
/* @__PURE__ */ (0,
|
|
1396
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
1172
1397
|
Step2,
|
|
1173
1398
|
{
|
|
1174
1399
|
n: 3,
|
|
1175
1400
|
title: copy.step3.title,
|
|
1176
|
-
visual: /* @__PURE__ */ (0,
|
|
1401
|
+
visual: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
1177
1402
|
"div",
|
|
1178
1403
|
{
|
|
1179
1404
|
style: {
|
|
@@ -1184,7 +1409,7 @@ function IOSafariVariant({
|
|
|
1184
1409
|
padding: "10px 14px",
|
|
1185
1410
|
marginTop: 8
|
|
1186
1411
|
},
|
|
1187
|
-
children: /* @__PURE__ */ (0,
|
|
1412
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
1188
1413
|
"span",
|
|
1189
1414
|
{
|
|
1190
1415
|
style: {
|
|
@@ -1199,7 +1424,7 @@ function IOSafariVariant({
|
|
|
1199
1424
|
)
|
|
1200
1425
|
}
|
|
1201
1426
|
),
|
|
1202
|
-
/* @__PURE__ */ (0,
|
|
1427
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
1203
1428
|
"button",
|
|
1204
1429
|
{
|
|
1205
1430
|
"data-testid": "install-prompt-skip-session",
|
|
@@ -1209,7 +1434,7 @@ function IOSafariVariant({
|
|
|
1209
1434
|
children: copy.skip
|
|
1210
1435
|
}
|
|
1211
1436
|
),
|
|
1212
|
-
showPermanent && /* @__PURE__ */ (0,
|
|
1437
|
+
showPermanent && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
1213
1438
|
"button",
|
|
1214
1439
|
{
|
|
1215
1440
|
"data-testid": "install-prompt-skip-permanent",
|
|
@@ -1223,21 +1448,21 @@ function IOSafariVariant({
|
|
|
1223
1448
|
}
|
|
1224
1449
|
|
|
1225
1450
|
// src/components/InstallGate/variants/IOSOtherVariant.tsx
|
|
1226
|
-
var
|
|
1451
|
+
var import_jsx_runtime12 = require("react/jsx-runtime");
|
|
1227
1452
|
function IOSOtherVariant({
|
|
1228
1453
|
state,
|
|
1229
1454
|
actions
|
|
1230
1455
|
}) {
|
|
1231
1456
|
const copy = INSTALL_COPY.iosOther;
|
|
1232
1457
|
const showPermanent = shouldShowPermanentOption(state);
|
|
1233
|
-
return /* @__PURE__ */ (0,
|
|
1234
|
-
/* @__PURE__ */ (0,
|
|
1458
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(InstallSplash, { title: copy.title, subtitle: copy.subtitle, children: [
|
|
1459
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
1235
1460
|
Step2,
|
|
1236
1461
|
{
|
|
1237
1462
|
n: 1,
|
|
1238
1463
|
title: copy.step1.title,
|
|
1239
1464
|
subtitle: copy.step1.subtitle,
|
|
1240
|
-
visual: /* @__PURE__ */ (0,
|
|
1465
|
+
visual: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
1241
1466
|
"div",
|
|
1242
1467
|
{
|
|
1243
1468
|
style: {
|
|
@@ -1249,17 +1474,17 @@ function IOSOtherVariant({
|
|
|
1249
1474
|
padding: "12px 0",
|
|
1250
1475
|
marginTop: 8
|
|
1251
1476
|
},
|
|
1252
|
-
children: /* @__PURE__ */ (0,
|
|
1477
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(ShareIconIOS, { size: 32, style: { color: "var(--hook-color-primary)" } })
|
|
1253
1478
|
}
|
|
1254
1479
|
)
|
|
1255
1480
|
}
|
|
1256
1481
|
),
|
|
1257
|
-
/* @__PURE__ */ (0,
|
|
1482
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
1258
1483
|
Step2,
|
|
1259
1484
|
{
|
|
1260
1485
|
n: 2,
|
|
1261
1486
|
title: copy.step2.title,
|
|
1262
|
-
visual: /* @__PURE__ */ (0,
|
|
1487
|
+
visual: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
|
|
1263
1488
|
"div",
|
|
1264
1489
|
{
|
|
1265
1490
|
style: {
|
|
@@ -1272,19 +1497,19 @@ function IOSOtherVariant({
|
|
|
1272
1497
|
marginTop: 8
|
|
1273
1498
|
},
|
|
1274
1499
|
children: [
|
|
1275
|
-
/* @__PURE__ */ (0,
|
|
1276
|
-
/* @__PURE__ */ (0,
|
|
1500
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(SquarePlusIcon, { size: 22, style: { color: "#555" } }),
|
|
1501
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { style: { fontSize: 14, color: "#333" }, children: copy.step2.iconLabel })
|
|
1277
1502
|
]
|
|
1278
1503
|
}
|
|
1279
1504
|
)
|
|
1280
1505
|
}
|
|
1281
1506
|
),
|
|
1282
|
-
/* @__PURE__ */ (0,
|
|
1507
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
1283
1508
|
Step2,
|
|
1284
1509
|
{
|
|
1285
1510
|
n: 3,
|
|
1286
1511
|
title: copy.step3.title,
|
|
1287
|
-
visual: /* @__PURE__ */ (0,
|
|
1512
|
+
visual: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
1288
1513
|
"div",
|
|
1289
1514
|
{
|
|
1290
1515
|
style: {
|
|
@@ -1295,7 +1520,7 @@ function IOSOtherVariant({
|
|
|
1295
1520
|
padding: "10px 14px",
|
|
1296
1521
|
marginTop: 8
|
|
1297
1522
|
},
|
|
1298
|
-
children: /* @__PURE__ */ (0,
|
|
1523
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
1299
1524
|
"span",
|
|
1300
1525
|
{
|
|
1301
1526
|
style: {
|
|
@@ -1310,7 +1535,7 @@ function IOSOtherVariant({
|
|
|
1310
1535
|
)
|
|
1311
1536
|
}
|
|
1312
1537
|
),
|
|
1313
|
-
/* @__PURE__ */ (0,
|
|
1538
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
1314
1539
|
"button",
|
|
1315
1540
|
{
|
|
1316
1541
|
"data-testid": "install-prompt-skip-session",
|
|
@@ -1320,7 +1545,7 @@ function IOSOtherVariant({
|
|
|
1320
1545
|
children: copy.skip
|
|
1321
1546
|
}
|
|
1322
1547
|
),
|
|
1323
|
-
showPermanent && /* @__PURE__ */ (0,
|
|
1548
|
+
showPermanent && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
1324
1549
|
"button",
|
|
1325
1550
|
{
|
|
1326
1551
|
"data-testid": "install-prompt-skip-permanent",
|
|
@@ -1334,8 +1559,8 @@ function IOSOtherVariant({
|
|
|
1334
1559
|
}
|
|
1335
1560
|
|
|
1336
1561
|
// src/components/InstallGate/variants/InAppBrowserVariant.tsx
|
|
1337
|
-
var
|
|
1338
|
-
var
|
|
1562
|
+
var import_react7 = require("react");
|
|
1563
|
+
var import_jsx_runtime13 = require("react/jsx-runtime");
|
|
1339
1564
|
function InAppBrowserVariant({
|
|
1340
1565
|
state,
|
|
1341
1566
|
actions
|
|
@@ -1344,17 +1569,17 @@ function InAppBrowserVariant({
|
|
|
1344
1569
|
const appCopy = INSTALL_COPY.inApp[app] ?? INSTALL_COPY.inApp.other;
|
|
1345
1570
|
const copy = INSTALL_COPY.inApp;
|
|
1346
1571
|
const showPermanent = shouldShowPermanentOption(state);
|
|
1347
|
-
const [copied, setCopied] = (0,
|
|
1572
|
+
const [copied, setCopied] = (0, import_react7.useState)(false);
|
|
1348
1573
|
const handleCopy = async () => {
|
|
1349
1574
|
await actions.copyLink();
|
|
1350
1575
|
setCopied(true);
|
|
1351
1576
|
setTimeout(() => setCopied(false), 2e3);
|
|
1352
1577
|
};
|
|
1353
1578
|
const DotsIcon = app === "facebook" || app === "telegram" ? MenuDotsVerticalIcon : MenuDotsHorizontalIcon;
|
|
1354
|
-
return /* @__PURE__ */ (0,
|
|
1355
|
-
/* @__PURE__ */ (0,
|
|
1356
|
-
/* @__PURE__ */ (0,
|
|
1357
|
-
/* @__PURE__ */ (0,
|
|
1579
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(InstallSplash, { title: appCopy.title, children: [
|
|
1580
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Step3, { n: 1, icon: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(DotsIcon, { size: 20 }), children: appCopy.step1 }),
|
|
1581
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Step3, { n: 2, icon: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(ExternalLinkIcon, { size: 18 }), children: appCopy.step2 }),
|
|
1582
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1358
1583
|
"button",
|
|
1359
1584
|
{
|
|
1360
1585
|
"data-testid": "install-prompt-cta-inapp-copy",
|
|
@@ -1364,7 +1589,7 @@ function InAppBrowserVariant({
|
|
|
1364
1589
|
children: copied ? copy.copiedToast : copy.copy
|
|
1365
1590
|
}
|
|
1366
1591
|
),
|
|
1367
|
-
/* @__PURE__ */ (0,
|
|
1592
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1368
1593
|
"button",
|
|
1369
1594
|
{
|
|
1370
1595
|
"data-testid": "install-prompt-skip-session",
|
|
@@ -1374,7 +1599,7 @@ function InAppBrowserVariant({
|
|
|
1374
1599
|
children: copy.skip
|
|
1375
1600
|
}
|
|
1376
1601
|
),
|
|
1377
|
-
showPermanent && /* @__PURE__ */ (0,
|
|
1602
|
+
showPermanent && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1378
1603
|
"button",
|
|
1379
1604
|
{
|
|
1380
1605
|
"data-testid": "install-prompt-skip-permanent",
|
|
@@ -1391,7 +1616,7 @@ function Step3({
|
|
|
1391
1616
|
icon,
|
|
1392
1617
|
children
|
|
1393
1618
|
}) {
|
|
1394
|
-
return /* @__PURE__ */ (0,
|
|
1619
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
|
|
1395
1620
|
"div",
|
|
1396
1621
|
{
|
|
1397
1622
|
style: {
|
|
@@ -1405,7 +1630,7 @@ function Step3({
|
|
|
1405
1630
|
textAlign: "left"
|
|
1406
1631
|
},
|
|
1407
1632
|
children: [
|
|
1408
|
-
/* @__PURE__ */ (0,
|
|
1633
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1409
1634
|
"div",
|
|
1410
1635
|
{
|
|
1411
1636
|
style: {
|
|
@@ -1424,15 +1649,15 @@ function Step3({
|
|
|
1424
1649
|
children: n
|
|
1425
1650
|
}
|
|
1426
1651
|
),
|
|
1427
|
-
/* @__PURE__ */ (0,
|
|
1428
|
-
/* @__PURE__ */ (0,
|
|
1652
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { style: { flex: 1, fontSize: 14, color: "#333" }, children }),
|
|
1653
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { style: { color: "#888", flexShrink: 0 }, children: icon })
|
|
1429
1654
|
]
|
|
1430
1655
|
}
|
|
1431
1656
|
);
|
|
1432
1657
|
}
|
|
1433
1658
|
|
|
1434
1659
|
// src/components/InstallGate/variants/DesktopVariant.tsx
|
|
1435
|
-
var
|
|
1660
|
+
var import_jsx_runtime14 = require("react/jsx-runtime");
|
|
1436
1661
|
function DesktopVariant({
|
|
1437
1662
|
state,
|
|
1438
1663
|
actions
|
|
@@ -1441,21 +1666,21 @@ function DesktopVariant({
|
|
|
1441
1666
|
const copy = INSTALL_COPY.desktop;
|
|
1442
1667
|
const iconUrl = theme.icon_url || theme.logo_url || null;
|
|
1443
1668
|
if (!state.isInstallable) return null;
|
|
1444
|
-
return /* @__PURE__ */ (0,
|
|
1669
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
|
|
1445
1670
|
"div",
|
|
1446
1671
|
{
|
|
1447
1672
|
role: "complementary",
|
|
1448
1673
|
"aria-label": copy.title,
|
|
1449
1674
|
style: bannerStyle,
|
|
1450
1675
|
children: [
|
|
1451
|
-
iconUrl ? /* @__PURE__ */ (0,
|
|
1676
|
+
iconUrl ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
1452
1677
|
"img",
|
|
1453
1678
|
{
|
|
1454
1679
|
src: iconUrl,
|
|
1455
1680
|
alt: "",
|
|
1456
1681
|
style: { width: 40, height: 40, borderRadius: 10, objectFit: "cover", flexShrink: 0 }
|
|
1457
1682
|
}
|
|
1458
|
-
) : /* @__PURE__ */ (0,
|
|
1683
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
1459
1684
|
"div",
|
|
1460
1685
|
{
|
|
1461
1686
|
style: {
|
|
@@ -1474,11 +1699,11 @@ function DesktopVariant({
|
|
|
1474
1699
|
children: name.charAt(0).toUpperCase()
|
|
1475
1700
|
}
|
|
1476
1701
|
),
|
|
1477
|
-
/* @__PURE__ */ (0,
|
|
1478
|
-
/* @__PURE__ */ (0,
|
|
1479
|
-
/* @__PURE__ */ (0,
|
|
1702
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { style: { flex: 1, minWidth: 0 }, children: [
|
|
1703
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { style: { fontSize: 14, fontWeight: 600, color: "#111" }, children: copy.title }),
|
|
1704
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { style: { fontSize: 12, color: "#666" }, children: copy.subtitle })
|
|
1480
1705
|
] }),
|
|
1481
|
-
/* @__PURE__ */ (0,
|
|
1706
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
|
|
1482
1707
|
"button",
|
|
1483
1708
|
{
|
|
1484
1709
|
"data-testid": "install-prompt-cta-desktop",
|
|
@@ -1499,12 +1724,12 @@ function DesktopVariant({
|
|
|
1499
1724
|
flexShrink: 0
|
|
1500
1725
|
},
|
|
1501
1726
|
children: [
|
|
1502
|
-
/* @__PURE__ */ (0,
|
|
1727
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(DownloadIcon, { size: 14 }),
|
|
1503
1728
|
copy.cta
|
|
1504
1729
|
]
|
|
1505
1730
|
}
|
|
1506
1731
|
),
|
|
1507
|
-
/* @__PURE__ */ (0,
|
|
1732
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
1508
1733
|
"button",
|
|
1509
1734
|
{
|
|
1510
1735
|
"data-testid": "install-prompt-desktop-close",
|
|
@@ -1519,7 +1744,7 @@ function DesktopVariant({
|
|
|
1519
1744
|
padding: 4,
|
|
1520
1745
|
flexShrink: 0
|
|
1521
1746
|
},
|
|
1522
|
-
children: /* @__PURE__ */ (0,
|
|
1747
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(XIcon, { size: 16 })
|
|
1523
1748
|
}
|
|
1524
1749
|
)
|
|
1525
1750
|
]
|
|
@@ -1543,14 +1768,14 @@ var bannerStyle = {
|
|
|
1543
1768
|
};
|
|
1544
1769
|
|
|
1545
1770
|
// src/components/InstallGate/InstallGate.tsx
|
|
1546
|
-
var
|
|
1771
|
+
var import_jsx_runtime15 = require("react/jsx-runtime");
|
|
1547
1772
|
function InstallGate({ children }) {
|
|
1548
1773
|
const { slug, features_enabled } = useTemplateConfig();
|
|
1549
1774
|
const enabled = features_enabled.includes("install_prompt");
|
|
1550
1775
|
const installState = useInstallPrompt(slug);
|
|
1551
1776
|
const shouldBlock = enabled && shouldBlockInstall(installState);
|
|
1552
|
-
const trackedRef = (0,
|
|
1553
|
-
(0,
|
|
1777
|
+
const trackedRef = (0, import_react8.useRef)(null);
|
|
1778
|
+
(0, import_react8.useEffect)(() => {
|
|
1554
1779
|
if (!shouldBlock) return;
|
|
1555
1780
|
if (typeof window === "undefined") return;
|
|
1556
1781
|
const variantKey = `${slug}:${installState.variant}`;
|
|
@@ -1564,37 +1789,42 @@ function InstallGate({ children }) {
|
|
|
1564
1789
|
variant: installState.variant
|
|
1565
1790
|
});
|
|
1566
1791
|
}, [shouldBlock, slug, installState.variant, installState.platform, installState.iosBrowser, installState.androidBrowser, installState.inAppApp]);
|
|
1567
|
-
if (!enabled) return /* @__PURE__ */ (0,
|
|
1568
|
-
if (installState.isInstalled) return /* @__PURE__ */ (0,
|
|
1792
|
+
if (!enabled) return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_jsx_runtime15.Fragment, { children });
|
|
1793
|
+
if (installState.isInstalled) return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_jsx_runtime15.Fragment, { children });
|
|
1569
1794
|
if (installState.variant === "desktop") {
|
|
1570
1795
|
const showBanner = !installState.isDismissedSession && !installState.isDismissedPermanent;
|
|
1571
|
-
return /* @__PURE__ */ (0,
|
|
1796
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_jsx_runtime15.Fragment, { children: [
|
|
1572
1797
|
children,
|
|
1573
|
-
showBanner && /* @__PURE__ */ (0,
|
|
1798
|
+
showBanner && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(DesktopVariant, { state: installState, actions: installState })
|
|
1574
1799
|
] });
|
|
1575
1800
|
}
|
|
1576
|
-
if (!shouldBlock) return /* @__PURE__ */ (0,
|
|
1801
|
+
if (!shouldBlock) return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_jsx_runtime15.Fragment, { children });
|
|
1577
1802
|
switch (installState.variant) {
|
|
1578
1803
|
case "android-native":
|
|
1579
|
-
return /* @__PURE__ */ (0,
|
|
1804
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(AndroidNativeVariant, { state: installState, actions: installState });
|
|
1580
1805
|
case "android-manual":
|
|
1581
|
-
return /* @__PURE__ */ (0,
|
|
1806
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(AndroidManualVariant, { state: installState, actions: installState });
|
|
1582
1807
|
case "ios-safari":
|
|
1583
|
-
return /* @__PURE__ */ (0,
|
|
1808
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(IOSafariVariant, { state: installState, actions: installState });
|
|
1584
1809
|
case "ios-other":
|
|
1585
|
-
return /* @__PURE__ */ (0,
|
|
1810
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(IOSOtherVariant, { state: installState, actions: installState });
|
|
1586
1811
|
case "in-app":
|
|
1587
|
-
return /* @__PURE__ */ (0,
|
|
1812
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(InAppBrowserVariant, { state: installState, actions: installState });
|
|
1588
1813
|
case "none":
|
|
1589
1814
|
default:
|
|
1590
|
-
return /* @__PURE__ */ (0,
|
|
1815
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_jsx_runtime15.Fragment, { children });
|
|
1591
1816
|
}
|
|
1592
1817
|
}
|
|
1593
1818
|
|
|
1819
|
+
// src/internal/PushPrompt.tsx
|
|
1820
|
+
function PushPrompt() {
|
|
1821
|
+
return null;
|
|
1822
|
+
}
|
|
1823
|
+
|
|
1594
1824
|
// src/defaults/ErrorBoundary.tsx
|
|
1595
|
-
var
|
|
1596
|
-
var
|
|
1597
|
-
var ErrorBoundary = class extends
|
|
1825
|
+
var import_react9 = require("react");
|
|
1826
|
+
var import_jsx_runtime16 = require("react/jsx-runtime");
|
|
1827
|
+
var ErrorBoundary = class extends import_react9.Component {
|
|
1598
1828
|
state = { error: null };
|
|
1599
1829
|
static getDerivedStateFromError(error) {
|
|
1600
1830
|
return { error };
|
|
@@ -1604,1239 +1834,27 @@ var ErrorBoundary = class extends import_react8.Component {
|
|
|
1604
1834
|
}
|
|
1605
1835
|
render() {
|
|
1606
1836
|
if (this.state.error) {
|
|
1607
|
-
return this.props.fallback ?? /* @__PURE__ */ (0,
|
|
1608
|
-
/* @__PURE__ */ (0,
|
|
1609
|
-
/* @__PURE__ */ (0,
|
|
1837
|
+
return this.props.fallback ?? /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { role: "alert", style: { padding: 24, textAlign: "center" }, children: [
|
|
1838
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("h2", { children: "Algo deu errado" }),
|
|
1839
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("p", { style: { opacity: 0.7 }, children: "Recarregue a p\xE1gina pra tentar de novo." })
|
|
1610
1840
|
] });
|
|
1611
1841
|
}
|
|
1612
|
-
return /* @__PURE__ */ (0,
|
|
1842
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_jsx_runtime16.Fragment, { children: this.props.children });
|
|
1613
1843
|
}
|
|
1614
1844
|
};
|
|
1615
1845
|
|
|
1616
|
-
// src/
|
|
1617
|
-
var
|
|
1618
|
-
var
|
|
1619
|
-
|
|
1620
|
-
// src/errors.ts
|
|
1621
|
-
var import_sdk4 = require("@hook-sdk/sdk");
|
|
1622
|
-
function mapSdkError(err) {
|
|
1623
|
-
if (err instanceof import_sdk4.SdkRateLimitError) {
|
|
1624
|
-
return {
|
|
1625
|
-
code: "rate_limited",
|
|
1626
|
-
message: `Aguarde ${err.retryAfter}s e tente novamente.`,
|
|
1627
|
-
retryAfter: err.retryAfter
|
|
1628
|
-
};
|
|
1629
|
-
}
|
|
1630
|
-
if (err instanceof import_sdk4.SdkAuthError) {
|
|
1631
|
-
const detail = err.detail;
|
|
1632
|
-
if (detail === "email_unverified") {
|
|
1633
|
-
return { code: "email_unverified", message: "Confirme seu e-mail antes de entrar." };
|
|
1634
|
-
}
|
|
1635
|
-
if (detail === "account_locked") {
|
|
1636
|
-
return { code: "account_locked", message: "Conta bloqueada. Contate o suporte." };
|
|
1637
|
-
}
|
|
1638
|
-
return { code: "invalid_credentials", message: "E-mail ou senha inv\xE1lidos." };
|
|
1639
|
-
}
|
|
1640
|
-
if (err instanceof import_sdk4.SdkError && err.httpStatus === 0) {
|
|
1641
|
-
return { code: "network", message: "Sem conex\xE3o com o servidor. Verifique sua internet." };
|
|
1642
|
-
}
|
|
1643
|
-
if (err instanceof TypeError) {
|
|
1644
|
-
return { code: "network", message: "Sem conex\xE3o com o servidor. Verifique sua internet." };
|
|
1645
|
-
}
|
|
1646
|
-
return { code: "server", message: "Algo deu errado. Tente novamente em instantes." };
|
|
1647
|
-
}
|
|
1648
|
-
|
|
1649
|
-
// src/hooks/useLoginForm.ts
|
|
1650
|
-
var EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
1651
|
-
var MIN_PASSWORD = 8;
|
|
1652
|
-
function useLoginForm() {
|
|
1653
|
-
const { auth } = (0, import_sdk5.useHook)();
|
|
1654
|
-
const [email, setEmail] = (0, import_react9.useState)("");
|
|
1655
|
-
const [password, setPassword] = (0, import_react9.useState)("");
|
|
1656
|
-
const [submitting, setSubmitting] = (0, import_react9.useState)(false);
|
|
1657
|
-
const [error, setError] = (0, import_react9.useState)(null);
|
|
1658
|
-
const emailError = (0, import_react9.useMemo)(() => {
|
|
1659
|
-
if (email.length === 0) return null;
|
|
1660
|
-
if (!EMAIL_RE.test(email)) return "Formato de e-mail inv\xE1lido.";
|
|
1661
|
-
return null;
|
|
1662
|
-
}, [email]);
|
|
1663
|
-
const passwordError = (0, import_react9.useMemo)(() => {
|
|
1664
|
-
if (password.length === 0) return null;
|
|
1665
|
-
if (password.length < MIN_PASSWORD) return `M\xEDnimo de ${MIN_PASSWORD} caracteres.`;
|
|
1666
|
-
return null;
|
|
1667
|
-
}, [password]);
|
|
1668
|
-
const canSubmit = email.length > 0 && password.length >= MIN_PASSWORD && emailError === null && passwordError === null && !submitting;
|
|
1669
|
-
const submit = (0, import_react9.useCallback)(async () => {
|
|
1670
|
-
if (!canSubmit) return false;
|
|
1671
|
-
setSubmitting(true);
|
|
1672
|
-
setError(null);
|
|
1673
|
-
try {
|
|
1674
|
-
await auth.login({ email, password });
|
|
1675
|
-
return true;
|
|
1676
|
-
} catch (err) {
|
|
1677
|
-
setError(mapSdkError(err));
|
|
1678
|
-
return false;
|
|
1679
|
-
} finally {
|
|
1680
|
-
setSubmitting(false);
|
|
1681
|
-
}
|
|
1682
|
-
}, [auth, email, password, canSubmit]);
|
|
1683
|
-
return {
|
|
1684
|
-
email,
|
|
1685
|
-
setEmail,
|
|
1686
|
-
emailError,
|
|
1687
|
-
password,
|
|
1688
|
-
setPassword,
|
|
1689
|
-
passwordError,
|
|
1690
|
-
submit,
|
|
1691
|
-
submitting,
|
|
1692
|
-
canSubmit,
|
|
1693
|
-
error,
|
|
1694
|
-
loginWithGoogle: () => auth.loginWithGoogle()
|
|
1695
|
-
};
|
|
1696
|
-
}
|
|
1697
|
-
|
|
1698
|
-
// src/internal/GoogleSignInButton.tsx
|
|
1699
|
-
var import_jsx_runtime18 = require("react/jsx-runtime");
|
|
1700
|
-
function GoogleSignInButton({
|
|
1701
|
-
onClick,
|
|
1702
|
-
testId = "oauth-google",
|
|
1703
|
-
label = "Continuar com Google"
|
|
1704
|
-
}) {
|
|
1705
|
-
return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
|
|
1706
|
-
"button",
|
|
1707
|
-
{
|
|
1708
|
-
"data-testid": testId,
|
|
1709
|
-
type: "button",
|
|
1710
|
-
onClick,
|
|
1711
|
-
style: {
|
|
1712
|
-
width: "100%",
|
|
1713
|
-
padding: "10px 12px",
|
|
1714
|
-
display: "flex",
|
|
1715
|
-
alignItems: "center",
|
|
1716
|
-
justifyContent: "center",
|
|
1717
|
-
gap: 10,
|
|
1718
|
-
background: "#fff",
|
|
1719
|
-
color: "#1f1f1f",
|
|
1720
|
-
border: "1px solid #dadce0",
|
|
1721
|
-
borderRadius: 8,
|
|
1722
|
-
cursor: "pointer",
|
|
1723
|
-
fontSize: 14,
|
|
1724
|
-
fontWeight: 500,
|
|
1725
|
-
fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif'
|
|
1726
|
-
},
|
|
1727
|
-
children: [
|
|
1728
|
-
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(GoogleGlyph, {}),
|
|
1729
|
-
label
|
|
1730
|
-
]
|
|
1731
|
-
}
|
|
1732
|
-
);
|
|
1733
|
-
}
|
|
1734
|
-
function GoogleGlyph() {
|
|
1735
|
-
return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("svg", { width: "18", height: "18", viewBox: "0 0 18 18", xmlns: "http://www.w3.org/2000/svg", "aria-hidden": "true", children: [
|
|
1736
|
-
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
1737
|
-
"path",
|
|
1738
|
-
{
|
|
1739
|
-
d: "M17.64 9.2c0-.637-.057-1.251-.164-1.84H9v3.481h4.844a4.14 4.14 0 0 1-1.796 2.716v2.259h2.908c1.702-1.567 2.684-3.874 2.684-6.615z",
|
|
1740
|
-
fill: "#4285F4"
|
|
1741
|
-
}
|
|
1742
|
-
),
|
|
1743
|
-
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
1744
|
-
"path",
|
|
1745
|
-
{
|
|
1746
|
-
d: "M9 18c2.43 0 4.467-.806 5.956-2.18l-2.908-2.259c-.806.54-1.837.86-3.048.86-2.344 0-4.328-1.584-5.036-3.711H.957v2.332A8.997 8.997 0 0 0 9 18z",
|
|
1747
|
-
fill: "#34A853"
|
|
1748
|
-
}
|
|
1749
|
-
),
|
|
1750
|
-
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
1751
|
-
"path",
|
|
1752
|
-
{
|
|
1753
|
-
d: "M3.964 10.71A5.41 5.41 0 0 1 3.682 9c0-.593.102-1.17.282-1.71V4.958H.957A8.996 8.996 0 0 0 0 9c0 1.452.348 2.827.957 4.042l3.007-2.332z",
|
|
1754
|
-
fill: "#FBBC05"
|
|
1755
|
-
}
|
|
1756
|
-
),
|
|
1757
|
-
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
1758
|
-
"path",
|
|
1759
|
-
{
|
|
1760
|
-
d: "M9 3.58c1.321 0 2.508.454 3.44 1.345l2.582-2.58C13.463.891 11.426 0 9 0A8.997 8.997 0 0 0 .957 4.958L3.964 7.29C4.672 5.163 6.656 3.58 9 3.58z",
|
|
1761
|
-
fill: "#EA4335"
|
|
1762
|
-
}
|
|
1763
|
-
)
|
|
1764
|
-
] });
|
|
1765
|
-
}
|
|
1766
|
-
|
|
1767
|
-
// src/internal/OAuthErrorBanner.tsx
|
|
1768
|
-
var import_react10 = require("react");
|
|
1769
|
-
var import_jsx_runtime19 = require("react/jsx-runtime");
|
|
1770
|
-
var ERROR_MESSAGES = {
|
|
1771
|
-
invalid_state: "Sess\xE3o expirou, tente de novo.",
|
|
1772
|
-
access_denied: "Voc\xEA cancelou o login com Google.",
|
|
1773
|
-
provider_error: "O Google recusou a autentica\xE7\xE3o. Tente de novo em alguns segundos.",
|
|
1774
|
-
invalid_return_to: "Link inv\xE1lido. Tente entrar novamente."
|
|
1775
|
-
};
|
|
1776
|
-
function readErrorCode() {
|
|
1777
|
-
if (typeof window === "undefined") return null;
|
|
1778
|
-
const code = new URLSearchParams(window.location.search).get("oauth_error");
|
|
1779
|
-
if (!code) return null;
|
|
1780
|
-
return code;
|
|
1781
|
-
}
|
|
1782
|
-
function stripErrorFromUrl() {
|
|
1783
|
-
if (typeof window === "undefined") return;
|
|
1784
|
-
const url = new URL(window.location.href);
|
|
1785
|
-
url.searchParams.delete("oauth_error");
|
|
1786
|
-
window.history.replaceState({}, "", url.toString());
|
|
1787
|
-
}
|
|
1788
|
-
function OAuthErrorBanner() {
|
|
1789
|
-
const [code, setCode] = (0, import_react10.useState)(() => readErrorCode());
|
|
1790
|
-
(0, import_react10.useEffect)(() => {
|
|
1791
|
-
if (code !== null) stripErrorFromUrl();
|
|
1792
|
-
}, [code]);
|
|
1793
|
-
if (!code) return null;
|
|
1794
|
-
const message = ERROR_MESSAGES[code] ?? "N\xE3o conseguimos conectar ao Google. Tente de novo.";
|
|
1795
|
-
return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
|
|
1796
|
-
"div",
|
|
1797
|
-
{
|
|
1798
|
-
role: "alert",
|
|
1799
|
-
"data-testid": "oauth-error-banner",
|
|
1800
|
-
style: {
|
|
1801
|
-
padding: "10px 12px",
|
|
1802
|
-
marginBottom: 16,
|
|
1803
|
-
background: "#fce8e6",
|
|
1804
|
-
color: "#a50e0e",
|
|
1805
|
-
borderRadius: 8,
|
|
1806
|
-
fontSize: 14
|
|
1807
|
-
},
|
|
1808
|
-
children: [
|
|
1809
|
-
message,
|
|
1810
|
-
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
1811
|
-
"button",
|
|
1812
|
-
{
|
|
1813
|
-
type: "button",
|
|
1814
|
-
onClick: () => setCode(null),
|
|
1815
|
-
"aria-label": "Fechar",
|
|
1816
|
-
style: {
|
|
1817
|
-
float: "right",
|
|
1818
|
-
background: "none",
|
|
1819
|
-
border: "none",
|
|
1820
|
-
color: "#a50e0e",
|
|
1821
|
-
cursor: "pointer",
|
|
1822
|
-
fontSize: 16,
|
|
1823
|
-
lineHeight: 1,
|
|
1824
|
-
padding: 0
|
|
1825
|
-
},
|
|
1826
|
-
children: "\xD7"
|
|
1827
|
-
}
|
|
1828
|
-
)
|
|
1829
|
-
]
|
|
1830
|
-
}
|
|
1831
|
-
);
|
|
1832
|
-
}
|
|
1833
|
-
|
|
1834
|
-
// src/defaults/DefaultLoginScreen.tsx
|
|
1835
|
-
var import_jsx_runtime20 = require("react/jsx-runtime");
|
|
1836
|
-
function DefaultLoginScreen({ onNavigate }) {
|
|
1837
|
-
const { name } = useTemplateConfig();
|
|
1838
|
-
const f = useLoginForm();
|
|
1839
|
-
return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("main", { style: { padding: 24, maxWidth: 360, margin: "0 auto" }, children: [
|
|
1840
|
-
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("h1", { style: { marginBottom: 8 }, children: name }),
|
|
1841
|
-
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("p", { style: { opacity: 0.7, marginBottom: 24 }, children: "Entre na sua conta" }),
|
|
1842
|
-
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(OAuthErrorBanner, {}),
|
|
1843
|
-
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(GoogleSignInButton, { onClick: f.loginWithGoogle, testId: "login-oauth-google" }),
|
|
1844
|
-
/* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
|
|
1845
|
-
"div",
|
|
1846
|
-
{
|
|
1847
|
-
"aria-hidden": "true",
|
|
1848
|
-
style: {
|
|
1849
|
-
display: "flex",
|
|
1850
|
-
alignItems: "center",
|
|
1851
|
-
gap: 8,
|
|
1852
|
-
margin: "16px 0",
|
|
1853
|
-
color: "rgba(0,0,0,0.45)",
|
|
1854
|
-
fontSize: 12
|
|
1855
|
-
},
|
|
1856
|
-
children: [
|
|
1857
|
-
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { style: { flex: 1, height: 1, background: "rgba(0,0,0,0.1)" } }),
|
|
1858
|
-
"ou",
|
|
1859
|
-
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { style: { flex: 1, height: 1, background: "rgba(0,0,0,0.1)" } })
|
|
1860
|
-
]
|
|
1861
|
-
}
|
|
1862
|
-
),
|
|
1863
|
-
/* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("form", { onSubmit: (e) => {
|
|
1864
|
-
e.preventDefault();
|
|
1865
|
-
void f.submit();
|
|
1866
|
-
}, children: [
|
|
1867
|
-
/* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("label", { style: { display: "block", marginBottom: 12 }, children: [
|
|
1868
|
-
"E-mail",
|
|
1869
|
-
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
1870
|
-
"input",
|
|
1871
|
-
{
|
|
1872
|
-
"data-testid": "login-email",
|
|
1873
|
-
type: "email",
|
|
1874
|
-
value: f.email,
|
|
1875
|
-
onChange: (e) => f.setEmail(e.target.value),
|
|
1876
|
-
style: { display: "block", width: "100%" }
|
|
1877
|
-
}
|
|
1878
|
-
),
|
|
1879
|
-
f.emailError && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("small", { style: { color: "#c00" }, children: f.emailError })
|
|
1880
|
-
] }),
|
|
1881
|
-
/* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("label", { style: { display: "block", marginBottom: 12 }, children: [
|
|
1882
|
-
"Senha",
|
|
1883
|
-
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
1884
|
-
"input",
|
|
1885
|
-
{
|
|
1886
|
-
"data-testid": "login-password",
|
|
1887
|
-
type: "password",
|
|
1888
|
-
value: f.password,
|
|
1889
|
-
onChange: (e) => f.setPassword(e.target.value),
|
|
1890
|
-
style: { display: "block", width: "100%" }
|
|
1891
|
-
}
|
|
1892
|
-
),
|
|
1893
|
-
f.passwordError && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("small", { style: { color: "#c00" }, children: f.passwordError })
|
|
1894
|
-
] }),
|
|
1895
|
-
f.error && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { role: "alert", style: { color: "#c00", marginBottom: 12 }, children: f.error.message }),
|
|
1896
|
-
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
1897
|
-
"button",
|
|
1898
|
-
{
|
|
1899
|
-
"data-testid": "login-submit",
|
|
1900
|
-
type: "submit",
|
|
1901
|
-
disabled: !f.canSubmit,
|
|
1902
|
-
style: {
|
|
1903
|
-
width: "100%",
|
|
1904
|
-
padding: 12,
|
|
1905
|
-
background: "var(--hook-color-primary)",
|
|
1906
|
-
color: "#fff",
|
|
1907
|
-
border: "none",
|
|
1908
|
-
borderRadius: 8,
|
|
1909
|
-
opacity: f.canSubmit ? 1 : 0.5
|
|
1910
|
-
},
|
|
1911
|
-
children: f.submitting ? "Entrando..." : "Entrar"
|
|
1912
|
-
}
|
|
1913
|
-
)
|
|
1914
|
-
] }),
|
|
1915
|
-
/* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { style: { marginTop: 16, display: "flex", justifyContent: "space-between" }, children: [
|
|
1916
|
-
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { "data-testid": "login-goto-signup", type: "button", onClick: () => onNavigate("signup"), style: { background: "none", border: "none", cursor: "pointer" }, children: "Criar conta" }),
|
|
1917
|
-
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { "data-testid": "login-goto-forgot", type: "button", onClick: () => onNavigate("forgot"), style: { background: "none", border: "none", cursor: "pointer" }, children: "Esqueci senha" })
|
|
1918
|
-
] })
|
|
1919
|
-
] });
|
|
1920
|
-
}
|
|
1921
|
-
|
|
1922
|
-
// src/hooks/useSignupForm.ts
|
|
1923
|
-
var import_react11 = require("react");
|
|
1924
|
-
var import_sdk6 = require("@hook-sdk/sdk");
|
|
1925
|
-
var EMAIL_RE2 = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
1926
|
-
var MIN_PASSWORD2 = 8;
|
|
1927
|
-
function useSignupForm() {
|
|
1928
|
-
const { auth } = (0, import_sdk6.useHook)();
|
|
1929
|
-
const [name, setName] = (0, import_react11.useState)("");
|
|
1930
|
-
const [email, setEmail] = (0, import_react11.useState)("");
|
|
1931
|
-
const [password, setPassword] = (0, import_react11.useState)("");
|
|
1932
|
-
const [submitting, setSubmitting] = (0, import_react11.useState)(false);
|
|
1933
|
-
const [error, setError] = (0, import_react11.useState)(null);
|
|
1934
|
-
const nameError = (0, import_react11.useMemo)(() => {
|
|
1935
|
-
if (name.length === 0) return null;
|
|
1936
|
-
if (name.trim().length < 2) return "Nome muito curto.";
|
|
1937
|
-
return null;
|
|
1938
|
-
}, [name]);
|
|
1939
|
-
const emailError = (0, import_react11.useMemo)(() => {
|
|
1940
|
-
if (email.length === 0) return null;
|
|
1941
|
-
if (!EMAIL_RE2.test(email)) return "Formato de e-mail inv\xE1lido.";
|
|
1942
|
-
return null;
|
|
1943
|
-
}, [email]);
|
|
1944
|
-
const passwordError = (0, import_react11.useMemo)(() => {
|
|
1945
|
-
if (password.length === 0) return null;
|
|
1946
|
-
if (password.length < MIN_PASSWORD2) return `M\xEDnimo de ${MIN_PASSWORD2} caracteres.`;
|
|
1947
|
-
return null;
|
|
1948
|
-
}, [password]);
|
|
1949
|
-
const canSubmit = name.trim().length >= 2 && email.length > 0 && password.length >= MIN_PASSWORD2 && nameError === null && emailError === null && passwordError === null && !submitting;
|
|
1950
|
-
const submit = (0, import_react11.useCallback)(async () => {
|
|
1951
|
-
if (!canSubmit) return false;
|
|
1952
|
-
setSubmitting(true);
|
|
1953
|
-
setError(null);
|
|
1954
|
-
try {
|
|
1955
|
-
await auth.signup({ name, email, password });
|
|
1956
|
-
return true;
|
|
1957
|
-
} catch (err) {
|
|
1958
|
-
setError(mapSdkError(err));
|
|
1959
|
-
return false;
|
|
1960
|
-
} finally {
|
|
1961
|
-
setSubmitting(false);
|
|
1962
|
-
}
|
|
1963
|
-
}, [auth, name, email, password, canSubmit]);
|
|
1964
|
-
return {
|
|
1965
|
-
name,
|
|
1966
|
-
setName,
|
|
1967
|
-
nameError,
|
|
1968
|
-
email,
|
|
1969
|
-
setEmail,
|
|
1970
|
-
emailError,
|
|
1971
|
-
password,
|
|
1972
|
-
setPassword,
|
|
1973
|
-
passwordError,
|
|
1974
|
-
submit,
|
|
1975
|
-
submitting,
|
|
1976
|
-
canSubmit,
|
|
1977
|
-
error,
|
|
1978
|
-
loginWithGoogle: () => auth.loginWithGoogle()
|
|
1979
|
-
};
|
|
1980
|
-
}
|
|
1981
|
-
|
|
1982
|
-
// src/defaults/DefaultSignupScreen.tsx
|
|
1983
|
-
var import_jsx_runtime21 = require("react/jsx-runtime");
|
|
1984
|
-
function DefaultSignupScreen({ onNavigate }) {
|
|
1985
|
-
const { name } = useTemplateConfig();
|
|
1986
|
-
const f = useSignupForm();
|
|
1987
|
-
return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("main", { style: { padding: 24, maxWidth: 360, margin: "0 auto" }, children: [
|
|
1988
|
-
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("h1", { style: { marginBottom: 8 }, children: name }),
|
|
1989
|
-
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { style: { opacity: 0.7, marginBottom: 24 }, children: "Criar sua conta" }),
|
|
1990
|
-
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(OAuthErrorBanner, {}),
|
|
1991
|
-
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(GoogleSignInButton, { onClick: f.loginWithGoogle, testId: "signup-oauth-google" }),
|
|
1992
|
-
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
|
|
1993
|
-
"div",
|
|
1994
|
-
{
|
|
1995
|
-
"aria-hidden": "true",
|
|
1996
|
-
style: {
|
|
1997
|
-
display: "flex",
|
|
1998
|
-
alignItems: "center",
|
|
1999
|
-
gap: 8,
|
|
2000
|
-
margin: "16px 0",
|
|
2001
|
-
color: "rgba(0,0,0,0.45)",
|
|
2002
|
-
fontSize: 12
|
|
2003
|
-
},
|
|
2004
|
-
children: [
|
|
2005
|
-
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { style: { flex: 1, height: 1, background: "rgba(0,0,0,0.1)" } }),
|
|
2006
|
-
"ou",
|
|
2007
|
-
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { style: { flex: 1, height: 1, background: "rgba(0,0,0,0.1)" } })
|
|
2008
|
-
]
|
|
2009
|
-
}
|
|
2010
|
-
),
|
|
2011
|
-
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("form", { onSubmit: (e) => {
|
|
2012
|
-
e.preventDefault();
|
|
2013
|
-
void f.submit();
|
|
2014
|
-
}, children: [
|
|
2015
|
-
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("label", { style: { display: "block", marginBottom: 12 }, children: [
|
|
2016
|
-
"Nome",
|
|
2017
|
-
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("input", { "data-testid": "signup-name", value: f.name, onChange: (e) => f.setName(e.target.value), style: { display: "block", width: "100%" } }),
|
|
2018
|
-
f.nameError && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("small", { style: { color: "#c00" }, children: f.nameError })
|
|
2019
|
-
] }),
|
|
2020
|
-
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("label", { style: { display: "block", marginBottom: 12 }, children: [
|
|
2021
|
-
"E-mail",
|
|
2022
|
-
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("input", { "data-testid": "signup-email", type: "email", value: f.email, onChange: (e) => f.setEmail(e.target.value), style: { display: "block", width: "100%" } }),
|
|
2023
|
-
f.emailError && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("small", { style: { color: "#c00" }, children: f.emailError })
|
|
2024
|
-
] }),
|
|
2025
|
-
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("label", { style: { display: "block", marginBottom: 12 }, children: [
|
|
2026
|
-
"Senha",
|
|
2027
|
-
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("input", { "data-testid": "signup-password", type: "password", value: f.password, onChange: (e) => f.setPassword(e.target.value), style: { display: "block", width: "100%" } }),
|
|
2028
|
-
f.passwordError && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("small", { style: { color: "#c00" }, children: f.passwordError })
|
|
2029
|
-
] }),
|
|
2030
|
-
f.error && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { role: "alert", style: { color: "#c00", marginBottom: 12 }, children: f.error.message }),
|
|
2031
|
-
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("button", { "data-testid": "signup-submit", type: "submit", disabled: !f.canSubmit, style: { width: "100%", padding: 12, background: "var(--hook-color-primary)", color: "#fff", border: "none", borderRadius: 8, opacity: f.canSubmit ? 1 : 0.5 }, children: f.submitting ? "Criando..." : "Criar conta" })
|
|
2032
|
-
] }),
|
|
2033
|
-
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { style: { marginTop: 16 }, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("button", { "data-testid": "signup-goto-login", type: "button", onClick: () => onNavigate("login"), style: { background: "none", border: "none", cursor: "pointer" }, children: "J\xE1 tem conta? Entre" }) })
|
|
2034
|
-
] });
|
|
2035
|
-
}
|
|
2036
|
-
|
|
2037
|
-
// src/hooks/useForgotForm.ts
|
|
2038
|
-
var import_react12 = require("react");
|
|
2039
|
-
var import_sdk7 = require("@hook-sdk/sdk");
|
|
2040
|
-
var EMAIL_RE3 = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
2041
|
-
function useForgotForm() {
|
|
2042
|
-
const { auth } = (0, import_sdk7.useHook)();
|
|
2043
|
-
const [email, setEmail] = (0, import_react12.useState)("");
|
|
2044
|
-
const [submitting, setSubmitting] = (0, import_react12.useState)(false);
|
|
2045
|
-
const [sent, setSent] = (0, import_react12.useState)(false);
|
|
2046
|
-
const [error, setError] = (0, import_react12.useState)(null);
|
|
2047
|
-
const emailError = (0, import_react12.useMemo)(() => {
|
|
2048
|
-
if (email.length === 0) return null;
|
|
2049
|
-
if (!EMAIL_RE3.test(email)) return "Formato de e-mail inv\xE1lido.";
|
|
2050
|
-
return null;
|
|
2051
|
-
}, [email]);
|
|
2052
|
-
const canSubmit = email.length > 0 && emailError === null && !submitting;
|
|
2053
|
-
const submit = (0, import_react12.useCallback)(async () => {
|
|
2054
|
-
if (!canSubmit) return false;
|
|
2055
|
-
setSubmitting(true);
|
|
2056
|
-
setError(null);
|
|
2057
|
-
try {
|
|
2058
|
-
await auth.forgot({ email });
|
|
2059
|
-
setSent(true);
|
|
2060
|
-
return true;
|
|
2061
|
-
} catch (err) {
|
|
2062
|
-
setError(mapSdkError(err));
|
|
2063
|
-
return false;
|
|
2064
|
-
} finally {
|
|
2065
|
-
setSubmitting(false);
|
|
2066
|
-
}
|
|
2067
|
-
}, [auth, email, canSubmit]);
|
|
2068
|
-
return {
|
|
2069
|
-
email,
|
|
2070
|
-
setEmail,
|
|
2071
|
-
emailError,
|
|
2072
|
-
submit,
|
|
2073
|
-
submitting,
|
|
2074
|
-
canSubmit,
|
|
2075
|
-
sent,
|
|
2076
|
-
error
|
|
2077
|
-
};
|
|
2078
|
-
}
|
|
2079
|
-
|
|
2080
|
-
// src/defaults/DefaultForgotScreen.tsx
|
|
2081
|
-
var import_jsx_runtime22 = require("react/jsx-runtime");
|
|
2082
|
-
function DefaultForgotScreen({ onNavigate }) {
|
|
2083
|
-
const { name } = useTemplateConfig();
|
|
2084
|
-
const f = useForgotForm();
|
|
2085
|
-
if (f.sent) {
|
|
2086
|
-
return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("main", { style: { padding: 24, maxWidth: 360, margin: "0 auto", textAlign: "center" }, children: [
|
|
2087
|
-
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("h1", { children: "Verifique seu e-mail" }),
|
|
2088
|
-
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("p", { style: { opacity: 0.7 }, children: "Enviamos um link pra redefinir sua senha." }),
|
|
2089
|
-
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("button", { "data-testid": "forgot-back-login", type: "button", onClick: () => onNavigate("login"), children: "Voltar pro login" })
|
|
2090
|
-
] });
|
|
2091
|
-
}
|
|
2092
|
-
return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("main", { style: { padding: 24, maxWidth: 360, margin: "0 auto" }, children: [
|
|
2093
|
-
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("h1", { style: { marginBottom: 8 }, children: name }),
|
|
2094
|
-
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("p", { style: { opacity: 0.7, marginBottom: 24 }, children: "Redefinir senha" }),
|
|
2095
|
-
/* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("form", { onSubmit: (e) => {
|
|
2096
|
-
e.preventDefault();
|
|
2097
|
-
void f.submit();
|
|
2098
|
-
}, children: [
|
|
2099
|
-
/* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("label", { style: { display: "block", marginBottom: 12 }, children: [
|
|
2100
|
-
"E-mail",
|
|
2101
|
-
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("input", { "data-testid": "forgot-email", type: "email", value: f.email, onChange: (e) => f.setEmail(e.target.value), style: { display: "block", width: "100%" } }),
|
|
2102
|
-
f.emailError && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("small", { style: { color: "#c00" }, children: f.emailError })
|
|
2103
|
-
] }),
|
|
2104
|
-
f.error && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { role: "alert", style: { color: "#c00", marginBottom: 12 }, children: f.error.message }),
|
|
2105
|
-
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("button", { "data-testid": "forgot-submit", type: "submit", disabled: !f.canSubmit, style: { width: "100%", padding: 12, background: "var(--hook-color-primary)", color: "#fff", border: "none", borderRadius: 8, opacity: f.canSubmit ? 1 : 0.5 }, children: f.submitting ? "Enviando..." : "Enviar link" })
|
|
2106
|
-
] }),
|
|
2107
|
-
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { style: { marginTop: 16 }, children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("button", { "data-testid": "forgot-goto-login", type: "button", onClick: () => onNavigate("login"), style: { background: "none", border: "none", cursor: "pointer" }, children: "Voltar pro login" }) })
|
|
2108
|
-
] });
|
|
2109
|
-
}
|
|
2110
|
-
|
|
2111
|
-
// src/hooks/useResetForm.ts
|
|
2112
|
-
var import_react13 = require("react");
|
|
2113
|
-
var import_sdk8 = require("@hook-sdk/sdk");
|
|
2114
|
-
var MIN_PASSWORD3 = 12;
|
|
2115
|
-
function useResetForm() {
|
|
2116
|
-
const { auth } = (0, import_sdk8.useHook)();
|
|
2117
|
-
const [token, setToken] = (0, import_react13.useState)(null);
|
|
2118
|
-
const [password, setPassword] = (0, import_react13.useState)("");
|
|
2119
|
-
const [confirm, setConfirm] = (0, import_react13.useState)("");
|
|
2120
|
-
const [submitting, setSubmitting] = (0, import_react13.useState)(false);
|
|
2121
|
-
const [done, setDone] = (0, import_react13.useState)(false);
|
|
2122
|
-
const [error, setError] = (0, import_react13.useState)(null);
|
|
2123
|
-
(0, import_react13.useEffect)(() => {
|
|
2124
|
-
if (typeof window === "undefined") return;
|
|
2125
|
-
const params = new URLSearchParams(window.location.search);
|
|
2126
|
-
const t = params.get("token");
|
|
2127
|
-
setToken(t && t.length > 0 ? t : null);
|
|
2128
|
-
}, []);
|
|
2129
|
-
const passwordError = (0, import_react13.useMemo)(() => {
|
|
2130
|
-
if (password.length === 0) return null;
|
|
2131
|
-
if (password.length < MIN_PASSWORD3) return `M\xEDnimo de ${MIN_PASSWORD3} caracteres.`;
|
|
2132
|
-
return null;
|
|
2133
|
-
}, [password]);
|
|
2134
|
-
const confirmError = (0, import_react13.useMemo)(() => {
|
|
2135
|
-
if (confirm.length === 0) return null;
|
|
2136
|
-
if (confirm !== password) return "Senhas n\xE3o coincidem.";
|
|
2137
|
-
return null;
|
|
2138
|
-
}, [confirm, password]);
|
|
2139
|
-
const canSubmit = token !== null && password.length >= MIN_PASSWORD3 && confirm === password && passwordError === null && confirmError === null && !submitting && !done;
|
|
2140
|
-
const submit = (0, import_react13.useCallback)(async () => {
|
|
2141
|
-
if (!canSubmit || token === null) return;
|
|
2142
|
-
setSubmitting(true);
|
|
2143
|
-
setError(null);
|
|
2144
|
-
try {
|
|
2145
|
-
await auth.reset({ token, newPassword: password });
|
|
2146
|
-
setDone(true);
|
|
2147
|
-
if (typeof window !== "undefined") {
|
|
2148
|
-
const url = new URL(window.location.href);
|
|
2149
|
-
url.searchParams.delete("token");
|
|
2150
|
-
url.searchParams.delete("screen");
|
|
2151
|
-
window.history.replaceState({}, "", url.toString());
|
|
2152
|
-
}
|
|
2153
|
-
} catch (err) {
|
|
2154
|
-
setError(mapSdkError(err));
|
|
2155
|
-
} finally {
|
|
2156
|
-
setSubmitting(false);
|
|
2157
|
-
}
|
|
2158
|
-
}, [auth, token, password, canSubmit]);
|
|
2159
|
-
return {
|
|
2160
|
-
token,
|
|
2161
|
-
password,
|
|
2162
|
-
setPassword,
|
|
2163
|
-
passwordError,
|
|
2164
|
-
confirm,
|
|
2165
|
-
setConfirm,
|
|
2166
|
-
confirmError,
|
|
2167
|
-
submit,
|
|
2168
|
-
submitting,
|
|
2169
|
-
canSubmit,
|
|
2170
|
-
done,
|
|
2171
|
-
error
|
|
2172
|
-
};
|
|
2173
|
-
}
|
|
2174
|
-
|
|
2175
|
-
// src/defaults/DefaultResetScreen.tsx
|
|
2176
|
-
var import_jsx_runtime23 = require("react/jsx-runtime");
|
|
2177
|
-
function DefaultResetScreen({ onNavigate }) {
|
|
2178
|
-
const { name } = useTemplateConfig();
|
|
2179
|
-
const f = useResetForm();
|
|
2180
|
-
if (f.done) {
|
|
2181
|
-
return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("main", { style: { padding: 24, maxWidth: 360, margin: "0 auto", textAlign: "center" }, children: [
|
|
2182
|
-
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)("h1", { children: "Senha alterada" }),
|
|
2183
|
-
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)("p", { style: { opacity: 0.7 }, children: "Agora \xE9 s\xF3 fazer login com a nova senha." }),
|
|
2184
|
-
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)("button", { "data-testid": "reset-back-login", type: "button", onClick: () => onNavigate("login"), children: "Ir pro login" })
|
|
2185
|
-
] });
|
|
2186
|
-
}
|
|
2187
|
-
if (f.token === null) {
|
|
2188
|
-
return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("main", { style: { padding: 24, maxWidth: 360, margin: "0 auto", textAlign: "center" }, children: [
|
|
2189
|
-
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)("h1", { children: "Link inv\xE1lido" }),
|
|
2190
|
-
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)("p", { style: { opacity: 0.7 }, children: "Pe\xE7a um novo link de reset." }),
|
|
2191
|
-
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)("button", { "data-testid": "reset-goto-forgot", type: "button", onClick: () => onNavigate("forgot"), children: "Pedir novo link" })
|
|
2192
|
-
] });
|
|
2193
|
-
}
|
|
2194
|
-
return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("main", { style: { padding: 24, maxWidth: 360, margin: "0 auto" }, children: [
|
|
2195
|
-
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)("h1", { style: { marginBottom: 8 }, children: name }),
|
|
2196
|
-
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)("p", { style: { opacity: 0.7, marginBottom: 24 }, children: "Escolha uma nova senha" }),
|
|
2197
|
-
/* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("form", { onSubmit: (e) => {
|
|
2198
|
-
e.preventDefault();
|
|
2199
|
-
void f.submit();
|
|
2200
|
-
}, children: [
|
|
2201
|
-
/* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("label", { style: { display: "block", marginBottom: 12 }, children: [
|
|
2202
|
-
"Nova senha",
|
|
2203
|
-
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)("input", { "data-testid": "reset-password", type: "password", value: f.password, onChange: (e) => f.setPassword(e.target.value), style: { display: "block", width: "100%" }, autoComplete: "new-password" }),
|
|
2204
|
-
f.passwordError && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("small", { style: { color: "#c00" }, children: f.passwordError })
|
|
2205
|
-
] }),
|
|
2206
|
-
/* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("label", { style: { display: "block", marginBottom: 12 }, children: [
|
|
2207
|
-
"Confirmar senha",
|
|
2208
|
-
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)("input", { "data-testid": "reset-confirm", type: "password", value: f.confirm, onChange: (e) => f.setConfirm(e.target.value), style: { display: "block", width: "100%" }, autoComplete: "new-password" }),
|
|
2209
|
-
f.confirmError && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("small", { style: { color: "#c00" }, children: f.confirmError })
|
|
2210
|
-
] }),
|
|
2211
|
-
f.error && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { role: "alert", style: { color: "#c00", marginBottom: 12 }, children: f.error.message }),
|
|
2212
|
-
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)("button", { "data-testid": "reset-submit", type: "submit", disabled: !f.canSubmit, style: { width: "100%", padding: 12, background: "var(--hook-color-primary)", color: "#fff", border: "none", borderRadius: 8, opacity: f.canSubmit ? 1 : 0.5 }, children: f.submitting ? "Alterando..." : "Alterar senha" })
|
|
2213
|
-
] })
|
|
2214
|
-
] });
|
|
2215
|
-
}
|
|
2216
|
-
|
|
2217
|
-
// src/defaults/DefaultPaywall.tsx
|
|
2218
|
-
var import_react14 = require("react");
|
|
2219
|
-
|
|
2220
|
-
// src/hooks/usePlan.ts
|
|
2221
|
-
var import_sdk9 = require("@hook-sdk/sdk");
|
|
2222
|
-
function usePlan() {
|
|
2223
|
-
const { plan } = (0, import_sdk9.useHook)();
|
|
2224
|
-
return plan;
|
|
2225
|
-
}
|
|
2226
|
-
|
|
2227
|
-
// src/utils/price.ts
|
|
2228
|
-
function formatBRL(cents) {
|
|
2229
|
-
if (cents === null || cents === void 0) return "";
|
|
2230
|
-
const reais = cents / 100;
|
|
2231
|
-
return new Intl.NumberFormat("pt-BR", {
|
|
2232
|
-
style: "currency",
|
|
2233
|
-
currency: "BRL"
|
|
2234
|
-
}).format(reais);
|
|
2235
|
-
}
|
|
2236
|
-
function monthlyFromYearly(yearlyCents) {
|
|
2237
|
-
if (yearlyCents === null || yearlyCents === void 0) return 0;
|
|
2238
|
-
return Math.round(yearlyCents / 12);
|
|
2239
|
-
}
|
|
2240
|
-
function dailyFromYearly(yearlyCents) {
|
|
2241
|
-
if (yearlyCents === null || yearlyCents === void 0) return 0;
|
|
2242
|
-
return Math.round(yearlyCents / 365);
|
|
2243
|
-
}
|
|
2244
|
-
function computeAnchorCents(baseCents, multiplier) {
|
|
2245
|
-
if (multiplier === null || multiplier === void 0) return null;
|
|
2246
|
-
if (!Number.isFinite(multiplier)) return null;
|
|
2247
|
-
if (multiplier <= 1) return null;
|
|
2248
|
-
return Math.round(baseCents * multiplier);
|
|
2249
|
-
}
|
|
2250
|
-
function discountPercent(anchorCents, realCents) {
|
|
2251
|
-
if (anchorCents <= realCents) return 0;
|
|
2252
|
-
return Math.floor((anchorCents - realCents) / anchorCents * 100);
|
|
2253
|
-
}
|
|
2254
|
-
|
|
2255
|
-
// src/defaults/DefaultPaywall.tsx
|
|
2256
|
-
var import_jsx_runtime24 = require("react/jsx-runtime");
|
|
2257
|
-
function DefaultPaywall() {
|
|
2258
|
-
const config = useTemplateConfig();
|
|
2259
|
-
const plan = usePlan();
|
|
2260
|
-
const {
|
|
2261
|
-
checkout,
|
|
2262
|
-
opening,
|
|
2263
|
-
error,
|
|
2264
|
-
availableMethods,
|
|
2265
|
-
monthlyEquivalent,
|
|
2266
|
-
pixPending,
|
|
2267
|
-
dismissPix
|
|
2268
|
-
} = usePaywallState();
|
|
2269
|
-
const p = config.subscription.paywall_config;
|
|
2270
|
-
const paywallCfg = plan.data?.paywallConfig ?? {};
|
|
2271
|
-
const anchorMultiplier = paywallCfg.anchorMultiplier ?? p.anchorMultiplier;
|
|
2272
|
-
const anchorPriceCents = paywallCfg.anchorPriceCents ?? p.anchorPriceCents;
|
|
2273
|
-
const [cycle, setCycle] = (0, import_react14.useState)("MONTHLY");
|
|
2274
|
-
const [method, setMethod] = (0, import_react14.useState)("card");
|
|
2275
|
-
const [cpf, setCpf] = (0, import_react14.useState)("");
|
|
2276
|
-
const [cardNumber, setCardNumber] = (0, import_react14.useState)("");
|
|
2277
|
-
const [cardHolderName, setCardHolderName] = (0, import_react14.useState)("");
|
|
2278
|
-
const [cardExpiryMonth, setCardExpiryMonth] = (0, import_react14.useState)("");
|
|
2279
|
-
const [cardExpiryYear, setCardExpiryYear] = (0, import_react14.useState)("");
|
|
2280
|
-
const [cardCcv, setCardCcv] = (0, import_react14.useState)("");
|
|
2281
|
-
const [holderName, setHolderName] = (0, import_react14.useState)("");
|
|
2282
|
-
const [holderEmail, setHolderEmail] = (0, import_react14.useState)("");
|
|
2283
|
-
const [holderPostalCode, setHolderPostalCode] = (0, import_react14.useState)("");
|
|
2284
|
-
const [holderAddressNumber, setHolderAddressNumber] = (0, import_react14.useState)("");
|
|
2285
|
-
const [holderPhone, setHolderPhone] = (0, import_react14.useState)("");
|
|
2286
|
-
const trialDays = plan.data?.trialDays ?? 0;
|
|
2287
|
-
const monthlyCents = plan.data?.priceCents ?? 0;
|
|
2288
|
-
const yearlyCents = plan.data?.yearlyPriceCents ?? null;
|
|
2289
|
-
const activeCents = cycle === "YEARLY" && yearlyCents ? monthlyEquivalent("YEARLY") : monthlyCents;
|
|
2290
|
-
const cycleValueCents = cycle === "YEARLY" && yearlyCents ? yearlyCents : monthlyCents;
|
|
2291
|
-
const cycleLabel = cycle === "YEARLY" ? "por ano" : "por m\xEAs";
|
|
2292
|
-
const pct = (0, import_react14.useMemo)(() => {
|
|
2293
|
-
if (!yearlyCents || !monthlyCents) return 0;
|
|
2294
|
-
const derived = Math.round((1 - yearlyCents / 12 / monthlyCents) * 100);
|
|
2295
|
-
return Math.max(0, derived);
|
|
2296
|
-
}, [monthlyCents, yearlyCents]);
|
|
2297
|
-
const anchorBaseCents = cycle === "YEARLY" && yearlyCents ? monthlyFromYearly(yearlyCents) : monthlyCents;
|
|
2298
|
-
const anchorCents = computeAnchorCents(anchorBaseCents, anchorMultiplier) ?? (anchorPriceCents && anchorPriceCents > anchorBaseCents ? anchorPriceCents : null);
|
|
2299
|
-
const anchorDiscount = anchorCents ? discountPercent(anchorCents, activeCents) : 0;
|
|
2300
|
-
const cpfDigits = cpf.replace(/\D/g, "");
|
|
2301
|
-
const cardFieldsFilled = cardNumber.replace(/\s/g, "").length >= 13 && cardHolderName.trim().length > 0 && cardExpiryMonth.length === 2 && cardExpiryYear.length >= 2 && cardCcv.length >= 3 && holderName.trim().length > 0 && /.+@.+\..+/.test(holderEmail) && holderPostalCode.replace(/\D/g, "").length === 8 && holderAddressNumber.trim().length > 0;
|
|
2302
|
-
const canCheckout = cpfDigits.length === 11 && !opening && (method === "pix-auto" || cardFieldsFilled);
|
|
2303
|
-
const ctaLabel = (0, import_react14.useMemo)(() => {
|
|
2304
|
-
if (opening) return "Abrindo\u2026";
|
|
2305
|
-
if (trialDays > 0) return `Comece trial de ${trialDays} dias gr\xE1tis`;
|
|
2306
|
-
return p.cta ?? "Assinar agora";
|
|
2307
|
-
}, [opening, trialDays, p.cta]);
|
|
2308
|
-
const footer = (0, import_react14.useMemo)(() => {
|
|
2309
|
-
if (trialDays > 0) {
|
|
2310
|
-
return `Sem cobran\xE7a agora. Cobran\xE7a autom\xE1tica em ${trialDays} dias. Cancele quando quiser.`;
|
|
2311
|
-
}
|
|
2312
|
-
return "Cobran\xE7a imediata. Cancele quando quiser.";
|
|
2313
|
-
}, [trialDays]);
|
|
2314
|
-
const yearSuffix = cardExpiryYear.length === 2 ? `20${cardExpiryYear}` : cardExpiryYear;
|
|
2315
|
-
const phoneDigits = holderPhone.replace(/\D/g, "");
|
|
2316
|
-
const postalDigits = holderPostalCode.replace(/\D/g, "");
|
|
2317
|
-
const submit = () => {
|
|
2318
|
-
if (method === "card") {
|
|
2319
|
-
void checkout({
|
|
2320
|
-
cpf: cpfDigits,
|
|
2321
|
-
cycle,
|
|
2322
|
-
method: "card",
|
|
2323
|
-
card: {
|
|
2324
|
-
number: cardNumber.replace(/\s/g, ""),
|
|
2325
|
-
holderName: cardHolderName.trim(),
|
|
2326
|
-
expiryMonth: cardExpiryMonth,
|
|
2327
|
-
expiryYear: yearSuffix,
|
|
2328
|
-
ccv: cardCcv
|
|
2329
|
-
},
|
|
2330
|
-
holderInfo: {
|
|
2331
|
-
name: holderName.trim(),
|
|
2332
|
-
email: holderEmail.trim(),
|
|
2333
|
-
cpfCnpj: cpfDigits,
|
|
2334
|
-
postalCode: postalDigits,
|
|
2335
|
-
addressNumber: holderAddressNumber.trim(),
|
|
2336
|
-
...phoneDigits ? { phone: phoneDigits } : {}
|
|
2337
|
-
}
|
|
2338
|
-
});
|
|
2339
|
-
return;
|
|
2340
|
-
}
|
|
2341
|
-
void checkout({ cpf: cpfDigits, cycle, method: "pix-auto" });
|
|
2342
|
-
};
|
|
2343
|
-
const inputStyle = {
|
|
2344
|
-
width: "100%",
|
|
2345
|
-
padding: 10,
|
|
2346
|
-
fontSize: 14,
|
|
2347
|
-
borderRadius: 8,
|
|
2348
|
-
border: "1px solid #ccc",
|
|
2349
|
-
boxSizing: "border-box"
|
|
2350
|
-
};
|
|
2351
|
-
const labelStyle = { display: "block", fontSize: 13, opacity: 0.75, marginBottom: 4 };
|
|
2352
|
-
const fieldGroup = { marginBottom: 10, textAlign: "left" };
|
|
2353
|
-
return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("main", { style: { padding: 24, maxWidth: 480, margin: "0 auto", textAlign: "center" }, children: [
|
|
2354
|
-
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)("h1", { style: { marginBottom: 8 }, children: p.title }),
|
|
2355
|
-
p.subtitle && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("p", { style: { opacity: 0.7, marginBottom: 24 }, children: p.subtitle }),
|
|
2356
|
-
/* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
|
|
2357
|
-
"div",
|
|
2358
|
-
{
|
|
2359
|
-
role: "group",
|
|
2360
|
-
"aria-label": "Per\xEDodo de cobran\xE7a",
|
|
2361
|
-
style: { display: "flex", gap: 8, marginBottom: 16 },
|
|
2362
|
-
children: [
|
|
2363
|
-
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
2364
|
-
"button",
|
|
2365
|
-
{
|
|
2366
|
-
type: "button",
|
|
2367
|
-
"aria-pressed": cycle === "MONTHLY",
|
|
2368
|
-
onClick: () => setCycle("MONTHLY"),
|
|
2369
|
-
style: {
|
|
2370
|
-
flex: 1,
|
|
2371
|
-
padding: 12,
|
|
2372
|
-
borderRadius: 8,
|
|
2373
|
-
border: cycle === "MONTHLY" ? "2px solid var(--hook-color-primary)" : "1px solid #ccc",
|
|
2374
|
-
background: cycle === "MONTHLY" ? "var(--hook-color-primary-soft, #eef)" : "white",
|
|
2375
|
-
cursor: "pointer"
|
|
2376
|
-
},
|
|
2377
|
-
children: "Mensal"
|
|
2378
|
-
}
|
|
2379
|
-
),
|
|
2380
|
-
/* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
|
|
2381
|
-
"button",
|
|
2382
|
-
{
|
|
2383
|
-
type: "button",
|
|
2384
|
-
"aria-pressed": cycle === "YEARLY",
|
|
2385
|
-
onClick: () => setCycle("YEARLY"),
|
|
2386
|
-
disabled: !yearlyCents,
|
|
2387
|
-
style: {
|
|
2388
|
-
flex: 1,
|
|
2389
|
-
padding: 12,
|
|
2390
|
-
borderRadius: 8,
|
|
2391
|
-
border: cycle === "YEARLY" ? "2px solid var(--hook-color-primary)" : "1px solid #ccc",
|
|
2392
|
-
background: cycle === "YEARLY" ? "var(--hook-color-primary-soft, #eef)" : "white",
|
|
2393
|
-
cursor: yearlyCents ? "pointer" : "not-allowed",
|
|
2394
|
-
opacity: yearlyCents ? 1 : 0.5
|
|
2395
|
-
},
|
|
2396
|
-
children: [
|
|
2397
|
-
"Anual",
|
|
2398
|
-
pct > 0 ? ` \u2212${pct}%` : ""
|
|
2399
|
-
]
|
|
2400
|
-
}
|
|
2401
|
-
)
|
|
2402
|
-
]
|
|
2403
|
-
}
|
|
2404
|
-
),
|
|
2405
|
-
/* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { style: { marginBottom: 8 }, children: [
|
|
2406
|
-
/* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { style: { fontSize: 32, fontWeight: 700, lineHeight: 1 }, children: [
|
|
2407
|
-
formatBRL(activeCents),
|
|
2408
|
-
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { style: { fontSize: 16, fontWeight: 400, opacity: 0.7 }, children: "/m\xEAs" })
|
|
2409
|
-
] }),
|
|
2410
|
-
anchorCents && /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { style: { fontSize: 14, opacity: 0.6, marginTop: 4 }, children: [
|
|
2411
|
-
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { style: { textDecoration: "line-through" }, children: formatBRL(anchorCents) }),
|
|
2412
|
-
anchorDiscount > 0 && /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("span", { style: { marginLeft: 6 }, children: [
|
|
2413
|
-
"\u2212",
|
|
2414
|
-
anchorDiscount,
|
|
2415
|
-
"%"
|
|
2416
|
-
] })
|
|
2417
|
-
] }),
|
|
2418
|
-
cycle === "YEARLY" && yearlyCents && /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { style: { fontSize: 12, opacity: 0.6, marginTop: 4 }, children: [
|
|
2419
|
-
"Cobrado ",
|
|
2420
|
-
formatBRL(yearlyCents),
|
|
2421
|
-
" por ano"
|
|
2422
|
-
] })
|
|
2423
|
-
] }),
|
|
2424
|
-
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)("ul", { style: { listStyle: "none", padding: 0, textAlign: "left", margin: "24px 0" }, children: p.benefits.map((b) => /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("li", { style: { padding: "8px 0", display: "flex", alignItems: "center" }, children: [
|
|
2425
|
-
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { "aria-hidden": true, style: { marginRight: 8 }, children: "\u2713" }),
|
|
2426
|
-
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { children: b })
|
|
2427
|
-
] }, b)) }),
|
|
2428
|
-
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { role: "tablist", "aria-label": "M\xE9todo de pagamento", style: { display: "flex", gap: 8, marginBottom: 16 }, children: availableMethods.map((m) => /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
2429
|
-
"button",
|
|
2430
|
-
{
|
|
2431
|
-
type: "button",
|
|
2432
|
-
role: "tab",
|
|
2433
|
-
"aria-selected": method === m,
|
|
2434
|
-
onClick: () => setMethod(m),
|
|
2435
|
-
style: {
|
|
2436
|
-
flex: 1,
|
|
2437
|
-
padding: 10,
|
|
2438
|
-
borderRadius: 8,
|
|
2439
|
-
border: method === m ? "2px solid var(--hook-color-primary)" : "1px solid #ccc",
|
|
2440
|
-
background: method === m ? "var(--hook-color-primary-soft, #eef)" : "white",
|
|
2441
|
-
cursor: "pointer"
|
|
2442
|
-
},
|
|
2443
|
-
children: m === "card" ? "\u{1F4B3} Cart\xE3o" : "\u{1F4F1} Pix Autom\xE1tico"
|
|
2444
|
-
},
|
|
2445
|
-
m
|
|
2446
|
-
)) }),
|
|
2447
|
-
method === "card" && /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
|
|
2448
|
-
"fieldset",
|
|
2449
|
-
{
|
|
2450
|
-
"data-testid": "paywall-card-form",
|
|
2451
|
-
style: { border: "none", padding: 0, marginBottom: 16 },
|
|
2452
|
-
children: [
|
|
2453
|
-
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)("legend", { style: { fontSize: 13, opacity: 0.75, marginBottom: 8 }, children: "Dados do cart\xE3o" }),
|
|
2454
|
-
/* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { style: fieldGroup, children: [
|
|
2455
|
-
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)("label", { htmlFor: "pw-card-number", style: labelStyle, children: "N\xFAmero do cart\xE3o" }),
|
|
2456
|
-
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
2457
|
-
"input",
|
|
2458
|
-
{
|
|
2459
|
-
id: "pw-card-number",
|
|
2460
|
-
"data-testid": "pw-card-number",
|
|
2461
|
-
type: "text",
|
|
2462
|
-
inputMode: "numeric",
|
|
2463
|
-
autoComplete: "cc-number",
|
|
2464
|
-
placeholder: "0000 0000 0000 0000",
|
|
2465
|
-
value: cardNumber,
|
|
2466
|
-
onChange: (e) => setCardNumber(e.target.value),
|
|
2467
|
-
style: inputStyle
|
|
2468
|
-
}
|
|
2469
|
-
)
|
|
2470
|
-
] }),
|
|
2471
|
-
/* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { style: fieldGroup, children: [
|
|
2472
|
-
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)("label", { htmlFor: "pw-card-holder", style: labelStyle, children: "Nome impresso no cart\xE3o" }),
|
|
2473
|
-
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
2474
|
-
"input",
|
|
2475
|
-
{
|
|
2476
|
-
id: "pw-card-holder",
|
|
2477
|
-
"data-testid": "pw-card-holder",
|
|
2478
|
-
type: "text",
|
|
2479
|
-
autoComplete: "cc-name",
|
|
2480
|
-
placeholder: "NOME SOBRENOME",
|
|
2481
|
-
value: cardHolderName,
|
|
2482
|
-
onChange: (e) => setCardHolderName(e.target.value),
|
|
2483
|
-
style: inputStyle
|
|
2484
|
-
}
|
|
2485
|
-
)
|
|
2486
|
-
] }),
|
|
2487
|
-
/* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { style: { display: "flex", gap: 8, marginBottom: 10 }, children: [
|
|
2488
|
-
/* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { style: { flex: 1, textAlign: "left" }, children: [
|
|
2489
|
-
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)("label", { htmlFor: "pw-card-exp-m", style: labelStyle, children: "M\xEAs" }),
|
|
2490
|
-
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
2491
|
-
"input",
|
|
2492
|
-
{
|
|
2493
|
-
id: "pw-card-exp-m",
|
|
2494
|
-
"data-testid": "pw-card-exp-m",
|
|
2495
|
-
type: "text",
|
|
2496
|
-
inputMode: "numeric",
|
|
2497
|
-
autoComplete: "cc-exp-month",
|
|
2498
|
-
placeholder: "MM",
|
|
2499
|
-
maxLength: 2,
|
|
2500
|
-
value: cardExpiryMonth,
|
|
2501
|
-
onChange: (e) => setCardExpiryMonth(e.target.value.replace(/\D/g, "")),
|
|
2502
|
-
style: inputStyle
|
|
2503
|
-
}
|
|
2504
|
-
)
|
|
2505
|
-
] }),
|
|
2506
|
-
/* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { style: { flex: 1, textAlign: "left" }, children: [
|
|
2507
|
-
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)("label", { htmlFor: "pw-card-exp-y", style: labelStyle, children: "Ano" }),
|
|
2508
|
-
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
2509
|
-
"input",
|
|
2510
|
-
{
|
|
2511
|
-
id: "pw-card-exp-y",
|
|
2512
|
-
"data-testid": "pw-card-exp-y",
|
|
2513
|
-
type: "text",
|
|
2514
|
-
inputMode: "numeric",
|
|
2515
|
-
autoComplete: "cc-exp-year",
|
|
2516
|
-
placeholder: "AA",
|
|
2517
|
-
maxLength: 4,
|
|
2518
|
-
value: cardExpiryYear,
|
|
2519
|
-
onChange: (e) => setCardExpiryYear(e.target.value.replace(/\D/g, "")),
|
|
2520
|
-
style: inputStyle
|
|
2521
|
-
}
|
|
2522
|
-
)
|
|
2523
|
-
] }),
|
|
2524
|
-
/* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { style: { flex: 1, textAlign: "left" }, children: [
|
|
2525
|
-
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)("label", { htmlFor: "pw-card-cvv", style: labelStyle, children: "CVV" }),
|
|
2526
|
-
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
2527
|
-
"input",
|
|
2528
|
-
{
|
|
2529
|
-
id: "pw-card-cvv",
|
|
2530
|
-
"data-testid": "pw-card-cvv",
|
|
2531
|
-
type: "text",
|
|
2532
|
-
inputMode: "numeric",
|
|
2533
|
-
autoComplete: "cc-csc",
|
|
2534
|
-
placeholder: "123",
|
|
2535
|
-
maxLength: 4,
|
|
2536
|
-
value: cardCcv,
|
|
2537
|
-
onChange: (e) => setCardCcv(e.target.value.replace(/\D/g, "")),
|
|
2538
|
-
style: inputStyle
|
|
2539
|
-
}
|
|
2540
|
-
)
|
|
2541
|
-
] })
|
|
2542
|
-
] }),
|
|
2543
|
-
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)("legend", { style: { fontSize: 13, opacity: 0.75, marginBottom: 8, marginTop: 8 }, children: "Dados do titular" }),
|
|
2544
|
-
/* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { style: fieldGroup, children: [
|
|
2545
|
-
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)("label", { htmlFor: "pw-holder-name", style: labelStyle, children: "Nome completo" }),
|
|
2546
|
-
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
2547
|
-
"input",
|
|
2548
|
-
{
|
|
2549
|
-
id: "pw-holder-name",
|
|
2550
|
-
"data-testid": "pw-holder-name",
|
|
2551
|
-
type: "text",
|
|
2552
|
-
autoComplete: "name",
|
|
2553
|
-
placeholder: "Nome Sobrenome",
|
|
2554
|
-
value: holderName,
|
|
2555
|
-
onChange: (e) => setHolderName(e.target.value),
|
|
2556
|
-
style: inputStyle
|
|
2557
|
-
}
|
|
2558
|
-
)
|
|
2559
|
-
] }),
|
|
2560
|
-
/* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { style: fieldGroup, children: [
|
|
2561
|
-
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)("label", { htmlFor: "pw-holder-email", style: labelStyle, children: "E-mail" }),
|
|
2562
|
-
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
2563
|
-
"input",
|
|
2564
|
-
{
|
|
2565
|
-
id: "pw-holder-email",
|
|
2566
|
-
"data-testid": "pw-holder-email",
|
|
2567
|
-
type: "email",
|
|
2568
|
-
autoComplete: "email",
|
|
2569
|
-
placeholder: "voce@email.com",
|
|
2570
|
-
value: holderEmail,
|
|
2571
|
-
onChange: (e) => setHolderEmail(e.target.value),
|
|
2572
|
-
style: inputStyle
|
|
2573
|
-
}
|
|
2574
|
-
)
|
|
2575
|
-
] }),
|
|
2576
|
-
/* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { style: { display: "flex", gap: 8, marginBottom: 10 }, children: [
|
|
2577
|
-
/* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { style: { flex: 1, textAlign: "left" }, children: [
|
|
2578
|
-
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)("label", { htmlFor: "pw-holder-cep", style: labelStyle, children: "CEP" }),
|
|
2579
|
-
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
2580
|
-
"input",
|
|
2581
|
-
{
|
|
2582
|
-
id: "pw-holder-cep",
|
|
2583
|
-
"data-testid": "pw-holder-cep",
|
|
2584
|
-
type: "text",
|
|
2585
|
-
inputMode: "numeric",
|
|
2586
|
-
autoComplete: "postal-code",
|
|
2587
|
-
placeholder: "00000-000",
|
|
2588
|
-
value: holderPostalCode,
|
|
2589
|
-
onChange: (e) => setHolderPostalCode(e.target.value),
|
|
2590
|
-
style: inputStyle
|
|
2591
|
-
}
|
|
2592
|
-
)
|
|
2593
|
-
] }),
|
|
2594
|
-
/* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { style: { flex: 1, textAlign: "left" }, children: [
|
|
2595
|
-
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)("label", { htmlFor: "pw-holder-addr-n", style: labelStyle, children: "N\xFAmero" }),
|
|
2596
|
-
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
2597
|
-
"input",
|
|
2598
|
-
{
|
|
2599
|
-
id: "pw-holder-addr-n",
|
|
2600
|
-
"data-testid": "pw-holder-addr-n",
|
|
2601
|
-
type: "text",
|
|
2602
|
-
inputMode: "numeric",
|
|
2603
|
-
placeholder: "123",
|
|
2604
|
-
value: holderAddressNumber,
|
|
2605
|
-
onChange: (e) => setHolderAddressNumber(e.target.value),
|
|
2606
|
-
style: inputStyle
|
|
2607
|
-
}
|
|
2608
|
-
)
|
|
2609
|
-
] })
|
|
2610
|
-
] }),
|
|
2611
|
-
/* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { style: fieldGroup, children: [
|
|
2612
|
-
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)("label", { htmlFor: "pw-holder-phone", style: labelStyle, children: "Telefone (opcional)" }),
|
|
2613
|
-
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
2614
|
-
"input",
|
|
2615
|
-
{
|
|
2616
|
-
id: "pw-holder-phone",
|
|
2617
|
-
"data-testid": "pw-holder-phone",
|
|
2618
|
-
type: "tel",
|
|
2619
|
-
inputMode: "tel",
|
|
2620
|
-
autoComplete: "tel",
|
|
2621
|
-
placeholder: "(11) 99999-9999",
|
|
2622
|
-
value: holderPhone,
|
|
2623
|
-
onChange: (e) => setHolderPhone(e.target.value),
|
|
2624
|
-
style: inputStyle
|
|
2625
|
-
}
|
|
2626
|
-
)
|
|
2627
|
-
] })
|
|
2628
|
-
]
|
|
2629
|
-
}
|
|
2630
|
-
),
|
|
2631
|
-
/* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { style: fieldGroup, children: [
|
|
2632
|
-
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)("label", { htmlFor: "pw-cpf", style: labelStyle, children: "Seu CPF" }),
|
|
2633
|
-
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
2634
|
-
"input",
|
|
2635
|
-
{
|
|
2636
|
-
id: "pw-cpf",
|
|
2637
|
-
"data-testid": "paywall-cpf",
|
|
2638
|
-
type: "text",
|
|
2639
|
-
inputMode: "numeric",
|
|
2640
|
-
placeholder: "000.000.000-00",
|
|
2641
|
-
value: cpf,
|
|
2642
|
-
onChange: (e) => setCpf(e.target.value),
|
|
2643
|
-
style: inputStyle
|
|
2644
|
-
}
|
|
2645
|
-
)
|
|
2646
|
-
] }),
|
|
2647
|
-
error && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { role: "alert", style: { color: "#c00", marginBottom: 12 }, children: error.message }),
|
|
2648
|
-
method === "pix-auto" && /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
|
|
2649
|
-
"div",
|
|
2650
|
-
{
|
|
2651
|
-
"data-testid": "paywall-pix-callout",
|
|
2652
|
-
style: {
|
|
2653
|
-
background: "rgba(0,0,0,0.04)",
|
|
2654
|
-
borderLeft: "3px solid var(--hook-color-primary)",
|
|
2655
|
-
padding: "10px 12px",
|
|
2656
|
-
marginBottom: 12,
|
|
2657
|
-
borderRadius: 4,
|
|
2658
|
-
fontSize: 12,
|
|
2659
|
-
lineHeight: 1.45,
|
|
2660
|
-
textAlign: "left"
|
|
2661
|
-
},
|
|
2662
|
-
children: [
|
|
2663
|
-
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)("strong", { children: "Como funciona:" }),
|
|
2664
|
-
" no app do seu banco vai aparecer uma cobran\xE7a de",
|
|
2665
|
-
" ",
|
|
2666
|
-
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)("strong", { children: "R$ 0,01" }),
|
|
2667
|
-
" \u2014 \xE9 simb\xF3lica, s\xF3 pra ativar o PIX Autom\xE1tico.",
|
|
2668
|
-
trialDays > 0 ? /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(import_jsx_runtime24.Fragment, { children: [
|
|
2669
|
-
" ",
|
|
2670
|
-
"Depois, ",
|
|
2671
|
-
/* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("strong", { children: [
|
|
2672
|
-
trialDays,
|
|
2673
|
-
" dias gr\xE1tis"
|
|
2674
|
-
] }),
|
|
2675
|
-
"; a cobran\xE7a de",
|
|
2676
|
-
" ",
|
|
2677
|
-
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)("strong", { children: formatBRL(cycleValueCents) }),
|
|
2678
|
-
" ",
|
|
2679
|
-
cycleLabel,
|
|
2680
|
-
" s\xF3 come\xE7a depois."
|
|
2681
|
-
] }) : /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(import_jsx_runtime24.Fragment, { children: [
|
|
2682
|
-
" ",
|
|
2683
|
-
"A cobran\xE7a de ",
|
|
2684
|
-
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)("strong", { children: formatBRL(cycleValueCents) }),
|
|
2685
|
-
" ",
|
|
2686
|
-
cycleLabel,
|
|
2687
|
-
" vem em seguida."
|
|
2688
|
-
] })
|
|
2689
|
-
]
|
|
2690
|
-
}
|
|
2691
|
-
),
|
|
2692
|
-
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
2693
|
-
"button",
|
|
2694
|
-
{
|
|
2695
|
-
"data-testid": "paywall-cta",
|
|
2696
|
-
type: "button",
|
|
2697
|
-
onClick: submit,
|
|
2698
|
-
disabled: !canCheckout,
|
|
2699
|
-
style: {
|
|
2700
|
-
width: "100%",
|
|
2701
|
-
padding: 14,
|
|
2702
|
-
background: "var(--hook-color-primary)",
|
|
2703
|
-
color: "#fff",
|
|
2704
|
-
border: "none",
|
|
2705
|
-
borderRadius: 8,
|
|
2706
|
-
opacity: canCheckout ? 1 : 0.5,
|
|
2707
|
-
fontSize: 16,
|
|
2708
|
-
fontWeight: 600,
|
|
2709
|
-
cursor: canCheckout ? "pointer" : "not-allowed"
|
|
2710
|
-
},
|
|
2711
|
-
children: ctaLabel
|
|
2712
|
-
}
|
|
2713
|
-
),
|
|
2714
|
-
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)("p", { style: { opacity: 0.55, marginTop: 16, fontSize: 12 }, children: footer }),
|
|
2715
|
-
p.priceHint && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("p", { style: { opacity: 0.6, marginTop: 8, fontSize: 12 }, children: p.priceHint }),
|
|
2716
|
-
p.footerNote && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("p", { style: { opacity: 0.5, marginTop: 8, fontSize: 12 }, children: p.footerNote }),
|
|
2717
|
-
pixPending && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
2718
|
-
"div",
|
|
2719
|
-
{
|
|
2720
|
-
"data-testid": "paywall-pix-modal",
|
|
2721
|
-
role: "dialog",
|
|
2722
|
-
"aria-label": "Pagamento Pix pendente",
|
|
2723
|
-
style: {
|
|
2724
|
-
position: "fixed",
|
|
2725
|
-
inset: 0,
|
|
2726
|
-
background: "rgba(0,0,0,0.6)",
|
|
2727
|
-
display: "flex",
|
|
2728
|
-
alignItems: "center",
|
|
2729
|
-
justifyContent: "center",
|
|
2730
|
-
padding: 24,
|
|
2731
|
-
zIndex: 1e3
|
|
2732
|
-
},
|
|
2733
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { style: {
|
|
2734
|
-
background: "#fff",
|
|
2735
|
-
borderRadius: 12,
|
|
2736
|
-
padding: 24,
|
|
2737
|
-
maxWidth: 360,
|
|
2738
|
-
width: "100%",
|
|
2739
|
-
textAlign: "center"
|
|
2740
|
-
}, children: [
|
|
2741
|
-
pixPending.paid ? /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(import_jsx_runtime24.Fragment, { children: [
|
|
2742
|
-
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)("h2", { style: { marginTop: 0 }, children: "Pagamento confirmado!" }),
|
|
2743
|
-
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)("p", { style: { opacity: 0.7 }, children: "Liberando acesso\u2026" })
|
|
2744
|
-
] }) : /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(import_jsx_runtime24.Fragment, { children: [
|
|
2745
|
-
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)("h2", { style: { marginTop: 0, fontSize: 18 }, children: "Pague com Pix Autom\xE1tico" }),
|
|
2746
|
-
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)("p", { style: { fontSize: 13, opacity: 0.75 }, children: "Escaneie o QR Code no app do seu banco pra autorizar o d\xE9bito recorrente." }),
|
|
2747
|
-
/* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
|
|
2748
|
-
"p",
|
|
2749
|
-
{
|
|
2750
|
-
"data-testid": "pix-modal-explain",
|
|
2751
|
-
style: { fontSize: 12, opacity: 0.65, marginTop: 8, lineHeight: 1.4 },
|
|
2752
|
-
children: [
|
|
2753
|
-
"Seu banco vai mostrar uma cobran\xE7a de ",
|
|
2754
|
-
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)("strong", { children: "R$ 0,01" }),
|
|
2755
|
-
" \u2014 \xE9 simb\xF3lica, s\xF3 pra ativar o PIX Autom\xE1tico.",
|
|
2756
|
-
trialDays > 0 ? /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(import_jsx_runtime24.Fragment, { children: [
|
|
2757
|
-
" ",
|
|
2758
|
-
"A cobran\xE7a de ",
|
|
2759
|
-
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)("strong", { children: formatBRL(cycleValueCents) }),
|
|
2760
|
-
" ",
|
|
2761
|
-
cycleLabel,
|
|
2762
|
-
" come\xE7a depois dos ",
|
|
2763
|
-
/* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("strong", { children: [
|
|
2764
|
-
trialDays,
|
|
2765
|
-
" dias gr\xE1tis"
|
|
2766
|
-
] }),
|
|
2767
|
-
", automaticamente."
|
|
2768
|
-
] }) : /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(import_jsx_runtime24.Fragment, { children: [
|
|
2769
|
-
" ",
|
|
2770
|
-
"A cobran\xE7a de ",
|
|
2771
|
-
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)("strong", { children: formatBRL(cycleValueCents) }),
|
|
2772
|
-
" ",
|
|
2773
|
-
cycleLabel,
|
|
2774
|
-
" vem logo em seguida."
|
|
2775
|
-
] })
|
|
2776
|
-
]
|
|
2777
|
-
}
|
|
2778
|
-
),
|
|
2779
|
-
pixPending.qrCodeBase64 && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
2780
|
-
"img",
|
|
2781
|
-
{
|
|
2782
|
-
"data-testid": "pix-qr-image",
|
|
2783
|
-
alt: "QR Code Pix",
|
|
2784
|
-
src: `data:image/png;base64,${pixPending.qrCodeBase64}`,
|
|
2785
|
-
style: { width: "100%", maxWidth: 240, margin: "12px auto", display: "block" }
|
|
2786
|
-
}
|
|
2787
|
-
),
|
|
2788
|
-
pixPending.qrCodePayload && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
2789
|
-
"textarea",
|
|
2790
|
-
{
|
|
2791
|
-
"data-testid": "pix-qr-payload",
|
|
2792
|
-
readOnly: true,
|
|
2793
|
-
value: pixPending.qrCodePayload,
|
|
2794
|
-
style: {
|
|
2795
|
-
width: "100%",
|
|
2796
|
-
minHeight: 72,
|
|
2797
|
-
padding: 8,
|
|
2798
|
-
fontSize: 11,
|
|
2799
|
-
fontFamily: "monospace",
|
|
2800
|
-
borderRadius: 6,
|
|
2801
|
-
border: "1px solid #ccc",
|
|
2802
|
-
resize: "none"
|
|
2803
|
-
}
|
|
2804
|
-
}
|
|
2805
|
-
),
|
|
2806
|
-
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)("p", { style: { fontSize: 11, opacity: 0.55, marginTop: 12 }, children: "Aguardando confirma\xE7\xE3o do banco\u2026 Pode levar alguns segundos." })
|
|
2807
|
-
] }),
|
|
2808
|
-
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
2809
|
-
"button",
|
|
2810
|
-
{
|
|
2811
|
-
type: "button",
|
|
2812
|
-
onClick: dismissPix,
|
|
2813
|
-
style: {
|
|
2814
|
-
marginTop: 16,
|
|
2815
|
-
padding: "8px 16px",
|
|
2816
|
-
border: "1px solid #ccc",
|
|
2817
|
-
borderRadius: 6,
|
|
2818
|
-
background: "white",
|
|
2819
|
-
cursor: "pointer"
|
|
2820
|
-
},
|
|
2821
|
-
children: "Fechar"
|
|
2822
|
-
}
|
|
2823
|
-
)
|
|
2824
|
-
] })
|
|
2825
|
-
}
|
|
2826
|
-
)
|
|
2827
|
-
] });
|
|
2828
|
-
}
|
|
2829
|
-
|
|
2830
|
-
// src/AppRoot.tsx
|
|
2831
|
-
var import_jsx_runtime25 = require("react/jsx-runtime");
|
|
1846
|
+
// src/internal/PaymentReturnHandler.tsx
|
|
1847
|
+
var import_react10 = require("react");
|
|
1848
|
+
var import_sdk3 = require("@hook-sdk/sdk");
|
|
1849
|
+
var import_jsx_runtime17 = require("react/jsx-runtime");
|
|
2832
1850
|
var BACKOFF_MS = [2e3, 5e3, 1e4, 2e4, 4e4];
|
|
2833
1851
|
function PaymentReturnHandler({ children }) {
|
|
2834
|
-
const { subscription } = (0,
|
|
2835
|
-
const subRef = (0,
|
|
1852
|
+
const { subscription } = (0, import_sdk3.useHook)();
|
|
1853
|
+
const subRef = (0, import_react10.useRef)(subscription);
|
|
2836
1854
|
subRef.current = subscription;
|
|
2837
|
-
const runIdRef = (0,
|
|
2838
|
-
const [state, setState] = (0,
|
|
2839
|
-
const runPoll = (0,
|
|
1855
|
+
const runIdRef = (0, import_react10.useRef)(0);
|
|
1856
|
+
const [state, setState] = (0, import_react10.useState)("idle");
|
|
1857
|
+
const runPoll = (0, import_react10.useCallback)(() => {
|
|
2840
1858
|
const runId = ++runIdRef.current;
|
|
2841
1859
|
setState("confirming");
|
|
2842
1860
|
let attempts = 0;
|
|
@@ -2865,7 +1883,7 @@ function PaymentReturnHandler({ children }) {
|
|
|
2865
1883
|
};
|
|
2866
1884
|
void tick();
|
|
2867
1885
|
}, []);
|
|
2868
|
-
(0,
|
|
1886
|
+
(0, import_react10.useEffect)(() => {
|
|
2869
1887
|
if (typeof window === "undefined") return;
|
|
2870
1888
|
const url = new URL(window.location.href);
|
|
2871
1889
|
if (url.searchParams.get("paymentReturn") !== "1") return;
|
|
@@ -2875,31 +1893,15 @@ function PaymentReturnHandler({ children }) {
|
|
|
2875
1893
|
};
|
|
2876
1894
|
}, [runPoll]);
|
|
2877
1895
|
if (state === "confirming") {
|
|
2878
|
-
return /* @__PURE__ */ (0,
|
|
2879
|
-
"div",
|
|
2880
|
-
{
|
|
2881
|
-
role: "status",
|
|
2882
|
-
"aria-live": "polite",
|
|
2883
|
-
style: overlayStyle2,
|
|
2884
|
-
children: "Confirmando pagamento\u2026"
|
|
2885
|
-
}
|
|
2886
|
-
);
|
|
1896
|
+
return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { role: "status", "aria-live": "polite", style: overlayStyle2, children: "Confirmando pagamento\u2026" });
|
|
2887
1897
|
}
|
|
2888
1898
|
if (state === "waiting") {
|
|
2889
|
-
return /* @__PURE__ */ (0,
|
|
2890
|
-
/* @__PURE__ */ (0,
|
|
2891
|
-
/* @__PURE__ */ (0,
|
|
2892
|
-
"button",
|
|
2893
|
-
{
|
|
2894
|
-
type: "button",
|
|
2895
|
-
onClick: runPoll,
|
|
2896
|
-
style: buttonStyle,
|
|
2897
|
-
children: "Atualizar"
|
|
2898
|
-
}
|
|
2899
|
-
)
|
|
1899
|
+
return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { role: "status", "aria-live": "polite", style: overlayStyle2, children: /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { style: { maxWidth: 320, textAlign: "center", lineHeight: 1.5 }, children: [
|
|
1900
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { style: { marginBottom: 16 }, children: "Pagamento aceito. Estamos confirmando com o banco \u2014 pode levar alguns minutos." }),
|
|
1901
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("button", { type: "button", onClick: runPoll, style: buttonStyle, children: "Atualizar" })
|
|
2900
1902
|
] }) });
|
|
2901
1903
|
}
|
|
2902
|
-
return /* @__PURE__ */ (0,
|
|
1904
|
+
return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_jsx_runtime17.Fragment, { children });
|
|
2903
1905
|
}
|
|
2904
1906
|
var overlayStyle2 = {
|
|
2905
1907
|
position: "fixed",
|
|
@@ -2923,129 +1925,534 @@ var buttonStyle = {
|
|
|
2923
1925
|
fontWeight: 600,
|
|
2924
1926
|
cursor: "pointer"
|
|
2925
1927
|
};
|
|
2926
|
-
|
|
2927
|
-
|
|
1928
|
+
|
|
1929
|
+
// src/AppRoot.tsx
|
|
1930
|
+
var import_jsx_runtime18 = require("react/jsx-runtime");
|
|
1931
|
+
function buildLegacyConfigShim(config) {
|
|
1932
|
+
const paywall = config.paywall;
|
|
1933
|
+
const isFree = paywall.mode === "free";
|
|
1934
|
+
const monthlyCents = isFree ? 0 : paywall.prices.monthlyCents;
|
|
1935
|
+
const trialDays = isFree ? 0 : paywall.trialDays ?? 0;
|
|
1936
|
+
return {
|
|
1937
|
+
slug: config.slug,
|
|
1938
|
+
name: config.name,
|
|
1939
|
+
email_alias: config.slug,
|
|
1940
|
+
theme: { primary_color: config.branding.primaryColor },
|
|
1941
|
+
features_enabled: config.features_enabled ?? [],
|
|
1942
|
+
dependencies_allowlist: ["react", "react-dom"],
|
|
1943
|
+
subscription: {
|
|
1944
|
+
mode: paywall.mode,
|
|
1945
|
+
price_cents: monthlyCents,
|
|
1946
|
+
currency: "brl",
|
|
1947
|
+
trial_days: trialDays,
|
|
1948
|
+
paywall_config: {
|
|
1949
|
+
title: config.name,
|
|
1950
|
+
benefits: ["Acesso completo"],
|
|
1951
|
+
cta: "Assinar"
|
|
1952
|
+
}
|
|
1953
|
+
},
|
|
1954
|
+
sdk_version_required: ">=0.16.0",
|
|
1955
|
+
max_bundle_size_kb: 500
|
|
1956
|
+
};
|
|
1957
|
+
}
|
|
1958
|
+
function AppRoot(props) {
|
|
1959
|
+
const {
|
|
1960
|
+
config: rawConfig,
|
|
1961
|
+
children,
|
|
1962
|
+
testRouter,
|
|
1963
|
+
testInitialEntries,
|
|
1964
|
+
Login,
|
|
1965
|
+
Signup,
|
|
1966
|
+
Forgot,
|
|
1967
|
+
Reset,
|
|
1968
|
+
EmailVerify,
|
|
1969
|
+
Paywall,
|
|
1970
|
+
Onboarding,
|
|
1971
|
+
PreAuthFlow
|
|
1972
|
+
} = props;
|
|
1973
|
+
if (!Login || !Signup || !Forgot || !Reset) {
|
|
1974
|
+
throw new Error(
|
|
1975
|
+
"[hook-template] <AppRoot>: Login, Signup, Forgot, Reset slot props are required."
|
|
1976
|
+
);
|
|
1977
|
+
}
|
|
1978
|
+
const config = parseAppConfig(rawConfig);
|
|
1979
|
+
if (config.paywall.mode !== "free" && !Paywall) {
|
|
1980
|
+
throw new Error(
|
|
1981
|
+
"[hook-template] <AppRoot>: Paywall slot prop is required when config.paywall.mode != 'free'."
|
|
1982
|
+
);
|
|
1983
|
+
}
|
|
1984
|
+
if (config.authFlow.requiresEmailVerify && !EmailVerify) {
|
|
1985
|
+
throw new Error(
|
|
1986
|
+
"[hook-template] <AppRoot>: EmailVerify slot prop is required when config.authFlow.requiresEmailVerify === true."
|
|
1987
|
+
);
|
|
1988
|
+
}
|
|
1989
|
+
if (config.onboarding?.trigger === "pre_signup_custom" && !PreAuthFlow) {
|
|
1990
|
+
throw new Error(
|
|
1991
|
+
"[hook-template] <AppRoot>: PreAuthFlow slot prop is required when config.onboarding.trigger === 'pre_signup_custom'."
|
|
1992
|
+
);
|
|
1993
|
+
}
|
|
1994
|
+
const legacyShim = (0, import_react11.useMemo)(() => buildLegacyConfigShim(config), [config]);
|
|
1995
|
+
const Router = testRouter === "memory" ? import_react_router_dom2.MemoryRouter : import_react_router_dom2.BrowserRouter;
|
|
1996
|
+
const basename = `/app/${config.slug}`;
|
|
1997
|
+
const routerProps = testRouter === "memory" ? { basename, initialEntries: testInitialEntries } : { basename };
|
|
1998
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(ErrorBoundary, { children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(AppConfigProvider, { config, children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(TemplateConfigProvider, { config: legacyShim, children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(ThemeProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(PersistenceRegistry, { config: config.persistedKeys, children: /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(Router, { ...routerProps, children: [
|
|
1999
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(DeepLinkHandler, { deepLinks: config.deepLinks }),
|
|
2000
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(InstallGate, { children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
2001
|
+
AuthGated,
|
|
2002
|
+
{
|
|
2003
|
+
config,
|
|
2004
|
+
Login,
|
|
2005
|
+
Signup,
|
|
2006
|
+
Forgot,
|
|
2007
|
+
Reset,
|
|
2008
|
+
EmailVerify,
|
|
2009
|
+
Paywall,
|
|
2010
|
+
Onboarding,
|
|
2011
|
+
PreAuthFlow,
|
|
2012
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(SubscriptionGate, { Paywall: Paywall ?? FallbackPaywall, children: [
|
|
2013
|
+
children,
|
|
2014
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(PushPrompt, {})
|
|
2015
|
+
] })
|
|
2016
|
+
}
|
|
2017
|
+
) })
|
|
2018
|
+
] }) }) }) }) }) });
|
|
2019
|
+
}
|
|
2020
|
+
function AuthGated({
|
|
2928
2021
|
children,
|
|
2929
|
-
|
|
2930
|
-
|
|
2931
|
-
|
|
2932
|
-
|
|
2933
|
-
|
|
2022
|
+
config,
|
|
2023
|
+
Login,
|
|
2024
|
+
Signup,
|
|
2025
|
+
Forgot,
|
|
2026
|
+
Reset,
|
|
2027
|
+
EmailVerify,
|
|
2028
|
+
PreAuthFlow
|
|
2934
2029
|
}) {
|
|
2935
|
-
|
|
2936
|
-
|
|
2937
|
-
|
|
2938
|
-
|
|
2030
|
+
const { authStatus } = (0, import_sdk4.useHook)();
|
|
2031
|
+
if (authStatus === "loading") return null;
|
|
2032
|
+
if (authStatus !== "authenticated") {
|
|
2033
|
+
if (config.onboarding?.trigger === "pre_signup_custom" && PreAuthFlow) {
|
|
2034
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_react_router_dom2.Routes, { children: [
|
|
2035
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_router_dom2.Route, { path: "/signin", element: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Login, {}) }),
|
|
2036
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_router_dom2.Route, { path: "/signup", element: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Signup, {}) }),
|
|
2037
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_router_dom2.Route, { path: "/forgot", element: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Forgot, {}) }),
|
|
2038
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_router_dom2.Route, { path: "/reset", element: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Reset, {}) }),
|
|
2039
|
+
EmailVerify ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_router_dom2.Route, { path: "/verify", element: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(EmailVerify, {}) }) : null,
|
|
2040
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_router_dom2.Route, { path: "/*", element: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(PreAuthFlow, {}) })
|
|
2041
|
+
] });
|
|
2042
|
+
}
|
|
2043
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_react_router_dom2.Routes, { children: [
|
|
2044
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_router_dom2.Route, { path: "/", element: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Login, {}) }),
|
|
2045
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_router_dom2.Route, { path: "/signup", element: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Signup, {}) }),
|
|
2046
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_router_dom2.Route, { path: "/forgot", element: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Forgot, {}) }),
|
|
2047
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_router_dom2.Route, { path: "/reset", element: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Reset, {}) }),
|
|
2048
|
+
EmailVerify ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_router_dom2.Route, { path: "/verify", element: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(EmailVerify, {}) }) : null,
|
|
2049
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_router_dom2.Route, { path: "*", element: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_router_dom2.Navigate, { to: "/", replace: true }) })
|
|
2050
|
+
] });
|
|
2051
|
+
}
|
|
2052
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_jsx_runtime18.Fragment, { children });
|
|
2053
|
+
}
|
|
2054
|
+
function FallbackPaywall() {
|
|
2055
|
+
return null;
|
|
2056
|
+
}
|
|
2057
|
+
|
|
2058
|
+
// src/hooks/usePush.ts
|
|
2059
|
+
var import_react12 = require("react");
|
|
2060
|
+
var import_sdk5 = require("@hook-sdk/sdk");
|
|
2061
|
+
function detectIosNeedsInstall() {
|
|
2062
|
+
if (typeof navigator === "undefined" || typeof window === "undefined") return false;
|
|
2063
|
+
const ua = navigator.userAgent || "";
|
|
2064
|
+
const isIos = /iPhone|iPad|iPod/.test(ua);
|
|
2065
|
+
if (!isIos) return false;
|
|
2066
|
+
const mm = window.matchMedia?.("(display-mode: standalone)");
|
|
2067
|
+
const standalone = mm?.matches === true;
|
|
2068
|
+
const legacyStandalone = typeof navigator.standalone === "boolean" ? navigator.standalone : false;
|
|
2069
|
+
return !(standalone || legacyStandalone);
|
|
2070
|
+
}
|
|
2071
|
+
function deriveState(push) {
|
|
2072
|
+
if (!push.isAvailable()) {
|
|
2073
|
+
if (detectIosNeedsInstall()) return { kind: "ios_needs_install" };
|
|
2074
|
+
return { kind: "unsupported" };
|
|
2075
|
+
}
|
|
2076
|
+
const status = push.status();
|
|
2077
|
+
if (status === "granted") return { kind: "subscribed" };
|
|
2078
|
+
if (status === "denied") return { kind: "denied" };
|
|
2079
|
+
if (status === "unsupported") {
|
|
2080
|
+
if (detectIosNeedsInstall()) return { kind: "ios_needs_install" };
|
|
2081
|
+
return { kind: "unsupported" };
|
|
2082
|
+
}
|
|
2083
|
+
return { kind: "prompt" };
|
|
2084
|
+
}
|
|
2085
|
+
function usePush() {
|
|
2086
|
+
const { push } = (0, import_sdk5.useHook)();
|
|
2087
|
+
const [state, setState] = (0, import_react12.useState)(() => deriveState(push));
|
|
2088
|
+
(0, import_react12.useEffect)(() => {
|
|
2089
|
+
setState(deriveState(push));
|
|
2090
|
+
}, [push]);
|
|
2091
|
+
const subscribe = (0, import_react12.useCallback)(async () => {
|
|
2092
|
+
try {
|
|
2093
|
+
await push.subscribe();
|
|
2094
|
+
setState({ kind: "subscribed" });
|
|
2095
|
+
} catch (e) {
|
|
2096
|
+
const code = e?.code ?? "push.unknown";
|
|
2097
|
+
const message = e?.message ?? "Push subscription failed";
|
|
2098
|
+
if (code === "push.permission_denied") setState({ kind: "denied" });
|
|
2099
|
+
else setState({ kind: "error", code, message });
|
|
2100
|
+
throw e;
|
|
2101
|
+
}
|
|
2102
|
+
}, [push]);
|
|
2103
|
+
const unsubscribe = (0, import_react12.useCallback)(async () => {
|
|
2104
|
+
try {
|
|
2105
|
+
await push.unsubscribe();
|
|
2106
|
+
setState({ kind: "prompt" });
|
|
2107
|
+
} catch (e) {
|
|
2108
|
+
setState({ kind: "error", code: e?.code ?? "push.unknown", message: e?.message ?? "failed" });
|
|
2109
|
+
throw e;
|
|
2110
|
+
}
|
|
2111
|
+
}, [push]);
|
|
2112
|
+
return { state, subscribe, unsubscribe };
|
|
2113
|
+
}
|
|
2114
|
+
|
|
2115
|
+
// src/components/PushPrompt.tsx
|
|
2116
|
+
var import_jsx_runtime19 = require("react/jsx-runtime");
|
|
2117
|
+
function PushPrompt2({ texts, onSubscribed, onDeclined, onInstallRequested, className }) {
|
|
2118
|
+
const { state, subscribe } = usePush();
|
|
2119
|
+
if (state.kind === "subscribed") return null;
|
|
2120
|
+
if (state.kind === "ios_needs_install") {
|
|
2121
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className, role: "region", "aria-label": texts.iosInstallTitle, children: [
|
|
2122
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("h3", { children: texts.iosInstallTitle }),
|
|
2123
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { children: texts.iosInstallBody }),
|
|
2124
|
+
onInstallRequested && texts.iosInstallCta && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("button", { onClick: onInstallRequested, children: texts.iosInstallCta })
|
|
2125
|
+
] });
|
|
2126
|
+
}
|
|
2127
|
+
if (state.kind === "denied") {
|
|
2128
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className, role: "region", "aria-label": texts.deniedTitle, children: [
|
|
2129
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("h3", { children: texts.deniedTitle }),
|
|
2130
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { children: texts.deniedBody })
|
|
2131
|
+
] });
|
|
2132
|
+
}
|
|
2133
|
+
if (state.kind === "unsupported") {
|
|
2134
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className, role: "region", children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { children: texts.unsupportedBody }) });
|
|
2135
|
+
}
|
|
2136
|
+
if (state.kind === "error") {
|
|
2137
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className, role: "region", "aria-label": "error", children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { children: state.message }) });
|
|
2138
|
+
}
|
|
2139
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className, role: "region", children: [
|
|
2140
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
2141
|
+
"button",
|
|
2142
|
+
{
|
|
2143
|
+
type: "button",
|
|
2144
|
+
onClick: async () => {
|
|
2145
|
+
try {
|
|
2146
|
+
await subscribe();
|
|
2147
|
+
onSubscribed?.();
|
|
2148
|
+
} catch {
|
|
2149
|
+
}
|
|
2150
|
+
},
|
|
2151
|
+
children: texts.cta
|
|
2152
|
+
}
|
|
2153
|
+
),
|
|
2154
|
+
onDeclined && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("button", { type: "button", onClick: onDeclined, children: texts.declineCta })
|
|
2155
|
+
] });
|
|
2156
|
+
}
|
|
2157
|
+
|
|
2158
|
+
// src/defaults/LoadingState.tsx
|
|
2159
|
+
var import_jsx_runtime20 = require("react/jsx-runtime");
|
|
2160
|
+
function LoadingState({ message }) {
|
|
2161
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { role: "status", "aria-live": "polite", style: { padding: 24, textAlign: "center" }, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { children: message ?? "Carregando..." }) });
|
|
2162
|
+
}
|
|
2163
|
+
|
|
2164
|
+
// src/defaults/EmptyState.tsx
|
|
2165
|
+
var import_jsx_runtime21 = require("react/jsx-runtime");
|
|
2166
|
+
function EmptyState({ title, description, action }) {
|
|
2167
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { role: "status", style: { padding: 32, textAlign: "center" }, children: [
|
|
2168
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("h2", { style: { marginBottom: 8 }, children: title }),
|
|
2169
|
+
description && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { style: { opacity: 0.7 }, children: description }),
|
|
2170
|
+
action && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { style: { marginTop: 16 }, children: action })
|
|
2171
|
+
] });
|
|
2172
|
+
}
|
|
2173
|
+
|
|
2174
|
+
// src/hooks/useLoginForm.ts
|
|
2175
|
+
var import_react13 = require("react");
|
|
2176
|
+
var import_sdk7 = require("@hook-sdk/sdk");
|
|
2177
|
+
|
|
2178
|
+
// src/errors.ts
|
|
2179
|
+
var import_sdk6 = require("@hook-sdk/sdk");
|
|
2180
|
+
function mapSdkError(err) {
|
|
2181
|
+
if (err instanceof import_sdk6.SdkRateLimitError) {
|
|
2182
|
+
return {
|
|
2183
|
+
code: "rate_limited",
|
|
2184
|
+
message: `Aguarde ${err.retryAfter}s e tente novamente.`,
|
|
2185
|
+
retryAfter: err.retryAfter
|
|
2186
|
+
};
|
|
2187
|
+
}
|
|
2188
|
+
if (err instanceof import_sdk6.SdkAuthError) {
|
|
2189
|
+
const detail = err.detail;
|
|
2190
|
+
if (detail === "email_unverified") {
|
|
2191
|
+
return { code: "email_unverified", message: "Confirme seu e-mail antes de entrar." };
|
|
2192
|
+
}
|
|
2193
|
+
if (detail === "account_locked") {
|
|
2194
|
+
return { code: "account_locked", message: "Conta bloqueada. Contate o suporte." };
|
|
2195
|
+
}
|
|
2196
|
+
return { code: "invalid_credentials", message: "E-mail ou senha inv\xE1lidos." };
|
|
2197
|
+
}
|
|
2198
|
+
if (err instanceof import_sdk6.SdkError && err.httpStatus === 0) {
|
|
2199
|
+
return { code: "network", message: "Sem conex\xE3o com o servidor. Verifique sua internet." };
|
|
2200
|
+
}
|
|
2201
|
+
if (err instanceof TypeError) {
|
|
2202
|
+
return { code: "network", message: "Sem conex\xE3o com o servidor. Verifique sua internet." };
|
|
2203
|
+
}
|
|
2204
|
+
return { code: "server", message: "Algo deu errado. Tente novamente em instantes." };
|
|
2205
|
+
}
|
|
2206
|
+
|
|
2207
|
+
// src/hooks/useLoginForm.ts
|
|
2208
|
+
var EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
2209
|
+
var MIN_PASSWORD = 8;
|
|
2210
|
+
function useLoginForm() {
|
|
2211
|
+
const { auth } = (0, import_sdk7.useHook)();
|
|
2212
|
+
const [email, setEmail] = (0, import_react13.useState)("");
|
|
2213
|
+
const [password, setPassword] = (0, import_react13.useState)("");
|
|
2214
|
+
const [submitting, setSubmitting] = (0, import_react13.useState)(false);
|
|
2215
|
+
const [error, setError] = (0, import_react13.useState)(null);
|
|
2216
|
+
const emailError = (0, import_react13.useMemo)(() => {
|
|
2217
|
+
if (email.length === 0) return null;
|
|
2218
|
+
if (!EMAIL_RE.test(email)) return "Formato de e-mail inv\xE1lido.";
|
|
2219
|
+
return null;
|
|
2220
|
+
}, [email]);
|
|
2221
|
+
const passwordError = (0, import_react13.useMemo)(() => {
|
|
2222
|
+
if (password.length === 0) return null;
|
|
2223
|
+
if (password.length < MIN_PASSWORD) return `M\xEDnimo de ${MIN_PASSWORD} caracteres.`;
|
|
2224
|
+
return null;
|
|
2225
|
+
}, [password]);
|
|
2226
|
+
const canSubmit = email.length > 0 && password.length >= MIN_PASSWORD && emailError === null && passwordError === null && !submitting;
|
|
2227
|
+
const submit = (0, import_react13.useCallback)(async () => {
|
|
2228
|
+
if (!canSubmit) return false;
|
|
2229
|
+
setSubmitting(true);
|
|
2230
|
+
setError(null);
|
|
2231
|
+
try {
|
|
2232
|
+
await auth.login({ email, password });
|
|
2233
|
+
return true;
|
|
2234
|
+
} catch (err) {
|
|
2235
|
+
setError(mapSdkError(err));
|
|
2236
|
+
return false;
|
|
2237
|
+
} finally {
|
|
2238
|
+
setSubmitting(false);
|
|
2239
|
+
}
|
|
2240
|
+
}, [auth, email, password, canSubmit]);
|
|
2241
|
+
return {
|
|
2242
|
+
email,
|
|
2243
|
+
setEmail,
|
|
2244
|
+
emailError,
|
|
2245
|
+
password,
|
|
2246
|
+
setPassword,
|
|
2247
|
+
passwordError,
|
|
2248
|
+
submit,
|
|
2249
|
+
submitting,
|
|
2250
|
+
canSubmit,
|
|
2251
|
+
error,
|
|
2252
|
+
loginWithGoogle: () => auth.loginWithGoogle()
|
|
2253
|
+
};
|
|
2254
|
+
}
|
|
2255
|
+
|
|
2256
|
+
// src/hooks/useSignupForm.ts
|
|
2257
|
+
var import_react14 = require("react");
|
|
2258
|
+
var import_sdk8 = require("@hook-sdk/sdk");
|
|
2259
|
+
var EMAIL_RE2 = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
2260
|
+
var MIN_PASSWORD2 = 8;
|
|
2261
|
+
function useSignupForm() {
|
|
2262
|
+
const { auth } = (0, import_sdk8.useHook)();
|
|
2263
|
+
const [name, setName] = (0, import_react14.useState)("");
|
|
2264
|
+
const [email, setEmail] = (0, import_react14.useState)("");
|
|
2265
|
+
const [password, setPassword] = (0, import_react14.useState)("");
|
|
2266
|
+
const [submitting, setSubmitting] = (0, import_react14.useState)(false);
|
|
2267
|
+
const [error, setError] = (0, import_react14.useState)(null);
|
|
2268
|
+
const nameError = (0, import_react14.useMemo)(() => {
|
|
2269
|
+
if (name.length === 0) return null;
|
|
2270
|
+
if (name.trim().length < 2) return "Nome muito curto.";
|
|
2271
|
+
return null;
|
|
2272
|
+
}, [name]);
|
|
2273
|
+
const emailError = (0, import_react14.useMemo)(() => {
|
|
2274
|
+
if (email.length === 0) return null;
|
|
2275
|
+
if (!EMAIL_RE2.test(email)) return "Formato de e-mail inv\xE1lido.";
|
|
2276
|
+
return null;
|
|
2277
|
+
}, [email]);
|
|
2278
|
+
const passwordError = (0, import_react14.useMemo)(() => {
|
|
2279
|
+
if (password.length === 0) return null;
|
|
2280
|
+
if (password.length < MIN_PASSWORD2) return `M\xEDnimo de ${MIN_PASSWORD2} caracteres.`;
|
|
2281
|
+
return null;
|
|
2282
|
+
}, [password]);
|
|
2283
|
+
const canSubmit = name.trim().length >= 2 && email.length > 0 && password.length >= MIN_PASSWORD2 && nameError === null && emailError === null && passwordError === null && !submitting;
|
|
2284
|
+
const submit = (0, import_react14.useCallback)(async () => {
|
|
2285
|
+
if (!canSubmit) return false;
|
|
2286
|
+
setSubmitting(true);
|
|
2287
|
+
setError(null);
|
|
2288
|
+
try {
|
|
2289
|
+
await auth.signup({ name, email, password });
|
|
2290
|
+
return true;
|
|
2291
|
+
} catch (err) {
|
|
2292
|
+
setError(mapSdkError(err));
|
|
2293
|
+
return false;
|
|
2294
|
+
} finally {
|
|
2295
|
+
setSubmitting(false);
|
|
2296
|
+
}
|
|
2297
|
+
}, [auth, name, email, password, canSubmit]);
|
|
2298
|
+
return {
|
|
2299
|
+
name,
|
|
2300
|
+
setName,
|
|
2301
|
+
nameError,
|
|
2302
|
+
email,
|
|
2303
|
+
setEmail,
|
|
2304
|
+
emailError,
|
|
2305
|
+
password,
|
|
2306
|
+
setPassword,
|
|
2307
|
+
passwordError,
|
|
2308
|
+
submit,
|
|
2309
|
+
submitting,
|
|
2310
|
+
canSubmit,
|
|
2311
|
+
error,
|
|
2312
|
+
loginWithGoogle: () => auth.loginWithGoogle()
|
|
2313
|
+
};
|
|
2939
2314
|
}
|
|
2940
2315
|
|
|
2941
|
-
// src/hooks/
|
|
2942
|
-
var
|
|
2943
|
-
var
|
|
2944
|
-
|
|
2945
|
-
|
|
2946
|
-
const
|
|
2947
|
-
const
|
|
2948
|
-
|
|
2949
|
-
const
|
|
2950
|
-
const
|
|
2951
|
-
const
|
|
2952
|
-
|
|
2953
|
-
|
|
2954
|
-
|
|
2955
|
-
|
|
2956
|
-
|
|
2957
|
-
|
|
2958
|
-
|
|
2959
|
-
|
|
2960
|
-
|
|
2961
|
-
if (status === "denied") return { kind: "denied" };
|
|
2962
|
-
if (status === "unsupported") {
|
|
2963
|
-
if (detectIosNeedsInstall()) return { kind: "ios_needs_install" };
|
|
2964
|
-
return { kind: "unsupported" };
|
|
2965
|
-
}
|
|
2966
|
-
return { kind: "prompt" };
|
|
2967
|
-
}
|
|
2968
|
-
function usePush() {
|
|
2969
|
-
const { push } = (0, import_sdk11.useHook)();
|
|
2970
|
-
const [state, setState] = (0, import_react16.useState)(() => deriveState(push));
|
|
2971
|
-
(0, import_react16.useEffect)(() => {
|
|
2972
|
-
setState(deriveState(push));
|
|
2973
|
-
}, [push]);
|
|
2974
|
-
const subscribe = (0, import_react16.useCallback)(async () => {
|
|
2316
|
+
// src/hooks/useForgotForm.ts
|
|
2317
|
+
var import_react15 = require("react");
|
|
2318
|
+
var import_sdk9 = require("@hook-sdk/sdk");
|
|
2319
|
+
var EMAIL_RE3 = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
2320
|
+
function useForgotForm() {
|
|
2321
|
+
const { auth } = (0, import_sdk9.useHook)();
|
|
2322
|
+
const [email, setEmail] = (0, import_react15.useState)("");
|
|
2323
|
+
const [submitting, setSubmitting] = (0, import_react15.useState)(false);
|
|
2324
|
+
const [sent, setSent] = (0, import_react15.useState)(false);
|
|
2325
|
+
const [error, setError] = (0, import_react15.useState)(null);
|
|
2326
|
+
const emailError = (0, import_react15.useMemo)(() => {
|
|
2327
|
+
if (email.length === 0) return null;
|
|
2328
|
+
if (!EMAIL_RE3.test(email)) return "Formato de e-mail inv\xE1lido.";
|
|
2329
|
+
return null;
|
|
2330
|
+
}, [email]);
|
|
2331
|
+
const canSubmit = email.length > 0 && emailError === null && !submitting;
|
|
2332
|
+
const submit = (0, import_react15.useCallback)(async () => {
|
|
2333
|
+
if (!canSubmit) return false;
|
|
2334
|
+
setSubmitting(true);
|
|
2335
|
+
setError(null);
|
|
2975
2336
|
try {
|
|
2976
|
-
await
|
|
2977
|
-
|
|
2978
|
-
|
|
2979
|
-
|
|
2980
|
-
|
|
2981
|
-
|
|
2982
|
-
|
|
2983
|
-
|
|
2337
|
+
await auth.forgot({ email });
|
|
2338
|
+
setSent(true);
|
|
2339
|
+
return true;
|
|
2340
|
+
} catch (err) {
|
|
2341
|
+
setError(mapSdkError(err));
|
|
2342
|
+
return false;
|
|
2343
|
+
} finally {
|
|
2344
|
+
setSubmitting(false);
|
|
2984
2345
|
}
|
|
2985
|
-
}, [
|
|
2986
|
-
|
|
2346
|
+
}, [auth, email, canSubmit]);
|
|
2347
|
+
return {
|
|
2348
|
+
email,
|
|
2349
|
+
setEmail,
|
|
2350
|
+
emailError,
|
|
2351
|
+
submit,
|
|
2352
|
+
submitting,
|
|
2353
|
+
canSubmit,
|
|
2354
|
+
sent,
|
|
2355
|
+
error
|
|
2356
|
+
};
|
|
2357
|
+
}
|
|
2358
|
+
|
|
2359
|
+
// src/hooks/useResetForm.ts
|
|
2360
|
+
var import_react16 = require("react");
|
|
2361
|
+
var import_sdk10 = require("@hook-sdk/sdk");
|
|
2362
|
+
var MIN_PASSWORD3 = 12;
|
|
2363
|
+
function useResetForm() {
|
|
2364
|
+
const { auth } = (0, import_sdk10.useHook)();
|
|
2365
|
+
const [token, setToken] = (0, import_react16.useState)(null);
|
|
2366
|
+
const [password, setPassword] = (0, import_react16.useState)("");
|
|
2367
|
+
const [confirm, setConfirm] = (0, import_react16.useState)("");
|
|
2368
|
+
const [submitting, setSubmitting] = (0, import_react16.useState)(false);
|
|
2369
|
+
const [done, setDone] = (0, import_react16.useState)(false);
|
|
2370
|
+
const [error, setError] = (0, import_react16.useState)(null);
|
|
2371
|
+
(0, import_react16.useEffect)(() => {
|
|
2372
|
+
if (typeof window === "undefined") return;
|
|
2373
|
+
const params = new URLSearchParams(window.location.search);
|
|
2374
|
+
const t = params.get("token");
|
|
2375
|
+
setToken(t && t.length > 0 ? t : null);
|
|
2376
|
+
}, []);
|
|
2377
|
+
const passwordError = (0, import_react16.useMemo)(() => {
|
|
2378
|
+
if (password.length === 0) return null;
|
|
2379
|
+
if (password.length < MIN_PASSWORD3) return `M\xEDnimo de ${MIN_PASSWORD3} caracteres.`;
|
|
2380
|
+
return null;
|
|
2381
|
+
}, [password]);
|
|
2382
|
+
const confirmError = (0, import_react16.useMemo)(() => {
|
|
2383
|
+
if (confirm.length === 0) return null;
|
|
2384
|
+
if (confirm !== password) return "Senhas n\xE3o coincidem.";
|
|
2385
|
+
return null;
|
|
2386
|
+
}, [confirm, password]);
|
|
2387
|
+
const canSubmit = token !== null && password.length >= MIN_PASSWORD3 && confirm === password && passwordError === null && confirmError === null && !submitting && !done;
|
|
2388
|
+
const submit = (0, import_react16.useCallback)(async () => {
|
|
2389
|
+
if (!canSubmit || token === null) return;
|
|
2390
|
+
setSubmitting(true);
|
|
2391
|
+
setError(null);
|
|
2987
2392
|
try {
|
|
2988
|
-
await
|
|
2989
|
-
|
|
2990
|
-
|
|
2991
|
-
|
|
2992
|
-
|
|
2393
|
+
await auth.reset({ token, newPassword: password });
|
|
2394
|
+
setDone(true);
|
|
2395
|
+
if (typeof window !== "undefined") {
|
|
2396
|
+
const url = new URL(window.location.href);
|
|
2397
|
+
url.searchParams.delete("token");
|
|
2398
|
+
url.searchParams.delete("screen");
|
|
2399
|
+
window.history.replaceState({}, "", url.toString());
|
|
2400
|
+
}
|
|
2401
|
+
} catch (err) {
|
|
2402
|
+
setError(mapSdkError(err));
|
|
2403
|
+
} finally {
|
|
2404
|
+
setSubmitting(false);
|
|
2993
2405
|
}
|
|
2994
|
-
}, [
|
|
2995
|
-
return {
|
|
2406
|
+
}, [auth, token, password, canSubmit]);
|
|
2407
|
+
return {
|
|
2408
|
+
token,
|
|
2409
|
+
password,
|
|
2410
|
+
setPassword,
|
|
2411
|
+
passwordError,
|
|
2412
|
+
confirm,
|
|
2413
|
+
setConfirm,
|
|
2414
|
+
confirmError,
|
|
2415
|
+
submit,
|
|
2416
|
+
submitting,
|
|
2417
|
+
canSubmit,
|
|
2418
|
+
done,
|
|
2419
|
+
error
|
|
2420
|
+
};
|
|
2996
2421
|
}
|
|
2997
2422
|
|
|
2998
|
-
// src/
|
|
2999
|
-
var
|
|
3000
|
-
function
|
|
3001
|
-
const {
|
|
3002
|
-
|
|
3003
|
-
if (state.kind === "ios_needs_install") {
|
|
3004
|
-
return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className, role: "region", "aria-label": texts.iosInstallTitle, children: [
|
|
3005
|
-
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)("h3", { children: texts.iosInstallTitle }),
|
|
3006
|
-
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)("p", { children: texts.iosInstallBody }),
|
|
3007
|
-
onInstallRequested && texts.iosInstallCta && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("button", { onClick: onInstallRequested, children: texts.iosInstallCta })
|
|
3008
|
-
] });
|
|
3009
|
-
}
|
|
3010
|
-
if (state.kind === "denied") {
|
|
3011
|
-
return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className, role: "region", "aria-label": texts.deniedTitle, children: [
|
|
3012
|
-
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)("h3", { children: texts.deniedTitle }),
|
|
3013
|
-
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)("p", { children: texts.deniedBody })
|
|
3014
|
-
] });
|
|
3015
|
-
}
|
|
3016
|
-
if (state.kind === "unsupported") {
|
|
3017
|
-
return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { className, role: "region", children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("p", { children: texts.unsupportedBody }) });
|
|
3018
|
-
}
|
|
3019
|
-
if (state.kind === "error") {
|
|
3020
|
-
return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { className, role: "region", "aria-label": "error", children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("p", { children: state.message }) });
|
|
3021
|
-
}
|
|
3022
|
-
return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className, role: "region", children: [
|
|
3023
|
-
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
|
|
3024
|
-
"button",
|
|
3025
|
-
{
|
|
3026
|
-
type: "button",
|
|
3027
|
-
onClick: async () => {
|
|
3028
|
-
try {
|
|
3029
|
-
await subscribe();
|
|
3030
|
-
onSubscribed?.();
|
|
3031
|
-
} catch {
|
|
3032
|
-
}
|
|
3033
|
-
},
|
|
3034
|
-
children: texts.cta
|
|
3035
|
-
}
|
|
3036
|
-
),
|
|
3037
|
-
onDeclined && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("button", { type: "button", onClick: onDeclined, children: texts.declineCta })
|
|
3038
|
-
] });
|
|
2423
|
+
// src/hooks/usePlan.ts
|
|
2424
|
+
var import_sdk11 = require("@hook-sdk/sdk");
|
|
2425
|
+
function usePlan() {
|
|
2426
|
+
const { plan } = (0, import_sdk11.useHook)();
|
|
2427
|
+
return plan;
|
|
3039
2428
|
}
|
|
3040
2429
|
|
|
3041
|
-
// src/
|
|
3042
|
-
|
|
3043
|
-
|
|
3044
|
-
|
|
3045
|
-
|
|
3046
|
-
|
|
3047
|
-
|
|
3048
|
-
|
|
2430
|
+
// src/utils/price.ts
|
|
2431
|
+
function formatBRL(cents) {
|
|
2432
|
+
if (cents === null || cents === void 0) return "";
|
|
2433
|
+
const reais = cents / 100;
|
|
2434
|
+
return new Intl.NumberFormat("pt-BR", {
|
|
2435
|
+
style: "currency",
|
|
2436
|
+
currency: "BRL"
|
|
2437
|
+
}).format(reais);
|
|
2438
|
+
}
|
|
2439
|
+
function monthlyFromYearly(yearlyCents) {
|
|
2440
|
+
if (yearlyCents === null || yearlyCents === void 0) return 0;
|
|
2441
|
+
return Math.round(yearlyCents / 12);
|
|
2442
|
+
}
|
|
2443
|
+
function dailyFromYearly(yearlyCents) {
|
|
2444
|
+
if (yearlyCents === null || yearlyCents === void 0) return 0;
|
|
2445
|
+
return Math.round(yearlyCents / 365);
|
|
2446
|
+
}
|
|
2447
|
+
function computeAnchorCents(baseCents, multiplier) {
|
|
2448
|
+
if (multiplier === null || multiplier === void 0) return null;
|
|
2449
|
+
if (!Number.isFinite(multiplier)) return null;
|
|
2450
|
+
if (multiplier <= 1) return null;
|
|
2451
|
+
return Math.round(baseCents * multiplier);
|
|
2452
|
+
}
|
|
2453
|
+
function discountPercent(anchorCents, realCents) {
|
|
2454
|
+
if (anchorCents <= realCents) return 0;
|
|
2455
|
+
return Math.floor((anchorCents - realCents) / anchorCents * 100);
|
|
3049
2456
|
}
|
|
3050
2457
|
|
|
3051
2458
|
// src/hooks/useAuthPrimitives.ts
|
|
@@ -3075,10 +2482,21 @@ function useAuthPrimitives() {
|
|
|
3075
2482
|
};
|
|
3076
2483
|
}
|
|
3077
2484
|
|
|
3078
|
-
// src/hooks/
|
|
2485
|
+
// src/hooks/useAuth.ts
|
|
3079
2486
|
var import_sdk13 = require("@hook-sdk/sdk");
|
|
2487
|
+
function useAuth() {
|
|
2488
|
+
const { user, authStatus, auth } = (0, import_sdk13.useHook)();
|
|
2489
|
+
return {
|
|
2490
|
+
user,
|
|
2491
|
+
authStatus,
|
|
2492
|
+
refresh: auth.refresh
|
|
2493
|
+
};
|
|
2494
|
+
}
|
|
2495
|
+
|
|
2496
|
+
// src/hooks/useSubscription.ts
|
|
2497
|
+
var import_sdk14 = require("@hook-sdk/sdk");
|
|
3080
2498
|
function useSubscription() {
|
|
3081
|
-
const { subscription } = (0,
|
|
2499
|
+
const { subscription } = (0, import_sdk14.useHook)();
|
|
3082
2500
|
return {
|
|
3083
2501
|
status: subscription.status()
|
|
3084
2502
|
};
|
|
@@ -3086,9 +2504,9 @@ function useSubscription() {
|
|
|
3086
2504
|
|
|
3087
2505
|
// src/hooks/useReminders.ts
|
|
3088
2506
|
var import_react18 = require("react");
|
|
3089
|
-
var
|
|
2507
|
+
var import_sdk15 = require("@hook-sdk/sdk");
|
|
3090
2508
|
function useReminders() {
|
|
3091
|
-
const { push } = (0,
|
|
2509
|
+
const { push } = (0, import_sdk15.useHook)();
|
|
3092
2510
|
const r = push.reminders;
|
|
3093
2511
|
const [reminders, setReminders] = (0, import_react18.useState)([]);
|
|
3094
2512
|
const [loading, setLoading] = (0, import_react18.useState)(true);
|
|
@@ -3137,20 +2555,137 @@ function useToast() {
|
|
|
3137
2555
|
}, []);
|
|
3138
2556
|
return { items, show, dismiss };
|
|
3139
2557
|
}
|
|
2558
|
+
|
|
2559
|
+
// src/RouteBoundary.tsx
|
|
2560
|
+
var import_react_router_dom3 = require("react-router-dom");
|
|
2561
|
+
var import_jsx_runtime22 = require("react/jsx-runtime");
|
|
2562
|
+
function RouteBoundary({ children }) {
|
|
2563
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_react_router_dom3.Routes, { children: [
|
|
2564
|
+
children,
|
|
2565
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_react_router_dom3.Route, { path: "*", element: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(DefaultNotFound, {}) })
|
|
2566
|
+
] });
|
|
2567
|
+
}
|
|
2568
|
+
function DefaultNotFound() {
|
|
2569
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { role: "alert", children: "P\xE1gina n\xE3o encontrada" });
|
|
2570
|
+
}
|
|
2571
|
+
|
|
2572
|
+
// src/PreAuthShell.tsx
|
|
2573
|
+
var import_react_router_dom4 = require("react-router-dom");
|
|
2574
|
+
var import_jsx_runtime23 = require("react/jsx-runtime");
|
|
2575
|
+
function PreAuthShell({
|
|
2576
|
+
basename,
|
|
2577
|
+
testRouter,
|
|
2578
|
+
testInitialEntries,
|
|
2579
|
+
children
|
|
2580
|
+
}) {
|
|
2581
|
+
if (testRouter === "memory") {
|
|
2582
|
+
return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_react_router_dom4.MemoryRouter, { basename, initialEntries: testInitialEntries, children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_react_router_dom4.Routes, { children }) });
|
|
2583
|
+
}
|
|
2584
|
+
return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_react_router_dom4.BrowserRouter, { basename, children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_react_router_dom4.Routes, { children }) });
|
|
2585
|
+
}
|
|
2586
|
+
|
|
2587
|
+
// src/OnboardingFlow.tsx
|
|
2588
|
+
var import_react21 = require("react");
|
|
2589
|
+
var import_sdk16 = require("@hook-sdk/sdk");
|
|
2590
|
+
|
|
2591
|
+
// src/hooks/useOnboardingStep.ts
|
|
2592
|
+
var import_react20 = require("react");
|
|
2593
|
+
var OnboardingStepContext = (0, import_react20.createContext)(null);
|
|
2594
|
+
function useOnboardingStep() {
|
|
2595
|
+
const ctx = (0, import_react20.useContext)(OnboardingStepContext);
|
|
2596
|
+
if (!ctx) {
|
|
2597
|
+
throw new Error(
|
|
2598
|
+
"[hook-template] useOnboardingStep must be used inside <OnboardingFlow>. (G75)"
|
|
2599
|
+
);
|
|
2600
|
+
}
|
|
2601
|
+
return ctx;
|
|
2602
|
+
}
|
|
2603
|
+
|
|
2604
|
+
// src/OnboardingFlow.tsx
|
|
2605
|
+
var import_jsx_runtime24 = require("react/jsx-runtime");
|
|
2606
|
+
var isFilled = (v) => v != null && v !== "";
|
|
2607
|
+
function OnboardingFlow({
|
|
2608
|
+
steps,
|
|
2609
|
+
screens,
|
|
2610
|
+
onComplete,
|
|
2611
|
+
persistKey
|
|
2612
|
+
}) {
|
|
2613
|
+
const [draft, setDraft] = (0, import_sdk16.usePersistedState)(persistKey, {});
|
|
2614
|
+
const [idx, setIdx] = (0, import_react21.useState)(0);
|
|
2615
|
+
const draftRef = (0, import_react21.useRef)(draft);
|
|
2616
|
+
draftRef.current = draft;
|
|
2617
|
+
const step = steps[idx];
|
|
2618
|
+
if (!step) {
|
|
2619
|
+
throw new Error(
|
|
2620
|
+
`[hook-template] OnboardingFlow: step index ${idx} out of range (steps.length=${steps.length})`
|
|
2621
|
+
);
|
|
2622
|
+
}
|
|
2623
|
+
const Screen = screens[step.screen];
|
|
2624
|
+
if (!Screen) {
|
|
2625
|
+
throw new Error(
|
|
2626
|
+
`[hook-template] OnboardingFlow: missing screen component for step '${step.id}' (expected key '${step.screen}' in screens prop)`
|
|
2627
|
+
);
|
|
2628
|
+
}
|
|
2629
|
+
const valid = (0, import_react21.useMemo)(
|
|
2630
|
+
() => (step.validates ?? []).every((field) => isFilled(draft[field])),
|
|
2631
|
+
[draft, step]
|
|
2632
|
+
);
|
|
2633
|
+
const setValue = (0, import_react21.useCallback)(
|
|
2634
|
+
(patch) => {
|
|
2635
|
+
draftRef.current = { ...draftRef.current, ...patch };
|
|
2636
|
+
setDraft((prev2) => ({ ...prev2, ...patch }));
|
|
2637
|
+
},
|
|
2638
|
+
[setDraft]
|
|
2639
|
+
);
|
|
2640
|
+
const next = (0, import_react21.useCallback)(() => {
|
|
2641
|
+
const current = draftRef.current;
|
|
2642
|
+
const validNow = (step.validates ?? []).every((field) => isFilled(current[field]));
|
|
2643
|
+
if (!validNow) return;
|
|
2644
|
+
if (idx + 1 >= steps.length) {
|
|
2645
|
+
onComplete(current);
|
|
2646
|
+
} else {
|
|
2647
|
+
setIdx(idx + 1);
|
|
2648
|
+
}
|
|
2649
|
+
}, [idx, onComplete, step, steps.length]);
|
|
2650
|
+
const prev = (0, import_react21.useCallback)(() => setIdx((i) => Math.max(0, i - 1)), []);
|
|
2651
|
+
const ctx = (0, import_react21.useMemo)(
|
|
2652
|
+
() => ({
|
|
2653
|
+
stepIndex: idx,
|
|
2654
|
+
totalSteps: steps.length,
|
|
2655
|
+
value: draft,
|
|
2656
|
+
setValue,
|
|
2657
|
+
valid,
|
|
2658
|
+
next,
|
|
2659
|
+
prev
|
|
2660
|
+
}),
|
|
2661
|
+
[idx, steps.length, draft, setValue, valid, next, prev]
|
|
2662
|
+
);
|
|
2663
|
+
return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(OnboardingStepContext.Provider, { value: ctx, children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(Screen, {}) });
|
|
2664
|
+
}
|
|
2665
|
+
|
|
2666
|
+
// src/hooks/useFeature.ts
|
|
2667
|
+
function useFeature(name) {
|
|
2668
|
+
const config = useAppConfig();
|
|
2669
|
+
return Array.isArray(config.features_enabled) && config.features_enabled.includes(name);
|
|
2670
|
+
}
|
|
3140
2671
|
// Annotate the CommonJS export names for ESM import in node:
|
|
3141
2672
|
0 && (module.exports = {
|
|
2673
|
+
AppConfigProvider,
|
|
2674
|
+
AppConfigSchema,
|
|
3142
2675
|
AppRoot,
|
|
3143
|
-
|
|
3144
|
-
DefaultLoginScreen,
|
|
3145
|
-
DefaultPaywall,
|
|
3146
|
-
DefaultResetScreen,
|
|
3147
|
-
DefaultSignupScreen,
|
|
2676
|
+
DeepLinkHandler,
|
|
3148
2677
|
EmptyState,
|
|
3149
2678
|
ErrorBoundary,
|
|
3150
2679
|
InstallGate,
|
|
3151
2680
|
InstallSplash,
|
|
3152
2681
|
LoadingState,
|
|
2682
|
+
OnboardingFlow,
|
|
2683
|
+
PaymentReturnHandler,
|
|
2684
|
+
PersistenceRegistry,
|
|
2685
|
+
PreAuthShell,
|
|
3153
2686
|
PushPrompt,
|
|
2687
|
+
RouteBoundary,
|
|
2688
|
+
asaasErrorMessage,
|
|
3154
2689
|
computeAnchorCents,
|
|
3155
2690
|
dailyFromYearly,
|
|
3156
2691
|
detectAndroidBrowser,
|
|
@@ -3161,13 +2696,17 @@ function useToast() {
|
|
|
3161
2696
|
discountPercent,
|
|
3162
2697
|
formatBRL,
|
|
3163
2698
|
monthlyFromYearly,
|
|
2699
|
+
parseAppConfig,
|
|
3164
2700
|
shouldBlockInstall,
|
|
3165
2701
|
shouldShowPermanentOption,
|
|
2702
|
+
useAppConfig,
|
|
3166
2703
|
useAuth,
|
|
3167
2704
|
useAuthPrimitives,
|
|
2705
|
+
useFeature,
|
|
3168
2706
|
useForgotForm,
|
|
3169
2707
|
useInstallPrompt,
|
|
3170
2708
|
useLoginForm,
|
|
2709
|
+
useOnboardingStep,
|
|
3171
2710
|
usePaywallState,
|
|
3172
2711
|
usePlan,
|
|
3173
2712
|
usePush,
|