added gallery and gallery filter
This commit is contained in:
parent
9886fac03e
commit
ad1bef4f7b
128
src/components/gallary/GalleryFilterPanel.jsx
Normal file
128
src/components/gallary/GalleryFilterPanel.jsx
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
import React, { useState } from "react";
|
||||||
|
import { useImageGalleryFilter } from "../../hooks/useImageGallery";
|
||||||
|
import { useSelectedProject } from "../../slices/apiDataManager";
|
||||||
|
import { FormProvider, useForm } from "react-hook-form";
|
||||||
|
import Label from "../common/Label";
|
||||||
|
import { DateRangePicker1 } from "../common/DateRangePicker";
|
||||||
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
|
import { defaultGalleryFilterValue, gallerySchema } from "./GallerySchema";
|
||||||
|
import SelectMultiple from "../common/SelectMultiple";
|
||||||
|
|
||||||
|
const GalleryFilterPanel = () => {
|
||||||
|
const selectedProject = useSelectedProject();
|
||||||
|
const [resetKey, setResetKey] = useState(0);
|
||||||
|
const { data, isLoading, isError, error } =
|
||||||
|
useImageGalleryFilter(selectedProject);
|
||||||
|
|
||||||
|
const methods = useForm({
|
||||||
|
resolver: zodResolver(gallerySchema),
|
||||||
|
defaultValues: defaultGalleryFilterValue,
|
||||||
|
});
|
||||||
|
|
||||||
|
const {
|
||||||
|
handleSubmit,
|
||||||
|
register,
|
||||||
|
setValue,
|
||||||
|
formState: { errors },
|
||||||
|
} = methods;
|
||||||
|
|
||||||
|
const onSubmit = (formData) => {
|
||||||
|
console.log(formData);
|
||||||
|
};
|
||||||
|
|
||||||
|
if (isLoading) return <div>Loading....</div>;
|
||||||
|
if (isError) return <div>{error.message}</div>;
|
||||||
|
return (
|
||||||
|
<div className="d-block text-start">
|
||||||
|
<FormProvider {...methods}>
|
||||||
|
<form onSubmit={handleSubmit(onSubmit)}>
|
||||||
|
<div className="mb-2">
|
||||||
|
<Label>Select Date:</Label>
|
||||||
|
<DateRangePicker1
|
||||||
|
placeholder="DD-MM-YYYY To DD-MM-YYYY"
|
||||||
|
startField="startDate"
|
||||||
|
endField="endDate"
|
||||||
|
resetSignal={resetKey}
|
||||||
|
defaultRange={false}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="mb-2">
|
||||||
|
<SelectMultiple
|
||||||
|
name="buildingIds"
|
||||||
|
label="Select building:"
|
||||||
|
options={data?.buildings}
|
||||||
|
labelKey="name"
|
||||||
|
valueKey="id"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="mb-2">
|
||||||
|
<SelectMultiple
|
||||||
|
name="floorIds"
|
||||||
|
label="Select Floor:"
|
||||||
|
options={data?.floors}
|
||||||
|
labelKey="name"
|
||||||
|
valueKey="id"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="mb-2">
|
||||||
|
<SelectMultiple
|
||||||
|
name="workAreaIds"
|
||||||
|
label="Select Work Area:"
|
||||||
|
options={data?.workAreas}
|
||||||
|
labelKey="name"
|
||||||
|
valueKey="id"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="mb-2">
|
||||||
|
<SelectMultiple
|
||||||
|
name="workCategoryIds"
|
||||||
|
label="Select Work Category:"
|
||||||
|
options={data?.workCategories}
|
||||||
|
labelKey="name"
|
||||||
|
valueKey="id"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="mb-2">
|
||||||
|
<SelectMultiple
|
||||||
|
name="activityIds"
|
||||||
|
label="Select Activity:"
|
||||||
|
|
||||||
|
|
||||||
|
options={data?.activities}
|
||||||
|
labelKey="name"
|
||||||
|
valueKey="id"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="mb-2">
|
||||||
|
<SelectMultiple
|
||||||
|
name="uploadedByIds"
|
||||||
|
label="Select Uploaded By:"
|
||||||
|
options={data?.UploadedBys}
|
||||||
|
labelKey="name"
|
||||||
|
valueKey="id"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="mb-2">
|
||||||
|
<SelectMultiple
|
||||||
|
name="serviceIds"
|
||||||
|
label="Select Service:"
|
||||||
|
options={data?.services}
|
||||||
|
labelKey="name"
|
||||||
|
valueKey="id"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="d-flex flex-row gap-3 justify-content-end">
|
||||||
|
<button className="btn btn-sm btn-label-secondary">Cancel</button>
|
||||||
|
<button type="submit" className="btn btn-sm btn-primary">
|
||||||
|
Apply
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</FormProvider>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default GalleryFilterPanel;
|
25
src/components/gallary/GallerySchema.jsx
Normal file
25
src/components/gallary/GallerySchema.jsx
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
|
export const gallerySchema = z.object({
|
||||||
|
buildingIds: z.array(z.string()).optional(),
|
||||||
|
floorIds: z.array(z.string()).optional(),
|
||||||
|
workAreaIds: z.array(z.string()).optional(),
|
||||||
|
activityIds: z.array(z.string()).optional(),
|
||||||
|
workCategoryIds: z.array(z.string()).optional(),
|
||||||
|
startDate: z.string().optional(),
|
||||||
|
endDate: z.string().optional(),
|
||||||
|
uploadedByIds: z.array(z.string()).optional(),
|
||||||
|
serviceIds: z.array(z.string()).optional(),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const defaultGalleryFilterValue = {
|
||||||
|
buildingIds: [],
|
||||||
|
floorIds: [],
|
||||||
|
workAreaIds: [],
|
||||||
|
activityIds: [],
|
||||||
|
workCategoryIds:[],
|
||||||
|
startDate: null,
|
||||||
|
endDate: null,
|
||||||
|
uploadedByIds:[],
|
||||||
|
serviceIds: [],
|
||||||
|
};
|
169
src/components/gallary/ImageGalleryListView.jsx
Normal file
169
src/components/gallary/ImageGalleryListView.jsx
Normal file
@ -0,0 +1,169 @@
|
|||||||
|
import React, { useRef, useState, useCallback, useEffect } from "react";
|
||||||
|
import moment from "moment";
|
||||||
|
import Avatar from "../../components/common/Avatar";
|
||||||
|
import { useGalleryContext } from "../../pages/Gallary/ImageGallaryPage";
|
||||||
|
import useImageGallery from "../../hooks/useImageGallery";
|
||||||
|
import { useSelectedProject } from "../../slices/apiDataManager";
|
||||||
|
import { ITEMS_PER_PAGE } from "../../utils/constants";
|
||||||
|
import Pagination from "../common/Pagination";
|
||||||
|
import { formatUTCToLocalTime } from "../../utils/dateUtils";
|
||||||
|
import Loader from "../common/Loader";
|
||||||
|
|
||||||
|
const ImageGalleryListView = () => {
|
||||||
|
const [hoveredImage, setHoveredImage] = useState(null);
|
||||||
|
const selectedProject = useSelectedProject();
|
||||||
|
const [currentPage, setCurrentPage] = useState(1);
|
||||||
|
const { setOpenGallery } = useGalleryContext();
|
||||||
|
|
||||||
|
const { data, isLoading, isError, error } = useImageGallery(
|
||||||
|
selectedProject,
|
||||||
|
currentPage,
|
||||||
|
10,
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
|
||||||
|
const paginate = (page) => {
|
||||||
|
if (page >= 1 && page <= (data?.totalPages ?? 1)) {
|
||||||
|
setCurrentPage(page);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!data?.data?.length && !isLoading) {
|
||||||
|
return (
|
||||||
|
<p className="text-center text-muted mt-5">
|
||||||
|
{selectedProject ? " No images match the selected filters.":"Please Select Project!"}
|
||||||
|
</p>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isLoading) {
|
||||||
|
return (
|
||||||
|
<div className="page-min-h d-flex justify-content-center align-items-center">
|
||||||
|
<Loader />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="main-content">
|
||||||
|
<div className="activity-section">
|
||||||
|
{data?.data?.map((batch) => {
|
||||||
|
if (!batch.documents?.length) return null;
|
||||||
|
|
||||||
|
const doc = batch.documents[0];
|
||||||
|
const userName = `${doc.uploadedBy?.firstName || ""} ${
|
||||||
|
doc.uploadedBy?.lastName || ""
|
||||||
|
}`.trim();
|
||||||
|
const date = formatUTCToLocalTime(doc.uploadedAt);
|
||||||
|
// const hasArrows = batch.documents.length > scrollThreshold;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div key={batch.batchId} className="grouped-section">
|
||||||
|
<div className="group-heading">
|
||||||
|
<div className="d-flex align-items-center mb-1">
|
||||||
|
<Avatar
|
||||||
|
size="xs"
|
||||||
|
firstName={doc.uploadedBy?.firstName}
|
||||||
|
lastName={doc.uploadedBy?.lastName}
|
||||||
|
className="me-2"
|
||||||
|
/>
|
||||||
|
<div className="d-flex flex-column align-items-start">
|
||||||
|
<strong className="user-name-text">{userName}</strong>
|
||||||
|
<span className="text-muted small">{date}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="location-line text-secondary">
|
||||||
|
<div className="d-flex align-items-center flex-wrap gap-1 text-secondary">
|
||||||
|
<span className="d-flex align-items-center">
|
||||||
|
<span>{batch.buildingName}</span>
|
||||||
|
<i className="bx bx-chevron-right " />
|
||||||
|
</span>
|
||||||
|
<span className="d-flex align-items-center">
|
||||||
|
<span>{batch.floorName}</span>
|
||||||
|
<i className="bx bx-chevron-right m" />
|
||||||
|
</span>
|
||||||
|
<span className="d-flex align-items-center ">
|
||||||
|
<span>{batch.workAreaName || "Unknown"}</span>
|
||||||
|
<i className="bx bx-chevron-right " />
|
||||||
|
<span>{batch.activityName}</span>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
{batch.workCategoryName && (
|
||||||
|
<span className="badge bg-label-primary ms-2">
|
||||||
|
{batch.workCategoryName}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="image-group-wrapper">
|
||||||
|
{/* {hasArrows && (
|
||||||
|
<button className="scroll-arrow left-arrow" onClick={() => scrollLeft(batch.batchId)}>
|
||||||
|
‹
|
||||||
|
</button>
|
||||||
|
)} */}
|
||||||
|
<div
|
||||||
|
className="image-group-horizontal"
|
||||||
|
// ref={(el) => (imageGroupRefs.current[batch.batchId] = el)}
|
||||||
|
>
|
||||||
|
{batch.documents.map((d, i) => {
|
||||||
|
const hoverDate = moment().format("DD MMMM, YYYY");
|
||||||
|
const hoverTime = moment(d.uploadedAt).format("hh:mm A");
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
key={d.id}
|
||||||
|
className="image-card"
|
||||||
|
onMouseEnter={() => setHoveredImage(d)}
|
||||||
|
onMouseLeave={() => setHoveredImage(null)}
|
||||||
|
onClick={() =>
|
||||||
|
setOpenGallery({
|
||||||
|
isOpen: true,
|
||||||
|
data: { data: batch, index: i },
|
||||||
|
})
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<div className="image-wrapper">
|
||||||
|
<img src={d.url} alt={`Image ${i + 1}`} />
|
||||||
|
</div>
|
||||||
|
{hoveredImage === d && (
|
||||||
|
<div className="image-hover-description">
|
||||||
|
<p>
|
||||||
|
<strong>Date:</strong> {hoverDate}
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<strong>Time:</strong> {hoverTime}
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<strong>Activity:</strong> {batch.activityName}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
{/* {hasArrows && (
|
||||||
|
<button className="scroll-arrow right-arrow" onClick={() => scrollRight(batch.batchId)}>
|
||||||
|
‹
|
||||||
|
</button>
|
||||||
|
)} */}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{data?.data?.length > 0 && (
|
||||||
|
<Pagination
|
||||||
|
currentPage={currentPage}
|
||||||
|
totalPages={data?.totalPages}
|
||||||
|
onPageChange={paginate}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ImageGalleryListView;
|
111
src/components/gallary/ViewGallery.jsx
Normal file
111
src/components/gallary/ViewGallery.jsx
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
import React, { useState, useEffect } from "react";
|
||||||
|
import { formatUTCToLocalTime } from "../../utils/dateUtils";
|
||||||
|
|
||||||
|
const ViewGallery = ({ batch, index }) => {
|
||||||
|
const [loading, setLoading] = useState(true);
|
||||||
|
const [currentIndex, setCurrentIndex] = useState(index);
|
||||||
|
console.log(batch);
|
||||||
|
useEffect(() => {
|
||||||
|
setCurrentIndex(index);
|
||||||
|
}, [index, batch]);
|
||||||
|
|
||||||
|
if (!batch || !batch.documents || batch.documents.length === 0) return null;
|
||||||
|
|
||||||
|
const image = batch.documents[currentIndex];
|
||||||
|
if (!image) return null;
|
||||||
|
|
||||||
|
const fullName = `${image.uploadedBy?.firstName || ""} ${
|
||||||
|
image.uploadedBy?.lastName || ""
|
||||||
|
}`.trim();
|
||||||
|
const date = formatUTCToLocalTime(image.uploadedAt);
|
||||||
|
|
||||||
|
const buildingName = batch.buildingName;
|
||||||
|
const floorName = batch.floorName;
|
||||||
|
const workAreaName = batch.workAreaName;
|
||||||
|
const activityName = batch.activityName;
|
||||||
|
const batchComment = batch.comment;
|
||||||
|
|
||||||
|
const handlePrev = () => {
|
||||||
|
setCurrentIndex((prevIndex) => Math.max(0, prevIndex - 1));
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleNext = () => {
|
||||||
|
setCurrentIndex((prevIndex) =>
|
||||||
|
Math.min(batch.documents.length - 1, prevIndex + 1)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const hasPrev = currentIndex > 0;
|
||||||
|
const hasNext = currentIndex < batch.documents.length - 1;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
|
||||||
|
{loading && <p>Loading...</p>}
|
||||||
|
<div className="position-relative d-flex justify-content-center align-items-center">
|
||||||
|
{hasPrev && (
|
||||||
|
<button
|
||||||
|
className="btn btn-icon btn-outline-primary rounded-circle position-absolute start-0 top-50 translate-middle-y shadow"
|
||||||
|
onClick={handlePrev}
|
||||||
|
>
|
||||||
|
<i className="bx bx-chevron-left fs-4"></i>
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<img
|
||||||
|
src={image.url}
|
||||||
|
alt="Preview"
|
||||||
|
className="img-fluid rounded"
|
||||||
|
style={{
|
||||||
|
maxHeight: "500px",
|
||||||
|
width: "100%",
|
||||||
|
objectFit: "contain",
|
||||||
|
}}
|
||||||
|
onLoad={() => setLoading(false)}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{hasNext && (
|
||||||
|
<button
|
||||||
|
className="btn btn-icon btn-outline-primary position-absolute end-0 top-50 translate-middle-y rounded-circle shadow"
|
||||||
|
onClick={handleNext}
|
||||||
|
>
|
||||||
|
<i className="bx bx-chevron-right fs-4"></i>
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* 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>
|
||||||
|
|
||||||
|
<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>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ViewGallery;
|
@ -1,116 +1,45 @@
|
|||||||
import { useState, useCallback } from "react";
|
import { useState, useCallback } from "react";
|
||||||
// import { ImageGalleryAPI } from "../repositories/ImageGalleyRepository";
|
// import { ImageGalleryAPI } from "../repositories/ImageGalleyRepository";
|
||||||
import { ImageGalleryAPI } from "../repositories/ImageGalleryAPI";
|
import { ImageGalleryRepository } from "../repositories/ImageGalleryAPI";
|
||||||
|
|
||||||
// const PAGE_SIZE = 10;
|
|
||||||
|
|
||||||
// const useImageGallery = (selectedProjectId) => {
|
import { useInfiniteQuery, useQuery } from "@tanstack/react-query";
|
||||||
// const [images, setImages] = useState([]);
|
|
||||||
// const [allImagesData, setAllImagesData] = useState([]);
|
|
||||||
// const [pageNumber, setPageNumber] = useState(1);
|
|
||||||
// const [hasMore, setHasMore] = useState(true);
|
|
||||||
// const [loading, setLoading] = useState(false);
|
|
||||||
// const [loadingMore, setLoadingMore] = useState(false);
|
|
||||||
|
|
||||||
// const fetchImages = useCallback(async (page = 1, filters = {}, reset = false) => {
|
|
||||||
// if (!selectedProjectId) return;
|
|
||||||
|
|
||||||
// try {
|
|
||||||
// if (page === 1) {
|
|
||||||
// setLoading(true);
|
|
||||||
// } else {
|
|
||||||
// setLoadingMore(true);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// const res = await ImageGalleryAPI.ImagesGet(
|
|
||||||
// selectedProjectId,
|
|
||||||
// filters,
|
|
||||||
// page,
|
|
||||||
// PAGE_SIZE
|
|
||||||
// );
|
|
||||||
|
|
||||||
// const newBatches = res.data || [];
|
|
||||||
// const receivedCount = newBatches.length;
|
|
||||||
|
|
||||||
// setImages((prev) => {
|
|
||||||
// if (page === 1 || reset) return newBatches;
|
|
||||||
// const uniqueNew = newBatches.filter(
|
|
||||||
// (batch) => !prev.some((b) => b.batchId === batch.batchId)
|
|
||||||
// );
|
|
||||||
// return [...prev, ...uniqueNew];
|
|
||||||
// });
|
|
||||||
|
|
||||||
// setAllImagesData((prev) => {
|
|
||||||
// if (page === 1 || reset) return newBatches;
|
|
||||||
// const uniqueAll = newBatches.filter(
|
|
||||||
// (batch) => !prev.some((b) => b.batchId === batch.batchId)
|
|
||||||
// );
|
|
||||||
// return [...prev, ...uniqueAll];
|
|
||||||
// });
|
|
||||||
|
|
||||||
// setHasMore(receivedCount === PAGE_SIZE);
|
|
||||||
// } catch (error) {
|
|
||||||
// console.error("Error fetching images:", error);
|
|
||||||
// if (page === 1) {
|
|
||||||
// setImages([]);
|
|
||||||
// setAllImagesData([]);
|
|
||||||
// }
|
|
||||||
// setHasMore(false);
|
|
||||||
// } finally {
|
|
||||||
// setLoading(false);
|
|
||||||
// setLoadingMore(false);
|
|
||||||
// }
|
|
||||||
// }, [selectedProjectId]);
|
|
||||||
|
|
||||||
// const resetGallery = useCallback(() => {
|
|
||||||
// setImages([]);
|
|
||||||
// setAllImagesData([]);
|
|
||||||
// setPageNumber(1);
|
|
||||||
// setHasMore(true);
|
|
||||||
// }, []);
|
|
||||||
|
|
||||||
// return {
|
|
||||||
// images,
|
|
||||||
// allImagesData,
|
|
||||||
// pageNumber,
|
|
||||||
// setPageNumber,
|
|
||||||
// hasMore,
|
|
||||||
// loading,
|
|
||||||
// loadingMore,
|
|
||||||
// fetchImages,
|
|
||||||
// resetGallery,
|
|
||||||
// };
|
|
||||||
// };
|
|
||||||
|
|
||||||
// export default useImageGallery;
|
|
||||||
import { useInfiniteQuery } from "@tanstack/react-query";
|
|
||||||
|
|
||||||
|
|
||||||
const PAGE_SIZE = 10;
|
const PAGE_SIZE = 10;
|
||||||
|
|
||||||
const useImageGallery = (selectedProjectId, filters) => {
|
const useImageGallery = (selectedProjectId,pageNumber, pageSize, filters) => {
|
||||||
const hasFilters = filters && Object.values(filters).some(
|
const hasFilters = filters && Object.values(filters).some(
|
||||||
value => Array.isArray(value) ? value.length > 0 : value !== null && value !== ""
|
value => Array.isArray(value) ? value.length > 0 : value !== null && value !== ""
|
||||||
);
|
);
|
||||||
|
|
||||||
return useInfiniteQuery({
|
return useQuery({
|
||||||
queryKey: ["imageGallery", selectedProjectId, hasFilters ? filters : null],
|
queryKey: ["imageGallery", selectedProjectId, pageNumber, pageSize, hasFilters ? filters : null],
|
||||||
enabled: !!selectedProjectId,
|
enabled: !!selectedProjectId,
|
||||||
getNextPageParam: (lastPage, allPages) => {
|
|
||||||
if (!lastPage?.data?.length) return undefined;
|
queryFn: async () => {
|
||||||
return allPages.length + 1;
|
const res = await ImageGalleryRepository.ImagesGet(
|
||||||
},
|
|
||||||
queryFn: async ({ pageParam = 1 }) => {
|
|
||||||
const res = await ImageGalleryAPI.ImagesGet(
|
|
||||||
selectedProjectId,
|
selectedProjectId,
|
||||||
|
pageNumber,
|
||||||
|
pageSize,
|
||||||
hasFilters ? filters : undefined,
|
hasFilters ? filters : undefined,
|
||||||
pageParam,
|
|
||||||
PAGE_SIZE
|
|
||||||
);
|
);
|
||||||
return res;
|
return res.data;
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export default useImageGallery;
|
export default useImageGallery;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
export const useImageGalleryFilter = (project)=>{
|
||||||
|
return useQuery({
|
||||||
|
queryKey:["imageGalleryFlter",project],
|
||||||
|
queryFn:async() => {
|
||||||
|
const response = await ImageGalleryRepository.getImageGalleryFilter(project);
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import React, { useState, useEffect, useRef, useCallback } from "react";
|
import React, { useState, useEffect, useRef, useCallback } from "react";
|
||||||
import "./ImageGallery.css";
|
// import "./ImageGallery.css";
|
||||||
import moment from "moment";
|
import moment from "moment";
|
||||||
import { useDispatch, useSelector } from "react-redux";
|
import { useDispatch, useSelector } from "react-redux";
|
||||||
import { useModal } from "./ModalContext";
|
import { useModal } from "./ModalContext";
|
||||||
|
124
src/pages/Gallary/ImageGallaryPage.jsx
Normal file
124
src/pages/Gallary/ImageGallaryPage.jsx
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
import React, {
|
||||||
|
useState,
|
||||||
|
useEffect,
|
||||||
|
useRef,
|
||||||
|
useContext,
|
||||||
|
createContext,
|
||||||
|
} from "react";
|
||||||
|
import { useDispatch, useSelector } from "react-redux";
|
||||||
|
import moment from "moment";
|
||||||
|
import eventBus from "../../services/eventBus";
|
||||||
|
import Breadcrumb from "../../components/common/Breadcrumb";
|
||||||
|
import { formatUTCToLocalTime } from "../../utils/dateUtils";
|
||||||
|
import useImageGallery from "../../hooks/useImageGallery";
|
||||||
|
import {
|
||||||
|
useProjectAssignedServices,
|
||||||
|
useProjectName,
|
||||||
|
} from "../../hooks/useProjects";
|
||||||
|
import { setProjectId } from "../../slices/localVariablesSlice";
|
||||||
|
import ImageGalleryListView from "../../components/gallary/ImageGalleryListView";
|
||||||
|
import "../../components/gallary/ImageGallery.css";
|
||||||
|
import { useSelectedProject } from "../../slices/apiDataManager";
|
||||||
|
import GlobalModel from "../../components/common/GlobalModel";
|
||||||
|
import ViewGallery from "../../components/gallary/ViewGallery";
|
||||||
|
import { useFab } from "../../Context/FabContext";
|
||||||
|
import GalleryFilterPanel from "../../components/gallary/GalleryFilterPanel";
|
||||||
|
|
||||||
|
const GalleryContext = createContext();
|
||||||
|
|
||||||
|
export const useGalleryContext = () => {
|
||||||
|
let context = useContext(GalleryContext);
|
||||||
|
|
||||||
|
if (!context) {
|
||||||
|
throw new Error("Error");
|
||||||
|
}
|
||||||
|
return context;
|
||||||
|
};
|
||||||
|
|
||||||
|
const ImageGalleryPage = () => {
|
||||||
|
const selectedProjectId = useSelectedProject();
|
||||||
|
const { projectNames } = useProjectName();
|
||||||
|
|
||||||
|
const [openGallery, setOpenGallery] = useState({ isOpen: false, data: null });
|
||||||
|
|
||||||
|
const { data: assignedServices = [], isLoading } =
|
||||||
|
useProjectAssignedServices(selectedProjectId);
|
||||||
|
|
||||||
|
const [selectedService, setSelectedService] = useState("");
|
||||||
|
|
||||||
|
const handleServiceChange = (e) => {
|
||||||
|
setSelectedService(e.target.value);
|
||||||
|
};
|
||||||
|
|
||||||
|
const contextMessager = {
|
||||||
|
setOpenGallery,
|
||||||
|
};
|
||||||
|
|
||||||
|
const { setOffcanvasContent, setShowTrigger } = useFab();
|
||||||
|
|
||||||
|
useEffect(()=>{
|
||||||
|
setShowTrigger(true);
|
||||||
|
setOffcanvasContent("Gallery Filter",<GalleryFilterPanel/>);
|
||||||
|
|
||||||
|
return ()=>{
|
||||||
|
setOffcanvasContent("",null)
|
||||||
|
setShowTrigger(false);
|
||||||
|
}
|
||||||
|
},[])
|
||||||
|
|
||||||
|
|
||||||
|
return (
|
||||||
|
<GalleryContext.Provider value={contextMessager}>
|
||||||
|
<div className="container-fluid">
|
||||||
|
<Breadcrumb
|
||||||
|
data={[{ label: "Home", link: "/" }, { label: "Gallery" }]}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div className="card page-min-h p-2">
|
||||||
|
{selectedProjectId && (
|
||||||
|
<div className="d-flex flex-row w-20 pb-2">
|
||||||
|
{!isLoading && assignedServices?.length === 0 ? (
|
||||||
|
<span className="badge bg-label-secondary">
|
||||||
|
Not service assiged yet
|
||||||
|
</span>
|
||||||
|
) : (
|
||||||
|
<select className="form-select form-select-sm">
|
||||||
|
<option>Select Service</option>
|
||||||
|
{isLoading ? (
|
||||||
|
<option>Loading...</option>
|
||||||
|
) : assignedServices.length === 1 ? (
|
||||||
|
<span className="badge bg-label-secondary">
|
||||||
|
{assignedServices[0].name}
|
||||||
|
</span>
|
||||||
|
) : (
|
||||||
|
assignedServices?.map((service) => (
|
||||||
|
<option key={service.id} value={service?.id}>
|
||||||
|
{service?.name}
|
||||||
|
</option>
|
||||||
|
))
|
||||||
|
)}
|
||||||
|
</select>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<ImageGalleryListView />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{openGallery?.isOpen && (
|
||||||
|
<GlobalModel
|
||||||
|
isOpen={openGallery?.isOpen}
|
||||||
|
closeModal={() => setOpenGallery({ isOpen: false, data: null })}
|
||||||
|
>
|
||||||
|
<ViewGallery
|
||||||
|
batch={openGallery?.data?.data}
|
||||||
|
index={openGallery?.data?.index}
|
||||||
|
/>
|
||||||
|
</GlobalModel>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</GalleryContext.Provider>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ImageGalleryPage;
|
@ -1,8 +1,12 @@
|
|||||||
import { api } from "../utils/axiosClient";
|
import { api } from "../utils/axiosClient";
|
||||||
|
|
||||||
export const ImageGalleryAPI = {
|
export const ImageGalleryRepository = {
|
||||||
ImagesGet: (projectId, filter, pageNumber, pageSize) => {
|
ImagesGet: (projectId, pageNumber, pageSize,filter) => {
|
||||||
const payloadJsonString = JSON.stringify(filter);
|
const payloadJsonString = JSON.stringify(filter);
|
||||||
return api.get(`/api/image/images/${projectId}?filter=${payloadJsonString}&pageNumber=${pageNumber}&pageSize=${pageSize}`);
|
return api.get(`/api/image/images/${projectId}?pageNumber=${pageNumber}&pageSize=${pageSize}&filter=${payloadJsonString}`);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
|
getImageGalleryFilter:(projectId)=>api.get(`/api/Image/filter/${projectId}`)
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -53,6 +53,7 @@ import TenantSelectionPage from "../pages/authentication/TenantSelectionPage";
|
|||||||
import DailyProgrssReport from "../pages/DailyProgressReport/DailyProgrssReport";
|
import DailyProgrssReport from "../pages/DailyProgressReport/DailyProgrssReport";
|
||||||
import ProjectPage from "../pages/project/ProjectPage";
|
import ProjectPage from "../pages/project/ProjectPage";
|
||||||
import { ComingSoonPage } from "../pages/Misc/ComingSoonPage";
|
import { ComingSoonPage } from "../pages/Misc/ComingSoonPage";
|
||||||
|
import ImageGalleryPage from "../pages/Gallary/ImageGallaryPage";
|
||||||
const router = createBrowserRouter(
|
const router = createBrowserRouter(
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
@ -93,7 +94,7 @@ const router = createBrowserRouter(
|
|||||||
{ path: "/activities/records/:projectId?", element: <DailyProgrssReport /> },
|
{ path: "/activities/records/:projectId?", element: <DailyProgrssReport /> },
|
||||||
{ path: "/activities/task", element: <TaskPlannng /> },
|
{ path: "/activities/task", element: <TaskPlannng /> },
|
||||||
{ path: "/activities/reports", element: <Reports /> },
|
{ path: "/activities/reports", element: <Reports /> },
|
||||||
{ path: "/gallary", element: <ComingSoonPage /> },
|
{ path: "/gallary", element: <ImageGalleryPage /> },
|
||||||
{ path: "/expenses", element: <ExpensePage /> },
|
{ path: "/expenses", element: <ExpensePage /> },
|
||||||
{ path: "/masters", element: <MasterPage /> },
|
{ path: "/masters", element: <MasterPage /> },
|
||||||
{ path: "/tenants", element: <TenantPage /> },
|
{ path: "/tenants", element: <TenantPage /> },
|
||||||
|
Loading…
x
Reference in New Issue
Block a user