From bbcd949c6dd9cfc6deb42a8f17678afa02d4a0e6 Mon Sep 17 00:00:00 2001 From: Chaiwat Trisuwan Date: Mon, 13 May 2024 15:42:31 +0700 Subject: [PATCH] fix: ASC-21792 - comment list infinite scroll (#330) * fix: hyperlink background * fix: hyperlink icon color * fix: css * fix: add scroller * fix: comment * fix: scroll * fix: comment list * fix: reaction list * fix: comment date css shrink * fix: type * fix: css * fix: color * fix: comment scroll * fix: comment list * fix: use intersection observer instead * fix: padding --- .../BottomSheet/BottomSheet.module.css | 3 +- .../components/BottomSheet/BottomSheet.tsx | 6 +- .../LoadMoreWrapper.module.css | 7 ++ .../LoadMoreWrapper/LoadMoreWrapper.tsx | 53 +++++---- .../HyperLinkConfig.module.css | 5 +- .../ReactionList/ReactionList.module.css | 58 ++++++---- .../components/ReactionList/ReactionList.tsx | 1 - .../social/components/ReactionList/styles.tsx | 104 ------------------ .../Comment/UIComment.module.css | 8 +- .../internal-components/Comment/index.tsx | 6 +- .../CommentList/CommentList.tsx | 48 ++++---- 11 files changed, 114 insertions(+), 185 deletions(-) delete mode 100644 src/v4/social/components/ReactionList/styles.tsx diff --git a/src/v4/core/components/BottomSheet/BottomSheet.module.css b/src/v4/core/components/BottomSheet/BottomSheet.module.css index 747db51f9..b258fba24 100644 --- a/src/v4/core/components/BottomSheet/BottomSheet.module.css +++ b/src/v4/core/components/BottomSheet/BottomSheet.module.css @@ -14,7 +14,6 @@ which have higher specificity. .react-modal-sheet-header { display: flex; - height: 2.5rem; padding-bottom: 1rem; justify-content: center; align-items: center; @@ -22,9 +21,11 @@ which have higher specificity. align-self: stretch; background-color: var(--asc-color-base-background); color: var(--asc-color-base-default); + border-bottom: 1px solid var(--asc-color-base-shade4); } .react-modal-sheet-content { + display: flex; background-color: var(--asc-color-base-background); padding: 1rem; color: var(--asc-color-base-default); diff --git a/src/v4/core/components/BottomSheet/BottomSheet.tsx b/src/v4/core/components/BottomSheet/BottomSheet.tsx index 3eadd5e1b..d74a40450 100644 --- a/src/v4/core/components/BottomSheet/BottomSheet.tsx +++ b/src/v4/core/components/BottomSheet/BottomSheet.tsx @@ -1,7 +1,7 @@ import React from 'react'; + import Sheet from 'react-modal-sheet'; import { Typography } from '~/v4/core/components/Typography'; - import styles from './BottomSheet.module.css'; interface BottomSheetProps { @@ -37,9 +37,7 @@ export const BottomSheet = ({ children, headerTitle, ...props }: BottomSheetProp {headerTitle} )} - - {children} - + {children} diff --git a/src/v4/core/components/LoadMoreWrapper/LoadMoreWrapper.module.css b/src/v4/core/components/LoadMoreWrapper/LoadMoreWrapper.module.css index cc3eb1311..a766c66c0 100644 --- a/src/v4/core/components/LoadMoreWrapper/LoadMoreWrapper.module.css +++ b/src/v4/core/components/LoadMoreWrapper/LoadMoreWrapper.module.css @@ -41,3 +41,10 @@ .chevronDownIcon { margin-left: 0.3125rem; } + +.content { + display: flex; + flex-direction: column; + flex: 1; + overflow-y: auto; +} diff --git a/src/v4/core/components/LoadMoreWrapper/LoadMoreWrapper.tsx b/src/v4/core/components/LoadMoreWrapper/LoadMoreWrapper.tsx index fbb7328f3..175a74e1d 100644 --- a/src/v4/core/components/LoadMoreWrapper/LoadMoreWrapper.tsx +++ b/src/v4/core/components/LoadMoreWrapper/LoadMoreWrapper.tsx @@ -1,15 +1,14 @@ -import React, { useState, useEffect, ReactNode } from 'react'; +import React, { useState, useEffect, ReactNode, useRef } from 'react'; import { useIntl } from 'react-intl'; import clsx from 'clsx'; import { Button } from '~/v4/core/components'; import styles from './LoadMoreWrapper.module.css'; -import { ChevronDownIcon } from '~/v4/social/icons'; interface LoadMoreWrapperProps { - hasMore?: boolean; - loadMore?: () => void; + hasMore: boolean; + loadMore: () => void; text?: string; - contentSlot: ReactNode; + contentSlot: React.JSX.Element[]; className?: string; prependIcon?: ReactNode; appendIcon?: ReactNode; @@ -23,30 +22,44 @@ export const LoadMoreWrapper = ({ contentSlot, className = '', prependIcon = null, - appendIcon = , + appendIcon, isExpanded = true, }: LoadMoreWrapperProps) => { const { formatMessage } = useIntl(); const [expanded, setExpanded] = useState(isExpanded); + const observerRef = useRef(null); - useEffect(() => setExpanded(isExpanded), [isExpanded]); + useEffect(() => { + setExpanded(isExpanded); + }, [isExpanded]); + + useEffect(() => { + const observer = new IntersectionObserver( + (entries) => { + if (entries[0].isIntersecting && hasMore) { + loadMore(); + } + }, + { threshold: 1 }, + ); + + if (observerRef.current) { + observer.observe(observerRef.current); + } + + return () => { + if (observerRef.current) { + observer.unobserve(observerRef.current); + } + }; + }, [hasMore, loadMore]); if (expanded) { return ( - <> +
{contentSlot} - {hasMore && ( - - )} - +
+
); } diff --git a/src/v4/social/components/HyperLinkConfig/HyperLinkConfig.module.css b/src/v4/social/components/HyperLinkConfig/HyperLinkConfig.module.css index 5e40478f4..5e5e68d50 100644 --- a/src/v4/social/components/HyperLinkConfig/HyperLinkConfig.module.css +++ b/src/v4/social/components/HyperLinkConfig/HyperLinkConfig.module.css @@ -76,7 +76,7 @@ .styledSecondaryButton { border: none; color: var(--asc-color-base-default); - background: var(--asc-color-base-background) + background: var(--asc-color-base-background); } .removeIcon { @@ -103,4 +103,5 @@ height: 0.0625rem; align-self: stretch; background-color: var(--asc-color-base-shade4); -} \ No newline at end of file + margin: 1rem 0; +} diff --git a/src/v4/social/components/ReactionList/ReactionList.module.css b/src/v4/social/components/ReactionList/ReactionList.module.css index cf31c26be..484874fd7 100644 --- a/src/v4/social/components/ReactionList/ReactionList.module.css +++ b/src/v4/social/components/ReactionList/ReactionList.module.css @@ -6,57 +6,67 @@ .tabList { display: flex; - gap: var(--asc-spacing-s1); - border-bottom: 1px solid var(--asc-color-base-shade4); - padding-bottom: var(--asc-spacing-s1); + justify-content: flex-start; + align-items: center; + border-bottom: 1px solid var(--asc-color-neutral-shade2); + margin-bottom: 1rem; } .tabItem { cursor: pointer; - padding: var(--asc-spacing-xxs2) var(--asc-spacing-s1); - border-radius: var(--asc-border-radius-sm); - background: var(--asc-color-base-background); - color: var(--asc-color-base-shade6); + padding: 0.5rem 1rem; + position: relative; + transition: color 0.3s ease; +} + +.tabItem::after { + content: ''; + position: absolute; + bottom: -1px; + left: 0; + width: 100%; + height: 2px; + background-color: transparent; + transition: background-color 0.3s ease; } .tabItem.active { - background-color: var(--asc-color-base-shade4); color: var(--asc-color-primary-default); } +.tabItem.active::after { + background-color: var(--asc-color-primary-default); +} + .reactionEmoji { display: flex; align-items: center; - gap: var(--asc-spacing-s1); + gap: 0.5rem; } .tabCount { - font-size: 0.8rem; - background: var(--asc-color-base-background); - color: var(--asc-color-base-shade1); - padding: 0.1rem 0.3rem; - border-radius: var(--asc-border-radius-sm); + color: var(--asc-color-base-shade2); + transition: color 0.3s ease; +} + +.tabItem.active .tabCount { + color: var(--asc-color-primary-default); } .userList { - display: flex; - flex-wrap: wrap; - gap: var(--asc-spacing-s1); + display: grid; + grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); + gap: 1rem; } .userItem { display: flex; align-items: center; - gap: var(--asc-spacing-s1); - background: var(--asc-color-base-background); - padding: var(--asc-spacing-s1); - border-radius: var(--asc-border-radius-sm); - width: 100%; + gap: 0.5rem; } .userDetailsContainer { display: flex; align-items: center; - gap: var(--asc-spacing-s1); - color: var(--asc-color-base-default); + gap: 0.5rem; } diff --git a/src/v4/social/components/ReactionList/ReactionList.tsx b/src/v4/social/components/ReactionList/ReactionList.tsx index c653c3b66..af25bb11f 100644 --- a/src/v4/social/components/ReactionList/ReactionList.tsx +++ b/src/v4/social/components/ReactionList/ReactionList.tsx @@ -1,5 +1,4 @@ import React, { Fragment, useState } from 'react'; - import { FireIcon, HeartIcon, LikedIcon } from '~/icons'; import styles from './ReactionList.module.css'; import { useReactionsCollection } from '~/v4/social/hooks/collections/useReactionsCollection'; diff --git a/src/v4/social/components/ReactionList/styles.tsx b/src/v4/social/components/ReactionList/styles.tsx deleted file mode 100644 index d5a90df78..000000000 --- a/src/v4/social/components/ReactionList/styles.tsx +++ /dev/null @@ -1,104 +0,0 @@ -import styled from 'styled-components'; - -export const ReactionListContainer = styled.div` - border-radius: 0.25rem; - overflow: hidden; - max-height: 100%; - width: 100%; - display: flex; - flex-direction: column; -`; - -export const TabList = styled.ul` - display: flex; - list-style-type: none; - padding: 0; - margin: 0; - overflow-x: auto; - white-space: nowrap; - width: 100%; - height: 3rem; - border-bottom: 0.0625rem solid ${({ theme }) => theme.v4.colors.base.shade4}; - gap: 1.25rem; - - &::-webkit-scrollbar { - display: none; - } - -ms-overflow-style: none; - scrollbar-width: none; -`; - -export const TabItem = styled.li<{ active: boolean }>` - display: flex; - align-items: center; - justify-content: center; - padding: 0rem 0.25rem; - cursor: pointer; - border-radius: 0.25rem; - border-bottom-left-radius: 0; - border-bottom-right-radius: 0; - border-bottom: 0.125rem solid transparent; - flex-shrink: 0; - - &:hover { - background-color: ${({ theme }) => theme.v4.colors.base.shade4}; - } - - ${({ active, theme }) => - active && - ` - border-bottom-color: ${theme.v4.colors.primary.default}; - color: ${theme.v4.colors.primary.default}; - `} -`; - -export const TabCount = styled.span` - margin-left: 0.25rem; -`; - -export const UserList = styled.ul` - list-style-type: none; - margin: 0; - padding: 0; - overflow-y: auto; - flex: 1; - max-height: calc(100% - 3rem); -`; - -export const UserItem = styled.li` - display: flex; - justify-content: space-between; - gap: 0.5rem; - align-items: center; - margin-bottom: 0.5rem; - padding: 0.5rem; - border-bottom: 0.0625rem solid ${({ theme }) => theme.v4.colors.base.shade4}; - - &:hover { - cursor: pointer; - background-color: ${({ theme }) => theme.v4.colors.base.shade4}; - } -`; - -export const Divider = styled.hr` - border: none; - border-bottom: 0.0625rem solid ${({ theme }) => theme.v4.colors.base.shade4}; - margin: 0.5rem 0; - - &:last-child { - display: none; - } -`; - -export const ReactionEmoji = styled.div` - display: flex; - align-items: center; - justify-content: center; - gap: 0.5rem; -`; - -export const UserDetailsContainer = styled.div` - display: flex; - align-items: center; - gap: 0.5rem; -`; diff --git a/src/v4/social/internal-components/Comment/UIComment.module.css b/src/v4/social/internal-components/Comment/UIComment.module.css index d5f70fc13..879e00e65 100644 --- a/src/v4/social/internal-components/Comment/UIComment.module.css +++ b/src/v4/social/internal-components/Comment/UIComment.module.css @@ -9,6 +9,7 @@ } .commentDate { + flex-shrink: 0; color: var(--asc-color-base-shade2); } @@ -43,10 +44,10 @@ .interactionBar { display: flex; + width: 100%; + justify-content: space-between; padding: 0.25rem 1rem 0.75rem 0rem; - align-items: flex-start; - gap: 12.9375rem; - align-self: stretch; + align-items: center; } .commentEditContainer { @@ -132,6 +133,7 @@ display: inline-flex; flex-direction: column; gap: 0.25rem; + width: 100%; } .commentHeader { diff --git a/src/v4/social/internal-components/Comment/index.tsx b/src/v4/social/internal-components/Comment/index.tsx index 518878018..4f12418fe 100644 --- a/src/v4/social/internal-components/Comment/index.tsx +++ b/src/v4/social/internal-components/Comment/index.tsx @@ -102,7 +102,11 @@ export const Comment = ({ commentId, readonly, onClickReply }: CommentProps) => return toggleFlagComment(); }; - const handleEditComment = async (text: string, mentionees: Mentionees, metadata: Metadata) => + const handleEditComment = async ( + text: string, + mentionees: Amity.UserMention[], + metadata: Metadata, + ) => commentId && CommentRepository.updateComment(commentId, { data: { diff --git a/src/v4/social/internal-components/CommentList/CommentList.tsx b/src/v4/social/internal-components/CommentList/CommentList.tsx index f3024056e..00718965e 100644 --- a/src/v4/social/internal-components/CommentList/CommentList.tsx +++ b/src/v4/social/internal-components/CommentList/CommentList.tsx @@ -1,11 +1,11 @@ import React, { memo } from 'react'; import { useIntl } from 'react-intl'; import useCommentsCollection from '~/social/hooks/collections/useCommentsCollection'; - import { Comment } from '../Comment'; import styles from './CommentList.module.css'; -import { LoadMoreWrapper } from '~/v4/core/components/LoadMoreWrapper'; import { ExpandIcon } from '~/v4/social/icons'; +import { Button } from '~/v4/core/components'; +import { LoadMoreWrapper } from '~/v4/core/components/LoadMoreWrapper/LoadMoreWrapper'; interface CommentListProps { parentId?: string; @@ -35,8 +35,8 @@ export const CommentList = ({ referenceType, limit, }); - const { formatMessage } = useIntl(); + const { formatMessage } = useIntl(); const isReplyComment = !!parentId; const commentCount = comments?.length; @@ -60,29 +60,27 @@ export const CommentList = ({ if (comments?.length === 0) return null; - return ( -
- { - return ( - onClickReply?.(comment as Amity.Comment)} - shouldAllowInteraction={shouldAllowInteraction} - /> - ); - })} + const renderComments = () => { + return comments.map((comment) => ( + onClickReply?.(comment as Amity.Comment)} + shouldAllowInteraction={shouldAllowInteraction} /> -
+ )); + }; + + return ( + ); };