import { desc, eq, sql } from "drizzle-orm"; import { redirect } from "next/navigation"; import { getTranslations } from "next-intl/server"; import { signOutEverywhere } from "@/actions/sessions"; import { ContentCard, EmptyState } from "@/components/public/ui"; import { auth } from "@/lib/auth"; import { db, WebsiteLoginLogs } from "@/lib/db"; import { formatDate } from "@/lib/format-date"; type SearchParams = Promise<{ signedOutAll?: string }>; /** Tiny user-agent → "Browser on OS" summary (no dependency). */ function deviceLabel(ua: string | null, unknown: string): string { if (!ua) return unknown; const browser = /Edg/.test(ua) ? "Edge" : /OPR|Opera/.test(ua) ? "Opera" : /Chrome/.test(ua) ? "Chrome" : /Firefox/.test(ua) ? "Firefox" : /Safari/.test(ua) ? "Safari" : "Browser"; const os = /Windows/.test(ua) ? "Windows" : /Android/.test(ua) ? "Android" : /iPhone|iPad|iOS/.test(ua) ? "iOS" : /Mac OS X|Macintosh/.test(ua) ? "macOS" : /Linux/.test(ua) ? "Linux" : ""; return os ? `${browser} on ${os}` : browser; } export async function generateMetadata() { const t = await getTranslations("pages.sessions"); return { title: t("title") }; } export default async function SessionsPage({ searchParams, }: { searchParams: SearchParams; }) { const t = await getTranslations("pages.sessions"); const session = await auth(); if (!session?.user?.id) redirect("/login"); const userId = Number(session.user.id); const { signedOutAll } = await searchParams; const logins = await db .select({ id: WebsiteLoginLogs.id, ip: WebsiteLoginLogs.ip, userAgent: WebsiteLoginLogs.userAgent, createdAt: WebsiteLoginLogs.createdAt, }) .from(WebsiteLoginLogs) .where(eq(WebsiteLoginLogs.userId, userId)) .orderBy(desc(WebsiteLoginLogs.id)) .limit(30) .catch(() => []); type Failed = { id: number; ip_address: string; attempted_at: Date | string }; let failed: Failed[] = []; try { const [rows] = (await db.execute(sql` SELECT id, ip_address, attempted_at FROM failed_logins WHERE username = ${session.user.name} ORDER BY id DESC LIMIT 15 `)) as unknown as [Failed[], unknown]; failed = rows ?? []; } catch { failed = []; } return (
{signedOutAll === "1" ? (

{t("successSignedOutAll")}

) : null}
{logins.length === 0 ? ( {t("recentEmpty")} ) : ( {logins.map((l) => ( ))}
{t("colWhen")} {t("colIp")} {t("colDevice")}
{formatDate(l.createdAt)} {l.ip} {deviceLabel(l.userAgent, t("unknownDevice"))}
)}
{failed.length > 0 ? ( {failed.map((f) => ( ))}
{t("colWhen")} {t("colIp")}
{formatDate( typeof f.attempted_at === "string" ? new Date(f.attempted_at) : f.attempted_at, )} {f.ip_address}
) : null}
); }