Compare commits

...

8 Commits

5 changed files with 382 additions and 18 deletions

View File

@ -0,0 +1,342 @@
import React, { useState, useEffect } from "react";
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import { z } from "zod";
import { useActivitiesMaster } from "../../../hooks/masterHook/useMaster";
import { useProjectDetails } from "../../../hooks/useProjects";
import useSelect from "../../common/useSelect";
import { useDispatch, useSelector } from "react-redux";
import ProjectRepository from "../../../repositories/ProjectRepository";
import {
cacheData,
clearCacheKey,
getCachedData,
} from "../../../slices/apiDataManager";
import { refreshData } from "../../../slices/localVariablesSlice";
import showToast from "../../../services/toastService";
const taskSchema = z
.object({
activityID: z.string().min(1, "Activity is required"),
plannedWork: z.number().min(1, "Planned Work must be greater than 0"),
completedWork: z.number().optional(),
})
.refine(
(data) =>
data.completedWork === undefined ||
data.completedWork <= data.plannedWork,
{
message: "Completed Work cannot be greater than Planned Work",
path: ["completedWork"], // error will show next to this field
}
);
const EditActivityModal = ({
workItem,
workArea,
building,
floor,
onClose,
}) => {
const selectedProject = useSelector(
(store) => store.localVariables.projectId
);
const defaultModel = {
activityID: 0,
plannedWork: 0,
completedWork: 0,
};
const { projects_Details, refetch } = useProjectDetails(selectedProject);
const { activities, loading, error } = useActivitiesMaster();
const [formData, setFormData] = useState(defaultModel);
const [selectedActivity, setSelectedActivity] = useState(null);
const [isSubmitting, setIsSubmitting] = useState(false);
const [activityData, setActivityData] = useState([]);
const dispatch = useDispatch();
const {
register,
handleSubmit,
formState: { errors },
reset,
setValue,
getValues,
watch,
} = useForm({
resolver: zodResolver(taskSchema),
defaultValues: defaultModel,
});
const handleActivityChange = (e) => {
const selectedId = Number(e.target.value);
const selected = activityData.find((a) => a.id === selectedId);
setSelectedActivity(selected || null);
setValue("activityID", selectedId);
};
const onSubmitForm = async (data) => {
const updatedProject = { ...projects_Details };
const finalData = {
...data,
id: workItem?.workItem?.id ?? workItem?.id,
buildingID: building?.id,
floorId: floor?.id,
workAreaId: workArea?.id,
};
console.log(finalData)
ProjectRepository.manageProjectTasks([finalData])
.then((response) => {
if (response?.data[0]) {
const { workItemId, workItem } = response.data[0];
let finalUpdatedWorkItem = null;
const newProject = {
...updatedProject,
buildings: updatedProject.buildings.map((building) =>
building.id === finalData.buildingID
? {
...building,
floors: building.floors.map((floor) =>
floor.id === finalData.floorId
? {
...floor,
workAreas: floor.workAreas.map((workArea) =>
workArea.id === workItem?.workAreaId
? {
...workArea,
workItems: (() => {
const exists = workArea.workItems.some(
(item) =>
String(
item?.workItem?.id ?? item?.id
) === String(finalData.id)
);
finalUpdatedWorkItem = workItem;
return exists
? workArea.workItems.map((item) =>
String(
item?.workItem?.id ?? item?.id
) === String(finalData.id)
? workItem
: item
)
: [...workArea.workItems, workItem];
})(),
}
: workArea
),
}
: floor
),
}
: building
),
};
cacheData("projectInfo", {
projectId: newProject.id,
data: newProject,
} );
resetForm();
dispatch(refreshData(true));
onClose();
}
})
.catch((error) => {
showToast(error.message, "error");
});
};
const resetForm = () => {
setFormData(defaultModel);
setSelectedActivity(null);
reset(defaultModel);
};
useEffect(() => {
reset({
activityID: workItem?.workItem?.activityId || workItem?.activityId || 0,
plannedWork:
workItem?.workItem?.plannedWork || workItem?.plannedWork || 0,
completedWork:
workItem?.workItem?.completedWork || workItem?.completedWork || 0,
});
return () => reset();
}, [activities, workItem]);
const ISselectedActivity = watch("activityID");
useEffect(() => {
const selected = activities.find((a) => a.id === ISselectedActivity);
setSelectedActivity(selected || null);
}, [ISselectedActivity]);
return (
<div className="modal-dialog modal-lg modal-simple modal-edit-user">
<div className="modal-content">
<div className="modal-body">
<div className="row">
<button
type="button"
className="btn-close"
aria-label="Close"
onClick={onClose}
/>
<div className="text-center mb-1">
<h5 className="mb-1">Manage Task</h5>
</div>
<form className="row g-2" onSubmit={handleSubmit(onSubmitForm)}>
{/* Select Building */}
<div className="col-6 col-md-6">
<label className="form-label" htmlFor="buildingID">
Select Building
</label>
<input
type="text"
className="form-control form-control-sm"
value={building?.name}
disabled
/>
</div>
{/* Select Floor */}
<div className="col-6 col-md-6">
<label className="form-label" htmlFor="floorId">
Select Floor
</label>
<input
type="text"
className="form-control form-control-sm"
value={floor?.floorName}
disabled
/>
</div>
<div className="col-12 col-md-12">
<label className="form-label" htmlFor="workAreaId">
Select Work Area
</label>
<input
type="text"
className="form-control form-control-sm"
value={workArea?.areaName}
disabled
/>
</div>
{/* Select Activity */}
<div className="col-12 col-md-12">
<label className="form-label" htmlFor="activityID">
Select Activity
</label>
<select
id="activityID"
className="form-select form-select-sm"
{...register("activityID")}
>
{loading ? (
<option value="">Loading...</option>
) : (
<option disabled>Select Activity</option>
)}
{activities &&
activities.length > 0 &&
activities
.slice()
.sort((a, b) =>
(a.activityName || "").localeCompare(
b.activityName || ""
)
)
.map((activity) => (
<option key={activity.id} value={activity.id}>
{activity.activityName}
</option>
))}
{!loading && activityData.length === 0 && (
<option disabled>No activities available</option>
)}
</select>
{errors.activityID && (
<p className="danger-text">{errors.activityID.message}</p>
)}
</div>
{/* Planned Work */}
{/* {ISselectedActivity && ( */}
<div className="col-5 col-md-5">
<label className="form-label" htmlFor="plannedWork">
Planned Work
</label>
<input
{...register("plannedWork", { valueAsNumber: true })}
type="number"
className="form-control form-control-sm me-2"
placeholder="Planned Work"
/>
{errors.plannedWork && (
<p className="danger-text">{errors.plannedWork.message}</p>
)}
</div>
{/* )} */}
{/* Completed Work */}
{/* {ISselectedActivity && ( */}
<div className="col-5 col-md-5">
<label className="form-label" htmlFor="completedWork">
Completed Work
</label>
<input
{...register("completedWork", { valueAsNumber: true })}
type="number"
className="form-control form-control-sm me-2"
placeholder="Completed Work"
/>
{errors.completedWork && (
<p className="danger-text">{errors.completedWork.message}</p>
)}
</div>
{/* )} */}
{/* Unit */}
{/* {ISselectedActivity && ( */}
<div className="col-2 col-md-2">
<label className="form-label" htmlFor="unit">
Unit
</label>
<input
type="text"
disabled
className="form-control form-control-sm me-2"
value={selectedActivity?.unitOfMeasurement || ""}
/>
</div>
{/* )} */}
<div className="col-12 text-center">
<button type="submit" className="btn btn-sm btn-primary me-3">
{isSubmitting ? "Please Wait.." : "Edit Task"}
</button>
<button
type="button"
className="btn btn-sm btn-label-secondary"
onClick={onClose}
>
Cancel
</button>
</div>
</form>
</div>
</div>
</div>
</div>
);
};
export default EditActivityModal;

