implement delete functionality for Draft expenses only

This commit is contained in:
pramod mahajan 2025-07-24 15:27:58 +05:30
parent f44bba5083
commit 55eeca5a29
3 changed files with 151 additions and 42 deletions

View File

@ -1,5 +1,5 @@
import React, { useState } from "react";
import { useExpenseList } from "../../hooks/useExpense";
import { useDeleteExpense, useExpenseList } from "../../hooks/useExpense";
import Avatar from "../common/Avatar";
import { useExpenseContext } from "../../pages/Expense/ExpensePage";
import { formatDate, formatUTCToLocalTime } from "../../utils/dateUtils";
@ -7,12 +7,17 @@ import Pagination from "../common/Pagination";
import { ITEMS_PER_PAGE } from "../../utils/constants";
import { AppColorconfig, getColorNameFromHex } from "../../utils/appUtils";
import { ExpenseTableSkeleton } from "./ExpenseSkeleton";
import ConfirmModal from "../common/ConfirmModal";
import { useProfile } from "../../hooks/useProfile";
const ExpenseList = () => {
const { setViewExpense,setManageExpenseModal } = useExpenseContext();
const [deletingId, setDeletingId] = useState(null);
const [IsDeleteModalOpen, setIsDeleteModalOpen] = useState(false);
const { setViewExpense, setManageExpenseModal } = useExpenseContext();
const [currentPage, setCurrentPage] = useState(1);
const pageSize = 10;
const {profile} = useProfile()
console.log(profile)
const filter = {
projectIds: [],
statusIds: [],
@ -21,10 +26,25 @@ const ExpenseList = () => {
startDate: null,
endDate: null,
};
const { data, isLoading, isError,isInitialLoading,error,isFetching } = useExpenseList(10, currentPage, filter);
if (isInitialLoading ) return <ExpenseTableSkeleton/>;
const { mutate: DeleteExpense, isPending } = useDeleteExpense();
const { data, isLoading, isError, isInitialLoading, error, isFetching } =
useExpenseList(10, currentPage, filter);
const handleDelete = (id) => {
setDeletingId(id);
DeleteExpense(
{ id },
{
onSettled: () => {
setDeletingId(null);
setIsDeleteModalOpen(false)
},
}
);
};
if (isInitialLoading) return <ExpenseTableSkeleton />;
if (isError) return <div>{error}</div>;
const items = data?.data ?? [];
const totalPages = data?.totalPages ?? 1;
@ -36,16 +56,41 @@ const ExpenseList = () => {
}
};
return (
<>
{IsDeleteModalOpen && (
<div
className={`modal fade ${IsDeleteModalOpen ? "show" : ""}`}
tabIndex="-1"
role="dialog"
style={{
display: IsDeleteModalOpen ? "block" : "none",
backgroundColor: IsDeleteModalOpen
? "rgba(0,0,0,0.5)"
: "transparent",
}}
aria-hidden="false"
>
<ConfirmModal
type={"delete"}
header={"Delete Expense"}
message={"Are you sure you want delete?"}
onSubmit={handleDelete}
onClose={() => setIsDeleteModalOpen(false)}
loading={isPending}
paramData={deletingId}
/>
</div>
)}
<div className="card ">
<div className="card-datatable table-responsive">
<div
id="DataTables_Table_0_wrapper"
className="dataTables_wrapper no-footer"
>
<table
className="datatables-users table border-top dataTable no-footer dtr-column text-nowrap"
aria-describedby="DataTables_Table_0_info"
id="horizontal-example"
>
@ -149,7 +194,9 @@ const ExpenseList = () => {
<tr key={expense.id} className="odd">
<td className="sorting_1" colSpan={2}>
<div className="d-flex justify-content-start align-items-center user-name ms-6">
<span>{formatUTCToLocalTime(expense.transactionDate)}</span>
<span>
{formatUTCToLocalTime(expense.transactionDate)}
</span>
</div>
</td>
<td className="text-start d-none d-sm-table-cell ms-5">
@ -173,36 +220,68 @@ const ExpenseList = () => {
</span>
</div>
</td>
<td className="d-none d-md-table-cell text-end"><i className='bx bx-rupee b-xs'></i>{expense?.amount}</td>
<td className="d-none d-md-table-cell text-end">
<i className="bx bx-rupee b-xs"></i>
{expense?.amount}
</td>
<td>
<span
className={`badge bg-label-${getColorNameFromHex(expense?.status?.color) || 'secondary'}`}
className={`badge bg-label-${
getColorNameFromHex(expense?.status?.color) ||
"secondary"
}`}
>
{expense.status?.displayName || "Unknown"}
{expense.status?.displayName || "Unknown"}
</span>
</td>
<td >
<div className="d-flex justify-content-center align-items-center gap-2">
<span
className="cursor-pointer"
onClick={() =>
setViewExpense({ expenseId:expense.id, view: true })
}
>
<i className="bx bx-show text-primary "></i>
</span>
<span
className="cursor-pointer"
onClick={()=>setManageExpenseModal({IsOpen:true,expenseId:expense.id})}
>
<i className='bx bx-edit bx-sm text-secondary'></i>
</span>
<span
className="cursor-pointer"
>
<i className='bx bx-trash bx-sm text-danger' ></i>
</span>
<td>
<div className="d-flex justify-content-strat align-items-center gap-2">
<span
className="cursor-pointer"
onClick={() =>
setViewExpense({
expenseId: expense.id,
view: true,
})
}
>
<i className="bx bx-show text-primary "></i>
</span>
{(expense.status.name === 'Draft' || expense.status.name === 'Rejected') && (expense.createdBy.id === profile.employeeInfo.id ) &&(
<span
className="cursor-pointer"
onClick={() =>
setManageExpenseModal({
IsOpen: true,
expenseId: expense.id,
})
}
>
<i className="bx bx-edit bx-sm text-secondary"></i>
</span>
)}
{expense.status.name == "Draft" && (
<span
className="cursor-pointer"
onClick={() => {
setIsDeleteModalOpen(true)
setDeletingId(expense.id)
}}
>
{/* {deletingId === expense.id ? (
<div
className="spinner-border spinner-border-sm text-secondary"
role="status"
>
<span className="visually-hidden">
Loading...
</span>
</div>
) : ( */}
<i className="bx bx-trash bx-sm text-danger"></i>
{/* )} */}
</span>
)}
</div>
</td>
</tr>
@ -211,15 +290,15 @@ const ExpenseList = () => {
</table>
</div>
{!isInitialLoading && items.length > 0 && (
<Pagination
currentPage={currentPage}
totalPages={totalPages}
onPageChange={paginate}
/>
)}
<Pagination
currentPage={currentPage}
totalPages={totalPages}
onPageChange={paginate}
/>
)}
</div>
</div>
</>
);
};

View File

@ -163,3 +163,33 @@ export const useActionOnExpense = (onSuccessCallBack) => {
},
});
};
export const useDeleteExpense = () => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: async ({ id }) => {
const response = await ExpenseRepository.DeleteExpense(id);
return response.data;
},
onSuccess: (data, variables) => {
queryClient.setQueryData(["Expenses"], (oldData) => {
if (!oldData || !oldData.data) return queryClient.invalidateQueries({queryKey:["Expenses"]});
const updatedList = oldData.data.filter(
(expense) => expense.id !== variables.id
);
return {
...oldData,
data: updatedList,
};
});
showToast(data.message || "Expense deleted successfully", "success");
},
onError: (error) => {
showToast("Failed to delete expense", "error");
},
});
}

View File

@ -13,7 +13,7 @@ const ExpenseRepository = {
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/edit/${id}`),
DeleteExpense:(id)=>api.delete(`/api/Expense/delete/${id}`),
ActionOnExpense:(data)=>api.post('/api/expense/action',data),