@riligar/auth-react 1.22.0 → 1.24.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 +39 -104
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +39 -104
- package/dist/index.js.map +1 -1
- package/package.json +1 -5
package/dist/index.esm.js
CHANGED
|
@@ -6,7 +6,6 @@ import { Navigate, Outlet, useNavigate } from 'react-router-dom';
|
|
|
6
6
|
import { Modal, Stack, Text, Image, Title, Paper, TextInput, PasswordInput, Anchor, Button, Divider, Group, Center, Loader, Box, Avatar, Collapse, Card, Tooltip, ThemeIcon, Badge } from '@mantine/core';
|
|
7
7
|
import { useForm } from '@mantine/form';
|
|
8
8
|
import { IconMail, IconLock, IconArrowRight, IconBrandGoogle, IconBrandGithub, IconUser, IconSend, IconCheck, IconX, IconRefresh, IconPhoto, IconTrash, IconPencil, IconShield, IconKey, IconDevices, IconDeviceMobile, IconLogout, IconUserCircle } from '@tabler/icons-react';
|
|
9
|
-
import { notifications } from '@mantine/notifications';
|
|
10
9
|
|
|
11
10
|
// Config - API Base URL fixa para o serviço de autenticação
|
|
12
11
|
let API_BASE = 'https://manager.myauth.click';
|
|
@@ -750,32 +749,39 @@ const useAuthStore = create((set, get) => ({
|
|
|
750
749
|
if (isAuthenticated()) {
|
|
751
750
|
const token = window.localStorage.getItem('auth:token');
|
|
752
751
|
if (token) {
|
|
753
|
-
//
|
|
754
|
-
const
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
752
|
+
// Usa o decoder oficial do SDK que é mais seguro
|
|
753
|
+
const payload = decodeJWT(token);
|
|
754
|
+
|
|
755
|
+
// Se não for um JWT ou não tiver expiração, não fazemos refresh em background
|
|
756
|
+
// O backend cuidará da expiração da sessão opaca via 401 nas requisições normais
|
|
757
|
+
if (!payload || !payload.exp) return;
|
|
758
758
|
const now = Date.now() / 1000;
|
|
759
759
|
const timeUntilExpiry = payload.exp - now;
|
|
760
760
|
|
|
761
|
-
// Se o token expira em menos de 5 minutos,
|
|
761
|
+
// Se o token expira em menos de 5 minutos, tenta o refresh
|
|
762
762
|
if (timeUntilExpiry < 300) {
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
763
|
+
try {
|
|
764
|
+
await refreshToken();
|
|
765
|
+
const user = getCurrentUser();
|
|
766
|
+
set({
|
|
767
|
+
user
|
|
768
|
+
});
|
|
769
|
+
} catch (refreshErr) {
|
|
770
|
+
console.warn('[AuthStore] Falha ao renovar token:', refreshErr);
|
|
771
|
+
// Só desloga se for um erro de autenticação explícito (401)
|
|
772
|
+
if (refreshErr.res?.status === 401) {
|
|
773
|
+
set({
|
|
774
|
+
user: null
|
|
775
|
+
});
|
|
776
|
+
window.localStorage.removeItem('auth:token');
|
|
777
|
+
}
|
|
778
|
+
}
|
|
769
779
|
}
|
|
770
780
|
}
|
|
771
781
|
}
|
|
772
782
|
} catch (error) {
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
set({
|
|
776
|
-
user: null
|
|
777
|
-
});
|
|
778
|
-
window.localStorage.removeItem('auth:token');
|
|
783
|
+
// Erros de processamento interno não devem deslogar o usuário
|
|
784
|
+
console.error('[AuthStore] Erro no ciclo de refresh automático:', error);
|
|
779
785
|
}
|
|
780
786
|
}, 4 * 60 * 1000); // Verifica a cada 4 minutos
|
|
781
787
|
|
|
@@ -2066,6 +2072,8 @@ function UserProfile({
|
|
|
2066
2072
|
onProfileUpdate,
|
|
2067
2073
|
onPasswordChange,
|
|
2068
2074
|
onEmailChange,
|
|
2075
|
+
onSessionRevoked,
|
|
2076
|
+
onOtherSessionsRevoked,
|
|
2069
2077
|
onError,
|
|
2070
2078
|
// Features toggle
|
|
2071
2079
|
showAvatar = true,
|
|
@@ -2152,7 +2160,9 @@ function UserProfile({
|
|
|
2152
2160
|
if (isCurrentSession) {
|
|
2153
2161
|
try {
|
|
2154
2162
|
await revokeSession(sessionId);
|
|
2163
|
+
onSessionRevoked?.(sessionId);
|
|
2155
2164
|
} catch (error) {
|
|
2165
|
+
onError?.(error);
|
|
2156
2166
|
// Even if it fails, we're revoking our own session, so just logout
|
|
2157
2167
|
// The server already revoked our session
|
|
2158
2168
|
}
|
|
@@ -2166,11 +2176,7 @@ function UserProfile({
|
|
|
2166
2176
|
// Revoking another session
|
|
2167
2177
|
try {
|
|
2168
2178
|
await revokeSession(sessionId);
|
|
2169
|
-
|
|
2170
|
-
title: labels.successTitle || 'Sucesso',
|
|
2171
|
-
message: labels.sessionRevoked || 'Sessão encerrada com sucesso',
|
|
2172
|
-
color: 'green'
|
|
2173
|
-
});
|
|
2179
|
+
onSessionRevoked?.(sessionId);
|
|
2174
2180
|
} catch (error) {
|
|
2175
2181
|
// Check for 401 error (our SDK uses error.res, axios uses error.response)
|
|
2176
2182
|
const status = error.res?.status || error.response?.status;
|
|
@@ -2181,28 +2187,14 @@ function UserProfile({
|
|
|
2181
2187
|
if (variant === 'modal') onClose?.();
|
|
2182
2188
|
return;
|
|
2183
2189
|
}
|
|
2184
|
-
notifications.show({
|
|
2185
|
-
title: labels.errorTitle || 'Erro',
|
|
2186
|
-
message: error.message || labels.sessionRevokeFailed || 'Falha ao encerrar sessão',
|
|
2187
|
-
color: 'red'
|
|
2188
|
-
});
|
|
2189
2190
|
onError?.(error);
|
|
2190
2191
|
}
|
|
2191
2192
|
};
|
|
2192
2193
|
const handleRevokeOtherSessions = async () => {
|
|
2193
2194
|
try {
|
|
2194
2195
|
await revokeOtherSessions();
|
|
2195
|
-
|
|
2196
|
-
title: labels.successTitle || 'Sucesso',
|
|
2197
|
-
message: labels.otherSessionsRevoked || 'Todas as outras sessões foram encerradas',
|
|
2198
|
-
color: 'green'
|
|
2199
|
-
});
|
|
2196
|
+
onOtherSessionsRevoked?.();
|
|
2200
2197
|
} catch (error) {
|
|
2201
|
-
notifications.show({
|
|
2202
|
-
title: labels.errorTitle || 'Erro',
|
|
2203
|
-
message: error.message || labels.otherSessionsRevokeFailed || 'Falha ao encerrar sessões',
|
|
2204
|
-
color: 'red'
|
|
2205
|
-
});
|
|
2206
2198
|
onError?.(error);
|
|
2207
2199
|
}
|
|
2208
2200
|
};
|
|
@@ -2263,21 +2255,13 @@ function UserProfile({
|
|
|
2263
2255
|
|
|
2264
2256
|
// Validate file type
|
|
2265
2257
|
if (!file.type.startsWith('image/')) {
|
|
2266
|
-
|
|
2267
|
-
title: labels.errorTitle || 'Erro',
|
|
2268
|
-
message: labels.avatarInvalidType || 'Por favor, selecione uma imagem válida',
|
|
2269
|
-
color: 'red'
|
|
2270
|
-
});
|
|
2258
|
+
onError?.(new Error(labels.avatarInvalidType || 'Por favor, selecione uma imagem válida'));
|
|
2271
2259
|
return;
|
|
2272
2260
|
}
|
|
2273
2261
|
|
|
2274
2262
|
// Validate file size
|
|
2275
2263
|
if (file.size > maxAvatarSize) {
|
|
2276
|
-
|
|
2277
|
-
title: labels.errorTitle || 'Erro',
|
|
2278
|
-
message: labels.avatarTooLarge || `Imagem muito grande. Máximo ${Math.round(maxAvatarSize / 1024)}KB.`,
|
|
2279
|
-
color: 'red'
|
|
2280
|
-
});
|
|
2264
|
+
onError?.(new Error(labels.avatarTooLarge || `Imagem muito grande. Máximo ${Math.round(maxAvatarSize / 1024)}KB.`));
|
|
2281
2265
|
return;
|
|
2282
2266
|
}
|
|
2283
2267
|
setAvatarFile(file);
|
|
@@ -2316,40 +2300,20 @@ function UserProfile({
|
|
|
2316
2300
|
const handleChangePassword = async values => {
|
|
2317
2301
|
try {
|
|
2318
2302
|
await changePassword(values.currentPassword, values.newPassword);
|
|
2319
|
-
notifications.show({
|
|
2320
|
-
title: labels.successTitle || 'Sucesso',
|
|
2321
|
-
message: labels.passwordChanged || 'Senha alterada com sucesso',
|
|
2322
|
-
color: 'green'
|
|
2323
|
-
});
|
|
2324
2303
|
passwordForm.reset();
|
|
2325
2304
|
setEditingSection(null);
|
|
2326
2305
|
onPasswordChange?.();
|
|
2327
2306
|
} catch (error) {
|
|
2328
|
-
notifications.show({
|
|
2329
|
-
title: labels.errorTitle || 'Erro',
|
|
2330
|
-
message: error.message || labels.passwordChangeFailed || 'Falha ao alterar senha',
|
|
2331
|
-
color: 'red'
|
|
2332
|
-
});
|
|
2333
2307
|
onError?.(error);
|
|
2334
2308
|
}
|
|
2335
2309
|
};
|
|
2336
2310
|
const handleChangeEmail = async values => {
|
|
2337
2311
|
try {
|
|
2338
2312
|
await changeEmail(values.newEmail);
|
|
2339
|
-
notifications.show({
|
|
2340
|
-
title: labels.successTitle || 'Sucesso',
|
|
2341
|
-
message: labels.emailVerificationSent || 'Verifique seu novo email para confirmar a alteração',
|
|
2342
|
-
color: 'green'
|
|
2343
|
-
});
|
|
2344
2313
|
emailForm.reset();
|
|
2345
2314
|
setEditingSection(null);
|
|
2346
2315
|
onEmailChange?.(values.newEmail);
|
|
2347
2316
|
} catch (error) {
|
|
2348
|
-
notifications.show({
|
|
2349
|
-
title: labels.errorTitle || 'Erro',
|
|
2350
|
-
message: error.message || labels.emailChangeFailed || 'Falha ao alterar email',
|
|
2351
|
-
color: 'red'
|
|
2352
|
-
});
|
|
2353
2317
|
onError?.(error);
|
|
2354
2318
|
}
|
|
2355
2319
|
};
|
|
@@ -2358,43 +2322,29 @@ function UserProfile({
|
|
|
2358
2322
|
await updateProfile({
|
|
2359
2323
|
name: values.name
|
|
2360
2324
|
});
|
|
2361
|
-
notifications.show({
|
|
2362
|
-
title: labels.successTitle || 'Sucesso',
|
|
2363
|
-
message: labels.nameUpdated || 'Nome atualizado com sucesso',
|
|
2364
|
-
color: 'green'
|
|
2365
|
-
});
|
|
2366
2325
|
nameForm.reset();
|
|
2367
2326
|
setEditingSection(null);
|
|
2368
2327
|
onProfileUpdate?.({
|
|
2369
2328
|
name: values.name
|
|
2370
2329
|
});
|
|
2371
2330
|
} catch (error) {
|
|
2372
|
-
notifications.show({
|
|
2373
|
-
title: labels.errorTitle || 'Erro',
|
|
2374
|
-
message: error.message || labels.nameUpdateFailed || 'Falha ao atualizar nome',
|
|
2375
|
-
color: 'red'
|
|
2376
|
-
});
|
|
2377
2331
|
onError?.(error);
|
|
2378
2332
|
}
|
|
2379
2333
|
};
|
|
2380
2334
|
const handleChangeAvatar = async () => {
|
|
2381
2335
|
if (!avatarPreview) {
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
|
|
2336
|
+
// Optionally handle this validation error via callback or just return?
|
|
2337
|
+
// Since it's a validation error before async call, we might want to expose it too?
|
|
2338
|
+
// The original code used notifications. Let's send to onError for consistency or just return if it's UI state.
|
|
2339
|
+
// Actually, for validation within the component, maybe we can just let it be silent or use form error if applicable?
|
|
2340
|
+
// But this is outside form context. Let's use onError with a custom error object.
|
|
2341
|
+
onError?.(new Error(labels.avatarRequired || 'Selecione uma imagem'));
|
|
2387
2342
|
return;
|
|
2388
2343
|
}
|
|
2389
2344
|
try {
|
|
2390
2345
|
await updateProfile({
|
|
2391
2346
|
image: avatarPreview
|
|
2392
2347
|
});
|
|
2393
|
-
notifications.show({
|
|
2394
|
-
title: labels.successTitle || 'Sucesso',
|
|
2395
|
-
message: labels.avatarUpdated || 'Foto de perfil atualizada com sucesso',
|
|
2396
|
-
color: 'green'
|
|
2397
|
-
});
|
|
2398
2348
|
setAvatarPreview(null);
|
|
2399
2349
|
setAvatarFile(null);
|
|
2400
2350
|
setEditingSection(null);
|
|
@@ -2402,11 +2352,6 @@ function UserProfile({
|
|
|
2402
2352
|
image: avatarPreview
|
|
2403
2353
|
});
|
|
2404
2354
|
} catch (error) {
|
|
2405
|
-
notifications.show({
|
|
2406
|
-
title: labels.errorTitle || 'Erro',
|
|
2407
|
-
message: error.message || labels.avatarUpdateFailed || 'Falha ao atualizar foto',
|
|
2408
|
-
color: 'red'
|
|
2409
|
-
});
|
|
2410
2355
|
onError?.(error);
|
|
2411
2356
|
}
|
|
2412
2357
|
};
|
|
@@ -2415,11 +2360,6 @@ function UserProfile({
|
|
|
2415
2360
|
await updateProfile({
|
|
2416
2361
|
image: ''
|
|
2417
2362
|
});
|
|
2418
|
-
notifications.show({
|
|
2419
|
-
title: labels.successTitle || 'Sucesso',
|
|
2420
|
-
message: labels.avatarRemoved || 'Foto de perfil removida',
|
|
2421
|
-
color: 'green'
|
|
2422
|
-
});
|
|
2423
2363
|
setAvatarPreview(null);
|
|
2424
2364
|
setAvatarFile(null);
|
|
2425
2365
|
setEditingSection(null);
|
|
@@ -2427,11 +2367,6 @@ function UserProfile({
|
|
|
2427
2367
|
image: ''
|
|
2428
2368
|
});
|
|
2429
2369
|
} catch (error) {
|
|
2430
|
-
notifications.show({
|
|
2431
|
-
title: labels.errorTitle || 'Erro',
|
|
2432
|
-
message: error.message || labels.avatarRemoveFailed || 'Falha ao remover foto',
|
|
2433
|
-
color: 'red'
|
|
2434
|
-
});
|
|
2435
2370
|
onError?.(error);
|
|
2436
2371
|
}
|
|
2437
2372
|
};
|