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]);
+};