"use client"; import { useEffect, useState, useCallback } from "react"; import ComponentCard from "@/components/common/ComponentCard"; import PageBreadcrumb from "@/components/common/PageBreadCrumb"; import Pagination from "@/components/tables/Pagination"; import { toast } from "sonner"; import ProjectsTable, { ProjectItem, ProjectSortColumn, } from "@/components/tables/ProjectsTable"; import { getProjects, updateProject, deleteProject, transferProjectOwnership, } from "@/service/projectService"; import Swal from "sweetalert2"; import { useRouter } from "next/navigation"; import { LIMIT_ITEM_TABLE } from "../../../../../../constant"; const formatDateTimeToISO = ( dateStr: string, timeStr: string, isEndOfDay: boolean = false, ): string | undefined => { if (!dateStr) return undefined; const time = timeStr || (isEndOfDay ? "23:59" : "00:00"); return `${dateStr}T${time}:00.000000+07:00`; }; export interface ProjectsResponse { status: boolean; message: string; data: ProjectItem[]; pagination: { current_page: number; page_size: number; total_records: number; total_pages: number; }; } export default function ProjectsPage() { const router = useRouter(); const [page, setPage] = useState(1); const [limitInput, setLimitInput] = useState( LIMIT_ITEM_TABLE.toString(), ); // Filters state const [searchTerm, setSearchTerm] = useState(""); const [statusFilter, setStatusFilter] = useState(""); const [userIdsFilter, setUserIdsFilter] = useState(""); const [fromDate, setFromDate] = useState(""); const [fromTime, setFromTime] = useState(""); const [toDate, setToDate] = useState(""); const [toTime, setToTime] = useState(""); const [debouncedParams, setDebouncedParams] = useState({ search: "", limit: LIMIT_ITEM_TABLE, statuses: "", userIds: "", fromDate: "", fromTime: "", toDate: "", toTime: "", }); const [tableData, setTableData] = useState(null); const [loading, setLoading] = useState(true); const [sortBy, setSortBy] = useState("created_at"); const [sortOrder, setSortOrder] = useState<"asc" | "desc">("desc"); const handleReset = () => { setSearchTerm(""); setStatusFilter(""); setUserIdsFilter(""); setLimitInput(LIMIT_ITEM_TABLE.toString()); setFromDate(""); setFromTime(""); setToDate(""); setToTime(""); setPage(1); }; useEffect(() => { const handler = setTimeout(() => { setDebouncedParams({ search: searchTerm, limit: parseInt(limitInput) || LIMIT_ITEM_TABLE, statuses: statusFilter, userIds: userIdsFilter, fromDate, fromTime, toDate, toTime, }); setPage(1); }, 100); return () => clearTimeout(handler); }, [ searchTerm, limitInput, statusFilter, userIdsFilter, fromDate, fromTime, toDate, toTime, ]); const fetchProjectsData = useCallback(async () => { setLoading(true); try { const payload: any = { page: page, limit: debouncedParams.limit, search: debouncedParams.search || undefined, sort: sortBy, order: sortOrder, statuses: debouncedParams.statuses || undefined, user_ids: debouncedParams.userIds || undefined, }; const createdFrom = formatDateTimeToISO(debouncedParams.fromDate, debouncedParams.fromTime); if (createdFrom) payload.created_from = createdFrom; const createdTo = formatDateTimeToISO(debouncedParams.toDate, debouncedParams.toTime, true); if (createdTo) payload.created_to = createdTo; const response = await getProjects(payload); if (response?.status) { setTableData(response as unknown as ProjectsResponse); } } catch (err) { toast.error("Lỗi lấy danh sách dự án"); console.error("Lỗi lấy danh sách dự án:", err); setTableData(null); } finally { setLoading(false); } }, [page, debouncedParams, sortBy, sortOrder]); useEffect(() => { fetchProjectsData(); }, [fetchProjectsData]); const handleSort = (column: ProjectSortColumn) => { setPage(1); if (sortBy === column) { setSortOrder(sortOrder === "asc" ? "desc" : "asc"); } else { setSortBy(column); setSortOrder("desc"); } }; const handleUpdate = async (project: ProjectItem) => { /* Tương tự handleCreate, sử dụng Swal.fire để tạo form cập nhật */ toast.info(`Chức năng cập nhật cho dự án "${project.title}"`); }; const handleDelete = async (id: string) => { const result = await Swal.fire({ title: "Xác nhận xóa?", text: "Bạn có chắc chắn muốn xóa dự án này? Hành động này không thể hoàn tác!", icon: "warning", showCancelButton: true, confirmButtonColor: "#ef4444", cancelButtonColor: "#6b7280", confirmButtonText: "Xóa", cancelButtonText: "Hủy", }); if (result.isConfirmed) { try { // const response = await deleteProject(id); // if (response?.status) { toast.success("Đã xóa dự án thành công."); fetchProjectsData(); // } else { // toast.error(response?.message || "Xóa dự án thất bại"); // } } catch (error) { toast.error("Đã xảy ra lỗi khi xóa"); console.error(error); } } }; const handleTransferOwner = async (project: ProjectItem) => { /* Sử dụng Swal.fire với input để nhập New Owner ID */ toast.info(`Chức năng chuyển quyền sở hữu cho dự án "${project.title}"`); }; const handleViewDetails = (id: string) => { // Điều hướng đến trang chi tiết dự án (quản lý members, commits) // router.push(`/projects/${id}`); toast.info(`Xem chi tiết dự án ID: ${id}`); }; const pagination = tableData?.pagination; return (
} >
setSearchTerm(e.target.value)} className="w-full px-3 py-2 border rounded-lg dark:bg-gray-800 dark:border-gray-700 outline-none focus:border-brand-500" /> setUserIdsFilter(e.target.value)} className="w-full px-3 py-2 border rounded-lg dark:bg-gray-800 dark:border-gray-700 outline-none focus:border-brand-500" />
setFromDate(e.target.value)} className="w-full px-3 py-2 border rounded-lg dark:bg-gray-800 dark:border-gray-700 outline-none focus:border-brand-500" /> setFromTime(e.target.value)} className="w-full px-3 py-2 border rounded-lg dark:bg-gray-800 dark:border-gray-700 outline-none focus:border-brand-500" />
setToDate(e.target.value)} className="w-full px-3 py-2 border rounded-lg dark:bg-gray-800 dark:border-gray-700 outline-none focus:border-brand-500" /> setToTime(e.target.value)} className="w-full px-3 py-2 border rounded-lg dark:bg-gray-800 dark:border-gray-700 outline-none focus:border-brand-500" />
setLimitInput(e.target.value)} className="w-full px-3 py-2 border rounded-lg dark:bg-gray-800 dark:border-gray-700 outline-none focus:border-brand-500" />
{loading && (
)}

Hiển thị {pagination?.total_records || 0} dự án

{pagination && pagination.total_pages > 1 && ( setPage(newPage)} /> )}
); }