373 lines
12 KiB
JavaScript
373 lines
12 KiB
JavaScript
import React, { useEffect, useState } from "react";
|
|
import { useForm } from "react-hook-form";
|
|
import { z } from "zod";
|
|
import { zodResolver } from "@hookform/resolvers/zod";
|
|
import {
|
|
useActivitiesByGroups,
|
|
useActivitiesMaster,
|
|
useGroups,
|
|
useWorkCategoriesMaster,
|
|
} from "../../../hooks/masterHook/useMaster";
|
|
import { useManageTask, useProjectAssignedOrganizations, useProjectAssignedServices } from "../../../hooks/useProjects";
|
|
import showToast from "../../../services/toastService";
|
|
import Label from "../../common/Label";
|
|
import { useSelectedProject } from "../../../slices/apiDataManager";
|
|
|
|
const taskSchema = z.object({
|
|
buildingID: z.string().min(1, "Building is required"),
|
|
floorId: z.string().min(1, "Floor is required"),
|
|
workAreaId: z.string().min(1, "Work Area is required"),
|
|
serviceId: z.string().min(1, "Service is required"),
|
|
activityGroupId: z.string().min(1, "Activity Group is required"),
|
|
activityID: z.string().min(1, "Activity is required"),
|
|
workCategoryId: z.string().min(1, "Work Category is required"),
|
|
plannedWork: z.number().min(1, "Planned Work must be greater than 0"),
|
|
completedWork: z.number().min(0, "Completed Work must be 0 or more"),
|
|
comment: z.string(),
|
|
});
|
|
|
|
const defaultModel = {
|
|
id: null,
|
|
buildingID: "",
|
|
floorId: "",
|
|
workAreaId: "",
|
|
serviceId: "",
|
|
activityGroupId: "",
|
|
activityID: "",
|
|
workCategoryId: "",
|
|
plannedWork: 0,
|
|
completedWork: 0,
|
|
comment: "",
|
|
};
|
|
|
|
const TaskModel = ({ project, onSubmit, onClose }) => {
|
|
// const { activities, loading: activityLoading } = useActivitiesMaster();
|
|
const { categories, categoryLoading } = useWorkCategoriesMaster();
|
|
|
|
const projectId = useSelectedProject();
|
|
|
|
const { data: assignedServices, isLoading: servicesLoading } = useProjectAssignedServices(projectId);
|
|
const { data: assignedOrganizations, isLoading: orgLoading } = useProjectAssignedOrganizations(projectId);
|
|
|
|
|
|
|
|
const [selectedService, setSelectedService] = useState("");
|
|
const [selectedGroup, setSelectedGroup] = useState("");
|
|
const { data: groupsResponse, isLoading: groupsLoading } = useGroups(selectedService);
|
|
const groups = groupsResponse?.data ?? [];
|
|
|
|
const { data: activitiesResponse, isLoading: activitiesLoading } = useActivitiesByGroups(selectedGroup);
|
|
const activities = activitiesResponse?.data ?? [];
|
|
// Fetch Assigned Organizations (Activity Groups)
|
|
|
|
const [selectedOrg, setSelectedOrg] = useState("");
|
|
const handleServiceChange = (e) => {
|
|
const value = e.target.value;
|
|
setSelectedService(value);
|
|
setSelectedGroup("");
|
|
setValue("activityGroupId", "");
|
|
setValue("activityID", "");
|
|
};
|
|
|
|
const handleGroupChange = (e) => {
|
|
const value = e.target.value;
|
|
setSelectedGroup(value);
|
|
setValue("activityGroupId", value);
|
|
setValue("activityID", "");
|
|
};
|
|
|
|
|
|
const {
|
|
register,
|
|
handleSubmit,
|
|
watch,
|
|
setValue,
|
|
reset,
|
|
formState: { errors },
|
|
} = useForm({
|
|
resolver: zodResolver(taskSchema),
|
|
defaultValues: defaultModel,
|
|
});
|
|
|
|
const [isSubmitting, setIsSubmitting] = useState(false);
|
|
const [activityData, setActivityData] = useState([]);
|
|
const [categoryData, setCategoryData] = useState([]);
|
|
|
|
const watchBuildingId = watch("buildingID");
|
|
const watchFloorId = watch("floorId");
|
|
const watchWorkAreaId = watch("workAreaId");
|
|
const watchActivityId = watch("activityID");
|
|
const watchCategoryId = watch("workCategoryId");
|
|
|
|
const selectedBuilding = project?.find((b) => b.id === watchBuildingId);
|
|
const selectedFloor = selectedBuilding?.floors?.find(
|
|
(f) => f.id === watchFloorId
|
|
);
|
|
const selectedWorkArea = selectedFloor?.workAreas?.find(
|
|
(w) => w.id === watchWorkAreaId
|
|
);
|
|
const selectedActivity = activityData?.find((a) => a.id === watchActivityId);
|
|
const selectedCategory = categoryData?.find((c) => c.id === watchCategoryId);
|
|
|
|
const { mutate: CreateTask, isPending } = useManageTask({
|
|
onSuccessCallback: (response) => {
|
|
showToast(response?.message, "success");
|
|
setValue("activityID",""),
|
|
setValue("plannedWork",0),
|
|
setValue("completedWork",0)
|
|
setValue("comment","")
|
|
},
|
|
});
|
|
useEffect(() => {
|
|
reset(defaultModel);
|
|
}, []);
|
|
|
|
useEffect(() => {
|
|
if (Array.isArray(activities) && activities.length > 0) {
|
|
setActivityData(activities);
|
|
}
|
|
}, [activities]);
|
|
|
|
useEffect(() => {
|
|
if (Array.isArray(categories) && categories.length > 0) {
|
|
const sorted = [...categories].sort((a, b) =>
|
|
(a?.name || "").localeCompare(b?.name || "")
|
|
);
|
|
setCategoryData(sorted);
|
|
setValue("workCategoryId", sorted?.[0]?.id?.toString() ?? "");
|
|
}
|
|
}, [categories]);
|
|
|
|
const onSubmitForm = async (data) => {
|
|
const payload = [data];
|
|
CreateTask({
|
|
payload: payload, buildingId: data.buildingID,
|
|
floorId: data.floorId,
|
|
workAreaId: data.workAreaId, PreviousPlannedWork: 0, previousCompletedWork: 0
|
|
});
|
|
};
|
|
|
|
return (
|
|
<form className="row g-2" onSubmit={handleSubmit(onSubmitForm)}>
|
|
<div className="text-center mb-1">
|
|
<h5 className="mb-1">Manage Task</h5>
|
|
</div>
|
|
<div className="col-6 text-start">
|
|
<Label className="form-label" required>Select Building</Label>
|
|
<select
|
|
className="form-select form-select-sm"
|
|
{...register("buildingID")}
|
|
>
|
|
<option value="">Select Building</option>
|
|
{project
|
|
?.filter((b) => b?.buildingName)
|
|
?.sort((a, b) => a?.buildingName.localeCompare(b.buildingName))
|
|
?.map((b) => (
|
|
<option key={b.id} value={b.id}>
|
|
{b.buildingName}
|
|
</option>
|
|
))}
|
|
</select>
|
|
{errors.buildingID && (
|
|
<p className="danger-text">{errors.buildingID.message}</p>
|
|
)}
|
|
</div>
|
|
|
|
{selectedBuilding && (
|
|
<div className="col-6 text-start">
|
|
<Label className="form-label" required>Select Floor</Label>
|
|
<select
|
|
className="form-select form-select-sm"
|
|
{...register("floorId")}
|
|
>
|
|
<option value="">Select Floor</option>
|
|
{selectedBuilding.floors
|
|
?.sort((a, b) => a.floorName.localeCompare(b.floorName))
|
|
?.map((f) => (
|
|
<option key={f.id} value={f.id}>
|
|
{f.floorName}
|
|
</option>
|
|
))}
|
|
</select>
|
|
{errors.floorId && (
|
|
<p className="danger-text">{errors.floorId.message}</p>
|
|
)}
|
|
</div>
|
|
)}
|
|
|
|
{/* Work Area Selection */}
|
|
{selectedFloor && (
|
|
<div className="col-12 text-start">
|
|
<Label className="form-label" required>Select Work Area</Label>
|
|
<select
|
|
className="form-select form-select-sm"
|
|
{...register("workAreaId")}
|
|
>
|
|
<option value="">Select Work Area</option>
|
|
{selectedFloor.workAreas
|
|
?.sort((a, b) => a.areaName.localeCompare(b.areaName))
|
|
?.map((w) => (
|
|
<option key={w.id} value={w.id}>
|
|
{w.areaName}
|
|
</option>
|
|
))}
|
|
</select>
|
|
{errors.workAreaId && (
|
|
<p className="danger-text">{errors.workAreaId.message}</p>
|
|
)}
|
|
</div>
|
|
)}
|
|
|
|
{/* Services Selection */}
|
|
{selectedWorkArea && (
|
|
<div className="col-12 text-start">
|
|
<Label className="form-label" required>Select Service</Label>
|
|
<select
|
|
className="form-select form-select-sm"
|
|
{...register("serviceId")}
|
|
value={selectedService}
|
|
// onChange={handleServiceChange}
|
|
onChange={(e) => {
|
|
handleServiceChange(e);
|
|
setValue("serviceId", e.target.value);
|
|
}}
|
|
>
|
|
<option value="">Select Service</option>
|
|
{servicesLoading && <option>Loading...</option>}
|
|
{assignedServices?.map((service) => (
|
|
<option key={service.id} value={service.id}>
|
|
{service.name}
|
|
</option>
|
|
))}
|
|
</select>
|
|
</div>
|
|
)}
|
|
|
|
{/* Activity Group (Organization) Selection */}
|
|
{selectedService && (
|
|
<div className="col-12 text-start">
|
|
<Label className="form-label" required>Select Activity Group</Label>
|
|
<select
|
|
className="form-select form-select-sm"
|
|
{...register("activityGroupId")}
|
|
value={selectedGroup}
|
|
onChange={handleGroupChange}
|
|
>
|
|
<option value="">Select Group</option>
|
|
{groupsLoading && <option>Loading...</option>}
|
|
{groups?.map((g) => (
|
|
<option key={g.id} value={g.id}>{g.name}</option>
|
|
))}
|
|
</select>
|
|
{errors.activityGroupId && <p className="danger-text">{errors.activityGroupId.message}</p>}
|
|
</div>
|
|
)}
|
|
|
|
|
|
{/* Activity Selection */}
|
|
{selectedGroup && (
|
|
<div className="col-12 text-start">
|
|
<Label className="form-label" required>Select Activity</Label>
|
|
<select className="form-select form-select-sm" {...register("activityID")}>
|
|
<option value="">Select Activity</option>
|
|
{activitiesLoading && <option>Loading...</option>}
|
|
{activities?.map((a) => (
|
|
<option key={a.id} value={a.id}>{a.activityName}</option>
|
|
))}
|
|
</select>
|
|
{errors.activityID && <p className="danger-text">{errors.activityID.message}</p>}
|
|
</div>
|
|
)}
|
|
|
|
{watchActivityId && (
|
|
<div className="col-12 text-start">
|
|
<label className="form-label">Select Work Category</label>
|
|
<select
|
|
className="form-select form-select-sm"
|
|
{...register("workCategoryId")}
|
|
>
|
|
{categoryData.map((c) => (
|
|
<option key={c.id} value={c.id}>
|
|
{c.name}
|
|
</option>
|
|
))}
|
|
</select>
|
|
{errors.workCategoryId && (
|
|
<p className="danger-text">{errors.workCategoryId.message}</p>
|
|
)}
|
|
</div>
|
|
)}
|
|
|
|
{selectedActivity && selectedCategory && (
|
|
<>
|
|
<div className="col-5 text-start">
|
|
<Label className="form-label" required>Planned Work</Label>
|
|
<input
|
|
type="number"
|
|
className="form-control form-control-sm"
|
|
{...register("plannedWork", { valueAsNumber: true })}
|
|
/>
|
|
{errors.plannedWork && (
|
|
<p className="danger-text">{errors.plannedWork.message}</p>
|
|
)}
|
|
</div>
|
|
<div className="col-5 text-start">
|
|
<label className="form-label">Completed Work</label>
|
|
<input
|
|
type="number"
|
|
className="form-control form-control-sm"
|
|
{...register("completedWork", { valueAsNumber: true })}
|
|
/>
|
|
{errors.completedWork && (
|
|
<p className="danger-text">{errors.completedWork.message}</p>
|
|
)}
|
|
</div>
|
|
<div className="col-2 text-start">
|
|
<label className="form-label">Unit</label>
|
|
<input
|
|
type="text"
|
|
className="form-control form-control-sm"
|
|
disabled
|
|
value={selectedActivity?.unitOfMeasurement || ""}
|
|
/>
|
|
</div>
|
|
</>
|
|
)}
|
|
|
|
{selectedActivity && selectedCategory && (
|
|
<div className="col-12 text-start">
|
|
<label className="form-label">Comment</label>
|
|
<textarea
|
|
className="form-control"
|
|
rows="2"
|
|
{...register("comment")}
|
|
/>
|
|
{errors.comment && (
|
|
<p className="danger-text">{errors.comment.message}</p>
|
|
)}
|
|
</div>
|
|
)}
|
|
|
|
<div className="col-12 text-end mt-5">
|
|
<button
|
|
type="button"
|
|
className="btn btn-sm btn-label-secondary me-3"
|
|
onClick={onClose}
|
|
>
|
|
Cancel
|
|
</button>
|
|
<button
|
|
type="submit"
|
|
className="btn btn-sm btn-primary"
|
|
// disabled={isSubmitting}
|
|
disabled={isPending}
|
|
>
|
|
{isPending ? "Please Wait..." : "Add Task"}
|
|
</button>
|
|
</div>
|
|
</form>
|
|
);
|
|
};
|
|
|
|
export default TaskModel;
|