Compare commits

...

2 Commits

Author SHA1 Message Date
a792f55340 Api changes for activity-group. 2025-08-23 12:26:21 +05:30
451a6b115b Creating a Services in Master. 2025-08-22 18:11:52 +05:30
9 changed files with 848 additions and 33 deletions

View File

@ -0,0 +1,223 @@
import React, { useEffect, useState } from "react";
import { useForm } from "react-hook-form";
import { z } from "zod";
import { zodResolver } from "@hookform/resolvers/zod";
import {
useCreateActivities,
useGetServices,
useGetActivityGroups,
} from "../../hooks/masterHook/useMaster";
// Schema validation
const schema = z.object({
serviceId: z.string().min(1, { message: "Service selection is required" }),
activityGroupId: z
.string()
.min(1, { message: "Activity Group selection is required" }),
activityName: z.string().min(1, { message: "Activity Name is required" }),
unitOfMeasurement: z
.string()
.min(1, { message: "Unit of Measurement is required" }),
description: z
.string()
.min(1, { message: "Description is required" })
.max(255, { message: "Description cannot exceed 255 characters" }),
});
const CreateActivities = ({ onClose }) => {
const {
register,
handleSubmit,
formState: { errors },
reset,
watch,
} = useForm({
resolver: zodResolver(schema),
defaultValues: {
serviceId: "",
activityGroupId: "",
activityName: "",
unitOfMeasurement: "",
description: "",
},
});
const [descriptionLength, setDescriptionLength] = useState(0);
const maxDescriptionLength = 255;
// Watch dropdown values
const selectedService = watch("serviceId");
const selectedActivityGroup = watch("activityGroupId");
// Mutation Hook
const createActivityMutation = useCreateActivities(() => {
resetForm();
onClose();
});
// Fetch services
const { data: services = [], isLoading: servicesLoading } = useGetServices();
// Fetch activity groups based on selected service
const { data: activityGroups = [], isLoading: groupsLoading } =
useGetActivityGroups(selectedService, {
enabled: !!selectedService,
});
const onSubmit = (data) => {
createActivityMutation.mutate({
activityName: data.activityName,
description: data.description,
serviceId: data.serviceId,
activityGroupId: data.activityGroupId,
unitOfMeasurement: data.unitOfMeasurement,
});
};
const resetForm = () => {
reset({
serviceId: "",
activityGroupId: "",
activityName: "",
unitOfMeasurement: "",
description: "",
});
setDescriptionLength(0);
};
useEffect(() => {
return () => resetForm();
}, []);
return (
<form className="row g-2" onSubmit={handleSubmit(onSubmit)}>
{/* Service Dropdown */}
<div className="col-12 col-md-12">
<label className="form-label">Service</label>
<select
{...register("serviceId")}
className={`form-select ${errors.serviceId ? "is-invalids" : ""}`}
disabled={servicesLoading}
>
<option value="">Select a Service</option>
{services.map((service) => (
<option key={service.id} value={service.id}>
{service.name}
</option>
))}
</select>
{errors.serviceId && (
<p className="text-danger">{errors.serviceId.message}</p>
)}
</div>
{/* Activity Group Dropdown */}
{selectedService && (
<div className="col-12 col-md-12">
<label className="form-label">Activity Group</label>
<select
{...register("activityGroupId")}
className={`form-select ${
errors.activityGroupId ? "is-invalids" : ""
}`}
disabled={groupsLoading}
>
<option value="">Select an Activity Group</option>
{activityGroups.map((group) => (
<option key={group.id} value={group.id}>
{group.name}
</option>
))}
</select>
{errors.activityGroupId && (
<p className="text-danger">{errors.activityGroupId.message}</p>
)}
</div>
)}
{/* Activity Name + Unit of Measurement + Description */}
{selectedActivityGroup && (
<>
{/* Activity Name */}
<div className="col-12 col-md-12">
<label className="form-label">Activity Name</label>
<input
type="text"
{...register("activityName")}
className={`form-control ${
errors.activityName ? "is-invalids" : ""
}`}
/>
{errors.activityName && (
<p className="text-danger">{errors.activityName.message}</p>
)}
</div>
{/* Unit of Measurement */}
<div className="col-12 col-md-12">
<label className="form-label">Unit of Measurement</label>
<input
type="text"
{...register("unitOfMeasurement")}
className={`form-control ${
errors.unitOfMeasurement ? "is-invalids" : ""
}`}
/>
{errors.unitOfMeasurement && (
<p className="text-danger">{errors.unitOfMeasurement.message}</p>
)}
</div>
{/* Description */}
<div className="col-12 col-md-12">
<label className="form-label" htmlFor="description">
Description
</label>
<textarea
rows="3"
{...register("description")}
className={`form-control ${
errors.description ? "is-invalids" : ""
}`}
onChange={(e) => {
setDescriptionLength(e.target.value.length);
register("description").onChange(e);
}}
></textarea>
<div className="text-end small text-muted">
{maxDescriptionLength - descriptionLength} characters left
</div>
{errors.description && (
<p className="text-danger">{errors.description.message}</p>
)}
</div>
{/* Buttons */}
<div className="col-12 text-center">
<button
type="submit"
className="btn btn-sm btn-primary me-3"
disabled={createActivityMutation.isPending}
>
{createActivityMutation.isPending
? "Please Wait..."
: "Submit"}
</button>
<button
type="button"
className="btn btn-sm btn-label-secondary"
onClick={() => {
resetForm();
onClose();
}}
>
Cancel
</button>
</div>
</>
)}
</form>
);
};
export default CreateActivities;

