import { useState, useEffect } from 'react'; import { apiClient } from '@/services/api/client'; import { Button } from '@/components/ui/button'; import { Card, CardContent, CardDescription, CardHeader, CardTitle, } from '@/components/ui/card'; import { LoadingSpinner } from '@/components/ui/loading-spinner'; import { Shield, Smartphone, Monitor, Globe, Trash2, LogOut, } from 'lucide-react'; interface Session { id: string; ip_address: string; user_agent: string; last_activity: string; created_at: string; is_current: boolean; } interface SessionsResponse { sessions: Session[]; count: number; } export function SessionsPage() { const [sessions, setSessions] = useState([]); const [loading, setLoading] = useState(true); const [revoking, setRevoking] = useState(null); const [revokingAll, setRevokingAll] = useState(false); const [error, setError] = useState(null); useEffect(() => { fetchSessions(); }, []); const fetchSessions = async () => { try { setLoading(true); setError(null); const response = await apiClient.get('/auth/sessions'); setSessions(response.data.sessions); } catch (error: any) { console.error('Failed to fetch sessions', error); setError( error.response?.data?.error || 'Failed to load sessions. Please try again.', ); } finally { setLoading(false); } }; const revokeSession = async (sessionId: string) => { try { setRevoking(sessionId); setError(null); await apiClient.delete(`/auth/sessions/${sessionId}`); await fetchSessions(); } catch (error: any) { console.error('Failed to revoke session', error); setError( error.response?.data?.error || 'Failed to revoke session. Please try again.', ); } finally { setRevoking(null); } }; const revokeAllOther = async () => { if ( !window.confirm( 'Are you sure you want to revoke all other sessions? You will remain logged in on this device.', ) ) { return; } try { setRevokingAll(true); setError(null); await apiClient.delete('/auth/sessions'); await fetchSessions(); } catch (error: any) { console.error('Failed to revoke sessions', error); setError( error.response?.data?.error || 'Failed to revoke sessions. Please try again.', ); } finally { setRevokingAll(false); } }; const getDeviceIcon = (userAgent: string) => { const ua = userAgent.toLowerCase(); if ( ua.includes('mobile') || ua.includes('android') || ua.includes('iphone') ) { return ; } if (ua.includes('tablet') || ua.includes('ipad')) { return ; } return ; }; const formatDate = (dateString: string) => { const date = new Date(dateString); return new Intl.DateTimeFormat('en-US', { year: 'numeric', month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit', }).format(date); }; if (loading) { return (
); } return (
{/* En-tête */}

Active Sessions

Manage your active sessions and sign out from other devices

{/* Message d'erreur */} {error && (
{error}
)} {/* Bouton pour révoquer toutes les autres sessions */}
{/* Liste des sessions */} Sessions ({sessions.length}) These are the devices where you're currently signed in {sessions.length === 0 ? (
No active sessions found.
) : (
{sessions.map((session) => (
{getDeviceIcon(session.user_agent)}

{session.user_agent || 'Unknown Device'}

{session.is_current && ( Current Session )}
{session.ip_address || 'Unknown IP'}
Created:{' '} {formatDate(session.created_at)}
{session.last_activity && (
Last activity:{' '} {formatDate(session.last_activity)}
)}
{!session.is_current && ( )}
))}
)}
); } export default SessionsPage;