@hook-sdk/template 0.12.0 → 0.14.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 CHANGED
@@ -69,9 +69,9 @@ __export(index_exports, {
69
69
  module.exports = __toCommonJS(index_exports);
70
70
 
71
71
  // src/AppRoot.tsx
72
- var import_react11 = require("react");
72
+ var import_react12 = require("react");
73
73
  var import_react_router_dom2 = require("react-router-dom");
74
- var import_sdk4 = require("@hook-sdk/sdk");
74
+ var import_sdk5 = require("@hook-sdk/sdk");
75
75
 
76
76
  // src/config/AppConfigContext.tsx
77
77
  var import_react = require("react");
@@ -1826,10 +1826,69 @@ function PushPrompt() {
1826
1826
  return null;
1827
1827
  }
1828
1828
 
1829
- // src/defaults/ErrorBoundary.tsx
1829
+ // src/internal/SessionExpiredBanner.tsx
1830
1830
  var import_react9 = require("react");
1831
+ var import_sdk3 = require("@hook-sdk/sdk");
1831
1832
  var import_jsx_runtime16 = require("react/jsx-runtime");
1832
- var ErrorBoundary = class extends import_react9.Component {
1833
+ var DISMISS_KEY = "hook:session-expired-dismissed-until";
1834
+ var DISMISS_TTL_MS = 60 * 60 * 1e3;
1835
+ function SessionExpiredBanner() {
1836
+ const { authStatus } = (0, import_sdk3.useHook)();
1837
+ const wasAuthRef = (0, import_react9.useRef)(false);
1838
+ const [show, setShow] = (0, import_react9.useState)(false);
1839
+ (0, import_react9.useEffect)(() => {
1840
+ if (authStatus === "authenticated") {
1841
+ wasAuthRef.current = true;
1842
+ setShow(false);
1843
+ return;
1844
+ }
1845
+ if (authStatus === "anonymous" && wasAuthRef.current) {
1846
+ const until = Number(localStorage.getItem(DISMISS_KEY) ?? "0");
1847
+ if (Date.now() < until) {
1848
+ setShow(false);
1849
+ return;
1850
+ }
1851
+ setShow(true);
1852
+ }
1853
+ }, [authStatus]);
1854
+ if (!show) return null;
1855
+ function dismiss() {
1856
+ localStorage.setItem(DISMISS_KEY, String(Date.now() + DISMISS_TTL_MS));
1857
+ setShow(false);
1858
+ }
1859
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { role: "alert", className: "fixed top-0 inset-x-0 bg-red-600 text-white px-4 py-2 flex items-center justify-between gap-3 text-sm shadow", style: { zIndex: 10001 }, children: [
1860
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("span", { children: [
1861
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("strong", { children: "Sua sess\xE3o expirou." }),
1862
+ " Fa\xE7a login novamente para continuar."
1863
+ ] }),
1864
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "flex items-center gap-2", children: [
1865
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
1866
+ "button",
1867
+ {
1868
+ type: "button",
1869
+ onClick: dismiss,
1870
+ className: "px-3 py-1 bg-white text-red-700 rounded text-xs font-medium hover:bg-red-50",
1871
+ children: "Fazer login"
1872
+ }
1873
+ ),
1874
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
1875
+ "button",
1876
+ {
1877
+ type: "button",
1878
+ onClick: dismiss,
1879
+ "aria-label": "Fechar",
1880
+ className: "px-2 py-1 text-white/80 hover:text-white text-xs",
1881
+ children: "Fechar"
1882
+ }
1883
+ )
1884
+ ] })
1885
+ ] });
1886
+ }
1887
+
1888
+ // src/defaults/ErrorBoundary.tsx
1889
+ var import_react10 = require("react");
1890
+ var import_jsx_runtime17 = require("react/jsx-runtime");
1891
+ var ErrorBoundary = class extends import_react10.Component {
1833
1892
  state = { error: null };
1834
1893
  static getDerivedStateFromError(error) {
1835
1894
  return { error };
@@ -1846,28 +1905,32 @@ var ErrorBoundary = class extends import_react9.Component {
1846
1905
  }
1847
1906
  render() {
1848
1907
  if (this.state.error) {
1849
- return this.props.fallback ?? /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { role: "alert", style: { padding: 24, textAlign: "center" }, children: [
1850
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("h2", { children: "Algo deu errado" }),
1851
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("p", { style: { opacity: 0.7 }, children: "Recarregue a p\xE1gina pra tentar de novo." })
1908
+ return this.props.fallback ?? /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { role: "alert", style: { padding: 24, textAlign: "center" }, children: [
1909
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("h2", { children: "Algo deu errado" }),
1910
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("p", { style: { opacity: 0.7 }, children: "Recarregue a p\xE1gina pra tentar de novo." })
1852
1911
  ] });
1853
1912
  }
1854
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_jsx_runtime16.Fragment, { children: this.props.children });
1913
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_jsx_runtime17.Fragment, { children: this.props.children });
1855
1914
  }
1856
1915
  };
1857
1916
 
1858
1917
  // src/internal/PaymentReturnHandler.tsx
1859
- var import_react10 = require("react");
1860
- var import_sdk3 = require("@hook-sdk/sdk");
1861
- var import_jsx_runtime17 = require("react/jsx-runtime");
1918
+ var import_react11 = require("react");
1919
+ var import_sdk4 = require("@hook-sdk/sdk");
1920
+ var import_jsx_runtime18 = require("react/jsx-runtime");
1862
1921
  var BACKOFF_MS = [2e3, 5e3, 1e4, 2e4, 4e4];
