Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

merge dev into master #1169

Merged
merged 3 commits into from
Nov 28, 2024
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
in progress
SejoB committed Nov 12, 2024
commit 78f8c17bd1109ed442f3e10550b71380a69bc017
7 changes: 4 additions & 3 deletions src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, { FC, useEffect } from 'react';
import { BrowserRouter as Router, Route, Routes } from 'react-router-dom';
import { BrowserRouter as Router, Route, Routes, useParams } from 'react-router-dom';
import HomePage from './pages/HomePage';
import { Footer } from './components/organisms/Footer';
import { Box, createStyles, makeStyles, Theme, ThemeProvider } from '@material-ui/core';
@@ -11,7 +11,7 @@ import { useTranslation } from 'react-i18next';
import { useTheme } from '@material-ui/core/styles';
import PopUpRedirect from './components/atoms/PopUpRedirect';
import WidgetsTemplate from './components/organisms/WidgetsTemplate';
import {observer} from "mobx-react-lite";
import { observer } from 'mobx-react-lite';
// main components height - must add up to 100

const headerHeight = '5vh';
@@ -31,7 +31,8 @@ const App: FC = () => {
const classes = useStyles();
const store = useStore();
const theme = useTheme();

const { newsId } = useParams();
console.log('🚀 ~ newsId:', newsId);
const appDir = i18n.dir();

useEffect(() => {
108 changes: 85 additions & 23 deletions src/components/atoms/InfiniteScroll.tsx
Original file line number Diff line number Diff line change
@@ -1,46 +1,108 @@
import React, { FC, useEffect, useCallback, useRef } from 'react';
import { makeStyles } from '@material-ui/core';
import { useStore } from 'store/storeConfig';
// InfiniteScroll.tsx
import { FC, UIEventHandler, useCallback, useRef } from 'react';
import { makeStyles } from '@material-ui/core/styles';

const TOP_THRESHOLD = 20; // Smaller threshold for top
const BOTTOM_THRESHOLD = 100; // Larger threshold for bottom
const INFINITE_SCROLLING_OFFSET: number = 30;

function isScrollEnd(element: HTMLDivElement) {
return element.scrollTop + element.clientHeight > element.scrollHeight - INFINITE_SCROLLING_OFFSET;
}

const useStyles = makeStyles({
root: {
overflow: 'auto',
position: 'relative',
height: '100%',
},
});

interface IProps {
onScrollEnd: () => any;
export enum Direction {
PREV = 'PREV',
NEXT = 'NEXT',
}

interface InfiniteScrollProps {
children: React.ReactNode;
onScroll: (direction: Direction) => void;
loading?: boolean;
}

const InfiniteScroll: FC<IProps> = ({ children, onScrollEnd }) => {
const InfiniteScroll: FC<InfiniteScrollProps> = ({ children, onScroll, loading = false }) => {
const classes = useStyles();
const scrollList = useRef<HTMLDivElement>(null);
const store = useStore();
const { newsFlashStore } = store;

const handleScroll = useCallback(() => {
if (scrollList.current !== null && !newsFlashStore.newsFlashLoading) {
if (isScrollEnd(scrollList.current)) {
onScrollEnd();
const containerRef = useRef<HTMLDivElement>(null);
const lastScrollTop = useRef(0);
const hasScrolledDown = useRef(false);
const initialLoading = useRef(true);

// const handleScroll = useCallback(
// (e) => {
// if (initialLoading.current) {
// initialLoading.current = false;
// return;
// }
// if (!e || loading) return;

// const { scrollTop, scrollHeight, clientHeight } = e.target;

// // Track scroll direction
// const direction: Direction = scrollTop > lastScrollTop.current ? Direction.NEXT : Direction.PREV;
// lastScrollTop.current = scrollTop;

// // Only set hasScrolledDown when actually scrolling down
// if (direction === Direction.NEXT && scrollTop > TOP_THRESHOLD) {
// hasScrolledDown.current = true;
// }

// // Near bottom - load more (larger threshold)
// if (scrollHeight - scrollTop - clientHeight <= BOTTOM_THRESHOLD) {
// onScroll(Direction.NEXT);
// }

// // Near top - load previous (smaller threshold)
// if (scrollTop <= TOP_THRESHOLD && hasScrolledDown.current) {
// onScroll(Direction.PREV);
// }
// },
// [loading, onScroll],
// );
const BUFFER_OFFSET = 500;
const handleScroll = useCallback(
(e) => {
if (initialLoading.current) {
initialLoading.current = false;
return;
}
}
}, [scrollList, onScrollEnd, newsFlashStore.newsFlashLoading]);
if (!e || loading) return;

useEffect(() => {
if (scrollList.current) {
scrollList.current.addEventListener('scroll', handleScroll);
}
}, [handleScroll]);
const { scrollTop, scrollHeight, clientHeight } = e.target;
const scrollOffset = scrollTop;
const totalSize = scrollHeight;

// Track direction
const direction: Direction = scrollTop > lastScrollTop.current ? Direction.NEXT : Direction.PREV;
lastScrollTop.current = scrollTop;

// Enable prev loading after scroll down
if (direction === Direction.NEXT) {
hasScrolledDown.current = true;
}

// Load more at bottom
if (scrollOffset > totalSize - clientHeight - BUFFER_OFFSET) {
onScroll(Direction.NEXT);
}

// Load previous at top
if (scrollOffset < BUFFER_OFFSET && hasScrolledDown.current) {
onScroll(Direction.PREV);
}
},
[loading, onScroll],
);

return (
<div ref={scrollList} className={classes.root}>
<div ref={containerRef} className={classes.root} onScroll={handleScroll}>
{children}
</div>
);
64 changes: 43 additions & 21 deletions src/components/organisms/News.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { FC } from 'react';
import { FC, useEffect, useRef } from 'react';
import { Typography } from 'components/atoms';
import { Box, makeStyles } from '@material-ui/core';
import { useStore } from 'store/storeConfig';
@@ -7,41 +7,63 @@ import RootStore from 'store/root.store';
import { observer } from 'mobx-react-lite';
import LocationSearchIndicator from 'components/molecules/LocationSearchIndicator';
import { IRouteProps } from 'models/Route';
import NewsFlashComp from "components/molecules/NewsFlashComp";

import NewsFlashComp from 'components/molecules/NewsFlashComp';

const useStyles = makeStyles({
container: {},
newsFeed: {
display: 'flex',
flexDirection: 'column',
flexGrow: 1,
overflow: 'auto',
},
});

<img src="" alt="" />
<img src="" alt="" />;

const News: FC = () => {
const store: RootStore = useStore();
const classes = useStyles();
const { gpsId, street, city } = useParams<IRouteProps>();
const { gpsId, street, city, newsId = '' } = useParams<IRouteProps>();
const { newsFlashStore } = store;
const selectedItemRef = useRef<HTMLDivElement>(null);
const containerRef = useRef<HTMLDivElement>(null);

useEffect(() => {
if (newsId && newsFlashStore.newsFlashCollection.data.length > 0 && !newsFlashStore.newsFlashLoading) {
// Find selected item index
const itemIndex = newsFlashStore.newsFlashCollection.data.findIndex((item) => item.id.toString() === newsId);

if (itemIndex !== -1) {
setTimeout(() => {
selectedItemRef.current?.scrollIntoView({
behavior: 'smooth',
block: 'center',
});
}, 100);
}
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);

return (
<Box flexGrow={1} display="flex" flexDirection="column" className={classes.newsFeed}>
<Box flexGrow={1}>
<Box className={classes.container} flexDirection={'column'}>
{gpsId && <LocationSearchIndicator searchType={'gps'} />}
{street && city && <LocationSearchIndicator searchType={'cityAndStreet'} />}
{newsFlashStore.newsFlashCollection.length > 0 ? (
newsFlashStore.newsFlashCollection.map((news) =>
<NewsFlashComp news={news} />
)
) : (
<Box p={1}>
<Typography.Body4>לא נמצאו תוצאות מהמקור המבוקש</Typography.Body4>
</Box>
)}
<div ref={containerRef} className={classes.newsFeed}>
{gpsId && <LocationSearchIndicator searchType={'gps'} />}
{street && city && <LocationSearchIndicator searchType={'cityAndStreet'} />}
{newsFlashStore.newsFlashCollection.data.length > 0 ? (
newsFlashStore.newsFlashCollection.data.map((news, index) => {
return (
<div key={news.id} ref={selectedItemRef}>
<NewsFlashComp news={news} />
</div>
);
})
) : (
<Box p={1}>
<Typography.Body4>לא נמצאו תוצאות מהמקור המבוקש</Typography.Body4>
</Box>
</Box>
</Box>
)}
</div>
);
};

23 changes: 16 additions & 7 deletions src/components/organisms/SideBar.tsx
Original file line number Diff line number Diff line change
@@ -11,8 +11,7 @@ import RootStore from 'store/root.store';
import { InfiniteScroll } from 'components/atoms';
import SideBarMap from 'components/molecules/SideBarMap';
import { useTranslation } from 'react-i18next';

const INFINITE_SCROLL_FETCH_SIZE = 100;
import { Direction } from 'hooks/useScrollObserver.hooks';

interface IProps {}

@@ -37,10 +36,20 @@ const SideBar: FC<IProps> = () => {
const mapTitle = `${t('sideBar')}`;
const location = newsFlashStore.activeNewsFlashLocation;
const loading = newsFlashStore.newsFlashLoading;
const initialPageNumber = newsFlashStore.newsFlashInitialPageNumber;
const currentPageNumber = newsFlashStore.newsFlashPageNumber;
const totalPages = newsFlashStore.newsFlashCollection.pagination.totalPages;

const fetchMoreNewsItems = useCallback(() => {
newsFlashStore.infiniteFetchLimit(INFINITE_SCROLL_FETCH_SIZE);
}, [newsFlashStore]);
const fetchMoreNewsItems = useCallback(
(direction: Direction) => {
if (direction === Direction.PREV && initialPageNumber !== 1 && currentPageNumber > 1) {
newsFlashStore.filterNewsFlashCollection(direction);
} else if (totalPages > currentPageNumber) {
newsFlashStore.filterNewsFlashCollection(Direction.NEXT);
}
},
[currentPageNumber, initialPageNumber, newsFlashStore, totalPages],
);

return (
<Box display="flex" flexDirection="column" justifyContent="center" alignItems="stretch">
@@ -51,7 +60,7 @@ const SideBar: FC<IProps> = () => {
<NewsFlashFilterPanel />
</ErrorBoundary>
</Box>
<InfiniteScroll onScrollEnd={fetchMoreNewsItems}>
<InfiniteScroll onScroll={fetchMoreNewsItems} loading={newsFlashStore.newsFlashLoading}>
<News />
</InfiniteScroll>
</Box>
@@ -62,7 +71,7 @@ const SideBar: FC<IProps> = () => {
{location && (
<ErrorBoundary>
<SideBarMap items={[location]} />
</ErrorBoundary>
</ErrorBoundary>
)}
</Box>
</Box>
Loading