kontenhumas-fe/components/table/image-table.tsx

470 lines
16 KiB
TypeScript

"use client";
import { useEffect, useState } from "react";
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@/components/ui/table"; // pastikan path sesuai
import { format } from "date-fns";
import { id } from "date-fns/locale";
import { Badge } from "@/components/ui/badge";
import { listDataImage } from "@/service/content";
import { Button } from "../ui/button";
import { getCookiesDecrypt } from "@/lib/utils";
import Swal from "sweetalert2";
import withReactContent from "sweetalert2-react-content";
import { useParams, useRouter, useSearchParams } from "next/navigation";
import { ChevronDown, Edit, Eye, Search, Trash, View } from "lucide-react";
import { InputGroup, InputGroupText } from "../ui/input-group";
import { Input } from "../ui/input";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuRadioGroup,
DropdownMenuRadioItem,
DropdownMenuTrigger,
} from "../ui/dropdown-menu";
import { Label } from "../ui/label";
import TablePagination from "./table-pagination";
import { table } from "console";
export default function ImageTable() {
const [dataTable, setDataTable] = useState([]);
const [loading, setLoading] = useState(false);
const router = useRouter();
const searchParams = useSearchParams();
const params = useParams();
const locale = params?.locale;
const MySwal = withReactContent(Swal);
const [totalData, setTotalData] = useState<number>(1);
const [showData, setShowData] = useState("10");
const [page, setPage] = useState(1);
const [totalPage, setTotalPage] = useState(1);
const [search, setSearch] = useState("");
const userId = getCookiesDecrypt("uie");
const userLevelId = getCookiesDecrypt("ulie");
const [categories, setCategories] = useState<any[]>([]);
const [selectedCategories, setSelectedCategories] = useState<number[]>([]);
const [categoryFilter, setCategoryFilter] = useState<string>("");
const [statusFilter, setStatusFilter] = useState<any[]>([]);
const [startDate, setStartDate] = useState("");
const [endDate, setEndDate] = useState("");
const [filterByCreator, setFilterByCreator] = useState("");
const [filterBySource, setFilterBySource] = useState("");
const [filterByCreatorGroup, setFilterByCreatorGroup] = useState("");
const roleId = getCookiesDecrypt("urie");
useEffect(() => {
fetchData();
}, [page, showData, search, categoryFilter, statusFilter]);
async function fetchData() {
const formattedStartDate = startDate
? format(new Date(startDate), "yyyy-MM-dd")
: "";
const formattedEndDate = endDate
? format(new Date(endDate), "yyyy-MM-dd")
: "";
try {
const isForSelf = Number(roleId) === 4;
setLoading(true);
const res = await listDataImage(
showData,
page - 1,
isForSelf,
!isForSelf,
categoryFilter,
statusFilter,
statusFilter?.sort().join(",").includes("1") ? userLevelId : "",
filterByCreator,
filterBySource,
formattedStartDate,
formattedEndDate,
search,
filterByCreatorGroup,
locale == "en"
);
const contentData = res?.data?.data?.content || [];
const formattedData = contentData.map((item: any, index: number) => ({
no: index + 1,
...item,
}));
setDataTable(formattedData);
} catch (error) {
console.error("Error fetching data:", error);
} finally {
setLoading(false);
}
}
useEffect(() => {
fetchData();
}, []);
const getStatusBadge = (status: number) => {
switch (status) {
case 1:
return <Badge className="bg-green-500">Done</Badge>;
case 2:
return <Badge className="bg-blue-500">Queue</Badge>;
case 3:
return <Badge className="bg-red-500">Trigger Error</Badge>;
default:
return <Badge>Unknown</Badge>;
}
};
// const handleSearch = (e: React.ChangeEvent<HTMLInputElement>) => {
// setSearch(e.target.value);
// dataTable.getColumn("judul")?.setFilterValue(e.target.value);
// };
const handleSearchFilterBySource = (
e: React.ChangeEvent<HTMLInputElement>
) => {
const value = e.target.value;
setFilterBySource(value);
fetchData();
};
function handleStatusCheckboxChange(value: any) {
setStatusFilter((prev: any) =>
prev.includes(value)
? prev.filter((status: any) => status !== value)
: [...prev, value]
);
}
const handleSearchFilterByCreator = (
e: React.ChangeEvent<HTMLInputElement>
) => {
const value = e.target.value;
setFilterByCreator(value);
fetchData();
};
const handleCheckboxChange = (categoryId: number) => {
setSelectedCategories((prev: any) =>
prev.includes(categoryId)
? prev.filter((id: any) => id !== categoryId)
: [...prev, categoryId]
);
// Perbarui filter kategori
setCategoryFilter((prev) => {
const updatedCategories = prev.split(",").filter(Boolean).map(Number);
const newCategories = updatedCategories.includes(categoryId)
? updatedCategories.filter((id) => id !== categoryId)
: [...updatedCategories, categoryId];
return newCategories.join(",");
});
};
return (
<div className="rounded-md border">
<div className="flex flex-col md:flex-row lg:flex-row md:justify-between lg:justify-between items-center md:px-5 lg:px-5">
<div className="w-full md:w-[200px] lg:w-[200px] ">
<div className="relative w-full">
<Search className="absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-gray-500 dark:text-white" />
<Input
type="text"
placeholder="Search Judul..."
className="pl-10 bg-transparent dark:border-secondary dark:placeholder-white/80 dark:focus:border-secondary dark:text-white"
defaultValue={search}
/>
</div>
</div>
<div className="flex flex-row items-center gap-3">
<div className="flex items-center py-4">
<div className="mx-3">
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button size="md" variant="outline">
{showData} Data
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent className="w-56 text-sm">
<DropdownMenuRadioGroup
value={showData}
onValueChange={setShowData}
>
<DropdownMenuRadioItem value="10">
10 Data
</DropdownMenuRadioItem>
<DropdownMenuRadioItem value="50">
50 Data
</DropdownMenuRadioItem>
<DropdownMenuRadioItem value="100">
100 Data
</DropdownMenuRadioItem>
<DropdownMenuRadioItem value="250">
250 Data
</DropdownMenuRadioItem>
</DropdownMenuRadioGroup>
</DropdownMenuContent>
</DropdownMenu>
</div>
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="outline" className="ml-auto" size="md">
Filter <ChevronDown />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent
align="end"
className="w-64 h-[200px] overflow-y-auto"
>
<div className="flex flex-row justify-between my-1 mx-1">
<p>Filter</p>
{/* <p
className="text-blue-600 cursor-pointer"
onClick={fetchData}
>
Simpan
</p> */}
</div>
<Label className="ml-2">Kategori</Label>
{categories.length > 0 ? (
categories.map((category) => (
<div
key={category.id}
className="flex items-center px-4 py-1"
>
<input
type="checkbox"
id={`category-${category.id}`}
className="mr-2"
checked={selectedCategories.includes(category.id)}
onChange={() => handleCheckboxChange(category.id)}
/>
<label
htmlFor={`category-${category.id}`}
className="text-sm"
>
{category.name}
</label>
</div>
))
) : (
<p className="text-sm text-gray-500 px-4 py-2">
No categories found.
</p>
)}
<div className="mx-2 my-1">
<Label>Tanggal Awal</Label>
<Input
type="date"
value={startDate}
onChange={(e) => setStartDate(e.target.value)}
className="max-w-sm"
/>
</div>
<div className="mx-2 my-1">
<Label>Tanggal Akhir</Label>
<Input
type="date"
value={endDate}
onChange={(e) => setEndDate(e.target.value)}
className="max-w-sm"
/>
</div>
<div className="mx-2 my-1">
<Label>Kreator</Label>
<Input
placeholder="Filter Status..."
value={filterByCreator}
onChange={handleSearchFilterByCreator}
className="max-w-sm"
/>
</div>
<div className="mx-2 my-1">
<Label>Sumber</Label>
<Input
placeholder="Filter Status..."
value={filterBySource}
onChange={handleSearchFilterBySource}
className="max-w-sm"
/>
</div>
<Label className="ml-2 mt-2">Status</Label>
<div className="flex items-center px-4 py-1">
<input
type="checkbox"
id="status-2"
className="mr-2"
checked={statusFilter.includes(1)}
onChange={() => handleStatusCheckboxChange(1)}
/>
<label htmlFor="status-2" className="text-sm">
Menunggu Review
</label>
</div>
<div className="flex items-center px-4 py-1">
<input
type="checkbox"
id="status-2"
className="mr-2"
checked={statusFilter.includes(2)}
onChange={() => handleStatusCheckboxChange(2)}
/>
<label htmlFor="status-2" className="text-sm">
Diterima
</label>
</div>
<div className="flex items-center px-4 py-1">
<input
type="checkbox"
id="status-3"
className="mr-2"
checked={statusFilter.includes(3)}
onChange={() => handleStatusCheckboxChange(3)}
/>
<label htmlFor="status-3" className="text-sm">
Minta Update
</label>
</div>
<div className="flex items-center px-4 py-1">
<input
type="checkbox"
id="status-4"
className="mr-2"
checked={statusFilter.includes(4)}
onChange={() => handleStatusCheckboxChange(4)}
/>
<label htmlFor="status-4" className="text-sm">
Ditolak
</label>
</div>
</DropdownMenuContent>
</DropdownMenu>
</div>
</div>
</div>
<Table>
<TableHeader>
<TableRow>
<TableHead className="text-center w-[70px]">No</TableHead>
<TableHead>Title</TableHead>
<TableHead>Category</TableHead>
<TableHead>Created At</TableHead>
<TableHead>Creator Name</TableHead>
<TableHead>Creator Group</TableHead>
<TableHead>Status</TableHead>
<TableHead className="text-center">Action</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{loading ? (
<TableRow>
<TableCell colSpan={8} className="text-center">
Loading...
</TableCell>
</TableRow>
) : dataTable.length > 0 ? (
dataTable.map((item: any) => (
<TableRow key={item.id}>
<TableCell className="text-center">{item.no}</TableCell>
<TableCell>{item.title}</TableCell>
<TableCell>{item.categoryName}</TableCell>
<TableCell>
{item.createdAt
? format(new Date(item.createdAt), "dd-MM-yyyy HH:mm", {
locale: id,
})
: "-"}
</TableCell>
<TableCell>{item.creatorName}</TableCell>
<TableCell>{item.creatorGroup}</TableCell>
<TableCell>{getStatusBadge(item.status)}</TableCell>
<TableCell className="flex flex-row text-center space-x-2">
<Button
size="sm"
variant="outline"
className="flex items-center gap-2"
>
<Eye size={15} />
Detail
</Button>
<Button
size="sm"
variant="outline"
className="flex items-center gap-2"
>
<Edit size={15} />
Edit
</Button>
<Button
size="sm"
className="flex items-center gap-2 bg-red-500 text-white"
>
<Trash size={15} />
Delete
</Button>
</TableCell>
</TableRow>
))
) : (
<TableRow>
<TableCell colSpan={8} className="text-center">
No data found
</TableCell>
</TableRow>
)}
</TableBody>
</Table>
{/* Pagination */}
<div className="flex justify-between items-center mt-4">
{/* Info jumlah data */}
<span className="text-sm text-gray-500">
Page {page} of {totalPage}
</span>
{/* Navigasi halaman */}
<div className="flex items-center space-x-2">
<button
onClick={() => setPage((prev) => Math.max(prev - 1, 1))}
disabled={page === 1}
className="px-3 py-1 border rounded disabled:opacity-50"
>
Prev
</button>
{Array.from({ length: totalPage }, (_, i) => (
<button
key={i}
onClick={() => setPage(i + 1)}
className={`px-3 py-1 border rounded ${
page === i + 1 ? "bg-blue-500 text-white" : "hover:bg-gray-100"
}`}
>
{i + 1}
</button>
))}
<button
onClick={() => setPage((prev) => Math.min(prev + 1, totalPage))}
disabled={page === totalPage}
className="px-3 py-1 border rounded disabled:opacity-50"
>
Next
</button>
</div>
</div>
</div>
);
}