@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.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);
|
|
@@ -196,7 +213,16 @@ var MAP = {
|
|
|
196
213
|
pix_expired: "QR Code do PIX expirou. Gere um novo.",
|
|
197
214
|
pix_not_paid_yet: "PIX ainda n\xE3o foi pago. Aguardando confirma\xE7\xE3o."
|
|
198
215
|
};
|
|
199
|
-
function asaasErrorMessage(code) {
|
|
216
|
+
function asaasErrorMessage(code, description) {
|
|
217
|
+
if (description) {
|
|
218
|
+
const lower = description.toLowerCase();
|
|
219
|
+
if (lower.includes("cep")) {
|
|
220
|
+
return "Nosso processador de pagamentos n\xE3o reconheceu esse CEP \u2014 a base deles pode estar desatualizada. Tente outro CEP.";
|
|
221
|
+
}
|
|
222
|
+
if (lower.includes("telefone") || lower.includes("contato com ddd")) {
|
|
223
|
+
return "Telefone inv\xE1lido. Confira o n\xFAmero com DDD e tente novamente.";
|
|
224
|
+
}
|
|
225
|
+
}
|
|
200
226
|
return MAP[code] ?? "Ocorreu um erro inesperado. Tente novamente em instantes.";
|
|
201
227
|
}
|
|
202
228
|
|
|
@@ -325,7 +351,9 @@ function usePaywallState() {
|
|
|
325
351
|
(code, fallbackMessage) => ({
|
|
326
352
|
code,
|
|
327
353
|
message: fallbackMessage,
|
|
328
|
-
|
|
354
|
+
// fallbackMessage carries Asaas's PT-BR description ("O CEP informado é inválido.")
|
|
355
|
+
// that distinguishes invalid_holderInfo sub-cases (CEP vs phone vs name).
|
|
356
|
+
userMessage: useDefaultMessages ? asaasErrorMessage(code, fallbackMessage) : fallbackMessage
|
|
329
357
|
}),
|
|
330
358
|
[useDefaultMessages]
|
|
331
359
|
);
|
|
@@ -1800,9 +1828,9 @@ var bannerStyle = {
|
|
|
1800
1828
|
|
|
1801
1829
|
// src/components/InstallGate/InstallGate.tsx
|
|
1802
1830
|
import { Fragment as Fragment3, jsx as jsx16, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
1803
|
-
function InstallGate({ children }) {
|
|
1831
|
+
function InstallGate({ children, position }) {
|
|
1804
1832
|
const { slug, features_enabled } = useTemplateConfig();
|
|
1805
|
-
const enabled = features_enabled.includes("
|
|
1833
|
+
const enabled = features_enabled.includes("pwa-install");
|
|
1806
1834
|
const installState = useInstallPrompt(slug);
|
|
1807
1835
|
const shouldBlock = enabled && shouldBlockInstall(installState);
|
|
1808
1836
|
const trackedRef = useRef2(null);
|
|
@@ -1817,9 +1845,10 @@ function InstallGate({ children }) {
|
|
|
1817
1845
|
platform: installState.platform,
|
|
1818
1846
|
browser: installState.iosBrowser ?? installState.androidBrowser ?? null,
|
|
1819
1847
|
in_app_app: installState.inAppApp,
|
|
1820
|
-
variant: installState.variant
|
|
1848
|
+
variant: installState.variant,
|
|
1849
|
+
...position !== void 0 ? { position } : {}
|
|
1821
1850
|
});
|
|
1822
|
-
}, [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]);
|
|
1823
1852
|
if (!enabled) return /* @__PURE__ */ jsx16(Fragment3, { children });
|
|
1824
1853
|
if (installState.isInstalled) return /* @__PURE__ */ jsx16(Fragment3, { children });
|
|
1825
1854
|
if (installState.variant === "desktop") {
|
|
@@ -1942,10 +1971,47 @@ var ErrorBoundary = class extends Component {
|
|
|
1942
1971
|
}
|
|
1943
1972
|
};
|
|
1944
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
|
+
|
|
1945
2011
|
// src/internal/PaymentReturnHandler.tsx
|
|
1946
|
-
import { useCallback as useCallback3, useEffect as
|
|
2012
|
+
import { useCallback as useCallback3, useEffect as useEffect8, useRef as useRef4, useState as useState5 } from "react";
|
|
1947
2013
|
import { useHook as useHook5 } from "@hook-sdk/sdk";
|
|
1948
|
-
import { Fragment as Fragment5, jsx as
|
|
2014
|
+
import { Fragment as Fragment5, jsx as jsx20, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
1949
2015
|
var BACKOFF_MS = [2e3, 5e3, 1e4, 2e4, 4e4];
|
|
1950
2016
|
var MAX_CYCLES = 3;
|
|
1951
2017
|
var SUPPORT_MAILTO = "mailto:suporte@usehook.net?subject=Pagamento%20pendente";
|
|
@@ -1991,7 +2057,7 @@ function PaymentReturnHandler({ children }) {
|
|
|
1991
2057
|
};
|
|
1992
2058
|
void tick();
|
|
1993
2059
|
}, []);
|
|
1994
|
-
|
|
2060
|
+
useEffect8(() => {
|
|
1995
2061
|
if (typeof window === "undefined") return;
|
|
1996
2062
|
const url = new URL(window.location.href);
|
|
1997
2063
|
if (url.searchParams.get("paymentReturn") !== "1") return;
|
|
@@ -2008,19 +2074,19 @@ function PaymentReturnHandler({ children }) {
|
|
|
2008
2074
|
window.location.href = cleanUrl.toString();
|
|
2009
2075
|
}, []);
|
|
2010
2076
|
if (state === "confirming") {
|
|
2011
|
-
return /* @__PURE__ */
|
|
2077
|
+
return /* @__PURE__ */ jsx20("div", { role: "status", "aria-live": "polite", style: overlayStyle2, children: "Confirmando pagamento\u2026" });
|
|
2012
2078
|
}
|
|
2013
2079
|
if (state === "waiting") {
|
|
2014
|
-
return /* @__PURE__ */
|
|
2015
|
-
/* @__PURE__ */
|
|
2016
|
-
/* @__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" })
|
|
2017
2083
|
] }) });
|
|
2018
2084
|
}
|
|
2019
2085
|
if (state === "timeout") {
|
|
2020
|
-
return /* @__PURE__ */
|
|
2021
|
-
/* @__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." }),
|
|
2022
2088
|
/* @__PURE__ */ jsxs13("div", { style: { display: "flex", flexDirection: "column", gap: 8 }, children: [
|
|
2023
|
-
/* @__PURE__ */
|
|
2089
|
+
/* @__PURE__ */ jsx20(
|
|
2024
2090
|
"button",
|
|
2025
2091
|
{
|
|
2026
2092
|
type: "button",
|
|
@@ -2033,7 +2099,7 @@ function PaymentReturnHandler({ children }) {
|
|
|
2033
2099
|
children: "Tentar de novo"
|
|
2034
2100
|
}
|
|
2035
2101
|
),
|
|
2036
|
-
/* @__PURE__ */
|
|
2102
|
+
/* @__PURE__ */ jsx20(
|
|
2037
2103
|
"button",
|
|
2038
2104
|
{
|
|
2039
2105
|
type: "button",
|
|
@@ -2043,7 +2109,7 @@ function PaymentReturnHandler({ children }) {
|
|
|
2043
2109
|
children: "Voltar pro app"
|
|
2044
2110
|
}
|
|
2045
2111
|
),
|
|
2046
|
-
/* @__PURE__ */
|
|
2112
|
+
/* @__PURE__ */ jsx20(
|
|
2047
2113
|
"a",
|
|
2048
2114
|
{
|
|
2049
2115
|
href: SUPPORT_MAILTO,
|
|
@@ -2055,7 +2121,7 @@ function PaymentReturnHandler({ children }) {
|
|
|
2055
2121
|
] })
|
|
2056
2122
|
] }) });
|
|
2057
2123
|
}
|
|
2058
|
-
return /* @__PURE__ */
|
|
2124
|
+
return /* @__PURE__ */ jsx20(Fragment5, { children });
|
|
2059
2125
|
}
|
|
2060
2126
|
var overlayStyle2 = {
|
|
2061
2127
|
position: "fixed",
|
|
@@ -2094,7 +2160,7 @@ var linkStyle = {
|
|
|
2094
2160
|
};
|
|
2095
2161
|
|
|
2096
2162
|
// src/AppRoot.tsx
|
|
2097
|
-
import { Fragment as Fragment6, jsx as
|
|
2163
|
+
import { Fragment as Fragment6, jsx as jsx21, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
2098
2164
|
function buildLegacyConfigShim(config) {
|
|
2099
2165
|
const paywall = config.paywall;
|
|
2100
2166
|
const isFree = paywall.mode === "free";
|
|
@@ -2171,28 +2237,43 @@ function AppRoot(props) {
|
|
|
2171
2237
|
const Router = testRouter === "memory" ? MemoryRouter : BrowserRouter;
|
|
2172
2238
|
const basename = `/app/${config.slug}`;
|
|
2173
2239
|
const routerProps = testRouter === "memory" ? { basename, initialEntries: testInitialEntries } : { basename };
|
|
2174
|
-
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
/* @__PURE__ */
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
-
|
|
2188
|
-
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
|
|
2195
|
-
|
|
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 }) }) }) }) });
|
|
2196
2277
|
}
|
|
2197
2278
|
function AuthGated({
|
|
2198
2279
|
children,
|
|
@@ -2209,31 +2290,31 @@ function AuthGated({
|
|
|
2209
2290
|
if (authStatus !== "authenticated") {
|
|
2210
2291
|
if (config.onboarding?.trigger === "pre_signup_custom" && PreAuthFlow) {
|
|
2211
2292
|
return /* @__PURE__ */ jsxs14(Routes, { children: [
|
|
2212
|
-
/* @__PURE__ */
|
|
2213
|
-
/* @__PURE__ */
|
|
2214
|
-
/* @__PURE__ */
|
|
2215
|
-
/* @__PURE__ */
|
|
2216
|
-
EmailVerify ? /* @__PURE__ */
|
|
2217
|
-
/* @__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, {}) })
|
|
2218
2299
|
] });
|
|
2219
2300
|
}
|
|
2220
2301
|
return /* @__PURE__ */ jsxs14(Routes, { children: [
|
|
2221
|
-
/* @__PURE__ */
|
|
2222
|
-
/* @__PURE__ */
|
|
2223
|
-
/* @__PURE__ */
|
|
2224
|
-
/* @__PURE__ */
|
|
2225
|
-
EmailVerify ? /* @__PURE__ */
|
|
2226
|
-
/* @__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 }) })
|
|
2227
2308
|
] });
|
|
2228
2309
|
}
|
|
2229
|
-
return /* @__PURE__ */
|
|
2310
|
+
return /* @__PURE__ */ jsx21(Fragment6, { children });
|
|
2230
2311
|
}
|
|
2231
2312
|
function FallbackPaywall() {
|
|
2232
2313
|
return null;
|
|
2233
2314
|
}
|
|
2234
2315
|
|
|
2235
2316
|
// src/hooks/usePush.ts
|
|
2236
|
-
import { useCallback as useCallback4, useEffect as
|
|
2317
|
+
import { useCallback as useCallback4, useEffect as useEffect9, useState as useState6 } from "react";
|
|
2237
2318
|
import { useHook as useHook7 } from "@hook-sdk/sdk";
|
|
2238
2319
|
var DISMISS_STORAGE_KEY = "push:dismissed-until";
|
|
2239
2320
|
var DISMISS_TTL_MS2 = 7 * 24 * 60 * 60 * 1e3;
|
|
@@ -2280,7 +2361,7 @@ function deriveState(push) {
|
|
|
2280
2361
|
function usePush() {
|
|
2281
2362
|
const { push } = useHook7();
|
|
2282
2363
|
const [state, setState] = useState6(() => deriveState(push));
|
|
2283
|
-
|
|
2364
|
+
useEffect9(() => {
|
|
2284
2365
|
setState(deriveState(push));
|
|
2285
2366
|
}, [push]);
|
|
2286
2367
|
const subscribe = useCallback4(async () => {
|
|
@@ -2317,7 +2398,7 @@ function usePush() {
|
|
|
2317
2398
|
}
|
|
2318
2399
|
|
|
2319
2400
|
// src/components/PushPrompt.tsx
|
|
2320
|
-
import { jsx as
|
|
2401
|
+
import { jsx as jsx22, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
2321
2402
|
function platformRecoveryCopy(texts) {
|
|
2322
2403
|
if (typeof navigator === "undefined") return null;
|
|
2323
2404
|
const ua = navigator.userAgent || "";
|
|
@@ -2341,27 +2422,27 @@ function PushPrompt2({ texts, onSubscribed, onDeclined, onInstallRequested, clas
|
|
|
2341
2422
|
if (state.kind === "subscribed" || state.kind === "dismissed") return null;
|
|
2342
2423
|
if (state.kind === "ios_needs_install") {
|
|
2343
2424
|
return /* @__PURE__ */ jsxs15("div", { className, role: "region", "aria-label": texts.iosInstallTitle, children: [
|
|
2344
|
-
/* @__PURE__ */
|
|
2345
|
-
/* @__PURE__ */
|
|
2346
|
-
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 })
|
|
2347
2428
|
] });
|
|
2348
2429
|
}
|
|
2349
2430
|
if (state.kind === "denied") {
|
|
2350
2431
|
const recovery = platformRecoveryCopy(texts);
|
|
2351
2432
|
return /* @__PURE__ */ jsxs15("div", { className, role: "region", "aria-label": texts.deniedTitle, children: [
|
|
2352
|
-
/* @__PURE__ */
|
|
2353
|
-
/* @__PURE__ */
|
|
2354
|
-
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 })
|
|
2355
2436
|
] });
|
|
2356
2437
|
}
|
|
2357
2438
|
if (state.kind === "unsupported") {
|
|
2358
|
-
return /* @__PURE__ */
|
|
2439
|
+
return /* @__PURE__ */ jsx22("div", { className, role: "region", children: /* @__PURE__ */ jsx22("p", { children: texts.unsupportedBody }) });
|
|
2359
2440
|
}
|
|
2360
2441
|
if (state.kind === "error") {
|
|
2361
|
-
return /* @__PURE__ */
|
|
2442
|
+
return /* @__PURE__ */ jsx22("div", { className, role: "region", "aria-label": "error", children: /* @__PURE__ */ jsx22("p", { children: state.message }) });
|
|
2362
2443
|
}
|
|
2363
2444
|
return /* @__PURE__ */ jsxs15("div", { className, role: "region", children: [
|
|
2364
|
-
/* @__PURE__ */
|
|
2445
|
+
/* @__PURE__ */ jsx22(
|
|
2365
2446
|
"button",
|
|
2366
2447
|
{
|
|
2367
2448
|
type: "button",
|
|
@@ -2375,23 +2456,49 @@ function PushPrompt2({ texts, onSubscribed, onDeclined, onInstallRequested, clas
|
|
|
2375
2456
|
children: texts.cta
|
|
2376
2457
|
}
|
|
2377
2458
|
),
|
|
2378
|
-
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
|
+
)
|
|
2379
2486
|
] });
|
|
2380
2487
|
}
|
|
2381
2488
|
|
|
2382
2489
|
// src/defaults/LoadingState.tsx
|
|
2383
|
-
import { jsx as
|
|
2490
|
+
import { jsx as jsx24 } from "react/jsx-runtime";
|
|
2384
2491
|
function LoadingState({ message }) {
|
|
2385
|
-
return /* @__PURE__ */
|
|
2492
|
+
return /* @__PURE__ */ jsx24("div", { role: "status", "aria-live": "polite", style: { padding: 24, textAlign: "center" }, children: /* @__PURE__ */ jsx24("span", { children: message ?? "Carregando..." }) });
|
|
2386
2493
|
}
|
|
2387
2494
|
|
|
2388
2495
|
// src/defaults/EmptyState.tsx
|
|
2389
|
-
import { jsx as
|
|
2496
|
+
import { jsx as jsx25, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
2390
2497
|
function EmptyState({ title, description, action }) {
|
|
2391
|
-
return /* @__PURE__ */
|
|
2392
|
-
/* @__PURE__ */
|
|
2393
|
-
description && /* @__PURE__ */
|
|
2394
|
-
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 })
|
|
2395
2502
|
] });
|
|
2396
2503
|
}
|
|
2397
2504
|
|
|
@@ -2608,7 +2715,7 @@ function useForgotForm() {
|
|
|
2608
2715
|
}
|
|
2609
2716
|
|
|
2610
2717
|
// src/hooks/useResetForm.ts
|
|
2611
|
-
import { useCallback as useCallback8, useEffect as
|
|
2718
|
+
import { useCallback as useCallback8, useEffect as useEffect10, useMemo as useMemo7, useState as useState10 } from "react";
|
|
2612
2719
|
import { useHook as useHook11 } from "@hook-sdk/sdk";
|
|
2613
2720
|
var MIN_PASSWORD3 = 12;
|
|
2614
2721
|
function useResetForm() {
|
|
@@ -2622,7 +2729,7 @@ function useResetForm() {
|
|
|
2622
2729
|
const [touchedPassword, setTouchedPassword] = useState10(false);
|
|
2623
2730
|
const [touchedConfirm, setTouchedConfirm] = useState10(false);
|
|
2624
2731
|
const [formSubmitAttempted, setFormSubmitAttempted] = useState10(false);
|
|
2625
|
-
|
|
2732
|
+
useEffect10(() => {
|
|
2626
2733
|
if (typeof window === "undefined") return;
|
|
2627
2734
|
const params = new URLSearchParams(window.location.search);
|
|
2628
2735
|
const t = params.get("token");
|
|
@@ -2716,12 +2823,12 @@ function discountPercent(anchorCents, realCents) {
|
|
|
2716
2823
|
}
|
|
2717
2824
|
|
|
2718
2825
|
// src/hooks/useAuthPrimitives.ts
|
|
2719
|
-
import { useEffect as
|
|
2826
|
+
import { useEffect as useEffect11 } from "react";
|
|
2720
2827
|
import { useHook as useHook13 } from "@hook-sdk/sdk";
|
|
2721
2828
|
var warned = false;
|
|
2722
2829
|
function useAuthPrimitives() {
|
|
2723
2830
|
const { auth } = useHook13();
|
|
2724
|
-
|
|
2831
|
+
useEffect11(() => {
|
|
2725
2832
|
if (!warned && process.env.NODE_ENV !== "production") {
|
|
2726
2833
|
warned = true;
|
|
2727
2834
|
console.warn(
|
|
@@ -2766,7 +2873,7 @@ function useSubscription() {
|
|
|
2766
2873
|
}
|
|
2767
2874
|
|
|
2768
2875
|
// src/hooks/useReminders.ts
|
|
2769
|
-
import { useCallback as useCallback9, useEffect as
|
|
2876
|
+
import { useCallback as useCallback9, useEffect as useEffect12, useState as useState11 } from "react";
|
|
2770
2877
|
import { useHook as useHook16 } from "@hook-sdk/sdk";
|
|
2771
2878
|
function useReminders() {
|
|
2772
2879
|
const { push } = useHook16();
|
|
@@ -2782,7 +2889,7 @@ function useReminders() {
|
|
|
2782
2889
|
setLoading(false);
|
|
2783
2890
|
}
|
|
2784
2891
|
}, [r]);
|
|
2785
|
-
|
|
2892
|
+
useEffect12(() => {
|
|
2786
2893
|
void reload();
|
|
2787
2894
|
}, [reload]);
|
|
2788
2895
|
const setReminder = useCallback9(async (input) => {
|
|
@@ -2821,20 +2928,20 @@ function useToast() {
|
|
|
2821
2928
|
|
|
2822
2929
|
// src/RouteBoundary.tsx
|
|
2823
2930
|
import { Routes as Routes2, Route as Route2 } from "react-router-dom";
|
|
2824
|
-
import { jsx as
|
|
2931
|
+
import { jsx as jsx26, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
2825
2932
|
function RouteBoundary({ children }) {
|
|
2826
|
-
return /* @__PURE__ */
|
|
2933
|
+
return /* @__PURE__ */ jsxs18(Routes2, { children: [
|
|
2827
2934
|
children,
|
|
2828
|
-
/* @__PURE__ */
|
|
2935
|
+
/* @__PURE__ */ jsx26(Route2, { path: "*", element: /* @__PURE__ */ jsx26(DefaultNotFound, {}) })
|
|
2829
2936
|
] });
|
|
2830
2937
|
}
|
|
2831
2938
|
function DefaultNotFound() {
|
|
2832
|
-
return /* @__PURE__ */
|
|
2939
|
+
return /* @__PURE__ */ jsx26("div", { role: "alert", children: "P\xE1gina n\xE3o encontrada" });
|
|
2833
2940
|
}
|
|
2834
2941
|
|
|
2835
2942
|
// src/PreAuthShell.tsx
|
|
2836
2943
|
import { BrowserRouter as BrowserRouter2, MemoryRouter as MemoryRouter2, Routes as Routes3 } from "react-router-dom";
|
|
2837
|
-
import { jsx as
|
|
2944
|
+
import { jsx as jsx27 } from "react/jsx-runtime";
|
|
2838
2945
|
function PreAuthShell({
|
|
2839
2946
|
basename,
|
|
2840
2947
|
testRouter,
|
|
@@ -2842,14 +2949,14 @@ function PreAuthShell({
|
|
|
2842
2949
|
children
|
|
2843
2950
|
}) {
|
|
2844
2951
|
if (testRouter === "memory") {
|
|
2845
|
-
return /* @__PURE__ */
|
|
2952
|
+
return /* @__PURE__ */ jsx27(MemoryRouter2, { basename, initialEntries: testInitialEntries, children: /* @__PURE__ */ jsx27(Routes3, { children }) });
|
|
2846
2953
|
}
|
|
2847
|
-
return /* @__PURE__ */
|
|
2954
|
+
return /* @__PURE__ */ jsx27(BrowserRouter2, { basename, children: /* @__PURE__ */ jsx27(Routes3, { children }) });
|
|
2848
2955
|
}
|
|
2849
2956
|
|
|
2850
2957
|
// src/OnboardingFlow.tsx
|
|
2851
|
-
import { useCallback as useCallback11, useEffect as
|
|
2852
|
-
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";
|
|
2853
2960
|
|
|
2854
2961
|
// src/hooks/useOnboardingStep.ts
|
|
2855
2962
|
import { createContext as createContext3, useContext as useContext4 } from "react";
|
|
@@ -2865,7 +2972,7 @@ function useOnboardingStep() {
|
|
|
2865
2972
|
}
|
|
2866
2973
|
|
|
2867
2974
|
// src/OnboardingFlow.tsx
|
|
2868
|
-
import { jsx as
|
|
2975
|
+
import { jsx as jsx28 } from "react/jsx-runtime";
|
|
2869
2976
|
var isFilled = (v) => v != null && v !== "";
|
|
2870
2977
|
var CURRENT_STEP_FIELD = "currentStep";
|
|
2871
2978
|
function readPersistedStepIdx(draft) {
|
|
@@ -2878,7 +2985,7 @@ function OnboardingFlow({
|
|
|
2878
2985
|
onComplete,
|
|
2879
2986
|
persistKey
|
|
2880
2987
|
}) {
|
|
2881
|
-
const [draft, setDraft, status] =
|
|
2988
|
+
const [draft, setDraft, status] = usePersistedState3(persistKey, {});
|
|
2882
2989
|
const draftRef = useRef5(draft);
|
|
2883
2990
|
draftRef.current = draft;
|
|
2884
2991
|
const idx = readPersistedStepIdx(draft);
|
|
@@ -2903,7 +3010,7 @@ function OnboardingFlow({
|
|
|
2903
3010
|
const step = steps[clampedIdx];
|
|
2904
3011
|
const hookCtx = useHook17();
|
|
2905
3012
|
const track2 = typeof hookCtx.track === "function" ? hookCtx.track : void 0;
|
|
2906
|
-
|
|
3013
|
+
useEffect13(() => {
|
|
2907
3014
|
if (status.loading) return;
|
|
2908
3015
|
if (!step) return;
|
|
2909
3016
|
if (!track2) return;
|
|
@@ -2955,7 +3062,7 @@ function OnboardingFlow({
|
|
|
2955
3062
|
`[hook-template] OnboardingFlow: missing screen component for step '${step.id}' (expected key '${step.screen}' in screens prop)`
|
|
2956
3063
|
);
|
|
2957
3064
|
}
|
|
2958
|
-
return /* @__PURE__ */
|
|
3065
|
+
return /* @__PURE__ */ jsx28(OnboardingStepContext.Provider, { value: ctx, children: /* @__PURE__ */ jsx28(Screen, {}) });
|
|
2959
3066
|
}
|
|
2960
3067
|
|
|
2961
3068
|
// src/hooks/useFeature.ts
|
|
@@ -2970,8 +3077,10 @@ export {
|
|
|
2970
3077
|
DeepLinkHandler,
|
|
2971
3078
|
EmptyState,
|
|
2972
3079
|
ErrorBoundary,
|
|
3080
|
+
I18nProvider,
|
|
2973
3081
|
InstallGate,
|
|
2974
3082
|
InstallSplash,
|
|
3083
|
+
LanguageSwitcher,
|
|
2975
3084
|
LoadingState,
|
|
2976
3085
|
OnboardingFlow,
|
|
2977
3086
|
PaymentReturnHandler,
|