View File

@ -0,0 +1,159 @@
import React, { useEffect, useState } from "react";
import { useForm } from "react-hook-form";
import { z } from "zod";
import { zodResolver } from "@hookform/resolvers/zod";
import { useCreateActivityGroup, useGetServices } from "../../hooks/masterHook/useMaster";
// Schema validation
const schema = z.object({
name: z.string().min(1, { message: "Activity Group Name is required" }),
description: z
.string()
.min(1, { message: "Description is required" })
.max(255, { message: "Description cannot exceed 255 characters" }),
serviceId: z.string().min(1, { message: "Service selection is required" }),
});
const CreateActivityGroup = ({ onClose }) => {
const {
register,
handleSubmit,
formState: { errors },
reset,
watch,
} = useForm({
resolver: zodResolver(schema),
defaultValues: {
name: "",
description: "",
serviceId: "",
},
});
const [descriptionLength, setDescriptionLength] = useState(0);
const maxDescriptionLength = 255;
// Watch serviceId value
const selectedService = watch("serviceId");
// Mutation Hook
const createActivityGroupMutation = useCreateActivityGroup(() => {
resetForm();
onClose();
});
// Fetch services for dropdown
const { data: services = [], isLoading: servicesLoading } = useGetServices();
const onSubmit = (data) => {
createActivityGroupMutation.mutate({
name: data.name,
description: data.description,
serviceId: data.serviceId, // attach serviceId
});
};
const resetForm = () => {
reset({
name: "",
description: "",
serviceId: "",
});
setDescriptionLength(0);
};
useEffect(() => {
return () => resetForm();
}, []);
return (
<form className="row g-2" onSubmit={handleSubmit(onSubmit)}>
{/* Service Dropdown */}
<div className="col-12 col-md-12">
<label className="form-label">Service</label>
<select
{...register("serviceId")}
className={`form-select ${errors.serviceId ? "is-invalids" : ""}`}
disabled={servicesLoading}
>
<option value="">Select a Service</option>
{services.map((service) => (
<option key={service.id} value={service.id}>
{service.name}
</option>
))}
</select>
{errors.serviceId && (
<p className="text-danger">{errors.serviceId.message}</p>
)}
</div>
{/* Render rest only when service is selected */}
{selectedService && (
<>
{/* Activity Group Name */}
<div className="col-12 col-md-12">
<label className="form-label">Activity Group Name</label>
<input
type="text"
{...register("name")}
className={`form-control ${errors.name ? "is-invalids" : ""}`}
/>
{errors.name && (
<p className="text-danger">{errors.name.message}</p>
)}
</div>
{/* Description */}
<div className="col-12 col-md-12">
<label className="form-label" htmlFor="description">
Description
</label>
<textarea
rows="3"
{...register("description")}
className={`form-control ${
errors.description ? "is-invalids" : ""
}`}
onChange={(e) => {
setDescriptionLength(e.target.value.length);
register("description").onChange(e);
}}
></textarea>
<div className="text-end small text-muted">
{maxDescriptionLength - descriptionLength} characters left
</div>
{errors.description && (
<p className="text-danger">{errors.description.message}</p>
)}
</div>
{/* Buttons */}
<div className="col-12 text-center">
<button
type="submit"
className="btn btn-sm btn-primary me-3"
disabled={createActivityGroupMutation.isPending}
>
{createActivityGroupMutation.isPending
? "Please Wait..."
: "Submit"}
</button>
<button
type="button"
className="btn btn-sm btn-label-secondary"
onClick={() => {
resetForm();
onClose();
}}
>
Cancel
</button>
</div>
</>
)}
</form>
);
};
export default CreateActivityGroup;

