diff --git a/packages/web/package.json b/packages/web/package.json index 7084359..7c1ed13 100644 --- a/packages/web/package.json +++ b/packages/web/package.json @@ -26,6 +26,7 @@ "react-ga4": "^2.1.0", "react-icons": "^4.10.1", "react-leaflet": "^4.2.1", + "react-leaflet-cluster": "^2.1.0", "react-resizable": "^3.0.5", "react-resizable-panels": "^0.0.53", "react-router-dom": "^6.11.2", diff --git a/packages/web/src/components/Home/Home.jsx b/packages/web/src/components/Home/Home.jsx index a230027..2c87abc 100644 --- a/packages/web/src/components/Home/Home.jsx +++ b/packages/web/src/components/Home/Home.jsx @@ -331,7 +331,7 @@ export default function Home() { > ); -} +} \ No newline at end of file diff --git a/packages/web/src/components/Login/Login.jsx b/packages/web/src/components/Login/Login.jsx index 7638b6a..a55c92b 100644 --- a/packages/web/src/components/Login/Login.jsx +++ b/packages/web/src/components/Login/Login.jsx @@ -19,7 +19,7 @@ export default function Login() { return ( @@ -47,7 +47,7 @@ export default function Login() { {"Login 0 ? results : data; - const allMarkers = markersData.filter(filterItemCallback).map((item) => { - return ( + const allMarkers = useMemo(() => { + return markersData.filter(filterItemCallback).map((item) => ( - ); - }); + )); + }, [markersData, filterItemCallback, onOpen, setItemData, setFocusLocation]); // moves map when focusLocation state changes function MapFocusLocation({ location }) { @@ -353,8 +354,11 @@ export default function Map({ {!isEdit && ( )} - {!isEdit} - {!isEdit && allMarkers} + {!isEdit && ( + + {allMarkers} + + )} {isEdit && } {showDonut && focusLocation && ( diff --git a/packages/web/src/components/ResultsBar/ResultsBar.jsx b/packages/web/src/components/ResultsBar/ResultsBar.jsx index 23ba064..54ad202 100644 --- a/packages/web/src/components/ResultsBar/ResultsBar.jsx +++ b/packages/web/src/components/ResultsBar/ResultsBar.jsx @@ -1,4 +1,4 @@ -import { useContext, useCallback, useState } from "react"; +import { useContext, useCallback, useState, useEffect, useRef } from "react"; import "./ResultsBar.css"; import ResultCard from "../ResultCard/ResultCard"; import { Box, Flex, Text, Button } from "@chakra-ui/react"; @@ -19,6 +19,8 @@ export default function ResultsBar({ const { user } = UserAuth(); const [itemsonScreenLimit, setItemsOnScreenLimit] = useState(10); + const [isAutoScrolling, setIsAutoScrolling] = useState(true); + const resultsBarRef = useRef(null); const filterItemCallback = useCallback( (item) => filterItem(item, findFilter, user), @@ -60,7 +62,6 @@ export default function ResultsBar({ ? data.filter(filterItemCallback).map(mapItem) : results.filter(filterItemCallback).map(mapItem); - // Callback function that increases the number of items displayed on the screen by 10 const handleLoadMore = useCallback(() => { setItemsOnScreenLimit(itemsonScreenLimit + 10); }, [itemsonScreenLimit]); @@ -80,15 +81,11 @@ export default function ResultsBar({ ); - // Retrieve all items that meet the filter criteria - - // Display only the first 10 items on the screen, all items if there are less than 10 items left to be loaded const viewableResults = allResults.slice( 0, Math.min(itemsonScreenLimit, allResults.length) ); - // Define JSX for empty results bar (no result cards) const noResults = ( @@ -97,16 +94,38 @@ export default function ResultsBar({ ); + useEffect(() => { + let scrollInterval; + if (isAutoScrolling && resultsBarRef.current) { + scrollInterval = setInterval(() => { + if (resultsBarRef.current.scrollTop + resultsBarRef.current.clientHeight < resultsBarRef.current.scrollHeight) { + resultsBarRef.current.scrollTop += 1; + } else { + resultsBarRef.current.scrollTop = 0; + } + }, 50); + } + return () => clearInterval(scrollInterval); + }, [isAutoScrolling]); + + const handleUserInteraction = () => { + setIsAutoScrolling(false); + }; + return ( {allResults.length > 0 ? viewableResults : noResults} {viewableResults.length < allResults.length && loadMoreButton} ); -} +} \ No newline at end of file diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6148c5a..21527e1 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -164,6 +164,9 @@ importers: react-leaflet: specifier: ^4.2.1 version: 4.2.1(leaflet@1.9.4)(react-dom@18.2.0)(react@18.2.0) + react-leaflet-cluster: + specifier: ^2.1.0 + version: 2.1.0(leaflet@1.9.4)(react-dom@18.2.0)(react-leaflet@4.2.1)(react@18.2.0) react-resizable: specifier: ^3.0.5 version: 3.0.5(react-dom@18.2.0)(react@18.2.0) @@ -9441,6 +9444,14 @@ packages: readable-stream: 2.3.8 dev: true + /leaflet.markercluster@1.5.3(leaflet@1.9.4): + resolution: {integrity: sha512-vPTw/Bndq7eQHjLBVlWpnGeLa3t+3zGiuM7fJwCkiMFq+nmRuG3RI3f7f4N4TDX7T4NpbAXpR2+NTRSEGfCSeA==} + peerDependencies: + leaflet: ^1.3.1 + dependencies: + leaflet: 1.9.4 + dev: false + /leaflet@1.9.4: resolution: {integrity: sha512-nxS1ynzJOmOlHp+iL3FyWqK89GtNL8U8rvlMOsQdTTssxZwCXh8N2NB3GDQOL+YR3XnWyZAxwQixURb+FA74PA==} dev: false @@ -10559,6 +10570,21 @@ packages: /react-is@18.3.1: resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} + /react-leaflet-cluster@2.1.0(leaflet@1.9.4)(react-dom@18.2.0)(react-leaflet@4.2.1)(react@18.2.0): + resolution: {integrity: sha512-16X7XQpRThQFC4PH4OpXHimGg19ouWmjxjtpxOeBKpvERSvIRqTx7fvhTwkEPNMFTQ8zTfddz6fRTUmUEQul7g==} + peerDependencies: + leaflet: ^1.8.0 + react: ^18.0.0 + react-dom: ^18.0.0 + react-leaflet: ^4.0.0 + dependencies: + leaflet: 1.9.4 + leaflet.markercluster: 1.5.3(leaflet@1.9.4) + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + react-leaflet: 4.2.1(leaflet@1.9.4)(react-dom@18.2.0)(react@18.2.0) + dev: false + /react-leaflet@4.2.1(leaflet@1.9.4)(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-p9chkvhcKrWn/H/1FFeVSqLdReGwn2qmiobOQGO3BifX+/vV/39qhY8dGqbdcPh1e6jxh/QHriLXr7a4eLFK4Q==} peerDependencies: