From 277f0fea43e40640329897c0a96d29fbbb0a8a88 Mon Sep 17 00:00:00 2001 From: Fedor Katurov Date: Wed, 6 Oct 2021 12:09:33 +0700 Subject: [PATCH] added highlight for new comments --- src/components/comment/Comment/index.tsx | 7 +- .../containers/CommentWrapper/index.tsx | 9 +- .../CommentWrapper/styles.module.scss | 24 ++++- src/components/node/NodeBottomBlock/index.tsx | 3 + src/components/node/NodeComments/index.tsx | 87 ++++++++++--------- .../node/NodeCommentsBlock/index.tsx | 18 +++- src/constants/comment.ts | 2 + src/layouts/NodeLayout/index.tsx | 4 +- src/redux/node/actions.ts | 6 -- src/redux/node/api.ts | 6 +- src/redux/node/constants.ts | 1 - src/redux/node/handlers.ts | 16 ---- src/redux/node/reducer.ts | 7 +- src/redux/node/sagas.ts | 11 +-- src/redux/node/types.ts | 2 +- src/redux/types.ts | 1 + src/utils/fn.ts | 20 ++++- src/utils/hooks/node/useGrouppedComments.ts | 17 ++++ src/utils/hooks/useScrollToTop.ts | 11 ++- 19 files changed, 158 insertions(+), 94 deletions(-) create mode 100644 src/utils/hooks/node/useGrouppedComments.ts diff --git a/src/components/comment/Comment/index.tsx b/src/components/comment/Comment/index.tsx index 622103e8..edd5005a 100644 --- a/src/components/comment/Comment/index.tsx +++ b/src/components/comment/Comment/index.tsx @@ -5,6 +5,8 @@ import { CommentContent } from '~/components/comment/CommentContent'; import styles from './styles.module.scss'; import { CommendDeleted } from '../../node/CommendDeleted'; import * as MODAL_ACTIONS from '~/redux/modal/actions'; +import classNames from 'classnames'; +import { NEW_COMMENT_CLASSNAME } from '~/constants/comment'; type IProps = HTMLAttributes & { is_empty?: boolean; @@ -30,11 +32,14 @@ const Comment: FC = memo( }) => { return (
diff --git a/src/components/containers/CommentWrapper/index.tsx b/src/components/containers/CommentWrapper/index.tsx index 2f80e466..59e5acb1 100644 --- a/src/components/containers/CommentWrapper/index.tsx +++ b/src/components/containers/CommentWrapper/index.tsx @@ -13,6 +13,7 @@ type IProps = DivProps & { isLoading?: boolean; isSame?: boolean; isForm?: boolean; + isNew?: boolean; }; const CommentWrapper: FC = ({ @@ -23,13 +24,15 @@ const CommentWrapper: FC = ({ isSame, isForm, children, + isNew, ...props }) => (
diff --git a/src/components/containers/CommentWrapper/styles.module.scss b/src/components/containers/CommentWrapper/styles.module.scss index f457a747..b44c96d0 100644 --- a/src/components/containers/CommentWrapper/styles.module.scss +++ b/src/components/containers/CommentWrapper/styles.module.scss @@ -1,5 +1,13 @@ @import "src/styles/variables"; +@keyframes highlight { + 0% { opacity: 0.75; } + 25% { opacity: 0.5; } + 50% { opacity: 0.75; } + 75% { opacity: 0; } + 100% { opacity: 0; } +} + .wrap { @include outer_shadow; @@ -10,15 +18,27 @@ min-width: 0; border-radius: $radius; - &:global(.is_empty) { + &.is_empty { opacity: 0.5; } - &:global(.is_same) { + &.is_same { margin: 0 !important; border-radius: 0; } + &.is_new::after { + content: ' '; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + animation: highlight 1s 0.25s forwards; + background: transparentize($wisegreen, 0.7); + border-radius: $radius; + } + @include tablet { flex-direction: column; } diff --git a/src/components/node/NodeBottomBlock/index.tsx b/src/components/node/NodeBottomBlock/index.tsx index a10bd12b..314c9d22 100644 --- a/src/components/node/NodeBottomBlock/index.tsx +++ b/src/components/node/NodeBottomBlock/index.tsx @@ -23,6 +23,7 @@ interface IProps { commentsCount: number; isLoadingComments: boolean; related: INodeRelated; + lastSeenCurrent?: string; } const NodeBottomBlock: FC = ({ @@ -34,6 +35,7 @@ const NodeBottomBlock: FC = ({ commentsCount, commentsOrder, related, + lastSeenCurrent, }) => { const { inline } = useNodeBlocks(node, isLoading); const { is_user } = useUser(); @@ -50,6 +52,7 @@ const NodeBottomBlock: FC = ({ {inline &&
{inline}
} = memo(({ comments, user, count = 0, order = 'DESC' }) => { - const dispatch = useDispatch(); - const left = useMemo(() => Math.max(0, count - comments.length), [comments, count]); +const NodeComments: FC = memo( + ({ comments, user, count = 0, order = 'DESC', lastSeenCurrent }) => { + const dispatch = useDispatch(); + const left = useMemo(() => Math.max(0, count - comments.length), [comments, count]); - const groupped: ICommentGroup[] = useMemo( - () => (order === 'DESC' ? [...comments].reverse() : comments).reduce(groupCommentsByUser, []), - [comments, order] - ); + const groupped: ICommentGroup[] = useGrouppedComments(comments, order, lastSeenCurrent); - const onDelete = useCallback( - (id: IComment['id'], locked: boolean) => dispatch(nodeLockComment(id, locked)), - [dispatch] - ); - const onLoadMoreComments = useCallback(() => dispatch(nodeLoadMoreComments()), [dispatch]); - const onShowPhotoswipe = useCallback( - (images: IFile[], index: number) => dispatch(modalShowPhotoswipe(images, index)), - [dispatch] - ); + const onDelete = useCallback( + (id: IComment['id'], locked: boolean) => dispatch(nodeLockComment(id, locked)), + [dispatch] + ); + const onLoadMoreComments = useCallback(() => dispatch(nodeLoadMoreComments()), [dispatch]); + const onShowPhotoswipe = useCallback( + (images: IFile[], index: number) => dispatch(modalShowPhotoswipe(images, index)), + [dispatch] + ); - const more = useMemo( - () => - left > 0 && ( -
- Показать ещё{' '} - {plural(Math.min(left, COMMENTS_DISPLAY), 'комментарий', 'комментария', 'комментариев')} - {left > COMMENTS_DISPLAY ? ` из ${left} оставшихся` : ''} -
- ), - [left, onLoadMoreComments] - ); + const more = useMemo( + () => + left > 0 && ( +
+ Показать ещё{' '} + {plural(Math.min(left, COMMENTS_DISPLAY), 'комментарий', 'комментария', 'комментариев')} + {left > COMMENTS_DISPLAY ? ` из ${left} оставшихся` : ''} +
+ ), + [left, onLoadMoreComments] + ); - return ( -
- {order === 'DESC' && more} + return ( +
+ {order === 'DESC' && more} - {groupped.map(group => ( - - ))} + {groupped.map(group => ( + + ))} - {order === 'ASC' && more} -
- ); -}); + {order === 'ASC' && more} +
+ ); + } +); export { NodeComments }; diff --git a/src/components/node/NodeCommentsBlock/index.tsx b/src/components/node/NodeCommentsBlock/index.tsx index f111dbff..d23c017e 100644 --- a/src/components/node/NodeCommentsBlock/index.tsx +++ b/src/components/node/NodeCommentsBlock/index.tsx @@ -10,18 +10,32 @@ interface IProps { node: INode; comments: IComment[]; count: number; + lastSeenCurrent?: string; isLoading: boolean; isLoadingComments: boolean; } -const NodeCommentsBlock: FC = ({ isLoading, isLoadingComments, node, comments, count }) => { +const NodeCommentsBlock: FC = ({ + isLoading, + isLoadingComments, + node, + comments, + count, + lastSeenCurrent, +}) => { const user = useUser(); const { inline } = useNodeBlocks(node, isLoading); return isLoading || isLoadingComments || (!comments.length && !inline) ? ( ) : ( - + ); }; diff --git a/src/constants/comment.ts b/src/constants/comment.ts index 9689c167..4d46d0f5 100644 --- a/src/constants/comment.ts +++ b/src/constants/comment.ts @@ -36,3 +36,5 @@ export const COMMENT_BLOCK_RENDERERS = { [COMMENT_BLOCK_TYPES.MARK]: CommentTextBlock, [COMMENT_BLOCK_TYPES.EMBED]: CommentEmbedBlock, }; + +export const NEW_COMMENT_CLASSNAME = 'newComment'; diff --git a/src/layouts/NodeLayout/index.tsx b/src/layouts/NodeLayout/index.tsx index 48b56896..4728ea09 100644 --- a/src/layouts/NodeLayout/index.tsx +++ b/src/layouts/NodeLayout/index.tsx @@ -36,10 +36,11 @@ const NodeLayout: FC = memo( comment_count, is_loading_comments, related, + lastSeenCurrent, } = useShallowSelect(selectNode); useNodeCoverImage(current); - useScrollToTop([id]); + useScrollToTop([id, comments, is_loading_comments]); useLoadNode(id, is_loading); useOnNodeSeen(current); @@ -65,6 +66,7 @@ const NodeLayout: FC = memo( related={related} isLoadingComments={is_loading_comments} isLoading={is_loading} + lastSeenCurrent={lastSeenCurrent} />