359 lines
12 KiB
JavaScript
359 lines
12 KiB
JavaScript
import React, { useEffect } from "react";
|
|
import { useProjectName } from "../../../hooks/useProjects";
|
|
import { useForm } from "react-hook-form";
|
|
import { zodResolver } from "@hookform/resolvers/zod";
|
|
import Label from "../../common/Label";
|
|
import {
|
|
useBranchDetails,
|
|
useBranchTypes,
|
|
useCreateBranch,
|
|
useServiceProjects,
|
|
useUpdateBranch,
|
|
} from "../../../hooks/useServiceProject";
|
|
import { useAppForm } from "../../../hooks/appHooks/useAppForm";
|
|
import { useParams } from "react-router-dom";
|
|
import { BranchSchema, defaultBranches } from "../ServiceProjectSchema";
|
|
import InputSuggessionField from "../../common/Forms/InputSuggesstionField";
|
|
import InputSuggestions from "../../common/InputSuggestion";
|
|
|
|
const ManageBranch = ({ closeModal, BranchToEdit = null }) => {
|
|
const {
|
|
data,
|
|
isLoading,
|
|
isError,
|
|
error: requestError,
|
|
} = useBranchDetails(BranchToEdit);
|
|
const { data: branchTypes } = useBranchTypes();
|
|
const [contacts, setContacts] = React.useState([
|
|
{
|
|
contactPerson: "",
|
|
designation: "",
|
|
contactEmails: [""],
|
|
contactNumbers: [""],
|
|
},
|
|
]);
|
|
|
|
const { projectId } = useParams();
|
|
const schema = BranchSchema();
|
|
const {
|
|
register,
|
|
control,
|
|
watch,
|
|
handleSubmit,
|
|
setValue,
|
|
reset,
|
|
formState: { errors },
|
|
} = useAppForm({
|
|
resolver: zodResolver(schema),
|
|
defaultValues: {
|
|
...defaultBranches,
|
|
projectId: projectId || "",
|
|
},
|
|
});
|
|
|
|
const handleClose = () => {
|
|
reset();
|
|
closeModal();
|
|
};
|
|
|
|
useEffect(() => {
|
|
if (BranchToEdit && data) {
|
|
reset({
|
|
branchName: data.branchName || "",
|
|
projectId: data.project?.id || projectId || "",
|
|
address: data.address || "",
|
|
branchType: data.branchType || "",
|
|
googleMapUrl: data.googleMapUrl || "",
|
|
});
|
|
|
|
if (data.contactInformation) {
|
|
try {
|
|
setContacts(JSON.parse(data.contactInformation));
|
|
} catch {
|
|
setContacts([]);
|
|
}
|
|
}
|
|
}
|
|
}, [data, reset]);
|
|
|
|
const { mutate: CreateServiceBranch, isPending: createPending } =
|
|
useCreateBranch(() => {
|
|
handleClose();
|
|
});
|
|
const { mutate: ServiceBranchUpdate, isPending } = useUpdateBranch(() =>
|
|
handleClose()
|
|
);
|
|
|
|
const onSubmit = (formdata) => {
|
|
let payload = {
|
|
...data,
|
|
...formdata,
|
|
projectId,
|
|
contactInformation: JSON.stringify(contacts), // ← important
|
|
};
|
|
|
|
if (BranchToEdit) {
|
|
ServiceBranchUpdate({ id: data.id, payload });
|
|
} else {
|
|
CreateServiceBranch(payload);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<div className="container p-3">
|
|
<h5 className="m-0">
|
|
{BranchToEdit ? "Update Branch" : "Create Branch"}
|
|
</h5>
|
|
<form onSubmit={handleSubmit(onSubmit)}>
|
|
<div className="row my-2 text-start">
|
|
<div className="col-md-6">
|
|
<Label htmlFor="branchName" className="form-label" required>
|
|
Branch Name
|
|
</Label>
|
|
<input
|
|
type="text"
|
|
id="branchName"
|
|
className="form-control form-control-sm"
|
|
{...register("branchName")}
|
|
placeholder="Enter Branch"
|
|
/>
|
|
{errors.branchName && (
|
|
<small className="danger-text">{errors.branchName.message}</small>
|
|
)}
|
|
</div>
|
|
<div className="col-md-6">
|
|
<Label htmlFor="branchType" className="form-label" required>
|
|
Branch Type
|
|
</Label>
|
|
|
|
<InputSuggestions
|
|
organizationList={branchTypes}
|
|
value={watch("branchType") || ""}
|
|
onChange={(val) =>
|
|
setValue("branchType", val, { shouldValidate: true })
|
|
}
|
|
error={errors.branchType?.message}
|
|
/>
|
|
|
|
|
|
</div>
|
|
</div>
|
|
|
|
<div className="row my-2 text-start">
|
|
<div className="col-md-6">
|
|
<Label htmlFor="googleMapUrl" className="form-label">
|
|
Google Map URL
|
|
</Label>
|
|
<input
|
|
type="text"
|
|
id="googleMapUrl"
|
|
className="form-control form-control-sm"
|
|
{...register("googleMapUrl")}
|
|
/>
|
|
{errors.googleMapUrl && (
|
|
<small className="danger-text">
|
|
{errors.googleMapUrl.message}
|
|
</small>
|
|
)}
|
|
</div>
|
|
</div>
|
|
|
|
<div className="row my-2 text-start">
|
|
<div className="col-12">
|
|
<Label className="form-label" required>
|
|
Contact Persons
|
|
</Label>
|
|
|
|
{contacts.map((item, index) => (
|
|
<div key={index} className="border rounded p-2 mb-3">
|
|
<div className="d-flex justify-content-end py-1">
|
|
{" "}
|
|
<div className="col-md-1 d-flex align-items-center">
|
|
<i
|
|
className="bx bx-trash text-danger cursor-pointer"
|
|
onClick={() =>
|
|
setContacts(contacts.filter((_, i) => i !== index))
|
|
}
|
|
></i>
|
|
</div>
|
|
</div>
|
|
<div className="row mb-2">
|
|
<div className=" col-md-6">
|
|
<Label className="form-label">Contact Name</Label>
|
|
<input
|
|
type="text"
|
|
placeholder="Contact Name"
|
|
className="form-control form-control-sm"
|
|
value={item.contactPerson}
|
|
onChange={(e) => {
|
|
const list = [...contacts];
|
|
list[index].contactPerson = e.target.value;
|
|
setContacts(list);
|
|
}}
|
|
/>
|
|
</div>
|
|
|
|
<div className="col-md-6">
|
|
<Label className="form-label">Designation</Label>
|
|
<input
|
|
type="text"
|
|
placeholder="Designation"
|
|
className="form-control form-control-sm"
|
|
value={item.designation}
|
|
onChange={(e) => {
|
|
const list = [...contacts];
|
|
list[index].designation = e.target.value;
|
|
setContacts(list);
|
|
}}
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Numbers Section */}
|
|
<Label className="form-label">Contact Numbers</Label>
|
|
|
|
{item.contactNumbers.map((num, numIndex) => (
|
|
<div
|
|
key={numIndex}
|
|
className="d-flex gap-2 mb-2 align-items-center"
|
|
>
|
|
<input
|
|
type="text"
|
|
placeholder="Number"
|
|
className="form-control form-control-sm"
|
|
maxLength={10}
|
|
value={num}
|
|
onChange={(e) => {
|
|
const value = e.target.value.replace(/\D/g, ""); // remove non-digit characters
|
|
const list = [...contacts];
|
|
list[index].contactNumbers[numIndex] = value;
|
|
setContacts(list);
|
|
}}
|
|
/>
|
|
|
|
{/* Show PLUS only on last row */}
|
|
{numIndex === item.contactNumbers.length - 1 ? (
|
|
<i
|
|
className="bx bx-plus-circle text-primary cursor-pointer fs-5"
|
|
onClick={() => {
|
|
const list = [...contacts];
|
|
list[index].contactNumbers.push("");
|
|
setContacts(list);
|
|
}}
|
|
></i>
|
|
) : (
|
|
<i
|
|
className="bx bx-minus-circle text-danger cursor-pointer fs-5"
|
|
onClick={() => {
|
|
const list = [...contacts];
|
|
list[index].contactNumbers.splice(numIndex, 1);
|
|
setContacts(list);
|
|
}}
|
|
></i>
|
|
)}
|
|
</div>
|
|
))}
|
|
|
|
<hr />
|
|
|
|
{/* Emails Section */}
|
|
<Label className="form-label">Contact Emails</Label>
|
|
|
|
{item.contactEmails.map((email, emailIndex) => (
|
|
<div
|
|
key={emailIndex}
|
|
className="d-flex gap-2 mb-2 align-items-center"
|
|
>
|
|
<input
|
|
type="email"
|
|
placeholder="Email"
|
|
className="form-control form-control-sm"
|
|
value={email}
|
|
onChange={(e) => {
|
|
const list = [...contacts];
|
|
list[index].contactEmails[emailIndex] = e.target.value;
|
|
setContacts(list);
|
|
}}
|
|
/>
|
|
|
|
{/* Show PLUS only on the last row */}
|
|
{emailIndex === item.contactEmails.length - 1 ? (
|
|
<i
|
|
className="bx bx-plus-circle text-primary cursor-pointer fs-5"
|
|
onClick={() => {
|
|
const list = [...contacts];
|
|
list[index].contactEmails.push("");
|
|
setContacts(list);
|
|
}}
|
|
></i>
|
|
) : (
|
|
<i
|
|
className="bx bx-minus-circle text-danger cursor-pointer fs-5"
|
|
onClick={() => {
|
|
const list = [...contacts];
|
|
list[index].contactEmails.splice(emailIndex, 1);
|
|
setContacts(list);
|
|
}}
|
|
></i>
|
|
)}
|
|
</div>
|
|
))}
|
|
</div>
|
|
))}
|
|
|
|
<button
|
|
type="button"
|
|
className="btn btn-sm btn-primary mt-2"
|
|
onClick={() =>
|
|
setContacts([
|
|
...contacts,
|
|
{
|
|
contactPerson: "",
|
|
designation: "",
|
|
contactEmails: [""], // ← important
|
|
contactNumbers: [""], // ← important
|
|
},
|
|
])
|
|
}
|
|
>
|
|
<i className="bx bx-plus"></i> Add Contact
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="row my-2 text-start">
|
|
<div className="col-12">
|
|
<Label htmlFor="address" className="form-label" required>
|
|
Address
|
|
</Label>
|
|
<textarea
|
|
id="address"
|
|
className="form-control form-control-sm"
|
|
{...register("address")}
|
|
/>
|
|
{errors.address && (
|
|
<small className="danger-text">{errors.address.message}</small>
|
|
)}
|
|
</div>
|
|
</div>
|
|
|
|
<div className="d-flex justify-content-end gap-3">
|
|
<button
|
|
type="reset"
|
|
onClick={handleClose}
|
|
className="btn btn-label-secondary btn-sm mt-3"
|
|
>
|
|
Cancel
|
|
</button>
|
|
|
|
<button type="submit" className="btn btn-primary btn-sm mt-3">
|
|
{isPending ? "Please wait..." : "Submit"}
|
|
</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default ManageBranch;
|