tahamajs/IE / Projects /front /src /components /dashboard /widgets /RecentActivityWidget.tsx
tahamajs's picture
download
raw
2.7 kB
// src/components/dashboard/widgets/RecentActivityWidget.tsx
import { Activity, FileText, Loader2 } from "lucide-react";
import { useEffect, useState, useCallback } from "react";
import api from "@/lib/api";
import { Link } from "react-router-dom";
interface ActivityItem {
id: string;
type: "article";
content: string;
link: string;
timestamp: string;
}
export function RecentActivityWidget() {
const [activities, setActivities] = useState<ActivityItem[]>([]);
const [loading, setLoading] = useState(false);
const fetchActivities = useCallback(async () => {
if (loading) return;
setLoading(true);
try {
const res = await api.get("/dashboard/recent-activity?limit=10");
const items = res.data.activity || [];
const formatted: ActivityItem[] = items.map((item: any) => ({
id: String(item.id),
type: "article",
content: `Published "${item.title}" (${item.views || 0} views, ${item.likes || 0} likes)`,
link: `/articles/${item.id}`,
timestamp: item.createdAt || new Date().toISOString(),
}));
setActivities(formatted);
} catch (err) {
console.error("Failed to load activities:", err);
setActivities([]);
} finally {
setLoading(false);
}
}, [loading]);
useEffect(() => {
void fetchActivities();
}, []);
return (
<div className="space-y-3 bg-white/5 dark:bg-black/20 backdrop-blur-md border border-white/10 dark:border-white/5 rounded-2xl p-4">
<div className="flex items-center gap-2">
<Activity className="w-4 h-4 text-primary" />
<h3 className="text-sm font-semibold text-gray-200">Recent Activity</h3>
</div>
<div className="space-y-2 max-h-64 overflow-y-auto">
{activities.length > 0 ? (
activities.map((a) => (
<Link
key={a.id}
to={a.link}
className="flex items-center gap-3 text-xs p-2 rounded-lg bg-white/5 border border-white/5 hover:border-white/15 hover:bg-white/10 transition-all duration-300"
>
<FileText className="w-3.5 h-3.5 text-gray-400" />
<span className="flex-1 text-gray-300 font-medium truncate">{a.content}</span>
<span className="text-[10px] text-gray-500">{new Date(a.timestamp).toLocaleDateString()}</span>
</Link>
))
) : (
!loading && <p className="text-xs text-gray-500 py-4 text-center">No recent activity</p>
)}
{loading && (
<div className="flex justify-center py-4">
<Loader2 className="w-4 h-4 animate-spin text-gray-400" />
</div>
)}
</div>
</div>
);
}

Xet Storage Details

Size:
2.7 kB
·
Xet hash:
a1d6f23ad28e1521ff33403a6ab2aefc40b95a0b8e415d56be14d65e1a0e114c

Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.