added popup for branch view

This commit is contained in:
pramod.mahajan 2025-11-20 14:39:54 +05:30
parent bd43475d12
commit fa923d4c3a
5 changed files with 155 additions and 135 deletions

View File

@ -6,56 +6,81 @@ import { BranchDetailsSkeleton } from "../ServiceProjectSeketon";
const BranchDetails = ({ branch }) => { const BranchDetails = ({ branch }) => {
const [copied, setCopied] = useState(false); const [copied, setCopied] = useState(false);
const { data, isLoading, isError, error } = useBranchDetails(branch); const { data, isLoading, isError, error } = useBranchDetails(branch);
if (isLoading) return <BranchDetailsSkeleton />;
if (isError) return <Error error={error} />;
let contactInfo = [];
try {
contactInfo = JSON.parse(data?.contactInformation || "[]");
} catch (e) {}
const googleMapUrl = data?.googleMapUrl || data?.locationLink; const googleMapUrl = data?.googleMapUrl || data?.locationLink;
const handleCopy = async () => { const handleCopy = async () => {
if (!googleMapUrl) return; if (!googleMapUrl) return;
await navigator.clipboard.writeText(googleMapUrl); await navigator.clipboard.writeText(googleMapUrl);
setCopied(true); setCopied(true);
setTimeout(() => setCopied(false), 2000);
setTimeout(() => setCopied(false), 3000);
}; };
if (isLoading) return <BranchDetailsSkeleton />;
if (isError)
return (
<div>
<Error error={error} />
</div>
);
return ( return (
<> <div className="w-100">
<div className="d-flex mb-2"> <div className="d-flex mb-2 align-items-center">
<span className="fs-6 fw-medium"> <i className="bx bx-buildings bx-sm me-2 text-primary"></i>
<i className="bx bx-sm me-2 bx-buildings"></i>Branch Details <span className="fw-semibold">Branch Details</span>
</span> </div>
</div>
<div className="row mb-1"> <DetailRow label="Branch Name" value={data?.branchName} />
<div className="col-4 text-secondary">Contact No:</div>
<div className="col-8">{data?.contactInformation}</div>
</div>
<div className="row mb-1"> <DetailRow label="Type" value={data?.branchType} />
<div className="col-4 text-secondary">Type:</div>
<div className="col-8">{data?.branchType}</div>
</div>
<div className="row mb-1"> <DetailRow label="Address" value={data?.address} />
<div className="col-4 text-secondary">Email:</div>
<div className="col-8">{data?.email}</div>
</div>
<div className="row mb-1"> {/* Contact persons */}
<div className="col-4 text-secondary">Address:</div> {contactInfo.map((person, index) => (
<div className="col-8">{data?.address}</div> <div key={index} className="mb-2">
</div> <div className="fw-medium text-primary">{person.contactPerson}</div>
</> <DetailRow label="Role" value={person.designation} />
<DetailRow label="Emails" value={person.contactEmails.join(", ")} />
<DetailRow label="Phone" value={person.contactNumbers.join(", ")} />
</div>
))}
{/* Map Link */}
{googleMapUrl && (
<div className="mt-2">
<a
href={googleMapUrl}
target="_blank"
rel="noopener noreferrer"
className="text-primary text-decoration-underline"
>
View on Google Maps
</a>
<button
className="btn btn-sm btn-light border ms-2"
onClick={handleCopy}
>
{copied ? "Copied!" : "Copy"}
</button>
</div>
)}
</div>
); );
}; };
const DetailRow = ({ label, value }) => (
<div className="d-flex mb-1">
<div className="text-secondary" style={{ width: "90px", flexShrink: 0 }}>
{label}:
</div>
<div className="fw-medium" style={{ wordBreak: "break-word" }}>
{value || "N/A"}
</div>
</div>
);
export default BranchDetails; export default BranchDetails;

View File

