@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.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
|
|
@@ -273,11 +273,11 @@ const getSession = async () => {
|
|
|
273
273
|
const listSessions = async () => {
|
|
274
274
|
return await api('/auth/list-sessions');
|
|
275
275
|
};
|
|
276
|
-
const revokeSession = async
|
|
277
|
-
return await api('/auth/revoke-session', {
|
|
276
|
+
const revokeSession = async id => {
|
|
277
|
+
return await api('/auth/revoke-session-by-id', {
|
|
278
278
|
method: 'POST',
|
|
279
279
|
body: JSON.stringify({
|
|
280
|
-
|
|
280
|
+
id
|
|
281
281
|
})
|
|
282
282
|
});
|
|
283
283
|
};
|
|
@@ -339,7 +339,7 @@ const useAuthStore = create((set, get) => ({
|
|
|
339
339
|
error: null,
|
|
340
340
|
// Session management
|
|
341
341
|
sessions: [],
|
|
342
|
-
|
|
342
|
+
currentSession: null,
|
|
343
343
|
// Loading states granulares
|
|
344
344
|
loadingStates: {
|
|
345
345
|
signIn: false,
|
|
@@ -397,9 +397,14 @@ const useAuthStore = create((set, get) => ({
|
|
|
397
397
|
// Precisamos buscar a sessão no servidor.
|
|
398
398
|
if (!user) {
|
|
399
399
|
try {
|
|
400
|
-
const
|
|
401
|
-
if (
|
|
402
|
-
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
|
+
});
|
|
403
408
|
}
|
|
404
409
|
} catch (sessionError) {
|
|
405
410
|
console.warn('[AuthStore] Failed to fetch session:', sessionError);
|
|
@@ -472,8 +477,13 @@ const useAuthStore = create((set, get) => ({
|
|
|
472
477
|
|
|
473
478
|
// Se não encontrou no token (sessão opaca), busca do servidor
|
|
474
479
|
if (!user) {
|
|
475
|
-
const
|
|
476
|
-
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
|
+
}
|
|
477
487
|
}
|
|
478
488
|
set({
|
|
479
489
|
user,
|
|
@@ -655,14 +665,14 @@ const useAuthStore = create((set, get) => ({
|
|
|
655
665
|
/* Session */
|
|
656
666
|
getSession: async () => {
|
|
657
667
|
try {
|
|
658
|
-
const
|
|
659
|
-
// Store current session
|
|
660
|
-
if (
|
|
668
|
+
const sessionData = await getSession();
|
|
669
|
+
// Store current session for comparison (includes id)
|
|
670
|
+
if (sessionData?.session) {
|
|
661
671
|
set({
|
|
662
|
-
|
|
672
|
+
currentSession: sessionData.session
|
|
663
673
|
});
|
|
664
674
|
}
|
|
665
|
-
return
|
|
675
|
+
return sessionData;
|
|
666
676
|
} catch (err) {
|
|
667
677
|
set({
|
|
668
678
|
error: err
|
|
@@ -914,8 +924,24 @@ function AuthProvider({
|
|
|
914
924
|
checkTokenValidity();
|
|
915
925
|
}
|
|
916
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
|
+
};
|
|
917
939
|
window.addEventListener('storage', handleStorageChange);
|
|
918
|
-
|
|
940
|
+
window.addEventListener('auth:session-revoked', handleSessionRevoked);
|
|
941
|
+
return () => {
|
|
942
|
+
window.removeEventListener('storage', handleStorageChange);
|
|
943
|
+
window.removeEventListener('auth:session-revoked', handleSessionRevoked);
|
|
944
|
+
};
|
|
919
945
|
}, [checkTokenValidity]);
|
|
920
946
|
|
|
921
947
|
// Verifica validade do token periodicamente
|
|
@@ -1003,6 +1029,19 @@ const useUser = () => useAuthStore(useShallow(s => ({
|
|
|
1003
1029
|
// Alias deprecado para backwards compatibility
|
|
1004
1030
|
const useProfile = useUser;
|
|
1005
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
|
+
|
|
1006
1045
|
// Application Logo Hook
|
|
1007
1046
|
const useApplicationLogo = () => {
|
|
1008
1047
|
const applicationInfo = useAuthStore(s => s.applicationInfo);
|
|
@@ -2032,6 +2071,7 @@ function UserProfile({
|
|
|
2032
2071
|
showName = true,
|
|
2033
2072
|
showEmail = true,
|
|
2034
2073
|
showPassword = true,
|
|
2074
|
+
showSessions = true,
|
|
2035
2075
|
// Customização
|
|
2036
2076
|
labels = {},
|
|
2037
2077
|
title = 'Account',
|
|
@@ -2059,6 +2099,111 @@ function UserProfile({
|
|
|
2059
2099
|
loadingChangeEmail
|
|
2060
2100
|
} = useProfile();
|
|
2061
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
|
+
|
|
2062
2207
|
// Password form
|
|
2063
2208
|
const passwordForm = useForm({
|
|
2064
2209
|
initialValues: {
|
|
@@ -2590,7 +2735,7 @@ function UserProfile({
|
|
|
2590
2735
|
})]
|
|
2591
2736
|
})]
|
|
2592
2737
|
})]
|
|
2593
|
-
}), showPassword && /*#__PURE__*/jsxs(Box, {
|
|
2738
|
+
}), (showPassword || showSessions) && /*#__PURE__*/jsxs(Box, {
|
|
2594
2739
|
mb: "md",
|
|
2595
2740
|
children: [/*#__PURE__*/jsx(SectionHeader, {
|
|
2596
2741
|
icon: IconShield,
|
|
@@ -2598,69 +2743,196 @@ function UserProfile({
|
|
|
2598
2743
|
description: labels.securityDescription || 'Protect your account'
|
|
2599
2744
|
}), /*#__PURE__*/jsxs(Stack, {
|
|
2600
2745
|
gap: "sm",
|
|
2601
|
-
children: [/*#__PURE__*/
|
|
2602
|
-
|
|
2603
|
-
|
|
2604
|
-
|
|
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
|
-
|
|
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
|
+
})]
|
|
2659
2806
|
})]
|
|
2660
|
-
})
|
|
2807
|
+
})
|
|
2661
2808
|
})
|
|
2662
2809
|
})
|
|
2663
|
-
})
|
|
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
|
+
})]
|
|
2664
2936
|
})]
|
|
2665
2937
|
})]
|
|
2666
2938
|
})]
|
|
@@ -2844,5 +3116,5 @@ function SignOutButton({
|
|
|
2844
3116
|
});
|
|
2845
3117
|
}
|
|
2846
3118
|
|
|
2847
|
-
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, 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 };
|
|
2848
3120
|
//# sourceMappingURL=index.esm.js.map
|