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,101 +24,96 @@ 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,
handleSubmit, handleSubmit,
control, control,
setValue, setValue,
clearErrors, clearErrors,
setError, setError,
getValues, getValues,
reset, reset,
formState: { errors }, formState: { errors },
} = useForm({ } = useForm({
resolver: zodResolver(schema), resolver: zodResolver(schema),
defaultValues: { defaultValues: {
activityName: "", activityName: "",
unitOfMeasurement: "", unitOfMeasurement: "",
checkList: [], checkList: [],
}, },
}); });
const {
fields: checkListItems,
append,
remove,
} = useFieldArray({
control,
name: "checkList",
});
const { const addChecklistItem = useCallback(() => {
fields: checkListItems, const values = getValues("checkList");
append, const lastIndex = checkListItems.length - 1;
remove,
} = useFieldArray({
control,
name: "checkList",
});
// Form submission handler if (
const onSubmit = (data) => { checkListItems.length > 0 &&
setIsLoading(true); (!values?.[lastIndex] || values[lastIndex].description.trim() === "")
) {
MasterRespository.createActivity(data) setError(`checkList.${lastIndex}.description`, {
.then( ( resp ) => type: "manual",
{ message: "Please fill this checklist item before adding another.",
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 lastIndex = checkListItems.length - 1;
if (
checkListItems.length > 0 &&
(!values?.[lastIndex] || values[lastIndex].description.trim() === "")
) {
setError(`checkList.${lastIndex}.description`, {
type: "manual",
message: "Please fill this checklist item before adding another.",
});
return;
}
clearErrors(`checkList.${lastIndex}.description`);
append({
id: null,
description: "",
isMandatory: false,
}); });
}; return;
}
const removeChecklistItem = (index) => { clearErrors(`checkList.${lastIndex}.description`);
remove(index); append({ id: null, description: "", isMandatory: false });
}; }, [checkListItems, getValues, append, setError, clearErrors]);
const removeChecklistItem = useCallback((index) => {
remove(index);
}, [remove]);
const handleChecklistChange = (index, value) => { const handleChecklistChange = useCallback((index, value) => {
setValue(`checkList.${index}`, value); setValue(`checkList.${index}`, value);
}; }, [setValue]);
const handleClose = () => { const onSubmit = (formData) => {
reset(); createActivity(formData);
onClose(); };
}; // 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();
onClose();
}, [reset, onClose]);
useEffect(() => {
const tooltipTriggerList = Array.from(document.querySelectorAll('[data-bs-toggle="tooltip"]'));
tooltipTriggerList.forEach((el) => new bootstrap.Tooltip(el));
}, []);
// for tooltip
useEffect(() => {
const tooltipTriggerList = Array.from(document.querySelectorAll('[data-bs-toggle="tooltip"]'));
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 },
formState: { errors },reset 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() const [descriptionLength, setDescriptionLength] = useState(0);
}).catch((error)=>{ const maxDescriptionLength = 255;
showToast(error?.response?.data?.message, "error");
setIsLoading(false)
})
};
const resetForm = () => {
reset({
name: "",
description: ""
});
setDescriptionLength(0);
}
useEffect(()=>{ const { mutate: createContactCategory, isPending: isLoading } = useCreateContactCategory(() => onClose?.());
return ()=>resetForm()
},[]) const onSubmit = (payload) => {
createContactCategory(payload);
const [descriptionLength, setDescriptionLength] = useState(0); };
const maxDescriptionLength = 255; // 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 {
register,
handleSubmit,
formState: { errors },
reset,
} = useForm({
resolver: zodResolver(schema),
defaultValues: {
name: "",
description: "",
},
});
const[isLoading,setIsLoading] = useState(false) const [descriptionLength, setDescriptionLength] = useState(0);
const { const maxDescriptionLength = 255;
register,
handleSubmit,
formState: { errors },reset
} = useForm({
resolver: zodResolver(schema),
defaultValues: {
name: "",
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(()=>{ const { mutate: createContactTag, isPending: isLoading } = useCreateContactTag(() => onClose?.());
return ()=>resetForm()
},[]) const onSubmit = (payload) => {
createContactTag(payload);
const [descriptionLength, setDescriptionLength] = useState(0); };
const maxDescriptionLength = 255; // 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 { const [descriptionLength, setDescriptionLength] = useState(0);
register,
handleSubmit,
formState: { errors },reset
} = useForm({
resolver: zodResolver(schema),
defaultValues: {
role: "",
description: "",
},
});
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() const {
}).catch((error)=>{ register,
showToast(error.message, "error"); handleSubmit,
setIsLoading(false) formState: { errors },
}) reset,
watch,
} = useForm({
resolver: zodResolver(schema),
defaultValues: {
role: "",
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 payload = {
name: data.role,
description: data.description,
}; };
const resetForm = () => { createJobRole(payload);
reset({ };
role: "",
description: "" useEffect(() => {
}); const sub = watch((values) => {
setDescriptionLength(0); setDescriptionLength(values.description?.length || 0);
} });
return () => sub.unsubscribe();
}, [watch]);
useEffect(() => {
return () => resetForm();
}, []);
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,33 +218,23 @@ const CreateRole = ({ modalType, onClose }) => {
{!masterFeatures && <p>Loading...</p>} {!masterFeatures && <p>Loading...</p>}
</div> </div>
{masterFeatures && (
{ <div className="col-12 text-center">
masterFeatures && ( <button type="submit" className="btn btn-sm btn-primary me-3">
{isLoading ? "Please Wait..." : "Submit"}
<div className="col-12 text-center"> </button>
<button type="submit" className="btn btn-sm btn-primary me-3"> <button
{isLoading ? "Please Wait..." : "Submit"} type="reset"
</button> className="btn btn-sm btn-label-secondary"
<button data-bs-dismiss="modal"
type="reset" aria-label="Close"
className="btn btn-sm btn-label-secondary" >
data-bs-dismiss="modal" Cancel
aria-label="Close" </button>
> </div>
Cancel )}
</button>
</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 },
formState: { errors },reset reset,
} = useForm({
} = useForm({ resolver: zodResolver(schema),
resolver: zodResolver(schema), defaultValues: {
defaultValues: { name: "",
name: "", description: "",
description: "", },
});
},
});
const onSubmit = (data) => {
setIsLoading(true)
// const result = {
// name: data.name,
// description: data.description,
// };
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() const [descriptionLength, setDescriptionLength] = useState(0);
}).catch((error)=>{ const maxDescriptionLength = 255;
showToast(error?.response?.data?.message, "error");
setIsLoading(false) const { mutate: createWorkCategory, isPending: isLoading } = useCreateWorkCategory(() => {
}) 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)
// })
}; // };
const resetForm = () => {
reset({
name: "",
description: ""
});
setDescriptionLength(0);
}
useEffect(()=>{ const resetForm = () => {
return ()=>resetForm() reset({
},[]) name: "",
description: "",
const [descriptionLength, setDescriptionLength] = useState(0); });
const maxDescriptionLength = 255; 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

@ -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,111 +24,107 @@ 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,
handleSubmit, handleSubmit,
control, control,
setValue, setValue,
reset, reset,
setError, setError,
clearErrors, clearErrors,
getValues, getValues,
formState: { errors }, formState: { errors },
} = 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 || [],
}, },
}); });
const { fields: checkListItems, append, remove } = useFieldArray({ const { fields: checkListItems, append, remove } = useFieldArray({
control, control,
name: "checkList", name: "checkList",
}); });
// Load initial data useEffect(() => {
useEffect(() => { if (activityData) {
if (activityData) { reset({
reset( { id: activityData.id,
id:activityData.id, activityName: activityData.activityName,
activityName: activityData.activityName, unitOfMeasurement: activityData.unitOfMeasurement,
unitOfMeasurement: activityData.unitOfMeasurement, checkList: activityData.checkLists || [],
checkList: activityData.checkLists || [], });
}); }
} }, [activityData, reset]);
}, [activityData]);
const addChecklistItem = () => {
const handleChecklistChange = (index, value) => { const values = getValues("checkList");
setValue(`checkList.${index}`, value); const lastIndex = checkListItems.length - 1;
if (
checkListItems.length > 0 &&
(!values?.[lastIndex] || values[lastIndex].description.trim() === "")
) {
setError(`checkList.${lastIndex}.description`, {
type: "manual",
message: "Please fill this checklist item before adding another.",
});
return;
}
clearErrors(`checkList.${lastIndex}.description`);
append({ id: null, description: "", isMandatory: false });
};
const removeChecklistItem = (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) => {
// Submit handler // setIsLoading(true);
const onSubmit = async(data) => {
setIsLoading(true);
const Activity = {...data, id:activityData.id} // const Activity = {...data, id:activityData.id}
try // try
{ // {
const response = await MasterRespository.updateActivity( activityData?.id, Activity ); // const response = await MasterRespository.updateActivity( activityData?.id, Activity );
const updatedActivity = response.data; // const updatedActivity = response.data;
const cachedData = getCachedData("Activity") // const cachedData = getCachedData("Activity")
if (cachedData) { // if (cachedData) {
const updatedActivities = cachedData.map((activity) => // const updatedActivities = cachedData.map((activity) =>
activity.id === updatedActivity.id ? { ...activity, ...updatedActivity } : activity // activity.id === updatedActivity.id ? { ...activity, ...updatedActivity } : activity
); // );
cacheData( "Activity", updatedActivities ); // cacheData( "Activity", updatedActivities );
onClose() // onClose()
} // }
setIsLoading( false ) // setIsLoading( false )
showToast("Activity Successfully Updated", "success"); // showToast("Activity Successfully Updated", "success");
} catch ( err ) // } catch ( err )
{ // {
setIsLoading( false ) // setIsLoading( false )
showToast("error.message", "error"); // showToast("error.message", "error");
} // }
}; // };
useEffect(() => {
const tooltipTriggerList = Array.from(document.querySelectorAll('[data-bs-toggle="tooltip"]'));
// Add new checklist item tooltipTriggerList.forEach((el) => new bootstrap.Tooltip(el));
const addChecklistItem = () => { }, []);
const values = getValues("checkList");
const lastIndex = checkListItems.length - 1;
if (
checkListItems.length > 0 &&
(!values?.[lastIndex] || values[lastIndex].description.trim() === "")
) {
setError(`checkList.${lastIndex}.description`, {
type: "manual",
message: "Please fill this checklist item before adding another.",
});
return;
}
clearErrors(`checkList.${lastIndex}.description`);
append({ id: null, description: "", isMandatory: false });
};
const removeChecklistItem = (index) => {
remove(index);
};
// for tooltip
useEffect(() => {
const tooltipTriggerList = Array.from(document.querySelectorAll('[data-bs-toggle="tooltip"]'));
tooltipTriggerList.forEach((el) => new bootstrap.Tooltip(el));
}, []);
return ( return (
<form onSubmit={handleSubmit(onSubmit)}> <form onSubmit={handleSubmit(onSubmit)}>
@ -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>
@ -256,4 +253,4 @@ const UpdateActivity = ({ activityData, onClose }) => {
); );
}; };
export default UpdateActivity; export default UpdateActivity;

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 {
register,
handleSubmit,
formState: { errors },
reset,
} = useForm({
resolver: zodResolver(schema),
defaultValues: {
name: data?.name || "",
description: data?.description || "",
},
});
const[isLoading,setIsLoading] = useState(false) const [descriptionLength, setDescriptionLength] = useState(data?.description?.length || 0);
const { const maxDescriptionLength = 255;
register,
handleSubmit, const { mutate: updateContactCategory, isPending: isLoading } = useUpdateContactCategory(() => onClose?.());
formState: { errors },reset
const onSubmit = (formData) => {
} = useForm({ const payload = {
resolver: zodResolver(schema), id: data?.id,
defaultValues: { name: formData.name,
name: data?.name || "", description: formData.description,
description:data?.description || "", };
}, updateContactCategory({id:data?.id,payload});
}); };
// const onSubmit = (formdata) => {
const onSubmit = (formdata) => { // setIsLoading(true)
setIsLoading(true) // const result = {
const result = { // id:data?.id,
id:data?.id, // name: formdata?.name,
name: formdata?.name, // description: formdata.description,
description: formdata.description, // };
};
MasterRespository.updateContactCategory(data?.id,result).then((resp)=>{ // MasterRespository.updateContactCategory(data?.id,result).then((resp)=>{
setIsLoading(false) // setIsLoading(false)
showToast("Contact Category Updated successfully.", "success"); // showToast("Contact Category Updated successfully.", "success");
const cachedData = getCachedData("Contact Category"); // const cachedData = getCachedData("Contact Category");
if (cachedData) { // if (cachedData) {
const updatedData = cachedData.map((category) => // const updatedData = cachedData.map((category) =>
category.id === data?.id ? { ...category, ...resp.data } : category // category.id === data?.id ? { ...category, ...resp.data } : category
); // );
cacheData("Contact Category", updatedData); // cacheData("Contact Category", updatedData);
} // }
onClose() // onClose()
}).catch((error)=>{ // }).catch((error)=>{
showToast(error?.response?.data?.message, "error") // showToast(error?.response?.data?.message, "error")
setIsLoading(false) // setIsLoading(false)
}) // })
}; // };
const resetForm = () => {
reset({
name: "",
description: ""
});
setDescriptionLength(0);
}
useEffect(()=>{ const resetForm = () => {
return ()=>resetForm() reset({ name: "", description: "" });
},[]) setDescriptionLength(0);
};
const [descriptionLength, setDescriptionLength] = useState(0);
const maxDescriptionLength = 255; 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 {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 {
register,
handleSubmit,
formState: { errors },
reset
} = useForm({
resolver: zodResolver(schema),
defaultValues: {
name: data?.name || "",
description: data?.description || "",
},
});
const[isLoading,setIsLoading] = useState(false) const [descriptionLength, setDescriptionLength] = useState(data?.description?.length || 0);
const { const maxDescriptionLength = 255;
register,
handleSubmit, const { mutate: updateContactTag, isPending: isLoading } = useUpdateContactTag(() => onClose?.());
formState: { errors },reset
const onSubmit = (formData) => {
} = useForm({ const payload = {
resolver: zodResolver(schema), id: data?.id,
defaultValues: { name: formData.name,
name: data?.name || "", description: formData.description,
description:data?.description || "", };
debugger
}, updateContactTag({ id: data?.id, payload} );
}); }
// const onSubmit = (formdata) => {
const onSubmit = (formdata) => { // setIsLoading(true)
setIsLoading(true) // const result = {
const result = { // id:data?.id,
id:data?.id, // name: formdata?.name,
name: formdata?.name, // description: formdata.description,
description: formdata.description, // };
};
MasterRespository.updateContactTag(data?.id,result).then((resp)=>{ // MasterRespository.updateContactTag(data?.id,result).then((resp)=>{
setIsLoading(false) // setIsLoading(false)
showToast("Contact Tag Updated successfully.", "success"); // showToast("Contact Tag Updated successfully.", "success");
const cachedData = getCachedData("Contact Tag"); // const cachedData = getCachedData("Contact Tag");
if (cachedData) { // if (cachedData) {
const updatedData = cachedData.map((category) => // const updatedData = cachedData.map((category) =>
category.id === data?.id ? { ...category, ...resp.data } : category // category.id === data?.id ? { ...category, ...resp.data } : category
); // );
cacheData("Contact Tag", updatedData); // cacheData("Contact Tag", updatedData);
} // }
onClose() // onClose()
}).catch((error)=>{ // }).catch((error)=>{
showToast(error?.response?.data?.message, "error") // showToast(error?.response?.data?.message, "error")
setIsLoading(false) // setIsLoading(false)
}) // })
}; // };
const resetForm = () => {
reset({
name: "",
description: ""
});
setDescriptionLength(0);
}
useEffect(()=>{ const resetForm = () => {
return ()=>resetForm() reset({ name: "", description: "" });
},[]) setDescriptionLength(0);
};
const [descriptionLength, setDescriptionLength] = useState(0);
const maxDescriptionLength = 255; 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

@ -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[isLoading,setIsLoading] = useState(false)
const {
register,
handleSubmit,
formState: { errors } ,reset
} = useForm({
resolver: zodResolver(schema),
defaultValues: {
role: data?.name || "",
description:data?.description || "",
},
});
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)
})
};
useEffect(() => {
reset({
role: data?.name,
description: data?.description
});
setDescriptionLength(data?.description?.length || 0);
}, [data, reset]);
const [descriptionLength, setDescriptionLength] = useState(data?.description?.length || 0);
const maxDescriptionLength = 255; const maxDescriptionLength = 255;
const {
register,
handleSubmit,
formState: { errors },
reset,
watch,
} = useForm({
resolver: zodResolver(schema),
defaultValues: {
role: data?.name || "",
description: data?.description || "",
},
});
const { mutate: updateJobRole, isPendin:isLoading } = useUpdateJobRole(() => {
onClose?.();
});
// 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,
payload: {
id: data?.id,
name: formData.role,
description: formData.description,
},
});
};
useEffect(() => {
reset({
role: data?.name || "",
description: data?.description || "",
});
setDescriptionLength(data?.description?.length || 0);
}, [data, reset]);
useEffect(() => {
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,128 +28,149 @@ 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;
};
const initialPermissions = buildDefaultPermissions();
const {
register,
handleSubmit,
formState: { errors, dirtyFields },
setError, reset
} = useForm({
resolver: zodResolver(updateSchema),
defaultValues: {
role: master?.item?.role,
description: master?.item?.description,
permissions: initialPermissions,
},
}); });
return defaults;
};
const onSubmit = (data) => { const initialPermissions = buildDefaultPermissions();
setIsLoading(true)
const existingIds = new Set(
master?.item?.featurePermission?.map((p) => p.id)
);
const {
register,
handleSubmit,
formState: { errors, dirtyFields },
setError,
reset,
} = useForm({
resolver: zodResolver(updateSchema),
defaultValues: {
role: master?.item?.role || "",
description: master?.item?.description || "",
permissions: initialPermissions,
},
});
const updatedPermissions = Object.entries(data.permissions) const [descriptionLength, setDescriptionLength] = useState(master?.item?.description?.length || 0);
.filter(([id, value]) => {
if (existingIds.has(id)) return true;
return ( const onSubmit = (data) => {
value === true || const existingIds = new Set(master?.item?.featurePermission?.map(p => p.id));
(dirtyFields.permissions && dirtyFields.permissions[id])
);
})
.map(([id, value]) => ({ id, isEnabled: value }));
const updatedPermissions = Object.entries(data.permissions)
if (updatedPermissions.length === 0) { .filter(([id, value]) => {
setError("permissions", { return existingIds.has(id) || value === true || (dirtyFields.permissions?.[id]);
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)
}) })
.map(([id, value]) => ({ id, isEnabled: value }));
if (updatedPermissions.length === 0) {
setError("permissions", {
type: "manual",
message: "At least one permission must be selected.",
});
return;
}
const payload = {
id: master?.item?.id,
role: data.role,
description: data.description,
featuresPermission: updatedPermissions,
}; };
useEffect(() => { updateApplicationRole({ id: payload.id, payload });
reset({ };
role: master?.item?.role, // const onSubmit = (data) => {
description: master?.item?.description, // setIsLoading(true)
permissions: initialPermissions, // const existingIds = new Set(
}); // master?.item?.featurePermission?.map((p) => p.id)
setDescriptionLength(master?.item?.description?.length || 0); // );
}, [master, reset]);
const [descriptionLength, setDescriptionLength] = useState(master?.item?.description?.length || 0);
const maxDescriptionLength = 255;
useEffect(() => { // const updatedPermissions = Object.entries(data.permissions)
popoverRefs.current.forEach((el) => { // .filter(([id, value]) => {
if (el) { // if (existingIds.has(id)) return true;
new bootstrap.Popover(el, {
trigger: "focus", // return (
placement: "right", // value === true ||
html: true, // (dirtyFields.permissions && dirtyFields.permissions[id])
content: el.getAttribute("data-bs-content"), // use inline content from attribute // );
}); // })
} // .map(([id, value]) => ({ id, isEnabled: value }));
});
}, [masterFeatures]);
// 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(() => {
reset({
role: master?.item?.role || "",
description: master?.item?.description || "",
permissions: buildDefaultPermissions(),
});
setDescriptionLength(master?.item?.description?.length || 0);
}, [master, reset]);
useEffect(() => {
popoverRefs.current.forEach((el) => {
if (el) {
new bootstrap.Popover(el, {
trigger: "focus",
placement: "right",
html: true,
content: el.getAttribute("data-bs-content"),
});
}
});
}, [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 },
formState: { errors } ,reset reset,
} = useForm({ } = useForm({
resolver: zodResolver(schema), resolver: zodResolver(schema),
defaultValues: { defaultValues: {
name: data?.name || "", name: data?.name || "",
description:data?.description || "", description: data?.description || "",
},
}, });
});
const [descriptionLength, setDescriptionLength] = useState(data?.description?.length || 0);
const onSubmit = (formdata) => { const maxDescriptionLength = 255;
setIsLoading(true)
const result = { const { mutate: updateWorkCategory, isPending: isLoading } = useUpdateWorkCategory(() => onClose?.());
id:data?.id,
name: formdata?.name, const onSubmit = (formdata) => {
description: formdata.description, 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)=>{ // MasterRespository.updateWorkCategory(data?.id,result).then((resp)=>{
setIsLoading(false) // setIsLoading(false)
showToast("Work Category Update successfully.", "success"); // showToast("Work Category Update successfully.", "success");
const cachedData = getCachedData("Work Category"); // const cachedData = getCachedData("Work Category");
if (cachedData) { // if (cachedData) {
const updatedData = cachedData.map((category) => // const updatedData = cachedData.map((category) =>
category.id === data?.id ? { ...category, ...resp.data } : category // category.id === data?.id ? { ...category, ...resp.data } : category
); // );
cacheData("Work Category", updatedData); // cacheData("Work Category", updatedData);
} // }
onClose() // onClose()
}).catch((error)=>{ // }).catch((error)=>{
showToast(error?.response?.data?.message, "error") // showToast(error?.response?.data?.message, "error")
setIsLoading(false) // setIsLoading(false)
}) // })
}; // };
useEffect(() => {
reset({
name: data?.name || "",
description: data?.description || "",
});
setDescriptionLength(data?.description?.length || 0);
}, [data, reset]);
useEffect(() => {
reset({
name: data?.name,
description: data?.description
});
setDescriptionLength(data?.description?.length || 0);
}, [data, reset]);
const [descriptionLength, setDescriptionLength] = useState(data?.description?.length || 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">
<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

@ -8,8 +8,8 @@ import EditJobRole from "./EditJobRole";
import CreateActivity from "./CreateActivity"; import CreateActivity from "./CreateActivity";
import EditActivity from "./EditActivity"; import EditActivity from "./EditActivity";
import ConfirmModal from "../common/ConfirmModal"; import ConfirmModal from "../common/ConfirmModal";
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 CreateWorkCategory from "./CreateWorkCategory"; import CreateWorkCategory from "./CreateWorkCategory";
import EditWorkCategory from "./EditWorkCategory"; import EditWorkCategory from "./EditWorkCategory";
@ -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"); onSuccess: () => {
handleCloseDeleteModal() handleCloseDeleteModal();
},
} catch ( error ) }
{ );
const message = error.response.data.message || error.message || "Error occured api during call" };
showToast(message, "success");
}
}
useEffect(() => { useEffect(() => {
if (modaldata?.modalType === "delete") { if (modaldata?.modalType === "delete") {
@ -55,7 +75,7 @@ const MasterModal = ({ modaldata, closeModal }) => {
const handleCloseDeleteModal = () => { const handleCloseDeleteModal = () => {
setIsDeleteModalOpen(false); setIsDeleteModalOpen(false);
closeModal(); closeModal();
}; };
if (modaldata?.modalType === "delete" && isDeleteModalOpen) { if (modaldata?.modalType === "delete" && isDeleteModalOpen) {
@ -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`}
@ -96,18 +118,21 @@ const MasterModal = ({ modaldata, closeModal }) => {
<div className="modal-content"> <div className="modal-content">
<div className="modal-body p-sm-4 p-0"> <div className="modal-body p-sm-4 p-0">
<div className="d-flex justify-content-between"> <div className="d-flex justify-content-between">
<h6>{ `${modaldata?.modalType} `}</h6> <h6>{`${modaldata?.modalType} `}</h6>
<button <button
type="button" type="button"
className="btn-close" className="btn-close"
data-bs-dismiss="modal" data-bs-dismiss="modal"
aria-label="Close" aria-label="Close"
onClick={closeModal} onClick={closeModal}
></button> ></button>
</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} />
@ -133,10 +161,10 @@ const MasterModal = ({ modaldata, closeModal }) => {
{modaldata.modalType === "Contact Category" && ( {modaldata.modalType === "Contact Category" && (
<CreateCategory data={modaldata.item} onClose={closeModal} /> <CreateCategory data={modaldata.item} onClose={closeModal} />
)} )}
{modaldata.modalType === "Edit-Contact Category" && ( {modaldata.modalType === "Edit-Contact Category" && (
<EditContactCategory data={modaldata.item} onClose={closeModal} /> <EditContactCategory data={modaldata.item} onClose={closeModal} />
)} )}
{modaldata.modalType === "Contact Tag" && ( {modaldata.modalType === "Contact Tag" && (
<CreateContactTag data={modaldata.item} onClose={closeModal} /> <CreateContactTag data={modaldata.item} onClose={closeModal} />
)} )}
{modaldata.modalType === "Edit-Contact Tag" && ( {modaldata.modalType === "Edit-Contact Tag" && (

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 useMaster = (isMa) => { // const [data, setData] = useState([]);
// const [loading, setLoading] = useState(true);
const selectedMaster = useSelector((store)=>store.localVariables.selectedMaster); // const [error, setError] = useState("");
const [data, setData] = useState([]); // useEffect(() => {
const [loading, setLoading] = useState(true); // const fetchData = async () => {
const [error, setError] = useState(""); // if (!selectedMaster) return;
useEffect(() => { // setLoading(true);
const fetchData = async () => { // try {
if (!selectedMaster) return; // const cachedData = getCachedData(selectedMaster);
setLoading(true); // if (cachedData) {
try {
const cachedData = getCachedData(selectedMaster);
if (cachedData) {
setData(cachedData); // setData(cachedData);
} else { // } else {
let response; // let response;
switch (selectedMaster) { // switch (selectedMaster) {
case "Application Role": // case "Application Role":
response = await MasterRespository.getRoles(); // response = await MasterRespository.getRoles();
response = response.data; // response = response.data;
break; // break;
case "Job Role": // case "Job Role":
response = await MasterRespository.getJobRole(); // response = await MasterRespository.getJobRole();
response = response.data // response = response.data
break; // break;
case "Activity": // case "Activity":
response = await MasterRespository.getActivites(); // response = await MasterRespository.getActivites();
response = response.data // response = response.data
break; // break;
case "Work Category": // case "Work Category":
response = await MasterRespository.getWorkCategory(); // response = await MasterRespository.getWorkCategory();
response = response.data // response = response.data
break; // break;
case "Contact Category": // case "Contact Category":
response = await MasterRespository.getContactCategory(); // response = await MasterRespository.getContactCategory();
response = response.data // response = response.data
break; // break;
case "Contact Tag": // case "Contact Tag":
response = await MasterRespository.getContactTag(); // response = await MasterRespository.getContactTag();
response = response.data // response = response.data
break; // 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"}]; // 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; // break;
default: // default:
response = []; // response = [];
} // }
if (response) { // if (response) {
setData(response); // setData(response);
cacheData(selectedMaster, response); // cacheData(selectedMaster, response);
} // }
} // }
} catch (err) { // } catch (err) {
setError("Failed to fetch data."); // setError("Failed to fetch data.");
} finally { // } finally {
setLoading(false); // setLoading(false);
} // }
}; // };
if ( selectedMaster ) // if ( selectedMaster )
{ // {
fetchData(); // fetchData();
} // }
}, [selectedMaster]); // }, [selectedMaster]);
return { data, loading, error } // return { data, loading, error }
// };
// 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":
return (await MasterRespository.getRoles()).data;
case "Job Role":
return (await MasterRespository.getJobRole()).data;
case "Activity":
return (await MasterRespository.getActivites()).data;
case "Work Category":
return (await MasterRespository.getWorkCategory()).data;
case "Contact Category":
return (await MasterRespository.getContactCategory()).data;
case "Contact Tag":
return (await MasterRespository.getContactTag()).data;
case "Status":
return [
{
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:
return [];
}
};
const useMaster = () => {
const selectedMaster = useSelector((store) => store.localVariables.selectedMaster);
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");
},
});
return { data, loading: isLoading, 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}
}
export const useWorkCategoriesMaster = () => // Job Role-----------------------------------
{ export const useUpdateJobRole = (onSuccessCallback, onErrorCallback) => {
const [ categories, setCategories ] = useState( [] ) const queryClient = useQueryClient();
const [ categoryLoading, setloading ] = useState( false );
const [ categoryError, setError ] = useState( "" ) return useMutation({
mutationFn: async ({ id, payload }) => {
const fetchCategories =async () => { const response = await MasterRespository.updateJobRole(id, payload);
const cacheddata = getCachedData("Work Category"); return response.data;
},
if (!cacheddata) { onSuccess: (data, variables) => {
setloading(true); showToast("JobRole updated successfully.", "success");
try {
const response = await MasterRespository.getWorkCategory(); queryClient.invalidateQueries({
setCategories(response.data); queryKey: ["masterData", "Job Role"],
cacheData("Work Category", response.data); });
} catch (err) {
setError(err); if (onSuccessCallback) onSuccessCallback(data);
console.log(err); },
} finally { onError: (error) => {
setloading(false); showToast(error.message || "Something went wrong", "error");
} if (onErrorCallback) onErrorCallback(error);
} else { },
setCategories(cacheddata); });
} };
}
useEffect( () => export const useCreateJobRole = (onSuccessCallback) => {
{ const queryClient = useQueryClient();
fetchCategories()
}, [] ) return useMutation({
mutationFn: async (payload) => {
return {categories,categoryLoading,categoryError} const response = await MasterRespository.createJobRole(payload);
} return response.data;
},
export const useContactCategory = () => 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 [ contactCategory, setContactCategory ] = useState( [] ) const queryClient = useQueryClient();
const [ loading, setLoading ] = useState( false )
const [ Error, setError ] = useState() return useMutation( {
mutationFn: async ( payload ) =>
const fetchConatctCategory = async() =>
{
const cache_Category = getCachedData( "Contact Category" );
if ( !cache_Category )
{ {
try const resp = await MasterRespository.createRole( payload );
{ return resp.data;
let resp = await MasterRespository.getContactCategory(); },
setContactCategory( resp.data ); onSuccess: ( data ) =>
cacheData("Contact Category",resp.data)
} catch ( error )
{
setError(error)
}
} else
{ {
setContactCategory(cache_Category) queryClient.invalidateQueries( [ "masterData", "Application Role" ] )
showToast( "Application Role added successfully", "success" );
if(onSuccessCallback) onSuccessCallback(data)
},
onError: ( error ) =>
{
showToast(error.message || "Something went wrong", "error");
} }
} })
useEffect( () =>
{
fetchConatctCategory()
}, [] )
return { contactCategory,loading,Error}
} }
export const useContactTags = () => {
const [contactTags, setContactTags] = useState([]);
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
useEffect(() => { export const useUpdateApplicationRole = (onSuccessCallback) =>
const fetchContactTag = async () => { {
const cache_Tags = getCachedData("Contact Tag"); const queryClient = useQueryClient();
if (!cache_Tags) { return useMutation({
setLoading(true); mutationFn: async ( {id, payload} ) =>
try { {
const resp = await MasterRespository.getContactTag(); const response = await MasterRespository.updateRoles(id,payload);
setContactTags(resp.data); return response.data;
cacheData("Contact Tag", resp.data); },
} catch (err) { onSuccess: (data, variables) => {
setError(err);
} finally { queryClient.invalidateQueries({
setLoading(false); queryKey: ["masterData", "Application Role"],
} });
} else { showToast("Application Role updated successfully.", "success");
setContactTags(cache_Tags);
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}`);
} }
};
fetchContactTag(); await deleteFn(item.id);
}, []); return { masterType };
},
return { contactTags, loading, error }; 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 [searchTerm, setSearchTerm] = useState('');
const [filteredResults, setFilteredResults] = useState([]);
const [isCreateModalOpen, setIsCreateModalOpen] = useState(false);
const [modalConfig, setmodalConfig] = useState({modalType: "", item: null, masterType:null }); const hasMasterPermission = useHasUserPermission(MANAGE_MASTER);
const [searchTerm, setSearchTerm] = useState(''); const dispatch = useDispatch();
const [ filteredResults, setFilteredResults ] = useState( [] ); const selectedMaster = useSelector((store) => store.localVariables.selectedMaster);
const hasMasterPermission = useHasUserPermission( MANAGE_MASTER ) const queryClient = useQueryClient();
const dispatch = useDispatch();
const selectedMaster = useSelector((store)=>store.localVariables.selectedMaster)
const [isCreateModalOpen, setIsCreateModalOpen] = useState(false);
const openModal = () => {
setIsCreateModalOpen(true);
const { data: masterData = [], loading, error, RecallApi } = useMaster();
const openModal = () => setIsCreateModalOpen(true);
const closeModal = () => {
setIsCreateModalOpen(false);
setModalConfig(null);
// Clean up Bootstrap modal manually
const modalEl = document.getElementById('master-modal');
modalEl?.classList.remove('show');
if (modalEl) modalEl.style.display = 'none';
document.body.classList.remove('modal-open');
document.body.style.overflow = 'auto';
document.querySelectorAll('.modal-backdrop').forEach((el) => el.remove());
};
const handleModalData = (modalType, item, masterType = selectedMaster) => {
setModalConfig({ modalType, item, masterType });
};
const handleSearch = (e) => {
const value = e.target.value.toLowerCase();
setSearchTerm(value);
if (!masterData?.length) return;
const results = masterData.filter((item) =>
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;
}, [searchTerm, filteredResults, selectedMaster, masterData]);
const columns = useMemo(() => {
if (!displayData?.length) return [];
return Object.keys(displayData[0]).map((key) => ({
key,
label: key.toUpperCase(),
}));
}, [displayData]);
useEffect(() => {
if (modalConfig) openModal();
}, [modalConfig]);
useEffect(() => {
return () => {
setIsCreateModalOpen(false);
closeModal();
}; };
}, []);
const closeModal = () => {
setIsCreateModalOpen(false);
setmodalConfig(null);
const modalElement = document.getElementById('master-modal');
if (modalElement) {
modalElement.classList.remove('show');
modalElement.style.display = 'none';
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';
};
const {data:masterData, loading,error , RecallApi} = useMaster();
const handleSearch = (e) => {
const value = e.target.value.toLowerCase();
setSearchTerm(value);
if (!masterData.length) return;
const results = masterData.filter((item) =>
Object.values(item).some((field) =>
field && field.toString().toLowerCase().includes(value)
)
);
setFilteredResults(results);
};
const displayData = searchTerm ? filteredResults : getCachedData(selectedMaster) ? getCachedData(selectedMaster) : masterData
const columns = displayData?.length
? Object.keys(displayData[0]).map((key) => ({ key, label: key.toUpperCase() }))
: [];
const handleModalData =(modalType,item,masterType = selectedMaster)=>{
setmodalConfig({ modalType: modalType, item:item,masterType:masterType });
}
useEffect(() => {
if (modalConfig !== null) {
openModal();
}
}, [ modalConfig, isCreateModalOpen ] );
useEffect(() => {
return () => {
setIsCreateModalOpen(false)
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`),