View File

@ -1,7 +1,7 @@
import React, { useState, useEffect } from "react";
import AssignRoleModel from "../AssignRole";
import { useParams } from "react-router-dom";
//import EditActivityModal from "./EditActivityModal";
import EditActivityModal from "./EditActivityModal";
import { useHasUserPermission } from "../../../hooks/useHasUserPermission";
import { MANAGE_PROJECT_INFRA, MANAGE_TASK } from "../../../utils/constants";
@ -59,7 +59,7 @@ const WorkItem = ({ workItem, forBuilding, forFloor, forWorkArea }) => {
</div>
)}
{/* <div
{showModal && <div
className={`modal fade ${showModal ? "show" : ""}`}
tabIndex="-1"
role="dialog"
@ -73,7 +73,7 @@ const WorkItem = ({ workItem, forBuilding, forFloor, forWorkArea }) => {
floor={forFloor}
onClose={closeModal1}
/>
</div> */}
</div> }
<tr>
<td className="text-start table-cell-small">
@ -87,19 +87,23 @@ const WorkItem = ({ workItem, forBuilding, forFloor, forWorkArea }) => {
</td>
{/* for mobile view */}
<td className="text-center d-sm-none d-sm-table-cell">
{NewWorkItem?.workItem?.completedWork}/{" "}
{hasWorkItem
? NewWorkItem?.workItem?.completedWork ?? workItem?.completedWork ?? "NA"
: "NA"}/{" "}
{hasWorkItem
? NewWorkItem?.workItem?.plannedWork || workItem?.plannedWork
: "NA"}
</td>
{/* for greather than mobile view ************* */}
<td className="text-center d-none d-md-table-cell">
{hasWorkItem
? NewWorkItem?.workItem?.plannedWork || workItem?.plannedWork
: "NA"}
{hasWorkItem
? NewWorkItem?.workItem?.plannedWork ?? workItem?.plannedWork ?? "NA"
: "NA"}
</td>
<td className="text-center d-none d-md-table-cell">
{NewWorkItem?.workItem?.completedWork}
{hasWorkItem
? NewWorkItem?.workItem?.completedWork ?? workItem?.completedWork ?? "NA"
: "NA"}
</td>
<td className="text-center" style={{ width: "15%" }}>
<div className="progress p-0">

View File

@ -14,12 +14,16 @@ import { MANAGE_PROJECT_INFRA } from "../../utils/constants";
import InfraTable from "./Infrastructure/InfraTable";
import { cacheData, clearCacheKey, getCachedData } from "../../slices/apiDataManager";
import { useProjectDetails } from "../../hooks/useProjects";
import {useDispatch, useSelector} from "react-redux";
import {refreshData} from "../../slices/localVariablesSlice";
const ProjectInfra = ({
data,
onDataChange,
eachSiteEngineer,
}) => {
} ) =>
{
const reloadedData = useSelector((store)=>store.localVariables.reload)
const [expandedBuildings, setExpandedBuildings] = useState([]);
const { projects_Details,refetch, loading } = useProjectDetails(data?.id);
const [project, setProject] = useState(projects_Details);
@ -35,7 +39,8 @@ const ProjectInfra = ({
const [isCreateModalOpen, setIsCreateModalOpen] = useState(false);
const [clearFormTrigger, setClearFormTrigger] = useState(false);
const [CurrentBuilding, setCurrentBuilding] = useState("");
const [showModal, setShowModal] = useState(false);
const [ showModal, setShowModal ] = useState( false );
const dispatch = useDispatch()
useEffect(() => {
setProject(projects_Details);
@ -339,7 +344,15 @@ const ProjectInfra = ({
};
const handleShow = () => setShowModal(true);
const handleClose = () => setShowModal(false);
const handleClose = () => setShowModal( false );
useEffect( () =>
{
if (reloadedData)
{
refetch()
dispatch( refreshData( false ) )
}
},[reloadedData])
return (
<>

View File

@ -7,12 +7,10 @@ import { setProjectId } from "../slices/localVariablesSlice";
export const useProjects = () => {
const { profile } = useProfile();
const dispatch = useDispatch();
const [projects, setProjects] = useState([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState("");
const projects_cache = getCachedData("projectslist");
const fetchData = async () => {
const projectIds = profile?.projects || [];
@ -22,6 +20,8 @@ export const useProjects = () => {
.sort((a, b) => a.name.localeCompare(b.name));
};
const projects_cache = getCachedData("projectslist");
if (!projects_cache) {
setLoading(true);
try {
@ -38,7 +38,7 @@ export const useProjects = () => {
} else {
if (!projects.length) {
const filtered = filterProjects(projects_cache);
setProjects( filtered );
setProjects(filtered);
setLoading(false);
}
}
@ -128,5 +128,5 @@ export const useProjectDetails = (projectId) => {
}
}, [projectId, profile]);
return { projects_Details, loading, error, refetch: fetchData };
};
return { projects_Details, loading, error, refetch: fetchData }
}

View File

@ -5,7 +5,8 @@ const localVariablesSlice = createSlice({
initialState: {
selectedMaster:"Application Role",
regularizationCount:0,
projectId:1,
projectId: 1,
reload:false
},
reducers: {
@ -18,8 +19,12 @@ const localVariablesSlice = createSlice({
setProjectId: (state, action) => {
state.projectId = action.payload;
},
refreshData: ( state, action ) =>
{
state.reload = action.payload
}
},
});
export const { changeMaster ,updateRegularizationCount,setProjectId} = localVariablesSlice.actions;
export const { changeMaster ,updateRegularizationCount,setProjectId,refreshData} = localVariablesSlice.actions;
export default localVariablesSlice.reducer;