diff --git a/src/components/flow/Cell/index.tsx b/src/components/flow/Cell/index.tsx index 2823dfb6..059723c7 100644 --- a/src/components/flow/Cell/index.tsx +++ b/src/components/flow/Cell/index.tsx @@ -6,10 +6,8 @@ import classNames from 'classnames'; import styles from './styles.module.scss'; import markdown from '~/styles/common/markdown.module.scss'; import { Icon } from '~/components/input/Icon'; -import { flowSetCellView } from '~/redux/flow/actions'; import { PRESETS } from '~/constants/urls'; import { NODE_TYPES } from '~/redux/node/constants'; -import { Group } from '~/components/containers/Group'; import { Link } from 'react-router-dom'; const THUMBNAIL_SIZES = { @@ -21,8 +19,8 @@ interface IProps { is_text?: boolean; can_edit?: boolean; - onSelect: (id: INode['id'], type: INode['type']) => void; - onChangeCellView: typeof flowSetCellView; + onSelect: (id: INode['id']) => void; + onChangeCellView: (id: INode['id'], flow: INode['flow']) => void; } const Cell: FC = ({ diff --git a/src/components/flow/FlowGrid/index.tsx b/src/components/flow/FlowGrid/index.tsx index df0765ce..17e2c700 100644 --- a/src/components/flow/FlowGrid/index.tsx +++ b/src/components/flow/FlowGrid/index.tsx @@ -1,19 +1,22 @@ -import React, { FC, Fragment } from 'react'; +import React, { FC, Fragment, useCallback } from 'react'; import { Cell } from '~/components/flow/Cell'; import { IFlowState } from '~/redux/flow/reducer'; import { INode } from '~/redux/types'; import { canEditNode } from '~/utils/node'; import { IUser } from '~/redux/auth/types'; -import { flowSetCellView } from '~/redux/flow/actions'; +import { useHistory } from 'react-router'; +import { URLS } from '~/constants/urls'; type IProps = Partial & { user: Partial; - onSelect: (id: INode['id'], type: INode['type']) => void; - onChangeCellView: typeof flowSetCellView; + onChangeCellView: (id: INode['id'], flow: INode['flow']) => void; }; -export const FlowGrid: FC = ({ user, nodes, onSelect, onChangeCellView }) => { +export const FlowGrid: FC = ({ user, nodes, onChangeCellView }) => { + const history = useHistory(); + const onSelect = useCallback((id: INode['id']) => history.push(URLS.NODE_URL(id)), [history]); + if (!nodes) { return null; } diff --git a/src/components/flow/FlowRecentItem/index.tsx b/src/components/flow/FlowRecentItem/index.tsx index 16192e69..838daa29 100644 --- a/src/components/flow/FlowRecentItem/index.tsx +++ b/src/components/flow/FlowRecentItem/index.tsx @@ -6,6 +6,7 @@ import { NodeRelatedItem } from '~/components/node/NodeRelatedItem'; import { getPrettyDate } from '~/utils/dom'; import { Link } from 'react-router-dom'; import classNames from 'classnames'; +import { Icon } from '~/components/input/Icon'; interface IProps { node: Partial; @@ -15,13 +16,22 @@ interface IProps { const FlowRecentItem: FC = ({ node, has_new }) => { return ( -
+
{node.title || '...'}
-
{getPrettyDate(node.created_at)}
+ +
+ {!node.is_promoted && } + {getPrettyDate(node.created_at)} +
); diff --git a/src/components/flow/FlowRecentItem/styles.module.scss b/src/components/flow/FlowRecentItem/styles.module.scss index a666028f..1e3639e5 100644 --- a/src/components/flow/FlowRecentItem/styles.module.scss +++ b/src/components/flow/FlowRecentItem/styles.module.scss @@ -37,6 +37,12 @@ bottom: -2px; } } + + &.lab { + &::after { + background: $blue; + } + } } .info { @@ -55,8 +61,16 @@ .comment { font: $font_12_regular; margin-top: 4px; - opacity: 0.5; + color: darken(white, 50%); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; + display: flex; + align-items: center; + + svg { + fill: currentColor; + margin-right: $gap / 2; + margin-top: 1px; + } } diff --git a/src/components/flow/FlowStamp/index.tsx b/src/components/flow/FlowStamp/index.tsx index 04005887..e10071d7 100644 --- a/src/components/flow/FlowStamp/index.tsx +++ b/src/components/flow/FlowStamp/index.tsx @@ -13,20 +13,16 @@ interface IProps { recent: IFlowState['recent']; updated: IFlowState['updated']; search: IFlowState['search']; - flowChangeSearch: typeof FLOW_ACTIONS.flowChangeSearch; + onSearchChange: (text: string) => void; onLoadMore: () => void; } -const FlowStamp: FC = ({ recent, updated, search, flowChangeSearch, onLoadMore }) => { - const onSearchChange = useCallback((text: string) => flowChangeSearch({ text }), [ - flowChangeSearch, - ]); - +const FlowStamp: FC = ({ recent, updated, search, onSearchChange, onLoadMore }) => { const onSearchSubmit = useCallback((event: FormEvent) => { event.preventDefault(); }, []); - const onClearSearch = useCallback(() => flowChangeSearch({ text: '' }), [flowChangeSearch]); + const onClearSearch = useCallback(() => onSearchChange(''), [onSearchChange]); const onKeyUp = useCallback( event => { diff --git a/src/components/main/Header/index.tsx b/src/components/main/Header/index.tsx index 21eb7cea..83f37062 100644 --- a/src/components/main/Header/index.tsx +++ b/src/components/main/Header/index.tsx @@ -21,6 +21,9 @@ import * as AUTH_ACTIONS from '~/redux/auth/actions'; import { IState } from '~/redux/store'; import isBefore from 'date-fns/isBefore'; import { Authorized } from '~/components/containers/Authorized'; +import { useShallowSelect } from '~/utils/hooks/useShallowSelect'; +import { selectLabUpdates, selectLabUpdatesNodes } from '~/redux/lab/selectors'; +import { selectFlow, selectFlowUpdated } from '~/redux/flow/selectors'; const mapStateToProps = (state: IState) => ({ user: pick(['username', 'is_user', 'photo', 'last_seen_boris'])(selectUser(state)), @@ -48,7 +51,8 @@ const HeaderUnconnected: FC = memo( authOpenProfile, }) => { const [is_scrolled, setIsScrolled] = useState(false); - + const labUpdates = useShallowSelect(selectLabUpdatesNodes); + const flowUpdates = useShallowSelect(selectFlowUpdated); const onLogin = useCallback(() => showDialog(DIALOGS.LOGIN), [showDialog]); const onScroll = useCallback(() => { @@ -74,6 +78,9 @@ const HeaderUnconnected: FC = memo( [boris_commented_at, last_seen_boris] ); + const hasLabUpdates = useMemo(() => labUpdates.length > 0, [labUpdates]); + const hasFlowUpdates = useMemo(() => flowUpdates.length > 0, [flowUpdates]); + return createPortal(
@@ -83,7 +90,10 @@ const HeaderUnconnected: FC = memo(
ФЛОУ @@ -91,7 +101,10 @@ const HeaderUnconnected: FC = memo( ЛАБ @@ -99,7 +112,7 @@ const HeaderUnconnected: FC = memo( = () => { const tags = useShallowSelect(selectLabStatsTags); const heroes = useShallowSelect(selectLabStatsHeroes); const isLoading = useShallowSelect(selectLabStatsLoading); + const updates = useShallowSelect(selectLabUpdatesNodes); return ( @@ -42,6 +45,17 @@ const LabStats: FC = () => {
+ {updates.length > 0 && ( + <> +
Новые
+ + {updates.map(node => ( + + ))} + + + )} + {isLoading ? ( ) : ( diff --git a/src/containers/lab/LabStats/styles.module.scss b/src/containers/lab/LabStats/styles.module.scss index dee75ce6..86a04b08 100644 --- a/src/containers/lab/LabStats/styles.module.scss +++ b/src/containers/lab/LabStats/styles.module.scss @@ -23,3 +23,7 @@ background-color: $comment_bg; padding: $gap; } + +.updates { + padding: 0 $gap / 4 $gap * 2; +} diff --git a/src/layouts/FlowLayout/index.tsx b/src/layouts/FlowLayout/index.tsx index 1c02288a..e7e4ca7e 100644 --- a/src/layouts/FlowLayout/index.tsx +++ b/src/layouts/FlowLayout/index.tsx @@ -1,42 +1,29 @@ -import React, { FC, useCallback, useEffect } from 'react'; -import { connect } from 'react-redux'; +import React, { FC, useCallback, useEffect, useMemo } from 'react'; +import { useDispatch } from 'react-redux'; import { FlowGrid } from '~/components/flow/FlowGrid'; import { selectFlow } from '~/redux/flow/selectors'; -import * as NODE_ACTIONS from '~/redux/node/actions'; -import * as FLOW_ACTIONS from '~/redux/flow/actions'; -import { pick } from 'ramda'; +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 { IState } from '~/redux/store'; 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 { INode } from '~/redux/types'; +import { selectLabUpdatesNodes } from '~/redux/lab/selectors'; -const mapStateToProps = (state: IState) => ({ - flow: pick(['nodes', 'heroes', 'recent', 'updated', 'is_loading', 'search'], selectFlow(state)), - user: pick(['role', 'id'], selectUser(state)), -}); +const FlowLayout: FC = () => { + const { nodes, heroes, recent, updated, is_loading, search } = useShallowSelect(selectFlow); + const labUpdates = useShallowSelect(selectLabUpdatesNodes); + const user = useShallowSelect(selectUser); + const dispatch = useDispatch(); -const mapDispatchToProps = { - nodeGotoNode: NODE_ACTIONS.nodeGotoNode, - flowSetCellView: FLOW_ACTIONS.flowSetCellView, - flowGetMore: FLOW_ACTIONS.flowGetMore, - flowChangeSearch: FLOW_ACTIONS.flowChangeSearch, - flowLoadMoreSearch: FLOW_ACTIONS.flowLoadMoreSearch, -}; - -type IProps = ReturnType & typeof mapDispatchToProps & {}; - -const FlowLayoutUnconnected: FC = ({ - flow: { nodes, heroes, recent, updated, is_loading, search }, - user, - nodeGotoNode, - flowSetCellView, - flowGetMore, - flowChangeSearch, - flowLoadMoreSearch, -}) => { const onLoadMore = useCallback(() => { (window as any).flowScrollPos = window.scrollY; @@ -44,13 +31,29 @@ const FlowLayoutUnconnected: FC = ({ if (is_loading || pos < -600) return; - flowGetMore(); - }, [flowGetMore, is_loading]); + dispatch(flowGetMore()); + }, [dispatch, is_loading]); const onLoadMoreSearch = useCallback(() => { if (search.is_loading_more) return; - flowLoadMoreSearch(); - }, [search.is_loading_more, flowLoadMoreSearch]); + dispatch(flowLoadMoreSearch()); + }, [search.is_loading_more, dispatch]); + + const onChangeSearch = useCallback( + (text: string) => { + dispatch(flowChangeSearch({ text })); + }, + [dispatch] + ); + + const onChangeCellView = useCallback( + (id: INode['id'], flow: INode['flow']) => { + dispatch(flowSetCellView(id, flow)); + }, + [dispatch] + ); + + const cumulativeUpdates = useMemo(() => [...updated, ...labUpdates], [updated, labUpdates]); useEffect(() => { window.addEventListener('scroll', onLoadMore); @@ -72,19 +75,14 @@ const FlowLayoutUnconnected: FC = ({
- +
@@ -92,6 +90,4 @@ const FlowLayoutUnconnected: FC = ({ ); }; -const FlowLayout = connect(mapStateToProps, mapDispatchToProps)(FlowLayoutUnconnected); - -export { FlowLayout, FlowLayoutUnconnected }; +export { FlowLayout }; diff --git a/src/layouts/NodeLayout/index.tsx b/src/layouts/NodeLayout/index.tsx index 5e43d5ca..c75abed8 100644 --- a/src/layouts/NodeLayout/index.tsx +++ b/src/layouts/NodeLayout/index.tsx @@ -17,6 +17,7 @@ import { useScrollToTop } from '~/utils/hooks/useScrollToTop'; import { useLoadNode } from '~/utils/hooks/node/useLoadNode'; import { URLS } from '~/constants/urls'; import { EditorEditDialog } from '~/containers/dialogs/EditorEditDialog'; +import { useOnNodeSeen } from '~/utils/hooks/node/useOnNodeSeen'; type IProps = RouteComponentProps<{ id: string }> & {}; @@ -38,6 +39,7 @@ const NodeLayout: FC = memo( useNodeCoverImage(current); useScrollToTop([id]); useLoadNode(id, is_loading); + useOnNodeSeen(current); const { head, block } = useNodeBlocks(current, is_loading); diff --git a/src/redux/auth/sagas.ts b/src/redux/auth/sagas.ts index 40d8912b..da6d4cd5 100644 --- a/src/redux/auth/sagas.ts +++ b/src/redux/auth/sagas.ts @@ -58,6 +58,7 @@ import { messagesSet } from '~/redux/messages/actions'; import { SagaIterator } from 'redux-saga'; import { isEmpty } from 'ramda'; import { AxiosError } from 'axios'; +import { labGetUpdates } from '~/redux/lab/actions'; function* setTokenSaga({ token }: ReturnType) { localStorage.setItem('token', token); @@ -193,6 +194,7 @@ function* getUpdates() { function* startPollingSaga() { while (true) { yield call(getUpdates); + yield put(labGetUpdates()); yield delay(60000); } } diff --git a/src/redux/flow/actions.ts b/src/redux/flow/actions.ts index 97764d3f..fdd68dae 100644 --- a/src/redux/flow/actions.ts +++ b/src/redux/flow/actions.ts @@ -2,6 +2,10 @@ import { FLOW_ACTIONS } from './constants'; import { IFlowState } from './reducer'; import { INode } from '../types'; +export const flowGetFlow = () => ({ + type: FLOW_ACTIONS.GET_FLOW, +}); + export const flowSetNodes = (nodes: IFlowState['nodes']) => ({ nodes, type: FLOW_ACTIONS.SET_NODES, @@ -50,3 +54,8 @@ export const flowChangeSearch = (search: Partial) => ({ export const flowLoadMoreSearch = () => ({ type: FLOW_ACTIONS.LOAD_MORE_SEARCH, }); + +export const flowSeenNode = (nodeId: INode['id']) => ({ + type: FLOW_ACTIONS.SEEN_NODE, + nodeId, +}); diff --git a/src/redux/flow/constants.ts b/src/redux/flow/constants.ts index fecb6d93..e4e9ede5 100644 --- a/src/redux/flow/constants.ts +++ b/src/redux/flow/constants.ts @@ -14,4 +14,6 @@ export const FLOW_ACTIONS = { SET_SEARCH: `${prefix}SET_SEARCH`, CHANGE_SEARCH: `${prefix}CHANGE_SEARCH`, LOAD_MORE_SEARCH: `${prefix}LOAD_MORE_SEARCH`, + + SEEN_NODE: `${prefix}SEEN_NODE`, }; diff --git a/src/redux/flow/sagas.ts b/src/redux/flow/sagas.ts index 09f4ac8d..168561b4 100644 --- a/src/redux/flow/sagas.ts +++ b/src/redux/flow/sagas.ts @@ -16,6 +16,8 @@ import { Unwrap } from '../types'; import { selectFlow, selectFlowNodes } from './selectors'; import { getSearchResults, postCellView } from './api'; import { uniq } from 'ramda'; +import { labSeenNode, labSetUpdates } from '~/redux/lab/actions'; +import { selectLabUpdatesNodes } from '~/redux/lab/selectors'; function hideLoader() { const loader = document.getElementById('main_loader'); @@ -185,10 +187,16 @@ function* loadMoreSearch() { } } +function* seenNode({ nodeId }: ReturnType) { + const { updated }: ReturnType = yield select(selectFlow); + yield put(flowSetUpdated(updated.filter(node => node.id != nodeId))); +} + export default function* nodeSaga() { yield takeLatest([FLOW_ACTIONS.GET_FLOW, REHYDRATE], onGetFlow); yield takeLatest(FLOW_ACTIONS.SET_CELL_VIEW, onSetCellView); yield takeLeading(FLOW_ACTIONS.GET_MORE, getMore); yield takeLatest(FLOW_ACTIONS.CHANGE_SEARCH, changeSearch); yield takeLatest(FLOW_ACTIONS.LOAD_MORE_SEARCH, loadMoreSearch); + yield takeLatest(FLOW_ACTIONS.SEEN_NODE, seenNode); } diff --git a/src/redux/flow/selectors.ts b/src/redux/flow/selectors.ts index 9c5706ac..f0892de8 100644 --- a/src/redux/flow/selectors.ts +++ b/src/redux/flow/selectors.ts @@ -3,3 +3,4 @@ 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; diff --git a/src/redux/lab/actions.ts b/src/redux/lab/actions.ts index 438a8ad6..3617262f 100644 --- a/src/redux/lab/actions.ts +++ b/src/redux/lab/actions.ts @@ -1,5 +1,6 @@ import { LAB_ACTIONS } from '~/redux/lab/constants'; import { ILabState } from '~/redux/lab/types'; +import { INode } from '~/redux/types'; export const labGetList = (after?: string) => ({ type: LAB_ACTIONS.GET_LIST, @@ -19,3 +20,17 @@ export const labSetStats = (stats: Partial) => ({ type: LAB_ACTIONS.SET_STATS, stats, }); + +export const labSetUpdates = (updates: Partial) => ({ + type: LAB_ACTIONS.SET_UPDATES, + updates, +}); + +export const labGetUpdates = () => ({ + type: LAB_ACTIONS.GET_UPDATES, +}); + +export const labSeenNode = (nodeId: INode['id']) => ({ + type: LAB_ACTIONS.SEEN_NODE, + nodeId, +}); diff --git a/src/redux/lab/api.ts b/src/redux/lab/api.ts index 16bac864..87e6a7e8 100644 --- a/src/redux/lab/api.ts +++ b/src/redux/lab/api.ts @@ -1,6 +1,11 @@ import { api, cleanResult } from '~/utils/api'; import { API } from '~/constants/api'; -import { GetLabNodesRequest, GetLabNodesResult, GetLabStatsResult } from '~/redux/lab/types'; +import { + GetLabNodesRequest, + GetLabNodesResult, + GetLabStatsResult, + GetLabUpdatesResult, +} from '~/redux/lab/types'; export const getLabNodes = ({ after }: GetLabNodesRequest) => api @@ -8,3 +13,4 @@ export const getLabNodes = ({ after }: GetLabNodesRequest) => .then(cleanResult); export const getLabStats = () => api.get(API.LAB.STATS).then(cleanResult); +export const getLabUpdates = () => api.get(API.LAB.UPDATES).then(cleanResult); diff --git a/src/redux/lab/constants.ts b/src/redux/lab/constants.ts index 0b7979b8..16e2d985 100644 --- a/src/redux/lab/constants.ts +++ b/src/redux/lab/constants.ts @@ -6,4 +6,8 @@ export const LAB_ACTIONS = { GET_STATS: `${prefix}GET_STATS`, SET_STATS: `${prefix}SET_STATS`, + + SET_UPDATES: `${prefix}SET_UPDATES`, + GET_UPDATES: `${prefix}GET_UPDATES`, + SEEN_NODE: `${prefix}SET_UPDATE_SEEN`, }; diff --git a/src/redux/lab/handlers.ts b/src/redux/lab/handlers.ts index f23fada1..15c0b923 100644 --- a/src/redux/lab/handlers.ts +++ b/src/redux/lab/handlers.ts @@ -1,5 +1,5 @@ import { LAB_ACTIONS } from '~/redux/lab/constants'; -import { labSetList, labSetStats } from '~/redux/lab/actions'; +import { labSetList, labSetStats, labSetUpdates } from '~/redux/lab/actions'; import { ILabState } from '~/redux/lab/types'; type LabHandler any> = ( @@ -23,7 +23,16 @@ const setStats: LabHandler = (state, { stats }) => ({ }, }); +const setUpdates: LabHandler = (state, { updates }) => ({ + ...state, + updates: { + ...state.updates, + ...updates, + }, +}); + export const LAB_HANDLERS = { [LAB_ACTIONS.SET_LIST]: setList, [LAB_ACTIONS.SET_STATS]: setStats, + [LAB_ACTIONS.SET_UPDATES]: setUpdates, }; diff --git a/src/redux/lab/index.ts b/src/redux/lab/index.ts index 1a0bc0aa..95559f49 100644 --- a/src/redux/lab/index.ts +++ b/src/redux/lab/index.ts @@ -16,6 +16,10 @@ const INITIAL_STATE: ILabState = { tags: [], error: undefined, }, + updates: { + nodes: [], + isLoading: false, + }, }; export default createReducer(INITIAL_STATE, LAB_HANDLERS); diff --git a/src/redux/lab/sagas.ts b/src/redux/lab/sagas.ts index 1a66b3a5..5e3baaaf 100644 --- a/src/redux/lab/sagas.ts +++ b/src/redux/lab/sagas.ts @@ -1,8 +1,15 @@ -import { takeLeading, call, put } from 'redux-saga/effects'; -import { labGetList, labSetList, labSetStats } from '~/redux/lab/actions'; +import { takeLeading, call, put, select } from 'redux-saga/effects'; +import { + labGetList, + labSetList, + labSetStats, + labSetUpdates, + labSeenNode, +} from '~/redux/lab/actions'; import { LAB_ACTIONS } from '~/redux/lab/constants'; import { Unwrap } from '~/redux/types'; -import { getLabNodes, getLabStats } from '~/redux/lab/api'; +import { getLabNodes, getLabStats, getLabUpdates } from '~/redux/lab/api'; +import { selectLabUpdatesNodes } from '~/redux/lab/selectors'; function* getList({ after = '' }: ReturnType) { try { @@ -28,7 +35,28 @@ function* getStats() { } } +function* getUpdates() { + try { + yield put(labSetUpdates({ isLoading: true })); + const { nodes }: Unwrap = yield call(getLabUpdates); + yield put(labSetUpdates({ nodes })); + } catch (error) { + console.log(error.message); + } finally { + yield put(labSetUpdates({ isLoading: false })); + } +} + +function* seenNode({ nodeId }: ReturnType) { + const nodes: ReturnType = yield select(selectLabUpdatesNodes); + const newNodes = nodes.filter(node => node.id != nodeId); + yield put(labSetUpdates({ nodes: newNodes })); +} + 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); } diff --git a/src/redux/lab/selectors.ts b/src/redux/lab/selectors.ts index 9c47744c..6b9e52ca 100644 --- a/src/redux/lab/selectors.ts +++ b/src/redux/lab/selectors.ts @@ -6,3 +6,5 @@ export const selectLabList = (state: IState) => state.lab.list; export const selectLabStatsHeroes = (state: IState) => state.lab.stats.heroes; export const selectLabStatsTags = (state: IState) => state.lab.stats.tags; export const selectLabStatsLoading = (state: IState) => state.lab.stats.is_loading; +export const selectLabUpdates = (state: IState) => state.lab.updates; +export const selectLabUpdatesNodes = (state: IState) => state.lab.updates.nodes; diff --git a/src/redux/lab/types.ts b/src/redux/lab/types.ts index 4a188e97..6d583042 100644 --- a/src/redux/lab/types.ts +++ b/src/redux/lab/types.ts @@ -13,6 +13,10 @@ export type ILabState = Readonly<{ tags: ITag[]; error?: string; }; + updates: { + nodes: INode[]; + isLoading: boolean; + }; }>; export type GetLabNodesRequest = { @@ -34,3 +38,7 @@ export type GetLabStatsResult = { heroes: INode[]; tags: ITag[]; }; + +export type GetLabUpdatesResult = { + nodes: INode[]; +}; diff --git a/src/redux/node/sagas.ts b/src/redux/node/sagas.ts index 16232f05..31ff9776 100644 --- a/src/redux/node/sagas.ts +++ b/src/redux/node/sagas.ts @@ -177,13 +177,6 @@ function* onNodeLoad({ id }: ReturnType) { }) ); } catch {} - - // Remove current node from recently updated - const { updated } = yield select(selectFlow); - - if (updated.some(item => item.id === id)) { - yield put(flowSetUpdated(updated.filter(item => item.id !== id))); - } } function* onPostComment({ nodeId, comment, callback }: ReturnType) { diff --git a/src/utils/hooks/node/useOnNodeSeen.ts b/src/utils/hooks/node/useOnNodeSeen.ts new file mode 100644 index 00000000..f9e87d9e --- /dev/null +++ b/src/utils/hooks/node/useOnNodeSeen.ts @@ -0,0 +1,16 @@ +import { INode } from '~/redux/types'; +import { useDispatch } from 'react-redux'; +import { labSeenNode } from '~/redux/lab/actions'; +import { flowSeenNode } from '~/redux/flow/actions'; + +// useOnNodeSeen updates node seen status across all needed places +export const useOnNodeSeen = (node: INode) => { + const dispatch = useDispatch(); + + // Remove node from updated + if (node.is_promoted) { + dispatch(flowSeenNode(node.id)); + } else { + dispatch(labSeenNode(node.id)); + } +};