import { useEffect, useState } from "react"; import { formatRelative } from "../../components/TaskDetailFields"; import { Skeleton } from "../../components/ui/skeleton"; import { authClient } from "../../lib/auth-client"; interface Session { id: string; token: string; ipAddress?: string; userAgent?: string; createdAt: string; expiresAt: string; } type ToastType = "success" | "error"; interface Props { userId: string; onToast: (type: ToastType, msg: string) => void; } export function SessionsPanel({ userId, onToast }: Props) { const [sessions, setSessions] = useState([]); const [loading, setLoading] = useState(true); const [revoking, setRevoking] = useState(null); useEffect(() => { (authClient.admin as any) .listUserSessions({ userId }) .then(({ data, error }: any) => { if (!error && data) setSessions(data.sessions ?? data ?? []); }) .finally(() => setLoading(false)); }, [userId]); async function revokeSession(token: string) { setRevoking(token); const { error } = await (authClient.admin as any).revokeUserSession({ sessionToken: token }); setRevoking(null); if (error) { onToast("error", "Failed to revoke session"); } else { onToast("success", "Session revoked"); setSessions((prev) => prev.filter((s) => s.token !== token)); } } async function revokeAll() { setRevoking("all"); const { error } = await (authClient.admin as any).revokeUserSessions({ userId }); setRevoking(null); if (error) { onToast("error", "Failed to revoke sessions"); } else { onToast("success", "All sessions revoked"); setSessions([]); } } if (loading) { return (
{[0, 1].map((i) => ( ))}
); } if (sessions.length === 0) { return

No active sessions.

; } return (
{sessions.length} active session{sessions.length !== 1 ? "s" : ""}
{sessions.map((s) => (

{s.token.slice(0, 16)}…

{s.ipAddress &&

{s.ipAddress}

} {s.userAgent &&

{s.userAgent}

}

Created {formatRelative(s.createdAt)} · Expires {formatRelative(s.expiresAt)}

))}
); }