Adding Export functionality in Payment Request.

This commit is contained in:
Kartik Sharma 2025-11-27 17:41:49 +05:30
parent b5fb48104c
commit a31d5d5015
3 changed files with 133 additions and 17 deletions

View File

@ -1,4 +1,4 @@
import React, { useState } from "react";
import React, { useEffect, useState } from "react";
import {
EXPENSE_DRAFT,
EXPENSE_REJECTEDBY,
@ -22,7 +22,7 @@ import Error from "../common/Error";
import Pagination from "../common/Pagination";
import PaymentRequestFilterChips from "./PaymentRequestFilterChips";
const PaymentRequestList = ({ filters, filterData, removeFilterChip, clearFilter, search, groupBy = "submittedBy" }) => {
const PaymentRequestList = ({ filters, filterData, removeFilterChip, clearFilter, search, groupBy = "submittedBy", tableRef, onDataFiltered }) => {
const { setManageRequest, setVieRequest } = usePaymentRequestContext();
const navigate = useNavigate();
const [IsDeleteModalOpen, setIsDeleteModalOpen] = useState(false);
@ -30,6 +30,7 @@ const PaymentRequestList = ({ filters, filterData, removeFilterChip, clearFilter
const SelfId = useSelector(
(store) => store?.globalVariables?.loginUser?.employeeInfo?.id
);
const groupByField = (items, field) => {
return items.reduce((acc, item) => {
let key;
@ -149,6 +150,12 @@ const PaymentRequestList = ({ filters, filterData, removeFilterChip, clearFilter
debouncedSearch
);
useEffect(() => {
if (onDataFiltered) {
onDataFiltered(data?.data ?? []);
}
}, [data, onDataFiltered]);
if (isError) {
return <Error error={error} isFeteching={isRefetching} refetch={refetch} />;
}
@ -222,7 +229,7 @@ const PaymentRequestList = ({ filters, filterData, removeFilterChip, clearFilter
paramData={deletingId}
/>
)}
<div className="card page-min-h table-responsive px-sm-4">
<div className="card page-min-h table-responsive px-sm-4" ref={tableRef}>
<div className="card-datatable mx-2" id="payment-request-table ">
<div className="col-12 mb-2 mt-2">
<PaymentRequestFilterChips
@ -240,7 +247,7 @@ const PaymentRequestList = ({ filters, filterData, removeFilterChip, clearFilter
{col.label}
</th>
))}
<th className="text-center">Action</th>
<th className="text-start">Action</th>
</tr>
</thead>
@ -262,7 +269,7 @@ const PaymentRequestList = ({ filters, filterData, removeFilterChip, clearFilter
</td>
</tr>
{items?.map((paymentRequest) => (
<tr key={paymentRequest.id} style={{ height: "40px" }}>
<tr key={paymentRequest.id} style={{ height: "40px" }}>
{paymentRequestColumns.map(
(col) =>
(col.isAlwaysVisible || groupBy !== col.key) && (

View File

@ -0,0 +1,58 @@
import moment from "moment";
import { exportToCSV, exportToExcel, exportToPDF, printTable } from "../../utils/tableExportUtils";
const handlePaymentRequestExport = (type, requests, tableRef) => {
if (!requests || requests.length === 0) return;
// Map export data
const exportData = requests.map((item) => ({
"Request ID": item?.paymentRequestUID ?? "-",
"Title": item?.title ?? "-",
"Payee": item?.payee ?? "-",
"Amount": item?.amount?.toLocaleString() ?? "-",
"Currency": item?.currency?.currencyCode ?? "-",
"Created At": item?.createdAt ? moment(item.createdAt).format("DD-MMM-YYYY") : "-",
"Due Date": item?.dueDate ? moment(item.dueDate).format("DD-MMM-YYYY") : "-",
"Status": item?.expenseStatus?.name ?? "-",
"Submitted By": `${item?.createdBy?.firstName ?? ""} ${item?.createdBy?.lastName ?? ""}`.trim() || "-",
"Project": item?.project?.name ?? "-",
}));
// Define column order
const columns = [
"Request ID",
"Title",
"Payee",
"Amount",
"Currency",
"Created At",
"Due Date",
"Status",
"Submitted By",
"Project",
];
switch (type) {
case "csv":
exportToCSV(exportData, "payment-requests", columns);
break;
case "excel":
exportToExcel(exportData, "payment-requests", columns);
break;
case "pdf":
exportToPDF(exportData, "payment-requests", columns);
break;
case "print":
if (tableRef?.current) printTable(tableRef.current);
break;
default:
console.warn("Unhandled export type:", type);
break;
}
};
export default handlePaymentRequestExport;

View File

@ -9,6 +9,7 @@ import { defaultPaymentRequestFilter } from "../../components/PaymentRequest/Pay
import ViewPaymentRequest from "../../components/PaymentRequest/ViewPaymentRequest";
import PreviewDocument from "../../components/Expenses/PreviewDocument";
import MakeExpense from "../../components/PaymentRequest/MakeExpense";
import handlePaymentRequestExport from "../../components/PaymentRequest/handlePaymentRequestExport";
export const PaymentRequestContext = createContext();
export const usePaymentRequestContext = () => {
@ -30,7 +31,8 @@ const PaymentRequestPage = () => {
const [search, setSearch] = useState("");
const updatedRef = useRef();
const { setOffcanvasContent, setShowTrigger } = useFab();
const tableRef = useRef(null);
const [filteredData, setFilteredData] = useState([]);
const contextValue = {
setManageRequest,
setVieRequest,
@ -76,6 +78,10 @@ const PaymentRequestPage = () => {
});
};
const handleExport = (type) => {
handlePaymentRequestExport(type, filteredData, tableRef); // <-- corrected
};
return (
<PaymentRequestContext.Provider value={contextValue}>
<div className="container-fluid">
@ -92,18 +98,19 @@ const PaymentRequestPage = () => {
<div className="card my-3 px-sm-4 px-0">
<div className="card-body py-2 px-0 mx-2">
<div className="row align-items-center">
<div className="col-6">
<input
type="search"
className="form-control form-control-sm w-auto"
placeholder="Search Payment Request"
value={search}
style={{ minWidth: "200px" }}
onChange={(e) => setSearch(e.target.value)}
/>
<div className="col-md-8 col-sm-12 mb-2 mb-md-0">
<div className="d-flex align-items-center flex-wrap gap-0">
<input
type="search"
className="form-control form-control-sm w-auto"
placeholder="Search Payment Request"
value={search}
style={{ minWidth: "200px" }}
onChange={(e) => setSearch(e.target.value)}
/>
</div>
</div>
<div className="col-6 text-end mt-sm-0">
<div className="col-md-4 col-sm-12 text-md-end text-end d-flex justify-content-end align-items-center gap-0">
<button
className="btn btn-sm btn-primary"
type="button"
@ -119,7 +126,49 @@ const PaymentRequestPage = () => {
Add Payment Request
</span>
</button>
{/* 3-Dots Dropdown */}
<div className="dropdown">
<button
className="btn btn-icon"
type="button"
data-bs-toggle="dropdown"
aria-expanded="false"
>
<i className="bx bx-dots-vertical-rounded bx-md"></i>
</button>
<ul className="dropdown-menu dropdown-menu-end shadow-sm" style={{ minWidth: "220px" }}>
<li>
<button className="dropdown-item" onClick={() => handleExport("print")}>
<i className="bx bx-printer me-2"></i> Print
</button>
</li>
<li><hr className="dropdown-divider" /></li>
<li>
<button className="dropdown-item" onClick={() => handleExport("csv")}>
<i className="bx bx-file me-2"></i> CSV
</button>
</li>
<li>
<button className="dropdown-item" onClick={() => handleExport("excel")}>
<i className="bx bxs-file-export me-2"></i> Excel
</button>
</li>
<li>
<button className="dropdown-item" onClick={() => handleExport("pdf")}>
<i className="bx bxs-file-pdf me-2"></i> PDF
</button>
</li>
</ul>
</div>
</div>
</div>
</div>
</div>
@ -129,6 +178,8 @@ const PaymentRequestPage = () => {
filterData={filterData}
removeFilterChip={handleRemoveChip}
clearFilter={clearFilter}
tableRef={tableRef}
onDataFiltered={setFilteredData}
/>
{/* Add/Edit Modal */}