1922
+ var MAX_CYCLES = 3;
1923
+ var SUPPORT_MAILTO = "mailto:suporte@usehook.net?subject=Pagamento%20pendente";
1863
1924
  function PaymentReturnHandler({ children }) {
1864
- const { subscription } = (0, import_sdk3.useHook)();
1865
- const subRef = (0, import_react10.useRef)(subscription);
1925
+ const { subscription } = (0, import_sdk4.useHook)();
1926
+ const subRef = (0, import_react11.useRef)(subscription);
1866
1927
  subRef.current = subscription;
1867
- const runIdRef = (0, import_react10.useRef)(0);
1868
- const [state, setState] = (0, import_react10.useState)("idle");
1869
- const runPoll = (0, import_react10.useCallback)(() => {
1928
+ const runIdRef = (0, import_react11.useRef)(0);
1929
+ const cyclesRef = (0, import_react11.useRef)(0);
1930
+ const [state, setState] = (0, import_react11.useState)("idle");
1931
+ const runPoll = (0, import_react11.useCallback)(() => {
1870
1932
  const runId = ++runIdRef.current;
1933
+ cyclesRef.current += 1;
1871
1934
  setState("confirming");
1872
1935
  let attempts = 0;
1873
1936
  const tick = async () => {
@@ -1883,37 +1946,88 @@ function PaymentReturnHandler({ children }) {
1883
1946
  const cleanUrl = new URL(window.location.href);
1884
1947
  cleanUrl.searchParams.delete("paymentReturn");
1885
1948
  window.history.replaceState({}, "", cleanUrl.toString());
1949
+ cyclesRef.current = 0;
1886
1950
  setState("idle");
1887
1951
  return;
1888
1952
  }
1889
1953
  const delay = BACKOFF_MS[attempts - 1];
1890
1954
  if (delay === void 0) {
1891
- setState("waiting");
1955
+ if (cyclesRef.current >= MAX_CYCLES) {
1956
+ setState("timeout");
1957
+ } else {
1958
+ setState("waiting");
1959
+ }
1892
1960
  return;
1893
1961
  }
1894
1962
  setTimeout(tick, delay);
1895
1963
  };
1896
1964
  void tick();
1897
1965
  }, []);
1898
- (0, import_react10.useEffect)(() => {
1966
+ (0, import_react11.useEffect)(() => {
1899
1967
  if (typeof window === "undefined") return;
1900
1968
  const url = new URL(window.location.href);
1901
1969
  if (url.searchParams.get("paymentReturn") !== "1") return;
1970
+ cyclesRef.current = 0;
1902
1971
  runPoll();
1903
1972
  return () => {
1904
1973
  runIdRef.current++;
1905
1974
  };
1906
1975
  }, [runPoll]);
1976
+ const goHome = (0, import_react11.useCallback)(() => {
1977
+ const cleanUrl = new URL(window.location.href);
1978
+ cleanUrl.searchParams.delete("paymentReturn");
1979
+ cleanUrl.pathname = "/app/home";
1980
+ window.location.href = cleanUrl.toString();
1981
+ }, []);
1907
1982
  if (state === "confirming") {
1908
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { role: "status", "aria-live": "polite", style: overlayStyle2, children: "Confirmando pagamento\u2026" });
1983
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { role: "status", "aria-live": "polite", style: overlayStyle2, children: "Confirmando pagamento\u2026" });
1909
1984
  }
1910
1985
  if (state === "waiting") {
1911
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { role: "status", "aria-live": "polite", style: overlayStyle2, children: /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { style: { maxWidth: 320, textAlign: "center", lineHeight: 1.5 }, children: [
1912
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { style: { marginBottom: 16 }, children: "Pagamento aceito. Estamos confirmando com o banco \u2014 pode levar alguns minutos." }),
1913
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("button", { type: "button", onClick: runPoll, style: buttonStyle, children: "Atualizar" })
1986
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { role: "status", "aria-live": "polite", style: overlayStyle2, children: /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { style: { maxWidth: 320, textAlign: "center", lineHeight: 1.5 }, children: [
1987
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: { marginBottom: 16 }, children: "Pagamento aceito. Estamos confirmando com o banco \u2014 pode levar alguns minutos." }),
1988
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("button", { type: "button", onClick: runPoll, style: buttonStyle, children: "Atualizar" })
1989
+ ] }) });
1990
+ }
1991
+ if (state === "timeout") {
1992
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { role: "alert", "aria-live": "assertive", style: overlayStyle2, children: /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { style: { maxWidth: 360, textAlign: "center", lineHeight: 1.5 }, children: [
1993
+ /* @__PURE__ */ (0, import_jsx_runtime18.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." }),
1994
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: 8 }, children: [
1995
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
1996
+ "button",
1997
+ {
1998
+ type: "button",
1999
+ onClick: () => {
2000
+ cyclesRef.current = 0;
2001
+ runPoll();
2002
+ },
2003
+ style: buttonStyle,
2004
+ "data-testid": "payment-timeout-retry",
2005
+ children: "Tentar de novo"
2006
+ }
2007
+ ),
2008
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
2009
+ "button",
2010
+ {
2011
+ type: "button",
2012
+ onClick: goHome,
2013
+ style: secondaryButtonStyle,
2014
+ "data-testid": "payment-timeout-home",
2015
+ children: "Voltar pro app"
2016
+ }
2017
+ ),
2018
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
2019
+ "a",
2020
+ {
2021
+ href: SUPPORT_MAILTO,
2022
+ style: linkStyle,
2023
+ "data-testid": "payment-timeout-support",
2024
+ children: "Falar com suporte"
2025
+ }
2026
+ )
2027
+ ] })
1914
2028
  ] }) });
1915
2029
  }
1916
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_jsx_runtime17.Fragment, { children });
2030
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_jsx_runtime18.Fragment, { children });
1917
2031
  }
