import React, { useState } from "react"; import { useDeleteExpense, useExpenseList } from "../../hooks/useExpense"; 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, EXPENSE_DRAFT, EXPENSE_REJECTEDBY, ITEMS_PER_PAGE, } from "../../utils/constants"; import { formatCurrency, getColorNameFromHex, useDebounce, } 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, groupBy = "transactionDate", searchText }) => { const [deletingId, setDeletingId] = useState(null); const [IsDeleteModalOpen, setIsDeleteModalOpen] = useState(false); const { setViewExpense, setManageExpenseModal } = useExpenseContext(); const IsExpenseEditable = useHasUserPermission(); const IsExpesneApprpve = useHasUserPermission(APPROVE_EXPENSE); const [currentPage, setCurrentPage] = useState(1); const debouncedSearch = useDebounce(searchText, 500); const { mutate: DeleteExpense, isPending } = useDeleteExpense(); const { data, isLoading, isError, isInitialLoading, error } = useExpenseList( ITEMS_PER_PAGE, currentPage, filters, debouncedSearch ); const SelfId = useSelector( (store) => store?.globalVariables?.loginUser?.employeeInfo?.id ); const handleDelete = (id) => { setDeletingId(id); DeleteExpense( { id }, { onSettled: () => { setDeletingId(null); setIsDeleteModalOpen(false); }, } ); }; const paginate = (page) => { if (page >= 1 && page <= (data?.totalPages ?? 1)) { setCurrentPage(page); } }; const groupByField = (items, field) => { return items.reduce((acc, item) => { let key; let displayField; switch (field) { case "transactionDate": key = item?.transactionDate?.split("T")[0]; displayField = "Transaction Date"; break; case "status": key = item?.status?.displayName || "Unknown"; displayField = "Status"; break; case "submittedBy": key = `${item?.createdBy?.firstName ?? ""} ${ item.createdBy?.lastName ?? "" }`.trim(); displayField = "Submitted By"; break; case "project": key = item?.project?.name || "Unknown Project"; displayField = "Project"; break; case "paymentMode": key = item?.paymentMode?.name || "Unknown Mode"; displayField = "Payment Mode"; break; case "expensesType": key = item?.expensesType?.name || "Unknown Type"; displayField = "Expense Type"; break; case "createdAt": key = item?.createdAt?.split("T")[0] || "Unknown Date"; displayField = "Created Date"; break; default: key = "Others"; displayField = "Others"; } const groupKey = `${field}_${key}`; // unique key for object property if (!acc[groupKey]) { acc[groupKey] = { key, displayField, items: [] }; } acc[groupKey].items.push(item); return acc; }, {}); }; const expenseColumns = [ { key: "expenseUId", label: "Expense Id", getValue: (e) => e.expenseUId || "N/A", align: "text-start mx-2", }, { key: "expensesType", label: "Expense Type", getValue: (e) => e.expensesType?.name || "N/A", align: "text-start", }, { key: "paymentMode", label: "Payment Mode", getValue: (e) => e.paymentMode?.name || "N/A", align: "text-start", }, { key: "Submitted By", label: "Submitted By", align: "text-start", getValue: (e) => `${e.createdBy?.firstName ?? ""} ${ e.createdBy?.lastName ?? "" }`.trim() || "N/A", customRender: (e) => (
{`${e.createdBy?.firstName ?? ""} ${ e.createdBy?.lastName ?? "" }`.trim() || "N/A"}
), }, { key: "submitted", label: "Submitted", getValue: (e) => formatUTCToLocalTime(e?.createdAt), isAlwaysVisible: true, }, { key: "amount", label: "Amount", getValue: (e) => <>{formatCurrency(e?.amount)}, isAlwaysVisible: true, align: "text-end", }, { key: "status", label: "Status", align: "text-center", getValue: (e) => ( {e.status?.name || "Unknown"} ), }, ]; if (isInitialLoading) return ; if (isError) return
{error?.message}
; const grouped = groupBy ? groupByField(data?.data ?? [], groupBy) : { All: data?.data ?? [] }; const IsGroupedByDate = [ { key: "transactionDate", displayField: "Transaction Date" }, { key: "createdAt", displayField: "created Date" }, ]?.includes(groupBy); const canEditExpense = (expense) => { return ( (expense?.status?.id === EXPENSE_DRAFT || EXPENSE_REJECTEDBY.includes(expense?.status?.id)) && expense?.createdBy?.id === SelfId ); }; const canDetetExpense = (expense) => { return ( expense?.status?.id === EXPENSE_DRAFT && expense?.createdBy?.id === SelfId ); }; return ( <> {IsDeleteModalOpen && ( setIsDeleteModalOpen(false)} loading={isPending} paramData={deletingId} /> )}
{expenseColumns.map( (col) => (col.isAlwaysVisible || groupBy !== col.key) && ( ) )} {Object.keys(grouped).length > 0 ? ( Object.values(grouped).map(({ key, displayField, items }) => ( {items?.map((expense) => ( {expenseColumns.map( (col) => (col.isAlwaysVisible || groupBy !== col.key) && ( ) )} ))} )) ) : ( )}
{col.label}
Action
{" "} {displayField} :{" "} {" "} {IsGroupedByDate ? formatUTCToLocalTime(key) : key}
{col.customRender ? col.customRender(expense) : col.getValue(expense)}
setViewExpense({ expenseId: expense.id, view: true, }) } > {canDetetExpense(expense) && canEditExpense(expense) && (
    {canDetetExpense(expense) && (
  • setManageExpenseModal({ IsOpen: true, expenseId: expense.id, }) } > Modify
  • )} {canDetetExpense(expense) && (
  • { setIsDeleteModalOpen(true); setDeletingId(expense.id); }} > Delete
  • )}
)}

No Expense Found

{data?.data?.length > 0 && ( )}
); }; export default ExpenseList;