@hook-sdk/template 0.19.0 → 0.20.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.d.cts CHANGED
@@ -155,17 +155,17 @@ interface PushPromptTexts {
155
155
  iosInstallTitle: string;
156
156
  iosInstallBody: string;
157
157
  iosInstallCta?: string;
158
- deniedTitle: string;
159
- deniedBody: string;
160
- /**
161
- * Audit Wave 3 — Fix #33: per-platform recovery copy shown when permission
162
- * is denied. All four are optional; if the matching platform's copy is
163
- * missing the recovery paragraph is omitted (back-compat for callers that
164
- * haven't supplied them yet).
165
- */
158
+ /** @deprecated denied state no longer renders UI; field retained for back-compat. */
159
+ deniedTitle?: string;
160
+ /** @deprecated denied state no longer renders UI; field retained for back-compat. */
161
+ deniedBody?: string;
162
+ /** @deprecated denied state no longer renders UI; field retained for back-compat. */
166
163
  deniedRecoveryIos?: string;
164
+ /** @deprecated denied state no longer renders UI; field retained for back-compat. */
167
165
  deniedRecoveryAndroid?: string;
166
+ /** @deprecated denied state no longer renders UI; field retained for back-compat. */
168
167
  deniedRecoveryDesktop?: string;
168
+ /** @deprecated denied state no longer renders UI; field retained for back-compat. */
169
169
  deniedRecoveryInApp?: string;
170
170
  unsupportedBody: string;
171
171
  }
package/dist/index.d.ts CHANGED
@@ -155,17 +155,17 @@ interface PushPromptTexts {
155
155
  iosInstallTitle: string;
156
156
  iosInstallBody: string;
157
157
  iosInstallCta?: string;
158
- deniedTitle: string;
159
- deniedBody: string;
160
- /**
161
- * Audit Wave 3 — Fix #33: per-platform recovery copy shown when permission
162
- * is denied. All four are optional; if the matching platform's copy is
163
- * missing the recovery paragraph is omitted (back-compat for callers that
164
- * haven't supplied them yet).
165
- */
158
+ /** @deprecated denied state no longer renders UI; field retained for back-compat. */
159
+ deniedTitle?: string;
160
+ /** @deprecated denied state no longer renders UI; field retained for back-compat. */
161
+ deniedBody?: string;
162
+ /** @deprecated denied state no longer renders UI; field retained for back-compat. */
166
163
  deniedRecoveryIos?: string;
164
+ /** @deprecated denied state no longer renders UI; field retained for back-compat. */
167
165
  deniedRecoveryAndroid?: string;
166
+ /** @deprecated denied state no longer renders UI; field retained for back-compat. */
168
167
  deniedRecoveryDesktop?: string;
168
+ /** @deprecated denied state no longer renders UI; field retained for back-compat. */
169
169
  deniedRecoveryInApp?: string;
170
170
  unsupportedBody: string;
171
171
  }
package/dist/index.js CHANGED
@@ -269,7 +269,7 @@ var FALLBACK_PAYWALL = {
269
269
  };
270
270
  var isMethodAvailable = (availability, method) => availability[method] !== false;
