From 81712a0695d89b0172e26956458cf4a60e1316bf Mon Sep 17 00:00:00 2001 From: pramod mahajan Date: Wed, 30 Jul 2025 19:33:01 +0530 Subject: [PATCH] Expense List display group by selected filed --- src/components/Expenses/ExpenseList.jsx | 378 ++++++++++-------------- 1 file changed, 164 insertions(+), 214 deletions(-) diff --git a/src/components/Expenses/ExpenseList.jsx b/src/components/Expenses/ExpenseList.jsx index 23df9eec..d2254193 100644 --- a/src/components/Expenses/ExpenseList.jsx +++ b/src/components/Expenses/ExpenseList.jsx @@ -4,14 +4,14 @@ import Avatar from "../common/Avatar"; import { useExpenseContext } from "../../pages/Expense/ExpensePage"; import { formatDate, formatUTCToLocalTime } from "../../utils/dateUtils"; import Pagination from "../common/Pagination"; -import { APPROVE_EXPENSE, ITEMS_PER_PAGE } from "../../utils/constants"; -import { AppColorconfig, getColorNameFromHex } from "../../utils/appUtils"; +import { APPROVE_EXPENSE } from "../../utils/constants"; +import { getColorNameFromHex } from "../../utils/appUtils"; import { ExpenseTableSkeleton } from "./ExpenseSkeleton"; import ConfirmModal from "../common/ConfirmModal"; import { useHasUserPermission } from "../../hooks/useHasUserPermission"; import { useSelector } from "react-redux"; -const ExpenseList = ({ filters }) => { +const ExpenseList = ({ filters, groupBy = "transactionDate" }) => { const [deletingId, setDeletingId] = useState(null); const [IsDeleteModalOpen, setIsDeleteModalOpen] = useState(false); const { setViewExpense, setManageExpenseModal } = useExpenseContext(); @@ -21,8 +21,12 @@ const ExpenseList = ({ filters }) => { const pageSize = 10; const { mutate: DeleteExpense, isPending } = useDeleteExpense(); - const { data, isLoading, isError, isInitialLoading, error, isFetching } = - useExpenseList(10, currentPage, filters); + const { data, isLoading, isError, isInitialLoading, error } = useExpenseList( + pageSize, + currentPage, + filters + ); + const SelfId = useSelector( (store) => store?.globalVariables?.loginUser?.employeeInfo?.id ); @@ -40,70 +44,65 @@ const ExpenseList = ({ filters }) => { ); }; - if (isInitialLoading) return ; - if (isError) return
{error}
; - const items = data?.data ?? []; - const totalPages = data?.totalPages ?? 1; - const hasMore = currentPage < totalPages; - const paginate = (page) => { - if (page >= 1 && page <= totalPages) { + if (page >= 1 && page <= (data?.totalPages ?? 1)) { setCurrentPage(page); } }; - const STATUS_ORDER = [ - "Draft", - "Review Pending", - "Approval Pending", - "Process Pending", - "Processed", - "Paid", - "Rejected", - ]; - const groupExpensesByDateAndStatus = (expenses) => { - const grouped = {}; - - expenses.forEach((expense) => { - const dateKey = expense.transactionDate.split("T")[0]; - if (!grouped[dateKey]) grouped[dateKey] = []; - grouped[dateKey].push(expense); - }); - - const sortedDates = Object.keys(grouped).sort( - (a, b) => new Date(b) - new Date(a) - ); - - return sortedDates.map((date) => ({ - date, - expenses: grouped[date].sort((a, b) => { - return ( - STATUS_ORDER.indexOf(a.status.name) - - STATUS_ORDER.indexOf(b.status.name) - ); - }), - })); + const groupByField = (items, field) => { + return items.reduce((acc, item) => { + let key; + switch (field) { + case "transactionDate": + key = item.transactionDate?.split("T")[0]; + break; + case "status": + key = item.status?.displayName || "Unknown"; + break; + case "paidBy": + key = `${item.paidBy?.firstName ?? ""} ${item.paidBy?.lastName ?? ""}`.trim(); + break; + case "project": + key = item.project?.name || "Unknown Project"; + break; + case "paymentMode": + key = item.paymentMode?.name || "Unknown Mode"; + break; + case "expensesType": + key = item.expensesType?.name || "Unknown Type"; + break; + default: + key = "Others"; + } + if (!acc[key]) acc[key] = []; + acc[key].push(item); + return acc; + }, {}); }; + if (isInitialLoading) return ; + if (isError) return
{error}
; + + const grouped = groupBy ? groupByField(data?.data ?? [], groupBy) : { All: data?.data ?? [] }; + const IsGroupedByDate = ["transactionDate","createdAt"].includes(groupBy) return ( <> {IsDeleteModalOpen && (
setIsDeleteModalOpen(false)} loading={isPending} @@ -111,20 +110,15 @@ const ExpenseList = ({ filters }) => { />
)} -
+ +
-
- +
+
- - - - - - - - + )} + + + {![groupBy].includes("status") && } + - {!isInitialLoading && - groupExpensesByDateAndStatus(items).map( - ({ date, expenses }) => ( - <> - - - {" "} - {expenses.map((expense) => ( - - - - - - - + + + {expenses.map((expense) => ( + + {![groupBy].includes("expensesType") && ( + + )} + {![groupBy].includes("paymentMode") && ( + + )} + {![ groupBy].includes("paidBy") && ( + - - - ))} - - ) - )} - - {!isInitialLoading && items.length === 0 && ( - - + + + )} + + + {![ groupBy].includes("status") && ( + + )} + + + ))} + + ))} + {data?.data?.length === 0 && ( + + )}
{ >
Expense Type
{ >
Payment Mode
{ >
Paid By
-
Submitted
-
- Amount - - Status - - Action -
Submitted
AmountStatusAction
- {formatUTCToLocalTime(date)} -
- {expense.expensesType?.name || "N/A"} - - {expense.paymentMode?.name || "N/A"} - -
- - - {`${expense.paidBy?.firstName ?? ""} ${ - expense.paidBy?.lastName ?? "" - }`.trim() || "N/A"} - -
-
- {formatUTCToLocalTime(expense?.createdAt)} - - - {expense?.amount} - - - {expense.status?.displayName || "Unknown"} + {Object.entries(grouped).map(([group, expenses]) => ( + +
+ {IsGroupedByDate ? formatUTCToLocalTime(group) : group} +
{expense.expensesType?.name || "N/A"}{expense.paymentMode?.name || "N/A"} +
+ + + {`${expense.paidBy?.firstName ?? ""} ${ + expense.paidBy?.lastName ?? "" + }`.trim() || "N/A"} -
-
- - - setViewExpense({ - expenseId: expense.id, - view: true, - }) - } - > - - - {(expense.status.name === "Draft" || - expense.status.name === "Rejected") && - expense.createdBy.id === SelfId && ( - - - setManageExpenseModal({ - IsOpen: true, - expenseId: expense.id, - }) - } - > - - )} - - {expense.status.name === "Draft" && - expense?.createdBy?.id === SelfId && ( - - { - setIsDeleteModalOpen(true); - setDeletingId(expense.id); - }} - > - - )} -
-
No Expnese Found{formatUTCToLocalTime(expense?.createdAt)} + + {expense?.amount} + + + {expense.status?.name || "Unknown"} + + +
+ + setViewExpense({ expenseId: expense.id, view: true }) + } + > + {(expense.status.name === "Draft" || + expense.status.name === "Rejected") && + expense.createdBy.id === SelfId && ( + + setManageExpenseModal({ + IsOpen: true, + expenseId: expense.id, + }) + } + > + )} + {expense.status.name === "Draft" && + expense?.createdBy?.id === SelfId && ( + { + setIsDeleteModalOpen(true); + setDeletingId(expense.id); + }} + > + )} +
+
+ No Expense Found +
+ {data?.data?.length > 0 && ( + + )}
- {!isInitialLoading && items.length > 0 && ( - - )}