Skip to content

Commit

Permalink
Infinite scrolling using IntersectionObserver
Browse files Browse the repository at this point in the history
  • Loading branch information
Max Frederiksen authored and maxfrederiksen-ess committed Feb 13, 2025
1 parent 12e10c7 commit 46fff4b
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 65 deletions.
52 changes: 49 additions & 3 deletions src/beta/components/search/SearchResultList/SearchResultList.jsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,20 @@
import { useEffect, useMemo } from "react";
import { Stack, styled } from "@mui/material";
import { useEffect, useMemo, useRef } from "react";
import { useDispatch } from "react-redux";
import { Box, CircularProgress, Stack, styled } from "@mui/material";
import { useParams } from "react-router-dom";
import { SearchResultSingleItem } from "./SearchResultSingleItem";
import { SearchResultGroupItem } from "./SearchResultGroupItem/SearchResultGroupItem";
import { getLogEntryGroupId } from "components/Properties";
import { sortByCreatedDate } from "components/log/sort";
import useBetaNavigate from "hooks/useBetaNavigate";
import { incrementPageSize } from "src/features/searchPageParamsReducer";

export const SearchResultList = styled(
({ logs, dateDescending, className }) => {
({ logs, dateDescending, isFetchingSearchResults, className }) => {
const navigate = useBetaNavigate();
const dispatch = useDispatch();
const searchResultListRef = useRef(null);
const loadMoreLogsRef = useRef(null);

const { id: paramLogId } = useParams();
const currentLogEntryId = Number(paramLogId);
Expand Down Expand Up @@ -76,8 +81,35 @@ export const SearchResultList = styled(
}
};

useEffect(() => {
// Infinite scrolling with IntersectionObserver
if (searchResultListRef.current && loadMoreLogsRef.current) {
const target = loadMoreLogsRef.current;
const observer = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
dispatch(incrementPageSize());
}
});
},
{
root: searchResultListRef.current,
rootMargin: "1500px",
threshold: 0
}
);

observer.observe(target);
return () => {
observer.unobserve(target);
};
}
}, [searchResultListRef, loadMoreLogsRef, dispatch]);

return (
<Stack
ref={searchResultListRef}
flex={2}
px={0}
overflow="scroll"
Expand Down Expand Up @@ -106,6 +138,20 @@ export const SearchResultList = styled(
);
}
})}
<Box ref={loadMoreLogsRef}>
{isFetchingSearchResults && (
<Box
display="flex"
justifyContent="center"
py={1.25}
>
<CircularProgress
size="1.5rem"
sx={{ color: "#757575" }}
/>
</Box>
)}
</Box>
</Stack>
);
}
Expand Down
69 changes: 7 additions & 62 deletions src/beta/components/search/SearchResults.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,38 +4,23 @@ import {
Divider,
LinearProgress,
Stack,
TablePagination,
Typography,
styled
} from "@mui/material";
import { useEffect, useMemo, useState } from "react";
import { useDispatch } from "react-redux";
import { useMemo } from "react";
import { SearchResultList } from "./SearchResultList";
import { SearchParamsBadges } from "./SearchParamsBadges";
import { ologApi, removeEmptyKeys } from "api/ologApi";
import customization from "config/customization";
import {
updateSearchPageParams,
useSearchPageParams
} from "features/searchPageParamsReducer";
import { useSearchPageParams } from "features/searchPageParamsReducer";
import { useSearchParams } from "features/searchParamsReducer";
import { useAdvancedSearch } from "features/advancedSearchReducer";
import { withCacheBust } from "hooks/useSanitizedSearchParams";

export const SearchResults = styled(({ className }) => {
const dispatch = useDispatch();

const { active: advancedSearchActive } = useAdvancedSearch();
const searchParams = useSearchParams();
const searchPageParams = useSearchPageParams();
const rowsPerPageOptions = customization.defaultRowsPerPageOptions;

const [page, setPage] = useState(0);
const [pageSize, setPageSize] = useState(
rowsPerPageOptions.includes(searchPageParams?.size)
? searchPageParams?.size
: customization.defaultPageSize
);

const searchLogsQuery = useMemo(() => {
let params = {
Expand Down Expand Up @@ -74,33 +59,14 @@ export const SearchResults = styled(({ className }) => {
hitCount: 0
},
error,
isLoading: loading
isLoading: loading,
isFetching: isFetchingSearchResults
} = ologApi.endpoints.searchLogs.useQuery(searchLogsQuery, {
pollingInterval: customization.defaultSearchFrequency,
refetchOnMountOrArgChange: true,
refetchOnFocus: true
});

const count = searchResults?.hitCount ?? 0;

const onPageChange = (event, page) => {
setPage(page);
};

const onRowsPerPageChange = (event) => {
setPageSize(event.target.value);
};

useEffect(() => {
dispatch(
updateSearchPageParams({
from: page * pageSize,
size: pageSize,
dateDescending: searchPageParams?.dateDescending
})
);
}, [dispatch, page, pageSize, searchPageParams.dateDescending]);

return (
<Stack
className={`SearchResultList ${className}`}
Expand All @@ -123,19 +89,20 @@ export const SearchResults = styled(({ className }) => {
</Box>
)}
{loading && <LinearProgress />}
{error ? (
{error && (
<Box>
<Alert severity="error">
{error?.status === "FETCH_ERROR"
? "Error: Log Service Unavailable"
: `Error ${error?.code}: ${error?.message}`}
</Alert>
</Box>
) : null}
)}
{searchResults?.logs?.length > 0 ? (
<SearchResultList
logs={searchResults.logs}
dateDescending={searchPageParams?.dateDescending}
isFetchingSearchResults={isFetchingSearchResults}
/>
) : (
<Box
Expand All @@ -146,28 +113,6 @@ export const SearchResults = styled(({ className }) => {
<Typography>No records found</Typography>
</Box>
)}
<TablePagination
component="div"
count={count}
page={page}
onPageChange={onPageChange}
rowsPerPageOptions={rowsPerPageOptions}
rowsPerPage={pageSize}
onRowsPerPageChange={onRowsPerPageChange}
variant={"outlined"}
shape={"rounded"}
labelRowsPerPage={"Hits Per Page"}
labelDisplayedRows={() => null}
showFirstButton
showLastButton
sx={{
borderTop: "1px solid #dedede",
minHeight: "52px",
"&:last-child": {
paddingRight: "20px"
}
}}
/>
</Stack>
);
})({});

0 comments on commit 46fff4b

Please sign in to comment.