qudoco-fe/components/main/news-image.tsx

211 lines
6.4 KiB
TypeScript

"use client";
import { useEffect, useState } from "react";
import { Card, CardContent } from "@/components/ui/card";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Badge } from "@/components/ui/badge";
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@/components/ui/table";
import { Search, Filter, Eye, Pencil, Trash2, Plus } from "lucide-react";
import Link from "next/link";
import { getArticlePagination } from "@/service/article";
import { formatDate } from "@/utils/global";
import { close, loading } from "@/config/swal";
export default function NewsImage() {
const [articles, setArticles] = useState<any[]>([]);
const [page, setPage] = useState(1);
const [totalPage, setTotalPage] = useState(1);
const [search, setSearch] = useState("");
useEffect(() => {
fetchData();
}, [page, search]);
async function fetchData() {
loading();
const req = {
limit: "10",
page: page,
search: search,
source: "internal", // jika ingin filter image/internal
sort: "desc",
sortBy: "created_at",
};
const res = await getArticlePagination(req);
const data = res?.data?.data || [];
setArticles(data);
setTotalPage(res?.data?.meta?.totalPage || 1);
close();
}
const statusVariant = (status: string) => {
switch (status?.toLowerCase()) {
case "publish":
return "bg-green-100 text-green-700";
case "pending":
return "bg-yellow-100 text-yellow-700";
case "draft":
return "bg-gray-200 text-gray-600";
case "reject":
return "bg-red-100 text-red-600";
default:
return "bg-gray-200 text-gray-600";
}
};
return (
<div className="space-y-6">
{/* ================= HEADER ================= */}
<div className="flex items-start justify-between">
<div>
<h1 className="text-2xl font-semibold text-slate-800">
News & Articles
</h1>
<p className="text-sm text-slate-500 mt-1">
Create and manage news articles and blog posts
</p>
</div>
<Link href={"/admin/news-article/image/create"}>
<Button className="bg-blue-600 hover:bg-blue-700 rounded-lg">
<Plus className="w-4 h-4 mr-2" />
Create New Article
</Button>
</Link>
</div>
{/* ================= SEARCH ================= */}
<div className="flex gap-3">
<div className="relative flex-1">
<Search className="absolute left-3 top-3 w-4 h-4 text-slate-400" />
<Input
placeholder="Search articles..."
className="pl-9"
onChange={(e) => setSearch(e.target.value)}
/>
</div>
<Button variant="outline" className="rounded-lg">
<Filter className="w-4 h-4 mr-2" />
Filters
</Button>
</div>
{/* ================= TABLE ================= */}
<Card className="rounded-2xl border shadow-sm">
<CardContent className="p-0">
<Table>
<TableHeader>
<TableRow>
<TableHead>Article</TableHead>
<TableHead>Category</TableHead>
<TableHead>Author</TableHead>
<TableHead>Status</TableHead>
<TableHead>Date</TableHead>
<TableHead className="text-right">Actions</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{articles.length > 0 ? (
articles.map((article, index) => (
<TableRow key={article.id}>
<TableCell className="font-medium max-w-xs">
{article.title}
</TableCell>
<TableCell>
<Badge variant="secondary">
{article?.categories
?.map((c: any) => c.title)
.join(", ")}
</Badge>
</TableCell>
<TableCell>
{article.customCreatorName || article.createdByName}
</TableCell>
<TableCell>
<span
className={`px-3 py-1 text-xs rounded-full font-medium ${statusVariant(
article.publishStatus,
)}`}
>
{article.publishStatus}
</span>
</TableCell>
<TableCell>{formatDate(article.createdAt)}</TableCell>
<TableCell className="text-right space-x-2">
<Button size="icon" variant="ghost">
<Eye className="w-4 h-4" />
</Button>
<Button size="icon" variant="ghost">
<Pencil className="w-4 h-4" />
</Button>
<Button size="icon" variant="ghost">
<Trash2 className="w-4 h-4 text-red-500" />
</Button>
</TableCell>
</TableRow>
))
) : (
<TableRow>
<TableCell colSpan={6} className="text-center py-4">
No data available
</TableCell>
</TableRow>
)}
</TableBody>
</Table>
{/* ================= PAGINATION ================= */}
<div className="flex items-center justify-between p-4 border-t text-sm text-slate-500">
<p>
Page {page} of {totalPage}
</p>
<div className="flex gap-2">
<Button
variant="outline"
size="sm"
disabled={page === 1}
onClick={() => setPage(page - 1)}
>
Previous
</Button>
<Button size="sm" className="bg-blue-600">
{page}
</Button>
<Button
variant="outline"
size="sm"
disabled={page === totalPage}
onClick={() => setPage(page + 1)}
>
Next
</Button>
</div>
</div>
</CardContent>
</Card>
</div>
);
}