diff --git a/src/components/PaymentRequest/PaymentRequestFilterPanel.jsx b/src/components/PaymentRequest/PaymentRequestFilterPanel.jsx new file mode 100644 index 00000000..84375874 --- /dev/null +++ b/src/components/PaymentRequest/PaymentRequestFilterPanel.jsx @@ -0,0 +1,203 @@ +import React, { useEffect, useState, useMemo } from "react"; +import { FormProvider, useForm, Controller } from "react-hook-form"; +import { zodResolver } from "@hookform/resolvers/zod"; +import { defaultPaymentRequestFilter,SearchPaymentRequestSchema } from "./PaymentRequestSchema"; + +import DateRangePicker, { DateRangePicker1 } from "../common/DateRangePicker"; +import SelectMultiple from "../common/SelectMultiple"; +import { useProjectName } from "../../hooks/useProjects"; +import { useExpenseStatus } from "../../hooks/masterHook/useMaster"; +import { useEmployeesAllOrByProjectId } from "../../hooks/useEmployees"; +import { useSelector } from "react-redux"; +import moment from "moment"; +import { usePaymentRequestFilter } from "../../hooks/useExpense"; +import { useLocation, useNavigate, useParams } from "react-router-dom"; + +const PaymentRequestFilterPanel = ({ onApply, handleGroupBy }) => { + const { status } = useParams(); + const navigate = useNavigate(); + const selectedProjectId = useSelector( + (store) => store.localVariables.projectId + ); + const { data, isLoading, isError, error, isFetching, isFetched } = + usePaymentRequestFilter(); + + const groupByList = useMemo(() => { + return [ + { id: "projects", name: "Project" }, + { id: "status", name: "Status" }, + { id: "createdBy", name: "Submitted By" }, + { id: "currency", name: "Currency" }, + { id: "expensesCategory", name: "Expense Category" }, + { id: "payees", name: "Payee" }, + { id: "date", name: "Due Date" }, + + ].sort((a, b) => a.name.localeCompare(b.name)); + }, []); + + const [selectedGroup, setSelectedGroup] = useState(groupByList[6]); + const [resetKey, setResetKey] = useState(0); + +console.log("Kartik",data) + + const methods = useForm({ + resolver: zodResolver(SearchPaymentRequestSchema), + defaultValues: defaultPaymentRequestFilter, + }); + + const { control, handleSubmit, reset, setValue, watch } = methods; + const isTransactionDate = watch("isTransactionDate"); + + const closePanel = () => { + document.querySelector(".offcanvas.show .btn-close")?.click(); + }; + + + + const handleGroupChange = (e) => { + const group = groupByList.find((g) => g.id === e.target.value); + if (group) setSelectedGroup(group); + }; + + + const onSubmit = (formData) => { + onApply({ + ...formData, + startDate: moment.utc(formData.startDate, "DD-MM-YYYY").toISOString(), + endDate: moment.utc(formData.endDate, "DD-MM-YYYY").toISOString(), + }); + handleGroupBy(selectedGroup.id); + // closePanel(); + }; + + const onClear = () => { + reset(defaultPaymentRequestFilter); + setResetKey((prev) => prev + 1); + onApply(defaultPaymentRequestFilter); + if (status) { + navigate("/expenses", { replace: true }); + } + }; + + const location = useLocation(); + useEffect(() => { + closePanel(); + }, [location]); + + const [appliedStatusId, setAppliedStatusId] = useState(null); + + if (isError && isFetched) + return
Something went wrong Here- {error.message}
; + + return ( + <> + +
+
+
+ +
+ + +
+ +
+ + item.name} + valueKey="id" + /> + item.name} + valueKey="id" + /> + item.name} + valueKey="id" + /> + item.name} + valueKey="id" + /> + +
+ +
+ {data?.status + ?.slice() + .sort((a, b) => a.name.localeCompare(b.name)) + .map((status) => ( +
+ ( +
+ { + const checked = e.target.checked; + onChange( + checked + ? [...value, status.id] + : value.filter((v) => v !== status.id) + ); + }} + /> + +
+ )} + /> +
+ ))} +
+
+
+ +
+ + +
+
+
+ + ); +}; + +export default PaymentRequestFilterPanel; \ No newline at end of file diff --git a/src/components/PaymentRequest/PaymentRequestList.jsx b/src/components/PaymentRequest/PaymentRequestList.jsx index 6356736d..0f3a8d66 100644 --- a/src/components/PaymentRequest/PaymentRequestList.jsx +++ b/src/components/PaymentRequest/PaymentRequestList.jsx @@ -10,9 +10,14 @@ import { formatDate, formatUTCToLocalTime } from "../../utils/dateUtils"; import Avatar from "../../components/common/Avatar"; import { usePaymentRequestContext } from "../../pages/PaymentRequest/PaymentRequestPage"; import { ExpenseTableSkeleton } from "../Expenses/ExpenseSkeleton"; +import ConfirmModal from "../common/ConfirmModal"; +import { useNavigate } from "react-router-dom"; -const PaymentRequestList = ({ groupBy = "submittedBy", search }) => { +const PaymentRequestList = ({filters, groupBy = "submittedBy", search }) => { const { setManageRequest } = usePaymentRequestContext(); + const navigate = useNavigate(); + const [IsDeleteModalOpen, setIsDeleteModalOpen] = useState(false); + const [deletingId, setDeletingId] = useState(null); const groupByField = (items, field) => { return items.reduce((acc, item) => { let key; @@ -28,9 +33,8 @@ const PaymentRequestList = ({ groupBy = "submittedBy", search }) => { displayField = "Status"; break; case "submittedBy": - key = `${item?.createdBy?.firstName ?? ""} ${ - item.createdBy?.lastName ?? "" - }`.trim(); + key = `${item?.createdBy?.firstName ?? ""} ${item.createdBy?.lastName ?? "" + }`.trim(); displayField = "Submitted By"; break; case "project": @@ -83,9 +87,8 @@ const PaymentRequestList = ({ groupBy = "submittedBy", search }) => { label: "Submitted By", align: "text-start", getValue: (e) => - `${e.createdBy?.firstName ?? ""} ${ - e.createdBy?.lastName ?? "" - }`.trim() || "N/A", + `${e.createdBy?.firstName ?? ""} ${e.createdBy?.lastName ?? "" + }`.trim() || "N/A", customRender: (e) => (
{ lastName={e.createdBy?.lastName} /> - {`${e.createdBy?.firstName ?? ""} ${ - e.createdBy?.lastName ?? "" - }`.trim() || "N/A"} + {`${e.createdBy?.firstName ?? ""} ${e.createdBy?.lastName ?? "" + }`.trim() || "N/A"}
), @@ -126,9 +128,8 @@ const PaymentRequestList = ({ groupBy = "submittedBy", search }) => { align: "text-center", getValue: (e) => ( {e?.expenseStatus?.name || "Unknown"} @@ -142,7 +143,7 @@ const PaymentRequestList = ({ groupBy = "submittedBy", search }) => { const { data, isLoading, isError, error, isFetching } = usePaymentRequestList( ITEMS_PER_PAGE, currentPage, - {}, + filters, true, debouncedSearch ); @@ -190,153 +191,179 @@ const PaymentRequestList = ({ groupBy = "submittedBy", search }) => { ); }; + const handleDelete = (id) => { + setDeletingId(id); + DeleteExpense( + { id }, + { + onSettled: () => { + setDeletingId(null); + setIsDeleteModalOpen(false); + }, + } + ); + }; + return ( -
-
- - - - {paymentRequestColumns.map((col) => ( - - ))} - - - + <> + {IsDeleteModalOpen && ( + setIsDeleteModalOpen(false)} + // loading={isPending} + paramData={deletingId} + /> + )} +
+
+
- {col.label} - Action
+ + + {paymentRequestColumns.map((col) => ( + + ))} + + + - - {Object.keys(grouped).length > 0 ? ( - Object.values(grouped).map(({ key, displayField, items }) => ( - - - - - {items?.map((paymentRequest) => ( - - {paymentRequestColumns.map( - (col) => - (col.isAlwaysVisible || groupBy !== col.key) && ( - - ) - )} - + {Object.keys(grouped).length > 0 ? ( + Object.values(grouped).map(({ key, displayField, items }) => ( + + + - ))} - - )) - ) : ( - - - - )} - -
+ {col.label} + Action
-
- {" "} - - {displayField} :{" "} - {" "} - - {IsGroupedByDate ? formatUTCToLocalTime(key) : key} - -
-
- {col?.customRender - ? col?.customRender(paymentRequest) - : col?.getValue(paymentRequest)} - -
- - setViewExpense({ - expenseId: paymentRequest.id, - view: true, - }) - } - > - -
- -
    -
  • - setManageRequest({ - IsOpen: true, - RequestId: paymentRequest.id, - }) - } - > - - - Modify - -
  • - -
  • { - setIsDeleteModalOpen(true); - setDeletingId(paymentRequest.id); - }} - > - - - Delete - -
  • -
-
+
+
+ {" "} + + {displayField} :{" "} + {" "} + + {IsGroupedByDate ? formatUTCToLocalTime(key) : key} +
-
-

No Request Found

-
-
-
+ {items?.map((paymentRequest) => ( + + {paymentRequestColumns.map( + (col) => + (col.isAlwaysVisible || groupBy !== col.key) && ( + + {col?.customRender + ? col?.customRender(paymentRequest) + : col?.getValue(paymentRequest)} + + ) + )} + +
+ + setViewExpense({ + expenseId: paymentRequest.id, + view: true, + }) + } + > - {/* Pagination */} - {totalPages > 1 && ( -
- +
+ +
    +
  • + setManageRequest({ + IsOpen: true, + RequestId: paymentRequest.id, + }) + } + > + + + Modify + +
  • + +
  • { + setIsDeleteModalOpen(true); + setDeletingId(paymentRequest.id); + }} + > + + + Delete + +
  • +
+
+
+ + + ))} + + )) + ) : ( + + +
+

No Request Found

+
+ + + )} + +
- )} -
+ + {/* Pagination */} + {totalPages > 1 && ( +
+ +
+ )} + + ); }; diff --git a/src/components/PaymentRequest/PaymentRequestSchema.js b/src/components/PaymentRequest/PaymentRequestSchema.js index 39432d9b..2f63394e 100644 --- a/src/components/PaymentRequest/PaymentRequestSchema.js +++ b/src/components/PaymentRequest/PaymentRequestSchema.js @@ -64,3 +64,25 @@ export const defaultPaymentRequest = { billAttachments: [], }; + +export const SearchPaymentRequestSchema = z.object({ + projectIds: z.array(z.string()).optional(), + statusIds: z.array(z.string()).optional(), + createdByIds: z.array(z.string()).optional(), + currencyIds: z.array(z.string()).optional(), + expenseCategoryIds: z.array(z.string()).optional(), + payees: z.array(z.string()).optional(), + startDate: z.string().optional(), + endDate: z.string().optional(), +}); + +export const defaultPaymentRequestFilter = { + projectIds: [], + statusIds: [], + createdByIds: [], + currencyIds: [], + expenseCategoryIds: [], + payees: [], + startDate: null, + endDate: null, +}; \ No newline at end of file diff --git a/src/hooks/useExpense.js b/src/hooks/useExpense.js index 1a608929..9f853b38 100644 --- a/src/hooks/useExpense.js +++ b/src/hooks/useExpense.js @@ -334,6 +334,14 @@ export const useUpdatePaymentRequest = (onSuccessCallBack) => { }; //#endregion +export const usePaymentRequestFilter = () => { + return useQuery({ + queryKey: ["PaymentRequestFilter"], + queryFn: async () => + await ExpenseRepository.GetPaymentRequestFilter().then((res) => res.data), + }); +}; + //#region Advance Payment export const useExpenseTransactions = (employeeId)=>{ return useQuery({ diff --git a/src/pages/PaymentRequest/PaymentRequestPage.jsx b/src/pages/PaymentRequest/PaymentRequestPage.jsx index 15680ac1..4a9924e7 100644 --- a/src/pages/PaymentRequest/PaymentRequestPage.jsx +++ b/src/pages/PaymentRequest/PaymentRequestPage.jsx @@ -1,10 +1,12 @@ -import React, { createContext, useState,useEffect, useContext } from "react"; +import React, { createContext, useState, useEffect, useContext } from "react"; import Breadcrumb from "../../components/common/Breadcrumb"; import GlobalModel from "../../components/common/GlobalModel"; import ManagePaymentRequest from "../../components/PaymentRequest/ManagePaymentRequest"; import ExpenseFilterPanel from "../../components/Expenses/ExpenseFilterPanel"; import { useFab } from "../../Context/FabContext"; import PaymentRequestList from "../../components/PaymentRequest/PaymentRequestList"; +import PaymentRequestFilterPanel from "../../components/PaymentRequest/PaymentRequestFilterPanel"; +import { defaultPaymentRequestFilter,SearchPaymentRequestSchema } from "../../components/PaymentRequest/PaymentRequestSchema"; export const PaymentRequestContext = createContext(); export const usePaymentRequestContext = () => { @@ -20,32 +22,27 @@ const PaymentRequestPage = () => { RequestId: null, }); const { setOffcanvasContent, setShowTrigger } = useFab(); + const [filters, setFilters] = useState(defaultPaymentRequestFilter); const [search, setSearch] = useState(""); const contextValue = { - // setViewExpense, setManageRequest, - // setDocumentView, - // filterData, - // removeFilterChip }; useEffect(() => { setShowTrigger(true); setOffcanvasContent( - "Expense Filters", - + "Payment Request Filters", + ); return () => { setShowTrigger(false); setOffcanvasContent("", null); }; - },[]); + }, []); return ( @@ -94,8 +91,9 @@ const PaymentRequestPage = () => { + search={search} + filters={filters} + /> {/* Add/Edit Modal */} {ManageRequest.IsOpen && ( @@ -115,7 +113,7 @@ const PaymentRequestPage = () => { /> )} - + ); diff --git a/src/repositories/ExpsenseRepository.jsx b/src/repositories/ExpsenseRepository.jsx index f69aa4cf..7fb47a3b 100644 --- a/src/repositories/ExpsenseRepository.jsx +++ b/src/repositories/ExpsenseRepository.jsx @@ -16,20 +16,21 @@ const ExpenseRepository = { //#endregion -//#region Payment Request + //#region Payment Request GetPaymentRequestList: (pageSize, pageNumber, filter, isActive, searchString) => { const payloadJsonString = JSON.stringify(filter); return api.get(`/api/Expense/get/payment-requests/list?isActive=${isActive}&pageSize=${pageSize}&pageNumber=${pageNumber}&filter=${payloadJsonString}&searchString=${searchString}`); }, CreatePaymentRequest: (data) => api.post("/api/expense/payment-request/create", data), UpdatePaymentRequest: (id, data) => api.put(`/api/Expense/payment-request/edit/${id}`, data), - GetPaymentRequest:(id)=>api.get(`/api/Expense/get/payment-request/details/${id}`), + GetPaymentRequest: (id) => api.get(`/api/Expense/get/payment-request/details/${id}`), + GetPaymentRequestFilter: () => api.get('/api/Expense/payment-request/filter'), //#endregion //#region Advance Payment - GetTranctionList:()=>api.get(`/get/transactions/${employeeId}`) + GetTranctionList: () => api.get(`/get/transactions/${employeeId}`) //#endregion }