@riligar/auth-react 1.4.0 → 1.5.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.esm.js CHANGED
@@ -1,4 +1,4 @@
1
- import React$1, { useEffect, useMemo, createContext, useState } from 'react';
1
+ import React$1, { useMemo, useEffect, createContext, useState, useRef } from 'react';
2
2
  import { Navigate, Outlet } from 'react-router-dom';
3
3
  import { Paper, Stack, Image, Title, Text, TextInput, PasswordInput, Anchor, Button, Divider, Group, Center, Loader } from '@mantine/core';
4
4
  import { useForm } from '@mantine/form';
@@ -58,10 +58,18 @@ async function api(route, opts = {}) {
58
58
 
59
59
  // Converte JSON automaticamente e lança erro legível
60
60
  const data = res.status !== 204 ? await res.json().catch(() => ({})) : null;
61
- if (!res.ok) throw Object.assign(new Error(data?.error ?? res.statusText), {
62
- res,
63
- data
64
- });
61
+ if (!res.ok) {
62
+ let errorMessage = data?.message || data?.error || data?.detail || res.statusText;
63
+
64
+ // Se a mensagem for um objeto, tenta extrair string ou stringify
65
+ if (typeof errorMessage === 'object') {
66
+ errorMessage = errorMessage.message || JSON.stringify(errorMessage);
67
+ }
68
+ throw Object.assign(new Error(errorMessage), {
69
+ res,
70
+ data
71
+ });
72
+ }
65
73
  return data;
66
74
  }
67
75
 
