@hook-sdk/template 0.11.0 → 0.13.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,27 +1905,27 @@ 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];
1863
1922
  function PaymentReturnHandler({ children }) {
1864
- const { subscription } = (0, import_sdk3.useHook)();
1865
- const subRef = (0, import_react10.useRef)(subscription);
1923
+ const { subscription } = (0, import_sdk4.useHook)();
1924
+ const subRef = (0, import_react11.useRef)(subscription);
1866
1925
  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)(() => {
1926
+ const runIdRef = (0, import_react11.useRef)(0);
1927
+ const [state, setState] = (0, import_react11.useState)("idle");
1928
+ const runPoll = (0, import_react11.useCallback)(() => {
1870
1929
  const runId = ++runIdRef.current;
1871
1930
  setState("confirming");
1872
1931
  let attempts = 0;
@@ -1895,7 +1954,7 @@ function PaymentReturnHandler({ children }) {
1895
1954
  };
1896
1955
  void tick();
1897
1956
  }, []);
1898
- (0, import_react10.useEffect)(() => {
1957
+ (0, import_react11.useEffect)(() => {
1899
1958
  if (typeof window === "undefined") return;
1900
1959
  const url = new URL(window.location.href);
1901
1960
  if (url.searchParams.get("paymentReturn") !== "1") return;
@@ -1905,15 +1964,15 @@ function PaymentReturnHandler({ children }) {
1905
1964
  };
1906
1965
  }, [runPoll]);
1907
1966
  if (state === "confirming") {
1908
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { role: "status", "aria-live": "polite", style: overlayStyle2, children: "Confirmando pagamento\u2026" });
1967
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { role: "status", "aria-live": "polite", style: overlayStyle2, children: "Confirmando pagamento\u2026" });
1909
1968
  }
1910
1969
  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" })
1970
+ 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: [
1971
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: { marginBottom: 16 }, children: "Pagamento aceito. Estamos confirmando com o banco \u2014 pode levar alguns minutos." }),
1972
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("button", { type: "button", onClick: runPoll, style: buttonStyle, children: "Atualizar" })
1914
1973
  ] }) });
1915
1974
  }
1916
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_jsx_runtime17.Fragment, { children });
1975
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_jsx_runtime18.Fragment, { children });
1917
1976
  }
1918
1977
  var overlayStyle2 = {
1919
1978
  position: "fixed",
@@ -1939,7 +1998,7 @@ var buttonStyle = {
1939
1998
  };
1940
1999
 
1941
2000
  // src/AppRoot.tsx
1942
- var import_jsx_runtime18 = require("react/jsx-runtime");
2001
+ var import_jsx_runtime19 = require("react/jsx-runtime");
1943
2002
  function buildLegacyConfigShim(config) {
1944
2003
  const paywall = config.paywall;
1945
2004
  const isFree = paywall.mode === "free";
@@ -2003,13 +2062,14 @@ function AppRoot(props) {
2003
2062
  "[hook-template] <AppRoot>: PreAuthFlow slot prop is required when config.onboarding.trigger === 'pre_signup_custom'."
2004
2063
  );
2005
2064
  }
2006
- const legacyShim = (0, import_react11.useMemo)(() => buildLegacyConfigShim(config), [config]);
2065
+ const legacyShim = (0, import_react12.useMemo)(() => buildLegacyConfigShim(config), [config]);
2007
2066
  const Router = testRouter === "memory" ? import_react_router_dom2.MemoryRouter : import_react_router_dom2.BrowserRouter;
2008
2067
  const basename = `/app/${config.slug}`;
2009
2068
  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)(
2069
+ 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: [
2070
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(DeepLinkHandler, { deepLinks: config.deepLinks }),
2071
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(SessionExpiredBanner, {}),
2072
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(InstallGate, { children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2013
2073
  AuthGated,
2014
2074
  {
2015
2075
  config,
@@ -2021,9 +2081,9 @@ function AppRoot(props) {
2021
2081
  Paywall,
2022
2082
  Onboarding,
2023
2083
  PreAuthFlow,
2024
- children: /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(SubscriptionGate, { Paywall: Paywall ?? FallbackPaywall, children: [
2084
+ children: /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(SubscriptionGate, { Paywall: Paywall ?? FallbackPaywall, children: [
2025
2085
  children,
2026
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(PushPrompt, {})
2086
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(PushPrompt, {})
2027
2087
  ] })
2028
2088
  }
2029
2089
  ) })
@@ -2039,37 +2099,39 @@ function AuthGated({
2039
2099
  EmailVerify,
2040
2100
  PreAuthFlow
2041
2101
  }) {
2042
- const { authStatus } = (0, import_sdk4.useHook)();
2102
+ const { authStatus } = (0, import_sdk5.useHook)();
2043
2103
  if (authStatus === "loading") return null;
2044
2104
  if (authStatus !== "authenticated") {
2045
2105
  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, {}) })
2106
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(import_react_router_dom2.Routes, { children: [
2107
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_react_router_dom2.Route, { path: "/signin", element: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Login, {}) }),
2108
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_react_router_dom2.Route, { path: "/signup", element: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Signup, {}) }),
2109
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_react_router_dom2.Route, { path: "/forgot", element: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Forgot, {}) }),
2110
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_react_router_dom2.Route, { path: "/reset", element: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Reset, {}) }),
2111
+ EmailVerify ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_react_router_dom2.Route, { path: "/verify", element: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(EmailVerify, {}) }) : null,
2112
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_react_router_dom2.Route, { path: "/*", element: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(PreAuthFlow, {}) })
2053
2113
  ] });
