implement partial react-query in task assignment flow

This commit is contained in:
Pramod Mahajan 2025-06-30 20:20:52 +05:30
parent 7fbbe98373
commit f848f97d87
9 changed files with 601 additions and 472 deletions

View File

@ -21,17 +21,13 @@ const InfraPlanning = () =>
{ {
const {profile: LoggedUser, refetch : fetchData} = useProfile() const {profile: LoggedUser, refetch : fetchData} = useProfile()
const dispatch = useDispatch() const dispatch = useDispatch()
const {projects,loading:project_listLoader,error:projects_error} = useProjects() // const {projects,loading:project_listLoader,error:projects_error} = useProjects()
const selectedProject = useSelector((store)=>store.localVariables.projectId) const selectedProject = useSelector((store)=>store.localVariables.projectId)
const ManageInfra = useHasUserPermission( MANAGE_PROJECT_INFRA ) const ManageInfra = useHasUserPermission( MANAGE_PROJECT_INFRA )
const {projects_Details, loading: project_deatilsLoader, error: project_error,refetch} = useProjectDetails( selectedProject ) const {projects_Details, loading: project_deatilsLoader, error: project_error,refetch} = useProjectDetails( selectedProject )
const reloadedData = useSelector( ( store ) => store.localVariables.reload ) const reloadedData = useSelector( ( store ) => store.localVariables.reload )
// useEffect( () =>
// {
// dispatch(setProjectId(projects[0]?.id))
// }, [ projects ] )
useEffect( () => useEffect( () =>
{ {
@ -48,24 +44,6 @@ const InfraPlanning = () =>
<div className="card"> <div className="card">
<div className="card-body" style={{ padding: "0.5rem" }}> <div className="card-body" style={{ padding: "0.5rem" }}>
<div className="align-items-center"> <div className="align-items-center">
{/* <div className="row ">
<div className="col-sm-3 col-8 text-start mb-1">
<select name="DataTables_Table_0_length"
aria-controls="DataTables_Table_0"
className="form-select form-select-sm"
value={selectedProject}
onChange={(e)=>dispatch(setProjectId(e.target.value))}
aria-label=""
>
{(project_listLoader || projects.length < 0) && <option value="Loading..." disabled>Loading...</option> }
{!project_listLoader && projects?.map((project)=>(
<option key={project.id} value={project.id}>{project.name}</option>
))}
</select>
</div>
</div> */}
<div className="row "> <div className="row ">
{project_deatilsLoader && ( <p>Loading...</p> )} {project_deatilsLoader && ( <p>Loading...</p> )}
{( !project_deatilsLoader && projects_Details?.buildings.length === 0 ) && ( <p>No Result Found</p> )} {( !project_deatilsLoader && projects_Details?.buildings.length === 0 ) && ( <p>No Result Found</p> )}

View File

@ -5,9 +5,21 @@ import { zodResolver } from "@hookform/resolvers/zod";
import { z } from "zod"; import { z } from "zod";
import showToast from "../../services/toastService"; import showToast from "../../services/toastService";
import { TasksRepository } from "../../repositories/TaskRepository"; import { TasksRepository } from "../../repositories/TaskRepository";
import {useReportTask} from "../../hooks/useTasks";
export const ReportTask = ({ report, closeModal, refetch }) => { export const ReportTask = ({ report, closeModal }) => {
const [loading, setloading] = useState(false); const [ loading, setloading ] = useState( false );
const { mutate: reportTask, isPending } = useReportTask({
onSuccessCallback: () => {
// refetch();
reset();
setloading(false);
closeModal();
},
onErrorCallback: () => {
setloading(false);
},
} );
const maxPending = const maxPending =
report?.workItem?.plannedWork - report?.workItem?.completedWork; report?.workItem?.plannedWork - report?.workItem?.completedWork;
@ -43,33 +55,45 @@ export const ReportTask = ({ report, closeModal, refetch }) => {
useEffect(() => { useEffect(() => {
if (report) { if (report) {
reset({ completedTask: 0, comment: "" }); // optional: customize default if needed reset({ completedTask: 0, comment: "" });
} }
}, [report, reset]); }, [report, reset]);
const onSubmit = async (data) => { // const onSubmit = async (data) => {
try { // try {
setloading(true); // setloading(true);
const reportData = { // const reportData = {
...data, // ...data,
id: report?.id, // id: report?.id,
reportedDate: new Date().toISOString(), // reportedDate: new Date().toISOString(),
checkList: [], // checkList: [],
}; // };
let response = await TasksRepository.reportTask(reportData); // let response = await TasksRepository.reportTask(reportData);
showToast("Task Reported Successfully.", "success"); // showToast("Task Reported Successfully.", "success");
refetch(); // refetch();
reset() // reset()
setloading(false); // setloading(false);
closeModal(); // closeModal();
} catch ( error ) // } catch ( error )
{ // {
const msg = error.response.data.message || error.message || "Error Occur During Api Call" // const msg = error.response.data.message || error.message || "Error Occur During Api Call"
showToast(msg, "error"); // showToast(msg, "error");
} // }
// }
const onSubmit = (data) => {
setloading(true);
const reportData = {
...data,
id: report?.id,
reportedDate: new Date().toISOString(),
checkList: [],
}; };
reportTask(reportData);
};
const handleClose = () => { const handleClose = () => {
closeModal(); closeModal();
reset(); reset();

View File

@ -9,7 +9,7 @@ import Avatar from "../common/Avatar";
import { getBgClassFromHash } from "../../utils/projectStatus"; import { getBgClassFromHash } from "../../utils/projectStatus";
import { cacheData, getCachedData } from "../../slices/apiDataManager"; import { cacheData, getCachedData } from "../../slices/apiDataManager";
import ImagePreview from "../common/ImagePreview"; import ImagePreview from "../common/ImagePreview";
import { useAuditStatus } from "../../hooks/useTasks"; import { useAuditStatus, useSubmitTaskComment } from "../../hooks/useTasks";
const ReportTaskComments = ({ const ReportTaskComments = ({
commentsData, commentsData,
@ -48,7 +48,18 @@ const ReportTaskComments = ({
const [loading, setloading] = useState(false); const [loading, setloading] = useState(false);
const [comments, setComment] = useState([]); const [comments, setComment] = useState([]);
const { status, loading: auditStatusLoading } = useAuditStatus(); const { status, loading: auditStatusLoading } = useAuditStatus();
const [IsNeededSubTask, setIsNeededSubTask] = useState(false); const [ IsNeededSubTask, setIsNeededSubTask ] = useState( false );
const { submitComment, isPending } = useSubmitTaskComment({
actionAllow,
onSuccessCallback: (data) => {
setComment((prev) => [...prev, data]);
reset();
if ( actionAllow )
{
handleCloseAction(IsNeededSubTask);
}
},
});
const { const {
watch, watch,
@ -88,70 +99,73 @@ const ReportTaskComments = ({
} }
}, [comments]); }, [comments]);
const onSubmit = async (data) => { // const onSubmit = async (data) => {
let payload = { // let payload = {
...data, // ...data,
[actionAllow ? "id" : "taskAllocationId"]: commentsData?.id, // [actionAllow ? "id" : "taskAllocationId"]: commentsData?.id,
...(actionAllow ? {} : { commentDate: new Date().toISOString() }), // ...(actionAllow ? {} : { commentDate: new Date().toISOString() }),
}; // };
try { // try {
setloading(true); // setloading(true);
const resp = actionAllow // const resp = actionAllow
? await TasksRepository.auditTask(payload) // ? await TasksRepository.auditTask(payload)
: await TasksRepository.taskComments(payload); // : await TasksRepository.taskComments(payload);
setComment((prevItems) => [...prevItems, resp.data]); // setComment((prevItems) => [...prevItems, resp.data]);
const taskList = getCachedData("taskList"); // const taskList = getCachedData("taskList");
if (actionAllow) { // if (actionAllow) {
handleCloseAction(IsNeededSubTask); // handleCloseAction(IsNeededSubTask);
showToast( // showToast(
"Review submitted successfully. Record has been updated.", // "Review submitted successfully. Record has been updated.",
"success" // "success"
); // );
} else { // } else {
if (taskList && taskList.data) { // if (taskList && taskList.data) {
const updatedTaskList = taskList.data.map((task) => { // const updatedTaskList = taskList.data.map((task) => {
if (task.id === resp.data.taskAllocationId) { // if (task.id === resp.data.taskAllocationId) {
const existingComments = Array.isArray(task.comments) // const existingComments = Array.isArray(task.comments)
? task.comments // ? task.comments
: []; // : [];
return { // return {
...task, // ...task,
comments: [...existingComments, resp.data], // comments: [...existingComments, resp.data],
}; // };
} // }
return task; // return task;
}); // });
cacheData("taskList", { // cacheData("taskList", {
data: updatedTaskList, // data: updatedTaskList,
projectId: taskList.projectId, // projectId: taskList.projectId,
}); // });
} // }
showToast("Successfully Sent", "success"); // showToast("Successfully Sent", "success");
} // }
reset(); // reset();
setloading(false); // setloading(false);
} catch (error) { // } catch (error) {
setloading(false); // setloading(false);
showToast( // showToast(
error.response.data?.message || "Something went wrong", // error.response.data?.message || "Something went wrong",
"error" // "error"
); // );
} // }
// };
const onSubmit = (formData) => {
submitComment({ data: formData, commentsData });
}; };
const selectedAuditStatus = watch("workStatus"); const selectedAuditStatus = watch("workStatus");
useEffect(() => { useEffect(() => {
reset({ reset({
approvedTask: defaultCompletedTask || 0, approvedTask: defaultCompletedTask || 0,
}); });
}, [ defaultCompletedTask ] ); }, [defaultCompletedTask]);
return ( return (
<div className="p-2 p-sm-1"> <div className="p-2 p-sm-1">
<div className="modal-body p-sm-4 p-0"> <div className="modal-body p-sm-4 p-0">
@ -233,7 +247,6 @@ const ReportTaskComments = ({
)} )}
</div> </div>
</div> </div>
<div className="d-flex align-items-center flex-wrap"> <div className="d-flex align-items-center flex-wrap">
<p className="fw-bold text-start m-0 me-1"> <p className="fw-bold text-start m-0 me-1">
@ -260,50 +273,50 @@ const ReportTaskComments = ({
<div className="fw-normal ms-2">{commentsData?.description}</div> <div className="fw-normal ms-2">{commentsData?.description}</div>
</div> </div>
{commentsData?.approvedBy && ( {commentsData?.approvedBy && (
<> <>
<hr className="my-1"/> <hr className="my-1" />
<div className="row"> <div className="row">
<div className="col-12 col-sm-6">
<div className="col-12 col-sm-6"> {commentsData.approvedBy && (
{commentsData.approvedBy && ( <div className="fw-bold text-start d-flex align-items-center">
<div className="fw-bold text-start d-flex align-items-center"> <i className="bx bx-user-check bx-lg me-1"></i>
<i className="bx bx-user-check bx-lg me-1"></i> <span className="me-2">Approved By:</span>
<span className="me-2">Approved By:</span> <div className="d-flex align-items-center fw-normal">
<div className="d-flex align-items-center fw-normal"> <Avatar
<Avatar firstName={commentsData.approvedBy.firstName}
firstName={commentsData.approvedBy.firstName} lastName={commentsData.approvedBy.lastName}
lastName={commentsData.approvedBy.lastName} size="xs"
size="xs" className="me-1"
className="me-1" />
/> {commentsData.approvedBy.firstName +
{commentsData.approvedBy.firstName + " " +
" " + commentsData.approvedBy.lastName}
commentsData.approvedBy.lastName} </div>
</div> </div>
)}
</div> </div>
)}
</div>
<div className="col-12 col-sm-6"> <div className="col-12 col-sm-6">
{commentsData?.workStatus != null && ( {commentsData?.workStatus != null && (
<div className="fw-bold my-2 text-start d-flex align-items-center"> <div className="fw-bold my-2 text-start d-flex align-items-center">
<i className="bx bx-time-five me-2"></i> <i className="bx bx-time-five me-2"></i>
<span className="me-2">Work Status :</span> <span className="me-2">Work Status :</span>
<span className="fw-normal"> <span className="fw-normal">
{commentsData?.workStatus.name} {commentsData?.workStatus.name}
{/* {commentsData?.} */} {/* {commentsData?.} */}
</span> </span>
</div>
)}
</div> </div>
)}
</div>
</div> </div>
<div className="col-12 d-flex"> <div className="col-12 d-flex">
<span className="fw-bold">Total Approved : </span><span className="ms-2">{commentsData?.completedTask }</span> <span className="fw-bold">Total Approved : </span>
</div> <span className="ms-2">{commentsData?.completedTask}</span>
</> )} </div>
</>
)}
{commentsData?.reportedPreSignedUrls?.length > 0 && ( {commentsData?.reportedPreSignedUrls?.length > 0 && (
<> <>
<p className="fw-bold m-0 text-start"> <p className="fw-bold m-0 text-start">
@ -319,54 +332,53 @@ const ReportTaskComments = ({
)} )}
<form onSubmit={handleSubmit(onSubmit)} className="text-start"> <form onSubmit={handleSubmit(onSubmit)} className="text-start">
{( actionAllow && !commentsData.approvedBy ) && ( {actionAllow && !commentsData.approvedBy && (
<> <>
<div className="row align-items-end my-1"> <div className="row align-items-end my-1">
<div className="col-6 col-sm-4 text-start"> <div className="col-6 col-sm-4 text-start">
<label>Completed</label> <label>Completed</label>
<input <input
className="form-control form-control-sm" className="form-control form-control-sm"
{...register("approvedTask")} {...register("approvedTask")}
type="number" type="number"
/> />
{errors.approvedTask && ( {errors.approvedTask && (
<p className="danger-text m-0"> <p className="danger-text m-0">
{errors.approvedTask.message} {errors.approvedTask.message}
</p> </p>
)}
</div>
<div className="col-6 col-sm-4 text-center align-items-end m-0">
<label htmlFor="workStatus" className="form-label">
Audit Status
</label>
<select
id="workStatus"
className={`form-select form-select-sm`}
{...register("workStatus")}
defaultValue=""
onChange={(e) => setValue("workStatus", e.target.value)}
>
<option value="" disabled>
Select Status
</option>
{auditStatusLoading ? (
<option disabled>Loading...</option>
) : (
status.map((stat) => (
<option key={stat.id} value={stat.id}>
{stat.name}
</option>
))
)} )}
</select> </div>
{errors.workStatus && ( <div className="col-6 col-sm-4 text-center align-items-end m-0">
<div className="danger-text"> <label htmlFor="workStatus" className="form-label">
{errors.workStatus.message} Audit Status
</div> </label>
)} <select
id="workStatus"
className={`form-select form-select-sm`}
{...register("workStatus")}
defaultValue=""
onChange={(e) => setValue("workStatus", e.target.value)}
>
<option value="" disabled>
Select Status
</option>
{auditStatusLoading ? (
<option disabled>Loading...</option>
) : (
status.map((stat) => (
<option key={stat.id} value={stat.id}>
{stat.name}
</option>
))
)}
</select>
{errors.workStatus && (
<div className="danger-text">
{errors.workStatus.message}
</div>
)}
</div>
</div> </div>
</div>
</> </>
)} )}
<i className="bx bx-comment-detail me-2"></i> <i className="bx bx-comment-detail me-2"></i>
@ -382,10 +394,16 @@ const ReportTaskComments = ({
)} )}
<div <div
className={` ${ className={` ${
(actionAllow && !commentsData.approvedBy)? " d-flex justify-content-between" : "text-end" actionAllow && !commentsData.approvedBy
? " d-flex justify-content-between"
: "text-end"
} mt-2`} } mt-2`}
> >
<div className={`form-check ${!(actionAllow && !commentsData.approvedBy) && "d-none"} `}> <div
className={`form-check ${
!(actionAllow && !commentsData.approvedBy) && "d-none"
} `}
>
<input <input
className="form-check-input" className="form-check-input"
type="checkbox" type="checkbox"

View File

@ -120,10 +120,10 @@ const Header = () => {
[fetchData,projectNames,selectedProject] [fetchData,projectNames,selectedProject]
); );
useEffect(() => { // useEffect(() => {
eventBus.on("assign_project_one", handler); // eventBus.on("assign_project_one", handler);
return () => eventBus.off("assign_project_one", handler); // return () => eventBus.off("assign_project_one", handler);
}, [handler]); // }, [handler]);
const newProjectHandler = useCallback( const newProjectHandler = useCallback(
async (msg) => { async (msg) => {
@ -139,10 +139,23 @@ const Header = () => {
[HasManageProjectPermission,projectNames] [HasManageProjectPermission,projectNames]
); );
// useEffect(() => {
// eventBus.on("project", newProjectHandler);
// return () => eventBus.off("project", newProjectHandler);
// }, [handler]);
useEffect(() => { useEffect(() => {
eventBus.on("project", newProjectHandler); eventBus.on("assign_project_one", handler);
return () => eventBus.off("project", newProjectHandler); eventBus.on("project", newProjectHandler);
}, [handler]);
return () => {
eventBus.off("assign_project_one", handler);
eventBus.off("project", newProjectHandler);
};
}, [handler, newProjectHandler]);
return ( return (
<nav <nav
className="layout-navbar container-xxl navbar navbar-expand-xl navbar-detached align-items-center bg-navbar-theme" className="layout-navbar container-xxl navbar navbar-expand-xl navbar-detached align-items-center bg-navbar-theme"

View File

@ -11,6 +11,7 @@ import { TasksRepository } from "../../repositories/ProjectRepository";
import showToast from "../../services/toastService"; import showToast from "../../services/toastService";
import { useProjectDetails } from "../../hooks/useProjects"; import { useProjectDetails } from "../../hooks/useProjects";
import eventBus from "../../services/eventBus"; import eventBus from "../../services/eventBus";
import { useCreateTask } from "../../hooks/useTasks";
const AssignTask = ({ assignData, onClose, setAssigned }) => { const AssignTask = ({ assignData, onClose, setAssigned }) => {
const maxPlanned = const maxPlanned =
@ -41,9 +42,12 @@ const AssignTask = ({ assignData, onClose, setAssigned }) => {
const [isHelpVisibleTarget, setIsHelpVisibleTarget] = useState(false); const [isHelpVisibleTarget, setIsHelpVisibleTarget] = useState(false);
const helpPopupRefTarget = useRef(null); const helpPopupRefTarget = useRef(null);
const [isHelpVisible, setIsHelpVisible] = useState(false); const [isHelpVisible, setIsHelpVisible] = useState(false);
const [isSubmitting, setIsSubmitting] = useState(false); const { mutate: assignTask, isPending: isSubmitting } = useCreateTask({
onSuccessCallback: () => {
closedModel();
},
});
// Refs for Bootstrap Popovers
const infoRef = useRef(null); const infoRef = useRef(null);
const infoRef1 = useRef(null); const infoRef1 = useRef(null);
@ -149,34 +153,49 @@ const AssignTask = ({ assignData, onClose, setAssigned }) => {
); );
// Form submission handler // Form submission handler
const onSubmit = async (data) => { // const onSubmit = async (data) => {
const selectedEmployeeIds = data.selectedEmployees; // const selectedEmployeeIds = data.selectedEmployees;
setIsSubmitting(true); // setIsSubmitting(true);
// Prepare taskTeam data (only IDs are needed for the backend based on previous context) // // Prepare taskTeam data (only IDs are needed for the backend based on previous context)
const taskTeamWithDetails = selectedEmployeeIds // const taskTeamWithDetails = selectedEmployeeIds
.map((empId) => { // .map((empId) => {
return empId; // Return just the ID as per previous discussions // return empId; // Return just the ID as per previous discussions
}) // })
.filter(Boolean); // Ensure no nulls if employee not found (though unlikely with current logic) // .filter(Boolean); // Ensure no nulls if employee not found (though unlikely with current logic)
// Format data for API call // // Format data for API call
// const formattedData = {
// taskTeam: taskTeamWithDetails,
// plannedTask: data.plannedTask,
// description: data.description,
// assignmentDate: new Date().toISOString(), // Current date/time
// workItemId: assignData?.workItem?.workItem.id,
// };
// try {
// await TasksRepository.assignTask(formattedData);
// setIsSubmitting( false );
// showToast("Task Assined Successfully.", "success");
// closedModel();
// } catch (error) {
// setIsSubmitting(false);
// showToast("Something went wrong. Please try again.", "error");
// }
// };
const onSubmit = (data) => {
const selectedEmployeeIds = data.selectedEmployees;
const taskTeamWithDetails = selectedEmployeeIds?.map((empId) => empId)?.filter(Boolean);
const formattedData = { const formattedData = {
taskTeam: taskTeamWithDetails, taskTeam: taskTeamWithDetails,
plannedTask: data.plannedTask, plannedTask: data.plannedTask,
description: data.description, description: data.description,
assignmentDate: new Date().toISOString(), // Current date/time assignmentDate: new Date().toISOString(),
workItemId: assignData?.workItem?.workItem.id, workItemId: assignData?.workItem?.workItem.id,
}; };
try { assignTask(formattedData);
await TasksRepository.assignTask(formattedData);
setIsSubmitting( false );
showToast("Task Assined Successfully.", "success");
closedModel();
} catch (error) {
setIsSubmitting(false);
showToast("Something went wrong. Please try again.", "error");
}
}; };
// Handler to close the modal and reset form // Handler to close the modal and reset form

View File

@ -2,103 +2,282 @@ import { useEffect, useState } from "react";
import { TasksRepository } from "../repositories/TaskRepository"; import { TasksRepository } from "../repositories/TaskRepository";
import { cacheData, getCachedData } from "../slices/apiDataManager"; import { cacheData, getCachedData } from "../slices/apiDataManager";
import {MasterRespository} from "../repositories/MastersRepository"; import {MasterRespository} from "../repositories/MastersRepository";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import showToast from "../services/toastService";
import {useSelector} from "react-redux";
// import {formatDate} from "../utils/dateUtils"; // import {formatDate} from "../utils/dateUtils";
export const useTaskList = (projectId, dateFrom, toDate) => { // export const useTaskList = (projectId, dateFrom, toDate) => {
const [TaskList, setTaskList] = useState([]); // const [TaskList, setTaskList] = useState([]);
const [loading, setLoading] = useState(false); // const [loading, setLoading] = useState(false);
const [error, setError] = useState(null); // const [error, setError] = useState(null);
const fetchList = async (projectId, dateFrom, toDate) => { // const fetchList = async (projectId, dateFrom, toDate) => {
const taskList_cached = getCachedData("taskList"); // const taskList_cached = getCachedData("taskList");
// if (!taskList_cached || taskList_cached?.projectId !== projectId) { // // if (!taskList_cached || taskList_cached?.projectId !== projectId) {
try { // try {
setLoading(true); // setLoading(true);
const resp = await TasksRepository.getTaskList( // const resp = await TasksRepository.getTaskList(
projectId, // projectId,
dateFrom, // dateFrom,
toDate // toDate
); // );
setTaskList(resp.data); // setTaskList(resp.data);
cacheData("taskList", { projectId: projectId, data: resp.data }); // cacheData("taskList", { projectId: projectId, data: resp.data });
setLoading(false); // setLoading(false);
} catch (err) { // } catch (err) {
setLoading(false); // setLoading(false);
setError(err); // setError(err);
} // }
// } else { // // } else {
// setTaskList(taskList_cached.data); // // setTaskList(taskList_cached.data);
// } // // }
}; // };
useEffect( () => // useEffect( () =>
{ // {
if (projectId && dateFrom && toDate) { // if (projectId && dateFrom && toDate) {
fetchList(projectId, dateFrom, toDate); // fetchList(projectId, dateFrom, toDate);
} // }
}, [projectId, dateFrom, toDate]); // }, [projectId, dateFrom, toDate]);
return { TaskList, loading, error, refetch:fetchList}; // return { TaskList, loading, error, refetch:fetchList};
// };
// export const useTaskById = (TaskId) =>
// {
// const [Task, setTask] = useState([]);
// const [loading, setLoading] = useState(false);
// const [ error, setError ] = useState( null );
// const fetchTask = async(TaskId) =>
// {
// try
// {
// let res = await TasksRepository.getTaskById( TaskId );
// setTask( res.data );
// } catch ( error )
// {
// setError(err)
// }
// }
// useEffect( () =>
// {
// if ( TaskId )
// {
// fetchTask(TaskId)
// }
// }, [ TaskId ] )
// return { Task,loading}
// }
// export const useAuditStatus = () =>
// {
// const [ status, setStatus ] = useState( [] );
// const [ error, setError ] = useState( '' );
// const [ loading, setLoading ] = useState( false )
// const fetchStatus = async() =>
// {
// try
// {
// const res = await MasterRespository.getAuditStatus()
// setStatus( res.data )
// cacheData("AuditStatus",res.data)
// } catch ( err )
// {
// setError(err)
// }
// }
// useEffect(() => {
// const cache_status = getCachedData('AuditStatus');
// if (cache_status) {
// setStatus(cache_status);
// } else {
// fetchStatus();
// }
// }, []);
// return {status,error,loading}
// }
// ---------Query---------------------------------
export const useTaskList = (projectId, dateFrom, toDate) => {
const enabled = !!projectId && !!dateFrom && !!toDate;
const {
data: TaskList = [],
isLoading: loading,
error,
refetch,
} = useQuery({
queryKey: ["taskList", projectId, dateFrom, toDate],
queryFn: async () => {
const response = await TasksRepository.getTaskList(
projectId,
dateFrom,
toDate
);
return response.data;
},
enabled,
});
return { TaskList, loading, error, refetch };
};
export const useTaskById = (TaskId) => {
const {
data: Task = null,
isLoading: loading,
error,
refetch,
} = useQuery({
queryKey: ["taskDetails", TaskId],
queryFn: async () => {
const res = await TasksRepository.getTaskById(TaskId);
return res.data;
},
enabled: !!TaskId,
});
return { Task, loading, error, refetch };
};
// export const useActivities = () => {
// return useQuery({
// queryKey: ["activitiesMaster"],
// queryFn: async () => {
// const response = await ActivityRepository.getActivities();
// return response.data;
// },
// });
// };
export const useAuditStatus = () => {
const {
data: status = [],
isLoading: loading,
error,
refetch,
} = useQuery({
queryKey: ["AuditStatus"],
queryFn: async () => {
const res = await MasterRespository.getAuditStatus();
return res.data;
},
});
return { status, loading, error, refetch };
}; };
export const useTaskById = (TaskId) => // -----------------------Mutation------------------------
const toDate = new Date().toISOString().split('T')[0];
const dateFrom = new Date(Date.now() - 6 * 24 * 60 * 60 * 1000).toISOString().split('T')[0];
export const useReportTask = ( {onSuccessCallback, onErrorCallback} = {} ) =>
{ {
const [Task, setTask] = useState([]); const queryClient = useQueryClient();
const [loading, setLoading] = useState(false); const {
const [ error, setError ] = useState( null ); mutate,
isPending,
isSuccess,
isError,
error,
} = useMutation({
mutationFn: async (reportData) => {
return await TasksRepository.reportTask(reportData);
},
onSuccess: (data) => {
showToast( "Task Reported Successfully.", "success" );
queryClient.invalidateQueries({ queryKey: ["taskList"] });
if (onSuccessCallback) onSuccessCallback(data);
},
onError: (error) => {
const msg =
error?.response?.data?.message || error.message || "Error occurred during API call";
showToast( msg, "error" );
if (onErrorCallback) onErrorCallback(error);
},
});
return {
mutate,
isPending,
isSuccess,
isError,
error,
};
};
const fetchTask = async(TaskId) => export const useSubmitTaskComment = ({ actionAllow, onSuccessCallback }) => {
{ const queryClient = useQueryClient();
try const { mutate, isPending } = useMutation({
{ mutationFn: async ({ data, commentsData }) => {
let res = await TasksRepository.getTaskById( TaskId ); const payload = {
setTask( res.data ); ...data,
[actionAllow ? "id" : "taskAllocationId"]: commentsData?.id,
} catch ( error ) ...(actionAllow ? {} : { commentDate: new Date().toISOString() }),
{ };
setError(err)
}
}
useEffect( () =>
{
if ( TaskId )
{
fetchTask(TaskId)
}
}, [ TaskId ] )
return { Task,loading}
}
export const useAuditStatus = () => const response = actionAllow
? await TasksRepository.auditTask(payload)
: await TasksRepository.taskComments(payload);
return response.data;
},
onSuccess: ( data ) =>
{
queryClient.invalidateQueries({ queryKey: ["taskList"] });
if (actionAllow) {
showToast("Review submitted successfully.", "success");
} else
{
showToast("Comment sent successfully.", "success");
}
onSuccessCallback?.(data);
},
onError: (error) => {
const msg = error?.response?.data?.message || error.message || "Error during API call";
showToast(msg, "error");
},
});
return { submitComment: mutate, isPending };
};
export const useCreateTask = ( {onSuccessCallback, onErrorCallback} = {} ) =>
{ {
const [ status, setStatus ] = useState( [] ); const queryClient = useQueryClient();
const [ error, setError ] = useState( '' ); return useMutation({
const [ loading, setLoading ] = useState( false ) mutationFn: async (payload) => {
return await TasksRepository.assignTask(payload);
const fetchStatus = async() => },
{ onSuccess: ( _, variables ) =>
try
{ {
const res = await MasterRespository.getAuditStatus() queryClient.invalidateQueries({ queryKey: ["taskList"] });
setStatus( res.data ) showToast("Task Assigned Successfully.", "success");
cacheData("AuditStatus",res.data) if (onSuccessCallback) onSuccessCallback(variables);
} catch ( err ) },
onError: ( error ) =>
{ {
setError(err) showToast("Something went wrong. Please try again.", "error");
} if (onErrorCallback) onErrorCallback(error);
} },
useEffect(() => { });
const cache_status = getCachedData('AuditStatus'); };
if (cache_status) {
setStatus(cache_status);
} else {
fetchStatus();
}
}, []);
return {status,error,loading}
}

View File

@ -9,7 +9,7 @@ import ReportTaskComments from "../../components/Activities/ReportTaskComments";
import DateRangePicker from "../../components/common/DateRangePicker"; import DateRangePicker from "../../components/common/DateRangePicker";
import { useSearchParams } from "react-router-dom"; import { useSearchParams } from "react-router-dom";
import moment from "moment"; import moment from "moment";
import FilterIcon from "../../components/common/FilterIcon"; // Import the FilterIcon component import FilterIcon from "../../components/common/FilterIcon";
import GlobalModel from "../../components/common/GlobalModel"; import GlobalModel from "../../components/common/GlobalModel";
import AssignTask from "../../components/Project/AssignTask"; import AssignTask from "../../components/Project/AssignTask";
import SubTask from "../../components/Activities/SubTask"; import SubTask from "../../components/Activities/SubTask";
@ -20,14 +20,14 @@ const DailyTask = () => {
const selectedProject = useSelector( const selectedProject = useSelector(
(store) => store.localVariables.projectId (store) => store.localVariables.projectId
); );
const { // const {
projects, // projects,
loading: project_loading, // loading: project_loading,
error: projects_Error, // error: projects_Error,
} = useProjects(); // } = useProjects();
const [initialized, setInitialized] = useState(false); // const [initialized, setInitialized] = useState(false);
const dispatch = useDispatch(); // const dispatch = useDispatch();
const [filters, setFilters] = useState({ const [filters, setFilters] = useState({
selectedBuilding: "", selectedBuilding: "",
@ -35,23 +35,23 @@ const DailyTask = () => {
selectedActivities: [], selectedActivities: [],
}); });
useEffect(() => { // useEffect(() => {
if (!project_loading && projects.length > 0 && !initialized) { // if (!project_loading && projects.length > 0 && !initialized) {
if (projectIdFromUrl) { // if (projectIdFromUrl) {
dispatch(setProjectId(projectIdFromUrl)); // dispatch(setProjectId(projectIdFromUrl));
} else if (selectedProject === 1 || selectedProject === undefined) { // } else if (selectedProject === 1 || selectedProject === undefined) {
dispatch(setProjectId(projects[0].id)); // dispatch(setProjectId(projects[0].id));
} // }
setInitialized(true); // setInitialized(true);
} // }
}, [ // }, [
project_loading, // project_loading,
projects, // projects,
projectIdFromUrl, // projectIdFromUrl,
selectedProject, // selectedProject,
initialized, // initialized,
dispatch, // dispatch,
]); // ]);
const [dateRange, setDateRange] = useState({ startDate: "", endDate: "" }); const [dateRange, setDateRange] = useState({ startDate: "", endDate: "" });
@ -61,10 +61,11 @@ const DailyTask = () => {
error: task_error, error: task_error,
refetch, refetch,
} = useTaskList( } = useTaskList(
initialized ? selectedProject : null, selectedProject || null,
initialized ? dateRange.startDate : null, dateRange?.startDate || null,
initialized ? dateRange.endDate : null dateRange?.endDate || null
); );
const [TaskLists, setTaskLists] = useState([]); const [TaskLists, setTaskLists] = useState([]);
const [dates, setDates] = useState([]); const [dates, setDates] = useState([]);
@ -83,8 +84,8 @@ const DailyTask = () => {
} }
if (filters.selectedFloors.length > 0) { if (filters.selectedFloors.length > 0) {
filteredTasks = filteredTasks.filter((task) => filteredTasks = filteredTasks?.filter((task) =>
filters.selectedFloors.includes( filters.selectedFloors?.includes(
task?.workItem?.workArea?.floor?.floorName task?.workItem?.workArea?.floor?.floorName
) )
); );
@ -103,9 +104,9 @@ const DailyTask = () => {
} }
}, [ }, [
TaskList, TaskList,
filters.selectedBuilding, filters?.selectedBuilding,
filters.selectedFloors, filters?.selectedFloors,
filters.selectedActivities, filters?.selectedActivities,
]); ]);
useEffect(() => { useEffect(() => {
@ -150,43 +151,41 @@ const DailyTask = () => {
const handlecloseModal = () => const handlecloseModal = () =>
{ {
setIsModalOpen( false ) setIsModalOpen( false )
refetch(selectedProject, dateRange.startDate, dateRange.endDate); // refetch();
} }
const handleProjectChange = (e) => { // const handleProjectChange = (e) => {
const newProjectId = e.target.value; // const newProjectId = e.target.value;
dispatch(setProjectId(newProjectId)); // dispatch(setProjectId(newProjectId));
setTaskLists([]); // setTaskLists([]);
setFilters({ // setFilters({
selectedBuilding: "", // selectedBuilding: "",
selectedFloors: [], // selectedFloors: [],
selectedActivities: [], // selectedActivities: [],
}); // });
}; // };
const handleCloseAction = (IsSubTask) => { const handleCloseAction = (IsSubTask) => {
if (IsSubTask) { if (IsSubTask) {
setIsSubTaskNeeded(true); setIsSubTaskNeeded(true);
setIsModalOpenComment(false); setIsModalOpenComment(false);
} else { } else {
refetch(selectedProject, dateRange.startDate, dateRange.endDate); // refetch();
setIsModalOpenComment(false); setIsModalOpenComment(false);
} }
}; };
const hanleCloseSubTask = () => { const hanleCloseSubTask = () => {
setIsSubTaskNeeded(false); setIsSubTaskNeeded(false);
setComment( null ); setComment( null );
refetch(selectedProject, dateRange.startDate, dateRange.endDate); // refetch();
}; };
return ( return (
<> <>
{isModalOpen && <GlobalModel isOpen={isModalOpen} size="md" closeModal={handlecloseModal} > {isModalOpen && <GlobalModel isOpen={isModalOpen} size="md" closeModal={handlecloseModal} >
<ReportTask <ReportTask
report={selectedTask} report={selectedTask}
closeModal={handlecloseModal} closeModal={handlecloseModal}
refetch={refetch} // refetch={refetch}
/> />
</GlobalModel>} </GlobalModel>}
@ -255,7 +254,7 @@ const DailyTask = () => {
</thead> </thead>
<tbody className="table-border-bottom-0"> <tbody className="table-border-bottom-0">
{/* --- Spinner when tasks are loading --- */} {/* --- Spinner when tasks are loading --- */}
{(task_loading || project_loading) && ( {task_loading && (
<tr> <tr>
<td colSpan={6} className="text-center"> <td colSpan={6} className="text-center">
{" "} {" "}
@ -272,7 +271,6 @@ const DailyTask = () => {
</tr> </tr>
)} )}
{!task_loading && {!task_loading &&
!project_loading &&
TaskLists.length === 0 && ( TaskLists.length === 0 && (
<tr> <tr>
<td colSpan={6} className="text-center"> <td colSpan={6} className="text-center">
@ -413,7 +411,7 @@ const DailyTask = () => {
} more`} } more`}
> >
<span className="avatar-initial rounded-circle bg-label-secondary pull-up"> <span className="avatar-initial rounded-circle bg-label-secondary pull-up">
+{task.teamMembers.length - 3} + {task.teamMembers.length - 3}
</span> </span>
</div> </div>
)} )}

View File

@ -1,110 +1,9 @@
import React, { useState, useEffect } from "react"; import React from "react";
import "../../components/Project/ProjectInfra.css";
import ProjectRepository from "../../repositories/ProjectRepository";
import Breadcrumb from "../../components/common/Breadcrumb"; import Breadcrumb from "../../components/common/Breadcrumb";
import InfraPlanning from "../../components/Activities/InfraPlanning"; import InfraPlanning from "../../components/Activities/InfraPlanning";
import { cacheData, getCachedData } from "../../slices/apiDataManager";
import { useProfile } from "../../hooks/useProfile";
import { useDispatch, useSelector } from "react-redux";
import { useProjectDetails, useProjects } from "../../hooks/useProjects";
import { setProjectId } from "../../slices/localVariablesSlice";
import showToast from "../../services/toastService";
const TaskPlannng = () => { const TaskPlannng = () => {
const { profile } = useProfile();
const {
projects,
loading: project_listLoader,
error: projects_error,
} = useProjects();
const dispatch = useDispatch();
const selectedProject = useSelector(
(store) => store.localVariables.projectId
);
const [project, setProject] = useState(null);
const [projectDetails, setProjectDetails] = useState(null);
const [activities, setActivities] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState("");
const fetchActivities = async () => {
try {
const activities_cache = getCachedData("activitiesMaster");
if (!activities_cache) {
ActivityeRepository.getActivities()
.then((response) => {
setActivities(response.data);
cacheData("activitiesMaster", response.data);
})
.catch((error) => {
setError("Failed to fetch data.");
});
} else {
setActivities(activities_cache);
}
} catch (err) {
setError("Failed to fetch activities.");
} finally {
// setLoading(false);
}
};
const fetchData = async () => {
try {
const project_cache = getCachedData("projectInfo");
if (!project_cache || !project_cache.projectId == selectedProject) {
ProjectRepository.getProjectByprojectId(selectedProject)
.then((response) => {
setProjectDetails(response);
setProject(response);
cacheData("projectInfo", {
data: response.data,
projectId: selectedProject,
});
})
.catch((error) => {
const message =
error.response?.data?.message ||
error.message ||
"An unexpected error occurred";
showToast( message, "error" );
});
} else {
setProjectDetails(project_cache);
}
} catch (err) {
setError( "Failed to fetch data." );
const message =
error.response?.data?.message ||
error.message ||
"An unexpected error occurred";
showToast( message, "error" );
} finally {
setLoading(false);
}
};
const [activePill, setActivePill] = useState("profile");
const handlePillClick = (pillKey) => {
setActivePill(pillKey);
};
const handleDataChange = (data) => {
fetchData();
};
useEffect(() => {
if (projects.length != 0 && selectedProject) {
fetchData();
fetchActivities();
}
}, [selectedProject]);
return ( return (
<> <>
@ -115,17 +14,7 @@ const TaskPlannng = () => {
{ label: "Daily Task Planning", link: "/activities/task" }, { label: "Daily Task Planning", link: "/activities/task" },
]} ]}
></Breadcrumb> ></Breadcrumb>
{project_listLoader && <p>Loading..</p>} <InfraPlanning/>
{!project_listLoader && projects.length === 0 && (
<p>No Project Found.</p>
)}
{!project_listLoader && projects.length > 0 && (
<InfraPlanning
data={projectDetails}
activityMaster={activities}
onDataChange={handleDataChange}
/>
)}
</div> </div>
</> </>
); );

View File

@ -8,7 +8,8 @@ import showToast from "./toastService";
import eventBus from "./eventBus"; import eventBus from "./eventBus";
import { useSelector } from "react-redux"; import { useSelector } from "react-redux";
import { clearApiCacheKey } from "../slices/apiCacheSlice"; import { clearApiCacheKey } from "../slices/apiCacheSlice";
import { BASE_URL } from "../utils/constants"; import {BASE_URL} from "../utils/constants";
import { queryClient } from "../layouts/AuthLayout";
const base_Url = BASE_URL; const base_Url = BASE_URL;
let connection = null; let connection = null;
@ -57,7 +58,8 @@ export function startSignalR(loggedUser) {
data.keyword == "Create_Project" || data.keyword == "Create_Project" ||
data.keyword == "Update_Project" data.keyword == "Update_Project"
) { ) {
clearCacheKey("projectslist"); // clearCacheKey("projectslist");
queryClient.invalidateQueries(['projectslist']);
eventBus.emit("project", data); eventBus.emit("project", data);
} }
@ -83,13 +85,22 @@ export function startSignalR(loggedUser) {
// if created or updated Employee // if created or updated Employee
if (data.keyword == "Employee") { if (data.keyword == "Employee") {
clearCacheKey("employeeListByProject"); // clearCacheKey("employeeListByProject");
clearCacheKey("allEmployeeList"); // clearCacheKey("allEmployeeList");
clearCacheKey("allInactiveEmployeeList"); // clearCacheKey("allInactiveEmployeeList");
clearCacheKey("employeeProfile"); // clearCacheKey("employeeProfile");
clearCacheKey("Attendance"); clearCacheKey("Attendance");
clearCacheKey("regularizedList") clearCacheKey("regularizedList")
clearCacheKey("AttendanceLogs") clearCacheKey("AttendanceLogs")
// ---we can do also----
// queryClient.removeQueries(['allEmployee', true]);
// but best practies is refetch
queryClient.invalidateQueries(['allEmployee', true]);
queryClient.invalidateQueries(['allEmployee', false]);
queryClient.invalidateQueries(['employeeProfile', data.response?.employeeId]);
queryClient.invalidateQueries(['employeeListByProject']); // optional if scope
queryClient
eventBus.emit("employee", data); eventBus.emit("employee", data);
} }
} }