@hook-sdk/template 0.18.0 → 0.19.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 +330 -209
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +85 -4
- package/dist/index.d.ts +85 -4
- package/dist/index.js +204 -95
- package/dist/index.js.map +1 -1
- package/package.json +5 -2
package/dist/index.cjs
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
2
3
|
var __defProp = Object.defineProperty;
|
|
3
4
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
5
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
8
|
var __export = (target, all) => {
|
|
7
9
|
for (var name in all)
|
|
@@ -15,6 +17,14 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
15
17
|
}
|
|
16
18
|
return to;
|
|
17
19
|
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
18
28
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
29
|
|
|
20
30
|
// src/index.ts
|
|
@@ -26,8 +36,10 @@ __export(index_exports, {
|
|
|
26
36
|
DeepLinkHandler: () => DeepLinkHandler,
|
|
27
37
|
EmptyState: () => EmptyState,
|
|
28
38
|
ErrorBoundary: () => ErrorBoundary,
|
|
39
|
+
I18nProvider: () => I18nProvider,
|
|
29
40
|
InstallGate: () => InstallGate,
|
|
30
41
|
InstallSplash: () => InstallSplash,
|
|
42
|
+
LanguageSwitcher: () => LanguageSwitcher,
|
|
31
43
|
LoadingState: () => LoadingState,
|
|
32
44
|
OnboardingFlow: () => OnboardingFlow,
|
|
33
45
|
PaymentReturnHandler: () => PaymentReturnHandler,
|
|
@@ -65,14 +77,14 @@ __export(index_exports, {
|
|
|
65
77
|
useSignupForm: () => useSignupForm,
|
|
66
78
|
useSubscription: () => useSubscription,
|
|
67
79
|
useToast: () => useToast,
|
|
68
|
-
useTrackOnboardingStep: () =>
|
|
80
|
+
useTrackOnboardingStep: () => import_sdk21.useTrackOnboardingStep
|
|
69
81
|
});
|
|
70
82
|
module.exports = __toCommonJS(index_exports);
|
|
71
83
|
|
|
72
84
|
// src/AppRoot.tsx
|
|
73
|
-
var
|
|
85
|
+
var import_react14 = require("react");
|
|
74
86
|
var import_react_router_dom2 = require("react-router-dom");
|
|
75
|
-
var
|
|
87
|
+
var import_sdk7 = require("@hook-sdk/sdk");
|
|
76
88
|
|
|
77
89
|
// src/config/AppConfigContext.tsx
|
|
78
90
|
var import_react = require("react");
|
|
@@ -145,6 +157,17 @@ var DeepLinksSchema = import_zod.z.object({
|
|
|
145
157
|
passwordReset: import_zod.z.string().startsWith("/").optional(),
|
|
146
158
|
emailVerify: import_zod.z.string().startsWith("/").optional()
|
|
147
159
|
}).strict();
|
|
160
|
+
var I18nConfigSchema = import_zod.z.object({
|
|
161
|
+
defaultLocale: import_zod.z.string().min(2),
|
|
162
|
+
supportedLocales: import_zod.z.array(import_zod.z.string().min(2)).min(1),
|
|
163
|
+
resources: import_zod.z.record(import_zod.z.string(), import_zod.z.record(import_zod.z.string(), import_zod.z.string()))
|
|
164
|
+
}).strict().refine((v) => v.supportedLocales.includes(v.defaultLocale), {
|
|
165
|
+
message: "i18n.defaultLocale must be a member of i18n.supportedLocales",
|
|
166
|
+
path: ["defaultLocale"]
|
|
167
|
+
});
|
|
168
|
+
var InstallPromptSchema = import_zod.z.object({
|
|
169
|
+
position: import_zod.z.enum(["pre-auth", "post-paywall"]).optional()
|
|
170
|
+
}).strict();
|
|
148
171
|
var AppConfigSchema = import_zod.z.object({
|
|
149
172
|
slug: import_zod.z.string().regex(/^[a-z0-9-]+$/),
|
|
150
173
|
name: import_zod.z.string().min(1),
|
|
@@ -158,12 +181,18 @@ var AppConfigSchema = import_zod.z.object({
|
|
|
158
181
|
persistedKeys: import_zod.z.array(PersistedKeySchema),
|
|
159
182
|
onboarding: OnboardingSchema.optional(),
|
|
160
183
|
deepLinks: DeepLinksSchema.optional(),
|
|
184
|
+
i18n: I18nConfigSchema.optional(),
|
|
161
185
|
features_enabled: import_zod.z.array(import_zod.z.string()).optional(),
|
|
186
|
+
install_prompt: InstallPromptSchema.optional(),
|
|
162
187
|
// Build-time injected theme metadata (e.g. icon_url for InstallSplash).
|
|
163
188
|
// Apps don't author this directly; deploy workflows fill it from
|
|
164
189
|
// env-resolved bundle host. Permissive shape so apps/workflows can
|
|
165
190
|
// extend without re-bumping the template schema.
|
|
166
|
-
theme: import_zod.z.object({}).passthrough().optional()
|
|
191
|
+
theme: import_zod.z.object({}).passthrough().optional(),
|
|
192
|
+
// G133 — per-tenant public app-data keys allowlist. Optional; default
|
|
193
|
+
// backfill em migration 0044 = canonical 6. Apps com keys próprias
|
|
194
|
+
// declaram aqui pra evitar 402 spam pós-signup no SubscriptionGate.
|
|
195
|
+
publicKeys: import_zod.z.array(import_zod.z.string().regex(SnakeKeyRE)).optional()
|
|
167
196
|
}).strict();
|
|
168
197
|
function parseAppConfig(input) {
|
|
169
198
|
const r = AppConfigSchema.safeParse(input);
|
|
@@ -267,7 +296,16 @@ var MAP = {
|
|
|
267
296
|
pix_expired: "QR Code do PIX expirou. Gere um novo.",
|
|
268
297
|
pix_not_paid_yet: "PIX ainda n\xE3o foi pago. Aguardando confirma\xE7\xE3o."
|
|
269
298
|
};
|
|
270
|
-
function asaasErrorMessage(code) {
|
|
299
|
+
function asaasErrorMessage(code, description) {
|
|
300
|
+
if (description) {
|
|
301
|
+
const lower = description.toLowerCase();
|
|
302
|
+
if (lower.includes("cep")) {
|
|
303
|
+
return "Nosso processador de pagamentos n\xE3o reconheceu esse CEP \u2014 a base deles pode estar desatualizada. Tente outro CEP.";
|
|
304
|
+
}
|
|
305
|
+
if (lower.includes("telefone") || lower.includes("contato com ddd")) {
|
|
306
|
+
return "Telefone inv\xE1lido. Confira o n\xFAmero com DDD e tente novamente.";
|
|
307
|
+
}
|
|
308
|
+
}
|
|
271
309
|
return MAP[code] ?? "Ocorreu um erro inesperado. Tente novamente em instantes.";
|
|
272
310
|
}
|
|
273
311
|
|
|
@@ -396,7 +434,9 @@ function usePaywallState() {
|
|
|
396
434
|
(code, fallbackMessage) => ({
|
|
397
435
|
code,
|
|
398
436
|
message: fallbackMessage,
|
|
399
|
-
|
|
437
|
+
// fallbackMessage carries Asaas's PT-BR description ("O CEP informado é inválido.")
|
|
438
|
+
// that distinguishes invalid_holderInfo sub-cases (CEP vs phone vs name).
|
|
439
|
+
userMessage: useDefaultMessages ? asaasErrorMessage(code, fallbackMessage) : fallbackMessage
|
|
400
440
|
}),
|
|
401
441
|
[useDefaultMessages]
|
|
402
442
|
);
|
|
@@ -1871,9 +1911,9 @@ var bannerStyle = {
|
|
|
1871
1911
|
|
|
1872
1912
|
// src/components/InstallGate/InstallGate.tsx
|
|
1873
1913
|
var import_jsx_runtime16 = require("react/jsx-runtime");
|
|
1874
|
-
function InstallGate({ children }) {
|
|
1914
|
+
function InstallGate({ children, position }) {
|
|
1875
1915
|
const { slug, features_enabled } = useTemplateConfig();
|
|
1876
|
-
const enabled = features_enabled.includes("
|
|
1916
|
+
const enabled = features_enabled.includes("pwa-install");
|
|
1877
1917
|
const installState = useInstallPrompt(slug);
|
|
1878
1918
|
const shouldBlock = enabled && shouldBlockInstall(installState);
|
|
1879
1919
|
const trackedRef = (0, import_react9.useRef)(null);
|
|
@@ -1888,9 +1928,10 @@ function InstallGate({ children }) {
|
|
|
1888
1928
|
platform: installState.platform,
|
|
1889
1929
|
browser: installState.iosBrowser ?? installState.androidBrowser ?? null,
|
|
1890
1930
|
in_app_app: installState.inAppApp,
|
|
1891
|
-
variant: installState.variant
|
|
1931
|
+
variant: installState.variant,
|
|
1932
|
+
...position !== void 0 ? { position } : {}
|
|
1892
1933
|
});
|
|
1893
|
-
}, [shouldBlock, slug, installState.variant, installState.platform, installState.iosBrowser, installState.androidBrowser, installState.inAppApp]);
|
|
1934
|
+
}, [shouldBlock, slug, installState.variant, installState.platform, installState.iosBrowser, installState.androidBrowser, installState.inAppApp, position]);
|
|
1894
1935
|
if (!enabled) return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_jsx_runtime16.Fragment, { children });
|
|
1895
1936
|
if (installState.isInstalled) return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_jsx_runtime16.Fragment, { children });
|
|
1896
1937
|
if (installState.variant === "desktop") {
|
|
@@ -2013,21 +2054,58 @@ var ErrorBoundary = class extends import_react11.Component {
|
|
|
2013
2054
|
}
|
|
2014
2055
|
};
|
|
2015
2056
|
|
|
2016
|
-
// src/
|
|
2057
|
+
// src/i18n/I18nProvider.tsx
|
|
2017
2058
|
var import_react12 = require("react");
|
|
2059
|
+
var import_i18next = __toESM(require("i18next"), 1);
|
|
2060
|
+
var import_react_i18next = require("react-i18next");
|
|
2018
2061
|
var import_sdk5 = require("@hook-sdk/sdk");
|
|
2019
2062
|
var import_jsx_runtime19 = require("react/jsx-runtime");
|
|
2063
|
+
function ensureInitialized(defaultLocale, supportedLocales, resources, initialLocale) {
|
|
2064
|
+
if (import_i18next.default.isInitialized) return;
|
|
2065
|
+
import_i18next.default.use(import_react_i18next.initReactI18next).init({
|
|
2066
|
+
resources: Object.fromEntries(
|
|
2067
|
+
supportedLocales.map((l) => [l, { translation: resources[l] ?? {} }])
|
|
2068
|
+
),
|
|
2069
|
+
lng: initialLocale,
|
|
2070
|
+
fallbackLng: defaultLocale,
|
|
2071
|
+
interpolation: { escapeValue: false },
|
|
2072
|
+
// useTranslation suspends by default until i18next is "ready". Inline
|
|
2073
|
+
// resources are sync, so suspending creates a guaranteed empty render
|
|
2074
|
+
// tick — confusing in apps and breaks tests that don't use Suspense.
|
|
2075
|
+
react: { useSuspense: false }
|
|
2076
|
+
});
|
|
2077
|
+
}
|
|
2078
|
+
function I18nProvider({
|
|
2079
|
+
defaultLocale,
|
|
2080
|
+
supportedLocales,
|
|
2081
|
+
resources,
|
|
2082
|
+
children
|
|
2083
|
+
}) {
|
|
2084
|
+
const [userLocale] = (0, import_sdk5.usePersistedState)("user-locale", defaultLocale);
|
|
2085
|
+
ensureInitialized(defaultLocale, supportedLocales, resources, userLocale);
|
|
2086
|
+
(0, import_react12.useEffect)(() => {
|
|
2087
|
+
if (import_i18next.default.isInitialized && import_i18next.default.language !== userLocale) {
|
|
2088
|
+
import_i18next.default.changeLanguage(userLocale);
|
|
2089
|
+
}
|
|
2090
|
+
}, [userLocale]);
|
|
2091
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_react_i18next.I18nextProvider, { i18n: import_i18next.default, children });
|
|
2092
|
+
}
|
|
2093
|
+
|
|
2094
|
+
// src/internal/PaymentReturnHandler.tsx
|
|
2095
|
+
var import_react13 = require("react");
|
|
2096
|
+
var import_sdk6 = require("@hook-sdk/sdk");
|
|
2097
|
+
var import_jsx_runtime20 = require("react/jsx-runtime");
|
|
2020
2098
|
var BACKOFF_MS = [2e3, 5e3, 1e4, 2e4, 4e4];
|
|
2021
2099
|
var MAX_CYCLES = 3;
|
|
2022
2100
|
var SUPPORT_MAILTO = "mailto:suporte@usehook.net?subject=Pagamento%20pendente";
|
|
2023
2101
|
function PaymentReturnHandler({ children }) {
|
|
2024
|
-
const { subscription } = (0,
|
|
2025
|
-
const subRef = (0,
|
|
2102
|
+
const { subscription } = (0, import_sdk6.useHook)();
|
|
2103
|
+
const subRef = (0, import_react13.useRef)(subscription);
|
|
2026
2104
|
subRef.current = subscription;
|
|
2027
|
-
const runIdRef = (0,
|
|
2028
|
-
const cyclesRef = (0,
|
|
2029
|
-
const [state, setState] = (0,
|
|
2030
|
-
const runPoll = (0,
|
|
2105
|
+
const runIdRef = (0, import_react13.useRef)(0);
|
|
2106
|
+
const cyclesRef = (0, import_react13.useRef)(0);
|
|
2107
|
+
const [state, setState] = (0, import_react13.useState)("idle");
|
|
2108
|
+
const runPoll = (0, import_react13.useCallback)(() => {
|
|
2031
2109
|
const runId = ++runIdRef.current;
|
|
2032
2110
|
cyclesRef.current += 1;
|
|
2033
2111
|
setState("confirming");
|
|
@@ -2062,7 +2140,7 @@ function PaymentReturnHandler({ children }) {
|
|
|
2062
2140
|
};
|
|
2063
2141
|
void tick();
|
|
2064
2142
|
}, []);
|
|
2065
|
-
(0,
|
|
2143
|
+
(0, import_react13.useEffect)(() => {
|
|
2066
2144
|
if (typeof window === "undefined") return;
|
|
2067
2145
|
const url = new URL(window.location.href);
|
|
2068
2146
|
if (url.searchParams.get("paymentReturn") !== "1") return;
|
|
@@ -2072,26 +2150,26 @@ function PaymentReturnHandler({ children }) {
|
|
|
2072
2150
|
runIdRef.current++;
|
|
2073
2151
|
};
|
|
2074
2152
|
}, [runPoll]);
|
|
2075
|
-
const goHome = (0,
|
|
2153
|
+
const goHome = (0, import_react13.useCallback)(() => {
|
|
2076
2154
|
const cleanUrl = new URL(window.location.href);
|
|
2077
2155
|
cleanUrl.searchParams.delete("paymentReturn");
|
|
2078
2156
|
cleanUrl.pathname = "/app/home";
|
|
2079
2157
|
window.location.href = cleanUrl.toString();
|
|
2080
2158
|
}, []);
|
|
2081
2159
|
if (state === "confirming") {
|
|
2082
|
-
return /* @__PURE__ */ (0,
|
|
2160
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { role: "status", "aria-live": "polite", style: overlayStyle2, children: "Confirmando pagamento\u2026" });
|
|
2083
2161
|
}
|
|
2084
2162
|
if (state === "waiting") {
|
|
2085
|
-
return /* @__PURE__ */ (0,
|
|
2086
|
-
/* @__PURE__ */ (0,
|
|
2087
|
-
/* @__PURE__ */ (0,
|
|
2163
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { role: "status", "aria-live": "polite", style: overlayStyle2, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { style: { maxWidth: 320, textAlign: "center", lineHeight: 1.5 }, children: [
|
|
2164
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { style: { marginBottom: 16 }, children: "Pagamento aceito. Estamos confirmando com o banco \u2014 pode levar alguns minutos." }),
|
|
2165
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { type: "button", onClick: runPoll, style: buttonStyle, children: "Atualizar" })
|
|
2088
2166
|
] }) });
|
|
2089
2167
|
}
|
|
2090
2168
|
if (state === "timeout") {
|
|
2091
|
-
return /* @__PURE__ */ (0,
|
|
2092
|
-
/* @__PURE__ */ (0,
|
|
2093
|
-
/* @__PURE__ */ (0,
|
|
2094
|
-
/* @__PURE__ */ (0,
|
|
2169
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { role: "alert", "aria-live": "assertive", style: overlayStyle2, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { style: { maxWidth: 360, textAlign: "center", lineHeight: 1.5 }, children: [
|
|
2170
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { style: { marginBottom: 16 }, children: "Ainda n\xE3o conseguimos confirmar seu pagamento com o banco. Voc\xEA pode tentar de novo, voltar pro app, ou falar com a gente." }),
|
|
2171
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: 8 }, children: [
|
|
2172
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
2095
2173
|
"button",
|
|
2096
2174
|
{
|
|
2097
2175
|
type: "button",
|
|
@@ -2104,7 +2182,7 @@ function PaymentReturnHandler({ children }) {
|
|
|
2104
2182
|
children: "Tentar de novo"
|
|
2105
2183
|
}
|
|
2106
2184
|
),
|
|
2107
|
-
/* @__PURE__ */ (0,
|
|
2185
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
2108
2186
|
"button",
|
|
2109
2187
|
{
|
|
2110
2188
|
type: "button",
|
|
@@ -2114,7 +2192,7 @@ function PaymentReturnHandler({ children }) {
|
|
|
2114
2192
|
children: "Voltar pro app"
|
|
2115
2193
|
}
|
|
2116
2194
|
),
|
|
2117
|
-
/* @__PURE__ */ (0,
|
|
2195
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
2118
2196
|
"a",
|
|
2119
2197
|
{
|
|
2120
2198
|
href: SUPPORT_MAILTO,
|
|
@@ -2126,7 +2204,7 @@ function PaymentReturnHandler({ children }) {
|
|
|
2126
2204
|
] })
|
|
2127
2205
|
] }) });
|
|
2128
2206
|
}
|
|
2129
|
-
return /* @__PURE__ */ (0,
|
|
2207
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_jsx_runtime20.Fragment, { children });
|
|
2130
2208
|
}
|
|
2131
2209
|
var overlayStyle2 = {
|
|
2132
2210
|
position: "fixed",
|
|
@@ -2165,7 +2243,7 @@ var linkStyle = {
|
|
|
2165
2243
|
};
|
|
2166
2244
|
|
|
2167
2245
|
// src/AppRoot.tsx
|
|
2168
|
-
var
|
|
2246
|
+
var import_jsx_runtime21 = require("react/jsx-runtime");
|
|
2169
2247
|
function buildLegacyConfigShim(config) {
|
|
2170
2248
|
const paywall = config.paywall;
|
|
2171
2249
|
const isFree = paywall.mode === "free";
|
|
@@ -2238,32 +2316,47 @@ function AppRoot(props) {
|
|
|
2238
2316
|
"[hook-template] <AppRoot>: PreAuthFlow slot prop is required when config.onboarding.trigger === 'pre_signup_custom'."
|
|
2239
2317
|
);
|
|
2240
2318
|
}
|
|
2241
|
-
const legacyShim = (0,
|
|
2319
|
+
const legacyShim = (0, import_react14.useMemo)(() => buildLegacyConfigShim(config), [config]);
|
|
2242
2320
|
const Router = testRouter === "memory" ? import_react_router_dom2.MemoryRouter : import_react_router_dom2.BrowserRouter;
|
|
2243
2321
|
const basename = `/app/${config.slug}`;
|
|
2244
2322
|
const routerProps = testRouter === "memory" ? { basename, initialEntries: testInitialEntries } : { basename };
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
|
|
2248
|
-
/* @__PURE__ */ (0,
|
|
2249
|
-
|
|
2250
|
-
|
|
2251
|
-
|
|
2252
|
-
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
|
|
2323
|
+
const position = config.install_prompt?.position ?? "post-paywall";
|
|
2324
|
+
const subscriptionGated = /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(SubscriptionGate, { Paywall: Paywall ?? FallbackPaywall, children: position === "post-paywall" ? /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(InstallGate, { position: "post-paywall", children: [
|
|
2325
|
+
children,
|
|
2326
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(PushPrompt, {})
|
|
2327
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_jsx_runtime21.Fragment, { children: [
|
|
2328
|
+
children,
|
|
2329
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(PushPrompt, {})
|
|
2330
|
+
] }) });
|
|
2331
|
+
const authGated = /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
2332
|
+
AuthGated,
|
|
2333
|
+
{
|
|
2334
|
+
config,
|
|
2335
|
+
Login,
|
|
2336
|
+
Signup,
|
|
2337
|
+
Forgot,
|
|
2338
|
+
Reset,
|
|
2339
|
+
EmailVerify,
|
|
2340
|
+
Paywall,
|
|
2341
|
+
Onboarding,
|
|
2342
|
+
PreAuthFlow,
|
|
2343
|
+
children: subscriptionGated
|
|
2344
|
+
}
|
|
2345
|
+
);
|
|
2346
|
+
const routedTree = /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(Router, { ...routerProps, children: [
|
|
2347
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(DeepLinkHandler, { deepLinks: config.deepLinks }),
|
|
2348
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(SessionExpiredBanner, {}),
|
|
2349
|
+
position === "pre-auth" ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(InstallGate, { position: "pre-auth", children: authGated }) : authGated
|
|
2350
|
+
] });
|
|
2351
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ErrorBoundary, { children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(AppConfigProvider, { config, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(TemplateConfigProvider, { config: legacyShim, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ThemeProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(PersistenceRegistry, { config: config.persistedKeys, children: config.i18n ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
2352
|
+
I18nProvider,
|
|
2353
|
+
{
|
|
2354
|
+
defaultLocale: config.i18n.defaultLocale,
|
|
2355
|
+
supportedLocales: config.i18n.supportedLocales,
|
|
2356
|
+
resources: config.i18n.resources,
|
|
2357
|
+
children: routedTree
|
|
2358
|
+
}
|
|
2359
|
+
) : routedTree }) }) }) }) });
|
|
2267
2360
|
}
|
|
2268
2361
|
function AuthGated({
|
|
2269
2362
|
children,
|
|
@@ -2275,37 +2368,37 @@ function AuthGated({
|
|
|
2275
2368
|
EmailVerify,
|
|
2276
2369
|
PreAuthFlow
|
|
2277
2370
|
}) {
|
|
2278
|
-
const { authStatus } = (0,
|
|
2371
|
+
const { authStatus } = (0, import_sdk7.useHook)();
|
|
2279
2372
|
if (authStatus === "loading") return null;
|
|
2280
2373
|
if (authStatus !== "authenticated") {
|
|
2281
2374
|
if (config.onboarding?.trigger === "pre_signup_custom" && PreAuthFlow) {
|
|
2282
|
-
return /* @__PURE__ */ (0,
|
|
2283
|
-
/* @__PURE__ */ (0,
|
|
2284
|
-
/* @__PURE__ */ (0,
|
|
2285
|
-
/* @__PURE__ */ (0,
|
|
2286
|
-
/* @__PURE__ */ (0,
|
|
2287
|
-
EmailVerify ? /* @__PURE__ */ (0,
|
|
2288
|
-
/* @__PURE__ */ (0,
|
|
2375
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_react_router_dom2.Routes, { children: [
|
|
2376
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_react_router_dom2.Route, { path: "/signin", element: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Login, {}) }),
|
|
2377
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_react_router_dom2.Route, { path: "/signup", element: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Signup, {}) }),
|
|
2378
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_react_router_dom2.Route, { path: "/forgot", element: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Forgot, {}) }),
|
|
2379
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_react_router_dom2.Route, { path: "/reset", element: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Reset, {}) }),
|
|
2380
|
+
EmailVerify ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_react_router_dom2.Route, { path: "/verify", element: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(EmailVerify, {}) }) : null,
|
|
2381
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_react_router_dom2.Route, { path: "/*", element: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(PreAuthFlow, {}) })
|
|
2289
2382
|
] });
|
|
2290
2383
|
}
|
|
2291
|
-
return /* @__PURE__ */ (0,
|
|
2292
|
-
/* @__PURE__ */ (0,
|
|
2293
|
-
/* @__PURE__ */ (0,
|
|
2294
|
-
/* @__PURE__ */ (0,
|
|
2295
|
-
/* @__PURE__ */ (0,
|
|
2296
|
-
EmailVerify ? /* @__PURE__ */ (0,
|
|
2297
|
-
/* @__PURE__ */ (0,
|
|
2384
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_react_router_dom2.Routes, { children: [
|
|
2385
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_react_router_dom2.Route, { path: "/", element: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Login, {}) }),
|
|
2386
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_react_router_dom2.Route, { path: "/signup", element: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Signup, {}) }),
|
|
2387
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_react_router_dom2.Route, { path: "/forgot", element: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Forgot, {}) }),
|
|
2388
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_react_router_dom2.Route, { path: "/reset", element: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Reset, {}) }),
|
|
2389
|
+
EmailVerify ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_react_router_dom2.Route, { path: "/verify", element: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(EmailVerify, {}) }) : null,
|
|
2390
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_react_router_dom2.Route, { path: "*", element: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_react_router_dom2.Navigate, { to: "/", replace: true }) })
|
|
2298
2391
|
] });
|
|
2299
2392
|
}
|
|
2300
|
-
return /* @__PURE__ */ (0,
|
|
2393
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_jsx_runtime21.Fragment, { children });
|
|
2301
2394
|
}
|
|
2302
2395
|
function FallbackPaywall() {
|
|
2303
2396
|
return null;
|
|
2304
2397
|
}
|
|
2305
2398
|
|
|
2306
2399
|
// src/hooks/usePush.ts
|
|
2307
|
-
var
|
|
2308
|
-
var
|
|
2400
|
+
var import_react15 = require("react");
|
|
2401
|
+
var import_sdk8 = require("@hook-sdk/sdk");
|
|
2309
2402
|
var DISMISS_STORAGE_KEY = "push:dismissed-until";
|
|
2310
2403
|
var DISMISS_TTL_MS2 = 7 * 24 * 60 * 60 * 1e3;
|
|
2311
2404
|
function detectIosNeedsInstall() {
|
|
@@ -2349,12 +2442,12 @@ function deriveState(push) {
|
|
|
2349
2442
|
return { kind: "prompt" };
|
|
2350
2443
|
}
|
|
2351
2444
|
function usePush() {
|
|
2352
|
-
const { push } = (0,
|
|
2353
|
-
const [state, setState] = (0,
|
|
2354
|
-
(0,
|
|
2445
|
+
const { push } = (0, import_sdk8.useHook)();
|
|
2446
|
+
const [state, setState] = (0, import_react15.useState)(() => deriveState(push));
|
|
2447
|
+
(0, import_react15.useEffect)(() => {
|
|
2355
2448
|
setState(deriveState(push));
|
|
2356
2449
|
}, [push]);
|
|
2357
|
-
const subscribe = (0,
|
|
2450
|
+
const subscribe = (0, import_react15.useCallback)(async () => {
|
|
2358
2451
|
try {
|
|
2359
2452
|
await push.subscribe();
|
|
2360
2453
|
setState({ kind: "subscribed" });
|
|
@@ -2366,7 +2459,7 @@ function usePush() {
|
|
|
2366
2459
|
throw e;
|
|
2367
2460
|
}
|
|
2368
2461
|
}, [push]);
|
|
2369
|
-
const unsubscribe = (0,
|
|
2462
|
+
const unsubscribe = (0, import_react15.useCallback)(async () => {
|
|
2370
2463
|
try {
|
|
2371
2464
|
await push.unsubscribe();
|
|
2372
2465
|
setState({ kind: "prompt" });
|
|
@@ -2375,7 +2468,7 @@ function usePush() {
|
|
|
2375
2468
|
throw e;
|
|
2376
2469
|
}
|
|
2377
2470
|
}, [push]);
|
|
2378
|
-
const dismiss = (0,
|
|
2471
|
+
const dismiss = (0, import_react15.useCallback)(() => {
|
|
2379
2472
|
if (typeof localStorage !== "undefined") {
|
|
2380
2473
|
try {
|
|
2381
2474
|
localStorage.setItem(DISMISS_STORAGE_KEY, String(Date.now() + DISMISS_TTL_MS2));
|
|
@@ -2388,7 +2481,7 @@ function usePush() {
|
|
|
2388
2481
|
}
|
|
2389
2482
|
|
|
2390
2483
|
// src/components/PushPrompt.tsx
|
|
2391
|
-
var
|
|
2484
|
+
var import_jsx_runtime22 = require("react/jsx-runtime");
|
|
2392
2485
|
function platformRecoveryCopy(texts) {
|
|
2393
2486
|
if (typeof navigator === "undefined") return null;
|
|
2394
2487
|
const ua = navigator.userAgent || "";
|
|
@@ -2411,28 +2504,28 @@ function PushPrompt2({ texts, onSubscribed, onDeclined, onInstallRequested, clas
|
|
|
2411
2504
|
const { state, subscribe } = usePush();
|
|
2412
2505
|
if (state.kind === "subscribed" || state.kind === "dismissed") return null;
|
|
2413
2506
|
if (state.kind === "ios_needs_install") {
|
|
2414
|
-
return /* @__PURE__ */ (0,
|
|
2415
|
-
/* @__PURE__ */ (0,
|
|
2416
|
-
/* @__PURE__ */ (0,
|
|
2417
|
-
onInstallRequested && texts.iosInstallCta && /* @__PURE__ */ (0,
|
|
2507
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className, role: "region", "aria-label": texts.iosInstallTitle, children: [
|
|
2508
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("h3", { children: texts.iosInstallTitle }),
|
|
2509
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("p", { children: texts.iosInstallBody }),
|
|
2510
|
+
onInstallRequested && texts.iosInstallCta && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("button", { onClick: onInstallRequested, children: texts.iosInstallCta })
|
|
2418
2511
|
] });
|
|
2419
2512
|
}
|
|
2420
2513
|
if (state.kind === "denied") {
|
|
2421
2514
|
const recovery = platformRecoveryCopy(texts);
|
|
2422
|
-
return /* @__PURE__ */ (0,
|
|
2423
|
-
/* @__PURE__ */ (0,
|
|
2424
|
-
/* @__PURE__ */ (0,
|
|
2425
|
-
recovery && /* @__PURE__ */ (0,
|
|
2515
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className, role: "region", "aria-label": texts.deniedTitle, children: [
|
|
2516
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("h3", { children: texts.deniedTitle }),
|
|
2517
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("p", { children: texts.deniedBody }),
|
|
2518
|
+
recovery && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("p", { "data-testid": "denied-recovery", children: recovery })
|
|
2426
2519
|
] });
|
|
2427
2520
|
}
|
|
2428
2521
|
if (state.kind === "unsupported") {
|
|
2429
|
-
return /* @__PURE__ */ (0,
|
|
2522
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className, role: "region", children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("p", { children: texts.unsupportedBody }) });
|
|
2430
2523
|
}
|
|
2431
2524
|
if (state.kind === "error") {
|
|
2432
|
-
return /* @__PURE__ */ (0,
|
|
2525
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className, role: "region", "aria-label": "error", children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("p", { children: state.message }) });
|
|
2433
2526
|
}
|
|
2434
|
-
return /* @__PURE__ */ (0,
|
|
2435
|
-
/* @__PURE__ */ (0,
|
|
2527
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className, role: "region", children: [
|
|
2528
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
2436
2529
|
"button",
|
|
2437
2530
|
{
|
|
2438
2531
|
type: "button",
|
|
@@ -2446,41 +2539,67 @@ function PushPrompt2({ texts, onSubscribed, onDeclined, onInstallRequested, clas
|
|
|
2446
2539
|
children: texts.cta
|
|
2447
2540
|
}
|
|
2448
2541
|
),
|
|
2449
|
-
onDeclined && /* @__PURE__ */ (0,
|
|
2542
|
+
onDeclined && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("button", { type: "button", onClick: onDeclined, children: texts.declineCta })
|
|
2543
|
+
] });
|
|
2544
|
+
}
|
|
2545
|
+
|
|
2546
|
+
// src/components/LanguageSwitcher.tsx
|
|
2547
|
+
var import_sdk9 = require("@hook-sdk/sdk");
|
|
2548
|
+
var import_jsx_runtime23 = require("react/jsx-runtime");
|
|
2549
|
+
function LanguageSwitcher({ id, className, label = "Language" }) {
|
|
2550
|
+
const config = useAppConfig();
|
|
2551
|
+
const i18nConfig = config.i18n;
|
|
2552
|
+
const [userLocale, setUserLocale] = (0, import_sdk9.usePersistedState)(
|
|
2553
|
+
"user-locale",
|
|
2554
|
+
i18nConfig?.defaultLocale ?? "en-US"
|
|
2555
|
+
);
|
|
2556
|
+
if (!i18nConfig) return null;
|
|
2557
|
+
return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("label", { className, children: [
|
|
2558
|
+
label ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { children: label }) : null,
|
|
2559
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
2560
|
+
"select",
|
|
2561
|
+
{
|
|
2562
|
+
id,
|
|
2563
|
+
value: userLocale,
|
|
2564
|
+
onChange: (e) => setUserLocale(e.target.value),
|
|
2565
|
+
"data-testid": "language-switcher",
|
|
2566
|
+
children: i18nConfig.supportedLocales.map((loc) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("option", { value: loc, children: loc }, loc))
|
|
2567
|
+
}
|
|
2568
|
+
)
|
|
2450
2569
|
] });
|
|
2451
2570
|
}
|
|
2452
2571
|
|
|
2453
2572
|
// src/defaults/LoadingState.tsx
|
|
2454
|
-
var
|
|
2573
|
+
var import_jsx_runtime24 = require("react/jsx-runtime");
|
|
2455
2574
|
function LoadingState({ message }) {
|
|
2456
|
-
return /* @__PURE__ */ (0,
|
|
2575
|
+
return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { role: "status", "aria-live": "polite", style: { padding: 24, textAlign: "center" }, children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { children: message ?? "Carregando..." }) });
|
|
2457
2576
|
}
|
|
2458
2577
|
|
|
2459
2578
|
// src/defaults/EmptyState.tsx
|
|
2460
|
-
var
|
|
2579
|
+
var import_jsx_runtime25 = require("react/jsx-runtime");
|
|
2461
2580
|
function EmptyState({ title, description, action }) {
|
|
2462
|
-
return /* @__PURE__ */ (0,
|
|
2463
|
-
/* @__PURE__ */ (0,
|
|
2464
|
-
description && /* @__PURE__ */ (0,
|
|
2465
|
-
action && /* @__PURE__ */ (0,
|
|
2581
|
+
return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { role: "status", style: { padding: 32, textAlign: "center" }, children: [
|
|
2582
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)("h2", { style: { marginBottom: 8 }, children: title }),
|
|
2583
|
+
description && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("p", { style: { opacity: 0.7 }, children: description }),
|
|
2584
|
+
action && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { style: { marginTop: 16 }, children: action })
|
|
2466
2585
|
] });
|
|
2467
2586
|
}
|
|
2468
2587
|
|
|
2469
2588
|
// src/hooks/useLoginForm.ts
|
|
2470
|
-
var
|
|
2471
|
-
var
|
|
2589
|
+
var import_react16 = require("react");
|
|
2590
|
+
var import_sdk11 = require("@hook-sdk/sdk");
|
|
2472
2591
|
|
|
2473
2592
|
// src/errors.ts
|
|
2474
|
-
var
|
|
2593
|
+
var import_sdk10 = require("@hook-sdk/sdk");
|
|
2475
2594
|
function mapSdkError(err) {
|
|
2476
|
-
if (err instanceof
|
|
2595
|
+
if (err instanceof import_sdk10.SdkRateLimitError) {
|
|
2477
2596
|
return {
|
|
2478
2597
|
code: "rate_limited",
|
|
2479
2598
|
message: `Aguarde ${err.retryAfter}s e tente novamente.`,
|
|
2480
2599
|
retryAfter: err.retryAfter
|
|
2481
2600
|
};
|
|
2482
2601
|
}
|
|
2483
|
-
if (err instanceof
|
|
2602
|
+
if (err instanceof import_sdk10.SdkAuthError) {
|
|
2484
2603
|
const detail = err.detail;
|
|
2485
2604
|
if (detail === "email_unverified") {
|
|
2486
2605
|
return { code: "email_unverified", message: "Confirme seu e-mail antes de entrar." };
|
|
@@ -2490,7 +2609,7 @@ function mapSdkError(err) {
|
|
|
2490
2609
|
}
|
|
2491
2610
|
return { code: "invalid_credentials", message: "E-mail ou senha inv\xE1lidos." };
|
|
2492
2611
|
}
|
|
2493
|
-
if (err instanceof
|
|
2612
|
+
if (err instanceof import_sdk10.SdkError && err.httpStatus === 0) {
|
|
2494
2613
|
return { code: "network", message: "Sem conex\xE3o com o servidor. Verifique sua internet." };
|
|
2495
2614
|
}
|
|
2496
2615
|
if (err instanceof TypeError) {
|
|
@@ -2503,20 +2622,20 @@ function mapSdkError(err) {
|
|
|
2503
2622
|
var EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
2504
2623
|
var MIN_PASSWORD = 8;
|
|
2505
2624
|
function useLoginForm() {
|
|
2506
|
-
const { auth } = (0,
|
|
2507
|
-
const [email, setEmail] = (0,
|
|
2508
|
-
const [password, setPassword] = (0,
|
|
2509
|
-
const [submitting, setSubmitting] = (0,
|
|
2510
|
-
const [error, setError] = (0,
|
|
2511
|
-
const [touchedEmail, setTouchedEmail] = (0,
|
|
2512
|
-
const [touchedPassword, setTouchedPassword] = (0,
|
|
2513
|
-
const [formSubmitAttempted, setFormSubmitAttempted] = (0,
|
|
2514
|
-
const validateEmail = (0,
|
|
2625
|
+
const { auth } = (0, import_sdk11.useHook)();
|
|
2626
|
+
const [email, setEmail] = (0, import_react16.useState)("");
|
|
2627
|
+
const [password, setPassword] = (0, import_react16.useState)("");
|
|
2628
|
+
const [submitting, setSubmitting] = (0, import_react16.useState)(false);
|
|
2629
|
+
const [error, setError] = (0, import_react16.useState)(null);
|
|
2630
|
+
const [touchedEmail, setTouchedEmail] = (0, import_react16.useState)(false);
|
|
2631
|
+
const [touchedPassword, setTouchedPassword] = (0, import_react16.useState)(false);
|
|
2632
|
+
const [formSubmitAttempted, setFormSubmitAttempted] = (0, import_react16.useState)(false);
|
|
2633
|
+
const validateEmail = (0, import_react16.useMemo)(() => {
|
|
2515
2634
|
if (email.length === 0) return null;
|
|
2516
2635
|
if (!EMAIL_RE.test(email)) return "Formato de e-mail inv\xE1lido.";
|
|
2517
2636
|
return null;
|
|
2518
2637
|
}, [email]);
|
|
2519
|
-
const validatePassword = (0,
|
|
2638
|
+
const validatePassword = (0, import_react16.useMemo)(() => {
|
|
2520
2639
|
if (password.length === 0) return null;
|
|
2521
2640
|
if (password.length < MIN_PASSWORD) return `M\xEDnimo de ${MIN_PASSWORD} caracteres.`;
|
|
2522
2641
|
return null;
|
|
@@ -2524,7 +2643,7 @@ function useLoginForm() {
|
|
|
2524
2643
|
const emailError = touchedEmail || formSubmitAttempted ? validateEmail : null;
|
|
2525
2644
|
const passwordError = touchedPassword || formSubmitAttempted ? validatePassword : null;
|
|
2526
2645
|
const canSubmit = email.length > 0 && password.length >= MIN_PASSWORD && validateEmail === null && validatePassword === null && !submitting;
|
|
2527
|
-
const submit = (0,
|
|
2646
|
+
const submit = (0, import_react16.useCallback)(async () => {
|
|
2528
2647
|
setFormSubmitAttempted(true);
|
|
2529
2648
|
if (!canSubmit) return false;
|
|
2530
2649
|
setSubmitting(true);
|
|
@@ -2558,32 +2677,32 @@ function useLoginForm() {
|
|
|
2558
2677
|
}
|
|
2559
2678
|
|
|
2560
2679
|
// src/hooks/useSignupForm.ts
|
|
2561
|
-
var
|
|
2562
|
-
var
|
|
2680
|
+
var import_react17 = require("react");
|
|
2681
|
+
var import_sdk12 = require("@hook-sdk/sdk");
|
|
2563
2682
|
var EMAIL_RE2 = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
2564
2683
|
var MIN_PASSWORD2 = 8;
|
|
2565
2684
|
function useSignupForm() {
|
|
2566
|
-
const { auth } = (0,
|
|
2567
|
-
const [name, setName] = (0,
|
|
2568
|
-
const [email, setEmail] = (0,
|
|
2569
|
-
const [password, setPassword] = (0,
|
|
2570
|
-
const [submitting, setSubmitting] = (0,
|
|
2571
|
-
const [error, setError] = (0,
|
|
2572
|
-
const [touchedName, setTouchedName] = (0,
|
|
2573
|
-
const [touchedEmail, setTouchedEmail] = (0,
|
|
2574
|
-
const [touchedPassword, setTouchedPassword] = (0,
|
|
2575
|
-
const [formSubmitAttempted, setFormSubmitAttempted] = (0,
|
|
2576
|
-
const validateName = (0,
|
|
2685
|
+
const { auth } = (0, import_sdk12.useHook)();
|
|
2686
|
+
const [name, setName] = (0, import_react17.useState)("");
|
|
2687
|
+
const [email, setEmail] = (0, import_react17.useState)("");
|
|
2688
|
+
const [password, setPassword] = (0, import_react17.useState)("");
|
|
2689
|
+
const [submitting, setSubmitting] = (0, import_react17.useState)(false);
|
|
2690
|
+
const [error, setError] = (0, import_react17.useState)(null);
|
|
2691
|
+
const [touchedName, setTouchedName] = (0, import_react17.useState)(false);
|
|
2692
|
+
const [touchedEmail, setTouchedEmail] = (0, import_react17.useState)(false);
|
|
2693
|
+
const [touchedPassword, setTouchedPassword] = (0, import_react17.useState)(false);
|
|
2694
|
+
const [formSubmitAttempted, setFormSubmitAttempted] = (0, import_react17.useState)(false);
|
|
2695
|
+
const validateName = (0, import_react17.useMemo)(() => {
|
|
2577
2696
|
if (name.length === 0) return null;
|
|
2578
2697
|
if (name.trim().length < 2) return "Nome muito curto.";
|
|
2579
2698
|
return null;
|
|
2580
2699
|
}, [name]);
|
|
2581
|
-
const validateEmail = (0,
|
|
2700
|
+
const validateEmail = (0, import_react17.useMemo)(() => {
|
|
2582
2701
|
if (email.length === 0) return null;
|
|
2583
2702
|
if (!EMAIL_RE2.test(email)) return "Formato de e-mail inv\xE1lido.";
|
|
2584
2703
|
return null;
|
|
2585
2704
|
}, [email]);
|
|
2586
|
-
const validatePassword = (0,
|
|
2705
|
+
const validatePassword = (0, import_react17.useMemo)(() => {
|
|
2587
2706
|
if (password.length === 0) return null;
|
|
2588
2707
|
if (password.length < MIN_PASSWORD2) return `M\xEDnimo de ${MIN_PASSWORD2} caracteres.`;
|
|
2589
2708
|
return null;
|
|
@@ -2592,7 +2711,7 @@ function useSignupForm() {
|
|
|
2592
2711
|
const emailError = touchedEmail || formSubmitAttempted ? validateEmail : null;
|
|
2593
2712
|
const passwordError = touchedPassword || formSubmitAttempted ? validatePassword : null;
|
|
2594
2713
|
const canSubmit = name.trim().length >= 2 && email.length > 0 && password.length >= MIN_PASSWORD2 && validateName === null && validateEmail === null && validatePassword === null && !submitting;
|
|
2595
|
-
const submit = (0,
|
|
2714
|
+
const submit = (0, import_react17.useCallback)(async () => {
|
|
2596
2715
|
setFormSubmitAttempted(true);
|
|
2597
2716
|
if (!canSubmit) return false;
|
|
2598
2717
|
setSubmitting(true);
|
|
@@ -2630,25 +2749,25 @@ function useSignupForm() {
|
|
|
2630
2749
|
}
|
|
2631
2750
|
|
|
2632
2751
|
// src/hooks/useForgotForm.ts
|
|
2633
|
-
var
|
|
2634
|
-
var
|
|
2752
|
+
var import_react18 = require("react");
|
|
2753
|
+
var import_sdk13 = require("@hook-sdk/sdk");
|
|
2635
2754
|
var EMAIL_RE3 = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
2636
2755
|
function useForgotForm() {
|
|
2637
|
-
const { auth } = (0,
|
|
2638
|
-
const [email, setEmail] = (0,
|
|
2639
|
-
const [submitting, setSubmitting] = (0,
|
|
2640
|
-
const [sent, setSent] = (0,
|
|
2641
|
-
const [error, setError] = (0,
|
|
2642
|
-
const [touchedEmail, setTouchedEmail] = (0,
|
|
2643
|
-
const [formSubmitAttempted, setFormSubmitAttempted] = (0,
|
|
2644
|
-
const validateEmail = (0,
|
|
2756
|
+
const { auth } = (0, import_sdk13.useHook)();
|
|
2757
|
+
const [email, setEmail] = (0, import_react18.useState)("");
|
|
2758
|
+
const [submitting, setSubmitting] = (0, import_react18.useState)(false);
|
|
2759
|
+
const [sent, setSent] = (0, import_react18.useState)(false);
|
|
2760
|
+
const [error, setError] = (0, import_react18.useState)(null);
|
|
2761
|
+
const [touchedEmail, setTouchedEmail] = (0, import_react18.useState)(false);
|
|
2762
|
+
const [formSubmitAttempted, setFormSubmitAttempted] = (0, import_react18.useState)(false);
|
|
2763
|
+
const validateEmail = (0, import_react18.useMemo)(() => {
|
|
2645
2764
|
if (email.length === 0) return null;
|
|
2646
2765
|
if (!EMAIL_RE3.test(email)) return "Formato de e-mail inv\xE1lido.";
|
|
2647
2766
|
return null;
|
|
2648
2767
|
}, [email]);
|
|
2649
2768
|
const emailError = touchedEmail || formSubmitAttempted ? validateEmail : null;
|
|
2650
2769
|
const canSubmit = email.length > 0 && validateEmail === null && !submitting;
|
|
2651
|
-
const submit = (0,
|
|
2770
|
+
const submit = (0, import_react18.useCallback)(async () => {
|
|
2652
2771
|
setFormSubmitAttempted(true);
|
|
2653
2772
|
if (!canSubmit) return false;
|
|
2654
2773
|
setSubmitting(true);
|
|
@@ -2679,32 +2798,32 @@ function useForgotForm() {
|
|
|
2679
2798
|
}
|
|
2680
2799
|
|
|
2681
2800
|
// src/hooks/useResetForm.ts
|
|
2682
|
-
var
|
|
2683
|
-
var
|
|
2801
|
+
var import_react19 = require("react");
|
|
2802
|
+
var import_sdk14 = require("@hook-sdk/sdk");
|
|
2684
2803
|
var MIN_PASSWORD3 = 12;
|
|
2685
2804
|
function useResetForm() {
|
|
2686
|
-
const { auth } = (0,
|
|
2687
|
-
const [token, setToken] = (0,
|
|
2688
|
-
const [password, setPassword] = (0,
|
|
2689
|
-
const [confirm, setConfirm] = (0,
|
|
2690
|
-
const [submitting, setSubmitting] = (0,
|
|
2691
|
-
const [done, setDone] = (0,
|
|
2692
|
-
const [error, setError] = (0,
|
|
2693
|
-
const [touchedPassword, setTouchedPassword] = (0,
|
|
2694
|
-
const [touchedConfirm, setTouchedConfirm] = (0,
|
|
2695
|
-
const [formSubmitAttempted, setFormSubmitAttempted] = (0,
|
|
2696
|
-
(0,
|
|
2805
|
+
const { auth } = (0, import_sdk14.useHook)();
|
|
2806
|
+
const [token, setToken] = (0, import_react19.useState)(null);
|
|
2807
|
+
const [password, setPassword] = (0, import_react19.useState)("");
|
|
2808
|
+
const [confirm, setConfirm] = (0, import_react19.useState)("");
|
|
2809
|
+
const [submitting, setSubmitting] = (0, import_react19.useState)(false);
|
|
2810
|
+
const [done, setDone] = (0, import_react19.useState)(false);
|
|
2811
|
+
const [error, setError] = (0, import_react19.useState)(null);
|
|
2812
|
+
const [touchedPassword, setTouchedPassword] = (0, import_react19.useState)(false);
|
|
2813
|
+
const [touchedConfirm, setTouchedConfirm] = (0, import_react19.useState)(false);
|
|
2814
|
+
const [formSubmitAttempted, setFormSubmitAttempted] = (0, import_react19.useState)(false);
|
|
2815
|
+
(0, import_react19.useEffect)(() => {
|
|
2697
2816
|
if (typeof window === "undefined") return;
|
|
2698
2817
|
const params = new URLSearchParams(window.location.search);
|
|
2699
2818
|
const t = params.get("token");
|
|
2700
2819
|
setToken(t && t.length > 0 ? t : null);
|
|
2701
2820
|
}, []);
|
|
2702
|
-
const validatePassword = (0,
|
|
2821
|
+
const validatePassword = (0, import_react19.useMemo)(() => {
|
|
2703
2822
|
if (password.length === 0) return null;
|
|
2704
2823
|
if (password.length < MIN_PASSWORD3) return `M\xEDnimo de ${MIN_PASSWORD3} caracteres.`;
|
|
2705
2824
|
return null;
|
|
2706
2825
|
}, [password]);
|
|
2707
|
-
const validateConfirm = (0,
|
|
2826
|
+
const validateConfirm = (0, import_react19.useMemo)(() => {
|
|
2708
2827
|
if (confirm.length === 0) return null;
|
|
2709
2828
|
if (confirm !== password) return "Senhas n\xE3o coincidem.";
|
|
2710
2829
|
return null;
|
|
@@ -2712,7 +2831,7 @@ function useResetForm() {
|
|
|
2712
2831
|
const passwordError = touchedPassword || formSubmitAttempted ? validatePassword : null;
|
|
2713
2832
|
const confirmError = touchedConfirm || formSubmitAttempted ? validateConfirm : null;
|
|
2714
2833
|
const canSubmit = token !== null && password.length >= MIN_PASSWORD3 && confirm === password && validatePassword === null && validateConfirm === null && !submitting && !done;
|
|
2715
|
-
const submit = (0,
|
|
2834
|
+
const submit = (0, import_react19.useCallback)(async () => {
|
|
2716
2835
|
setFormSubmitAttempted(true);
|
|
2717
2836
|
if (!canSubmit || token === null) return;
|
|
2718
2837
|
setSubmitting(true);
|
|
@@ -2752,9 +2871,9 @@ function useResetForm() {
|
|
|
2752
2871
|
}
|
|
2753
2872
|
|
|
2754
2873
|
// src/hooks/usePlan.ts
|
|
2755
|
-
var
|
|
2874
|
+
var import_sdk15 = require("@hook-sdk/sdk");
|
|
2756
2875
|
function usePlan() {
|
|
2757
|
-
const { plan } = (0,
|
|
2876
|
+
const { plan } = (0, import_sdk15.useHook)();
|
|
2758
2877
|
return plan;
|
|
2759
2878
|
}
|
|
2760
2879
|
|
|
@@ -2787,12 +2906,12 @@ function discountPercent(anchorCents, realCents) {
|
|
|
2787
2906
|
}
|
|
2788
2907
|
|
|
2789
2908
|
// src/hooks/useAuthPrimitives.ts
|
|
2790
|
-
var
|
|
2791
|
-
var
|
|
2909
|
+
var import_react20 = require("react");
|
|
2910
|
+
var import_sdk16 = require("@hook-sdk/sdk");
|
|
2792
2911
|
var warned = false;
|
|
2793
2912
|
function useAuthPrimitives() {
|
|
2794
|
-
const { auth } = (0,
|
|
2795
|
-
(0,
|
|
2913
|
+
const { auth } = (0, import_sdk16.useHook)();
|
|
2914
|
+
(0, import_react20.useEffect)(() => {
|
|
2796
2915
|
if (!warned && process.env.NODE_ENV !== "production") {
|
|
2797
2916
|
warned = true;
|
|
2798
2917
|
console.warn(
|
|
@@ -2814,9 +2933,9 @@ function useAuthPrimitives() {
|
|
|
2814
2933
|
}
|
|
2815
2934
|
|
|
2816
2935
|
// src/hooks/useAuth.ts
|
|
2817
|
-
var
|
|
2936
|
+
var import_sdk17 = require("@hook-sdk/sdk");
|
|
2818
2937
|
function useAuth() {
|
|
2819
|
-
const { user, authStatus, auth } = (0,
|
|
2938
|
+
const { user, authStatus, auth } = (0, import_sdk17.useHook)();
|
|
2820
2939
|
return {
|
|
2821
2940
|
user,
|
|
2822
2941
|
authStatus,
|
|
@@ -2825,26 +2944,26 @@ function useAuth() {
|
|
|
2825
2944
|
}
|
|
2826
2945
|
|
|
2827
2946
|
// src/index.ts
|
|
2828
|
-
var
|
|
2947
|
+
var import_sdk21 = require("@hook-sdk/sdk");
|
|
2829
2948
|
|
|
2830
2949
|
// src/hooks/useSubscription.ts
|
|
2831
|
-
var
|
|
2950
|
+
var import_sdk18 = require("@hook-sdk/sdk");
|
|
2832
2951
|
function useSubscription() {
|
|
2833
|
-
const { subscription } = (0,
|
|
2952
|
+
const { subscription } = (0, import_sdk18.useHook)();
|
|
2834
2953
|
return {
|
|
2835
2954
|
status: subscription.status()
|
|
2836
2955
|
};
|
|
2837
2956
|
}
|
|
2838
2957
|
|
|
2839
2958
|
// src/hooks/useReminders.ts
|
|
2840
|
-
var
|
|
2841
|
-
var
|
|
2959
|
+
var import_react21 = require("react");
|
|
2960
|
+
var import_sdk19 = require("@hook-sdk/sdk");
|
|
2842
2961
|
function useReminders() {
|
|
2843
|
-
const { push } = (0,
|
|
2962
|
+
const { push } = (0, import_sdk19.useHook)();
|
|
2844
2963
|
const r = push.reminders;
|
|
2845
|
-
const [reminders, setReminders] = (0,
|
|
2846
|
-
const [loading, setLoading] = (0,
|
|
2847
|
-
const reload = (0,
|
|
2964
|
+
const [reminders, setReminders] = (0, import_react21.useState)([]);
|
|
2965
|
+
const [loading, setLoading] = (0, import_react21.useState)(true);
|
|
2966
|
+
const reload = (0, import_react21.useCallback)(async () => {
|
|
2848
2967
|
setLoading(true);
|
|
2849
2968
|
try {
|
|
2850
2969
|
const next = await r.list();
|
|
@@ -2853,38 +2972,38 @@ function useReminders() {
|
|
|
2853
2972
|
setLoading(false);
|
|
2854
2973
|
}
|
|
2855
2974
|
}, [r]);
|
|
2856
|
-
(0,
|
|
2975
|
+
(0, import_react21.useEffect)(() => {
|
|
2857
2976
|
void reload();
|
|
2858
2977
|
}, [reload]);
|
|
2859
|
-
const setReminder = (0,
|
|
2978
|
+
const setReminder = (0, import_react21.useCallback)(async (input) => {
|
|
2860
2979
|
await r.set(input);
|
|
2861
2980
|
await reload();
|
|
2862
2981
|
}, [r, reload]);
|
|
2863
|
-
const deleteReminder = (0,
|
|
2982
|
+
const deleteReminder = (0, import_react21.useCallback)(async (slot) => {
|
|
2864
2983
|
await r.delete(slot);
|
|
2865
2984
|
await reload();
|
|
2866
2985
|
}, [r, reload]);
|
|
2867
|
-
const schedule = (0,
|
|
2986
|
+
const schedule = (0, import_react21.useCallback)(async (items) => {
|
|
2868
2987
|
return r.schedule(items);
|
|
2869
2988
|
}, [r]);
|
|
2870
|
-
const setFallbacks = (0,
|
|
2989
|
+
const setFallbacks = (0, import_react21.useCallback)(async (items) => {
|
|
2871
2990
|
return r.setFallbacks(items);
|
|
2872
2991
|
}, [r]);
|
|
2873
2992
|
return { reminders, loading, setReminder, deleteReminder, schedule, setFallbacks };
|
|
2874
2993
|
}
|
|
2875
2994
|
|
|
2876
2995
|
// src/hooks/useToast.ts
|
|
2877
|
-
var
|
|
2996
|
+
var import_react22 = require("react");
|
|
2878
2997
|
function useToast() {
|
|
2879
|
-
const [items, setItems] = (0,
|
|
2880
|
-
const show = (0,
|
|
2998
|
+
const [items, setItems] = (0, import_react22.useState)([]);
|
|
2999
|
+
const show = (0, import_react22.useCallback)((message, kind = "info") => {
|
|
2881
3000
|
const id = `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
2882
3001
|
setItems((prev) => [...prev, { id, message, kind }]);
|
|
2883
3002
|
setTimeout(() => {
|
|
2884
3003
|
setItems((prev) => prev.filter((t) => t.id !== id));
|
|
2885
3004
|
}, 4e3);
|
|
2886
3005
|
}, []);
|
|
2887
|
-
const dismiss = (0,
|
|
3006
|
+
const dismiss = (0, import_react22.useCallback)((id) => {
|
|
2888
3007
|
setItems((prev) => prev.filter((t) => t.id !== id));
|
|
2889
3008
|
}, []);
|
|
2890
3009
|
return { items, show, dismiss };
|
|
@@ -2892,20 +3011,20 @@ function useToast() {
|
|
|
2892
3011
|
|
|
2893
3012
|
// src/RouteBoundary.tsx
|
|
2894
3013
|
var import_react_router_dom3 = require("react-router-dom");
|
|
2895
|
-
var
|
|
3014
|
+
var import_jsx_runtime26 = require("react/jsx-runtime");
|
|
2896
3015
|
function RouteBoundary({ children }) {
|
|
2897
|
-
return /* @__PURE__ */ (0,
|
|
3016
|
+
return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(import_react_router_dom3.Routes, { children: [
|
|
2898
3017
|
children,
|
|
2899
|
-
/* @__PURE__ */ (0,
|
|
3018
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_react_router_dom3.Route, { path: "*", element: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(DefaultNotFound, {}) })
|
|
2900
3019
|
] });
|
|
2901
3020
|
}
|
|
2902
3021
|
function DefaultNotFound() {
|
|
2903
|
-
return /* @__PURE__ */ (0,
|
|
3022
|
+
return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { role: "alert", children: "P\xE1gina n\xE3o encontrada" });
|
|
2904
3023
|
}
|
|
2905
3024
|
|
|
2906
3025
|
// src/PreAuthShell.tsx
|
|
2907
3026
|
var import_react_router_dom4 = require("react-router-dom");
|
|
2908
|
-
var
|
|
3027
|
+
var import_jsx_runtime27 = require("react/jsx-runtime");
|
|
2909
3028
|
function PreAuthShell({
|
|
2910
3029
|
basename,
|
|
2911
3030
|
testRouter,
|
|
@@ -2913,20 +3032,20 @@ function PreAuthShell({
|
|
|
2913
3032
|
children
|
|
2914
3033
|
}) {
|
|
2915
3034
|
if (testRouter === "memory") {
|
|
2916
|
-
return /* @__PURE__ */ (0,
|
|
3035
|
+
return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_react_router_dom4.MemoryRouter, { basename, initialEntries: testInitialEntries, children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_react_router_dom4.Routes, { children }) });
|
|
2917
3036
|
}
|
|
2918
|
-
return /* @__PURE__ */ (0,
|
|
3037
|
+
return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_react_router_dom4.BrowserRouter, { basename, children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_react_router_dom4.Routes, { children }) });
|
|
2919
3038
|
}
|
|
2920
3039
|
|
|
2921
3040
|
// src/OnboardingFlow.tsx
|
|
2922
|
-
var
|
|
2923
|
-
var
|
|
3041
|
+
var import_react24 = require("react");
|
|
3042
|
+
var import_sdk20 = require("@hook-sdk/sdk");
|
|
2924
3043
|
|
|
2925
3044
|
// src/hooks/useOnboardingStep.ts
|
|
2926
|
-
var
|
|
2927
|
-
var OnboardingStepContext = (0,
|
|
3045
|
+
var import_react23 = require("react");
|
|
3046
|
+
var OnboardingStepContext = (0, import_react23.createContext)(null);
|
|
2928
3047
|
function useOnboardingStep() {
|
|
2929
|
-
const ctx = (0,
|
|
3048
|
+
const ctx = (0, import_react23.useContext)(OnboardingStepContext);
|
|
2930
3049
|
if (!ctx) {
|
|
2931
3050
|
throw new Error(
|
|
2932
3051
|
"[hook-template] useOnboardingStep must be used inside <OnboardingFlow>. (G75)"
|
|
@@ -2936,7 +3055,7 @@ function useOnboardingStep() {
|
|
|
2936
3055
|
}
|
|
2937
3056
|
|
|
2938
3057
|
// src/OnboardingFlow.tsx
|
|
2939
|
-
var
|
|
3058
|
+
var import_jsx_runtime28 = require("react/jsx-runtime");
|
|
2940
3059
|
var isFilled = (v) => v != null && v !== "";
|
|
2941
3060
|
var CURRENT_STEP_FIELD = "currentStep";
|
|
2942
3061
|
function readPersistedStepIdx(draft) {
|
|
@@ -2949,12 +3068,12 @@ function OnboardingFlow({
|
|
|
2949
3068
|
onComplete,
|
|
2950
3069
|
persistKey
|
|
2951
3070
|
}) {
|
|
2952
|
-
const [draft, setDraft, status] = (0,
|
|
2953
|
-
const draftRef = (0,
|
|
3071
|
+
const [draft, setDraft, status] = (0, import_sdk20.usePersistedState)(persistKey, {});
|
|
3072
|
+
const draftRef = (0, import_react24.useRef)(draft);
|
|
2954
3073
|
draftRef.current = draft;
|
|
2955
3074
|
const idx = readPersistedStepIdx(draft);
|
|
2956
3075
|
const clampedIdx = Math.min(Math.max(idx, 0), Math.max(steps.length - 1, 0));
|
|
2957
|
-
const setIdx = (0,
|
|
3076
|
+
const setIdx = (0, import_react24.useCallback)(
|
|
2958
3077
|
(n) => {
|
|
2959
3078
|
setDraft((prev) => {
|
|
2960
3079
|
const prevIdx = readPersistedStepIdx(prev);
|
|
@@ -2964,7 +3083,7 @@ function OnboardingFlow({
|
|
|
2964
3083
|
},
|
|
2965
3084
|
[setDraft]
|
|
2966
3085
|
);
|
|
2967
|
-
const setValue = (0,
|
|
3086
|
+
const setValue = (0, import_react24.useCallback)(
|
|
2968
3087
|
(patch) => {
|
|
2969
3088
|
draftRef.current = { ...draftRef.current, ...patch };
|
|
2970
3089
|
setDraft((prev) => ({ ...prev, ...patch }));
|
|
@@ -2972,9 +3091,9 @@ function OnboardingFlow({
|
|
|
2972
3091
|
[setDraft]
|
|
2973
3092
|
);
|
|
2974
3093
|
const step = steps[clampedIdx];
|
|
2975
|
-
const hookCtx = (0,
|
|
3094
|
+
const hookCtx = (0, import_sdk20.useHook)();
|
|
2976
3095
|
const track2 = typeof hookCtx.track === "function" ? hookCtx.track : void 0;
|
|
2977
|
-
(0,
|
|
3096
|
+
(0, import_react24.useEffect)(() => {
|
|
2978
3097
|
if (status.loading) return;
|
|
2979
3098
|
if (!step) return;
|
|
2980
3099
|
if (!track2) return;
|
|
@@ -2984,11 +3103,11 @@ function OnboardingFlow({
|
|
|
2984
3103
|
total_steps: steps.length
|
|
2985
3104
|
});
|
|
2986
3105
|
}, [step?.id, clampedIdx, steps.length, status.loading, track2]);
|
|
2987
|
-
const valid = (0,
|
|
3106
|
+
const valid = (0, import_react24.useMemo)(
|
|
2988
3107
|
() => step ? (step.validates ?? []).every((field) => isFilled(draft[field])) : false,
|
|
2989
3108
|
[draft, step]
|
|
2990
3109
|
);
|
|
2991
|
-
const next = (0,
|
|
3110
|
+
const next = (0, import_react24.useCallback)(() => {
|
|
2992
3111
|
if (!step) return;
|
|
2993
3112
|
const current = draftRef.current;
|
|
2994
3113
|
const validNow = (step.validates ?? []).every((field) => isFilled(current[field]));
|
|
@@ -2999,8 +3118,8 @@ function OnboardingFlow({
|
|
|
2999
3118
|
setIdx(clampedIdx + 1);
|
|
3000
3119
|
}
|
|
3001
3120
|
}, [clampedIdx, onComplete, step, steps.length, setIdx]);
|
|
3002
|
-
const prevStep = (0,
|
|
3003
|
-
const ctx = (0,
|
|
3121
|
+
const prevStep = (0, import_react24.useCallback)(() => setIdx((i) => Math.max(0, i - 1)), [setIdx]);
|
|
3122
|
+
const ctx = (0, import_react24.useMemo)(
|
|
3004
3123
|
() => ({
|
|
3005
3124
|
stepIndex: clampedIdx,
|
|
3006
3125
|
totalSteps: steps.length,
|
|
@@ -3026,7 +3145,7 @@ function OnboardingFlow({
|
|
|
3026
3145
|
`[hook-template] OnboardingFlow: missing screen component for step '${step.id}' (expected key '${step.screen}' in screens prop)`
|
|
3027
3146
|
);
|
|
3028
3147
|
}
|
|
3029
|
-
return /* @__PURE__ */ (0,
|
|
3148
|
+
return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(OnboardingStepContext.Provider, { value: ctx, children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(Screen, {}) });
|
|
3030
3149
|
}
|
|
3031
3150
|
|
|
3032
3151
|
// src/hooks/useFeature.ts
|
|
@@ -3042,8 +3161,10 @@ function useFeature(name) {
|
|
|
3042
3161
|
DeepLinkHandler,
|
|
3043
3162
|
EmptyState,
|
|
3044
3163
|
ErrorBoundary,
|
|
3164
|
+
I18nProvider,
|
|
3045
3165
|
InstallGate,
|
|
3046
3166
|
InstallSplash,
|
|
3167
|
+
LanguageSwitcher,
|
|
3047
3168
|
LoadingState,
|
|
3048
3169
|
OnboardingFlow,
|
|
3049
3170
|
PaymentReturnHandler,
|