@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.js CHANGED
@@ -1,5 +1,5 @@
1
1
  // src/AppRoot.tsx
2
- import { useCallback as useCallback6, useEffect as useEffect4, useRef, useState as useState8 } from "react";
2
+ import { useCallback as useCallback6, useEffect as useEffect5, useRef, useState as useState9 } from "react";
3
3
  import { useHook as useHook8 } from "@hook-sdk/sdk";
4
4
 
5
5
  // src/internal/TemplateConfigContext.tsx
@@ -263,25 +263,183 @@ function useLoginForm() {
263
263
  submit,
264
264
  submitting,
265
265
  canSubmit,
266
- error
266
+ error,
267
+ loginWithGoogle: () => auth.loginWithGoogle()
267
268
  };
268
269
  }
269
270
 
270
- // src/defaults/DefaultLoginScreen.tsx
271
+ // src/internal/GoogleSignInButton.tsx
271
272
  import { jsx as jsx8, jsxs as jsxs2 } from "react/jsx-runtime";
273
+ function GoogleSignInButton({
274
+ onClick,
275
+ testId = "oauth-google",
276
+ label = "Continuar com Google"
277
+ }) {
278
+ return /* @__PURE__ */ jsxs2(
279
+ "button",
280
+ {
281
+ "data-testid": testId,
282
+ type: "button",
283
+ onClick,
284
+ style: {
285
+ width: "100%",
286
+ padding: "10px 12px",
287
+ display: "flex",
288
+ alignItems: "center",
289
+ justifyContent: "center",
290
+ gap: 10,
291
+ background: "#fff",
292
+ color: "#1f1f1f",
293
+ border: "1px solid #dadce0",
294
+ borderRadius: 8,
295
+ cursor: "pointer",
296
+ fontSize: 14,
297
+ fontWeight: 500,
298
+ fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif'
299
+ },
300
+ children: [
301
+ /* @__PURE__ */ jsx8(GoogleGlyph, {}),
302
+ label
303
+ ]
304
+ }
305
+ );
306
+ }
307
+ function GoogleGlyph() {
308
+ return /* @__PURE__ */ jsxs2("svg", { width: "18", height: "18", viewBox: "0 0 18 18", xmlns: "http://www.w3.org/2000/svg", "aria-hidden": "true", children: [
309
+ /* @__PURE__ */ jsx8(
310
+ "path",
311
+ {
312
+ 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",
313
+ fill: "#4285F4"
314
+ }
315
+ ),
316
+ /* @__PURE__ */ jsx8(
317
+ "path",
318
+ {
319
+ 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",
320
+ fill: "#34A853"
321
+ }
322
+ ),
323
+ /* @__PURE__ */ jsx8(
324
+ "path",
325
+ {
326
+ 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",
327
+ fill: "#FBBC05"
328
+ }
329
+ ),
330
+ /* @__PURE__ */ jsx8(
331
+ "path",
332
+ {
333
+ 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",
334
+ fill: "#EA4335"
335
+ }
336
+ )
337
+ ] });
338
+ }
339
+
340
+ // src/internal/OAuthErrorBanner.tsx
341
+ import { useEffect as useEffect3, useState as useState4 } from "react";
342
+ import { jsx as jsx9, jsxs as jsxs3 } from "react/jsx-runtime";
343
+ var ERROR_MESSAGES = {
344
+ invalid_state: "Sess\xE3o expirou, tente de novo.",
345
+ access_denied: "Voc\xEA cancelou o login com Google.",
346
+ provider_error: "O Google recusou a autentica\xE7\xE3o. Tente de novo em alguns segundos.",
347
+ invalid_return_to: "Link inv\xE1lido. Tente entrar novamente."
348
+ };
349
+ function readErrorCode() {
350
+ if (typeof window === "undefined") return null;
351
+ const code = new URLSearchParams(window.location.search).get("oauth_error");
352
+ if (!code) return null;
353
+ return code;
354
+ }
355
+ function stripErrorFromUrl() {
356
+ if (typeof window === "undefined") return;
357
+ const url = new URL(window.location.href);
358
+ url.searchParams.delete("oauth_error");
359
+ window.history.replaceState({}, "", url.toString());
360
+ }
361
+ function OAuthErrorBanner() {
362
+ const [code, setCode] = useState4(() => readErrorCode());
363
+ useEffect3(() => {
364
+ if (code !== null) stripErrorFromUrl();
365
+ }, [code]);
366
+ if (!code) return null;
367
+ const message = ERROR_MESSAGES[code] ?? "N\xE3o conseguimos conectar ao Google. Tente de novo.";
368
+ return /* @__PURE__ */ jsxs3(
369
+ "div",
370
+ {
371
+ role: "alert",
372
+ "data-testid": "oauth-error-banner",
373
+ style: {
374
+ padding: "10px 12px",
375
+ marginBottom: 16,
376
+ background: "#fce8e6",
377
+ color: "#a50e0e",
378
+ borderRadius: 8,
379
+ fontSize: 14
380
+ },
381
+ children: [
382
+ message,
383
+ /* @__PURE__ */ jsx9(
384
+ "button",
385
+ {
386
+ type: "button",
387
+ onClick: () => setCode(null),
388
+ "aria-label": "Fechar",
389
+ style: {
390
+ float: "right",
391
+ background: "none",
392
+ border: "none",
393
+ color: "#a50e0e",
394
+ cursor: "pointer",
395
+ fontSize: 16,
396
+ lineHeight: 1,
397
+ padding: 0
398
+ },
399
+ children: "\xD7"
400
+ }
401
+ )
402
+ ]
403
+ }
404
+ );
405
+ }
406
+
407
+ // src/defaults/DefaultLoginScreen.tsx
408
+ import { jsx as jsx10, jsxs as jsxs4 } from "react/jsx-runtime";
272
409
  function DefaultLoginScreen({ onNavigate }) {
273
410
  const { name } = useTemplateConfig();
274
411
  const f = useLoginForm();
275
- return /* @__PURE__ */ jsxs2("main", { style: { padding: 24, maxWidth: 360, margin: "0 auto" }, children: [
276
- /* @__PURE__ */ jsx8("h1", { style: { marginBottom: 8 }, children: name }),
277
- /* @__PURE__ */ jsx8("p", { style: { opacity: 0.7, marginBottom: 24 }, children: "Entre na sua conta" }),
278
- /* @__PURE__ */ jsxs2("form", { onSubmit: (e) => {
412
+ return /* @__PURE__ */ jsxs4("main", { style: { padding: 24, maxWidth: 360, margin: "0 auto" }, children: [
413
+ /* @__PURE__ */ jsx10("h1", { style: { marginBottom: 8 }, children: name }),
414
+ /* @__PURE__ */ jsx10("p", { style: { opacity: 0.7, marginBottom: 24 }, children: "Entre na sua conta" }),
415
+ /* @__PURE__ */ jsx10(OAuthErrorBanner, {}),
416
+ /* @__PURE__ */ jsx10(GoogleSignInButton, { onClick: f.loginWithGoogle, testId: "login-oauth-google" }),
417
+ /* @__PURE__ */ jsxs4(
418
+ "div",
419
+ {
420
+ "aria-hidden": "true",
421
+ style: {
422
+ display: "flex",
423
+ alignItems: "center",
424
+ gap: 8,
425
+ margin: "16px 0",
426
+ color: "rgba(0,0,0,0.45)",
427
+ fontSize: 12
428
+ },
429
+ children: [
430
+ /* @__PURE__ */ jsx10("span", { style: { flex: 1, height: 1, background: "rgba(0,0,0,0.1)" } }),
431
+ "ou",
432
+ /* @__PURE__ */ jsx10("span", { style: { flex: 1, height: 1, background: "rgba(0,0,0,0.1)" } })
433
+ ]
434
+ }
435
+ ),
436
+ /* @__PURE__ */ jsxs4("form", { onSubmit: (e) => {
279
437
  e.preventDefault();
280
438
  void f.submit();
281
439
  }, children: [
282
- /* @__PURE__ */ jsxs2("label", { style: { display: "block", marginBottom: 12 }, children: [
440
+ /* @__PURE__ */ jsxs4("label", { style: { display: "block", marginBottom: 12 }, children: [
283
441
  "E-mail",
284
- /* @__PURE__ */ jsx8(
442
+ /* @__PURE__ */ jsx10(
285
443
  "input",
286
444
  {
287
445
  "data-testid": "login-email",
@@ -291,11 +449,11 @@ function DefaultLoginScreen({ onNavigate }) {
291
449
  style: { display: "block", width: "100%" }
292
450
  }
293
451
  ),
294
- f.emailError && /* @__PURE__ */ jsx8("small", { style: { color: "#c00" }, children: f.emailError })
452
+ f.emailError && /* @__PURE__ */ jsx10("small", { style: { color: "#c00" }, children: f.emailError })
295
453
  ] }),
296
- /* @__PURE__ */ jsxs2("label", { style: { display: "block", marginBottom: 12 }, children: [
454
+ /* @__PURE__ */ jsxs4("label", { style: { display: "block", marginBottom: 12 }, children: [
297
455
  "Senha",
298
- /* @__PURE__ */ jsx8(
456
+ /* @__PURE__ */ jsx10(
299
457
  "input",
300
458
  {
301
459
  "data-testid": "login-password",
@@ -305,10 +463,10 @@ function DefaultLoginScreen({ onNavigate }) {
305
463
  style: { display: "block", width: "100%" }
306
464
  }
307
465
  ),
308
- f.passwordError && /* @__PURE__ */ jsx8("small", { style: { color: "#c00" }, children: f.passwordError })
466
+ f.passwordError && /* @__PURE__ */ jsx10("small", { style: { color: "#c00" }, children: f.passwordError })
309
467
  ] }),
310
- f.error && /* @__PURE__ */ jsx8("div", { role: "alert", style: { color: "#c00", marginBottom: 12 }, children: f.error.message }),
311
- /* @__PURE__ */ jsx8(
468
+ f.error && /* @__PURE__ */ jsx10("div", { role: "alert", style: { color: "#c00", marginBottom: 12 }, children: f.error.message }),
469
+ /* @__PURE__ */ jsx10(
312
470
  "button",
313
471
  {
314
472
  "data-testid": "login-submit",
@@ -327,25 +485,25 @@ function DefaultLoginScreen({ onNavigate }) {
327
485
  }
328
486
  )
329
487
  ] }),
330
- /* @__PURE__ */ jsxs2("div", { style: { marginTop: 16, display: "flex", justifyContent: "space-between" }, children: [
331
- /* @__PURE__ */ jsx8("button", { "data-testid": "login-goto-signup", type: "button", onClick: () => onNavigate("signup"), style: { background: "none", border: "none", cursor: "pointer" }, children: "Criar conta" }),
332
- /* @__PURE__ */ jsx8("button", { "data-testid": "login-goto-forgot", type: "button", onClick: () => onNavigate("forgot"), style: { background: "none", border: "none", cursor: "pointer" }, children: "Esqueci senha" })
488
+ /* @__PURE__ */ jsxs4("div", { style: { marginTop: 16, display: "flex", justifyContent: "space-between" }, children: [
489
+ /* @__PURE__ */ jsx10("button", { "data-testid": "login-goto-signup", type: "button", onClick: () => onNavigate("signup"), style: { background: "none", border: "none", cursor: "pointer" }, children: "Criar conta" }),
490
+ /* @__PURE__ */ jsx10("button", { "data-testid": "login-goto-forgot", type: "button", onClick: () => onNavigate("forgot"), style: { background: "none", border: "none", cursor: "pointer" }, children: "Esqueci senha" })
333
491
  ] })
334
492
  ] });
335
493
  }
336
494
 
337
495
  // src/hooks/useSignupForm.ts
338
- import { useCallback as useCallback3, useMemo as useMemo3, useState as useState4 } from "react";
496
+ import { useCallback as useCallback3, useMemo as useMemo3, useState as useState5 } from "react";
339
497
  import { useHook as useHook5 } from "@hook-sdk/sdk";
340
498
  var EMAIL_RE2 = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
341
499
  var MIN_PASSWORD2 = 8;
342
500
  function useSignupForm() {
343
501
  const { auth } = useHook5();
344
- const [name, setName] = useState4("");
345
- const [email, setEmail] = useState4("");
346
- const [password, setPassword] = useState4("");
347
- const [submitting, setSubmitting] = useState4(false);
348
- const [error, setError] = useState4(null);
502
+ const [name, setName] = useState5("");
503
+ const [email, setEmail] = useState5("");
504
+ const [password, setPassword] = useState5("");
505
+ const [submitting, setSubmitting] = useState5(false);
506
+ const [error, setError] = useState5(null);
349
507
  const nameError = useMemo3(() => {
350
508
  if (name.length === 0) return null;
351
509
  if (name.trim().length < 2) return "Nome muito curto.";
@@ -389,54 +547,76 @@ function useSignupForm() {
389
547
  submit,
390
548
  submitting,
391
549
  canSubmit,
392
- error
550
+ error,
551
+ loginWithGoogle: () => auth.loginWithGoogle()
393
552
  };
394
553
  }
395
554
 
396
555
  // src/defaults/DefaultSignupScreen.tsx
397
- import { jsx as jsx9, jsxs as jsxs3 } from "react/jsx-runtime";
556
+ import { jsx as jsx11, jsxs as jsxs5 } from "react/jsx-runtime";
398
557
  function DefaultSignupScreen({ onNavigate }) {
399
558
  const { name } = useTemplateConfig();
400
559
  const f = useSignupForm();
401
- return /* @__PURE__ */ jsxs3("main", { style: { padding: 24, maxWidth: 360, margin: "0 auto" }, children: [
402
- /* @__PURE__ */ jsx9("h1", { style: { marginBottom: 8 }, children: name }),
403
- /* @__PURE__ */ jsx9("p", { style: { opacity: 0.7, marginBottom: 24 }, children: "Criar sua conta" }),
404
- /* @__PURE__ */ jsxs3("form", { onSubmit: (e) => {
560
+ return /* @__PURE__ */ jsxs5("main", { style: { padding: 24, maxWidth: 360, margin: "0 auto" }, children: [
561
+ /* @__PURE__ */ jsx11("h1", { style: { marginBottom: 8 }, children: name }),
562
+ /* @__PURE__ */ jsx11("p", { style: { opacity: 0.7, marginBottom: 24 }, children: "Criar sua conta" }),
563
+ /* @__PURE__ */ jsx11(OAuthErrorBanner, {}),
564
+ /* @__PURE__ */ jsx11(GoogleSignInButton, { onClick: f.loginWithGoogle, testId: "signup-oauth-google" }),
565
+ /* @__PURE__ */ jsxs5(
566
+ "div",
567
+ {
568
+ "aria-hidden": "true",
569
+ style: {
570
+ display: "flex",
571
+ alignItems: "center",
572
+ gap: 8,
573
+ margin: "16px 0",
574
+ color: "rgba(0,0,0,0.45)",
575
+ fontSize: 12
576
+ },
577
+ children: [
578
+ /* @__PURE__ */ jsx11("span", { style: { flex: 1, height: 1, background: "rgba(0,0,0,0.1)" } }),
579
+ "ou",
580
+ /* @__PURE__ */ jsx11("span", { style: { flex: 1, height: 1, background: "rgba(0,0,0,0.1)" } })
581
+ ]
582
+ }
583
+ ),
584
+ /* @__PURE__ */ jsxs5("form", { onSubmit: (e) => {
405
585
  e.preventDefault();
406
586
  void f.submit();
407
587
  }, children: [
408
- /* @__PURE__ */ jsxs3("label", { style: { display: "block", marginBottom: 12 }, children: [
588
+ /* @__PURE__ */ jsxs5("label", { style: { display: "block", marginBottom: 12 }, children: [
409
589
  "Nome",
410
- /* @__PURE__ */ jsx9("input", { "data-testid": "signup-name", value: f.name, onChange: (e) => f.setName(e.target.value), style: { display: "block", width: "100%" } }),
411
- f.nameError && /* @__PURE__ */ jsx9("small", { style: { color: "#c00" }, children: f.nameError })
590
+ /* @__PURE__ */ jsx11("input", { "data-testid": "signup-name", value: f.name, onChange: (e) => f.setName(e.target.value), style: { display: "block", width: "100%" } }),
591
+ f.nameError && /* @__PURE__ */ jsx11("small", { style: { color: "#c00" }, children: f.nameError })
412
592
  ] }),
413
- /* @__PURE__ */ jsxs3("label", { style: { display: "block", marginBottom: 12 }, children: [
593
+ /* @__PURE__ */ jsxs5("label", { style: { display: "block", marginBottom: 12 }, children: [
414
594
  "E-mail",
415
- /* @__PURE__ */ jsx9("input", { "data-testid": "signup-email", type: "email", value: f.email, onChange: (e) => f.setEmail(e.target.value), style: { display: "block", width: "100%" } }),
416
- f.emailError && /* @__PURE__ */ jsx9("small", { style: { color: "#c00" }, children: f.emailError })
595
+ /* @__PURE__ */ jsx11("input", { "data-testid": "signup-email", type: "email", value: f.email, onChange: (e) => f.setEmail(e.target.value), style: { display: "block", width: "100%" } }),
596
+ f.emailError && /* @__PURE__ */ jsx11("small", { style: { color: "#c00" }, children: f.emailError })
417
597
  ] }),
418
- /* @__PURE__ */ jsxs3("label", { style: { display: "block", marginBottom: 12 }, children: [
598
+ /* @__PURE__ */ jsxs5("label", { style: { display: "block", marginBottom: 12 }, children: [
419
599
  "Senha",
420
- /* @__PURE__ */ jsx9("input", { "data-testid": "signup-password", type: "password", value: f.password, onChange: (e) => f.setPassword(e.target.value), style: { display: "block", width: "100%" } }),
421
- f.passwordError && /* @__PURE__ */ jsx9("small", { style: { color: "#c00" }, children: f.passwordError })
600
+ /* @__PURE__ */ jsx11("input", { "data-testid": "signup-password", type: "password", value: f.password, onChange: (e) => f.setPassword(e.target.value), style: { display: "block", width: "100%" } }),
601
+ f.passwordError && /* @__PURE__ */ jsx11("small", { style: { color: "#c00" }, children: f.passwordError })
422
602
  ] }),
423
- f.error && /* @__PURE__ */ jsx9("div", { role: "alert", style: { color: "#c00", marginBottom: 12 }, children: f.error.message }),
424
- /* @__PURE__ */ jsx9("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" })
603
+ f.error && /* @__PURE__ */ jsx11("div", { role: "alert", style: { color: "#c00", marginBottom: 12 }, children: f.error.message }),
604
+ /* @__PURE__ */ jsx11("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" })
425
605
  ] }),
426
- /* @__PURE__ */ jsx9("div", { style: { marginTop: 16 }, children: /* @__PURE__ */ jsx9("button", { "data-testid": "signup-goto-login", type: "button", onClick: () => onNavigate("login"), style: { background: "none", border: "none", cursor: "pointer" }, children: "J\xE1 tem conta? Entre" }) })
606
+ /* @__PURE__ */ jsx11("div", { style: { marginTop: 16 }, children: /* @__PURE__ */ jsx11("button", { "data-testid": "signup-goto-login", type: "button", onClick: () => onNavigate("login"), style: { background: "none", border: "none", cursor: "pointer" }, children: "J\xE1 tem conta? Entre" }) })
427
607
  ] });
428
608
  }
429
609
 
430
610
  // src/hooks/useForgotForm.ts
431
- import { useCallback as useCallback4, useMemo as useMemo4, useState as useState5 } from "react";
611
+ import { useCallback as useCallback4, useMemo as useMemo4, useState as useState6 } from "react";
432
612
  import { useHook as useHook6 } from "@hook-sdk/sdk";
433
613
  var EMAIL_RE3 = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
434
614
  function useForgotForm() {
435
615
  const { auth } = useHook6();
436
- const [email, setEmail] = useState5("");
437
- const [submitting, setSubmitting] = useState5(false);
438
- const [sent, setSent] = useState5(false);
439
- const [error, setError] = useState5(null);
616
+ const [email, setEmail] = useState6("");
617
+ const [submitting, setSubmitting] = useState6(false);
618
+ const [sent, setSent] = useState6(false);
619
+ const [error, setError] = useState6(null);
440
620
  const emailError = useMemo4(() => {
441
621
  if (email.length === 0) return null;
442
622
  if (!EMAIL_RE3.test(email)) return "Formato de e-mail inv\xE1lido.";
@@ -471,49 +651,49 @@ function useForgotForm() {
471
651
  }
472
652
 
473
653
  // src/defaults/DefaultForgotScreen.tsx
474
- import { jsx as jsx10, jsxs as jsxs4 } from "react/jsx-runtime";
654
+ import { jsx as jsx12, jsxs as jsxs6 } from "react/jsx-runtime";
475
655
  function DefaultForgotScreen({ onNavigate }) {
476
656
  const { name } = useTemplateConfig();
477
657
  const f = useForgotForm();
478
658
  if (f.sent) {
479
- return /* @__PURE__ */ jsxs4("main", { style: { padding: 24, maxWidth: 360, margin: "0 auto", textAlign: "center" }, children: [
480
- /* @__PURE__ */ jsx10("h1", { children: "Verifique seu e-mail" }),
481
- /* @__PURE__ */ jsx10("p", { style: { opacity: 0.7 }, children: "Enviamos um link pra redefinir sua senha." }),
482
- /* @__PURE__ */ jsx10("button", { "data-testid": "forgot-back-login", type: "button", onClick: () => onNavigate("login"), children: "Voltar pro login" })
659
+ return /* @__PURE__ */ jsxs6("main", { style: { padding: 24, maxWidth: 360, margin: "0 auto", textAlign: "center" }, children: [
660
+ /* @__PURE__ */ jsx12("h1", { children: "Verifique seu e-mail" }),
661
+ /* @__PURE__ */ jsx12("p", { style: { opacity: 0.7 }, children: "Enviamos um link pra redefinir sua senha." }),
662
+ /* @__PURE__ */ jsx12("button", { "data-testid": "forgot-back-login", type: "button", onClick: () => onNavigate("login"), children: "Voltar pro login" })
483
663
  ] });
484
664
  }
485
- return /* @__PURE__ */ jsxs4("main", { style: { padding: 24, maxWidth: 360, margin: "0 auto" }, children: [
486
- /* @__PURE__ */ jsx10("h1", { style: { marginBottom: 8 }, children: name }),
487
- /* @__PURE__ */ jsx10("p", { style: { opacity: 0.7, marginBottom: 24 }, children: "Redefinir senha" }),
488
- /* @__PURE__ */ jsxs4("form", { onSubmit: (e) => {
665
+ return /* @__PURE__ */ jsxs6("main", { style: { padding: 24, maxWidth: 360, margin: "0 auto" }, children: [
666
+ /* @__PURE__ */ jsx12("h1", { style: { marginBottom: 8 }, children: name }),
667
+ /* @__PURE__ */ jsx12("p", { style: { opacity: 0.7, marginBottom: 24 }, children: "Redefinir senha" }),
668
+ /* @__PURE__ */ jsxs6("form", { onSubmit: (e) => {
489
669
  e.preventDefault();
490
670
  void f.submit();
491
671
  }, children: [
492
- /* @__PURE__ */ jsxs4("label", { style: { display: "block", marginBottom: 12 }, children: [
672
+ /* @__PURE__ */ jsxs6("label", { style: { display: "block", marginBottom: 12 }, children: [
493
673
  "E-mail",
494
- /* @__PURE__ */ jsx10("input", { "data-testid": "forgot-email", type: "email", value: f.email, onChange: (e) => f.setEmail(e.target.value), style: { display: "block", width: "100%" } }),
495
- f.emailError && /* @__PURE__ */ jsx10("small", { style: { color: "#c00" }, children: f.emailError })
674
+ /* @__PURE__ */ jsx12("input", { "data-testid": "forgot-email", type: "email", value: f.email, onChange: (e) => f.setEmail(e.target.value), style: { display: "block", width: "100%" } }),
675
+ f.emailError && /* @__PURE__ */ jsx12("small", { style: { color: "#c00" }, children: f.emailError })
496
676
  ] }),
497
- f.error && /* @__PURE__ */ jsx10("div", { role: "alert", style: { color: "#c00", marginBottom: 12 }, children: f.error.message }),
498
- /* @__PURE__ */ jsx10("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" })
677
+ f.error && /* @__PURE__ */ jsx12("div", { role: "alert", style: { color: "#c00", marginBottom: 12 }, children: f.error.message }),
678
+ /* @__PURE__ */ jsx12("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" })
499
679
  ] }),
500
- /* @__PURE__ */ jsx10("div", { style: { marginTop: 16 }, children: /* @__PURE__ */ jsx10("button", { "data-testid": "forgot-goto-login", type: "button", onClick: () => onNavigate("login"), style: { background: "none", border: "none", cursor: "pointer" }, children: "Voltar pro login" }) })
680
+ /* @__PURE__ */ jsx12("div", { style: { marginTop: 16 }, children: /* @__PURE__ */ jsx12("button", { "data-testid": "forgot-goto-login", type: "button", onClick: () => onNavigate("login"), style: { background: "none", border: "none", cursor: "pointer" }, children: "Voltar pro login" }) })
501
681
  ] });
502
682
  }
503
683
 
504
684
  // src/hooks/useResetForm.ts
505
- import { useCallback as useCallback5, useEffect as useEffect3, useMemo as useMemo5, useState as useState6 } from "react";
685
+ import { useCallback as useCallback5, useEffect as useEffect4, useMemo as useMemo5, useState as useState7 } from "react";
506
686
  import { useHook as useHook7 } from "@hook-sdk/sdk";
507
687
  var MIN_PASSWORD3 = 12;
508
688
  function useResetForm() {
509
689
  const { auth } = useHook7();
510
- const [token, setToken] = useState6(null);
511
- const [password, setPassword] = useState6("");
512
- const [confirm, setConfirm] = useState6("");
513
- const [submitting, setSubmitting] = useState6(false);
514
- const [done, setDone] = useState6(false);
515
- const [error, setError] = useState6(null);
516
- useEffect3(() => {
690
+ const [token, setToken] = useState7(null);
691
+ const [password, setPassword] = useState7("");
692
+ const [confirm, setConfirm] = useState7("");
693
+ const [submitting, setSubmitting] = useState7(false);
694
+ const [done, setDone] = useState7(false);
695
+ const [error, setError] = useState7(null);
696
+ useEffect4(() => {
517
697
  if (typeof window === "undefined") return;
518
698
  const params = new URLSearchParams(window.location.search);
519
699
  const t = params.get("token");
@@ -566,67 +746,67 @@ function useResetForm() {
566
746
  }
567
747
 
568
748
  // src/defaults/DefaultResetScreen.tsx
569
- import { jsx as jsx11, jsxs as jsxs5 } from "react/jsx-runtime";
749
+ import { jsx as jsx13, jsxs as jsxs7 } from "react/jsx-runtime";
570
750
  function DefaultResetScreen({ onNavigate }) {
571
751
  const { name } = useTemplateConfig();
572
752
  const f = useResetForm();
573
753
  if (f.done) {
574
- return /* @__PURE__ */ jsxs5("main", { style: { padding: 24, maxWidth: 360, margin: "0 auto", textAlign: "center" }, children: [
575
- /* @__PURE__ */ jsx11("h1", { children: "Senha alterada" }),
576
- /* @__PURE__ */ jsx11("p", { style: { opacity: 0.7 }, children: "Agora \xE9 s\xF3 fazer login com a nova senha." }),
577
- /* @__PURE__ */ jsx11("button", { "data-testid": "reset-back-login", type: "button", onClick: () => onNavigate("login"), children: "Ir pro login" })
754
+ return /* @__PURE__ */ jsxs7("main", { style: { padding: 24, maxWidth: 360, margin: "0 auto", textAlign: "center" }, children: [
755
+ /* @__PURE__ */ jsx13("h1", { children: "Senha alterada" }),
756
+ /* @__PURE__ */ jsx13("p", { style: { opacity: 0.7 }, children: "Agora \xE9 s\xF3 fazer login com a nova senha." }),
757
+ /* @__PURE__ */ jsx13("button", { "data-testid": "reset-back-login", type: "button", onClick: () => onNavigate("login"), children: "Ir pro login" })
578
758
  ] });
579
759
  }
580
760
  if (f.token === null) {
581
- return /* @__PURE__ */ jsxs5("main", { style: { padding: 24, maxWidth: 360, margin: "0 auto", textAlign: "center" }, children: [
582
- /* @__PURE__ */ jsx11("h1", { children: "Link inv\xE1lido" }),
583
- /* @__PURE__ */ jsx11("p", { style: { opacity: 0.7 }, children: "Pe\xE7a um novo link de reset." }),
584
- /* @__PURE__ */ jsx11("button", { "data-testid": "reset-goto-forgot", type: "button", onClick: () => onNavigate("forgot"), children: "Pedir novo link" })
761
+ return /* @__PURE__ */ jsxs7("main", { style: { padding: 24, maxWidth: 360, margin: "0 auto", textAlign: "center" }, children: [
762
+ /* @__PURE__ */ jsx13("h1", { children: "Link inv\xE1lido" }),
763
+ /* @__PURE__ */ jsx13("p", { style: { opacity: 0.7 }, children: "Pe\xE7a um novo link de reset." }),
764
+ /* @__PURE__ */ jsx13("button", { "data-testid": "reset-goto-forgot", type: "button", onClick: () => onNavigate("forgot"), children: "Pedir novo link" })
585
765
  ] });
586
766
  }
587
- return /* @__PURE__ */ jsxs5("main", { style: { padding: 24, maxWidth: 360, margin: "0 auto" }, children: [
588
- /* @__PURE__ */ jsx11("h1", { style: { marginBottom: 8 }, children: name }),
589
- /* @__PURE__ */ jsx11("p", { style: { opacity: 0.7, marginBottom: 24 }, children: "Escolha uma nova senha" }),
590
- /* @__PURE__ */ jsxs5("form", { onSubmit: (e) => {
767
+ return /* @__PURE__ */ jsxs7("main", { style: { padding: 24, maxWidth: 360, margin: "0 auto" }, children: [
768
+ /* @__PURE__ */ jsx13("h1", { style: { marginBottom: 8 }, children: name }),
769
+ /* @__PURE__ */ jsx13("p", { style: { opacity: 0.7, marginBottom: 24 }, children: "Escolha uma nova senha" }),
770
+ /* @__PURE__ */ jsxs7("form", { onSubmit: (e) => {
591
771
  e.preventDefault();
592
772
  void f.submit();
593
773
  }, children: [
594
- /* @__PURE__ */ jsxs5("label", { style: { display: "block", marginBottom: 12 }, children: [
774
+ /* @__PURE__ */ jsxs7("label", { style: { display: "block", marginBottom: 12 }, children: [
595
775
  "Nova senha",
596
- /* @__PURE__ */ jsx11("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" }),
597
- f.passwordError && /* @__PURE__ */ jsx11("small", { style: { color: "#c00" }, children: f.passwordError })
776
+ /* @__PURE__ */ jsx13("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" }),
777
+ f.passwordError && /* @__PURE__ */ jsx13("small", { style: { color: "#c00" }, children: f.passwordError })
598
778
  ] }),
599
- /* @__PURE__ */ jsxs5("label", { style: { display: "block", marginBottom: 12 }, children: [
779
+ /* @__PURE__ */ jsxs7("label", { style: { display: "block", marginBottom: 12 }, children: [
600
780
  "Confirmar senha",
601
- /* @__PURE__ */ jsx11("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" }),
602
- f.confirmError && /* @__PURE__ */ jsx11("small", { style: { color: "#c00" }, children: f.confirmError })
781
+ /* @__PURE__ */ jsx13("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" }),
782
+ f.confirmError && /* @__PURE__ */ jsx13("small", { style: { color: "#c00" }, children: f.confirmError })
603
783
  ] }),
604
- f.error && /* @__PURE__ */ jsx11("div", { role: "alert", style: { color: "#c00", marginBottom: 12 }, children: f.error.message }),
605
- /* @__PURE__ */ jsx11("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" })
784
+ f.error && /* @__PURE__ */ jsx13("div", { role: "alert", style: { color: "#c00", marginBottom: 12 }, children: f.error.message }),
785
+ /* @__PURE__ */ jsx13("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" })
606
786
  ] })
607
787
  ] });
608
788
  }
609
789
 
610
790
  // src/defaults/DefaultPaywall.tsx
611
- import { useState as useState7 } from "react";
612
- import { jsx as jsx12, jsxs as jsxs6 } from "react/jsx-runtime";
791
+ import { useState as useState8 } from "react";
792
+ import { jsx as jsx14, jsxs as jsxs8 } from "react/jsx-runtime";
613
793
  function DefaultPaywall() {
614
794
  const config = useTemplateConfig();
615
795
  const { checkout, opening, error } = usePaywallState();
616
796
  const p = config.subscription.paywall_config;
617
- const [cpf, setCpf] = useState7("");
797
+ const [cpf, setCpf] = useState8("");
618
798
  const cpfDigits = cpf.replace(/\D/g, "");
619
799
  const canCheckout = cpfDigits.length === 11 && !opening;
620
- return /* @__PURE__ */ jsxs6("main", { style: { padding: 24, maxWidth: 440, margin: "0 auto", textAlign: "center" }, children: [
621
- /* @__PURE__ */ jsx12("h1", { style: { marginBottom: 8 }, children: p.title }),
622
- p.subtitle && /* @__PURE__ */ jsx12("p", { style: { opacity: 0.7, marginBottom: 24 }, children: p.subtitle }),
623
- /* @__PURE__ */ jsx12("ul", { style: { listStyle: "none", padding: 0, textAlign: "left", marginBottom: 24 }, children: p.benefits.map((b) => /* @__PURE__ */ jsxs6("li", { style: { padding: "8px 0", display: "flex", alignItems: "center" }, children: [
624
- /* @__PURE__ */ jsx12("span", { "aria-hidden": true, style: { marginRight: 8 }, children: "\u2713" }),
625
- /* @__PURE__ */ jsx12("span", { children: b })
800
+ return /* @__PURE__ */ jsxs8("main", { style: { padding: 24, maxWidth: 440, margin: "0 auto", textAlign: "center" }, children: [
801
+ /* @__PURE__ */ jsx14("h1", { style: { marginBottom: 8 }, children: p.title }),
802
+ p.subtitle && /* @__PURE__ */ jsx14("p", { style: { opacity: 0.7, marginBottom: 24 }, children: p.subtitle }),
803
+ /* @__PURE__ */ jsx14("ul", { style: { listStyle: "none", padding: 0, textAlign: "left", marginBottom: 24 }, children: p.benefits.map((b) => /* @__PURE__ */ jsxs8("li", { style: { padding: "8px 0", display: "flex", alignItems: "center" }, children: [
804
+ /* @__PURE__ */ jsx14("span", { "aria-hidden": true, style: { marginRight: 8 }, children: "\u2713" }),
805
+ /* @__PURE__ */ jsx14("span", { children: b })
626
806
  ] }, b)) }),
627
- /* @__PURE__ */ jsxs6("div", { style: { textAlign: "left", marginBottom: 16 }, children: [
628
- /* @__PURE__ */ jsx12("label", { style: { display: "block", fontSize: 14, opacity: 0.7, marginBottom: 4 }, children: "Seu CPF (pra emiss\xE3o de recibo)" }),
629
- /* @__PURE__ */ jsx12(
807
+ /* @__PURE__ */ jsxs8("div", { style: { textAlign: "left", marginBottom: 16 }, children: [
808
+ /* @__PURE__ */ jsx14("label", { style: { display: "block", fontSize: 14, opacity: 0.7, marginBottom: 4 }, children: "Seu CPF (pra emiss\xE3o de recibo)" }),
809
+ /* @__PURE__ */ jsx14(
630
810
  "input",
631
811
  {
632
812
  "data-testid": "paywall-cpf",
@@ -639,8 +819,8 @@ function DefaultPaywall() {
639
819
  }
640
820
  )
641
821
  ] }),
642
- error && /* @__PURE__ */ jsx12("div", { role: "alert", style: { color: "#c00", marginBottom: 12 }, children: error.message }),
643
- /* @__PURE__ */ jsx12(
822
+ error && /* @__PURE__ */ jsx14("div", { role: "alert", style: { color: "#c00", marginBottom: 12 }, children: error.message }),
823
+ /* @__PURE__ */ jsx14(
644
824
  "button",
645
825
  {
646
826
  "data-testid": "paywall-cta",
@@ -661,20 +841,20 @@ function DefaultPaywall() {
661
841
  children: opening ? "Abrindo..." : p.cta
662
842
  }
663
843
  ),
664
- p.priceHint && /* @__PURE__ */ jsx12("p", { style: { opacity: 0.6, marginTop: 12 }, children: p.priceHint }),
665
- p.footerNote && /* @__PURE__ */ jsx12("p", { style: { opacity: 0.5, marginTop: 16, fontSize: 12 }, children: p.footerNote })
844
+ p.priceHint && /* @__PURE__ */ jsx14("p", { style: { opacity: 0.6, marginTop: 12 }, children: p.priceHint }),
845
+ p.footerNote && /* @__PURE__ */ jsx14("p", { style: { opacity: 0.5, marginTop: 16, fontSize: 12 }, children: p.footerNote })
666
846
  ] });
667
847
  }
668
848
 
669
849
  // src/AppRoot.tsx
670
- import { Fragment as Fragment5, jsx as jsx13, jsxs as jsxs7 } from "react/jsx-runtime";
850
+ import { Fragment as Fragment5, jsx as jsx15, jsxs as jsxs9 } from "react/jsx-runtime";
671
851
  var BACKOFF_MS = [2e3, 5e3, 1e4, 2e4, 4e4];
672
852
  function PaymentReturnHandler({ children }) {
673
853
  const { subscription } = useHook8();
674
854
  const subRef = useRef(subscription);
675
855
  subRef.current = subscription;
676
856
  const runIdRef = useRef(0);
677
- const [state, setState] = useState8("idle");
857
+ const [state, setState] = useState9("idle");
678
858
  const runPoll = useCallback6(() => {
679
859
  const runId = ++runIdRef.current;
680
860
  setState("confirming");
@@ -704,7 +884,7 @@ function PaymentReturnHandler({ children }) {
704
884
  };
705
885
  void tick();
706
886
  }, []);
707
- useEffect4(() => {
887
+ useEffect5(() => {
708
888
  if (typeof window === "undefined") return;
709
889
  const url = new URL(window.location.href);
710
890
  if (url.searchParams.get("paymentReturn") !== "1") return;
@@ -714,7 +894,7 @@ function PaymentReturnHandler({ children }) {
714
894
  };
715
895
  }, [runPoll]);
716
896
  if (state === "confirming") {
717
- return /* @__PURE__ */ jsx13(
897
+ return /* @__PURE__ */ jsx15(
718
898
  "div",
719
899
  {
720
900
  role: "status",
@@ -725,9 +905,9 @@ function PaymentReturnHandler({ children }) {
725
905
  );
726
906
  }
727
907
  if (state === "waiting") {
728
- return /* @__PURE__ */ jsx13("div", { role: "status", "aria-live": "polite", style: overlayStyle, children: /* @__PURE__ */ jsxs7("div", { style: { maxWidth: 320, textAlign: "center", lineHeight: 1.5 }, children: [
729
- /* @__PURE__ */ jsx13("div", { style: { marginBottom: 16 }, children: "Pagamento aceito. Estamos confirmando com o banco \u2014 pode levar alguns minutos." }),
730
- /* @__PURE__ */ jsx13(
908
+ return /* @__PURE__ */ jsx15("div", { role: "status", "aria-live": "polite", style: overlayStyle, children: /* @__PURE__ */ jsxs9("div", { style: { maxWidth: 320, textAlign: "center", lineHeight: 1.5 }, children: [
909
+ /* @__PURE__ */ jsx15("div", { style: { marginBottom: 16 }, children: "Pagamento aceito. Estamos confirmando com o banco \u2014 pode levar alguns minutos." }),
910
+ /* @__PURE__ */ jsx15(
731
911
  "button",
732
912
  {
733
913
  type: "button",
@@ -738,7 +918,7 @@ function PaymentReturnHandler({ children }) {
738
918
  )
739
919
  ] }) });
740
920
  }
741
- return /* @__PURE__ */ jsx13(Fragment5, { children });
921
+ return /* @__PURE__ */ jsx15(Fragment5, { children });
742
922
  }
743
923
  var overlayStyle = {
744
924
  position: "fixed",
@@ -771,29 +951,129 @@ function AppRoot({
771
951
  Reset = DefaultResetScreen,
772
952
  Paywall = DefaultPaywall
773
953
  }) {
774
- return /* @__PURE__ */ jsx13(PaymentReturnHandler, { children: /* @__PURE__ */ jsx13(TemplateConfigProvider, { config, children: /* @__PURE__ */ jsx13(ErrorBoundary, { children: /* @__PURE__ */ jsx13(ThemeProvider, { children: /* @__PURE__ */ jsx13(AuthGate, { Login, Signup, Forgot, Reset, children: /* @__PURE__ */ jsx13(PersistedKeysPrefetch, { children: /* @__PURE__ */ jsxs7(SubscriptionGate, { Paywall, children: [
954
+ return /* @__PURE__ */ jsx15(PaymentReturnHandler, { children: /* @__PURE__ */ jsx15(TemplateConfigProvider, { config, children: /* @__PURE__ */ jsx15(ErrorBoundary, { children: /* @__PURE__ */ jsx15(ThemeProvider, { children: /* @__PURE__ */ jsx15(AuthGate, { Login, Signup, Forgot, Reset, children: /* @__PURE__ */ jsx15(PersistedKeysPrefetch, { children: /* @__PURE__ */ jsxs9(SubscriptionGate, { Paywall, children: [
775
955
  children,
776
- /* @__PURE__ */ jsx13(PushPrompt, {})
956
+ /* @__PURE__ */ jsx15(PushPrompt, {})
777
957
  ] }) }) }) }) }) }) });
778
958
  }
779
959
 
960
+ // src/hooks/usePush.ts
961
+ import { useCallback as useCallback7, useEffect as useEffect6, useState as useState10 } from "react";
962
+ import { useHook as useHook9 } from "@hook-sdk/sdk";
963
+ function detectIosNeedsInstall() {
964
+ if (typeof navigator === "undefined" || typeof window === "undefined") return false;
965
+ const ua = navigator.userAgent || "";
966
+ const isIos = /iPhone|iPad|iPod/.test(ua);
967
+ if (!isIos) return false;
968
+ const mm = window.matchMedia?.("(display-mode: standalone)");
969
+ const standalone = mm?.matches === true;
970
+ const legacyStandalone = typeof navigator.standalone === "boolean" ? navigator.standalone : false;
971
+ return !(standalone || legacyStandalone);
972
+ }
973
+ function deriveState(push) {
974
+ if (!push.isAvailable()) {
975
+ if (detectIosNeedsInstall()) return { kind: "ios_needs_install" };
976
+ return { kind: "unsupported" };
977
+ }
978
+ const status = push.status();
979
+ if (status === "granted") return { kind: "subscribed" };
980
+ if (status === "denied") return { kind: "denied" };
981
+ if (status === "unsupported") {
982
+ if (detectIosNeedsInstall()) return { kind: "ios_needs_install" };
983
+ return { kind: "unsupported" };
984
+ }
985
+ return { kind: "prompt" };
986
+ }
987
+ function usePush() {
988
+ const { push } = useHook9();
989
+ const [state, setState] = useState10(() => deriveState(push));
990
+ useEffect6(() => {
991
+ setState(deriveState(push));
992
+ }, [push]);
993
+ const subscribe = useCallback7(async () => {
994
+ try {
995
+ await push.subscribe();
996
+ setState({ kind: "subscribed" });
997
+ } catch (e) {
998
+ const code = e?.code ?? "push.unknown";
999
+ const message = e?.message ?? "Push subscription failed";
1000
+ if (code === "push.permission_denied") setState({ kind: "denied" });
1001
+ else setState({ kind: "error", code, message });
1002
+ throw e;
1003
+ }
1004
+ }, [push]);
1005
+ const unsubscribe = useCallback7(async () => {
1006
+ try {
1007
+ await push.unsubscribe();
1008
+ setState({ kind: "prompt" });
1009
+ } catch (e) {
1010
+ setState({ kind: "error", code: e?.code ?? "push.unknown", message: e?.message ?? "failed" });
1011
+ throw e;
1012
+ }
1013
+ }, [push]);
1014
+ return { state, subscribe, unsubscribe };
1015
+ }
1016
+
1017
+ // src/components/PushPrompt.tsx
1018
+ import { jsx as jsx16, jsxs as jsxs10 } from "react/jsx-runtime";
1019
+ function PushPrompt2({ texts, onSubscribed, onDeclined, onInstallRequested, className }) {
1020
+ const { state, subscribe } = usePush();
1021
+ if (state.kind === "subscribed") return null;
1022
+ if (state.kind === "ios_needs_install") {
1023
+ return /* @__PURE__ */ jsxs10("div", { className, role: "region", "aria-label": texts.iosInstallTitle, children: [
1024
+ /* @__PURE__ */ jsx16("h3", { children: texts.iosInstallTitle }),
1025
+ /* @__PURE__ */ jsx16("p", { children: texts.iosInstallBody }),
1026
+ onInstallRequested && texts.iosInstallCta && /* @__PURE__ */ jsx16("button", { onClick: onInstallRequested, children: texts.iosInstallCta })
1027
+ ] });
1028
+ }
1029
+ if (state.kind === "denied") {
1030
+ return /* @__PURE__ */ jsxs10("div", { className, role: "region", "aria-label": texts.deniedTitle, children: [
1031
+ /* @__PURE__ */ jsx16("h3", { children: texts.deniedTitle }),
1032
+ /* @__PURE__ */ jsx16("p", { children: texts.deniedBody })
1033
+ ] });
1034
+ }
1035
+ if (state.kind === "unsupported") {
1036
+ return /* @__PURE__ */ jsx16("div", { className, role: "region", children: /* @__PURE__ */ jsx16("p", { children: texts.unsupportedBody }) });
1037
+ }
1038
+ if (state.kind === "error") {
1039
+ return /* @__PURE__ */ jsx16("div", { className, role: "region", "aria-label": "error", children: /* @__PURE__ */ jsx16("p", { children: state.message }) });
1040
+ }
1041
+ return /* @__PURE__ */ jsxs10("div", { className, role: "region", children: [
1042
+ /* @__PURE__ */ jsx16(
1043
+ "button",
1044
+ {
1045
+ type: "button",
1046
+ onClick: async () => {
1047
+ try {
1048
+ await subscribe();
1049
+ onSubscribed?.();
1050
+ } catch {
1051
+ }
1052
+ },
1053
+ children: texts.cta
1054
+ }
1055
+ ),
1056
+ onDeclined && /* @__PURE__ */ jsx16("button", { type: "button", onClick: onDeclined, children: texts.declineCta })
1057
+ ] });
1058
+ }
1059
+
780
1060
  // src/defaults/EmptyState.tsx
781
- import { jsx as jsx14, jsxs as jsxs8 } from "react/jsx-runtime";
1061
+ import { jsx as jsx17, jsxs as jsxs11 } from "react/jsx-runtime";
782
1062
  function EmptyState({ title, description, action }) {
783
- return /* @__PURE__ */ jsxs8("div", { role: "status", style: { padding: 32, textAlign: "center" }, children: [
784
- /* @__PURE__ */ jsx14("h2", { style: { marginBottom: 8 }, children: title }),
785
- description && /* @__PURE__ */ jsx14("p", { style: { opacity: 0.7 }, children: description }),
786
- action && /* @__PURE__ */ jsx14("div", { style: { marginTop: 16 }, children: action })
1063
+ return /* @__PURE__ */ jsxs11("div", { role: "status", style: { padding: 32, textAlign: "center" }, children: [
1064
+ /* @__PURE__ */ jsx17("h2", { style: { marginBottom: 8 }, children: title }),
1065
+ description && /* @__PURE__ */ jsx17("p", { style: { opacity: 0.7 }, children: description }),
1066
+ action && /* @__PURE__ */ jsx17("div", { style: { marginTop: 16 }, children: action })
787
1067
  ] });
788
1068
  }
789
1069
 
790
1070
  // src/hooks/useAuthPrimitives.ts
791
- import { useEffect as useEffect5 } from "react";
792
- import { useHook as useHook9 } from "@hook-sdk/sdk";
1071
+ import { useEffect as useEffect7 } from "react";
1072
+ import { useHook as useHook10 } from "@hook-sdk/sdk";
793
1073
  var warned = false;
794
1074
  function useAuthPrimitives() {
795
- const { auth } = useHook9();
796
- useEffect5(() => {
1075
+ const { auth } = useHook10();
1076
+ useEffect7(() => {
797
1077
  if (!warned && process.env.NODE_ENV !== "production") {
798
1078
  warned = true;
799
1079
  console.warn(
@@ -815,37 +1095,63 @@ function useAuthPrimitives() {
815
1095
  }
816
1096
 
817
1097
  // src/hooks/useSubscription.ts
818
- import { useHook as useHook10 } from "@hook-sdk/sdk";
1098
+ import { useHook as useHook11 } from "@hook-sdk/sdk";
819
1099
  function useSubscription() {
820
- const { subscription } = useHook10();
1100
+ const { subscription } = useHook11();
821
1101
  return {
822
1102
  status: subscription.status()
823
1103
  };
824
1104
  }
825
1105
 
826
- // src/hooks/usePush.ts
827
- import { useHook as useHook11 } from "@hook-sdk/sdk";
828
- function usePush() {
829
- const { push } = useHook11();
830
- return {
831
- status: push.status(),
832
- subscribe: push.subscribe,
833
- unsubscribe: push.unsubscribe
834
- };
1106
+ // src/hooks/useReminders.ts
1107
+ import { useCallback as useCallback8, useEffect as useEffect8, useState as useState11 } from "react";
1108
+ import { useHook as useHook12 } from "@hook-sdk/sdk";
1109
+ function useReminders() {
1110
+ const { push } = useHook12();
1111
+ const r = push.reminders;
1112
+ const [reminders, setReminders] = useState11([]);
1113
+ const [loading, setLoading] = useState11(true);
1114
+ const reload = useCallback8(async () => {
1115
+ setLoading(true);
1116
+ try {
1117
+ const next = await r.list();
1118
+ setReminders(next);
1119
+ } finally {
1120
+ setLoading(false);
1121
+ }
1122
+ }, [r]);
1123
+ useEffect8(() => {
1124
+ void reload();
1125
+ }, [reload]);
1126
+ const setReminder = useCallback8(async (input) => {
1127
+ await r.set(input);
1128
+ await reload();
1129
+ }, [r, reload]);
1130
+ const deleteReminder = useCallback8(async (slot) => {
1131
+ await r.delete(slot);
1132
+ await reload();
1133
+ }, [r, reload]);
1134
+ const schedule = useCallback8(async (items) => {
1135
+ return r.schedule(items);
1136
+ }, [r]);
1137
+ const setFallbacks = useCallback8(async (items) => {
1138
+ return r.setFallbacks(items);
1139
+ }, [r]);
1140
+ return { reminders, loading, setReminder, deleteReminder, schedule, setFallbacks };
835
1141
  }
836
1142
 
837
1143
  // src/hooks/useToast.ts
838
- import { useCallback as useCallback7, useState as useState9 } from "react";
1144
+ import { useCallback as useCallback9, useState as useState12 } from "react";
839
1145
  function useToast() {
840
- const [items, setItems] = useState9([]);
841
- const show = useCallback7((message, kind = "info") => {
1146
+ const [items, setItems] = useState12([]);
1147
+ const show = useCallback9((message, kind = "info") => {
842
1148
  const id = `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
843
1149
  setItems((prev) => [...prev, { id, message, kind }]);
844
1150
  setTimeout(() => {
845
1151
  setItems((prev) => prev.filter((t) => t.id !== id));
846
1152
  }, 4e3);
847
1153
  }, []);
848
- const dismiss = useCallback7((id) => {
1154
+ const dismiss = useCallback9((id) => {
849
1155
  setItems((prev) => prev.filter((t) => t.id !== id));
850
1156
  }, []);
851
1157
  return { items, show, dismiss };
@@ -860,12 +1166,14 @@ export {
860
1166
  EmptyState,
861
1167
  ErrorBoundary,
862
1168
  LoadingState,
1169
+ PushPrompt2 as PushPrompt,
863
1170
  useAuth,
864
1171
  useAuthPrimitives,
865
1172
  useForgotForm,
866
1173
  useLoginForm,
867
1174
  usePaywallState,
868
1175
  usePush,
1176
+ useReminders,
869
1177
  useResetForm,
870
1178
  useSignupForm,
871
1179
  useSubscription,