diff --git a/src/components/flow/FlowGrid/index.tsx b/src/components/flow/FlowGrid/index.tsx index 4bcdf6ef..d9ca30b6 100644 --- a/src/components/flow/FlowGrid/index.tsx +++ b/src/components/flow/FlowGrid/index.tsx @@ -1,7 +1,5 @@ import React, { FC, Fragment } from 'react'; - -import { IFlowState } from '~/redux/flow/reducer'; -import { FlowDisplay, INode } from '~/redux/types'; +import { FlowDisplay, IFlowNode, INode } from '~/redux/types'; import { IUser } from '~/redux/auth/types'; import { PRESETS, URLS } from '~/constants/urls'; import { FlowCell } from '~/components/flow/FlowCell'; @@ -10,7 +8,8 @@ import styles from './styles.module.scss'; import { getURLFromString } from '~/utils/dom'; import { canEditNode } from '~/utils/node'; -type IProps = Partial & { +type IProps = { + nodes: IFlowNode[]; user: Partial; onChangeCellView: (id: INode['id'], flow: FlowDisplay) => void; }; diff --git a/src/components/flow/FlowSearchResults/index.tsx b/src/components/flow/FlowSearchResults/index.tsx index b159ff40..d6b7be3d 100644 --- a/src/components/flow/FlowSearchResults/index.tsx +++ b/src/components/flow/FlowSearchResults/index.tsx @@ -1,16 +1,17 @@ import React, { FC, useCallback } from 'react'; import styles from './styles.module.scss'; -import { IFlowState } from '~/redux/flow/reducer'; import { LoaderCircle } from '~/components/input/LoaderCircle'; import { FlowRecentItem } from '../FlowRecentItem'; import { Icon } from '~/components/input/Icon'; +import { INode } from '~/redux/types'; interface IProps { - search: IFlowState['search']; + isLoading: boolean; + results: INode[]; onLoadMore: () => void; } -const FlowSearchResults: FC = ({ search, onLoadMore }) => { +const FlowSearchResults: FC = ({ results, isLoading, onLoadMore }) => { const onScroll = useCallback( event => { const el = event.target; @@ -23,7 +24,7 @@ const FlowSearchResults: FC = ({ search, onLoadMore }) => { [onLoadMore] ); - if (search.is_loading) { + if (isLoading) { return (
@@ -31,7 +32,7 @@ const FlowSearchResults: FC = ({ search, onLoadMore }) => { ); } - if (!search.results.length) { + if (!results.length) { return (
@@ -42,7 +43,7 @@ const FlowSearchResults: FC = ({ search, onLoadMore }) => { return (
- {search.results.map(node => ( + {results.map(node => ( ))}
diff --git a/src/components/flow/FlowStamp/index.tsx b/src/components/flow/FlowStamp/index.tsx index 3f206c6f..2e939504 100644 --- a/src/components/flow/FlowStamp/index.tsx +++ b/src/components/flow/FlowStamp/index.tsx @@ -1,5 +1,4 @@ import React, { FC, FormEvent, useCallback, useMemo } from 'react'; -import { IFlowState } from '~/redux/flow/reducer'; import { InputText } from '~/components/input/InputText'; import { FlowRecent } from '../FlowRecent'; @@ -11,25 +10,34 @@ import { Toggle } from '~/components/input/Toggle'; import classNames from 'classnames'; import { Superpower } from '~/components/boris/Superpower'; import { experimentalFeatures } from '~/constants/features'; +import { IFlowNode, INode } from '~/redux/types'; interface IProps { - recent: IFlowState['recent']; - updated: IFlowState['updated']; - search: IFlowState['search']; - isFluid: boolean; + searchText: string; + searchTotal: number; + searchIsLoading: boolean; + searchResults: INode[]; onSearchChange: (text: string) => void; - onLoadMore: () => void; - toggleLayout: () => void; + onSearchLoadMore: () => void; + + recent: IFlowNode[]; + updated: IFlowNode[]; + isFluid: boolean; + onToggleLayout: () => void; } const FlowStamp: FC = ({ + searchText, + searchIsLoading, + searchTotal, + searchResults, + onSearchChange, + onSearchLoadMore, + recent, updated, - search, - onSearchChange, - onLoadMore, isFluid, - toggleLayout, + onToggleLayout, }) => { const onSearchSubmit = useCallback((event: FormEvent) => { event.preventDefault(); @@ -48,12 +56,12 @@ const FlowStamp: FC = ({ const after = useMemo( () => - search.text ? ( + searchText ? ( ) : ( ), - [search.text] + [searchText] ); return ( @@ -61,7 +69,7 @@ const FlowStamp: FC = ({
= ({
- {search.text ? ( + {searchText ? ( <>
Результаты поиска - {!search.is_loading && search.total} + {!searchIsLoading && searchTotal}
- +
) : ( @@ -98,7 +110,7 @@ const FlowStamp: FC = ({ {experimentalFeatures.liquidFlow && (
- +
Жидкое течение
diff --git a/src/containers/main/MainRouter/index.tsx b/src/containers/main/MainRouter/index.tsx index f53e0334..84358a5f 100644 --- a/src/containers/main/MainRouter/index.tsx +++ b/src/containers/main/MainRouter/index.tsx @@ -1,6 +1,5 @@ import React, { FC } from 'react'; import { URLS } from '~/constants/urls'; -import { FlowLayout } from '~/layouts/FlowLayout'; import { NodeLayout } from '~/layouts/NodeLayout'; import { BorisLayout } from '~/layouts/BorisLayout'; import { ErrorNotFound } from '~/containers/pages/ErrorNotFound'; @@ -9,6 +8,7 @@ import { LabLayout } from '~/layouts/LabLayout'; import { useShallowSelect } from '~/utils/hooks/useShallowSelect'; import { selectAuthUser } from '~/redux/auth/selectors'; import { ProfileLayout } from '~/layouts/ProfileLayout'; +import FlowPage from '~/pages'; interface IProps {} @@ -25,7 +25,7 @@ const MainRouter: FC = () => { {is_user && } - + ); diff --git a/src/layouts/FlowLayout/index.tsx b/src/layouts/FlowLayout/index.tsx index c88aebbb..a6756640 100644 --- a/src/layouts/FlowLayout/index.tsx +++ b/src/layouts/FlowLayout/index.tsx @@ -1,61 +1,50 @@ -import React, { FC, useCallback, useEffect, useMemo, useState } from 'react'; -import { useDispatch } from 'react-redux'; +import React, { FC } from 'react'; import { FlowGrid } from '~/components/flow/FlowGrid'; -import { selectFlow } from '~/redux/flow/selectors'; -import { - flowChangeSearch, - flowGetMore, - flowLoadMoreSearch, - flowSetCellView, -} from '~/redux/flow/actions'; -import { selectUser } from '~/redux/auth/selectors'; -import { FlowHero } from '~/components/flow/FlowHero'; import styles from './styles.module.scss'; import { FlowStamp } from '~/components/flow/FlowStamp'; -import { Container } from '~/containers/main/Container'; import { SidebarRouter } from '~/containers/main/SidebarRouter'; -import { useShallowSelect } from '~/utils/hooks/useShallowSelect'; -import { FlowDisplay, INode } from '~/redux/types'; -import { selectLabUpdatesNodes } from '~/redux/lab/selectors'; -import { usePersistedState } from '~/utils/hooks/usePersistedState'; +import { FlowDisplay, IFlowNode, INode } from '~/redux/types'; import classNames from 'classnames'; -import { useFlowLayout } from '~/utils/hooks/flow/useFlowLayout'; -import { useFlowPagination } from '~/utils/hooks/flow/useFlowPagination'; import { FlowSwiperHero } from '~/components/flow/FlowSwiperHero'; +import { IUser } from '~/redux/auth/types'; -const FlowLayout: FC = () => { - const { nodes, heroes, recent, updated, isLoading, search } = useShallowSelect(selectFlow); - const { isFluid, toggleLayout } = useFlowLayout(); - const labUpdates = useShallowSelect(selectLabUpdatesNodes); - const user = useShallowSelect(selectUser); - const dispatch = useDispatch(); +interface Props { + updates: IFlowNode[]; + recent: IFlowNode[]; + heroes: IFlowNode[]; + nodes: IFlowNode[]; + user: IUser; + isFluid: boolean; + onToggleLayout: () => void; + onChangeCellView: (id: INode['id'], flow: FlowDisplay) => void; - useFlowPagination({ isLoading }); + searchText: string; + searchTotal: number; + searchIsLoading: boolean; + searchResults: INode[]; + onSearchChange: (text: string) => void; + onSearchLoadMore: () => void; +} - const onLoadMoreSearch = useCallback(() => { - if (search.is_loading_more) return; - dispatch(flowLoadMoreSearch()); - }, [search.is_loading_more, dispatch]); - - const onChangeSearch = useCallback( - (text: string) => { - dispatch(flowChangeSearch({ text })); - }, - [dispatch] - ); - - const cumulativeUpdates = useMemo(() => [...updated, ...labUpdates].slice(0, 10), [ - updated, - labUpdates, - ]); - - const onChangeCellView = useCallback( - (id: INode['id'], val: FlowDisplay) => dispatch(flowSetCellView(id, val)), - [] - ); +const FlowLayout: FC = ({ + updates, + heroes, + recent, + nodes, + user, + isFluid, + onToggleLayout, + onChangeCellView, + searchText, + searchTotal, + searchIsLoading, + searchResults, + onSearchChange, + onSearchLoadMore, +}) => { return ( -
+
@@ -63,13 +52,16 @@ const FlowLayout: FC = () => {
diff --git a/src/pages/index.tsx b/src/pages/index.tsx new file mode 100644 index 00000000..01943ef9 --- /dev/null +++ b/src/pages/index.tsx @@ -0,0 +1,34 @@ +import React, { FC } from 'react'; +import { FlowLayout } from '~/layouts/FlowLayout'; +import { useFlow } from '~/utils/hooks/flow/useFlow'; +import { useSearch } from '~/utils/hooks/search/useSearch'; +import { useUser } from '~/utils/hooks/user/userUser'; + +interface Props {} + +const FlowPage: FC = () => { + const { updates, nodes, heroes, recent, isFluid, toggleLayout, onChangeCellView } = useFlow(); + const user = useUser(); + const { search, onSearchLoadMore, onSearchChange } = useSearch(); + + return ( + + ); +}; + +export default FlowPage; diff --git a/src/redux/flow/reducer.ts b/src/redux/flow/reducer.ts index bbf7452a..5325fcdf 100644 --- a/src/redux/flow/reducer.ts +++ b/src/redux/flow/reducer.ts @@ -1,13 +1,13 @@ import { createReducer } from '~/utils/reducer'; -import { INode, IError } from '../types'; +import { IError, IFlowNode, INode } from '../types'; import { FLOW_HANDLERS } from './handlers'; export type IFlowState = Readonly<{ isLoading: boolean; - nodes: INode[]; - heroes: Partial[]; - recent: Partial[]; - updated: Partial[]; + nodes: IFlowNode[]; + heroes: IFlowNode[]; + recent: IFlowNode[]; + updated: IFlowNode[]; search: { text: string; results: INode[]; diff --git a/src/redux/types.ts b/src/redux/types.ts index 152e8eea..6a93719e 100644 --- a/src/redux/types.ts +++ b/src/redux/types.ts @@ -147,6 +147,11 @@ export interface INode { commented_at?: string; } +export type IFlowNode = Pick< + INode, + 'id' | 'flow' | 'description' | 'title' | 'thumbnail' | 'created_at' +>; + export interface IComment { id: number; text: string; diff --git a/src/utils/hooks/flow/useFlow.ts b/src/utils/hooks/flow/useFlow.ts new file mode 100644 index 00000000..8204fe9c --- /dev/null +++ b/src/utils/hooks/flow/useFlow.ts @@ -0,0 +1,27 @@ +import { useShallowSelect } from '~/utils/hooks/useShallowSelect'; +import { selectFlow } from '~/redux/flow/selectors'; +import { useFlowLayout } from '~/utils/hooks/flow/useFlowLayout'; +import { selectLabUpdatesNodes } from '~/redux/lab/selectors'; +import { useDispatch } from 'react-redux'; +import { useFlowPagination } from '~/utils/hooks/flow/useFlowPagination'; +import { useCallback, useMemo } from 'react'; +import { FlowDisplay, INode } from '~/redux/types'; +import { flowSetCellView } from '~/redux/flow/actions'; + +export const useFlow = () => { + const { nodes, heroes, recent, updated, isLoading } = useShallowSelect(selectFlow); + const { isFluid, toggleLayout } = useFlowLayout(); + const labUpdates = useShallowSelect(selectLabUpdatesNodes); + const dispatch = useDispatch(); + + useFlowPagination({ isLoading }); + + const updates = useMemo(() => [...updated, ...labUpdates].slice(0, 10), [updated, labUpdates]); + + const onChangeCellView = useCallback( + (id: INode['id'], val: FlowDisplay) => dispatch(flowSetCellView(id, val)), + [] + ); + + return { nodes, heroes, recent, updates, isFluid, toggleLayout, onChangeCellView }; +}; diff --git a/src/utils/hooks/search/useSearch.ts b/src/utils/hooks/search/useSearch.ts new file mode 100644 index 00000000..e2aff97e --- /dev/null +++ b/src/utils/hooks/search/useSearch.ts @@ -0,0 +1,24 @@ +import { useCallback } from 'react'; +import { flowChangeSearch, flowLoadMoreSearch } from '~/redux/flow/actions'; +import { useDispatch } from 'react-redux'; +import { useShallowSelect } from '~/utils/hooks/useShallowSelect'; +import { selectFlow } from '~/redux/flow/selectors'; + +export const useSearch = () => { + const dispatch = useDispatch(); + const { search } = useShallowSelect(selectFlow); + + const onSearchLoadMore = useCallback(() => { + if (search.is_loading_more) return; + dispatch(flowLoadMoreSearch()); + }, [search.is_loading_more, dispatch]); + + const onSearchChange = useCallback( + (text: string) => { + dispatch(flowChangeSearch({ text })); + }, + [dispatch] + ); + + return { onSearchChange, onSearchLoadMore, search }; +};