@riligar/auth-react 1.14.0 → 1.16.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 +441 -73
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +442 -70
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.esm.js
CHANGED
|
@@ -3,9 +3,9 @@ import { useMemo, useEffect, createContext, useState, useRef } from 'react';
|
|
|
3
3
|
import { useShallow } from 'zustand/react/shallow';
|
|
4
4
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
5
5
|
import { Navigate, Outlet, useNavigate } from 'react-router-dom';
|
|
6
|
-
import { Modal, Stack, Text, Image, Title, Paper, TextInput, PasswordInput, Anchor, Button, Divider, Group, Center, Loader, Box, Avatar, Collapse, Card, Tooltip, ThemeIcon } from '@mantine/core';
|
|
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
|
-
import { IconMail, IconLock, IconArrowRight, IconBrandGoogle, IconBrandGithub, IconUser, IconSend, IconCheck, IconX, IconRefresh, IconPhoto, IconTrash, IconPencil, IconShield, IconKey, IconUserCircle } from '@tabler/icons-react';
|
|
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
9
|
import { notifications } from '@mantine/notifications';
|
|
10
10
|
|
|
11
11
|
// Config - pode ser sobrescrita pelo AuthProvider
|
|
@@ -232,7 +232,7 @@ const verifyMagicLink = async token => {
|
|
|
232
232
|
/*--- Password Reset -----------------------------*/
|
|
233
233
|
const forgotPassword = async (email, redirectTo) => {
|
|
234
234
|
const redirect = redirectTo || (typeof window !== 'undefined' ? `${window.location.origin}/auth/reset-password` : '/auth/reset-password');
|
|
235
|
-
return await api('/auth/
|
|
235
|
+
return await api('/auth/request-password-reset', {
|
|
236
236
|
method: 'POST',
|
|
237
237
|
body: JSON.stringify({
|
|
238
238
|
email,
|
|
@@ -270,6 +270,22 @@ const resendVerification = async (email, callbackURL) => {
|
|
|
270
270
|
const getSession = async () => {
|
|
271
271
|
return await api('/auth/session');
|
|
272
272
|
};
|
|
273
|
+
const listSessions = async () => {
|
|
274
|
+
return await api('/auth/list-sessions');
|
|
275
|
+
};
|
|
276
|
+
const revokeSession = async id => {
|
|
277
|
+
return await api('/auth/revoke-session-by-id', {
|
|
278
|
+
method: 'POST',
|
|
279
|
+
body: JSON.stringify({
|
|
280
|
+
id
|
|
281
|
+
})
|
|
282
|
+
});
|
|
283
|
+
};
|
|
284
|
+
const revokeOtherSessions = async () => {
|
|
285
|
+
return await api('/auth/revoke-other-sessions', {
|
|
286
|
+
method: 'POST'
|
|
287
|
+
});
|
|
288
|
+
};
|
|
273
289
|
|
|
274
290
|
/*--- Application Info ----------------------------*/
|
|
275
291
|
const getApplicationInfo = async () => {
|
|
@@ -321,6 +337,9 @@ const useAuthStore = create((set, get) => ({
|
|
|
321
337
|
user: null,
|
|
322
338
|
loading: true,
|
|
323
339
|
error: null,
|
|
340
|
+
// Session management
|
|
341
|
+
sessions: [],
|
|
342
|
+
currentSession: null,
|
|
324
343
|
// Loading states granulares
|
|
325
344
|
loadingStates: {
|
|
326
345
|
signIn: false,
|
|
@@ -333,7 +352,9 @@ const useAuthStore = create((set, get) => ({
|
|
|
333
352
|
resendVerification: false,
|
|
334
353
|
updateProfile: false,
|
|
335
354
|
changePassword: false,
|
|
336
|
-
changeEmail: false
|
|
355
|
+
changeEmail: false,
|
|
356
|
+
listSessions: false,
|
|
357
|
+
revokeSession: false
|
|
337
358
|
},
|
|
338
359
|
// Application info (logo, nome, etc)
|
|
339
360
|
applicationInfo: null,
|
|
@@ -376,9 +397,14 @@ const useAuthStore = create((set, get) => ({
|
|
|
376
397
|
// Precisamos buscar a sessão no servidor.
|
|
377
398
|
if (!user) {
|
|
378
399
|
try {
|
|
379
|
-
const
|
|
380
|
-
if (
|
|
381
|
-
user =
|
|
400
|
+
const sessionData = await getSession();
|
|
401
|
+
if (sessionData?.user) {
|
|
402
|
+
user = sessionData.user;
|
|
403
|
+
}
|
|
404
|
+
if (sessionData?.session) {
|
|
405
|
+
set({
|
|
406
|
+
currentSession: sessionData.session
|
|
407
|
+
});
|
|
382
408
|
}
|
|
383
409
|
} catch (sessionError) {
|
|
384
410
|
console.warn('[AuthStore] Failed to fetch session:', sessionError);
|
|
@@ -451,8 +477,13 @@ const useAuthStore = create((set, get) => ({
|
|
|
451
477
|
|
|
452
478
|
// Se não encontrou no token (sessão opaca), busca do servidor
|
|
453
479
|
if (!user) {
|
|
454
|
-
const
|
|
455
|
-
if (
|
|
480
|
+
const sessionData = await getSession();
|
|
481
|
+
if (sessionData?.user) user = sessionData.user;
|
|
482
|
+
if (sessionData?.session) {
|
|
483
|
+
set({
|
|
484
|
+
currentSession: sessionData.session
|
|
485
|
+
});
|
|
486
|
+
}
|
|
456
487
|
}
|
|
457
488
|
set({
|
|
458
489
|
user,
|
|
@@ -634,11 +665,86 @@ const useAuthStore = create((set, get) => ({
|
|
|
634
665
|
/* Session */
|
|
635
666
|
getSession: async () => {
|
|
636
667
|
try {
|
|
637
|
-
|
|
668
|
+
const sessionData = await getSession();
|
|
669
|
+
// Store current session for comparison (includes id)
|
|
670
|
+
if (sessionData?.session) {
|
|
671
|
+
set({
|
|
672
|
+
currentSession: sessionData.session
|
|
673
|
+
});
|
|
674
|
+
}
|
|
675
|
+
return sessionData;
|
|
676
|
+
} catch (err) {
|
|
677
|
+
set({
|
|
678
|
+
error: err
|
|
679
|
+
});
|
|
680
|
+
throw err;
|
|
681
|
+
}
|
|
682
|
+
},
|
|
683
|
+
listSessions: async () => {
|
|
684
|
+
const {
|
|
685
|
+
setLoading
|
|
686
|
+
} = get();
|
|
687
|
+
setLoading('listSessions', true);
|
|
688
|
+
set({
|
|
689
|
+
error: null
|
|
690
|
+
});
|
|
691
|
+
try {
|
|
692
|
+
const result = await listSessions();
|
|
693
|
+
set({
|
|
694
|
+
sessions: result || []
|
|
695
|
+
});
|
|
696
|
+
setLoading('listSessions', false);
|
|
697
|
+
return result;
|
|
698
|
+
} catch (err) {
|
|
699
|
+
set({
|
|
700
|
+
error: err,
|
|
701
|
+
sessions: []
|
|
702
|
+
});
|
|
703
|
+
setLoading('listSessions', false);
|
|
704
|
+
throw err;
|
|
705
|
+
}
|
|
706
|
+
},
|
|
707
|
+
revokeSession: async token => {
|
|
708
|
+
const {
|
|
709
|
+
setLoading,
|
|
710
|
+
listSessions
|
|
711
|
+
} = get();
|
|
712
|
+
setLoading('revokeSession', true);
|
|
713
|
+
set({
|
|
714
|
+
error: null
|
|
715
|
+
});
|
|
716
|
+
try {
|
|
717
|
+
await revokeSession(token);
|
|
718
|
+
// Refresh sessions list after revocation
|
|
719
|
+
await listSessions();
|
|
720
|
+
setLoading('revokeSession', false);
|
|
721
|
+
} catch (err) {
|
|
722
|
+
set({
|
|
723
|
+
error: err
|
|
724
|
+
});
|
|
725
|
+
setLoading('revokeSession', false);
|
|
726
|
+
throw err;
|
|
727
|
+
}
|
|
728
|
+
},
|
|
729
|
+
revokeOtherSessions: async () => {
|
|
730
|
+
const {
|
|
731
|
+
setLoading,
|
|
732
|
+
listSessions
|
|
733
|
+
} = get();
|
|
734
|
+
setLoading('revokeSession', true);
|
|
735
|
+
set({
|
|
736
|
+
error: null
|
|
737
|
+
});
|
|
738
|
+
try {
|
|
739
|
+
await revokeOtherSessions();
|
|
740
|
+
// Refresh sessions list after revocation
|
|
741
|
+
await listSessions();
|
|
742
|
+
setLoading('revokeSession', false);
|
|
638
743
|
} catch (err) {
|
|
639
744
|
set({
|
|
640
745
|
error: err
|
|
641
746
|
});
|
|
747
|
+
setLoading('revokeSession', false);
|
|
642
748
|
throw err;
|
|
643
749
|
}
|
|
644
750
|
},
|
|
@@ -818,8 +924,24 @@ function AuthProvider({
|
|
|
818
924
|
checkTokenValidity();
|
|
819
925
|
}
|
|
820
926
|
};
|
|
927
|
+
|
|
928
|
+
// Escuta evento de sessão revogada (quando o usuário revoga sua própria sessão)
|
|
929
|
+
const handleSessionRevoked = () => {
|
|
930
|
+
// Limpa o usuário do store
|
|
931
|
+
useAuthStore.setState({
|
|
932
|
+
user: null,
|
|
933
|
+
currentSession: null,
|
|
934
|
+
sessions: []
|
|
935
|
+
});
|
|
936
|
+
// Dispara evento de logout para sincronizar entre abas
|
|
937
|
+
localStorage.setItem('auth:logout', Date.now());
|
|
938
|
+
};
|
|
821
939
|
window.addEventListener('storage', handleStorageChange);
|
|
822
|
-
|
|
940
|
+
window.addEventListener('auth:session-revoked', handleSessionRevoked);
|
|
941
|
+
return () => {
|
|
942
|
+
window.removeEventListener('storage', handleStorageChange);
|
|
943
|
+
window.removeEventListener('auth:session-revoked', handleSessionRevoked);
|
|
944
|
+
};
|
|
823
945
|
}, [checkTokenValidity]);
|
|
824
946
|
|
|
825
947
|
// Verifica validade do token periodicamente
|
|
@@ -907,6 +1029,19 @@ const useUser = () => useAuthStore(useShallow(s => ({
|
|
|
907
1029
|
// Alias deprecado para backwards compatibility
|
|
908
1030
|
const useProfile = useUser;
|
|
909
1031
|
|
|
1032
|
+
// Sessions Management Hook
|
|
1033
|
+
const useSessions = () => useAuthStore(useShallow(s => ({
|
|
1034
|
+
currentSession: s.currentSession,
|
|
1035
|
+
sessions: s.sessions,
|
|
1036
|
+
getSession: s.getSession,
|
|
1037
|
+
listSessions: s.listSessions,
|
|
1038
|
+
revokeSession: s.revokeSession,
|
|
1039
|
+
revokeOtherSessions: s.revokeOtherSessions,
|
|
1040
|
+
loadingListSessions: s.loadingStates.listSessions,
|
|
1041
|
+
loadingRevokeSession: s.loadingStates.revokeSession,
|
|
1042
|
+
error: s.error
|
|
1043
|
+
})));
|
|
1044
|
+
|
|
910
1045
|
// Application Logo Hook
|
|
911
1046
|
const useApplicationLogo = () => {
|
|
912
1047
|
const applicationInfo = useAuthStore(s => s.applicationInfo);
|
|
@@ -1936,6 +2071,7 @@ function UserProfile({
|
|
|
1936
2071
|
showName = true,
|
|
1937
2072
|
showEmail = true,
|
|
1938
2073
|
showPassword = true,
|
|
2074
|
+
showSessions = true,
|
|
1939
2075
|
// Customização
|
|
1940
2076
|
labels = {},
|
|
1941
2077
|
title = 'Account',
|
|
@@ -1963,6 +2099,111 @@ function UserProfile({
|
|
|
1963
2099
|
loadingChangeEmail
|
|
1964
2100
|
} = useProfile();
|
|
1965
2101
|
|
|
2102
|
+
// Hook para sessions
|
|
2103
|
+
const {
|
|
2104
|
+
currentSession,
|
|
2105
|
+
sessions,
|
|
2106
|
+
listSessions,
|
|
2107
|
+
getSession,
|
|
2108
|
+
revokeSession,
|
|
2109
|
+
revokeOtherSessions,
|
|
2110
|
+
loadingListSessions,
|
|
2111
|
+
loadingRevokeSession
|
|
2112
|
+
} = useSessions();
|
|
2113
|
+
|
|
2114
|
+
// Load sessions when opened (modal) or component mounts (card), and when sessions section is opened
|
|
2115
|
+
useEffect(() => {
|
|
2116
|
+
if (showSessions && (variant === 'card' || opened)) {
|
|
2117
|
+
// Fetch current session first to get the session ID, then list all sessions
|
|
2118
|
+
getSession().catch(err => console.warn('Failed to get current session:', err));
|
|
2119
|
+
listSessions().catch(err => console.warn('Failed to load sessions:', err));
|
|
2120
|
+
}
|
|
2121
|
+
}, [opened, showSessions, variant]);
|
|
2122
|
+
|
|
2123
|
+
// Helper to parse user agent string
|
|
2124
|
+
const parseUserAgent = ua => {
|
|
2125
|
+
if (!ua) return {
|
|
2126
|
+
browser: 'Unknown Browser',
|
|
2127
|
+
os: 'Unknown OS'
|
|
2128
|
+
};
|
|
2129
|
+
let browser = 'Unknown Browser';
|
|
2130
|
+
let os = 'Unknown OS';
|
|
2131
|
+
|
|
2132
|
+
// Detect browser
|
|
2133
|
+
if (ua.includes('Chrome') && !ua.includes('Edg')) browser = 'Chrome';else if (ua.includes('Firefox')) browser = 'Firefox';else if (ua.includes('Safari') && !ua.includes('Chrome')) browser = 'Safari';else if (ua.includes('Edg')) browser = 'Edge';else if (ua.includes('Opera') || ua.includes('OPR')) browser = 'Opera';
|
|
2134
|
+
|
|
2135
|
+
// Detect OS
|
|
2136
|
+
if (ua.includes('Windows')) os = 'Windows';else if (ua.includes('Mac OS')) os = 'macOS';else if (ua.includes('Linux')) os = 'Linux';else if (ua.includes('Android')) os = 'Android';else if (ua.includes('iPhone') || ua.includes('iPad')) os = 'iOS';
|
|
2137
|
+
return {
|
|
2138
|
+
browser,
|
|
2139
|
+
os
|
|
2140
|
+
};
|
|
2141
|
+
};
|
|
2142
|
+
|
|
2143
|
+
// Session handlers
|
|
2144
|
+
const handleRevokeSession = async sessionId => {
|
|
2145
|
+
// Check if revoking current session
|
|
2146
|
+
const isCurrentSession = sessionId === currentSession?.id || sessions.length === 1;
|
|
2147
|
+
|
|
2148
|
+
// If revoking current session, handle logout immediately after revocation
|
|
2149
|
+
if (isCurrentSession) {
|
|
2150
|
+
try {
|
|
2151
|
+
await revokeSession(sessionId);
|
|
2152
|
+
} catch (error) {
|
|
2153
|
+
// Even if it fails, we're revoking our own session, so just logout
|
|
2154
|
+
// The server already revoked our session
|
|
2155
|
+
}
|
|
2156
|
+
// Clear auth state and redirect
|
|
2157
|
+
localStorage.removeItem('auth:token');
|
|
2158
|
+
window.dispatchEvent(new CustomEvent('auth:session-revoked'));
|
|
2159
|
+
if (variant === 'modal') onClose?.();
|
|
2160
|
+
return;
|
|
2161
|
+
}
|
|
2162
|
+
|
|
2163
|
+
// Revoking another session
|
|
2164
|
+
try {
|
|
2165
|
+
await revokeSession(sessionId);
|
|
2166
|
+
notifications.show({
|
|
2167
|
+
title: labels.successTitle || 'Sucesso',
|
|
2168
|
+
message: labels.sessionRevoked || 'Sessão encerrada com sucesso',
|
|
2169
|
+
color: 'green'
|
|
2170
|
+
});
|
|
2171
|
+
} catch (error) {
|
|
2172
|
+
// Check for 401 error (our SDK uses error.res, axios uses error.response)
|
|
2173
|
+
const status = error.res?.status || error.response?.status;
|
|
2174
|
+
if (status === 401) {
|
|
2175
|
+
// This means our session was revoked, not the target one - do logout
|
|
2176
|
+
localStorage.removeItem('auth:token');
|
|
2177
|
+
window.dispatchEvent(new CustomEvent('auth:session-revoked'));
|
|
2178
|
+
if (variant === 'modal') onClose?.();
|
|
2179
|
+
return;
|
|
2180
|
+
}
|
|
2181
|
+
notifications.show({
|
|
2182
|
+
title: labels.errorTitle || 'Erro',
|
|
2183
|
+
message: error.message || labels.sessionRevokeFailed || 'Falha ao encerrar sessão',
|
|
2184
|
+
color: 'red'
|
|
2185
|
+
});
|
|
2186
|
+
onError?.(error);
|
|
2187
|
+
}
|
|
2188
|
+
};
|
|
2189
|
+
const handleRevokeOtherSessions = async () => {
|
|
2190
|
+
try {
|
|
2191
|
+
await revokeOtherSessions();
|
|
2192
|
+
notifications.show({
|
|
2193
|
+
title: labels.successTitle || 'Sucesso',
|
|
2194
|
+
message: labels.otherSessionsRevoked || 'Todas as outras sessões foram encerradas',
|
|
2195
|
+
color: 'green'
|
|
2196
|
+
});
|
|
2197
|
+
} catch (error) {
|
|
2198
|
+
notifications.show({
|
|
2199
|
+
title: labels.errorTitle || 'Erro',
|
|
2200
|
+
message: error.message || labels.otherSessionsRevokeFailed || 'Falha ao encerrar sessões',
|
|
2201
|
+
color: 'red'
|
|
2202
|
+
});
|
|
2203
|
+
onError?.(error);
|
|
2204
|
+
}
|
|
2205
|
+
};
|
|
2206
|
+
|
|
1966
2207
|
// Password form
|
|
1967
2208
|
const passwordForm = useForm({
|
|
1968
2209
|
initialValues: {
|
|
@@ -2494,7 +2735,7 @@ function UserProfile({
|
|
|
2494
2735
|
})]
|
|
2495
2736
|
})]
|
|
2496
2737
|
})]
|
|
2497
|
-
}), showPassword && /*#__PURE__*/jsxs(Box, {
|
|
2738
|
+
}), (showPassword || showSessions) && /*#__PURE__*/jsxs(Box, {
|
|
2498
2739
|
mb: "md",
|
|
2499
2740
|
children: [/*#__PURE__*/jsx(SectionHeader, {
|
|
2500
2741
|
icon: IconShield,
|
|
@@ -2502,69 +2743,196 @@ function UserProfile({
|
|
|
2502
2743
|
description: labels.securityDescription || 'Protect your account'
|
|
2503
2744
|
}), /*#__PURE__*/jsxs(Stack, {
|
|
2504
2745
|
gap: "sm",
|
|
2505
|
-
children: [/*#__PURE__*/
|
|
2506
|
-
|
|
2507
|
-
|
|
2508
|
-
|
|
2509
|
-
|
|
2510
|
-
|
|
2511
|
-
|
|
2512
|
-
|
|
2513
|
-
|
|
2514
|
-
|
|
2515
|
-
|
|
2516
|
-
|
|
2517
|
-
|
|
2518
|
-
|
|
2519
|
-
|
|
2520
|
-
|
|
2521
|
-
|
|
2522
|
-
|
|
2523
|
-
|
|
2524
|
-
|
|
2525
|
-
|
|
2526
|
-
|
|
2527
|
-
|
|
2528
|
-
|
|
2529
|
-
|
|
2530
|
-
|
|
2531
|
-
|
|
2532
|
-
|
|
2533
|
-
|
|
2534
|
-
|
|
2535
|
-
|
|
2536
|
-
|
|
2537
|
-
|
|
2538
|
-
|
|
2539
|
-
|
|
2540
|
-
|
|
2541
|
-
|
|
2542
|
-
|
|
2543
|
-
|
|
2544
|
-
|
|
2545
|
-
|
|
2546
|
-
|
|
2547
|
-
|
|
2548
|
-
|
|
2549
|
-
|
|
2550
|
-
|
|
2551
|
-
|
|
2552
|
-
|
|
2553
|
-
|
|
2554
|
-
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
|
|
2559
|
-
|
|
2560
|
-
|
|
2561
|
-
|
|
2562
|
-
|
|
2746
|
+
children: [showPassword && /*#__PURE__*/jsxs(Fragment, {
|
|
2747
|
+
children: [/*#__PURE__*/jsx(SettingRow, {
|
|
2748
|
+
label: labels.password || 'Password',
|
|
2749
|
+
action: labels.change || 'Change',
|
|
2750
|
+
actionLabel: labels.changePassword || 'Change your password',
|
|
2751
|
+
onClick: () => handleToggleSection('password'),
|
|
2752
|
+
expanded: editingSection === 'password',
|
|
2753
|
+
children: /*#__PURE__*/jsxs(Group, {
|
|
2754
|
+
gap: "xs",
|
|
2755
|
+
children: [/*#__PURE__*/jsx(IconKey, {
|
|
2756
|
+
size: 16,
|
|
2757
|
+
color: "var(--mantine-color-dimmed)"
|
|
2758
|
+
}), /*#__PURE__*/jsx(Text, {
|
|
2759
|
+
size: "sm",
|
|
2760
|
+
c: "dimmed",
|
|
2761
|
+
children: "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022"
|
|
2762
|
+
})]
|
|
2763
|
+
})
|
|
2764
|
+
}), /*#__PURE__*/jsx(Collapse, {
|
|
2765
|
+
in: editingSection === 'password',
|
|
2766
|
+
children: /*#__PURE__*/jsx(Card, {
|
|
2767
|
+
p: "md",
|
|
2768
|
+
withBorder: true,
|
|
2769
|
+
children: /*#__PURE__*/jsx("form", {
|
|
2770
|
+
onSubmit: passwordForm.onSubmit(handleChangePassword),
|
|
2771
|
+
children: /*#__PURE__*/jsxs(Stack, {
|
|
2772
|
+
gap: "sm",
|
|
2773
|
+
children: [/*#__PURE__*/jsx(PasswordInput, {
|
|
2774
|
+
label: labels.currentPassword || 'Senha Atual',
|
|
2775
|
+
placeholder: labels.currentPasswordPlaceholder || 'Digite sua senha atual',
|
|
2776
|
+
...passwordForm.getInputProps('currentPassword')
|
|
2777
|
+
}), /*#__PURE__*/jsx(PasswordInput, {
|
|
2778
|
+
label: labels.newPassword || 'Nova Senha',
|
|
2779
|
+
placeholder: labels.newPasswordPlaceholder || 'Digite a nova senha',
|
|
2780
|
+
description: labels.passwordDescription || 'Mínimo 8 caracteres',
|
|
2781
|
+
...passwordForm.getInputProps('newPassword')
|
|
2782
|
+
}), /*#__PURE__*/jsx(PasswordInput, {
|
|
2783
|
+
label: labels.confirmPassword || 'Confirmar Nova Senha',
|
|
2784
|
+
placeholder: labels.confirmPasswordPlaceholder || 'Confirme a nova senha',
|
|
2785
|
+
...passwordForm.getInputProps('confirmPassword')
|
|
2786
|
+
}), /*#__PURE__*/jsxs(Group, {
|
|
2787
|
+
justify: "flex-end",
|
|
2788
|
+
gap: "xs",
|
|
2789
|
+
children: [/*#__PURE__*/jsx(Button, {
|
|
2790
|
+
variant: "default",
|
|
2791
|
+
size: "xs",
|
|
2792
|
+
onClick: () => handleToggleSection('password'),
|
|
2793
|
+
leftSection: /*#__PURE__*/jsx(IconX, {
|
|
2794
|
+
size: 14
|
|
2795
|
+
}),
|
|
2796
|
+
children: labels.cancel || 'Cancelar'
|
|
2797
|
+
}), /*#__PURE__*/jsx(Button, {
|
|
2798
|
+
type: "submit",
|
|
2799
|
+
size: "xs",
|
|
2800
|
+
loading: loadingChangePassword,
|
|
2801
|
+
leftSection: /*#__PURE__*/jsx(IconCheck, {
|
|
2802
|
+
size: 14
|
|
2803
|
+
}),
|
|
2804
|
+
children: labels.save || 'Salvar'
|
|
2805
|
+
})]
|
|
2563
2806
|
})]
|
|
2564
|
-
})
|
|
2807
|
+
})
|
|
2565
2808
|
})
|
|
2566
2809
|
})
|
|
2567
|
-
})
|
|
2810
|
+
})]
|
|
2811
|
+
}), showSessions && /*#__PURE__*/jsxs(Fragment, {
|
|
2812
|
+
children: [/*#__PURE__*/jsx(SettingRow, {
|
|
2813
|
+
label: labels.sessions || 'Sessions',
|
|
2814
|
+
action: editingSection === 'sessions' ? labels.close || 'Close' : labels.manage || 'Manage',
|
|
2815
|
+
actionLabel: labels.manageSessions || 'Manage your active sessions',
|
|
2816
|
+
onClick: () => handleToggleSection('sessions'),
|
|
2817
|
+
expanded: editingSection === 'sessions',
|
|
2818
|
+
children: /*#__PURE__*/jsxs(Group, {
|
|
2819
|
+
gap: "xs",
|
|
2820
|
+
children: [/*#__PURE__*/jsx(IconDevices, {
|
|
2821
|
+
size: 16,
|
|
2822
|
+
color: "var(--mantine-color-dimmed)"
|
|
2823
|
+
}), /*#__PURE__*/jsx(Text, {
|
|
2824
|
+
size: "sm",
|
|
2825
|
+
c: "dimmed",
|
|
2826
|
+
children: sessions.length > 0 ? `${sessions.length} active session${sessions.length > 1 ? 's' : ''}` : loadingListSessions ? 'Loading...' : 'No sessions'
|
|
2827
|
+
})]
|
|
2828
|
+
})
|
|
2829
|
+
}), /*#__PURE__*/jsx(Collapse, {
|
|
2830
|
+
in: editingSection === 'sessions',
|
|
2831
|
+
children: /*#__PURE__*/jsx(Card, {
|
|
2832
|
+
p: "md",
|
|
2833
|
+
withBorder: true,
|
|
2834
|
+
children: /*#__PURE__*/jsx(Stack, {
|
|
2835
|
+
gap: "md",
|
|
2836
|
+
children: loadingListSessions ? /*#__PURE__*/jsx(Text, {
|
|
2837
|
+
size: "sm",
|
|
2838
|
+
c: "dimmed",
|
|
2839
|
+
ta: "center",
|
|
2840
|
+
children: labels.loadingSessions || 'Carregando sessões...'
|
|
2841
|
+
}) : sessions.length === 0 ? /*#__PURE__*/jsx(Text, {
|
|
2842
|
+
size: "sm",
|
|
2843
|
+
c: "dimmed",
|
|
2844
|
+
ta: "center",
|
|
2845
|
+
children: labels.noSessionsFound || 'Nenhuma sessão encontrada'
|
|
2846
|
+
}) : /*#__PURE__*/jsxs(Fragment, {
|
|
2847
|
+
children: [sessions.map(sessionItem => {
|
|
2848
|
+
const isCurrentSession = sessionItem.id === currentSession?.id;
|
|
2849
|
+
const deviceInfo = parseUserAgent(sessionItem.userAgent);
|
|
2850
|
+
const createdDate = new Date(sessionItem.createdAt);
|
|
2851
|
+
return /*#__PURE__*/jsx(Card, {
|
|
2852
|
+
p: "sm",
|
|
2853
|
+
style: {
|
|
2854
|
+
borderColor: isCurrentSession ? 'var(--mantine-color-blue-5)' : undefined,
|
|
2855
|
+
backgroundColor: isCurrentSession ? 'var(--mantine-color-blue-light)' : undefined
|
|
2856
|
+
},
|
|
2857
|
+
children: /*#__PURE__*/jsxs(Group, {
|
|
2858
|
+
justify: "space-between",
|
|
2859
|
+
wrap: "nowrap",
|
|
2860
|
+
children: [/*#__PURE__*/jsxs(Group, {
|
|
2861
|
+
gap: "sm",
|
|
2862
|
+
wrap: "nowrap",
|
|
2863
|
+
style: {
|
|
2864
|
+
flex: 1
|
|
2865
|
+
},
|
|
2866
|
+
children: [/*#__PURE__*/jsx(ThemeIcon, {
|
|
2867
|
+
size: 36,
|
|
2868
|
+
variant: "light",
|
|
2869
|
+
color: isCurrentSession ? 'blue' : 'gray',
|
|
2870
|
+
children: /*#__PURE__*/jsx(IconDeviceMobile, {
|
|
2871
|
+
size: 18
|
|
2872
|
+
})
|
|
2873
|
+
}), /*#__PURE__*/jsxs(Box, {
|
|
2874
|
+
style: {
|
|
2875
|
+
flex: 1
|
|
2876
|
+
},
|
|
2877
|
+
children: [/*#__PURE__*/jsxs(Group, {
|
|
2878
|
+
gap: "xs",
|
|
2879
|
+
children: [/*#__PURE__*/jsx(Text, {
|
|
2880
|
+
size: "sm",
|
|
2881
|
+
fw: 500,
|
|
2882
|
+
children: deviceInfo.browser
|
|
2883
|
+
}), isCurrentSession && /*#__PURE__*/jsx(Badge, {
|
|
2884
|
+
size: "xs",
|
|
2885
|
+
variant: "filled",
|
|
2886
|
+
color: "blue",
|
|
2887
|
+
children: labels.thisDevice || 'Este dispositivo'
|
|
2888
|
+
})]
|
|
2889
|
+
}), /*#__PURE__*/jsxs(Text, {
|
|
2890
|
+
size: "xs",
|
|
2891
|
+
c: "dimmed",
|
|
2892
|
+
children: [deviceInfo.os, " \u2022 ", sessionItem.ipAddress || labels.unknownIP || 'IP desconhecido']
|
|
2893
|
+
}), /*#__PURE__*/jsxs(Text, {
|
|
2894
|
+
size: "xs",
|
|
2895
|
+
c: "dimmed",
|
|
2896
|
+
children: [labels.createdAt || 'Criada em', " ", createdDate.toLocaleDateString('pt-BR'), " ", labels.at || 'às', ' ', createdDate.toLocaleTimeString('pt-BR', {
|
|
2897
|
+
hour: '2-digit',
|
|
2898
|
+
minute: '2-digit'
|
|
2899
|
+
})]
|
|
2900
|
+
})]
|
|
2901
|
+
})]
|
|
2902
|
+
}), /*#__PURE__*/jsx(Tooltip, {
|
|
2903
|
+
label: isCurrentSession ? labels.signOutAndEnd || 'Encerrar e sair' : labels.endSession || 'Encerrar sessão',
|
|
2904
|
+
children: /*#__PURE__*/jsx(Button, {
|
|
2905
|
+
variant: "light",
|
|
2906
|
+
color: "red",
|
|
2907
|
+
size: "xs",
|
|
2908
|
+
onClick: () => handleRevokeSession(sessionItem.id),
|
|
2909
|
+
loading: loadingRevokeSession,
|
|
2910
|
+
leftSection: /*#__PURE__*/jsx(IconLogout, {
|
|
2911
|
+
size: 14
|
|
2912
|
+
}),
|
|
2913
|
+
children: labels.end || 'Encerrar'
|
|
2914
|
+
})
|
|
2915
|
+
})]
|
|
2916
|
+
})
|
|
2917
|
+
}, sessionItem.id);
|
|
2918
|
+
}), sessions.length > 1 && /*#__PURE__*/jsx(Group, {
|
|
2919
|
+
justify: "flex-end",
|
|
2920
|
+
children: /*#__PURE__*/jsx(Button, {
|
|
2921
|
+
variant: "light",
|
|
2922
|
+
color: "red",
|
|
2923
|
+
size: "xs",
|
|
2924
|
+
onClick: handleRevokeOtherSessions,
|
|
2925
|
+
loading: loadingRevokeSession,
|
|
2926
|
+
leftSection: /*#__PURE__*/jsx(IconLogout, {
|
|
2927
|
+
size: 14
|
|
2928
|
+
}),
|
|
2929
|
+
children: labels.endOtherSessions || 'Encerrar todas as outras sessões'
|
|
2930
|
+
})
|
|
2931
|
+
})]
|
|
2932
|
+
})
|
|
2933
|
+
})
|
|
2934
|
+
})
|
|
2935
|
+
})]
|
|
2568
2936
|
})]
|
|
2569
2937
|
})]
|
|
2570
2938
|
})]
|
|
@@ -2748,5 +3116,5 @@ function SignOutButton({
|
|
|
2748
3116
|
});
|
|
2749
3117
|
}
|
|
2750
3118
|
|
|
2751
|
-
export { UserProfile as AccountModal, AuthCard, AuthLoaded, AuthLoading, AuthProvider, ForgotPassword, ForgotPassword as ForgotPasswordForm, MagicLink, MagicLinkCallback, MagicLink as MagicLinkForm, MagicLinkCallback as MagicLinkVerify, Protect, Protect as ProtectedRoute, ResetPassword, ResetPassword as ResetPasswordForm, SignIn, SignInButton, SignIn as SignInForm, SignOutButton, SignUp, SignUpButton, SignUp as SignUpForm, SignedIn, SignedOut, UserProfile, VerifyEmail, VerifyEmail as VerifyEmailCard, changeEmail, changePassword, configure, decodeJWT, forgotPassword, getApplicationInfo, getCurrentUser, getSession, isAuthenticated, refreshToken, resendVerification, resetPassword, sendMagicLink, signIn, signOut, signUp, socialRedirect, updateProfile, useApplicationLogo, useAuth, useAuthLoading, useAuthStore, useCheckToken, useEmailVerification, useMagicLink, usePasswordReset, useUser as useProfile, useSession, useSignIn, useSignOut, useSignUp, useUser, verifyEmail, verifyMagicLink };
|
|
3119
|
+
export { UserProfile as AccountModal, AuthCard, AuthLoaded, AuthLoading, AuthProvider, ForgotPassword, ForgotPassword as ForgotPasswordForm, MagicLink, MagicLinkCallback, MagicLink as MagicLinkForm, MagicLinkCallback as MagicLinkVerify, Protect, Protect as ProtectedRoute, ResetPassword, ResetPassword as ResetPasswordForm, SignIn, SignInButton, SignIn as SignInForm, SignOutButton, SignUp, SignUpButton, SignUp as SignUpForm, SignedIn, SignedOut, UserProfile, VerifyEmail, VerifyEmail as VerifyEmailCard, changeEmail, changePassword, configure, decodeJWT, forgotPassword, getApplicationInfo, getCurrentUser, getSession, isAuthenticated, listSessions, refreshToken, resendVerification, resetPassword, revokeOtherSessions, revokeSession, sendMagicLink, signIn, signOut, signUp, socialRedirect, updateProfile, useApplicationLogo, useAuth, useAuthLoading, useAuthStore, useCheckToken, useEmailVerification, useMagicLink, usePasswordReset, useUser as useProfile, useSession, useSessions, useSignIn, useSignOut, useSignUp, useUser, verifyEmail, verifyMagicLink };
|
|
2752
3120
|
//# sourceMappingURL=index.esm.js.map
|