diff --git a/src/components/master/MasterModal.jsx b/src/components/master/MasterModal.jsx index d6665767..bd7f9ba1 100644 --- a/src/components/master/MasterModal.jsx +++ b/src/components/master/MasterModal.jsx @@ -16,6 +16,7 @@ import ManagePaymentMode from "./ManagePaymentMode"; import ManageExpenseStatus from "./ManageExpenseStatus"; import ManageDocumentCategory from "./ManageDocumentCategory"; import ManageDocumentType from "./ManageDocumentType"; +import ManageServices from "./Services/ManageServices"; const MasterModal = ({ modaldata, closeModal }) => { if (!modaldata?.modalType || modaldata.modalType === "delete") { @@ -60,6 +61,12 @@ const MasterModal = ({ modaldata, closeModal }) => { "Edit-Document Type": ( ), + "Services": ( + + ), + "Edit-Services": ( + + ), }; return modalComponents[modalType] || null; diff --git a/src/components/master/Services/ManageServices.jsx b/src/components/master/Services/ManageServices.jsx new file mode 100644 index 00000000..bdc379a2 --- /dev/null +++ b/src/components/master/Services/ManageServices.jsx @@ -0,0 +1,107 @@ +import React, { useEffect } from "react"; +import Label from "../../common/Label"; +import { useForm } from "react-hook-form"; +import { useCreateService, useUpdateService } from "../../../hooks/masterHook/useMaster"; +import { z } from "zod"; +import { zodResolver } from "@hookform/resolvers/zod"; + +const schema = z.object({ + name: z.string().min(1, { message: "Service Name is required" }), + description: z + .string() + .min(1, { message: "Description is required" }) + .max(255, { message: "Description cannot exceed 255 characters" }), +}); + +const ManageServices = ({ data , onClose }) => { + const { + register, + handleSubmit, + reset, + formState: { errors }, + } = useForm({ + resolver: zodResolver(schema), + defaultValues: { name: "", description: "" }, + }); + + const { mutate: CreateServices, isPending: Creating } = useCreateService(() => + onClose?.() + ); + const { mutate: UpdateServices, isPending: Updating } = useUpdateService(() => + onClose?.() + ); + + const onSubmit = (payload) => { + if (data && data.id) { + UpdateServices({ id: data.id, payload: { ...payload, id: data.id } }); + } else { + CreateServices(payload); + } + }; + + useEffect(() => { + if (data) { + reset({ + name: data.name ?? "", + description: data.description ?? "", + }); + } + }, [data, reset]); + + return ( +
+
+ + + {errors.name &&

{errors.name.message}

} +
+ +
+ + + {errors.description && ( +

{errors.description.message}

+ )} +
+ +
+ + +
+
+ ); +}; + +export default ManageServices; diff --git a/src/components/master/Services/ServicesSchema.js b/src/components/master/Services/ServicesSchema.js new file mode 100644 index 00000000..ceaa8bf5 --- /dev/null +++ b/src/components/master/Services/ServicesSchema.js @@ -0,0 +1,9 @@ +import { z } from "zod"; + +const schema = z.object({ + name: z.string().min(1, { message: "Service Name is required" }), + description: z + .string() + .min(1, { message: "Description is required" }) + .max(255, { message: "Description cannot exceed 255 characters" }), +}); \ No newline at end of file diff --git a/src/hooks/masterHook/useMaster.js b/src/hooks/masterHook/useMaster.js index 952745fa..6e589efe 100644 --- a/src/hooks/masterHook/useMaster.js +++ b/src/hooks/masterHook/useMaster.js @@ -248,6 +248,8 @@ const fetchMasterData = async (masterType) => { return (await MasterRespository.getJobRole()).data; case "Activity": return (await MasterRespository.getActivites()).data; + case "Services": + return (await MasterRespository.getService()).data; case "Work Category": return (await MasterRespository.getWorkCategory()).data; case "Contact Category": @@ -684,6 +686,7 @@ export const useCreatePaymentMode = (onSuccessCallback)=>{ } }) } + export const useUpdatePaymentMode = (onSuccessCallback)=>{ const queryClient = useQueryClient(); @@ -706,6 +709,81 @@ export const useUpdatePaymentMode = (onSuccessCallback)=>{ }) } + +// Services------------------------------- + +// export const useCreateService = (onSuccessCallback) => { +// const queryClient = useQueryClient(); + +// return useMutation({ +// mutationFn: async (payload) => { +// const resp = await MasterRespository.createService(payload); +// return resp.data; // full API response +// }, +// onSuccess: (data) => { +// // Invalidate & refetch service list +// queryClient.invalidateQueries({ queryKey: ["masterData", "Services"] }); + +// showToast(data?.message || "Service added successfully", "success"); + +// if (onSuccessCallback) onSuccessCallback(data?.data); // pass back new service object +// }, +// onError: (error) => { +// showToast(error.message || "Something went wrong", "error"); +// }, +// }); +// }; + +export const useCreateService = (onSuccessCallback) => { + const queryClient = useQueryClient(); + + return useMutation({ + mutationFn: async (payload) => { + debugger; + const resp = await MasterRespository.createService(payload); + debugger; + return resp.data; + }, + onSuccess: (data) => { + debugger; + queryClient.invalidateQueries({ queryKey: ["masterData", "Services"] }); + + showToast(data?.message || "Service added successfully", "success"); + + if (onSuccessCallback) onSuccessCallback(data?.data); + }, + onError: (error) => { + debugger; + showToast(error.message || "Something went wrong", "error"); + }, + }); +}; + + +export const useUpdateService = (onSuccessCallback) => { + const queryClient = useQueryClient(); + + return useMutation({ + mutationFn: async ({ id, payload }) => { + const response = await MasterRespository.updateService(id, payload); + return response; // full response since it already has { success, message, data } + }, + onSuccess: (data, variables) => { + queryClient.invalidateQueries({ + queryKey: ["masterData", "Services"], + }); + + showToast(data.message || "Service updated successfully.", "success"); + + if (onSuccessCallback) onSuccessCallback(data); + }, + onError: (error) => { + showToast(error?.message || "Something went wrong", "error"); + }, + }); +}; + + // -------------------Expense Status---------------------------------- export const useCreateExpenseStatus =(onSuccessCallback)=>{ const queryClient = useQueryClient(); diff --git a/src/pages/master/MasterPage.jsx b/src/pages/master/MasterPage.jsx index 1640f2ba..b187efd1 100644 --- a/src/pages/master/MasterPage.jsx +++ b/src/pages/master/MasterPage.jsx @@ -91,7 +91,7 @@ const MasterPage = () => { {modalConfig && ( api.get("api/master/activities"), createActivity: (data) => api.post("api/master/activity", data), + +//Services + getService: () => api.get("api/master/service/list"), + createService: (data) => api.post("api/master/service/create", data), + updateService: (id, data) => api.put(`api/master/service/edit/${id}`, data), + "Services": (id) => api.delete(`/api/master/service/delete/${id}`), + updateActivity: (id, data) => api.post(`api/master/activity/edit/${id}`, data), getIndustries: () => api.get("api/master/industries"),