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,27 +176,20 @@ 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" }]} />
{/* Card wrapper */}
<div className="card shadow-sm">
<div className="card-body">
{/* Filter Chips */}
{appliedFiltersChips.length > 0 && ( {appliedFiltersChips.length > 0 && (
<div className="mb-3 text-start d-flex flex-wrap align-items-center gap-2"> <div className="mb-3 d-flex flex-wrap align-items-center gap-2">
<strong className="me-2 fs-6 ms-1">Filters:</strong> <strong className="me-2 fs-6">Filters:</strong>
{appliedFiltersChips.map((chip, idx) => (
{/* Group chips by label */} <span key={idx} className="d-flex align-items-center bg-label-secondary px-2 py-1 rounded me-1">
{["Building", "Floor", "Work Area", "Activity", "Uploaded By", "Work Category"].map((label) => { {chip.label} : {chip.value}
const chipsForLabel = appliedFiltersChips.filter((chip) => chip.label === label);
if (chipsForLabel.length === 0) return null;
return (
<span key={label} className="d-flex align-items-center px-2 py-1 rounded" style={{ background: "transparent" }}>
<strong className="me-1">{label} :</strong>
{chipsForLabel.map((chip, idx) => (
<span
key={chip.id}
className="d-flex align-items-center bg-label-secondary px-2 py-1 rounded me-1"
>
{chip.value}
<button <button
type="button" type="button"
className="btn-close btn-close-white btn-sm ms-1" className="btn-close btn-close-white btn-sm ms-1"
@ -228,33 +198,10 @@ const ImageGalleryPage = () => {
/> />
</span> </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>
)}
</div> </div>
)} )}
{/* Gallery */}
{isLoading ? ( {isLoading ? (
<ImageGallerySkeleton count={4} /> <ImageGallerySkeleton count={4} />
) : ( ) : (
@ -271,6 +218,8 @@ const ImageGalleryPage = () => {
)} )}
</div> </div>
</div>
</div>
); );
}; };