1918
2032
  var overlayStyle2 = {
1919
2033
  position: "fixed",
@@ -1937,9 +2051,22 @@ var buttonStyle = {
1937
2051
  fontWeight: 600,
1938
2052
  cursor: "pointer"
1939
2053
  };
2054
+ var secondaryButtonStyle = {
2055
+ ...buttonStyle,
2056
+ background: "transparent",
2057
+ color: "white",
2058
+ border: "1px solid rgba(255,255,255,0.5)"
2059
+ };
2060
+ var linkStyle = {
2061
+ color: "white",
2062
+ textDecoration: "underline",
2063
+ fontSize: "0.9rem",
2064
+ marginTop: 4,
2065
+ textAlign: "center"
2066
+ };
1940
2067
 
1941
2068
  // src/AppRoot.tsx
1942
- var import_jsx_runtime18 = require("react/jsx-runtime");
2069
+ var import_jsx_runtime19 = require("react/jsx-runtime");
1943
2070
  function buildLegacyConfigShim(config) {
1944
2071
  const paywall = config.paywall;
1945
2072
  const isFree = paywall.mode === "free";
@@ -2003,13 +2130,14 @@ function AppRoot(props) {
2003
2130
  "[hook-template] <AppRoot>: PreAuthFlow slot prop is required when config.onboarding.trigger === 'pre_signup_custom'."
2004
2131
  );
2005
2132
  }
2006
- const legacyShim = (0, import_react11.useMemo)(() => buildLegacyConfigShim(config), [config]);
2133
+ const legacyShim = (0, import_react12.useMemo)(() => buildLegacyConfigShim(config), [config]);
2007
2134
  const Router = testRouter === "memory" ? import_react_router_dom2.MemoryRouter : import_react_router_dom2.BrowserRouter;
2008
2135
  const basename = `/app/${config.slug}`;
2009
2136
  const routerProps = testRouter === "memory" ? { basename, initialEntries: testInitialEntries } : { basename };
2010
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(ErrorBoundary, { children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(AppConfigProvider, { config, children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(TemplateConfigProvider, { config: legacyShim, children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(ThemeProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(PersistenceRegistry, { config: config.persistedKeys, children: /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(Router, { ...routerProps, children: [
2011
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(DeepLinkHandler, { deepLinks: config.deepLinks }),
2012
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(InstallGate, { children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
2137
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(ErrorBoundary, { children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(AppConfigProvider, { config, children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(TemplateConfigProvider, { config: legacyShim, children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(ThemeProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(PersistenceRegistry, { config: config.persistedKeys, children: /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(Router, { ...routerProps, children: [
2138
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(DeepLinkHandler, { deepLinks: config.deepLinks }),
2139
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(SessionExpiredBanner, {}),
2140
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(InstallGate, { children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2013
2141
  AuthGated,
2014
2142
  {
2015
2143
  config,
@@ -2021,9 +2149,9 @@ function AppRoot(props) {
2021
2149
  Paywall,
2022
2150
  Onboarding,
2023
2151
  PreAuthFlow,
2024
- children: /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(SubscriptionGate, { Paywall: Paywall ?? FallbackPaywall, children: [
2152
+ children: /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(SubscriptionGate, { Paywall: Paywall ?? FallbackPaywall, children: [
2025
2153
  children,
2026
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(PushPrompt, {})
2154
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(PushPrompt, {})
2027
2155
  ] })
2028
2156
  }
2029
2157
  ) })
@@ -2039,39 +2167,39 @@ function AuthGated({
2039
2167
  EmailVerify,
2040
2168
  PreAuthFlow
2041
2169
  }) {
2042
- const { authStatus } = (0, import_sdk4.useHook)();
2170
+ const { authStatus } = (0, import_sdk5.useHook)();
2043
2171
  if (authStatus === "loading") return null;
2044
2172
  if (authStatus !== "authenticated") {
2045
2173
  if (config.onboarding?.trigger === "pre_signup_custom" && PreAuthFlow) {
2046
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_react_router_dom2.Routes, { children: [
2047
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_router_dom2.Route, { path: "/signin", element: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Login, {}) }),
2048
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_router_dom2.Route, { path: "/signup", element: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Signup, {}) }),
2049
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_router_dom2.Route, { path: "/forgot", element: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Forgot, {}) }),
2050
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_router_dom2.Route, { path: "/reset", element: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Reset, {}) }),
2051
- EmailVerify ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_router_dom2.Route, { path: "/verify", element: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(EmailVerify, {}) }) : null,
2052
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_router_dom2.Route, { path: "/*", element: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(PreAuthFlow, {}) })
2174
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(import_react_router_dom2.Routes, { children: [
2175
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_react_router_dom2.Route, { path: "/signin", element: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Login, {}) }),
2176
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_react_router_dom2.Route, { path: "/signup", element: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Signup, {}) }),
2177
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_react_router_dom2.Route, { path: "/forgot", element: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Forgot, {}) }),
2178
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_react_router_dom2.Route, { path: "/reset", element: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Reset, {}) }),
2179
+ EmailVerify ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_react_router_dom2.Route, { path: "/verify", element: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(EmailVerify, {}) }) : null,
2180
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_react_router_dom2.Route, { path: "/*", element: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(PreAuthFlow, {}) })
2053
2181
  ] });
2054
2182
  }
2055
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_react_router_dom2.Routes, { children: [
2056
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_router_dom2.Route, { path: "/", element: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Login, {}) }),
2057
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_router_dom2.Route, { path: "/signup", element: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Signup, {}) }),
2058
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_router_dom2.Route, { path: "/forgot", element: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Forgot, {}) }),
2059
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_router_dom2.Route, { path: "/reset", element: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Reset, {}) }),
2060
- EmailVerify ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_router_dom2.Route, { path: "/verify", element: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(EmailVerify, {}) }) : null,
2061
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_router_dom2.Route, { path: "*", element: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_router_dom2.Navigate, { to: "/", replace: true }) })
2183
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(import_react_router_dom2.Routes, { children: [
2184
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_react_router_dom2.Route, { path: "/", element: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Login, {}) }),
2185
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_react_router_dom2.Route, { path: "/signup", element: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Signup, {}) }),
2186
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_react_router_dom2.Route, { path: "/forgot", element: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Forgot, {}) }),
2187
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_react_router_dom2.Route, { path: "/reset", element: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Reset, {}) }),
2188
+ EmailVerify ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_react_router_dom2.Route, { path: "/verify", element: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(EmailVerify, {}) }) : null,
2189
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_react_router_dom2.Route, { path: "*", element: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_react_router_dom2.Navigate, { to: "/", replace: true }) })
2062
2190
  ] });
2063
2191
  }
2064
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_jsx_runtime18.Fragment, { children });
2192
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_jsx_runtime19.Fragment, { children });
2065
2193
  }
2066
2194
  function FallbackPaywall() {
2067
2195
  return null;
2068
2196
  }
2069
2197
 
2070
2198
  // src/hooks/usePush.ts
2071
- var import_react12 = require("react");
2072
- var import_sdk5 = require("@hook-sdk/sdk");
2199
+ var import_react13 = require("react");
2200
+ var import_sdk6 = require("@hook-sdk/sdk");
2073
2201
  var DISMISS_STORAGE_KEY = "push:dismissed-until";
