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 { categories, categoryLoading, categoryError } =
useWorkCategoriesMaster();
const {
register,
handleSubmit,

View File

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

View File

@ -6,6 +6,7 @@ import { MasterRespository } from '../../repositories/MastersRepository';
import { clearApiCacheKey } from '../../slices/apiCacheSlice';
import { getCachedData,cacheData } from '../../slices/apiDataManager';
import showToast from '../../services/toastService';
import {useCreateContactCategory} from '../../hooks/masterHook/useMaster';
const schema = z.object({
@ -16,51 +17,52 @@ const schema = z.object({
const CreateContactCategory = ({onClose}) => {
const[isLoading,setIsLoading] = useState(false)
const {
register,
handleSubmit,
formState: { errors },reset
formState: { errors },
reset,
} = useForm({
resolver: zodResolver(schema),
defaultValues: {
name: "",
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 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 (<>
<form className="row g-2" onSubmit={handleSubmit(onSubmit)}>
<div className="col-12 col-md-12">

View File

@ -6,6 +6,7 @@ import { MasterRespository } from '../../repositories/MastersRepository';
import { clearApiCacheKey } from '../../slices/apiCacheSlice';
import { getCachedData,cacheData } from '../../slices/apiDataManager';
import showToast from '../../services/toastService';
import {useCreateContactTag} from '../../hooks/masterHook/useMaster';
const schema = z.object({
@ -15,53 +16,53 @@ const schema = z.object({
});
const CreateContactTag = ({onClose}) => {
const[isLoading,setIsLoading] = useState(false)
const {
register,
handleSubmit,
formState: { errors },reset
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(()=>{
return ()=>resetForm()
},[])
const [descriptionLength, setDescriptionLength] = useState(0);
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 (<>
<form className="row g-2" onSubmit={handleSubmit(onSubmit)}>
<div className="col-12 col-md-12">

View File

@ -6,6 +6,7 @@ import { MasterRespository } from '../../repositories/MastersRepository';
import { clearApiCacheKey } from '../../slices/apiCacheSlice';
import { getCachedData,cacheData } from '../../slices/apiDataManager';
import showToast from '../../services/toastService';
import {useCreateJobRole} from '../../hooks/masterHook/useMaster';
const schema = z.object({
@ -16,58 +17,75 @@ const schema = z.object({
const CreateJobRole = ({onClose}) => {
const[isLoading,setIsLoading] = useState(false)
const maxDescriptionLength = 255;
const [descriptionLength, setDescriptionLength] = useState(0);
const {
register,
handleSubmit,
formState: { errors },reset
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) => {
setIsLoading(true)
const result = {
const payload = {
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)
})
createJobRole(payload);
};
const resetForm = () => {
reset({
role: "",
description: ""
});
setDescriptionLength(0);
}
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 (<>
<form className="row g-2" onSubmit={handleSubmit(onSubmit)}>
{/* <div className="col-12 col-md-12">

View File

@ -1,21 +1,19 @@
import React, { useEffect, useState, useRef } from "react";
import { useFeatures } from "../../hooks/useMasterRole";
import { useForm } from 'react-hook-form';
import { set, z } from 'zod';
import { zodResolver } from '@hookform/resolvers/zod';
import { useForm } from "react-hook-form";
import { set, z } from "zod";
import { zodResolver } from "@hookform/resolvers/zod";
import { MasterRespository } from "../../repositories/MastersRepository";
import { cacheData, getCachedData } from "../../slices/apiDataManager";
import showToast from "../../services/toastService";
import { useCreateApplicationRole } from "../../hooks/masterHook/useMaster";
const schema = z.object({
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" }),
selectedPermissions: z
@ -23,21 +21,22 @@ const schema = z.object({
.min(1, { message: "Please select at least one permission" }),
});
const CreateRole = ({ modalType, onClose }) => {
const [isLoading, setIsLoading] = useState(false)
const maxDescriptionLength = 255;
const [descriptionLength, setDescriptionLength] = useState(0);
const popoverRefs = useRef([]);
const { masterFeatures } = useFeatures()
const { masterFeatures } = useFeatures();
const { mutate: submitNewApplicationRole, isPending: isLoading } =
useCreateApplicationRole(() => {
onClose?.();
});
const {
register,
handleSubmit,
formState: { errors },
reset,
} = useForm({
resolver: zodResolver(schema),
defaultValues: {
@ -48,9 +47,7 @@ const CreateRole = ({ modalType, onClose }) => {
});
const onSubmit = (values) => {
setIsLoading(true)
const result = {
const payload = {
role: values.role,
description: values.description,
featuresPermission: values.selectedPermissions.map((id) => ({
@ -59,27 +56,40 @@ const CreateRole = ({ modalType, onClose }) => {
})),
};
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()
})
submitNewApplicationRole(payload);
};
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(() => {
setDescriptionLength(0);
}, []);
useEffect(() => {
popoverRefs.current.forEach((el) => {
if (el) {
@ -87,14 +97,13 @@ const CreateRole = ({ modalType, onClose }) => {
trigger: "focus",
placement: "right",
html: true,
content: el.getAttribute("data-bs-content"), // use inline content from attribute
content: el.getAttribute("data-bs-content"),
});
}
});
}, [masterFeatures]);
return (
<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">Create Application Role</label>
@ -102,23 +111,24 @@ const CreateRole = ({ modalType, onClose }) => {
</div> */}
<div className="col-12 col-md-12">
<label className="form-label">Role</label>
<input type="text"
<input
type="text"
{...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>}
</div>
<div className="col-12 col-md-12">
<label className="form-label" htmlFor="description">Description</label>
<label className="form-label" htmlFor="description">
Description
</label>
<textarea
rows="3"
{...register("description")}
className={`form-control ${errors.description ? 'is-invalids' : ''}`}
className={`form-control ${errors.description ? "is-invalids" : ""}`}
onChange={(e) => {
setDescriptionLength(e.target.value.length);
// Also update react-hook-form's value
register("description").onChange(e);
}}
></textarea>
@ -131,26 +141,26 @@ const CreateRole = ({ modalType, onClose }) => {
)}
</div>
<div className="col-12 col-md-12 border">
{masterFeatures.map((feature, featureIndex) => (
<React.Fragment key={feature.id}>
<div className="row my-1" key={feature.id} style={{ marginLeft: "0px" }}>
<div className="col-12 col-md-3 d-flex text-start align-items-start" style={{ wordWrap: 'break-word' }}>
<div
className="row my-1"
key={feature.id}
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>
</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">
{feature.featurePermissions.map((perm, permIndex) => {
const refIndex = (featureIndex * 10) + permIndex;
const refIndex = featureIndex * 10 + permIndex;
return (
<div className="d-flex me-3 mb-2" key={perm.id}>
<label className="form-check-label" htmlFor={perm.id}>
@ -163,15 +173,14 @@ const CreateRole = ({ modalType, onClose }) => {
/>
{perm.name}
</label>
<div style={{ display: 'flex', alignItems: 'center' }}>
<div style={{ display: "flex", alignItems: "center" }}>
<div
key={refIndex}
ref={(el) =>
(popoverRefs.current[refIndex] = el)
}
ref={(el) => (popoverRefs.current[refIndex] = el)}
tabIndex="0"
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-placement="right"
data-bs-html="true"
@ -182,23 +191,26 @@ const CreateRole = ({ modalType, onClose }) => {
`}
>
&nbsp;
<svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" fill="currentColor" className="bi bi-info-circle" viewBox="0 0 16 16">
<svg
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.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>
</div>
</div>
</div>
)
);
})}
</div>
</div>
<hr className="hr my-1 py-1" />
</React.Fragment>
))}
{errors.selectedPermissions && (
<p className="text-danger">{errors.selectedPermissions.message}</p>
@ -206,10 +218,7 @@ const CreateRole = ({ modalType, onClose }) => {
{!masterFeatures && <p>Loading...</p>}
</div>
{
masterFeatures && (
{masterFeatures && (
<div className="col-12 text-center">
<button type="submit" className="btn btn-sm btn-primary me-3">
{isLoading ? "Please Wait..." : "Submit"}
@ -223,16 +232,9 @@ const CreateRole = ({ modalType, onClose }) => {
Cancel
</button>
</div>
)
}
)}
</form>
);
};
export default CreateRole;

View File

@ -6,6 +6,7 @@ import { MasterRespository } from '../../repositories/MastersRepository';
import { clearApiCacheKey } from '../../slices/apiCacheSlice';
import { getCachedData,cacheData } from '../../slices/apiDataManager';
import showToast from '../../services/toastService';
import {useCreateWorkCategory} from '../../hooks/masterHook/useMaster';
const schema = z.object({
@ -16,58 +17,64 @@ const schema = z.object({
const CreateWorkCategory = ({onClose}) => {
const[isLoading,setIsLoading] = useState(false)
const {
register,
handleSubmit,
formState: { errors },reset
formState: { errors },
reset,
} = useForm({
resolver: zodResolver(schema),
defaultValues: {
name: "",
description: "",
},
});
const onSubmit = (data) => {
setIsLoading(true)
// const result = {
// name: data.name,
// description: data.description,
const [descriptionLength, setDescriptionLength] = useState(0);
const maxDescriptionLength = 255;
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)
// })
// };
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: ""
description: "",
});
setDescriptionLength(0);
}
};
useEffect(() => {
return ()=>resetForm()
},[])
return () => resetForm();
}, []);
const [descriptionLength, setDescriptionLength] = useState(0);
const maxDescriptionLength = 255;
return (<>
<form className="row g-2" onSubmit={handleSubmit(onSubmit)}>
<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 showToast from "../../services/toastService";
import {getCachedData,cacheData} from "../../slices/apiDataManager";
import {useUpdateActivity} from "../../hooks/masterHook/useMaster";
const schema = z.object({
@ -23,7 +24,7 @@ const schema = z.object({
const UpdateActivity = ({ activityData, onClose }) => {
const [isLoading, setIsLoading] = useState(false);
const { mutate: updateActivity, isPending: isLoading } = useUpdateActivity(() => onClose?.());
const {
register,
@ -38,10 +39,10 @@ const UpdateActivity = ({ activityData, onClose }) => {
} = useForm({
resolver: zodResolver(schema),
defaultValues: {
id:activityData.id,
activityName: activityData.activityName,
unitOfMeasurement: activityData.unitOfMeasurement,
checkLists: activityData.checkLists || [],
id: activityData?.id,
activityName: activityData?.activityName,
unitOfMeasurement: activityData?.unitOfMeasurement,
checkList: activityData?.checkLists || [],
},
});
@ -50,7 +51,6 @@ const UpdateActivity = ({ activityData, onClose }) => {
name: "checkList",
});
// Load initial data
useEffect(() => {
if (activityData) {
reset({
@ -60,45 +60,8 @@ const UpdateActivity = ({ activityData, onClose }) => {
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 values = getValues("checkList");
const lastIndex = checkListItems.length - 1;
@ -122,8 +85,42 @@ const UpdateActivity = ({ activityData, onClose }) => {
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(() => {
const tooltipTriggerList = Array.from(document.querySelectorAll('[data-bs-toggle="tooltip"]'));
tooltipTriggerList.forEach((el) => new bootstrap.Tooltip(el));
@ -232,7 +229,7 @@ const UpdateActivity = ({ activityData, onClose }) => {
className="btn btn-xs btn-primary mt-2"
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"
data-bs-original-title="Add check" ></i>
</button>

View File

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

View File

@ -6,6 +6,7 @@ import { MasterRespository } from '../../repositories/MastersRepository';
import { clearApiCacheKey } from '../../slices/apiCacheSlice';
import { getCachedData,cacheData } from '../../slices/apiDataManager';
import showToast from '../../services/toastService';
import {useUpdateContactTag} from '../../hooks/masterHook/useMaster';
const schema = z.object({
@ -15,65 +16,72 @@ const schema = z.object({
});
const EditContactTag= ({data,onClose}) => {
const[isLoading,setIsLoading] = useState(false)
const {
register,
handleSubmit,
formState: { errors },reset
formState: { errors },
reset
} = useForm({
resolver: zodResolver(schema),
defaultValues: {
name: data?.name || "",
description: data?.description || "",
},
});
const onSubmit = (formdata) => {
setIsLoading(true)
const result = {
const [descriptionLength, setDescriptionLength] = useState(data?.description?.length || 0);
const maxDescriptionLength = 255;
const { mutate: updateContactTag, isPending: isLoading } = useUpdateContactTag(() => onClose?.());
const onSubmit = (formData) => {
const payload = {
id: data?.id,
name: formdata?.name,
description: formdata.description,
name: formData.name,
description: formData.description,
};
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);
debugger
updateContactTag({ id: data?.id, payload} );
}
// 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 = () => {
reset({
name: "",
description: ""
});
reset({ name: "", description: "" });
setDescriptionLength(0);
}
};
useEffect(() => {
return ()=>resetForm()
},[])
return () => resetForm();
}, []);
const [descriptionLength, setDescriptionLength] = useState(0);
const maxDescriptionLength = 255;
return (<>
<form className="row g-2" onSubmit={handleSubmit(onSubmit)}>
<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 { cacheData,getCachedData } from '../../slices/apiDataManager';
import showToast from '../../services/toastService';
import {useUpdateJobRole} from '../../hooks/masterHook/useMaster';
@ -17,63 +18,81 @@ const schema = z.object({
const EditJobRole = ({data,onClose}) => {
const [descriptionLength, setDescriptionLength] = useState(data?.description?.length || 0);
const maxDescriptionLength = 255;
const[isLoading,setIsLoading] = useState(false)
const {
register,
handleSubmit,
formState: { errors } ,reset
formState: { errors },
reset,
watch,
} = useForm({
resolver: zodResolver(schema),
defaultValues: {
role: data?.name || "",
description: data?.description || "",
},
});
const onSubmit = (formdata) => {
setIsLoading(true)
const result = {
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,
name: formdata?.role,
description: formdata.description,
payload: {
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
role: data?.name || "",
description: data?.description || "",
});
setDescriptionLength(data?.description?.length || 0);
}, [data, reset]);
const [descriptionLength, setDescriptionLength] = useState(data?.description?.length || 0);
const maxDescriptionLength = 255;
useEffect(() => {
const sub = watch((values) => {
setDescriptionLength(values.description?.length || 0);
});
return () => sub.unsubscribe();
}, [watch]);
return (<>
<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 { cacheData, getCachedData } from "../../slices/apiDataManager";
import showToast from "../../services/toastService";
import {useUpdateApplicationRole} from "../../hooks/masterHook/useMaster";
@ -27,59 +28,50 @@ const updateSchema = z.object({
const EditMaster = ({ master, onClose }) => {
const [isLoading, setIsLoading] = useState(false)
const { masterFeatures } = useFeatures()
const maxDescriptionLength = 255;
const popoverRefs = useRef([]);
const { masterFeatures } = useFeatures();
const { mutate: updateApplicationRole, isPending: isLoading } = useUpdateApplicationRole(() => onClose?.());
const buildDefaultPermissions = () => {
const defaults = {};
masterFeatures.forEach((feature) => {
feature.featurePermissions.forEach((perm) => {
const existing = master?.item?.featurePermission?.find(
(p) => p.id === perm.id
);
defaults[perm.id] = existing ? existing.isEnabled : false;
const existing = master?.item?.featurePermission?.find(p => p.id === perm.id);
defaults[perm.id] = existing?.isEnabled || false;
});
});
return defaults;
};
const initialPermissions = buildDefaultPermissions();
const {
register,
handleSubmit,
formState: { errors, dirtyFields },
setError, reset
setError,
reset,
} = useForm({
resolver: zodResolver(updateSchema),
defaultValues: {
role: master?.item?.role,
description: master?.item?.description,
role: master?.item?.role || "",
description: master?.item?.description || "",
permissions: initialPermissions,
},
});
const onSubmit = (data) => {
setIsLoading(true)
const existingIds = new Set(
master?.item?.featurePermission?.map((p) => p.id)
);
const [descriptionLength, setDescriptionLength] = useState(master?.item?.description?.length || 0);
const onSubmit = (data) => {
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])
);
return existingIds.has(id) || value === true || (dirtyFields.permissions?.[id]);
})
.map(([id, value]) => ({ id, isEnabled: value }));
if (updatedPermissions.length === 0) {
setError("permissions", {
type: "manual",
@ -88,48 +80,80 @@ const EditMaster = ({ master, onClose }) => {
return;
}
const updatedRole = {
const payload = {
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)
})
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(() => {
reset({
role: master?.item?.role,
description: master?.item?.description,
permissions: initialPermissions,
role: master?.item?.role || "",
description: master?.item?.description || "",
permissions: buildDefaultPermissions(),
});
setDescriptionLength(master?.item?.description?.length || 0);
}, [master, reset]);
const [descriptionLength, setDescriptionLength] = useState(master?.item?.description?.length || 0);
const maxDescriptionLength = 255;
useEffect(() => {
popoverRefs.current.forEach((el) => {
if (el) {
@ -137,18 +161,16 @@ const EditMaster = ({ master, onClose }) => {
trigger: "focus",
placement: "right",
html: true,
content: el.getAttribute("data-bs-content"), // use inline content from attribute
content: el.getAttribute("data-bs-content"),
});
}
});
}, [masterFeatures]);
return (
<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">
<label className="form-label">Role</label>
<input type="text"

View File

@ -5,6 +5,7 @@ import { zodResolver } from '@hookform/resolvers/zod';
import { MasterRespository } from '../../repositories/MastersRepository';
import { cacheData,getCachedData } from '../../slices/apiDataManager';
import showToast from '../../services/toastService';
import {useUpdateWorkCategory} from '../../hooks/masterHook/useMaster';
@ -18,69 +19,75 @@ const schema = z.object({
const EditWorkCategory = ({data,onClose}) => {
const[isLoading,setIsLoading] = useState(false)
const {
register,
handleSubmit,
formState: { errors } ,reset
formState: { errors },
reset,
} = useForm({
resolver: zodResolver(schema),
defaultValues: {
name: data?.name || "",
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 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 (<>
<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">
<label className="form-label">Category Name</label>
<input type="text"

View File

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

View File

@ -2,6 +2,8 @@ import {useState,useEffect} from "react"
import { MasterRespository } from "../../repositories/MastersRepository";
import { cacheData,getCachedData } from "../../slices/apiDataManager";
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 = () =>
useMasterData("masterRole", MasterRespository.getRoles);
// const useMaster = () => {
// 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);
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) {
// return { data, loading, error }
// };
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":
response = await MasterRespository.getRoles();
response = response.data;
break;
return (await MasterRespository.getRoles()).data;
case "Job Role":
response = await MasterRespository.getJobRole();
response = response.data
break;
return (await MasterRespository.getJobRole()).data;
case "Activity":
response = await MasterRespository.getActivites();
response = response.data
break;
return (await MasterRespository.getActivites()).data;
case "Work Category":
response = await MasterRespository.getWorkCategory();
response = response.data
break;
return (await MasterRespository.getWorkCategory()).data;
case "Contact Category":
response = await MasterRespository.getContactCategory();
response = response.data
break;
return (await MasterRespository.getContactCategory()).data;
case "Contact Tag":
response = await MasterRespository.getContactTag();
response = response.data
break;
return (await MasterRespository.getContactTag()).data;
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;
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:
response = [];
}
if (response) {
setData(response);
cacheData(selectedMaster, response);
}
}
} catch (err) {
setError("Failed to fetch data.");
} finally {
setLoading(false);
return [];
}
};
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, error }
return { data, loading: isLoading, error };
};
export default useMaster;
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);
}
}, [] )
// ================================Mutation====================================
return {activities,loading,error}
}
// Job Role-----------------------------------
export const useUpdateJobRole = (onSuccessCallback, onErrorCallback) => {
const queryClient = useQueryClient();
export const useWorkCategoriesMaster = () =>
{
const [ categories, setCategories ] = useState( [] )
const [ categoryLoading, setloading ] = useState( false );
const [ categoryError, setError ] = useState( "" )
return useMutation({
mutationFn: async ({ id, payload }) => {
const response = await MasterRespository.updateJobRole(id, payload);
return response.data;
},
onSuccess: (data, variables) => {
showToast("JobRole updated successfully.", "success");
const fetchCategories =async () => {
const cacheddata = getCachedData("Work Category");
queryClient.invalidateQueries({
queryKey: ["masterData", "Job Role"],
});
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);
}
if (onSuccessCallback) onSuccessCallback(data);
},
onError: (error) => {
showToast(error.message || "Something went wrong", "error");
if (onErrorCallback) onErrorCallback(error);
},
});
};
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 MasterModal from "../../components/master/MasterModal";
import { mastersList} from "../../data/masters";
@ -9,92 +9,80 @@ import MasterTable from "./MasterTable";
import { getCachedData } from "../../slices/apiDataManager";
import {useHasUserPermission} from "../../hooks/useHasUserPermission";
import { MANAGE_MASTER } from "../../utils/constants";
import {useQueryClient} from "@tanstack/react-query";
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 [filteredResults, setFilteredResults] = useState([]);
const hasMasterPermission = useHasUserPermission( MANAGE_MASTER )
const dispatch = useDispatch();
const selectedMaster = useSelector((store)=>store.localVariables.selectedMaster)
const [isCreateModalOpen, setIsCreateModalOpen] = useState(false);
const openModal = () => {
setIsCreateModalOpen(true);
const hasMasterPermission = useHasUserPermission(MANAGE_MASTER);
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 = () => {
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');
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.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 value = e.target.value.toLowerCase();
setSearchTerm(value);
if (!masterData.length) return;
if (!masterData?.length) return;
const results = masterData.filter((item) =>
Object.values(item).some((field) =>
field && field.toString().toLowerCase().includes(value)
Object.values(item).some(
(field) => field?.toString().toLowerCase().includes(value)
)
);
setFilteredResults(results);
};
const displayData = useMemo(() => {
if (searchTerm) return filteredResults;
return queryClient.getQueryData(["masterData", selectedMaster]) || masterData;
}, [searchTerm, filteredResults, selectedMaster, masterData]);
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 });
}
const columns = useMemo(() => {
if (!displayData?.length) return [];
return Object.keys(displayData[0]).map((key) => ({
key,
label: key.toUpperCase(),
}));
}, [displayData]);
useEffect(() => {
if (modalConfig !== null) {
openModal();
}
}, [ modalConfig, isCreateModalOpen ] );
if (modalConfig) openModal();
}, [modalConfig]);
useEffect(() => {
return () => {
setIsCreateModalOpen(false)
setIsCreateModalOpen(false);
closeModal();
};
}, [])
}, []);
return (
<>

View File

@ -41,7 +41,7 @@ export const MasterRespository = {
"Activity": ( id ) => api.delete( `/api/master/activity/delete/${ id }` ),
"Application Role":(id)=>api.delete(`/api/roles/${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}`),
getWorkCategory:() => api.get(`/api/master/work-categories`),