"use client"; import { useState } from "react"; import { useRouter } from "next/navigation"; import { Loader2, Trash2, Monitor, Smartphone, Globe } from "lucide-react"; import { toast } from "sonner"; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from "@/components/ui/table"; import { Button } from "@/components/ui/button"; import { Badge } from "@/components/ui/badge"; import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, } from "@/components/ui/alert-dialog"; interface Session { id: string; ip_address: string; user_agent: string; created_at: string; expires_at: string; } interface UserSessionsProps { sessions: Session[]; userId: string; } function parseUserAgent(ua: string): { device: string; browser: string } { const isMobile = /mobile|android|iphone|ipad/i.test(ua); const device = isMobile ? "Mobile" : "Desktop"; let browser = "Unknown"; if (ua.includes("Chrome")) browser = "Chrome"; else if (ua.includes("Firefox")) browser = "Firefox"; else if (ua.includes("Safari")) browser = "Safari"; else if (ua.includes("Edge")) browser = "Edge"; return { device, browser }; } export function UserSessions({ sessions, userId }: UserSessionsProps) { const router = useRouter(); const [isLoading, setIsLoading] = useState(false); const [showRevokeAllDialog, setShowRevokeAllDialog] = useState(false); const [revokingSessionId, setRevokingSessionId] = useState(null); async function handleRevokeSession(sessionId: string) { setRevokingSessionId(sessionId); try { const response = await fetch(`/api/admin/users/${userId}/sessions/${sessionId}`, { method: "DELETE", }); if (!response.ok) { const data = await response.json(); throw new Error(data.error || "Failed to revoke session"); } toast.success("Session revoked"); router.refresh(); } catch (error) { toast.error(error instanceof Error ? error.message : "An error occurred"); } finally { setRevokingSessionId(null); } } async function handleRevokeAllSessions() { setIsLoading(true); try { const response = await fetch(`/api/admin/users/${userId}/sessions`, { method: "DELETE", }); if (!response.ok) { const data = await response.json(); throw new Error(data.error || "Failed to revoke sessions"); } toast.success("All sessions revoked"); router.refresh(); } catch (error) { toast.error(error instanceof Error ? error.message : "An error occurred"); } finally { setIsLoading(false); setShowRevokeAllDialog(false); } } if (sessions.length === 0) { return (
No active sessions
); } return (
Device IP Address Created Expires {sessions.map((session) => { const { device, browser } = parseUserAgent(session.user_agent || ""); const isExpired = new Date(session.expires_at) < new Date(); return (
{device === "Mobile" ? ( ) : ( )} {browser} {isExpired && ( Expired )}
{session.ip_address || "Unknown"}
{new Date(session.created_at).toLocaleString()} {new Date(session.expires_at).toLocaleString()}
); })}
Revoke All Sessions Are you sure you want to revoke all sessions for this user? They will be signed out from all devices. Cancel {isLoading ? ( <> Revoking... ) : ( "Revoke All" )}
); }