Compare commits

...

6 Commits

12 changed files with 583 additions and 206 deletions

View File

@ -13,10 +13,7 @@ export const ReportTask = ({ report, closeModal, refetch }) => {
completedTask: z
.number()
.min(1, "Completed Work must be at least 1")
.max(
report?.plannedTask,
`Completed Work cannot exceed ${report?.plannedTask}`
)
.int("Completed Work must be an integer")
.positive("Completed Work must be a positive number")
.optional(),

View File

@ -63,7 +63,7 @@ const ManageEmployee = () => {
CurrentAddress: z
.string()
.min(1, { message: "Current Address is required" })
.max(150, { message: "Address cannot exceed 150 characters" }),
.max(250, { message: "Address cannot exceed 250 characters" }),
BirthDate: z
.string()
.min(1, { message: "Birth Date is required" })
@ -112,7 +112,7 @@ const ManageEmployee = () => {
PermanentAddress: z
.string()
.min(1, { message: "Permanent Address is required" })
.max(150, { message: "Address cannot exceed 150 characters" }),
.max(250, { message: "Address cannot exceed 250 characters" }),
PhoneNumber: z
.string()
.min(1, { message: "Phone Number is required" })

View File

@ -89,8 +89,7 @@ const onSubmit = async(data) => {
};
try
{
// let response = await TasksRepository.assignTask( formattedData );
// console.log( response )
let response = await TasksRepository.assignTask( formattedData );
showToast( "Task Successfully Assigend", "success" )
reset()
closeModal()

View File

@ -2,6 +2,9 @@ import React, { useState, useEffect } from "react";
import { useForm } from "react-hook-form";
import { zodResolver } from '@hookform/resolvers/zod';
import { z } from "zod";
import {useDispatch} from "react-redux";
import {changeMaster} from "../../../slices/localVariablesSlice";
import useMaster from "../../../hooks/masterHook/useMaster";
// Define Zod validation schema
const taskSchema = z.object({
@ -23,11 +26,12 @@ const defaultModel = {
const TaskModel = ({
project,
activities,
onSubmit,
clearTrigger,
onClearComplete,onClose
}) => {
} )=>{
const dispatch = useDispatch()
const {data:activities,loading} = useMaster()
const [formData, setFormData] = useState(defaultModel);
const [selectedBuilding, setSelectedBuilding] = useState(null);
const [selectedFloor, setSelectedFloor] = useState(null);
@ -90,8 +94,6 @@ const TaskModel = ({
const onSubmitForm = ( data ) =>
{
onSubmit( data );
setSelectedActivity(null),
setSelectedWorkArea(null)
@ -104,6 +106,8 @@ const TaskModel = ({
useEffect( () =>
{
dispatch(changeMaster("Activity")),
() =>{
resetVlaue ()
}

View File

@ -82,7 +82,10 @@ const ManageProjectInfo = ( {project,handleSubmitForm, onClose} ) =>
handleSubmitForm( updatedProject )
};
useEffect( () =>
{
return ()=>setLoading(false)
},[])
return (

View File

@ -17,7 +17,6 @@ import { useProjectDetails } from "../../hooks/useProjects";
const ProjectInfra = ({
data,
activityMaster,
onDataChange,
eachSiteEngineer,
}) => {
@ -57,130 +56,6 @@ const ProjectInfra = ({
setIsBuildingModalOpen(true);
};
const submitData = async (infraObject) => {
try {
let response = await ProjectRepository.manageProjectInfra(infraObject);
const entity = response.data;
const updatedProject = { ...project };
// Handle the building data
if (entity.building) {
const { id, name, description } = entity.building;
const updatedBuildings = updatedProject?.buildings?.map((building) =>
building.id === id ? { ...building, name, description } : building
);
// Add building if it doesn't exist
if (!updatedProject.buildings.some((building) => building.id === id)) {
updatedBuildings.push({
id: id,
name,
description,
floors: [],
});
}
updatedProject.buildings = updatedBuildings;
// Update the cache for buildings
cacheData("projectInfo", {
projectId: updatedProject.id,
data: updatedProject,
});
setProject((prevProject) => ({
...prevProject,
buildings: updatedBuildings,
}));
}
// Handle the floor data
else if (entity.floor) {
const { buildingId, id, floorName } = entity.floor;
const updatedBuildings = updatedProject?.buildings?.map((building) =>
building.id == buildingId
? {
...building,
floors: building.floors
.map((floor) =>
floor.id === id
? {
...floor,
floorName, // Update the floor name only
// Keep other properties as they are (including workArea)
}
: floor
)
// Add the new floor if it doesn't already exist
.concat(
!building.floors.some((floor) => floor.id === id)
? [{ id: id, floorName, workAreas: [] }] // New floor added with workArea set to null
: []
),
}
: building
);
updatedProject.buildings = updatedBuildings;
// Cache the updated project
cacheData("projectInfo", {
projectId: updatedProject.id,
data: updatedProject,
});
setProject(updatedProject);
}
// Handle the work area data
else if (entity.workArea) {
let buildingId = infraObject[0].workArea.buildingId;
const { floorId, areaName, id } = entity.workArea;
// Check if the workArea exists, otherwise create a new one
const updatedBuildings = updatedProject.buildings.map((building) =>
building.id == buildingId
? {
...building,
floors: building.floors.map((floor) =>
floor.id == floorId
? {
...floor,
workAreas: floor.workAreas.some(
(workArea) => workArea.id === id
)
? floor.workAreas.map((workArea) =>
workArea.id === id
? { ...workArea, areaName }
: workArea
)
: [
...floor.workAreas,
{ id, areaName, workItems: [] },
],
}
: floor
),
}
: building
);
updatedProject.buildings = updatedBuildings;
// Update the cache for work areas
cacheData("projectInfo", {
projectId: updatedProject.id,
data: updatedProject,
});
setProject(updatedProject);
}
// Handle the task (workItem) data
else {
console.error("Unsupported data type for submitData", entity);
}
} catch (Err) {
console.log(Err);
showToast("Somthing wrong", "error");
}
handleClose();
};
const closeBuildingModel = () => {
setIsBuildingModalOpen(false);
};
@ -292,6 +167,139 @@ const ProjectInfra = ({
});
};
const submitData = async (infraObject) => {
try
{
debugger
let response = await ProjectRepository.manageProjectInfra(infraObject);
const entity = response.data;
const updatedProject = { ...project };
// Handle the building data
if (entity.building) {
const { id, name, description } = entity.building;
const updatedBuildings = updatedProject?.buildings?.map((building) =>
building.id === id ? { ...building, name, description } : building
);
// Add building if it doesn't exist
if (!updatedProject.buildings.some((building) => building.id === id)) {
updatedBuildings.push({
id: id,
name,
description,
floors: [],
});
}
updatedProject.buildings = updatedBuildings;
// Update the cache for buildings
cacheData("projectInfo", {
projectId: updatedProject.id,
data: updatedProject,
});
setProject((prevProject) => ({
...prevProject,
buildings: updatedBuildings,
} ) );
closeBuildingModel()
}
// Handle the floor data
else if (entity.floor) {
const { buildingId, id, floorName } = entity.floor;
const updatedBuildings = updatedProject?.buildings?.map((building) =>
building.id == buildingId
? {
...building,
floors: building.floors
.map((floor) =>
floor.id === id
? {
...floor,
floorName, // Update the floor name only
// Keep other properties as they are (including workArea)
}
: floor
)
// Add the new floor if it doesn't already exist
.concat(
!building.floors.some((floor) => floor.id === id)
? [{ id: id, floorName, workAreas: [] }] // New floor added with workArea set to null
: []
),
}
: building
);
updatedProject.buildings = updatedBuildings;
// Cache the updated project
cacheData("projectInfo", {
projectId: updatedProject.id,
data: updatedProject,
});
setProject( updatedProject );
closeFloorModel()
}
// Handle the work area data
else if ( entity.workArea )
{
let buildingId = infraObject[0].workArea.buildingId;
const { floorId, areaName, id } = entity.workArea;
// Check if the workArea exists, otherwise create a new one
const updatedBuildings = updatedProject.buildings.map((building) =>
building.id == buildingId
? {
...building,
floors: building.floors.map((floor) =>
floor.id == floorId
? {
...floor,
workAreas: floor.workAreas.some(
(workArea) => workArea.id === id
)
? floor.workAreas.map((workArea) =>
workArea.id === id
? { ...workArea, areaName }
: workArea
)
: [
...floor.workAreas,
{ id, areaName, workItems: [] },
],
}
: floor
),
}
: building
);
updatedProject.buildings = updatedBuildings;
// Update the cache for work areas
cacheData("projectInfo", {
projectId: updatedProject.id,
data: updatedProject,
});
setProject( updatedProject );
closeWorkAreaModel()
}
// Handle the task (workItem) data
else {
console.error("Unsupported data type for submitData", entity);
}
} catch (Err) {
console.log(Err);
showToast("Somthing wrong", "error");
}
handleClose();
};
const toggleBuilding = (id) => {
setExpandedBuildings((prev) =>
prev.includes(id) ? prev.filter((bid) => bid !== id) : [...prev, id]
@ -400,7 +408,7 @@ const ProjectInfra = ({
>
<TaskModel
project={project}
activities={activityMaster}
onClose={closeTaskModel}
onSubmit={handleTaskModelFormSubmit}
clearTrigger={clearFormTrigger}
@ -463,6 +471,7 @@ const ProjectInfra = ({
<InfraTable
buildings={project?.buildings}
project={project}
handleFloor={submitData}
/>
)}
</div>

View File

@ -0,0 +1,205 @@
import React,{useState,useEffect} from 'react'
import {useFieldArray, useForm } from 'react-hook-form';
import { z } from 'zod';
import {zodResolver} from '@hookform/resolvers/zod';
import { MasterRespository } from '../../repositories/MastersRepository';
import { clearApiCacheKey } from '../../slices/apiCacheSlice';
import { getCachedData,cacheData } from '../../slices/apiDataManager';
import showToast from '../../services/toastService';
const schema = z.object({
activityName: z.string().min(1, { message: "Role is required" }),
unitOfMeasurement: z.string().min(1, { message: "Description is required" }),
checkList: z
.array(z.string().min(1, { message: "Checklist item cannot be empty" }))
.optional(),
});
const CreateActivity = () =>
{
const [ isLoading, setIsLoading ] = useState( false )
// const {
// register,
// handleSubmit,
// formState: { errors },reset
// } = useForm({
// resolver: zodResolver(schema),
// defaultValues: {
// activityName: "",
// unitOfMeasurement: "",
// checkList: ['']
// },
// });
// const onSubmit = (data) => {
// setIsLoading(true)
// const result = {
// name: data.activityName,
// description: data.unitOfMeasurement,
// };
// console.log( result )
// reset()
// 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 resetForm =()=>{
// reset({
// activityName:"",
// unitOfMeasurement:""
// })
// }
// useEffect(()=>{
// return ()=>resetForm()
// }, [] )
const {
register,
handleSubmit,
control,
setValue,
clearErrors,
setError,
getValues,
reset,
formState: { errors },
} = useForm({
resolver: zodResolver(schema),
defaultValues: {
activityName: '',
unitOfMeasurement: '',
checkList: [],
},
});
// Setting up field array for checkList (dynamic fields)
const {
fields: checkListItems,
append,
remove,
} = useFieldArray({
control,
name: 'checkList',
});
// Form submission handler
const onSubmit = (data) => {
console.log('Submitted:', data);
};
// Add a new checklist item
const addChecklistItem = () => {
const values = getValues('checkList');
const lastIndex = checkListItems.length - 1;
if (checkListItems.length > 0 && (!values?.[lastIndex] || values[lastIndex].trim() === '')) {
setError(`checkList.${lastIndex}`, {
type: 'manual',
message: 'Please fill this checklist item before adding another.',
});
return;
}
clearErrors(`checkList.${lastIndex}`); // Clear the error if the input is filled.
append(''); // Add a new empty checklist input
};
const removeChecklistItem = (index) => {
remove(index);
};
// Handle checklist item input change
const handleChecklistChange = (index, value) => {
setValue(`checkList.${index}`, value);
};
return (
<form onSubmit={handleSubmit(onSubmit)}>
<div className="row">
<div className="col-6">
<label className="form-label">Activity</label>
<input
type="text"
{...register('activityName')}
className={`form-control form-control-sm ${errors.activityName ? 'is-invalid' : ''}`}
/>
{errors.activityName && <p className="danger-text">{errors.activityName.message}</p>}
</div>
<div className="col-6">
<label className="form-label">Measurement</label>
<input
type="text"
{...register('unitOfMeasurement')}
className={`form-control form-control-sm ${errors.unitOfMeasurement ? 'is-invalid' : ''}`}
/>
{errors.unitOfMeasurement && (
<p className="danger-text">{errors.unitOfMeasurement.message}</p>
)}
</div>
<div className="col-md-6 text-start">
{/* Dynamic checklist items */}
{checkListItems.map((item, index) => (
<div key={item.id} className=" align-items-center my-1">
<div className='d-flex align-items-center gap-2'>
<input
{...register(`checkList.${index}`)}
className="form-control form-control-sm"
placeholder={`Checklist item ${index + 1}`}
onChange={(e) => handleChecklistChange(index, e.target.value)} // Handle input change
/>
<button
type="button"
onClick={() => removeChecklistItem(index)} // Remove button
className="btn btn-xs btn-icon btn-text-secondary"
>
<span class='icon-base bx bx bx-x'></span>
</button>
</div>
{errors.checkList?.[index] && (
<p className="danger-text">{errors.checkList[index]?.message}</p>
)}
</div>
))}
{/* Add new checklist item */}
<button type="button" className="btn btn-sm btn-primary mt-2" onClick={addChecklistItem}>
+ Add Checklist Item
</button>
</div>
<div className="col-12 text-center mt-3">
<button type="submit" className="btn btn-sm btn-primary me-3">
Submit
</button>
<button
type="reset"
className="btn btn-sm btn-label-secondary"
onClick={() => reset()}
>
Cancel
</button>
</div>
</div>
</form>
)
}
export default CreateActivity

View File

@ -0,0 +1,175 @@
import React, { useState, useEffect } from 'react';
import { useFieldArray, useForm } from 'react-hook-form';
import { z } from 'zod';
import { zodResolver } from '@hookform/resolvers/zod';
// Zod Schema for validation
const schema = z.object({
activityName: z.string().min(1, { message: "Activity name is required" }),
unitOfMeasurement: z.string().min(1, { message: "Measurement is required" }),
checkList: z
.array(z.string().min(1, { message: "Checklist item cannot be empty" }))
.optional(),
} );
// for demo data
let initialData = {
activityName: "Item",
unitOfMeasurement: "Item-2",
checkList: [
'item 3',
'Item 4'
]
}
const EditActivity = ({onClose}) => {
const [isLoading, setIsLoading] = useState(false);
const {
register,
handleSubmit,
control,
setValue,
clearErrors,
setError,
getValues,
reset,
formState: { errors },
} = useForm({
resolver: zodResolver(schema),
defaultValues: {
activityName: '',
unitOfMeasurement: '',
checkList: [],
},
});
// Setting up field array for checkList (dynamic fields)
const {
fields: checkListItems,
append,
remove,
} = useFieldArray({
control,
name: 'checkList',
});
// Pre-populating the form with initial data when component mounts or initialData changes
useEffect(() => {
if (initialData) {
reset({
activityName: initialData.activityName,
unitOfMeasurement: initialData.unitOfMeasurement,
checkList: initialData.checkList || [],
});
}
}, [initialData, reset]);
// Form submission handler
const onSubmit = (data) => {
console.log('Submitted:', data);
};
// Add a new checklist item
const addChecklistItem = () => {
const values = getValues('checkList');
const lastIndex = checkListItems.length - 1;
// Prevent adding new input if the last one is empty
if (checkListItems.length > 0 && (!values?.[lastIndex] || values[lastIndex].trim() === '')) {
setError(`checkList.${lastIndex}`, {
type: 'manual',
message: 'Please fill this checklist item before adding another.',
});
return;
}
clearErrors(`checkList.${lastIndex}`); // Clear the error if the input is filled.
append(''); // Add a new empty checklist input
};
// Remove a checklist item
const removeChecklistItem = (index) => {
remove(index); // Remove the checklist item from the field array
};
// Handle checklist item input change
const handleChecklistChange = (index, value) => {
setValue(`checkList.${index}`, value); // Update the value of the checklist item
};
const handleCLose = () =>
{
() => reset()
onClose()
}
return (
<form onSubmit={handleSubmit(onSubmit)}>
<div className="row">
<div className="col-6">
<label className="form-label">Activity</label>
<input
type="text"
{...register('activityName')}
className={`form-control form-control-sm ${errors.activityName ? 'is-invalid' : ''}`}
/>
{errors.activityName && <p className="danger-text">{errors.activityName.message}</p>}
</div>
<div className="col-6">
<label className="form-label">Measurement</label>
<input
type="text"
{...register('unitOfMeasurement')}
className={`form-control form-control-sm ${errors.unitOfMeasurement ? 'is-invalid' : ''}`}
/>
{errors.unitOfMeasurement && (
<p className="danger-text">{errors.unitOfMeasurement.message}</p>
)}
</div>
<div className="col-md-6 text-start">
{/* Dynamic checklist items */}
{checkListItems.map((item, index) => (
<div key={item.id} className="d-flex align-items-center gap-2 my-1">
<input
{...register(`checkList.${index}`)}
className="form-control form-control-sm"
placeholder={`Checklist item ${index + 1}`}
onChange={(e) => handleChecklistChange(index, e.target.value)} // Handle input change
/>
<button
type="button"
onClick={() => removeChecklistItem(index)} // Remove button
className="btn btn-xs btn-icon btn-text-secondary"
>
<span className="icon-base bx bx-x"/>
</button>
{errors.checkList?.[index] && (
<p className="danger-text">{errors.checkList[index]?.message}</p>
)}
</div>
))}
{/* Add new checklist item */}
<button type="button" className="btn btn-sm btn-primary mt-2" onClick={addChecklistItem}>
+ Add Checklist Item
</button>
</div>
<div className="col-12 text-center mt-3">
<button type="submit" className="btn btn-sm btn-primary me-3">
Submit
</button>
<button
type="reset"
className="btn btn-sm btn-label-secondary"
onClick={handleCLose}
>
Cancel
</button>
</div>
</div>
</form>
);
};
export default EditActivity;

View File

@ -5,53 +5,62 @@ import DeleteMaster from "./DeleteMaster";
import EditRole from "./EditRole";
import CreateJobRole from "./CreateJobRole";
import EditJobRole from "./EditJobRole";
import CreateActivity from "./CreateActivity";
import EditActivity from "./EditActivity";
const MasterModal = ({ modaldata ,closeModal}) => {
const MasterModal = ({ modaldata, closeModal }) => {
return (
<div
className="modal fade"
id="master-modal"
tabIndex="-1"
aria-hidden="true"
role="dialog"
<div
className="modal fade"
id="master-modal"
tabIndex="-1"
aria-hidden="true"
role="dialog"
aria-labelledby="modalToggleLabel"
>
<div
className={`modal-dialog mx-sm-auto mx-1 ${
modaldata?.modalType === "delete" ? "modal-md" : "modal-lg"
} modal-simple ` }
>
<div className="modal-content">
<div className="modal-body p-sm-4 p-0">
<button
type="button"
className="btn-close"
data-bs-dismiss="modal"
aria-label="Close"
onClick={closeModal}
></button>
<div className="text-center mb-2"></div>
{modaldata?.modalType === "Role" &&
<CreateRole masmodalType={modaldata.masterType} onClose={closeModal} />}
{modaldata?.modalType === "Edit-Role" && (
<EditRole master={modaldata} onClose={closeModal} />
)}
{modaldata?.modalType === "delete" && (
<DeleteMaster master={modaldata} onClose={closeModal}/>
)}
{modaldata?.modalType === "Job Role" && (
<CreateJobRole onClose={closeModal} />
)}
{modaldata?.modalType === "Edit-Job Role" && (
<EditJobRole data ={modaldata.item} onClose={closeModal} />
)}
<div
className={`modal-dialog mx-sm-auto mx-1 ${
modaldata?.modalType === "delete" || `Ativity` ? "modal-md" : "modal-lg"
} modal-simple `}
>
<div className="modal-content">
<div className="modal-body p-sm-4 p-0">
<button
type="button"
className="btn-close"
data-bs-dismiss="modal"
aria-label="Close"
onClick={closeModal}
></button>
<div className="text-center mb-2"></div>
{modaldata?.modalType === "Role" && (
<CreateRole
masmodalType={modaldata.masterType}
onClose={closeModal}
/>
)}
{modaldata?.modalType === "Edit-Role" && (
<EditRole master={modaldata} onClose={closeModal} />
)}
{modaldata?.modalType === "delete" && (
<DeleteMaster master={modaldata} onClose={closeModal} />
)}
{modaldata?.modalType === "Job Role" && (
<CreateJobRole onClose={closeModal} />
)}
{modaldata?.modalType === "Edit-Job Role" && (
<EditJobRole data={modaldata.item} onClose={closeModal} />
)}
{modaldata?.modalType === "Activity" && (
<CreateActivity onClose={closeModal} /> )
}
{modaldata?.modalType === 'Edit-Activity' && (
<EditActivity onClose={closeModal} />
)}
</div>
</div>
</div>
</div>
</div>
);
};

View File

@ -53,10 +53,8 @@ const MasterPage = () => {
};
const {data:masterData, loading,error , RecallApi} = useMaster();
const handleSearch = (e) => {
const value = e.target.value.toLowerCase();

View File

@ -27,29 +27,10 @@ const ProjectDetails = () => {
const dispatch = useDispatch()
const [project, setProject] = useState(null);
const [ projectDetails, setProjectDetails ] = useState( null );
const [activities, setActivities] = useState(null);
const [loading, setLoading] = useState(true);
const [ error, setError ] = useState( "" );
const fetchActivities = async () => {
const activities_cache = getCachedData("activitiesMaster");
if (!activities_cache) {
ActivityeRepository.getActivities()
.then((response) => {
setActivities(response.data);
cacheData("activitiesMaster", response.data);
})
.catch((error) => {
setError("Failed to fetch data.");
});
} else {
setActivities(activities_cache);
}
};
const fetchData = async () => {
@ -124,7 +105,6 @@ const ProjectDetails = () => {
return (
<ProjectInfra
data={projectDetails}
activityMaster={activities}
onDataChange={handleDataChange}
></ProjectInfra>
);
@ -134,7 +114,6 @@ const ProjectDetails = () => {
return (
<WorkPlan
data={projectDetails}
activityMaster={activities}
onDataChange={handleDataChange}
></WorkPlan>
);
@ -156,15 +135,12 @@ const ProjectDetails = () => {
};
useEffect(() => {
// fetchData();
dispatch(setProjectId(projectId))
setProject( projects_Details )
setProjectDetails(projects_Details)
fetchActivities();
}, [projects_Details,projectId]);
return (
<>
{}
<div className="container-xxl flex-grow-1 container-p-y">

View File

@ -29,7 +29,9 @@ export const MasterRespository = {
getJobRole :()=>api.get("/api/roles/jobrole"),
updateJobRole: ( id, data ) => api.put( `/api/roles/jobrole/${ id }`, data ),
getActivites: () => api.get( 'api/task/activities' ),
getActivites: () => api.get( 'api/master/activities' ),
createActivities: () => api.post( 'api/master/activity' ),
updateActivity:(id) =>api.post(`api/master/edit/${id}`),
}