"use client"; import ComponentCard from "@/components/common/ComponentCard"; import Swal from "sweetalert2"; import PageBreadcrumb from "@/components/common/PageBreadCrumb"; import BasicTableOne from "@/components/tables/BasicTableOne"; import ChangeRoleModal from "@/components/tables/ChangeRoleModal"; import UserDetailModal from "@/components/tables/UserDetailModal"; import { responseUserTable, getUserDto, fullDataUser } from "@/interface/admin"; import { apiDeleteUser, apiGetAllRole, apiGetListUser, apiRestoreUser, } from "@/service/adminService"; import { useEffect, useState, useCallback } from "react"; import Pagination from "@/components/tables/Pagination"; import { LIMIT_ITEM_TABLE } from "../../../../../../constant"; export type SortColumn = "created_at" | "updated_at" | "display_name" | "email"; 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 default function UserTable() { const [page, setPage] = useState(1); const [limitInput, setLimitInput] = useState(LIMIT_ITEM_TABLE.toString()); const [selectedRole, setSelectedRole] = useState(""); const [roles, setRoles] = useState<{ id: string; name: string }[]>([]); const [searchTerm, setSearchTerm] = useState(""); const [authProvider, setAuthProvider] = useState(""); const [isDeleted, setIsDeleted] = useState(undefined); const [fromDate, setFromDate] = useState(""); const [fromTime, setFromTime] = useState(""); const [toDate, setToDate] = useState(""); const [toTime, setToTime] = useState(""); const [selectedUser, setSelectedUser] = useState(null); const [isModalOpen, setIsModalOpen] = useState(false); const [roleUser, setRoleUser] = useState(null); const [isRoleModalOpen, setIsRoleModalOpen] = useState(false); const [debouncedParams, setDebouncedParams] = useState({ search: "", limit: 5, authProvider: "", fromDate: "", fromTime: "", toDate: "", toTime: "", }); const [tableData, setTableData] = useState(null); const [loading, setLoading] = useState(true); const [sortBy, setSortBy] = useState(undefined); const [sortOrder, setSortOrder] = useState<"asc" | "desc">("asc"); const handleReset = () => { setSearchTerm(""); setAuthProvider(""); setIsDeleted(undefined); setSelectedRole(""); setLimitInput(LIMIT_ITEM_TABLE.toString()); setFromDate(""); setFromTime(""); setToDate(""); setToTime(""); setPage(1); setDebouncedParams({ search: "", limit: LIMIT_ITEM_TABLE, authProvider: "", fromDate: "", fromTime: "", toDate: "", toTime: "", }); }; useEffect(() => { const fetchRoles = async () => { try { const res = await apiGetAllRole(); if (res?.status) { setRoles(res.data); } } catch (err) { console.error("Lỗi lấy danh sách role:", err); } }; fetchRoles(); }, []); useEffect(() => { const handler = setTimeout(() => { setDebouncedParams({ search: searchTerm, limit: parseInt(limitInput) || LIMIT_ITEM_TABLE, authProvider: authProvider, fromDate, fromTime, toDate, toTime, }); setPage(1); }, 600); return () => clearTimeout(handler); }, [ searchTerm, limitInput, authProvider, fromDate, fromTime, toDate, toTime, ]); const fetchUsers = useCallback(async () => { setLoading(true); try { const payload: any = { page: page, limit: debouncedParams.limit, search: debouncedParams.search || undefined, auth_provider: debouncedParams.authProvider || undefined, is_deleted: isDeleted, sort: sortBy, order: sortOrder, role_ids: selectedRole ? [selectedRole] : undefined, }; // Thêm format ngày giờ vào payload const createdFrom = formatDateTimeToISO( debouncedParams.fromDate, debouncedParams.fromTime, false, ); if (createdFrom) payload.created_from = createdFrom; const createdTo = formatDateTimeToISO( debouncedParams.toDate, debouncedParams.toTime, true, ); if (createdTo) payload.created_to = createdTo; const response = await apiGetListUser(payload as getUserDto); if (response?.status) { setTableData(response); } } catch (err) { console.error("Fetch error:", err); setTableData(null); } finally { setLoading(false); } }, [page, debouncedParams, isDeleted, sortBy, sortOrder, selectedRole]); useEffect(() => { fetchUsers(); }, [fetchUsers]); const handleSort = (column: SortColumn) => { setPage(1); if (sortBy === column) { setSortOrder(sortOrder === "asc" ? "desc" : "asc"); } else { setSortBy(column); setSortOrder("desc"); } }; const pagination = tableData?.pagination; // console.log(pagination); const handleOpenDetail = (user: fullDataUser) => { setSelectedUser(user); setIsModalOpen(true); }; const handleOpenRoleModal = (user: fullDataUser) => { setRoleUser(user); setIsRoleModalOpen(true); }; const handleDelete = async (user: fullDataUser) => { const result = await Swal.fire({ title: "Xác nhận khóa?", text: `Bạn có chắc muốn khóa người dùng ${user.profile?.display_name || user.email}?`, icon: "warning", showCancelButton: true, showCloseButton: true, confirmButtonColor: "#d33", cancelButtonColor: "#3085d6", confirmButtonText: "Đồng ý, khóa!", cancelButtonText: "Hủy", reverseButtons: true, }); if (result.isConfirmed) { try { await apiDeleteUser(user.id); Swal.fire( "Đã khóa!", "Người dùng đã bị tạm dừng hoạt động.", "success", ); fetchUsers(); } catch (err) { Swal.fire("Lỗi!", "Không thể thực hiện thao tác này.", "error"); } } }; const handleRestore = async (user: fullDataUser) => { const result = await Swal.fire({ title: "Khôi phục tài khoản?", text: `Khôi phục quyền truy cập cho ${user.profile?.display_name || user.email}?`, icon: "question", showCancelButton: true, showCloseButton: true, confirmButtonColor: "#28a745", confirmButtonText: "Xác nhận", cancelButtonText: "Hủy", }); if (result.isConfirmed) { try { await apiRestoreUser(user.id); Swal.fire("Thành công", "Tài khoản đã được khôi phục.", "success"); fetchUsers(); } catch (err) { Swal.fire("Thất bại", "Vui lòng thử lại sau.", "error"); } } }; 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" />
{/* Từ ngày */}
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" />
{/* Đến ngày */}
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" />
{/* Limit */}
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 && (
)} setSelectedRole(role)} />

Hiển thị trang {pagination?.current_page || 1} /{" "} {pagination?.total_pages || 1} ({pagination?.total_records || 0}{" "} kết quả)

{pagination && pagination.total_pages > 1 && ( setPage(newPage)} /> )}
setIsModalOpen(false)} user={selectedUser} onChangeRole={handleOpenRoleModal} onDelete={(u) => { handleDelete(u); setIsModalOpen(false); }} onRestore={(u) => { handleRestore(u); setIsModalOpen(false); }} /> setIsRoleModalOpen(false)} user={roleUser} onSuccess={fetchUsers} />
); }