270 lines
8.4 KiB
JavaScript

import React, { useState } from "react";
import {
daysLeft,
getJobStatusBadge,
getNextBadgeColor,
} from "../../utils/appUtils";
import { useServiceProjectJobs, useUpdateServiceProjectJob } from "../../hooks/useServiceProject";
import { ITEMS_PER_PAGE, JOBS_STATUS_IDS } from "../../utils/constants";
import EmployeeAvatarGroup from "../common/EmployeeAvatarGroup";
import { formatUTCToLocalTime } from "../../utils/dateUtils";
import { SpinnerLoader } from "../common/Loader";
import { useParams } from "react-router-dom";
import ProjectPage from "../../pages/project/ProjectPage";
import { useServiceProjectJobContext } from "./Jobs";
import ConfirmModal from "../common/ConfirmModal";
const JobList = ({ isArchive }) => {
const { setSelectedJob, setManageJob } = useServiceProjectJobContext();
const { mutate: UpdateJob,isPending } = useUpdateServiceProjectJob(() => {
});
const { projectId } = useParams();
const { data, isLoading, isError, error } = useServiceProjectJobs(
ITEMS_PER_PAGE,
1,
true,
projectId,
isArchive
);
const [isArchiveModalOpen, setIsArchiveModalOpen] = useState(false);
const [archiveJobId, setArchiveJobId] = useState(null);
const [isArchiveAction, setIsArchiveAction] = useState(true);
const handleArchive = () => {
const payload = [
{
op: "replace",
path: "/isArchive",
value: isArchiveAction,
},
];
UpdateJob({
id: archiveJobId,
payload,
isArchiveAction,
});
setIsArchiveModalOpen(false);
setArchiveJobId(null);
};
const jobGrid = [
{
key: "jobTicketUId",
label: "Job Id",
getValue: (e) => <span>{e?.jobTicketUId || "N/A"}</span>,
align: "text-start",
},
{
key: "title",
label: "Title",
getValue: (e) => (
<span
className={`fw-semibold text-truncate d-inline-block ${!isArchive ? "cursor-pointer" : ""}`}
style={{
maxWidth: "100%",
width: "210px",
}}
onClick={() => {
if (!isArchive) {
setSelectedJob({ showCanvas: true, job: e?.id });
}
}}
title={e?.title}
>
{e?.title}
</span>
),
isAlwaysVisible: true,
className: "text-start",
},
{
key: "dueDate",
label: "Due On",
getValue: (e) => formatUTCToLocalTime(e.startDate),
isAlwaysVisible: true,
className: "text-start d-none d-sm-table-cell",
},
{
key: "status",
label: "Status",
getValue: (e) => {
return (
<span className={`badge ${getJobStatusBadge(e?.status?.id)}`}>
{e?.status?.displayName}
</span>
);
},
isAlwaysVisible: true,
className: "text-start d-none d-sm-table-cell",
},
{
key: "daysLeft",
label: "Days Left",
getValue: (e) => {
const { days, color } = daysLeft(e.startDate, e.dueDate);
return (
<span className={`badge bg-${color}`}>
{days !== null ? `${days} days` : "N/A"}
</span>
);
},
isAlwaysVisible: true,
className: "text-start d-none d-sm-table-cell",
},
];
const canArchive = (statusId) => {
const closedId = JOBS_STATUS_IDS.find((s) => s.label === "Closed")?.id;
const reviewDoneId = JOBS_STATUS_IDS.find((s) => s.label === "Review Done")?.id;
return statusId === closedId || statusId === reviewDoneId;
};
return (
<>
{isArchiveModalOpen && (
<ConfirmModal
isOpen={isArchiveModalOpen}
type={isArchiveAction ? "archive" : "Un-archive"}
header={isArchiveAction ? "Archive Job" : "Restore Job"}
message={
isArchiveAction
? "Are you sure you want to archive this job?"
: "Are you sure you want to restore this job?"
}
onSubmit={handleArchive}
onClose={() => setIsArchiveModalOpen(false)}
loading={isPending}
/>
)}
<div className="dataTables_wrapper dt-bootstrap5 no-footer table-responsive">
<table
className="datatables-users table border-top dataTable no-footer dtr-column text-nowrap table-responsive"
aria-describedby="DataTables_Table_0_info"
>
<thead>
<tr>
{jobGrid.map((col) => (
<th
key={col.key}
className={`${col.align || "text-center"} ${col.className || ""
}`}
scope="col"
>
<div className={col.className}>{col.label}</div>
</th>
))}
<th className="sorting_disabled text-center" aria-label="Actions">
Actions
</th>
</tr>
</thead>
<tbody>
{Array.isArray(data?.data) && data.data.length > 0 ? (
data.data.map((row, i) => (
<tr key={i} className="text-start">
{jobGrid.map((col) => (
<td
key={col.key}
className={col.className}
onClick={() => {
if (!isArchive) {
setSelectedJob({ showCanvas: true, job: row?.id });
}
}}
>
{col.getValue(row)}
</td>
))}
<td>
<div className="dropdown text-center">
<button
className="btn btn-icon dropdown-toggle hide-arrow"
data-bs-toggle="dropdown"
>
<i className="bx bx-dots-vertical-rounded bx-md"></i>
</button>
<div className="dropdown-menu dropdown-menu-end">
{!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
className="dropdown-item py-1"
onClick={() => {
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);
}}
>
<i className="bx bx-archive bx-sm"></i> Archive
</button>
)}
</div>
</div>
</td>
</tr>
))
) : (
<tr style={{ height: "200px" }}>
<td
colSpan={jobGrid.length + 1}
className="text-center border-0 align-middle"
>
{isLoading ? <SpinnerLoader /> : "Not Found Jobs."}
</td>
</tr>
)}
</tbody>
</table>
</div>
</>
);
};
export default JobList;