1
0
Fork 0
mirror of https://github.com/muerwre/vault-frontend.git synced 2025-04-24 20:36:40 +07:00

added lab loader

This commit is contained in:
Fedor Katurov 2022-10-17 12:29:04 +06:00
parent dfcf0a541d
commit 165c79d82f
4 changed files with 83 additions and 66 deletions

View file

@ -1,52 +1,17 @@
import React, { FC } from 'react'; import { FC, memo } from 'react';
import { Columns } from '~/components/containers/Columns'; import { Columns } from '~/components/containers/Columns';
import { InfiniteScroll } from '~/components/containers/InfiniteScroll'; import { InfiniteScroll } from '~/components/containers/InfiniteScroll';
import { LabNoResults } from '~/components/lab/LabNoResults'; import { LabNoResults } from '~/components/lab/LabNoResults';
import { LabNode } from '~/components/lab/LabNode'; import { LabNode } from '~/components/lab/LabNode';
import { EMPTY_NODE, NODE_TYPES } from '~/constants/node';
import { useLabContext } from '~/utils/context/LabContextProvider'; import { useLabContext } from '~/utils/context/LabContextProvider';
import { values } from '~/utils/ramda';
import styles from './styles.module.scss'; import styles from './styles.module.scss';
interface IProps {} interface IProps {}
const breakpointCols = { const LabGrid: FC<IProps> = memo(() => {
default: 2, const { nodes, hasMore, loadMore, search, setSearch } = useLabContext();
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>
);
}
if (search && !nodes.length) { if (search && !nodes.length) {
return <LabNoResults resetSearch={() => setSearch('')} />; return <LabNoResults resetSearch={() => setSearch('')} />;
@ -56,7 +21,7 @@ const LabGrid: FC<IProps> = () => {
<InfiniteScroll hasMore={hasMore} loadMore={loadMore}> <InfiniteScroll hasMore={hasMore} loadMore={loadMore}>
<div className={styles.wrap}> <div className={styles.wrap}>
<Columns> <Columns>
{nodes.map(node => ( {nodes.map((node) => (
<LabNode <LabNode
node={node.node} node={node.node}
key={node.node.id} key={node.node.id}
@ -68,6 +33,6 @@ const LabGrid: FC<IProps> = () => {
</div> </div>
</InfiniteScroll> </InfiniteScroll>
); );
}; });
export { LabGrid }; export { LabGrid };

View file

@ -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 };

View file

@ -10,11 +10,12 @@ import { INode } from '~/types';
import { GetLabNodesRequest, ILabNode, LabNodesSort } from '~/types/lab'; import { GetLabNodesRequest, ILabNode, LabNodesSort } from '~/types/lab';
import { flatten, uniqBy } from '~/utils/ramda'; import { flatten, uniqBy } from '~/utils/ramda';
const getKey: (isUser: boolean, sort?: LabNodesSort, search?: string) => SWRInfiniteKeyLoader = ( const getKey: (
isUser, isUser: boolean,
sort, sort?: LabNodesSort,
search search?: string,
) => (index, prev: ILabNode[]) => { ) => SWRInfiniteKeyLoader =
(isUser, sort, search) => (index, prev: ILabNode[]) => {
if (!isUser) return null; if (!isUser) return null;
if (index > 0 && (!prev?.length || prev.length < 20)) return null; if (index > 0 && (!prev?.length || prev.length < 20)) return null;
@ -49,12 +50,15 @@ export const useGetLabNodes = (sort?: LabNodesSort, search?: string) => {
}, },
{ {
fallbackData: [labStore.nodes], fallbackData: [labStore.nodes],
onSuccess: data => labStore.setNodes(flatten(data)), onSuccess: (data) => labStore.setNodes(flatten(data)),
dedupingInterval: 300, 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 hasMore = (data?.[size - 1]?.length || 0) >= 1;
const loadMore = useCallback(() => setSize(size + 1), [setSize, size]); const loadMore = useCallback(() => setSize(size + 1), [setSize, size]);
@ -63,20 +67,29 @@ export const useGetLabNodes = (sort?: LabNodesSort, search?: string) => {
async (node: ILabNode) => { async (node: ILabNode) => {
await mutate([[node], ...(data || [])]); await mutate([[node], ...(data || [])]);
}, },
[data, mutate] [data, mutate],
); );
/** updates node on cache */ /** updates node on cache */
const updateNode = useCallback( const updateNode = useCallback(
async (nodeId: number, node: Partial<INode>) => { async (nodeId: number, node: Partial<INode>) => {
await mutate( await mutate(
data?.map(page => data?.map((page) =>
page.map(it => (it.node.id === nodeId ? { ...it, node: { ...it.node, node } } : it)) 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,
};
}; };

View file

@ -1,9 +1,10 @@
import React, { FC } from 'react'; import React, { FC, useMemo } from 'react';
import { Group } from '~/components/containers/Group'; import { Group } from '~/components/containers/Group';
import { Sticky } from '~/components/containers/Sticky'; import { Sticky } from '~/components/containers/Sticky';
import { LabHead } from '~/components/lab/LabHead'; import { LabHead } from '~/components/lab/LabHead';
import { LabGrid } from '~/containers/lab/LabGrid'; import { LabGrid } from '~/containers/lab/LabGrid';
import { LabLoading } from '~/containers/lab/LabLoading';
import { LabStats } from '~/containers/lab/LabStats'; import { LabStats } from '~/containers/lab/LabStats';
import { Container } from '~/containers/main/Container'; import { Container } from '~/containers/main/Container';
import { SidebarRouter } from '~/containers/main/SidebarRouter'; import { SidebarRouter } from '~/containers/main/SidebarRouter';
@ -13,6 +14,8 @@ import styles from './styles.module.scss';
interface IProps {} interface IProps {}
const loader = <LabLoading />;
const LabLayout: FC<IProps> = () => { const LabLayout: FC<IProps> = () => {
const { isLoading } = useLabContext(); const { isLoading } = useLabContext();
@ -25,7 +28,7 @@ const LabLayout: FC<IProps> = () => {
<LabHead isLoading={isLoading} /> <LabHead isLoading={isLoading} />
</div> </div>
<LabGrid /> {isLoading ? loader : <LabGrid />}
</Group> </Group>
<div className={styles.panel}> <div className={styles.panel}>