diff --git a/src/components/RecurringExpense/ManageRecurringExpense.jsx b/src/components/RecurringExpense/ManageRecurringExpense.jsx
new file mode 100644
index 00000000..38df1105
--- /dev/null
+++ b/src/components/RecurringExpense/ManageRecurringExpense.jsx
@@ -0,0 +1,431 @@
+import React, { useEffect, useState } from 'react'
+import Label from '../common/Label';
+import { useForm } from 'react-hook-form';
+import { useExpenseCategory } from '../../hooks/masterHook/useMaster';
+import DatePicker from '../common/DatePicker';
+// import { useCreatePaymentRequest, usePaymentRequestDetail, useUpdatePaymentRequest } from '../../hooks/useExpense';
+
+import { zodResolver } from '@hookform/resolvers/zod';
+import { defaultRecurringExpense, PaymentRecurringExpense } from './RecurringExpenseSchema';
+import { INR_CURRENCY_CODE } from '../../utils/constants';
+import { useCurrencies, useProjectName } from '../../hooks/useProjects';
+
+function ManageRecurringExpense({ closeModal, requestToEdit = null }) {
+
+ const data = {}
+ const { projectNames, loading: projectLoading, error, isError: isProjectError,
+ } = useProjectName();
+
+ const { data: currencyData, isLoading: currencyLoading, isError: currencyError } = useCurrencies();
+
+
+ const {
+ ExpenseCategories,
+ loading: ExpenseLoading,
+ error: ExpenseError,
+ } = useExpenseCategory();
+
+ const schema = PaymentRecurringExpense();
+
+ const { register, control, watch, handleSubmit, setValue, reset, formState: { errors }, } = useForm({
+ resolver: zodResolver(schema),
+ defaultValues: defaultRecurringExpense,
+ });
+ const handleClose = () => {
+ reset();
+ closeModal();
+ };
+
+ // const { mutate: CreatePaymentRequest, isPending: createPending } = useCreatePaymentRequest(
+ // () => {
+ // handleClose();
+ // }
+ // );
+ // const { mutate: PaymentRequestUpdate, isPending } = useUpdatePaymentRequest(() =>
+ // handleClose()
+ // );
+
+ useEffect(() => {
+ if (requestToEdit && data) {
+ reset({
+ title: data.title || "",
+ description: data.description || "",
+ payee: data.payee || "",
+ notifyTo: data.notifyTo || "",
+ currencyId: data.currency.id || "",
+ amount: data.amount || "",
+ strikeDate: data.strikeDate?.slice(0, 10) || "",
+ projectId: data.project.id || "",
+ paymentBufferDays: data.paymentBufferDays || "",
+ numberOfIteration: data.numberOfIteration || "",
+ expenseCategoryId: data.expenseCategory.id || "",
+ statusId: data.statusId || "",
+ frequency: data.frequency || "",
+ isVariable: data.isVariable || false,
+
+ });
+ }
+ }, [data, reset]);
+
+ // console.log("Veer",data)
+
+ const onSubmit = (fromdata) => {
+
+ let payload = {
+ ...fromdata,
+ // strikeDate: localToUtc(fromdata.strikeDate),
+ strikeDate: fromdata.strikeDate ? new Date(fromdata.strikeDate).toISOString() : null,
+ };
+ // if (requestToEdit) {
+ // const editPayload = { ...payload, id: data.id};
+ // PaymentRequestUpdate({ id: data.id, payload: editPayload });
+ // } else {
+ // CreatePaymentRequest(payload);
+ // }
+ console.log("Kartik", payload)
+ };
+
+ return (
+
+
+ {requestToEdit ? "Update Payment Request " : "Create Payment Request"}
+
+
+
+ )
+}
+
+export default ManageRecurringExpense
diff --git a/src/components/RecurringExpense/RecurringExpenseFilterPanel.jsx b/src/components/RecurringExpense/RecurringExpenseFilterPanel.jsx
new file mode 100644
index 00000000..e69de29b
diff --git a/src/components/RecurringExpense/RecurringExpenseSchema.js b/src/components/RecurringExpense/RecurringExpenseSchema.js
new file mode 100644
index 00000000..7c5e3b9e
--- /dev/null
+++ b/src/components/RecurringExpense/RecurringExpenseSchema.js
@@ -0,0 +1,158 @@
+import { boolean, z } from "zod";
+import { INR_CURRENCY_CODE } from "../../utils/constants";
+
+// export const PaymentRecurringExpense = (expenseTypes) => {
+// return z
+// .object({
+// title: z.string().min(1, { message: "Project is required" }),
+
+// description: z.string().min(1, { message: "Description is required" }),
+
+// payee: z.string().min(1, { message: "Supplier name is required" }),
+
+// notifyTo: z.string().min(1, { message: "Notification is required" }),
+
+// currencyId: z
+// .string()
+// .min(1, { message: "Currency is required" }),
+
+// amount: z.coerce
+// .number({
+// invalid_type_error: "Amount is required and must be a number",
+// })
+// .min(1, "Amount must be Enter")
+// .refine((val) => /^\d+(\.\d{1,2})?$/.test(val.toString()), {
+// message: "Amount must have at most 2 decimal places",
+// }),
+
+// strikeDate: z.string().min(1, { message: "Date is required" }),
+
+// projectId: z.string().min(1, { message: "Project is required" }),
+
+// paymentBufferDays: z.string().min(1, { message: "Buffer days is required" }),
+
+// numberOfIteration: z.string().min(1, { message: "Iteration is required" }),
+
+// expenseCategoryId: z
+// .string()
+// .min(1, { message: "Expense Category is required" }),
+
+// statusId: z.string().min(1, { message: "Please select a status" }),
+
+// frequency: z.string().min(1, { message: "Frequency is required" }),
+
+// isVariable: z.boolean().optional(),
+
+// })
+// };
+
+
+export const PaymentRecurringExpense = (expenseTypes) => {
+ return z.object({
+ title: z.string().min(1, { message: "Project is required" }),
+
+ description: z.string().min(1, { message: "Description is required" }),
+
+ payee: z.string().min(1, { message: "Supplier name is required" }),
+
+ notifyTo: z.string().min(1, { message: "Notification is required" }),
+
+ currencyId: z
+ .string()
+ .min(1, { message: "Currency is required" }),
+
+ amount: z
+ .number({
+ required_error: "Amount is required",
+ invalid_type_error: "Amount must be a number",
+ })
+ .min(1, { message: "Amount must be greater than 0" })
+ .refine((val) => /^\d+(\.\d{1,2})?$/.test(val.toString()), {
+ message: "Amount must have at most 2 decimal places",
+ }),
+
+ strikeDate: z
+ .string()
+ .min(1, { message: "Date is required" })
+ .refine((val) => !isNaN(Date.parse(val)), {
+ message: "Invalid date format",
+ }),
+
+ projectId: z
+ .string()
+ .min(1, { message: "Project is required" }),
+
+ paymentBufferDays: z
+ .number({
+ required_error: "Buffer days is required",
+ invalid_type_error: "Buffer days must be a number",
+ })
+ .min(0, { message: "Buffer days cannot be negative" }),
+
+ numberOfIteration: z
+ .number({
+ required_error: "Iteration is required",
+ invalid_type_error: "Iteration must be a number",
+ })
+ .min(1, { message: "Iteration must be at least 1" }),
+
+ expenseCategoryId: z
+ .string()
+ .min(1, { message: "Expense Category is required" }),
+
+ statusId: z
+ .string()
+ .min(1, { message: "Please select a status" }),
+
+ frequency: z
+ .number({
+ required_error: "Frequency is required",
+ invalid_type_error: "Frequency must be a number",
+ })
+ .min(1, { message: "Frequency must be greater than 0" }),
+
+ isVariable: z.boolean().optional(),
+ });
+};
+
+export const defaultRecurringExpense = {
+ title: "",
+ description: "",
+ payee: "",
+ notifyTo: "",
+ currencyId: "",
+ amount: 0,
+ strikeDate: "", // or null if your DatePicker accepts null
+ projectId: "",
+ paymentBufferDays: 0,
+ numberOfIteration: 1,
+ expenseCategoryId: "",
+ statusId: "",
+ frequency: 1,
+ isVariable: false,
+};
+
+
+// export const SearchPaymentRequestSchema = z.object({
+// projectIds: z.array(z.string()).optional(),
+// statusIds: z.array(z.string()).optional(),
+// createdByIds: z.array(z.string()).optional(),
+// currencyIds: z.array(z.string()).optional(),
+// expenseCategoryIds: z.array(z.string()).optional(),
+// payees: z.array(z.string()).optional(),
+// startDate: z.string().optional(),
+// endDate: z.string().optional(),
+// });
+
+// export const defaultPaymentRequestFilter = {
+// projectIds: [],
+// statusIds: [],
+// createdByIds: [],
+// currencyIds: [],
+// expenseCategoryIds: [],
+// payees: [],
+// startDate: null,
+// endDate: null,
+// };
+
+
diff --git a/src/components/RecurringExpense/RecurringRexpenseList.jsx b/src/components/RecurringExpense/RecurringRexpenseList.jsx
new file mode 100644
index 00000000..e69de29b
diff --git a/src/pages/RecurringExpense/RecurringExpensePage.jsx b/src/pages/RecurringExpense/RecurringExpensePage.jsx
new file mode 100644
index 00000000..dd7775f1
--- /dev/null
+++ b/src/pages/RecurringExpense/RecurringExpensePage.jsx
@@ -0,0 +1,132 @@
+import React, { createContext, useState, useEffect, useContext } from "react";
+import Breadcrumb from "../../components/common/Breadcrumb";
+import GlobalModel from "../../components/common/GlobalModel";
+import { useFab } from "../../Context/FabContext";
+// import { defaultPaymentRequestFilter,SearchPaymentRequestSchema } from "../../components/PaymentRequest/PaymentRequestSchema";
+import ManageRecurringExpense from "../../components/RecurringExpense/ManageRecurringExpense";
+
+export const RecurringExpenseContext = createContext();
+export const useRecurringExpenseContext = () => {
+ const context = useContext(RecurringExpenseContext);
+ if (!context) {
+ throw new Error("useRecurringExpenseContext must be used within an ExpenseProvider");
+ }
+ return context;
+};
+const RecurringExpensePage = () => {
+ const [ManageRequest, setManageRequest] = useState({
+ IsOpen: null,
+ RequestId: null,
+ });
+ const [ViewRequest,setVieRequest] = useState({view:false,requestId:null})
+ const { setOffcanvasContent, setShowTrigger } = useFab();
+// const [filters, setFilters] = useState(defaultPaymentRequestFilter);
+
+ const [search, setSearch] = useState("");
+
+ const contextValue = {
+ setManageRequest,
+ setVieRequest
+ };
+
+ useEffect(() => {
+
+ setShowTrigger(true);
+ setOffcanvasContent(
+ "Payment Request Filters",
+ //
+ );
+
+ return () => {
+ setShowTrigger(false);
+ setOffcanvasContent("", null);
+ };
+ }, []);
+
+ return (
+
+
+ {/* Breadcrumb */}
+
+
+ {/* Top Bar */}
+
+
+
+
+ setSearch(e.target.value)}
+ />
+
+
+
+
+
+
+
+
+ {/*
*/}
+
+ {/* Add/Edit Modal */}
+ {ManageRequest.IsOpen && (
+
+ setManageRequest({ IsOpen: null, expenseId: null })
+ }
+ >
+
+ setManageRequest({ IsOpen: null, RequestId: null })
+ }
+ />
+
+ )}
+
+ {/* {ViewRequest.view && (
+
setVieRequest({ requestId: null, view: false })}
+ >
+
+
+ )} */}
+
+
+
+ );
+};
+
+export default RecurringExpensePage;
diff --git a/src/router/AppRoutes.jsx b/src/router/AppRoutes.jsx
index a36f0499..adc58771 100644
--- a/src/router/AppRoutes.jsx
+++ b/src/router/AppRoutes.jsx
@@ -56,6 +56,7 @@ import { ComingSoonPage } from "../pages/Misc/ComingSoonPage";
import CollectionPage from "../pages/collections/CollectionPage";
import AdvancePaymentPage from "../pages/AdvancePayment/AdvancePaymentPage";
import PaymentRequestPage from "../pages/PaymentRequest/PaymentRequestPage";
+import RecurringExpensePage from "../pages/RecurringExpense/RecurringExpensePage";
const router = createBrowserRouter(
[
{
@@ -102,6 +103,7 @@ const router = createBrowserRouter(
{ path: "/expenses", element: },
{ path: "/payment-request", element: },
{ path: "/advance-payment", element: },
+ { path: "/recurring-payment", element: },
{ path: "/masters", element: },
{ path: "/tenants", element: },
{ path: "/tenants/new-tenant", element: },