@hook-sdk/template 0.18.1 → 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 +317 -207
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +70 -3
- package/dist/index.d.ts +70 -3
- package/dist/index.js +191 -93
- package/dist/index.js.map +1 -1
- package/package.json +5 -2
package/dist/index.js
CHANGED
|
@@ -74,6 +74,17 @@ var DeepLinksSchema = z.object({
|
|
|
74
74
|
passwordReset: z.string().startsWith("/").optional(),
|
|
75
75
|
emailVerify: z.string().startsWith("/").optional()
|
|
76
76
|
}).strict();
|
|
77
|
+
var I18nConfigSchema = z.object({
|
|
78
|
+
defaultLocale: z.string().min(2),
|
|
79
|
+
supportedLocales: z.array(z.string().min(2)).min(1),
|
|
80
|
+
resources: z.record(z.string(), z.record(z.string(), z.string()))
|
|
81
|
+
}).strict().refine((v) => v.supportedLocales.includes(v.defaultLocale), {
|
|
82
|
+
message: "i18n.defaultLocale must be a member of i18n.supportedLocales",
|
|
83
|
+
path: ["defaultLocale"]
|
|
84
|
+
});
|
|
85
|
+
var InstallPromptSchema = z.object({
|
|
86
|
+
position: z.enum(["pre-auth", "post-paywall"]).optional()
|
|
87
|
+
}).strict();
|
|
77
88
|
var AppConfigSchema = z.object({
|
|
78
89
|
slug: z.string().regex(/^[a-z0-9-]+$/),
|
|
79
90
|
name: z.string().min(1),
|
|
@@ -87,12 +98,18 @@ var AppConfigSchema = z.object({
|
|
|
87
98
|
persistedKeys: z.array(PersistedKeySchema),
|
|
88
99
|
onboarding: OnboardingSchema.optional(),
|
|
89
100
|
deepLinks: DeepLinksSchema.optional(),
|
|
101
|
+
i18n: I18nConfigSchema.optional(),
|
|
90
102
|
features_enabled: z.array(z.string()).optional(),
|
|
103
|
+
install_prompt: InstallPromptSchema.optional(),
|
|
91
104
|
// Build-time injected theme metadata (e.g. icon_url for InstallSplash).
|
|
92
105
|
// Apps don't author this directly; deploy workflows fill it from
|
|
93
106
|
// env-resolved bundle host. Permissive shape so apps/workflows can
|
|
94
107
|
// extend without re-bumping the template schema.
|
|
95
|
-
theme: z.object({}).passthrough().optional()
|
|
108
|
+
theme: z.object({}).passthrough().optional(),
|
|
109
|
+
// G133 — per-tenant public app-data keys allowlist. Optional; default
|
|
110
|
+
// backfill em migration 0044 = canonical 6. Apps com keys próprias
|
|
111
|
+
// declaram aqui pra evitar 402 spam pós-signup no SubscriptionGate.
|
|
112
|
+
publicKeys: z.array(z.string().regex(SnakeKeyRE)).optional()
|
|
96
113
|
}).strict();
|
|
97
114
|
function parseAppConfig(input) {
|
|
98
115
|
const r = AppConfigSchema.safeParse(input);
|
|
@@ -1811,9 +1828,9 @@ var bannerStyle = {
|
|
|
1811
1828
|
|
|
1812
1829
|
// src/components/InstallGate/InstallGate.tsx
|
|
1813
1830
|
import { Fragment as Fragment3, jsx as jsx16, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
1814
|
-
function InstallGate({ children }) {
|
|
1831
|
+
function InstallGate({ children, position }) {
|
|
1815
1832
|
const { slug, features_enabled } = useTemplateConfig();
|
|
1816
|
-
const enabled = features_enabled.includes("
|
|
1833
|
+
const enabled = features_enabled.includes("pwa-install");
|
|
1817
1834
|
const installState = useInstallPrompt(slug);
|
|
1818
1835
|
const shouldBlock = enabled && shouldBlockInstall(installState);
|
|
1819
1836
|
const trackedRef = useRef2(null);
|
|
@@ -1828,9 +1845,10 @@ function InstallGate({ children }) {
|
|
|
1828
1845
|
platform: installState.platform,
|
|
1829
1846
|
browser: installState.iosBrowser ?? installState.androidBrowser ?? null,
|
|
1830
1847
|
in_app_app: installState.inAppApp,
|
|
1831
|
-
variant: installState.variant
|
|
1848
|
+
variant: installState.variant,
|
|
1849
|
+
...position !== void 0 ? { position } : {}
|
|
1832
1850
|
});
|
|
1833
|
-
}, [shouldBlock, slug, installState.variant, installState.platform, installState.iosBrowser, installState.androidBrowser, installState.inAppApp]);
|
|
1851
|
+
}, [shouldBlock, slug, installState.variant, installState.platform, installState.iosBrowser, installState.androidBrowser, installState.inAppApp, position]);
|
|
1834
1852
|
if (!enabled) return /* @__PURE__ */ jsx16(Fragment3, { children });
|
|
1835
1853
|
if (installState.isInstalled) return /* @__PURE__ */ jsx16(Fragment3, { children });
|
|
1836
1854
|
if (installState.variant === "desktop") {
|
|
@@ -1953,10 +1971,47 @@ var ErrorBoundary = class extends Component {
|
|
|
1953
1971
|
}
|
|
1954
1972
|
};
|
|
1955
1973
|
|
|
1974
|
+
// src/i18n/I18nProvider.tsx
|
|
1975
|
+
import { useEffect as useEffect7 } from "react";
|
|
1976
|
+
import i18n from "i18next";
|
|
1977
|
+
import { I18nextProvider, initReactI18next } from "react-i18next";
|
|
1978
|
+
import { usePersistedState } from "@hook-sdk/sdk";
|
|
1979
|
+
import { jsx as jsx19 } from "react/jsx-runtime";
|
|
1980
|
+
function ensureInitialized(defaultLocale, supportedLocales, resources, initialLocale) {
|
|
1981
|
+
if (i18n.isInitialized) return;
|
|
1982
|
+
i18n.use(initReactI18next).init({
|
|
1983
|
+
resources: Object.fromEntries(
|
|
1984
|
+
supportedLocales.map((l) => [l, { translation: resources[l] ?? {} }])
|
|
1985
|
+
),
|
|
1986
|
+
lng: initialLocale,
|
|
1987
|
+
fallbackLng: defaultLocale,
|
|
1988
|
+
interpolation: { escapeValue: false },
|
|
1989
|
+
// useTranslation suspends by default until i18next is "ready". Inline
|
|
1990
|
+
// resources are sync, so suspending creates a guaranteed empty render
|
|
1991
|
+
// tick — confusing in apps and breaks tests that don't use Suspense.
|
|
1992
|
+
react: { useSuspense: false }
|
|
1993
|
+
});
|
|
1994
|
+
}
|
|
1995
|
+
function I18nProvider({
|
|
1996
|
+
defaultLocale,
|
|
1997
|
+
supportedLocales,
|
|
1998
|
+
resources,
|
|
1999
|
+
children
|
|
2000
|
+
}) {
|
|
2001
|
+
const [userLocale] = usePersistedState("user-locale", defaultLocale);
|
|
2002
|
+
ensureInitialized(defaultLocale, supportedLocales, resources, userLocale);
|
|
2003
|
+
useEffect7(() => {
|
|
2004
|
+
if (i18n.isInitialized && i18n.language !== userLocale) {
|
|
2005
|
+
i18n.changeLanguage(userLocale);
|
|
2006
|
+
}
|
|
2007
|
+
}, [userLocale]);
|
|
2008
|
+
return /* @__PURE__ */ jsx19(I18nextProvider, { i18n, children });
|
|
2009
|
+
}
|
|
2010
|
+
|
|
1956
2011
|
// src/internal/PaymentReturnHandler.tsx
|
|
1957
|
-
import { useCallback as useCallback3, useEffect as
|
|
2012
|
+
import { useCallback as useCallback3, useEffect as useEffect8, useRef as useRef4, useState as useState5 } from "react";
|
|
1958
2013
|
import { useHook as useHook5 } from "@hook-sdk/sdk";
|
|
1959
|
-
import { Fragment as Fragment5, jsx as
|
|
2014
|
+
import { Fragment as Fragment5, jsx as jsx20, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
1960
2015
|
var BACKOFF_MS = [2e3, 5e3, 1e4, 2e4, 4e4];
|
|
1961
2016
|
var MAX_CYCLES = 3;
|
|
1962
2017
|
var SUPPORT_MAILTO = "mailto:suporte@usehook.net?subject=Pagamento%20pendente";
|
|
@@ -2002,7 +2057,7 @@ function PaymentReturnHandler({ children }) {
|
|
|
2002
2057
|
};
|
|
2003
2058
|
void tick();
|
|
2004
2059
|
}, []);
|
|
2005
|
-
|
|
2060
|
+
useEffect8(() => {
|
|
2006
2061
|
if (typeof window === "undefined") return;
|
|
2007
2062
|
const url = new URL(window.location.href);
|
|
2008
2063
|
if (url.searchParams.get("paymentReturn") !== "1") return;
|
|
@@ -2019,19 +2074,19 @@ function PaymentReturnHandler({ children }) {
|
|
|
2019
2074
|
window.location.href = cleanUrl.toString();
|
|
2020
2075
|
}, []);
|
|
2021
2076
|
if (state === "confirming") {
|
|
2022
|
-
return /* @__PURE__ */
|
|
2077
|
+
return /* @__PURE__ */ jsx20("div", { role: "status", "aria-live": "polite", style: overlayStyle2, children: "Confirmando pagamento\u2026" });
|
|
2023
2078
|
}
|
|
2024
2079
|
if (state === "waiting") {
|
|
2025
|
-
return /* @__PURE__ */
|
|
2026
|
-
/* @__PURE__ */
|
|
2027
|
-
/* @__PURE__ */
|
|
2080
|
+
return /* @__PURE__ */ jsx20("div", { role: "status", "aria-live": "polite", style: overlayStyle2, children: /* @__PURE__ */ jsxs13("div", { style: { maxWidth: 320, textAlign: "center", lineHeight: 1.5 }, children: [
|
|
2081
|
+
/* @__PURE__ */ jsx20("div", { style: { marginBottom: 16 }, children: "Pagamento aceito. Estamos confirmando com o banco \u2014 pode levar alguns minutos." }),
|
|
2082
|
+
/* @__PURE__ */ jsx20("button", { type: "button", onClick: runPoll, style: buttonStyle, children: "Atualizar" })
|
|
2028
2083
|
] }) });
|
|
2029
2084
|
}
|
|
2030
2085
|
if (state === "timeout") {
|
|
2031
|
-
return /* @__PURE__ */
|
|
2032
|
-
/* @__PURE__ */
|
|
2086
|
+
return /* @__PURE__ */ jsx20("div", { role: "alert", "aria-live": "assertive", style: overlayStyle2, children: /* @__PURE__ */ jsxs13("div", { style: { maxWidth: 360, textAlign: "center", lineHeight: 1.5 }, children: [
|
|
2087
|
+
/* @__PURE__ */ jsx20("div", { style: { marginBottom: 16 }, children: "Ainda n\xE3o conseguimos confirmar seu pagamento com o banco. Voc\xEA pode tentar de novo, voltar pro app, ou falar com a gente." }),
|
|
2033
2088
|
/* @__PURE__ */ jsxs13("div", { style: { display: "flex", flexDirection: "column", gap: 8 }, children: [
|
|
2034
|
-
/* @__PURE__ */
|
|
2089
|
+
/* @__PURE__ */ jsx20(
|
|
2035
2090
|
"button",
|
|
2036
2091
|
{
|
|
2037
2092
|
type: "button",
|
|
@@ -2044,7 +2099,7 @@ function PaymentReturnHandler({ children }) {
|
|
|
2044
2099
|
children: "Tentar de novo"
|
|
2045
2100
|
}
|
|
2046
2101
|
),
|
|
2047
|
-
/* @__PURE__ */
|
|
2102
|
+
/* @__PURE__ */ jsx20(
|
|
2048
2103
|
"button",
|
|
2049
2104
|
{
|
|
2050
2105
|
type: "button",
|
|
@@ -2054,7 +2109,7 @@ function PaymentReturnHandler({ children }) {
|
|
|
2054
2109
|
children: "Voltar pro app"
|
|
2055
2110
|
}
|
|
2056
2111
|
),
|
|
2057
|
-
/* @__PURE__ */
|
|
2112
|
+
/* @__PURE__ */ jsx20(
|
|
2058
2113
|
"a",
|
|
2059
2114
|
{
|
|
2060
2115
|
href: SUPPORT_MAILTO,
|
|
@@ -2066,7 +2121,7 @@ function PaymentReturnHandler({ children }) {
|
|
|
2066
2121
|
] })
|
|
2067
2122
|
] }) });
|
|
2068
2123
|
}
|
|
2069
|
-
return /* @__PURE__ */
|
|
2124
|
+
return /* @__PURE__ */ jsx20(Fragment5, { children });
|
|
2070
2125
|
}
|
|
2071
2126
|
var overlayStyle2 = {
|
|
2072
2127
|
position: "fixed",
|
|
@@ -2105,7 +2160,7 @@ var linkStyle = {
|
|
|
2105
2160
|
};
|
|
2106
2161
|
|
|
2107
2162
|
// src/AppRoot.tsx
|
|
2108
|
-
import { Fragment as Fragment6, jsx as
|
|
2163
|
+
import { Fragment as Fragment6, jsx as jsx21, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
2109
2164
|
function buildLegacyConfigShim(config) {
|
|
2110
2165
|
const paywall = config.paywall;
|
|
2111
2166
|
const isFree = paywall.mode === "free";
|
|
@@ -2182,28 +2237,43 @@ function AppRoot(props) {
|
|
|
2182
2237
|
const Router = testRouter === "memory" ? MemoryRouter : BrowserRouter;
|
|
2183
2238
|
const basename = `/app/${config.slug}`;
|
|
2184
2239
|
const routerProps = testRouter === "memory" ? { basename, initialEntries: testInitialEntries } : { basename };
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
-
|
|
2188
|
-
/* @__PURE__ */
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
|
|
2202
|
-
|
|
2203
|
-
|
|
2204
|
-
|
|
2205
|
-
|
|
2206
|
-
|
|
2240
|
+
const position = config.install_prompt?.position ?? "post-paywall";
|
|
2241
|
+
const subscriptionGated = /* @__PURE__ */ jsx21(SubscriptionGate, { Paywall: Paywall ?? FallbackPaywall, children: position === "post-paywall" ? /* @__PURE__ */ jsxs14(InstallGate, { position: "post-paywall", children: [
|
|
2242
|
+
children,
|
|
2243
|
+
/* @__PURE__ */ jsx21(PushPrompt, {})
|
|
2244
|
+
] }) : /* @__PURE__ */ jsxs14(Fragment6, { children: [
|
|
2245
|
+
children,
|
|
2246
|
+
/* @__PURE__ */ jsx21(PushPrompt, {})
|
|
2247
|
+
] }) });
|
|
2248
|
+
const authGated = /* @__PURE__ */ jsx21(
|
|
2249
|
+
AuthGated,
|
|
2250
|
+
{
|
|
2251
|
+
config,
|
|
2252
|
+
Login,
|
|
2253
|
+
Signup,
|
|
2254
|
+
Forgot,
|
|
2255
|
+
Reset,
|
|
2256
|
+
EmailVerify,
|
|
2257
|
+
Paywall,
|
|
2258
|
+
Onboarding,
|
|
2259
|
+
PreAuthFlow,
|
|
2260
|
+
children: subscriptionGated
|
|
2261
|
+
}
|
|
2262
|
+
);
|
|
2263
|
+
const routedTree = /* @__PURE__ */ jsxs14(Router, { ...routerProps, children: [
|
|
2264
|
+
/* @__PURE__ */ jsx21(DeepLinkHandler, { deepLinks: config.deepLinks }),
|
|
2265
|
+
/* @__PURE__ */ jsx21(SessionExpiredBanner, {}),
|
|
2266
|
+
position === "pre-auth" ? /* @__PURE__ */ jsx21(InstallGate, { position: "pre-auth", children: authGated }) : authGated
|
|
2267
|
+
] });
|
|
2268
|
+
return /* @__PURE__ */ jsx21(ErrorBoundary, { children: /* @__PURE__ */ jsx21(AppConfigProvider, { config, children: /* @__PURE__ */ jsx21(TemplateConfigProvider, { config: legacyShim, children: /* @__PURE__ */ jsx21(ThemeProvider, { children: /* @__PURE__ */ jsx21(PersistenceRegistry, { config: config.persistedKeys, children: config.i18n ? /* @__PURE__ */ jsx21(
|
|
2269
|
+
I18nProvider,
|
|
2270
|
+
{
|
|
2271
|
+
defaultLocale: config.i18n.defaultLocale,
|
|
2272
|
+
supportedLocales: config.i18n.supportedLocales,
|
|
2273
|
+
resources: config.i18n.resources,
|
|
2274
|
+
children: routedTree
|
|
2275
|
+
}
|
|
2276
|
+
) : routedTree }) }) }) }) });
|
|
2207
2277
|
}
|
|
2208
2278
|
function AuthGated({
|
|
2209
2279
|
children,
|
|
@@ -2220,31 +2290,31 @@ function AuthGated({
|
|
|
2220
2290
|
if (authStatus !== "authenticated") {
|
|
2221
2291
|
if (config.onboarding?.trigger === "pre_signup_custom" && PreAuthFlow) {
|
|
2222
2292
|
return /* @__PURE__ */ jsxs14(Routes, { children: [
|
|
2223
|
-
/* @__PURE__ */
|
|
2224
|
-
/* @__PURE__ */
|
|
2225
|
-
/* @__PURE__ */
|
|
2226
|
-
/* @__PURE__ */
|
|
2227
|
-
EmailVerify ? /* @__PURE__ */
|
|
2228
|
-
/* @__PURE__ */
|
|
2293
|
+
/* @__PURE__ */ jsx21(Route, { path: "/signin", element: /* @__PURE__ */ jsx21(Login, {}) }),
|
|
2294
|
+
/* @__PURE__ */ jsx21(Route, { path: "/signup", element: /* @__PURE__ */ jsx21(Signup, {}) }),
|
|
2295
|
+
/* @__PURE__ */ jsx21(Route, { path: "/forgot", element: /* @__PURE__ */ jsx21(Forgot, {}) }),
|
|
2296
|
+
/* @__PURE__ */ jsx21(Route, { path: "/reset", element: /* @__PURE__ */ jsx21(Reset, {}) }),
|
|
2297
|
+
EmailVerify ? /* @__PURE__ */ jsx21(Route, { path: "/verify", element: /* @__PURE__ */ jsx21(EmailVerify, {}) }) : null,
|
|
2298
|
+
/* @__PURE__ */ jsx21(Route, { path: "/*", element: /* @__PURE__ */ jsx21(PreAuthFlow, {}) })
|
|
2229
2299
|
] });
|
|
2230
2300
|
}
|
|
2231
2301
|
return /* @__PURE__ */ jsxs14(Routes, { children: [
|
|
2232
|
-
/* @__PURE__ */
|
|
2233
|
-
/* @__PURE__ */
|
|
2234
|
-
/* @__PURE__ */
|
|
2235
|
-
/* @__PURE__ */
|
|
2236
|
-
EmailVerify ? /* @__PURE__ */
|
|
2237
|
-
/* @__PURE__ */
|
|
2302
|
+
/* @__PURE__ */ jsx21(Route, { path: "/", element: /* @__PURE__ */ jsx21(Login, {}) }),
|
|
2303
|
+
/* @__PURE__ */ jsx21(Route, { path: "/signup", element: /* @__PURE__ */ jsx21(Signup, {}) }),
|
|
2304
|
+
/* @__PURE__ */ jsx21(Route, { path: "/forgot", element: /* @__PURE__ */ jsx21(Forgot, {}) }),
|
|
2305
|
+
/* @__PURE__ */ jsx21(Route, { path: "/reset", element: /* @__PURE__ */ jsx21(Reset, {}) }),
|
|
2306
|
+
EmailVerify ? /* @__PURE__ */ jsx21(Route, { path: "/verify", element: /* @__PURE__ */ jsx21(EmailVerify, {}) }) : null,
|
|
2307
|
+
/* @__PURE__ */ jsx21(Route, { path: "*", element: /* @__PURE__ */ jsx21(Navigate, { to: "/", replace: true }) })
|
|
2238
2308
|
] });
|
|
2239
2309
|
}
|
|
2240
|
-
return /* @__PURE__ */
|
|
2310
|
+
return /* @__PURE__ */ jsx21(Fragment6, { children });
|
|
2241
2311
|
}
|
|
2242
2312
|
function FallbackPaywall() {
|
|
2243
2313
|
return null;
|
|
2244
2314
|
}
|
|
2245
2315
|
|
|
2246
2316
|
// src/hooks/usePush.ts
|
|
2247
|
-
import { useCallback as useCallback4, useEffect as
|
|
2317
|
+
import { useCallback as useCallback4, useEffect as useEffect9, useState as useState6 } from "react";
|
|
2248
2318
|
import { useHook as useHook7 } from "@hook-sdk/sdk";
|
|
2249
2319
|
var DISMISS_STORAGE_KEY = "push:dismissed-until";
|
|
2250
2320
|
var DISMISS_TTL_MS2 = 7 * 24 * 60 * 60 * 1e3;
|
|
@@ -2291,7 +2361,7 @@ function deriveState(push) {
|
|
|
2291
2361
|
function usePush() {
|
|
2292
2362
|
const { push } = useHook7();
|
|
2293
2363
|
const [state, setState] = useState6(() => deriveState(push));
|
|
2294
|
-
|
|
2364
|
+
useEffect9(() => {
|
|
2295
2365
|
setState(deriveState(push));
|
|
2296
2366
|
}, [push]);
|
|
2297
2367
|
const subscribe = useCallback4(async () => {
|
|
@@ -2328,7 +2398,7 @@ function usePush() {
|
|
|
2328
2398
|
}
|
|
2329
2399
|
|
|
2330
2400
|
// src/components/PushPrompt.tsx
|
|
2331
|
-
import { jsx as
|
|
2401
|
+
import { jsx as jsx22, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
2332
2402
|
function platformRecoveryCopy(texts) {
|
|
2333
2403
|
if (typeof navigator === "undefined") return null;
|
|
2334
2404
|
const ua = navigator.userAgent || "";
|
|
@@ -2352,27 +2422,27 @@ function PushPrompt2({ texts, onSubscribed, onDeclined, onInstallRequested, clas
|
|
|
2352
2422
|
if (state.kind === "subscribed" || state.kind === "dismissed") return null;
|
|
2353
2423
|
if (state.kind === "ios_needs_install") {
|
|
2354
2424
|
return /* @__PURE__ */ jsxs15("div", { className, role: "region", "aria-label": texts.iosInstallTitle, children: [
|
|
2355
|
-
/* @__PURE__ */
|
|
2356
|
-
/* @__PURE__ */
|
|
2357
|
-
onInstallRequested && texts.iosInstallCta && /* @__PURE__ */
|
|
2425
|
+
/* @__PURE__ */ jsx22("h3", { children: texts.iosInstallTitle }),
|
|
2426
|
+
/* @__PURE__ */ jsx22("p", { children: texts.iosInstallBody }),
|
|
2427
|
+
onInstallRequested && texts.iosInstallCta && /* @__PURE__ */ jsx22("button", { onClick: onInstallRequested, children: texts.iosInstallCta })
|
|
2358
2428
|
] });
|
|
2359
2429
|
}
|
|
2360
2430
|
if (state.kind === "denied") {
|
|
2361
2431
|
const recovery = platformRecoveryCopy(texts);
|
|
2362
2432
|
return /* @__PURE__ */ jsxs15("div", { className, role: "region", "aria-label": texts.deniedTitle, children: [
|
|
2363
|
-
/* @__PURE__ */
|
|
2364
|
-
/* @__PURE__ */
|
|
2365
|
-
recovery && /* @__PURE__ */
|
|
2433
|
+
/* @__PURE__ */ jsx22("h3", { children: texts.deniedTitle }),
|
|
2434
|
+
/* @__PURE__ */ jsx22("p", { children: texts.deniedBody }),
|
|
2435
|
+
recovery && /* @__PURE__ */ jsx22("p", { "data-testid": "denied-recovery", children: recovery })
|
|
2366
2436
|
] });
|
|
2367
2437
|
}
|
|
2368
2438
|
if (state.kind === "unsupported") {
|
|
2369
|
-
return /* @__PURE__ */
|
|
2439
|
+
return /* @__PURE__ */ jsx22("div", { className, role: "region", children: /* @__PURE__ */ jsx22("p", { children: texts.unsupportedBody }) });
|
|
2370
2440
|
}
|
|
2371
2441
|
if (state.kind === "error") {
|
|
2372
|
-
return /* @__PURE__ */
|
|
2442
|
+
return /* @__PURE__ */ jsx22("div", { className, role: "region", "aria-label": "error", children: /* @__PURE__ */ jsx22("p", { children: state.message }) });
|
|
2373
2443
|
}
|
|
2374
2444
|
return /* @__PURE__ */ jsxs15("div", { className, role: "region", children: [
|
|
2375
|
-
/* @__PURE__ */
|
|
2445
|
+
/* @__PURE__ */ jsx22(
|
|
2376
2446
|
"button",
|
|
2377
2447
|
{
|
|
2378
2448
|
type: "button",
|
|
@@ -2386,23 +2456,49 @@ function PushPrompt2({ texts, onSubscribed, onDeclined, onInstallRequested, clas
|
|
|
2386
2456
|
children: texts.cta
|
|
2387
2457
|
}
|
|
2388
2458
|
),
|
|
2389
|
-
onDeclined && /* @__PURE__ */
|
|
2459
|
+
onDeclined && /* @__PURE__ */ jsx22("button", { type: "button", onClick: onDeclined, children: texts.declineCta })
|
|
2460
|
+
] });
|
|
2461
|
+
}
|
|
2462
|
+
|
|
2463
|
+
// src/components/LanguageSwitcher.tsx
|
|
2464
|
+
import { usePersistedState as usePersistedState2 } from "@hook-sdk/sdk";
|
|
2465
|
+
import { jsx as jsx23, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
2466
|
+
function LanguageSwitcher({ id, className, label = "Language" }) {
|
|
2467
|
+
const config = useAppConfig();
|
|
2468
|
+
const i18nConfig = config.i18n;
|
|
2469
|
+
const [userLocale, setUserLocale] = usePersistedState2(
|
|
2470
|
+
"user-locale",
|
|
2471
|
+
i18nConfig?.defaultLocale ?? "en-US"
|
|
2472
|
+
);
|
|
2473
|
+
if (!i18nConfig) return null;
|
|
2474
|
+
return /* @__PURE__ */ jsxs16("label", { className, children: [
|
|
2475
|
+
label ? /* @__PURE__ */ jsx23("span", { children: label }) : null,
|
|
2476
|
+
/* @__PURE__ */ jsx23(
|
|
2477
|
+
"select",
|
|
2478
|
+
{
|
|
2479
|
+
id,
|
|
2480
|
+
value: userLocale,
|
|
2481
|
+
onChange: (e) => setUserLocale(e.target.value),
|
|
2482
|
+
"data-testid": "language-switcher",
|
|
2483
|
+
children: i18nConfig.supportedLocales.map((loc) => /* @__PURE__ */ jsx23("option", { value: loc, children: loc }, loc))
|
|
2484
|
+
}
|
|
2485
|
+
)
|
|
2390
2486
|
] });
|
|
2391
2487
|
}
|
|
2392
2488
|
|
|
2393
2489
|
// src/defaults/LoadingState.tsx
|
|
2394
|
-
import { jsx as
|
|
2490
|
+
import { jsx as jsx24 } from "react/jsx-runtime";
|
|
2395
2491
|
function LoadingState({ message }) {
|
|
2396
|
-
return /* @__PURE__ */
|
|
2492
|
+
return /* @__PURE__ */ jsx24("div", { role: "status", "aria-live": "polite", style: { padding: 24, textAlign: "center" }, children: /* @__PURE__ */ jsx24("span", { children: message ?? "Carregando..." }) });
|
|
2397
2493
|
}
|
|
2398
2494
|
|
|
2399
2495
|
// src/defaults/EmptyState.tsx
|
|
2400
|
-
import { jsx as
|
|
2496
|
+
import { jsx as jsx25, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
2401
2497
|
function EmptyState({ title, description, action }) {
|
|
2402
|
-
return /* @__PURE__ */
|
|
2403
|
-
/* @__PURE__ */
|
|
2404
|
-
description && /* @__PURE__ */
|
|
2405
|
-
action && /* @__PURE__ */
|
|
2498
|
+
return /* @__PURE__ */ jsxs17("div", { role: "status", style: { padding: 32, textAlign: "center" }, children: [
|
|
2499
|
+
/* @__PURE__ */ jsx25("h2", { style: { marginBottom: 8 }, children: title }),
|
|
2500
|
+
description && /* @__PURE__ */ jsx25("p", { style: { opacity: 0.7 }, children: description }),
|
|
2501
|
+
action && /* @__PURE__ */ jsx25("div", { style: { marginTop: 16 }, children: action })
|
|
2406
2502
|
] });
|
|
2407
2503
|
}
|
|
2408
2504
|
|
|
@@ -2619,7 +2715,7 @@ function useForgotForm() {
|
|
|
2619
2715
|
}
|
|
2620
2716
|
|
|
2621
2717
|
// src/hooks/useResetForm.ts
|
|
2622
|
-
import { useCallback as useCallback8, useEffect as
|
|
2718
|
+
import { useCallback as useCallback8, useEffect as useEffect10, useMemo as useMemo7, useState as useState10 } from "react";
|
|
2623
2719
|
import { useHook as useHook11 } from "@hook-sdk/sdk";
|
|
2624
2720
|
var MIN_PASSWORD3 = 12;
|
|
2625
2721
|
function useResetForm() {
|
|
@@ -2633,7 +2729,7 @@ function useResetForm() {
|
|
|
2633
2729
|
const [touchedPassword, setTouchedPassword] = useState10(false);
|
|
2634
2730
|
const [touchedConfirm, setTouchedConfirm] = useState10(false);
|
|
2635
2731
|
const [formSubmitAttempted, setFormSubmitAttempted] = useState10(false);
|
|
2636
|
-
|
|
2732
|
+
useEffect10(() => {
|
|
2637
2733
|
if (typeof window === "undefined") return;
|
|
2638
2734
|
const params = new URLSearchParams(window.location.search);
|
|
2639
2735
|
const t = params.get("token");
|
|
@@ -2727,12 +2823,12 @@ function discountPercent(anchorCents, realCents) {
|
|
|
2727
2823
|
}
|
|
2728
2824
|
|
|
2729
2825
|
// src/hooks/useAuthPrimitives.ts
|
|
2730
|
-
import { useEffect as
|
|
2826
|
+
import { useEffect as useEffect11 } from "react";
|
|
2731
2827
|
import { useHook as useHook13 } from "@hook-sdk/sdk";
|
|
2732
2828
|
var warned = false;
|
|
2733
2829
|
function useAuthPrimitives() {
|
|
2734
2830
|
const { auth } = useHook13();
|
|
2735
|
-
|
|
2831
|
+
useEffect11(() => {
|
|
2736
2832
|
if (!warned && process.env.NODE_ENV !== "production") {
|
|
2737
2833
|
warned = true;
|
|
2738
2834
|
console.warn(
|
|
@@ -2777,7 +2873,7 @@ function useSubscription() {
|
|
|
2777
2873
|
}
|
|
2778
2874
|
|
|
2779
2875
|
// src/hooks/useReminders.ts
|
|
2780
|
-
import { useCallback as useCallback9, useEffect as
|
|
2876
|
+
import { useCallback as useCallback9, useEffect as useEffect12, useState as useState11 } from "react";
|
|
2781
2877
|
import { useHook as useHook16 } from "@hook-sdk/sdk";
|
|
2782
2878
|
function useReminders() {
|
|
2783
2879
|
const { push } = useHook16();
|
|
@@ -2793,7 +2889,7 @@ function useReminders() {
|
|
|
2793
2889
|
setLoading(false);
|
|
2794
2890
|
}
|
|
2795
2891
|
}, [r]);
|
|
2796
|
-
|
|
2892
|
+
useEffect12(() => {
|
|
2797
2893
|
void reload();
|
|
2798
2894
|
}, [reload]);
|
|
2799
2895
|
const setReminder = useCallback9(async (input) => {
|
|
@@ -2832,20 +2928,20 @@ function useToast() {
|
|
|
2832
2928
|
|
|
2833
2929
|
// src/RouteBoundary.tsx
|
|
2834
2930
|
import { Routes as Routes2, Route as Route2 } from "react-router-dom";
|
|
2835
|
-
import { jsx as
|
|
2931
|
+
import { jsx as jsx26, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
2836
2932
|
function RouteBoundary({ children }) {
|
|
2837
|
-
return /* @__PURE__ */
|
|
2933
|
+
return /* @__PURE__ */ jsxs18(Routes2, { children: [
|
|
2838
2934
|
children,
|
|
2839
|
-
/* @__PURE__ */
|
|
2935
|
+
/* @__PURE__ */ jsx26(Route2, { path: "*", element: /* @__PURE__ */ jsx26(DefaultNotFound, {}) })
|
|
2840
2936
|
] });
|
|
2841
2937
|
}
|
|
2842
2938
|
function DefaultNotFound() {
|
|
2843
|
-
return /* @__PURE__ */
|
|
2939
|
+
return /* @__PURE__ */ jsx26("div", { role: "alert", children: "P\xE1gina n\xE3o encontrada" });
|
|
2844
2940
|
}
|
|
2845
2941
|
|
|
2846
2942
|
// src/PreAuthShell.tsx
|
|
2847
2943
|
import { BrowserRouter as BrowserRouter2, MemoryRouter as MemoryRouter2, Routes as Routes3 } from "react-router-dom";
|
|
2848
|
-
import { jsx as
|
|
2944
|
+
import { jsx as jsx27 } from "react/jsx-runtime";
|
|
2849
2945
|
function PreAuthShell({
|
|
2850
2946
|
basename,
|
|
2851
2947
|
testRouter,
|
|
@@ -2853,14 +2949,14 @@ function PreAuthShell({
|
|
|
2853
2949
|
children
|
|
2854
2950
|
}) {
|
|
2855
2951
|
if (testRouter === "memory") {
|
|
2856
|
-
return /* @__PURE__ */
|
|
2952
|
+
return /* @__PURE__ */ jsx27(MemoryRouter2, { basename, initialEntries: testInitialEntries, children: /* @__PURE__ */ jsx27(Routes3, { children }) });
|
|
2857
2953
|
}
|
|
2858
|
-
return /* @__PURE__ */
|
|
2954
|
+
return /* @__PURE__ */ jsx27(BrowserRouter2, { basename, children: /* @__PURE__ */ jsx27(Routes3, { children }) });
|
|
2859
2955
|
}
|
|
2860
2956
|
|
|
2861
2957
|
// src/OnboardingFlow.tsx
|
|
2862
|
-
import { useCallback as useCallback11, useEffect as
|
|
2863
|
-
import { usePersistedState, useHook as useHook17 } from "@hook-sdk/sdk";
|
|
2958
|
+
import { useCallback as useCallback11, useEffect as useEffect13, useMemo as useMemo8, useRef as useRef5 } from "react";
|
|
2959
|
+
import { usePersistedState as usePersistedState3, useHook as useHook17 } from "@hook-sdk/sdk";
|
|
2864
2960
|
|
|
2865
2961
|
// src/hooks/useOnboardingStep.ts
|
|
2866
2962
|
import { createContext as createContext3, useContext as useContext4 } from "react";
|
|
@@ -2876,7 +2972,7 @@ function useOnboardingStep() {
|
|
|
2876
2972
|
}
|
|
2877
2973
|
|
|
2878
2974
|
// src/OnboardingFlow.tsx
|
|
2879
|
-
import { jsx as
|
|
2975
|
+
import { jsx as jsx28 } from "react/jsx-runtime";
|
|
2880
2976
|
var isFilled = (v) => v != null && v !== "";
|
|
2881
2977
|
var CURRENT_STEP_FIELD = "currentStep";
|
|
2882
2978
|
function readPersistedStepIdx(draft) {
|
|
@@ -2889,7 +2985,7 @@ function OnboardingFlow({
|
|
|
2889
2985
|
onComplete,
|
|
2890
2986
|
persistKey
|
|
2891
2987
|
}) {
|
|
2892
|
-
const [draft, setDraft, status] =
|
|
2988
|
+
const [draft, setDraft, status] = usePersistedState3(persistKey, {});
|
|
2893
2989
|
const draftRef = useRef5(draft);
|
|
2894
2990
|
draftRef.current = draft;
|
|
2895
2991
|
const idx = readPersistedStepIdx(draft);
|
|
@@ -2914,7 +3010,7 @@ function OnboardingFlow({
|
|
|
2914
3010
|
const step = steps[clampedIdx];
|
|
2915
3011
|
const hookCtx = useHook17();
|
|
2916
3012
|
const track2 = typeof hookCtx.track === "function" ? hookCtx.track : void 0;
|
|
2917
|
-
|
|
3013
|
+
useEffect13(() => {
|
|
2918
3014
|
if (status.loading) return;
|
|
2919
3015
|
if (!step) return;
|
|
2920
3016
|
if (!track2) return;
|
|
@@ -2966,7 +3062,7 @@ function OnboardingFlow({
|
|
|
2966
3062
|
`[hook-template] OnboardingFlow: missing screen component for step '${step.id}' (expected key '${step.screen}' in screens prop)`
|
|
2967
3063
|
);
|
|
2968
3064
|
}
|
|
2969
|
-
return /* @__PURE__ */
|
|
3065
|
+
return /* @__PURE__ */ jsx28(OnboardingStepContext.Provider, { value: ctx, children: /* @__PURE__ */ jsx28(Screen, {}) });
|
|
2970
3066
|
}
|
|
2971
3067
|
|
|
2972
3068
|
// src/hooks/useFeature.ts
|
|
@@ -2981,8 +3077,10 @@ export {
|
|
|
2981
3077
|
DeepLinkHandler,
|
|
2982
3078
|
EmptyState,
|
|
2983
3079
|
ErrorBoundary,
|
|
3080
|
+
I18nProvider,
|
|
2984
3081
|
InstallGate,
|
|
2985
3082
|
InstallSplash,
|
|
3083
|
+
LanguageSwitcher,
|
|
2986
3084
|
LoadingState,
|
|
2987
3085
|
OnboardingFlow,
|
|
2988
3086
|
PaymentReturnHandler,
|