adding api for get list for payment request.
This commit is contained in:
parent
e0c0a14777
commit
f3cfb3cf24
@ -4,7 +4,7 @@ import Label from '../common/Label';
|
|||||||
import { useForm } from 'react-hook-form';
|
import { useForm } from 'react-hook-form';
|
||||||
import { useExpenseType } from '../../hooks/masterHook/useMaster';
|
import { useExpenseType } from '../../hooks/masterHook/useMaster';
|
||||||
import DatePicker from '../common/DatePicker';
|
import DatePicker from '../common/DatePicker';
|
||||||
import { useCreatePaymentRequest } from '../../hooks/usePaymentRequest';
|
import { useCreatePaymentRequest, useUpdatePaymentRequest } from '../../hooks/useExpense';
|
||||||
import { defaultPaymentRequest, PaymentRequestSchema } from '../../pages/PaymentRequest/PaymentRequestSchema';
|
import { defaultPaymentRequest, PaymentRequestSchema } from '../../pages/PaymentRequest/PaymentRequestSchema';
|
||||||
import { zodResolver } from '@hookform/resolvers/zod';
|
import { zodResolver } from '@hookform/resolvers/zod';
|
||||||
import { formatFileSize, localToUtc } from '../../utils/appUtils';
|
import { formatFileSize, localToUtc } from '../../utils/appUtils';
|
||||||
@ -103,6 +103,9 @@ function ManagePaymentRequest({ closeModal, expenseToEdit = null }) {
|
|||||||
handleClose();
|
handleClose();
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
const { mutate: PaymentRequestUpdate, isPending } = useUpdatePaymentRequest(() =>
|
||||||
|
handleClose()
|
||||||
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (expenseToEdit && data) {
|
if (expenseToEdit && data) {
|
||||||
@ -140,13 +143,13 @@ function ManagePaymentRequest({ closeModal, expenseToEdit = null }) {
|
|||||||
};
|
};
|
||||||
if (expenseToEdit) {
|
if (expenseToEdit) {
|
||||||
const editPayload = { ...payload, id: data.id };
|
const editPayload = { ...payload, id: data.id };
|
||||||
ExpenseUpdate({ id: data.id, payload: editPayload });
|
PaymentRequestUpdate({ id: data.id, payload: editPayload });
|
||||||
} else {
|
} else {
|
||||||
CreatePaymentRequest(payload);
|
CreatePaymentRequest(payload);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="container p-3">
|
<div className="container p-3">
|
||||||
<h5 className="m-0">
|
<h5 className="m-0">
|
||||||
|
|||||||
@ -262,3 +262,64 @@ export const useHasAnyPermission = (permissionIdsInput) => {
|
|||||||
|
|
||||||
return permissionIds.some((id) => permissions.includes(id));
|
return permissionIds.some((id) => permissions.includes(id));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// ---------------------------Payment Request---------------------------------------------
|
||||||
|
export const usePaymentRequestList = (
|
||||||
|
pageSize,
|
||||||
|
pageNumber,
|
||||||
|
filter,
|
||||||
|
isActive,
|
||||||
|
searchString = "",
|
||||||
|
) => {
|
||||||
|
return useQuery({
|
||||||
|
queryKey: ["PaymentRequest",pageSize,pageNumber,filter,isActive,searchString],
|
||||||
|
queryFn: async()=>{
|
||||||
|
const resp = await ExpenseRepository.GetPaymentRequestList(pageSize,pageNumber,filter,isActive,searchString);
|
||||||
|
return resp.data;
|
||||||
|
},
|
||||||
|
keepPreviousData: true,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// CREATE PAYMENT REQUEST
|
||||||
|
export const useCreatePaymentRequest = (onSuccessCallBack) => {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
|
||||||
|
return useMutation({
|
||||||
|
mutationFn: async (payload) => {
|
||||||
|
await ExpenseRepository.CreatePaymentRequest(payload);
|
||||||
|
},
|
||||||
|
|
||||||
|
onSuccess: (_, variables) => {
|
||||||
|
queryClient.invalidateQueries({ queryKey: ["PaymentRequest"] });
|
||||||
|
showToast("Payment Created Successfully", "success");
|
||||||
|
if (onSuccessCallBack) onSuccessCallBack();
|
||||||
|
},
|
||||||
|
onError: (error) => {
|
||||||
|
showToast(
|
||||||
|
error.message || "Something went wrong please try again !",
|
||||||
|
"error"
|
||||||
|
);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useUpdatePaymentRequest = (onSuccessCallBack) => {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
return useMutation({
|
||||||
|
mutationFn: async ({ id, payload }) => {
|
||||||
|
const response = await ExpenseRepository.UpdatePaymentRequest(id, payload);
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
onSuccess: (updatedExpense, variables) => {
|
||||||
|
queryClient.removeQueries({ queryKey: ["PaymentRequest", variables.id] });
|
||||||
|
queryClient.invalidateQueries({ queryKey: ["PaymentRequest"] });
|
||||||
|
showToast("PaymentRequest updated Successfully", "success");
|
||||||
|
|
||||||
|
if (onSuccessCallBack) onSuccessCallBack();
|
||||||
|
},
|
||||||
|
onError: (error) => {
|
||||||
|
showToast("Something went wrong.Please try again later.", "error");
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
@ -1,25 +0,0 @@
|
|||||||
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
|
||||||
import PaymentRequestRepository from "../repositories/PaymentRequestRepository";
|
|
||||||
import showToast from "../services/toastService";
|
|
||||||
|
|
||||||
export const useCreatePaymentRequest = (onSuccessCallBack) => {
|
|
||||||
const queryClient = useQueryClient();
|
|
||||||
|
|
||||||
return useMutation({
|
|
||||||
mutationFn: async (payload) => {
|
|
||||||
await PaymentRequestRepository.CreatePaymentRequest(payload);
|
|
||||||
},
|
|
||||||
|
|
||||||
onSuccess: (_, variables) => {
|
|
||||||
queryClient.invalidateQueries({ queryKey: ["PaymentRequest"] });
|
|
||||||
showToast("Payment Created Successfully", "success");
|
|
||||||
if (onSuccessCallBack) onSuccessCallBack();
|
|
||||||
},
|
|
||||||
onError: (error) => {
|
|
||||||
showToast(
|
|
||||||
error.message || "Something went wrong please try again !",
|
|
||||||
"error"
|
|
||||||
);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
};
|
|
||||||
@ -1,41 +1,150 @@
|
|||||||
import React from "react";
|
import React, { useState } from "react";
|
||||||
|
import { ITEMS_PER_PAGE } from "../../utils/constants";
|
||||||
|
import { useDebounce } from "../../utils/appUtils";
|
||||||
|
import { usePaymentRequestList } from "../../hooks/useExpense";
|
||||||
|
import { formatDate } from "../../utils/dateUtils";
|
||||||
|
|
||||||
const PaymentRequestList = () => {
|
const PaymentRequestList = ({ setManagePaymentRequestModal, search }) => {
|
||||||
const paymentRequestColumns = [
|
const paymentRequestColumns = [
|
||||||
{ key: "requestId", label: "Request Id" },
|
{ key: "paymentRequestUID", label: "Request ID", align: "text-start mx-2" },
|
||||||
{ key: "RequestType", label: "Request Type" },
|
{ key: "title", label: "Request Title", align: "text-start" },
|
||||||
{ key: "submittedBy", label: "Submitted By" },
|
{ key: "payee", label: "Payee", align: "text-start" },
|
||||||
{ key: "submittedOn", label: "Submitted On" },
|
{ key: "createdAt", label: "Submitted On", align: "text-start" },
|
||||||
{ key: "amount", label: "Amount" },
|
{ key: "amount", label: "Amount", align: "text-start" },
|
||||||
{ key: "status", label: "Status" },
|
{ key: "expenseStatus", label: "Status", align: "text-start" },
|
||||||
];
|
];
|
||||||
|
|
||||||
return (
|
const [currentPage, setCurrentPage] = useState(1);
|
||||||
<div className="card page-min-h table-responsive px-sm-4">
|
const debouncedSearch = useDebounce(search, 500);
|
||||||
<div className="card-datatable " id="payment-request-table">
|
|
||||||
<table className="table border-top dataTable text-nowrap">
|
const { data, isLoading, isError, error, isFetching } = usePaymentRequestList(
|
||||||
<thead>
|
ITEMS_PER_PAGE,
|
||||||
<tr>
|
currentPage,
|
||||||
{paymentRequestColumns.map((col) => (
|
{},
|
||||||
<th key={col.key} className="sorting text-start">
|
true,
|
||||||
{col.label}
|
debouncedSearch
|
||||||
</th>
|
);
|
||||||
))}
|
|
||||||
<th className="text-center">Action</th>
|
const paymentRequestData = data?.data || [];
|
||||||
</tr>
|
const totalPages = data?.data?.totalPages || 1;
|
||||||
</thead>
|
|
||||||
<tbody>
|
if (isError) {
|
||||||
{/* Data rows will be added here later */}
|
return (
|
||||||
<tr>
|
<div className="text-center text-danger py-5">
|
||||||
<td colSpan={paymentRequestColumns.length + 1} className="text-center py-4">
|
<p>Failed to load payment requests.</p>
|
||||||
No Payment Request Found
|
<small>{error?.message || "Something went wrong."}</small>
|
||||||
</td>
|
</div>
|
||||||
</tr>
|
);
|
||||||
</tbody>
|
}
|
||||||
</table>
|
|
||||||
</div>
|
return (
|
||||||
</div>
|
<div className="card page-min-h table-responsive px-sm-4">
|
||||||
);
|
<div className="card-datatable" id="payment-request-table">
|
||||||
|
<table className="table border-top dataTable text-nowrap align-middle">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
{paymentRequestColumns.map((col) => (
|
||||||
|
<th key={col.key} className={`sorting ${col.align}`}>
|
||||||
|
{col.label}
|
||||||
|
</th>
|
||||||
|
))}
|
||||||
|
<th className="text-center">Action</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
|
||||||
|
<tbody>
|
||||||
|
{isLoading || isFetching ? (
|
||||||
|
<tr>
|
||||||
|
<td
|
||||||
|
colSpan={paymentRequestColumns.length + 1}
|
||||||
|
className="text-center py-4"
|
||||||
|
>
|
||||||
|
Loading Payment Requests...
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
) : paymentRequestData.length > 0 ? (
|
||||||
|
paymentRequestData.map((row) => (
|
||||||
|
<tr key={row.id}>
|
||||||
|
<td>{row.paymentRequestUID}</td>
|
||||||
|
<td>{row.title}</td>
|
||||||
|
<td>{row.payee}</td>
|
||||||
|
<td>{formatDate(row.createdAt)}</td>
|
||||||
|
<td>
|
||||||
|
{row.currency?.symbol}
|
||||||
|
{row.amount}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<span
|
||||||
|
className="badge"
|
||||||
|
style={{
|
||||||
|
backgroundColor: row.expenseStatus?.color || "#6c757d",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{row.expenseStatus?.displayName || "Unknown"}
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td className="text-center">
|
||||||
|
<div className="d-flex justify-content-center gap-2">
|
||||||
|
<i
|
||||||
|
className="bx bx-show text-primary cursor-pointer"
|
||||||
|
title="View"
|
||||||
|
onClick={() =>
|
||||||
|
console.log("View clicked for:", row.paymentRequestUID)
|
||||||
|
}
|
||||||
|
></i>
|
||||||
|
|
||||||
|
<i
|
||||||
|
className="bx bx-edit text-secondary cursor-pointer"
|
||||||
|
title="Edit"
|
||||||
|
onClick={() =>
|
||||||
|
setManagePaymentRequestModal({
|
||||||
|
IsOpen: true,
|
||||||
|
expenseId: row.id, // Pass ID for editing
|
||||||
|
})
|
||||||
|
}
|
||||||
|
></i>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
))
|
||||||
|
) : (
|
||||||
|
<tr>
|
||||||
|
<td
|
||||||
|
colSpan={paymentRequestColumns.length + 1}
|
||||||
|
className="text-center py-4"
|
||||||
|
>
|
||||||
|
No Payment Requests Found
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
)}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Pagination */}
|
||||||
|
{totalPages > 1 && (
|
||||||
|
<div className="d-flex justify-content-end py-3 pe-3">
|
||||||
|
<nav>
|
||||||
|
<ul className="pagination mb-0">
|
||||||
|
{[...Array(totalPages)].map((_, index) => (
|
||||||
|
<li
|
||||||
|
key={index}
|
||||||
|
className={`page-item ${currentPage === index + 1 ? "active" : ""}`}
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
className="page-link"
|
||||||
|
onClick={() => setCurrentPage(index + 1)}
|
||||||
|
>
|
||||||
|
{index + 1}
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default PaymentRequestList;
|
export default PaymentRequestList;
|
||||||
|
|||||||
@ -3,16 +3,25 @@ import Breadcrumb from "../../components/common/Breadcrumb";
|
|||||||
import GlobalModel from "../../components/common/GlobalModel";
|
import GlobalModel from "../../components/common/GlobalModel";
|
||||||
import ManagePaymentRequest from "../../components/PaymentRequest/ManagePaymentRequest";
|
import ManagePaymentRequest from "../../components/PaymentRequest/ManagePaymentRequest";
|
||||||
import PaymentRequestList from "./PaymentRequestList";
|
import PaymentRequestList from "./PaymentRequestList";
|
||||||
|
|
||||||
const PaymentRequestPage = () => {
|
const PaymentRequestPage = () => {
|
||||||
const [ManagePaymentRequestModal, setManagePaymentRequestModal] = useState({
|
const [ManagePaymentRequestModal, setManagePaymentRequestModal] = useState({
|
||||||
IsOpen: null,
|
IsOpen: null,
|
||||||
expenseId: null,
|
expenseId: null,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const [search, setSearch] = useState("");
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="container-fluid">
|
<div className="container-fluid">
|
||||||
{/* Breadcrumb */}
|
{/* Breadcrumb */}
|
||||||
<Breadcrumb data={[{ label: "Home", link: "/" }, { label: "Finance", link: "/Payment Request" }, { label: "Payment Request" }]} />
|
<Breadcrumb
|
||||||
|
data={[
|
||||||
|
{ label: "Home", link: "/" },
|
||||||
|
{ label: "Finance", link: "/Payment Request" },
|
||||||
|
{ label: "Payment Request" },
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
|
||||||
{/* Top Bar */}
|
{/* Top Bar */}
|
||||||
<div className="card my-3 px-sm-4 px-0">
|
<div className="card my-3 px-sm-4 px-0">
|
||||||
@ -23,6 +32,8 @@ const PaymentRequestPage = () => {
|
|||||||
type="search"
|
type="search"
|
||||||
className="form-control form-control-sm w-auto"
|
className="form-control form-control-sm w-auto"
|
||||||
placeholder="Search Payment Req.."
|
placeholder="Search Payment Req.."
|
||||||
|
value={search}
|
||||||
|
onChange={(e) => setSearch(e.target.value)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -38,13 +49,16 @@ const PaymentRequestPage = () => {
|
|||||||
}
|
}
|
||||||
>
|
>
|
||||||
<i className="bx bx-plus-circle me-2"></i>
|
<i className="bx bx-plus-circle me-2"></i>
|
||||||
<span className="d-none d-md-inline-block">Add Payment Request</span>
|
<span className="d-none d-md-inline-block">
|
||||||
|
Add Payment Request
|
||||||
|
</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Add/Edit Modal */}
|
||||||
{ManagePaymentRequestModal.IsOpen && (
|
{ManagePaymentRequestModal.IsOpen && (
|
||||||
<GlobalModel
|
<GlobalModel
|
||||||
isOpen
|
isOpen
|
||||||
@ -63,15 +77,13 @@ const PaymentRequestPage = () => {
|
|||||||
</GlobalModel>
|
</GlobalModel>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Expense List Placeholder */}
|
{/* Payment Request List */}
|
||||||
<div className="card">
|
<div className="card">
|
||||||
{/* <div className="card-body text-center text-muted py-5">
|
<PaymentRequestList
|
||||||
<p>No Expense Data found</p>
|
search={search}
|
||||||
</div> */}
|
setManagePaymentRequestModal={setManagePaymentRequestModal}
|
||||||
<PaymentRequestList/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -2,22 +2,27 @@ import { api } from "../utils/axiosClient";
|
|||||||
|
|
||||||
|
|
||||||
const ExpenseRepository = {
|
const ExpenseRepository = {
|
||||||
GetExpenseList: ( pageSize, pageNumber, filter,searchString ) => {
|
GetExpenseList: (pageSize, pageNumber, filter, searchString) => {
|
||||||
const payloadJsonString = JSON.stringify(filter);
|
const payloadJsonString = JSON.stringify(filter);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return api.get(`/api/expense/list?pageSize=${pageSize}&pageNumber=${pageNumber}&filter=${payloadJsonString}&searchString=${searchString}`);
|
return api.get(`/api/expense/list?pageSize=${pageSize}&pageNumber=${pageNumber}&filter=${payloadJsonString}&searchString=${searchString}`);
|
||||||
},
|
},
|
||||||
|
|
||||||
GetExpenseDetails:(id)=>api.get(`/api/Expense/details/${id}`),
|
|
||||||
CreateExpense:(data)=>api.post("/api/Expense/create",data),
|
|
||||||
UpdateExpense:(id,data)=>api.put(`/api/Expense/edit/${id}`,data),
|
|
||||||
DeleteExpense:(id)=>api.delete(`/api/Expense/delete/${id}`),
|
|
||||||
|
|
||||||
ActionOnExpense:(data)=>api.post('/api/expense/action',data),
|
GetExpenseDetails: (id) => api.get(`/api/Expense/details/${id}`),
|
||||||
|
CreateExpense: (data) => api.post("/api/Expense/create", data),
|
||||||
GetExpenseFilter:()=>api.get('/api/Expense/filter')
|
UpdateExpense: (id, data) => api.put(`/api/Expense/edit/${id}`, data),
|
||||||
|
DeleteExpense: (id) => api.delete(`/api/Expense/delete/${id}`),
|
||||||
|
|
||||||
|
ActionOnExpense: (data) => api.post('/api/expense/action', data),
|
||||||
|
|
||||||
|
GetExpenseFilter: () => api.get('/api/Expense/filter'),
|
||||||
|
|
||||||
|
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),
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,12 +0,0 @@
|
|||||||
import { api } from "../utils/axiosClient";
|
|
||||||
|
|
||||||
|
|
||||||
const PaymentRequestRepository = {
|
|
||||||
|
|
||||||
|
|
||||||
CreatePaymentRequest:(data)=>api.post("/api/expense/payment-request/create",data),
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
export default PaymentRequestRepository;
|
|
||||||
Loading…
x
Reference in New Issue
Block a user