Compare commits
2 Commits
main
...
Kartik_Tas
Author | SHA1 | Date | |
---|---|---|---|
a792f55340 | |||
451a6b115b |
223
src/components/master/CreateActivities.jsx
Normal file
223
src/components/master/CreateActivities.jsx
Normal 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;
|
159
src/components/master/CreateActivityGroup.jsx
Normal file
159
src/components/master/CreateActivityGroup.jsx
Normal 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;
|
113
src/components/master/CreateServices.jsx
Normal file
113
src/components/master/CreateServices.jsx
Normal 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;
|
123
src/components/master/EditServices.jsx
Normal file
123
src/components/master/EditServices.jsx
Normal 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;
|
@ -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} />,
|
||||
|
@ -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" },
|
||||
|
@ -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) =>
|
||||
{
|
||||
|
@ -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>
|
||||
</>
|
||||
);
|
||||
|
@ -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}`),
|
||||
|
Loading…
x
Reference in New Issue
Block a user