Adding Card inside Image Gallery.

This commit is contained in:
Kartik Sharma 2025-09-20 14:52:32 +05:30
parent eaccf0fca2
commit 32bcaf2602

View File

@ -22,14 +22,12 @@ const ImageGalleryPage = () => {
const { openModal } = useModal(); const { openModal } = useModal();
const { setOffcanvasContent, setShowTrigger } = useFab(); const { setOffcanvasContent, setShowTrigger } = useFab();
// Auto-select first project if none selected
useEffect(() => { useEffect(() => {
if (!selectedProjectId && projectNames?.length) { if (!selectedProjectId && projectNames?.length) {
dispatch(setProjectId(projectNames[0].id)); dispatch(setProjectId(projectNames[0].id));
} }
}, [selectedProjectId, projectNames, dispatch]); }, [selectedProjectId, projectNames, dispatch]);
// --- Filters state ---
const [appliedFilters, setAppliedFilters] = useState({ const [appliedFilters, setAppliedFilters] = useState({
buildingIds: [], buildingIds: [],
floorIds: [], floorIds: [],
@ -41,18 +39,11 @@ const ImageGalleryPage = () => {
endDate: null, endDate: null,
}); });
const { const { data, fetchNextPage, hasNextPage, isLoading, isFetchingNextPage, refetch } =
data, useImageGallery(selectedProjectId, appliedFilters);
fetchNextPage,
hasNextPage,
isLoading,
isFetchingNextPage,
refetch,
} = useImageGallery(selectedProjectId, appliedFilters);
const images = data?.pages.flatMap((page) => page.data) || []; const images = data?.pages.flatMap((page) => page.data) || [];
// --- Utility: store mappings independent of images ---
const [labelMaps, setLabelMaps] = useState({ const [labelMaps, setLabelMaps] = useState({
buildings: new Map(), buildings: new Map(),
floors: new Map(), floors: new Map(),
@ -92,31 +83,21 @@ const ImageGalleryPage = () => {
}); });
}, [images]); }, [images]);
// --- Apply filters ---
const handleApplyFilters = useCallback((values) => setAppliedFilters(values), []); const handleApplyFilters = useCallback((values) => setAppliedFilters(values), []);
// --- Remove single filter ---
const handleRemoveFilter = (filterKey, valueId) => { const handleRemoveFilter = (filterKey, valueId) => {
setAppliedFilters((prev) => { setAppliedFilters((prev) => {
const updated = { ...prev }; const updated = { ...prev };
if (Array.isArray(updated[filterKey])) { if (Array.isArray(updated[filterKey])) {
updated[filterKey] = updated[filterKey].filter((id) => id !== valueId); updated[filterKey] = updated[filterKey].filter((id) => id !== valueId);
} } else if (filterKey === "startDate" || filterKey === "endDate" || filterKey === "dateRange") {
else if (filterKey === "startDate" || filterKey === "endDate") {
updated[filterKey] = null;
}
else if (filterKey === "dateRange") {
updated.startDate = null; updated.startDate = null;
updated.endDate = null; updated.endDate = null;
} }
return updated; return updated;
}); });
}; };
// --- Chips ---
const appliedFiltersChips = useMemo(() => { const appliedFiltersChips = useMemo(() => {
const chips = []; const chips = [];
const { buildings, floors, activities, workAreas, workCategories, uploadedByUsers } = labelMaps; const { buildings, floors, activities, workAreas, workCategories, uploadedByUsers } = labelMaps;
@ -139,6 +120,7 @@ const ImageGalleryPage = () => {
appliedFilters.workCategoryIds?.forEach((id) => appliedFilters.workCategoryIds?.forEach((id) =>
chips.push({ label: "Work Category", value: workCategories.get(id) || id, key: "workCategoryIds", id }) chips.push({ label: "Work Category", value: workCategories.get(id) || id, key: "workCategoryIds", id })
); );
if (appliedFilters.startDate || appliedFilters.endDate) { if (appliedFilters.startDate || appliedFilters.endDate) {
const start = appliedFilters.startDate ? moment(appliedFilters.startDate).format("DD MMM, YYYY") : ""; const start = appliedFilters.startDate ? moment(appliedFilters.startDate).format("DD MMM, YYYY") : "";
const end = appliedFilters.endDate ? moment(appliedFilters.endDate).format("DD MMM, YYYY") : ""; const end = appliedFilters.endDate ? moment(appliedFilters.endDate).format("DD MMM, YYYY") : "";
@ -147,10 +129,8 @@ const ImageGalleryPage = () => {
return chips; return chips;
}, [appliedFilters, labelMaps]); }, [appliedFilters, labelMaps]);
// --- Refetch on filter change ---
useEffect(() => { refetch(); }, [appliedFilters, refetch]); useEffect(() => { refetch(); }, [appliedFilters, refetch]);
// --- Filter Panel ---
const filterPanelElement = useMemo( const filterPanelElement = useMemo(
() => ( () => (
<ImageGalleryFilters <ImageGalleryFilters
@ -168,7 +148,6 @@ const ImageGalleryPage = () => {
[labelMaps, appliedFilters, handleApplyFilters] [labelMaps, appliedFilters, handleApplyFilters]
); );
// --- Fab Offcanvas ---
useEffect(() => { useEffect(() => {
setShowTrigger(true); setShowTrigger(true);
setOffcanvasContent("Gallery Filters", filterPanelElement); setOffcanvasContent("Gallery Filters", filterPanelElement);
@ -178,14 +157,12 @@ const ImageGalleryPage = () => {
}; };
}, [filterPanelElement, setOffcanvasContent, setShowTrigger]); }, [filterPanelElement, setOffcanvasContent, setShowTrigger]);
// --- EventBus ---
useEffect(() => { useEffect(() => {
const handler = (data) => { if (data.projectId === selectedProjectId) refetch(); }; const handler = (data) => { if (data.projectId === selectedProjectId) refetch(); };
eventBus.on("image_gallery", handler); eventBus.on("image_gallery", handler);
return () => eventBus.off("image_gallery", handler); return () => eventBus.off("image_gallery", handler);
}, [selectedProjectId, refetch]); }, [selectedProjectId, refetch]);
// --- Infinite scroll ---
useEffect(() => { useEffect(() => {
if (!loaderRef.current) return; if (!loaderRef.current) return;
const observer = new IntersectionObserver( const observer = new IntersectionObserver(
@ -199,77 +176,49 @@ const ImageGalleryPage = () => {
}, [hasNextPage, isFetchingNextPage, isLoading, fetchNextPage]); }, [hasNextPage, isFetchingNextPage, isLoading, fetchNextPage]);
return ( return (
<div className="gallery-container container-fluid"> <div className="container my-3">
<Breadcrumb data={[{ label: "Home", link: "/" }, { label: "Gallery" }]} /> <Breadcrumb data={[{ label: "Home", link: "/" }, { label: "Gallery" }]} />
{appliedFiltersChips.length > 0 && ( {/* Card wrapper */}
<div className="mb-3 text-start d-flex flex-wrap align-items-center gap-2"> <div className="card shadow-sm">
<strong className="me-2 fs-6 ms-1">Filters:</strong> <div className="card-body">
{/* Group chips by label */} {/* Filter Chips */}
{["Building", "Floor", "Work Area", "Activity", "Uploaded By", "Work Category"].map((label) => { {appliedFiltersChips.length > 0 && (
const chipsForLabel = appliedFiltersChips.filter((chip) => chip.label === label); <div className="mb-3 d-flex flex-wrap align-items-center gap-2">
if (chipsForLabel.length === 0) return null; <strong className="me-2 fs-6">Filters:</strong>
{appliedFiltersChips.map((chip, idx) => (
return ( <span key={idx} className="d-flex align-items-center bg-label-secondary px-2 py-1 rounded me-1">
<span key={label} className="d-flex align-items-center px-2 py-1 rounded" style={{ background: "transparent" }}> {chip.label} : {chip.value}
<strong className="me-1">{label} :</strong> <button
{chipsForLabel.map((chip, idx) => ( type="button"
<span className="btn-close btn-close-white btn-sm ms-1"
key={chip.id} aria-label="Remove"
className="d-flex align-items-center bg-label-secondary px-2 py-1 rounded me-1" onClick={() => handleRemoveFilter(chip.key, chip.id)}
> />
{chip.value} </span>
<button ))}
type="button" </div>
className="btn-close btn-close-white btn-sm ms-1"
aria-label="Remove"
onClick={() => handleRemoveFilter(chip.key, chip.id)}
/>
</span>
))}
</span>
);
})}
{/* Date Range */}
{appliedFiltersChips.some((chip) => chip.label === "Date Range") && (
<span className="d-flex align-items-center px-2 py-1 rounded bg-label-secondary">
<strong className="me-1">Date Range :</strong>
{appliedFiltersChips
.filter((chip) => chip.label === "Date Range")
.map((chip, idx) => (
<span key={idx} className="d-flex align-items-center me-1">
{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>
))}
</span>
)} )}
{/* Gallery */}
{isLoading ? (
<ImageGallerySkeleton count={4} />
) : (
<ImageGalleryListView
images={images}
isLoading={isLoading}
isFetchingNextPage={isFetchingNextPage}
hasNextPage={hasNextPage}
loaderRef={loaderRef}
openModal={openModal}
formatUTCToLocalTime={formatUTCToLocalTime}
moment={moment}
/>
)}
</div> </div>
)} </div>
{isLoading ? (
<ImageGallerySkeleton count={4} />
) : (
<ImageGalleryListView
images={images}
isLoading={isLoading}
isFetchingNextPage={isFetchingNextPage}
hasNextPage={hasNextPage}
loaderRef={loaderRef}
openModal={openModal}
formatUTCToLocalTime={formatUTCToLocalTime}
moment={moment}
/>
)}
</div> </div>
); );
}; };