2074
- var DISMISS_TTL_MS = 7 * 24 * 60 * 60 * 1e3;
2202
+ var DISMISS_TTL_MS2 = 7 * 24 * 60 * 60 * 1e3;
2075
2203
  function detectIosNeedsInstall() {
2076
2204
  if (typeof navigator === "undefined" || typeof window === "undefined") return false;
2077
2205
  const ua = navigator.userAgent || "";
@@ -2113,12 +2241,12 @@ function deriveState(push) {
2113
2241
  return { kind: "prompt" };
2114
2242
  }
2115
2243
  function usePush() {
2116
- const { push } = (0, import_sdk5.useHook)();
2117
- const [state, setState] = (0, import_react12.useState)(() => deriveState(push));
2118
- (0, import_react12.useEffect)(() => {
2244
+ const { push } = (0, import_sdk6.useHook)();
2245
+ const [state, setState] = (0, import_react13.useState)(() => deriveState(push));
2246
+ (0, import_react13.useEffect)(() => {
2119
2247
  setState(deriveState(push));
2120
2248
  }, [push]);
2121
- const subscribe = (0, import_react12.useCallback)(async () => {
2249
+ const subscribe = (0, import_react13.useCallback)(async () => {
2122
2250
  try {
2123
2251
  await push.subscribe();
2124
2252
  setState({ kind: "subscribed" });
@@ -2130,7 +2258,7 @@ function usePush() {
2130
2258
  throw e;
2131
2259
  }
2132
2260
  }, [push]);
2133
- const unsubscribe = (0, import_react12.useCallback)(async () => {
2261
+ const unsubscribe = (0, import_react13.useCallback)(async () => {
2134
2262
  try {
2135
2263
  await push.unsubscribe();
2136
2264
  setState({ kind: "prompt" });
@@ -2139,10 +2267,10 @@ function usePush() {
2139
2267
  throw e;
2140
2268
  }
2141
2269
  }, [push]);
2142
- const dismiss = (0, import_react12.useCallback)(() => {
2270
+ const dismiss = (0, import_react13.useCallback)(() => {
2143
2271
  if (typeof localStorage !== "undefined") {
2144
2272
  try {
2145
- localStorage.setItem(DISMISS_STORAGE_KEY, String(Date.now() + DISMISS_TTL_MS));
2273
+ localStorage.setItem(DISMISS_STORAGE_KEY, String(Date.now() + DISMISS_TTL_MS2));
2146
2274
  } catch {
2147
2275
  }
2148
2276
  }
@@ -2152,7 +2280,7 @@ function usePush() {
2152
2280
  }
2153
2281
 
2154
2282
  // src/components/PushPrompt.tsx
2155
- var import_jsx_runtime19 = require("react/jsx-runtime");
2283
+ var import_jsx_runtime20 = require("react/jsx-runtime");
2156
2284
  function platformRecoveryCopy(texts) {
2157
2285
  if (typeof navigator === "undefined") return null;
2158
2286
  const ua = navigator.userAgent || "";
@@ -2175,28 +2303,28 @@ function PushPrompt2({ texts, onSubscribed, onDeclined, onInstallRequested, clas
2175
2303
  const { state, subscribe } = usePush();
2176
2304
  if (state.kind === "subscribed" || state.kind === "dismissed") return null;
2177
2305
  if (state.kind === "ios_needs_install") {
2178
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className, role: "region", "aria-label": texts.iosInstallTitle, children: [
2179
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("h3", { children: texts.iosInstallTitle }),
2180
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { children: texts.iosInstallBody }),
2181
- onInstallRequested && texts.iosInstallCta && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("button", { onClick: onInstallRequested, children: texts.iosInstallCta })
2306
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className, role: "region", "aria-label": texts.iosInstallTitle, children: [
2307
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("h3", { children: texts.iosInstallTitle }),
2308
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("p", { children: texts.iosInstallBody }),
2309
+ onInstallRequested && texts.iosInstallCta && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { onClick: onInstallRequested, children: texts.iosInstallCta })
2182
2310
  ] });
2183
2311
  }
2184
2312
  if (state.kind === "denied") {
2185
2313
  const recovery = platformRecoveryCopy(texts);
2186
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className, role: "region", "aria-label": texts.deniedTitle, children: [
2187
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("h3", { children: texts.deniedTitle }),
2188
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { children: texts.deniedBody }),
2189
- recovery && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { "data-testid": "denied-recovery", children: recovery })
2314
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className, role: "region", "aria-label": texts.deniedTitle, children: [
2315
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("h3", { children: texts.deniedTitle }),
2316
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("p", { children: texts.deniedBody }),
2317
+ recovery && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("p", { "data-testid": "denied-recovery", children: recovery })
2190
2318
  ] });
2191
2319
  }
2192
2320
  if (state.kind === "unsupported") {
2193
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className, role: "region", children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { children: texts.unsupportedBody }) });
2321
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className, role: "region", children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("p", { children: texts.unsupportedBody }) });
2194
2322
  }
2195
2323
  if (state.kind === "error") {
2196
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className, role: "region", "aria-label": "error", children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { children: state.message }) });
2324
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className, role: "region", "aria-label": "error", children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("p", { children: state.message }) });
2197
2325
  }
2198
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className, role: "region", children: [
2199
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2326
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className, role: "region", children: [
2327
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
2200
2328
  "button",
2201
2329
  {
2202
2330
  type: "button",
@@ -2210,41 +2338,41 @@ function PushPrompt2({ texts, onSubscribed, onDeclined, onInstallRequested, clas
2210
2338
  children: texts.cta
2211
2339
  }
2212
2340
  ),
2213
- onDeclined && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("button", { type: "button", onClick: onDeclined, children: texts.declineCta })
2341
+ onDeclined && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { type: "button", onClick: onDeclined, children: texts.declineCta })
2214
2342
  ] });
2215
2343
  }
2216
2344
 
2217
2345
  // src/defaults/LoadingState.tsx
2218
- var import_jsx_runtime20 = require("react/jsx-runtime");
2346
+ var import_jsx_runtime21 = require("react/jsx-runtime");
2219
2347
  function LoadingState({ message }) {
2220
- return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { role: "status", "aria-live": "polite", style: { padding: 24, textAlign: "center" }, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { children: message ?? "Carregando..." }) });
2348
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { role: "status", "aria-live": "polite", style: { padding: 24, textAlign: "center" }, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { children: message ?? "Carregando..." }) });
2221
2349
  }
2222
2350
 
2223
2351
  // src/defaults/EmptyState.tsx
2224
- var import_jsx_runtime21 = require("react/jsx-runtime");
2352
+ var import_jsx_runtime22 = require("react/jsx-runtime");
2225
2353
  function EmptyState({ title, description, action }) {
2226
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { role: "status", style: { padding: 32, textAlign: "center" }, children: [
2227
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("h2", { style: { marginBottom: 8 }, children: title }),
2228
- description && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { style: { opacity: 0.7 }, children: description }),
2229
- action && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { style: { marginTop: 16 }, children: action })
2354
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { role: "status", style: { padding: 32, textAlign: "center" }, children: [
2355
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("h2", { style: { marginBottom: 8 }, children: title }),
2356
+ description && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("p", { style: { opacity: 0.7 }, children: description }),
2357
+ action && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { style: { marginTop: 16 }, children: action })
2230
2358
  ] });
2231
2359
  }
2232
2360
 
2233
2361
  // src/hooks/useLoginForm.ts
2234
- var import_react13 = require("react");
2235
- var import_sdk7 = require("@hook-sdk/sdk");
2362
+ var import_react14 = require("react");
2363
+ var import_sdk8 = require("@hook-sdk/sdk");
2236
2364
 
2237
2365
  // src/errors.ts