@ -26,8 +26,8 @@ const ManageBranch = ({ closeModal, BranchToEdit = null }) => {
contactPerson: "", contactPerson: "",
designation: "", designation: "",
contactEmails: [""], contactEmails: [""],
contactNumbers: [""] contactNumbers: [""],
} },
]); ]);
const { projectId } = useParams(); const { projectId } = useParams();
@ -73,7 +73,6 @@ const ManageBranch = ({ closeModal, BranchToEdit = null }) => {
} }
}, [data, reset]); }, [data, reset]);
const { mutate: CreateServiceBranch, isPending: createPending } = const { mutate: CreateServiceBranch, isPending: createPending } =
useCreateBranch(() => { useCreateBranch(() => {
handleClose(); handleClose();
@ -97,8 +96,6 @@ const ManageBranch = ({ closeModal, BranchToEdit = null }) => {
} }
}; };
return ( return (
<div className="container p-3"> <div className="container p-3">
<h5 className="m-0"> <h5 className="m-0">
@ -138,8 +135,6 @@ const ManageBranch = ({ closeModal, BranchToEdit = null }) => {
</div> </div>
<div className="row my-2 text-start"> <div className="row my-2 text-start">
<div className="col-md-6"> <div className="col-md-6">
<Label htmlFor="googleMapUrl" className="form-label"> <Label htmlFor="googleMapUrl" className="form-label">
Google Map URL Google Map URL
@ -160,17 +155,29 @@ const ManageBranch = ({ closeModal, BranchToEdit = null }) => {
<div className="row my-2 text-start"> <div className="row my-2 text-start">
<div className="col-12"> <div className="col-12">
<Label className="form-label" required>Contact Persons</Label> <Label className="form-label" required>
Contact Persons
</Label>
{contacts.map((item, index) => ( {contacts.map((item, index) => (
<div key={index} className="border rounded p-2 mb-3"> <div key={index} className="border rounded p-2 mb-3">
<div className="d-flex justify-content-end py-1">
{/* Contact Person + Designation */} {" "}
<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="row mb-2">
<div className="col-md-4"> <div className=" col-md-6">
<Label className="form-label">Contact Name</Label>
<input <input
type="text" type="text"
placeholder="Contact Person" placeholder="Contact Name"
className="form-control form-control-sm" className="form-control form-control-sm"
value={item.contactPerson} value={item.contactPerson}
onChange={(e) => { onChange={(e) => {
@ -181,7 +188,8 @@ const ManageBranch = ({ closeModal, BranchToEdit = null }) => {
/> />
</div> </div>
<div className="col-md-4"> <div className="col-md-6">
<Label className="form-label">Designation</Label>
<input <input
type="text" type="text"
placeholder="Designation" placeholder="Designation"
@ -194,24 +202,16 @@ const ManageBranch = ({ closeModal, BranchToEdit = null }) => {
}} }}
/> />
</div> </div>
{/* Remove entire contact */}
<div className="col-md-2 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>
{/* Numbers Section */} {/* Numbers Section */}
<Label className="form-label">Contact Numbers</Label> <Label className="form-label">Contact Numbers</Label>
{item.contactNumbers.map((num, numIndex) => ( {item.contactNumbers.map((num, numIndex) => (
<div key={numIndex} className="d-flex gap-2 mb-2 align-items-center"> <div
key={numIndex}
className="d-flex gap-2 mb-2 align-items-center"
>
<input <input
type="text" type="text"
placeholder="Number" placeholder="Number"
@ -246,7 +246,6 @@ const ManageBranch = ({ closeModal, BranchToEdit = null }) => {
}} }}
></i> ></i>
)} )}
</div> </div>
))} ))}
@ -256,8 +255,10 @@ const ManageBranch = ({ closeModal, BranchToEdit = null }) => {
<Label className="form-label">Contact Emails</Label> <Label className="form-label">Contact Emails</Label>
{item.contactEmails.map((email, emailIndex) => ( {item.contactEmails.map((email, emailIndex) => (
<div key={emailIndex} className="d-flex gap-2 mb-2 align-items-center"> <div
key={emailIndex}
className="d-flex gap-2 mb-2 align-items-center"
>
<input <input
type="email" type="email"
placeholder="Email" placeholder="Email"
@ -290,15 +291,11 @@ const ManageBranch = ({ closeModal, BranchToEdit = null }) => {
}} }}
></i> ></i>
)} )}
</div> </div>
))} ))}
</div> </div>
))} ))}
<button <button
type="button" type="button"
className="btn btn-sm btn-primary mt-2" className="btn btn-sm btn-primary mt-2"
@ -308,21 +305,18 @@ const ManageBranch = ({ closeModal, BranchToEdit = null }) => {
{ {
contactPerson: "", contactPerson: "",
designation: "", designation: "",
contactEmails: [""], // important contactEmails: [""], // important
contactNumbers: [""], // important contactNumbers: [""], // important
}, },
]) ])
} }
> >
<i className="bx bx-plus"></i> Add Contact <i className="bx bx-plus"></i> Add Contact
</button> </button>
</div> </div>
</div> </div>
<div className="row my-2 text-start"> <div className="row my-2 text-start">
<div className="col-12"> <div className="col-12">
<Label htmlFor="address" className="form-label" required> <Label htmlFor="address" className="form-label" required>
Address Address

View File

