diff --git a/src/components/Documents/DocumentFilterPanel.jsx b/src/components/Documents/DocumentFilterPanel.jsx
new file mode 100644
index 00000000..0fa039fa
--- /dev/null
+++ b/src/components/Documents/DocumentFilterPanel.jsx
@@ -0,0 +1,9 @@
+import React from 'react'
+
+const DocumentFilterPanel = () => {
+ return (
+
-
-
-
- {/* Search */}
-
-
-
-
- {/* Actions */}
-
-
- Refresh
- < i className={`bx bx-refresh ms-1 `}>
-
-
-
-
-
+
+
+
+ {/* Search */}
+
+ setSearchText(e.target.value)}
+ className="form-control form-control-sm"
+ placeholder="Search Document"
+ />
- {isUpload && (
-
setUpload(false)}>
- setUpload(false)}/>
-
- )}
-
-
- )
-}
-export default Documents
\ No newline at end of file
+ {/* Actions */}
+
+ refetchFn && refetchFn()}>
+ Refresh
+
+
+
+
+
+
+
+
+
+ {isUpload && (
+
setUpload(false)}>
+ setUpload(false)}
+ Document_Entity={Document_Entity}
+ Entity={Entity}
+ />
+
+ )}
+
+ );
+};
+
+export default Documents;
diff --git a/src/components/Documents/DocumentsList.jsx b/src/components/Documents/DocumentsList.jsx
new file mode 100644
index 00000000..11bbb649
--- /dev/null
+++ b/src/components/Documents/DocumentsList.jsx
@@ -0,0 +1,142 @@
+import React, { useEffect } from "react";
+import { useDocumentListByEntityId } from "../../hooks/useDocument";
+import { ITEMS_PER_PAGE } from "../../utils/constants";
+import Avatar from "../common/Avatar";
+import { formatUTCToLocalTime } from "../../utils/dateUtils";
+import Loader from "../common/Loader";
+import { useDebounce } from "../../utils/appUtils";
+
+export const getDocuementsStatus = (status) => {
+ switch (status) {
+ case true:
+ return (
+
Verified
+ );
+ case false:
+ return (
+
Rejected
+ );
+ case null:
+ default:
+ return (
+
Pending
+ );
+ }
+};
+const DocumentsList = ({ Document_Entity, Entity,searchText ,setIsRefetching,
+ setRefetchFn,}) => {
+ const debouncedSearch = useDebounce(searchText, 500);
+ const { data, isError, isLoading, error,refetch,isFetching } = useDocumentListByEntityId(
+ Document_Entity,
+ Entity,
+ ITEMS_PER_PAGE,
+ 1,{},debouncedSearch
+ );
+
+ // Pass the refetch function to parent when component mounts
+ useEffect(() => {
+ setRefetchFn(() => refetch);
+ }, [setRefetchFn, refetch]);
+
+ // Sync fetching status with parent
+ useEffect(() => {
+ setIsRefetching(isFetching);
+ }, [isFetching, setIsRefetching]);
+
+ if (isLoading) return
;
+ if (isError) return
Error: {error?.message || "Something went wrong"}
;
+
+ 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",
+ getValue: (e) =>
+ `${e.uploadedBy?.firstName ?? ""} ${
+ e.uploadedBy?.lastName ?? ""
+ }`.trim() || "N/A",
+ customRender: (e) => (
+
+
+
+ {`${e.uploadedBy?.firstName ?? ""} ${
+ e.uploadedBy?.lastName ?? ""
+ }`.trim() || "N/A"}
+
+
+ ),
+ },
+ {
+ key: "uploadedAt",
+ label: "Uploaded on",
+ getValue: (e) => formatUTCToLocalTime(e?.uploadedAt),
+ isAlwaysVisible: true,
+ align: "text-center",
+ },
+ {
+ key: "Status",
+ label: "status",
+ getValue: (e) => getDocuementsStatus(e.isVerified),
+ isAlwaysVisible: true,
+ align: "text-center",
+ },
+ ];
+
+ return (
+
+
+
+
+ {DocumentColumns.map((col) => (
+ |
+ {col.label}
+ |
+ ))}
+
+ Action
+ |
+
+
+
+ {data?.map((doc) => (
+
+ {DocumentColumns.map((col) => (
+ |
+ {col.customRender ? col.customRender(doc) : col.getValue(doc)}
+ |
+ ))}
+
+
+
+
+
+
+
+
+ |
+
+ ))}
+
+
+
+ );
+};
+
+export default DocumentsList;
diff --git a/src/components/Documents/NewDocument.jsx b/src/components/Documents/NewDocument.jsx
index 7bdfa352..180ee24e 100644
--- a/src/components/Documents/NewDocument.jsx
+++ b/src/components/Documents/NewDocument.jsx
@@ -3,7 +3,6 @@ import React, { useEffect, useState } from "react";
import { useForm, FormProvider } from "react-hook-form";
import { defaultDocumentValues, DocumentPayloadSchema } from "./DocumentSchema";
import Label from "../common/Label";
-import { DOCUMENTS_ENTITIES } from "../../utils/constants";
import {
useDocumentCategories,
useDocumentTypes,
@@ -11,7 +10,6 @@ import {
import TagInput from "../common/TagInput";
import { useUploadDocument } from "../../hooks/useDocument";
import showToast from "../../services/toastService";
-import { useParams } from "react-router-dom";
const toBase64 = (file) =>
new Promise((resolve, reject) => {
@@ -21,8 +19,8 @@ const toBase64 = (file) =>
reader.onerror = (err) => reject(err);
});
-const NewDocument = ({closeModal}) => {
- const { employeeId } = useParams();
+const NewDocument = ({closeModal,Document_Entity,Entity}) => {
+
const [selectedType, setSelectedType] = useState(null);
const [selectedCategory, setSelectedCategory] = useState(null);
const [schema, setSchema] = useState(() => DocumentPayloadSchema({}));
@@ -44,7 +42,7 @@ const NewDocument = ({closeModal}) => {
closeModal();
});
const onSubmit = (data) => {
- const DocumentPayload = { ...data, entityId: employeeId };
+ const DocumentPayload = { ...data, entityId: Entity };
UploadDocument(DocumentPayload);
};
@@ -54,7 +52,7 @@ const NewDocument = ({closeModal}) => {
// This hooks calling api base Entity(Employee) and Category
const { DocumentCategories, isLoading } = useDocumentCategories(
- DOCUMENTS_ENTITIES.EmployeeEntity
+ Document_Entity
);
const categoryId = watch("documentCategoryId");
diff --git a/src/components/Employee/EmpDashboard.jsx b/src/components/Employee/EmpDashboard.jsx
index b25f6803..85c97836 100644
--- a/src/components/Employee/EmpDashboard.jsx
+++ b/src/components/Employee/EmpDashboard.jsx
@@ -9,7 +9,6 @@ const EmpDashboard = ({ profile }) => {
refetch,
} = useProjectsAllocationByEmployee(profile?.id);
- console.log(projectList);
return (
<>
diff --git a/src/components/Employee/EmpDocuments.jsx b/src/components/Employee/EmpDocuments.jsx
index 39d6e900..b4c8046b 100644
--- a/src/components/Employee/EmpDocuments.jsx
+++ b/src/components/Employee/EmpDocuments.jsx
@@ -2,11 +2,14 @@ import React, { useState, useEffect } from "react";
import { ComingSoonPage } from "../../pages/Misc/ComingSoonPage";
import DocumentPage from "../../pages/Documents/DocumentPage";
import Documents from "../Documents/Documents";
+import { useParams } from "react-router-dom";
+import { DOCUMENTS_ENTITIES } from "../../utils/constants";
const EmpDocuments = ({ profile, loggedInUser }) => {
+ const {employeeId} = useParams()
return (
<>
-
+
>
);
};
diff --git a/src/components/Project/ProjectDocuments.jsx b/src/components/Project/ProjectDocuments.jsx
new file mode 100644
index 00000000..061a25ec
--- /dev/null
+++ b/src/components/Project/ProjectDocuments.jsx
@@ -0,0 +1,14 @@
+import React from "react";
+import Documents from "../Documents/Documents";
+import { useSelectedproject } from "../../slices/apiDataManager";
+import { DOCUMENTS_ENTITIES } from "../../utils/constants";
+const ProjectDocuments = () => {
+ const selectedProject = useSelectedproject()
+ return (
+ <>
+
+ >
+ );
+};
+
+export default ProjectDocuments;
diff --git a/src/components/Project/ProjectNav.jsx b/src/components/Project/ProjectNav.jsx
index 0a7f960e..633be7d7 100644
--- a/src/components/Project/ProjectNav.jsx
+++ b/src/components/Project/ProjectNav.jsx
@@ -67,15 +67,15 @@ const ProjectNav = ({ onPillClick, activePill }) => {
{
e.preventDefault(); // Prevent page reload
- onPillClick("imagegallary");
+ onPillClick("documents");
}}
>
- project Setup
+ Documents
diff --git a/src/hooks/useDocument.js b/src/hooks/useDocument.js
index 4885359b..c9262491 100644
--- a/src/hooks/useDocument.js
+++ b/src/hooks/useDocument.js
@@ -1,20 +1,46 @@
-
-
-//----------------------- MUTATION -------------------------
-
-import { useMutation } from "@tanstack/react-query"
+import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"
import showToast from "../services/toastService";
import { DocumentRepository } from "../repositories/DocumentRepository";
+// ----------------------Query-------------------------------
+const cleanFilter = (filter) => {
+ const cleaned = { ...filter };
+
+ ["uploadedByIds", "documentCategoryIds", "documentTypeIds", "documentTagIds"].forEach((key) => {
+ if (Array.isArray(cleaned[key]) && cleaned[key].length === 0) {
+ delete cleaned[key];
+ }
+
+ });
+
+ return cleaned;
+};
+export const useDocumentListByEntityId=(entityTypeId,entityId,pageSize, pageNumber, filter,searchString="")=>{
+ return useQuery({
+ queryKey:["DocumentList",entityTypeId,entityId,pageSize, pageNumber, filter,searchString],
+ queryFn:async()=>{
+ const cleanedFilter = cleanFilter(filter);
+ const resp = await DocumentRepository.getDocumentList(entityTypeId,entityId,pageSize, pageNumber,cleanedFilter,searchString);
+ return resp.data;
+ },
+ enabled:!!entityTypeId && !! entityId
+ })
+}
+
+//----------------------- MUTATION -------------------------
+
export const useUploadDocument =(onSuccessCallBack)=>{
+ const queryClient = useQueryClient()
return useMutation(({
mutationFn:async(DocumentPayload)=>DocumentRepository.uploadDocument(DocumentPayload),
onSuccess:(data,variables)=>{
+ queryClient.invalidateQueries({queryKey:["DocumentList"]});
if(onSuccessCallBack) onSuccessCallBack()
},
onError: (error) => {
+ console.log(error)
showToast(
- error.message || "Something went wrong please try again !",
+ error.response.data.message || "Something went wrong please try again !",
"error"
);
},
diff --git a/src/pages/project/ProjectDetails.jsx b/src/pages/project/ProjectDetails.jsx
index 75f7705b..78b2b662 100644
--- a/src/pages/project/ProjectDetails.jsx
+++ b/src/pages/project/ProjectDetails.jsx
@@ -16,9 +16,7 @@ import {
useSelectedproject,
} from "../../slices/apiDataManager";
import "./ProjectDetails.css";
-import {
- useProjectDetails,
-} from "../../hooks/useProjects";
+import { useProjectDetails } from "../../hooks/useProjects";
import { ComingSoonPage } from "../Misc/ComingSoonPage";
import Directory from "../Directory/Directory";
import eventBus from "../../services/eventBus";
@@ -26,19 +24,20 @@ import ProjectProgressChart from "../../components/Dashboard/ProjectProgressChar
import { useProjectName } from "../../hooks/useProjects";
import AttendanceOverview from "../../components/Dashboard/AttendanceChart";
import { setProjectId } from "../../slices/localVariablesSlice";
+import ProjectDocument from "../../components/Project/ProjectDocuments";
+import ProjectDocuments from "../../components/Project/ProjectDocuments";
const ProjectDetails = () => {
-
- const projectId = useSelectedproject()
+ const projectId = useSelectedproject();
const { projectNames, fetchData } = useProjectName();
- const dispatch = useDispatch()
+ const dispatch = useDispatch();
useEffect(() => {
if (projectId == null) {
dispatch(setProjectId(projectNames[0]?.id));
}
- }, [projectNames])
+ }, [projectNames]);
const {
projects_Details,
@@ -49,12 +48,15 @@ const ProjectDetails = () => {
// const [activePill, setActivePill] = useState("profile");
const [activePill, setActivePill] = useState(() => {
- return localStorage.getItem("lastActiveProjectTab") || "profile";
-});
+ return localStorage.getItem("lastActiveProjectTab") || "profile";
+ });
const handler = useCallback(
(msg) => {
- if (msg.keyword === "Update_Project" && projects_Details?.id === msg.response.id) {
+ if (
+ msg.keyword === "Update_Project" &&
+ projects_Details?.id === msg.response.id
+ ) {
refetch();
}
},
@@ -66,11 +68,10 @@ const ProjectDetails = () => {
return () => eventBus.off("project", handler);
}, [handler]);
- const handlePillClick = (pillKey) => {
- setActivePill(pillKey);
- localStorage.setItem("lastActiveProjectTab", pillKey); // ✅ Save to localStorage
-};
-
+ const handlePillClick = (pillKey) => {
+ setActivePill(pillKey);
+ localStorage.setItem("lastActiveProjectTab", pillKey); // ✅ Save to localStorage
+ };
const renderContent = () => {
if (projectLoading || !projects_Details) return
;
@@ -85,9 +86,14 @@ const ProjectDetails = () => {
>
@@ -103,14 +109,10 @@ const ProjectDetails = () => {
);
case "infra":
- return (
-