partially implementation of masters in react query hooks

This commit is contained in:
Pramod Mahajan 2025-07-01 13:23:16 +05:30
parent 8dbce6dd49
commit a02a33a247
17 changed files with 1651 additions and 1074 deletions

View File

@ -49,7 +49,6 @@ const TaskModel = ({
const { activities, loading, error } = useActivitiesMaster(); const { activities, loading, error } = useActivitiesMaster();
const { categories, categoryLoading, categoryError } = const { categories, categoryLoading, categoryError } =
useWorkCategoriesMaster(); useWorkCategoriesMaster();
const { const {
register, register,
handleSubmit, handleSubmit,

View File

@ -7,6 +7,7 @@ import { MasterRespository } from "../../repositories/MastersRepository";
import { clearApiCacheKey } from "../../slices/apiCacheSlice"; import { clearApiCacheKey } from "../../slices/apiCacheSlice";
import { getCachedData, cacheData } from "../../slices/apiDataManager"; import { getCachedData, cacheData } from "../../slices/apiDataManager";
import showToast from "../../services/toastService"; import showToast from "../../services/toastService";
import {useCreateActivity} from "../../hooks/masterHook/useMaster";
const schema = z.object({ const schema = z.object({
activityName: z.string().min(1, { message: "Activity Name is required" }), activityName: z.string().min(1, { message: "Activity Name is required" }),
@ -23,7 +24,8 @@ const schema = z.object({
}); });
const CreateActivity = ({ onClose }) => { const CreateActivity = ({ onClose }) => {
const [isLoading, setIsLoading] = useState(false); const maxDescriptionLength = 255;
const { mutate: createActivity, isPending: isLoading } = useCreateActivity(() => onClose?.());
const { const {
register, register,
@ -44,7 +46,6 @@ const CreateActivity = ({ onClose }) => {
}, },
}); });
const { const {
fields: checkListItems, fields: checkListItems,
append, append,
@ -54,31 +55,10 @@ const CreateActivity = ({ onClose }) => {
name: "checkList", name: "checkList",
}); });
// Form submission handler const addChecklistItem = useCallback(() => {
const onSubmit = (data) => {
setIsLoading(true);
MasterRespository.createActivity(data)
.then( ( resp ) =>
{
const cachedData = getCachedData("Activity");
const updatedData = [ ...cachedData, resp?.data ];
cacheData("Activity", updatedData);
showToast("Activity Successfully Added.", "success");
setIsLoading(false);
handleClose()
})
.catch((error) => {
showToast(error.message, "error");
setIsLoading(false);
});
};
const addChecklistItem = () => {
const values = getValues("checkList"); const values = getValues("checkList");
const lastIndex = checkListItems.length - 1; const lastIndex = checkListItems.length - 1;
if ( if (
checkListItems.length > 0 && checkListItems.length > 0 &&
(!values?.[lastIndex] || values[lastIndex].description.trim() === "") (!values?.[lastIndex] || values[lastIndex].description.trim() === "")
@ -89,35 +69,51 @@ const CreateActivity = ({ onClose }) => {
}); });
return; return;
} }
clearErrors(`checkList.${lastIndex}.description`); clearErrors(`checkList.${lastIndex}.description`);
append({ append({ id: null, description: "", isMandatory: false });
id: null, }, [checkListItems, getValues, append, setError, clearErrors]);
description: "",
isMandatory: false,
});
};
const removeChecklistItem = (index) => { const removeChecklistItem = useCallback((index) => {
remove(index); remove(index);
}; }, [remove]);
const handleChecklistChange = useCallback((index, value) => {
const handleChecklistChange = (index, value) => {
setValue(`checkList.${index}`, value); setValue(`checkList.${index}`, value);
}; }, [setValue]);
const handleClose = () => { const onSubmit = (formData) => {
createActivity(formData);
};
// const onSubmit = (data) => {
// setIsLoading(true);
// MasterRespository.createActivity(data)
// .then( ( resp ) =>
// {
// const cachedData = getCachedData("Activity");
// const updatedData = [ ...cachedData, resp?.data ];
// cacheData("Activity", updatedData);
// showToast("Activity Successfully Added.", "success");
// setIsLoading(false);
// handleClose()
// })
// .catch((error) => {
// showToast(error.message, "error");
// setIsLoading(false);
// });
// };
const handleClose = useCallback(() => {
reset(); reset();
onClose(); onClose();
}; }, [reset, onClose]);
// for tooltip
useEffect(() => { useEffect(() => {
const tooltipTriggerList = Array.from(document.querySelectorAll('[data-bs-toggle="tooltip"]')); const tooltipTriggerList = Array.from(document.querySelectorAll('[data-bs-toggle="tooltip"]'));
tooltipTriggerList.forEach((el) => new bootstrap.Tooltip(el)); tooltipTriggerList.forEach((el) => new bootstrap.Tooltip(el));
}, []); }, []);
return ( return (
<form onSubmit={handleSubmit(onSubmit)}> <form onSubmit={handleSubmit(onSubmit)}>
{/* <h6>Create Activity</h6> */} {/* <h6>Create Activity</h6> */}

View File

@ -6,6 +6,7 @@ import { MasterRespository } from '../../repositories/MastersRepository';
import { clearApiCacheKey } from '../../slices/apiCacheSlice'; import { clearApiCacheKey } from '../../slices/apiCacheSlice';
import { getCachedData,cacheData } from '../../slices/apiDataManager'; import { getCachedData,cacheData } from '../../slices/apiDataManager';
import showToast from '../../services/toastService'; import showToast from '../../services/toastService';
import {useCreateContactCategory} from '../../hooks/masterHook/useMaster';
const schema = z.object({ const schema = z.object({
@ -16,51 +17,52 @@ const schema = z.object({
const CreateContactCategory = ({onClose}) => { const CreateContactCategory = ({onClose}) => {
const[isLoading,setIsLoading] = useState(false)
const { const {
register, register,
handleSubmit, handleSubmit,
formState: { errors },reset formState: { errors },
reset,
} = useForm({ } = useForm({
resolver: zodResolver(schema), resolver: zodResolver(schema),
defaultValues: { defaultValues: {
name: "", name: "",
description: "", description: "",
}, },
}); });
const onSubmit = (data) => {
setIsLoading(true)
MasterRespository.createContactCategory(data).then((resp)=>{
setIsLoading(false)
resetForm()
const cachedData = getCachedData("Contact Category");
const updatedData = [...cachedData, resp?.data];
cacheData("Contact Category", updatedData);
showToast("Contact Category Added successfully.", "success");
onClose()
}).catch((error)=>{
showToast(error?.response?.data?.message, "error");
setIsLoading(false)
})
};
const resetForm = () => {
reset({
name: "",
description: ""
});
setDescriptionLength(0);
}
useEffect(()=>{
return ()=>resetForm()
},[])
const [descriptionLength, setDescriptionLength] = useState(0); const [descriptionLength, setDescriptionLength] = useState(0);
const maxDescriptionLength = 255; const maxDescriptionLength = 255;
const { mutate: createContactCategory, isPending: isLoading } = useCreateContactCategory(() => onClose?.());
const onSubmit = (payload) => {
createContactCategory(payload);
};
// const onSubmit = (data) => {
// setIsLoading(true)
// MasterRespository.createContactCategory(data).then((resp)=>{
// setIsLoading(false)
// resetForm()
// const cachedData = getCachedData("Contact Category");
// const updatedData = [...cachedData, resp?.data];
// cacheData("Contact Category", updatedData);
// showToast("Contact Category Added successfully.", "success");
// onClose()
// }).catch((error)=>{
// showToast(error?.response?.data?.message, "error");
// setIsLoading(false)
// })
// };
const resetForm = () => {
reset({ name: "", description: "" });
setDescriptionLength(0);
};
useEffect(() => {
return () => resetForm();
}, []);
return (<> return (<>
<form className="row g-2" onSubmit={handleSubmit(onSubmit)}> <form className="row g-2" onSubmit={handleSubmit(onSubmit)}>
<div className="col-12 col-md-12"> <div className="col-12 col-md-12">

View File

@ -6,6 +6,7 @@ import { MasterRespository } from '../../repositories/MastersRepository';
import { clearApiCacheKey } from '../../slices/apiCacheSlice'; import { clearApiCacheKey } from '../../slices/apiCacheSlice';
import { getCachedData,cacheData } from '../../slices/apiDataManager'; import { getCachedData,cacheData } from '../../slices/apiDataManager';
import showToast from '../../services/toastService'; import showToast from '../../services/toastService';
import {useCreateContactTag} from '../../hooks/masterHook/useMaster';
const schema = z.object({ const schema = z.object({
@ -15,53 +16,53 @@ const schema = z.object({
}); });
const CreateContactTag = ({onClose}) => { const CreateContactTag = ({onClose}) => {
const[isLoading,setIsLoading] = useState(false)
const { const {
register, register,
handleSubmit, handleSubmit,
formState: { errors },reset formState: { errors },
reset,
} = useForm({ } = useForm({
resolver: zodResolver(schema), resolver: zodResolver(schema),
defaultValues: { defaultValues: {
name: "", name: "",
description: "", description: "",
}, },
}); });
const onSubmit = (data) => {
setIsLoading(true)
MasterRespository.createContactTag(data).then((resp)=>{
setIsLoading(false)
resetForm()
debugger
const cachedData = getCachedData("Contact Tag");
const updatedData = [...cachedData, resp?.data];
cacheData("Contact Tag", updatedData);
showToast("Contact Tag Added successfully.", "success");
console.log(getCachedData("Contact Tag"))
onClose()
}).catch((error)=>{
showToast(error?.response?.data?.message, "error");
setIsLoading(false)
})
};
const resetForm = () => {
reset({
name: "",
description: ""
});
setDescriptionLength(0);
}
useEffect(()=>{
return ()=>resetForm()
},[])
const [descriptionLength, setDescriptionLength] = useState(0); const [descriptionLength, setDescriptionLength] = useState(0);
const maxDescriptionLength = 255; const maxDescriptionLength = 255;
const { mutate: createContactTag, isPending: isLoading } = useCreateContactTag(() => onClose?.());
const onSubmit = (payload) => {
createContactTag(payload);
};
// const onSubmit = (data) => {
// setIsLoading(true)
// MasterRespository.createContactTag(data).then((resp)=>{
// setIsLoading(false)
// resetForm()
// debugger
// const cachedData = getCachedData("Contact Tag");
// const updatedData = [...cachedData, resp?.data];
// cacheData("Contact Tag", updatedData);
// showToast("Contact Tag Added successfully.", "success");
// console.log(getCachedData("Contact Tag"))
// onClose()
// }).catch((error)=>{
// showToast(error?.response?.data?.message, "error");
// setIsLoading(false)
// })
// };
const resetForm = () => {
reset({ name: "", description: "" });
setDescriptionLength(0);
};
useEffect(() => {
return () => resetForm();
}, []);
return (<> return (<>
<form className="row g-2" onSubmit={handleSubmit(onSubmit)}> <form className="row g-2" onSubmit={handleSubmit(onSubmit)}>
<div className="col-12 col-md-12"> <div className="col-12 col-md-12">

View File

@ -6,6 +6,7 @@ import { MasterRespository } from '../../repositories/MastersRepository';
import { clearApiCacheKey } from '../../slices/apiCacheSlice'; import { clearApiCacheKey } from '../../slices/apiCacheSlice';
import { getCachedData,cacheData } from '../../slices/apiDataManager'; import { getCachedData,cacheData } from '../../slices/apiDataManager';
import showToast from '../../services/toastService'; import showToast from '../../services/toastService';
import {useCreateJobRole} from '../../hooks/masterHook/useMaster';
const schema = z.object({ const schema = z.object({
@ -16,58 +17,75 @@ const schema = z.object({
const CreateJobRole = ({onClose}) => { const CreateJobRole = ({onClose}) => {
const[isLoading,setIsLoading] = useState(false) const maxDescriptionLength = 255;
const [descriptionLength, setDescriptionLength] = useState(0);
const { const {
register, register,
handleSubmit, handleSubmit,
formState: { errors },reset formState: { errors },
reset,
watch,
} = useForm({ } = useForm({
resolver: zodResolver(schema), resolver: zodResolver(schema),
defaultValues: { defaultValues: {
role: "", role: "",
description: "", description: "",
}, },
}); });
const resetForm = () => {
reset({ role: "", description: "" });
setDescriptionLength(0);
};
const { mutate: createJobRole, isPending:isLoading } = useCreateJobRole(() => {
onClose?.();
} );
// const onSubmit = (data) => {
// setIsLoading(true)
// const result = {
// name: data.role,
// description: data.description,
// };
// MasterRespository.createJobRole(result).then((resp)=>{
// setIsLoading(false)
// resetForm()
// const cachedData = getCachedData("Job Role");
// const updatedData = [...cachedData, resp?.data];
// cacheData("Job Role", updatedData);
// showToast("JobRole Added successfully.", "success");
// onClose()
// }).catch((error)=>{
// showToast(error.message, "error");
// setIsLoading(false)
// })
// };
const onSubmit = (data) => { const onSubmit = (data) => {
setIsLoading(true) const payload = {
const result = {
name: data.role, name: data.role,
description: data.description, description: data.description,
}; };
createJobRole(payload);
MasterRespository.createJobRole(result).then((resp)=>{
setIsLoading(false)
resetForm()
const cachedData = getCachedData("Job Role");
const updatedData = [...cachedData, resp?.data];
cacheData("Job Role", updatedData);
showToast("JobRole Added successfully.", "success");
onClose()
}).catch((error)=>{
showToast(error.message, "error");
setIsLoading(false)
})
}; };
const resetForm = () => {
reset({
role: "",
description: ""
});
setDescriptionLength(0);
}
useEffect(() => { useEffect(() => {
return ()=>resetForm() const sub = watch((values) => {
},[]) setDescriptionLength(values.description?.length || 0);
});
return () => sub.unsubscribe();
}, [watch]);
useEffect(() => {
return () => resetForm();
}, []);
const [descriptionLength, setDescriptionLength] = useState(0);
const maxDescriptionLength = 255;
return (<> return (<>
<form className="row g-2" onSubmit={handleSubmit(onSubmit)}> <form className="row g-2" onSubmit={handleSubmit(onSubmit)}>
{/* <div className="col-12 col-md-12"> {/* <div className="col-12 col-md-12">

View File

@ -1,21 +1,19 @@
import React, { useEffect, useState, useRef } from "react"; import React, { useEffect, useState, useRef } from "react";
import { useFeatures } from "../../hooks/useMasterRole"; import { useFeatures } from "../../hooks/useMasterRole";
import { useForm } from 'react-hook-form'; import { useForm } from "react-hook-form";
import { set, z } from 'zod'; import { set, z } from "zod";
import { zodResolver } from '@hookform/resolvers/zod'; import { zodResolver } from "@hookform/resolvers/zod";
import { MasterRespository } from "../../repositories/MastersRepository"; import { MasterRespository } from "../../repositories/MastersRepository";
import { cacheData, getCachedData } from "../../slices/apiDataManager"; import { cacheData, getCachedData } from "../../slices/apiDataManager";
import showToast from "../../services/toastService"; import showToast from "../../services/toastService";
import { useCreateApplicationRole } from "../../hooks/masterHook/useMaster";
const schema = z.object({ const schema = z.object({
role: z.string().min(1, { message: "Role is required" }), role: z.string().min(1, { message: "Role is required" }),
description: z.string().min(1, { message: "Description is required" }) description: z
.string()
.min(1, { message: "Description is required" })
.max(255, { message: "Description cannot exceed 255 characters" }), .max(255, { message: "Description cannot exceed 255 characters" }),
selectedPermissions: z selectedPermissions: z
@ -23,21 +21,22 @@ const schema = z.object({
.min(1, { message: "Please select at least one permission" }), .min(1, { message: "Please select at least one permission" }),
}); });
const CreateRole = ({ modalType, onClose }) => { const CreateRole = ({ modalType, onClose }) => {
const maxDescriptionLength = 255;
const [isLoading, setIsLoading] = useState(false) const [descriptionLength, setDescriptionLength] = useState(0);
const popoverRefs = useRef([]); const popoverRefs = useRef([]);
const { masterFeatures } = useFeatures() const { masterFeatures } = useFeatures();
const { mutate: submitNewApplicationRole, isPending: isLoading } =
useCreateApplicationRole(() => {
onClose?.();
});
const { const {
register, register,
handleSubmit, handleSubmit,
formState: { errors }, formState: { errors },
reset,
} = useForm({ } = useForm({
resolver: zodResolver(schema), resolver: zodResolver(schema),
defaultValues: { defaultValues: {
@ -48,9 +47,7 @@ const CreateRole = ({ modalType, onClose }) => {
}); });
const onSubmit = (values) => { const onSubmit = (values) => {
setIsLoading(true) const payload = {
const result = {
role: values.role, role: values.role,
description: values.description, description: values.description,
featuresPermission: values.selectedPermissions.map((id) => ({ featuresPermission: values.selectedPermissions.map((id) => ({
@ -59,27 +56,40 @@ const CreateRole = ({ modalType, onClose }) => {
})), })),
}; };
MasterRespository.createRole(result).then((resp) => { submitNewApplicationRole(payload);
setIsLoading(false)
const cachedData = getCachedData("Application Role");
const updatedData = [...cachedData, resp.data];
cacheData("Application Role", updatedData);
showToast("Application Role Added successfully.", "success");
onClose()
}).catch((err) => {
showToast(err?.response?.data?.message, "error");
setIsLoading(false)
onClose()
})
}; };
const [descriptionLength, setDescriptionLength] = useState(0);
const maxDescriptionLength = 255; // const onSubmit = (values) => {
// setIsLoading(true)
// const result = {
// role: values.role,
// description: values.description,
// featuresPermission: values.selectedPermissions.map((id) => ({
// id,
// isEnabled: true,
// })),
// };
// MasterRespository.createRole(result).then((resp) => {
// setIsLoading(false)
// const cachedData = getCachedData("Application Role");
// const updatedData = [...cachedData, resp.data];
// cacheData("Application Role", updatedData);
// showToast("Application Role Added successfully.", "success");
// onClose()
// }).catch((err) => {
// showToast(err?.response?.data?.message, "error");
// setIsLoading(false)
// onClose()
// })
// };
useEffect(() => { useEffect(() => {
setDescriptionLength(0); setDescriptionLength(0);
}, []); }, []);
useEffect(() => { useEffect(() => {
popoverRefs.current.forEach((el) => { popoverRefs.current.forEach((el) => {
if (el) { if (el) {
@ -87,14 +97,13 @@ const CreateRole = ({ modalType, onClose }) => {
trigger: "focus", trigger: "focus",
placement: "right", placement: "right",
html: true, html: true,
content: el.getAttribute("data-bs-content"), // use inline content from attribute content: el.getAttribute("data-bs-content"),
}); });
} }
}); });
}, [masterFeatures]); }, [masterFeatures]);
return ( return (
<form className="row g-2" onSubmit={handleSubmit(onSubmit)}> <form className="row g-2" onSubmit={handleSubmit(onSubmit)}>
{/* <div className="col-12 col-md-12"> {/* <div className="col-12 col-md-12">
<label className="fs-5 text-dark text-center d-flex align-items-center justify-content-center flex-wrap">Create Application Role</label> <label className="fs-5 text-dark text-center d-flex align-items-center justify-content-center flex-wrap">Create Application Role</label>
@ -102,23 +111,24 @@ const CreateRole = ({ modalType, onClose }) => {
</div> */} </div> */}
<div className="col-12 col-md-12"> <div className="col-12 col-md-12">
<label className="form-label">Role</label> <label className="form-label">Role</label>
<input type="text" <input
type="text"
{...register("role")} {...register("role")}
className={`form-control ${errors.role ? 'is-invalids' : ''}`} className={`form-control ${errors.role ? "is-invalids" : ""}`}
/> />
{errors.role && <p className="text-danger">{errors.role.message}</p>} {errors.role && <p className="text-danger">{errors.role.message}</p>}
</div> </div>
<div className="col-12 col-md-12"> <div className="col-12 col-md-12">
<label className="form-label" htmlFor="description">Description</label> <label className="form-label" htmlFor="description">
Description
</label>
<textarea <textarea
rows="3" rows="3"
{...register("description")} {...register("description")}
className={`form-control ${errors.description ? 'is-invalids' : ''}`} className={`form-control ${errors.description ? "is-invalids" : ""}`}
onChange={(e) => { onChange={(e) => {
setDescriptionLength(e.target.value.length); setDescriptionLength(e.target.value.length);
// Also update react-hook-form's value
register("description").onChange(e); register("description").onChange(e);
}} }}
></textarea> ></textarea>
@ -131,26 +141,26 @@ const CreateRole = ({ modalType, onClose }) => {
)} )}
</div> </div>
<div className="col-12 col-md-12 border"> <div className="col-12 col-md-12 border">
{masterFeatures.map((feature, featureIndex) => ( {masterFeatures.map((feature, featureIndex) => (
<React.Fragment key={feature.id}> <React.Fragment key={feature.id}>
<div className="row my-1" key={feature.id} style={{ marginLeft: "0px" }}> <div
className="row my-1"
key={feature.id}
<div className="col-12 col-md-3 d-flex text-start align-items-start" style={{ wordWrap: 'break-word' }}> style={{ marginLeft: "0px" }}
>
<div
className="col-12 col-md-3 d-flex text-start align-items-start"
style={{ wordWrap: "break-word" }}
>
<span className="fs">{feature.name}</span> <span className="fs">{feature.name}</span>
</div> </div>
<div className="col-12 col-md-1"></div> <div className="col-12 col-md-1"></div>
<div className="col-12 col-md-8 d-flex justify-content-start align-items-center flex-wrap"> <div className="col-12 col-md-8 d-flex justify-content-start align-items-center flex-wrap">
{feature.featurePermissions.map((perm, permIndex) => { {feature.featurePermissions.map((perm, permIndex) => {
const refIndex = (featureIndex * 10) + permIndex; const refIndex = featureIndex * 10 + permIndex;
return ( return (
<div className="d-flex me-3 mb-2" key={perm.id}> <div className="d-flex me-3 mb-2" key={perm.id}>
<label className="form-check-label" htmlFor={perm.id}> <label className="form-check-label" htmlFor={perm.id}>
@ -163,15 +173,14 @@ const CreateRole = ({ modalType, onClose }) => {
/> />
{perm.name} {perm.name}
</label> </label>
<div style={{ display: 'flex', alignItems: 'center' }}> <div style={{ display: "flex", alignItems: "center" }}>
<div <div
key={refIndex} key={refIndex}
ref={(el) => ref={(el) => (popoverRefs.current[refIndex] = el)}
(popoverRefs.current[refIndex] = el)
}
tabIndex="0" tabIndex="0"
className="d-flex align-items-center avatar-group justify-content-center" className="d-flex align-items-center avatar-group justify-content-center"
data-bs-toggle="popover" refIndex data-bs-toggle="popover"
refIndex
data-bs-trigger="focus" data-bs-trigger="focus"
data-bs-placement="right" data-bs-placement="right"
data-bs-html="true" data-bs-html="true"
@ -182,23 +191,26 @@ const CreateRole = ({ modalType, onClose }) => {
`} `}
> >
&nbsp; &nbsp;
<svg
<svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" fill="currentColor" className="bi bi-info-circle" viewBox="0 0 16 16"> xmlns="http://www.w3.org/2000/svg"
width="13"
height="13"
fill="currentColor"
className="bi bi-info-circle"
viewBox="0 0 16 16"
>
<path d="M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14zm0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16z" /> <path d="M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14zm0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16z" />
<path d="m8.93 6.588-2.29.287-.082.38.45.083c.294.07.352.176.288.469l-.738 3.468c-.194.897.105 1.319.547 1.11l1.91-2.011c.241-.256.384-.592.287-.984-.172-.439-.58-.827-1.13-.967a.664.664 0 0 1-.58-.309l-.15-.241-.002-.002zM8 4c-.535 0-.943.372-.943.836 0 .464.408.836.943.836.535 0 .943-.372.943-.836 0-.464-.408-.836-.943-.836z" /> <path d="m8.93 6.588-2.29.287-.082.38.45.083c.294.07.352.176.288.469l-.738 3.468c-.194.897.105 1.319.547 1.11l1.91-2.011c.241-.256.384-.592.287-.984-.172-.439-.58-.827-1.13-.967a.664.664 0 0 1-.58-.309l-.15-.241-.002-.002zM8 4c-.535 0-.943.372-.943.836 0 .464.408.836.943.836.535 0 .943-.372.943-.836 0-.464-.408-.836-.943-.836z" />
</svg> </svg>
</div> </div>
</div> </div>
</div> </div>
);
)
})} })}
</div> </div>
</div> </div>
<hr className="hr my-1 py-1" /> <hr className="hr my-1 py-1" />
</React.Fragment> </React.Fragment>
))} ))}
{errors.selectedPermissions && ( {errors.selectedPermissions && (
<p className="text-danger">{errors.selectedPermissions.message}</p> <p className="text-danger">{errors.selectedPermissions.message}</p>
@ -206,10 +218,7 @@ const CreateRole = ({ modalType, onClose }) => {
{!masterFeatures && <p>Loading...</p>} {!masterFeatures && <p>Loading...</p>}
</div> </div>
{masterFeatures && (
{
masterFeatures && (
<div className="col-12 text-center"> <div className="col-12 text-center">
<button type="submit" className="btn btn-sm btn-primary me-3"> <button type="submit" className="btn btn-sm btn-primary me-3">
{isLoading ? "Please Wait..." : "Submit"} {isLoading ? "Please Wait..." : "Submit"}
@ -223,16 +232,9 @@ const CreateRole = ({ modalType, onClose }) => {
Cancel Cancel
</button> </button>
</div> </div>
) )}
}
</form> </form>
); );
}; };
export default CreateRole; export default CreateRole;

View File

@ -6,6 +6,7 @@ import { MasterRespository } from '../../repositories/MastersRepository';
import { clearApiCacheKey } from '../../slices/apiCacheSlice'; import { clearApiCacheKey } from '../../slices/apiCacheSlice';
import { getCachedData,cacheData } from '../../slices/apiDataManager'; import { getCachedData,cacheData } from '../../slices/apiDataManager';
import showToast from '../../services/toastService'; import showToast from '../../services/toastService';
import {useCreateWorkCategory} from '../../hooks/masterHook/useMaster';
const schema = z.object({ const schema = z.object({
@ -16,58 +17,64 @@ const schema = z.object({
const CreateWorkCategory = ({onClose}) => { const CreateWorkCategory = ({onClose}) => {
const[isLoading,setIsLoading] = useState(false)
const { const {
register, register,
handleSubmit, handleSubmit,
formState: { errors },reset formState: { errors },
reset,
} = useForm({ } = useForm({
resolver: zodResolver(schema), resolver: zodResolver(schema),
defaultValues: { defaultValues: {
name: "", name: "",
description: "", description: "",
}, },
}); });
const onSubmit = (data) => { const [descriptionLength, setDescriptionLength] = useState(0);
setIsLoading(true) const maxDescriptionLength = 255;
// const result = {
// name: data.name, const { mutate: createWorkCategory, isPending: isLoading } = useCreateWorkCategory(() => {
// description: data.description, resetForm();
onClose?.();
});
const onSubmit = (payload) => {
createWorkCategory(payload)
};
// const onSubmit = (data) => {
// setIsLoading(true)
// MasterRespository.createWorkCategory(data).then((resp)=>{
// setIsLoading(false)
// resetForm()
// const cachedData = getCachedData("Work Category");
// const updatedData = [...cachedData, resp?.data];
// cacheData("Work Category", updatedData);
// showToast("Work Category Added successfully.", "success");
// onClose()
// }).catch((error)=>{
// showToast(error?.response?.data?.message, "error");
// setIsLoading(false)
// })
// }; // };
MasterRespository.createWorkCategory(data).then((resp)=>{
setIsLoading(false)
resetForm()
const cachedData = getCachedData("Work Category");
const updatedData = [...cachedData, resp?.data];
cacheData("Work Category", updatedData);
showToast("Work Category Added successfully.", "success");
onClose()
}).catch((error)=>{
showToast(error?.response?.data?.message, "error");
setIsLoading(false)
})
};
const resetForm = () => { const resetForm = () => {
reset({ reset({
name: "", name: "",
description: "" description: "",
}); });
setDescriptionLength(0); setDescriptionLength(0);
} };
useEffect(() => { useEffect(() => {
return ()=>resetForm() return () => resetForm();
},[]) }, []);
const [descriptionLength, setDescriptionLength] = useState(0);
const maxDescriptionLength = 255;
return (<> return (<>
<form className="row g-2" onSubmit={handleSubmit(onSubmit)}> <form className="row g-2" onSubmit={handleSubmit(onSubmit)}>
<div className="col-12 col-md-12"> <div className="col-12 col-md-12">

View File

@ -5,6 +5,7 @@ import { zodResolver } from "@hookform/resolvers/zod";
import {MasterRespository} from "../../repositories/MastersRepository"; import {MasterRespository} from "../../repositories/MastersRepository";
import showToast from "../../services/toastService"; import showToast from "../../services/toastService";
import {getCachedData,cacheData} from "../../slices/apiDataManager"; import {getCachedData,cacheData} from "../../slices/apiDataManager";
import {useUpdateActivity} from "../../hooks/masterHook/useMaster";
const schema = z.object({ const schema = z.object({
@ -23,7 +24,7 @@ const schema = z.object({
const UpdateActivity = ({ activityData, onClose }) => { const UpdateActivity = ({ activityData, onClose }) => {
const [isLoading, setIsLoading] = useState(false); const { mutate: updateActivity, isPending: isLoading } = useUpdateActivity(() => onClose?.());
const { const {
register, register,
@ -38,10 +39,10 @@ const UpdateActivity = ({ activityData, onClose }) => {
} = useForm({ } = useForm({
resolver: zodResolver(schema), resolver: zodResolver(schema),
defaultValues: { defaultValues: {
id:activityData.id, id: activityData?.id,
activityName: activityData.activityName, activityName: activityData?.activityName,
unitOfMeasurement: activityData.unitOfMeasurement, unitOfMeasurement: activityData?.unitOfMeasurement,
checkLists: activityData.checkLists || [], checkList: activityData?.checkLists || [],
}, },
}); });
@ -50,7 +51,6 @@ const UpdateActivity = ({ activityData, onClose }) => {
name: "checkList", name: "checkList",
}); });
// Load initial data
useEffect(() => { useEffect(() => {
if (activityData) { if (activityData) {
reset({ reset({
@ -60,45 +60,8 @@ const UpdateActivity = ({ activityData, onClose }) => {
checkList: activityData.checkLists || [], checkList: activityData.checkLists || [],
}); });
} }
}, [activityData]); }, [activityData, reset]);
const handleChecklistChange = (index, value) => {
setValue(`checkList.${index}`, value);
};
// Submit handler
const onSubmit = async(data) => {
setIsLoading(true);
const Activity = {...data, id:activityData.id}
try
{
const response = await MasterRespository.updateActivity( activityData?.id, Activity );
const updatedActivity = response.data;
const cachedData = getCachedData("Activity")
if (cachedData) {
const updatedActivities = cachedData.map((activity) =>
activity.id === updatedActivity.id ? { ...activity, ...updatedActivity } : activity
);
cacheData( "Activity", updatedActivities );
onClose()
}
setIsLoading( false )
showToast("Activity Successfully Updated", "success");
} catch ( err )
{
setIsLoading( false )
showToast("error.message", "error");
}
};
// Add new checklist item
const addChecklistItem = () => { const addChecklistItem = () => {
const values = getValues("checkList"); const values = getValues("checkList");
const lastIndex = checkListItems.length - 1; const lastIndex = checkListItems.length - 1;
@ -122,8 +85,42 @@ const UpdateActivity = ({ activityData, onClose }) => {
remove(index); remove(index);
}; };
const handleChecklistChange = (index, value) => {
setValue(`checkList.${index}`, value);
};
const onSubmit = (formData) => {
const payload = { ...formData, id: activityData.id };
updateActivity({ id: activityData.id, payload });
};
// const onSubmit = async(data) => {
// setIsLoading(true);
// const Activity = {...data, id:activityData.id}
// try
// {
// const response = await MasterRespository.updateActivity( activityData?.id, Activity );
// const updatedActivity = response.data;
// const cachedData = getCachedData("Activity")
// if (cachedData) {
// const updatedActivities = cachedData.map((activity) =>
// activity.id === updatedActivity.id ? { ...activity, ...updatedActivity } : activity
// );
// cacheData( "Activity", updatedActivities );
// onClose()
// }
// setIsLoading( false )
// showToast("Activity Successfully Updated", "success");
// } catch ( err )
// {
// setIsLoading( false )
// showToast("error.message", "error");
// }
// };
// for tooltip
useEffect(() => { useEffect(() => {
const tooltipTriggerList = Array.from(document.querySelectorAll('[data-bs-toggle="tooltip"]')); const tooltipTriggerList = Array.from(document.querySelectorAll('[data-bs-toggle="tooltip"]'));
tooltipTriggerList.forEach((el) => new bootstrap.Tooltip(el)); tooltipTriggerList.forEach((el) => new bootstrap.Tooltip(el));
@ -232,7 +229,7 @@ const UpdateActivity = ({ activityData, onClose }) => {
className="btn btn-xs btn-primary mt-2" className="btn btn-xs btn-primary mt-2"
onClick={addChecklistItem} onClick={addChecklistItem}
> >
<i class="bx bx-plus-circle" data-bs-toggle="tooltip" <i className="bx bx-plus-circle" data-bs-toggle="tooltip"
title="Add Check" title="Add Check"
data-bs-original-title="Add check" ></i> data-bs-original-title="Add check" ></i>
</button> </button>

View File

@ -6,6 +6,7 @@ import { MasterRespository } from '../../repositories/MastersRepository';
import { clearApiCacheKey } from '../../slices/apiCacheSlice'; import { clearApiCacheKey } from '../../slices/apiCacheSlice';
import { getCachedData,cacheData } from '../../slices/apiDataManager'; import { getCachedData,cacheData } from '../../slices/apiDataManager';
import showToast from '../../services/toastService'; import showToast from '../../services/toastService';
import {useUpdateContactCategory} from '../../hooks/masterHook/useMaster';
const schema = z.object({ const schema = z.object({
@ -15,65 +16,72 @@ const schema = z.object({
}); });
const EditContactCategory= ({data,onClose}) => { const EditContactCategory= ({data,onClose}) => {
const[isLoading,setIsLoading] = useState(false)
const { const {
register, register,
handleSubmit, handleSubmit,
formState: { errors },reset formState: { errors },
reset,
} = useForm({ } = useForm({
resolver: zodResolver(schema), resolver: zodResolver(schema),
defaultValues: { defaultValues: {
name: data?.name || "", name: data?.name || "",
description: data?.description || "", description: data?.description || "",
}, },
}); });
const onSubmit = (formdata) => { const [descriptionLength, setDescriptionLength] = useState(data?.description?.length || 0);
setIsLoading(true) const maxDescriptionLength = 255;
const result = {
const { mutate: updateContactCategory, isPending: isLoading } = useUpdateContactCategory(() => onClose?.());
const onSubmit = (formData) => {
const payload = {
id: data?.id, id: data?.id,
name: formdata?.name, name: formData.name,
description: formdata.description, description: formData.description,
}; };
updateContactCategory({id:data?.id,payload});
MasterRespository.updateContactCategory(data?.id,result).then((resp)=>{
setIsLoading(false)
showToast("Contact Category Updated successfully.", "success");
const cachedData = getCachedData("Contact Category");
if (cachedData) {
const updatedData = cachedData.map((category) =>
category.id === data?.id ? { ...category, ...resp.data } : category
);
cacheData("Contact Category", updatedData);
}
onClose()
}).catch((error)=>{
showToast(error?.response?.data?.message, "error")
setIsLoading(false)
})
}; };
// const onSubmit = (formdata) => {
// setIsLoading(true)
// const result = {
// id:data?.id,
// name: formdata?.name,
// description: formdata.description,
// };
// MasterRespository.updateContactCategory(data?.id,result).then((resp)=>{
// setIsLoading(false)
// showToast("Contact Category Updated successfully.", "success");
// const cachedData = getCachedData("Contact Category");
// if (cachedData) {
// const updatedData = cachedData.map((category) =>
// category.id === data?.id ? { ...category, ...resp.data } : category
// );
// cacheData("Contact Category", updatedData);
// }
// onClose()
// }).catch((error)=>{
// showToast(error?.response?.data?.message, "error")
// setIsLoading(false)
// })
// };
const resetForm = () => { const resetForm = () => {
reset({ reset({ name: "", description: "" });
name: "",
description: ""
});
setDescriptionLength(0); setDescriptionLength(0);
} };
useEffect(() => { useEffect(() => {
return ()=>resetForm() return () => resetForm();
},[]) }, []);
const [descriptionLength, setDescriptionLength] = useState(0);
const maxDescriptionLength = 255;
return (<> return (<>
<form className="row g-2" onSubmit={handleSubmit(onSubmit)}> <form className="row g-2" onSubmit={handleSubmit(onSubmit)}>
<div className="col-12 col-md-12"> <div className="col-12 col-md-12">

View File

@ -6,6 +6,7 @@ import { MasterRespository } from '../../repositories/MastersRepository';
import { clearApiCacheKey } from '../../slices/apiCacheSlice'; import { clearApiCacheKey } from '../../slices/apiCacheSlice';
import { getCachedData,cacheData } from '../../slices/apiDataManager'; import { getCachedData,cacheData } from '../../slices/apiDataManager';
import showToast from '../../services/toastService'; import showToast from '../../services/toastService';
import {useUpdateContactTag} from '../../hooks/masterHook/useMaster';
const schema = z.object({ const schema = z.object({
@ -15,65 +16,72 @@ const schema = z.object({
}); });
const EditContactTag= ({data,onClose}) => { const EditContactTag= ({data,onClose}) => {
const[isLoading,setIsLoading] = useState(false)
const { const {
register, register,
handleSubmit, handleSubmit,
formState: { errors },reset formState: { errors },
reset
} = useForm({ } = useForm({
resolver: zodResolver(schema), resolver: zodResolver(schema),
defaultValues: { defaultValues: {
name: data?.name || "", name: data?.name || "",
description: data?.description || "", description: data?.description || "",
}, },
}); });
const onSubmit = (formdata) => { const [descriptionLength, setDescriptionLength] = useState(data?.description?.length || 0);
setIsLoading(true) const maxDescriptionLength = 255;
const result = {
const { mutate: updateContactTag, isPending: isLoading } = useUpdateContactTag(() => onClose?.());
const onSubmit = (formData) => {
const payload = {
id: data?.id, id: data?.id,
name: formdata?.name, name: formData.name,
description: formdata.description, description: formData.description,
}; };
debugger
updateContactTag({ id: data?.id, payload} );
MasterRespository.updateContactTag(data?.id,result).then((resp)=>{
setIsLoading(false)
showToast("Contact Tag Updated successfully.", "success");
const cachedData = getCachedData("Contact Tag");
if (cachedData) {
const updatedData = cachedData.map((category) =>
category.id === data?.id ? { ...category, ...resp.data } : category
);
cacheData("Contact Tag", updatedData);
} }
// const onSubmit = (formdata) => {
// setIsLoading(true)
// const result = {
// id:data?.id,
// name: formdata?.name,
// description: formdata.description,
// };
onClose()
}).catch((error)=>{
showToast(error?.response?.data?.message, "error")
setIsLoading(false)
})
};
// MasterRespository.updateContactTag(data?.id,result).then((resp)=>{
// setIsLoading(false)
// showToast("Contact Tag Updated successfully.", "success");
// const cachedData = getCachedData("Contact Tag");
// if (cachedData) {
// const updatedData = cachedData.map((category) =>
// category.id === data?.id ? { ...category, ...resp.data } : category
// );
// cacheData("Contact Tag", updatedData);
// }
// onClose()
// }).catch((error)=>{
// showToast(error?.response?.data?.message, "error")
// setIsLoading(false)
// })
// };
const resetForm = () => { const resetForm = () => {
reset({ reset({ name: "", description: "" });
name: "",
description: ""
});
setDescriptionLength(0); setDescriptionLength(0);
} };
useEffect(() => { useEffect(() => {
return ()=>resetForm() return () => resetForm();
},[]) }, []);
const [descriptionLength, setDescriptionLength] = useState(0);
const maxDescriptionLength = 255;
return (<> return (<>
<form className="row g-2" onSubmit={handleSubmit(onSubmit)}> <form className="row g-2" onSubmit={handleSubmit(onSubmit)}>
<div className="col-12 col-md-12"> <div className="col-12 col-md-12">

View File

@ -5,6 +5,7 @@ import { zodResolver } from '@hookform/resolvers/zod';
import { MasterRespository } from '../../repositories/MastersRepository'; import { MasterRespository } from '../../repositories/MastersRepository';
import { cacheData,getCachedData } from '../../slices/apiDataManager'; import { cacheData,getCachedData } from '../../slices/apiDataManager';
import showToast from '../../services/toastService'; import showToast from '../../services/toastService';
import {useUpdateJobRole} from '../../hooks/masterHook/useMaster';
@ -17,63 +18,81 @@ const schema = z.object({
const EditJobRole = ({data,onClose}) => { const EditJobRole = ({data,onClose}) => {
const [descriptionLength, setDescriptionLength] = useState(data?.description?.length || 0);
const maxDescriptionLength = 255;
const[isLoading,setIsLoading] = useState(false)
const { const {
register, register,
handleSubmit, handleSubmit,
formState: { errors } ,reset formState: { errors },
reset,
watch,
} = useForm({ } = useForm({
resolver: zodResolver(schema), resolver: zodResolver(schema),
defaultValues: { defaultValues: {
role: data?.name || "", role: data?.name || "",
description: data?.description || "", description: data?.description || "",
}, },
}); });
const onSubmit = (formdata) => { const { mutate: updateJobRole, isPendin:isLoading } = useUpdateJobRole(() => {
setIsLoading(true) onClose?.();
const result = { });
// const onSubmit = (formdata) => {
// setIsLoading(true)
// const result = {
// id:data?.id,
// name: formdata?.role,
// description: formdata.description,
// };
// MasterRespository.updateJobRole(data?.id,result).then((resp)=>{
// setIsLoading(false)
// showToast("JobRole Update successfully.", "success");
// const cachedData = getCachedData("Job Role");
// if (cachedData) {
// const updatedData = cachedData.map((role) =>
// role.id === data?.id ? { ...role, ...resp.data } : role
// );
// cacheData("Job Role", updatedData);
// }
// onClose()
// }).catch((error)=>{
// showToast(error.message, "error")
// setIsLoading(false)
// })
// };
const onSubmit = (formData) => {
updateJobRole({
id: data?.id, id: data?.id,
name: formdata?.role, payload: {
description: formdata.description, id: data?.id,
name: formData.role,
description: formData.description,
},
});
}; };
MasterRespository.updateJobRole(data?.id,result).then((resp)=>{
setIsLoading(false)
showToast("JobRole Update successfully.", "success");
const cachedData = getCachedData("Job Role");
if (cachedData) {
const updatedData = cachedData.map((role) =>
role.id === data?.id ? { ...role, ...resp.data } : role
);
cacheData("Job Role", updatedData);
}
onClose()
}).catch((error)=>{
showToast(error.message, "error")
setIsLoading(false)
})
};
useEffect(() => { useEffect(() => {
reset({ reset({
role: data?.name, role: data?.name || "",
description: data?.description description: data?.description || "",
}); });
setDescriptionLength(data?.description?.length || 0); setDescriptionLength(data?.description?.length || 0);
}, [data, reset]); }, [data, reset]);
const [descriptionLength, setDescriptionLength] = useState(data?.description?.length || 0); useEffect(() => {
const maxDescriptionLength = 255; const sub = watch((values) => {
setDescriptionLength(values.description?.length || 0);
});
return () => sub.unsubscribe();
}, [watch]);
return (<> return (<>
<form className="row g-2" onSubmit={handleSubmit(onSubmit)}> <form className="row g-2" onSubmit={handleSubmit(onSubmit)}>

View File

@ -7,6 +7,7 @@ import { useFeatures } from "../../hooks/useMasterRole";
import { MasterRespository } from "../../repositories/MastersRepository"; import { MasterRespository } from "../../repositories/MastersRepository";
import { cacheData, getCachedData } from "../../slices/apiDataManager"; import { cacheData, getCachedData } from "../../slices/apiDataManager";
import showToast from "../../services/toastService"; import showToast from "../../services/toastService";
import {useUpdateApplicationRole} from "../../hooks/masterHook/useMaster";
@ -27,59 +28,50 @@ const updateSchema = z.object({
const EditMaster = ({ master, onClose }) => { const EditMaster = ({ master, onClose }) => {
const [isLoading, setIsLoading] = useState(false) const maxDescriptionLength = 255;
const { masterFeatures } = useFeatures()
const popoverRefs = useRef([]); const popoverRefs = useRef([]);
const { masterFeatures } = useFeatures();
const { mutate: updateApplicationRole, isPending: isLoading } = useUpdateApplicationRole(() => onClose?.());
const buildDefaultPermissions = () => { const buildDefaultPermissions = () => {
const defaults = {}; const defaults = {};
masterFeatures.forEach((feature) => { masterFeatures.forEach((feature) => {
feature.featurePermissions.forEach((perm) => { feature.featurePermissions.forEach((perm) => {
const existing = master?.item?.featurePermission?.find( const existing = master?.item?.featurePermission?.find(p => p.id === perm.id);
(p) => p.id === perm.id defaults[perm.id] = existing?.isEnabled || false;
);
defaults[perm.id] = existing ? existing.isEnabled : false;
}); });
}); });
return defaults; return defaults;
}; };
const initialPermissions = buildDefaultPermissions(); const initialPermissions = buildDefaultPermissions();
const { const {
register, register,
handleSubmit, handleSubmit,
formState: { errors, dirtyFields }, formState: { errors, dirtyFields },
setError, reset setError,
reset,
} = useForm({ } = useForm({
resolver: zodResolver(updateSchema), resolver: zodResolver(updateSchema),
defaultValues: { defaultValues: {
role: master?.item?.role, role: master?.item?.role || "",
description: master?.item?.description, description: master?.item?.description || "",
permissions: initialPermissions, permissions: initialPermissions,
}, },
}); });
const onSubmit = (data) => { const [descriptionLength, setDescriptionLength] = useState(master?.item?.description?.length || 0);
setIsLoading(true)
const existingIds = new Set(
master?.item?.featurePermission?.map((p) => p.id)
);
const onSubmit = (data) => {
const existingIds = new Set(master?.item?.featurePermission?.map(p => p.id));
const updatedPermissions = Object.entries(data.permissions) const updatedPermissions = Object.entries(data.permissions)
.filter(([id, value]) => { .filter(([id, value]) => {
if (existingIds.has(id)) return true; return existingIds.has(id) || value === true || (dirtyFields.permissions?.[id]);
return (
value === true ||
(dirtyFields.permissions && dirtyFields.permissions[id])
);
}) })
.map(([id, value]) => ({ id, isEnabled: value })); .map(([id, value]) => ({ id, isEnabled: value }));
if (updatedPermissions.length === 0) { if (updatedPermissions.length === 0) {
setError("permissions", { setError("permissions", {
type: "manual", type: "manual",
@ -88,48 +80,80 @@ const EditMaster = ({ master, onClose }) => {
return; return;
} }
const updatedRole = { const payload = {
id: master?.item?.id, id: master?.item?.id,
role: data.role, role: data.role,
description: data.description, description: data.description,
featuresPermission: updatedPermissions, featuresPermission: updatedPermissions,
}; };
MasterRespository.updateRoles(master?.item?.id, updatedRole).then((resp) => {
setIsLoading(false)
const cachedData = getCachedData("Application Role");
if (cachedData) {
const updatedData = cachedData.map((role) =>
role.id === resp.data?.id ? { ...role, ...resp.data } : role
);
cacheData("Application Role", updatedData);
}
showToast("Application Role Updated successfully.", "success");
setIsLoading(false)
onClose()
}).catch((Err) => {
showToast(Err.message, "error");
setIsLoading(false)
})
updateApplicationRole({ id: payload.id, payload });
}; };
// const onSubmit = (data) => {
// setIsLoading(true)
// const existingIds = new Set(
// master?.item?.featurePermission?.map((p) => p.id)
// );
// const updatedPermissions = Object.entries(data.permissions)
// .filter(([id, value]) => {
// if (existingIds.has(id)) return true;
// return (
// value === true ||
// (dirtyFields.permissions && dirtyFields.permissions[id])
// );
// })
// .map(([id, value]) => ({ id, isEnabled: value }));
// if (updatedPermissions.length === 0) {
// setError("permissions", {
// type: "manual",
// message: "At least one permission must be selected.",
// });
// return;
// }
// const updatedRole = {
// id: master?.item?.id,
// role: data.role,
// description: data.description,
// featuresPermission: updatedPermissions,
// };
// MasterRespository.updateRoles(master?.item?.id, updatedRole).then((resp) => {
// setIsLoading(false)
// const cachedData = getCachedData("Application Role");
// if (cachedData) {
// const updatedData = cachedData.map((role) =>
// role.id === resp.data?.id ? { ...role, ...resp.data } : role
// );
// cacheData("Application Role", updatedData);
// }
// showToast("Application Role Updated successfully.", "success");
// setIsLoading(false)
// onClose()
// }).catch((Err) => {
// showToast(Err.message, "error");
// setIsLoading(false)
// })
// };
useEffect(() => { useEffect(() => {
reset({ reset({
role: master?.item?.role, role: master?.item?.role || "",
description: master?.item?.description, description: master?.item?.description || "",
permissions: initialPermissions, permissions: buildDefaultPermissions(),
}); });
setDescriptionLength(master?.item?.description?.length || 0); setDescriptionLength(master?.item?.description?.length || 0);
}, [master, reset]); }, [master, reset]);
const [descriptionLength, setDescriptionLength] = useState(master?.item?.description?.length || 0);
const maxDescriptionLength = 255;
useEffect(() => { useEffect(() => {
popoverRefs.current.forEach((el) => { popoverRefs.current.forEach((el) => {
if (el) { if (el) {
@ -137,18 +161,16 @@ const EditMaster = ({ master, onClose }) => {
trigger: "focus", trigger: "focus",
placement: "right", placement: "right",
html: true, html: true,
content: el.getAttribute("data-bs-content"), // use inline content from attribute content: el.getAttribute("data-bs-content"),
}); });
} }
}); });
}, [masterFeatures]); }, [masterFeatures]);
return ( return (
<form className="row g-2 " onSubmit={handleSubmit(onSubmit)}> <form className="row g-2 " onSubmit={handleSubmit(onSubmit)}>
{/* <div className="col-12 col-md-12">
<label className="fs-5 text-dark text-center d-flex align-items-center justify-content-center flex-wrap">Edit Application Role</label>
</div> */}
<div className="col-12 col-md-12"> <div className="col-12 col-md-12">
<label className="form-label">Role</label> <label className="form-label">Role</label>
<input type="text" <input type="text"

View File

@ -5,6 +5,7 @@ import { zodResolver } from '@hookform/resolvers/zod';
import { MasterRespository } from '../../repositories/MastersRepository'; import { MasterRespository } from '../../repositories/MastersRepository';
import { cacheData,getCachedData } from '../../slices/apiDataManager'; import { cacheData,getCachedData } from '../../slices/apiDataManager';
import showToast from '../../services/toastService'; import showToast from '../../services/toastService';
import {useUpdateWorkCategory} from '../../hooks/masterHook/useMaster';
@ -18,69 +19,75 @@ const schema = z.object({
const EditWorkCategory = ({data,onClose}) => { const EditWorkCategory = ({data,onClose}) => {
const[isLoading,setIsLoading] = useState(false)
const { const {
register, register,
handleSubmit, handleSubmit,
formState: { errors } ,reset formState: { errors },
reset,
} = useForm({ } = useForm({
resolver: zodResolver(schema), resolver: zodResolver(schema),
defaultValues: { defaultValues: {
name: data?.name || "", name: data?.name || "",
description: data?.description || "", description: data?.description || "",
}, },
}); });
const onSubmit = (formdata) => {
setIsLoading(true)
const result = {
id:data?.id,
name: formdata?.name,
description: formdata.description,
};
MasterRespository.updateWorkCategory(data?.id,result).then((resp)=>{
setIsLoading(false)
showToast("Work Category Update successfully.", "success");
const cachedData = getCachedData("Work Category");
if (cachedData) {
const updatedData = cachedData.map((category) =>
category.id === data?.id ? { ...category, ...resp.data } : category
);
cacheData("Work Category", updatedData);
}
onClose()
}).catch((error)=>{
showToast(error?.response?.data?.message, "error")
setIsLoading(false)
})
};
useEffect(() => {
reset({
name: data?.name,
description: data?.description
});
setDescriptionLength(data?.description?.length || 0);
}, [data, reset]);
const [descriptionLength, setDescriptionLength] = useState(data?.description?.length || 0); const [descriptionLength, setDescriptionLength] = useState(data?.description?.length || 0);
const maxDescriptionLength = 255; const maxDescriptionLength = 255;
const { mutate: updateWorkCategory, isPending: isLoading } = useUpdateWorkCategory(() => onClose?.());
const onSubmit = (formdata) => {
const payload = {
id: data?.id,
name: formdata.name,
description: formdata.description,
};
updateWorkCategory({id:data?.id,payload});
};
// const onSubmit = (formdata) => {
// setIsLoading(true)
// const result = {
// id:data?.id,
// name: formdata?.name,
// description: formdata.description,
// };
// MasterRespository.updateWorkCategory(data?.id,result).then((resp)=>{
// setIsLoading(false)
// showToast("Work Category Update successfully.", "success");
// const cachedData = getCachedData("Work Category");
// if (cachedData) {
// const updatedData = cachedData.map((category) =>
// category.id === data?.id ? { ...category, ...resp.data } : category
// );
// cacheData("Work Category", updatedData);
// }
// onClose()
// }).catch((error)=>{
// showToast(error?.response?.data?.message, "error")
// setIsLoading(false)
// })
// };
useEffect(() => {
reset({
name: data?.name || "",
description: data?.description || "",
});
setDescriptionLength(data?.description?.length || 0);
}, [data, reset]);
return (<> return (<>
<form className="row g-2" onSubmit={handleSubmit(onSubmit)}> <form className="row g-2" onSubmit={handleSubmit(onSubmit)}>
{/* <div className="col-12 col-md-12">
<label className="fs-5 text-dark text-center d-flex align-items-center justify-content-center flex-wrap">Edit Work Category</label>
</div>
*/}
<div className="col-12 col-md-12"> <div className="col-12 col-md-12">
<label className="form-label">Category Name</label> <label className="form-label">Category Name</label>
<input type="text" <input type="text"

View File

@ -17,35 +17,55 @@ import CreateCategory from "./CreateContactCategory";
import CreateContactTag from "./CreateContactTag"; import CreateContactTag from "./CreateContactTag";
import EditContactCategory from "./EditContactCategory"; import EditContactCategory from "./EditContactCategory";
import EditContactTag from "./EditContactTag"; import EditContactTag from "./EditContactTag";
import { useDeleteMasterItem } from "../../hooks/masterHook/useMaster";
const MasterModal = ({ modaldata, closeModal }) => { const MasterModal = ({ modaldata, closeModal }) => {
const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false); const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false);
const { mutate: deleteMasterItem, isPending } = useDeleteMasterItem();
const handleSelectedMasterDeleted = async () => // const handleSelectedMasterDeleted = async () =>
{ // {
const deleteFn = MasterRespository[modaldata.masterType]; // debugger
if (!deleteFn) { // const deleteFn = MasterRespository[modaldata.masterType];
showToast(`No delete strategy defined for master type`,"error"); // if (!deleteFn) {
return false; // showToast(`No delete strategy defined for master type`,"error");
// return false;
// }
// try
// {
// const response = await deleteFn( modaldata?.item?.id );
// const selected_cachedData = getCachedData( modaldata?.masterType );
// const updated_master = selected_cachedData?.filter(item => item.id !== modaldata?.item.id);
// cacheData( modaldata?.masterType, updated_master )
// showToast(`${modaldata?.masterType} is deleted successfully`, "success");
// handleCloseDeleteModal()
// } catch ( error )
// {
// const message = error.response.data.message || error.message || "Error occured api during call"
// showToast(message, "success");
// }
// }
const handleSelectedMasterDeleted = () => {
if (!modaldata?.masterType || !modaldata?.item?.id) {
showToast("Missing master type or item", "error");
return;
} }
try deleteMasterItem(
{ {
const response = await deleteFn( modaldata?.item?.id ); masterType: modaldata.masterType,
const selected_cachedData = getCachedData( modaldata?.masterType ); item: modaldata.item,
const updated_master = selected_cachedData?.filter(item => item.id !== modaldata?.item.id); validateFn: modaldata.validateFn, // optional
cacheData( modaldata?.masterType, updated_master ) },
showToast(`${modaldata?.masterType} is deleted successfully`, "success");
handleCloseDeleteModal()
} catch ( error )
{ {
const message = error.response.data.message || error.message || "Error occured api during call" onSuccess: () => {
showToast(message, "success"); handleCloseDeleteModal();
},
} }
} );
};
useEffect(() => { useEffect(() => {
if (modaldata?.modalType === "delete") { if (modaldata?.modalType === "delete") {
@ -88,7 +108,9 @@ const MasterModal = ({ modaldata, closeModal }) => {
> >
<div <div
className={`modal-dialog mx-sm-auto mx-1 ${ className={`modal-dialog mx-sm-auto mx-1 ${
["Application Role", "Edit-Application Role"].includes(modaldata?.modalType) ["Application Role", "Edit-Application Role"].includes(
modaldata?.modalType
)
? "modal-lg" ? "modal-lg"
: "modal-md" : "modal-md"
} modal-simple`} } modal-simple`}
@ -107,7 +129,10 @@ const MasterModal = ({ modaldata, closeModal }) => {
</div> </div>
{modaldata.modalType === "Application Role" && ( {modaldata.modalType === "Application Role" && (
<CreateRole masmodalType={modaldata.masterType} onClose={closeModal} /> <CreateRole
masmodalType={modaldata.masterType}
onClose={closeModal}
/>
)} )}
{modaldata.modalType === "Edit-Application Role" && ( {modaldata.modalType === "Edit-Application Role" && (
<EditRole master={modaldata} onClose={closeModal} /> <EditRole master={modaldata} onClose={closeModal} />
@ -122,7 +147,10 @@ const MasterModal = ({ modaldata, closeModal }) => {
<CreateActivity onClose={closeModal} /> <CreateActivity onClose={closeModal} />
)} )}
{modaldata.modalType === "Edit-Activity" && ( {modaldata.modalType === "Edit-Activity" && (
<EditActivity activityData={modaldata.item} onClose={closeModal} /> <EditActivity
activityData={modaldata.item}
onClose={closeModal}
/>
)} )}
{modaldata.modalType === "Work Category" && ( {modaldata.modalType === "Work Category" && (
<CreateWorkCategory onClose={closeModal} /> <CreateWorkCategory onClose={closeModal} />

View File

@ -2,6 +2,8 @@ import {useState,useEffect} from "react"
import { MasterRespository } from "../../repositories/MastersRepository"; import { MasterRespository } from "../../repositories/MastersRepository";
import { cacheData,getCachedData } from "../../slices/apiDataManager"; import { cacheData,getCachedData } from "../../slices/apiDataManager";
import { useSelector } from "react-redux"; import { useSelector } from "react-redux";
import {useMutation, useQueries, useQuery, useQueryClient} from "@tanstack/react-query";
import showToast from "../../services/toastService";
@ -9,214 +11,687 @@ import { useSelector } from "react-redux";
export const useFeatures = () =>
useMasterData("masterFeatures", MasterRespository.getFeatures);
export const useMasterRole = () => // const useMaster = () => {
useMasterData("masterRole", MasterRespository.getRoles);
// const selectedMaster = useSelector((store)=>store.localVariables.selectedMaster);
// const [data, setData] = useState([]);
// const [loading, setLoading] = useState(true);
// const [error, setError] = useState("");
// useEffect(() => {
// const fetchData = async () => {
// if (!selectedMaster) return;
// setLoading(true);
// try {
// const cachedData = getCachedData(selectedMaster);
// if (cachedData) {
// setData(cachedData);
// } else {
// let response;
// switch (selectedMaster) {
// case "Application Role":
// response = await MasterRespository.getRoles();
// response = response.data;
// break;
// case "Job Role":
// response = await MasterRespository.getJobRole();
// response = response.data
// break;
// case "Activity":
// response = await MasterRespository.getActivites();
// response = response.data
// break;
// case "Work Category":
// response = await MasterRespository.getWorkCategory();
// response = response.data
// break;
// case "Contact Category":
// response = await MasterRespository.getContactCategory();
// response = response.data
// break;
// case "Contact Tag":
// response = await MasterRespository.getContactTag();
// response = response.data
// break;
// case "Status":
// response = [{description: null,featurePermission: null,id: "02dd4761-363c-49ed-8851-3d2489a3e98d",status:"status 1"},{description: null,featurePermission: null,id: "03dy9761-363c-49ed-8851-3d2489a3e98d",status:"status 2"},{description: null,featurePermission: null,id: "03dy7761-263c-49ed-8851-3d2489a3e98d",status:"Status 3"}];
// break;
// default:
// response = [];
// }
// if (response) {
// setData(response);
// cacheData(selectedMaster, response);
// }
// }
// } catch (err) {
// setError("Failed to fetch data.");
// } finally {
// setLoading(false);
// }
// };
// if ( selectedMaster )
// {
// fetchData();
// }
// }, [selectedMaster]);
const useMaster = (isMa) => {
const selectedMaster = useSelector((store)=>store.localVariables.selectedMaster); // return { data, loading, error }
const [data, setData] = useState([]); // };
const [loading, setLoading] = useState(true);
const [error, setError] = useState("");
useEffect(() => {
const fetchData = async () => {
if (!selectedMaster) return;
setLoading(true);
try {
const cachedData = getCachedData(selectedMaster);
if (cachedData) {
setData(cachedData);
} else {
let response;
switch (selectedMaster) { // export const useActivitiesMaster = () =>
// {
// const [ activities, setActivites ] = useState( [] )
// const [ loading, setloading ] = useState( false );
// const [ error, setError ] = useState()
// const fetchActivities =async () => {
// setloading(true);
// try {
// const response = await MasterRespository.getActivites();
// setActivites(response.data);
// cacheData( "ActivityMaster", response.data );
// setloading(false);
// } catch (err) {
// setError(err);
// setloading(false);
// }
// }
// useEffect( () =>
// {
// const cacheddata = getCachedData( "ActivityMaster" );
// if ( !cacheddata )
// {
// fetchActivities()
// } else
// {
// setActivites(cacheddata);
// }
// }, [] )
// return {activities,loading,error}
// }
// export const useWorkCategoriesMaster = () =>
// {
// const [ categories, setCategories ] = useState( [] )
// const [ categoryLoading, setloading ] = useState( false );
// const [ categoryError, setError ] = useState( "" )
// const fetchCategories =async () => {
// const cacheddata = getCachedData("Work Category");
// if (!cacheddata) {
// setloading(true);
// try {
// const response = await MasterRespository.getWorkCategory();
// setCategories(response.data);
// cacheData("Work Category", response.data);
// } catch (err) {
// setError(err);
// console.log(err);
// } finally {
// setloading(false);
// }
// } else {
// setCategories(cacheddata);
// }
// }
// useEffect( () =>
// {
// fetchCategories()
// }, [] )
// return {categories,categoryLoading,categoryError}
// }
// export const useContactCategory = () =>
// {
// const [ contactCategory, setContactCategory ] = useState( [] )
// const [ loading, setLoading ] = useState( false )
// const [ Error, setError ] = useState()
// const fetchConatctCategory = async() =>
// {
// const cache_Category = getCachedData( "Contact Category" );
// if ( !cache_Category )
// {
// try
// {
// let resp = await MasterRespository.getContactCategory();
// setContactCategory( resp.data );
// cacheData("Contact Category",resp.data)
// } catch ( error )
// {
// setError(error)
// }
// } else
// {
// setContactCategory(cache_Category)
// }
// }
// useEffect( () =>
// {
// fetchConatctCategory()
// }, [] )
// return { contactCategory,loading,Error}
// }
// export const useContactTags = () => {
// const [contactTags, setContactTags] = useState([]);
// const [loading, setLoading] = useState(false);
// const [error, setError] = useState(null);
// useEffect(() => {
// const fetchContactTag = async () => {
// const cache_Tags = getCachedData("Contact Tag");
// if (!cache_Tags) {
// setLoading(true);
// try {
// const resp = await MasterRespository.getContactTag();
// setContactTags(resp.data);
// cacheData("Contact Tag", resp.data);
// } catch (err) {
// setError(err);
// } finally {
// setLoading(false);
// }
// } else {
// setContactTags(cache_Tags);
// }
// };
// fetchContactTag();
// }, []);
// return { contactTags, loading, error };
// };
// Separate matser-------------
export const useActivitiesMaster = () =>
{
const { data:activities=[],isLoading:loading,error} = useQuery( {
queryKey: [ "ActivityMaster" ],
queryFn: async() =>
{
const response = await MasterRespository.getActivites();
return response.data
},
onError: (error) => {
showToast(error?.response?.data?.message || error.message || "Failed to fetch ActivityMasters", "error");
},
} )
return {activities,loading,error}
}
export const useWorkCategoriesMaster = () => {
const {
data: categories = [],
isLoading: categoryLoading,
error: categoryError,
} = useQuery({
queryKey: ["Work Category"],
queryFn: async () => {
const response = await MasterRespository.getWorkCategory();
return response.data;
},
onError: (error) => {
showToast(
error?.response?.data?.message ||
error.message ||
"Failed to fetch work categories",
"error"
);
},
});
return { categories, categoryLoading, categoryError };
};
export const useContactCategory = () =>
{
const {data:contactCategory=[],isLoading:loading,error:Error } = useQuery( {
queryKey: [ "Contact Category" ],
queryFn: async () =>
{
let resp = await MasterRespository.getContactCategory();
return resp.data
},
onError: (error) => {
showToast(error?.response?.data?.message || error.message || "Failed to fetch Contact categories", "error");
},
} )
return { contactCategory,loading,Error}
}
export const useContactTags = () => {
const {
data: contactTags = [],
isLoading: loading,
error,
} = useQuery({
queryKey: ["Contact Tag"],
queryFn: async () => {
const res = await MasterRespository.getContactTag();
return res.data;
},
onError: (error) => {
showToast(
error?.response?.data?.message ||
error.message ||
"Failed to fetch Contact Tag",
"error"
);
},
});
return { contactTags, loading, error };
};
// ===Application Masters Query=================================================
const fetchMasterData = async (masterType) => {
switch (masterType) {
case "Application Role": case "Application Role":
response = await MasterRespository.getRoles(); return (await MasterRespository.getRoles()).data;
response = response.data;
break;
case "Job Role": case "Job Role":
response = await MasterRespository.getJobRole(); return (await MasterRespository.getJobRole()).data;
response = response.data
break;
case "Activity": case "Activity":
response = await MasterRespository.getActivites(); return (await MasterRespository.getActivites()).data;
response = response.data
break;
case "Work Category": case "Work Category":
response = await MasterRespository.getWorkCategory(); return (await MasterRespository.getWorkCategory()).data;
response = response.data
break;
case "Contact Category": case "Contact Category":
response = await MasterRespository.getContactCategory(); return (await MasterRespository.getContactCategory()).data;
response = response.data
break;
case "Contact Tag": case "Contact Tag":
response = await MasterRespository.getContactTag(); return (await MasterRespository.getContactTag()).data;
response = response.data
break;
case "Status": case "Status":
response = [{description: null,featurePermission: null,id: "02dd4761-363c-49ed-8851-3d2489a3e98d",status:"status 1"},{description: null,featurePermission: null,id: "03dy9761-363c-49ed-8851-3d2489a3e98d",status:"status 2"},{description: null,featurePermission: null,id: "03dy7761-263c-49ed-8851-3d2489a3e98d",status:"Status 3"}]; return [
break; {
description: null,
featurePermission: null,
id: "02dd4761-363c-49ed-8851-3d2489a3e98d",
status: "status 1",
},
{
description: null,
featurePermission: null,
id: "03dy9761-363c-49ed-8851-3d2489a3e98d",
status: "status 2",
},
{
description: null,
featurePermission: null,
id: "03dy7761-263c-49ed-8851-3d2489a3e98d",
status: "Status 3",
},
];
default: default:
response = []; return [];
}
if (response) {
setData(response);
cacheData(selectedMaster, response);
}
}
} catch (err) {
setError("Failed to fetch data.");
} finally {
setLoading(false);
} }
}; };
if ( selectedMaster ) const useMaster = () => {
{ const selectedMaster = useSelector((store) => store.localVariables.selectedMaster);
fetchData(); const {
} data = [],
isLoading,
error,
} = useQuery({
queryKey: ["masterData", selectedMaster],
queryFn: () => fetchMasterData(selectedMaster),
enabled: !!selectedMaster,
staleTime: 1000 * 60 * 10,
refetchOnWindowFocus: false,
onError: (error) => {
showToast(error?.response?.data?.message || error.message || `Failed to fetch ${selectedMaster} Maseter`, "error");
},
});
}, [selectedMaster]); return { data, loading: isLoading, error };
return { data, loading, error }
}; };
export default useMaster; export default useMaster;
export const useActivitiesMaster = () => // ================================Mutation====================================
{
const [ activities, setActivites ] = useState( [] )
const [ loading, setloading ] = useState( false );
const [ error, setError ] = useState()
const fetchActivities =async () => {
setloading(true);
try {
const response = await MasterRespository.getActivites();
setActivites(response.data);
cacheData( "ActivityMaster", response.data );
setloading(false);
} catch (err) {
setError(err);
setloading(false);
}
}
useEffect( () =>
{
const cacheddata = getCachedData( "ActivityMaster" );
if ( !cacheddata )
{
fetchActivities()
} else
{
setActivites(cacheddata);
}
}, [] )
return {activities,loading,error} // Job Role-----------------------------------
} export const useUpdateJobRole = (onSuccessCallback, onErrorCallback) => {
const queryClient = useQueryClient();
export const useWorkCategoriesMaster = () => return useMutation({
{ mutationFn: async ({ id, payload }) => {
const [ categories, setCategories ] = useState( [] ) const response = await MasterRespository.updateJobRole(id, payload);
const [ categoryLoading, setloading ] = useState( false ); return response.data;
const [ categoryError, setError ] = useState( "" ) },
onSuccess: (data, variables) => {
showToast("JobRole updated successfully.", "success");
const fetchCategories =async () => { queryClient.invalidateQueries({
const cacheddata = getCachedData("Work Category"); queryKey: ["masterData", "Job Role"],
});
if (!cacheddata) { if (onSuccessCallback) onSuccessCallback(data);
setloading(true); },
try { onError: (error) => {
const response = await MasterRespository.getWorkCategory(); showToast(error.message || "Something went wrong", "error");
setCategories(response.data); if (onErrorCallback) onErrorCallback(error);
cacheData("Work Category", response.data); },
} catch (err) { });
setError(err);
console.log(err);
} finally {
setloading(false);
}
} else {
setCategories(cacheddata);
}
}
useEffect( () =>
{
fetchCategories()
}, [] )
return {categories,categoryLoading,categoryError}
}
export const useContactCategory = () =>
{
const [ contactCategory, setContactCategory ] = useState( [] )
const [ loading, setLoading ] = useState( false )
const [ Error, setError ] = useState()
const fetchConatctCategory = async() =>
{
const cache_Category = getCachedData( "Contact Category" );
if ( !cache_Category )
{
try
{
let resp = await MasterRespository.getContactCategory();
setContactCategory( resp.data );
cacheData("Contact Category",resp.data)
} catch ( error )
{
setError(error)
}
} else
{
setContactCategory(cache_Category)
}
}
useEffect( () =>
{
fetchConatctCategory()
}, [] )
return { contactCategory,loading,Error}
}
export const useContactTags = () => {
const [contactTags, setContactTags] = useState([]);
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
useEffect(() => {
const fetchContactTag = async () => {
const cache_Tags = getCachedData("Contact Tag");
if (!cache_Tags) {
setLoading(true);
try {
const resp = await MasterRespository.getContactTag();
setContactTags(resp.data);
cacheData("Contact Tag", resp.data);
} catch (err) {
setError(err);
} finally {
setLoading(false);
}
} else {
setContactTags(cache_Tags);
}
}; };
fetchContactTag(); export const useCreateJobRole = (onSuccessCallback) => {
}, []); const queryClient = useQueryClient();
return { contactTags, loading, error }; return useMutation({
mutationFn: async (payload) => {
const response = await MasterRespository.createJobRole(payload);
return response.data;
},
onSuccess: (data) => {
showToast("JobRole added successfully.", "success");
queryClient.invalidateQueries(["masterData", "Job Role"]);
if (onSuccessCallback) onSuccessCallback(data);
},
onError: (error) => {
showToast(error.message || "Something went wrong", "error");
},
});
};
// Application Role-------------------------------------------
export const useCreateApplicationRole = (onSuccessCallback) =>
{
const queryClient = useQueryClient();
return useMutation( {
mutationFn: async ( payload ) =>
{
const resp = await MasterRespository.createRole( payload );
return resp.data;
},
onSuccess: ( data ) =>
{
queryClient.invalidateQueries( [ "masterData", "Application Role" ] )
showToast( "Application Role added successfully", "success" );
if(onSuccessCallback) onSuccessCallback(data)
},
onError: ( error ) =>
{
showToast(error.message || "Something went wrong", "error");
}
})
}
export const useUpdateApplicationRole = (onSuccessCallback) =>
{
const queryClient = useQueryClient();
return useMutation({
mutationFn: async ( {id, payload} ) =>
{
const response = await MasterRespository.updateRoles(id,payload);
return response.data;
},
onSuccess: (data, variables) => {
queryClient.invalidateQueries({
queryKey: ["masterData", "Application Role"],
});
showToast("Application Role updated successfully.", "success");
if (onSuccessCallback) onSuccessCallback(data);
},
onError: (error) => {
showToast(error.message || "Something went wrong", "error");
},
});
}
// Activity------------------------------
export const useCreateActivity = (onSuccessCallback) =>
{
const queryClient = useQueryClient();
return useMutation( {
mutationFn: async ( payload ) =>
{
const resp = await MasterRespository.createActivity(payload);
return resp.data;
},
onSuccess: ( data ) =>
{
queryClient.invalidateQueries( [ "masterData", "Activity" ] )
showToast( "Activity added successfully", "success" );
if(onSuccessCallback) onSuccessCallback(data)
},
onError: ( error ) =>
{
showToast(error.message || "Something went wrong", "error");
}
})
}
export const useUpdateActivity = (onSuccessCallback) =>
{
const queryClient = useQueryClient();
return useMutation({
mutationFn: async ( {id, payload} ) =>
{
const response = await MasterRespository.updateActivity(id,payload);
return response.data;
},
onSuccess: (data, variables) => {
queryClient.invalidateQueries({
queryKey: ["masterData", "Activity"],
});
showToast("Activity updated successfully.", "success");
if (onSuccessCallback) onSuccessCallback(data);
},
onError: (error) => {
showToast(error.message || "Something went wrong", "error");
},
});
}
//-----Create work Category-------------------------------
export const useCreateWorkCategory = (onSuccessCallback) =>
{
const queryClient = useQueryClient();
return useMutation( {
mutationFn: async ( payload ) =>
{
const resp = await MasterRespository.createWorkCategory(payload);
return resp.data;
},
onSuccess: ( data ) =>
{
queryClient.invalidateQueries( [ "masterData", "Work Category" ] )
showToast( "Work Category added successfully", "success" );
if(onSuccessCallback) onSuccessCallback(data)
},
onError: ( error ) =>
{
showToast(error.message || "Something went wrong", "error");
}
})
}
export const useUpdateWorkCategory = (onSuccessCallback) =>
{
const queryClient = useQueryClient();
return useMutation({
mutationFn: async ( {id, payload} ) =>
{
const response = await MasterRespository.updateWorkCategory(id,payload);
return response.data;
},
onSuccess: (data, variables) => {
queryClient.invalidateQueries({
queryKey: ["masterData", "Work Category"],
});
showToast("Work Category updated successfully.", "success");
if (onSuccessCallback) onSuccessCallback(data);
},
onError: (error) => {
showToast(error.message || "Something went wrong", "error");
},
});
}
//-- Contact Category---------------------------
export const useCreateContactCategory = (onSuccessCallback) =>
{
const queryClient = useQueryClient();
return useMutation( {
mutationFn: async ( payload ) =>
{
const resp = await MasterRespository.createContactCategory(payload);
return resp.data;
},
onSuccess: ( data ) =>
{
queryClient.invalidateQueries( [ "masterData", "Contact Category" ] )
showToast( "Contact Category added successfully", "success" );
if(onSuccessCallback) onSuccessCallback(data)
},
onError: ( error ) =>
{
showToast(error.message || "Something went wrong", "error");
}
})
}
export const useUpdateContactCategory = (onSuccessCallback) =>
{
const queryClient = useQueryClient();
return useMutation({
mutationFn: async ( {id, payload} ) =>
{
const response = await MasterRespository.updateContactCategory(id,payload);
return response.data;
},
onSuccess: (data, variables) => {
queryClient.invalidateQueries({
queryKey: ["masterData", "Contact Category"],
});
showToast("Contact Category updated successfully.", "success");
if (onSuccessCallback) onSuccessCallback(data);
},
onError: (error) => {
showToast(error.message || "Something went wrong", "error");
},
});
}
// ---------Contact Tag-------------------
export const useCreateContactTag = (onSuccessCallback) =>
{
const queryClient = useQueryClient();
return useMutation( {
mutationFn: async ( payload ) =>
{
const resp = await MasterRespository.createContactTag(payload);
return resp.data;
},
onSuccess: ( data ) =>
{
queryClient.invalidateQueries( [ "masterData", "Contact Tag" ] )
showToast( "Contact Tag added successfully", "success" );
if(onSuccessCallback) onSuccessCallback(data)
},
onError: ( error ) =>
{
showToast(error.message || "Something went wrong", "error");
}
})
}
export const useUpdateContactTag = (onSuccessCallback) =>
{
const queryClient = useQueryClient();
return useMutation({
mutationFn: async ( {id, payload} ) =>
{
debugger
const response = await MasterRespository.updateContactTag(id,payload);
return response.data;
},
onSuccess: (data, variables) => {
queryClient.invalidateQueries({
queryKey: ["masterData", "Contact Tag"],
});
showToast("Contact Tag updated successfully.", "success");
if (onSuccessCallback) onSuccessCallback(data);
},
onError: (error) => {
showToast(error.message || "Something went wrong", "error");
},
});
}
// -Delete Master --------
export const useDeleteMasterItem = () => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: async ( {masterType, item} ) =>
{
const deleteFn = MasterRespository[masterType];
if (!deleteFn) {
throw new Error(`No delete strategy defined for master type: ${masterType}`);
}
await deleteFn(item.id);
return { masterType };
},
onSuccess: ({ masterType }) => {
queryClient.invalidateQueries({ queryKey: ["masterData", masterType] });
showToast(`${masterType} deleted successfully.`, "success");
},
onError: (error) => {
const message =
error?.response?.data?.message || error?.message || "Error occurred during deletion";
showToast(message, "error");
},
});
}; };

View File

@ -1,4 +1,4 @@
import React, { useState, useEffect } from "react"; import React, { useState, useEffect, useMemo } from "react";
import Breadcrumb from "../../components/common/Breadcrumb"; import Breadcrumb from "../../components/common/Breadcrumb";
import MasterModal from "../../components/master/MasterModal"; import MasterModal from "../../components/master/MasterModal";
import { mastersList} from "../../data/masters"; import { mastersList} from "../../data/masters";
@ -9,92 +9,80 @@ import MasterTable from "./MasterTable";
import { getCachedData } from "../../slices/apiDataManager"; import { getCachedData } from "../../slices/apiDataManager";
import {useHasUserPermission} from "../../hooks/useHasUserPermission"; import {useHasUserPermission} from "../../hooks/useHasUserPermission";
import { MANAGE_MASTER } from "../../utils/constants"; import { MANAGE_MASTER } from "../../utils/constants";
import {useQueryClient} from "@tanstack/react-query";
const MasterPage = () => { const MasterPage = () => {
const [modalConfig, setModalConfig] = useState({ modalType: "", item: null, masterType: null });
const [modalConfig, setmodalConfig] = useState({modalType: "", item: null, masterType:null });
const [searchTerm, setSearchTerm] = useState(''); const [searchTerm, setSearchTerm] = useState('');
const [filteredResults, setFilteredResults] = useState([]); const [filteredResults, setFilteredResults] = useState([]);
const hasMasterPermission = useHasUserPermission( MANAGE_MASTER )
const dispatch = useDispatch();
const selectedMaster = useSelector((store)=>store.localVariables.selectedMaster)
const [isCreateModalOpen, setIsCreateModalOpen] = useState(false); const [isCreateModalOpen, setIsCreateModalOpen] = useState(false);
const openModal = () => { const hasMasterPermission = useHasUserPermission(MANAGE_MASTER);
setIsCreateModalOpen(true); const dispatch = useDispatch();
const selectedMaster = useSelector((store) => store.localVariables.selectedMaster);
const queryClient = useQueryClient();
}; const { data: masterData = [], loading, error, RecallApi } = useMaster();
const openModal = () => setIsCreateModalOpen(true);
const closeModal = () => { const closeModal = () => {
setIsCreateModalOpen(false); setIsCreateModalOpen(false);
setmodalConfig(null); setModalConfig(null);
// Clean up Bootstrap modal manually
const modalEl = document.getElementById('master-modal');
modalEl?.classList.remove('show');
if (modalEl) modalEl.style.display = 'none';
const modalElement = document.getElementById('master-modal');
if (modalElement) {
modalElement.classList.remove('show');
modalElement.style.display = 'none';
document.body.classList.remove('modal-open'); document.body.classList.remove('modal-open');
const backdropElement = document.querySelector('.modal-backdrop');
if (backdropElement) {
backdropElement.classList.remove('modal-backdrop');
backdropElement.style.display = 'none';
}
}
const modalBackdropElement = document.querySelector('.modal-backdrop');
if (modalBackdropElement) {
modalBackdropElement.remove();
}
document.body.style.overflow = 'auto'; document.body.style.overflow = 'auto';
document.querySelectorAll('.modal-backdrop').forEach((el) => el.remove());
}; };
const {data:masterData, loading,error , RecallApi} = useMaster(); const handleModalData = (modalType, item, masterType = selectedMaster) => {
setModalConfig({ modalType, item, masterType });
};
const handleSearch = (e) => { const handleSearch = (e) => {
const value = e.target.value.toLowerCase(); const value = e.target.value.toLowerCase();
setSearchTerm(value); setSearchTerm(value);
if (!masterData.length) return; if (!masterData?.length) return;
const results = masterData.filter((item) => const results = masterData.filter((item) =>
Object.values(item).some((field) => Object.values(item).some(
field && field.toString().toLowerCase().includes(value) (field) => field?.toString().toLowerCase().includes(value)
) )
); );
setFilteredResults(results); setFilteredResults(results);
}; };
const displayData = useMemo(() => {
if (searchTerm) return filteredResults;
return queryClient.getQueryData(["masterData", selectedMaster]) || masterData;
}, [searchTerm, filteredResults, selectedMaster, masterData]);
const displayData = searchTerm ? filteredResults : getCachedData(selectedMaster) ? getCachedData(selectedMaster) : masterData const columns = useMemo(() => {
if (!displayData?.length) return [];
const columns = displayData?.length return Object.keys(displayData[0]).map((key) => ({
? Object.keys(displayData[0]).map((key) => ({ key, label: key.toUpperCase() })) key,
: []; label: key.toUpperCase(),
}));
const handleModalData =(modalType,item,masterType = selectedMaster)=>{ }, [displayData]);
setmodalConfig({ modalType: modalType, item:item,masterType:masterType });
}
useEffect(() => { useEffect(() => {
if (modalConfig !== null) { if (modalConfig) openModal();
openModal(); }, [modalConfig]);
}
}, [ modalConfig, isCreateModalOpen ] );
useEffect(() => { useEffect(() => {
return () => { return () => {
setIsCreateModalOpen(false) setIsCreateModalOpen(false);
closeModal(); closeModal();
}; };
}, []) }, []);
return ( return (
<> <>

View File

@ -41,7 +41,7 @@ export const MasterRespository = {
"Activity": ( id ) => api.delete( `/api/master/activity/delete/${ id }` ), "Activity": ( id ) => api.delete( `/api/master/activity/delete/${ id }` ),
"Application Role":(id)=>api.delete(`/api/roles/${id}`), "Application Role":(id)=>api.delete(`/api/roles/${id}`),
"Work Category": ( id ) => api.delete( `api/master/work-category/${ id }` ), "Work Category": ( id ) => api.delete( `api/master/work-category/${ id }` ),
"Contact Category": ( id ) => api.delete( `/api/master/contact-category` ), "Contact Category": ( id ) => api.delete( `/api/master/contact-category/${id}` ),
"Contact Tag" :(id)=>api.delete(`/api/master/contact-tag/${id}`), "Contact Tag" :(id)=>api.delete(`/api/master/contact-tag/${id}`),
getWorkCategory:() => api.get(`/api/master/work-categories`), getWorkCategory:() => api.get(`/api/master/work-categories`),