@hook-sdk/template 0.1.4 → 0.3.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
@@ -29,12 +29,14 @@ __export(index_exports, {
29
29
  EmptyState: () => EmptyState,
30
30
  ErrorBoundary: () => ErrorBoundary,
31
31
  LoadingState: () => LoadingState,
32
+ PushPrompt: () => PushPrompt2,
32
33
  useAuth: () => useAuth,
33
34
  useAuthPrimitives: () => useAuthPrimitives,
34
35
  useForgotForm: () => useForgotForm,
35
36
  useLoginForm: () => useLoginForm,
36
37
  usePaywallState: () => usePaywallState,
37
38
  usePush: () => usePush,
39
+ useReminders: () => useReminders,
38
40
  useResetForm: () => useResetForm,
39
41
  useSignupForm: () => useSignupForm,
40
42
  useSubscription: () => useSubscription,
@@ -43,7 +45,7 @@ __export(index_exports, {
43
45
  module.exports = __toCommonJS(index_exports);
44
46
 
45
47
  // src/AppRoot.tsx
46
- var import_react11 = require("react");
48
+ var import_react12 = require("react");
47
49
  var import_sdk9 = require("@hook-sdk/sdk");
48
50
 
49
51
  // src/internal/TemplateConfigContext.tsx
@@ -307,25 +309,183 @@ function useLoginForm() {
307
309
  submit,
308
310
  submitting,
309
311
  canSubmit,
310
- error
312
+ error,
313
+ loginWithGoogle: () => auth.loginWithGoogle()
311
314
  };
312
315
  }
313
316
 
314
- // src/defaults/DefaultLoginScreen.tsx
317
+ // src/internal/GoogleSignInButton.tsx
315
318
  var import_jsx_runtime8 = require("react/jsx-runtime");
319
+ function GoogleSignInButton({
320
+ onClick,
321
+ testId = "oauth-google",
322
+ label = "Continuar com Google"
323
+ }) {
324
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
325
+ "button",
326
+ {
327
+ "data-testid": testId,
328
+ type: "button",
329
+ onClick,
330
+ style: {
331
+ width: "100%",
332
+ padding: "10px 12px",
333
+ display: "flex",
334
+ alignItems: "center",
335
+ justifyContent: "center",
336
+ gap: 10,
337
+ background: "#fff",
338
+ color: "#1f1f1f",
339
+ border: "1px solid #dadce0",
340
+ borderRadius: 8,
341
+ cursor: "pointer",
342
+ fontSize: 14,
343
+ fontWeight: 500,
344
+ fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif'
345
+ },
346
+ children: [
347
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(GoogleGlyph, {}),
348
+ label
349
+ ]
350
+ }
351
+ );
352
+ }
353
+ function GoogleGlyph() {
354
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("svg", { width: "18", height: "18", viewBox: "0 0 18 18", xmlns: "http://www.w3.org/2000/svg", "aria-hidden": "true", children: [
355
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
356
+ "path",
357
+ {
358
+ d: "M17.64 9.2c0-.637-.057-1.251-.164-1.84H9v3.481h4.844a4.14 4.14 0 0 1-1.796 2.716v2.259h2.908c1.702-1.567 2.684-3.874 2.684-6.615z",
359
+ fill: "#4285F4"
360
+ }
361
+ ),
362
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
363
+ "path",
364
+ {
365
+ d: "M9 18c2.43 0 4.467-.806 5.956-2.18l-2.908-2.259c-.806.54-1.837.86-3.048.86-2.344 0-4.328-1.584-5.036-3.711H.957v2.332A8.997 8.997 0 0 0 9 18z",
366
+ fill: "#34A853"
367
+ }
368
+ ),
369
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
370
+ "path",
371
+ {
372
+ d: "M3.964 10.71A5.41 5.41 0 0 1 3.682 9c0-.593.102-1.17.282-1.71V4.958H.957A8.996 8.996 0 0 0 0 9c0 1.452.348 2.827.957 4.042l3.007-2.332z",
373
+ fill: "#FBBC05"
374
+ }
375
+ ),
376
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
377
+ "path",
378
+ {
379
+ d: "M9 3.58c1.321 0 2.508.454 3.44 1.345l2.582-2.58C13.463.891 11.426 0 9 0A8.997 8.997 0 0 0 .957 4.958L3.964 7.29C4.672 5.163 6.656 3.58 9 3.58z",
380
+ fill: "#EA4335"
381
+ }
382
+ )
383
+ ] });
384
+ }
385
+
386
+ // src/internal/OAuthErrorBanner.tsx
387
+ var import_react7 = require("react");
388
+ var import_jsx_runtime9 = require("react/jsx-runtime");
389
+ var ERROR_MESSAGES = {
390
+ invalid_state: "Sess\xE3o expirou, tente de novo.",
391
+ access_denied: "Voc\xEA cancelou o login com Google.",
392
+ provider_error: "O Google recusou a autentica\xE7\xE3o. Tente de novo em alguns segundos.",
393
+ invalid_return_to: "Link inv\xE1lido. Tente entrar novamente."
394
+ };
395
+ function readErrorCode() {
396
+ if (typeof window === "undefined") return null;
397
+ const code = new URLSearchParams(window.location.search).get("oauth_error");
398
+ if (!code) return null;
399
+ return code;
400
+ }
401
+ function stripErrorFromUrl() {
402
+ if (typeof window === "undefined") return;
403
+ const url = new URL(window.location.href);
404
+ url.searchParams.delete("oauth_error");
405
+ window.history.replaceState({}, "", url.toString());
406
+ }
407
+ function OAuthErrorBanner() {
408
+ const [code, setCode] = (0, import_react7.useState)(() => readErrorCode());
409
+ (0, import_react7.useEffect)(() => {
410
+ if (code !== null) stripErrorFromUrl();
411
+ }, [code]);
412
+ if (!code) return null;
413
+ const message = ERROR_MESSAGES[code] ?? "N\xE3o conseguimos conectar ao Google. Tente de novo.";
414
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
415
+ "div",
416
+ {
417
+ role: "alert",
418
+ "data-testid": "oauth-error-banner",
419
+ style: {
420
+ padding: "10px 12px",
421
+ marginBottom: 16,
422
+ background: "#fce8e6",
423
+ color: "#a50e0e",
424
+ borderRadius: 8,
425
+ fontSize: 14
426
+ },
427
+ children: [
428
+ message,
429
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
430
+ "button",
431
+ {
432
+ type: "button",
433
+ onClick: () => setCode(null),
434
+ "aria-label": "Fechar",
435
+ style: {
436
+ float: "right",
437
+ background: "none",
438
+ border: "none",
439
+ color: "#a50e0e",
440
+ cursor: "pointer",
441
+ fontSize: 16,
442
+ lineHeight: 1,
443
+ padding: 0
444
+ },
445
+ children: "\xD7"
446
+ }
447
+ )
448
+ ]
449
+ }
450
+ );
451
+ }
452
+
453
+ // src/defaults/DefaultLoginScreen.tsx
454
+ var import_jsx_runtime10 = require("react/jsx-runtime");
316
455
  function DefaultLoginScreen({ onNavigate }) {
317
456
  const { name } = useTemplateConfig();
318
457
  const f = useLoginForm();
319
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("main", { style: { padding: 24, maxWidth: 360, margin: "0 auto" }, children: [
320
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("h1", { style: { marginBottom: 8 }, children: name }),
321
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { style: { opacity: 0.7, marginBottom: 24 }, children: "Entre na sua conta" }),
322
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("form", { onSubmit: (e) => {
458
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("main", { style: { padding: 24, maxWidth: 360, margin: "0 auto" }, children: [
459
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("h1", { style: { marginBottom: 8 }, children: name }),
460
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { style: { opacity: 0.7, marginBottom: 24 }, children: "Entre na sua conta" }),
461
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(OAuthErrorBanner, {}),
462
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(GoogleSignInButton, { onClick: f.loginWithGoogle, testId: "login-oauth-google" }),
463
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
464
+ "div",
465
+ {
466
+ "aria-hidden": "true",
467
+ style: {
468
+ display: "flex",
469
+ alignItems: "center",
470
+ gap: 8,
471
+ margin: "16px 0",
472
+ color: "rgba(0,0,0,0.45)",
473
+ fontSize: 12
474
+ },
475
+ children: [
476
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { style: { flex: 1, height: 1, background: "rgba(0,0,0,0.1)" } }),
477
+ "ou",
478
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { style: { flex: 1, height: 1, background: "rgba(0,0,0,0.1)" } })
479
+ ]
480
+ }
481
+ ),
482
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("form", { onSubmit: (e) => {
323
483
  e.preventDefault();
324
484
  void f.submit();
325
485
  }, children: [
326
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("label", { style: { display: "block", marginBottom: 12 }, children: [
486
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("label", { style: { display: "block", marginBottom: 12 }, children: [
327
487
  "E-mail",
328
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
488
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
329
489
  "input",
330
490
  {
331
491
  "data-testid": "login-email",
@@ -335,11 +495,11 @@ function DefaultLoginScreen({ onNavigate }) {
335
495
  style: { display: "block", width: "100%" }
336
496
  }
337
497
  ),
338
- f.emailError && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("small", { style: { color: "#c00" }, children: f.emailError })
498
+ f.emailError && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("small", { style: { color: "#c00" }, children: f.emailError })
339
499
  ] }),
340
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("label", { style: { display: "block", marginBottom: 12 }, children: [
500
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("label", { style: { display: "block", marginBottom: 12 }, children: [
341
501
  "Senha",
342
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
502
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
343
503
  "input",
344
504
  {
345
505
  "data-testid": "login-password",
@@ -349,10 +509,10 @@ function DefaultLoginScreen({ onNavigate }) {
349
509
  style: { display: "block", width: "100%" }
350
510
  }
351
511
  ),
352
- f.passwordError && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("small", { style: { color: "#c00" }, children: f.passwordError })
512
+ f.passwordError && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("small", { style: { color: "#c00" }, children: f.passwordError })
353
513
  ] }),
354
- f.error && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { role: "alert", style: { color: "#c00", marginBottom: 12 }, children: f.error.message }),
355
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
514
+ f.error && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { role: "alert", style: { color: "#c00", marginBottom: 12 }, children: f.error.message }),
515
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
356
516
  "button",
357
517
  {
358
518
  "data-testid": "login-submit",
@@ -371,42 +531,42 @@ function DefaultLoginScreen({ onNavigate }) {
371
531
  }
372
532
  )
373
533
  ] }),
374
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { style: { marginTop: 16, display: "flex", justifyContent: "space-between" }, children: [
375
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { "data-testid": "login-goto-signup", type: "button", onClick: () => onNavigate("signup"), style: { background: "none", border: "none", cursor: "pointer" }, children: "Criar conta" }),
376
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { "data-testid": "login-goto-forgot", type: "button", onClick: () => onNavigate("forgot"), style: { background: "none", border: "none", cursor: "pointer" }, children: "Esqueci senha" })
534
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { style: { marginTop: 16, display: "flex", justifyContent: "space-between" }, children: [
535
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { "data-testid": "login-goto-signup", type: "button", onClick: () => onNavigate("signup"), style: { background: "none", border: "none", cursor: "pointer" }, children: "Criar conta" }),
536
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { "data-testid": "login-goto-forgot", type: "button", onClick: () => onNavigate("forgot"), style: { background: "none", border: "none", cursor: "pointer" }, children: "Esqueci senha" })
377
537
  ] })
378
538
  ] });
379
539
  }
380
540
 
381
541
  // src/hooks/useSignupForm.ts
382
- var import_react7 = require("react");
542
+ var import_react8 = require("react");
383
543
  var import_sdk6 = require("@hook-sdk/sdk");
384
544
  var EMAIL_RE2 = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
385
545
  var MIN_PASSWORD2 = 8;
386
546
  function useSignupForm() {
387
547
  const { auth } = (0, import_sdk6.useHook)();
388
- const [name, setName] = (0, import_react7.useState)("");
389
- const [email, setEmail] = (0, import_react7.useState)("");
390
- const [password, setPassword] = (0, import_react7.useState)("");
391
- const [submitting, setSubmitting] = (0, import_react7.useState)(false);
392
- const [error, setError] = (0, import_react7.useState)(null);
393
- const nameError = (0, import_react7.useMemo)(() => {
548
+ const [name, setName] = (0, import_react8.useState)("");
549
+ const [email, setEmail] = (0, import_react8.useState)("");
550
+ const [password, setPassword] = (0, import_react8.useState)("");
551
+ const [submitting, setSubmitting] = (0, import_react8.useState)(false);
552
+ const [error, setError] = (0, import_react8.useState)(null);
553
+ const nameError = (0, import_react8.useMemo)(() => {
394
554
  if (name.length === 0) return null;
395
555
  if (name.trim().length < 2) return "Nome muito curto.";
396
556
  return null;
397
557
  }, [name]);
398
- const emailError = (0, import_react7.useMemo)(() => {
558
+ const emailError = (0, import_react8.useMemo)(() => {
399
559
  if (email.length === 0) return null;
400
560
  if (!EMAIL_RE2.test(email)) return "Formato de e-mail inv\xE1lido.";
401
561
  return null;
402
562
  }, [email]);
403
- const passwordError = (0, import_react7.useMemo)(() => {
563
+ const passwordError = (0, import_react8.useMemo)(() => {
404
564
  if (password.length === 0) return null;
405
565
  if (password.length < MIN_PASSWORD2) return `M\xEDnimo de ${MIN_PASSWORD2} caracteres.`;
406
566
  return null;
407
567
  }, [password]);
408
568
  const canSubmit = name.trim().length >= 2 && email.length > 0 && password.length >= MIN_PASSWORD2 && nameError === null && emailError === null && passwordError === null && !submitting;
409
- const submit = (0, import_react7.useCallback)(async () => {
569
+ const submit = (0, import_react8.useCallback)(async () => {
410
570
  if (!canSubmit) return false;
411
571
  setSubmitting(true);
412
572
  setError(null);
@@ -433,61 +593,83 @@ function useSignupForm() {
433
593
  submit,
434
594
  submitting,
435
595
  canSubmit,
436
- error
596
+ error,
597
+ loginWithGoogle: () => auth.loginWithGoogle()
437
598
  };
438
599
  }
439
600
 
440
601
  // src/defaults/DefaultSignupScreen.tsx
441
- var import_jsx_runtime9 = require("react/jsx-runtime");
602
+ var import_jsx_runtime11 = require("react/jsx-runtime");
442
603
  function DefaultSignupScreen({ onNavigate }) {
443
604
  const { name } = useTemplateConfig();
444
605
  const f = useSignupForm();
445
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("main", { style: { padding: 24, maxWidth: 360, margin: "0 auto" }, children: [
446
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("h1", { style: { marginBottom: 8 }, children: name }),
447
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("p", { style: { opacity: 0.7, marginBottom: 24 }, children: "Criar sua conta" }),
448
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("form", { onSubmit: (e) => {
606
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("main", { style: { padding: 24, maxWidth: 360, margin: "0 auto" }, children: [
607
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("h1", { style: { marginBottom: 8 }, children: name }),
608
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { style: { opacity: 0.7, marginBottom: 24 }, children: "Criar sua conta" }),
609
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(OAuthErrorBanner, {}),
610
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(GoogleSignInButton, { onClick: f.loginWithGoogle, testId: "signup-oauth-google" }),
611
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
612
+ "div",
613
+ {
614
+ "aria-hidden": "true",
615
+ style: {
616
+ display: "flex",
617
+ alignItems: "center",
618
+ gap: 8,
619
+ margin: "16px 0",
620
+ color: "rgba(0,0,0,0.45)",
621
+ fontSize: 12
622
+ },
623
+ children: [
624
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { style: { flex: 1, height: 1, background: "rgba(0,0,0,0.1)" } }),
625
+ "ou",
626
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { style: { flex: 1, height: 1, background: "rgba(0,0,0,0.1)" } })
627
+ ]
628
+ }
629
+ ),
630
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("form", { onSubmit: (e) => {
449
631
  e.preventDefault();
450
632
  void f.submit();
451
633
  }, children: [
452
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("label", { style: { display: "block", marginBottom: 12 }, children: [
634
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("label", { style: { display: "block", marginBottom: 12 }, children: [
453
635
  "Nome",
454
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("input", { "data-testid": "signup-name", value: f.name, onChange: (e) => f.setName(e.target.value), style: { display: "block", width: "100%" } }),
455
- f.nameError && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("small", { style: { color: "#c00" }, children: f.nameError })
636
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("input", { "data-testid": "signup-name", value: f.name, onChange: (e) => f.setName(e.target.value), style: { display: "block", width: "100%" } }),
637
+ f.nameError && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("small", { style: { color: "#c00" }, children: f.nameError })
456
638
  ] }),
457
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("label", { style: { display: "block", marginBottom: 12 }, children: [
639
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("label", { style: { display: "block", marginBottom: 12 }, children: [
458
640
  "E-mail",
459
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("input", { "data-testid": "signup-email", type: "email", value: f.email, onChange: (e) => f.setEmail(e.target.value), style: { display: "block", width: "100%" } }),
460
- f.emailError && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("small", { style: { color: "#c00" }, children: f.emailError })
641
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("input", { "data-testid": "signup-email", type: "email", value: f.email, onChange: (e) => f.setEmail(e.target.value), style: { display: "block", width: "100%" } }),
642
+ f.emailError && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("small", { style: { color: "#c00" }, children: f.emailError })
461
643
  ] }),
462
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("label", { style: { display: "block", marginBottom: 12 }, children: [
644
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("label", { style: { display: "block", marginBottom: 12 }, children: [
463
645
  "Senha",
464
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("input", { "data-testid": "signup-password", type: "password", value: f.password, onChange: (e) => f.setPassword(e.target.value), style: { display: "block", width: "100%" } }),
465
- f.passwordError && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("small", { style: { color: "#c00" }, children: f.passwordError })
646
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("input", { "data-testid": "signup-password", type: "password", value: f.password, onChange: (e) => f.setPassword(e.target.value), style: { display: "block", width: "100%" } }),
647
+ f.passwordError && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("small", { style: { color: "#c00" }, children: f.passwordError })
466
648
  ] }),
467
- f.error && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { role: "alert", style: { color: "#c00", marginBottom: 12 }, children: f.error.message }),
468
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("button", { "data-testid": "signup-submit", type: "submit", disabled: !f.canSubmit, style: { width: "100%", padding: 12, background: "var(--hook-color-primary)", color: "#fff", border: "none", borderRadius: 8, opacity: f.canSubmit ? 1 : 0.5 }, children: f.submitting ? "Criando..." : "Criar conta" })
649
+ f.error && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { role: "alert", style: { color: "#c00", marginBottom: 12 }, children: f.error.message }),
650
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { "data-testid": "signup-submit", type: "submit", disabled: !f.canSubmit, style: { width: "100%", padding: 12, background: "var(--hook-color-primary)", color: "#fff", border: "none", borderRadius: 8, opacity: f.canSubmit ? 1 : 0.5 }, children: f.submitting ? "Criando..." : "Criar conta" })
469
651
  ] }),
470
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { style: { marginTop: 16 }, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("button", { "data-testid": "signup-goto-login", type: "button", onClick: () => onNavigate("login"), style: { background: "none", border: "none", cursor: "pointer" }, children: "J\xE1 tem conta? Entre" }) })
652
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { style: { marginTop: 16 }, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { "data-testid": "signup-goto-login", type: "button", onClick: () => onNavigate("login"), style: { background: "none", border: "none", cursor: "pointer" }, children: "J\xE1 tem conta? Entre" }) })
471
653
  ] });
472
654
  }
473
655
 
474
656
  // src/hooks/useForgotForm.ts
475
- var import_react8 = require("react");
657
+ var import_react9 = require("react");
476
658
  var import_sdk7 = require("@hook-sdk/sdk");
477
659
  var EMAIL_RE3 = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
478
660
  function useForgotForm() {
479
661
  const { auth } = (0, import_sdk7.useHook)();
480
- const [email, setEmail] = (0, import_react8.useState)("");
481
- const [submitting, setSubmitting] = (0, import_react8.useState)(false);
482
- const [sent, setSent] = (0, import_react8.useState)(false);
483
- const [error, setError] = (0, import_react8.useState)(null);
484
- const emailError = (0, import_react8.useMemo)(() => {
662
+ const [email, setEmail] = (0, import_react9.useState)("");
663
+ const [submitting, setSubmitting] = (0, import_react9.useState)(false);
664
+ const [sent, setSent] = (0, import_react9.useState)(false);
665
+ const [error, setError] = (0, import_react9.useState)(null);
666
+ const emailError = (0, import_react9.useMemo)(() => {
485
667
  if (email.length === 0) return null;
486
668
  if (!EMAIL_RE3.test(email)) return "Formato de e-mail inv\xE1lido.";
487
669
  return null;
488
670
  }, [email]);
489
671
  const canSubmit = email.length > 0 && emailError === null && !submitting;
490
- const submit = (0, import_react8.useCallback)(async () => {
672
+ const submit = (0, import_react9.useCallback)(async () => {
491
673
  if (!canSubmit) return false;
492
674
  setSubmitting(true);
493
675
  setError(null);
@@ -515,66 +697,66 @@ function useForgotForm() {
515
697
  }
516
698
 
517
699
  // src/defaults/DefaultForgotScreen.tsx
518
- var import_jsx_runtime10 = require("react/jsx-runtime");
700
+ var import_jsx_runtime12 = require("react/jsx-runtime");
519
701
  function DefaultForgotScreen({ onNavigate }) {
520
702
  const { name } = useTemplateConfig();
521
703
  const f = useForgotForm();
522
704
  if (f.sent) {
523
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("main", { style: { padding: 24, maxWidth: 360, margin: "0 auto", textAlign: "center" }, children: [
524
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("h1", { children: "Verifique seu e-mail" }),
525
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { style: { opacity: 0.7 }, children: "Enviamos um link pra redefinir sua senha." }),
526
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { "data-testid": "forgot-back-login", type: "button", onClick: () => onNavigate("login"), children: "Voltar pro login" })
705
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("main", { style: { padding: 24, maxWidth: 360, margin: "0 auto", textAlign: "center" }, children: [
706
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("h1", { children: "Verifique seu e-mail" }),
707
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { style: { opacity: 0.7 }, children: "Enviamos um link pra redefinir sua senha." }),
708
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("button", { "data-testid": "forgot-back-login", type: "button", onClick: () => onNavigate("login"), children: "Voltar pro login" })
527
709
  ] });
528
710
  }
529
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("main", { style: { padding: 24, maxWidth: 360, margin: "0 auto" }, children: [
530
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("h1", { style: { marginBottom: 8 }, children: name }),
531
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { style: { opacity: 0.7, marginBottom: 24 }, children: "Redefinir senha" }),
532
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("form", { onSubmit: (e) => {
711
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("main", { style: { padding: 24, maxWidth: 360, margin: "0 auto" }, children: [
712
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("h1", { style: { marginBottom: 8 }, children: name }),
713
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { style: { opacity: 0.7, marginBottom: 24 }, children: "Redefinir senha" }),
714
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("form", { onSubmit: (e) => {
533
715
  e.preventDefault();
534
716
  void f.submit();
535
717
  }, children: [
536
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("label", { style: { display: "block", marginBottom: 12 }, children: [
718
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("label", { style: { display: "block", marginBottom: 12 }, children: [
537
719
  "E-mail",
538
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("input", { "data-testid": "forgot-email", type: "email", value: f.email, onChange: (e) => f.setEmail(e.target.value), style: { display: "block", width: "100%" } }),
539
- f.emailError && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("small", { style: { color: "#c00" }, children: f.emailError })
720
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("input", { "data-testid": "forgot-email", type: "email", value: f.email, onChange: (e) => f.setEmail(e.target.value), style: { display: "block", width: "100%" } }),
721
+ f.emailError && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("small", { style: { color: "#c00" }, children: f.emailError })
540
722
  ] }),
541
- f.error && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { role: "alert", style: { color: "#c00", marginBottom: 12 }, children: f.error.message }),
542
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { "data-testid": "forgot-submit", type: "submit", disabled: !f.canSubmit, style: { width: "100%", padding: 12, background: "var(--hook-color-primary)", color: "#fff", border: "none", borderRadius: 8, opacity: f.canSubmit ? 1 : 0.5 }, children: f.submitting ? "Enviando..." : "Enviar link" })
723
+ f.error && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { role: "alert", style: { color: "#c00", marginBottom: 12 }, children: f.error.message }),
724
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("button", { "data-testid": "forgot-submit", type: "submit", disabled: !f.canSubmit, style: { width: "100%", padding: 12, background: "var(--hook-color-primary)", color: "#fff", border: "none", borderRadius: 8, opacity: f.canSubmit ? 1 : 0.5 }, children: f.submitting ? "Enviando..." : "Enviar link" })
543
725
  ] }),
544
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { style: { marginTop: 16 }, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { "data-testid": "forgot-goto-login", type: "button", onClick: () => onNavigate("login"), style: { background: "none", border: "none", cursor: "pointer" }, children: "Voltar pro login" }) })
726
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { style: { marginTop: 16 }, children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("button", { "data-testid": "forgot-goto-login", type: "button", onClick: () => onNavigate("login"), style: { background: "none", border: "none", cursor: "pointer" }, children: "Voltar pro login" }) })
545
727
  ] });
546
728
  }
547
729
 
548
730
  // src/hooks/useResetForm.ts
549
- var import_react9 = require("react");
731
+ var import_react10 = require("react");
550
732
  var import_sdk8 = require("@hook-sdk/sdk");
551
733
  var MIN_PASSWORD3 = 12;
552
734
  function useResetForm() {
553
735
  const { auth } = (0, import_sdk8.useHook)();
554
- const [token, setToken] = (0, import_react9.useState)(null);
555
- const [password, setPassword] = (0, import_react9.useState)("");
556
- const [confirm, setConfirm] = (0, import_react9.useState)("");
557
- const [submitting, setSubmitting] = (0, import_react9.useState)(false);
558
- const [done, setDone] = (0, import_react9.useState)(false);
559
- const [error, setError] = (0, import_react9.useState)(null);
560
- (0, import_react9.useEffect)(() => {
736
+ const [token, setToken] = (0, import_react10.useState)(null);
737
+ const [password, setPassword] = (0, import_react10.useState)("");
738
+ const [confirm, setConfirm] = (0, import_react10.useState)("");
739
+ const [submitting, setSubmitting] = (0, import_react10.useState)(false);
740
+ const [done, setDone] = (0, import_react10.useState)(false);
741
+ const [error, setError] = (0, import_react10.useState)(null);
742
+ (0, import_react10.useEffect)(() => {
561
743
  if (typeof window === "undefined") return;
562
744
  const params = new URLSearchParams(window.location.search);
563
745
  const t = params.get("token");
564
746
  setToken(t && t.length > 0 ? t : null);
565
747
  }, []);
566
- const passwordError = (0, import_react9.useMemo)(() => {
748
+ const passwordError = (0, import_react10.useMemo)(() => {
567
749
  if (password.length === 0) return null;
568
750
  if (password.length < MIN_PASSWORD3) return `M\xEDnimo de ${MIN_PASSWORD3} caracteres.`;
569
751
  return null;
570
752
  }, [password]);
571
- const confirmError = (0, import_react9.useMemo)(() => {
753
+ const confirmError = (0, import_react10.useMemo)(() => {
572
754
  if (confirm.length === 0) return null;
573
755
  if (confirm !== password) return "Senhas n\xE3o coincidem.";
574
756
  return null;
575
757
  }, [confirm, password]);
576
758
  const canSubmit = token !== null && password.length >= MIN_PASSWORD3 && confirm === password && passwordError === null && confirmError === null && !submitting && !done;
577
- const submit = (0, import_react9.useCallback)(async () => {
759
+ const submit = (0, import_react10.useCallback)(async () => {
578
760
  if (!canSubmit || token === null) return;
579
761
  setSubmitting(true);
580
762
  setError(null);
@@ -610,67 +792,67 @@ function useResetForm() {
610
792
  }
611
793
 
612
794
  // src/defaults/DefaultResetScreen.tsx
613
- var import_jsx_runtime11 = require("react/jsx-runtime");
795
+ var import_jsx_runtime13 = require("react/jsx-runtime");
614
796
  function DefaultResetScreen({ onNavigate }) {
615
797
  const { name } = useTemplateConfig();
616
798
  const f = useResetForm();
617
799
  if (f.done) {
618
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("main", { style: { padding: 24, maxWidth: 360, margin: "0 auto", textAlign: "center" }, children: [
619
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("h1", { children: "Senha alterada" }),
620
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { style: { opacity: 0.7 }, children: "Agora \xE9 s\xF3 fazer login com a nova senha." }),
621
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { "data-testid": "reset-back-login", type: "button", onClick: () => onNavigate("login"), children: "Ir pro login" })
800
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("main", { style: { padding: 24, maxWidth: 360, margin: "0 auto", textAlign: "center" }, children: [
801
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("h1", { children: "Senha alterada" }),
802
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { style: { opacity: 0.7 }, children: "Agora \xE9 s\xF3 fazer login com a nova senha." }),
803
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("button", { "data-testid": "reset-back-login", type: "button", onClick: () => onNavigate("login"), children: "Ir pro login" })
622
804
  ] });
623
805
  }
624
806
  if (f.token === null) {
625
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("main", { style: { padding: 24, maxWidth: 360, margin: "0 auto", textAlign: "center" }, children: [
626
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("h1", { children: "Link inv\xE1lido" }),
627
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { style: { opacity: 0.7 }, children: "Pe\xE7a um novo link de reset." }),
628
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { "data-testid": "reset-goto-forgot", type: "button", onClick: () => onNavigate("forgot"), children: "Pedir novo link" })
807
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("main", { style: { padding: 24, maxWidth: 360, margin: "0 auto", textAlign: "center" }, children: [
808
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("h1", { children: "Link inv\xE1lido" }),
809
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { style: { opacity: 0.7 }, children: "Pe\xE7a um novo link de reset." }),
810
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("button", { "data-testid": "reset-goto-forgot", type: "button", onClick: () => onNavigate("forgot"), children: "Pedir novo link" })
629
811
  ] });
630
812
  }
631
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("main", { style: { padding: 24, maxWidth: 360, margin: "0 auto" }, children: [
632
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("h1", { style: { marginBottom: 8 }, children: name }),
633
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { style: { opacity: 0.7, marginBottom: 24 }, children: "Escolha uma nova senha" }),
634
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("form", { onSubmit: (e) => {
813
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("main", { style: { padding: 24, maxWidth: 360, margin: "0 auto" }, children: [
814
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("h1", { style: { marginBottom: 8 }, children: name }),
815
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { style: { opacity: 0.7, marginBottom: 24 }, children: "Escolha uma nova senha" }),
816
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("form", { onSubmit: (e) => {
635
817
  e.preventDefault();
636
818
  void f.submit();
637
819
  }, children: [
638
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("label", { style: { display: "block", marginBottom: 12 }, children: [
820
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("label", { style: { display: "block", marginBottom: 12 }, children: [
639
821
  "Nova senha",
640
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("input", { "data-testid": "reset-password", type: "password", value: f.password, onChange: (e) => f.setPassword(e.target.value), style: { display: "block", width: "100%" }, autoComplete: "new-password" }),
641
- f.passwordError && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("small", { style: { color: "#c00" }, children: f.passwordError })
822
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("input", { "data-testid": "reset-password", type: "password", value: f.password, onChange: (e) => f.setPassword(e.target.value), style: { display: "block", width: "100%" }, autoComplete: "new-password" }),
823
+ f.passwordError && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("small", { style: { color: "#c00" }, children: f.passwordError })
642
824
  ] }),
643
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("label", { style: { display: "block", marginBottom: 12 }, children: [
825
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("label", { style: { display: "block", marginBottom: 12 }, children: [
644
826
  "Confirmar senha",
645
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("input", { "data-testid": "reset-confirm", type: "password", value: f.confirm, onChange: (e) => f.setConfirm(e.target.value), style: { display: "block", width: "100%" }, autoComplete: "new-password" }),
646
- f.confirmError && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("small", { style: { color: "#c00" }, children: f.confirmError })
827
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("input", { "data-testid": "reset-confirm", type: "password", value: f.confirm, onChange: (e) => f.setConfirm(e.target.value), style: { display: "block", width: "100%" }, autoComplete: "new-password" }),
828
+ f.confirmError && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("small", { style: { color: "#c00" }, children: f.confirmError })
647
829
  ] }),
648
- f.error && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { role: "alert", style: { color: "#c00", marginBottom: 12 }, children: f.error.message }),
649
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { "data-testid": "reset-submit", type: "submit", disabled: !f.canSubmit, style: { width: "100%", padding: 12, background: "var(--hook-color-primary)", color: "#fff", border: "none", borderRadius: 8, opacity: f.canSubmit ? 1 : 0.5 }, children: f.submitting ? "Alterando..." : "Alterar senha" })
830
+ f.error && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { role: "alert", style: { color: "#c00", marginBottom: 12 }, children: f.error.message }),
831
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("button", { "data-testid": "reset-submit", type: "submit", disabled: !f.canSubmit, style: { width: "100%", padding: 12, background: "var(--hook-color-primary)", color: "#fff", border: "none", borderRadius: 8, opacity: f.canSubmit ? 1 : 0.5 }, children: f.submitting ? "Alterando..." : "Alterar senha" })
650
832
  ] })
651
833
  ] });
652
834
  }
653
835
 
654
836
  // src/defaults/DefaultPaywall.tsx
655
- var import_react10 = require("react");
656
- var import_jsx_runtime12 = require("react/jsx-runtime");
837
+ var import_react11 = require("react");
838
+ var import_jsx_runtime14 = require("react/jsx-runtime");
657
839
  function DefaultPaywall() {
658
840
  const config = useTemplateConfig();
659
841
  const { checkout, opening, error } = usePaywallState();
660
842
  const p = config.subscription.paywall_config;
661
- const [cpf, setCpf] = (0, import_react10.useState)("");
843
+ const [cpf, setCpf] = (0, import_react11.useState)("");
662
844
  const cpfDigits = cpf.replace(/\D/g, "");
663
845
  const canCheckout = cpfDigits.length === 11 && !opening;
664
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("main", { style: { padding: 24, maxWidth: 440, margin: "0 auto", textAlign: "center" }, children: [
665
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("h1", { style: { marginBottom: 8 }, children: p.title }),
666
- p.subtitle && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { style: { opacity: 0.7, marginBottom: 24 }, children: p.subtitle }),
667
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("ul", { style: { listStyle: "none", padding: 0, textAlign: "left", marginBottom: 24 }, children: p.benefits.map((b) => /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("li", { style: { padding: "8px 0", display: "flex", alignItems: "center" }, children: [
668
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { "aria-hidden": true, style: { marginRight: 8 }, children: "\u2713" }),
669
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { children: b })
846
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("main", { style: { padding: 24, maxWidth: 440, margin: "0 auto", textAlign: "center" }, children: [
847
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("h1", { style: { marginBottom: 8 }, children: p.title }),
848
+ p.subtitle && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { style: { opacity: 0.7, marginBottom: 24 }, children: p.subtitle }),
849
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("ul", { style: { listStyle: "none", padding: 0, textAlign: "left", marginBottom: 24 }, children: p.benefits.map((b) => /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("li", { style: { padding: "8px 0", display: "flex", alignItems: "center" }, children: [
850
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { "aria-hidden": true, style: { marginRight: 8 }, children: "\u2713" }),
851
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { children: b })
670
852
  ] }, b)) }),
671
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { style: { textAlign: "left", marginBottom: 16 }, children: [
672
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("label", { style: { display: "block", fontSize: 14, opacity: 0.7, marginBottom: 4 }, children: "Seu CPF (pra emiss\xE3o de recibo)" }),
673
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
853
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { style: { textAlign: "left", marginBottom: 16 }, children: [
854
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("label", { style: { display: "block", fontSize: 14, opacity: 0.7, marginBottom: 4 }, children: "Seu CPF (pra emiss\xE3o de recibo)" }),
855
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
674
856
  "input",
675
857
  {
676
858
  "data-testid": "paywall-cpf",
@@ -683,8 +865,8 @@ function DefaultPaywall() {
683
865
  }
684
866
  )
685
867
  ] }),
686
- error && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { role: "alert", style: { color: "#c00", marginBottom: 12 }, children: error.message }),
687
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
868
+ error && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { role: "alert", style: { color: "#c00", marginBottom: 12 }, children: error.message }),
869
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
688
870
  "button",
689
871
  {
690
872
  "data-testid": "paywall-cta",
@@ -705,21 +887,21 @@ function DefaultPaywall() {
705
887
  children: opening ? "Abrindo..." : p.cta
706
888
  }
707
889
  ),
708
- p.priceHint && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { style: { opacity: 0.6, marginTop: 12 }, children: p.priceHint }),
709
- p.footerNote && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { style: { opacity: 0.5, marginTop: 16, fontSize: 12 }, children: p.footerNote })
890
+ p.priceHint && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { style: { opacity: 0.6, marginTop: 12 }, children: p.priceHint }),
891
+ p.footerNote && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { style: { opacity: 0.5, marginTop: 16, fontSize: 12 }, children: p.footerNote })
710
892
  ] });
711
893
  }
712
894
 
713
895
  // src/AppRoot.tsx
714
- var import_jsx_runtime13 = require("react/jsx-runtime");
896
+ var import_jsx_runtime15 = require("react/jsx-runtime");
715
897
  var BACKOFF_MS = [2e3, 5e3, 1e4, 2e4, 4e4];
716
898
  function PaymentReturnHandler({ children }) {
717
899
  const { subscription } = (0, import_sdk9.useHook)();
718
- const subRef = (0, import_react11.useRef)(subscription);
900
+ const subRef = (0, import_react12.useRef)(subscription);
719
901
  subRef.current = subscription;
720
- const runIdRef = (0, import_react11.useRef)(0);
721
- const [state, setState] = (0, import_react11.useState)("idle");
722
- const runPoll = (0, import_react11.useCallback)(() => {
902
+ const runIdRef = (0, import_react12.useRef)(0);
903
+ const [state, setState] = (0, import_react12.useState)("idle");
904
+ const runPoll = (0, import_react12.useCallback)(() => {
723
905
  const runId = ++runIdRef.current;
724
906
  setState("confirming");
725
907
  let attempts = 0;
@@ -748,7 +930,7 @@ function PaymentReturnHandler({ children }) {
748
930
  };
749
931
  void tick();
750
932
  }, []);
751
- (0, import_react11.useEffect)(() => {
933
+ (0, import_react12.useEffect)(() => {
752
934
  if (typeof window === "undefined") return;
753
935
  const url = new URL(window.location.href);
754
936
  if (url.searchParams.get("paymentReturn") !== "1") return;
@@ -758,7 +940,7 @@ function PaymentReturnHandler({ children }) {
758
940
  };
759
941
  }, [runPoll]);
760
942
  if (state === "confirming") {
761
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
943
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
762
944
  "div",
763
945
  {
764
946
  role: "status",
@@ -769,9 +951,9 @@ function PaymentReturnHandler({ children }) {
769
951
  );
770
952
  }
771
953
  if (state === "waiting") {
772
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { role: "status", "aria-live": "polite", style: overlayStyle, children: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { style: { maxWidth: 320, textAlign: "center", lineHeight: 1.5 }, children: [
773
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { style: { marginBottom: 16 }, children: "Pagamento aceito. Estamos confirmando com o banco \u2014 pode levar alguns minutos." }),
774
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
954
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { role: "status", "aria-live": "polite", style: overlayStyle, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { style: { maxWidth: 320, textAlign: "center", lineHeight: 1.5 }, children: [
955
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { style: { marginBottom: 16 }, children: "Pagamento aceito. Estamos confirmando com o banco \u2014 pode levar alguns minutos." }),
956
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
775
957
  "button",
776
958
  {
777
959
  type: "button",
@@ -782,7 +964,7 @@ function PaymentReturnHandler({ children }) {
782
964
  )
783
965
  ] }) });
784
966
  }
785
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_jsx_runtime13.Fragment, { children });
967
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_jsx_runtime15.Fragment, { children });
786
968
  }
787
969
  var overlayStyle = {
788
970
  position: "fixed",
@@ -815,29 +997,129 @@ function AppRoot({
815
997
  Reset = DefaultResetScreen,
816
998
  Paywall = DefaultPaywall
817
999
  }) {
818
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(PaymentReturnHandler, { children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(TemplateConfigProvider, { config, children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(ErrorBoundary, { children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(ThemeProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(AuthGate, { Login, Signup, Forgot, Reset, children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(PersistedKeysPrefetch, { children: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(SubscriptionGate, { Paywall, children: [
1000
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(PaymentReturnHandler, { children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(TemplateConfigProvider, { config, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(ErrorBoundary, { children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(ThemeProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(AuthGate, { Login, Signup, Forgot, Reset, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(PersistedKeysPrefetch, { children: /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(SubscriptionGate, { Paywall, children: [
819
1001
  children,
820
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(PushPrompt, {})
1002
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(PushPrompt, {})
821
1003
  ] }) }) }) }) }) }) });
822
1004
  }
823
1005
 
1006
+ // src/hooks/usePush.ts
1007
+ var import_react13 = require("react");
1008
+ var import_sdk10 = require("@hook-sdk/sdk");
1009
+ function detectIosNeedsInstall() {
1010
+ if (typeof navigator === "undefined" || typeof window === "undefined") return false;
1011
+ const ua = navigator.userAgent || "";
1012
+ const isIos = /iPhone|iPad|iPod/.test(ua);
1013
+ if (!isIos) return false;
1014
+ const mm = window.matchMedia?.("(display-mode: standalone)");
1015
+ const standalone = mm?.matches === true;
1016
+ const legacyStandalone = typeof navigator.standalone === "boolean" ? navigator.standalone : false;
1017
+ return !(standalone || legacyStandalone);
1018
+ }
1019
+ function deriveState(push) {
1020
+ if (!push.isAvailable()) {
1021
+ if (detectIosNeedsInstall()) return { kind: "ios_needs_install" };
1022
+ return { kind: "unsupported" };
1023
+ }
1024
+ const status = push.status();
1025
+ if (status === "granted") return { kind: "subscribed" };
1026
+ if (status === "denied") return { kind: "denied" };
1027
+ if (status === "unsupported") {
1028
+ if (detectIosNeedsInstall()) return { kind: "ios_needs_install" };
1029
+ return { kind: "unsupported" };
1030
+ }
1031
+ return { kind: "prompt" };
1032
+ }
1033
+ function usePush() {
1034
+ const { push } = (0, import_sdk10.useHook)();
1035
+ const [state, setState] = (0, import_react13.useState)(() => deriveState(push));
1036
+ (0, import_react13.useEffect)(() => {
1037
+ setState(deriveState(push));
1038
+ }, [push]);
1039
+ const subscribe = (0, import_react13.useCallback)(async () => {
1040
+ try {
1041
+ await push.subscribe();
1042
+ setState({ kind: "subscribed" });
1043
+ } catch (e) {
1044
+ const code = e?.code ?? "push.unknown";
1045
+ const message = e?.message ?? "Push subscription failed";
1046
+ if (code === "push.permission_denied") setState({ kind: "denied" });
1047
+ else setState({ kind: "error", code, message });
1048
+ throw e;
1049
+ }
1050
+ }, [push]);
1051
+ const unsubscribe = (0, import_react13.useCallback)(async () => {
1052
+ try {
1053
+ await push.unsubscribe();
1054
+ setState({ kind: "prompt" });
1055
+ } catch (e) {
1056
+ setState({ kind: "error", code: e?.code ?? "push.unknown", message: e?.message ?? "failed" });
1057
+ throw e;
1058
+ }
1059
+ }, [push]);
1060
+ return { state, subscribe, unsubscribe };
1061
+ }
1062
+
1063
+ // src/components/PushPrompt.tsx
1064
+ var import_jsx_runtime16 = require("react/jsx-runtime");
1065
+ function PushPrompt2({ texts, onSubscribed, onDeclined, onInstallRequested, className }) {
1066
+ const { state, subscribe } = usePush();
1067
+ if (state.kind === "subscribed") return null;
1068
+ if (state.kind === "ios_needs_install") {
1069
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className, role: "region", "aria-label": texts.iosInstallTitle, children: [
1070
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("h3", { children: texts.iosInstallTitle }),
1071
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("p", { children: texts.iosInstallBody }),
1072
+ onInstallRequested && texts.iosInstallCta && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("button", { onClick: onInstallRequested, children: texts.iosInstallCta })
1073
+ ] });
1074
+ }
1075
+ if (state.kind === "denied") {
1076
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className, role: "region", "aria-label": texts.deniedTitle, children: [
1077
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("h3", { children: texts.deniedTitle }),
1078
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("p", { children: texts.deniedBody })
1079
+ ] });
1080
+ }
1081
+ if (state.kind === "unsupported") {
1082
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className, role: "region", children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("p", { children: texts.unsupportedBody }) });
1083
+ }
1084
+ if (state.kind === "error") {
1085
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className, role: "region", "aria-label": "error", children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("p", { children: state.message }) });
1086
+ }
1087
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className, role: "region", children: [
1088
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
1089
+ "button",
1090
+ {
1091
+ type: "button",
1092
+ onClick: async () => {
1093
+ try {
1094
+ await subscribe();
1095
+ onSubscribed?.();
1096
+ } catch {
1097
+ }
1098
+ },
1099
+ children: texts.cta
1100
+ }
1101
+ ),
1102
+ onDeclined && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("button", { type: "button", onClick: onDeclined, children: texts.declineCta })
1103
+ ] });
1104
+ }
1105
+
824
1106
  // src/defaults/EmptyState.tsx
825
- var import_jsx_runtime14 = require("react/jsx-runtime");
1107
+ var import_jsx_runtime17 = require("react/jsx-runtime");
826
1108
  function EmptyState({ title, description, action }) {
827
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { role: "status", style: { padding: 32, textAlign: "center" }, children: [
828
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("h2", { style: { marginBottom: 8 }, children: title }),
829
- description && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { style: { opacity: 0.7 }, children: description }),
830
- action && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { style: { marginTop: 16 }, children: action })
1109
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { role: "status", style: { padding: 32, textAlign: "center" }, children: [
1110
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("h2", { style: { marginBottom: 8 }, children: title }),
1111
+ description && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("p", { style: { opacity: 0.7 }, children: description }),
1112
+ action && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { style: { marginTop: 16 }, children: action })
831
1113
  ] });
832
1114
  }
833
1115
 
834
1116
  // src/hooks/useAuthPrimitives.ts
835
- var import_react12 = require("react");
836
- var import_sdk10 = require("@hook-sdk/sdk");
1117
+ var import_react14 = require("react");
1118
+ var import_sdk11 = require("@hook-sdk/sdk");
837
1119
  var warned = false;
838
1120
  function useAuthPrimitives() {
839
- const { auth } = (0, import_sdk10.useHook)();
840
- (0, import_react12.useEffect)(() => {
1121
+ const { auth } = (0, import_sdk11.useHook)();
1122
+ (0, import_react14.useEffect)(() => {
841
1123
  if (!warned && process.env.NODE_ENV !== "production") {
842
1124
  warned = true;
843
1125
  console.warn(
@@ -859,37 +1141,63 @@ function useAuthPrimitives() {
859
1141
  }
860
1142
 
861
1143
  // src/hooks/useSubscription.ts
862
- var import_sdk11 = require("@hook-sdk/sdk");
1144
+ var import_sdk12 = require("@hook-sdk/sdk");
863
1145
  function useSubscription() {
864
- const { subscription } = (0, import_sdk11.useHook)();
1146
+ const { subscription } = (0, import_sdk12.useHook)();
865
1147
  return {
866
1148
  status: subscription.status()
867
1149
  };
868
1150
  }
869
1151
 
870
- // src/hooks/usePush.ts
871
- var import_sdk12 = require("@hook-sdk/sdk");
872
- function usePush() {
873
- const { push } = (0, import_sdk12.useHook)();
874
- return {
875
- status: push.status(),
876
- subscribe: push.subscribe,
877
- unsubscribe: push.unsubscribe
878
- };
1152
+ // src/hooks/useReminders.ts
1153
+ var import_react15 = require("react");
1154
+ var import_sdk13 = require("@hook-sdk/sdk");
1155
+ function useReminders() {
1156
+ const { push } = (0, import_sdk13.useHook)();
1157
+ const r = push.reminders;
1158
+ const [reminders, setReminders] = (0, import_react15.useState)([]);
1159
+ const [loading, setLoading] = (0, import_react15.useState)(true);
1160
+ const reload = (0, import_react15.useCallback)(async () => {
1161
+ setLoading(true);
1162
+ try {
1163
+ const next = await r.list();
1164
+ setReminders(next);
1165
+ } finally {
1166
+ setLoading(false);
1167
+ }
1168
+ }, [r]);
1169
+ (0, import_react15.useEffect)(() => {
1170
+ void reload();
1171
+ }, [reload]);
1172
+ const setReminder = (0, import_react15.useCallback)(async (input) => {
1173
+ await r.set(input);
1174
+ await reload();
1175
+ }, [r, reload]);
1176
+ const deleteReminder = (0, import_react15.useCallback)(async (slot) => {
1177
+ await r.delete(slot);
1178
+ await reload();
1179
+ }, [r, reload]);
1180
+ const schedule = (0, import_react15.useCallback)(async (items) => {
1181
+ return r.schedule(items);
1182
+ }, [r]);
1183
+ const setFallbacks = (0, import_react15.useCallback)(async (items) => {
1184
+ return r.setFallbacks(items);
1185
+ }, [r]);
1186
+ return { reminders, loading, setReminder, deleteReminder, schedule, setFallbacks };
879
1187
  }
880
1188
 
881
1189
  // src/hooks/useToast.ts
882
- var import_react13 = require("react");
1190
+ var import_react16 = require("react");
883
1191
  function useToast() {
884
- const [items, setItems] = (0, import_react13.useState)([]);
885
- const show = (0, import_react13.useCallback)((message, kind = "info") => {
1192
+ const [items, setItems] = (0, import_react16.useState)([]);
1193
+ const show = (0, import_react16.useCallback)((message, kind = "info") => {
886
1194
  const id = `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
887
1195
  setItems((prev) => [...prev, { id, message, kind }]);
888
1196
  setTimeout(() => {
889
1197
  setItems((prev) => prev.filter((t) => t.id !== id));
890
1198
  }, 4e3);
891
1199
  }, []);
892
- const dismiss = (0, import_react13.useCallback)((id) => {
1200
+ const dismiss = (0, import_react16.useCallback)((id) => {
893
1201
  setItems((prev) => prev.filter((t) => t.id !== id));
894
1202
  }, []);
895
1203
  return { items, show, dismiss };
@@ -905,12 +1213,14 @@ function useToast() {
905
1213
  EmptyState,
906
1214
  ErrorBoundary,
907
1215
  LoadingState,
1216
+ PushPrompt,
908
1217
  useAuth,
909
1218
  useAuthPrimitives,
910
1219
  useForgotForm,
911
1220
  useLoginForm,
912
1221
  usePaywallState,
913
1222
  usePush,
1223
+ useReminders,
914
1224
  useResetForm,
915
1225
  useSignupForm,
916
1226
  useSubscription,