From 165c79d82f31b2bca46ad107751213337c062fc3 Mon Sep 17 00:00:00 2001 From: Fedor Katurov <gotham48@gmail.com> Date: Mon, 17 Oct 2022 12:29:04 +0600 Subject: [PATCH] added lab loader --- src/containers/lab/LabGrid/index.tsx | 45 ++---------------- src/containers/lab/LabLoading/index.tsx | 36 +++++++++++++++ src/hooks/lab/useGetLabNodes.ts | 61 +++++++++++++++---------- src/layouts/LabLayout/index.tsx | 7 ++- 4 files changed, 83 insertions(+), 66 deletions(-) create mode 100644 src/containers/lab/LabLoading/index.tsx diff --git a/src/containers/lab/LabGrid/index.tsx b/src/containers/lab/LabGrid/index.tsx index 98b9e173..a8b9c1a3 100644 --- a/src/containers/lab/LabGrid/index.tsx +++ b/src/containers/lab/LabGrid/index.tsx @@ -1,52 +1,17 @@ -import React, { FC } from 'react'; +import { FC, memo } from 'react'; import { Columns } from '~/components/containers/Columns'; import { InfiniteScroll } from '~/components/containers/InfiniteScroll'; import { LabNoResults } from '~/components/lab/LabNoResults'; import { LabNode } from '~/components/lab/LabNode'; -import { EMPTY_NODE, NODE_TYPES } from '~/constants/node'; import { useLabContext } from '~/utils/context/LabContextProvider'; -import { values } from '~/utils/ramda'; import styles from './styles.module.scss'; interface IProps {} -const breakpointCols = { - default: 2, - 1280: 1, -}; - -const getRandomNodeType = () => - values(NODE_TYPES)[Math.floor(Math.random() * values(NODE_TYPES).length)]; - -const LoadingNode = () => ( - <LabNode - node={{ ...EMPTY_NODE, type: getRandomNodeType() }} - isLoading - lastSeen="" - commentCount={0} - /> -); - -const LabGrid: FC<IProps> = () => { - const { isLoading, nodes, hasMore, loadMore, search, setSearch } = useLabContext(); - - if (isLoading) { - return ( - <Columns> - <LoadingNode /> - <LoadingNode /> - <LoadingNode /> - <LoadingNode /> - <LoadingNode /> - <LoadingNode /> - <LoadingNode /> - <LoadingNode /> - <LoadingNode /> - </Columns> - ); - } +const LabGrid: FC<IProps> = memo(() => { + const { nodes, hasMore, loadMore, search, setSearch } = useLabContext(); if (search && !nodes.length) { return <LabNoResults resetSearch={() => setSearch('')} />; @@ -56,7 +21,7 @@ const LabGrid: FC<IProps> = () => { <InfiniteScroll hasMore={hasMore} loadMore={loadMore}> <div className={styles.wrap}> <Columns> - {nodes.map(node => ( + {nodes.map((node) => ( <LabNode node={node.node} key={node.node.id} @@ -68,6 +33,6 @@ const LabGrid: FC<IProps> = () => { </div> </InfiniteScroll> ); -}; +}); export { LabGrid }; diff --git a/src/containers/lab/LabLoading/index.tsx b/src/containers/lab/LabLoading/index.tsx new file mode 100644 index 00000000..2e0b74bd --- /dev/null +++ b/src/containers/lab/LabLoading/index.tsx @@ -0,0 +1,36 @@ +import React, { FC, memo } from 'react'; + +import { Columns } from '~/components/containers/Columns'; +import { LabNode } from '~/components/lab/LabNode'; +import { EMPTY_NODE, NODE_TYPES } from '~/constants/node'; +import { values } from '~/utils/ramda'; + +interface LabLoadingProps {} + +const getRandomNodeType = () => + values(NODE_TYPES)[Math.floor(Math.random() * values(NODE_TYPES).length)]; + +const LoadingNode = memo(() => ( + <LabNode + node={{ ...EMPTY_NODE, type: getRandomNodeType() }} + isLoading + lastSeen="" + commentCount={0} + /> +)); + +const LabLoading: FC<LabLoadingProps> = memo(() => ( + <Columns> + <LoadingNode /> + <LoadingNode /> + <LoadingNode /> + <LoadingNode /> + <LoadingNode /> + <LoadingNode /> + <LoadingNode /> + <LoadingNode /> + <LoadingNode /> + </Columns> +)); + +export { LabLoading }; diff --git a/src/hooks/lab/useGetLabNodes.ts b/src/hooks/lab/useGetLabNodes.ts index 06dea212..144b274c 100644 --- a/src/hooks/lab/useGetLabNodes.ts +++ b/src/hooks/lab/useGetLabNodes.ts @@ -10,24 +10,25 @@ import { INode } from '~/types'; import { GetLabNodesRequest, ILabNode, LabNodesSort } from '~/types/lab'; import { flatten, uniqBy } from '~/utils/ramda'; -const getKey: (isUser: boolean, sort?: LabNodesSort, search?: string) => SWRInfiniteKeyLoader = ( - isUser, - sort, - search -) => (index, prev: ILabNode[]) => { - if (!isUser) return null; - if (index > 0 && (!prev?.length || prev.length < 20)) return null; +const getKey: ( + isUser: boolean, + sort?: LabNodesSort, + search?: string, +) => SWRInfiniteKeyLoader = + (isUser, sort, search) => (index, prev: ILabNode[]) => { + if (!isUser) return null; + if (index > 0 && (!prev?.length || prev.length < 20)) return null; - const props: GetLabNodesRequest = { - limit: 20, - offset: index * 20, - sort: sort || LabNodesSort.New, - search: search || '', + const props: GetLabNodesRequest = { + limit: 20, + offset: index * 20, + sort: sort || LabNodesSort.New, + search: search || '', + }; + + return JSON.stringify(props); }; - return JSON.stringify(props); -}; - const parseKey = (key: string): GetLabNodesRequest => { try { return JSON.parse(key); @@ -49,12 +50,15 @@ export const useGetLabNodes = (sort?: LabNodesSort, search?: string) => { }, { fallbackData: [labStore.nodes], - onSuccess: data => labStore.setNodes(flatten(data)), + onSuccess: (data) => labStore.setNodes(flatten(data)), dedupingInterval: 300, - } + }, ); - const nodes = useMemo(() => uniqBy(n => n.node.id, flatten(data || [])), [data]); + const nodes = useMemo( + () => uniqBy((n) => n.node.id, flatten(data || [])), + [data], + ); const hasMore = (data?.[size - 1]?.length || 0) >= 1; const loadMore = useCallback(() => setSize(size + 1), [setSize, size]); @@ -63,20 +67,29 @@ export const useGetLabNodes = (sort?: LabNodesSort, search?: string) => { async (node: ILabNode) => { await mutate([[node], ...(data || [])]); }, - [data, mutate] + [data, mutate], ); /** updates node on cache */ const updateNode = useCallback( async (nodeId: number, node: Partial<INode>) => { await mutate( - data?.map(page => - page.map(it => (it.node.id === nodeId ? { ...it, node: { ...it.node, node } } : it)) - ) + data?.map((page) => + page.map((it) => + it.node.id === nodeId ? { ...it, node: { ...it.node, node } } : it, + ), + ), ); }, - [data, mutate] + [data, mutate], ); - return { nodes, isLoading: !data && isValidating, hasMore, loadMore, unshift, updateNode }; + return { + nodes, + isLoading: !!data?.length && isValidating, + hasMore, + loadMore, + unshift, + updateNode, + }; }; diff --git a/src/layouts/LabLayout/index.tsx b/src/layouts/LabLayout/index.tsx index b5c6fb23..02a42b1d 100644 --- a/src/layouts/LabLayout/index.tsx +++ b/src/layouts/LabLayout/index.tsx @@ -1,9 +1,10 @@ -import React, { FC } from 'react'; +import React, { FC, useMemo } from 'react'; import { Group } from '~/components/containers/Group'; import { Sticky } from '~/components/containers/Sticky'; import { LabHead } from '~/components/lab/LabHead'; import { LabGrid } from '~/containers/lab/LabGrid'; +import { LabLoading } from '~/containers/lab/LabLoading'; import { LabStats } from '~/containers/lab/LabStats'; import { Container } from '~/containers/main/Container'; import { SidebarRouter } from '~/containers/main/SidebarRouter'; @@ -13,6 +14,8 @@ import styles from './styles.module.scss'; interface IProps {} +const loader = <LabLoading />; + const LabLayout: FC<IProps> = () => { const { isLoading } = useLabContext(); @@ -25,7 +28,7 @@ const LabLayout: FC<IProps> = () => { <LabHead isLoading={isLoading} /> </div> - <LabGrid /> + {isLoading ? loader : <LabGrid />} </Group> <div className={styles.panel}>