From 9822ae91ece024b16ecd75dafd00d2f09a7f1772 Mon Sep 17 00:00:00 2001 From: Kartik Sharma Date: Tue, 18 Nov 2025 15:56:16 +0530 Subject: [PATCH 01/58] Adding AdvancePayment a list view. --- .../AdvancePayment/AdvancePaymentList.jsx | 17 +++++++---- .../AdvancePayment/AdvancePaymentList1.jsx | 16 ++++++++++ src/hooks/useExpense.js | 9 ++++++ .../AdvancePayment/AdvancePaymentPage.jsx | 10 ++++--- .../AdvancePayment/AdvancePaymentPage1.jsx | 29 +++++++++++++++++++ src/repositories/ExpsenseRepository.jsx | 8 +++-- src/router/AppRoutes.jsx | 3 +- 7 files changed, 78 insertions(+), 14 deletions(-) create mode 100644 src/components/AdvancePayment/AdvancePaymentList1.jsx create mode 100644 src/pages/AdvancePayment/AdvancePaymentPage1.jsx diff --git a/src/components/AdvancePayment/AdvancePaymentList.jsx b/src/components/AdvancePayment/AdvancePaymentList.jsx index e9113b48..5aef0de7 100644 --- a/src/components/AdvancePayment/AdvancePaymentList.jsx +++ b/src/components/AdvancePayment/AdvancePaymentList.jsx @@ -1,6 +1,6 @@ import React, { useEffect, useMemo } from "react"; -import { useExpenseTransactions } from "../../hooks/useExpense"; +import { useExpenseAllTransactionsList, useExpenseTransactions } from "../../hooks/useExpense"; import Error from "../common/Error"; import { formatUTCToLocalTime } from "../../utils/dateUtils"; import Loader, { SpinnerLoader } from "../common/Loader"; @@ -11,11 +11,16 @@ import { employee } from "../../data/masters"; import { useAdvancePaymentContext } from "../../pages/AdvancePayment/AdvancePaymentPage"; import { formatFigure } from "../../utils/appUtils"; -const AdvancePaymentList = ({ employeeId }) => { - const { setBalance } = useAdvancePaymentContext(); +const AdvancePaymentList = ({ employeeId, searchString }) => { + const { setBalance } = useAdvancePaymentContext(); const { data, isError, isLoading, error, isFetching } = useExpenseTransactions(employeeId, { enabled: !!employeeId }); + const { data: getAllData } = + useExpenseAllTransactionsList(searchString ?? ""); + + console.log("Kartik", getAllData) + const records = Array.isArray(data) ? data : []; let currentBalance = 0; @@ -85,7 +90,7 @@ const AdvancePaymentList = ({ employeeId }) => { key: "date", label: ( <> - Date + Date ), align: "text-start", @@ -154,8 +159,8 @@ const AdvancePaymentList = ({ employeeId }) => { - {Array.isArray(data) && data.length > 0 ? ( - data.map((row) => ( + {Array.isArray(getAllData) && getAllData.length > 0 ? ( + getAllData.map((row) => ( {columns.map((col) => ( diff --git a/src/components/AdvancePayment/AdvancePaymentList1.jsx b/src/components/AdvancePayment/AdvancePaymentList1.jsx new file mode 100644 index 00000000..9e5fb3e5 --- /dev/null +++ b/src/components/AdvancePayment/AdvancePaymentList1.jsx @@ -0,0 +1,16 @@ +import React from 'react' +import { useExpenseAllTransactionsList } from '../../hooks/useExpense'; + +const AdvancePaymentList1 = ({searchString}) => { + const { data, isError, isLoading, error, isFetching } = + useExpenseAllTransactionsList(); + return ( +
+
+ +
+
+ ) +} + +export default AdvancePaymentList1 diff --git a/src/hooks/useExpense.js b/src/hooks/useExpense.js index bc5c1da4..539f0afd 100644 --- a/src/hooks/useExpense.js +++ b/src/hooks/useExpense.js @@ -438,6 +438,15 @@ export const useExpenseTransactions = (employeeId)=>{ keepPreviousData:true, }) } +export const useExpenseAllTransactionsList = (searchString) => { + return useQuery({ + queryKey: ["transaction", searchString], + queryFn: async () => { + const resp = await ExpenseRepository.getAllTranctionList(searchString); + return resp.data; + }, + }); +}; //#endregion // ---------------------------Put Post Recurring Expense--------------------------------------- diff --git a/src/pages/AdvancePayment/AdvancePaymentPage.jsx b/src/pages/AdvancePayment/AdvancePaymentPage.jsx index 9af4a6c9..70913ba8 100644 --- a/src/pages/AdvancePayment/AdvancePaymentPage.jsx +++ b/src/pages/AdvancePayment/AdvancePaymentPage.jsx @@ -29,10 +29,13 @@ const AdvancePaymentPage = () => { const { control, reset, watch } = useForm({ defaultValues: { employeeId: "", + searchString: "", }, }); const selectedEmployeeId = watch("employeeId"); + const searchString = watch("searchString"); + useEffect(() => { const selectedEmpoyee = sessionStorage.getItem("transaction-empId"); reset({ @@ -68,9 +71,8 @@ const AdvancePaymentPage = () => { <> 0 ? "text-success" : "text-danger" - } fs-5 fw-bold ms-1`} + className={`${balance > 0 ? "text-success" : "text-danger" + } fs-5 fw-bold ms-1`} > {balance > 0 ? ( @@ -88,7 +90,7 @@ const AdvancePaymentPage = () => { )} - + diff --git a/src/pages/AdvancePayment/AdvancePaymentPage1.jsx b/src/pages/AdvancePayment/AdvancePaymentPage1.jsx new file mode 100644 index 00000000..1d1b457a --- /dev/null +++ b/src/pages/AdvancePayment/AdvancePaymentPage1.jsx @@ -0,0 +1,29 @@ +import React from 'react' +import Breadcrumb from '../../components/common/Breadcrumb' +import AdvancePaymentList1 from '../../components/AdvancePayment/AdvancePaymentList1' +import { useForm } from 'react-hook-form'; + +const AdvancePaymentPage1 = () => { + const { control, reset, watch } = useForm({ + defaultValues: { + searchString: "", + }, + }); + const searchString = watch("searchString"); + return ( +
+ +
+ +
+
+ ) +} + +export default AdvancePaymentPage1 diff --git a/src/repositories/ExpsenseRepository.jsx b/src/repositories/ExpsenseRepository.jsx index 5e30bf76..6be424b0 100644 --- a/src/repositories/ExpsenseRepository.jsx +++ b/src/repositories/ExpsenseRepository.jsx @@ -44,13 +44,13 @@ const ExpenseRepository = { DeletePaymentRequest: () => api.get("delete here come"), CreatePaymentRequestExpense: (data) => api.post("/api/Expense/payment-request/expense/create", data), - GetPayee:()=>api.get('/api/Expense/payment-request/payee'), + GetPayee: () => api.get('/api/Expense/payment-request/payee'), //#endregion //#region Recurring Expense - GetRecurringExpenseList:(pageSize, pageNumber, filter,isActive, searchString) => { + GetRecurringExpenseList: (pageSize, pageNumber, filter, isActive, searchString) => { const payloadJsonString = JSON.stringify(filter); return api.get( `/api/expense/get/recurring-payment/list?pageSize=${pageSize}&pageNumber=${pageNumber}&filter=${payloadJsonString}&isActive=${isActive}&searchString=${searchString}` @@ -70,9 +70,11 @@ const ExpenseRepository = { //#region Advance Payment GetTranctionList: (employeeId) => api.get(`/api/Expense/get/transactions/${employeeId}`), + getAllTranctionList: (searchString) => + api.get(`/api/Expense/get/advance-payment/employee/list?searchString=${searchString}`), //#endregion - + }; export default ExpenseRepository; diff --git a/src/router/AppRoutes.jsx b/src/router/AppRoutes.jsx index 1c95ec64..619b5465 100644 --- a/src/router/AppRoutes.jsx +++ b/src/router/AppRoutes.jsx @@ -61,6 +61,7 @@ import RecurringExpensePage from "../pages/RecurringExpense/RecurringExpensePage import AdvancePaymentPage from "../pages/AdvancePayment/AdvancePaymentPage"; import ServiceProjectDetail from "../pages/ServiceProject/ServiceProjectDetail"; import ManageJob from "../components/ServiceProject/ManageJob"; +import AdvancePaymentPage1 from "../pages/AdvancePayment/AdvancePaymentPage1"; const router = createBrowserRouter( [ { @@ -116,7 +117,7 @@ const router = createBrowserRouter( { path: "/expenses", element: }, { path: "/payment-request", element: }, { path: "/recurring-payment", element: }, - { path: "/advance-payment", element: }, + { path: "/advance-payment", element: }, { path: "/collection", element: }, { path: "/masters", element: }, { path: "/tenants", element: }, From 5b91c13b857ab74157ba8f46a1da177e0ef579aa Mon Sep 17 00:00:00 2001 From: Kartik Sharma Date: Wed, 19 Nov 2025 09:46:41 +0530 Subject: [PATCH 02/58] adding list view in advance payment list. --- .../AdvancePayment/AdvancePaymentList1.jsx | 105 +++++++++++++++++- .../RecurringExpense/RecurringExpenseList.jsx | 2 +- .../AdvancePayment/AdvancePaymentPage1.jsx | 21 +++- 3 files changed, 119 insertions(+), 9 deletions(-) diff --git a/src/components/AdvancePayment/AdvancePaymentList1.jsx b/src/components/AdvancePayment/AdvancePaymentList1.jsx index 9e5fb3e5..eb35942c 100644 --- a/src/components/AdvancePayment/AdvancePaymentList1.jsx +++ b/src/components/AdvancePayment/AdvancePaymentList1.jsx @@ -1,15 +1,108 @@ import React from 'react' import { useExpenseAllTransactionsList } from '../../hooks/useExpense'; -const AdvancePaymentList1 = ({searchString}) => { +const AdvancePaymentList1 = ({ searchString }) => { const { data, isError, isLoading, error, isFetching } = - useExpenseAllTransactionsList(); - return ( -
-
+ useExpenseAllTransactionsList(searchString); + console.log("Kartik", data) + const recurringExpenseColumns = [ + { + key: "date", + label: ( + <> + Date + + ), + align: "text-start", + }, + { key: "description", label: "Description", align: "text-start" }, + { + key: "credit", + label: ( + <> + Credit + + ), + align: "text-end", + }, + { + key: "debit", + label: ( + <> + Debit + + ), + align: "text-end", + }, + + { + key: "balance", + label: ( + <> + Balance + + ), + align: "text-end fw-bold", + }, + + ]; + return ( +
+
+ {/* {Array.isArray(data) && data.length > 0 && ( */} + + + + {recurringExpenseColumns.map((col) => ( + + ))} + + + + + {data?.length > 0 ? ( + data?.map((recurringExpense) => ( + + {recurringExpenseColumns.map((col) => ( + + ))} + + + )) + ) : ( + + + + )} + +
+ {col.label} +
+ {col?.customRender + ? col?.customRender(recurringExpense) + : col?.getValue(recurringExpense)} +
+ {/* )} */} + {/* {!data || + data.length === 0 + && ( +
+ {isError ? (

{error.message}

) : (

No Recurring Expense Found

)} +
+ )} */} +
-
) } diff --git a/src/components/RecurringExpense/RecurringExpenseList.jsx b/src/components/RecurringExpense/RecurringExpenseList.jsx index 338a3f38..a4c45fba 100644 --- a/src/components/RecurringExpense/RecurringExpenseList.jsx +++ b/src/components/RecurringExpense/RecurringExpenseList.jsx @@ -166,7 +166,7 @@ const RecurringExpenseList = ({ search, filterStatuses }) => { } ); }; - +console.log("Tanish",filteredData) return ( <> {IsDeleteModalOpen && ( diff --git a/src/pages/AdvancePayment/AdvancePaymentPage1.jsx b/src/pages/AdvancePayment/AdvancePaymentPage1.jsx index 1d1b457a..0a35dd44 100644 --- a/src/pages/AdvancePayment/AdvancePaymentPage1.jsx +++ b/src/pages/AdvancePayment/AdvancePaymentPage1.jsx @@ -2,6 +2,7 @@ import React from 'react' import Breadcrumb from '../../components/common/Breadcrumb' import AdvancePaymentList1 from '../../components/AdvancePayment/AdvancePaymentList1' import { useForm } from 'react-hook-form'; +import EmployeeSearchInput from '../../components/common/EmployeeSearchInput'; const AdvancePaymentPage1 = () => { const { control, reset, watch } = useForm({ @@ -19,9 +20,25 @@ const AdvancePaymentPage1 = () => { { label: "Advance Payment" }, ]} /> -
- +
+
+
+
+ +
+
+ +
+ + +
) } From 10e54637d56e9263ed4c73c74fbc2a9f69838765 Mon Sep 17 00:00:00 2001 From: Kartik Sharma Date: Wed, 19 Nov 2025 10:47:11 +0530 Subject: [PATCH 03/58] Adding list view in Advance payment list. --- .../AdvancePayment/AdvancePaymentList1.jsx | 255 +++++++++++------- 1 file changed, 159 insertions(+), 96 deletions(-) diff --git a/src/components/AdvancePayment/AdvancePaymentList1.jsx b/src/components/AdvancePayment/AdvancePaymentList1.jsx index eb35942c..2269f23f 100644 --- a/src/components/AdvancePayment/AdvancePaymentList1.jsx +++ b/src/components/AdvancePayment/AdvancePaymentList1.jsx @@ -1,109 +1,172 @@ +// import React from 'react' +// import { useExpenseAllTransactionsList } from '../../hooks/useExpense'; + +// const AdvancePaymentList1 = ({ searchString }) => { +// const { data, isError, isLoading, error, isFetching } = +// useExpenseAllTransactionsList(searchString); +// console.log("Kartik", data) + +// const recurringExpenseColumns = [ +// { +// key: "date", +// label: ( +// <> +// Date +// +// ), +// align: "text-start", +// }, +// { key: "description", label: "Description", align: "text-start" }, +// { +// key: "credit", +// label: ( +// <> +// Credit +// +// ), +// align: "text-end", +// }, +// { +// key: "debit", +// label: ( +// <> +// Debit +// +// ), +// align: "text-end", +// }, + +// { +// key: "balance", +// label: ( +// <> +// Balance +// +// ), +// align: "text-end fw-bold", +// }, + +// ]; +// return ( +//
+//
+// {/* {Array.isArray(data) && data.length > 0 && ( */} +// +// +// +// {recurringExpenseColumns.map((col) => ( +// +// ))} +// +// + +// +// {data?.length > 0 ? ( +// data?.map((recurringExpense) => ( +// +// {recurringExpenseColumns.map((col) => ( +// +// ))} + +// +// )) +// ) : ( +// +// +// +// )} +// +//
+// {col.label} +//
+// {col?.customRender +// ? col?.customRender(recurringExpense) +// : col?.getValue(recurringExpense)} +//
+// {/* )} */} +// {/* {!data || +// data.length === 0 +// && ( +//
+// {isError ? (

{error.message}

) : (

No Recurring Expense Found

)} +//
+// )} */} +//
+//
+// ) +// } + +// export default AdvancePaymentList1 + import React from 'react' import { useExpenseAllTransactionsList } from '../../hooks/useExpense'; const AdvancePaymentList1 = ({ searchString }) => { - const { data, isError, isLoading, error, isFetching } = + + const { data, isError, isLoading, error } = useExpenseAllTransactionsList(searchString); - console.log("Kartik", data) - const recurringExpenseColumns = [ - { - key: "date", - label: ( - <> - Date - - ), - align: "text-start", - }, - { key: "description", label: "Description", align: "text-start" }, - { - key: "credit", - label: ( - <> - Credit - - ), - align: "text-end", - }, - { - key: "debit", - label: ( - <> - Debit - - ), - align: "text-end", - }, - - { - key: "balance", - label: ( - <> - Balance - - ), - align: "text-end fw-bold", - }, + const rows = data; + const columns = [ + { key: "employee", label: "Employee Name", align: "text-start", getValue: (r) => r.firstName + " " + r.lastName }, + { key: "jobRoleName", label: "Job Role", align: "text-start", getValue: (r) => r.jobRoleName }, + { key: "balanceAmount", label: "Balance (₹)", align: "text-end", getValue: (r) => r.balanceAmount }, ]; - return ( -
-
- {/* {Array.isArray(data) && data.length > 0 && ( */} - - - - {recurringExpenseColumns.map((col) => ( - - ))} - - - - {data?.length > 0 ? ( - data?.map((recurringExpense) => ( - - {recurringExpenseColumns.map((col) => ( - - ))} - - - )) - ) : ( - - - - )} - -
- {col.label} -
- {col?.customRender - ? col?.customRender(recurringExpense) - : col?.getValue(recurringExpense)} -
- {/* )} */} - {/* {!data || - data.length === 0 - && ( -
- {isError ? (

{error.message}

) : (

No Recurring Expense Found

)} -
- )} */} -
+ if (isLoading) return

Loading...

; + if (isError) return

{error.message}

; + + return ( +
+
+ + + + + {columns.map((col) => ( + + ))} + + + + + {rows.length > 0 ? ( + rows.map((row) => ( + + {columns.map((col) => ( + + ))} + + )) + ) : ( + + + + )} + +
+ {col.label} +
+ {col.getValue(row)} +
+ No Employees Found +
+
+
) } -export default AdvancePaymentList1 +export default AdvancePaymentList1; + From a3be63b74f2376f8dd6a28a98236c3906b690ada Mon Sep 17 00:00:00 2001 From: Kartik Sharma Date: Wed, 19 Nov 2025 12:22:38 +0530 Subject: [PATCH 04/58] Implementing api for Advance payment all data. --- .../AdvancePayment/AdvancePaymentList.jsx | 10 +- .../AdvancePayment/AdvancePaymentList1.jsx | 164 +++++------------- src/components/Layout/Header.jsx | 5 +- .../AdvancePayment/AdvancePaymentPage.jsx | 40 +++-- .../AdvancePayment/AdvancePaymentPage1.jsx | 18 +- src/router/AppRoutes.jsx | 1 + 6 files changed, 80 insertions(+), 158 deletions(-) diff --git a/src/components/AdvancePayment/AdvancePaymentList.jsx b/src/components/AdvancePayment/AdvancePaymentList.jsx index 5aef0de7..c6e9d004 100644 --- a/src/components/AdvancePayment/AdvancePaymentList.jsx +++ b/src/components/AdvancePayment/AdvancePaymentList.jsx @@ -15,12 +15,6 @@ const AdvancePaymentList = ({ employeeId, searchString }) => { const { setBalance } = useAdvancePaymentContext(); const { data, isError, isLoading, error, isFetching } = useExpenseTransactions(employeeId, { enabled: !!employeeId }); - - const { data: getAllData } = - useExpenseAllTransactionsList(searchString ?? ""); - - console.log("Kartik", getAllData) - const records = Array.isArray(data) ? data : []; let currentBalance = 0; @@ -159,8 +153,8 @@ const AdvancePaymentList = ({ employeeId, searchString }) => { - {Array.isArray(getAllData) && getAllData.length > 0 ? ( - getAllData.map((row) => ( + {Array.isArray(data) && data.length > 0 ? ( + data.map((row) => ( {columns.map((col) => ( diff --git a/src/components/AdvancePayment/AdvancePaymentList1.jsx b/src/components/AdvancePayment/AdvancePaymentList1.jsx index 2269f23f..e17cd1b1 100644 --- a/src/components/AdvancePayment/AdvancePaymentList1.jsx +++ b/src/components/AdvancePayment/AdvancePaymentList1.jsx @@ -1,127 +1,56 @@ -// import React from 'react' -// import { useExpenseAllTransactionsList } from '../../hooks/useExpense'; - -// const AdvancePaymentList1 = ({ searchString }) => { -// const { data, isError, isLoading, error, isFetching } = -// useExpenseAllTransactionsList(searchString); -// console.log("Kartik", data) - -// const recurringExpenseColumns = [ -// { -// key: "date", -// label: ( -// <> -// Date -// -// ), -// align: "text-start", -// }, -// { key: "description", label: "Description", align: "text-start" }, -// { -// key: "credit", -// label: ( -// <> -// Credit -// -// ), -// align: "text-end", -// }, -// { -// key: "debit", -// label: ( -// <> -// Debit -// -// ), -// align: "text-end", -// }, - -// { -// key: "balance", -// label: ( -// <> -// Balance -// -// ), -// align: "text-end fw-bold", -// }, - -// ]; -// return ( -//
-//
-// {/* {Array.isArray(data) && data.length > 0 && ( */} -// -// -// -// {recurringExpenseColumns.map((col) => ( -// -// ))} -// -// - -// -// {data?.length > 0 ? ( -// data?.map((recurringExpense) => ( -// -// {recurringExpenseColumns.map((col) => ( -// -// ))} - -// -// )) -// ) : ( -// -// -// -// )} -// -//
-// {col.label} -//
-// {col?.customRender -// ? col?.customRender(recurringExpense) -// : col?.getValue(recurringExpense)} -//
-// {/* )} */} -// {/* {!data || -// data.length === 0 -// && ( -//
-// {isError ? (

{error.message}

) : (

No Recurring Expense Found

)} -//
-// )} */} -//
-//
-// ) -// } - -// export default AdvancePaymentList1 - import React from 'react' +import Avatar from "../../components/common/Avatar"; // <-- ADD THIS import { useExpenseAllTransactionsList } from '../../hooks/useExpense'; +import { useNavigate } from 'react-router-dom'; +import { formatFigure } from '../../utils/appUtils'; const AdvancePaymentList1 = ({ searchString }) => { const { data, isError, isLoading, error } = useExpenseAllTransactionsList(searchString); - const rows = data; + const rows = data || []; + const navigate = useNavigate(); const columns = [ - { key: "employee", label: "Employee Name", align: "text-start", getValue: (r) => r.firstName + " " + r.lastName }, - { key: "jobRoleName", label: "Job Role", align: "text-start", getValue: (r) => r.jobRoleName }, - { key: "balanceAmount", label: "Balance (₹)", align: "text-end", getValue: (r) => r.balanceAmount }, + { + key: "employee", + label: "Employee Name", + align: "text-start", + customRender: (r) => ( +
navigate(`/advance-payment/${r.id}`)} + style={{ cursor: "pointer" }}> + + + + {r.firstName} {r.lastName} + +
+ ), + }, + { + key: "jobRoleName", + label: "Job Role", + align: "text-start", + customRender: (r) => ( + + {r.jobRoleName} + + ), + }, + { + key: "balanceAmount", + label: "Balance (₹)", + align: "text-end", + customRender: (r) => ( + + {formatFigure(r.balanceAmount, { + // type: "currency", + currency: "INR", + })} + + ), + }, ]; if (isLoading) return

Loading...

; @@ -130,7 +59,6 @@ const AdvancePaymentList1 = ({ searchString }) => { return (
- @@ -148,7 +76,9 @@ const AdvancePaymentList1 = ({ searchString }) => { {columns.map((col) => ( ))} @@ -162,11 +92,9 @@ const AdvancePaymentList1 = ({ searchString }) => { )}
- {col.getValue(row)} + {col.customRender + ? col.customRender(row) + : col.getValue(row)}
-
) } export default AdvancePaymentList1; - diff --git a/src/components/Layout/Header.jsx b/src/components/Layout/Header.jsx index 0437539e..0dca90e5 100644 --- a/src/components/Layout/Header.jsx +++ b/src/components/Layout/Header.jsx @@ -50,8 +50,11 @@ const Header = () => { const isRecurringExpense = /^\/recurring-payment$/.test(pathname); const isAdvancePayment = /^\/advance-payment$/.test(pathname); const isServiceProjectPage = /^\/service-projects\/[0-9a-fA-F-]{36}$/.test(pathname); + const isAdvancePayment1 = + /^\/advance-payment(\/[0-9a-fA-F-]{36})?$/.test(pathname); - return !(isDirectoryPath || isProfilePage || isExpensePage || isPaymentRequest || isRecurringExpense || isAdvancePayment ||isServiceProjectPage); + + return !(isDirectoryPath || isProfilePage || isExpensePage || isPaymentRequest || isRecurringExpense || isAdvancePayment ||isServiceProjectPage || isAdvancePayment1); }; const allowedProjectStatusIds = [ "603e994b-a27f-4e5d-a251-f3d69b0498ba", diff --git a/src/pages/AdvancePayment/AdvancePaymentPage.jsx b/src/pages/AdvancePayment/AdvancePaymentPage.jsx index 70913ba8..f95f199a 100644 --- a/src/pages/AdvancePayment/AdvancePaymentPage.jsx +++ b/src/pages/AdvancePayment/AdvancePaymentPage.jsx @@ -13,6 +13,8 @@ import Label from "../../components/common/Label"; import AdvancePaymentList from "../../components/AdvancePayment/AdvancePaymentList"; import { employee } from "../../data/masters"; import { formatFigure } from "../../utils/appUtils"; +import { useParams } from "react-router-dom"; +import { useExpenseTransactions } from "../../hooks/useExpense"; export const AdvancePaymentContext = createContext(); export const useAdvancePaymentContext = () => { @@ -25,15 +27,30 @@ export const useAdvancePaymentContext = () => { return context; }; const AdvancePaymentPage = () => { + const { employeeId } = useParams(); + + const { data: transactionData } = useExpenseTransactions(employeeId, { + enabled: !!employeeId + }); + + const employeeName = useMemo(() => { + if (Array.isArray(transactionData) && transactionData.length > 0) { + const emp = transactionData[0].employee; + if (emp) return `${emp.firstName} ${emp.lastName}`; + } + return ""; + }, [transactionData]); + const [balance, setBalance] = useState(null); const { control, reset, watch } = useForm({ defaultValues: { - employeeId: "", + employeeId: employeeId || "", searchString: "", }, }); - const selectedEmployeeId = watch("employeeId"); + const selectedEmployeeId = employeeId || watch("employeeId"); + const searchString = watch("searchString"); useEffect(() => { @@ -50,22 +67,13 @@ const AdvancePaymentPage = () => { data={[ { label: "Home", link: "/dashboard" }, { label: "Finance", link: "/advance-payment" }, - { label: "Advance Payment" }, - ]} + { label: "Advance Payment", link: "/advance-payment" }, + employeeName && { label: employeeName, link: "" }, + ].filter(Boolean)} /> +
-
-
-
- -
-
+
{balance ? ( <> diff --git a/src/pages/AdvancePayment/AdvancePaymentPage1.jsx b/src/pages/AdvancePayment/AdvancePaymentPage1.jsx index 0a35dd44..4ba3721b 100644 --- a/src/pages/AdvancePayment/AdvancePaymentPage1.jsx +++ b/src/pages/AdvancePayment/AdvancePaymentPage1.jsx @@ -11,6 +11,7 @@ const AdvancePaymentPage1 = () => { }, }); const searchString = watch("searchString"); + return (
{ ]} />
-
-
-
- -
-
+
-
- - +
) diff --git a/src/router/AppRoutes.jsx b/src/router/AppRoutes.jsx index 619b5465..c5d37aa3 100644 --- a/src/router/AppRoutes.jsx +++ b/src/router/AppRoutes.jsx @@ -118,6 +118,7 @@ const router = createBrowserRouter( { path: "/payment-request", element: }, { path: "/recurring-payment", element: }, { path: "/advance-payment", element: }, + { path: "/advance-payment/:employeeId", element: }, { path: "/collection", element: }, { path: "/masters", element: }, { path: "/tenants", element: }, From 7773b7a43bb74e385158d5ade48f7527cc21cdbf Mon Sep 17 00:00:00 2001 From: Kartik Sharma Date: Wed, 19 Nov 2025 12:59:57 +0530 Subject: [PATCH 05/58] Adding Status and UI implementation in Collection. --- src/components/collections/CollectionList.jsx | 13 +++++- src/components/collections/ViewCollection.jsx | 16 +++----- src/pages/collections/CollectionPage.jsx | 41 ++++++++++--------- 3 files changed, 38 insertions(+), 32 deletions(-) diff --git a/src/components/collections/CollectionList.jsx b/src/components/collections/CollectionList.jsx index bb94130e..339828ed 100644 --- a/src/components/collections/CollectionList.jsx +++ b/src/components/collections/CollectionList.jsx @@ -27,7 +27,7 @@ const CollectionList = ({ fromDate, toDate, isPending, searchString }) => { const selectedProject = useSelectedProject(); const searchDebounce = useDebounce(searchString, 500); - + const { data, isLoading, isError, error } = useCollections( selectedProject, searchDebounce, @@ -40,7 +40,6 @@ const CollectionList = ({ fromDate, toDate, isPending, searchString }) => { ); const { setProcessedPayment, setAddPayment, setViewCollection } = useCollectionContext(); - const paginate = (page) => { if (page >= 1 && page <= (data?.totalPages ?? 1)) { setCurrentPage(page); @@ -129,6 +128,16 @@ const CollectionList = ({ fromDate, toDate, isPending, searchString }) => { ), align: "text-end", }, + { + key: "status", + label: "Status", + getValue: (col) => ( + + {col?.isActive ? "Active" : "Inactive"} + + ), + align: "text-center", + }, { key: "balance", label: "Balance", diff --git a/src/components/collections/ViewCollection.jsx b/src/components/collections/ViewCollection.jsx index 77bc78fe..fdf563b9 100644 --- a/src/components/collections/ViewCollection.jsx +++ b/src/components/collections/ViewCollection.jsx @@ -25,7 +25,6 @@ const ViewCollection = ({ onClose }) => { if (isLoading) return ; if (isError) return
{error.message}
; - return (

Collection Details

@@ -43,9 +42,8 @@ const ViewCollection = ({ onClose }) => {
{" "} {data?.isActive ? "Active" : "Inactive"} @@ -214,9 +212,8 @@ const ViewCollection = ({ onClose }) => {
  • +
{/* Right side: Search + Add Button */}
+ + + Date: Wed, 19 Nov 2025 14:26:12 +0530 Subject: [PATCH 06/58] Changing the position of Status in Collection list view. --- src/components/collections/CollectionList.jsx | 21 ++++++++++--------- src/pages/collections/CollectionPage.jsx | 2 +- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/src/components/collections/CollectionList.jsx b/src/components/collections/CollectionList.jsx index 339828ed..ad1ff5c0 100644 --- a/src/components/collections/CollectionList.jsx +++ b/src/components/collections/CollectionList.jsx @@ -112,6 +112,16 @@ const CollectionList = ({ fromDate, toDate, isPending, searchString }) => { ), align: "text-center", }, + { + key: "status", + label: "Status", + getValue: (col) => ( + + {col?.isActive ? "Active" : "Inactive"} + + ), + align: "text-center", + }, { key: "amount", label: "Total Amount", @@ -128,16 +138,7 @@ const CollectionList = ({ fromDate, toDate, isPending, searchString }) => { ), align: "text-end", }, - { - key: "status", - label: "Status", - getValue: (col) => ( - - {col?.isActive ? "Active" : "Inactive"} - - ), - align: "text-center", - }, + { key: "balance", label: "Balance", diff --git a/src/pages/collections/CollectionPage.jsx b/src/pages/collections/CollectionPage.jsx index 8f68641d..5469be62 100644 --- a/src/pages/collections/CollectionPage.jsx +++ b/src/pages/collections/CollectionPage.jsx @@ -126,7 +126,7 @@ const CollectionPage = () => { }`} onClick={() => setShowPending(false)} > - All + Show All + + +
+ + + + +
+ ) +} + +export default ManageBranch diff --git a/src/components/ServiceProject/ServiceBranch.jsx b/src/components/ServiceProject/ServiceBranch.jsx new file mode 100644 index 00000000..7722bb19 --- /dev/null +++ b/src/components/ServiceProject/ServiceBranch.jsx @@ -0,0 +1,170 @@ +import React, { useState } from 'react' +import GlobalModel from '../common/GlobalModel'; +import ManageBranch from './ManageBranch'; + +const ServiceBranch = () => { + + const [ManageServiceBranch, setManageServiceBranch] = useState({ + IsOpen: null, + branchId: null, + }); + + const ServiceBranch = [ + { + key: "branchName", + label: "Branch Name", + align: "text-start", + getValue: (e) => e?.payee || "N/A", + }, + ]; + return ( +
+
+
+
+ +
+
+ + +
+ {/* {Array.isArray(filteredData) && filteredData.length > 0 && ( */} + + + + {ServiceBranch.map((col) => ( + + ))} + + + + + {/* + {filteredData?.length > 0 ? ( + filteredData?.map((recurringExpense) => ( + + {recurringExpenseColumns.map((col) => ( + + ))} + + + )) + ) : ( + + + + )} + */} +
+ {col.label} + Action
+ {col?.customRender + ? col?.customRender(recurringExpense) + : col?.getValue(recurringExpense)} + +
+ + setViewRecurring({ + recurringId: recurringExpense?.id, + view: true, + }) + } + > + +
+ +
    +
  • + setManageServiceBranch({ + IsOpen: true, + RecurringId: recurringExpense?.id, + }) + } + > + + + Modify + +
  • + +
  • { + setIsDeleteModalOpen(true); + setDeletingId(recurringExpense.id); + }} + > + + + Delete + +
  • +
+
+
+
+ {/* )} */} + {/* {!filteredData || + filteredData.length === 0 + && ( +
+ {isError ? (

{error.message}

) : (

No Recurring Expense Found

)} +
+ )} */} +
+ + {ManageServiceBranch.IsOpen && ( + + setManageServiceBranch({ IsOpen: null, branchId: null }) + } + > + + setManageServiceBranch({ IsOpen: null, branchId: null }) + } + // requestToEdit={ManageServiceBranch.branchId} + /> + + )} +
+
+ ) +} + +export default ServiceBranch diff --git a/src/components/ServiceProject/ServiceProjectProfile.jsx b/src/components/ServiceProject/ServiceProjectProfile.jsx index 8e131852..05a05fd3 100644 --- a/src/components/ServiceProject/ServiceProjectProfile.jsx +++ b/src/components/ServiceProject/ServiceProjectProfile.jsx @@ -5,6 +5,7 @@ import { formatUTCToLocalTime } from "../../utils/dateUtils"; import ManageServiceProject from "./ManageServiceProject"; import GlobalModel from "../common/GlobalModel"; import { SpinnerLoader } from "../common/Loader"; +import ServiceBranch from "./ServiceBranch"; const ServiceProjectProfile = () => { const { projectId } = useParams(); @@ -114,6 +115,10 @@ const ServiceProjectProfile = () => {
+
+ +
+
diff --git a/src/repositories/ServiceProjectRepository.jsx b/src/repositories/ServiceProjectRepository.jsx index 94ef3c8e..1da42fd2 100644 --- a/src/repositories/ServiceProjectRepository.jsx +++ b/src/repositories/ServiceProjectRepository.jsx @@ -35,4 +35,13 @@ export const ServiceProjectRepository = { api.patch(`/api/ServiceProject/job/edit/${id}`, patchData, { "Content-Type": "application/json-patch+json", }), + + //Branch API + getServiceBranch: (jobTicketId, pageSize, pageNumber) => + api.get( + `/api/serviceproject/branch/list?jobTicketId=${jobTicketId}&pageSize=${pageSize}&pageNumber=${pageNumber}` + ), + }; + + From 15978b2ac7308e33dba8aa1f87dee4e5cd1f4191 Mon Sep 17 00:00:00 2001 From: "pramod.mahajan" Date: Wed, 19 Nov 2025 16:35:53 +0530 Subject: [PATCH 11/58] fixed useClient implmention --- src/hooks/useServiceProject.jsx | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/hooks/useServiceProject.jsx b/src/hooks/useServiceProject.jsx index 95283992..b0b98719 100644 --- a/src/hooks/useServiceProject.jsx +++ b/src/hooks/useServiceProject.jsx @@ -317,7 +317,7 @@ export const useBranches = ( export const useBranch = (id)=>{ return useQuery({ queryKey:["branch",id], - queryFn:()=>{ + queryFn:async()=>{ const resp = await ServiceProjectRepository.GetBranchDetail(id); return resp.data ?? resp; }, @@ -326,8 +326,9 @@ export const useBranch = (id)=>{ } export const useCreateBranche =()=>{ + const queryClient = useQueryClient(); return useMutation({ - mutationFn:(payload)=> await ServiceProjectRepository.CreateBranch(payload), + mutationFn:async(payload)=> await ServiceProjectRepository.CreateBranch(payload), onSuccess: (data, variables) => { queryClient.invalidateQueries({ queryKey: ["branches"], @@ -347,6 +348,7 @@ export const useCreateBranche =()=>{ } export const useUpdateBranch=()=>{ + const queryClient = useQueryClient(); return useMutation({ mutationFn:async({id,payload})=> await ServiceProjectRepository.UpdateBranch(id,payload), onSuccess: (_,variables) => { @@ -367,6 +369,7 @@ export const useUpdateBranch=()=>{ } export const useDeleteBranch=()=>{ + const queryClient = useQueryClient(); return useMutation({ mutationFn:async(id)=> await ServiceProjectRepository.DeleteBranch(id), onSuccess: (_,variables) => { From df24b18a27b24b4a46f9c30061af04ef251105d1 Mon Sep 17 00:00:00 2001 From: Kartik Sharma Date: Wed, 19 Nov 2025 16:36:32 +0530 Subject: [PATCH 12/58] At the time of hit in cancel form will be closed. --- src/components/ServiceProject/ManageBranch.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/ServiceProject/ManageBranch.jsx b/src/components/ServiceProject/ManageBranch.jsx index 51c8f7f6..2eae8c49 100644 --- a/src/components/ServiceProject/ManageBranch.jsx +++ b/src/components/ServiceProject/ManageBranch.jsx @@ -5,7 +5,7 @@ import { useForm } from 'react-hook-form'; import { zodResolver } from '@hookform/resolvers/zod'; import Label from '../common/Label'; -const ManageBranch = ({ BranchToEdit = null }) => { +const ManageBranch = ({ closeModal,BranchToEdit = null }) => { const schema = BranchSchema(); const { From 50269aead221f3533d18f2e113ecf1a85d0c623d Mon Sep 17 00:00:00 2001 From: "pramod.mahajan" Date: Wed, 19 Nov 2025 18:28:54 +0530 Subject: [PATCH 13/58] added selectFiled for branch --- src/components/ServiceProject/ManageJob.jsx | 20 +- .../ServiceProject/ServiceProjectSchema.jsx | 3 + .../common/Forms/SelectFieldServerSide.jsx | 179 ++++++++++++++++++ src/hooks/useServiceProject.jsx | 2 + src/repositories/ServiceProjectRepository.jsx | 4 +- 5 files changed, 204 insertions(+), 4 deletions(-) diff --git a/src/components/ServiceProject/ManageJob.jsx b/src/components/ServiceProject/ManageJob.jsx index c0d9223e..97cd1a97 100644 --- a/src/components/ServiceProject/ManageJob.jsx +++ b/src/components/ServiceProject/ManageJob.jsx @@ -4,6 +4,7 @@ import Label from "../common/Label"; import { zodResolver } from "@hookform/resolvers/zod"; import { defaultJobValue, jobSchema } from "./ServiceProjectSchema"; import { + useBranches, useCreateServiceProjectJob, useJobTags, useServiceProjectJobDetails, @@ -25,6 +26,7 @@ import { useParams } from "react-router-dom"; import { useDispatch } from "react-redux"; import { useJobStatus } from "../../hooks/masterHook/useMaster"; import { useServiceProjectJobContext } from "./Jobs"; +import { SelectFieldSearch } from "../common/Forms/SelectFieldServerSide"; const ManageJob = ({ Job }) => { const { setManageJob, setSelectedJob } = useServiceProjectJobContext(); @@ -39,7 +41,7 @@ const ManageJob = ({ Job }) => { control, watch, handleSubmit, - reset, + reset,setValue, formState: { errors }, } = methods; @@ -199,7 +201,7 @@ const ManageJob = ({ Job }) => { />
- + { name="tags" label="Tag" placeholder="Enter Tag" + + /> +
+
+ setValue("branchId", val)} + valueKey="id" + labelKey="branchName" + hookParams={[projectId,true,10,1]} + useFetchHook={useBranches} + isMultiple={false} />
diff --git a/src/components/ServiceProject/ServiceProjectSchema.jsx b/src/components/ServiceProject/ServiceProjectSchema.jsx index 5a5727b7..9a14605c 100644 --- a/src/components/ServiceProject/ServiceProjectSchema.jsx +++ b/src/components/ServiceProject/ServiceProjectSchema.jsx @@ -70,6 +70,8 @@ export const jobSchema = z.object({ tags: z.array(TagSchema).optional().default([]), statusId: z.string().optional().nullable(), + + branchId: z.string().optional().nullable(), }); const MAX_FILE_SIZE = 5 * 1024 * 1024; // 5MB @@ -109,6 +111,7 @@ export const defaultJobValue = { startDate: null, dueDate: null, tags: [], + branchId: null, }; //#endregion diff --git a/src/components/common/Forms/SelectFieldServerSide.jsx b/src/components/common/Forms/SelectFieldServerSide.jsx index 6ff6eb90..de0265af 100644 --- a/src/components/common/Forms/SelectFieldServerSide.jsx +++ b/src/components/common/Forms/SelectFieldServerSide.jsx @@ -361,3 +361,182 @@ export const SelectProjectField = ({
); }; + + + +export const SelectFieldSearch = ({ + label = "Select", + placeholder = "Select ", + required = false, + value = null, + onChange, + valueKey = "id", + labelKey = "name", + + isFullObject = false, + isMultiple = false, + hookParams, + useFetchHook, +}) => { + const [searchText, setSearchText] = useState(""); + const debounce = useDebounce(searchText, 300); + + const { data, isLoading } = useFetchHook(...hookParams,debounce); + const options = data?.data ?? []; + const [open, setOpen] = useState(false); + const dropdownRef = useRef(null); + + const getDisplayName = (entity) => { + if (!entity) return ""; + return `${entity[labelKey] || ""}`.trim(); + }; + + /** ----------------------------- + * SELECTED OPTION (SINGLE) + * ----------------------------- */ + let selectedSingle = null; + + if (!isMultiple) { + if (isFullObject && value) selectedSingle = value; + else if (!isFullObject && value) + selectedSingle = options.find((o) => o[valueKey] === value); + } + + /** ----------------------------- + * SELECTED OPTION (MULTIPLE) + * ----------------------------- */ + let selectedList = []; + if (isMultiple && Array.isArray(value)) { + if (isFullObject) selectedList = value; + else { + selectedList = options.filter((opt) => value.includes(opt[valueKey])); + } + } + + /** Main button label */ + const displayText = !isMultiple + ? getDisplayName(selectedSingle) || placeholder + : selectedList.length > 0 + ? selectedList.map((e) => getDisplayName(e)).join(", ") + : placeholder; + + /** ----------------------------- + * HANDLE OUTSIDE CLICK + * ----------------------------- */ + useEffect(() => { + const handleClickOutside = (e) => { + if (dropdownRef.current && !dropdownRef.current.contains(e.target)) { + setOpen(false); + } + }; + + document.addEventListener("mousedown", handleClickOutside); + return () => document.removeEventListener("mousedown", handleClickOutside); + }, []); + + /** ----------------------------- + * HANDLE SELECT + * ----------------------------- */ + const handleSelect = (option) => { + if (!isMultiple) { + // SINGLE SELECT + if (isFullObject) onChange(option); + else onChange(option[valueKey]); + } else { + // MULTIPLE SELECT + let updated = []; + + const exists = selectedList.some((e) => e[valueKey] === option[valueKey]); + + if (exists) { + // remove + updated = selectedList.filter((e) => e[valueKey] !== option[valueKey]); + } else { + // add + updated = [...selectedList, option]; + } + + if (isFullObject) onChange(updated); + else onChange(updated.map((x) => x[valueKey])); + } + }; + + return ( +
+ {label && ( + + )} + + {/* MAIN BUTTON */} + + + {/* DROPDOWN */} + {open && ( +
    +
    + setSearchText(e.target.value)} + className="form-control form-control-sm" + placeholder="Search..." + /> +
    + + {isLoading && ( +
  • Loading...
  • + )} + + {!isLoading && options.length === 0 && ( +
  • + No results found +
  • + )} + + {!isLoading && + options.map((option) => { + const isActive = isMultiple + ? selectedList.some((x) => x[valueKey] === option[valueKey]) + : selectedSingle && + selectedSingle[valueKey] === option[valueKey]; + + return ( +
  • + +
  • + ); + })} +
+ )} +
+ ); +}; diff --git a/src/hooks/useServiceProject.jsx b/src/hooks/useServiceProject.jsx index b0b98719..ab536e2b 100644 --- a/src/hooks/useServiceProject.jsx +++ b/src/hooks/useServiceProject.jsx @@ -308,12 +308,14 @@ export const useBranches = ( pageNumber, searchString ); + console.log(resp) return resp.data; }, enabled: !!projectId, }); }; + export const useBranch = (id)=>{ return useQuery({ queryKey:["branch",id], diff --git a/src/repositories/ServiceProjectRepository.jsx b/src/repositories/ServiceProjectRepository.jsx index b61505cd..339d5212 100644 --- a/src/repositories/ServiceProjectRepository.jsx +++ b/src/repositories/ServiceProjectRepository.jsx @@ -45,8 +45,8 @@ export const ServiceProjectRepository = { UpdateBranch: (id, data) => api.put("/api/ServiceProject/branch/edit/${id}", data), GetBranchList: (projectId, isActive, pageSize, pageNumber, searchString) => { - api.get( - `/api/ServiceProject/branch/list/${projectId}&isActive=${isActive}&pageSize=${pageSize}&pageNumber=${pageNumber}&searchString=${searchString}` + return api.get( + `/api/ServiceProject/branch/list/${projectId}?isActive=${isActive}&pageSize=${pageSize}&pageNumber=${pageNumber}&searchString=${searchString}` ); }, GetBranchDetail: (id) => api.get(`/api/ServiceProject/branch/details/${id}`), From 8a5d6158c2c5b27649fc7b6e851aba525d091bdb Mon Sep 17 00:00:00 2001 From: Kartik Sharma Date: Wed, 19 Nov 2025 18:31:17 +0530 Subject: [PATCH 14/58] Implementing Creating API. --- .../ServiceProject/ManageBranch.jsx | 120 +++++++------- .../ServiceProject/ServiceBranch.jsx | 155 ++++++++---------- src/hooks/useServiceProject.jsx | 83 +++++----- src/repositories/ServiceProjectRepository.jsx | 8 +- 4 files changed, 181 insertions(+), 185 deletions(-) diff --git a/src/components/ServiceProject/ManageBranch.jsx b/src/components/ServiceProject/ManageBranch.jsx index 2eae8c49..70257710 100644 --- a/src/components/ServiceProject/ManageBranch.jsx +++ b/src/components/ServiceProject/ManageBranch.jsx @@ -1,12 +1,16 @@ -import React from 'react' +import React, { useEffect } from 'react' import { useProjectName } from '../../hooks/useProjects'; import { BranchSchema, defaultBranches } from './BranchSchema'; import { useForm } from 'react-hook-form'; import { zodResolver } from '@hookform/resolvers/zod'; import Label from '../common/Label'; +import { useCreateBranch, useServiceProjects, useUpdateBranch } from '../../hooks/useServiceProject'; +import { useAppForm } from '../../hooks/appHooks/useAppForm'; +import { useParams } from 'react-router-dom'; -const ManageBranch = ({ closeModal,BranchToEdit = null }) => { - +const ManageBranch = ({ closeModal, BranchToEdit = null }) => { + const { data } = {} + const { projectId } = useParams(); const schema = BranchSchema(); const { register, @@ -16,23 +20,50 @@ const ManageBranch = ({ closeModal,BranchToEdit = null }) => { setValue, reset, formState: { errors }, - } = useForm({ + } = useAppForm({ resolver: zodResolver(schema), - defaultValues: defaultBranches, + defaultValues: { + ...defaultBranches, + projectId: projectId || "" + }, }); - const { - projectNames, - loading: projectLoading, - error, - isError: isProjectError, - } = useProjectName(); - const handleClose = () => { reset(); closeModal(); }; + useEffect(() => { + if (BranchToEdit && data) { + reset({ + branchName: data.branchName || "", + projectId: data.project?.id || projectId || "", + contactInformation: data.contactInformation || "", + address: data.address || "", + branchType: data.branchType || "", + googleMapUrl: data.googleMapUrl || "", + }); + } + }, [data, reset]); + + const { mutate: CreateServiceBranch, isPending: createPending } = + useCreateBranch(() => { + handleClose(); + }); + const { mutate: ServiceBranchUpdate, isPending } = + useUpdateBranch(() => handleClose()); + + const onSubmit = (fromdata) => { + let payload = { + ...fromdata, projectId, + }; + if (BranchToEdit) { + const editPayload = { ...payload, id: data.id }; + ServiceBranchUpdate({ id: data.id, payload: editPayload }); + } else { + CreateServiceBranch(payload); + } + }; return (
@@ -41,50 +72,24 @@ const ManageBranch = ({ closeModal,BranchToEdit = null }) => { ? "Update Branch" : "Create Branch"} -
+
+
-
- -
- - - {errors.branchName && ( - {errors.branchName.message} - )} -
-
- -
+
+ +
+
-
- - -
+
+ + +
+
-
- - - )) - ) : ( - - + + + setManageServiceBranch({ + IsOpen: true, + branchId: branch.id, + }) + } + > + - )} - */} + )) + ) : ( + + + No Branch Found + + + )} + */} + + {/* )} */} {/* {!filteredData || @@ -158,10 +139,16 @@ const ServiceBranch = () => { closeModal={() => setManageServiceBranch({ IsOpen: null, branchId: null }) } - // requestToEdit={ManageServiceBranch.branchId} + // requestToEdit={ManageServiceBranch.branchId} /> )} + + {/* */}
) diff --git a/src/hooks/useServiceProject.jsx b/src/hooks/useServiceProject.jsx index b0b98719..3dfd4115 100644 --- a/src/hooks/useServiceProject.jsx +++ b/src/hooks/useServiceProject.jsx @@ -59,8 +59,8 @@ export const useCreateServiceProject = (onSuccessCallback) => { onError: (error) => { showToast( error?.response?.data?.message || - error.message || - "Failed to delete task", + error.message || + "Failed to delete task", "error" ); }, @@ -84,8 +84,8 @@ export const useUpdateServiceProject = (onSuccessCallback) => { onError: (error) => { showToast( error?.response?.data?.message || - error.message || - "Failed to update project", + error.message || + "Failed to update project", "error" ); }, @@ -110,8 +110,8 @@ export const useActiveInActiveServiceProject = (onSuccessCallback) => { onError: (error) => { showToast( error?.response?.data?.message || - error.message || - "Failed to update project", + error.message || + "Failed to update project", "error" ); }, @@ -138,8 +138,8 @@ export const useAllocationServiceProjectTeam = (onSuccessCallback) => { onError: (error) => { showToast( error?.response?.data?.message || - error.message || - "Failed to update project", + error.message || + "Failed to update project", "error" ); }, @@ -223,8 +223,8 @@ export const useAddCommentJob = (onSuccessCallback) => { onError: (error) => { showToast( error?.response?.data?.message || - error.message || - "Failed to update project", + error.message || + "Failed to update project", "error" ); }, @@ -247,8 +247,8 @@ export const useCreateServiceProjectJob = (onSuccessCallback) => { onError: (error) => { showToast( error?.response?.data?.message || - error.message || - "Failed to update project", + error.message || + "Failed to update project", "error" ); }, @@ -273,8 +273,8 @@ export const useUpdateServiceProjectJob = (onSuccessCallback) => { onError: (error) => { showToast( error?.response?.data?.message || - error.message || - "Failed to update project", + error.message || + "Failed to update project", "error" ); }, @@ -314,65 +314,64 @@ export const useBranches = ( }); }; -export const useBranch = (id)=>{ +export const useBranch = (id) => { return useQuery({ - queryKey:["branch",id], - queryFn:async()=>{ + queryKey: ["branch", id], + queryFn: async () => { const resp = await ServiceProjectRepository.GetBranchDetail(id); return resp.data ?? resp; }, - enabled:!!id + enabled: !!id }) } -export const useCreateBranche =()=>{ +export const useCreateBranch = (onSuccessCallBack) => { const queryClient = useQueryClient(); return useMutation({ - mutationFn:async(payload)=> await ServiceProjectRepository.CreateBranch(payload), - onSuccess: (data, variables) => { - queryClient.invalidateQueries({ - queryKey: ["branches"], - }); - if (onSuccessCallback) onSuccessCallback(); - showToast("Branch created successfully", "success"); + mutationFn: async (payload) => { + await ServiceProjectRepository.CreateBranch(payload); + }, + + onSuccess: (_, variables) => { + queryClient.invalidateQueries({ queryKey: ["branches"] }); + showToast("Branches Created Successfully", "success"); + if (onSuccessCallBack) onSuccessCallBack(); }, onError: (error) => { showToast( - error?.response?.data?.message || - error.message || - "Failed to create branch", + error.message || "Something went wrong please try again !", "error" ); }, - }) -} + }); +}; -export const useUpdateBranch=()=>{ +export const useUpdateBranch = () => { const queryClient = useQueryClient(); return useMutation({ - mutationFn:async({id,payload})=> await ServiceProjectRepository.UpdateBranch(id,payload), - onSuccess: (_,variables) => { + mutationFn: async ({ id, payload }) => await ServiceProjectRepository.UpdateBranch(id, payload), + onSuccess: (_, variables) => { queryClient.invalidateQueries({ queryKey: ["branches"] }); - queryClient.invalidateQueries({ queryKey: ["branch",variables.id] }); + queryClient.invalidateQueries({ queryKey: ["branch", variables.id] }); if (onSuccessCallback) onSuccessCallback(); showToast("Branch Updated successfully", "success"); }, onError: (error) => { showToast( error?.response?.data?.message || - error.message || - "Failed to update branch", + error.message || + "Failed to update branch", "error" ); }, }) } -export const useDeleteBranch=()=>{ +export const useDeleteBranch = () => { const queryClient = useQueryClient(); return useMutation({ - mutationFn:async(id)=> await ServiceProjectRepository.DeleteBranch(id), - onSuccess: (_,variables) => { + mutationFn: async (id) => await ServiceProjectRepository.DeleteBranch(id), + onSuccess: (_, variables) => { queryClient.invalidateQueries({ queryKey: ["branches"] }); if (onSuccessCallback) onSuccessCallback(); showToast("Branch Deleted successfully", "success"); @@ -380,8 +379,8 @@ export const useDeleteBranch=()=>{ onError: (error) => { showToast( error?.response?.data?.message || - error.message || - "Failed to delete branch", + error.message || + "Failed to delete branch", "error" ); }, diff --git a/src/repositories/ServiceProjectRepository.jsx b/src/repositories/ServiceProjectRepository.jsx index b61505cd..e838a04b 100644 --- a/src/repositories/ServiceProjectRepository.jsx +++ b/src/repositories/ServiceProjectRepository.jsx @@ -41,16 +41,16 @@ export const ServiceProjectRepository = { //#endregion //#region Project Branch - CreateBranch: (data) => api.post(`/api/ServiceProject/create`, data), + CreateBranch: (data) => api.post(`/api/ServiceProject/branch/create`, data), UpdateBranch: (id, data) => api.put("/api/ServiceProject/branch/edit/${id}", data), GetBranchList: (projectId, isActive, pageSize, pageNumber, searchString) => { api.get( - `/api/ServiceProject/branch/list/${projectId}&isActive=${isActive}&pageSize=${pageSize}&pageNumber=${pageNumber}&searchString=${searchString}` + `/api/ServiceProject/branch/list/${projectId}/?isActive=${isActive}&pageSize=${pageSize}&pageNumber=${pageNumber}&searchString=${searchString}` ); - }, + }, + GetBranchDetail: (id) => api.get(`/api/ServiceProject/branch/details/${id}`), DeleteBranch: (id) => api.delete(`/api/ServiceProject/branch/delete/${id}`), }; - From 7e4dffff34ea1d2b01aefb28f029440b02e5e703 Mon Sep 17 00:00:00 2001 From: Kartik Sharma Date: Wed, 19 Nov 2025 18:47:30 +0530 Subject: [PATCH 15/58] Implementing Get api. --- .../ServiceProject/ServiceBranch.jsx | 35 +++++++++++-------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/src/components/ServiceProject/ServiceBranch.jsx b/src/components/ServiceProject/ServiceBranch.jsx index 982b4ab4..fc0bf1ac 100644 --- a/src/components/ServiceProject/ServiceBranch.jsx +++ b/src/components/ServiceProject/ServiceBranch.jsx @@ -22,12 +22,11 @@ const ServiceBranch = () => { const { data, isLoading, isError, error } = useBranches( projectId, - debouncedSearch || null, - null, + true, + ITEMS_PER_PAGE, currentPage, - ITEMS_PER_PAGE + debouncedSearch, ); - const paginate = (page) => { if (page >= 1 && page <= (data?.totalPages ?? 1)) { setCurrentPage(page); @@ -68,30 +67,38 @@ const ServiceBranch = () => {
{/* {Array.isArray(filteredData) && filteredData.length > 0 && ( */} - +
{ServiceBranch.map((col) => ( - ))} - - {/* + {isLoading ? ( + ) : isError ? ( + + + ) : data?.data?.length > 0 ? ( data.data.map((branch) => ( - - - + + {ServiceBranch.map((col) => ( + + ))} )) @@ -112,9 +119,7 @@ const ServiceBranch = () => { )} - */} - - +
+ {col.label} Action
Loading...
+ {error?.message || "Error loading branches"} +
{branch.branchName}
+ {col.getValue(branch)} + { branchId: branch.id, }) } - > + />
{/* )} */} {/* {!filteredData || From e7fddd41c2fb0f1606ecf6578ba7ee089cf47be2 Mon Sep 17 00:00:00 2001 From: "pramod.mahajan" Date: Wed, 19 Nov 2025 21:28:01 +0530 Subject: [PATCH 16/58] added branch for projects --- .../PaymentRequest/ActionPaymentRequest.jsx | 1 - .../Infrastructure/EditActivityModal.jsx | 1 - src/components/ServiceProject/BranchSchema.js | 43 ---- .../ServiceProject/ManageBranch.jsx | 186 ------------------ src/components/ServiceProject/ManageJob.jsx | 11 +- .../ServiceProject/ManageJobTicket.jsx | 10 +- .../ServiceProject/ServiceBranch.jsx | 162 --------------- .../ServiceProject/ServiceProfile.jsx | 95 +++++++++ .../ServiceProjectBranch/ManageBranch.jsx | 183 +++++++++++++++++ .../ServiceProjectBranch/ServiceBranch.jsx | 174 ++++++++++++++++ .../ServiceProject/ServiceProjectProfile.jsx | 108 ++-------- .../ServiceProject/ServiceProjectSchema.jsx | 55 ++++++ src/components/Tenant/SubScriptionHistory.jsx | 3 +- src/components/Tenant/TenantForm.jsx | 2 - .../common/Forms/SelectFieldServerSide.jsx | 40 +++- .../common/GlobalModal/CommentEditor.jsx | 1 - src/hooks/useProjects.js | 1 - src/hooks/useServiceProject.jsx | 1 - 18 files changed, 571 insertions(+), 506 deletions(-) delete mode 100644 src/components/ServiceProject/BranchSchema.js delete mode 100644 src/components/ServiceProject/ManageBranch.jsx delete mode 100644 src/components/ServiceProject/ServiceBranch.jsx create mode 100644 src/components/ServiceProject/ServiceProfile.jsx create mode 100644 src/components/ServiceProject/ServiceProjectBranch/ManageBranch.jsx create mode 100644 src/components/ServiceProject/ServiceProjectBranch/ServiceBranch.jsx diff --git a/src/components/PaymentRequest/ActionPaymentRequest.jsx b/src/components/PaymentRequest/ActionPaymentRequest.jsx index 5f3cc1d9..52222b55 100644 --- a/src/components/PaymentRequest/ActionPaymentRequest.jsx +++ b/src/components/PaymentRequest/ActionPaymentRequest.jsx @@ -40,7 +40,6 @@ const ActionPaymentRequest = ({ requestId }) => { error: PaymentModeError, } = usePaymentMode(); - console.log("Kartik", data) const IsReview = useHasUserPermission(REVIEW_EXPENSE); const [imageLoaded, setImageLoaded] = useState({}); diff --git a/src/components/Project/Infrastructure/EditActivityModal.jsx b/src/components/Project/Infrastructure/EditActivityModal.jsx index e57b6a30..14e66020 100644 --- a/src/components/Project/Infrastructure/EditActivityModal.jsx +++ b/src/components/Project/Infrastructure/EditActivityModal.jsx @@ -82,7 +82,6 @@ const EditActivityModal = ({ useEffect(() => { if (!workItem) return; - console.log(workItem) reset({ activityID: String( workItem?.workItem?.activityId || workItem?.activityMaster?.id diff --git a/src/components/ServiceProject/BranchSchema.js b/src/components/ServiceProject/BranchSchema.js deleted file mode 100644 index 346654d3..00000000 --- a/src/components/ServiceProject/BranchSchema.js +++ /dev/null @@ -1,43 +0,0 @@ -import { z } from "zod"; - -export const BranchSchema = () => - z.object({ - projectId: z - .string() - .trim() - .min(1, { message: "Project is required" }), - - branchName: z - .string() - .trim() - .min(1, { message: "Branch Name is required" }), - - contactInformation: z - .string() - .trim() - .min(1, { message: "Contact Information is required" }), - - address: z - .string() - .trim() - .min(1, { message: "Address is required" }), - - branchType: z - .string() - .trim() - .min(1, { message: "Branch Type is required" }), - - googleMapUrl: z - .string() - .trim() - .url({ message: "Enter a valid Google Map URL" }), - }); - -export const defaultBranches = { - branchName: "", - projectId: "", - contactInformation: "", - address: "", - branchType: "", - googleMapUrl: "", -}; \ No newline at end of file diff --git a/src/components/ServiceProject/ManageBranch.jsx b/src/components/ServiceProject/ManageBranch.jsx deleted file mode 100644 index 70257710..00000000 --- a/src/components/ServiceProject/ManageBranch.jsx +++ /dev/null @@ -1,186 +0,0 @@ -import React, { useEffect } from 'react' -import { useProjectName } from '../../hooks/useProjects'; -import { BranchSchema, defaultBranches } from './BranchSchema'; -import { useForm } from 'react-hook-form'; -import { zodResolver } from '@hookform/resolvers/zod'; -import Label from '../common/Label'; -import { useCreateBranch, useServiceProjects, useUpdateBranch } from '../../hooks/useServiceProject'; -import { useAppForm } from '../../hooks/appHooks/useAppForm'; -import { useParams } from 'react-router-dom'; - -const ManageBranch = ({ closeModal, BranchToEdit = null }) => { - const { data } = {} - const { projectId } = useParams(); - const schema = BranchSchema(); - const { - register, - control, - watch, - handleSubmit, - setValue, - reset, - formState: { errors }, - } = useAppForm({ - resolver: zodResolver(schema), - defaultValues: { - ...defaultBranches, - projectId: projectId || "" - }, - }); - - const handleClose = () => { - reset(); - closeModal(); - }; - - useEffect(() => { - if (BranchToEdit && data) { - reset({ - branchName: data.branchName || "", - projectId: data.project?.id || projectId || "", - contactInformation: data.contactInformation || "", - address: data.address || "", - branchType: data.branchType || "", - googleMapUrl: data.googleMapUrl || "", - }); - } - }, [data, reset]); - - const { mutate: CreateServiceBranch, isPending: createPending } = - useCreateBranch(() => { - handleClose(); - }); - const { mutate: ServiceBranchUpdate, isPending } = - useUpdateBranch(() => handleClose()); - - const onSubmit = (fromdata) => { - let payload = { - ...fromdata, projectId, - }; - if (BranchToEdit) { - const editPayload = { ...payload, id: data.id }; - ServiceBranchUpdate({ id: data.id, payload: editPayload }); - } else { - CreateServiceBranch(payload); - } - }; - - return ( -
-
- {BranchToEdit - ? "Update Branch" - : "Create Branch"} -
- -
- -
- - - {errors.branchName && ( - {errors.branchName.message} - )} -
-
- - - {errors.contactInformation && ( - {errors.contactInformation.message} - )} -
-
- -
- - -
- - - {errors.address && ( - {errors.address.message} - )} -
-
- - - {errors.branchType && ( - {errors.branchType.message} - )} -
-
- - -
- - -
- - - {errors.googleMapUrl && ( - {errors.googleMapUrl.message} - )} -
-
- -
- - - -
- - - - -
- ) -} - -export default ManageBranch diff --git a/src/components/ServiceProject/ManageJob.jsx b/src/components/ServiceProject/ManageJob.jsx index 97cd1a97..6ec96e3b 100644 --- a/src/components/ServiceProject/ManageJob.jsx +++ b/src/components/ServiceProject/ManageJob.jsx @@ -41,7 +41,8 @@ const ManageJob = ({ Job }) => { control, watch, handleSubmit, - reset,setValue, + reset, + setValue, formState: { errors }, } = methods; @@ -164,6 +165,7 @@ const ManageJob = ({ Job }) => { dueDate: JobData.dueDate ?? null, tags: JobData.tags ?? [], statusId: JobData.status.id, + branchId : JobData?.projectBranch?.id }); }, [JobData, Job, projectId]); return ( @@ -201,7 +203,7 @@ const ManageJob = ({ Job }) => { />
- + { name="tags" label="Tag" placeholder="Enter Tag" - />
setValue("branchId", val)} valueKey="id" labelKey="branchName" - hookParams={[projectId,true,10,1]} + hookParams={[projectId, true, 10, 1]} useFetchHook={useBranches} isMultiple={false} + disabled={Job} />
diff --git a/src/components/ServiceProject/ManageJobTicket.jsx b/src/components/ServiceProject/ManageJobTicket.jsx index 9dbf0b9f..c589509c 100644 --- a/src/components/ServiceProject/ManageJobTicket.jsx +++ b/src/components/ServiceProject/ManageJobTicket.jsx @@ -124,10 +124,16 @@ const ManageJobTicket = ({ Job }) => { ); })()}
+
+ + {" "} + Branch Name : + +
- Created By + Created By
{ {data?.assignees?.length > 0 && (
- Assigned To + Assigned To
diff --git a/src/components/ServiceProject/ServiceBranch.jsx b/src/components/ServiceProject/ServiceBranch.jsx deleted file mode 100644 index fc0bf1ac..00000000 --- a/src/components/ServiceProject/ServiceBranch.jsx +++ /dev/null @@ -1,162 +0,0 @@ -import React, { useState } from 'react' -import GlobalModel from '../common/GlobalModel'; -import ManageBranch from './ManageBranch'; -import { Pagination } from 'swiper/modules'; -import { useBranches } from '../../hooks/useServiceProject'; -import { ITEMS_PER_PAGE } from '../../utils/constants'; -import { useDebounce } from '../../utils/appUtils'; -import { useParams } from 'react-router-dom'; - -const ServiceBranch = () => { - - const [ManageServiceBranch, setManageServiceBranch] = useState({ - IsOpen: null, - branchId: null, - }); - - const { projectId } = useParams(); - - const [search, setSearch] = useState(""); - const [currentPage, setCurrentPage] = useState(1); - const debouncedSearch = useDebounce(search, 500); - - const { data, isLoading, isError, error } = useBranches( - projectId, - true, - ITEMS_PER_PAGE, - currentPage, - debouncedSearch, - ); - const paginate = (page) => { - if (page >= 1 && page <= (data?.totalPages ?? 1)) { - setCurrentPage(page); - } - }; - - const ServiceBranch = [ - { - key: "branchName", - label: "Branch Name", - align: "text-start", - getValue: (e) => e?.branchName || "N/A", - }, - ]; - return ( -
-
-
-
- -
-
- - -
- {/* {Array.isArray(filteredData) && filteredData.length > 0 && ( */} - - - - {ServiceBranch.map((col) => ( - - ))} - - - - - {isLoading ? ( - - - - ) : isError ? ( - - - - ) : data?.data?.length > 0 ? ( - data.data.map((branch) => ( - - {ServiceBranch.map((col) => ( - - ))} - - - )) - ) : ( - - - - )} - -
- {col.label} - Action
- Loading... -
- {error?.message || "Error loading branches"} -
- {col.getValue(branch)} - - - setManageServiceBranch({ - IsOpen: true, - branchId: branch.id, - }) - } - /> -
- No Branch Found -
- {/* )} */} - {/* {!filteredData || - filteredData.length === 0 - && ( -
- {isError ? (

{error.message}

) : (

No Recurring Expense Found

)} -
- )} */} -
- - {ManageServiceBranch.IsOpen && ( - - setManageServiceBranch({ IsOpen: null, branchId: null }) - } - > - - setManageServiceBranch({ IsOpen: null, branchId: null }) - } - // requestToEdit={ManageServiceBranch.branchId} - /> - - )} - - {/* */} -
-
- ) -} - -export default ServiceBranch diff --git a/src/components/ServiceProject/ServiceProfile.jsx b/src/components/ServiceProject/ServiceProfile.jsx new file mode 100644 index 00000000..30864106 --- /dev/null +++ b/src/components/ServiceProject/ServiceProfile.jsx @@ -0,0 +1,95 @@ +import React from 'react' +import { formatUTCToLocalTime } from '../../utils/dateUtils' + +const ServiceProfile = ({data,setIsOpenModal}) => { + return ( +
+
+
+ {" "} + + Project Profile +
+
+
+
    + +
  • +
    + + Name: +
    + +
    + {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} +
    +
  • + + + +
  • + + + + + +
  • +
+ +
+
+ ) +} + +export default ServiceProfile diff --git a/src/components/ServiceProject/ServiceProjectBranch/ManageBranch.jsx b/src/components/ServiceProject/ServiceProjectBranch/ManageBranch.jsx new file mode 100644 index 00000000..34cc0530 --- /dev/null +++ b/src/components/ServiceProject/ServiceProjectBranch/ManageBranch.jsx @@ -0,0 +1,183 @@ +import React, { useEffect } from "react"; +import { useProjectName } from "../../../hooks/useProjects"; +import { useForm } from "react-hook-form"; +import { zodResolver } from "@hookform/resolvers/zod"; +import Label from "../../common/Label"; +import { + useCreateBranch, + useServiceProjects, + useUpdateBranch, +} from "../../../hooks/useServiceProject"; +import { useAppForm } from "../../../hooks/appHooks/useAppForm"; +import { useParams } from "react-router-dom"; +import { BranchSchema, defaultBranches } from "../ServiceProjectSchema"; + +const ManageBranch = ({ closeModal, BranchToEdit = null }) => { + const { data } = {}; + const { projectId } = useParams(); + const schema = BranchSchema(); + const { + register, + control, + watch, + handleSubmit, + setValue, + reset, + formState: { errors }, + } = useAppForm({ + resolver: zodResolver(schema), + defaultValues: { + ...defaultBranches, + projectId: projectId || "", + }, + }); + + const handleClose = () => { + reset(); + closeModal(); + }; + + useEffect(() => { + if (BranchToEdit && data) { + reset({ + branchName: data.branchName || "", + projectId: data.project?.id || projectId || "", + contactInformation: data.contactInformation || "", + address: data.address || "", + branchType: data.branchType || "", + googleMapUrl: data.googleMapUrl || "", + }); + } + }, [data, reset]); + + const { mutate: CreateServiceBranch, isPending: createPending } = + useCreateBranch(() => { + handleClose(); + }); + const { mutate: ServiceBranchUpdate, isPending } = useUpdateBranch(() => + handleClose() + ); + + const onSubmit = (fromdata) => { + let payload = { + ...fromdata, + projectId, + }; + if (BranchToEdit) { + const editPayload = { ...payload, id: data.id }; + ServiceBranchUpdate({ id: data.id, payload: editPayload }); + } else { + CreateServiceBranch(payload); + } + }; + + return ( +
+
+ {BranchToEdit ? "Update Branch" : "Create Branch"} +
+
+
+
+ + + {errors.branchName && ( + {errors.branchName.message} + )} +
+
+ + + {errors.contactInformation && ( + + {errors.contactInformation.message} + + )} +
+
+ +
+ +
+ + + {errors.branchType && ( + {errors.branchType.message} + )} +
+
+ + + {errors.googleMapUrl && ( + + {errors.googleMapUrl.message} + + )} +
+
+ +
+ +
+ + + + {errors?.comment && ( + {errors?.comment?.message} + )} +
+
+ {/*
+ {files?.length > 0 && ( + + )} +
*/} +
+
document.getElementById("attachments").click()} + className="cursor-pointer" + style={{ whiteSpace: "nowrap" }} + > + { + onFileChange(e); + e.target.value = ""; + }} + /> + + Add Attachment +
+ + +
+
+
+ ); +}; + +export default UpdateJobComment; diff --git a/src/components/ServiceProject/ServiceProjectSeketon.jsx b/src/components/ServiceProject/ServiceProjectSeketon.jsx new file mode 100644 index 00000000..b4b3a93e --- /dev/null +++ b/src/components/ServiceProject/ServiceProjectSeketon.jsx @@ -0,0 +1,138 @@ +import React from "react"; + +const SkeletonLine = ({ height = 18, width = "100%", className = "" }) => ( +
+); + +export const BranchDetailsSkeleton = () => { + return ( +
+
+ +
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ + +
+
+
+ ); +}; + +export const JobDetailsSkeleton = () => { + return ( +
+
+ {/* Title */} + + + {/* Job ID + Status */} +
+ +
+ + +
+
+ + {/* Description */} + + + {/* Created Date */} +
+ +
+ + {/* Start / Due Date */} +
+ + +
+ + {/* Branch Name */} +
+ + +
+ + {/* Created By */} +
+
+ +
+ +
+ {/* Avatar */} + +
+
+ + {/* Assigned To */} +
+
+ +
+
+ + {/* Tabs */} +
+
+ + + +
+ + +
+
+
+ ); +}; diff --git a/src/router/AppRoutes.jsx b/src/router/AppRoutes.jsx index 1c95ec64..3ef8131b 100644 --- a/src/router/AppRoutes.jsx +++ b/src/router/AppRoutes.jsx @@ -60,7 +60,7 @@ import PaymentRequestPage from "../pages/PaymentRequest/PaymentRequestPage"; import RecurringExpensePage from "../pages/RecurringExpense/RecurringExpensePage"; import AdvancePaymentPage from "../pages/AdvancePayment/AdvancePaymentPage"; import ServiceProjectDetail from "../pages/ServiceProject/ServiceProjectDetail"; -import ManageJob from "../components/ServiceProject/ManageJob"; +import ManageJob from "../components/ServiceProject/ServiceProjectJob/ManageJob"; const router = createBrowserRouter( [ { From 5b86a2f64f5c27b1d721cf4db88b40ea74906b0a Mon Sep 17 00:00:00 2001 From: "pramod.mahajan" Date: Thu, 20 Nov 2025 09:50:49 +0530 Subject: [PATCH 19/58] removed console error --- src/components/Layout/Sidebar.jsx | 10 ++-- .../ServiceProjectJob/ManageJobTicket.jsx | 59 +------------------ 2 files changed, 8 insertions(+), 61 deletions(-) diff --git a/src/components/Layout/Sidebar.jsx b/src/components/Layout/Sidebar.jsx index 1f4b63b8..4fa7cd9f 100644 --- a/src/components/Layout/Sidebar.jsx +++ b/src/components/Layout/Sidebar.jsx @@ -25,8 +25,7 @@ const Sidebar = () => { /> */} - @@ -35,12 +34,13 @@ const Sidebar = () => { OnField Work .com - + - + + - +
diff --git a/src/components/ServiceProject/ServiceProjectJob/ManageJobTicket.jsx b/src/components/ServiceProject/ServiceProjectJob/ManageJobTicket.jsx index 1041d93c..12428c77 100644 --- a/src/components/ServiceProject/ServiceProjectJob/ManageJobTicket.jsx +++ b/src/components/ServiceProject/ServiceProjectJob/ManageJobTicket.jsx @@ -145,62 +145,9 @@ const ManageJobTicket = ({ Job }) => {
)} -
-
-
- Created By -
-
- {" "} -
-

{`${data?.createdBy?.firstName} ${data?.createdBy?.lastName}`}

- - ({data?.createdBy?.jobRoleName}) - -
-
-
- - {data?.assignees?.length > 0 && ( -
-
- Assigned To -
- -
-
- {data?.assignees?.map((emp) => ( -
-
- - -
- - {emp.firstName} {emp.lastName} - - - {emp.jobRoleName} - -
-
-
- ))} -
-
-
- )} -
+
+ People +
From dd716187da267263557fac390a222807ce6e58bf Mon Sep 17 00:00:00 2001 From: Kartik Sharma Date: Thu, 20 Nov 2025 09:51:23 +0530 Subject: [PATCH 20/58] Implementing edit api for branches. --- .../ServiceProjectBranch/ManageBranch.jsx | 17 +- .../ServiceProjectBranch/ServiceBranch.jsx | 320 ++++++++++++------ src/hooks/useServiceProject.jsx | 51 +-- src/repositories/ServiceProjectRepository.jsx | 10 +- 4 files changed, 255 insertions(+), 143 deletions(-) diff --git a/src/components/ServiceProject/ServiceProjectBranch/ManageBranch.jsx b/src/components/ServiceProject/ServiceProjectBranch/ManageBranch.jsx index 34cc0530..11bcdafd 100644 --- a/src/components/ServiceProject/ServiceProjectBranch/ManageBranch.jsx +++ b/src/components/ServiceProject/ServiceProjectBranch/ManageBranch.jsx @@ -4,6 +4,7 @@ import { useForm } from "react-hook-form"; import { zodResolver } from "@hookform/resolvers/zod"; import Label from "../../common/Label"; import { + useBranchDetails, useCreateBranch, useServiceProjects, useUpdateBranch, @@ -13,7 +14,13 @@ import { useParams } from "react-router-dom"; import { BranchSchema, defaultBranches } from "../ServiceProjectSchema"; const ManageBranch = ({ closeModal, BranchToEdit = null }) => { - const { data } = {}; + const { + data, + isLoading, + isError, + error: requestError, + } = useBranchDetails(BranchToEdit); + const { projectId } = useParams(); const schema = BranchSchema(); const { @@ -112,7 +119,7 @@ const ManageBranch = ({ closeModal, BranchToEdit = null }) => {
- +
-
+
@@ -146,7 +153,7 @@ const ManageBranch = ({ closeModal, BranchToEdit = null }) => {
- +
diff --git a/src/components/ServiceProject/ServiceProjectBranch/ServiceBranch.jsx b/src/components/ServiceProject/ServiceProjectBranch/ServiceBranch.jsx index 0cae102a..e168778b 100644 --- a/src/components/ServiceProject/ServiceProjectBranch/ServiceBranch.jsx +++ b/src/components/ServiceProject/ServiceProjectBranch/ServiceBranch.jsx @@ -1,19 +1,24 @@ import React, { useState } from "react"; import GlobalModel from "../../common/GlobalModel"; import ManageBranch from "./ManageBranch"; -import { useBranches } from "../../../hooks/useServiceProject"; +import { useBranches, useDeleteBranch } from "../../../hooks/useServiceProject"; import { ITEMS_PER_PAGE } from "../../../utils/constants"; import { useDebounce } from "../../../utils/appUtils"; import { useParams } from "react-router-dom"; import Pagination from "../../common/Pagination"; +import ConfirmModal from "../../common/ConfirmModal"; +import { SpinnerLoader } from "../../common/Loader"; const ServiceBranch = () => { const { projectId } = useParams(); - + const [IsDeleteModalOpen, setIsDeleteModalOpen] = useState(false); + const [showInactive, setShowInactive] = useState(false); const [manageState, setManageState] = useState({ IsOpen: false, branchId: null, }); + const { mutate: DeleteBranch, isPending } = useDeleteBranch(); + const [deletingId, setDeletingId] = useState(null); const [search, setSearch] = useState(""); const [currentPage, setCurrentPage] = useState(1); @@ -21,7 +26,8 @@ const ServiceBranch = () => { const { data, isLoading, isError, error } = useBranches( projectId, - true, + // true, + !showInactive, ITEMS_PER_PAGE - 10, currentPage, debouncedSearch @@ -42,132 +48,222 @@ const ServiceBranch = () => { }, ]; + const handleDelete = (id) => { + setDeletingId(id); + DeleteBranch( + { id, isActive: false }, + { + onSettled: () => { + setDeletingId(null); + setIsDeleteModalOpen(false); + }, + } + ); + }; return ( -
-
- {/* Header Section */} -
-
-
- - Branches -
+ <> + {IsDeleteModalOpen && ( + setIsDeleteModalOpen(false)} + loading={isPending} + paramData={deletingId} + /> + )} +
+
+ {/* Header Section */} +
+
+
+ + Branch +
+
+ + {/* Flex container for toggle + button */} +
+
+ + {/* Toggle Switch */} +
+ setShowInactive(!showInactive)} + /> + +
+ + {/* Add Branch Button */} + + +
+
+
-
- -
-
- -
- - - - {columns.map((col) => ( - - ))} - - - - - - {isLoading && ( +
+
- {col.label} - Action
+ - + {columns.map((col) => ( + + ))} + - )} + - {isError && ( - - - - )} - - {!isLoading && - !isError && - data?.data?.length > 0 && - data.data.map((branch) => ( - - {columns.map((col) => ( - - ))} - - - ))} - - {!isLoading && - !isError && - (!data?.data || data.data.length === 0) && ( + + {isLoading && ( )} - -
- Loading... - + {col.label} + Action
- {error?.message || "Error loading branches"} -
- {col.getValue(branch)} - - - setManageState({ - IsOpen: true, - branchId: branch.id, - }) - } - /> -
- No Branch Found +
+ +
- {data?.data?.length > 0 && ( - + + {isError && ( + + + {error?.message || "Error loading branches"} + + + )} + + {!isLoading && + !isError && + data?.data?.length > 0 && + data.data.map((branch) => ( + + {columns.map((col) => ( + + {col.getValue(branch)} + + ))} + +
+ + +
    + {/* Modify */} +
  • + setManageState({ + IsOpen: true, + branchId: branch.id, + }) + } + > + + + Modify + +
  • + + {/* Delete */} +
  • { + setIsDeleteModalOpen(true); + setDeletingId(branch.id); + }} + > + + + Delete + +
  • +
+
+ + + + ))} + + {!isLoading && + !isError && + (!data?.data || data.data.length === 0) && ( + + + No Branch Found + + + )} + + + + {data?.data?.length > 0 && ( + + )} +
+ + {manageState.IsOpen && ( + setManageState({ IsOpen: false, branchId: null })} + > + + setManageState({ IsOpen: false, branchId: null }) + } + /> + + )}
- - {manageState.IsOpen && ( - setManageState({ IsOpen: false, branchId: null })} - > - - setManageState({ IsOpen: false, branchId: null }) - } - /> - - )}
-
+ ); }; diff --git a/src/hooks/useServiceProject.jsx b/src/hooks/useServiceProject.jsx index 3278fa2a..93817800 100644 --- a/src/hooks/useServiceProject.jsx +++ b/src/hooks/useServiceProject.jsx @@ -315,12 +315,12 @@ export const useBranches = ( }; -export const useBranch = (id)=>{ +export const useBranchDetails = (id) => { return useQuery({ queryKey: ["branch", id], queryFn: async () => { const resp = await ServiceProjectRepository.GetBranchDetail(id); - return resp.data ?? resp; + return resp.data; }, enabled: !!id }) @@ -346,37 +346,42 @@ export const useCreateBranch = (onSuccessCallBack) => { }, }); }; - -export const useUpdateBranch = () => { +export const useUpdateBranch = (onSuccessCallBack) => { const queryClient = useQueryClient(); return useMutation({ - mutationFn: async ({ id, payload }) => await ServiceProjectRepository.UpdateBranch(id, payload), + mutationFn: async ({ id, payload }) => + await ServiceProjectRepository.UpdateBranch(id, payload), + onSuccess: (_, variables) => { + // remove old single-branch cache + queryClient.removeQueries({ queryKey: ["branch", variables.id] }); + + // refresh list queryClient.invalidateQueries({ queryKey: ["branches"] }); - queryClient.invalidateQueries({ queryKey: ["branch", variables.id] }); - if (onSuccessCallback) onSuccessCallback(); - showToast("Branch Updated successfully", "success"); + + showToast("Branch updated successfully", "success"); + onSuccessCallBack?.(); }, - onError: (error) => { - showToast( - error?.response?.data?.message || - error.message || - "Failed to update branch", - "error" - ); + + onError: () => { + showToast("Something went wrong. Please try again later.", "error"); }, - }) -} + }); +}; + export const useDeleteBranch = () => { const queryClient = useQueryClient(); + return useMutation({ - mutationFn: async (id) => await ServiceProjectRepository.DeleteBranch(id), - onSuccess: (_, variables) => { + mutationFn: async ({ id, isActive}) => + await ServiceProjectRepository.DeleteBranch(id, isActive), + + onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["branches"] }); - if (onSuccessCallback) onSuccessCallback(); - showToast("Branch Deleted successfully", "success"); + showToast("Branch deleted successfully", "success"); }, + onError: (error) => { showToast( error?.response?.data?.message || @@ -385,5 +390,5 @@ export const useDeleteBranch = () => { "error" ); }, - }) -} \ No newline at end of file + }); +}; diff --git a/src/repositories/ServiceProjectRepository.jsx b/src/repositories/ServiceProjectRepository.jsx index 1fa29fa9..23fe8b38 100644 --- a/src/repositories/ServiceProjectRepository.jsx +++ b/src/repositories/ServiceProjectRepository.jsx @@ -1,3 +1,4 @@ +import { isAction } from "@reduxjs/toolkit"; import { api } from "../utils/axiosClient"; export const ServiceProjectRepository = { @@ -43,14 +44,17 @@ export const ServiceProjectRepository = { //#region Project Branch CreateBranch: (data) => api.post(`/api/ServiceProject/branch/create`, data), UpdateBranch: (id, data) => - api.put("/api/ServiceProject/branch/edit/${id}", data), + api.put(`/api/ServiceProject/branch/edit/${id}`, data), + GetBranchList: (projectId, isActive, pageSize, pageNumber, searchString) => { return api.get( `/api/ServiceProject/branch/list/${projectId}?isActive=${isActive}&pageSize=${pageSize}&pageNumber=${pageNumber}&searchString=${searchString}` ); - }, + }, GetBranchDetail: (id) => api.get(`/api/ServiceProject/branch/details/${id}`), - DeleteBranch: (id) => api.delete(`/api/ServiceProject/branch/delete/${id}`), + DeleteBranch: (id, isActive = false) => + api.delete(`/api/ServiceProject/branch/delete/${id}?isActive=${isActive}`), + }; From 195a0c83bb8a0fea2bb634cb6efea183703821d6 Mon Sep 17 00:00:00 2001 From: Kartik Sharma Date: Thu, 20 Nov 2025 10:00:06 +0530 Subject: [PATCH 21/58] Correction in api for details. --- .../ServiceProject/ServiceProjectBranch/BranchDetails.jsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/ServiceProject/ServiceProjectBranch/BranchDetails.jsx b/src/components/ServiceProject/ServiceProjectBranch/BranchDetails.jsx index 66bd700c..2aefa4ad 100644 --- a/src/components/ServiceProject/ServiceProjectBranch/BranchDetails.jsx +++ b/src/components/ServiceProject/ServiceProjectBranch/BranchDetails.jsx @@ -1,5 +1,5 @@ import React, { useState } from "react"; -import { useBranch } from "../../../hooks/useServiceProject"; +import { useBranchDetails } from "../../../hooks/useServiceProject"; import { SpinnerLoader } from "../../common/Loader"; import Error from "../../common/Error"; import { BranchDetailsSkeleton } from "../ServiceProjectSeketon"; @@ -7,7 +7,7 @@ import { BranchDetailsSkeleton } from "../ServiceProjectSeketon"; const BranchDetails = ({ branch }) => { const [copied, setCopied] = useState(false); - const { data, isLoading, isError, error } = useBranch(branch); + const { data, isLoading, isError, error } = useBranchDetails(branch); const googleMapUrl = data?.googleMapUrl || data?.locationLink; From d3c006279c7614ec0f1f377b08e3b61805682071 Mon Sep 17 00:00:00 2001 From: Kartik Sharma Date: Thu, 20 Nov 2025 10:29:42 +0530 Subject: [PATCH 22/58] Increasing the size of Service details page. --- .../ServiceProject/ServiceProjectBranch/ServiceBranch.jsx | 4 +--- src/components/ServiceProject/ServiceProjectProfile.jsx | 4 ++-- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/components/ServiceProject/ServiceProjectBranch/ServiceBranch.jsx b/src/components/ServiceProject/ServiceProjectBranch/ServiceBranch.jsx index e168778b..0655247f 100644 --- a/src/components/ServiceProject/ServiceProjectBranch/ServiceBranch.jsx +++ b/src/components/ServiceProject/ServiceProjectBranch/ServiceBranch.jsx @@ -117,10 +117,8 @@ const ServiceBranch = () => { Add Branch -
-
@@ -170,7 +168,7 @@ const ServiceBranch = () => { !isError && data?.data?.length > 0 && data.data.map((branch) => ( - + {columns.map((col) => ( {col.getValue(branch)} diff --git a/src/components/ServiceProject/ServiceProjectProfile.jsx b/src/components/ServiceProject/ServiceProjectProfile.jsx index 2a04be99..6ef359ff 100644 --- a/src/components/ServiceProject/ServiceProjectProfile.jsx +++ b/src/components/ServiceProject/ServiceProjectProfile.jsx @@ -33,11 +33,11 @@ const ServiceProjectProfile = () => { )}
-
+
-
+
From d167c57ab01c5fc7210a002ec54b0dde85acad6c Mon Sep 17 00:00:00 2001 From: Kartik Sharma Date: Thu, 20 Nov 2025 12:34:45 +0530 Subject: [PATCH 23/58] Implementing the Update api for branches. --- .../ServiceProjectBranch/ManageBranch.jsx | 221 +++++++++++++++--- .../ServiceProject/ServiceProjectSchema.jsx | 8 +- 2 files changed, 196 insertions(+), 33 deletions(-) diff --git a/src/components/ServiceProject/ServiceProjectBranch/ManageBranch.jsx b/src/components/ServiceProject/ServiceProjectBranch/ManageBranch.jsx index 11bcdafd..720fa08f 100644 --- a/src/components/ServiceProject/ServiceProjectBranch/ManageBranch.jsx +++ b/src/components/ServiceProject/ServiceProjectBranch/ManageBranch.jsx @@ -21,6 +21,15 @@ const ManageBranch = ({ closeModal, BranchToEdit = null }) => { error: requestError, } = useBranchDetails(BranchToEdit); + const [contacts, setContacts] = React.useState([ + { + contactPerson: "", + designation: "", + contactEmails: [""], + contactNumbers: [""] + } + ]); + const { projectId } = useParams(); const schema = BranchSchema(); const { @@ -49,14 +58,22 @@ const ManageBranch = ({ closeModal, BranchToEdit = null }) => { reset({ branchName: data.branchName || "", projectId: data.project?.id || projectId || "", - contactInformation: data.contactInformation || "", address: data.address || "", branchType: data.branchType || "", googleMapUrl: data.googleMapUrl || "", }); + + if (data.contactInformation) { + try { + setContacts(JSON.parse(data.contactInformation)); + } catch { + setContacts([]); + } + } } }, [data, reset]); + const { mutate: CreateServiceBranch, isPending: createPending } = useCreateBranch(() => { handleClose(); @@ -65,19 +82,23 @@ const ManageBranch = ({ closeModal, BranchToEdit = null }) => { handleClose() ); - const onSubmit = (fromdata) => { + const onSubmit = (formdata) => { let payload = { - ...fromdata, + ...data, + ...formdata, projectId, + contactInformation: JSON.stringify(contacts), // ← important }; + if (BranchToEdit) { - const editPayload = { ...payload, id: data.id }; - ServiceBranchUpdate({ id: data.id, payload: editPayload }); + ServiceBranchUpdate({ id: data.id, payload }); } else { CreateServiceBranch(payload); } }; + + return (
@@ -100,26 +121,6 @@ const ManageBranch = ({ closeModal, BranchToEdit = null }) => { {errors.branchName.message} )}
-
- - - {errors.contactInformation && ( - - {errors.contactInformation.message} - - )} -
-
- -
-
+
+ +
+ +
-
+
+
+ + + {contacts.map((item, index) => ( +
+ + {/* Contact Person + Designation */} +
+
+ { + const list = [...contacts]; + list[index].contactPerson = e.target.value; + setContacts(list); + }} + /> +
+ +
+ { + const list = [...contacts]; + list[index].designation = e.target.value; + setContacts(list); + }} + /> +
+ + {/* Remove entire contact */} +
+ + setContacts(contacts.filter((_, i) => i !== index)) + } + > +
+
+ + {/* Numbers Section */} + + + {item.contactNumbers.map((num, numIndex) => ( +
+ + { + const value = e.target.value.replace(/\D/g, ""); // remove non-digit characters + const list = [...contacts]; + list[index].contactNumbers[numIndex] = value; + setContacts(list); + }} + /> + + {/* Show PLUS only on last row */} + {numIndex === item.contactNumbers.length - 1 ? ( + { + const list = [...contacts]; + list[index].contactNumbers.push(""); + setContacts(list); + }} + > + ) : ( + { + const list = [...contacts]; + list[index].contactNumbers.splice(numIndex, 1); + setContacts(list); + }} + > + )} + +
+ ))} + +
+ + {/* Emails Section */} + + + {item.contactEmails.map((email, emailIndex) => ( +
+ + { + const list = [...contacts]; + list[index].contactEmails[emailIndex] = e.target.value; + setContacts(list); + }} + /> + + {/* Show PLUS only on the last row */} + {emailIndex === item.contactEmails.length - 1 ? ( + { + const list = [...contacts]; + list[index].contactEmails.push(""); + setContacts(list); + }} + > + ) : ( + { + const list = [...contacts]; + list[index].contactEmails.splice(emailIndex, 1); + setContacts(list); + }} + > + )} + +
+ ))} + + +
+ ))} + + + + +
+
+ +
diff --git a/src/components/ServiceProject/ServiceProjectSchema.jsx b/src/components/ServiceProject/ServiceProjectSchema.jsx index dc8a6713..589f1497 100644 --- a/src/components/ServiceProject/ServiceProjectSchema.jsx +++ b/src/components/ServiceProject/ServiceProjectSchema.jsx @@ -138,11 +138,7 @@ export const BranchSchema = () => .trim() .min(1, { message: "Branch Name is required" }), - contactInformation: z - .string() - .trim() - .min(1, { message: "Contact Information is required" }), - + contactInformation: z.string().optional(), address: z .string() .trim() @@ -155,8 +151,6 @@ export const BranchSchema = () => googleMapUrl: z .string() - .trim() - .url({ message: "Enter a valid Google Map URL" }), }); export const defaultBranches = { From 047e563505632736383e0955b3d59d83fa9e22a6 Mon Sep 17 00:00:00 2001 From: "pramod.mahajan" Date: Thu, 20 Nov 2025 12:49:56 +0530 Subject: [PATCH 24/58] added mutiple contact person inside branch --- .../Dashboard/ProjectCompletionChart.jsx | 14 +- .../ServiceProjectBranch/BranchDetails.jsx | 71 ++---- .../ServiceProjectBranch/ServiceBranch.jsx | 76 +++---- .../ServiceProjectJob/JobComments.jsx | 2 +- .../ServiceProjectJob/ManageJobTicket.jsx | 100 +++++++-- src/components/common/HoverPopup.jsx | 38 +++- src/hooks/useDashboard_Data.jsx | 206 +++++------------- src/repositories/GlobalRepository.jsx | 2 + src/repositories/ProjectRepository.jsx | 1 + 9 files changed, 238 insertions(+), 272 deletions(-) diff --git a/src/components/Dashboard/ProjectCompletionChart.jsx b/src/components/Dashboard/ProjectCompletionChart.jsx index b8c656b8..f1f63936 100644 --- a/src/components/Dashboard/ProjectCompletionChart.jsx +++ b/src/components/Dashboard/ProjectCompletionChart.jsx @@ -2,15 +2,19 @@ import React, { useState } from "react"; import HorizontalBarChart from "../Charts/HorizontalBarChart"; import { useProjects } from "../../hooks/useProjects"; import { ITEMS_PER_PAGE } from "../../utils/constants"; +import { useProjectCompletionStatus } from "../../hooks/useDashboard_Data"; const ProjectCompletionChart = () => { - const [currentPage, setCurrentPage] = useState(1); - const { data: projects, isLoading: loading, isError, error } = useProjects(50,currentPage); - // Bar chart logic - const projectNames = projects?.data?.map((p) => p.name) || []; + const { + data: projects, + isLoading: loading, + isError, + error, + } = useProjectCompletionStatus(); + const projectNames = projects?.map((p) => p.name) || []; const projectProgress = - projects?.data?.map((p) => { + projects?.map((p) => { const completed = p.completedWork || 0; const planned = p.plannedWork || 1; const percent = planned ? (completed / planned) * 100 : 0; diff --git a/src/components/ServiceProject/ServiceProjectBranch/BranchDetails.jsx b/src/components/ServiceProject/ServiceProjectBranch/BranchDetails.jsx index 2aefa4ad..87d59b8c 100644 --- a/src/components/ServiceProject/ServiceProjectBranch/BranchDetails.jsx +++ b/src/components/ServiceProject/ServiceProjectBranch/BranchDetails.jsx @@ -27,59 +27,34 @@ const BranchDetails = ({ branch }) => {
); return ( -
-
- - Branch Details - -
-
-
Name:
-
{data?.branchName}
-
+<> +
+ + Branch Details + +
-
-
Type:
-
{data?.branchType}
-
-
-
Contact No:
-
{data?.contactInformation}
-
+
+
Contact No:
+
{data?.contactInformation}
+
-
-
Address:
-
{data?.address}
-
+
+
Type:
+
{data?.branchType}
+
- {googleMapUrl && ( -
-
Map:
+
+
Email:
+
{data?.email}
+
-
- - Open in Google Maps - +
+
Address:
+
{data?.address}
+
+ - - - {copied && Copied!} -
-
- )} -
); }; diff --git a/src/components/ServiceProject/ServiceProjectBranch/ServiceBranch.jsx b/src/components/ServiceProject/ServiceProjectBranch/ServiceBranch.jsx index 0655247f..cfa35f17 100644 --- a/src/components/ServiceProject/ServiceProjectBranch/ServiceBranch.jsx +++ b/src/components/ServiceProject/ServiceProjectBranch/ServiceBranch.jsx @@ -26,7 +26,6 @@ const ServiceBranch = () => { const { data, isLoading, isError, error } = useBranches( projectId, - // true, !showInactive, ITEMS_PER_PAGE - 10, currentPage, @@ -78,45 +77,47 @@ const ServiceBranch = () => {
{/* Header Section */}
-
+
- Branch + Branchs
{/* Flex container for toggle + button */} -
-
- - {/* Toggle Switch */} -
- setShowInactive(!showInactive)} - /> - -
- - {/* Add Branch Button */} - +
+
+ +
+ setShowInactive(!showInactive)} + /> + +
+
+ +
@@ -152,7 +153,6 @@ const ServiceBranch = () => { )} - {isError && ( {
- ))} @@ -247,7 +246,9 @@ const ServiceBranch = () => { setManageState({ IsOpen: false, branchId: null })} + closeModal={() => + setManageState({ IsOpen: false, branchId: null }) + } > { setManageState({ IsOpen: false, branchId: null }) } /> - )}
diff --git a/src/components/ServiceProject/ServiceProjectJob/JobComments.jsx b/src/components/ServiceProject/ServiceProjectJob/JobComments.jsx index 197aa729..4e1dfb9d 100644 --- a/src/components/ServiceProject/ServiceProjectJob/JobComments.jsx +++ b/src/components/ServiceProject/ServiceProjectJob/JobComments.jsx @@ -150,7 +150,7 @@ const JobComments = ({ data }) => { type="submit" disabled={!watch("comment")?.trim() || isPending} > - Submit + Send
diff --git a/src/components/ServiceProject/ServiceProjectJob/ManageJobTicket.jsx b/src/components/ServiceProject/ServiceProjectJob/ManageJobTicket.jsx index 12428c77..fd5c69da 100644 --- a/src/components/ServiceProject/ServiceProjectJob/ManageJobTicket.jsx +++ b/src/components/ServiceProject/ServiceProjectJob/ManageJobTicket.jsx @@ -47,7 +47,11 @@ const ManageJobTicket = ({ Job }) => {
); return ( -
+
{data?.title}
@@ -56,7 +60,7 @@ const ManageJobTicket = ({ Job }) => { {data?.jobTicketUId || "N/A"}

-
+
{data?.status?.displayName} @@ -65,6 +69,7 @@ const ManageJobTicket = ({ Job }) => { id="STATUS_CHANEG" Mode="click" className="" + align="right" content={ {

{data?.description || "N/A"}

-
-
+
+
{" "} Created Date : {formatUTCToLocalTime(data?.createdAt, true)}
+
+ {data?.tags?.map((tag, ind) => ( + + {tag?.name} + + ))} +
- + Start Date :{" "} {formatUTCToLocalTime(data?.startDate)} {" "} {" "} - + Due on :{" "} {formatUTCToLocalTime(data?.startDate)} @@ -117,7 +132,7 @@ const ManageJobTicket = ({ Job }) => { const { days, color } = daysLeft(data?.startDate, data?.dueDate); return ( - Days Left: + Days Left: {days !== null ? `${days} days` : "N/A"} @@ -125,29 +140,80 @@ const ManageJobTicket = ({ Job }) => { ); })()}
- {data?.projectBranch && ( -
- - Branch Name : + {/* {data?.projectBranch && ( +
+ + Branch Name: } > - + {data?.projectBranch?.branchName}
- )} + )} */} -
- People -
+
+

+ Peoples +

+ + {/* Created By */} +
+

Created By

+ +
+ +
+

+ {data?.createdBy?.firstName} {data?.createdBy?.lastName} +

+ + {data?.createdBy?.jobRoleName} + +
+
+
+ + {/* Assigned To */} +
+

Assigned To

+ +
+
+ {data?.assignees?.map((emp) => ( +
+ + +
+ + {emp.firstName} {emp.lastName} + + + {emp.jobRoleName} + +
+
+ ))} +
+
+
+
diff --git a/src/components/common/HoverPopup.jsx b/src/components/common/HoverPopup.jsx index 2093c25a..89716984 100644 --- a/src/components/common/HoverPopup.jsx +++ b/src/components/common/HoverPopup.jsx @@ -1,6 +1,10 @@ import React, { useEffect, useRef } from "react"; import { useDispatch, useSelector } from "react-redux"; -import { closePopup, openPopup, togglePopup } from "../../slices/localVariablesSlice"; +import { + closePopup, + openPopup, + togglePopup, +} from "../../slices/localVariablesSlice"; /** * align: "auto" | "left" | "right" @@ -63,7 +67,8 @@ const HoverPopup = ({ const popup = popupRef.current; // choose boundary: provided boundaryRef or nearest positioned parent (popup.parentElement) - const boundaryEl = (boundaryRef && boundaryRef.current) || popup.parentElement; + const boundaryEl = + (boundaryRef && boundaryRef.current) || popup.parentElement; if (!boundaryEl) return; const boundaryRect = boundaryEl.getBoundingClientRect(); @@ -75,15 +80,12 @@ const HoverPopup = ({ popup.style.transform = ""; popup.style.top = ""; - // default: place below trigger and center horizontally relative to parent - // We'll use absolute positioning with respect to the positioned parent container. - // Ensure popup is positioned using left/right in parent's coordinate system. - // Compute desired left (centered under trigger) const popupRect = popup.getBoundingClientRect(); const parentRect = boundaryRect; // alias // Convert trigger center to parent coordinates - const triggerCenterX = triggerRect.left + triggerRect.width / 2 - parentRect.left; + const triggerCenterX = + triggerRect.left + triggerRect.width / 2 - parentRect.left; // preferred left so popup center aligns to trigger center: const preferredLeft = triggerCenterX - popupRect.width / 2; @@ -111,10 +113,19 @@ const HoverPopup = ({ setRight(0); return; } + if (align === "center") { + popup.style.left = "50%"; + popup.style.right = "auto"; + popup.style.transform = "translateX(-50%)"; + return; + } // align === "auto": try preferred centered position, but flip fully if overflow // clamp preferredLeft to boundaries so it doesn't render partially outside - const leftIfCentered = Math.max(0, Math.min(preferredLeft, parentRect.width - popupRect.width)); + const leftIfCentered = Math.max( + 0, + Math.min(preferredLeft, parentRect.width - popupRect.width) + ); // if centered fits, use it if (leftIfCentered === preferredLeft) { @@ -142,8 +153,17 @@ const HoverPopup = ({ }, [visible, align, boundaryRef]); return ( -
+
{ const [dashboard_data, setDashboard_Data] = useState([]); const [isLineChartLoading, setLoading] = useState(false); @@ -18,11 +17,13 @@ export const useDashboard_Data = ({ days, FromDate, projectId }) => { try { const payload = { days, - FromDate: FromDate || '', + FromDate: FromDate || "", projectId: projectId || null, }; - const response = await GlobalRepository.getDashboardProgressionData(payload); + const response = await GlobalRepository.getDashboardProgressionData( + payload + ); setDashboard_Data(response.data); } catch (err) { setError("Failed to fetch dashboard data."); @@ -38,123 +39,6 @@ export const useDashboard_Data = ({ days, FromDate, projectId }) => { return { dashboard_data, loading: isLineChartLoading, error }; }; - -// export const useDashboard_AttendanceData = (date, projectId) => { -// const [dashboard_Attendancedata, setDashboard_AttendanceData] = useState([]); -// const [isLineChartLoading, setLoading] = useState(false); -// const [error, setError] = useState(""); - -// useEffect(() => { -// const fetchData = async () => { -// setLoading(true); -// setError(""); - -// try { -// const response = await GlobalRepository.getDashboardAttendanceData(date, projectId); // date in 2nd param -// setDashboard_AttendanceData(response.data); -// } catch (err) { -// setError("Failed to fetch dashboard data."); -// console.error(err); -// } finally { -// setLoading(false); -// } -// }; - -// if (date && projectId !== null) { -// fetchData(); -// } -// }, [date, projectId]); - -// return { dashboard_Attendancedata, isLineChartLoading: isLineChartLoading, error }; -// }; - - -// 🔹 Dashboard Projects Card Data Hook -// export const useDashboardProjectsCardData = () => { -// const [projectsCardData, setProjectsData] = useState([]); -// const [loading, setLoading] = useState(false); -// const [error, setError] = useState(""); - -// useEffect(() => { -// const fetchProjectsData = async () => { -// setLoading(true); -// setError(""); - -// try { -// const response = await GlobalRepository.getDashboardProjectsCardData(); -// setProjectsData(response.data); -// } catch (err) { -// setError("Failed to fetch projects card data."); -// console.error(err); -// } finally { -// setLoading(false); -// } -// }; - -// fetchProjectsData(); -// }, []); - -// return { projectsCardData, loading, error }; -// }; - -// 🔹 Dashboard Teams Card Data Hook -// export const useDashboardTeamsCardData = (projectId) => { -// const [teamsCardData, setTeamsData] = useState({}); -// const [loading, setLoading] = useState(false); -// const [error, setError] = useState(""); - -// useEffect(() => { -// const fetchTeamsData = async () => { -// setLoading(true); -// setError(""); - -// try { -// const response = await GlobalRepository.getDashboardTeamsCardData(projectId); -// setTeamsData(response.data || {}); -// } catch (err) { -// setError("Failed to fetch teams card data."); -// console.error("Error fetching teams card data:", err); -// setTeamsData({}); -// } finally { -// setLoading(false); -// } -// }; - -// fetchTeamsData(); -// }, [projectId]); - -// return { teamsCardData, loading, error }; -// }; - -// export const useDashboardTasksCardData = (projectId) => { -// const [tasksCardData, setTasksData] = useState({}); -// const [loading, setLoading] = useState(false); -// const [error, setError] = useState(""); - -// useEffect(() => { -// const fetchTasksData = async () => { -// setLoading(true); -// setError(""); - -// try { -// const response = await GlobalRepository.getDashboardTasksCardData(projectId); -// setTasksData(response.data); -// } catch (err) { -// setError("Failed to fetch tasks card data."); -// console.error(err); -// setTasksData({}); -// } finally { -// setLoading(false); -// } -// }; - -// fetchTasksData(); -// }, [projectId]); - -// return { tasksCardData, loading, error }; -// }; - - export const useAttendanceOverviewData = (projectId, days) => { const [attendanceOverviewData, setAttendanceOverviewData] = useState([]); const [loading, setLoading] = useState(false); @@ -167,7 +51,10 @@ export const useAttendanceOverviewData = (projectId, days) => { setError(""); try { - const response = await GlobalRepository.getAttendanceOverview(projectId, days); + const response = await GlobalRepository.getAttendanceOverview( + projectId, + days + ); setAttendanceOverviewData(response.data); } catch (err) { setError("Failed to fetch attendance overview data."); @@ -182,7 +69,6 @@ export const useAttendanceOverviewData = (projectId, days) => { return { attendanceOverviewData, loading, error }; }; - // -------------------Query---------------------------- // export const useDashboard_Data = (days, FromDate, projectId)=>{ @@ -199,39 +85,47 @@ export const useAttendanceOverviewData = (projectId, days) => { // } // }) // } - +export const useProjectCompletionStatus = () => { + return useQuery({ + queryKey: ["projectCompletionStatus"], + queryFn: async () => { + const resp = await await GlobalRepository.getProjectCompletionStatus(); + return resp.data; + }, + }); +}; export const useDashboard_AttendanceData = (date, projectId) => { return useQuery({ queryKey: ["dashboardAttendances", date, projectId], queryFn: async () => { - - const resp = await await GlobalRepository.getDashboardAttendanceData(date, projectId) + const resp = await await GlobalRepository.getDashboardAttendanceData( + date, + projectId + ); return resp.data; - } - }) -} + }, + }); +}; export const useDashboardTeamsCardData = (projectId) => { return useQuery({ queryKey: ["dashboardTeams", projectId], queryFn: async () => { - - const resp = await GlobalRepository.getDashboardTeamsCardData(projectId) + const resp = await GlobalRepository.getDashboardTeamsCardData(projectId); return resp.data; - } - }) -} + }, + }); +}; export const useDashboardTasksCardData = (projectId) => { return useQuery({ queryKey: ["dashboardTasks", projectId], queryFn: async () => { - - const resp = await GlobalRepository.getDashboardTasksCardData(projectId) + const resp = await GlobalRepository.getDashboardTasksCardData(projectId); return resp.data; - } - }) -} + }, + }); +}; // export const useAttendanceOverviewData = (projectId, days) => { // return useQuery({ // queryKey:["dashboardAttendanceOverView",projectId], @@ -247,29 +141,30 @@ export const useDashboardProjectsCardData = () => { return useQuery({ queryKey: ["dashboardProjects"], queryFn: async () => { - const resp = await GlobalRepository.getDashboardProjectsCardData(); return resp.data; - } - }) -} + }, + }); +}; export const useExpenseAnalysis = (projectId, startDate, endDate) => { const hasBothDates = !!startDate && !!endDate; const noDatesSelected = !startDate && !endDate; - const shouldFetch = - noDatesSelected || - hasBothDates; + const shouldFetch = noDatesSelected || hasBothDates; return useQuery({ queryKey: ["expenseAnalysis", projectId, startDate, endDate], queryFn: async () => { - const resp = await GlobalRepository.getExpenseData(projectId, startDate, endDate); + const resp = await GlobalRepository.getExpenseData( + projectId, + startDate, + endDate + ); return resp.data; }, enabled: shouldFetch, - refetchOnWindowFocus: true, // refetch when you come back - refetchOnMount: "always", // always refetch on remount + refetchOnWindowFocus: true, // refetch when you come back + refetchOnMount: "always", // always refetch on remount staleTime: 0, }); }; @@ -280,17 +175,20 @@ export const useExpenseStatus = (projectId) => { queryFn: async () => { const resp = await GlobalRepository.getExpenseStatus(projectId); return resp.data; - } - }) -} + }, + }); +}; export const useExpenseDataByProject = (projectId, categoryId, months) => { return useQuery({ queryKey: ["expenseByProject", projectId, categoryId, months], queryFn: async () => { - const resp = await GlobalRepository.getExpenseDataByProject(projectId, categoryId, months); + const resp = await GlobalRepository.getExpenseDataByProject( + projectId, + categoryId, + months + ); return resp.data; }, - }); -}; \ No newline at end of file +}; diff --git a/src/repositories/GlobalRepository.jsx b/src/repositories/GlobalRepository.jsx index ec90d25d..2516020a 100644 --- a/src/repositories/GlobalRepository.jsx +++ b/src/repositories/GlobalRepository.jsx @@ -18,6 +18,8 @@ const GlobalRepository = { return api.get(`/api/Dashboard/Progression?${params.toString()}`); }, + getProjectCompletionStatus:()=>api.get(`/api/Dashboard/project-completion-status`), + getDashboardAttendanceData: (date, projectId) => { diff --git a/src/repositories/ProjectRepository.jsx b/src/repositories/ProjectRepository.jsx index 86e59955..9894feae 100644 --- a/src/repositories/ProjectRepository.jsx +++ b/src/repositories/ProjectRepository.jsx @@ -1,6 +1,7 @@ import { api } from "../utils/axiosClient"; const ProjectRepository = { + getProjectList: (pageSize, pageNumber) => api.get(`/api/project/list?pageSize=${pageSize}&pageNumber=${pageNumber}`), getProjectByprojectId: (projetid) => From 604bb68dc2e6f10957af7457ff8fcaa82b4ea4a7 Mon Sep 17 00:00:00 2001 From: Kartik Sharma Date: Wed, 19 Nov 2025 11:23:38 +0530 Subject: [PATCH 25/58] Adding Billed To field in Manage Collection. --- .../collections/ManageCollection.jsx | 91 +++++++++++++------ .../collections/collectionSchema.jsx | 2 + 2 files changed, 65 insertions(+), 28 deletions(-) diff --git a/src/components/collections/ManageCollection.jsx b/src/components/collections/ManageCollection.jsx index 608a6c33..c0160b6b 100644 --- a/src/components/collections/ManageCollection.jsx +++ b/src/components/collections/ManageCollection.jsx @@ -16,10 +16,16 @@ import { import { formatFileSize, localToUtc } from "../../utils/appUtils"; import { useCollectionContext } from "../../pages/collections/CollectionPage"; import { formatDate } from "../../utils/dateUtils"; +import { SelectProjectField } from "../common/Forms/SelectFieldServerSide"; +import { ITEMS_PER_PAGE } from "../../utils/constants"; +import { useOrganizationsList } from "../../hooks/useOrganization"; const ManageCollection = ({ collectionId, onClose }) => { const { data, isError, isLoading, error } = useCollection(collectionId); const { projectNames, projectLoading } = useProjectName(true); + const { data: organization, isLoading: isLoadingOrganization } = + useOrganizationsList(ITEMS_PER_PAGE, 1, true); + const methods = useForm({ resolver: zodResolver(newCollection), defaultValues: defaultCollection, @@ -138,6 +144,7 @@ const ManageCollection = ({ collectionId, onClose }) => { taxAmount: data?.taxAmount, basicAmount: data?.basicAmount, description: data?.description, + billedToId: data?.billedToId, attachments: data.attachments ? data.attachments.map((doc) => ({ fileName: doc.fileName, @@ -163,36 +170,61 @@ const ManageCollection = ({ collectionId, onClose }) => {
-
- - +
+ + setValue("projectId", val, { + shouldDirty: true, + shouldValidate: true, + }) + } + /> {errors.projectId && ( - - {errors.projectId.message} - + {errors.projectId.message} )}
+ +
+ +
+ +
+ {errors?.clientId && ( + {errors.billedToId.message} + )} +
+
{errors.title && ( @@ -203,7 +235,7 @@ const ManageCollection = ({ collectionId, onClose }) => { {errors.invoiceId && ( @@ -216,7 +248,7 @@ const ManageCollection = ({ collectionId, onClose }) => { {errors.invoiceId && ( @@ -232,6 +264,7 @@ const ManageCollection = ({ collectionId, onClose }) => { name="invoiceDate" control={control} maxDate={new Date()} + size="md" /> {errors.invoiceDate && ( @@ -246,6 +279,7 @@ const ManageCollection = ({ collectionId, onClose }) => { name="exceptedPaymentDate" control={control} minDate={watch("invoiceDate")} + size="md" /> {errors.exceptedPaymentDate && ( @@ -260,6 +294,7 @@ const ManageCollection = ({ collectionId, onClose }) => { name="clientSubmitedDate" control={control} maxDate={new Date()} + size="md" /> {errors.exceptedPaymentDate && ( @@ -275,7 +310,7 @@ const ManageCollection = ({ collectionId, onClose }) => { { { diff --git a/src/components/collections/collectionSchema.jsx b/src/components/collections/collectionSchema.jsx index bb97fede..84ea806b 100644 --- a/src/components/collections/collectionSchema.jsx +++ b/src/components/collections/collectionSchema.jsx @@ -19,6 +19,7 @@ export const newCollection = z.object({ invoiceDate: z.string().min(1, { message: "Date is required" }), description: z.string().trim().optional(), clientSubmitedDate: z.string().min(1, { message: "Date is required" }), + billedToId: z.string().min(1, { message: "Date is required" }), exceptedPaymentDate: z.string().min(1, { message: "Date is required" }), invoiceNumber: z .string() @@ -75,6 +76,7 @@ export const defaultCollection = { taxAmount: "", basicAmount: "", description: "", + billedToId:"", attachments: [], }; From fa923d4c3ab4f48375dbd43819adfe9aab005f19 Mon Sep 17 00:00:00 2001 From: "pramod.mahajan" Date: Thu, 20 Nov 2025 14:39:54 +0530 Subject: [PATCH 26/58] added popup for branch view --- .../ServiceProjectBranch/BranchDetails.jsx | 93 ++++++++++++------- .../ServiceProjectBranch/ManageBranch.jsx | 68 +++++++------- .../ServiceProjectBranch/ServiceBranch.jsx | 41 ++++---- .../ServiceProjectJob/ManageJobTicket.jsx | 13 ++- src/components/common/HoverPopup.jsx | 75 ++++++++------- 5 files changed, 155 insertions(+), 135 deletions(-) diff --git a/src/components/ServiceProject/ServiceProjectBranch/BranchDetails.jsx b/src/components/ServiceProject/ServiceProjectBranch/BranchDetails.jsx index 87d59b8c..b7c441d6 100644 --- a/src/components/ServiceProject/ServiceProjectBranch/BranchDetails.jsx +++ b/src/components/ServiceProject/ServiceProjectBranch/BranchDetails.jsx @@ -6,56 +6,81 @@ import { BranchDetailsSkeleton } from "../ServiceProjectSeketon"; const BranchDetails = ({ branch }) => { const [copied, setCopied] = useState(false); - const { data, isLoading, isError, error } = useBranchDetails(branch); + if (isLoading) return ; + if (isError) return ; + + let contactInfo = []; + try { + contactInfo = JSON.parse(data?.contactInformation || "[]"); + } catch (e) {} + const googleMapUrl = data?.googleMapUrl || data?.locationLink; const handleCopy = async () => { if (!googleMapUrl) return; - await navigator.clipboard.writeText(googleMapUrl); setCopied(true); - - setTimeout(() => setCopied(false), 3000); + setTimeout(() => setCopied(false), 2000); }; - if (isLoading) return ; - if (isError) - return ( -
- -
- ); + return ( -<> -
- - Branch Details - -
+
+
+ + Branch Details +
-
-
Contact No:
-
{data?.contactInformation}
-
+ -
-
Type:
-
{data?.branchType}
-
+ -
-
Email:
-
{data?.email}
-
+ -
-
Address:
-
{data?.address}
-
- + {/* Contact persons */} + {contactInfo.map((person, index) => ( +
+
{person.contactPerson}
+ + + +
+ ))} + {/* Map Link */} + {googleMapUrl && ( +
+ + View on Google Maps + + + +
+ )} +
); }; +const DetailRow = ({ label, value }) => ( +
+
+ {label}: +
+
+ {value || "N/A"} +
+
+); + export default BranchDetails; diff --git a/src/components/ServiceProject/ServiceProjectBranch/ManageBranch.jsx b/src/components/ServiceProject/ServiceProjectBranch/ManageBranch.jsx index 720fa08f..b78f8895 100644 --- a/src/components/ServiceProject/ServiceProjectBranch/ManageBranch.jsx +++ b/src/components/ServiceProject/ServiceProjectBranch/ManageBranch.jsx @@ -26,8 +26,8 @@ const ManageBranch = ({ closeModal, BranchToEdit = null }) => { contactPerson: "", designation: "", contactEmails: [""], - contactNumbers: [""] - } + contactNumbers: [""], + }, ]); const { projectId } = useParams(); @@ -73,7 +73,6 @@ const ManageBranch = ({ closeModal, BranchToEdit = null }) => { } }, [data, reset]); - const { mutate: CreateServiceBranch, isPending: createPending } = useCreateBranch(() => { handleClose(); @@ -97,8 +96,6 @@ const ManageBranch = ({ closeModal, BranchToEdit = null }) => { } }; - - return (
@@ -138,8 +135,6 @@ const ManageBranch = ({ closeModal, BranchToEdit = null }) => {
- -