Merge branch 'Project_Branch_Management' of https://git.marcoaiot.com/admin/marco.pms.web into Project_Branch_Management

This commit is contained in:
pramod.mahajan 2025-11-21 12:58:52 +05:30
commit 33d94f6f06
3 changed files with 94 additions and 73 deletions

View File

@ -16,7 +16,7 @@ import ConfirmModal from "../common/ConfirmModal";
const JobList = ({ isArchive }) => { const JobList = ({ isArchive }) => {
const { setSelectedJob, setManageJob } = useServiceProjectJobContext(); const { setSelectedJob, setManageJob } = useServiceProjectJobContext();
const { mutate: UpdateJob } = useUpdateServiceProjectJob(() => { const { mutate: UpdateJob,isPending } = useUpdateServiceProjectJob(() => {
}); });
const { projectId } = useParams(); const { projectId } = useParams();
const { data, isLoading, isError, error } = useServiceProjectJobs( const { data, isLoading, isError, error } = useServiceProjectJobs(
@ -28,28 +28,26 @@ const JobList = ({ isArchive }) => {
); );
const [isArchiveModalOpen, setIsArchiveModalOpen] = useState(false); const [isArchiveModalOpen, setIsArchiveModalOpen] = useState(false);
const [archiveJobId, setArchiveJobId] = useState(null); const [archiveJobId, setArchiveJobId] = useState(null);
const [isArchiveAction, setIsArchiveAction] = useState(true);
const handleArchive = () => { const handleArchive = () => {
const payload = [ const payload = [
{ {
op: "replace", op: "replace",
path: "/isArchive", path: "/isArchive",
value: true, value: isArchiveAction,
}, },
]; ];
UpdateJob({ UpdateJob({
id: archiveJobId, id: archiveJobId,
payload, payload,
isArchiveAction: true, isArchiveAction,
}); });
setIsArchiveModalOpen(false); setIsArchiveModalOpen(false);
setArchiveJobId(null); setArchiveJobId(null);
}; };
const jobGrid = [ const jobGrid = [
{ {
key: "jobTicketUId", key: "jobTicketUId",
@ -62,12 +60,17 @@ const JobList = ({ isArchive }) => {
label: "Title", label: "Title",
getValue: (e) => ( getValue: (e) => (
<span <span
className="fw-semibold text-truncate d-inline-block cursor-pointer" className={`fw-semibold text-truncate d-inline-block ${!isArchive ? "cursor-pointer" : ""}`}
style={{ style={{
maxWidth: "100%", maxWidth: "100%",
width: "210px", width: "210px",
}} }}
onClick={() => setSelectedJob({ showCanvas: true, job: e?.id })} onClick={() => {
if (!isArchive) {
setSelectedJob({ showCanvas: true, job: e?.id });
}
}}
title={e?.title}
> >
{e?.title} {e?.title}
</span> </span>
@ -76,6 +79,7 @@ const JobList = ({ isArchive }) => {
className: "text-start", className: "text-start",
}, },
{ {
key: "dueDate", key: "dueDate",
label: "Due On", label: "Due On",
@ -115,26 +119,30 @@ const JobList = ({ isArchive }) => {
const canArchive = (statusId) => { const canArchive = (statusId) => {
const closedId = JOBS_STATUS_IDS.find((s) => s.label === "Closed")?.id; const closedId = JOBS_STATUS_IDS.find((s) => s.label === "Closed")?.id;
const workDoneId = JOBS_STATUS_IDS.find((s) => s.label === "Work Done")?.id; const reviewDoneId = JOBS_STATUS_IDS.find((s) => s.label === "Review Done")?.id;
return statusId === closedId || statusId === workDoneId; return statusId === closedId || statusId === reviewDoneId;
}; };
return ( return (
<> <>
{isArchiveModalOpen && ( {isArchiveModalOpen && (
<ConfirmModal <ConfirmModal
isOpen={isArchiveModalOpen} isOpen={isArchiveModalOpen}
type="success" type={isArchiveAction ? "success" : "undo"}
header="Archive Job" header={isArchiveAction ? "Archive Job" : "Restore Job"}
message="Are you sure you want to archive this job?" message={
isArchiveAction
? "Are you sure you want to archive this job?"
: "Are you sure you want to restore this job?"
}
onSubmit={handleArchive} onSubmit={handleArchive}
onClose={() => setIsArchiveModalOpen(false)} onClose={() => setIsArchiveModalOpen(false)}
loading={false} loading={isPending}
/> />
)} )}
<div className="dataTables_wrapper dt-bootstrap5 no-footer table-responsive"> <div className="dataTables_wrapper dt-bootstrap5 no-footer table-responsive">
<table <table
@ -167,9 +175,15 @@ const JobList = ({ isArchive }) => {
<td <td
key={col.key} key={col.key}
className={col.className} className={col.className}
onClick={() => // onClick={() =>
setSelectedJob({ showCanvas: true, job: row?.id }) // setSelectedJob({ showCanvas: true, job: row?.id })
} // }
onClick={() => {
if (!isArchive) {
setSelectedJob({ showCanvas: true, job: e?.id });
}
}}
> >
{col.getValue(row)} {col.getValue(row)}
</td> </td>
@ -183,30 +197,48 @@ const JobList = ({ isArchive }) => {
<i className="bx bx-dots-vertical-rounded bx-md"></i> <i className="bx bx-dots-vertical-rounded bx-md"></i>
</button> </button>
<div className="dropdown-menu dropdown-menu-end"> <div className="dropdown-menu dropdown-menu-end">
<button
className="dropdown-item py-1"
onClick={() =>
setSelectedJob({ showCanvas: true, job: row?.id })
}
>
<i className="bx bx-detail bx-sm"></i> View
</button>
<>
<button
className="dropdown-item py-1"
onClick={() =>
setManageJob({ isOpen: true, jobId: row?.id })
}
>
<i className="bx bx-edit bx-sm"></i> Edit
</button>
</>
{canArchive(row?.status?.id) && ( {!isArchive && (
<>
<button
className="dropdown-item py-1"
onClick={() =>
setSelectedJob({ showCanvas: true, job: row?.id })
}
>
<i className="bx bx-detail bx-sm"></i> View
</button>
<button
className="dropdown-item py-1"
onClick={() =>
setManageJob({ isOpen: true, jobId: row?.id })
}
>
<i className="bx bx-edit bx-sm"></i> Edit
</button>
</>
)}
{isArchive && (
<button <button
className="dropdown-item py-1" className="dropdown-item py-1"
onClick={() => { onClick={() => {
setArchiveJobId(row.id); setArchiveJobId(row.id);
setIsArchiveAction(false);
setIsArchiveModalOpen(true);
}}
>
<i className="bx bx-reset bx-sm"></i> Restore
</button>
)}
{!isArchive && canArchive(row?.status?.id) && (
<button
className="dropdown-item py-1"
onClick={() => {
setArchiveJobId(row.id);
setIsArchiveAction(true);
setIsArchiveModalOpen(true); setIsArchiveModalOpen(true);
}} }}
> >
@ -215,6 +247,7 @@ const JobList = ({ isArchive }) => {
)} )}
</div> </div>
</div> </div>
</td> </td>
</tr> </tr>

View File

@ -63,37 +63,25 @@ const Jobs = () => {
<div className="row align-items-center py-4"> <div className="row align-items-center py-4">
{/* LEFT — Tabs */} {/* LEFT — Tabs */}
<div className="col-12 col-md-6"> <div className="col-12 col-md-6 text-start">
<ul className="nav nav-pills" role="tablist"> <button
type="button"
<li className="nav-item"> className={`btn btn-sm ${showArchive ? "btn-primary" : "btn-outline-secondary"}`}
<button onClick={() => setShowArchive(!showArchive)}
type="button" style={{ fontSize: "13px" }}
className={`nav-link px-2 py-2 ${!showArchive ? "active" : ""}`} >
role="tab" {showArchive ? (
onClick={() => setShowArchive(false)} <>
style={{ fontSize: "13px" }} <i className="bx bx-list-ul me-1 mt-1"></i> Show Active Jobs
> </>
Active Jobs ) : (
</button> <>
</li> <i className="bx bx-archive me-1 mt-1"></i> Show Archived Jobs
</>
<li className="nav-item"> )}
<button </button>
type="button"
className={`nav-link px-2 py-2 ${showArchive ? "active" : ""}`}
role="tab"
onClick={() => setShowArchive(true)}
style={{ fontSize: "13px" }}
>
Archived Jobs
</button>
</li>
</ul>
</div> </div>
{/* RIGHT — New Job button */} {/* RIGHT — New Job button */}
<div className="col-12 col-md-6 d-flex justify-content-md-end mt-2 mt-md-0"> <div className="col-12 col-md-6 d-flex justify-content-md-end mt-2 mt-md-0">
<button <button

View File

@ -264,7 +264,6 @@ export const useCreateServiceProjectJob = (onSuccessCallback) => {
export const useUpdateServiceProjectJob = (onSuccessCallback) => { export const useUpdateServiceProjectJob = (onSuccessCallback) => {
const queryClient = useQueryClient(); const queryClient = useQueryClient();
return useMutation({ return useMutation({
mutationFn: async ({ id, payload, isArchiveAction = false }) => { mutationFn: async ({ id, payload, isArchiveAction = false }) => {
const resp = await ServiceProjectRepository.UpdateJob(id, payload); const resp = await ServiceProjectRepository.UpdateJob(id, payload);
@ -281,10 +280,11 @@ export const useUpdateServiceProjectJob = (onSuccessCallback) => {
if (isArchiveAction) { if (isArchiveAction) {
showToast("Job archived successfully", "success"); showToast("Job archived successfully", "success");
} else { } else {
showToast("Job Updated successfully", "success"); showToast("Job restored successfully", "success");
} }
}, },
onError: (error) => { onError: (error) => {
showToast( showToast(
error?.response?.data?.message || error?.response?.data?.message ||
@ -336,10 +336,10 @@ export const useBranches = (
}); });
}; };
export const useBranchTypes = ()=>{ export const useBranchTypes = () => {
return useQuery({ return useQuery({
queryKey:["branch_Type"], queryKey: ["branch_Type"],
queryFn:async()=> { queryFn: async () => {
const resp = await ServiceProjectRepository.GetBranchTypeList(); const resp = await ServiceProjectRepository.GetBranchTypeList();
return resp.data; return resp.data;
}, },
@ -409,9 +409,9 @@ export const useDeleteBranch = () => {
mutationFn: async ({ id, isActive }) => mutationFn: async ({ id, isActive }) =>
await ServiceProjectRepository.DeleteBranch(id, isActive), await ServiceProjectRepository.DeleteBranch(id, isActive),
onSuccess: (_,variable) => { onSuccess: (_, variable) => {
queryClient.invalidateQueries({ queryKey: ["branches"] }); queryClient.invalidateQueries({ queryKey: ["branches"] });
showToast(`Branch ${variable.isActive ? "restored":"deleted"} successfully`, "success"); showToast(`Branch ${variable.isActive ? "restored" : "deleted"} successfully`, "success");
}, },
onError: (error) => { onError: (error) => {