View File

@ -0,0 +1,113 @@
import React, { useEffect, useState } from "react";
import { useForm } from "react-hook-form";
import { z } from "zod";
import { zodResolver } from "@hookform/resolvers/zod";
import { useCreateService } from "../../hooks/masterHook/useMaster";
const schema = z.object({
name: z.string().min(1, { message: "Service Name is required" }),
description: z
.string()
.min(1, { message: "Description is required" })
.max(255, { message: "Description cannot exceed 255 characters" }),
});
const CreateServices = ({ onClose }) => {
const {
register,
handleSubmit,
formState: { errors },
reset,
} = useForm({
resolver: zodResolver(schema),
defaultValues: {
name: "",
description: "",
},
});
const [descriptionLength, setDescriptionLength] = useState(0);
const maxDescriptionLength = 255;
// Use mutation hook
const createServiceMutation = useCreateService(() => {
resetForm();
onClose();
});
const onSubmit = (data) => {
createServiceMutation.mutate({
name: data.name,
description: data.description,
});
};
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">
<label className="form-label">Service Name</label>
<input
type="text"
{...register("name")}
className={`form-control ${errors.name ? "is-invalids" : ""}`}
/>
{errors.name && <p className="text-danger">{errors.name.message}</p>}
</div>
<div className="col-12 col-md-12">
<label className="form-label" htmlFor="description">
Description
</label>
<textarea
rows="3"
{...register("description")}
className={`form-control ${errors.description ? "is-invalids" : ""}`}
onChange={(e) => {
setDescriptionLength(e.target.value.length);
register("description").onChange(e);
}}
></textarea>
<div className="text-end small text-muted">
{maxDescriptionLength - descriptionLength} characters left
</div>
{errors.description && (
<p className="text-danger">{errors.description.message}</p>
)}
</div>
<div className="col-12 text-center">
<button
type="submit"
className="btn btn-sm btn-primary me-3"
disabled={createServiceMutation.isPending}
>
{createServiceMutation.isPending ? "Please Wait..." : "Submit"}
</button>
<button
type="button"
className="btn btn-sm btn-label-secondary"
onClick={() => {
resetForm();
onClose();
}}
>
Cancel
</button>
</div>
</form>
);
};
export default CreateServices;

View File

