update form article
continuous-integration/drone/push Build is passing Details

This commit is contained in:
Anang Yusman 2026-02-26 12:11:35 +08:00
parent 4d45e89a28
commit cf78d137ed
2 changed files with 111 additions and 121 deletions

View File

@ -1,6 +1,6 @@
"use client";
import { useState } from "react";
import { useEffect, useState } from "react";
import { Card, CardContent } from "@/components/ui/card";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
@ -15,74 +15,54 @@ import {
} 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 [activeCategory, setActiveCategory] = useState("All");
const [articles, setArticles] = useState<any[]>([]);
const [page, setPage] = useState(1);
const [totalPage, setTotalPage] = useState(1);
const [search, setSearch] = useState("");
const categories = [
{ name: "All", count: 24 },
{ name: "Technology", count: 8 },
{ name: "Partnership", count: 5 },
{ name: "Investment", count: 3 },
{ name: "News", count: 4 },
{ name: "Event", count: 2 },
{ name: "CSR", count: 2 },
];
useEffect(() => {
fetchData();
}, [page, search]);
const articles = [
{
title:
"Novita Hardini: Jangan Sampai Pariwisata Meminggirkan Warga Lokal",
category: "Technology",
author: "John Kontributor",
status: "Published",
date: "2024-01-15",
},
{
title:
"Bharatu Mardi Hadji Gugur Saat Bertugas, Diganjar Kenaikan Pangkat Luar Biasa",
category: "Partnership",
author: "Sarah Editor",
status: "Pending",
date: "2024-01-14",
},
{
title:
"Lestari Moerdijat: Butuh Afirmasi dan Edukasi untuk Dorong Perempuan Aktif di Dunia Politik",
category: "Investment",
author: "Mike Writer",
status: "Draft",
date: "2024-01-13",
},
{
title: "SEKRETARIS MAHKAMAH AGUNG LANTIK HAKIM TINGGI PENGAWAS",
category: "CSR",
author: "Jane Content",
status: "Published",
date: "2024-01-12",
},
{
title:
"Mudik Nyaman Bersama Pertamina: Layanan 24 Jam, Motoris, dan Fasilitas Lengkap",
category: "Event",
author: "John Kontributor",
status: "Rejected",
date: "2024-01-11",
},
];
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) {
case "Published":
switch (status?.toLowerCase()) {
case "publish":
return "bg-green-100 text-green-700";
case "Pending":
case "pending":
return "bg-yellow-100 text-yellow-700";
case "Draft":
case "draft":
return "bg-gray-200 text-gray-600";
case "Rejected":
case "reject":
return "bg-red-100 text-red-600";
default:
return "";
return "bg-gray-200 text-gray-600";
}
};
@ -106,28 +86,14 @@ export default function NewsImage() {
</Link>
</div>
{/* ================= CATEGORY FILTER ================= */}
<div className="flex flex-wrap gap-3">
{categories.map((cat) => (
<Button
key={cat.name}
variant={activeCategory === cat.name ? "default" : "outline"}
className="rounded-full text-sm"
onClick={() => setActiveCategory(cat.name)}
>
{cat.name}
<span className="ml-2 text-xs opacity-70">{cat.count}</span>
</Button>
))}
</div>
{/* ================= SEARCH + FILTER ================= */}
{/* ================= 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 by title, author, or content..."
placeholder="Search articles..."
className="pl-9"
onChange={(e) => setSearch(e.target.value)}
/>
</div>
@ -153,68 +119,86 @@ export default function NewsImage() {
</TableHeader>
<TableBody>
{articles.map((article, index) => (
<TableRow key={index}>
<TableCell className="font-medium max-w-xs">
{article.title}
</TableCell>
{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.category}</Badge>
</TableCell>
<TableCell>
<Badge variant="secondary">
{article?.categories
?.map((c: any) => c.title)
.join(", ")}
</Badge>
</TableCell>
<TableCell>{article.author}</TableCell>
<TableCell>
{article.customCreatorName || article.createdByName}
</TableCell>
<TableCell>
<span
className={`px-3 py-1 text-xs rounded-full font-medium ${statusVariant(
article.status,
)}`}
>
{article.status}
</span>
</TableCell>
<TableCell>
<span
className={`px-3 py-1 text-xs rounded-full font-medium ${statusVariant(
article.publishStatus,
)}`}
>
{article.publishStatus}
</span>
</TableCell>
<TableCell>{article.date}</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 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>Showing 1 to 5 of 24 articles</p>
<p>
Page {page} of {totalPage}
</p>
<div className="flex gap-2">
<Button variant="outline" size="sm">
<Button
variant="outline"
size="sm"
disabled={page === 1}
onClick={() => setPage(page - 1)}
>
Previous
</Button>
<Button size="sm" className="bg-blue-600">
1
{page}
</Button>
<Button variant="outline" size="sm">
2
</Button>
<Button variant="outline" size="sm">
3
</Button>
<Button variant="outline" size="sm">
<Button
variant="outline"
size="sm"
disabled={page === totalPage}
onClick={() => setPage(page + 1)}
>
Next
</Button>
</div>

View File

@ -165,10 +165,16 @@ export function convertDateFormatNoTime(date: Date): string {
return `${year}-${month}-${day}`;
}
export function formatDate(date: Date | null) {
export function formatDate(date: Date | string | null) {
if (!date) return "";
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, "0");
const day = String(date.getDate()).padStart(2, "0");
const parsedDate = typeof date === "string" ? new Date(date) : date;
if (isNaN(parsedDate.getTime())) return "";
const year = parsedDate.getFullYear();
const month = String(parsedDate.getMonth() + 1).padStart(2, "0");
const day = String(parsedDate.getDate()).padStart(2, "0");
return `${year}-${month}-${day}`;
}