From c1be1dafc807f6cbeab21515d4d1e831554f63b0 Mon Sep 17 00:00:00 2001 From: Kartik Sharma Date: Thu, 13 Nov 2025 17:45:05 +0530 Subject: [PATCH 1/4] Changes in Payment Request List view adding Due Date, Created at and Payee. --- .../PaymentRequest/PaymentRequestList.jsx | 90 ++++++++++--------- .../PaymentRequest/ViewPaymentRequest.jsx | 2 +- 2 files changed, 51 insertions(+), 41 deletions(-) diff --git a/src/components/PaymentRequest/PaymentRequestList.jsx b/src/components/PaymentRequest/PaymentRequestList.jsx index d7143939..f97171b4 100644 --- a/src/components/PaymentRequest/PaymentRequestList.jsx +++ b/src/components/PaymentRequest/PaymentRequestList.jsx @@ -44,9 +44,8 @@ const PaymentRequestList = ({ filters, groupBy = "submittedBy", search }) => { displayField = "Status"; break; case "submittedBy": - key = `${item?.createdBy?.firstName ?? ""} ${ - item.createdBy?.lastName ?? "" - }`.trim(); + key = `${item?.createdBy?.firstName ?? ""} ${item.createdBy?.lastName ?? "" + }`.trim(); displayField = "Submitted By"; break; case "project": @@ -93,40 +92,52 @@ const PaymentRequestList = ({ filters, groupBy = "submittedBy", search }) => { align: "text-start", getValue: (e) => e.title || "N/A", }, - // { key: "payee", label: "Payee", align: "text-start" }, - { - key: "SubmittedBy", - label: "Submitted By", - align: "text-start", - getValue: (e) => - `${e.createdBy?.firstName ?? ""} ${ - e.createdBy?.lastName ?? "" - }`.trim() || "N/A", - customRender: (e) => ( -
navigate(`/employee/${e.createdBy?.id}`)} - > - - - {`${e.createdBy?.firstName ?? ""} ${ - e.createdBy?.lastName ?? "" - }`.trim() || "N/A"} - -
- ), - }, + // { + // key: "SubmittedBy", + // label: "Submitted By", + // align: "text-start", + // getValue: (e) => + // `${e.createdBy?.firstName ?? ""} ${ + // e.createdBy?.lastName ?? "" + // }`.trim() || "N/A", + // customRender: (e) => ( + //
navigate(`/employee/${e.createdBy?.id}`)} + // > + // + // + // {`${e.createdBy?.firstName ?? ""} ${ + // e.createdBy?.lastName ?? "" + // }`.trim() || "N/A"} + // + //
+ // ), + // }, { key: "createdAt", - label: "Submitted On", + label: "Created At", align: "text-start", getValue: (e) => formatUTCToLocalTime(e?.createdAt), }, + { + key: "payee", + label: "Payee", + align: "text-start", + getValue: (e) => e.payee || "N/A", + }, + { + key: "dueDate", + label: "Due Date", + align: "text-start", + getValue: (e) => formatUTCToLocalTime(e?.dueDate), + }, + { key: "amount", label: "Amount", @@ -143,9 +154,8 @@ const PaymentRequestList = ({ filters, groupBy = "submittedBy", search }) => { align: "text-center", getValue: (e) => ( {e?.expenseStatus?.name || "Unknown"} @@ -171,8 +181,8 @@ const PaymentRequestList = ({ filters, groupBy = "submittedBy", search }) => { const header = [ "Request ID", "Request Title", - "Submitted By", - "Submitted On", + "Created At", + "Due Date", "Amount", "Status", "Action", @@ -181,10 +191,10 @@ const PaymentRequestList = ({ filters, groupBy = "submittedBy", search }) => { const grouped = groupBy ? Object.fromEntries( - Object.entries(groupByField(data?.data ?? [], groupBy)).sort( - ([keyA], [keyB]) => keyA.localeCompare(keyB) - ) + Object.entries(groupByField(data?.data ?? [], groupBy)).sort( + ([keyA], [keyB]) => keyA.localeCompare(keyB) ) + ) : { All: data?.data ?? [] }; const IsGroupedByDate = [ diff --git a/src/components/PaymentRequest/ViewPaymentRequest.jsx b/src/components/PaymentRequest/ViewPaymentRequest.jsx index c1e6170e..878b37fb 100644 --- a/src/components/PaymentRequest/ViewPaymentRequest.jsx +++ b/src/components/PaymentRequest/ViewPaymentRequest.jsx @@ -199,7 +199,7 @@ const ViewPaymentRequest = ({ requestId }) => {
From 844a6f59d1547e1ee8ffb0904465a152673800ca Mon Sep 17 00:00:00 2001 From: "pramod.mahajan" Date: Thu, 13 Nov 2025 19:50:19 +0530 Subject: [PATCH 2/4] added fetch api of jobs --- src/components/ServiceProject/JobList.jsx | 141 +++++++++++++++ src/components/ServiceProject/Jobs.jsx | 54 +++++- src/components/ServiceProject/ManageJob.jsx | 170 +++++++++++++++++- .../ServiceProject/ServiceProjectNav.jsx | 1 + .../ServiceProject/ServiceProjectSchema.jsx | 34 ++++ src/components/common/EmployeeAvatarGroup.jsx | 91 ++++++++++ src/components/common/HoverPopup.jsx | 16 +- src/components/common/TagInput.jsx | 8 +- src/hooks/useServiceProject.jsx | 42 ++++- src/repositories/ServiceProject.jsx | 10 -- src/repositories/ServiceProjectRepository.jsx | 22 +++ src/utils/appUtils.js | 17 ++ 12 files changed, 563 insertions(+), 43 deletions(-) create mode 100644 src/components/ServiceProject/JobList.jsx create mode 100644 src/components/common/EmployeeAvatarGroup.jsx delete mode 100644 src/repositories/ServiceProject.jsx create mode 100644 src/repositories/ServiceProjectRepository.jsx diff --git a/src/components/ServiceProject/JobList.jsx b/src/components/ServiceProject/JobList.jsx new file mode 100644 index 00000000..f3f79b5f --- /dev/null +++ b/src/components/ServiceProject/JobList.jsx @@ -0,0 +1,141 @@ +import React from "react"; +import { getNextBadgeColor } from "../../utils/appUtils"; +import { useServiceProjectJobs } from "../../hooks/useServiceProject"; +import { ITEMS_PER_PAGE } from "../../utils/constants"; +import EmployeeAvatarGroup from "../common/EmployeeAvatarGroup"; +import { formatUTCToLocalTime } from "../../utils/dateUtils"; +import { SpinnerLoader } from "../common/Loader"; +import { useParams } from "react-router-dom"; + +const JobList = ({ filterByProject }) => { + const { id } = useParams(); + const { data, isLoading, isError, error } = useServiceProjectJobs( + ITEMS_PER_PAGE, + 1, + true, + filterByProject ?? id + ); + + const jobGrid = [ + { + key: "title", + label: "Title", + getValue: (e) => ( + + {e?.title} + + ), + isAlwaysVisible: true, + className: "text-start", + }, + { + key: "project", + label: "Project", + getValue: (e) =>
{e?.project?.name}
, + isAlwaysVisible: true, + className: "text-start d-none d-sm-table-cell", + }, + + { + key: "employee", + label: "Team", + getValue: (e) => , + isAlwaysVisible: true, + className: "text-start d-none d-sm-table-cell", + }, + + { + key: "startDate", + label: "Start Date", + getValue: (e) => formatUTCToLocalTime(e.startDate), + isAlwaysVisible: true, + className: "text-center ", + }, + { + key: "dueDate", + label: "Due To", + getValue: (e) => formatUTCToLocalTime(e.startDate), + isAlwaysVisible: true, + className: "text-center d-none d-sm-table-cell", + }, + ]; + + return ( +
+ + + + {jobGrid.map((col) => ( + + ))} + + + + + + {Array.isArray(data?.data) && data.data.length > 0 ? ( + data.data.map((row, i) => ( + + {jobGrid.map((col) => ( + + ))} + + + )) + ) : ( + + + + )} + +
+
{col.label}
+
+ Actions +
+ {col.getValue(row)} + +
+ +
+ {/* View always visible */} + + + <> + + +
+
+
+ {isLoading ? : "Not Found Jobs."} +
+
+ ); +}; + +export default JobList; diff --git a/src/components/ServiceProject/Jobs.jsx b/src/components/ServiceProject/Jobs.jsx index 7b71a465..88bfc902 100644 --- a/src/components/ServiceProject/Jobs.jsx +++ b/src/components/ServiceProject/Jobs.jsx @@ -1,11 +1,49 @@ -import React from 'react' +import React, { useEffect, useState } from "react"; +import JobList from "./JobList"; +import { useNavigate } from "react-router-dom"; +import { useServiceProjects } from "../../hooks/useServiceProject"; +import { ITEMS_PER_PAGE } from "../../utils/constants"; const Jobs = () => { - return ( -
-
-
- ) -} + const [selectedProject, setSelectedProject] = useState(null); + const navigate = useNavigate(); -export default Jobs + const { data } = useServiceProjects(ITEMS_PER_PAGE, 1); + return ( +
+
+
+
+ {" "} + +
+
+ +
+
+ + +
+
+ ); +}; + +export default Jobs; diff --git a/src/components/ServiceProject/ManageJob.jsx b/src/components/ServiceProject/ManageJob.jsx index e8917c04..55b54239 100644 --- a/src/components/ServiceProject/ManageJob.jsx +++ b/src/components/ServiceProject/ManageJob.jsx @@ -1,9 +1,72 @@ -import React from 'react' -import Breadcrumb from '../common/Breadcrumb' +import React from "react"; +import Breadcrumb from "../common/Breadcrumb"; +import Label from "../common/Label"; +import { FormProvider, useForm } from "react-hook-form"; +import { zodResolver } from "@hookform/resolvers/zod"; +import { defaultJobValue, jobSchema } from "./ServiceProjectSchema"; +import { + useCreateServiceProjectJob, + useServiceProjects, +} from "../../hooks/useServiceProject"; +import { ITEMS_PER_PAGE } from "../../utils/constants"; +import DatePicker from "../common/DatePicker"; +import PmsEmployeeInputTag from "../common/PmsEmployeeInputTag"; +import TagInput from "../common/TagInput"; +import { localToUtc } from "../../utils/appUtils"; const ManageJob = () => { + const methods = useForm({ + resolver: zodResolver(jobSchema), + defaultValues: defaultJobValue, + }); + + const { + register, + control, + watch, + handleSubmit, + reset, + formState: { errors }, + } = methods; + + const { + data, + isLoading: isProjectLoading, + isError: isProjectError, + error, + } = useServiceProjects(ITEMS_PER_PAGE, 1); + + const { mutate: CreateJob, isPending } = useCreateServiceProjectJob(() => { + reset(); + }); + const onSubmit = (formData) => { + // if (serviceProjectId) { + // let existingServiceIds = projectdata?.services?.map((s) => s.id) || []; + + // const oldAssigneed = projectdata.services.map((service) => ({ + // serviceId: service.id, + // isActive: formData.services.includes(service.id), + // })); + + // const newAassigneed = formData.services + // .filter((s) => !existingServiceIds.includes(s)) + // .map((service) => ({ serviceId: service, isActive: true })); + + // formData.assignees = [...oldServices, ...newServices]; + // } + + formData.assignees = formData.assignees.map((emp) => ({ + employeeId: emp, + isActive: true, + })); + + formData.startDate = localToUtc(formData.startDate); + formData.dueDate = localToUtc(formData.dueDate); + CreateJob(formData); + }; + return ( -
+
{ { label: "" || "Jobs", link: null }, ]} /> - +
+
+
+ +
+
+

Create Job

+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ +
+
+ +