-
-
- {header && < strong className='mb-0 font-weight-bold'>{header }}
+
+ {header && {header}}
-
-
-
-
{TypeofIcon(type)}
-
-
{message}
-
+
+
+
+
{TypeofIcon()}
+
+
{message}
+
-
-
-
-
diff --git a/src/components/master/ManageDocumentType.jsx b/src/components/master/ManageDocumentType.jsx
new file mode 100644
index 00000000..51ea943e
--- /dev/null
+++ b/src/components/master/ManageDocumentType.jsx
@@ -0,0 +1,223 @@
+import React, { useEffect } from "react";
+import { useForm, FormProvider } from "react-hook-form";
+import { z } from "zod";
+import { zodResolver } from "@hookform/resolvers/zod";
+import { useCreateDocumentType, useDocumentCategories, useUpdateDocumentType } from "../../hooks/masterHook/useMaster";
+import { DOCUMENTS_ENTITIES } from "../../utils/constants";
+
+
+export const Document_Entity = Object.entries(DOCUMENTS_ENTITIES).map(
+ ([key, value]) => ({ key, value })
+);
+const DocumentTypeSchema = z.object({
+ name: z.string().min(1, { message: "Name is required" }),
+ regexExpression: z.string().optional(),
+ allowedContentType: z.string().min(1, { message: "Allowed content type is required" }),
+ maxSizeAllowedInMB: z
+ .number({ invalid_type_error: "Must be a number" })
+ .min(1, { message: "Max size must be at least 1MB" }),
+ isValidationRequired: z.boolean().default(true),
+ isMandatory: z.boolean().default(true),
+ documentCategoryId: z.string().min(1, { message: "Document Category is required" }),
+});
+
+const ManageDocumentType = ({ data, onClose, documentCategories = [] }) => {
+ const methods = useForm({
+ resolver: zodResolver(DocumentTypeSchema),
+ defaultValues: {
+ name: "",
+ regexExpression: "",
+ allowedContentType: "",
+ maxSizeAllowedInMB: 25,
+ isValidationRequired: true,
+ isMandatory: true,
+ documentCategoryId: "",
+ entityTypeId:""
+ },
+ });
+ const {
+ register,
+ handleSubmit,
+ reset,watch,
+ formState: { errors },
+ } = methods;
+
+
+ const selectedDocumentEntity = watch("entityTypeId")
+ const {DocumentCategories,isLoading} = useDocumentCategories(selectedDocumentEntity)
+
+
+
+ const { mutate: createDocType, isPending: creating } = useCreateDocumentType(() =>
+ onClose?.()
+ );
+ const { mutate: updateDocType, isPending: updating } = useUpdateDocumentType(() =>
+ onClose?.()
+ );
+const onSubmit = (payload) => {
+ const { entityTypeId, ...rest } = payload;
+
+ if (data) {
+ updateDocType({ id: data.id, payload: { ...rest, id: data.id } });
+ } else {
+ createDocType(rest);
+ }
+};
+
+
+ useEffect(() => {
+ if (data) {
+ reset({
+ name: data.name ?? "",
+ regexExpression: data.regexExpression ?? "",
+ allowedContentType: data.allowedContentType ?? "",
+ maxSizeAllowedInMB: data.maxSizeAllowedInMB ?? 25,
+ isValidationRequired: data.isValidationRequired ?? true,
+ isMandatory: data.isMandatory ?? true,
+ documentCategoryId: data.documentCategory?.id ?? "",
+ entityTypeId:data.documentCategory?.entityTypeId ?? ""
+ });
+ }
+ }, [data]);
+
+ return (
+
+
+
+ );
+};
+
+export default ManageDocumentType;
diff --git a/src/components/master/MasterModal.jsx b/src/components/master/MasterModal.jsx
index 3f644420..d6665767 100644
--- a/src/components/master/MasterModal.jsx
+++ b/src/components/master/MasterModal.jsx
@@ -1,119 +1,68 @@
-import React, { useState, useEffect } from "react";
+import React from "react";
import CreateRole from "./CreateRole";
-import DeleteMaster from "./DeleteMaster";
import EditRole from "./EditRole";
import CreateJobRole from "./CreateJobRole";
import EditJobRole from "./EditJobRole";
import CreateActivity from "./CreateActivity";
import EditActivity from "./EditActivity";
-import ConfirmModal from "../common/ConfirmModal";
-import { MasterRespository } from "../../repositories/MastersRepository";
-import { cacheData, getCachedData } from "../../slices/apiDataManager";
-import showToast from "../../services/toastService";
import CreateWorkCategory from "./CreateWorkCategory";
import EditWorkCategory from "./EditWorkCategory";
import CreateCategory from "./CreateContactCategory";
import CreateContactTag from "./CreateContactTag";
import EditContactCategory from "./EditContactCategory";
import EditContactTag from "./EditContactTag";
-import { useDeleteMasterItem } from "../../hooks/masterHook/useMaster";
import ManageExpenseType from "./ManageExpenseType";
import ManagePaymentMode from "./ManagePaymentMode";
import ManageExpenseStatus from "./ManageExpenseStatus";
import ManageDocumentCategory from "./ManageDocumentCategory";
-
+import ManageDocumentType from "./ManageDocumentType";
const MasterModal = ({ modaldata, closeModal }) => {
- const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false);
- const { mutate: deleteMasterItem, isPending } = useDeleteMasterItem();
-
- const handleSelectedMasterDeleted = () => {
- const { masterType, item, validateFn } = modaldata || {};
- if (!masterType || !item?.id) {
- showToast("Missing master type or item", "error");
- return;
- }
-
- deleteMasterItem(
- { masterType, item, validateFn },
- { onSuccess: handleCloseDeleteModal }
- );
- };
-
- const handleCloseDeleteModal = () => {
- setIsDeleteModalOpen(false);
- closeModal();
- };
-
- useEffect(() => {
- if (modaldata?.modalType === "delete") {
- setIsDeleteModalOpen(true);
- }
- }, [modaldata]);
-
- if (!modaldata?.modalType) {
- closeModal();
+ if (!modaldata?.modalType || modaldata.modalType === "delete") {
+
return null;
}
- if (modaldata.modalType === "delete" && isDeleteModalOpen) {
- return (
-
-
-
- );
- }
+ const { modalType, item, masterType } = modaldata;
- const renderModalContent = () => {
- const { modalType, item, masterType } = modaldata;
-
- const modalComponents = {
- "Application Role":
,
- "Edit-Application Role":
,
- "Job Role":
,
- "Edit-Job Role":
,
- "Activity":
,
- "Edit-Activity":
,
- "Work Category":
,
- "Edit-Work Category":
,
- "Contact Category":
,
- "Edit-Contact Category":
,
- "Contact Tag":
,
- "Edit-Contact Tag":
,
- "Expense Type":
,
- "Edit-Expense Type":
,
- "Payment Mode":
,
- "Edit-Payment Mode":,
- "Expense Status":,
- "Edit-Expense Status":,
- "Document Category":,
- "Edit-Document Category":
- };
-
- return modalComponents[modalType] || null;
+ const modalComponents = {
+ "Application Role": (
+
+ ),
+ "Edit-Application Role": (
+
+ ),
+ "Job Role": ,
+ "Edit-Job Role": ,
+ "Activity": ,
+ "Edit-Activity": ,
+ "Work Category": ,
+ "Edit-Work Category": ,
+ "Contact Category": ,
+ "Edit-Contact Category": (
+
+ ),
+ "Contact Tag": ,
+ "Edit-Contact Tag": ,
+ "Expense Type": ,
+ "Edit-Expense Type": ,
+ "Payment Mode": ,
+ "Edit-Payment Mode": ,
+ "Expense Status": ,
+ "Edit-Expense Status": (
+
+ ),
+ "Document Category": ,
+ "Edit-Document Category": (
+
+ ),
+ "Document Type": ,
+ "Edit-Document Type": (
+
+ ),
};
- const isLargeModal = ["Application Role", "Edit-Application Role"].includes(
- modaldata.modalType
- );
-
- return (
- <>
- {renderModalContent()}
- >
- );
+ return modalComponents[modalType] || null;
};
export default MasterModal;
diff --git a/src/hooks/masterHook/useMaster.js b/src/hooks/masterHook/useMaster.js
index c7d23bc9..cae0f027 100644
--- a/src/hooks/masterHook/useMaster.js
+++ b/src/hooks/masterHook/useMaster.js
@@ -748,6 +748,7 @@ export const useCreateDocumentCatgory =(onSuccessCallback)=>{
onSuccess: ( data ) =>
{
queryClient.invalidateQueries( {queryKey:[ "masterData", "Document Category" ]} )
+ queryClient.invalidateQueries( {queryKey:[ "Document Category" ]} )
showToast( "Document Category added successfully", "success" );
if(onSuccessCallback) onSuccessCallback(data)
},
@@ -770,6 +771,7 @@ export const useUpdateDocumentCategory =(onSuccessCallback)=>{
onSuccess: ( data ) =>
{
queryClient.invalidateQueries( {queryKey:[ "masterData", "Document Category" ]} )
+ queryClient.invalidateQueries( {queryKey:[ "Document Category" ]} )
showToast( "Document Category Updated successfully", "success" );
if(onSuccessCallback) onSuccessCallback(data)
},
@@ -779,6 +781,51 @@ export const useUpdateDocumentCategory =(onSuccessCallback)=>{
}
})
}
+
+// ------------------------------Document-Type-----------------------------------
+export const useCreateDocumentType =(onSuccessCallback)=>{
+ const queryClient = useQueryClient();
+
+ return useMutation( {
+ mutationFn: async ( payload ) =>
+ {
+ const resp = await MasterRespository.createDocumentType(payload);
+ return resp.data;
+ },
+ onSuccess: ( data ) =>
+ {
+ queryClient.invalidateQueries( {queryKey:[ "masterData", "Document Type" ]} )
+ showToast( "Document Type added successfully", "success" );
+ if(onSuccessCallback) onSuccessCallback(data)
+ },
+ onError: ( error ) =>
+ {
+ showToast(error.message || "Something went wrong", "error");
+ }
+ })
+}
+
+export const useUpdateDocumentType =(onSuccessCallback)=>{
+ const queryClient = useQueryClient();
+
+ return useMutation( {
+ mutationFn: async ( {id,payload} ) =>
+ {
+ const resp = await MasterRespository.updateDocumentType(id,payload);
+ return resp.data;
+ },
+ onSuccess: ( data ) =>
+ {
+ queryClient.invalidateQueries( {queryKey:[ "masterData", "Document Type" ]} )
+ showToast( "Document Type Updated successfully", "success" );
+ if(onSuccessCallback) onSuccessCallback(data)
+ },
+ onError: ( error ) =>
+ {
+ showToast(error.message || "Something went wrong", "error");
+ }
+ })
+}
// -Delete Master --------
export const useDeleteMasterItem = () => {
const queryClient = useQueryClient();
diff --git a/src/pages/master/MasterPage.jsx b/src/pages/master/MasterPage.jsx
index 3d6295c9..c73a1c29 100644
--- a/src/pages/master/MasterPage.jsx
+++ b/src/pages/master/MasterPage.jsx
@@ -4,35 +4,45 @@ import MasterModal from "../../components/master/MasterModal";
import { mastersList } from "../../data/masters";
import { useDispatch, useSelector } from "react-redux";
import { changeMaster } from "../../slices/localVariablesSlice";
-import useMaster, { useMasterMenu } from "../../hooks/masterHook/useMaster"
+import useMaster, {
+ useDeleteMasterItem,
+ useMasterMenu,
+} from "../../hooks/masterHook/useMaster";
import MasterTable from "./MasterTable";
import { getCachedData } from "../../slices/apiDataManager";
import { useHasUserPermission } from "../../hooks/useHasUserPermission";
import { MANAGE_MASTER } from "../../utils/constants";
import { useQueryClient } from "@tanstack/react-query";
import GlobalModel from "../../components/common/GlobalModel";
-
+import ConfirmModal from "../../components/common/ConfirmModal";
const MasterPage = () => {
- const {data,isLoading,isError,error:menuError} = useMasterMenu()
- const [modalConfig, setModalConfig] = useState({ modalType: "", item: null, masterType: null });
- const [searchTerm, setSearchTerm] = useState('');
+ const { data, isLoading, isError, error: menuError } = useMasterMenu();
+ const [modalConfig, setModalConfig] = useState(null);
+ const [searchTerm, setSearchTerm] = useState("");
const [filteredResults, setFilteredResults] = useState([]);
const [isCreateModalOpen, setIsCreateModalOpen] = useState(false);
const hasMasterPermission = useHasUserPermission(MANAGE_MASTER);
const dispatch = useDispatch();
- const selectedMaster = useSelector((store) => store.localVariables.selectedMaster);
+ const selectedMaster = useSelector(
+ (store) => store.localVariables.selectedMaster
+ );
const queryClient = useQueryClient();
- const { data: masterData = [], loading, error, RecallApi,isError:isMasterError } = useMaster();
-
+ const {
+ data: masterData = [],
+ loading,
+ error,
+ RecallApi,
+ isError: isMasterError,
+ } = useMaster();
+ const { mutate: deleteMasterItem, isPending } = useDeleteMasterItem();
const openModal = () => setIsCreateModalOpen(true);
const closeModal = () => {
setIsCreateModalOpen(false);
setModalConfig(null);
-
};
const handleModalData = (modalType, item, masterType = selectedMaster) => {
@@ -46,15 +56,17 @@ const MasterPage = () => {
if (!masterData?.length) return;
const results = masterData.filter((item) =>
- Object.values(item).some(
- (field) => field?.toString().toLowerCase().includes(value)
+ Object.values(item).some((field) =>
+ field?.toString().toLowerCase().includes(value)
)
);
setFilteredResults(results);
};
const displayData = useMemo(() => {
if (searchTerm) return filteredResults;
- return queryClient.getQueryData(["masterData", selectedMaster]) || masterData;
+ return (
+ queryClient.getQueryData(["masterData", selectedMaster]) || masterData
+ );
}, [searchTerm, filteredResults, selectedMaster, masterData]);
const columns = useMemo(() => {
@@ -65,9 +77,12 @@ const MasterPage = () => {
}));
}, [displayData]);
- useEffect(() => {
- if (modalConfig) openModal();
- }, [modalConfig]);
+useEffect(() => {
+ if (modalConfig?.modalType && modalConfig?.modalType !== "delete") {
+ openModal();
+ }
+}, [modalConfig]);
+
useEffect(() => {
return () => {
@@ -76,14 +91,44 @@ const MasterPage = () => {
};
}, []);
- if(isError || isMasterError) return
-
Oops, an error occurred
-
{error?.message || menuError?.message}
-
+ if (isError || isMasterError)
+ return (
+
+
+ Oops, an error
+ occurred
+
+
{error?.message || menuError?.message}
+
+ );
return (
<>
- {isCreateModalOpen && (
- setIsCreateModalOpen(false)} size={modalConfig.masterType === "Application Role" ? "lg":"md"}>
+ {modalConfig?.modalType === "delete" && (
+ {
+ deleteMasterItem(
+ {
+ masterType: modalConfig.masterType,
+ item: modalConfig.item,
+ validateFn: modalConfig.validateFn,
+ },
+ { onSuccess: closeModal }
+ );
+ }}
+ onClose={closeModal}
+ loading={isPending}
+ isOpen={true}
+ />
+ )}
+ {isCreateModalOpen && modalConfig?.modalType !== "delete" && (
+
)}
@@ -112,17 +157,24 @@ const MasterPage = () => {
>
@@ -145,10 +197,13 @@ const MasterPage = () => {
>