264 lines
8.3 KiB
JavaScript

import React, { useEffect, useState } from "react";
import {
useActiveInActiveDocument,
useDocumentListByEntityId,
} from "../../hooks/useDocument";
import {
DELETE_DOCUMENT,
ITEMS_PER_PAGE,
MODIFY_DOCUMENT,
} from "../../utils/constants";
import Avatar from "../common/Avatar";
import { formatUTCToLocalTime } from "../../utils/dateUtils";
import { useDebounce } from "../../utils/appUtils";
import { DocumentTableSkeleton } from "./DocumentSkeleton";
import { getDocuementsStatus, useDocumentContext } from "./Documents";
import Pagination from "../common/Pagination";
import ConfirmModal from "../common/ConfirmModal";
import { isPending } from "@reduxjs/toolkit";
import { useHasUserPermission } from "../../hooks/useHasUserPermission";
import { useProfile } from "../../hooks/useProfile";
import { useParams } from "react-router-dom";
import showToast from "../../services/toastService";
const DocumentsList = ({
Document_Entity,
Entity,
filters,
searchText,
setIsRefetching,
setRefetchFn,
isActive,
}) => {
const { employeeId } = useParams();
const [isSelf, setIsSelf] = useState(false);
const { profile } = useProfile();
const canDeleteDocument = useHasUserPermission(DELETE_DOCUMENT);
const canModifyDocument = useHasUserPermission(MODIFY_DOCUMENT);
useEffect(() => {
if (profile?.employeeInfo?.id && employeeId) {
setIsSelf(String(profile.employeeInfo.id) === String(employeeId));
}
}, [profile?.employeeInfo?.id, employeeId]);
const [IsDeleteModalOpen, setIsDeleteModalOpen] = useState(false);
const [deletingId, setDeletingId] = useState(null);
const [restoringIds, setRestoringIds] = useState([]);
const debouncedSearch = useDebounce(searchText, 500);
const [currentPage, setCurrentPage] = useState(1);
const { data, isError, isLoading, error, refetch, isFetching } =
useDocumentListByEntityId(
Document_Entity,
Entity,
ITEMS_PER_PAGE,
currentPage,
filters,
debouncedSearch,
isActive
);
useEffect(() => {
setRefetchFn(() => refetch);
}, [setRefetchFn, refetch]);
useEffect(() => {
setIsRefetching(isFetching);
}, [isFetching, setIsRefetching]);
const { setManageDoc, setViewDoc,removeFilterChip } = useDocumentContext();
const { mutate: ActiveInActive, isPending } = useActiveInActiveDocument();
const paginate = (page) => {
if (page >= 1 && page <= (data?.totalPages ?? 1)) {
setCurrentPage(page);
}
};
const noData = !isLoading && !isError && data?.data.length === 0;
const isSearchEmpty = noData && !!debouncedSearch;
const isFilterEmpty = noData && !!filters && Object.keys(filters).length > 0;
const isInitialEmpty = noData && !debouncedSearch && !isFilterEmpty;
if (isLoading || isFetching) return <DocumentTableSkeleton />;
if (isError)
return <div>Error: {error?.message || "Something went wrong"}</div>;
if (isInitialEmpty) return <div className="py-12 my-12">No documents found yet.</div>;
if (isSearchEmpty) return <div className="py-12 my-12">No results found for "{debouncedSearch}"</div>;
if (isFilterEmpty) return <div className="py-12 my-12">No documents match your filter.</div>;
const handleDelete = () => {
ActiveInActive(
{ documentId: deletingId, isActive: !isActive },
{
onSettled: () => {
setDeletingId(null);
setIsDeleteModalOpen(false);
},
}
);
};
const handleRestore = (docId) => {
setRestoringIds((prev) => [...prev, docId]);
ActiveInActive(
{ documentId: docId, isActive: true },
{
onSettled: () => {
setRestoringIds((prev) => prev.filter((id) => id !== docId));
refetch();
},
}
);
};
const DocumentColumns = [
{
key: "name",
label: "Name",
getValue: (e) => e.name || "N/A",
align: "text-start",
},
{
key: "documentType",
label: "Document Type",
getValue: (e) => e.documentType?.name || "N/A",
align: "text-start",
},
{
key: "uploadedBy",
label: "Uploaded By",
align: "text-start",
customRender: (e) => (
<div className="d-flex align-items-center">
<Avatar
size="xs"
classAvatar="m-0"
firstName={e.uploadedBy?.firstName}
lastName={e.uploadedBy?.lastName}
/>
<span className="text-truncate ms-1">
{`${e.uploadedBy?.firstName ?? ""} ${
e.uploadedBy?.lastName ?? ""
}`.trim() || "N/A"}
</span>
</div>
),
getValue: (e) =>
`${e.uploadedBy?.firstName ?? ""} ${
e.uploadedBy?.lastName ?? ""
}`.trim() || "N/A",
},
{
key: "uploadedAt",
label: "Uploaded on",
getValue: (e) => formatUTCToLocalTime(e.uploadedAt),
align: "text-center",
isAlwaysVisible: true,
},
{
key: "Status",
label: "Status",
getValue: (e) => getDocuementsStatus(e.isVerified),
align: "text-center",
isAlwaysVisible: true,
},
];
return (
<>
{IsDeleteModalOpen && (
<ConfirmModal
isOpen={IsDeleteModalOpen}
type="delete"
header="Delete Document"
message="Are you sure you want to delete this document?"
onSubmit={handleDelete}
onClose={() => setIsDeleteModalOpen(false)}
loading={!!isPending}
paramData={deletingId}
/>
)}
<div className="table-responsive p-2">
<table className="table border-top dataTable text-nowrap">
<thead className="">
<tr className="py-2 ">
{DocumentColumns.map((col) => (
<th key={col.key} className={`sorting ${col.align}`}>
{col.label}
</th>
))}
<th className="sticky-action-column bg-white text-center">
Action
</th>
</tr>
</thead>
<tbody className="text-start">
{data?.data?.map((doc) => {
const isRestoring = restoringIds.includes(doc.id);
return (
<tr key={doc.id}>
{DocumentColumns.map((col) => (
<td key={col.key} className={`sorting ${col.align}`}>
{col.customRender
? col.customRender(doc)
: col.getValue(doc)}
</td>
))}
<td className="text-center">
{doc.isActive ? (
<div className="d-flex justify-content-center gap-2">
<i
className="bx bx-show text-primary cursor-pointer"
onClick={() =>
setViewDoc({ document: doc.id, isOpen: true })
}
></i>
{(isSelf || canModifyDocument) && (
<i
className="bx bx-edit text-secondary cursor-pointer"
onClick={() =>
setManageDoc({ document: doc.id, isOpen: true })
}
></i>
)}
{(isSelf || canDeleteDocument) && (
<i
className="bx bx-trash text-danger cursor-pointer"
onClick={() => {
setIsDeleteModalOpen(true);
setDeletingId(doc.id);
}}
></i>
)}
</div>
) : isRestoring ? (
<div
className="spinner-border spinner-border-sm text-primary"
role="status"
>
<span className="visually-hidden">Loading...</span>
</div>
) : (
<i
className="bx bx-recycle me-1 text-primary cursor-pointer"
onClick={() => handleRestore(doc.id)}
></i>
)}
</td>
</tr>
);
})}
</tbody>
</table>
</div>
</>
);
};
export default DocumentsList;