@ -0,0 +1,123 @@
import React, { useEffect, useState } from "react";
import { useForm } from "react-hook-form";
import { z } from "zod";
import { zodResolver } from "@hookform/resolvers/zod";
import { useUpdateService } from "../../hooks/masterHook/useMaster"; // your custom hook
// Validation schema
const schema = z.object({
name: z.string().min(1, { message: "Service Name is required" }),
description: z
.string()
.min(1, { message: "Description is required" })
.max(255, { message: "Description cannot exceed 255 characters" }),
});
const EditServices = ({ data, onClose }) => {
const {
register,
handleSubmit,
formState: { errors },
reset,
watch,
} = useForm({
resolver: zodResolver(schema),
defaultValues: {
name: data?.name || "",
description: data?.description || "",
},
});
const [descriptionLength, setDescriptionLength] = useState(
data?.description?.length || 0
);
const maxDescriptionLength = 255;
// hook for update
const { mutate: updateService, isPending } = useUpdateService(() => {
onClose(); // close modal on success
});
const onSubmit = (formData) => {
const payload= {
id: data?.id,
name: formData.name,
description: formData.description,
};
updateService({ id: data?.id, payload });
// });
};
// Reset form when modal opens with fresh data
useEffect(() => {
reset({
name: data?.name,
description: data?.description,
});
setDescriptionLength(data?.description?.length || 0);
}, [data, reset]);
return (
<form className="row g-2" onSubmit={handleSubmit(onSubmit)}>
{/* Service Name */}
<div className="col-12">
<label className="form-label">Service Name</label>
<input
type="text"
{...register("name")}
className={`form-control ${errors.name ? "is-invalid" : ""}`}
/>
{errors.name && <p className="text-danger">{errors.name.message}</p>}
</div>
{/* Description */}
<div className="col-12">
<label className="form-label" htmlFor="description">
Description
</label>
<textarea
rows="3"
{...register("description")}
className={`form-control ${errors.description ? "is-invalid" : ""}`}
onChange={(e) => {
setDescriptionLength(e.target.value.length);
register("description").onChange(e); // keep RHF sync
}}
></textarea>
<div className="text-end small text-muted">
{maxDescriptionLength - descriptionLength} characters left
</div>
{errors.description && (
<p className="text-danger">{errors.description.message}</p>
)}
</div>
{/* Buttons */}
<div className="col-12 text-center">
<button
type="submit"
className="btn btn-sm btn-primary me-3"
disabled={isPending}
>
{isPending ? "Please Wait..." : "Submit"}
</button>
<button
type="button"
className="btn btn-sm btn-label-secondary"
onClick={() => {
reset({
name: data?.name || "",
description: data?.description || "",
});
onClose();
}}
>
Cancel
</button>
</div>
</form>
);
};
export default EditServices;

View File