2054
2114
  }
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 }) })
2115
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(import_react_router_dom2.Routes, { children: [
2116
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_react_router_dom2.Route, { path: "/", element: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Login, {}) }),
2117
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_react_router_dom2.Route, { path: "/signup", element: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Signup, {}) }),
2118
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_react_router_dom2.Route, { path: "/forgot", element: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Forgot, {}) }),
2119
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_react_router_dom2.Route, { path: "/reset", element: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Reset, {}) }),
2120
+ EmailVerify ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_react_router_dom2.Route, { path: "/verify", element: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(EmailVerify, {}) }) : null,
2121
+ /* @__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
2122
  ] });
2063
2123
  }
2064
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_jsx_runtime18.Fragment, { children });
2124
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_jsx_runtime19.Fragment, { children });
2065
2125
  }
2066
2126
  function FallbackPaywall() {
2067
2127
  return null;
2068
2128
  }
2069
2129
 
2070
2130
  // src/hooks/usePush.ts
2071
- var import_react12 = require("react");
2072
- var import_sdk5 = require("@hook-sdk/sdk");
2131
+ var import_react13 = require("react");
2132
+ var import_sdk6 = require("@hook-sdk/sdk");
2133
+ var DISMISS_STORAGE_KEY = "push:dismissed-until";
2134
+ var DISMISS_TTL_MS2 = 7 * 24 * 60 * 60 * 1e3;
2073
2135
  function detectIosNeedsInstall() {
2074
2136
  if (typeof navigator === "undefined" || typeof window === "undefined") return false;
2075
2137
  const ua = navigator.userAgent || "";
@@ -2080,6 +2142,21 @@ function detectIosNeedsInstall() {
2080
2142
  const legacyStandalone = typeof navigator.standalone === "boolean" ? navigator.standalone : false;
2081
2143
  return !(standalone || legacyStandalone);
2082
2144
  }
2145
+ function readDismissedUntil() {
2146
+ if (typeof localStorage === "undefined") return null;
2147
+ try {
2148
+ const raw = localStorage.getItem(DISMISS_STORAGE_KEY);
2149
+ if (raw === null) return null;
2150
+ const n = Number.parseInt(raw, 10);
2151
+ return Number.isFinite(n) ? n : null;
2152
+ } catch {
2153
+ return null;
2154
+ }
2155
+ }
2156
+ function isDismissedNow() {
2157
+ const until = readDismissedUntil();
2158
+ return until !== null && until > Date.now();
2159
+ }
2083
2160
  function deriveState(push) {
2084
2161
  if (!push.isAvailable()) {
2085
2162
  if (detectIosNeedsInstall()) return { kind: "ios_needs_install" };
@@ -2092,15 +2169,16 @@ function deriveState(push) {
2092
2169
  if (detectIosNeedsInstall()) return { kind: "ios_needs_install" };
2093
2170
  return { kind: "unsupported" };
2094
2171
  }
2172
+ if (isDismissedNow()) return { kind: "dismissed" };
2095
2173
  return { kind: "prompt" };
2096
2174
  }
2097
2175
  function usePush() {
2098
- const { push } = (0, import_sdk5.useHook)();
2099
- const [state, setState] = (0, import_react12.useState)(() => deriveState(push));
2100
- (0, import_react12.useEffect)(() => {
2176
+ const { push } = (0, import_sdk6.useHook)();
2177
+ const [state, setState] = (0, import_react13.useState)(() => deriveState(push));
2178
+ (0, import_react13.useEffect)(() => {
2101
2179
  setState(deriveState(push));
2102
2180
  }, [push]);
2103
- const subscribe = (0, import_react12.useCallback)(async () => {
2181
+ const subscribe = (0, import_react13.useCallback)(async () => {
2104
2182
  try {
2105
2183
  await push.subscribe();
2106
2184
  setState({ kind: "subscribed" });
@@ -2112,7 +2190,7 @@ function usePush() {
2112
2190
  throw e;
2113
2191
  }
2114
2192
  }, [push]);
2115
- const unsubscribe = (0, import_react12.useCallback)(async () => {
2193
+ const unsubscribe = (0, import_react13.useCallback)(async () => {
2116
2194
  try {
2117
2195
  await push.unsubscribe();
2118
2196
  setState({ kind: "prompt" });
@@ -2121,35 +2199,64 @@ function usePush() {
2121
2199
  throw e;
2122
2200
  }
2123
2201
  }, [push]);
2124
- return { state, subscribe, unsubscribe };
2202
+ const dismiss = (0, import_react13.useCallback)(() => {
2203
+ if (typeof localStorage !== "undefined") {
2204
+ try {
2205
+ localStorage.setItem(DISMISS_STORAGE_KEY, String(Date.now() + DISMISS_TTL_MS2));
2206
+ } catch {
2207
+ }
2208
+ }
2209
+ setState({ kind: "dismissed" });
2210
+ }, []);
2211
+ return { state, subscribe, unsubscribe, dismiss };
2125
2212
  }
2126
2213
 
2127
2214
  // src/components/PushPrompt.tsx
2128
- var import_jsx_runtime19 = require("react/jsx-runtime");
2215
+ var import_jsx_runtime20 = require("react/jsx-runtime");
2216
+ function platformRecoveryCopy(texts) {
2217
+ if (typeof navigator === "undefined") return null;
2218
+ const ua = navigator.userAgent || "";
2219
+ const platform = detectPlatform(ua);
2220
+ switch (platform) {
2221
+ case "ios-safari":
2222
+ case "ios-other":
2223
+ return texts.deniedRecoveryIos ?? null;
2224
+ case "android":
2225
+ return texts.deniedRecoveryAndroid ?? null;
2226
+ case "desktop":
2227
+ return texts.deniedRecoveryDesktop ?? null;
2228
+ case "in-app":
2229
+ return texts.deniedRecoveryInApp ?? null;
2230
+ default:
2231
+ return null;
2232
+ }
2233
+ }
2129
2234
  function PushPrompt2({ texts, onSubscribed, onDeclined, onInstallRequested, className }) {
2130
2235
  const { state, subscribe } = usePush();
2131
- if (state.kind === "subscribed") return null;
2236
+ if (state.kind === "subscribed" || state.kind === "dismissed") return null;
2132
2237
  if (state.kind === "ios_needs_install") {
2133
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className, role: "region", "aria-label": texts.iosInstallTitle, children: [
2134
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("h3", { children: texts.iosInstallTitle }),
2135
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { children: texts.iosInstallBody }),
2136
- onInstallRequested && texts.iosInstallCta && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("button", { onClick: onInstallRequested, children: texts.iosInstallCta })
2238
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className, role: "region", "aria-label": texts.iosInstallTitle, children: [
2239
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("h3", { children: texts.iosInstallTitle }),
2240
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("p", { children: texts.iosInstallBody }),
2241
+ onInstallRequested && texts.iosInstallCta && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { onClick: onInstallRequested, children: texts.iosInstallCta })
2137
2242
  ] });
2138
2243
  }
2139
2244
  if (state.kind === "denied") {
2140
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className, role: "region", "aria-label": texts.deniedTitle, children: [
2141
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("h3", { children: texts.deniedTitle }),
2142
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { children: texts.deniedBody })
2245
+ const recovery = platformRecoveryCopy(texts);
2246
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className, role: "region", "aria-label": texts.deniedTitle, children: [
2247
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("h3", { children: texts.deniedTitle }),
2248
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("p", { children: texts.deniedBody }),
2249
+ recovery && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("p", { "data-testid": "denied-recovery", children: recovery })
2143
2250
  ] });
2144
2251
  }
2145
2252
  if (state.kind === "unsupported") {
2146
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className, role: "region", children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { children: texts.unsupportedBody }) });
2253
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className, role: "region", children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("p", { children: texts.unsupportedBody }) });
2147
2254
  }
2148
2255
  if (state.kind === "error") {
2149
- 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 }) });
2256
+ 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 }) });
2150
2257
  }
2151
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className, role: "region", children: [
2152
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2258
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className, role: "region", children: [
2259
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
2153
2260
  "button",
2154
2261
  {
2155
2262
  type: "button",
@@ -2163,41 +2270,41 @@ function PushPrompt2({ texts, onSubscribed, onDeclined, onInstallRequested, clas
2163
2270
  children: texts.cta
2164
2271
  }
2165
2272
  ),
2166
- onDeclined && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("button", { type: "button", onClick: onDeclined, children: texts.declineCta })
2273
+ onDeclined && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { type: "button", onClick: onDeclined, children: texts.declineCta })
2167
2274
  ] });
2168
2275
  }
2169
2276
 
2170
2277
  // src/defaults/LoadingState.tsx
2171
- var import_jsx_runtime20 = require("react/jsx-runtime");
2278
+ var import_jsx_runtime21 = require("react/jsx-runtime");
2172
2279
  function LoadingState({ message }) {
2173
- 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..." }) });
2280
+ 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..." }) });
2174
2281
  }
2175
2282
 
2176
2283
  // src/defaults/EmptyState.tsx
2177
- var import_jsx_runtime21 = require("react/jsx-runtime");
2284
+ var import_jsx_runtime22 = require("react/jsx-runtime");
2178
2285
  function EmptyState({ title, description, action }) {
2179
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { role: "status", style: { padding: 32, textAlign: "center" }, children: [
2180
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("h2", { style: { marginBottom: 8 }, children: title }),
2181
- description && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { style: { opacity: 0.7 }, children: description }),
2182
- action && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { style: { marginTop: 16 }, children: action })
2286
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { role: "status", style: { padding: 32, textAlign: "center" }, children: [
2287
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("h2", { style: { marginBottom: 8 }, children: title }),
2288
+ description && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("p", { style: { opacity: 0.7 }, children: description }),
2289
+ action && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { style: { marginTop: 16 }, children: action })
2183
2290
  ] });
2184
2291
  }
2185
2292
 
2186
2293
  // src/hooks/useLoginForm.ts
2187
- var import_react13 = require("react");
2188
- var import_sdk7 = require("@hook-sdk/sdk");
2294
+ var import_react14 = require("react");
2295
+ var import_sdk8 = require("@hook-sdk/sdk");
2189
2296
 
2190
2297
  // src/errors.ts
2191
- var import_sdk6 = require("@hook-sdk/sdk");
2298
+ var import_sdk7 = require("@hook-sdk/sdk");
2192
2299
  function mapSdkError(err) {
2193
- if (err instanceof import_sdk6.SdkRateLimitError) {
2300
+ if (err instanceof import_sdk7.SdkRateLimitError) {
2194
2301
  return {
2195
2302
  code: "rate_limited",
2196
2303
  message: `Aguarde ${err.retryAfter}s e tente novamente.`,
2197
2304
  retryAfter: err.retryAfter
2198
2305
  };
2199
2306
  }
2200
- if (err instanceof import_sdk6.SdkAuthError) {
2307
+ if (err instanceof import_sdk7.SdkAuthError) {
2201
2308
  const detail = err.detail;
2202
2309
  if (detail === "email_unverified") {
2203
2310
  return { code: "email_unverified", message: "Confirme seu e-mail antes de entrar." };
@@ -2207,7 +2314,7 @@ function mapSdkError(err) {
2207
2314
  }
2208
2315
  return { code: "invalid_credentials", message: "E-mail ou senha inv\xE1lidos." };
2209
2316
  }
2210
- if (err instanceof import_sdk6.SdkError && err.httpStatus === 0) {
2317
+ if (err instanceof import_sdk7.SdkError && err.httpStatus === 0) {
2211
2318
  return { code: "network", message: "Sem conex\xE3o com o servidor. Verifique sua internet." };
2212
2319
  }
2213
2320
  if (err instanceof TypeError) {
@@ -2220,23 +2327,23 @@ function mapSdkError(err) {
2220
2327
  var EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
2221
2328
  var MIN_PASSWORD = 8;
2222
2329
  function useLoginForm() {
2223
- const { auth } = (0, import_sdk7.useHook)();
2224
- const [email, setEmail] = (0, import_react13.useState)("");
2225
- const [password, setPassword] = (0, import_react13.useState)("");
2226
- const [submitting, setSubmitting] = (0, import_react13.useState)(false);
2227
- const [error, setError] = (0, import_react13.useState)(null);
2228
- const emailError = (0, import_react13.useMemo)(() => {
2330
+ const { auth } = (0, import_sdk8.useHook)();
2331
+ const [email, setEmail] = (0, import_react14.useState)("");
2332
+ const [password, setPassword] = (0, import_react14.useState)("");
2333
+ const [submitting, setSubmitting] = (0, import_react14.useState)(false);
2334
+ const [error, setError] = (0, import_react14.useState)(null);
2335
+ const emailError = (0, import_react14.useMemo)(() => {
2229
2336
  if (email.length === 0) return null;
2230
2337
  if (!EMAIL_RE.test(email)) return "Formato de e-mail inv\xE1lido.";
2231
2338
  return null;
2232
2339
  }, [email]);
2233
- const passwordError = (0, import_react13.useMemo)(() => {
2340
+ const passwordError = (0, import_react14.useMemo)(() => {
2234
2341
  if (password.length === 0) return null;
2235
2342
  if (password.length < MIN_PASSWORD) return `M\xEDnimo de ${MIN_PASSWORD} caracteres.`;
2236
2343
  return null;
2237
2344
  }, [password]);
2238
2345
  const canSubmit = email.length > 0 && password.length >= MIN_PASSWORD && emailError === null && passwordError === null && !submitting;
2239
- const submit = (0, import_react13.useCallback)(async () => {
2346
+ const submit = (0, import_react14.useCallback)(async () => {
2240
2347
  if (!canSubmit) return false;
2241
2348
  setSubmitting(true);
2242
2349
  setError(null);
@@ -2266,34 +2373,34 @@ function useLoginForm() {
2266
2373
  }
2267
2374
 
2268
2375
  // src/hooks/useSignupForm.ts
2269
- var import_react14 = require("react");
2270
- var import_sdk8 = require("@hook-sdk/sdk");
2376
+ var import_react15 = require("react");
2377
+ var import_sdk9 = require("@hook-sdk/sdk");
2271
2378
  var EMAIL_RE2 = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
2272
2379
  var MIN_PASSWORD2 = 8;
2273
2380
  function useSignupForm() {
2274
- const { auth } = (0, import_sdk8.useHook)();
2275
- const [name, setName] = (0, import_react14.useState)("");
2276
- const [email, setEmail] = (0, import_react14.useState)("");
2277
- const [password, setPassword] = (0, import_react14.useState)("");
2278
- const [submitting, setSubmitting] = (0, import_react14.useState)(false);
2279
- const [error, setError] = (0, import_react14.useState)(null);
2280
- const nameError = (0, import_react14.useMemo)(() => {
2381
+ const { auth } = (0, import_sdk9.useHook)();
2382
+ const [name, setName] = (0, import_react15.useState)("");
2383
+ const [email, setEmail] = (0, import_react15.useState)("");
2384
+ const [password, setPassword] = (0, import_react15.useState)("");
2385
+ const [submitting, setSubmitting] = (0, import_react15.useState)(false);
2386
+ const [error, setError] = (0, import_react15.useState)(null);
2387
+ const nameError = (0, import_react15.useMemo)(() => {
2281
2388
  if (name.length === 0) return null;
2282
2389
  if (name.trim().length < 2) return "Nome muito curto.";
2283
2390
  return null;
2284
2391
  }, [name]);
2285
- const emailError = (0, import_react14.useMemo)(() => {
2392
+ const emailError = (0, import_react15.useMemo)(() => {
2286
2393
  if (email.length === 0) return null;
2287
2394
  if (!EMAIL_RE2.test(email)) return "Formato de e-mail inv\xE1lido.";
2288
2395
  return null;
2289
2396
  }, [email]);
2290
- const passwordError = (0, import_react14.useMemo)(() => {
2397
+ const passwordError = (0, import_react15.useMemo)(() => {
2291
2398
  if (password.length === 0) return null;
2292
2399
  if (password.length < MIN_PASSWORD2) return `M\xEDnimo de ${MIN_PASSWORD2} caracteres.`;
2293
2400
  return null;
2294
2401
  }, [password]);
2295
2402
  const canSubmit = name.trim().length >= 2 && email.length > 0 && password.length >= MIN_PASSWORD2 && nameError === null && emailError === null && passwordError === null && !submitting;
2296
- const submit = (0, import_react14.useCallback)(async () => {
2403
+ const submit = (0, import_react15.useCallback)(async () => {
2297
2404
  if (!canSubmit) return false;
2298
2405
  setSubmitting(true);
2299
2406
  setError(null);
@@ -2326,22 +2433,22 @@ function useSignupForm() {
2326
2433
  }
2327
2434
 
2328
2435
  // src/hooks/useForgotForm.ts
2329
- var import_react15 = require("react");
2330
- var import_sdk9 = require("@hook-sdk/sdk");
2436
+ var import_react16 = require("react");
2437
+ var import_sdk10 = require("@hook-sdk/sdk");
2331
2438
  var EMAIL_RE3 = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
2332
2439
  function useForgotForm() {
2333
- const { auth } = (0, import_sdk9.useHook)();
2334
- const [email, setEmail] = (0, import_react15.useState)("");
2335
- const [submitting, setSubmitting] = (0, import_react15.useState)(false);
2336
- const [sent, setSent] = (0, import_react15.useState)(false);
2337
- const [error, setError] = (0, import_react15.useState)(null);
2338
- const emailError = (0, import_react15.useMemo)(() => {
2440
+ const { auth } = (0, import_sdk10.useHook)();
2441
+ const [email, setEmail] = (0, import_react16.useState)("");
2442
+ const [submitting, setSubmitting] = (0, import_react16.useState)(false);
2443
+ const [sent, setSent] = (0, import_react16.useState)(false);
2444
+ const [error, setError] = (0, import_react16.useState)(null);
2445
+ const emailError = (0, import_react16.useMemo)(() => {
2339
2446
  if (email.length === 0) return null;
2340
2447
  if (!EMAIL_RE3.test(email)) return "Formato de e-mail inv\xE1lido.";
2341
2448
  return null;
2342
2449
  }, [email]);
2343
2450
  const canSubmit = email.length > 0 && emailError === null && !submitting;
2344
- const submit = (0, import_react15.useCallback)(async () => {
2451
+ const submit = (0, import_react16.useCallback)(async () => {
2345
2452
  if (!canSubmit) return false;
2346
2453
  setSubmitting(true);
2347
2454
  setError(null);
@@ -2369,35 +2476,35 @@ function useForgotForm() {
2369
2476
  }
2370
2477
 
2371
2478
  // src/hooks/useResetForm.ts
2372
- var import_react16 = require("react");
2373
- var import_sdk10 = require("@hook-sdk/sdk");
2479
+ var import_react17 = require("react");
2480
+ var import_sdk11 = require("@hook-sdk/sdk");
2374
2481
  var MIN_PASSWORD3 = 12;
2375
2482
  function useResetForm() {
2376
- const { auth } = (0, import_sdk10.useHook)();
2377
- const [token, setToken] = (0, import_react16.useState)(null);
2378
- const [password, setPassword] = (0, import_react16.useState)("");
2379
- const [confirm, setConfirm] = (0, import_react16.useState)("");
2380
- const [submitting, setSubmitting] = (0, import_react16.useState)(false);
2381
- const [done, setDone] = (0, import_react16.useState)(false);
2382
- const [error, setError] = (0, import_react16.useState)(null);
2383
- (0, import_react16.useEffect)(() => {
2483
+ const { auth } = (0, import_sdk11.useHook)();
2484
+ const [token, setToken] = (0, import_react17.useState)(null);
2485
+ const [password, setPassword] = (0, import_react17.useState)("");
2486
+ const [confirm, setConfirm] = (0, import_react17.useState)("");
2487
+ const [submitting, setSubmitting] = (0, import_react17.useState)(false);
2488
+ const [done, setDone] = (0, import_react17.useState)(false);
2489
+ const [error, setError] = (0, import_react17.useState)(null);
2490
+ (0, import_react17.useEffect)(() => {
2384
2491
  if (typeof window === "undefined") return;
2385
2492
  const params = new URLSearchParams(window.location.search);
2386
2493
  const t = params.get("token");
2387
2494
  setToken(t && t.length > 0 ? t : null);
2388
2495
  }, []);
2389
- const passwordError = (0, import_react16.useMemo)(() => {
2496
+ const passwordError = (0, import_react17.useMemo)(() => {
2390
2497
  if (password.length === 0) return null;
2391
2498
  if (password.length < MIN_PASSWORD3) return `M\xEDnimo de ${MIN_PASSWORD3} caracteres.`;
2392
2499
  return null;
2393
2500
  }, [password]);
2394
- const confirmError = (0, import_react16.useMemo)(() => {
2501
+ const confirmError = (0, import_react17.useMemo)(() => {
2395
2502
  if (confirm.length === 0) return null;
2396
2503
  if (confirm !== password) return "Senhas n\xE3o coincidem.";
2397
2504
  return null;
2398
2505
  }, [confirm, password]);
2399
2506
  const canSubmit = token !== null && password.length >= MIN_PASSWORD3 && confirm === password && passwordError === null && confirmError === null && !submitting && !done;
2400
- const submit = (0, import_react16.useCallback)(async () => {
2507
+ const submit = (0, import_react17.useCallback)(async () => {
2401
2508
  if (!canSubmit || token === null) return;
2402
2509
  setSubmitting(true);
2403
2510
  setError(null);
@@ -2433,9 +2540,9 @@ function useResetForm() {
2433
2540
  }
2434
2541
 
2435
2542
  // src/hooks/usePlan.ts
2436
- var import_sdk11 = require("@hook-sdk/sdk");
2543
+ var import_sdk12 = require("@hook-sdk/sdk");
2437
2544
  function usePlan() {
2438
- const { plan } = (0, import_sdk11.useHook)();
2545
+ const { plan } = (0, import_sdk12.useHook)();
2439
2546
  return plan;
2440
2547
  }
2441
2548
 
@@ -2468,12 +2575,12 @@ function discountPercent(anchorCents, realCents) {
2468
2575
  }
2469
2576
 
2470
2577
  // src/hooks/useAuthPrimitives.ts
2471
- var import_react17 = require("react");
2472
- var import_sdk12 = require("@hook-sdk/sdk");
2578
+ var import_react18 = require("react");
2579
+ var import_sdk13 = require("@hook-sdk/sdk");
2473
2580
  var warned = false;
2474
2581
  function useAuthPrimitives() {
2475
- const { auth } = (0, import_sdk12.useHook)();
2476
- (0, import_react17.useEffect)(() => {
2582
+ const { auth } = (0, import_sdk13.useHook)();
2583
+ (0, import_react18.useEffect)(() => {
2477
2584
  if (!warned && process.env.NODE_ENV !== "production") {
2478
2585
  warned = true;
2479
2586
  console.warn(
@@ -2495,9 +2602,9 @@ function useAuthPrimitives() {
2495
2602
  }
2496
2603
 
2497
2604
  // src/hooks/useAuth.ts
2498
- var import_sdk13 = require("@hook-sdk/sdk");
2605
+ var import_sdk14 = require("@hook-sdk/sdk");
2499
2606
  function useAuth() {
2500
- const { user, authStatus, auth } = (0, import_sdk13.useHook)();
2607
+ const { user, authStatus, auth } = (0, import_sdk14.useHook)();
2501
2608
  return {
2502
2609
  user,
2503
2610
  authStatus,
@@ -2506,23 +2613,23 @@ function useAuth() {
2506
2613
  }
2507
2614
 
2508
2615
  // src/hooks/useSubscription.ts
2509
- var import_sdk14 = require("@hook-sdk/sdk");
2616
+ var import_sdk15 = require("@hook-sdk/sdk");
2510
2617
  function useSubscription() {
2511
- const { subscription } = (0, import_sdk14.useHook)();
2618
+ const { subscription } = (0, import_sdk15.useHook)();
2512
2619
  return {
2513
2620
  status: subscription.status()
2514
2621
  };
2515
2622
  }
2516
2623
 
2517
2624
  // src/hooks/useReminders.ts
2518
- var import_react18 = require("react");
2519
- var import_sdk15 = require("@hook-sdk/sdk");
2625
+ var import_react19 = require("react");
2626
+ var import_sdk16 = require("@hook-sdk/sdk");
2520
2627
  function useReminders() {
2521
- const { push } = (0, import_sdk15.useHook)();
2628
+ const { push } = (0, import_sdk16.useHook)();
2522
2629
  const r = push.reminders;
2523
- const [reminders, setReminders] = (0, import_react18.useState)([]);
2524
- const [loading, setLoading] = (0, import_react18.useState)(true);
2525
- const reload = (0, import_react18.useCallback)(async () => {
2630
+ const [reminders, setReminders] = (0, import_react19.useState)([]);
2631
+ const [loading, setLoading] = (0, import_react19.useState)(true);
2632
+ const reload = (0, import_react19.useCallback)(async () => {
2526
2633
  setLoading(true);
2527
2634
  try {
2528
2635
  const next = await r.list();
@@ -2531,38 +2638,38 @@ function useReminders() {
2531
2638
  setLoading(false);
2532
2639
  }
2533
2640
  }, [r]);
2534
- (0, import_react18.useEffect)(() => {
2641
+ (0, import_react19.useEffect)(() => {
2535
2642
  void reload();
2536
2643
  }, [reload]);
2537
- const setReminder = (0, import_react18.useCallback)(async (input) => {
2644
+ const setReminder = (0, import_react19.useCallback)(async (input) => {
2538
2645
  await r.set(input);
2539
2646
  await reload();
2540
2647
  }, [r, reload]);
2541
- const deleteReminder = (0, import_react18.useCallback)(async (slot) => {
2648
+ const deleteReminder = (0, import_react19.useCallback)(async (slot) => {
2542
2649
  await r.delete(slot);
2543
2650
  await reload();
2544
2651
  }, [r, reload]);
2545
- const schedule = (0, import_react18.useCallback)(async (items) => {
2652
+ const schedule = (0, import_react19.useCallback)(async (items) => {
2546
2653
  return r.schedule(items);
2547
2654
  }, [r]);
2548
- const setFallbacks = (0, import_react18.useCallback)(async (items) => {
2655
+ const setFallbacks = (0, import_react19.useCallback)(async (items) => {
2549
2656
  return r.setFallbacks(items);
2550
2657
  }, [r]);
2551
2658
  return { reminders, loading, setReminder, deleteReminder, schedule, setFallbacks };
2552
2659
  }
2553
2660
 
2554
2661
  // src/hooks/useToast.ts
2555
- var import_react19 = require("react");
2662
+ var import_react20 = require("react");
2556
2663
  function useToast() {
2557
- const [items, setItems] = (0, import_react19.useState)([]);
2558
- const show = (0, import_react19.useCallback)((message, kind = "info") => {
2664
+ const [items, setItems] = (0, import_react20.useState)([]);
2665
+ const show = (0, import_react20.useCallback)((message, kind = "info") => {
2559
2666
  const id = `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
2560
2667
  setItems((prev) => [...prev, { id, message, kind }]);
2561
2668
  setTimeout(() => {
2562
2669
  setItems((prev) => prev.filter((t) => t.id !== id));
2563
2670
  }, 4e3);
2564
2671
  }, []);
2565
- const dismiss = (0, import_react19.useCallback)((id) => {
2672
+ const dismiss = (0, import_react20.useCallback)((id) => {
2566
2673
  setItems((prev) => prev.filter((t) => t.id !== id));
2567
2674
  }, []);
2568
2675
  return { items, show, dismiss };
@@ -2570,20 +2677,20 @@ function useToast() {
2570
2677
 
2571
2678
  // src/RouteBoundary.tsx
2572
2679
  var import_react_router_dom3 = require("react-router-dom");
2573
- var import_jsx_runtime22 = require("react/jsx-runtime");
2680
+ var import_jsx_runtime23 = require("react/jsx-runtime");
2574
2681
  function RouteBoundary({ children }) {
2575
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_react_router_dom3.Routes, { children: [
2682
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_react_router_dom3.Routes, { children: [
2576
2683
  children,
2577
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_react_router_dom3.Route, { path: "*", element: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(DefaultNotFound, {}) })
2684
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_react_router_dom3.Route, { path: "*", element: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(DefaultNotFound, {}) })
2578
2685
  ] });
2579
2686
  }
2580
2687
  function DefaultNotFound() {
2581
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { role: "alert", children: "P\xE1gina n\xE3o encontrada" });
2688
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { role: "alert", children: "P\xE1gina n\xE3o encontrada" });
2582
2689
  }
2583
2690
 
2584
2691
  // src/PreAuthShell.tsx
2585
2692
  var import_react_router_dom4 = require("react-router-dom");
2586
- var import_jsx_runtime23 = require("react/jsx-runtime");
2693
+ var import_jsx_runtime24 = require("react/jsx-runtime");
2587
2694
  function PreAuthShell({
2588
2695
  basename,
2589
2696
  testRouter,
@@ -2591,20 +2698,20 @@ function PreAuthShell({
2591
2698
  children
2592
2699
  }) {
2593
2700
  if (testRouter === "memory") {
2594
- 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 }) });
2701
+ 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 }) });
2595
2702
  }
2596
- 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 }) });
2703
+ 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 }) });
2597
2704
  }
2598
2705
 
2599
2706
  // src/OnboardingFlow.tsx
2600
- var import_react21 = require("react");
2601
- var import_sdk16 = require("@hook-sdk/sdk");
2707
+ var import_react22 = require("react");
2708
+ var import_sdk17 = require("@hook-sdk/sdk");
2602
2709
 
2603
2710
  // src/hooks/useOnboardingStep.ts
2604
- var import_react20 = require("react");
2605
- var OnboardingStepContext = (0, import_react20.createContext)(null);
2711
+ var import_react21 = require("react");
2712
+ var OnboardingStepContext = (0, import_react21.createContext)(null);
2606
2713
  function useOnboardingStep() {
2607
- const ctx = (0, import_react20.useContext)(OnboardingStepContext);
2714
+ const ctx = (0, import_react21.useContext)(OnboardingStepContext);
2608
2715
  if (!ctx) {
2609
2716
  throw new Error(
2610
2717
  "[hook-template] useOnboardingStep must be used inside <OnboardingFlow>. (G75)"
@@ -2614,7 +2721,7 @@ function useOnboardingStep() {
2614
2721
  }
2615
2722
 
2616
2723
  // src/OnboardingFlow.tsx
2617
- var import_jsx_runtime24 = require("react/jsx-runtime");
2724
+ var import_jsx_runtime25 = require("react/jsx-runtime");
2618
2725
  var isFilled = (v) => v != null && v !== "";
2619
2726
  var CURRENT_STEP_FIELD = "currentStep";
2620
2727
  function readPersistedStepIdx(draft) {
@@ -2627,12 +2734,12 @@ function OnboardingFlow({
2627
2734
  onComplete,
2628
2735
  persistKey
2629
2736
  }) {
2630
- const [draft, setDraft, status] = (0, import_sdk16.usePersistedState)(persistKey, {});
2631
- const draftRef = (0, import_react21.useRef)(draft);
2737
+ const [draft, setDraft, status] = (0, import_sdk17.usePersistedState)(persistKey, {});
2738
+ const draftRef = (0, import_react22.useRef)(draft);
2632
2739
  draftRef.current = draft;
2633
2740
  const idx = readPersistedStepIdx(draft);
2634
2741
  const clampedIdx = Math.min(Math.max(idx, 0), Math.max(steps.length - 1, 0));
2635
- const setIdx = (0, import_react21.useCallback)(
2742
+ const setIdx = (0, import_react22.useCallback)(
2636
2743
  (n) => {
2637
2744
  setDraft((prev) => {
2638
2745
  const prevIdx = readPersistedStepIdx(prev);
@@ -2642,7 +2749,7 @@ function OnboardingFlow({
2642
2749
  },
2643
2750
  [setDraft]
2644
2751
  );
2645
- const setValue = (0, import_react21.useCallback)(
2752
+ const setValue = (0, import_react22.useCallback)(
2646
2753
  (patch) => {
2647
2754
  draftRef.current = { ...draftRef.current, ...patch };
2648
2755
  setDraft((prev) => ({ ...prev, ...patch }));
@@ -2650,11 +2757,11 @@ function OnboardingFlow({
2650
2757
  [setDraft]
2651
2758
  );
2652
2759
  const step = steps[clampedIdx];
2653
- const valid = (0, import_react21.useMemo)(
2760
+ const valid = (0, import_react22.useMemo)(
2654
2761
  () => step ? (step.validates ?? []).every((field) => isFilled(draft[field])) : false,
2655
2762
  [draft, step]
2656
2763
  );
2657
- const next = (0, import_react21.useCallback)(() => {
2764
+ const next = (0, import_react22.useCallback)(() => {
2658
2765
  if (!step) return;
2659
2766
  const current = draftRef.current;
2660
2767
  const validNow = (step.validates ?? []).every((field) => isFilled(current[field]));
@@ -2665,8 +2772,8 @@ function OnboardingFlow({
2665
2772
  setIdx(clampedIdx + 1);
2666
2773
  }
2667
2774
  }, [clampedIdx, onComplete, step, steps.length, setIdx]);
2668
- const prevStep = (0, import_react21.useCallback)(() => setIdx((i) => Math.max(0, i - 1)), [setIdx]);
2669
- const ctx = (0, import_react21.useMemo)(
2775
+ const prevStep = (0, import_react22.useCallback)(() => setIdx((i) => Math.max(0, i - 1)), [setIdx]);
2776
+ const ctx = (0, import_react22.useMemo)(
2670
2777
  () => ({
2671
2778
  stepIndex: clampedIdx,
2672
2779
  totalSteps: steps.length,
@@ -2692,7 +2799,7 @@ function OnboardingFlow({
2692
2799
  `[hook-template] OnboardingFlow: missing screen component for step '${step.id}' (expected key '${step.screen}' in screens prop)`
2693
2800
  );
2694
2801
  }
2695
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(OnboardingStepContext.Provider, { value: ctx, children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(Screen, {}) });
2802
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(OnboardingStepContext.Provider, { value: ctx, children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(Screen, {}) });
2696
2803
  }
2697
2804
 
2698
2805
  // src/hooks/useFeature.ts