@@ -756,7 +764,9 @@ function AuthProvider({
756
764
  const checkTokenValidity = useAuthStore(s => s.checkTokenValidity);
757
765
 
758
766
  // Configura SDK com apiUrl e apiKey
759
- useEffect(() => {
767
+ // Configura SDK com apiUrl e apiKey
768
+ // Usamos useMemo para garantir que a configuração ocorra ANTES dos efeitos dos componentes filhos
769
+ useMemo(() => {
760
770
  configure({
761
771
  apiUrl,
762
772
  apiKey
@@ -1274,6 +1284,7 @@ function MagicLinkVerify({
1274
1284
  const [status, setStatus] = useState('verifying'); // verifying, success, error
1275
1285
  const [errorMessage, setErrorMessage] = useState('');
1276
1286
  const verifyMagicLink = useAuthStore(s => s.verifyMagicLink);
1287
+ const verifyingTokenRef = useRef(null);
1277
1288
  useEffect(() => {
1278
1289
  const verify = async () => {
1279
1290
  // Pega token da prop ou da URL
@@ -1288,6 +1299,10 @@ function MagicLinkVerify({
1288
1299
  onError?.(new Error('No token'));
1289
1300
  return;
1290
1301
  }
1302
+
1303
+ // Evita verificar o mesmo token duas vezes (React Strict Mode ou re-renders)
1304
+ if (verifyingTokenRef.current === token) return;
1305
+ verifyingTokenRef.current = token;
1291
1306
  try {
1292
1307
  const result = await verifyMagicLink(token);
1293
1308
  setStatus('success');
@@ -1304,7 +1319,8 @@ function MagicLinkVerify({
1304
1319
  }
1305
1320
  };
1306
1321
  verify();
1307
- }, [propToken, verifyMagicLink, onSuccess, onError, redirectTo, redirectDelay, labels]);
1322
+ // eslint-disable-next-line react-hooks/exhaustive-deps
1323
+ }, [propToken, redirectTo, redirectDelay]);
1308
1324
  return /*#__PURE__*/React.createElement(AuthCard, _extends({
1309
1325
  logo: logo
1310
1326
  }, cardProps), status === 'verifying' && /*#__PURE__*/React.createElement(Stack, {
@@ -1559,9 +1575,13 @@ function VerifyEmailCard({
1559
1575
  }) {
1560
1576
  const [status, setStatus] = useState('verifying'); // verifying, success, error
1561
1577
  const [errorMessage, setErrorMessage] = useState('');
1578
+ const [tokenEmail, setTokenEmail] = useState(null); // Novo estado para email do token
1579
+
1562
1580
  const verifyEmail = useAuthStore(s => s.verifyEmail);
1563
1581
  const resendVerification = useAuthStore(s => s.resendVerification);
1564
1582
  const loadingResend = useAuthStore(s => s.loadingStates.resendVerification);
1583
+ const user = useAuthStore(s => s.user);
1584
+ const verifyingTokenRef = useRef(null);
1565
1585
  useEffect(() => {
1566
1586
  const verify = async () => {
1567
1587
  // Pega token da prop ou da URL
@@ -1571,11 +1591,25 @@ function VerifyEmailCard({
1571
1591
  token = urlParams.get('token');
1572
1592
  }
1573
1593
  if (!token) {
1574
- setStatus('error');
1575
- setErrorMessage(labels.noToken || 'Token não encontrado na URL');
1576
- onError?.(new Error('No token'));
1594
+ // Se já mostramos o erro de token faltando, não precisa fazer nada
1595
+ if (status === 'missing_token') return;
1596
+ setStatus('missing_token');
1577
1597
  return;
1578
1598
  }
1599
+
1600
+ // Tenta extrair email do token (mesmo expirado) para permitir reenvio
1601
+ try {
1602
+ const payload = decodeJWT(token);
1603
+ if (payload?.email) {
1604
+ setTokenEmail(payload.email);
1605
+ }
1606
+ } catch (e) {
1607
+ // ignore jwt error
1608
+ }
1609
+
1610
+ // Evita verificar o mesmo token duas vezes (React Strict Mode ou re-renders)
1611
+ if (verifyingTokenRef.current === token) return;
1612
+ verifyingTokenRef.current = token;
1579
1613
  try {
1580
1614
  const result = await verifyEmail(token);
1581
1615
  setStatus('success');
@@ -1586,18 +1620,22 @@ function VerifyEmailCard({
1586
1620
  }, redirectDelay);
1587
1621
  }
1588
1622
  } catch (error) {
1623
+ // Se der erro, permitimos tentar novamente apenas se o usuário recarregar
1624
+ // ou se implementarmos um botão de retry que limpe o ref
1589
1625
  setStatus('error');
1590
1626
  setErrorMessage(error.message || labels.verificationFailed || 'Verificação falhou');
1591
1627
  onError?.(error);
1592
1628
  }
1593
1629
  };
1594
1630
  verify();
1595
- }, [propToken, verifyEmail, onSuccess, onError, redirectTo, redirectDelay, labels]);
1631
+ // eslint-disable-next-line react-hooks/exhaustive-deps
1632
+ }, [propToken, redirectTo, redirectDelay]);
1596
1633
  const handleResend = async () => {
1597
- if (!email) return;
1634
+ const targetEmail = email || user?.email || tokenEmail;
1635
+ if (!targetEmail) return;
1598
1636
  try {
1599
- await resendVerification(email);
1600
- onResent?.(email);
1637
+ await resendVerification(targetEmail);
1638
+ onResent?.(targetEmail);
1601
1639
  } catch (error) {
1602
1640
  onError?.(error);
1603
1641
  }
@@ -1615,7 +1653,19 @@ function VerifyEmailCard({
1615
1653
  size: "sm",
1616
1654
  c: "dimmed",
1617
1655
  ta: "center"
1618
- }, labels.pleaseWait || 'Aguarde enquanto verificamos seu email...')), status === 'success' && /*#__PURE__*/React.createElement(Stack, {
1656
+ }, labels.pleaseWait || 'Aguarde enquanto verificamos seu email...')), status === 'missing_token' && /*#__PURE__*/React.createElement(Stack, {
1657
+ align: "center",
1658
+ gap: "sm"
1659
+ }, /*#__PURE__*/React.createElement(IconMail, {
1660
+ size: 48,
1661
+ color: "var(--mantine-color-blue-6)"
1662
+ }), /*#__PURE__*/React.createElement(Title, {
1663
+ order: 4
1664
+ }, labels.verification || 'Verificação de Email'), /*#__PURE__*/React.createElement(Text, {
1665
+ size: "sm",
1666
+ c: "dimmed",
1667
+ ta: "center"
1668
+ }, labels.missingToken || 'Para verificar seu conta, clique no link enviado para seu email.')), status === 'success' && /*#__PURE__*/React.createElement(Stack, {
1619
1669
  align: "center",
1620
1670
  gap: "sm"
1621
1671
  }, /*#__PURE__*/React.createElement(IconCheck, {
@@ -1639,7 +1689,7 @@ function VerifyEmailCard({
1639
1689
  size: "sm",
1640
1690
  c: "dimmed",
1641
1691
  ta: "center"
1642
- }, errorMessage || labels.invalidToken || 'O link é inválido ou expirou.'), email && /*#__PURE__*/React.createElement(Button, {
1692
+ }, errorMessage || labels.invalidToken || 'O link é inválido ou expirou.'), (email || user?.email || tokenEmail) && errorMessage?.toLowerCase().includes('expired') && /*#__PURE__*/React.createElement(Button, {
1643
1693
  variant: "light",
1644
1694
  leftSection: /*#__PURE__*/React.createElement(IconRefresh, {
1645
1695
  size: 16
@@ -1647,8 +1697,8 @@ function VerifyEmailCard({
1647
1697
  onClick: handleResend,
1648
1698
  loading: loadingResend,
1649
1699
  fullWidth: true
1650
- }, labels.resend || 'Reenviar Email de Verificação')));
1700
+ }, labels.resend || 'Solicitar novo link')));
1651
1701
  }
1652
1702
 
1653
- export { AuthCard, AuthProvider, ForgotPasswordForm, MagicLinkForm, MagicLinkVerify, ProtectedRoute, ResetPasswordForm, SignInForm, SignUpForm, VerifyEmailCard, configure, forgotPassword, getCurrentUser, getSession, isAuthenticated, refreshToken, resendVerification, resetPassword, sendMagicLink, signIn, signOut, signUp, socialRedirect, useAuth, useAuthLoading, useAuthStore, useCheckToken, useEmailVerification, useMagicLink, usePasswordReset, useSession, useSignIn, useSignOut, useSignUp, verifyEmail, verifyMagicLink };
1703
+ export { AuthCard, AuthProvider, ForgotPasswordForm, MagicLinkForm, MagicLinkVerify, ProtectedRoute, ResetPasswordForm, SignInForm, SignUpForm, VerifyEmailCard, configure, decodeJWT, forgotPassword, getCurrentUser, getSession, isAuthenticated, refreshToken, resendVerification, resetPassword, sendMagicLink, signIn, signOut, signUp, socialRedirect, useAuth, useAuthLoading, useAuthStore, useCheckToken, useEmailVerification, useMagicLink, usePasswordReset, useSession, useSignIn, useSignOut, useSignUp, verifyEmail, verifyMagicLink };
1654
1704
  //# sourceMappingURL=index.esm.js.map