AutoLoop / components /admin /activity-logs.tsx
shubhjn's picture
feat: Implement core CMS features including workflow management, admin dashboard, API infrastructure, queueing system, and new UI components.
59697b4
"use client";
import { useState } from "react";
import { Card, CardContent, CardHeader, CardTitle, CardDescription } from "@/components/ui/card";
import { Badge } from "@/components/ui/badge";
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@/components/ui/table";
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/components/ui/select";
import { Input } from "@/components/ui/input";
import { Button } from "@/components/ui/button";
import { Download, Search, Filter } from "lucide-react";
import { SystemEvent } from "@/types/admin";
interface ActivityLogsProps {
logs: SystemEvent[];
loading?: boolean;
}
export function ActivityLogs({ logs, loading }: ActivityLogsProps) {
const [filter, setFilter] = useState("all");
const [search, setSearch] = useState("");
const getEventColor = (type: string) => {
switch (type) {
case "error":
return "bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-100";
case "warning":
return "bg-amber-100 text-amber-800 dark:bg-amber-900 dark:text-amber-100";
case "success":
return "bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-100";
default:
return "bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-100";
}
};
const filteredLogs = logs.filter((log) => {
const matchesFilter = filter === "all" || log.type === filter;
const matchesSearch = log.message.toLowerCase().includes(search.toLowerCase());
return matchesFilter && matchesSearch;
});
return (
<Card>
<CardHeader>
<div className="flex items-center justify-between">
<div>
<CardTitle>System Activity</CardTitle>
<CardDescription>Recent system events and user actions</CardDescription>
</div>
<Button variant="outline" size="sm">
<Download className="mr-2 h-4 w-4" />
Export CSV
</Button>
</div>
</CardHeader>
<CardContent>
<div className="flex flex-col gap-4">
<div className="flex gap-2">
<div className="relative flex-1">
<Search className="absolute left-2 top-2.5 h-4 w-4 text-muted-foreground" />
<Input
placeholder="Search logs..."
value={search}
onChange={(e) => setSearch(e.target.value)}
className="pl-8"
/>
</div>
<Select value={filter} onValueChange={setFilter}>
<SelectTrigger className="w-[180px]">
<Filter className="mr-2 h-4 w-4" />
<SelectValue placeholder="Filter by type" />
</SelectTrigger>
<SelectContent>
<SelectItem value="all">All Events</SelectItem>
<SelectItem value="info">Info</SelectItem>
<SelectItem value="success">Success</SelectItem>
<SelectItem value="warning">Warning</SelectItem>
<SelectItem value="error">Error</SelectItem>
</SelectContent>
</Select>
</div>
<div className="rounded-md border">
<Table>
<TableHeader>
<TableRow>
<TableHead className="w-[100px]">Type</TableHead>
<TableHead>Message</TableHead>
<TableHead className="w-[200px]">Timestamp</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{loading ? (
<TableRow>
<TableCell colSpan={3} className="h-24 text-center">
Loading...
</TableCell>
</TableRow>
) : filteredLogs.length === 0 ? (
<TableRow>
<TableCell colSpan={3} className="h-24 text-center">
No logs found.
</TableCell>
</TableRow>
) : (
filteredLogs.map((log) => (
<TableRow key={log.id}>
<TableCell>
<Badge
variant="secondary"
className={getEventColor(log.type)}
>
{log.type}
</Badge>
</TableCell>
<TableCell className="font-medium">
{log.message}
{log.metadata && (
<pre className="mt-1 text-xs text-muted-foreground">
{JSON.stringify(log.metadata, null, 2)}
</pre>
)}
</TableCell>
<TableCell className="text-muted-foreground">
{new Date(log.timestamp).toLocaleString()}
</TableCell>
</TableRow>
))
)}
</TableBody>
</Table>
</div>
</div>
</CardContent>
</Card>
);
}