389 lines
12 KiB
JavaScript
389 lines
12 KiB
JavaScript
import React, { useEffect, useState } from "react";
|
|
import { projectSchema, projectDefault } from "./ProjectSchema";
|
|
import { useForm, Controller } from "react-hook-form";
|
|
import { zodResolver } from "@hookform/resolvers/zod";
|
|
|
|
import Label from "../common/Label";
|
|
import DatePicker from "../common/DatePicker";
|
|
import { useCreateProject, useProjectDetails, useUpdateProject } from "../../hooks/useProjects";
|
|
|
|
import {
|
|
DEFAULT_EMPTY_STATUS_ID,
|
|
ITEMS_PER_PAGE,
|
|
PROJECT_STATUS,
|
|
} from "../../utils/constants";
|
|
import {
|
|
useOrganizationModal,
|
|
useOrganizationsList,
|
|
} from "../../hooks/useOrganization";
|
|
import { localToUtc } from "../../utils/appUtils";
|
|
|
|
const currentDate = new Date().toLocaleDateString("en-CA");
|
|
const formatDate = (date) => {
|
|
if (!date) {
|
|
return currentDate;
|
|
}
|
|
const d = new Date(date);
|
|
if (isNaN(d.getTime())) {
|
|
return currentDate;
|
|
}
|
|
return d.toLocaleDateString("en-CA");
|
|
};
|
|
const ManageProjectInfo = ({ project, onClose }) => {
|
|
const [addressLength, setAddressLength] = useState(0);
|
|
const maxAddressLength = 500;
|
|
const { onOpen, startStep, flowType } = useOrganizationModal();
|
|
|
|
const ACTIVE_STATUS_ID = "b74da4c2-d07e-46f2-9919-e75e49b12731";
|
|
|
|
const { projects_Details, loading } = useProjectDetails(project);
|
|
const { data, isLoading, isError, error } = useOrganizationsList(
|
|
ITEMS_PER_PAGE,
|
|
1,
|
|
true
|
|
);
|
|
const { mutate: UpdateProject, isPending } = useUpdateProject(() => {onClose?.()});
|
|
const {mutate:CeateProject,isPending:isCreating}= useCreateProject(()=>onClose?.())
|
|
|
|
const {
|
|
register,
|
|
control,
|
|
handleSubmit,
|
|
formState: { errors },
|
|
reset,
|
|
getValues,
|
|
} = useForm({
|
|
resolver: zodResolver(projectSchema),
|
|
defaultValues: projectDefault,
|
|
mode: "onChange",
|
|
});
|
|
|
|
useEffect(() => {
|
|
if (project && projects_Details)
|
|
reset({
|
|
name: projects_Details?.name || "",
|
|
shortName: projects_Details?.shortName || "",
|
|
contactPerson: projects_Details?.contactPerson || "",
|
|
projectAddress: projects_Details?.projectAddress || "",
|
|
startDate: formatDate(projects_Details?.startDate) || "",
|
|
endDate: formatDate(projects_Details?.endDate) || "",
|
|
projectStatusId:
|
|
String(projects_Details?.projectStatus?.id) ||
|
|
DEFAULT_EMPTY_STATUS_IDF,
|
|
promoterId: projects_Details?.promoter.id || "",
|
|
pmcId: projects_Details?.pmc?.id || "",
|
|
});
|
|
setAddressLength(projects_Details?.projectAddress?.length || 0);
|
|
}, [project, projects_Details, reset,data]);
|
|
|
|
const onSubmitForm = (formData) => {
|
|
if (project) {
|
|
let payload = {
|
|
...formData,
|
|
startDate: localToUtc(formData.startDate),
|
|
endDate: localToUtc(formData.endDate),
|
|
id: project,
|
|
};
|
|
console.log(payload);
|
|
UpdateProject({ projectId: project, payload: payload });
|
|
}else{
|
|
let payload = {
|
|
...formData,
|
|
startDate: localToUtc(formData.startDate),
|
|
endDate: localToUtc(formData.endDate),
|
|
};
|
|
CeateProject(payload)
|
|
}
|
|
};
|
|
|
|
const handleCancel = () => {
|
|
reset(projectDefault);
|
|
onClose();
|
|
};
|
|
const handleOrganizaioFinder = () => {
|
|
onClose();
|
|
onOpen({ startStep: 2, flowType: "default" });
|
|
};
|
|
|
|
|
|
return (
|
|
<div className="p-sm-2 p-2">
|
|
<div className="text-center mb-2">
|
|
<h5 className="mb-2">{project ? "Edit Project" : "Create Project"}</h5>
|
|
</div>
|
|
<form
|
|
className="row g-2 text-start"
|
|
onSubmit={handleSubmit(onSubmitForm)}
|
|
>
|
|
<div className="col-12 col-md-12">
|
|
<Label htmlFor="name" required>
|
|
Project Name
|
|
</Label>
|
|
<input
|
|
type="text"
|
|
id="name"
|
|
name="name"
|
|
className="form-control form-control-sm"
|
|
placeholder="Project Name"
|
|
{...register("name")}
|
|
/>
|
|
{errors.name && (
|
|
<div
|
|
className="danger-text text-start"
|
|
style={{ fontSize: "12px" }}
|
|
>
|
|
{errors.name.message}
|
|
</div>
|
|
)}
|
|
</div>
|
|
<div className="col-12 col-md-12">
|
|
<label className="form-label" htmlFor="shortName">
|
|
Short Name
|
|
</label>
|
|
<input
|
|
type="text"
|
|
id="shortName"
|
|
name="shortName"
|
|
className="form-control form-control-sm"
|
|
placeholder="Short Name"
|
|
{...register("shortName")}
|
|
/>
|
|
{errors.shortName && (
|
|
<div
|
|
className="danger-text text-start"
|
|
style={{ fontSize: "12px" }}
|
|
>
|
|
{errors.shortName.message}
|
|
</div>
|
|
)}
|
|
</div>
|
|
<div className="col-12 col-md-12">
|
|
<Label htmlFor="contactPerson" required>
|
|
Contact Person
|
|
</Label>
|
|
<input
|
|
type="text"
|
|
id="contactPerson"
|
|
name="contactPerson"
|
|
className="form-control form-control-sm"
|
|
placeholder="Contact Person"
|
|
maxLength={50}
|
|
{...register("contactPerson")}
|
|
/>
|
|
{errors.contactPerson && (
|
|
<div
|
|
className="danger-text text-start"
|
|
style={{ fontSize: "12px" }}
|
|
>
|
|
{errors.contactPerson.message}
|
|
</div>
|
|
)}
|
|
</div>
|
|
|
|
<div className="col-12 col-md-6">
|
|
<label className="form-label" htmlFor="startDate">
|
|
Start Date
|
|
</label>
|
|
|
|
<DatePicker
|
|
name="startDate"
|
|
control={control}
|
|
placeholder="DD-MM-YYYY"
|
|
maxDate={new Date()} // optional: restrict future dates
|
|
className="w-100"
|
|
/>
|
|
|
|
{errors.startDate && (
|
|
<div
|
|
className="danger-text text-start"
|
|
style={{ fontSize: "12px" }}
|
|
>
|
|
{errors.startDate.message}
|
|
</div>
|
|
)}
|
|
</div>
|
|
|
|
<div className="col-12 col-md-6">
|
|
<label className="form-label" htmlFor="endDate">
|
|
End Date
|
|
</label>
|
|
|
|
<DatePicker
|
|
name="endDate"
|
|
control={control}
|
|
placeholder="DD-MM-YYYY"
|
|
minDate={getValues("startDate")} // optional: restrict future dates
|
|
className="w-100"
|
|
/>
|
|
|
|
{errors.endDate && (
|
|
<div
|
|
className="danger-text text-start"
|
|
style={{ fontSize: "12px" }}
|
|
>
|
|
{errors.endDate.message}
|
|
</div>
|
|
)}
|
|
</div>
|
|
|
|
<div className="col-12 ">
|
|
<label className="form-label" htmlFor="modalEditUserStatus">
|
|
Status
|
|
</label>
|
|
<select
|
|
id="modalEditUserStatus"
|
|
name="modalEditUserStatus"
|
|
className="select2 form-select form-select-sm"
|
|
aria-label="Default select example"
|
|
{...register("projectStatusId", {
|
|
required: "Status is required",
|
|
valueAsNumber: false,
|
|
})}
|
|
>
|
|
{PROJECT_STATUS.map((status) => (
|
|
<option key={status.id} value={status.id}>
|
|
{status.label}
|
|
</option>
|
|
))}
|
|
</select>
|
|
{errors.projectStatusId && (
|
|
<div
|
|
className="danger-text text-start"
|
|
style={{ fontSize: "12px" }}
|
|
>
|
|
{errors.projectStatusId.message}
|
|
</div>
|
|
)}
|
|
</div>
|
|
<div className="col-12 ">
|
|
<label className="form-label" htmlFor="modalEditUserStatus">
|
|
Promoter
|
|
</label>
|
|
<select
|
|
className="select2 form-select form-select-sm"
|
|
aria-label="Default select example"
|
|
{...register("promoterId", {
|
|
required: "Promoter is required",
|
|
valueAsNumber: false,
|
|
})}
|
|
>
|
|
{isLoading ? (
|
|
<option>Loading...</option>
|
|
) : (
|
|
<>
|
|
<option value="">Select Promoter</option>
|
|
{data?.data?.map((org) => (
|
|
<option key={org.id} value={org.id}>
|
|
{org.name}
|
|
</option>
|
|
))}
|
|
</>
|
|
)}
|
|
</select>
|
|
{errors.promoterId && (
|
|
<div
|
|
className="danger-text text-start"
|
|
style={{ fontSize: "12px" }}
|
|
>
|
|
{errors.promoterId.message}
|
|
</div>
|
|
)}
|
|
</div>
|
|
<div className="col-12 ">
|
|
<label className="form-label" htmlFor="modalEditUserStatus">
|
|
PMC
|
|
</label>
|
|
<select
|
|
className="select2 form-select form-select-sm"
|
|
aria-label="Default select example"
|
|
{...register("pmcId", {
|
|
required: "Promoter is required",
|
|
valueAsNumber: false,
|
|
})}
|
|
>
|
|
{isLoading ? (
|
|
<option>Loading...</option>
|
|
) : (
|
|
<>
|
|
<option value="">Select PMC</option>
|
|
{data?.data?.map((org) => (
|
|
<option key={org.id} value={org.id}>
|
|
{org.name}
|
|
</option>
|
|
))}
|
|
</>
|
|
)}
|
|
</select>
|
|
{errors.pmcId && (
|
|
<div
|
|
className="danger-text text-start"
|
|
style={{ fontSize: "12px" }}
|
|
>
|
|
{errors.pmcId.message}
|
|
</div>
|
|
)}
|
|
</div>
|
|
<div className="d-flex justify-content-between text-secondary text-tiny text-wrap">
|
|
<span>
|
|
<i className="bx bx-sm bx-info-circle"></i> Not found PMC and
|
|
Pomoter, find through SPRID or create new
|
|
</span>
|
|
<small className="cursor-pointer" onClick={handleOrganizaioFinder}>
|
|
<i className="bx bx-plus-circle text-primary"></i>
|
|
</small>
|
|
</div>
|
|
|
|
<div className="col-12 col-md-12">
|
|
<Label htmlFor="projectAddress" required>
|
|
Project Address
|
|
</Label>
|
|
<div className="input-group">
|
|
<textarea
|
|
id="projectAddress"
|
|
name="projectAddress"
|
|
className="form-control"
|
|
maxLength={maxAddressLength}
|
|
{...register("projectAddress")}
|
|
onChange={(e) => {
|
|
setAddressLength(e.target.value.length);
|
|
}}
|
|
/>
|
|
</div>
|
|
|
|
<div className="text-end" style={{ fontSize: "12px" }}>
|
|
{maxAddressLength - addressLength} characters left
|
|
</div>
|
|
{errors.projectAddress && (
|
|
<div
|
|
className="danger-text text-start"
|
|
style={{ fontSize: "12px" }}
|
|
>
|
|
{errors.projectAddress.message}
|
|
</div>
|
|
)}
|
|
</div>
|
|
<div className="col-12 text-end mt-4">
|
|
<button
|
|
type="button"
|
|
className="btn btn-label-secondary btn-sm me-2"
|
|
onClick={handleCancel}
|
|
aria-label="Close"
|
|
disabled={isPending || isCreating}
|
|
>
|
|
Cancel
|
|
</button>
|
|
<button
|
|
type="submit"
|
|
className="btn btn-primary btn-sm"
|
|
disabled={isPending || isCreating}
|
|
>
|
|
{isPending||isCreating ? "Please Wait..." : project ? "Update" : "Submit"}
|
|
</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default ManageProjectInfo;
|