@ -4,8 +4,8 @@ import DeleteMaster from "./DeleteMaster";
import EditRole from "./EditRole";
import CreateJobRole from "./CreateJobRole";
import EditJobRole from "./EditJobRole";
import CreateActivity from "./CreateActivity";
import EditActivity from "./EditActivity";
import CreateActivity from "./CreateServices";
import EditActivity from "./EditServices";
import ConfirmModal from "../common/ConfirmModal";
import { MasterRespository } from "../../repositories/MastersRepository";
import { cacheData, getCachedData } from "../../slices/apiDataManager";
@ -20,6 +20,10 @@ import { useDeleteMasterItem } from "../../hooks/masterHook/useMaster";
import ManageExpenseType from "./ManageExpenseType";
import ManagePaymentMode from "./ManagePaymentMode";
import ManageExpenseStatus from "./ManageExpenseStatus";
import CreateServices from "./CreateServices";
import EditServices from "./EditServices";
import CreateActivityGroup from "./CreateActivityGroup";
import CreateActivities from "./CreateActivities";
const MasterModal = ({ modaldata, closeModal }) => {
@ -83,8 +87,10 @@ const MasterModal = ({ modaldata, closeModal }) => {
"Edit-Application Role": <EditRole master={modaldata} onClose={closeModal} />,
"Job Role": <CreateJobRole onClose={closeModal} />,
"Edit-Job Role": <EditJobRole data={item} onClose={closeModal} />,
"Activity": <CreateActivity onClose={closeModal} />,
"Edit-Activity": <EditActivity activityData={item} onClose={closeModal} />,
"Services": <CreateServices onClose={closeModal} />,
"Edit-Services": <EditServices data={item} onClose={closeModal} />,
"Activity-Group": <CreateActivityGroup onClose={closeModal} />,
"Activities":<CreateActivities onClose={closeModal}/>,
"Work Category": <CreateWorkCategory onClose={closeModal} />,
"Edit-Work Category": <EditWorkCategory data={item} onClose={closeModal} />,
"Contact Category": <CreateCategory data={item} onClose={closeModal} />,

View File

@ -2,7 +2,7 @@
export const mastersList = [
{ id: 1, name: "Application Role" },
{ id: 2, name: "Job Role" },
{ id: 3, name: "Activity" },
{ id: 3, name: "Services" },
{ id: 4, name: "Work Category" },
{ id: 5, name: "Contact Category" },
{ id: 6, name: "Contact Tag" },

View File

@ -171,8 +171,12 @@ const fetchMasterData = async (masterType) => {
return (await MasterRespository.getRoles()).data;
case "Job Role":
return (await MasterRespository.getJobRole()).data;
case "Activity":
return (await MasterRespository.getActivites()).data;
case "Services":
return (await MasterRespository.getServices()).data;
case "Activity-Group":
return (await MasterRespository.getActivityGroups()).data;
case "Activities":
return (await MasterRespository.getActivities()).data;
case "Work Category":
return (await MasterRespository.getWorkCategory()).data;
case "Contact Category":
@ -332,6 +336,126 @@ export const useUpdateApplicationRole = (onSuccessCallback) =>
});
}
// Services-------------------------------
export const useCreateService = (onSuccessCallback) => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: async (payload) => {
const resp = await MasterRespository.createService(payload);
return resp.data; // full API response
},
onSuccess: (data) => {
// Invalidate & refetch service list
queryClient.invalidateQueries({ queryKey: ["masterData", "Services"] });
showToast(data?.message || "Service added successfully", "success");
if (onSuccessCallback) onSuccessCallback(data?.data); // pass back new service object
},
onError: (error) => {
showToast(error.message || "Something went wrong", "error");
},
});
};
export const useUpdateService = (onSuccessCallback) => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: async ({ id, payload }) => {
const response = await MasterRespository.updateService(id, payload);
return response; // full response since it already has { success, message, data }
},
onSuccess: (data, variables) => {
queryClient.invalidateQueries({
queryKey: ["masterData", "Services"],
});
showToast(data.message || "Service updated successfully.", "success");
if (onSuccessCallback) onSuccessCallback(data);
},
onError: (error) => {
showToast(error?.message || "Something went wrong", "error");
},
});
};
//Activity-group--------------------------------
export const useGetServices = () => {
return useQuery({
queryKey: ["masterData", "Services"],
queryFn: async () => {
const resp = await MasterRepository.getServices();
return resp.data?.data || []; // only return array of services
},
});
};
export const useCreateActivityGroup = (onSuccessCallback) => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: async (payload) => {
const resp = await MasterRespository.createActivityGroup(payload);
return resp.data; // full API response
},
onSuccess: (data) => {
// Invalidate & refetch activity groups
queryClient.invalidateQueries({
queryKey: ["masterData", "Activity-Group"],
});
showToast(data?.message || "Activity Group added successfully", "success");
if (onSuccessCallback) onSuccessCallback(data?.data);
},
onError: (error) => {
showToast(error.message || "Something went wrong", "error");
},
});
};
//Activities--------------------------------------
export const useGetActivityGroups = () => {
return useQuery({
queryKey: ["masterData", "Activity-Group"],
queryFn: async () => {
const resp = await MasterRepository.getActivityGroup();
return resp.data?.data || []; // only return array of services
},
});
};
export const useCreateActivities = (onSuccessCallback) => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: async (payload) => {
const resp = await MasterRespository.createActivities(payload);
return resp.data; // return full API response
},
onSuccess: (data) => {
// Invalidate & refetch activities list
queryClient.invalidateQueries({
queryKey: ["masterData", "Activities"],
});
showToast(data?.message || "Activity added successfully", "success");
if (onSuccessCallback) onSuccessCallback(data?.data);
},
onError: (error) => {
showToast(error.message || "Something went wrong", "error");
},
});
};
// Activity------------------------------
export const useCreateActivity = (onSuccessCallback) =>
{

View File

@ -23,7 +23,16 @@ const MasterPage = () => {
const selectedMaster = useSelector((store) => store.localVariables.selectedMaster);
const queryClient = useQueryClient();
const { data: masterData = [], loading, error, RecallApi } = useMaster();
const { data: masterData = [], loading } = useMaster();
// Define button configs for Services
const masterButtonsConfig = {
Services: [
{ label: "Add Service", modalType: "Services" },
{ label: "Add Activity-Group", modalType: "serviceActivity" },
{ label: "Add Activities", modalType: "serviceUnit" },
],
};
const openModal = () => setIsCreateModalOpen(true);
@ -61,7 +70,9 @@ const MasterPage = () => {
};
const displayData = useMemo(() => {
if (searchTerm) return filteredResults;
return queryClient.getQueryData(["masterData", selectedMaster]) || masterData;
return (
queryClient.getQueryData(["masterData", selectedMaster]) || masterData
);
}, [searchTerm, filteredResults, selectedMaster, masterData]);
const columns = useMemo(() => {
@ -148,43 +159,86 @@ const MasterPage = () => {
></input>
</label>
</div>
<div className={`dt-buttons btn-group flex-wrap ${!hasMasterPermission && 'd-none'}`}>
{" "}
<div className="input-group">
<button
className={`btn btn-sm add-new btn-primary `}
// ${hasUserPermission('660131a4-788c-4739-a082-cbbf7879cbf2') ? "":"d-none"}
tabIndex="0"
aria-controls="DataTables_Table_0"
type="button"
data-bs-toggle="modal"
data-bs-target="#master-modal"
onClick={() => {
handleModalData(selectedMaster, "null", selectedMaster)
{/* Add Buttons */}
<div
className={`dt-buttons btn-group flex-wrap ${!hasMasterPermission && "d-none"
}`}
>
<div className="d-flex flex-wrap gap-2">
{selectedMaster === "Services" ? (
<>
<button
className="btn btn-sm btn-primary"
type="button"
data-bs-toggle="modal"
data-bs-target="#master-modal"
onClick={() =>
handleModalData("Services", null, selectedMaster)
}
>
<i className="bx bx-plus-circle me-2"></i>
Add Service
</button>
}}
>
<span>
<button
className="btn btn-sm btn-primary"
type="button"
data-bs-toggle="modal"
data-bs-target="#master-modal"
onClick={() =>
handleModalData("Activity-Group", null, selectedMaster)
}
>
<i className="bx bx-plus-circle me-2"></i>
Add Activity-Group
</button>
<button
className="btn btn-sm btn-primary"
type="button"
data-bs-toggle="modal"
data-bs-target="#master-modal"
onClick={() =>
handleModalData("Activities", null, selectedMaster)
}
>
<i className="bx bx-plus-circle me-2"></i>
Add Activities
</button>
</>
) : (
<button
className="btn btn-sm btn-primary"
type="button"
data-bs-toggle="modal"
data-bs-target="#master-modal"
onClick={() =>
handleModalData(selectedMaster, null, selectedMaster)
}
>
<i className="bx bx-plus-circle me-2"></i>
<span className=" d-sm-inline-block">
Add {selectedMaster}
</span>
</span>
</button>{" "}
Add {selectedMaster}
</button>
)}
</div>
</div>
</div>
</div>
</div>
<MasterTable data={displayData} columns={columns} loading={loading} handleModalData={handleModalData} />
<MasterTable
data={displayData}
columns={columns}
loading={loading}
handleModalData={handleModalData}
/>
<div style={{ width: "1%" }}></div>
</div>
</div>
</div>
</div>
</div>
</>
);

View File

@ -27,7 +27,19 @@ export const MasterRespository = {
getJobRole: () => api.get("/api/roles/jobrole"),
updateJobRole: (id, data) => api.put(`/api/roles/jobrole/${id}`, data),
getActivites: () => api.get("api/master/activities"),
getServices: () => api.get("api/master/services"),
createService: (data) => api.post("api/master/service", data),
updateService: (id, data) => api.put(`api/master/service/${id}`, data),
getActivityGroups: () => api.get("api/master/activity-groups"),
createActivityGroup: (data) => api.post("api/master/activity-group", data),
updateActivityGroup:(id,data) => api.put(`api/master/activity-group/${id}`, data),
getActivities: () => api.get("api/master/activities"),
createActivities: (data) => api.post("api/master/activity", data),
updateActivities: (id, data) => api.put(`api/master/activity/${id}`, data),
// getActivites: () => api.get("api/master/activities"),
createActivity: (data) => api.post("api/master/activity", data),
updateActivity: (id, data) =>
api.post(`api/master/activity/edit/${id}`, data),
@ -36,6 +48,7 @@ export const MasterRespository = {
// delete
"Job Role": (id) => api.delete(`/api/roles/jobrole/${id}`),
Activity: (id) => api.delete(`/api/master/activity/delete/${id}`),
"Services": (id) => api.delete(`/api/master/service/${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/${id}`),