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

removed search reducer completely

This commit is contained in:
Fedor Katurov 2022-01-04 15:51:44 +07:00
parent 38eedab3c2
commit b82ccfb786
22 changed files with 146 additions and 570 deletions

View file

@ -1,108 +0,0 @@
import React, { FC, useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { IFlowState } from '~/redux/flow/reducer';
import classNames from 'classnames';
import styles from './styles.module.scss';
import { getURL } from '~/utils/dom';
import { RouteComponentProps, useHistory, withRouter } from 'react-router';
import { PRESETS, URLS } from '~/constants/urls';
import { Icon } from '~/components/input/Icon';
import { INode } from '~/redux/types';
type IProps = RouteComponentProps & {
heroes: IFlowState['heroes'];
};
const FlowHeroUnconnected: FC<IProps> = ({ heroes }) => {
const preset = useMemo(() => (window.innerWidth <= 768 ? PRESETS.cover : PRESETS.small_hero), []);
const [limit, setLimit] = useState(6);
const [current, setCurrent] = useState(0);
const [loaded, setLoaded] = useState<Partial<INode>[]>([]);
const timer = useRef<any>(null);
const history = useHistory();
const onLoad = useCallback(
(i: number) => {
setLoaded([...loaded, heroes[i]]);
},
[heroes, loaded, setLoaded]
);
const items = Math.min(heroes.length, limit);
const title = useMemo(() => {
return loaded[current]?.title || '';
}, [loaded, current]);
const onNext = useCallback(() => {
if (heroes.length > limit) setLimit(limit + 1);
setCurrent(current < items - 1 ? current + 1 : 0);
}, [current, items, limit, heroes.length]);
const onPrev = useCallback(() => setCurrent(current > 0 ? current - 1 : items - 1), [
current,
items,
]);
const goToNode = useCallback(() => {
history.push(URLS.NODE_URL(loaded[current].id));
}, [current, history, loaded]);
useEffect(() => {
timer.current = setTimeout(onNext, 5000);
return () => clearTimeout(timer.current);
}, [current, onNext]);
useEffect(() => {
if (loaded.length === 1) onNext();
}, [loaded, onNext]);
return (
<div className={styles.wrap}>
<div className={styles.loaders}>
{heroes.slice(0, items).map((hero, i) => (
<img
src={getURL({ url: hero.thumbnail }, preset)}
key={hero.id}
onLoad={() => onLoad(i)}
alt=""
/>
))}
</div>
{loaded.length > 0 && (
<div className={styles.info}>
<div className={styles.title_wrap}>{title}</div>
<div className={styles.buttons}>
<div className={styles.button} onClick={onPrev}>
<Icon icon="left" />
</div>
<div className={styles.button} onClick={onNext}>
<Icon icon="right" />
</div>
</div>
</div>
)}
{loaded.slice(0, limit).map((hero, index) => (
<div
className={classNames(styles.hero, {
[styles.is_visible]: true,
[styles.is_active]: current === index,
})}
style={{
backgroundImage: `url("${getURL({ url: hero.thumbnail }, preset)}")`,
}}
key={hero.id}
onClick={goToNode}
>
<img src={getURL({ url: hero.thumbnail }, preset)} alt={hero.thumbnail} />
</div>
))}
</div>
);
};
const FlowHero = withRouter(FlowHeroUnconnected);
export { FlowHero };

View file

@ -1,162 +0,0 @@
@import "src/styles/variables";
.wrap {
width: 100%;
height: 100%;
position: relative;
background: $content_bg;
border-radius: $cell_radius;
overflow: hidden;
user-select: none;
&::after {
content: ' ';
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: url('../../../sprites/stripes.svg') rgba(0, 0, 0, 0.3);
z-index: 4;
pointer-events: none;
box-shadow: inset transparentize($color: white, $amount: 0.85) 0 1px;
touch-action: none;
border-radius: $radius;
}
&::before {
content: ' ';
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: linear-gradient(
182deg,
transparentize($cell_shade, 1) 50%,
transparentize($cell_shade, 0) 95%
);
z-index: 4;
pointer-events: none;
touch-action: none;
}
}
.hero {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 150%;
display: none;
transition: opacity 2s, transform linear 5s 2s;
background: 50% 50% no-repeat;
background-size: cover;
border-radius: $cell_radius;
z-index: 2;
opacity: 0;
cursor: pointer;
transform: translate(0, 0);
img {
width: 0;
height: 0;
opacity: 0;
pointer-events: none;
touch-action: none;
}
&.is_visible {
display: block;
}
&.is_active {
opacity: 1;
z-index: 3;
will-change: transform;
// animation: rise 5s forwards;
transform: translate(0, -10%);
transition: opacity 2s, transform linear 5s;
}
}
.info {
display: flex;
position: absolute;
bottom: 0;
right: 0;
width: 100%;
padding: $gap;
box-sizing: border-box;
z-index: 5;
flex-direction: row;
align-items: flex-end;
pointer-events: none;
touch-action: none;
}
.title_wrap {
flex: 1;
white-space: nowrap;
display: flex;
margin-right: $gap;
overflow: hidden;
font: $font_hero_title;
text-transform: uppercase;
text-overflow: ellipsis;
line-height: 1.2em;
@include tablet {
white-space: initial;
word-wrap: break-word;
font: $font_32_bold;
max-height: 3.6em;
}
@include phone {
white-space: initial;
word-wrap: break-word;
font: $font_24_bold;
max-height: 3.6em;
}
}
.buttons {
display: flex;
align-items: center;
justify-content: center;
height: 48px;
flex-direction: row;
width: 96px;
border-radius: $radius;
pointer-events: all;
touch-action: auto;
.button {
cursor: pointer;
flex: 0 0 48px;
display: flex;
align-items: center;
justify-content: center;
svg {
width: 40px;
height: 40px;
}
}
}
.loaders {
position: absolute;
top: 0;
left: 0;
opacity: 0;
pointer-events: none;
touch-action: none;
img {
position: absolute;
left: 0;
top: 0;
}
}

View file

@ -1,11 +1,11 @@
import React, { FC } from 'react';
import { IFlowState } from '~/redux/flow/reducer';
import { FlowRecentItem } from '../FlowRecentItem';
import styles from './styles.module.scss';
import { IFlowNode } from '~/redux/types';
interface IProps {
recent: IFlowState['recent'];
updated: IFlowState['updated'];
recent: IFlowNode[];
updated: IFlowNode[];
}
const FlowRecent: FC<IProps> = ({ recent, updated }) => {

View file

@ -1,37 +1,18 @@
import React, { FC, useCallback } from 'react';
import React, { FC } from 'react';
import styles from './styles.module.scss';
import { LoaderCircle } from '~/components/input/LoaderCircle';
import { FlowRecentItem } from '../FlowRecentItem';
import { Icon } from '~/components/input/Icon';
import { INode } from '~/redux/types';
import { InfiniteScroll } from '~/components/containers/InfiniteScroll';
interface IProps {
isLoading: boolean;
results: INode[];
hasMore: boolean;
onLoadMore: () => void;
}
const FlowSearchResults: FC<IProps> = ({ results, isLoading, onLoadMore }) => {
const onScroll = useCallback(
event => {
const el = event.target;
const bottom = el.scrollHeight - el.scrollTop - el.clientHeight;
if (bottom > 100) return;
onLoadMore();
},
[onLoadMore]
);
if (isLoading) {
return (
<div className={styles.loading}>
<LoaderCircle size={64} />
</div>
);
}
const FlowSearchResults: FC<IProps> = ({ results, isLoading, onLoadMore, hasMore }) => {
if (!results.length) {
return (
<div className={styles.loading}>
@ -42,10 +23,12 @@ const FlowSearchResults: FC<IProps> = ({ results, isLoading, onLoadMore }) => {
}
return (
<div className={styles.wrap} onScroll={onScroll}>
{results.map(node => (
<FlowRecentItem node={node} key={node.id} />
))}
<div className={styles.wrap}>
<InfiniteScroll hasMore={hasMore} loadMore={onLoadMore}>
{results.map(node => (
<FlowRecentItem node={node} key={node.id} />
))}
</InfiniteScroll>
</div>
);
};

View file

@ -7,18 +7,18 @@ import styles from './styles.module.scss';
import SwiperCore, { Autoplay, EffectFade, Lazy, Navigation } from 'swiper';
import { Icon } from '~/components/input/Icon';
import { IFlowState } from '~/redux/flow/reducer';
import { getURLFromString } from '~/utils/dom';
import { PRESETS, URLS } from '~/constants/urls';
import SwiperClass from 'swiper/types/swiper-class';
import { LoaderCircle } from '~/components/input/LoaderCircle';
import { useHistory } from 'react-router';
import classNames from 'classnames';
import { IFlowNode } from '~/redux/types';
SwiperCore.use([EffectFade, Lazy, Autoplay, Navigation]);
interface Props {
heroes: IFlowState['heroes'];
heroes: IFlowNode[];
}
export const FlowSwiperHero: FC<Props> = ({ heroes }) => {

View file

@ -21,8 +21,9 @@ import isBefore from 'date-fns/isBefore';
import { Authorized } from '~/components/containers/Authorized';
import { useShallowSelect } from '~/hooks/data/useShallowSelect';
import { selectLabUpdatesNodes } from '~/redux/lab/selectors';
import { selectFlowUpdated } from '~/redux/flow/selectors';
import { Button } from '~/components/input/Button';
import { useFlowStore } from '~/store/flow/useFlowStore';
import { observer } from 'mobx-react';
const mapStateToProps = (state: IState) => ({
user: pick(['username', 'is_user', 'photo', 'last_seen_boris'])(selectUser(state)),
@ -39,7 +40,7 @@ const mapDispatchToProps = {
type IProps = ReturnType<typeof mapStateToProps> & typeof mapDispatchToProps & {};
const HeaderUnconnected: FC<IProps> = memo(
const HeaderUnconnected: FC<IProps> = observer(
({
user,
user: { is_user, last_seen_boris },
@ -51,7 +52,7 @@ const HeaderUnconnected: FC<IProps> = memo(
}) => {
const [is_scrolled, setIsScrolled] = useState(false);
const labUpdates = useShallowSelect(selectLabUpdatesNodes);
const flowUpdates = useShallowSelect(selectFlowUpdated);
const { updated: flowUpdates } = useFlowStore();
const onLogin = useCallback(() => showDialog(DIALOGS.LOGIN), [showDialog]);
const onScroll = useCallback(() => {

View file

@ -21,11 +21,11 @@ interface IProps {
const FlowStamp: FC<IProps> = ({ isFluid, onToggleLayout }) => {
const {
searchText,
searchTotal,
hasMore: searchHasMore,
searchIsLoading,
searchResults,
onSearchChange,
onSearchLoadMore,
setSearchText,
loadMore: onSearchLoadMore,
} = useSearchContext();
const { recent, updates } = useFlowContext();
@ -34,7 +34,7 @@ const FlowStamp: FC<IProps> = ({ isFluid, onToggleLayout }) => {
event.preventDefault();
}, []);
const onClearSearch = useCallback(() => onSearchChange(''), [onSearchChange]);
const onClearSearch = useCallback(() => setSearchText(''), [setSearchText]);
const onKeyUp = useCallback(
event => {
@ -61,7 +61,7 @@ const FlowStamp: FC<IProps> = ({ isFluid, onToggleLayout }) => {
<InputText
title="Поиск"
value={searchText}
handler={onSearchChange}
handler={setSearchText}
after={after}
onKeyUp={onKeyUp}
/>
@ -73,11 +73,11 @@ const FlowStamp: FC<IProps> = ({ isFluid, onToggleLayout }) => {
<div className={styles.label}>
<span className={styles.label_text}>Результаты поиска</span>
<span className="line" />
<span>{!searchIsLoading && searchTotal}</span>
</div>
<div className={styles.items}>
<FlowSearchResults
hasMore={searchHasMore}
isLoading={searchIsLoading}
results={searchResults}
onLoadMore={onSearchLoadMore}

View file

@ -123,6 +123,8 @@
}
.search_results {
overflow: auto;
@include tablet {
margin-top: $gap;
}

View file

@ -1,13 +1,11 @@
import { useShallowSelect } from '~/hooks/data/useShallowSelect';
import { useFlowLayout } from '~/hooks/flow/useFlowLayout';
import { selectLabUpdatesNodes } from '~/redux/lab/selectors';
import { useDispatch } from 'react-redux';
import { useCallback, useMemo } from 'react';
import { FlowDisplay, INode } from '~/redux/types';
import { flowSetCellView } from '~/redux/flow/actions';
import { useMemo } from 'react';
import { useFlowLoader } from '~/hooks/flow/useFlowLoader';
import { useFlowStore } from '~/store/flow/useFlowStore';
import { useInfiniteLoader } from '~/hooks/dom/useInfiniteLoader';
import { useFlowSetCellView } from '~/hooks/flow/useFlowSetCellView';
export const useFlow = () => {
const { loadMore, isSyncing } = useFlowLoader();
@ -15,16 +13,11 @@ export const useFlow = () => {
const { nodes, heroes, recent, updated } = useFlowStore();
const { isFluid, toggleLayout } = useFlowLayout();
const labUpdates = useShallowSelect(selectLabUpdatesNodes);
const dispatch = useDispatch();
useInfiniteLoader(loadMore, isSyncing);
const updates = useMemo(() => [...updated, ...labUpdates].slice(0, 10), [updated, labUpdates]);
const onChangeCellView = useCallback(
(id: INode['id'], val: FlowDisplay) => dispatch(flowSetCellView(id, val)),
[dispatch]
);
const onChangeCellView = useFlowSetCellView();
return { nodes, heroes, recent, updates, isFluid, toggleLayout, onChangeCellView };
};

View file

@ -2,7 +2,6 @@ import { useLoadNode } from '~/hooks/node/useLoadNode';
import { useCallback } from 'react';
import { INode } from '~/redux/types';
import { apiPostNode } from '~/api/node';
import { selectFlowNodes } from '~/redux/flow/selectors';
import { selectLabListNodes } from '~/redux/lab/selectors';
import { labSetList } from '~/redux/lab/actions';
import { useShallowSelect } from '~/hooks/data/useShallowSelect';

View file

@ -1,24 +1,69 @@
import { useCallback } from 'react';
import { flowChangeSearch, flowLoadMoreSearch } from '~/redux/flow/actions';
import { useDispatch } from 'react-redux';
import { useShallowSelect } from '~/hooks/data/useShallowSelect';
import { selectFlow } from '~/redux/flow/selectors';
import { useCallback, useEffect, useState } from 'react';
import useSWRInfinite from 'swr/infinite';
import { flatten } from 'ramda';
import { getSearchResults } from '~/redux/flow/api';
import { KeyLoader } from 'swr';
import { INode } from '~/redux/types';
import { GetSearchResultsRequest } from '~/redux/flow/types';
import { COMMENTS_DISPLAY } from '~/constants/node';
const RESULTS_COUNT = 20;
const getKey: (text: string) => KeyLoader<INode[]> = text => (pageIndex, previousPageData) => {
if ((pageIndex > 0 && !previousPageData?.length) || !text) return null;
const props: GetSearchResultsRequest = {
text,
skip: pageIndex * RESULTS_COUNT,
take: RESULTS_COUNT,
};
return JSON.stringify(props);
};
export const useSearch = () => {
const dispatch = useDispatch();
const { search } = useShallowSelect(selectFlow);
const [searchText, setSearchText] = useState('');
const [debouncedSearchText, setDebouncedSearchText] = useState('');
const onSearchLoadMore = useCallback(() => {
if (search.is_loading_more) return;
dispatch(flowLoadMoreSearch());
}, [search.is_loading_more, dispatch]);
const { data, size, setSize, mutate, isValidating } = useSWRInfinite(
getKey(debouncedSearchText),
async (key: string) => {
const props: GetSearchResultsRequest = key && JSON.parse(key);
const onSearchChange = useCallback(
(text: string) => {
dispatch(flowChangeSearch({ text }));
},
[dispatch]
if (!props) {
return [] as INode[];
}
const result = await getSearchResults(props);
return result.nodes;
}
);
return { onSearchChange, onSearchLoadMore, search };
const loadMore = useCallback(() => setSize(size + 1), [setSize, size]);
const hasMore = (data?.[size - 1]?.length || 0) >= RESULTS_COUNT;
const results = flatten(data || []);
useEffect(() => {
const timeout = setTimeout(async () => {
setDebouncedSearchText(searchText.length > 2 ? searchText : '');
await setSize(0);
await mutate([]);
}, 300);
return () => clearTimeout(timeout);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [searchText]);
console.log({ hasMore, data });
return {
results,
searchText,
setSearchText,
hasMore,
loadMore,
isLoading: isValidating,
};
};

View file

@ -9,53 +9,56 @@ import { ProfilePageLeft } from '~/containers/profile/ProfilePageLeft';
import { Container } from '~/containers/main/Container';
import { FlowGrid } from '~/components/flow/FlowGrid';
import { Sticky } from '~/components/containers/Sticky';
import { selectFlow } from '~/redux/flow/selectors';
import { ProfilePageStats } from '~/containers/profile/ProfilePageStats';
import { Card } from '~/components/containers/Card';
import { useFlowStore } from '~/store/flow/useFlowStore';
import { observer } from 'mobx-react';
type Props = RouteComponentProps<{ username: string }> & {};
const ProfileLayout: FC<Props> = ({
match: {
params: { username },
},
}) => {
const { nodes } = useShallowSelect(selectFlow);
const user = useShallowSelect(selectUser);
const ProfileLayout: FC<Props> = observer(
({
match: {
params: { username },
},
}) => {
const { nodes } = useFlowStore();
const user = useShallowSelect(selectUser);
const dispatch = useDispatch();
const dispatch = useDispatch();
useEffect(() => {
dispatch(authLoadProfile(username));
}, [dispatch, username]);
useEffect(() => {
dispatch(authLoadProfile(username));
}, [dispatch, username]);
const profile = useShallowSelect(selectAuthProfile);
const profile = useShallowSelect(selectAuthProfile);
return (
<Container className={styles.wrap}>
<div className={styles.left}>
<Sticky>
<div className={styles.row}>
<ProfilePageLeft profile={profile} username={username} />
</div>
{!!profile.user?.description && (
return (
<Container className={styles.wrap}>
<div className={styles.left}>
<Sticky>
<div className={styles.row}>
<Card className={styles.description}>{profile.user.description}</Card>
<ProfilePageLeft profile={profile} username={username} />
</div>
)}
<div className={styles.row}>
<ProfilePageStats />
</div>
</Sticky>
</div>
{!!profile.user?.description && (
<div className={styles.row}>
<Card className={styles.description}>{profile.user.description}</Card>
</div>
)}
<div className={styles.grid}>
<FlowGrid nodes={nodes} user={user} onChangeCellView={console.log} />
</div>
</Container>
);
};
<div className={styles.row}>
<ProfilePageStats />
</div>
</Sticky>
</div>
<div className={styles.grid}>
<FlowGrid nodes={nodes} user={user} onChangeCellView={console.log} />
</div>
</Container>
);
}
);
export { ProfileLayout };

View file

@ -1,23 +0,0 @@
import { FLOW_ACTIONS } from './constants';
import { IFlowState } from './reducer';
import { INode } from '../types';
export const flowSetCellView = (id: INode['id'], flow: INode['flow']) => ({
type: FLOW_ACTIONS.SET_CELL_VIEW,
id,
flow,
});
export const flowSetSearch = (search: Partial<IFlowState['search']>) => ({
type: FLOW_ACTIONS.SET_SEARCH,
search,
});
export const flowChangeSearch = (search: Partial<IFlowState['search']>) => ({
type: FLOW_ACTIONS.CHANGE_SEARCH,
search,
});
export const flowLoadMoreSearch = () => ({
type: FLOW_ACTIONS.LOAD_MORE_SEARCH,
});

View file

@ -18,7 +18,7 @@ export const postCellView = ({ id, flow }: PostCellViewRequest) =>
.post<PostCellViewResult>(API.NODE.SET_CELL_VIEW(id), { flow })
.then(cleanResult);
export const getSearchResults = ({ text, skip = 0 }: GetSearchResultsRequest) =>
export const getSearchResults = ({ text, skip, take }: GetSearchResultsRequest) =>
api
.get<GetSearchResultsResult>(API.SEARCH.NODES, { params: { text, skip } })
.get<GetSearchResultsResult>(API.SEARCH.NODES, { params: { text, skip, take } })
.then(cleanResult);

View file

@ -1,9 +0,0 @@
const prefix = 'FLOW.';
export const FLOW_ACTIONS = {
SET_CELL_VIEW: `${prefix}SET_CELL_VIEW`,
SET_SEARCH: `${prefix}SET_SEARCH`,
CHANGE_SEARCH: `${prefix}CHANGE_SEARCH`,
LOAD_MORE_SEARCH: `${prefix}LOAD_MORE_SEARCH`,
};

View file

@ -1,18 +0,0 @@
import { FLOW_ACTIONS } from './constants';
import { flowSetSearch } from './actions';
import { IFlowState } from './reducer';
const setSearch = (
state: IFlowState,
{ search }: ReturnType<typeof flowSetSearch>
): IFlowState => ({
...state,
search: {
...state.search,
...search,
},
});
export const FLOW_HANDLERS = {
[FLOW_ACTIONS.SET_SEARCH]: setSearch,
};

View file

@ -1,37 +0,0 @@
import { createReducer } from '~/utils/reducer';
import { IError, IFlowNode, INode } from '../types';
import { FLOW_HANDLERS } from './handlers';
export type IFlowState = Readonly<{
isLoading: boolean;
nodes: IFlowNode[];
heroes: IFlowNode[];
recent: IFlowNode[];
updated: IFlowNode[];
search: {
text: string;
results: INode[];
total: number;
is_loading: boolean;
is_loading_more: boolean;
};
error: IError;
}>;
const INITIAL_STATE: IFlowState = {
nodes: [],
heroes: [],
recent: [],
updated: [],
search: {
text: '',
results: [],
total: 0,
is_loading: false,
is_loading_more: false,
},
isLoading: false,
error: '',
};
export default createReducer(INITIAL_STATE, FLOW_HANDLERS);

View file

@ -1,78 +0,0 @@
import { call, delay, put, race, select, take, takeLatest } from 'redux-saga/effects';
import { FLOW_ACTIONS } from './constants';
import { flowChangeSearch, flowSetSearch } from './actions';
import { Unwrap } from '../types';
import { selectFlow } from './selectors';
import { getSearchResults } from './api';
function* changeSearch({ search }: ReturnType<typeof flowChangeSearch>) {
try {
yield put(
flowSetSearch({
...search,
is_loading: !!search.text,
})
);
if (!search.text) return;
yield delay(500);
const data: Unwrap<typeof getSearchResults> = yield call(getSearchResults, {
text: search.text,
});
yield put(
flowSetSearch({
results: data.nodes,
total: data.total,
})
);
} catch (error) {
yield put(flowSetSearch({ results: [], total: 0 }));
} finally {
yield put(flowSetSearch({ is_loading: false }));
}
}
function* loadMoreSearch() {
try {
yield put(
flowSetSearch({
is_loading_more: true,
})
);
const { search }: ReturnType<typeof selectFlow> = yield select(selectFlow);
const { result, delay }: { result: Unwrap<typeof getSearchResults>; delay: any } = yield race({
result: call(getSearchResults, {
...search,
skip: search.results.length,
}),
delay: take(FLOW_ACTIONS.CHANGE_SEARCH),
});
if (delay) {
return;
}
yield put(
flowSetSearch({
results: [...search.results, ...result.nodes],
total: result.total,
})
);
} catch (error) {
yield put(
flowSetSearch({
is_loading_more: false,
})
);
}
}
export default function* nodeSaga() {
yield takeLatest(FLOW_ACTIONS.CHANGE_SEARCH, changeSearch);
yield takeLatest(FLOW_ACTIONS.LOAD_MORE_SEARCH, loadMoreSearch);
}

View file

@ -1,6 +0,0 @@
import { IState } from '../store';
import { IFlowState } from './reducer';
export const selectFlow = (state: IState): IFlowState => state.flow;
export const selectFlowNodes = (state: IState) => state.flow.nodes;
export const selectFlowUpdated = (state: IState) => state.flow.updated;

View file

@ -2,7 +2,8 @@ import { INode } from '~/redux/types';
export type GetSearchResultsRequest = {
text: string;
skip?: number;
take: number;
skip: number;
};
export type GetSearchResultsResult = {
nodes: INode[];

View file

@ -11,9 +11,6 @@ import auth from '~/redux/auth';
import authSaga from '~/redux/auth/sagas';
import { IAuthState } from '~/redux/auth/types';
import flow, { IFlowState } from '~/redux/flow/reducer';
import flowSaga from '~/redux/flow/sagas';
import lab from '~/redux/lab';
import labSaga from '~/redux/lab/sagas';
import { ILabState } from '~/redux/lab/types';
@ -59,7 +56,6 @@ export interface IState {
modal: IModalState;
router: RouterState;
uploads: IUploadState;
flow: IFlowState;
player: IPlayerState;
messages: IMessagesState;
lab: ILabState;
@ -81,7 +77,6 @@ export const store = createStore(
modal,
router: connectRouter(history),
uploads,
flow: persistReducer(flowPersistConfig, flow),
player: persistReducer(playerPersistConfig, player),
messages,
lab: lab,
@ -95,7 +90,6 @@ export function configureStore(): {
} {
sagaMiddleware.run(authSaga);
sagaMiddleware.run(uploadSaga);
sagaMiddleware.run(flowSaga);
sagaMiddleware.run(playerSaga);
sagaMiddleware.run(modalSaga);
sagaMiddleware.run(messagesSaga);

View file

@ -4,38 +4,34 @@ import { useSearch } from '~/hooks/search/useSearch';
export interface SearchContextProps {
searchText: string;
searchTotal: number;
hasMore: boolean;
searchIsLoading: boolean;
searchResults: INode[];
onSearchChange: (text: string) => void;
onSearchLoadMore: () => void;
setSearchText: (text: string) => void;
loadMore: () => void;
}
export const SearchContext = createContext<SearchContextProps>({
searchText: '',
searchTotal: 0,
hasMore: false,
searchIsLoading: false,
searchResults: [],
onSearchChange: () => {},
onSearchLoadMore: () => {},
setSearchText: () => {},
loadMore: () => {},
});
export const SearchContextProvider: FC = ({ children }) => {
const {
search: { text, results, is_loading, total },
onSearchLoadMore,
onSearchChange,
} = useSearch();
const { results, searchText, isLoading, loadMore, setSearchText, hasMore } = useSearch();
return (
<SearchContext.Provider
value={{
searchText: text,
searchText,
searchResults: results,
searchIsLoading: is_loading,
searchTotal: total,
onSearchChange,
onSearchLoadMore,
searchIsLoading: isLoading,
hasMore,
setSearchText,
loadMore,
}}
>
{children}