tahamajs/IE / Projects /front /src /components /admin /AdminCommentsList.tsx
tahamajs's picture
download
raw
3.48 kB
// src/components/admin/AdminCommentsList.tsx
import { Link } from "react-router-dom";
import { Trash2, MessageSquare, Clock, RefreshCw } from "lucide-react";
import { useState } from "react";
import { toast } from "react-toastify";
interface AdminComment {
id: number;
articleId: number;
authorUsername: string;
body: string;
createdAt: string;
}
interface AdminCommentsListProps {
comments: AdminComment[];
onDelete: (id: number) => Promise<void>;
}
export function AdminCommentsList({ comments, onDelete }: AdminCommentsListProps) {
const [loadingStates, setLoadingStates] = useState<Record<number, boolean>>({});
const handleDelete = async (id: number) => {
setLoadingStates((prev) => ({ ...prev, [id]: true }));
try {
await onDelete(id);
toast.success("Comment deleted successfully");
} catch (err) {
console.error(err);
} finally {
setLoadingStates((prev) => ({ ...prev, [id]: false }));
}
};
if (!comments || comments.length === 0) {
return (
<div className="text-center py-12 bg-white/40 dark:bg-gray-900/40 backdrop-blur-md border border-gray-200 dark:border-gray-800 rounded-2xl text-gray-500">
No comments have been posted yet.
</div>
);
}
return (
<div className="space-y-4">
{comments.map((comment) => {
const isLoading = loadingStates[comment.id] || false;
return (
<div
key={comment.id}
className="bg-white/40 dark:bg-gray-900/40 backdrop-blur-md border border-gray-200/50 dark:border-gray-800/50 rounded-2xl p-5 shadow-lg flex justify-between items-start gap-4 transition duration-200 hover:shadow-xl hover:border-gray-300 dark:hover:border-gray-700"
>
<div className="flex-1 min-w-0">
<div className="flex flex-wrap items-center gap-x-2 gap-y-1 text-sm">
<span className="font-bold text-gray-800 dark:text-gray-200">
@{comment.authorUsername}
</span>
<span className="text-gray-450 dark:text-gray-400">on</span>
<Link
to={`/articles/${comment.articleId}`}
className="text-primary hover:underline font-semibold text-xs bg-primary/10 dark:bg-primary/20 px-2 py-0.5 rounded-full"
>
article #{comment.articleId}
</Link>
</div>
<p className="text-sm mt-2.5 text-gray-700 dark:text-gray-300 leading-relaxed font-light break-words">
{comment.body}
</p>
<div className="flex items-center gap-1 text-[11px] text-gray-400 mt-3 font-medium">
<Clock className="w-3.5 h-3.5" />
{new Date(comment.createdAt).toLocaleString()}
</div>
</div>
<div className="shrink-0 pt-1">
{isLoading ? (
<RefreshCw className="w-4 h-4 text-gray-400 animate-spin" />
) : (
<button
onClick={() => handleDelete(comment.id)}
className="p-2 text-gray-400 hover:text-rose-500 hover:bg-rose-50 dark:hover:bg-rose-500/10 rounded-xl transition duration-200"
title="Delete Comment"
>
<Trash2 className="w-4.5 h-4.5" />
</button>
)}
</div>
</div>
);
})}
</div>
);
}

Xet Storage Details

Size:
3.48 kB
·
Xet hash:
ee24aa107f26cc1eac0ba5b32e71aab8414a456286484d1e3d56c9634cb3e275

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