Files
EpicNext-Cms/src/app/admin/users/[id]/user-activity-log.tsx
T
openhands df38dccbf1
Local Build and Deploy / deploy (push) Failing after 46s
style: format code biome
2026-07-13 21:57:41 +02:00

130 lines
3.3 KiB
TypeScript

import { MessageSquare, Terminal } from "lucide-react";
import Link from "next/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>
);
}