diff --git a/src/components/Project/ProjectCard.jsx b/src/components/Project/ProjectCard.jsx
index a6f5c431..3bd818c4 100644
--- a/src/components/Project/ProjectCard.jsx
+++ b/src/components/Project/ProjectCard.jsx
@@ -18,7 +18,7 @@ import { useDispatch } from "react-redux";
import { setProjectId } from "../../slices/localVariablesSlice";
import { useProjectContext } from "../../pages/project/ProjectPage";
-const ProjectCard = ({ project }) => {
+const ProjectCard = ({ project, isCore = true }) => {
const dispatch = useDispatch();
const navigate = useNavigate();
const ManageProject = useHasUserPermission(MANAGE_PROJECT);
@@ -34,13 +34,30 @@ const ProjectCard = ({ project }) => {
const handleClose = () => setShowModal(false);
const handleViewProject = () => {
- dispatch(setProjectId(project.id));
- navigate(`/projects/details`);
+ if (isCore) {
+ dispatch(setProjectId(project.id));
+ navigate(`/projects/details`);
+ } else {
+ navigate(`/service-projects/${project.id}`);
+ }
};
const handleViewActivities = () => {
dispatch(setProjectId(project.id));
navigate(`/activities/records?project=${project.id}`);
};
+ const handleManage = () => {
+ if (isCore) {
+ setMangeProject({
+ isOpen: true,
+ Project: project.id,
+ });
+ } else {
+ setManageServiceProject({
+ isOpen: true,
+ Project: project.id,
+ });
+ }
+ };
return (
<>
diff --git a/src/components/Project/ProjectCardView.jsx b/src/components/Project/ProjectCardView.jsx
index 1108120c..cb44fd2a 100644
--- a/src/components/Project/ProjectCardView.jsx
+++ b/src/components/Project/ProjectCardView.jsx
@@ -1,70 +1,29 @@
-import React from 'react'
-import { useProjects } from '../../hooks/useProjects'
-import Loader from '../common/Loader'
-import ProjectCard from './ProjectCard'
-
-const ProjectCardView = ({currentItems,setCurrentPage,totalPages }) => {
-
+import React from "react";
+import { useProjects } from "../../hooks/useProjects";
+import Loader from "../common/Loader";
+import ProjectCard from "./ProjectCard";
+import Pagination from "../common/Pagination";
+const ProjectCardView = ({ data, currentPage, totalPages, paginate }) => {
return (
+
+ {data?.length === 0 && (
+
No projects found.
+ )}
-
+ {data?.map((project) => (
+
+ ))}
- { currentItems.length === 0 && (
-
No projects found.
- )}
-
- {currentItems.map((project) => (
-
- ))}
+
+
+ );
+};
-
- { totalPages > 1 && (
-
- )}
-
-
- )
-}
-
-export default ProjectCardView
+export default ProjectCardView;
diff --git a/src/components/ServiceProject/ManageServiceProject.jsx b/src/components/ServiceProject/ManageServiceProject.jsx
new file mode 100644
index 00000000..9e3c98ce
--- /dev/null
+++ b/src/components/ServiceProject/ManageServiceProject.jsx
@@ -0,0 +1,225 @@
+import { zodResolver } from "@hookform/resolvers/zod";
+import React, { useState } from "react";
+import { defaultProjectValues } from "./ServiceProjectSchema";
+import Label from "../common/Label";
+import { FormProvider, useForm } from "react-hook-form";
+import { useGlobalServices } from "../../hooks/masterHook/useMaster";
+import { ITEMS_PER_PAGE, PROJECT_STATUS } from "../../utils/constants";
+import DatePicker from "../common/DatePicker";
+
+import SelectMultiple from "../common/SelectMultiple";
+import { projectSchema } from "./ServiceProjectSchema";
+import {
+ useOrganization,
+ useOrganizationsList,
+} from "../../hooks/useOrganization";
+import { error } from "pdf-lib";
+import { useCreateServiceProject } from "../../hooks/useServiceProject";
+
+const ManageServiceProject = ({ servieceProjectId }) => {
+ console.log(servieceProjectId)
+ const [searchText, setSearchText] = useState("");
+ const methods = useForm({
+ resolver: zodResolver(projectSchema),
+ defaultValues: defaultProjectValues,
+ });
+ const {
+ register,
+ handleSubmit,
+ control,
+ formState: { errors },
+ } = methods;
+ const { data, isError, isLoading } = useGlobalServices();
+ const { data: organization, isLoading: isLoadingOrganization } =
+ useOrganizationsList(ITEMS_PER_PAGE, 1, true);
+
+ const { mutate: CreateServiceProject, isPending } = useCreateServiceProject();
+ const onSubmit = (formData) => {
+ formData.services = formData.services.filter((s) => s.serviceId);
+ CreateServiceProject(formData);
+ };
+ return (
+
+
+
+ );
+};
+
+export default ManageServiceProject;
diff --git a/src/components/ServiceProject/ServiceProjectNav.jsx b/src/components/ServiceProject/ServiceProjectNav.jsx
new file mode 100644
index 00000000..4015332f
--- /dev/null
+++ b/src/components/ServiceProject/ServiceProjectNav.jsx
@@ -0,0 +1,41 @@
+import React from 'react'
+
+const ServiceProjectNav = ({ onPillClick, activePill }) => {
+ const ProjectTab = [
+ { key: "profile", icon: "bx bx-user", label: "Profile" },
+ { key: "teams", icon: "bx bx-group", label: "Teams" },
+
+ {
+ key: "directory",
+ icon: "bx bxs-contact",
+ label: "Directory",
+ },
+
+ ];
+ return (
+
+ )
+}
+
+export default ServiceProjectNav
diff --git a/src/components/ServiceProject/ServiceProjectProfile.jsx b/src/components/ServiceProject/ServiceProjectProfile.jsx
new file mode 100644
index 00000000..3084a755
--- /dev/null
+++ b/src/components/ServiceProject/ServiceProjectProfile.jsx
@@ -0,0 +1,97 @@
+import React from "react";
+import { useParams } from "react-router-dom";
+import { useServiceProject } from "../../hooks/useServiceProject";
+import { formatUTCToLocalTime } from "../../utils/dateUtils";
+
+const ServiceProjectProfile = () => {
+ const { id } = useParams();
+ const { data, isLoading, isError, error } = useServiceProject(id);
+ if (isLoading) {
+ return Loadng.
;
+ }
+ return (
+
+
+
+
+
+ {" "}
+
+ Project Profile
+
+
+
+
+
+ -
+
+
+ Name:
+
+
+ {/* Content section that wraps nicely */}
+
+ {data.name}
+
+
+ -
+
+
+ Nick Name:
+
+ {data.shortName}
+
+ -
+
+
+ Assign Date:
+
+
+ {data.assignedDate ? formatUTCToLocalTime(data.assignedDate) : "NA"}
+
+
+
+ -
+
+
+ Status:
+
+ {data?.status.status}
+
+ -
+
+
+ Contact:
+
+ {data.contactName}
+
+ -
+ {/* Label section with icon */}
+
+
+ Address:
+
+
+ {/* Content section that wraps nicely */}
+
+ {data.address}
+
+
+
+
+
+ - {/* Added mt-4 for some top margin */}
+
+
+
+
+
+
+
+
+
+
+ );
+};
+
+export default ServiceProjectProfile;
diff --git a/src/components/ServiceProject/ServiceProjectSchema.jsx b/src/components/ServiceProject/ServiceProjectSchema.jsx
new file mode 100644
index 00000000..e21fefbb
--- /dev/null
+++ b/src/components/ServiceProject/ServiceProjectSchema.jsx
@@ -0,0 +1,53 @@
+import { z } from "zod";
+
+export const projectSchema = z.object({
+ name: z.string().min(1, "Name is required"),
+ shortName: z.string().min(1, "Short name is required"),
+ clientId: z.string().min(1, { message: "Client is required" }),
+ services: z
+ .any() // accept anything, then sanitize below
+ .transform((val) => {
+ if (!Array.isArray(val)) return [];
+ return val
+ .map((item) => {
+ if (typeof item === "string") {
+ return { serviceId: item, isActive: true };
+ }
+ if (item && typeof item === "object" && "serviceId" in item) {
+ return { serviceId: item.serviceId, isActive: !!item.isActive };
+ }
+ return null;
+ })
+ .filter(Boolean);
+ })
+ .refine((arr) => arr.length > 0, {
+ message: "At least one service is required",
+ }),
+ address: z.string().min(1, "Address is required"),
+ assignedDate: z.string().min(1, { message: "Date is required" }),
+ statusId: z.string().min(1, "Status is required"),
+ contactName: z.string().min(1, "Contact name is required"),
+ contactPhone: z
+ .string()
+ .min(7, "Invalid phone number")
+ .max(15, "Phone number too long"),
+ contactEmail: z.string().email("Invalid email address"),
+});
+
+export const defaultProjectValues = {
+ name: "",
+ shortName: "",
+ clientId: "",
+ services: [
+ {
+ serviceId:null,
+ isActive: true,
+ },
+ ],
+ address: "",
+ assignedDate: "",
+ statusId: "",
+ contactName: "",
+ contactPhone: "",
+ contactEmail: "",
+};
diff --git a/src/components/ServiceProject/SeviceProjectDisplayList.jsx b/src/components/ServiceProject/SeviceProjectDisplayList.jsx
new file mode 100644
index 00000000..e69de29b
diff --git a/src/hooks/useProjects.js b/src/hooks/useProjects.js
index 7175bb94..b958ff32 100644
--- a/src/hooks/useProjects.js
+++ b/src/hooks/useProjects.js
@@ -20,12 +20,12 @@ export const useCurrentService = () => {
// ------------------------------Query-------------------
-export const useProjects = () => {
+export const useProjects = (pageSize,pageNumber) => {
const loggedUser = useSelector((store) => store.globalVariables.loginUser);
return useQuery({
- queryKey: ["ProjectsList"],
+ queryKey: ["ProjectsList",pageSize,pageNumber],
queryFn: async () => {
- const response = await ProjectRepository.getProjectList();
+ const response = await ProjectRepository.getProjectList(pageSize,pageNumber);
return response.data;
},
enabled: !!loggedUser,
diff --git a/src/hooks/useServiceProject.jsx b/src/hooks/useServiceProject.jsx
new file mode 100644
index 00000000..b11bee22
--- /dev/null
+++ b/src/hooks/useServiceProject.jsx
@@ -0,0 +1,41 @@
+import { useMutation, useQuery } from "@tanstack/react-query";
+import { ServiceProjectRepository } from "../repositories/ServiceProject";
+import showToast from "../services/toastService";
+
+
+
+export const useServiceProjects = (pageSize,pageNumber)=>{
+ return useQuery({
+ queryKey:["serviceProjects",pageSize,pageNumber],
+ queryFn:async()=> {
+ const response = await ServiceProjectRepository.GetServiceProjects(pageSize,pageNumber);
+ return response.data;
+ },
+ })
+}
+export const useServiceProject=(projectId)=>{
+ return useQuery({
+ queryKey:["serviceProject",projectId],
+ queryFn:async()=> {
+ const response = await ServiceProjectRepository.GetServiceProject(projectId);
+ return response.data;
+ },
+ })
+}
+export const useCreateServiceProject = (onSuccessCallback) => {
+ return useMutation({
+ mutationFn: async (playload) =>
+ await ServiceProjectRepository.CreateServiceProject(playload),
+ onSuccess: (data, variables) => {
+ showToast("Project created successfully", "success");
+ },
+ onError: (error) => {
+ showToast(
+ error?.response?.data?.message ||
+ error.message ||
+ "Failed to delete task",
+ "error"
+ );
+ },
+ });
+};
diff --git a/src/pages/ServiceProject/ServiceProjectDetail.jsx b/src/pages/ServiceProject/ServiceProjectDetail.jsx
new file mode 100644
index 00000000..5e9f0a11
--- /dev/null
+++ b/src/pages/ServiceProject/ServiceProjectDetail.jsx
@@ -0,0 +1,45 @@
+import React, { useState } from "react";
+import Breadcrumb from "../../components/common/Breadcrumb";
+import ServiceProjectNav from "../../components/ServiceProject/ServiceProjectNav";
+import { ComingSoonPage } from "../Misc/ComingSoonPage";
+import ServiceProjectProfile from "../../components/ServiceProject/ServiceProjectProfile";
+
+const ServiceProjectDetail = () => {
+ const [activePill, setActivePill] = useState(
+ sessionStorage.getItem("servicePrjectTab") || "profile"
+ );
+ const handlePillClick = (pillKey) => {
+ setActivePill(pillKey);
+ localStorage.setItem("lastActiveProjectTab", pillKey);
+ };
+ const renderContent = () => {
+ switch (activePill) {
+ case "profile":
+ return ;
+ default:
+ return ;
+ }
+ };
+ return (
+
+
+
+
+
+
+ {renderContent()}
+
+
+ );
+};
+
+export default ServiceProjectDetail;
diff --git a/src/pages/ServiceProject/ServiceProjectDisplay.jsx b/src/pages/ServiceProject/ServiceProjectDisplay.jsx
new file mode 100644
index 00000000..e3d99091
--- /dev/null
+++ b/src/pages/ServiceProject/ServiceProjectDisplay.jsx
@@ -0,0 +1,41 @@
+import React, { useState } from "react";
+import { useProjectContext } from "../project/ProjectPage";
+import { useServiceProjects } from "../../hooks/useServiceProject";
+import { ITEMS_PER_PAGE } from "../../utils/constants";
+import ProjectCard from "../../components/Project/ProjectCard";
+import Pagination from "../../components/common/Pagination";
+
+const ServiceProjectDisplay = ({ listView }) => {
+ const [currentPage, setCurrentPage] = useState(1);
+
+ const { manageServiceProject, setManageServiceProject } = useProjectContext();
+ const { data, isLoading, isError, error } = useServiceProjects(
+ ITEMS_PER_PAGE,
+ currentPage
+ );
+ const paginate = (page) => {
+ if (page >= 1 && page <= (data?.totalPages ?? 1)) {
+ setCurrentPage(page);
+ }
+ };
+ return (
+
+ {listView ? (
+
List
+ ) : (
+ data?.data?.map((project) => (
+
+ ))
+ )}
+
+
+ );
+};
+
+export default ServiceProjectDisplay;
diff --git a/src/pages/project/ProjectPage.jsx b/src/pages/project/ProjectPage.jsx
index 3806608d..b95282e7 100644
--- a/src/pages/project/ProjectPage.jsx
+++ b/src/pages/project/ProjectPage.jsx
@@ -9,6 +9,10 @@ import usePagination from "../../hooks/usePagination";
import { useProjects } from "../../hooks/useProjects";
import { useHasUserPermission } from "../../hooks/useHasUserPermission";
import { SpinnerLoader } from "../../components/common/Loader";
+import { useServiceProjects } from "../../hooks/useServiceProject";
+import ManageServiceProject from "../../components/ServiceProject/ManageServiceProject";
+import ProjectsDisplay from "./ProjectsDisplay";
+import ServiceProjectDisplay from "../ServiceProject/ServiceProjectDisplay";
const ProjectContext = createContext();
export const useProjectContext = () => {
@@ -22,90 +26,30 @@ export const useProjectContext = () => {
const ProjectPage = () => {
const [manageProject, setMangeProject] = useState({
isOpen: false,
- Project: null,
+ project: null,
+ });
+ const [manageServiceProject, setManageServiceProject] = useState({
+ isOpen: false,
+ project: null,
});
const [projectList, setProjectList] = useState([]);
const [listView, setListView] = useState(false);
const [searchTerm, setSearchTerm] = useState("");
+ const [coreProjects, setCoreProjects] = useState(true);
const HasManageProject = useHasUserPermission(MANAGE_PROJECT);
const [selectedStatuses, setSelectedStatuses] = useState(
PROJECT_STATUS.map((s) => s.id)
);
- const { data, isLoading, isError, error } = useProjects();
-
const contextDispatcher = {
setMangeProject,
+ setManageServiceProject,
+ manageProject,
+ manageServiceProject
};
-
- const filteredProjects = projectList.filter((project) => {
- const matchesStatus = selectedStatuses.includes(project.projectStatusId);
- const matchesSearch = project.name
- .toLowerCase()
- .includes(searchTerm.toLowerCase());
- return matchesStatus && matchesSearch;
- });
-
- const totalPages = Math.ceil(filteredProjects.length / ITEMS_PER_PAGE);
-
- const { currentItems, currentPage, paginate, setCurrentPage } = usePagination(
- filteredProjects,
- ITEMS_PER_PAGE
- );
-
- const handleStatusChange = (statusId) => {
- setCurrentPage(1);
- setSelectedStatuses((prev) =>
- prev.includes(statusId)
- ? prev.filter((id) => id !== statusId)
- : [...prev, statusId]
- );
- };
-
- const sortingProject = (projects) => {
- if (!isLoading && Array.isArray(projects)) {
- const grouped = {};
-
- projects.forEach((project) => {
- const statusId = project.projectStatusId;
- if (!grouped[statusId]) grouped[statusId] = [];
- grouped[statusId].push(project);
- });
-
- const sortedGrouped = selectedStatuses
- .filter((statusId) => grouped[statusId])
- .flatMap((statusId) =>
- grouped[statusId].sort((a, b) =>
- a.name.toLowerCase().localeCompare(b.name.toLowerCase())
- )
- );
-
- setProjectList((prev) => {
- const isSame = JSON.stringify(prev) === JSON.stringify(sortedGrouped);
- return isSame ? prev : sortedGrouped;
- });
- }
- };
-
- useEffect(() => {
- if (!isLoading && data) {
- sortingProject(data);
- }
- }, [data, isLoading, selectedStatuses]);
-
- if (isLoading)
- return (
-
-
-
- );
-
- if (isError) return
+ const handleToggleProject = (e) => setCoreProjects(e.target.checked);
return (
@@ -184,6 +128,21 @@ const ProjectPage = () => {
))}
+
+
+
+
{HasManageProject && (
@@ -200,41 +159,29 @@ const ProjectPage = () => {
Add New Project
+
)}
- {/* Project Render here */}
- {listView ? (
-
- ) : (
-
- )}
-
- {/* ------------------ */}
-
- {/* Project Manage UPdate or create */}
-
- {manageProject.isOpen && (
- setMangeProject({ isOpen: false, Project: null })}
- >
- setMangeProject({ isOpen: false, Project: null })}
- />
-
- )}
+ {coreProjects ? : }
);
diff --git a/src/pages/project/ProjectsDisplay.jsx b/src/pages/project/ProjectsDisplay.jsx
new file mode 100644
index 00000000..aa21c747
--- /dev/null
+++ b/src/pages/project/ProjectsDisplay.jsx
@@ -0,0 +1,153 @@
+import React, { useEffect, useState } from "react";
+import ProjectListView from "../../components/Project/ProjectListView";
+import ProjectCardView from "../../components/Project/ProjectCardView";
+import GlobalModel from "../../components/common/GlobalModel";
+import ManageServiceProject from "../../components/ServiceProject/ManageServiceProject";
+import { useProjectContext } from "./ProjectPage";
+import { SpinnerLoader } from "../../components/common/Loader";
+import { useProjects } from "../../hooks/useProjects";
+import { useServiceProjects } from "../../hooks/useServiceProject";
+import { ITEMS_PER_PAGE, PROJECT_STATUS } from "../../utils/constants";
+import usePagination from "../../hooks/usePagination";
+import ManageProjectInfo from "../../components/Project/ManageProjectInfo";
+
+const ProjectsDisplay = ({ listView, searchTerm }) => {
+ const [currentPage, setCurrentPage] = useState(1);
+ const {
+ manageProject,
+ manageServiceProject,
+ setMangeProject,
+ setManageServiceProject,
+ } = useProjectContext();
+
+ const [projectList, setProjectList] = useState([]);
+ const [selectedStatuses, setSelectedStatuses] = useState(
+ PROJECT_STATUS.map((s) => s.id)
+ );
+
+ const { data, isLoading, isError, error } = useProjects(ITEMS_PER_PAGE, 1);
+
+ const filteredProjects =
+ data?.data?.filter((project) => {
+ const matchesStatus = selectedStatuses.includes(project.projectStatusId);
+ const matchesSearch = project?.name
+ ?.toLowerCase()
+ ?.includes(searchTerm?.toLowerCase());
+ return matchesStatus && matchesSearch;
+ }) ?? [];
+
+ const paginate = (page) => {
+ if (page >= 1 && page <= (data?.totalPages ?? 1)) {
+ setCurrentPage(page);
+ }
+ };
+
+ const handleStatusChange = (statusId) => {
+ setCurrentPage(1);
+ setSelectedStatuses((prev) =>
+ prev.includes(statusId)
+ ? prev.filter((id) => id !== statusId)
+ : [...prev, statusId]
+ );
+ };
+
+ const sortingProject = (projects) => {
+ if (!isLoading && Array.isArray(projects)) {
+ const grouped = {};
+
+ projects.forEach((project) => {
+ const statusId = project.projectStatusId ?? project?.status?.id;
+ if (!grouped[statusId]) grouped[statusId] = [];
+ grouped[statusId].push(project);
+ });
+
+ const sortedGrouped = selectedStatuses
+ .filter((statusId) => grouped[statusId])
+ .flatMap((statusId) =>
+ grouped[statusId].sort((a, b) =>
+ a?.name?.toLowerCase()?.localeCompare(b?.name?.toLowerCase())
+ )
+ );
+
+ setProjectList((prev) => {
+ const isSame = JSON.stringify(prev) === JSON.stringify(sortedGrouped);
+ return isSame ? prev : sortedGrouped;
+ });
+ }
+ };
+
+ useEffect(() => {
+ if (!isLoading && data?.data) {
+ sortingProject(data.data);
+ }
+ }, [data?.data, isLoading, selectedStatuses]);
+
+ if (isLoading)
+ return (
+
+
+
+ );
+
+ if (isError)
+ return (
+
+ );
+ return (
+
+ {listView ? (
+
+ ) : (
+
+ )}
+
+ {/* Project Manage Update or Create */}
+ {manageProject?.isOpen && (
+
setMangeProject({ isOpen: false, Project: null })}
+ >
+ setMangeProject({ isOpen: false, Project: null })}
+ />
+
+ )}
+
+ {/* Service Project */}
+ {manageServiceProject?.isOpen && (
+
+ setManageServiceProject({ isOpen: false, Project: null })
+ }
+ >
+
+
+ )}
+
+ );
+};
+
+export default ProjectsDisplay;
diff --git a/src/pages/project/ProjectsDisplayGround.jsx b/src/pages/project/ProjectsDisplayGround.jsx
new file mode 100644
index 00000000..43c5bf08
--- /dev/null
+++ b/src/pages/project/ProjectsDisplayGround.jsx
@@ -0,0 +1,154 @@
+import React, { useEffect, useState } from "react";
+import ProjectListView from "../../components/Project/ProjectListView";
+import ProjectCardView from "../../components/Project/ProjectCardView";
+import GlobalModel from "../../components/common/GlobalModel";
+import ManageServiceProject from "../../components/ServiceProject/ManageServiceProject";
+import { useProjectContext } from "./ProjectPage";
+import { SpinnerLoader } from "../../components/common/Loader";
+import { useProjects } from "../../hooks/useProjects";
+import { useServiceProjects } from "../../hooks/useServiceProject";
+import { ITEMS_PER_PAGE, PROJECT_STATUS } from "../../utils/constants";
+import usePagination from "../../hooks/usePagination";
+
+const ProjectsDisplayGround = ({ listView, searchTerm }) => {
+ const {
+ manageProject,
+ manageServiceProject,
+ setMangeProject,
+ setManageServiceProject,
+ } = useProjectContext();
+ const [projectList, setProjectList] = useState([]);
+
+ const [selectedStatuses, setSelectedStatuses] = useState(
+ PROJECT_STATUS.map((s) => s.id)
+ );
+
+ const contextDispatcher = {
+ setMangeProject,
+ setManageServiceProject,
+ };
+ const { data, isLoading, isError, error } = useProjects(ITEMS_PER_PAGE, 1);
+ const filteredProjects = data?.data?.filter((project) => {
+ const matchesStatus = selectedStatuses.includes(project.projectStatusId);
+ const matchesSearch = project?.name
+ ?.toLowerCase()
+ ?.includes(searchTerm?.toLowerCase());
+ return matchesStatus && matchesSearch;
+ });
+
+ const totalPages = Math.ceil(filteredProjects?.length / ITEMS_PER_PAGE);
+
+ const { currentItems, currentPage, paginate, setCurrentPage } = usePagination(
+ filteredProjects,
+ ITEMS_PER_PAGE
+ );
+
+ const handleStatusChange = (statusId) => {
+ setCurrentPage(1);
+ setSelectedStatuses((prev) =>
+ prev.includes(statusId)
+ ? prev.filter((id) => id !== statusId)
+ : [...prev, statusId]
+ );
+ };
+
+ const sortingProject = (projects) => {
+ if (!isLoading && Array.isArray(projects)) {
+ const grouped = {};
+
+ projects.forEach((project) => {
+ const statusId = project.projectStatusId ?? project?.status?.id;
+ if (!grouped[statusId]) grouped[statusId] = [];
+ grouped[statusId].push(project);
+ });
+
+ const sortedGrouped = selectedStatuses
+ .filter((statusId) => grouped[statusId])
+ .flatMap((statusId) =>
+ grouped[statusId].sort((a, b) =>
+ a?.name?.toLowerCase()?.localeCompare(b?.name?.toLowerCase())
+ )
+ );
+
+ setProjectList((prev) => {
+ const isSame = JSON.stringify(prev) === JSON.stringify(sortedGrouped);
+ return isSame ? prev : sortedGrouped;
+ });
+ }
+ };
+ useEffect(() => {
+ if (!isLoading && data) {
+ sortingProject([data.data]);
+ }
+ }, [data?.data, isLoading, selectedStatuses]);
+
+ if (isLoading)
+ return (
+
+
+
+ );
+
+ if (isError)
+ return (
+
+ );
+ return (
+
+ {/* Project Render here */}
+ {listView ? (
+
+ ) : (
+
+ )}
+
+ {/* Project Manage UPdate or create */}
+ {manageProject?.isOpen && (
+
setMangeProject({ isOpen: false, Project: null })}
+ >
+ setMangeProject({ isOpen: false, Project: null })}
+ />
+
+ )}
+
+ {/* Servicer Project */}
+
+ {manageServiceProject?.isOpen && (
+
+ setManageServiceProject({ isOpen: false, Project: null })
+ }
+ >
+
+
+ )}
+
+ );
+};
+
+export default ProjectsDisplayGround;
diff --git a/src/repositories/ProjectRepository.jsx b/src/repositories/ProjectRepository.jsx
index 06d33c58..1220d085 100644
--- a/src/repositories/ProjectRepository.jsx
+++ b/src/repositories/ProjectRepository.jsx
@@ -1,7 +1,7 @@
import { api } from "../utils/axiosClient";
const ProjectRepository = {
- getProjectList: () => api.get("/api/project/list"),
+ getProjectList: (pageSize,pageNumber) => api.get(`/api/project/list?pageSize=${pageSize}&pageNumber=${pageNumber}`),
getProjectByprojectId: (projetid) =>
api.get(`/api/project/details/${projetid}`),
diff --git a/src/repositories/ServiceProject.jsx b/src/repositories/ServiceProject.jsx
new file mode 100644
index 00000000..ba8dff9d
--- /dev/null
+++ b/src/repositories/ServiceProject.jsx
@@ -0,0 +1,10 @@
+import { api } from "../utils/axiosClient";
+
+export const ServiceProjectRepository = {
+ CreateServiceProject: (data) => api.post("/api/ServiceProject/create", data),
+ GetServiceProjects: (pageSize,pageNumber) => api.get(`/api/ServiceProject/list?pageSize=${pageSize}&pageNumber=${pageNumber}`),
+ GetServiceProject: (id) => api.get(`/api/ServiceProject/details/${id}`),
+ UpdateServiceProject: (id, data) =>
+ api.put(`/api/ServiceProject/edit/${id}`, data),
+ DeleteServiceProject: (id) => api.delete(`/api/ServiceProject/delete/{id}`),
+};
diff --git a/src/router/AppRoutes.jsx b/src/router/AppRoutes.jsx
index 185ac564..5031f18b 100644
--- a/src/router/AppRoutes.jsx
+++ b/src/router/AppRoutes.jsx
@@ -59,6 +59,7 @@ import MakeSubscription from "../pages/Home/MakeSubscription";
import PaymentRequestPage from "../pages/PaymentRequest/PaymentRequestPage";
import RecurringExpensePage from "../pages/RecurringExpense/RecurringExpensePage";
import AdvancePaymentPage from "../pages/AdvancePayment/AdvancePaymentPage";
+import ServiceProjectDetail from "../pages/ServiceProject/ServiceProjectDetail";
const router = createBrowserRouter(
[
{
@@ -93,6 +94,8 @@ const router = createBrowserRouter(
{ path: "/projects", element: },
{ path: "/projects/details", element: },
{ path: "/project/manage/:projectId", element: },
+ { path: "service-projects/:id", element: },
+
{ path: "/employees", element: },
{ path: "/employee/:employeeId", element: },
// { path: "/employee/manage", element: },