integrated create Task api and handling data caching updated for task.

This commit is contained in:
Pramod Mahajan 2025-04-07 17:14:07 +05:30
parent 10d6f96ea7
commit 93c95e007a
6 changed files with 375 additions and 284 deletions

View File

@ -37,9 +37,14 @@ const BuildingModel = ({
} else if (editingBuilding) {
setFormData({ ...editingBuilding, projectId: project.id });
}
return () =>
{
setValue("name",null)
}
}, [clearTrigger, onClearComplete, editingBuilding, project.id]);
const { register, handleSubmit, formState: { errors }, setValue } = useForm({
const { register, handleSubmit, formState: { errors }, setValue,reset,getValues} = useForm({
resolver: zodResolver(buildingSchema),
defaultValues: formData, // Set default values from formData state
});
@ -59,7 +64,11 @@ const BuildingModel = ({
const onSubmitHandler = async( data ) =>
{
onSubmit({ ...data, projectId: project.id });
onSubmit( {...data, projectId: project.id} );
reset( {
name: null,
description:null
})
};
return (
@ -116,7 +125,7 @@ const BuildingModel = ({
<div className="col-12 text-center">
<button type="submit" className="btn btn-primary me-3">
{formData.id ? "Edit Building" : "Add Building"}
{ ( formData.id && getValues("name")) ? "Edit Building" : "Add Building"}
</button>
<button type="reset" className="btn btn-label-secondary" data-bs-dismiss="modal" aria-label="Close" onClick={onClose}>
Cancel

View File

@ -1,9 +1,22 @@
import React, { useState, useEffect } from "react";
import { useForm } from "react-hook-form";
import { zodResolver } from '@hookform/resolvers/zod';
import { z } from "zod";
// Define Zod validation schema
const taskSchema = z.object({
buildingID: z.string().min(1, "Building is required"),
floorId: z.string().min(1, "Floor is required"),
workAreaId: z.number().min(1, "Work Area is required"),
activityID: z.number().min(1, "Activity is required"),
plannedWork: z.number().min(1, "Planned Work must be greater than 0"),
completedWork: z.number().optional(),
});
const defaultModel = {
id: "0",
workAreaId: 0,
activityId: 0,
activityID: 0,
plannedWork: 0,
completedWork: 0,
};
@ -14,46 +27,27 @@ const TaskModel = ({
onSubmit,
clearTrigger,
onClearComplete,
} ) =>
{
}) => {
const [formData, setFormData] = useState(defaultModel);
const [selectedBuilding, setSelectedBuilding] = useState(null);
const [selectedFloor, setSelectedFloor] = useState(null);
const [selectedWorkArea, setSelectedWorkArea] = useState(null);
const [selectedActivity, setSelectedActivity] = useState(null);
//if (floor && floor.id) setFormData(floor);
useEffect(() => {
if (selectedBuilding) {
let building = project.buildings.find(
(b) => b.id === selectedBuilding.id
);
setSelectedBuilding(building);
}
if (selectedFloor) {
let floor = selectedBuilding.floors.find(
(b) => b.id === Number(selectedFloor.id)
);
setSelectedFloor(floor);
}
if (selectedWorkArea) {
formData.workAreaId = selectedWorkArea.id;
}
}, [project]);
const { register, handleSubmit, formState: { errors },reset } = useForm({
resolver: zodResolver(taskSchema),
defaultValues: formData,
});
useEffect(() => {
if (clearTrigger) {
let model = defaultModel;
model.floorId = selectedFloor.id;
setFormData(defaultModel);
setFormData(defaultModel);
onClearComplete();
}
}, [clearTrigger, onClearComplete]);
// Handle input change
// Handle input changes
const handleChange = (e) => {
const { name, value } = e.target;
const activity = activities.find((b) => b.id === Number(value));
@ -64,29 +58,15 @@ const TaskModel = ({
const { value } = e.target;
const activity = activities.find((b) => b.id === Number(value));
setFormData({ ...formData, ["activityId"]: value });
setFormData({ ...formData, ["activityID"]: value });
setSelectedActivity(activity);
};
const handleWorkAreaChange = (e) => {
const { value } = e.target;
const workArea = selectedFloor.workAreas.find(
(b) => b.id === Number(value)
);
const workArea = selectedFloor.workAreas.find((b) => b.id === Number(value));
setSelectedWorkArea(workArea);
setSelectedActivity(null);
setFormData({ ...formData, ["workAreaId"]: value });
// if (workArea) {
// setFormData({
// id: workArea.id,
// floorId: workArea.floorId,
// areaName: workArea.areaName,
// });
// } else
// setFormData({
// id: "0",
// floorId: selectedFloor.id,
// areaName: "",
// });
};
const handleFloorChange = (e) => {
@ -97,7 +77,8 @@ const TaskModel = ({
setSelectedActivity(null);
setFormData(defaultModel);
};
const handleBuildigChange = (e) => {
const handleBuildingChange = (e) => {
const { value } = e.target;
const building = project.buildings.find((b) => b.id === Number(value));
setSelectedBuilding(building);
@ -107,14 +88,37 @@ const TaskModel = ({
setFormData(defaultModel);
};
// Handle form submission
const handleSubmit = (e) => {
e.preventDefault();
// onSubmit( formData ); // Pass the updated data to the parent
console.log(formData)
const onSubmitForm = ( data ) =>
{
onSubmit( data );
setSelectedActivity(null),
selectedWorkArea(null)
reset( {
plannedWork: 0,
completedWork:0
})
};
useEffect( () =>
{
() =>{
resetVlaue ()
}
},[])
const resetVlaue = () =>
{
setSelectedBuilding( null )
setSelectedFloor( null )
setSelectedWorkArea( null )
setSelectedActivity(null)
reset( {
plannedWork: 0,
completedWork:0
})
}
return (
<div className="modal-dialog modal-lg modal-simple modal-edit-user">
<div className="modal-content">
@ -129,18 +133,19 @@ const TaskModel = ({
<div className="text-center mb-1">
<h5 className="mb-1">Manage Task</h5>
</div>
<form className="row g-2" onSubmit={handleSubmit}>
<form className="row g-2" onSubmit={handleSubmit(onSubmitForm)}>
{/* Select Building */}
<div className="col-6 col-md-6">
<label className="form-label" htmlFor="name">
Select Building
</label>
<select
id="buildingId"
name="buildingId"
id="buildingID"
name="buildingID"
className="select2 form-select form-select-sm"
aria-label="Default select example"
onChange={handleBuildigChange}
value={formData.buildingId}
{...register("buildingID")}
onChange={(e) => handleBuildingChange(e)}
>
<option value="0">Select Building</option>
{project.buildings.map((building) => (
@ -149,9 +154,11 @@ const TaskModel = ({
</option>
))}
</select>
{errors.buildingID && <p className="danger-text">{errors.buildingID.message}</p>}
</div>
{selectedBuilding && selectedBuilding.id != "0" && (
{/* Select Floor */}
{selectedBuilding && selectedBuilding.id !== "0" && (
<div className="col-6 col-md-6">
<label className="form-label" htmlFor="floorId">
Select Floor
@ -161,19 +168,21 @@ const TaskModel = ({
name="floorId"
className="select2 form-select form-select-sm"
aria-label="Default select example"
onChange={handleFloorChange}
value={formData.floorId}
{...register("floorId")}
onChange={(e) => handleFloorChange(e)}
>
<option value="0">Select Floor</option>
{selectedBuilding.floors.map((floor) => (
<option key={floor.id} value={floor.id}>
{floor.floorName} - ({floor.workAreas.length} Work
Areas)
{floor.floorName} - ({floor.workAreas.length} Work Areas)
</option>
))}
</select>
{errors.floorId && <p className="danger-text">{errors.floorId.message}</p>}
</div>
)}
{/* Select Work Area */}
{selectedFloor && (
<div className="col-12 col-md-12">
<label className="form-label" htmlFor="workAreaId">
@ -184,8 +193,8 @@ const TaskModel = ({
name="workAreaId"
className="select2 form-select form-select-sm"
aria-label="Default select example"
onChange={handleWorkAreaChange}
value={formData.workAreaId}
{...register("workAreaId",{valueAsNumber:true})}
onChange={(e) => handleWorkAreaChange(e)}
>
<option value="0">Select Work Area</option>
{selectedFloor.workAreas.map((workArea) => (
@ -194,20 +203,23 @@ const TaskModel = ({
</option>
))}
</select>
{errors.workAreaId && <p className="danger-text">{errors.workAreaId.message}</p>}
</div>
)}
{/* Select Activity */}
{selectedWorkArea && (
<div className="col-12 col-md-12">
<label className="form-label" htmlFor="activityId">
<label className="form-label" htmlFor="activityID">
Select Activity
</label>
<select
id="activityId"
name="activityId"
id="activityID"
name="activityID"
className="select2 form-select form-select-sm"
aria-label="Default select example"
onChange={handleActivityChange}
value={formData.activityId}
{...register("activityID",{valueAsNumber:true})}
onChange={(e) => handleActivityChange(e)}
>
<option value="0">Select Activity</option>
{activities.map((activity) => (
@ -216,75 +228,67 @@ const TaskModel = ({
</option>
))}
</select>
</div>
)}
{selectedActivity && (
<div className="col-5 col-md-5">
{" "}
<label className="form-label" htmlFor="plannedWork">
{formData.id != "0" ? "Modify " : "Enter "} Planned Work
</label>
<div className="input-group">
<input
type="text"
id="plannedWork"
name="plannedWork"
className="form-control form-control-sm me-2"
placeholder="Task"
onChange={handleChange}
value={formData.plannedWork}
/>
</div>
</div>
)}
{selectedActivity && (
<div className="col-5 col-md-5">
{" "}
<label className="form-label" htmlFor="completedWork">
{formData.id != "0" ? "Modify " : "Enter "} Completed Work
</label>
<div className="input-group">
<input
type="text"
id="completedWork"
name="completedWork"
className="form-control form-control-sm me-2"
placeholder="Completed Work"
onChange={handleChange}
value={formData.completedWork}
/>
</div>
{errors.activityID && <p className="danger-text">{errors.activityID.message}</p>}
</div>
)}
{/* Planned Work */}
{selectedActivity && (
<div className="col-5 col-md-5">
<label className="form-label" htmlFor="plannedWork">
{formData.id !== "0" ? "Modify " : "Enter "} Planned Work
</label>
<input
{...register("plannedWork", { valueAsNumber: true })}
type="number"
id="plannedWork"
name="plannedWork"
className="form-control form-control-sm me-2"
placeholder="Planned Work"
/>
{errors.plannedWork && <p className="danger-text">{errors.plannedWork.message}</p>}
</div>
)}
{/* Completed Work */}
{selectedActivity && (
<div className="col-5 col-md-5">
<label className="form-label" htmlFor="completedWork">
{formData.id !== "0" ? "Modify " : "Enter "} Completed Work
</label>
<input
{...register("completedWork", { valueAsNumber: true })}
type="number"
id="completedWork"
name="completedWork"
className="form-control form-control-sm me-2"
placeholder="Completed Work"
/>
{errors.completedWork && <p className="danger-text">{errors.completedWork.message}</p>}
</div>
)}
{/* Unit */}
{selectedActivity && (
<div className="col-2 col-md-2">
{" "}
<label className="form-label" htmlFor="unit">
Unit
</label>
<div className="input-group">
<input
type="text"
id="unit"
disabled
name="unit"
className="form-control form-control-sm me-2"
placeholder="Unit"
onChange={handleChange}
value={selectedActivity.unitOfMeasurement}
/>
</div>
<input
type="text"
disabled
id="unit"
name="unit"
className="form-control form-control-sm me-2"
value={selectedActivity?.unitOfMeasurement || ""}
/>
</div>
)}
<div className="col-12 text-center">
{selectedActivity && (
<button type="submit" className="btn btn-primary me-3">
{formData.id != "0" && formData.id != ""
? "Edit Task"
: "Add Task"}
</button>
)}
<button type="submit" className="btn btn-primary me-3">
{formData.id !== "0" && formData.id !== "" ? "Edit Task" : "Add Task"}
</button>
<button
type="reset"
className="btn btn-label-secondary"
@ -293,6 +297,7 @@ const TaskModel = ({
>
Cancel
</button>
</div>
</form>
</div>

View File

@ -1,46 +1,62 @@
import React from "react";
import React,{useEffect} from "react";
import WorkItem from "./WorkItem";
const WorkArea = ({ workArea, floor,forBuilding }) => {
return (
<React.Fragment key={workArea.id}>
<tr>
<td colSpan="4" className="text-start table-cell">
<div className="row ps-2">
<div className="col-6">
<h6>
<span>
{floor.floorName} - {workArea.areaName} &nbsp;
</span>
</h6>
</div>
const WorkArea = ( {workArea, floor, forBuilding} ) =>
{
useEffect(() => {
}, [workArea]);
return (
<React.Fragment key={workArea.id}>
<tr>
<td colSpan="4" className="text-start table-cell">
<div className="row ps-2">
<div className="col-6">
<h6>
<span>
{floor.floorName} - {workArea.areaName} &nbsp;
</span>
</h6>
</div>
</div>
</td>
</tr>
{workArea?.workItems && workArea.workItems.length > 0 ? (
<tr className="overflow-auto">
<td colSpan={4}>
<table className="table mx-1">
<thead>
<tr>
<th>Activity</th>
{/* for mobile view */}
<th className="d-sm-none d-sm-table-cell">Status</th>
{/* for greather than mobile view ************* */}
<th className="d-none d-md-table-cell">Planned</th>
<th className="d-none d-md-table-cell">Completed</th>
{/* ************************** */}
<th>Progress</th>
<th>Actions</th>
</tr>
</thead>
<tbody className="table-border-bottom-0">
{workArea?.workItems && workArea.workItems.length > 0 ? (
workArea.workItems.map((workItem) => (
<WorkItem key={workItem.workItemId} workItem={workItem} />
))
) : (
<tr>
<td colSpan="4" className="text-center">
No Data
</td>
</tr>
)}
</tbody>
</table>
</td>
</tr>
{workArea?.workItems && workArea.workItems.length > 0 ? (
<tr className="overflow-auto">
<td colSpan={4}>
<table className="table mx-1">
<thead>
<tr>
<th>Activity</th>
<th>Planned</th>
<th>Completed</th>
<th>Progress</th>
<th>Actions</th>
</tr>
</thead>
<tbody className="table-border-bottom-0">
{workArea.workItems.map((workItem) => (
<WorkItem key={workItem.workItemId} workItem={workItem} forBuilding={forBuilding} forFloor={floor} forWorkArea={workArea} />
))}
</tbody>
</table>
</td>
</tr>
) : null}
</React.Fragment>
);
};
export default WorkArea;
) : null}
</React.Fragment>
);
};
export default WorkArea;

View File

@ -1,15 +1,15 @@
import React, { useState } from "react";
import React, { useState,useEffect } from "react";
import { useModal } from "../../../ModalContext";
import AssignRoleModel from "../AssignRole";
import {useParams} from "react-router-dom";
import { useParams } from "react-router-dom";
import GlobalModel from "../../common/GlobalModel";
const WorkItem = ( {workItem, forBuilding, forFloor, forWorkArea} ) =>{
const {projectId} = useParams()
const [ itemName, setItemName ] = useState( '' );
const WorkItem = ({ workItem, forBuilding, forFloor, forWorkArea }) => {
const { projectId } = useParams();
const [ itemName, setItemName ] = useState( "" );
const [NewWorkItem,setNewWorkItem] = useState()
const [isModalOpen, setIsModalOpen] = useState(false);
const openModal = () => setIsModalOpen(true);
const closeModal = () => setIsModalOpen(false);
const getProgress = (planned, completed) => {
@ -17,8 +17,8 @@ const WorkItem = ( {workItem, forBuilding, forFloor, forWorkArea} ) =>{
};
const handleAssignTask = () => {
console.log("Item Created:", itemName);
setItemName('');
setItemName("");
};
// const showCreateItemModal = (modalData) => {
@ -27,79 +27,131 @@ const WorkItem = ( {workItem, forBuilding, forFloor, forWorkArea} ) =>{
// handleAssignTask ,"lg"
// );
// };
useEffect(() => {
setNewWorkItem(workItem)
}, [workItem]); // This hook will run whenever the workItem prop changes
let assigndata = {
building: forBuilding,
floor: forFloor,
workArea: forWorkArea,
workItem
}
workItem,
};
const hasWorkItem = NewWorkItem && NewWorkItem
return (
<>
<GlobalModel isOpen={isModalOpen}
closeModal={closeModal} dialogClass="modal-dialog-centered" role="document" size="lg" >
<AssignRoleModel assignData={assigndata} onClose={closeModal} />
<GlobalModel
isOpen={isModalOpen}
closeModal={closeModal}
dialogClass="modal-dialog-centered"
role="document"
size="lg"
>
<AssignRoleModel assignData={assigndata} onClose={closeModal} />
</GlobalModel>
<tr>
<td className="text-start table-cell-small">
<i className="bx bx-right-arrow-alt"></i>
<span className="fw-medium">
{workItem.workItem.activityMaster
? workItem.workItem.activityMaster.activityName
: "NA"}
</span>
</td>
<td className="text-center">
{workItem.workItem ? workItem.workItem.plannedWork : "NA"}
</td>
<td className="text-center">
{workItem.workItem ? workItem.workItem.completedWork : "NA"}
</td>
<td className="text-center" style={{ width: "15%" }}>
<div className="progress p-0">
<div
className="progress-bar"
role="progressbar"
style={{
width: getProgress(workItem.workItem.plannedWork, workItem.workItem.completedWork),
height: "10px",
}}
aria-valuenow={workItem.workItem ? workItem.workItem.completedWork : 0}
aria-valuemin="0"
aria-valuemax={workItem.workItem ? workItem.workItem.plannedWork : 0}
></div>
</div>
</td>
<td>
<div className="dropdown">
{!projectId && ( <button
aria-label="Modify"
type="button"
className="btn p-0"
data-bs-toggle="modal"
data-bs-target="#project-modal"
onClick={openModal}
>
<span className="badge bg-label-primary me-1">Assign</span>
</button>)}
<button
aria-label="Modify"
type="button"
className="btn p-0 dropdown-toggle hide-arrow"
>
<i className="bx bxs-edit me-2 text-primary"></i>
</button>
<button
aria-label="Delete"
type="button"
className="btn p-0 dropdown-toggle hide-arrow"
>
<i className="bx bx-trash me-1 text-danger"></i>
</button>
</div>
</td>
<tr>
<td className="text-start table-cell-small">
<i className="bx bx-right-arrow-alt"></i>
<span className="fw-medium">
{hasWorkItem ? ( NewWorkItem?.workItem?.activityMaster?.activityName || workItem.activityMaster?.activityName ) :"NA"
}
</span>
</td>
{/* for mobile view */}
<td className="text-center d-sm-none d-sm-table-cell">
{hasWorkItem ? (NewWorkItem?.workItem?.completedWork || workItem?.completedWork) :"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"}
</td>
<td className="text-center d-none d-md-table-cell">
{hasWorkItem ? (NewWorkItem?.workItem?.completedWork || workItem?.completedWork) : "NA"}
</td>
{/* ************************************************ */}
<td className="text-center" style={{ width: "15%" }}>
<div className="progress p-0">
<div
className="progress-bar"
role="progressbar"
style={{
width: getProgress(
(NewWorkItem?.workItem?.plannedWork || workItem?.plannedWork),
(NewWorkItem?.workItem?.completedWork || workItem?.completedWork)
),
height: "10px",
}}
aria-valuenow={
hasWorkItem ? (NewWorkItem?.workItem?.completedWork || workItem?.completedWork) : 0
}
aria-valuemin="0"
aria-valuemax={
hasWorkItem ? (NewWorkItem?.workItem?.plannedWork || workItem?.plannedWork) : 0
}
></div>
</div>
</td>
{/* for greather than mobile view */}
<td className="d-none d-md-table-cell">
<div className="dropdown">
{!projectId && (
<button
aria-label="Modify"
type="button"
className="btn p-0"
data-bs-toggle="modal"
data-bs-target="#project-modal"
onClick={openModal}
>
<span className="badge bg-label-primary me-1">Assign</span>
</button>
)}
<button
aria-label="Modify"
type="button"
className="btn p-0 dropdown-toggle hide-arrow"
>
<i className="bx bxs-edit me-2 text-primary"></i>
</button>
<button
aria-label="Delete"
type="button"
className="btn p-0 dropdown-toggle hide-arrow"
>
<i className="bx bx-trash me-1 text-danger"></i>
</button>
</div>
</td>
{/* for mobile view */}
<td className="text-end d-sm-none d-sm-table-cell">
<div className="d-flex align-items-center justify-content-center ">
<a
className={`btn btn-icon dropdown-toggle hide-arrow`}
data-bs-toggle="dropdown"
>
<i className="bx bx-dots-vertical-rounded bx-md"></i>
</a>
<div className="dropdown-menu dropdown-menu-end m-0">
{" "}
<a className="dropdown-item">
{" "}
<i className="bx bxs-edit me-2 text-primary"></i>Edit
</a>
<a className="dropdown-item">
{" "}
<i className="bx bx-trash me-1 text-danger"></i>Delete
</a>
</div>
</div>
</td>
</tr>
</>
</>
);
};

View File

@ -64,7 +64,7 @@ const ProjectInfra = ({ data, activityMaster, onDataChange,eachSiteEngineer }) =
const submitData = async (infraObject) => {
try
{
console.log(infraObject)
@ -134,7 +134,7 @@ const ProjectInfra = ({ data, activityMaster, onDataChange,eachSiteEngineer }) =
// Handle the work area data
else if ( entity.workArea )
{
debugger
let buildingId = infraObject[0].workArea.buildingId
@ -172,38 +172,6 @@ const ProjectInfra = ({ data, activityMaster, onDataChange,eachSiteEngineer }) =
setProject(updatedProject)
}
// Handle the task (workItem) data
else if (entity.workItem) {
const { buildingId, floorId, workAreaId, name, description } = entity.workItem;
const updatedBuildings = updatedProject.buildings.map((building) =>
building.id === buildingId
? {
...building,
floors: building.floors.map((floor) =>
floor.id === floorId
? {
...floor,
workAreas: floor.workAreas.map((workArea) =>
workArea.id === workAreaId
? {
...workArea,
tasks: workArea.tasks.map((task) =>
task.id === entity.workItem.id ? { ...task, name, description } : task
),
}
: workArea
),
}
: floor
),
}
: building
);
updatedProject.buildings = updatedBuildings;
cacheData("projectInfo", { projectId: updatedProject.id, data: updatedProject });
}
else {
console.error("Unsupported data type for submitData", entity);
@ -277,15 +245,56 @@ const ProjectInfra = ({ data, activityMaster, onDataChange,eachSiteEngineer }) =
};
const handleTaskModelFormSubmit = (updatedModel) => {
const handleTaskModelFormSubmit = ( updatedModel ) =>
{
if (updatedModel.id == "") updatedModel.id = 0;
const updatedProject = { ...project };
ProjectRepository.manageProjectTasks([updatedModel])
.then((response) => {
onDataChange("task-change");
showToast("Details updated successfully.", "success");
setClearFormTrigger(true);
// setClearFormTrigger( true );
if (response?.data[0]) {
const { workItemId,workItem} = response.data[0];
const updatedBuildings = updatedProject.buildings.map((building) =>
building.id == updatedModel.buildingID
? {
...building,
floors: building.floors.map((floor) =>
floor.id == updatedModel.floorId
? {
...floor,
workAreas: floor.workAreas.map((workArea) =>
workArea.id === workItem?.workAreaId
? {
...workArea,
workItems: workArea.workItems.some((existingItem) => existingItem.workItemId === workItem.workItemId)
? workArea.workItems // If the workItemId already exists, keep the current workItems
: [...workArea.workItems, workItem],
}
: workArea
),
}
: floor
),
}
: building
);
updatedProject.buildings = updatedBuildings;
cacheData( "projectInfo", {projectId: updatedProject.id, data: updatedProject} );
setProject(updatedProject)
}
})
.catch((error) => {
showToast(error.message, "error");
@ -456,7 +465,7 @@ const ProjectInfra = ({ data, activityMaster, onDataChange,eachSiteEngineer }) =
onClick={() => openTaskModel()}
>
<i className="bx bx-plus-circle me-2"></i>
Manage Tasks
Create Tasks
</button>
</div>
</div>

View File

@ -16,7 +16,7 @@ const ProjectRepository = {
manageProjectAllocation: ( data ) => api.post( "/api/project/allocation", data ),
manageProjectInfra: (data) => api.post("/api/project/manage-infra", data),
manageProjectTasks: (data) => api.post("/api/project/manage-infra", data),
manageProjectTasks: (data) => api.post("/api/project/task", data),
updateProject: (id, data) => api.put(`/api/project/update/${id}`, data),
deleteProject: (id) => api.delete(`/projects/${id}`),