From a6577d8f0f6a28c6fe9fac4ccdf39340ac02ba1a Mon Sep 17 00:00:00 2001 From: Pavel Meyer Date: Thu, 1 Aug 2024 19:08:35 +0300 Subject: [PATCH 1/4] CW-some-stream-disappear Optimized FeedItem component. FIxed condition in FeedLayout --- .../common/components/FeedItem/FeedItem.tsx | 114 ++++++++++++------ .../components/FeedLayout/FeedLayout.tsx | 7 +- 2 files changed, 80 insertions(+), 41 deletions(-) diff --git a/src/pages/common/components/FeedItem/FeedItem.tsx b/src/pages/common/components/FeedItem/FeedItem.tsx index 366753b49..0c77addd8 100644 --- a/src/pages/common/components/FeedItem/FeedItem.tsx +++ b/src/pages/common/components/FeedItem/FeedItem.tsx @@ -6,10 +6,7 @@ import React, { useMemo, } from "react"; import { useFeedItemFollow } from "@/shared/hooks/useCases"; -import { - FeedLayoutItemChangeData, - SpaceListVisibility, -} from "@/shared/interfaces"; +import { FeedLayoutItemChangeData } from "@/shared/interfaces"; import { Circles, CirclesPermissions, @@ -20,7 +17,7 @@ import { CommonNotion, DirectParent, } from "@/shared/models"; -import { checkIsItemVisibleForUser, InternalLinkData } from "@/shared/utils"; +import { checkIsItemVisibleForUser } from "@/shared/utils"; import { useFeedItemSubscription } from "../../hooks"; import { DiscussionFeedCard } from "../DiscussionFeedCard"; import { ProposalFeedCard } from "../ProposalFeedCard"; @@ -113,14 +110,20 @@ const FeedItem = forwardRef((props, ref) => { const getNonAllowedItems = outerGetNonAllowedItems || contextGetNonAllowedItems; - const handleUserClick = useMemo( - () => onUserSelect && ((userId: string) => onUserSelect(userId, commonId)), + const handleUserClick = useCallback( + (userId: string) => { + if (onUserSelect) { + onUserSelect(userId, commonId); + } + }, [onUserSelect, commonId], ); const handleActiveItemDataChange = useCallback( (data: FeedLayoutItemChangeData) => { - onActiveItemDataChange?.(data, commonId); + if (onActiveItemDataChange) { + onActiveItemDataChange(data, commonId); + } }, [onActiveItemDataChange, commonId], ); @@ -130,11 +133,15 @@ const FeedItem = forwardRef((props, ref) => { feedItemFollow.isUserFeedItemFollowDataFetched && !feedItemFollow.userFeedItemFollowData ) { - onFeedItemUnfollowed?.(item.id); + if (onFeedItemUnfollowed) { + onFeedItemUnfollowed(item.id); + } } }, [ feedItemFollow.isUserFeedItemFollowDataFetched, feedItemFollow.userFeedItemFollowData, + item.id, + onFeedItemUnfollowed, ]); if ( @@ -150,35 +157,66 @@ const FeedItem = forwardRef((props, ref) => { return null; } - const generalProps = { - ref, - item, - commonId, - commonName, - commonImage, - commonNotion, - pinnedFeedItems, - isActive, - isExpanded, - isProject, - isPinned, - governanceCircles, - isPreviewMode, - getLastMessage, - commonMember, - getNonAllowedItems, - isMobileVersion, - onActiveItemDataChange: handleActiveItemDataChange, - directParent, - rootCommonId, - feedItemFollow, - onUserSelect, - shouldPreLoadMessages, - withoutMenu, - onUserClick: handleUserClick, - onFeedItemClick, - onInternalLinkClick, - }; + const generalProps = useMemo( + () => ({ + ref, + item, + commonId, + commonName, + commonImage, + commonNotion, + pinnedFeedItems, + isActive, + isExpanded, + isProject, + isPinned, + governanceCircles, + isPreviewMode, + getLastMessage, + commonMember, + getNonAllowedItems, + isMobileVersion, + onActiveItemDataChange: handleActiveItemDataChange, + directParent, + rootCommonId, + feedItemFollow, + onUserSelect, + shouldPreLoadMessages, + withoutMenu, + onUserClick: handleUserClick, + onFeedItemClick, + onInternalLinkClick, + }), + [ + ref, + item, + commonId, + commonName, + commonImage, + commonNotion, + pinnedFeedItems, + isActive, + isExpanded, + isProject, + isPinned, + governanceCircles, + isPreviewMode, + getLastMessage, + commonMember, + getNonAllowedItems, + isMobileVersion, + handleActiveItemDataChange, + directParent, + rootCommonId, + feedItemFollow, + onUserSelect, + shouldPreLoadMessages, + withoutMenu, + handleUserClick, + onFeedItemClick, + onInternalLinkClick, + ], + ); if (item.data.type === CommonFeedType.Discussion) { return ; diff --git a/src/pages/commonFeed/components/FeedLayout/FeedLayout.tsx b/src/pages/commonFeed/components/FeedLayout/FeedLayout.tsx index 0f730acc8..c349b456a 100644 --- a/src/pages/commonFeed/components/FeedLayout/FeedLayout.tsx +++ b/src/pages/commonFeed/components/FeedLayout/FeedLayout.tsx @@ -1,14 +1,14 @@ import React, { CSSProperties, forwardRef, - ForwardRefRenderFunction, - ReactNode, useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState, + ReactNode, + ForwardRefRenderFunction, } from "react"; import { useSelector } from "react-redux"; import { useHistory } from "react-router-dom"; @@ -221,8 +221,9 @@ const FeedLayout: ForwardRefRenderFunction = ( fetchedCommonMember; const userForProfile = useUserForProfile(); const governance = chatItem?.nestedItemData - ? fetchedGovernance + ? fetchedGovernance || outerGovernance : outerGovernance || fetchedGovernance; + const [splitPaneRef, setSplitPaneRef] = useState(null); const maxContentSize = settings?.getSplitViewMaxSize?.(windowWidth) ?? From 0e0bde068773e2693da6606b4e07e5e8c383bfdc Mon Sep 17 00:00:00 2001 From: Pavel Meyer Date: Mon, 5 Aug 2024 15:37:52 +0300 Subject: [PATCH 2/4] CW-some-stream-disappear Fixed Render fewer hooks issue --- .../common/components/FeedItem/FeedItem.tsx | 26 ++++++++++--------- .../components/FeedLayout/FeedLayout.tsx | 2 +- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/src/pages/common/components/FeedItem/FeedItem.tsx b/src/pages/common/components/FeedItem/FeedItem.tsx index 0c77addd8..56b8afca4 100644 --- a/src/pages/common/components/FeedItem/FeedItem.tsx +++ b/src/pages/common/components/FeedItem/FeedItem.tsx @@ -144,18 +144,6 @@ const FeedItem = forwardRef((props, ref) => { onFeedItemUnfollowed, ]); - if ( - shouldCheckItemVisibility && - !checkIsItemVisibleForUser({ - itemCircleVisibility: item.circleVisibility, - userCircleIds, - itemUserId: item.userId, - currentUserId, - itemDataType: item.data.type, - }) - ) { - return null; - } const generalProps = useMemo( () => ({ @@ -218,6 +206,20 @@ const FeedItem = forwardRef((props, ref) => { ], ); + + if ( + shouldCheckItemVisibility && + !checkIsItemVisibleForUser({ + itemCircleVisibility: item.circleVisibility, + userCircleIds, + itemUserId: item.userId, + currentUserId, + itemDataType: item.data.type, + }) + ) { + return null; + } + if (item.data.type === CommonFeedType.Discussion) { return ; } diff --git a/src/pages/commonFeed/components/FeedLayout/FeedLayout.tsx b/src/pages/commonFeed/components/FeedLayout/FeedLayout.tsx index c349b456a..c57d97461 100644 --- a/src/pages/commonFeed/components/FeedLayout/FeedLayout.tsx +++ b/src/pages/commonFeed/components/FeedLayout/FeedLayout.tsx @@ -221,7 +221,7 @@ const FeedLayout: ForwardRefRenderFunction = ( fetchedCommonMember; const userForProfile = useUserForProfile(); const governance = chatItem?.nestedItemData - ? fetchedGovernance || outerGovernance + ? (fetchedGovernance || outerGovernance) : outerGovernance || fetchedGovernance; const [splitPaneRef, setSplitPaneRef] = useState(null); From c14a3be245e166ba5e18d3aae3f5ed629f77c442 Mon Sep 17 00:00:00 2001 From: Pavel Meyer Date: Tue, 6 Aug 2024 13:03:43 +0300 Subject: [PATCH 3/4] CW-some-stream-disappear Added names to components for better debugging --- .../DiscussionFeedCard/DiscussionFeedCard.tsx | 762 +++++++++--------- .../common/components/FeedCard/FeedCard.tsx | 6 +- src/pages/common/components/FeedCard/index.ts | 2 +- .../ProposalFeedCard/ProposalFeedCard.tsx | 740 +++++++++-------- 4 files changed, 754 insertions(+), 756 deletions(-) diff --git a/src/pages/common/components/DiscussionFeedCard/DiscussionFeedCard.tsx b/src/pages/common/components/DiscussionFeedCard/DiscussionFeedCard.tsx index 3da4b2a80..06a09cc7f 100644 --- a/src/pages/common/components/DiscussionFeedCard/DiscussionFeedCard.tsx +++ b/src/pages/common/components/DiscussionFeedCard/DiscussionFeedCard.tsx @@ -78,409 +78,407 @@ interface DiscussionFeedCardProps { onInternalLinkClick: (data: InternalLinkData) => void; } -const DiscussionFeedCard = forwardRef( - (props, ref) => { - const { - setChatItem, - feedItemIdForAutoChatOpen, - shouldAllowChatAutoOpen, - nestedItemData, - } = useChatContext(); - const { notify } = useNotification(); - const { - item, - governanceCircles, - isMobileVersion = false, +function DiscussionFeedCard(props, ref) { + const { + setChatItem, + feedItemIdForAutoChatOpen, + shouldAllowChatAutoOpen, + nestedItemData, + } = useChatContext(); + const { notify } = useNotification(); + const { + item, + governanceCircles, + isMobileVersion = false, + commonId, + commonName, + commonImage, + commonNotion: outerCommonNotion, + pinnedFeedItems, + commonMember, + isProject, + isPinned, + isPreviewMode, + isActive, + isExpanded, + getLastMessage, + getNonAllowedItems, + onActiveItemDataChange, + directParent, + rootCommonId, + feedItemFollow, + shouldPreLoadMessages, + withoutMenu, + onUserClick, + onFeedItemClick, + onInternalLinkClick, + } = props; + const { + isShowing: isReportModalOpen, + onOpen: onReportModalOpen, + onClose: onReportModalClose, + } = useModal(false); + const { + isShowing: isShareModalOpen, + onOpen: onShareModalOpen, + onClose: onShareModalClose, + } = useModal(false); + const { + isShowing: isDeleteModalOpen, + onOpen: onDeleteModalOpen, + onClose: onDeleteModalClose, + } = useModal(false); + const { + isShowing: isLinkStreamModalOpen, + onOpen: onLinkStreamModalOpen, + onClose: onLinkStreamModalClose, + } = useModal(false); + const { + isShowing: isUnlinkStreamModalOpen, + onOpen: onUnlinkStreamModalOpen, + onClose: onUnlinkStreamModalClose, + } = useModal(false); + const { + isShowing: isMoveStreamModalOpen, + onOpen: onMoveStreamModalOpen, + onClose: onMoveStreamModalClose, + } = useModal(false); + const [isDeletingInProgress, setDeletingInProgress] = useState(false); + const { + fetchUser: fetchDiscussionCreator, + data: discussionCreator, + fetched: isDiscussionCreatorFetched, + } = useUserById(); + const { + fetchDiscussion, + data: discussion, + fetched: isDiscussionFetched, + } = useDiscussionById(); + const isHome = discussion?.predefinedType === PredefinedTypes.General; + const discussionNotion = commonId + ? discussion?.notionByCommon?.[commonId] + : undefined; + const { + data: feedItemUserMetadata, + fetched: isFeedItemUserMetadataFetched, + fetchFeedItemUserMetadata, + } = useFeedItemUserMetadata(); + const shouldLoadCommonData = + isHome || (discussionNotion && !outerCommonNotion); + const { data: common } = useCommon(shouldLoadCommonData ? commonId : ""); + const preloadDiscussionMessagesData = usePreloadDiscussionMessagesById({ + commonId, + discussionId: discussion?.id, + onUserClick, + onFeedItemClick, + onInternalLinkClick, + }); + const { markFeedItemAsSeen, markFeedItemAsUnseen } = + useUpdateFeedItemSeenState(); + const menuItems = useMenuItems( + { commonId, - commonName, - commonImage, - commonNotion: outerCommonNotion, pinnedFeedItems, + feedItem: item, + discussion, + governanceCircles, commonMember, - isProject, - isPinned, - isPreviewMode, - isActive, - isExpanded, - getLastMessage, - getNonAllowedItems, - onActiveItemDataChange, - directParent, - rootCommonId, feedItemFollow, - shouldPreLoadMessages, + getNonAllowedItems, + feedItemUserMetadata, withoutMenu, - onUserClick, - onFeedItemClick, - onInternalLinkClick, - } = props; - const { - isShowing: isReportModalOpen, - onOpen: onReportModalOpen, - onClose: onReportModalClose, - } = useModal(false); - const { - isShowing: isShareModalOpen, - onOpen: onShareModalOpen, - onClose: onShareModalClose, - } = useModal(false); - const { - isShowing: isDeleteModalOpen, - onOpen: onDeleteModalOpen, - onClose: onDeleteModalClose, - } = useModal(false); - const { - isShowing: isLinkStreamModalOpen, - onOpen: onLinkStreamModalOpen, - onClose: onLinkStreamModalClose, - } = useModal(false); - const { - isShowing: isUnlinkStreamModalOpen, - onOpen: onUnlinkStreamModalOpen, - onClose: onUnlinkStreamModalClose, - } = useModal(false); - const { - isShowing: isMoveStreamModalOpen, - onOpen: onMoveStreamModalOpen, - onClose: onMoveStreamModalClose, - } = useModal(false); - const [isDeletingInProgress, setDeletingInProgress] = useState(false); - const { - fetchUser: fetchDiscussionCreator, - data: discussionCreator, - fetched: isDiscussionCreatorFetched, - } = useUserById(); - const { - fetchDiscussion, - data: discussion, - fetched: isDiscussionFetched, - } = useDiscussionById(); - const isHome = discussion?.predefinedType === PredefinedTypes.General; - const discussionNotion = commonId - ? discussion?.notionByCommon?.[commonId] - : undefined; - const { - data: feedItemUserMetadata, - fetched: isFeedItemUserMetadataFetched, - fetchFeedItemUserMetadata, - } = useFeedItemUserMetadata(); - const shouldLoadCommonData = - isHome || (discussionNotion && !outerCommonNotion); - const { data: common } = useCommon(shouldLoadCommonData ? commonId : ""); - const preloadDiscussionMessagesData = usePreloadDiscussionMessagesById({ - commonId, - discussionId: discussion?.id, - onUserClick, - onFeedItemClick, - onInternalLinkClick, - }); - const { markFeedItemAsSeen, markFeedItemAsUnseen } = - useUpdateFeedItemSeenState(); - const menuItems = useMenuItems( - { - commonId, - pinnedFeedItems, - feedItem: item, - discussion, - governanceCircles, - commonMember, - feedItemFollow, - getNonAllowedItems, - feedItemUserMetadata, - withoutMenu, - }, - { - report: onReportModalOpen, - share: () => onShareModalOpen(), - remove: onDeleteModalOpen, - linkStream: onLinkStreamModalOpen, - unlinkStream: onUnlinkStreamModalOpen, - moveStream: onMoveStreamModalOpen, - markFeedItemAsSeen, - markFeedItemAsUnseen, - }, - ); - const user = useSelector(selectUser()); - const [isHovering, setHovering] = useState(false); - const onHover = (isMouseEnter: boolean): void => { - setHovering(isMouseEnter); - }; - const userId = user?.uid; - const isLoading = - !isDiscussionCreatorFetched || - !isDiscussionFetched || - !isFeedItemUserMetadataFetched || - !commonId; - const cardTitle = discussion?.title; - const commonNotion = outerCommonNotion ?? common?.notion; + }, + { + report: onReportModalOpen, + share: () => onShareModalOpen(), + remove: onDeleteModalOpen, + linkStream: onLinkStreamModalOpen, + unlinkStream: onUnlinkStreamModalOpen, + moveStream: onMoveStreamModalOpen, + markFeedItemAsSeen, + markFeedItemAsUnseen, + }, + ); + const user = useSelector(selectUser()); + const [isHovering, setHovering] = useState(false); + const onHover = (isMouseEnter: boolean): void => { + setHovering(isMouseEnter); + }; + const userId = user?.uid; + const isLoading = + !isDiscussionCreatorFetched || + !isDiscussionFetched || + !isFeedItemUserMetadataFetched || + !commonId; + const cardTitle = discussion?.title; + const commonNotion = outerCommonNotion ?? common?.notion; - const handleOpenChat = useCallback(() => { - if (discussion && !isPreviewMode) { - setChatItem({ - feedItemId: item.id, - discussion, - circleVisibility: item.circleVisibility, - lastSeenItem: feedItemUserMetadata?.lastSeen, - lastSeenAt: feedItemUserMetadata?.lastSeenAt, - count: feedItemUserMetadata?.count, - seenOnce: feedItemUserMetadata?.seenOnce, - seen: feedItemUserMetadata?.seen, - hasUnseenMention: feedItemUserMetadata?.hasUnseenMention, - nestedItemData: nestedItemData && { - ...nestedItemData, - feedItem: { - type: InboxItemType.FeedItemFollow, - itemId: item.id, - feedItem: item, - }, + const handleOpenChat = useCallback(() => { + if (discussion && !isPreviewMode) { + setChatItem({ + feedItemId: item.id, + discussion, + circleVisibility: item.circleVisibility, + lastSeenItem: feedItemUserMetadata?.lastSeen, + lastSeenAt: feedItemUserMetadata?.lastSeenAt, + count: feedItemUserMetadata?.count, + seenOnce: feedItemUserMetadata?.seenOnce, + seen: feedItemUserMetadata?.seen, + hasUnseenMention: feedItemUserMetadata?.hasUnseenMention, + nestedItemData: nestedItemData && { + ...nestedItemData, + feedItem: { + type: InboxItemType.FeedItemFollow, + itemId: item.id, + feedItem: item, }, - }); - } - }, [ - discussion, - item.id, - item.circleVisibility, - feedItemUserMetadata?.lastSeen, - feedItemUserMetadata?.lastSeenAt, - feedItemUserMetadata?.count, - feedItemUserMetadata?.seenOnce, - feedItemUserMetadata?.seen, - feedItemUserMetadata?.hasUnseenMention, - nestedItemData, - isPreviewMode, - ]); + }, + }); + } + }, [ + discussion, + item.id, + item.circleVisibility, + feedItemUserMetadata?.lastSeen, + feedItemUserMetadata?.lastSeenAt, + feedItemUserMetadata?.count, + feedItemUserMetadata?.seenOnce, + feedItemUserMetadata?.seen, + feedItemUserMetadata?.hasUnseenMention, + nestedItemData, + isPreviewMode, + ]); - const onDiscussionDelete = useCallback(async () => { - try { - if (discussion) { - setDeletingInProgress(true); - await DiscussionService.deleteDiscussion(discussion.id); - onDeleteModalClose(); - } - } catch { - notify("Something went wrong"); - } finally { - setDeletingInProgress(false); + const onDiscussionDelete = useCallback(async () => { + try { + if (discussion) { + setDeletingInProgress(true); + await DiscussionService.deleteDiscussion(discussion.id); + onDeleteModalClose(); } - }, [discussion]); + } catch { + notify("Something went wrong"); + } finally { + setDeletingInProgress(false); + } + }, [discussion]); - const preloadDiscussionMessages = useMemo( - () => - debounce< - typeof preloadDiscussionMessagesData.preloadDiscussionMessages - >( - (...args) => - preloadDiscussionMessagesData.preloadDiscussionMessages(...args), - 6000, - ), - [preloadDiscussionMessagesData.preloadDiscussionMessages], - ); + const preloadDiscussionMessages = useMemo( + () => + debounce( + (...args) => + preloadDiscussionMessagesData.preloadDiscussionMessages(...args), + 6000, + ), + [preloadDiscussionMessagesData.preloadDiscussionMessages], + ); - useEffect(() => { - fetchDiscussionCreator(item.userId); - }, [item.userId]); + useEffect(() => { + fetchDiscussionCreator(item.userId); + }, [item.userId]); - useEffect(() => { - fetchDiscussion(item.data.id); - }, [item.data.id]); + useEffect(() => { + fetchDiscussion(item.data.id); + }, [item.data.id]); - useEffect(() => { - if (commonId) { - fetchFeedItemUserMetadata({ - userId: userId || "", - commonId, - feedObjectId: item.id, - }); - } - }, [userId, commonId, item.id]); + useEffect(() => { + if (commonId) { + fetchFeedItemUserMetadata({ + userId: userId || "", + commonId, + feedObjectId: item.id, + }); + } + }, [userId, commonId, item.id]); - useEffect(() => { - if ( - (!isActive || - shouldAllowChatAutoOpen === null || - shouldAllowChatAutoOpen) && - isDiscussionFetched && - isFeedItemUserMetadataFetched && - item.id === feedItemIdForAutoChatOpen && - !isMobileVersion - ) { - handleOpenChat(); - } - }, [ - isDiscussionFetched, - isFeedItemUserMetadataFetched, - shouldAllowChatAutoOpen, - ]); + useEffect(() => { + if ( + (!isActive || + shouldAllowChatAutoOpen === null || + shouldAllowChatAutoOpen) && + isDiscussionFetched && + isFeedItemUserMetadataFetched && + item.id === feedItemIdForAutoChatOpen && + !isMobileVersion + ) { + handleOpenChat(); + } + }, [ + isDiscussionFetched, + isFeedItemUserMetadataFetched, + shouldAllowChatAutoOpen, + ]); - useEffect(() => { - if (isActive && shouldAllowChatAutoOpen !== null) { - handleOpenChat(); - } - }, [isActive, shouldAllowChatAutoOpen, handleOpenChat]); + useEffect(() => { + if (isActive && shouldAllowChatAutoOpen !== null) { + handleOpenChat(); + } + }, [isActive, shouldAllowChatAutoOpen, handleOpenChat]); - useEffect(() => { - if (isActive && cardTitle) { - onActiveItemDataChange?.({ - itemId: item.id, - title: cardTitle, - }); - } - }, [isActive, cardTitle]); + useEffect(() => { + if (isActive && cardTitle) { + onActiveItemDataChange?.({ + itemId: item.id, + title: cardTitle, + }); + } + }, [isActive, cardTitle]); - useEffect(() => { - if ( - shouldPreLoadMessages && - !isActive && - commonId && - item.circleVisibility - ) { - preloadDiscussionMessages(item.circleVisibility); - } - }, [shouldPreLoadMessages, isActive]); + useEffect(() => { + if ( + shouldPreLoadMessages && + !isActive && + commonId && + item.circleVisibility + ) { + preloadDiscussionMessages(item.circleVisibility); + } + }, [shouldPreLoadMessages, isActive]); - useUpdateEffect(() => { - if ( - shouldPreLoadMessages && - !isActive && - commonId && - item.circleVisibility - ) { - preloadDiscussionMessages(item.circleVisibility, true); - } - }, [item.data.lastMessage?.content]); + useUpdateEffect(() => { + if ( + shouldPreLoadMessages && + !isActive && + commonId && + item.circleVisibility + ) { + preloadDiscussionMessages(item.circleVisibility, true); + } + }, [item.data.lastMessage?.content]); - return ( - <> - - {(isExpanded || isActive) && ( - onUserClick(item.userId))} - discussionCreator={discussionCreator} - isHome={isHome} - menuItems={menuItems} - discussion={discussion} - common={common} - discussionNotion={discussionNotion} - handleOpenChat={handleOpenChat} - onHover={onHover} - isLoading={isLoading} - /> - )} - - {userId && discussion && ( - + + {(isExpanded || isActive) && ( + onUserClick(item.userId))} + discussionCreator={discussionCreator} + isHome={isHome} + menuItems={menuItems} + discussion={discussion} + common={common} + discussionNotion={discussionNotion} + handleOpenChat={handleOpenChat} + onHover={onHover} + isLoading={isLoading} /> )} - {discussion && ( - + {userId && discussion && ( + + )} + {discussion && ( + + )} + {isDeleteModalOpen && ( + + + + )} + {commonId && ( + <> + - )} - {isDeleteModalOpen && ( - - - - )} - {commonId && ( - <> - - - - - )} - - ); - }, -); + + + + )} + + ); +} -export default DiscussionFeedCard; +export default forwardRef( + DiscussionFeedCard, +); diff --git a/src/pages/common/components/FeedCard/FeedCard.tsx b/src/pages/common/components/FeedCard/FeedCard.tsx index 65f87967a..353d5bd9e 100644 --- a/src/pages/common/components/FeedCard/FeedCard.tsx +++ b/src/pages/common/components/FeedCard/FeedCard.tsx @@ -60,7 +60,7 @@ type FeedCardProps = PropsWithChildren<{ linkedCommonIds?: string[]; }>; -export const FeedCard = forwardRef((props, ref) => { +const FeedCard = (props, ref) => { const { className, feedItemId, @@ -278,4 +278,6 @@ export const FeedCard = forwardRef((props, ref) => { ); -}); +}; + +export default forwardRef(FeedCard); diff --git a/src/pages/common/components/FeedCard/index.ts b/src/pages/common/components/FeedCard/index.ts index 71201cbdf..257e55820 100644 --- a/src/pages/common/components/FeedCard/index.ts +++ b/src/pages/common/components/FeedCard/index.ts @@ -1,4 +1,4 @@ -export * from "./FeedCard"; +export { default as FeedCard } from "./FeedCard"; export * from "./components"; export * from "./types"; export * from "./utils"; diff --git a/src/pages/common/components/ProposalFeedCard/ProposalFeedCard.tsx b/src/pages/common/components/ProposalFeedCard/ProposalFeedCard.tsx index 949dcea0c..591068e5e 100644 --- a/src/pages/common/components/ProposalFeedCard/ProposalFeedCard.tsx +++ b/src/pages/common/components/ProposalFeedCard/ProposalFeedCard.tsx @@ -72,400 +72,398 @@ interface ProposalFeedCardProps { onInternalLinkClick: (data: InternalLinkData) => void; } -const ProposalFeedCard = forwardRef( - (props, ref) => { - const { +function ProposalFeedCard(props: ProposalFeedCardProps, ref: React.Ref) { + const { + commonId, + commonName, + commonImage, + commonNotion: outerCommonNotion, + pinnedFeedItems, + isProject, + isPinned, + item, + governanceCircles, + isPreviewMode, + isActive, + isExpanded, + getLastMessage, + getNonAllowedItems, + isMobileVersion, + feedItemFollow, + onActiveItemDataChange, + shouldPreLoadMessages, + withoutMenu, + onUserClick, + onFeedItemClick, + onInternalLinkClick, + } = props; + const user = useSelector(selectUser()); + const userId = user?.uid; + const { + setChatItem, + feedItemIdForAutoChatOpen, + shouldAllowChatAutoOpen, + nestedItemData, + } = useChatContext(); + const { notify } = useNotification(); + const forceUpdate = useForceUpdate(); + const { getCommonPagePath } = useRoutesContext(); + const { + fetchUser: fetchFeedItemUser, + data: feedItemUser, + fetched: isFeedItemUserFetched, + } = useUserById(); + const { + fetchDiscussion, + data: discussion, + fetched: isDiscussionFetched, + } = useDiscussionById(); + const { + fetchProposal, + data: proposal, + fetched: isProposalFetched, + } = useProposalById(); + const { + fetched: isCommonMemberFetched, + data: commonMember, + fetchCommonMember, + } = useCommonMember(); + const { + data: userVote, + loading: isUserVoteLoading, + fetchProposalVote, + setVote, + } = useProposalUserVote(); + const { + data: proposalSpecificData, + fetched: isProposalSpecificDataFetched, + fetchData: fetchProposalSpecificData, + } = useProposalSpecificData(); + const { + data: feedItemUserMetadata, + fetched: isFeedItemUserMetadataFetched, + fetchFeedItemUserMetadata, + } = useFeedItemUserMetadata(); + const discussionNotion = commonId + ? discussion?.notionByCommon?.[commonId] + : undefined; + const shouldLoadCommonData = discussionNotion && !outerCommonNotion; + const { data: common } = useCommon(shouldLoadCommonData ? commonId : ""); + const { + isShowing: isProposalDeleteModalOpen, + onOpen: onProposalDeleteModalOpen, + onClose: onProposalDeleteModalClose, + } = useModal(false); + const [isProposalDeletingInProgress, setProposalDeletingInProgress] = + useState(false); + const isLoading = + !isFeedItemUserFetched || + !isDiscussionFetched || + !isProposalFetched || + !proposal || + isUserVoteLoading || + !isCommonMemberFetched || + !isProposalSpecificDataFetched || + !isFeedItemUserMetadataFetched || + !commonId || + !governanceCircles; + const [isHovering, setHovering] = useState(false); + const onHover = (isMouseEnter: boolean): void => { + setHovering(isMouseEnter); + }; + const proposalId = item.data.id; + const { + isShowing: isShareModalOpen, + onOpen: onShareModalOpen, + onClose: onShareModalClose, + } = useModal(false); + const preloadDiscussionMessagesData = usePreloadDiscussionMessagesById({ + commonId, + discussionId: discussion?.id, + onUserClick, + onFeedItemClick, + onInternalLinkClick, + }); + const { markFeedItemAsSeen, markFeedItemAsUnseen } = + useUpdateFeedItemSeenState(); + const menuItems = useMenuItems( + { commonId, - commonName, - commonImage, - commonNotion: outerCommonNotion, pinnedFeedItems, - isProject, - isPinned, - item, + feedItem: item, + discussion, governanceCircles, - isPreviewMode, - isActive, - isExpanded, - getLastMessage, - getNonAllowedItems, - isMobileVersion, + commonMember, feedItemFollow, - onActiveItemDataChange, - shouldPreLoadMessages, + getNonAllowedItems, + feedItemUserMetadata, withoutMenu, - onUserClick, - onFeedItemClick, - onInternalLinkClick, - } = props; - const user = useSelector(selectUser()); - const userId = user?.uid; - const { - setChatItem, - feedItemIdForAutoChatOpen, - shouldAllowChatAutoOpen, - nestedItemData, - } = useChatContext(); - const { notify } = useNotification(); - const forceUpdate = useForceUpdate(); - const { getCommonPagePath } = useRoutesContext(); - const { - fetchUser: fetchFeedItemUser, - data: feedItemUser, - fetched: isFeedItemUserFetched, - } = useUserById(); - const { - fetchDiscussion, - data: discussion, - fetched: isDiscussionFetched, - } = useDiscussionById(); - const { - fetchProposal, - data: proposal, - fetched: isProposalFetched, - } = useProposalById(); - const { - fetched: isCommonMemberFetched, - data: commonMember, - fetchCommonMember, - } = useCommonMember(); - const { - data: userVote, - loading: isUserVoteLoading, - fetchProposalVote, - setVote, - } = useProposalUserVote(); - const { - data: proposalSpecificData, - fetched: isProposalSpecificDataFetched, - fetchData: fetchProposalSpecificData, - } = useProposalSpecificData(); - const { - data: feedItemUserMetadata, - fetched: isFeedItemUserMetadataFetched, - fetchFeedItemUserMetadata, - } = useFeedItemUserMetadata(); - const discussionNotion = commonId - ? discussion?.notionByCommon?.[commonId] - : undefined; - const shouldLoadCommonData = discussionNotion && !outerCommonNotion; - const { data: common } = useCommon(shouldLoadCommonData ? commonId : ""); - const { - isShowing: isProposalDeleteModalOpen, - onOpen: onProposalDeleteModalOpen, - onClose: onProposalDeleteModalClose, - } = useModal(false); - const [isProposalDeletingInProgress, setProposalDeletingInProgress] = - useState(false); - const isLoading = - !isFeedItemUserFetched || - !isDiscussionFetched || - !isProposalFetched || - !proposal || - isUserVoteLoading || - !isCommonMemberFetched || - !isProposalSpecificDataFetched || - !isFeedItemUserMetadataFetched || - !commonId || - !governanceCircles; - const [isHovering, setHovering] = useState(false); - const onHover = (isMouseEnter: boolean): void => { - setHovering(isMouseEnter); - }; - const proposalId = item.data.id; - const { - isShowing: isShareModalOpen, - onOpen: onShareModalOpen, - onClose: onShareModalClose, - } = useModal(false); - const preloadDiscussionMessagesData = usePreloadDiscussionMessagesById({ - commonId, - discussionId: discussion?.id, - onUserClick, - onFeedItemClick, - onInternalLinkClick, - }); - const { markFeedItemAsSeen, markFeedItemAsUnseen } = - useUpdateFeedItemSeenState(); - const menuItems = useMenuItems( - { - commonId, - pinnedFeedItems, - feedItem: item, - discussion, - governanceCircles, - commonMember, - feedItemFollow, - getNonAllowedItems, - feedItemUserMetadata, - withoutMenu, - }, - { - report: () => {}, - share: () => onShareModalOpen(), - remove: onProposalDeleteModalOpen, - markFeedItemAsSeen, - markFeedItemAsUnseen, - }, - ); - const cardTitle = discussion?.title; - const commonNotion = outerCommonNotion ?? common?.notion; + }, + { + report: () => {}, + share: () => onShareModalOpen(), + remove: onProposalDeleteModalOpen, + markFeedItemAsSeen, + markFeedItemAsUnseen, + }, + ); + const cardTitle = discussion?.title; + const commonNotion = outerCommonNotion ?? common?.notion; - const onProposalDelete = useCallback(async () => { - try { - setProposalDeletingInProgress(true); - await ProposalService.deleteProposal(proposalId); - onProposalDeleteModalClose(); - } catch { - notify("Something went wrong"); - } finally { - setProposalDeletingInProgress(false); - } - }, [proposalId]); + const onProposalDelete = useCallback(async () => { + try { + setProposalDeletingInProgress(true); + await ProposalService.deleteProposal(proposalId); + onProposalDeleteModalClose(); + } catch { + notify("Something went wrong"); + } finally { + setProposalDeletingInProgress(false); + } + }, [proposalId]); - const preloadDiscussionMessages = useMemo( - () => - debounce< - typeof preloadDiscussionMessagesData.preloadDiscussionMessages - >( - (...args) => - preloadDiscussionMessagesData.preloadDiscussionMessages(...args), - 6000, - ), - [preloadDiscussionMessagesData.preloadDiscussionMessages], - ); + const preloadDiscussionMessages = useMemo( + () => + debounce< + typeof preloadDiscussionMessagesData.preloadDiscussionMessages + >( + (...args) => + preloadDiscussionMessagesData.preloadDiscussionMessages(...args), + 6000, + ), + [preloadDiscussionMessagesData.preloadDiscussionMessages], + ); - useEffect(() => { - fetchFeedItemUser(item.userId); - }, [item.userId]); + useEffect(() => { + fetchFeedItemUser(item.userId); + }, [item.userId]); - useEffect(() => { - if (item.data.discussionId) { - fetchDiscussion(item.data.discussionId); - } - }, [item.data.discussionId]); + useEffect(() => { + if (item.data.discussionId) { + fetchDiscussion(item.data.discussionId); + } + }, [item.data.discussionId]); - useEffect(() => { - fetchProposal(item.data.id); - }, [item.data.id]); + useEffect(() => { + fetchProposal(item.data.id); + }, [item.data.id]); - useEffect(() => { - fetchProposalVote(proposalId); - }, [fetchProposalVote, proposalId]); + useEffect(() => { + fetchProposalVote(proposalId); + }, [fetchProposalVote, proposalId]); - useEffect(() => { - if (commonId) { - fetchCommonMember(commonId, {}); - } - }, [fetchCommonMember, commonId]); + useEffect(() => { + if (commonId) { + fetchCommonMember(commonId, {}); + } + }, [fetchCommonMember, commonId]); - useEffect(() => { - if (commonId) { - fetchFeedItemUserMetadata({ - userId: userId || "", - commonId, - feedObjectId: item.id, - }); - } - }, [userId, commonId, item.id]); + useEffect(() => { + if (commonId) { + fetchFeedItemUserMetadata({ + userId: userId || "", + commonId, + feedObjectId: item.id, + }); + } + }, [userId, commonId, item.id]); - useEffect(() => { - if (proposal) { - fetchProposalSpecificData(proposal, true); - } - }, [proposal?.id]); + useEffect(() => { + if (proposal) { + fetchProposalSpecificData(proposal, true); + } + }, [proposal?.id]); - useEffect(() => { - if (isActive && cardTitle) { - onActiveItemDataChange?.({ - itemId: item.id, - title: cardTitle, - }); - } - }, [isActive, cardTitle]); + useEffect(() => { + if (isActive && cardTitle) { + onActiveItemDataChange?.({ + itemId: item.id, + title: cardTitle, + }); + } + }, [isActive, cardTitle]); - const handleOpenChat = useCallback(() => { - if (discussion && proposal && !isPreviewMode) { - setChatItem({ - feedItemId: item.id, - discussion, - proposal, - circleVisibility: item.circleVisibility, - lastSeenItem: feedItemUserMetadata?.lastSeen, - lastSeenAt: feedItemUserMetadata?.lastSeenAt, - seenOnce: feedItemUserMetadata?.seenOnce, - seen: feedItemUserMetadata?.seen, - hasUnseenMention: feedItemUserMetadata?.hasUnseenMention, - nestedItemData: nestedItemData && { - ...nestedItemData, - feedItem: { - type: InboxItemType.FeedItemFollow, - itemId: item.id, - feedItem: item, - }, + const handleOpenChat = useCallback(() => { + if (discussion && proposal && !isPreviewMode) { + setChatItem({ + feedItemId: item.id, + discussion, + proposal, + circleVisibility: item.circleVisibility, + lastSeenItem: feedItemUserMetadata?.lastSeen, + lastSeenAt: feedItemUserMetadata?.lastSeenAt, + seenOnce: feedItemUserMetadata?.seenOnce, + seen: feedItemUserMetadata?.seen, + hasUnseenMention: feedItemUserMetadata?.hasUnseenMention, + nestedItemData: nestedItemData && { + ...nestedItemData, + feedItem: { + type: InboxItemType.FeedItemFollow, + itemId: item.id, + feedItem: item, }, - }); - } - }, [ - item.id, - proposal, - discussion, - setChatItem, - item.circleVisibility, - feedItemUserMetadata?.lastSeen, - feedItemUserMetadata?.lastSeenAt, - feedItemUserMetadata?.seenOnce, - feedItemUserMetadata?.seen, - feedItemUserMetadata?.hasUnseenMention, - nestedItemData, - isPreviewMode, - ]); + }, + }); + } + }, [ + item.id, + proposal, + discussion, + setChatItem, + item.circleVisibility, + feedItemUserMetadata?.lastSeen, + feedItemUserMetadata?.lastSeenAt, + feedItemUserMetadata?.seenOnce, + feedItemUserMetadata?.seen, + feedItemUserMetadata?.hasUnseenMention, + nestedItemData, + isPreviewMode, + ]); - useEffect(() => { - if ( - (!isActive || - shouldAllowChatAutoOpen === null || - shouldAllowChatAutoOpen) && - isDiscussionFetched && - isProposalFetched && - isFeedItemUserMetadataFetched && - item.id === feedItemIdForAutoChatOpen && - !isMobileVersion - ) { - handleOpenChat(); - } - }, [ - isDiscussionFetched, - isProposalFetched, - isFeedItemUserMetadataFetched, - shouldAllowChatAutoOpen, - ]); + useEffect(() => { + if ( + (!isActive || + shouldAllowChatAutoOpen === null || + shouldAllowChatAutoOpen) && + isDiscussionFetched && + isProposalFetched && + isFeedItemUserMetadataFetched && + item.id === feedItemIdForAutoChatOpen && + !isMobileVersion + ) { + handleOpenChat(); + } + }, [ + isDiscussionFetched, + isProposalFetched, + isFeedItemUserMetadataFetched, + shouldAllowChatAutoOpen, + ]); - useEffect(() => { - if (isActive && shouldAllowChatAutoOpen !== null) { - handleOpenChat(); - } - }, [isActive, shouldAllowChatAutoOpen, handleOpenChat]); + useEffect(() => { + if (isActive && shouldAllowChatAutoOpen !== null) { + handleOpenChat(); + } + }, [isActive, shouldAllowChatAutoOpen, handleOpenChat]); - useEffect(() => { - if (isExpanded) { - forceUpdate(); - } - }, [isExpanded]); + useEffect(() => { + if (isExpanded) { + forceUpdate(); + } + }, [isExpanded]); - useEffect(() => { - if ( - shouldPreLoadMessages && - !isActive && - commonId && - item.circleVisibility - ) { - preloadDiscussionMessages(item.circleVisibility); - } - }, [shouldPreLoadMessages, isActive]); + useEffect(() => { + if ( + shouldPreLoadMessages && + !isActive && + commonId && + item.circleVisibility + ) { + preloadDiscussionMessages(item.circleVisibility); + } + }, [shouldPreLoadMessages, isActive]); - useUpdateEffect(() => { - if ( - shouldPreLoadMessages && - !isActive && - commonId && - item.circleVisibility - ) { - preloadDiscussionMessages(item.circleVisibility, true); - } - }, [item.data.lastMessage?.content]); + useUpdateEffect(() => { + if ( + shouldPreLoadMessages && + !isActive && + commonId && + item.circleVisibility + ) { + preloadDiscussionMessages(item.circleVisibility, true); + } + }, [item.data.lastMessage?.content]); - return ( - <> - - {(isActive || isExpanded) && ( - - )} - - {discussion && ( - + + {(isActive || isExpanded) && ( + )} - {isProposalDeleteModalOpen && ( - - - - )} - - ); - }, -); + + {discussion && ( + + )} + {isProposalDeleteModalOpen && ( + + + + )} + + ); +} -export default ProposalFeedCard; +export default forwardRef(ProposalFeedCard); From b90ebbf6e50c626a4884444e0ab8b86ed5c0a087 Mon Sep 17 00:00:00 2001 From: Pavel Meyer Date: Wed, 7 Aug 2024 14:48:14 +0300 Subject: [PATCH 4/4] CW-some-stream-disappear Added commonId related logic for Feed --- src/pages/OldCommon/hooks/useCommonMember.ts | 3 +- src/pages/OldCommon/hooks/useCommonMembers.ts | 6 +-- .../components/FeedLayout/FeedLayout.tsx | 53 ++++++++++++++++--- src/shared/models/Common.tsx | 1 + 4 files changed, 52 insertions(+), 11 deletions(-) diff --git a/src/pages/OldCommon/hooks/useCommonMember.ts b/src/pages/OldCommon/hooks/useCommonMember.ts index f749b2b2e..8d01168e8 100644 --- a/src/pages/OldCommon/hooks/useCommonMember.ts +++ b/src/pages/OldCommon/hooks/useCommonMember.ts @@ -141,6 +141,7 @@ export const useCommonMember = (options: Options = {}): Return => { loading: false, fetched: true, data: { + commonId, ...commonMember, ...generateCirclesDataForCommonMember( governance.circles, @@ -189,7 +190,7 @@ export const useCommonMember = (options: Options = {}): Return => { } } }, - [state, userId], + [state, userId, commonId], ); const setCommonMember = useCallback( diff --git a/src/pages/OldCommon/hooks/useCommonMembers.ts b/src/pages/OldCommon/hooks/useCommonMembers.ts index 3f16ad080..f07c8221f 100644 --- a/src/pages/OldCommon/hooks/useCommonMembers.ts +++ b/src/pages/OldCommon/hooks/useCommonMembers.ts @@ -141,7 +141,7 @@ export const useCommonMembers = ({ commonId }: Options): Return => { const user = cachedUserStates[commonMember.userId]?.data; - return user ? [...acc, { ...commonMember, user }] : acc; + return user ? [...acc, { ...commonMember, user, commonId }] : acc; }, []); return { @@ -178,7 +178,7 @@ export const useCommonMembers = ({ commonId }: Options): Return => { ({ uid }) => uid === commonMember.userId, ); - return user ? [...acc, { ...commonMember, user }] : acc; + return user ? [...acc, { ...commonMember, user, commonId }] : acc; }, []); return { @@ -198,7 +198,7 @@ export const useCommonMembers = ({ commonId }: Options): Return => { })); } })(); - }, [commonMembersState.data]); + }, [commonMembersState.data, commonId]); return { ...state, diff --git a/src/pages/commonFeed/components/FeedLayout/FeedLayout.tsx b/src/pages/commonFeed/components/FeedLayout/FeedLayout.tsx index c57d97461..7f2e19cd8 100644 --- a/src/pages/commonFeed/components/FeedLayout/FeedLayout.tsx +++ b/src/pages/commonFeed/components/FeedLayout/FeedLayout.tsx @@ -13,7 +13,7 @@ import React, { import { useSelector } from "react-redux"; import { useHistory } from "react-router-dom"; import PullToRefresh from "react-simple-pull-to-refresh"; -import { useWindowSize } from "react-use"; +import { useDeepCompareEffect, useWindowSize } from "react-use"; import classNames from "classnames"; import { selectUser } from "@/pages/Auth/store/selectors"; import { useCommonMember } from "@/pages/OldCommon/hooks"; @@ -219,9 +219,39 @@ const FeedLayout: ForwardRefRenderFunction = ( chatItem?.nestedItemData?.commonMember || outerCommonMember || fetchedCommonMember; + + const [ + commonMemberForSpecificCommonIds, + setCommonMemberForSpecificCommonIds, + ] = useState({}); + + useDeepCompareEffect(() => { + const chatItemCommonMember = { ...chatItem?.nestedItemData?.commonMember }; + + setCommonMemberForSpecificCommonIds((prevCommonMembers) => { + if (chatItemCommonMember?.commonId) { + prevCommonMembers[chatItemCommonMember.commonId] = chatItemCommonMember; + } + + if (outerCommonMember?.commonId) { + prevCommonMembers[outerCommonMember.commonId] = outerCommonMember; + } + + if (fetchedCommonMember?.commonId) { + prevCommonMembers[fetchedCommonMember.commonId] = fetchedCommonMember; + } + + return prevCommonMembers; + }); + }, [ + fetchedCommonMember, + chatItem?.nestedItemData?.commonMember, + outerCommonMember, + ]); + const userForProfile = useUserForProfile(); const governance = chatItem?.nestedItemData - ? (fetchedGovernance || outerGovernance) + ? fetchedGovernance || outerGovernance : outerGovernance || fetchedGovernance; const [splitPaneRef, setSplitPaneRef] = useState(null); @@ -312,9 +342,16 @@ const FeedLayout: ForwardRefRenderFunction = ( ]); const activeFeedItemId = chatItem?.feedItemId || feedItemIdForAutoChatOpen; const sizeKey = `${windowWidth}_${contentWidth}`; - const userCircleIds = useMemo( - () => Object.values(commonMember?.circles.map ?? {}), - [commonMember?.circles.map], + + const getUserCircleIds = useCallback( + (commonId) => { + return Object.values( + commonMemberForSpecificCommonIds[commonId]?.circles.map ?? + commonMember?.circles.map ?? + {}, + ) as string[]; + }, + [commonMemberForSpecificCommonIds, commonMember?.circles.map], ); const selectedFeedItem = useMemo( @@ -831,7 +868,7 @@ const FeedLayout: ForwardRefRenderFunction = ( item={item.feedItem} governanceCircles={governance?.circles} isMobileVersion={isTabletView} - userCircleIds={userCircleIds} + userCircleIds={getUserCircleIds(commonData?.id)} isActive={isActive} isExpanded={item.feedItem.id === expandedFeedItemId} sizeKey={isActive ? sizeKey : undefined} @@ -917,7 +954,9 @@ const FeedLayout: ForwardRefRenderFunction = ( isProject={selectedItemCommonData.isProject} governanceCircles={governance?.circles} selectedFeedItem={selectedFeedItem?.feedItem} - userCircleIds={userCircleIds} + userCircleIds={getUserCircleIds( + selectedItemCommonData.id, + )} isShowFeedItemDetailsModal={isShowFeedItemDetailsModal} sizeKey={sizeKey} isMainModalOpen={Boolean(chatItem)} diff --git a/src/shared/models/Common.tsx b/src/shared/models/Common.tsx index c5d79b1d1..ca92fefb3 100644 --- a/src/shared/models/Common.tsx +++ b/src/shared/models/Common.tsx @@ -172,6 +172,7 @@ export interface CommonMember { isFollowing: boolean; streamsUnreadCountByProjectStream?: Record; unreadCountByProjectStream?: Record; + commonId?: string; } export interface CirclesPermissions {