271
271
  function usePaywallState() {
272
- const { subscription, plan } = useHook3();
272
+ const { subscription, plan, authStatus, track: track2 } = useHook3();
273
273
  const configFromCtx = useContext3(AppConfigContext);
274
274
  const paywall = configFromCtx?.paywall ?? FALLBACK_PAYWALL;
275
275
  const isFree = paywall.mode === "free";
@@ -358,6 +358,21 @@ function usePaywallState() {
358
358
  [useDefaultMessages]
359
359
  );
360
360
  const submit = useCallback(async () => {
361
+ if (authStatus === "loading") return void 0;
362
+ if (authStatus !== "authenticated") {
363
+ track2("unauthenticated_submit_attempted", {
364
+ method: selectedMethod,
365
+ cycle,
366
+ cpf_valid: cpfValid
367
+ });
368
+ return void 0;
369
+ }
370
+ track2("payment_attempted", {
371
+ method: selectedMethod,
372
+ cycle,
373
+ cpf_valid: cpfValid,
374
+ selected_amount_cents: cycle === "YEARLY" ? plan.data?.yearlyPriceCents ?? (isFree ? 0 : paywall.prices.yearlyCents) : plan.data?.priceCents ?? (isFree ? 0 : paywall.prices.monthlyCents)
375
+ });
361
376
  setSubmitting(true);
362
377
  setError(null);
363
378
  const methodToUse = selectedMethod;
@@ -418,7 +433,7 @@ function usePaywallState() {
418
433
  setSubmitting(false);
419
434
  return void 0;
420
435
  }
421
- }, [selectedMethod, availability, subscription, cycle, cpf, card, buildError]);
436
+ }, [authStatus, track2, selectedMethod, availability, subscription, cycle, cpf, cpfValid, card, buildError, plan, paywall]);
422
437
  const checkout = useCallback(
423
438
  async (args) => {
424
439
  setSubmitting(true);
@@ -2016,15 +2031,21 @@ var BACKOFF_MS = [2e3, 5e3, 1e4, 2e4, 4e4];
2016
2031
  var MAX_CYCLES = 3;
2017
2032
  var SUPPORT_MAILTO = "mailto:suporte@usehook.net?subject=Pagamento%20pendente";
2018
2033
  function PaymentReturnHandler({ children }) {
2019
- const { subscription } = useHook5();
2034
+ const { subscription, track: track2 } = useHook5();
2020
2035
  const subRef = useRef4(subscription);
2021
2036
  subRef.current = subscription;
2022
2037
  const runIdRef = useRef4(0);
2023
2038
  const cyclesRef = useRef4(0);
2039
+ const startMsRef = useRef4(0);
2024
2040
  const [state, setState] = useState5("idle");
2025
2041
  const runPoll = useCallback3(() => {
2026
2042
  const runId = ++runIdRef.current;
2043
+ const isFirstRun = cyclesRef.current === 0;
2027
2044
  cyclesRef.current += 1;
2045
+ if (isFirstRun) {
2046
+ startMsRef.current = Date.now();
2047
+ track2("payment_confirmation_started", {});
2048
+ }
2028
2049
  setState("confirming");
2029
2050
  let attempts = 0;
2030
2051
  const tick = async () => {
@@ -2037,6 +2058,11 @@ function PaymentReturnHandler({ children }) {
2037
2058
  if (runIdRef.current !== runId) return;
2038
2059
  const status = subRef.current.status();
2039
2060
  if (status === "active" || status === "trialing") {
2061
+ track2("payment_confirmation_succeeded", {
2062
+ cycle_count: cyclesRef.current,
2063
+ attempt_count: attempts,
2064
+ duration_ms: Date.now() - startMsRef.current
2065
+ });
2040
2066
  const cleanUrl = new URL(window.location.href);
2041
2067
  cleanUrl.searchParams.delete("paymentReturn");
2042
2068
  window.history.replaceState({}, "", cleanUrl.toString());
@@ -2047,6 +2073,9 @@ function PaymentReturnHandler({ children }) {
2047
2073
  const delay = BACKOFF_MS[attempts - 1];
2048
2074
  if (delay === void 0) {
2049
2075
  if (cyclesRef.current >= MAX_CYCLES) {
2076
+ track2("payment_confirmation_timed_out", {
2077
+ total_duration_ms: Date.now() - startMsRef.current
2078
+ });
2050
2079
  setState("timeout");
2051
2080
  } else {
2052
2081
  setState("waiting");
@@ -2056,7 +2085,7 @@ function PaymentReturnHandler({ children }) {
2056
2085
  setTimeout(tick, delay);
2057
2086
  };
2058
2087
  void tick();
2059
- }, []);
2088
+ }, [track2]);
2060
2089
  useEffect8(() => {
2061
2090
  if (typeof window === "undefined") return;
2062
2091
  const url = new URL(window.location.href);
@@ -2399,27 +2428,11 @@ function usePush() {
2399
2428
 
2400
2429
  // src/components/PushPrompt.tsx
2401
2430
  import { jsx as jsx22, jsxs as jsxs15 } from "react/jsx-runtime";
2402
- function platformRecoveryCopy(texts) {
2403
- if (typeof navigator === "undefined") return null;
2404
- const ua = navigator.userAgent || "";
2405
- const platform = detectPlatform(ua);
2406
- switch (platform) {
2407
- case "ios-safari":
2408
- case "ios-other":
2409
- return texts.deniedRecoveryIos ?? null;
2410
- case "android":
2411
- return texts.deniedRecoveryAndroid ?? null;
2412
- case "desktop":
2413
- return texts.deniedRecoveryDesktop ?? null;
2414
- case "in-app":
2415
- return texts.deniedRecoveryInApp ?? null;
2416
- default:
2417
- return null;
2418
- }
2419
- }
2420
2431
  function PushPrompt2({ texts, onSubscribed, onDeclined, onInstallRequested, className }) {
2421
2432
  const { state, subscribe } = usePush();
2422
- if (state.kind === "subscribed" || state.kind === "dismissed") return null;
2433
+ if (state.kind === "denied" || state.kind === "dismissed" || state.kind === "subscribed") {
2434
+ return null;
2435
+ }
2423
2436
  if (state.kind === "ios_needs_install") {
2424
2437
  return /* @__PURE__ */ jsxs15("div", { className, role: "region", "aria-label": texts.iosInstallTitle, children: [
2425
2438
  /* @__PURE__ */ jsx22("h3", { children: texts.iosInstallTitle }),
@@ -2427,14 +2440,6 @@ function PushPrompt2({ texts, onSubscribed, onDeclined, onInstallRequested, clas
2427
2440
  onInstallRequested && texts.iosInstallCta && /* @__PURE__ */ jsx22("button", { onClick: onInstallRequested, children: texts.iosInstallCta })
2428
2441
  ] });
2429
2442
  }
2430
- if (state.kind === "denied") {
2431
- const recovery = platformRecoveryCopy(texts);
2432
- return /* @__PURE__ */ jsxs15("div", { className, role: "region", "aria-label": texts.deniedTitle, children: [
2433
- /* @__PURE__ */ jsx22("h3", { children: texts.deniedTitle }),
2434
- /* @__PURE__ */ jsx22("p", { children: texts.deniedBody }),
2435
- recovery && /* @__PURE__ */ jsx22("p", { "data-testid": "denied-recovery", children: recovery })
2436
- ] });
2437
- }
2438
2443
  if (state.kind === "unsupported") {
2439
2444
  return /* @__PURE__ */ jsx22("div", { className, role: "region", children: /* @__PURE__ */ jsx22("p", { children: texts.unsupportedBody }) });
2440
2445
  }