2238
- var import_sdk6 = require("@hook-sdk/sdk");
2366
+ var import_sdk7 = require("@hook-sdk/sdk");
2239
2367
  function mapSdkError(err) {
2240
- if (err instanceof import_sdk6.SdkRateLimitError) {
2368
+ if (err instanceof import_sdk7.SdkRateLimitError) {
2241
2369
  return {
2242
2370
  code: "rate_limited",
2243
2371
  message: `Aguarde ${err.retryAfter}s e tente novamente.`,
2244
2372
  retryAfter: err.retryAfter
2245
2373
  };
2246
2374
  }
2247
- if (err instanceof import_sdk6.SdkAuthError) {
2375
+ if (err instanceof import_sdk7.SdkAuthError) {
2248
2376
  const detail = err.detail;
2249
2377
  if (detail === "email_unverified") {
2250
2378
  return { code: "email_unverified", message: "Confirme seu e-mail antes de entrar." };
@@ -2254,7 +2382,7 @@ function mapSdkError(err) {
2254
2382
  }
2255
2383
  return { code: "invalid_credentials", message: "E-mail ou senha inv\xE1lidos." };
2256
2384
  }
2257
- if (err instanceof import_sdk6.SdkError && err.httpStatus === 0) {
2385
+ if (err instanceof import_sdk7.SdkError && err.httpStatus === 0) {
2258
2386
  return { code: "network", message: "Sem conex\xE3o com o servidor. Verifique sua internet." };
2259
2387
  }
2260
2388
  if (err instanceof TypeError) {
@@ -2267,23 +2395,29 @@ function mapSdkError(err) {
2267
2395
  var EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
2268
2396
  var MIN_PASSWORD = 8;
2269
2397
  function useLoginForm() {
2270
- const { auth } = (0, import_sdk7.useHook)();
2271
- const [email, setEmail] = (0, import_react13.useState)("");
2272
- const [password, setPassword] = (0, import_react13.useState)("");
2273
- const [submitting, setSubmitting] = (0, import_react13.useState)(false);
2274
- const [error, setError] = (0, import_react13.useState)(null);
2275
- const emailError = (0, import_react13.useMemo)(() => {
2398
+ const { auth } = (0, import_sdk8.useHook)();
2399
+ const [email, setEmail] = (0, import_react14.useState)("");
2400
+ const [password, setPassword] = (0, import_react14.useState)("");
2401
+ const [submitting, setSubmitting] = (0, import_react14.useState)(false);
2402
+ const [error, setError] = (0, import_react14.useState)(null);
2403
+ const [touchedEmail, setTouchedEmail] = (0, import_react14.useState)(false);
2404
+ const [touchedPassword, setTouchedPassword] = (0, import_react14.useState)(false);
2405
+ const [formSubmitAttempted, setFormSubmitAttempted] = (0, import_react14.useState)(false);
2406
+ const validateEmail = (0, import_react14.useMemo)(() => {
2276
2407
  if (email.length === 0) return null;
2277
2408
  if (!EMAIL_RE.test(email)) return "Formato de e-mail inv\xE1lido.";
2278
2409
  return null;
2279
2410
  }, [email]);
2280
- const passwordError = (0, import_react13.useMemo)(() => {
2411
+ const validatePassword = (0, import_react14.useMemo)(() => {
2281
2412
  if (password.length === 0) return null;
2282
2413
  if (password.length < MIN_PASSWORD) return `M\xEDnimo de ${MIN_PASSWORD} caracteres.`;
2283
2414
  return null;
2284
2415
  }, [password]);
2285
- const canSubmit = email.length > 0 && password.length >= MIN_PASSWORD && emailError === null && passwordError === null && !submitting;
2286
- const submit = (0, import_react13.useCallback)(async () => {
2416
+ const emailError = touchedEmail || formSubmitAttempted ? validateEmail : null;
2417
+ const passwordError = touchedPassword || formSubmitAttempted ? validatePassword : null;
2418
+ const canSubmit = email.length > 0 && password.length >= MIN_PASSWORD && validateEmail === null && validatePassword === null && !submitting;
2419
+ const submit = (0, import_react14.useCallback)(async () => {
2420
+ setFormSubmitAttempted(true);
2287
2421
  if (!canSubmit) return false;
2288
2422
  setSubmitting(true);
2289
2423
  setError(null);
@@ -2301,9 +2435,12 @@ function useLoginForm() {
2301
2435
  email,
2302
2436
  setEmail,
2303
2437
  emailError,
2438
+ markEmailTouched: () => setTouchedEmail(true),
2304
2439
  password,
2305
2440
  setPassword,
2306
2441
  passwordError,
2442
+ markPasswordTouched: () => setTouchedPassword(true),
2443
+ formSubmitAttempted,
2307
2444
  submit,
2308
2445
  submitting,
2309
2446
  canSubmit,
@@ -2313,34 +2450,42 @@ function useLoginForm() {
2313
2450
  }
2314
2451
 
2315
2452
  // src/hooks/useSignupForm.ts
2316
- var import_react14 = require("react");
2317
- var import_sdk8 = require("@hook-sdk/sdk");
2453
+ var import_react15 = require("react");
2454
+ var import_sdk9 = require("@hook-sdk/sdk");
2318
2455
  var EMAIL_RE2 = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
2319
2456
  var MIN_PASSWORD2 = 8;
2320
2457
  function useSignupForm() {
2321
- const { auth } = (0, import_sdk8.useHook)();
2322
- const [name, setName] = (0, import_react14.useState)("");
2323
- const [email, setEmail] = (0, import_react14.useState)("");
2324
- const [password, setPassword] = (0, import_react14.useState)("");
2325
- const [submitting, setSubmitting] = (0, import_react14.useState)(false);
2326
- const [error, setError] = (0, import_react14.useState)(null);
2327
- const nameError = (0, import_react14.useMemo)(() => {
2458
+ const { auth } = (0, import_sdk9.useHook)();
2459
+ const [name, setName] = (0, import_react15.useState)("");
2460
+ const [email, setEmail] = (0, import_react15.useState)("");
2461
+ const [password, setPassword] = (0, import_react15.useState)("");
2462
+ const [submitting, setSubmitting] = (0, import_react15.useState)(false);
2463
+ const [error, setError] = (0, import_react15.useState)(null);
2464
+ const [touchedName, setTouchedName] = (0, import_react15.useState)(false);
2465
+ const [touchedEmail, setTouchedEmail] = (0, import_react15.useState)(false);
2466
+ const [touchedPassword, setTouchedPassword] = (0, import_react15.useState)(false);
2467
+ const [formSubmitAttempted, setFormSubmitAttempted] = (0, import_react15.useState)(false);
2468
+ const validateName = (0, import_react15.useMemo)(() => {
2328
2469
  if (name.length === 0) return null;
2329
2470
  if (name.trim().length < 2) return "Nome muito curto.";
2330
2471
  return null;
2331
2472
  }, [name]);
2332
- const emailError = (0, import_react14.useMemo)(() => {
2473
+ const validateEmail = (0, import_react15.useMemo)(() => {
2333
2474
  if (email.length === 0) return null;
2334
2475
  if (!EMAIL_RE2.test(email)) return "Formato de e-mail inv\xE1lido.";
2335
2476
  return null;
2336
2477
  }, [email]);
2337
- const passwordError = (0, import_react14.useMemo)(() => {
2478
+ const validatePassword = (0, import_react15.useMemo)(() => {
2338
2479
  if (password.length === 0) return null;
2339
2480
  if (password.length < MIN_PASSWORD2) return `M\xEDnimo de ${MIN_PASSWORD2} caracteres.`;
2340
2481
  return null;
2341
2482
  }, [password]);
2342
- const canSubmit = name.trim().length >= 2 && email.length > 0 && password.length >= MIN_PASSWORD2 && nameError === null && emailError === null && passwordError === null && !submitting;
2343
- const submit = (0, import_react14.useCallback)(async () => {
2483
+ const nameError = touchedName || formSubmitAttempted ? validateName : null;
2484
+ const emailError = touchedEmail || formSubmitAttempted ? validateEmail : null;
2485
+ const passwordError = touchedPassword || formSubmitAttempted ? validatePassword : null;
2486
+ const canSubmit = name.trim().length >= 2 && email.length > 0 && password.length >= MIN_PASSWORD2 && validateName === null && validateEmail === null && validatePassword === null && !submitting;
2487
+ const submit = (0, import_react15.useCallback)(async () => {
2488
+ setFormSubmitAttempted(true);
2344
2489
  if (!canSubmit) return false;
2345
2490
  setSubmitting(true);
2346
2491
  setError(null);
@@ -2358,12 +2503,16 @@ function useSignupForm() {
2358
2503
  name,
2359
2504
  setName,
2360
2505
  nameError,
2506
+ markNameTouched: () => setTouchedName(true),
2361
2507
  email,
2362
2508
  setEmail,
2363
2509
  emailError,
2510
+ markEmailTouched: () => setTouchedEmail(true),
2364
2511
  password,
2365
2512
  setPassword,
2366
2513
  passwordError,
2514
+ markPasswordTouched: () => setTouchedPassword(true),
2515
+ formSubmitAttempted,
2367
2516
  submit,
2368
2517
  submitting,
2369
2518
  canSubmit,
@@ -2373,22 +2522,26 @@ function useSignupForm() {
2373
2522
  }
2374
2523
 
2375
2524
  // src/hooks/useForgotForm.ts
2376
- var import_react15 = require("react");
2377
- var import_sdk9 = require("@hook-sdk/sdk");
2525
+ var import_react16 = require("react");
2526
+ var import_sdk10 = require("@hook-sdk/sdk");
2378
2527
  var EMAIL_RE3 = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
2379
2528
  function useForgotForm() {
2380
- const { auth } = (0, import_sdk9.useHook)();
2381
- const [email, setEmail] = (0, import_react15.useState)("");
2382
- const [submitting, setSubmitting] = (0, import_react15.useState)(false);
2383
- const [sent, setSent] = (0, import_react15.useState)(false);
2384
- const [error, setError] = (0, import_react15.useState)(null);
2385
- const emailError = (0, import_react15.useMemo)(() => {
2529
+ const { auth } = (0, import_sdk10.useHook)();
2530
+ const [email, setEmail] = (0, import_react16.useState)("");
2531
+ const [submitting, setSubmitting] = (0, import_react16.useState)(false);
2532
+ const [sent, setSent] = (0, import_react16.useState)(false);
2533
+ const [error, setError] = (0, import_react16.useState)(null);
2534
+ const [touchedEmail, setTouchedEmail] = (0, import_react16.useState)(false);
2535
+ const [formSubmitAttempted, setFormSubmitAttempted] = (0, import_react16.useState)(false);
2536
+ const validateEmail = (0, import_react16.useMemo)(() => {
2386
2537
  if (email.length === 0) return null;
2387
2538
  if (!EMAIL_RE3.test(email)) return "Formato de e-mail inv\xE1lido.";
2388
2539
  return null;
2389
2540
  }, [email]);
2390
- const canSubmit = email.length > 0 && emailError === null && !submitting;
2391
- const submit = (0, import_react15.useCallback)(async () => {
2541
+ const emailError = touchedEmail || formSubmitAttempted ? validateEmail : null;
2542
+ const canSubmit = email.length > 0 && validateEmail === null && !submitting;
2543
+ const submit = (0, import_react16.useCallback)(async () => {
2544
+ setFormSubmitAttempted(true);
2392
2545
  if (!canSubmit) return false;
2393
2546
  setSubmitting(true);
2394
2547
  setError(null);
@@ -2407,6 +2560,8 @@ function useForgotForm() {
2407
2560
  email,
2408
2561
  setEmail,
2409
2562
  emailError,
2563
+ markEmailTouched: () => setTouchedEmail(true),
2564
+ formSubmitAttempted,
2410
2565
  submit,
2411
2566
  submitting,
2412
2567
  canSubmit,
@@ -2416,35 +2571,41 @@ function useForgotForm() {
2416
2571
  }
2417
2572
 
2418
2573
  // src/hooks/useResetForm.ts
2419
- var import_react16 = require("react");
2420
- var import_sdk10 = require("@hook-sdk/sdk");
2574
+ var import_react17 = require("react");
2575
+ var import_sdk11 = require("@hook-sdk/sdk");
2421
2576
  var MIN_PASSWORD3 = 12;
2422
2577
  function useResetForm() {
2423
- const { auth } = (0, import_sdk10.useHook)();
2424
- const [token, setToken] = (0, import_react16.useState)(null);
2425
- const [password, setPassword] = (0, import_react16.useState)("");
2426
- const [confirm, setConfirm] = (0, import_react16.useState)("");
2427
- const [submitting, setSubmitting] = (0, import_react16.useState)(false);
2428
- const [done, setDone] = (0, import_react16.useState)(false);
2429
- const [error, setError] = (0, import_react16.useState)(null);
2430
- (0, import_react16.useEffect)(() => {
2578
+ const { auth } = (0, import_sdk11.useHook)();
2579
+ const [token, setToken] = (0, import_react17.useState)(null);
2580
+ const [password, setPassword] = (0, import_react17.useState)("");
2581
+ const [confirm, setConfirm] = (0, import_react17.useState)("");
2582
+ const [submitting, setSubmitting] = (0, import_react17.useState)(false);
2583
+ const [done, setDone] = (0, import_react17.useState)(false);
2584
+ const [error, setError] = (0, import_react17.useState)(null);
2585
+ const [touchedPassword, setTouchedPassword] = (0, import_react17.useState)(false);
2586
+ const [touchedConfirm, setTouchedConfirm] = (0, import_react17.useState)(false);
2587
+ const [formSubmitAttempted, setFormSubmitAttempted] = (0, import_react17.useState)(false);
2588
+ (0, import_react17.useEffect)(() => {
2431
2589
  if (typeof window === "undefined") return;
2432
2590
  const params = new URLSearchParams(window.location.search);
2433
2591
  const t = params.get("token");
2434
2592
  setToken(t && t.length > 0 ? t : null);
2435
2593
  }, []);
2436
- const passwordError = (0, import_react16.useMemo)(() => {
2594
+ const validatePassword = (0, import_react17.useMemo)(() => {
2437
2595
  if (password.length === 0) return null;
2438
2596
  if (password.length < MIN_PASSWORD3) return `M\xEDnimo de ${MIN_PASSWORD3} caracteres.`;
2439
2597
  return null;
2440
2598
  }, [password]);
2441
- const confirmError = (0, import_react16.useMemo)(() => {
2599
+ const validateConfirm = (0, import_react17.useMemo)(() => {
2442
2600
  if (confirm.length === 0) return null;
2443
2601
  if (confirm !== password) return "Senhas n\xE3o coincidem.";
2444
2602
  return null;
2445
2603
  }, [confirm, password]);
2446
- const canSubmit = token !== null && password.length >= MIN_PASSWORD3 && confirm === password && passwordError === null && confirmError === null && !submitting && !done;
2447
- const submit = (0, import_react16.useCallback)(async () => {
2604
+ const passwordError = touchedPassword || formSubmitAttempted ? validatePassword : null;
2605
+ const confirmError = touchedConfirm || formSubmitAttempted ? validateConfirm : null;
2606
+ const canSubmit = token !== null && password.length >= MIN_PASSWORD3 && confirm === password && validatePassword === null && validateConfirm === null && !submitting && !done;
2607
+ const submit = (0, import_react17.useCallback)(async () => {
2608
+ setFormSubmitAttempted(true);
2448
2609
  if (!canSubmit || token === null) return;
2449
2610
  setSubmitting(true);
2450
2611
  setError(null);
@@ -2468,9 +2629,12 @@ function useResetForm() {
2468
2629
  password,
2469
2630
  setPassword,
2470
2631
  passwordError,
2632
+ markPasswordTouched: () => setTouchedPassword(true),
2471
2633
  confirm,
2472
2634
  setConfirm,
2473
2635
  confirmError,
2636
+ markConfirmTouched: () => setTouchedConfirm(true),
2637
+ formSubmitAttempted,
2474
2638
  submit,
2475
2639
  submitting,
2476
2640
  canSubmit,
@@ -2480,9 +2644,9 @@ function useResetForm() {
2480
2644
  }
2481
2645
 
2482
2646
  // src/hooks/usePlan.ts
2483
- var import_sdk11 = require("@hook-sdk/sdk");
2647
+ var import_sdk12 = require("@hook-sdk/sdk");
2484
2648
  function usePlan() {
2485
- const { plan } = (0, import_sdk11.useHook)();
2649
+ const { plan } = (0, import_sdk12.useHook)();
2486
2650
  return plan;
2487
2651
  }
2488
2652
 
@@ -2515,12 +2679,12 @@ function discountPercent(anchorCents, realCents) {
2515
2679
  }
2516
2680
 
2517
2681
  // src/hooks/useAuthPrimitives.ts
2518
- var import_react17 = require("react");
2519
- var import_sdk12 = require("@hook-sdk/sdk");
2682
+ var import_react18 = require("react");
2683
+ var import_sdk13 = require("@hook-sdk/sdk");
2520
2684
  var warned = false;
2521
2685
  function useAuthPrimitives() {
2522
- const { auth } = (0, import_sdk12.useHook)();
2523
- (0, import_react17.useEffect)(() => {
2686
+ const { auth } = (0, import_sdk13.useHook)();
2687
+ (0, import_react18.useEffect)(() => {
2524
2688
  if (!warned && process.env.NODE_ENV !== "production") {
2525
2689
  warned = true;
2526
2690
  console.warn(
@@ -2542,9 +2706,9 @@ function useAuthPrimitives() {
2542
2706
  }
2543
2707
 
2544
2708
  // src/hooks/useAuth.ts
2545
- var import_sdk13 = require("@hook-sdk/sdk");
2709
+ var import_sdk14 = require("@hook-sdk/sdk");
2546
2710
  function useAuth() {
2547
- const { user, authStatus, auth } = (0, import_sdk13.useHook)();
2711
+ const { user, authStatus, auth } = (0, import_sdk14.useHook)();
2548
2712
  return {
2549
2713
  user,
2550
2714
  authStatus,
@@ -2553,23 +2717,23 @@ function useAuth() {
2553
2717
  }
2554
2718
 
2555
2719
  // src/hooks/useSubscription.ts
2556
- var import_sdk14 = require("@hook-sdk/sdk");
2720
+ var import_sdk15 = require("@hook-sdk/sdk");
2557
2721
  function useSubscription() {
2558
- const { subscription } = (0, import_sdk14.useHook)();
2722
+ const { subscription } = (0, import_sdk15.useHook)();
2559
2723
  return {
2560
2724
  status: subscription.status()
2561
2725
  };
2562
2726
  }
2563
2727
 
2564
2728
  // src/hooks/useReminders.ts
2565
- var import_react18 = require("react");
2566
- var import_sdk15 = require("@hook-sdk/sdk");
2729
+ var import_react19 = require("react");
2730
+ var import_sdk16 = require("@hook-sdk/sdk");
2567
2731
  function useReminders() {
2568
- const { push } = (0, import_sdk15.useHook)();
2732
+ const { push } = (0, import_sdk16.useHook)();
2569
2733
  const r = push.reminders;
2570
- const [reminders, setReminders] = (0, import_react18.useState)([]);
2571
- const [loading, setLoading] = (0, import_react18.useState)(true);
2572
- const reload = (0, import_react18.useCallback)(async () => {
2734
+ const [reminders, setReminders] = (0, import_react19.useState)([]);
2735
+ const [loading, setLoading] = (0, import_react19.useState)(true);
2736
+ const reload = (0, import_react19.useCallback)(async () => {
2573
2737
  setLoading(true);
2574
2738
  try {
2575
2739
  const next = await r.list();
@@ -2578,38 +2742,38 @@ function useReminders() {
2578
2742
  setLoading(false);
2579
2743
  }
2580
2744
  }, [r]);
2581
- (0, import_react18.useEffect)(() => {
2745
+ (0, import_react19.useEffect)(() => {
2582
2746
  void reload();
2583
2747
  }, [reload]);
2584
- const setReminder = (0, import_react18.useCallback)(async (input) => {
2748
+ const setReminder = (0, import_react19.useCallback)(async (input) => {
2585
2749
  await r.set(input);
2586
2750
  await reload();
2587
2751
  }, [r, reload]);
2588
- const deleteReminder = (0, import_react18.useCallback)(async (slot) => {
2752
+ const deleteReminder = (0, import_react19.useCallback)(async (slot) => {
2589
2753
  await r.delete(slot);
2590
2754
  await reload();
2591
2755
  }, [r, reload]);
2592
- const schedule = (0, import_react18.useCallback)(async (items) => {
2756
+ const schedule = (0, import_react19.useCallback)(async (items) => {
2593
2757
  return r.schedule(items);
2594
2758
  }, [r]);
2595
- const setFallbacks = (0, import_react18.useCallback)(async (items) => {
2759
+ const setFallbacks = (0, import_react19.useCallback)(async (items) => {
2596
2760
  return r.setFallbacks(items);
2597
2761
  }, [r]);
2598
2762
  return { reminders, loading, setReminder, deleteReminder, schedule, setFallbacks };
2599
2763
  }
2600
2764
 
2601
2765
  // src/hooks/useToast.ts
2602
- var import_react19 = require("react");
2766
+ var import_react20 = require("react");
2603
2767
  function useToast() {
2604
- const [items, setItems] = (0, import_react19.useState)([]);
2605
- const show = (0, import_react19.useCallback)((message, kind = "info") => {
2768
+ const [items, setItems] = (0, import_react20.useState)([]);
2769
+ const show = (0, import_react20.useCallback)((message, kind = "info") => {
2606
2770
  const id = `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
2607
2771
  setItems((prev) => [...prev, { id, message, kind }]);
2608
2772
  setTimeout(() => {
2609
2773
  setItems((prev) => prev.filter((t) => t.id !== id));
2610
2774
  }, 4e3);
2611
2775
  }, []);
2612
- const dismiss = (0, import_react19.useCallback)((id) => {
2776
+ const dismiss = (0, import_react20.useCallback)((id) => {
2613
2777
  setItems((prev) => prev.filter((t) => t.id !== id));
2614
2778
  }, []);
2615
2779
  return { items, show, dismiss };
@@ -2617,20 +2781,20 @@ function useToast() {
2617
2781
 
2618
2782
  // src/RouteBoundary.tsx
2619
2783
  var import_react_router_dom3 = require("react-router-dom");
2620
- var import_jsx_runtime22 = require("react/jsx-runtime");
2784
+ var import_jsx_runtime23 = require("react/jsx-runtime");
2621
2785
  function RouteBoundary({ children }) {
2622
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_react_router_dom3.Routes, { children: [
2786
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_react_router_dom3.Routes, { children: [
2623
2787
  children,
2624
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_react_router_dom3.Route, { path: "*", element: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(DefaultNotFound, {}) })
2788
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_react_router_dom3.Route, { path: "*", element: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(DefaultNotFound, {}) })
2625
2789
  ] });
2626
2790
  }
2627
2791
  function DefaultNotFound() {
2628
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { role: "alert", children: "P\xE1gina n\xE3o encontrada" });
2792
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { role: "alert", children: "P\xE1gina n\xE3o encontrada" });
2629
2793
  }
2630
2794
 
2631
2795
  // src/PreAuthShell.tsx
2632
2796
  var import_react_router_dom4 = require("react-router-dom");
2633
- var import_jsx_runtime23 = require("react/jsx-runtime");
2797
+ var import_jsx_runtime24 = require("react/jsx-runtime");
2634
2798
  function PreAuthShell({
2635
2799
  basename,
2636
2800
  testRouter,
@@ -2638,20 +2802,20 @@ function PreAuthShell({
2638
2802
  children
2639
2803
  }) {
2640
2804
  if (testRouter === "memory") {
2641
- return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_react_router_dom4.MemoryRouter, { basename, initialEntries: testInitialEntries, children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_react_router_dom4.Routes, { children }) });
2805
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_react_router_dom4.MemoryRouter, { basename, initialEntries: testInitialEntries, children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_react_router_dom4.Routes, { children }) });
2642
2806
  }
2643
- return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_react_router_dom4.BrowserRouter, { basename, children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_react_router_dom4.Routes, { children }) });
2807
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_react_router_dom4.BrowserRouter, { basename, children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_react_router_dom4.Routes, { children }) });
2644
2808
  }
2645
2809
 
2646
2810
  // src/OnboardingFlow.tsx
2647
- var import_react21 = require("react");
2648
- var import_sdk16 = require("@hook-sdk/sdk");
2811
+ var import_react22 = require("react");
2812
+ var import_sdk17 = require("@hook-sdk/sdk");
2649
2813
 
2650
2814
  // src/hooks/useOnboardingStep.ts
2651
- var import_react20 = require("react");
2652
- var OnboardingStepContext = (0, import_react20.createContext)(null);
2815
+ var import_react21 = require("react");
2816
+ var OnboardingStepContext = (0, import_react21.createContext)(null);
2653
2817
  function useOnboardingStep() {
2654
- const ctx = (0, import_react20.useContext)(OnboardingStepContext);
2818
+ const ctx = (0, import_react21.useContext)(OnboardingStepContext);
2655
2819
  if (!ctx) {
2656
2820
  throw new Error(
2657
2821
  "[hook-template] useOnboardingStep must be used inside <OnboardingFlow>. (G75)"
@@ -2661,7 +2825,7 @@ function useOnboardingStep() {
2661
2825
  }
2662
2826
 
2663
2827
  // src/OnboardingFlow.tsx
2664
- var import_jsx_runtime24 = require("react/jsx-runtime");
2828
+ var import_jsx_runtime25 = require("react/jsx-runtime");
2665
2829
  var isFilled = (v) => v != null && v !== "";
2666
2830
  var CURRENT_STEP_FIELD = "currentStep";
2667
2831
  function readPersistedStepIdx(draft) {
@@ -2674,12 +2838,12 @@ function OnboardingFlow({
2674
2838
  onComplete,
2675
2839
  persistKey
2676
2840
  }) {
2677
- const [draft, setDraft, status] = (0, import_sdk16.usePersistedState)(persistKey, {});
2678
- const draftRef = (0, import_react21.useRef)(draft);
2841
+ const [draft, setDraft, status] = (0, import_sdk17.usePersistedState)(persistKey, {});
2842
+ const draftRef = (0, import_react22.useRef)(draft);
2679
2843
  draftRef.current = draft;
2680
2844
  const idx = readPersistedStepIdx(draft);
2681
2845
  const clampedIdx = Math.min(Math.max(idx, 0), Math.max(steps.length - 1, 0));
2682
- const setIdx = (0, import_react21.useCallback)(
2846
+ const setIdx = (0, import_react22.useCallback)(
2683
2847
  (n) => {
2684
2848
  setDraft((prev) => {
2685
2849
  const prevIdx = readPersistedStepIdx(prev);
@@ -2689,7 +2853,7 @@ function OnboardingFlow({
2689
2853
  },
2690
2854
  [setDraft]
2691
2855
  );
2692
- const setValue = (0, import_react21.useCallback)(
2856
+ const setValue = (0, import_react22.useCallback)(
2693
2857
  (patch) => {
2694
2858
  draftRef.current = { ...draftRef.current, ...patch };
2695
2859
  setDraft((prev) => ({ ...prev, ...patch }));
@@ -2697,11 +2861,11 @@ function OnboardingFlow({
2697
2861
  [setDraft]
2698
2862
  );
2699
2863
  const step = steps[clampedIdx];
2700
- const valid = (0, import_react21.useMemo)(
2864
+ const valid = (0, import_react22.useMemo)(
2701
2865
  () => step ? (step.validates ?? []).every((field) => isFilled(draft[field])) : false,
2702
2866
  [draft, step]
2703
2867
  );
2704
- const next = (0, import_react21.useCallback)(() => {
2868
+ const next = (0, import_react22.useCallback)(() => {
2705
2869
  if (!step) return;
2706
2870
  const current = draftRef.current;
2707
2871
  const validNow = (step.validates ?? []).every((field) => isFilled(current[field]));
@@ -2712,8 +2876,8 @@ function OnboardingFlow({
2712
2876
  setIdx(clampedIdx + 1);
2713
2877
  }
2714
2878
  }, [clampedIdx, onComplete, step, steps.length, setIdx]);
2715
- const prevStep = (0, import_react21.useCallback)(() => setIdx((i) => Math.max(0, i - 1)), [setIdx]);
2716
- const ctx = (0, import_react21.useMemo)(
2879
+ const prevStep = (0, import_react22.useCallback)(() => setIdx((i) => Math.max(0, i - 1)), [setIdx]);
2880
+ const ctx = (0, import_react22.useMemo)(
2717
2881
  () => ({
2718
2882
  stepIndex: clampedIdx,
2719
2883
  totalSteps: steps.length,
@@ -2739,7 +2903,7 @@ function OnboardingFlow({
2739
2903
  `[hook-template] OnboardingFlow: missing screen component for step '${step.id}' (expected key '${step.screen}' in screens prop)`
2740
2904
  );
2741
2905
  }
2742
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(OnboardingStepContext.Provider, { value: ctx, children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(Screen, {}) });
2906
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(OnboardingStepContext.Provider, { value: ctx, children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(Screen, {}) });
2743
2907
  }
2744
2908
 
2745
2909
  // src/hooks/useFeature.ts