Changes in Images gallery popup and page.
This commit is contained in:
parent
3df68dff89
commit
59b62d2f10
@ -1,4 +1,4 @@
|
||||
import React, { useRef, useState, useCallback } from "react";
|
||||
import React, { useRef, useState, useCallback, useEffect } from "react";
|
||||
import Avatar from "../../components/common/Avatar";
|
||||
import ImagePopup from "./ImagePopup";
|
||||
|
||||
@ -14,8 +14,23 @@ const ImageGalleryListView = ({
|
||||
moment,
|
||||
}) => {
|
||||
const [hoveredImage, setHoveredImage] = useState(null);
|
||||
const [scrollThreshold, setScrollThreshold] = useState(5);
|
||||
const imageGroupRefs = useRef({});
|
||||
|
||||
useEffect(() => {
|
||||
const updateThreshold = () => {
|
||||
if (window.innerWidth >= 1400) setScrollThreshold(6); // xl screens
|
||||
else if (window.innerWidth >= 992) setScrollThreshold(5); // lg
|
||||
else if (window.innerWidth >= 768) setScrollThreshold(4); // md
|
||||
else setScrollThreshold(3); // sm & xs
|
||||
};
|
||||
updateThreshold();
|
||||
window.addEventListener("resize", updateThreshold);
|
||||
return () => window.removeEventListener("resize", updateThreshold);
|
||||
}, []);
|
||||
|
||||
|
||||
|
||||
const scrollLeft = useCallback(
|
||||
(key) =>
|
||||
imageGroupRefs.current[key]?.scrollBy({ left: -200, behavior: "smooth" }),
|
||||
@ -37,11 +52,10 @@ const ImageGalleryListView = ({
|
||||
) : images.length ? (
|
||||
images.map((batch) => {
|
||||
const doc = batch.documents[0];
|
||||
const userName = `${doc.uploadedBy?.firstName || ""} ${
|
||||
doc.uploadedBy?.lastName || ""
|
||||
}`.trim();
|
||||
const userName = `${doc.uploadedBy?.firstName || ""} ${doc.uploadedBy?.lastName || ""
|
||||
}`.trim();
|
||||
const date = formatUTCToLocalTime(doc.uploadedAt);
|
||||
const hasArrows = batch.documents.length > SCROLL_THRESHOLD;
|
||||
const hasArrows = batch.documents.length > scrollThreshold;
|
||||
|
||||
return (
|
||||
<div key={batch.batchId} className="grouped-section">
|
||||
|
@ -1,90 +1,128 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
import "./ImagePopup.css"
|
||||
import { useModal } from "./ModalContext";
|
||||
import moment from "moment";
|
||||
import { formatUTCToLocalTime } from "../../utils/dateUtils";
|
||||
|
||||
const ImagePopup = ({ batch, initialIndex = 0 }) => {
|
||||
const { closeModal } = useModal();
|
||||
const [currentIndex, setCurrentIndex] = useState(initialIndex);
|
||||
|
||||
// Effect to update currentIndex if the initialIndex prop changes
|
||||
useEffect(() => {
|
||||
setCurrentIndex(initialIndex);
|
||||
}, [initialIndex, batch]);
|
||||
|
||||
// If no batch or documents are provided, don't render
|
||||
if (!batch || !batch.documents || batch.documents.length === 0) return null;
|
||||
|
||||
// Get the current image document from the batch's documents array
|
||||
const image = batch.documents[currentIndex];
|
||||
|
||||
// Fallback if for some reason the image at the current index doesn't exist
|
||||
if (!image) return null;
|
||||
|
||||
// Format details for display from the individual image document
|
||||
const fullName = `${image.uploadedBy?.firstName || ""} ${image.uploadedBy?.lastName || ""
|
||||
}`.trim();
|
||||
const date = formatUTCToLocalTime(image.uploadedAt);
|
||||
|
||||
// Location and category details from the 'batch' object (as previously corrected)
|
||||
const buildingName = batch.buildingName;
|
||||
const floorName = batch.floorName;
|
||||
const workAreaName = batch.workAreaName;
|
||||
const activityName = batch.activityName;
|
||||
const batchComment = batch.comment;
|
||||
|
||||
// Handler for navigating to the previous image
|
||||
const handlePrev = () => {
|
||||
setCurrentIndex((prevIndex) => Math.max(0, prevIndex - 1));
|
||||
};
|
||||
|
||||
// Handler for navigating to the next image
|
||||
const handleNext = () => {
|
||||
setCurrentIndex((prevIndex) =>
|
||||
Math.min(batch.documents.length - 1, prevIndex + 1)
|
||||
);
|
||||
};
|
||||
|
||||
// Determine if previous/next buttons should be enabled/visible
|
||||
const hasPrev = currentIndex > 0;
|
||||
const hasNext = currentIndex < batch.documents.length - 1;
|
||||
|
||||
return (
|
||||
<div className="image-modal-overlay">
|
||||
<div className="image-modal-content">
|
||||
<div
|
||||
className="modal fade show"
|
||||
style={{ display: "block", backgroundColor: "rgba(0,0,0,0.6)", overflow: "hidden", }}
|
||||
tabIndex="-1"
|
||||
role="dialog"
|
||||
>
|
||||
<div className="modal-dialog modal-md modal-dialog-centered" role="document">
|
||||
<div className="modal-content border-0 shadow-lg rounded-3">
|
||||
{/* Header */}
|
||||
<div className="modal-header justify-content-center py-2">
|
||||
<h5 className="modal-title">Image Preview</h5>
|
||||
<button type="button" className="btn-close" onClick={closeModal}></button>
|
||||
</div>
|
||||
|
||||
<i className='bx bx-x close-button' onClick={closeModal}></i>
|
||||
{/* Body */}
|
||||
<div className="modal-body p-2 text-center">
|
||||
<div className="position-relative d-flex justify-content-center align-items-center">
|
||||
{hasPrev && (
|
||||
<button
|
||||
className="btn btn-sm btn-outline-primary rounded-circle d-flex align-items-center justify-content-center position-absolute start-0 top-50 translate-middle-y shadow"
|
||||
style={{ marginLeft: "-50px", width: "40px", height: "40px" }}
|
||||
onClick={handlePrev}
|
||||
>
|
||||
<i className="bx bx-chevron-left fs-4"></i>
|
||||
</button>
|
||||
)}
|
||||
|
||||
{hasPrev && (
|
||||
<button className="nav-button prev-button" onClick={handlePrev}>
|
||||
<i className='bx bx-chevron-left'></i>
|
||||
</button>
|
||||
)}
|
||||
<img
|
||||
src={image.url}
|
||||
alt="Preview"
|
||||
className="img-fluid rounded"
|
||||
style={{
|
||||
maxHeight: "500px", // bigger image
|
||||
width: "100%",
|
||||
objectFit: "contain",
|
||||
}}
|
||||
/>
|
||||
|
||||
<div className="image-container">
|
||||
<img src={image.url} alt="Preview" className="modal-image" />
|
||||
</div>
|
||||
{hasNext && (
|
||||
<button
|
||||
className="btn btn-sm btn-outline-primary rounded-circle d-flex align-items-center justify-content-center position-absolute end-0 top-50 translate-middle-y shadow"
|
||||
style={{ marginRight: "-50px", width: "40px", height: "40px" }}
|
||||
onClick={handleNext}
|
||||
>
|
||||
<i className="bx bx-chevron-right fs-4"></i>
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{hasNext && (
|
||||
<button className="nav-button next-button" onClick={handleNext}>
|
||||
<i className='bx bx-chevron-right'></i>
|
||||
</button>
|
||||
)}
|
||||
{/* Details */}
|
||||
<div className="mt-3 text-start small">
|
||||
<p className="mb-1">
|
||||
<i className="bx bxs-user me-2"></i>
|
||||
<span className="text-muted">Uploaded By: </span>
|
||||
<span className="fw-semibold">{fullName}</span>
|
||||
</p>
|
||||
|
||||
<div className="image-details">
|
||||
|
||||
<div className="flex alig-items-center"> <i className='bx bxs-user'></i> <span className="text-muted">Uploaded By : </span> <span className="text-secondary">{fullName}</span></div>
|
||||
<div className="flex alig-items-center"> <i class='bx bxs-calendar' ></i> <span className="text-muted">Date : </span> <span className="text-secondary"> {date}</span></div>
|
||||
<div className="flex alig-items-center"> <i class='bx bx-map' ></i> <span className="text-muted">Uploaded By : </span> <span className="text-secondary">{buildingName} <i className='bx bx-chevron-right'></i> {floorName} <i className='bx bx-chevron-right'></i>
|
||||
{workAreaName || "Unknown"} <i className='bx bx-chevron-right'></i> {activityName}</span></div>
|
||||
<div className="flex alig-items-center"> <i className='bx bx-comment-dots'></i> <span className="text-muted">comment : </span> <span className="text-secondary">{batchComment}</span></div>
|
||||
<p className="mb-1">
|
||||
<i className="bx bxs-calendar me-2"></i>
|
||||
<span className="text-muted">Date: </span>
|
||||
<span className="fw-semibold">{date}</span>
|
||||
</p>
|
||||
|
||||
<p className="mb-1">
|
||||
<i className="bx bx-map me-2"></i>
|
||||
<span className="text-muted">Location: </span>
|
||||
<span className="fw-semibold">
|
||||
{buildingName} <i className="bx bx-chevron-right"></i> {floorName}{" "}
|
||||
<i className="bx bx-chevron-right"></i> {workAreaName || "Unknown"}{" "}
|
||||
<i className="bx bx-chevron-right"></i> {activityName}
|
||||
</span>
|
||||
</p>
|
||||
|
||||
<p className="mb-0">
|
||||
<i className="bx bx-comment-dots me-2"></i>
|
||||
<span className="text-muted">Comment: </span>
|
||||
<span className="fw-semibold">{batchComment}</span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ImagePopup;
|
||||
export default ImagePopup;
|
||||
|
@ -218,24 +218,50 @@ const ImageGalleryPage = () => {
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Filter Chips */}
|
||||
{/* Filter Chips */}
|
||||
{appliedFiltersChips.length > 0 && (
|
||||
<div className="mb-3 d-flex flex-wrap align-items-center gap-2 mb-3">
|
||||
<strong className="me-2 fs-6">Filters:</strong>
|
||||
{appliedFiltersChips.map((chip, idx) => (
|
||||
<span key={idx} className="d-flex align-items-center bg-label-secondary px-2 py-1 rounded me-1">
|
||||
{chip.label} : {chip.value}
|
||||
<button
|
||||
type="button"
|
||||
className="btn-close btn-close-white btn-sm ms-1"
|
||||
aria-label="Remove"
|
||||
onClick={() => handleRemoveFilter(chip.key, chip.id)}
|
||||
/>
|
||||
</span>
|
||||
))}
|
||||
<div className="mb-3 d-flex flex-wrap gap-2 align-items-center">
|
||||
<strong className="me-2">Filters:</strong>
|
||||
|
||||
{["Building", "Floor", "Work Area", "Activity", "Uploaded By", "Work Category"].map((label) => {
|
||||
const chips = appliedFiltersChips.filter(c => c.label === label);
|
||||
if (!chips.length) return null;
|
||||
return (
|
||||
<div key={label} className="d-flex align-items-center gap-1">
|
||||
<strong>{label}:</strong>
|
||||
{chips.map(chip => (
|
||||
<span key={chip.id} className="d-flex align-items-center bg-label-secondary px-2 py-1 rounded">
|
||||
{chip.value}
|
||||
<button
|
||||
type="button"
|
||||
className="btn-close btn-close-white btn-sm ms-1"
|
||||
onClick={() => handleRemoveFilter(chip.key, chip.id)}
|
||||
/>
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
|
||||
{/* Date Range */}
|
||||
{appliedFiltersChips.some(c => c.label === "Date Range") && (
|
||||
<div className="d-flex align-items-center bg-label-secondary px-2 py-1 rounded">
|
||||
<strong>Date Range:</strong>
|
||||
{appliedFiltersChips.filter(c => c.label === "Date Range").map((chip, idx) => (
|
||||
<span key={idx} className="d-flex align-items-center ms-1">
|
||||
{chip.value}
|
||||
<button
|
||||
type="button"
|
||||
className="btn-close btn-close-white btn-sm ms-1"
|
||||
onClick={() => handleRemoveFilter(chip.key, chip.id)}
|
||||
/>
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Gallery */}
|
||||
{isLoading ? (
|
||||
<ImageGallerySkeleton count={4} />
|
||||
|
Loading…
x
Reference in New Issue
Block a user