339 lines
10 KiB
JavaScript
339 lines
10 KiB
JavaScript
import React, { useEffect, useState } from "react";
|
|
import { useForm, Controller } from "react-hook-form";
|
|
import { zodResolver } from "@hookform/resolvers/zod";
|
|
import { z } from "zod";
|
|
import Label from "../common/Label";
|
|
|
|
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, handleSubmitForm, onClose, isPending }) => {
|
|
const [CurrentProject, setCurrentProject] = useState();
|
|
const [addressLength, setAddressLength] = useState(0);
|
|
const maxAddressLength = 500;
|
|
|
|
const ACTIVE_STATUS_ID = "b74da4c2-d07e-46f2-9919-e75e49b12731";
|
|
const DEFAULT_EMPTY_STATUS_ID = "00000000-0000-0000-0000-000000000000";
|
|
|
|
const projectSchema = z
|
|
.object({
|
|
...(project?.id ? { id: z.string().optional() } : {}),
|
|
name: z.string().min(1, { message: "Project Name is required" }),
|
|
shortName: z.string().optional(),
|
|
contactPerson: z
|
|
.string()
|
|
.min(1, { message: "Contact Person Name is required" })
|
|
.regex(/^[A-Za-z\s]+$/, {
|
|
message: "Contact Person must contain only letters",
|
|
}),
|
|
projectAddress: z
|
|
.string()
|
|
.min(1, { message: "Address is required" })
|
|
.max(500, "Address must not exceed 150 characters"),
|
|
startDate: z
|
|
.string()
|
|
.min(1, { message: "Start Date is required" })
|
|
.default(currentDate),
|
|
endDate: z
|
|
.string()
|
|
.min(1, { message: "End Date is required" })
|
|
.default(currentDate),
|
|
projectStatusId: z
|
|
.string()
|
|
.min(1, { message: "Status is required" })
|
|
})
|
|
.refine(
|
|
(data) => {
|
|
const start = new Date(data.startDate);
|
|
const end = new Date(data.endDate);
|
|
return end >= start;
|
|
},
|
|
{
|
|
path: ["endDate"], // attaches the error to the endDate field
|
|
message: "End Date must be greater than Start Date",
|
|
}
|
|
);
|
|
|
|
const {
|
|
register,
|
|
control,
|
|
handleSubmit,
|
|
formState: { errors },
|
|
reset,
|
|
getValues,
|
|
} = useForm({
|
|
resolver: zodResolver(projectSchema),
|
|
defaultValues: {
|
|
id: project?.id || "",
|
|
name: project?.name || "",
|
|
shortName: project?.shortName || "",
|
|
contactPerson: project?.contactPerson || "",
|
|
projectAddress: project?.projectAddress || "",
|
|
startDate: formatDate(project?.startDate) || currentDate,
|
|
endDate: formatDate(project?.endDate) || currentDate,
|
|
// projectStatusId: String(project?.projectStatusId || "00000000-0000-0000-0000-000000000000"),
|
|
projectStatusId: project?.projectStatusId && project.projectStatusId !== DEFAULT_EMPTY_STATUS_ID
|
|
|
|
? String(project.projectStatusId)
|
|
|
|
: ACTIVE_STATUS_ID,
|
|
},
|
|
mode: "onChange",
|
|
});
|
|
|
|
useEffect(() => {
|
|
setCurrentProject(project);
|
|
reset(
|
|
project
|
|
? {
|
|
id: project?.id || "",
|
|
name: project?.name || "",
|
|
shortName: project?.shortName || "",
|
|
contactPerson: project?.contactPerson || "",
|
|
projectAddress: project?.projectAddress || "",
|
|
startDate: formatDate(project?.startDate) || "",
|
|
endDate: formatDate(project?.endDate) || "",
|
|
projectStatusId: String(project?.projectStatus?.id) || "00000000-0000-0000-0000-000000000000",
|
|
}
|
|
: {}
|
|
);
|
|
setAddressLength(project?.projectAddress?.length || 0);
|
|
}, [project, reset]);
|
|
|
|
/**
|
|
|
|
* Handles the form submission.
|
|
|
|
* @param {object} updatedProject - The project data from the form.
|
|
|
|
*/
|
|
|
|
const onSubmitForm = (updatedProject) => {
|
|
|
|
handleSubmitForm(updatedProject);
|
|
};
|
|
|
|
const handleCancel = () => {
|
|
reset({
|
|
id: project?.id || "",
|
|
name: project?.name || "",
|
|
shortName: project?.shortName || "",
|
|
contactPerson: project?.contactPerson || "",
|
|
projectAddress: project?.projectAddress || "",
|
|
startDate: formatDate(project?.startDate) || currentDate,
|
|
endDate: formatDate(project?.endDate) || currentDate,
|
|
projectStatusId: String(project?.projectStatus?.id || "00000000-0000-0000-0000-000000000000"),
|
|
});
|
|
onClose();
|
|
};
|
|
|
|
return (
|
|
|
|
<div className="p-sm-2 p-2">
|
|
|
|
<div className="text-center mb-2">
|
|
<h5 className="mb-2">
|
|
{project?.id ? "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>
|
|
<input
|
|
className="form-control form-control-sm"
|
|
type="date"
|
|
name="startDate"
|
|
{...register("startDate")}
|
|
id="startDate"
|
|
/>
|
|
{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>
|
|
<input
|
|
className="form-control form-control-sm"
|
|
type="date"
|
|
name="endDate"
|
|
{...register("endDate")}
|
|
id="endDate"
|
|
/>
|
|
{errors.endDate && (
|
|
<div
|
|
className="danger-text text-start"
|
|
style={{ fontSize: "12px" }}
|
|
>
|
|
{errors.endDate.message}
|
|
</div>
|
|
)}
|
|
</div>
|
|
<div className="col-12 col-md-6">
|
|
<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,
|
|
})}
|
|
>
|
|
{/* <option disabled>Status</option>
|
|
<option value="b74da4c2-d07e-46f2-9919-e75e49b12731">Active</option> */}
|
|
<option value={ACTIVE_STATUS_ID}>Active</option>
|
|
<option value="603e994b-a27f-4e5d-a251-f3d69b0498ba">On Hold</option>
|
|
|
|
<option value="cdad86aa-8a56-4ff4-b633-9c629057dfef">In Progress</option>
|
|
<option value="ef1c356e-0fe0-42df-a5d3-8daee355492d">Inactive</option>
|
|
|
|
<option value="33deaef9-9af1-4f2a-b443-681ea0d04f81">Completed</option>
|
|
</select>
|
|
{errors.projectStatusId && (
|
|
<div
|
|
className="danger-text text-start"
|
|
style={{ fontSize: "12px" }}
|
|
>
|
|
{errors.projectStatusId.message}
|
|
</div>
|
|
)}
|
|
</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}
|
|
>
|
|
Cancel
|
|
</button>
|
|
<button
|
|
type="submit"
|
|
className="btn btn-primary btn-sm"
|
|
disabled={isPending}
|
|
>
|
|
{isPending ? "Please Wait..." : project?.id ? "Update" : "Submit"}
|
|
</button>
|
|
</div>
|
|
|
|
</form>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default ManageProjectInfo; |