Added taking action on expense, like Review, Approve ...

This commit is contained in:
pramod mahajan 2025-07-22 17:20:08 +05:30
parent 2ab2a1d8bd
commit 280715d62f
3 changed files with 109 additions and 59 deletions

View File

@ -254,6 +254,11 @@ const CreateExpense = ({closeModal}) => {
))
)}
</select>
{errors.paidById && (
<small className="danger-text">
{errors.paidById.message}
</small>
)}
</div>
</div>

View File

@ -19,9 +19,10 @@ const ExpenseList = () => {
startDate: null,
endDate: null,
};
const { data, isLoading, isError } = useExpenseList(ITEMS_PER_PAGE, currentPage, filter);
if (isLoading) return <div>Loading...</div>;
const { data, isLoading, isError,isInitialLoading } = useExpenseList(2, currentPage, filter);
if (isInitialLoading) return <div>Loading...</div>;
const items = data.data ?? [];
const totalPages = data?.totalPages ?? 1;
const hasMore = currentPage < totalPages;
@ -37,12 +38,13 @@ const ExpenseList = () => {
<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"
id="DataTables_Table_0"
aria-describedby="DataTables_Table_0_info"
style={{ width: "100%" }}
id="horizontal-example"
>
<thead>
<tr>
@ -131,7 +133,7 @@ const ExpenseList = () => {
</tr>
)}
{!isLoading && items.length === 0 && (
{!isInitialLoading && items.length === 0 && (
<tr>
<td colSpan={7} className="text-center py-3">
No expenses found.
@ -139,12 +141,12 @@ const ExpenseList = () => {
</tr>
)}
{!isLoading &&
{!isInitialLoading &&
items.map((expense) => (
<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.createdAt)}</span>
<span>{formatUTCToLocalTime(expense.transactionDate)}</span>
</div>
</td>
<td className="text-start d-none d-sm-table-cell ms-5">
@ -183,22 +185,37 @@ const ExpenseList = () => {
{expense.status?.name || "Unknown"}
</span>
</td>
<td>
<span
<td >
<div className="d-flex justify-content-center align-items-center gap-2">
<span
className="cursor-pointer"
onClick={() =>
setViewExpense({ expenseId: expense, view: true })
}
>
<i className="bx bx-show "></i>
<i className="bx bx-show text-primary "></i>
</span>
<span
className="cursor-pointer"
>
<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>
</div>
</td>
</tr>
))}
</tbody>
</table>
</div>
{!isLoading && items.length > 0 && (
{!isInitialLoading && items.length > 0 && (
<Pagination
currentPage={currentPage}
totalPages={totalPages}

View File

@ -1,61 +1,89 @@
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"
import ExpenseRepository from "../repositories/ExpsenseRepository"
import showToast from "../services/toastService"
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import ExpenseRepository from "../repositories/ExpsenseRepository";
import showToast from "../services/toastService";
import { queryClient } from "../layouts/AuthLayout";
// -------------------Query------------------------------------------------------
export const useExpenseList=( pageSize, pageNumber, filter ) =>{
return useQuery({
export const useExpenseList = (pageSize, pageNumber, filter) => {
return useQuery({
queryKey: ["expenses", pageNumber, pageSize, filter],
queryFn: async() =>
await ExpenseRepository.GetExpenseList( pageSize, pageNumber, filter ).then((res) => res.data),
queryFn: async () =>
await ExpenseRepository.GetExpenseList(pageSize, pageNumber, filter).then(
(res) => res.data
),
keepPreviousData: true,
});
}
export const useExpense =(ExpenseId)=>{
return useQuery({
queryKey:["Expense",ExpenseId],
queryFn:async()=>await ExpenseRepository.GetExpenseDetails(ExpenseId)
})
}
};
export const useExpense = (ExpenseId) => {
return useQuery({
queryKey: ["Expense", ExpenseId],
queryFn: async () => await ExpenseRepository.GetExpenseDetails(ExpenseId),
});
};
// ---------------------------Mutation---------------------------------------------
export const useCreateExpnse =(onSuccessCallBack)=>{
const queryClient = useQueryClient()
return useMutation({
mutationFn: async(payload)=>{
await ExpenseRepository.CreateExpense(payload)
},
onSuccess:(_,variables)=>{
showToast("Expense Created Successfully","success")
queryClient.invalidateQueries({queryKey:["expenses"]})
if (onSuccessCallBack) onSuccessCallBack();
},
onError:(error)=>{
showToast(error.message || "Something went wrong please try again !","error")
}
})
}
export const useCreateExpnse = (onSuccessCallBack) => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: async (payload) => {
await ExpenseRepository.CreateExpense(payload);
},
onSuccess: (_, variables) => {
showToast("Expense Created Successfully", "success");
queryClient.invalidateQueries({ queryKey: ["expenses"] });
if (onSuccessCallBack) onSuccessCallBack();
},
onError: (error) => {
showToast(
error.message || "Something went wrong please try again !",
"error"
);
},
});
};
export const useActionOnExpense=(onSuccessCallBack)=>{
const queryClient = useQueryClient()
return useMutation({
mutationFn: async(payload)=>{
await ExpenseRepository.ActionOnExpense(payload)
export const useActionOnExpense = (onSuccessCallBack) => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: async (payload) => {
const response = await ExpenseRepository.ActionOnExpense(payload);
return response.data;
},
onSuccess: (updatedExpense, variables) => {
showToast("Expense updated successfully", "success");
queryClient.setQueriesData(
{
queryKey: ["expenses"],
exact: false,
},
onSuccess:(data,variables)=>{
console.log(data)
showToast("Expense Created Successfully","success")
if (onSuccessCallBack) onSuccessCallBack();
},
onError:(error)=>{
showToast(error.message || "Something went wrong please try again !","error")
(oldData) => {
if (!oldData) return oldData;
return {
...oldData,
data: oldData.data.map((item) =>
item.id === updatedExpense.id
? {
...item,
nextStatus: updatedExpense.nextStatus,
status: updatedExpense.status,
}
: item
),
};
}
})
}
);
if (onSuccessCallBack) onSuccessCallBack();
},
onError: (error) => {
showToast(
error.message || "Something went wrong, please try again!",
"error"
);
},
});
};