Implementing Get and Update API in Recurring Expense.

This commit is contained in:
Kartik Sharma 2025-11-04 18:34:00 +05:30
parent 7a749b14e9
commit e868d27d5f
7 changed files with 130 additions and 65 deletions

View File

@ -1,13 +1,13 @@
import React, { useEffect, useState } from 'react' import React, { useEffect, useState } from 'react'
import Label from '../common/Label'; import Label from '../common/Label';
import { useForm } from 'react-hook-form'; import { useForm } from 'react-hook-form';
import { useExpenseCategory } from '../../hooks/masterHook/useMaster'; import { useExpenseCategory, useRecurringStatus } from '../../hooks/masterHook/useMaster';
import DatePicker from '../common/DatePicker'; import DatePicker from '../common/DatePicker';
import { zodResolver } from '@hookform/resolvers/zod'; import { zodResolver } from '@hookform/resolvers/zod';
import { defaultRecurringExpense, PaymentRecurringExpense } from './RecurringExpenseSchema'; import { defaultRecurringExpense, PaymentRecurringExpense } from './RecurringExpenseSchema';
import { INR_CURRENCY_CODE } from '../../utils/constants'; import { INR_CURRENCY_CODE } from '../../utils/constants';
import { useCurrencies, useProjectName } from '../../hooks/useProjects'; import { useCurrencies, useProjectName } from '../../hooks/useProjects';
import { useCreateRecurringExpense } from '../../hooks/useExpense'; import { useCreateRecurringExpense, useUpdateRecurringExpense } from '../../hooks/useExpense';
function ManageRecurringExpense({ closeModal, requestToEdit = null }) { function ManageRecurringExpense({ closeModal, requestToEdit = null }) {
@ -17,7 +17,9 @@ function ManageRecurringExpense({ closeModal, requestToEdit = null }) {
const { data: currencyData, isLoading: currencyLoading, isError: currencyError } = useCurrencies(); const { data: currencyData, isLoading: currencyLoading, isError: currencyError } = useCurrencies();
const { data: statusData, isLoading: statusLoading, isError: statusError } = useRecurringStatus();
console.log("Tanish", statusData)
const { const {
ExpenseCategories, ExpenseCategories,
loading: ExpenseLoading, loading: ExpenseLoading,
@ -40,9 +42,9 @@ function ManageRecurringExpense({ closeModal, requestToEdit = null }) {
handleClose(); handleClose();
} }
); );
// const { mutate: PaymentRequestUpdate, isPending } = useUpdatePaymentRequest(() => const { mutate: RecurringExpenseUpdate, isPending } = useUpdateRecurringExpense(() =>
// handleClose() handleClose()
// ); );
useEffect(() => { useEffect(() => {
if (requestToEdit && data) { if (requestToEdit && data) {
@ -66,22 +68,30 @@ function ManageRecurringExpense({ closeModal, requestToEdit = null }) {
} }
}, [data, reset]); }, [data, reset]);
// console.log("Veer",data)
useEffect(() => {
if (!requestToEdit && currencyData && currencyData.length > 0) {
const inrCurrency = currencyData.find(
(c) => c.id === INR_CURRENCY_CODE
);
if (inrCurrency) {
setValue("currencyId", INR_CURRENCY_CODE, { shouldValidate: true });
}
}
}, [currencyData, requestToEdit, setValue]);
const onSubmit = (fromdata) => { const onSubmit = (fromdata) => {
let payload = { let payload = {
...fromdata, ...fromdata,
// strikeDate: localToUtc(fromdata.strikeDate),
strikeDate: fromdata.strikeDate ? new Date(fromdata.strikeDate).toISOString() : null, strikeDate: fromdata.strikeDate ? new Date(fromdata.strikeDate).toISOString() : null,
}; };
if (requestToEdit) { if (requestToEdit) {
const editPayload = { ...payload, id: data.id }; const editPayload = { ...payload, id: data.id };
PaymentRequestUpdate({ id: data.id, payload: editPayload }); RecurringExpenseUpdate({ id: data.id, payload: editPayload });
} else { } else {
CreateRecurringExpense(payload); CreateRecurringExpense(payload);
} }
console.log("Kartik", payload)
}; };
return ( return (
@ -294,10 +304,8 @@ function ManageRecurringExpense({ closeModal, requestToEdit = null }) {
{errors.notifyTo.message} {errors.notifyTo.message}
</small> </small>
)} )}
</div> </div>
<div className="col-md-6"> <div className="col-md-6">
<Label htmlFor="statusId" className="form-label" required> <Label htmlFor="statusId" className="form-label" required>
Status Status
@ -307,15 +315,11 @@ function ManageRecurringExpense({ closeModal, requestToEdit = null }) {
className="form-select form-select-sm" className="form-select form-select-sm"
{...register("statusId")} {...register("statusId")}
> >
<option value="">Select Currency</option> <option value="">Select Status</option>
{statusLoading && <option>Loading...</option>}
{currencyLoading && <option>Loading...</option>} {!statusLoading && !statusError && statusData?.data?.map((status) => (
<option key={status.id} value={status.id}>
{!currencyLoading && {status.name}
!currencyError &&
currencyData?.map((currency) => (
<option key={currency.id} value={currency.id}>
{`${currency.currencyName} (${currency.symbol})`}
</option> </option>
))} ))}
</select> </select>

View File

@ -9,15 +9,15 @@ import {
getColorNameFromHex, getColorNameFromHex,
useDebounce, useDebounce,
} from "../../utils/appUtils"; } from "../../utils/appUtils";
import { usePaymentRequestList } from "../../hooks/useExpense";
import { formatDate, formatUTCToLocalTime } from "../../utils/dateUtils"; import { formatDate, formatUTCToLocalTime } from "../../utils/dateUtils";
import Avatar from "../../components/common/Avatar"; import Avatar from "../common/Avatar";
import { ExpenseTableSkeleton } from "../Expenses/ExpenseSkeleton"; import { ExpenseTableSkeleton } from "../Expenses/ExpenseSkeleton";
import ConfirmModal from "../common/ConfirmModal"; import ConfirmModal from "../common/ConfirmModal";
import { useNavigate } from "react-router-dom"; import { useNavigate } from "react-router-dom";
import { useSelector } from "react-redux"; import { useSelector } from "react-redux";
import Error from "../common/Error"; import Error from "../common/Error";
import { useRecurringExpenseContext } from "../../pages/RecurringExpense/RecurringExpensePage"; import { useRecurringExpenseContext } from "../../pages/RecurringExpense/RecurringExpensePage";
import { useRecurringExpenseList } from "../../hooks/useExpense";
const RecurringExpenseList = ({ filters, groupBy = "submittedBy", search }) => { const RecurringExpenseList = ({ filters, groupBy = "submittedBy", search }) => {
const { setManageRequest, setVieRequest } = useRecurringExpenseContext(); const { setManageRequest, setVieRequest } = useRecurringExpenseContext();
@ -27,6 +27,8 @@ const RecurringExpenseList = ({ filters, groupBy = "submittedBy", search }) => {
const SelfId = useSelector( const SelfId = useSelector(
(store) => store?.globalVariables?.loginUser?.employeeInfo?.id (store) => store?.globalVariables?.loginUser?.employeeInfo?.id
); );
const groupByField = (items, field) => { const groupByField = (items, field) => {
return items.reduce((acc, item) => { return items.reduce((acc, item) => {
let key; let key;
@ -77,18 +79,18 @@ const RecurringExpenseList = ({ filters, groupBy = "submittedBy", search }) => {
}, {}); }, {});
}; };
const paymentRequestColumns = [ const recurringExpenseColumns = [
{
key: "paymentRequestUID",
label: "Template Name",
align: "text-start mx-2",
getValue: (e) => e.paymentRequestUID || "N/A",
},
{ {
key: "title", key: "title",
label: "Template Name",
align: "text-start mx-2",
getValue: (e) => e.title || "N/A",
},
{
key: "frequency",
label: "Frequency", label: "Frequency",
align: "text-start", align: "text-start",
getValue: (e) => e.title || "N/A", getValue: (e) => e.frequency || "N/A",
}, },
{ {
key: "createdAt", key: "createdAt",
@ -97,10 +99,16 @@ const RecurringExpenseList = ({ filters, groupBy = "submittedBy", search }) => {
getValue: (e) => formatUTCToLocalTime(e?.createdAt), getValue: (e) => formatUTCToLocalTime(e?.createdAt),
}, },
{ {
key: "createdAt", key: "latestPRGeneratedAt",
label: "Last Generation Date",
align: "text-start",
getValue: (e) => formatUTCToLocalTime(e?.latestPRGeneratedAt),
},
{
key: "status",
label: "Status", label: "Status",
align: "text-start", align: "text-start",
getValue: (e) => formatUTCToLocalTime(e?.createdAt), getValue: (e) => formatUTCToLocalTime(e?.status),
}, },
]; ];
@ -109,17 +117,18 @@ const RecurringExpenseList = ({ filters, groupBy = "submittedBy", search }) => {
const debouncedSearch = useDebounce(search, 500); const debouncedSearch = useDebounce(search, 500);
const { data, isLoading, isError, error, isRefetching, refetch } = const { data, isLoading, isError, error, isRefetching, refetch } =
usePaymentRequestList( useRecurringExpenseList(
ITEMS_PER_PAGE, ITEMS_PER_PAGE,
currentPage, currentPage,
filters, {},
true, true,
debouncedSearch debouncedSearch
); );
const paymentRequestData = data?.data || []; const recurringExpenseData= data?.data || [];
const totalPages = data?.data?.totalPages || 1; const totalPages = data?.data?.totalPages || 1;
console.log("Sharma",recurringExpenseData)
if (isError) { if (isError) {
return <Error error={error} isFeteching={isRefetching} refetch={refetch} />; return <Error error={error} isFeteching={isRefetching} refetch={refetch} />;
} }
@ -142,11 +151,11 @@ const RecurringExpenseList = ({ filters, groupBy = "submittedBy", search }) => {
{ key: "createdAt", displayField: "created Date" }, { key: "createdAt", displayField: "created Date" },
]?.includes(groupBy); ]?.includes(groupBy);
const canEditExpense = (paymentRequest) => { const canEditExpense = (recurringExpense) => {
return ( return (
(paymentRequest?.expenseStatus?.id === EXPENSE_DRAFT || (recurringExpense?.expenseStatus?.id === EXPENSE_DRAFT ||
EXPENSE_REJECTEDBY.includes(paymentRequest?.expenseStatus.id)) && EXPENSE_REJECTEDBY.includes(recurringExpense?.expenseStatus.id)) &&
paymentRequest?.createdBy?.id === SelfId recurringExpense?.createdBy?.id === SelfId
); );
}; };
const canDetetExpense = (request) => { const canDetetExpense = (request) => {
@ -188,7 +197,7 @@ const RecurringExpenseList = ({ filters, groupBy = "submittedBy", search }) => {
<table className="table border-top dataTable text-nowrap align-middle"> <table className="table border-top dataTable text-nowrap align-middle">
<thead> <thead>
<tr> <tr>
{paymentRequestColumns.map((col) => ( {recurringExpenseColumns.map((col) => (
<th key={col.key} className={`sorting ${col.align}`}> <th key={col.key} className={`sorting ${col.align}`}>
{col.label} {col.label}
</th> </th>
@ -214,9 +223,9 @@ const RecurringExpenseList = ({ filters, groupBy = "submittedBy", search }) => {
</div> </div>
</td> </td>
</tr> </tr>
{items?.map((paymentRequest) => ( {items?.map((recurringExpense) => (
<tr key={paymentRequest.id}> <tr key={recurringExpense.id}>
{paymentRequestColumns.map( {recurringExpenseColumns.map(
(col) => (col) =>
(col.isAlwaysVisible || groupBy !== col.key) && ( (col.isAlwaysVisible || groupBy !== col.key) && (
<td <td
@ -224,8 +233,8 @@ const RecurringExpenseList = ({ filters, groupBy = "submittedBy", search }) => {
className={`d-table-cell ${col.align ?? ""}`} className={`d-table-cell ${col.align ?? ""}`}
> >
{col?.customRender {col?.customRender
? col?.customRender(paymentRequest) ? col?.customRender(recurringExpense)
: col?.getValue(paymentRequest)} : col?.getValue(recurringExpense)}
</td> </td>
) )
)} )}
@ -235,12 +244,12 @@ const RecurringExpenseList = ({ filters, groupBy = "submittedBy", search }) => {
className="bx bx-show text-primary cursor-pointer" className="bx bx-show text-primary cursor-pointer"
onClick={() => onClick={() =>
setVieRequest({ setVieRequest({
requestId: paymentRequest.id, requestId: recurringExpense.id,
view: true, view: true,
}) })
} }
></i> ></i>
{canEditExpense(paymentRequest) && ( {/* {canEditExpense(recurringExpense) && (
<div className="dropdown z-2"> <div className="dropdown z-2">
<button <button
type="button" type="button"
@ -262,7 +271,7 @@ const RecurringExpenseList = ({ filters, groupBy = "submittedBy", search }) => {
onClick={() => onClick={() =>
setManageRequest({ setManageRequest({
IsOpen: true, IsOpen: true,
RequestId: paymentRequest.id, RequestId: recurringExpense.id,
}) })
} }
> >
@ -274,11 +283,11 @@ const RecurringExpenseList = ({ filters, groupBy = "submittedBy", search }) => {
</a> </a>
</li> </li>
{canDetetExpense(paymentRequest) && ( {canDetetExpense(recurringExpense) && (
<li <li
onClick={() => { onClick={() => {
setIsDeleteModalOpen(true); setIsDeleteModalOpen(true);
setDeletingId(paymentRequest.id); setDeletingId(recurringExpense.id);
}} }}
> >
<a className="dropdown-item px-2 cursor-pointer py-1"> <a className="dropdown-item px-2 cursor-pointer py-1">
@ -291,7 +300,7 @@ const RecurringExpenseList = ({ filters, groupBy = "submittedBy", search }) => {
)} )}
</ul> </ul>
</div> </div>
)} )} */}
</div> </div>
</td> </td>
</tr> </tr>
@ -307,6 +316,7 @@ const RecurringExpenseList = ({ filters, groupBy = "submittedBy", search }) => {
</td> </td>
</tr> </tr>
)} )}
</tbody> </tbody>
</table> </table>
</div> </div>

View File

@ -57,6 +57,14 @@ export const useMasterMenu = () => {
}); });
}; };
export const useRecurringStatus = () => {
return useQuery({
queryKey: ["recurringExpense"],
queryFn: async () =>
await MasterRespository.getRecurringStatus(),
});
};
export const useActivitiesMaster = () => { export const useActivitiesMaster = () => {
const { const {
data: activities = [], data: activities = [],

View File

@ -408,3 +408,40 @@ export const useCreateRecurringExpense = (onSuccessCallBack) => {
}, },
}); });
}; };
export const useUpdateRecurringExpense = (onSuccessCallBack) => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: async ({ id, payload }) => {
const response = await ExpenseRepository.UpdateRecurringExpense(id, payload);
return response.data;
},
onSuccess: (updatedExpense, variables) => {
queryClient.removeQueries({ queryKey: ["RecurringExpense", variables.id] });
queryClient.invalidateQueries({ queryKey: ["RecurringExpenseList"] });
showToast("Recurring Expense updated Successfully", "success");
if (onSuccessCallBack) onSuccessCallBack();
},
onError: (error) => {
showToast("Something went wrong.Please try again later.", "error");
},
});
};
export const useRecurringExpenseList = (
pageSize,
pageNumber,
filter,
isActive,
searchString = "",
) => {
return useQuery({
queryKey: ["paymentRequestList",pageSize,pageNumber,filter,isActive,searchString],
queryFn: async()=>{
const resp = await ExpenseRepository.GetRecurringExpenseList(pageSize,pageNumber,filter,isActive,searchString);
return resp.data;
},
keepPreviousData: true,
});
};

View File

@ -2,9 +2,8 @@ import React, { createContext, useState, useEffect, useContext } from "react";
import Breadcrumb from "../../components/common/Breadcrumb"; import Breadcrumb from "../../components/common/Breadcrumb";
import GlobalModel from "../../components/common/GlobalModel"; import GlobalModel from "../../components/common/GlobalModel";
import { useFab } from "../../Context/FabContext"; import { useFab } from "../../Context/FabContext";
// import { defaultPaymentRequestFilter,SearchPaymentRequestSchema } from "../../components/PaymentRequest/PaymentRequestSchema";
import ManageRecurringExpense from "../../components/RecurringExpense/ManageRecurringExpense"; import ManageRecurringExpense from "../../components/RecurringExpense/ManageRecurringExpense";
import RecurringExpenseList from "../../components/RecurringExpense/RecurringRexpenseList"; import RecurringExpenseList from "../../components/RecurringExpense/RecurringExpenseList";
export const RecurringExpenseContext = createContext(); export const RecurringExpenseContext = createContext();
export const useRecurringExpenseContext = () => { export const useRecurringExpenseContext = () => {
@ -17,7 +16,7 @@ export const useRecurringExpenseContext = () => {
const RecurringExpensePage = () => { const RecurringExpensePage = () => {
const [ManageRequest, setManageRequest] = useState({ const [ManageRequest, setManageRequest] = useState({
IsOpen: null, IsOpen: null,
RequestId: null, RecurringId: null,
}); });
const [ViewRequest, setVieRequest] = useState({ view: false, requestId: null }) const [ViewRequest, setVieRequest] = useState({ view: false, requestId: null })
const { setOffcanvasContent, setShowTrigger } = useFab(); const { setOffcanvasContent, setShowTrigger } = useFab();
@ -105,10 +104,10 @@ const RecurringExpensePage = () => {
} }
> >
<ManageRecurringExpense <ManageRecurringExpense
key={ManageRequest.RequestId ?? "new"} key={ManageRequest.RecurringId ?? "new"}
requestToEdit={ManageRequest.RequestId} requestToEdit={ManageRequest.RecurringId}
closeModal={() => closeModal={() =>
setManageRequest({ IsOpen: null, RequestId: null }) setManageRequest({ IsOpen: null, RecurringId: null })
} }
/> />
</GlobalModel> </GlobalModel>

View File

@ -30,7 +30,12 @@ const ExpenseRepository = {
//#region Recurring Expense //#region Recurring Expense
GetRecurringExpenseList: (pageSize, pageNumber, filter, isActive, searchString) => {
const payloadJsonString = JSON.stringify(filter);
return api.get(`/api/Expense/get/recurring-payment/list?isActive=${isActive}&pageSize=${pageSize}&pageNumber=${pageNumber}&filter=${payloadJsonString}&searchString=${searchString}`);
},
CreateRecurringExpense: (data) => api.post("/api/Expense/recurring-payment/create", data), CreateRecurringExpense: (data) => api.post("/api/Expense/recurring-payment/create", data),
UpdateRecurringExpense: (id, data) => api.put(`/api/Expense/recurring-payment/edit/${id}`, data),
//#endregion //#endregion

View File

@ -141,4 +141,6 @@ export const MasterRespository = {
api.post(`/api/Master/payment-adjustment-head`, data), api.post(`/api/Master/payment-adjustment-head`, data),
updatePaymentAjustmentHead: (id, data) => updatePaymentAjustmentHead: (id, data) =>
api.put(`/api/Master/payment-adjustment-head/edit/${id}`, data), api.put(`/api/Master/payment-adjustment-head/edit/${id}`, data),
getRecurringStatus: () => api.get(`/api/master/recurring-status/list`),
}; };