@riligar/auth-react 1.15.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 +351 -79
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +349 -76
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -276,11 +276,11 @@ const getSession = async () => {
|
|
|
276
276
|
const listSessions = async () => {
|
|
277
277
|
return await api('/auth/list-sessions');
|
|
278
278
|
};
|
|
279
|
-
const revokeSession = async
|
|
280
|
-
return await api('/auth/revoke-session', {
|
|
279
|
+
const revokeSession = async id => {
|
|
280
|
+
return await api('/auth/revoke-session-by-id', {
|
|
281
281
|
method: 'POST',
|
|
282
282
|
body: JSON.stringify({
|
|
283
|
-
|
|
283
|
+
id
|
|
284
284
|
})
|
|
285
285
|
});
|
|
286
286
|
};
|
|
@@ -342,7 +342,7 @@ const useAuthStore = zustand.create((set, get) => ({
|
|
|
342
342
|
error: null,
|
|
343
343
|
// Session management
|
|
344
344
|
sessions: [],
|
|
345
|
-
|
|
345
|
+
currentSession: null,
|
|
346
346
|
// Loading states granulares
|
|
347
347
|
loadingStates: {
|
|
348
348
|
signIn: false,
|
|
@@ -400,9 +400,14 @@ const useAuthStore = zustand.create((set, get) => ({
|
|
|
400
400
|
// Precisamos buscar a sessão no servidor.
|
|
401
401
|
if (!user) {
|
|
402
402
|
try {
|
|
403
|
-
const
|
|
404
|
-
if (
|
|
405
|
-
user =
|
|
403
|
+
const sessionData = await getSession();
|
|
404
|
+
if (sessionData?.user) {
|
|
405
|
+
user = sessionData.user;
|
|
406
|
+
}
|
|
407
|
+
if (sessionData?.session) {
|
|
408
|
+
set({
|
|
409
|
+
currentSession: sessionData.session
|
|
410
|
+
});
|
|
406
411
|
}
|
|
407
412
|
} catch (sessionError) {
|
|
408
413
|
console.warn('[AuthStore] Failed to fetch session:', sessionError);
|
|
@@ -475,8 +480,13 @@ const useAuthStore = zustand.create((set, get) => ({
|
|
|
475
480
|
|
|
476
481
|
// Se não encontrou no token (sessão opaca), busca do servidor
|
|
477
482
|
if (!user) {
|
|
478
|
-
const
|
|
479
|
-
if (
|
|
483
|
+
const sessionData = await getSession();
|
|
484
|
+
if (sessionData?.user) user = sessionData.user;
|
|
485
|
+
if (sessionData?.session) {
|
|
486
|
+
set({
|
|
487
|
+
currentSession: sessionData.session
|
|
488
|
+
});
|
|
489
|
+
}
|
|
480
490
|
}
|
|
481
491
|
set({
|
|
482
492
|
user,
|
|
@@ -658,14 +668,14 @@ const useAuthStore = zustand.create((set, get) => ({
|
|
|
658
668
|
/* Session */
|
|
659
669
|
getSession: async () => {
|
|
660
670
|
try {
|
|
661
|
-
const
|
|
662
|
-
// Store current session
|
|
663
|
-
if (
|
|
671
|
+
const sessionData = await getSession();
|
|
672
|
+
// Store current session for comparison (includes id)
|
|
673
|
+
if (sessionData?.session) {
|
|
664
674
|
set({
|
|
665
|
-
|
|
675
|
+
currentSession: sessionData.session
|
|
666
676
|
});
|
|
667
677
|
}
|
|
668
|
-
return
|
|
678
|
+
return sessionData;
|
|
669
679
|
} catch (err) {
|
|
670
680
|
set({
|
|
671
681
|
error: err
|
|
@@ -917,8 +927,24 @@ function AuthProvider({
|
|
|
917
927
|
checkTokenValidity();
|
|
918
928
|
}
|
|
919
929
|
};
|
|
930
|
+
|
|
931
|
+
// Escuta evento de sessão revogada (quando o usuário revoga sua própria sessão)
|
|
932
|
+
const handleSessionRevoked = () => {
|
|
933
|
+
// Limpa o usuário do store
|
|
934
|
+
useAuthStore.setState({
|
|
935
|
+
user: null,
|
|
936
|
+
currentSession: null,
|
|
937
|
+
sessions: []
|
|
938
|
+
});
|
|
939
|
+
// Dispara evento de logout para sincronizar entre abas
|
|
940
|
+
localStorage.setItem('auth:logout', Date.now());
|
|
941
|
+
};
|
|
920
942
|
window.addEventListener('storage', handleStorageChange);
|
|
921
|
-
|
|
943
|
+
window.addEventListener('auth:session-revoked', handleSessionRevoked);
|
|
944
|
+
return () => {
|
|
945
|
+
window.removeEventListener('storage', handleStorageChange);
|
|
946
|
+
window.removeEventListener('auth:session-revoked', handleSessionRevoked);
|
|
947
|
+
};
|
|
922
948
|
}, [checkTokenValidity]);
|
|
923
949
|
|
|
924
950
|
// Verifica validade do token periodicamente
|
|
@@ -1006,6 +1032,19 @@ const useUser = () => useAuthStore(shallow.useShallow(s => ({
|
|
|
1006
1032
|
// Alias deprecado para backwards compatibility
|
|
1007
1033
|
const useProfile = useUser;
|
|
1008
1034
|
|
|
1035
|
+
// Sessions Management Hook
|
|
1036
|
+
const useSessions = () => useAuthStore(shallow.useShallow(s => ({
|
|
1037
|
+
currentSession: s.currentSession,
|
|
1038
|
+
sessions: s.sessions,
|
|
1039
|
+
getSession: s.getSession,
|
|
1040
|
+
listSessions: s.listSessions,
|
|
1041
|
+
revokeSession: s.revokeSession,
|
|
1042
|
+
revokeOtherSessions: s.revokeOtherSessions,
|
|
1043
|
+
loadingListSessions: s.loadingStates.listSessions,
|
|
1044
|
+
loadingRevokeSession: s.loadingStates.revokeSession,
|
|
1045
|
+
error: s.error
|
|
1046
|
+
})));
|
|
1047
|
+
|
|
1009
1048
|
// Application Logo Hook
|
|
1010
1049
|
const useApplicationLogo = () => {
|
|
1011
1050
|
const applicationInfo = useAuthStore(s => s.applicationInfo);
|
|
@@ -2035,6 +2074,7 @@ function UserProfile({
|
|
|
2035
2074
|
showName = true,
|
|
2036
2075
|
showEmail = true,
|
|
2037
2076
|
showPassword = true,
|
|
2077
|
+
showSessions = true,
|
|
2038
2078
|
// Customização
|
|
2039
2079
|
labels = {},
|
|
2040
2080
|
title = 'Account',
|
|
@@ -2062,6 +2102,111 @@ function UserProfile({
|
|
|
2062
2102
|
loadingChangeEmail
|
|
2063
2103
|
} = useProfile();
|
|
2064
2104
|
|
|
2105
|
+
// Hook para sessions
|
|
2106
|
+
const {
|
|
2107
|
+
currentSession,
|
|
2108
|
+
sessions,
|
|
2109
|
+
listSessions,
|
|
2110
|
+
getSession,
|
|
2111
|
+
revokeSession,
|
|
2112
|
+
revokeOtherSessions,
|
|
2113
|
+
loadingListSessions,
|
|
2114
|
+
loadingRevokeSession
|
|
2115
|
+
} = useSessions();
|
|
2116
|
+
|
|
2117
|
+
// Load sessions when opened (modal) or component mounts (card), and when sessions section is opened
|
|
2118
|
+
react.useEffect(() => {
|
|
2119
|
+
if (showSessions && (variant === 'card' || opened)) {
|
|
2120
|
+
// Fetch current session first to get the session ID, then list all sessions
|
|
2121
|
+
getSession().catch(err => console.warn('Failed to get current session:', err));
|
|
2122
|
+
listSessions().catch(err => console.warn('Failed to load sessions:', err));
|
|
2123
|
+
}
|
|
2124
|
+
}, [opened, showSessions, variant]);
|
|
2125
|
+
|
|
2126
|
+
// Helper to parse user agent string
|
|
2127
|
+
const parseUserAgent = ua => {
|
|
2128
|
+
if (!ua) return {
|
|
2129
|
+
browser: 'Unknown Browser',
|
|
2130
|
+
os: 'Unknown OS'
|
|
2131
|
+
};
|
|
2132
|
+
let browser = 'Unknown Browser';
|
|
2133
|
+
let os = 'Unknown OS';
|
|
2134
|
+
|
|
2135
|
+
// Detect browser
|
|
2136
|
+
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';
|
|
2137
|
+
|
|
2138
|
+
// Detect OS
|
|
2139
|
+
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';
|
|
2140
|
+
return {
|
|
2141
|
+
browser,
|
|
2142
|
+
os
|
|
2143
|
+
};
|
|
2144
|
+
};
|
|
2145
|
+
|
|
2146
|
+
// Session handlers
|
|
2147
|
+
const handleRevokeSession = async sessionId => {
|
|
2148
|
+
// Check if revoking current session
|
|
2149
|
+
const isCurrentSession = sessionId === currentSession?.id || sessions.length === 1;
|
|
2150
|
+
|
|
2151
|
+
// If revoking current session, handle logout immediately after revocation
|
|
2152
|
+
if (isCurrentSession) {
|
|
2153
|
+
try {
|
|
2154
|
+
await revokeSession(sessionId);
|
|
2155
|
+
} catch (error) {
|
|
2156
|
+
// Even if it fails, we're revoking our own session, so just logout
|
|
2157
|
+
// The server already revoked our session
|
|
2158
|
+
}
|
|
2159
|
+
// Clear auth state and redirect
|
|
2160
|
+
localStorage.removeItem('auth:token');
|
|
2161
|
+
window.dispatchEvent(new CustomEvent('auth:session-revoked'));
|
|
2162
|
+
if (variant === 'modal') onClose?.();
|
|
2163
|
+
return;
|
|
2164
|
+
}
|
|
2165
|
+
|
|
2166
|
+
// Revoking another session
|
|
2167
|
+
try {
|
|
2168
|
+
await revokeSession(sessionId);
|
|
2169
|
+
notifications.notifications.show({
|
|
2170
|
+
title: labels.successTitle || 'Sucesso',
|
|
2171
|
+
message: labels.sessionRevoked || 'Sessão encerrada com sucesso',
|
|
2172
|
+
color: 'green'
|
|
2173
|
+
});
|
|
2174
|
+
} catch (error) {
|
|
2175
|
+
// Check for 401 error (our SDK uses error.res, axios uses error.response)
|
|
2176
|
+
const status = error.res?.status || error.response?.status;
|
|
2177
|
+
if (status === 401) {
|
|
2178
|
+
// This means our session was revoked, not the target one - do logout
|
|
2179
|
+
localStorage.removeItem('auth:token');
|
|
2180
|
+
window.dispatchEvent(new CustomEvent('auth:session-revoked'));
|
|
2181
|
+
if (variant === 'modal') onClose?.();
|
|
2182
|
+
return;
|
|
2183
|
+
}
|
|
2184
|
+
notifications.notifications.show({
|
|
2185
|
+
title: labels.errorTitle || 'Erro',
|
|
2186
|
+
message: error.message || labels.sessionRevokeFailed || 'Falha ao encerrar sessão',
|
|
2187
|
+
color: 'red'
|
|
2188
|
+
});
|
|
2189
|
+
onError?.(error);
|
|
2190
|
+
}
|
|
2191
|
+
};
|
|
2192
|
+
const handleRevokeOtherSessions = async () => {
|
|
2193
|
+
try {
|
|
2194
|
+
await revokeOtherSessions();
|
|
2195
|
+
notifications.notifications.show({
|
|
2196
|
+
title: labels.successTitle || 'Sucesso',
|
|
2197
|
+
message: labels.otherSessionsRevoked || 'Todas as outras sessões foram encerradas',
|
|
2198
|
+
color: 'green'
|
|
2199
|
+
});
|
|
2200
|
+
} catch (error) {
|
|
2201
|
+
notifications.notifications.show({
|
|
2202
|
+
title: labels.errorTitle || 'Erro',
|
|
2203
|
+
message: error.message || labels.otherSessionsRevokeFailed || 'Falha ao encerrar sessões',
|
|
2204
|
+
color: 'red'
|
|
2205
|
+
});
|
|
2206
|
+
onError?.(error);
|
|
2207
|
+
}
|
|
2208
|
+
};
|
|
2209
|
+
|
|
2065
2210
|
// Password form
|
|
2066
2211
|
const passwordForm = form.useForm({
|
|
2067
2212
|
initialValues: {
|
|
@@ -2593,7 +2738,7 @@ function UserProfile({
|
|
|
2593
2738
|
})]
|
|
2594
2739
|
})]
|
|
2595
2740
|
})]
|
|
2596
|
-
}), showPassword && /*#__PURE__*/jsxRuntime.jsxs(core.Box, {
|
|
2741
|
+
}), (showPassword || showSessions) && /*#__PURE__*/jsxRuntime.jsxs(core.Box, {
|
|
2597
2742
|
mb: "md",
|
|
2598
2743
|
children: [/*#__PURE__*/jsxRuntime.jsx(SectionHeader, {
|
|
2599
2744
|
icon: iconsReact.IconShield,
|
|
@@ -2601,69 +2746,196 @@ function UserProfile({
|
|
|
2601
2746
|
description: labels.securityDescription || 'Protect your account'
|
|
2602
2747
|
}), /*#__PURE__*/jsxRuntime.jsxs(core.Stack, {
|
|
2603
2748
|
gap: "sm",
|
|
2604
|
-
children: [/*#__PURE__*/jsxRuntime.
|
|
2605
|
-
|
|
2606
|
-
|
|
2607
|
-
|
|
2608
|
-
|
|
2609
|
-
|
|
2610
|
-
|
|
2611
|
-
|
|
2612
|
-
|
|
2613
|
-
|
|
2614
|
-
|
|
2615
|
-
|
|
2616
|
-
|
|
2617
|
-
|
|
2618
|
-
|
|
2619
|
-
|
|
2620
|
-
|
|
2621
|
-
|
|
2622
|
-
|
|
2623
|
-
|
|
2624
|
-
|
|
2625
|
-
|
|
2626
|
-
|
|
2627
|
-
|
|
2628
|
-
|
|
2629
|
-
|
|
2630
|
-
|
|
2631
|
-
|
|
2632
|
-
|
|
2633
|
-
|
|
2634
|
-
|
|
2635
|
-
|
|
2636
|
-
|
|
2637
|
-
|
|
2638
|
-
|
|
2639
|
-
|
|
2640
|
-
|
|
2641
|
-
|
|
2642
|
-
|
|
2643
|
-
|
|
2644
|
-
|
|
2645
|
-
|
|
2646
|
-
|
|
2647
|
-
|
|
2648
|
-
|
|
2649
|
-
|
|
2650
|
-
|
|
2651
|
-
|
|
2652
|
-
|
|
2653
|
-
|
|
2654
|
-
|
|
2655
|
-
|
|
2656
|
-
|
|
2657
|
-
|
|
2658
|
-
|
|
2659
|
-
|
|
2660
|
-
|
|
2661
|
-
|
|
2749
|
+
children: [showPassword && /*#__PURE__*/jsxRuntime.jsxs(jsxRuntime.Fragment, {
|
|
2750
|
+
children: [/*#__PURE__*/jsxRuntime.jsx(SettingRow, {
|
|
2751
|
+
label: labels.password || 'Password',
|
|
2752
|
+
action: labels.change || 'Change',
|
|
2753
|
+
actionLabel: labels.changePassword || 'Change your password',
|
|
2754
|
+
onClick: () => handleToggleSection('password'),
|
|
2755
|
+
expanded: editingSection === 'password',
|
|
2756
|
+
children: /*#__PURE__*/jsxRuntime.jsxs(core.Group, {
|
|
2757
|
+
gap: "xs",
|
|
2758
|
+
children: [/*#__PURE__*/jsxRuntime.jsx(iconsReact.IconKey, {
|
|
2759
|
+
size: 16,
|
|
2760
|
+
color: "var(--mantine-color-dimmed)"
|
|
2761
|
+
}), /*#__PURE__*/jsxRuntime.jsx(core.Text, {
|
|
2762
|
+
size: "sm",
|
|
2763
|
+
c: "dimmed",
|
|
2764
|
+
children: "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022"
|
|
2765
|
+
})]
|
|
2766
|
+
})
|
|
2767
|
+
}), /*#__PURE__*/jsxRuntime.jsx(core.Collapse, {
|
|
2768
|
+
in: editingSection === 'password',
|
|
2769
|
+
children: /*#__PURE__*/jsxRuntime.jsx(core.Card, {
|
|
2770
|
+
p: "md",
|
|
2771
|
+
withBorder: true,
|
|
2772
|
+
children: /*#__PURE__*/jsxRuntime.jsx("form", {
|
|
2773
|
+
onSubmit: passwordForm.onSubmit(handleChangePassword),
|
|
2774
|
+
children: /*#__PURE__*/jsxRuntime.jsxs(core.Stack, {
|
|
2775
|
+
gap: "sm",
|
|
2776
|
+
children: [/*#__PURE__*/jsxRuntime.jsx(core.PasswordInput, {
|
|
2777
|
+
label: labels.currentPassword || 'Senha Atual',
|
|
2778
|
+
placeholder: labels.currentPasswordPlaceholder || 'Digite sua senha atual',
|
|
2779
|
+
...passwordForm.getInputProps('currentPassword')
|
|
2780
|
+
}), /*#__PURE__*/jsxRuntime.jsx(core.PasswordInput, {
|
|
2781
|
+
label: labels.newPassword || 'Nova Senha',
|
|
2782
|
+
placeholder: labels.newPasswordPlaceholder || 'Digite a nova senha',
|
|
2783
|
+
description: labels.passwordDescription || 'Mínimo 8 caracteres',
|
|
2784
|
+
...passwordForm.getInputProps('newPassword')
|
|
2785
|
+
}), /*#__PURE__*/jsxRuntime.jsx(core.PasswordInput, {
|
|
2786
|
+
label: labels.confirmPassword || 'Confirmar Nova Senha',
|
|
2787
|
+
placeholder: labels.confirmPasswordPlaceholder || 'Confirme a nova senha',
|
|
2788
|
+
...passwordForm.getInputProps('confirmPassword')
|
|
2789
|
+
}), /*#__PURE__*/jsxRuntime.jsxs(core.Group, {
|
|
2790
|
+
justify: "flex-end",
|
|
2791
|
+
gap: "xs",
|
|
2792
|
+
children: [/*#__PURE__*/jsxRuntime.jsx(core.Button, {
|
|
2793
|
+
variant: "default",
|
|
2794
|
+
size: "xs",
|
|
2795
|
+
onClick: () => handleToggleSection('password'),
|
|
2796
|
+
leftSection: /*#__PURE__*/jsxRuntime.jsx(iconsReact.IconX, {
|
|
2797
|
+
size: 14
|
|
2798
|
+
}),
|
|
2799
|
+
children: labels.cancel || 'Cancelar'
|
|
2800
|
+
}), /*#__PURE__*/jsxRuntime.jsx(core.Button, {
|
|
2801
|
+
type: "submit",
|
|
2802
|
+
size: "xs",
|
|
2803
|
+
loading: loadingChangePassword,
|
|
2804
|
+
leftSection: /*#__PURE__*/jsxRuntime.jsx(iconsReact.IconCheck, {
|
|
2805
|
+
size: 14
|
|
2806
|
+
}),
|
|
2807
|
+
children: labels.save || 'Salvar'
|
|
2808
|
+
})]
|
|
2662
2809
|
})]
|
|
2663
|
-
})
|
|
2810
|
+
})
|
|
2664
2811
|
})
|
|
2665
2812
|
})
|
|
2666
|
-
})
|
|
2813
|
+
})]
|
|
2814
|
+
}), showSessions && /*#__PURE__*/jsxRuntime.jsxs(jsxRuntime.Fragment, {
|
|
2815
|
+
children: [/*#__PURE__*/jsxRuntime.jsx(SettingRow, {
|
|
2816
|
+
label: labels.sessions || 'Sessions',
|
|
2817
|
+
action: editingSection === 'sessions' ? labels.close || 'Close' : labels.manage || 'Manage',
|
|
2818
|
+
actionLabel: labels.manageSessions || 'Manage your active sessions',
|
|
2819
|
+
onClick: () => handleToggleSection('sessions'),
|
|
2820
|
+
expanded: editingSection === 'sessions',
|
|
2821
|
+
children: /*#__PURE__*/jsxRuntime.jsxs(core.Group, {
|
|
2822
|
+
gap: "xs",
|
|
2823
|
+
children: [/*#__PURE__*/jsxRuntime.jsx(iconsReact.IconDevices, {
|
|
2824
|
+
size: 16,
|
|
2825
|
+
color: "var(--mantine-color-dimmed)"
|
|
2826
|
+
}), /*#__PURE__*/jsxRuntime.jsx(core.Text, {
|
|
2827
|
+
size: "sm",
|
|
2828
|
+
c: "dimmed",
|
|
2829
|
+
children: sessions.length > 0 ? `${sessions.length} active session${sessions.length > 1 ? 's' : ''}` : loadingListSessions ? 'Loading...' : 'No sessions'
|
|
2830
|
+
})]
|
|
2831
|
+
})
|
|
2832
|
+
}), /*#__PURE__*/jsxRuntime.jsx(core.Collapse, {
|
|
2833
|
+
in: editingSection === 'sessions',
|
|
2834
|
+
children: /*#__PURE__*/jsxRuntime.jsx(core.Card, {
|
|
2835
|
+
p: "md",
|
|
2836
|
+
withBorder: true,
|
|
2837
|
+
children: /*#__PURE__*/jsxRuntime.jsx(core.Stack, {
|
|
2838
|
+
gap: "md",
|
|
2839
|
+
children: loadingListSessions ? /*#__PURE__*/jsxRuntime.jsx(core.Text, {
|
|
2840
|
+
size: "sm",
|
|
2841
|
+
c: "dimmed",
|
|
2842
|
+
ta: "center",
|
|
2843
|
+
children: labels.loadingSessions || 'Carregando sessões...'
|
|
2844
|
+
}) : sessions.length === 0 ? /*#__PURE__*/jsxRuntime.jsx(core.Text, {
|
|
2845
|
+
size: "sm",
|
|
2846
|
+
c: "dimmed",
|
|
2847
|
+
ta: "center",
|
|
2848
|
+
children: labels.noSessionsFound || 'Nenhuma sessão encontrada'
|
|
2849
|
+
}) : /*#__PURE__*/jsxRuntime.jsxs(jsxRuntime.Fragment, {
|
|
2850
|
+
children: [sessions.map(sessionItem => {
|
|
2851
|
+
const isCurrentSession = sessionItem.id === currentSession?.id;
|
|
2852
|
+
const deviceInfo = parseUserAgent(sessionItem.userAgent);
|
|
2853
|
+
const createdDate = new Date(sessionItem.createdAt);
|
|
2854
|
+
return /*#__PURE__*/jsxRuntime.jsx(core.Card, {
|
|
2855
|
+
p: "sm",
|
|
2856
|
+
style: {
|
|
2857
|
+
borderColor: isCurrentSession ? 'var(--mantine-color-blue-5)' : undefined,
|
|
2858
|
+
backgroundColor: isCurrentSession ? 'var(--mantine-color-blue-light)' : undefined
|
|
2859
|
+
},
|
|
2860
|
+
children: /*#__PURE__*/jsxRuntime.jsxs(core.Group, {
|
|
2861
|
+
justify: "space-between",
|
|
2862
|
+
wrap: "nowrap",
|
|
2863
|
+
children: [/*#__PURE__*/jsxRuntime.jsxs(core.Group, {
|
|
2864
|
+
gap: "sm",
|
|
2865
|
+
wrap: "nowrap",
|
|
2866
|
+
style: {
|
|
2867
|
+
flex: 1
|
|
2868
|
+
},
|
|
2869
|
+
children: [/*#__PURE__*/jsxRuntime.jsx(core.ThemeIcon, {
|
|
2870
|
+
size: 36,
|
|
2871
|
+
variant: "light",
|
|
2872
|
+
color: isCurrentSession ? 'blue' : 'gray',
|
|
2873
|
+
children: /*#__PURE__*/jsxRuntime.jsx(iconsReact.IconDeviceMobile, {
|
|
2874
|
+
size: 18
|
|
2875
|
+
})
|
|
2876
|
+
}), /*#__PURE__*/jsxRuntime.jsxs(core.Box, {
|
|
2877
|
+
style: {
|
|
2878
|
+
flex: 1
|
|
2879
|
+
},
|
|
2880
|
+
children: [/*#__PURE__*/jsxRuntime.jsxs(core.Group, {
|
|
2881
|
+
gap: "xs",
|
|
2882
|
+
children: [/*#__PURE__*/jsxRuntime.jsx(core.Text, {
|
|
2883
|
+
size: "sm",
|
|
2884
|
+
fw: 500,
|
|
2885
|
+
children: deviceInfo.browser
|
|
2886
|
+
}), isCurrentSession && /*#__PURE__*/jsxRuntime.jsx(core.Badge, {
|
|
2887
|
+
size: "xs",
|
|
2888
|
+
variant: "filled",
|
|
2889
|
+
color: "blue",
|
|
2890
|
+
children: labels.thisDevice || 'Este dispositivo'
|
|
2891
|
+
})]
|
|
2892
|
+
}), /*#__PURE__*/jsxRuntime.jsxs(core.Text, {
|
|
2893
|
+
size: "xs",
|
|
2894
|
+
c: "dimmed",
|
|
2895
|
+
children: [deviceInfo.os, " \u2022 ", sessionItem.ipAddress || labels.unknownIP || 'IP desconhecido']
|
|
2896
|
+
}), /*#__PURE__*/jsxRuntime.jsxs(core.Text, {
|
|
2897
|
+
size: "xs",
|
|
2898
|
+
c: "dimmed",
|
|
2899
|
+
children: [labels.createdAt || 'Criada em', " ", createdDate.toLocaleDateString('pt-BR'), " ", labels.at || 'às', ' ', createdDate.toLocaleTimeString('pt-BR', {
|
|
2900
|
+
hour: '2-digit',
|
|
2901
|
+
minute: '2-digit'
|
|
2902
|
+
})]
|
|
2903
|
+
})]
|
|
2904
|
+
})]
|
|
2905
|
+
}), /*#__PURE__*/jsxRuntime.jsx(core.Tooltip, {
|
|
2906
|
+
label: isCurrentSession ? labels.signOutAndEnd || 'Encerrar e sair' : labels.endSession || 'Encerrar sessão',
|
|
2907
|
+
children: /*#__PURE__*/jsxRuntime.jsx(core.Button, {
|
|
2908
|
+
variant: "light",
|
|
2909
|
+
color: "red",
|
|
2910
|
+
size: "xs",
|
|
2911
|
+
onClick: () => handleRevokeSession(sessionItem.id),
|
|
2912
|
+
loading: loadingRevokeSession,
|
|
2913
|
+
leftSection: /*#__PURE__*/jsxRuntime.jsx(iconsReact.IconLogout, {
|
|
2914
|
+
size: 14
|
|
2915
|
+
}),
|
|
2916
|
+
children: labels.end || 'Encerrar'
|
|
2917
|
+
})
|
|
2918
|
+
})]
|
|
2919
|
+
})
|
|
2920
|
+
}, sessionItem.id);
|
|
2921
|
+
}), sessions.length > 1 && /*#__PURE__*/jsxRuntime.jsx(core.Group, {
|
|
2922
|
+
justify: "flex-end",
|
|
2923
|
+
children: /*#__PURE__*/jsxRuntime.jsx(core.Button, {
|
|
2924
|
+
variant: "light",
|
|
2925
|
+
color: "red",
|
|
2926
|
+
size: "xs",
|
|
2927
|
+
onClick: handleRevokeOtherSessions,
|
|
2928
|
+
loading: loadingRevokeSession,
|
|
2929
|
+
leftSection: /*#__PURE__*/jsxRuntime.jsx(iconsReact.IconLogout, {
|
|
2930
|
+
size: 14
|
|
2931
|
+
}),
|
|
2932
|
+
children: labels.endOtherSessions || 'Encerrar todas as outras sessões'
|
|
2933
|
+
})
|
|
2934
|
+
})]
|
|
2935
|
+
})
|
|
2936
|
+
})
|
|
2937
|
+
})
|
|
2938
|
+
})]
|
|
2667
2939
|
})]
|
|
2668
2940
|
})]
|
|
2669
2941
|
})]
|
|
@@ -2905,6 +3177,7 @@ exports.useMagicLink = useMagicLink;
|
|
|
2905
3177
|
exports.usePasswordReset = usePasswordReset;
|
|
2906
3178
|
exports.useProfile = useUser;
|
|
2907
3179
|
exports.useSession = useSession;
|
|
3180
|
+
exports.useSessions = useSessions;
|
|
2908
3181
|
exports.useSignIn = useSignIn;
|
|
2909
3182
|
exports.useSignOut = useSignOut;
|
|
2910
3183
|
exports.useSignUp = useSignUp;
|