diff --git a/src/layouts/FlowLayout/index.tsx b/src/layouts/FlowLayout/index.tsx index bede37cf..9d03bc87 100644 --- a/src/layouts/FlowLayout/index.tsx +++ b/src/layouts/FlowLayout/index.tsx @@ -55,10 +55,6 @@ const FlowLayout: FC = () => { labUpdates, ]); - useEffect(() => { - window.scrollTo(0, (window as any).flowScrollPos || 0); - }, []); - return (
diff --git a/src/layouts/LabLayout/index.tsx b/src/layouts/LabLayout/index.tsx index c1d02176..a083c346 100644 --- a/src/layouts/LabLayout/index.tsx +++ b/src/layouts/LabLayout/index.tsx @@ -15,6 +15,7 @@ import { Superpower } from '~/components/boris/Superpower'; import { Toggle } from '~/components/input/Toggle'; import { usePersistedState } from '~/utils/hooks/usePersistedState'; import classNames from 'classnames'; +import { useLabPagination } from '~/utils/hooks/lab/useLabPagination'; interface IProps {} @@ -22,6 +23,8 @@ const LabLayout: FC = () => { const { is_loading } = useShallowSelect(selectLabList); const dispatch = useDispatch(); + useLabPagination({ isLoading: is_loading }); + useEffect(() => { dispatch(labGetList()); dispatch(labGetStats()); diff --git a/src/redux/lab/actions.ts b/src/redux/lab/actions.ts index 3617262f..00dcc529 100644 --- a/src/redux/lab/actions.ts +++ b/src/redux/lab/actions.ts @@ -34,3 +34,7 @@ export const labSeenNode = (nodeId: INode['id']) => ({ type: LAB_ACTIONS.SEEN_NODE, nodeId, }); + +export const labGetMore = () => ({ + type: LAB_ACTIONS.GET_MORE, +}); diff --git a/src/redux/lab/constants.ts b/src/redux/lab/constants.ts index 16e2d985..bc2e150e 100644 --- a/src/redux/lab/constants.ts +++ b/src/redux/lab/constants.ts @@ -10,4 +10,5 @@ export const LAB_ACTIONS = { SET_UPDATES: `${prefix}SET_UPDATES`, GET_UPDATES: `${prefix}GET_UPDATES`, SEEN_NODE: `${prefix}SET_UPDATE_SEEN`, + GET_MORE: `${prefix}GET_MORE`, }; diff --git a/src/redux/lab/sagas.ts b/src/redux/lab/sagas.ts index 5e3baaaf..d19380bb 100644 --- a/src/redux/lab/sagas.ts +++ b/src/redux/lab/sagas.ts @@ -9,7 +9,7 @@ import { import { LAB_ACTIONS } from '~/redux/lab/constants'; import { Unwrap } from '~/redux/types'; import { getLabNodes, getLabStats, getLabUpdates } from '~/redux/lab/api'; -import { selectLabUpdatesNodes } from '~/redux/lab/selectors'; +import { selectLabList, selectLabUpdatesNodes } from '~/redux/lab/selectors'; function* getList({ after = '' }: ReturnType) { try { @@ -53,10 +53,39 @@ function* seenNode({ nodeId }: ReturnType) { yield put(labSetUpdates({ nodes: newNodes })); } +function* getMore() { + try { + yield put(labSetList({ is_loading: true })); + + const list: ReturnType = yield select(selectLabList); + if (list.nodes.length === list.count) { + return; + } + + const last = list.nodes[list.nodes.length]; + + if (!last) { + return; + } + + const after = last.node.created_at; + const { nodes, count }: Unwrap = yield call(getLabNodes, { after }); + const newNodes = [...list.nodes, ...nodes]; + + yield put(labSetList({ nodes: newNodes, count })); + } catch (error) { + yield put(labSetList({ error: error.message })); + } finally { + yield put(labSetList({ is_loading: false })); + } +} + export default function* labSaga() { yield takeLeading(LAB_ACTIONS.GET_LIST, getList); yield takeLeading(LAB_ACTIONS.GET_STATS, getStats); yield takeLeading(LAB_ACTIONS.GET_UPDATES, getUpdates); yield takeLeading(LAB_ACTIONS.SEEN_NODE, seenNode); + + yield takeLeading(LAB_ACTIONS.GET_MORE, getMore); } diff --git a/src/utils/hooks/flow/useFlowPagination.ts b/src/utils/hooks/flow/useFlowPagination.ts index 255d9f55..bb88461c 100644 --- a/src/utils/hooks/flow/useFlowPagination.ts +++ b/src/utils/hooks/flow/useFlowPagination.ts @@ -1,23 +1,10 @@ import { useCallback, useEffect } from 'react'; import { flowGetMore } from '~/redux/flow/actions'; import { useDispatch } from 'react-redux'; +import { useInfiniteLoader } from '~/utils/hooks/useInfiniteLoader'; export const useFlowPagination = ({ isLoading }) => { const dispatch = useDispatch(); - - const onLoadMore = useCallback(() => { - (window as any).flowScrollPos = window.scrollY; - - const pos = window.scrollY + window.innerHeight - document.body.scrollHeight; - - if (isLoading || pos < -600) return; - - dispatch(flowGetMore()); - }, [dispatch, isLoading]); - - useEffect(() => { - window.addEventListener('scroll', onLoadMore); - - return () => window.removeEventListener('scroll', onLoadMore); - }, [onLoadMore]); + const loadMore = useCallback(() => dispatch(flowGetMore()), []); + useInfiniteLoader(loadMore, isLoading); }; diff --git a/src/utils/hooks/lab/useLabPagination.ts b/src/utils/hooks/lab/useLabPagination.ts new file mode 100644 index 00000000..4fb8d071 --- /dev/null +++ b/src/utils/hooks/lab/useLabPagination.ts @@ -0,0 +1,21 @@ +import { useDispatch } from 'react-redux'; +import { useCallback } from 'react'; +import { useInfiniteLoader } from '~/utils/hooks/useInfiniteLoader'; +import { labGetMore } from '~/redux/lab/actions'; +import { useShallowSelect } from '~/utils/hooks/useShallowSelect'; +import { selectLabList } from '~/redux/lab/selectors'; + +export const useLabPagination = ({ isLoading }) => { + const { nodes, count } = useShallowSelect(selectLabList); + + const dispatch = useDispatch(); + const loadMore = useCallback(() => { + if (nodes.length >= count) { + return; + } + + dispatch(labGetMore()); + }, [nodes, count]); + + useInfiniteLoader(loadMore, isLoading); +}; diff --git a/src/utils/hooks/useInfiniteLoader.ts b/src/utils/hooks/useInfiniteLoader.ts new file mode 100644 index 00000000..e6eb2608 --- /dev/null +++ b/src/utils/hooks/useInfiniteLoader.ts @@ -0,0 +1,17 @@ +import { useCallback, useEffect } from 'react'; + +export const useInfiniteLoader = (loader: () => void, isLoading?: boolean) => { + const onLoadMore = useCallback(() => { + const pos = window.scrollY + window.innerHeight - document.body.scrollHeight; + + if (isLoading || pos < -600) return; + + loader(); + }, [loader, isLoading]); + + useEffect(() => { + window.addEventListener('scroll', onLoadMore); + + return () => window.removeEventListener('scroll', onLoadMore); + }, [onLoadMore]); +};