From 8faf22dbbfde18436855b8d57b4196bb39e56a47 Mon Sep 17 00:00:00 2001 From: Fedor Katurov Date: Thu, 9 Apr 2020 14:18:52 +0700 Subject: [PATCH] boris comment more properly showing --- src/components/node/NodeComments/index.tsx | 32 ++++++++++++++---- src/components/node/NodeComments/styles.scss | 7 ++++ src/containers/node/BorisLayout/index.tsx | 4 +++ src/containers/node/NodeLayout/index.tsx | 4 ++- src/redux/node/actions.ts | 4 +++ src/redux/node/api.ts | 2 +- src/redux/node/constants.ts | 1 + src/redux/node/sagas.ts | 35 ++++++++++++++++++-- src/redux/types.ts | 2 ++ 9 files changed, 80 insertions(+), 11 deletions(-) diff --git a/src/components/node/NodeComments/index.tsx b/src/components/node/NodeComments/index.tsx index a0da7ee0..ec5fe23e 100644 --- a/src/components/node/NodeComments/index.tsx +++ b/src/components/node/NodeComments/index.tsx @@ -7,7 +7,7 @@ import { ICommentGroup, IComment } from '~/redux/types'; import { groupCommentsByUser } from '~/utils/fn'; import { IUser } from '~/redux/auth/types'; import { canEditComment } from '~/utils/node'; -import { nodeLockComment, nodeEditComment } from '~/redux/node/actions'; +import { nodeLockComment, nodeEditComment, nodeLoadMoreComments } from '~/redux/node/actions'; import { INodeState } from '~/redux/node/reducer'; import { COMMENTS_DISPLAY } from '~/redux/node/constants'; import { plural } from '~/utils/dom'; @@ -19,11 +19,21 @@ interface IProps { user: IUser; onDelete: typeof nodeLockComment; onEdit: typeof nodeEditComment; + onLoadMore: typeof nodeLoadMoreComments; order?: 'ASC' | 'DESC'; } const NodeComments: FC = memo( - ({ comments, comment_data, user, onDelete, onEdit, comment_count = 0, order = 'DESC' }) => { + ({ + comments, + comment_data, + user, + onDelete, + onEdit, + onLoadMore, + comment_count = 0, + order = 'DESC', + }) => { const comments_left = useMemo(() => Math.max(0, comment_count - comments.length), [ comments, comment_count, @@ -34,10 +44,10 @@ const NodeComments: FC = memo( [comments, order] ); - return ( -
- {comment_count > 0 && ( -
+ const more = useMemo( + () => + comments_left > 0 && ( +
Показать ещё{' '} {plural( Math.min(comments_left, COMMENTS_DISPLAY), @@ -47,7 +57,13 @@ const NodeComments: FC = memo( )} {comments_left > COMMENTS_DISPLAY ? ` из ${comments_left} оставшихся` : ''}
- )} + ), + [comments_left, onLoadMore, COMMENTS_DISPLAY] + ); + + return ( +
+ {order === 'DESC' && more} {groupped.map(group => ( = memo( onEdit={onEdit} /> ))} + + {order === 'ASC' && more}
); } diff --git a/src/components/node/NodeComments/styles.scss b/src/components/node/NodeComments/styles.scss index 4da06029..d7d3e212 100644 --- a/src/components/node/NodeComments/styles.scss +++ b/src/components/node/NodeComments/styles.scss @@ -20,4 +20,11 @@ text-transform: uppercase; color: darken(white, 50%); font: $font_14_regular; + cursor: pointer; + transition: background-color 0.25s; + user-select: none; + + &:hover { + background-color: lighten($comment_bg, 4%); + } } diff --git a/src/containers/node/BorisLayout/index.tsx b/src/containers/node/BorisLayout/index.tsx index 62d682cc..791605b9 100644 --- a/src/containers/node/BorisLayout/index.tsx +++ b/src/containers/node/BorisLayout/index.tsx @@ -22,6 +22,7 @@ const mapDispatchToProps = { nodeLoadNode: NODE_ACTIONS.nodeLoadNode, nodeLockComment: NODE_ACTIONS.nodeLockComment, nodeEditComment: NODE_ACTIONS.nodeEditComment, + nodeLoadMoreComments: NODE_ACTIONS.nodeLoadMoreComments, }; type IProps = ReturnType & @@ -37,6 +38,7 @@ const BorisLayoutUnconnected: FC = ({ nodeLoadNode, nodeLockComment, nodeEditComment, + nodeLoadMoreComments, }) => { const title = getRandomPhrase('BORIS_TITLE'); @@ -92,6 +94,8 @@ const BorisLayoutUnconnected: FC = ({ user={user} onDelete={nodeLockComment} onEdit={nodeEditComment} + onLoadMore={nodeLoadMoreComments} + order="ASC" /> )} diff --git a/src/containers/node/NodeLayout/index.tsx b/src/containers/node/NodeLayout/index.tsx index a9922cf4..10be9540 100644 --- a/src/containers/node/NodeLayout/index.tsx +++ b/src/containers/node/NodeLayout/index.tsx @@ -15,7 +15,6 @@ import { NodeComments } from '~/components/node/NodeComments'; import { NodeTags } from '~/components/node/NodeTags'; import { NODE_COMPONENTS, NODE_INLINES } from '~/redux/node/constants'; import * as NODE_ACTIONS from '~/redux/node/actions'; -import { CommentForm } from '~/components/node/CommentForm'; import { selectUser } from '~/redux/auth/selectors'; import pick from 'ramda/es/pick'; import { NodeRelatedPlaceholder } from '~/components/node/NodeRelated/placeholder'; @@ -37,6 +36,7 @@ const mapDispatchToProps = { nodeLock: NODE_ACTIONS.nodeLock, nodeLockComment: NODE_ACTIONS.nodeLockComment, nodeEditComment: NODE_ACTIONS.nodeEditComment, + nodeLoadMoreComments: NODE_ACTIONS.nodeLoadMoreComments, }; type IProps = ReturnType & @@ -68,6 +68,7 @@ const NodeLayoutUnconnected: FC = memo( nodeSetCoverImage, nodeLockComment, nodeEditComment, + nodeLoadMoreComments, }) => { const [layout, setLayout] = useState({}); @@ -148,6 +149,7 @@ const NodeLayoutUnconnected: FC = memo( user={user} onDelete={nodeLockComment} onEdit={nodeEditComment} + onLoadMore={nodeLoadMoreComments} order="DESC" /> )} diff --git a/src/redux/node/actions.ts b/src/redux/node/actions.ts index 2e5b13bd..90fe809c 100644 --- a/src/redux/node/actions.ts +++ b/src/redux/node/actions.ts @@ -133,3 +133,7 @@ export const nodeSetCoverImage = (current_cover_image: IFile) => ({ type: NODE_ACTIONS.SET_COVER_IMAGE, current_cover_image, }); + +export const nodeLoadMoreComments = () => ({ + type: NODE_ACTIONS.LOAD_MORE_COMMENTS, +}); diff --git a/src/redux/node/api.ts b/src/redux/node/api.ts index 1ff0c0ec..f9807891 100644 --- a/src/redux/node/api.ts +++ b/src/redux/node/api.ts @@ -103,7 +103,7 @@ export const getNodeComments = ({ access: string; take?: number; skip?: number; -}): Promise> => +}): Promise> => api .get(API.NODE.COMMENT(id), configWithToken(access, { params: { take, skip } })) .then(resultMiddleware) diff --git a/src/redux/node/constants.ts b/src/redux/node/constants.ts index a3f9b253..46e81770 100644 --- a/src/redux/node/constants.ts +++ b/src/redux/node/constants.ts @@ -29,6 +29,7 @@ export const NODE_ACTIONS = { EDIT_COMMENT: `${prefix}EDIT_COMMENT`, CANCEL_COMMENT_EDIT: `${prefix}CANCEL_COMMENT_EDIT`, CREATE: `${prefix}CREATE`, + LOAD_MORE_COMMENTS: `${prefix}LOAD_MORE_COMMENTS`, SET_SAVE_ERRORS: `${prefix}SET_SAVE_ERRORS`, SET_LOADING: `${prefix}SET_LOADING`, diff --git a/src/redux/node/sagas.ts b/src/redux/node/sagas.ts index 9ba52d47..8ce5a8f5 100644 --- a/src/redux/node/sagas.ts +++ b/src/redux/node/sagas.ts @@ -1,4 +1,4 @@ -import { takeLatest, call, put, select, delay, all } from 'redux-saga/effects'; +import { takeLatest, call, put, select, delay, all, takeLeading } from 'redux-saga/effects'; import { push } from 'connected-react-router'; import omit from 'ramda/es/omit'; @@ -53,7 +53,7 @@ import { modalSetShown, modalShowDialog } from '../modal/actions'; import { selectFlowNodes, selectFlow } from '../flow/selectors'; import { URLS } from '~/constants/urls'; import { selectNode } from './selectors'; -import { IResultWithStatus, INode } from '../types'; +import { IResultWithStatus, INode, Unwrap } from '../types'; import { NODE_EDITOR_DIALOGS } from '~/constants/dialogs'; import { DIALOGS } from '~/redux/modal/constants'; import { INodeState } from './reducer'; @@ -119,6 +119,36 @@ function* onNodeGoto({ id, node_type }: ReturnType) { yield put(push(URLS.NODE_URL(id))); } +function* onNodeLoadMoreComments() { + const { + current: { id }, + comments, + }: ReturnType = yield select(selectNode); + + const { data, error }: Unwrap> = yield call( + reqWrapper, + getNodeComments, + { + id, + take: COMMENTS_DISPLAY, + skip: comments.length, + } + ); + + const current: ReturnType = yield select(selectNode); + + if (!data || error || current.current.id != id) { + return; + } + + yield put( + nodeSet({ + comments: [...comments, ...data.comments], + comment_count: data.comment_count, + }) + ); +} + function* onNodeLoad({ id, order = 'ASC' }: ReturnType) { yield put(nodeSetLoading(true)); yield put(nodeSetLoadingComments(true)); @@ -338,4 +368,5 @@ export default function* nodeSaga() { yield takeLatest(NODE_ACTIONS.LOCK, onLockSaga); yield takeLatest(NODE_ACTIONS.LOCK_COMMENT, onLockCommentSaga); yield takeLatest(NODE_ACTIONS.EDIT_COMMENT, onEditCommentSaga); + yield takeLeading(NODE_ACTIONS.LOAD_MORE_COMMENTS, onNodeLoadMoreComments); } diff --git a/src/redux/types.ts b/src/redux/types.ts index 8ef305fb..adb1e0fd 100644 --- a/src/redux/types.ts +++ b/src/redux/types.ts @@ -191,3 +191,5 @@ export type INodeNotification = { }; export type INotification = IMessageNotification | ICommentNotification; + +export type Unwrap = T extends Promise ? U : T;