@ -27,7 +27,7 @@ const ServiceBranch = () => {
const { data, isLoading, isError, error } = useBranches( const { data, isLoading, isError, error } = useBranches(
projectId, projectId,
!showInactive, !showInactive,
ITEMS_PER_PAGE - 10, ITEMS_PER_PAGE - 12,
currentPage, currentPage,
debouncedSearch debouncedSearch
); );
@ -86,25 +86,24 @@ const ServiceBranch = () => {
{/* Flex container for toggle + button */} {/* Flex container for toggle + button */}
<div className="col-md-8 col-sm-12 text-end"> <div className="col-md-8 col-sm-12 text-end">
<div className="d-flex flex-column flex-md-row align-items-md-center gap-2"> <div className="d-flex justify-content-end gap-2">
<div className="form-check form-switch d-inline-flex align-items-center">
<div className="form-check form-switch d-inline-flex align-items-center"> <input
<input type="checkbox"
type="checkbox" className="form-check-input mt-1"
className="form-check-input mt-1" id="inactiveEmployeesCheckbox"
id="inactiveEmployeesCheckbox" checked={showInactive}
checked={showInactive} onChange={() => setShowInactive(!showInactive)}
onChange={() => setShowInactive(!showInactive)} />
/> <label
<label htmlFor="inactiveEmployeesCheckbox"
htmlFor="inactiveEmployeesCheckbox" className="ms-2 text-xs"
className="ms-2 mt-1" >
> Show Deleted Branches
Show Deleted Branches </label>
</label> </div>
</div> <div className="d-flex justify-content-end">
<div className="d-flex justify-content-end"> <button
<button
className="btn btn-sm btn-primary" className="btn btn-sm btn-primary"
type="button" type="button"
onClick={() => onClick={() =>
@ -117,7 +116,7 @@ const ServiceBranch = () => {
<i className="bx bx-sm bx-plus-circle me-2"></i> <i className="bx bx-sm bx-plus-circle me-2"></i>
Add Branch Add Branch
</button> </button>
</div> </div>
</div> </div>
</div> </div>
</div> </div>

View File

@ -140,8 +140,8 @@ const ManageJobTicket = ({ Job }) => {
); );
})()} })()}
</div> </div>
{/* {data?.projectBranch && ( {data?.projectBranch && (
<div className="d-flex gap-3 my-2 position-relative" ref={drawerRef} style={{ overflow: "visible" }}> <div className="d-flex gap-3 my-2 position-relative" ref={drawerRef} >
<span className="text-secondary"> <span className="text-secondary">
<i className="bx bx-buildings"></i> Branch Name: <i className="bx bx-buildings"></i> Branch Name:
</span> </span>
@ -150,7 +150,7 @@ const ManageJobTicket = ({ Job }) => {
id="BRANCH_DETAILS" id="BRANCH_DETAILS"
Mode="click" Mode="click"
align="auto" align="auto"
boundaryRef={drawerRef} // drawer has position-relative boundaryRef={drawerRef}
content={<BranchDetails branch={data?.projectBranch?.id} />} content={<BranchDetails branch={data?.projectBranch?.id} />}
> >
<span className="text-decoration-underline cursor-pointer"> <span className="text-decoration-underline cursor-pointer">
@ -158,9 +158,12 @@ const ManageJobTicket = ({ Job }) => {
</span> </span>
</HoverPopup> </HoverPopup>
</div> </div>
)} */} )}
<div className="border-top">
<div className="border-top my-1">
<p className="m-0 py-1"> <p className="m-0 py-1">
<i className="bx bx-group"></i> Peoples <i className="bx bx-group"></i> Peoples
</p> </p>

View File

@ -152,47 +152,46 @@ const HoverPopup = ({
}); });
}, [visible, align, boundaryRef]); }, [visible, align, boundaryRef]);
return ( return (
<div
className="d-inline-block position-relative" // <-- ADD THIS !!
style={{
maxWidth: "calc(700px - 100px)",
width: "100%",
wordWrap: "break-word",
overflow: "visible", // also make sure popup isn't clipped
}}
>
<div <div
className="d-inline-block " className="d-inline-block"
style={{ ref={triggerRef}
maxWidth: "calc(700px - 100px)", onMouseEnter={handleMouseEnter}
width: "100%", onMouseLeave={handleMouseLeave}
wordWrap: "break-word", onClick={handleClick}
overflow: "hidden", style={{ cursor: "pointer" }}
}}
> >
<div {children}
className="d-inline-block"
ref={triggerRef}
onMouseEnter={handleMouseEnter}
onMouseLeave={handleMouseLeave}
onClick={handleClick}
style={{ cursor: "pointer" }}
>
{children}
</div>
{visible && (
<div
ref={popupRef}
// position absolute; it should be inside a positioned parent (the drawer)
className={`hover-popup bg-white border rounded shadow-sm p-3 position-absolute mt-2 ${className}`}
style={{
zIndex: 2000,
top: "100%", // open below trigger
// left/right will be set by effect in parent coordinates
width: "max-content",
minWidth: "120px",
}}
onClick={(e) => e.stopPropagation()}
>
{title && <h6 className="fw-semibold mb-2">{title}</h6>}
<div>{content}</div>
</div>
)}
</div> </div>
);
{visible && (
<div
ref={popupRef}
className={`hover-popup bg-white border rounded shadow-sm p-3 position-absolute mt-2 ${className}`}
style={{
zIndex: 2000,
top: "100%",
width: "max-content",
minWidth: "120px",
}}
onClick={(e) => e.stopPropagation()}
>
{title && <h6 className="fw-semibold mb-2">{title}</h6>}
<div>{content}</div>
</div>
)}
</div>
);
}; };
export default HoverPopup; export default HoverPopup;