Files
Epicnabbo-Catalogus-Updated…/src/app/admin/users/[id]/user-activity-log.tsx
T
openhands 7a41775c7e fix: disable route prefetching app-wide to avoid spurious requests
Wrap next/link in a shared Link component that ships prefetch=false by
default, so no route is ever prefetched (viewport or hover) anymore, and
drop the DNS prefetch hint. Removes hidden background requests that were
the source of intermittent issues.
2026-08-29 19:27:13 +02:00

130 lines
3.3 KiB
TypeScript

import { MessageSquare, Terminal } from "lucide-react";
import Link from "@/components/link";
import { Badge } from "@/components/ui/badge";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
interface ChatMessage {
id: number;
roomId: number;
timestamp: number;
message: string;
}
interface CommandEntry {
id: number;
timestamp: number;
command: string;
params: string;
succes: string;
}
interface UserActivityLogProps {
chatLogs: ChatMessage[];
commandLogs: CommandEntry[];
}
function formatTime(ts: number) {
if (!ts) return "-";
const d = new Date(ts * 1000);
return d.toLocaleString(undefined, {
day: "2-digit",
month: "short",
hour: "2-digit",
minute: "2-digit",
});
}
export function UserActivityLog({
chatLogs,
commandLogs,
}: UserActivityLogProps) {
return (
<div className="grid gap-6 lg:grid-cols-2">
{/* Chat Messages */}
<Card>
<CardHeader>
<CardTitle className="flex items-center gap-2">
<MessageSquare className="h-4 w-4" />
Recent Messages ({chatLogs.length})
</CardTitle>
</CardHeader>
<CardContent>
{chatLogs.length === 0 ? (
<p className="text-sm text-muted-foreground">No recent messages.</p>
) : (
<div className="space-y-2 max-h-[400px] overflow-y-auto">
{chatLogs.map((log) => (
<div
key={log.id}
className="rounded-md border px-3 py-2 text-sm"
>
<div className="flex items-center justify-between gap-2 mb-1">
<Link
href={`/admin/rooms/${log.roomId}`}
className="text-xs text-primary hover:underline"
>
Room #{log.roomId}
</Link>
<span className="text-xs text-muted-foreground">
{formatTime(log.timestamp)}
</span>
</div>
<p className="break-words">{log.message}</p>
</div>
))}
</div>
)}
</CardContent>
</Card>
{/* Commands */}
<Card>
<CardHeader>
<CardTitle className="flex items-center gap-2">
<Terminal className="h-4 w-4" />
Recent Commands ({commandLogs.length})
</CardTitle>
</CardHeader>
<CardContent>
{commandLogs.length === 0 ? (
<p className="text-sm text-muted-foreground">No recent commands.</p>
) : (
<div className="space-y-2 max-h-[400px] overflow-y-auto">
{commandLogs.map((log) => (
<div
key={log.id}
className="rounded-md border px-3 py-2 text-sm"
>
<div className="flex items-center justify-between gap-2">
<code className="font-mono text-xs font-bold">
:{log.command}
</code>
<div className="flex items-center gap-2">
<Badge
variant={
log.succes === "yes" ? "default" : "destructive"
}
className="text-[10px]"
>
{log.succes === "yes" ? "OK" : "FAIL"}
</Badge>
<span className="text-xs text-muted-foreground">
{formatTime(log.timestamp)}
</span>
</div>
</div>
{log.params && (
<p className="text-xs text-muted-foreground mt-1 break-words">
{log.params}
</p>
)}
</div>
))}
</div>
)}
</CardContent>
</Card>
</div>
);
}