Skip to content

Commit 35cdb79

Browse files
authored
Merge pull request #2696 from daostack/CW-Message-performance
CW-Message-performance Increase message performance
2 parents d079665 + 075a410 commit 35cdb79

File tree

5 files changed

+168
-116
lines changed

5 files changed

+168
-116
lines changed

src/pages/common/components/ChatComponent/ChatComponent.tsx

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,16 +15,22 @@ import { debounce, delay, omit } from "lodash";
1515
import { v4 as uuidv4 } from "uuid";
1616
import { selectUser } from "@/pages/Auth/store/selectors";
1717
import { ChatService, DiscussionMessageService, FileService } from "@/services";
18+
import { Separator } from "@/shared/components";
1819
import {
1920
ChatType,
2021
DiscussionMessageOwnerType,
2122
GovernanceActions,
2223
LastSeenEntity,
24+
QueryParamKey,
2325
} from "@/shared/constants";
2426
import { FILES_ACCEPTED_EXTENSIONS } from "@/shared/constants";
2527
import { HotKeys } from "@/shared/constants/keyboardKeys";
2628
import { ChatMessageToUserDiscussionMessageConverter } from "@/shared/converters";
27-
import { useZoomDisabling, useImageSizeCheck } from "@/shared/hooks";
29+
import {
30+
useZoomDisabling,
31+
useImageSizeCheck,
32+
useQueryParams,
33+
} from "@/shared/hooks";
2834
import { ArrowInCircleIcon, PlusIcon, SendIcon } from "@/shared/icons";
2935
import { LinkPreviewData } from "@/shared/interfaces";
3036
import { CreateDiscussionMessageDto } from "@/shared/interfaces/api/discussionMessages";
@@ -73,7 +79,9 @@ import {
7379
MessageLinkPreview,
7480
MessageReply,
7581
ChatFilePreview,
82+
MessageInfoWithDateList,
7683
} from "./components";
84+
import { checkIsLastSeenInPreviousDay } from "./components/ChatContent/utils";
7785
import { useChatChannelChatAdapter, useDiscussionChatAdapter } from "./hooks";
7886
import { getLastNonUserMessage } from "./utils";
7987
import styles from "./ChatComponent.module.scss";
@@ -152,6 +160,9 @@ export default function ChatComponent({
152160
onInternalLinkClick,
153161
}: ChatComponentInterface) {
154162
const dispatch = useDispatch();
163+
const queryParams = useQueryParams();
164+
const shouldDisplayMessagesOnlyWithUncheckedItems =
165+
queryParams[QueryParamKey.Unchecked] === "true";
155166
const { checkImageSize } = useImageSizeCheck();
156167
useZoomDisabling();
157168
const editorRef = useRef<HTMLElement>(null);
@@ -289,7 +300,43 @@ export default function ChatComponent({
289300
),
290301
[discussionMessages],
291302
);
292-
const dateList = useMemo(() => Object.keys(messages), [messages]);
303+
304+
const dateList: MessageInfoWithDateList = useMemo(() => {
305+
const messagesDates = Object.keys(messages);
306+
const messagesWithInfo = messagesDates.map((day, dayIndex) => {
307+
const date = new Date(Number(day));
308+
const currentMessages = shouldDisplayMessagesOnlyWithUncheckedItems
309+
? messages[Number(day)].filter((message) => message.hasUncheckedItems)
310+
: messages[Number(day)];
311+
const previousDayMessages =
312+
messages[Number(messagesDates[dayIndex + 1])] || [];
313+
const isLastSeenInPreviousDay = checkIsLastSeenInPreviousDay(
314+
previousDayMessages,
315+
lastSeenItem?.id,
316+
);
317+
const isMyMessageFirst =
318+
checkIsUserDiscussionMessage(currentMessages[0]) &&
319+
currentMessages[0].ownerId === userId;
320+
const newSeparatorEl = (
321+
<li>
322+
<Separator>New</Separator>
323+
</li>
324+
);
325+
326+
return {
327+
day,
328+
date,
329+
currentMessages,
330+
isLastSeenInPreviousDay,
331+
isMyMessageFirst,
332+
newSeparatorEl,
333+
};
334+
});
335+
336+
return messagesWithInfo;
337+
}, [messages]);
338+
339+
// const dateListWith
293340

294341
const [newMessages, setMessages] = useState<
295342
CreateDiscussionMessageDtoWithFilesPreview[]

src/pages/common/components/ChatComponent/components/ChatContent/ChatContent.tsx

Lines changed: 107 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import React, {
66
ForwardRefRenderFunction,
77
useImperativeHandle,
88
forwardRef,
9-
memo,
109
} from "react";
1110
import { useSelector } from "react-redux";
1211
import { scroller, animateScroll } from "react-scroll";
@@ -34,22 +33,31 @@ import {
3433
import { Loader } from "@/shared/ui-kit";
3534
import { InternalLinkData } from "@/shared/utils";
3635
import { formatDate } from "@/shared/utils";
37-
import { Separator } from "./components";
38-
import { checkIsLastSeenInPreviousDay } from "./utils";
3936
import styles from "./ChatContent.module.scss";
4037

4138
export interface ChatContentRef {
4239
scrollToContainerBottom: () => void;
4340
}
4441

42+
export type MessageInfoWithDate = {
43+
day: string;
44+
date: Date;
45+
currentMessages: DiscussionMessageWithParsedText[];
46+
isLastSeenInPreviousDay: boolean;
47+
isMyMessageFirst: boolean;
48+
newSeparatorEl: JSX.Element;
49+
};
50+
51+
export type MessageInfoWithDateList = MessageInfoWithDate[];
52+
4553
interface ChatContentInterface {
4654
type: ChatType;
4755
commonMember: CommonMember | null;
4856
governanceCircles?: Circles;
4957
chatWrapperId: string;
5058
messages: Record<number, DiscussionMessageWithParsedText[]>;
5159
discussionMessages: DiscussionMessageWithParsedText[] | null;
52-
dateList: string[];
60+
dateList: MessageInfoWithDateList;
5361
lastSeenItem?: CommonFeedObjectUserUnique["lastSeen"];
5462
hasPermissionToHide: boolean;
5563
users: User[];
@@ -101,7 +109,6 @@ const ChatContent: ForwardRefRenderFunction<
101109
onFeedItemClick,
102110
onInternalLinkClick,
103111
isEmpty,
104-
messages,
105112
isChatChannel,
106113
isMessageEditAllowed,
107114
fetchReplied,
@@ -115,8 +122,6 @@ const ChatContent: ForwardRefRenderFunction<
115122
const isTabletView = useIsTabletView();
116123
const queryParams = useQueryParams();
117124
const messageIdParam = queryParams[QueryParamKey.Message];
118-
const shouldDisplayMessagesOnlyWithUncheckedItems =
119-
queryParams[QueryParamKey.Unchecked] === "true";
120125

121126
const [highlightedMessageId, setHighlightedMessageId] = useState(
122127
() => (typeof messageIdParam === "string" && messageIdParam) || null,
@@ -238,107 +243,102 @@ const ChatContent: ForwardRefRenderFunction<
238243

239244
return (
240245
<>
241-
{dateListReverse.map((day, dayIndex) => {
242-
const date = new Date(Number(day));
243-
const currentMessages = shouldDisplayMessagesOnlyWithUncheckedItems
244-
? messages[Number(day)].filter((message) => message.hasUncheckedItems)
245-
: messages[Number(day)];
246-
const previousDayMessages =
247-
messages[Number(dateListReverse[dayIndex + 1])] || [];
248-
const isLastSeenInPreviousDay = checkIsLastSeenInPreviousDay(
249-
previousDayMessages,
250-
lastSeenItem?.id,
251-
);
252-
const isMyMessageFirst =
253-
checkIsUserDiscussionMessage(currentMessages[0]) &&
254-
currentMessages[0].ownerId === userId;
255-
const newSeparatorEl = (
256-
<li>
257-
<Separator>New</Separator>
258-
</li>
259-
);
246+
{dateListReverse.map(
247+
(
248+
{
249+
day,
250+
currentMessages,
251+
date,
252+
isLastSeenInPreviousDay,
253+
isMyMessageFirst,
254+
newSeparatorEl,
255+
},
256+
dayIndex,
257+
) => {
258+
return (
259+
<Transition
260+
key={day}
261+
show={currentMessages.length > 0}
262+
transition={isTabletView ? ModalTransition.FadeIn : null}
263+
className={styles.messageListTransitionContainer}
264+
style={{ zIndex: dateListReverse.length - dayIndex }}
265+
>
266+
{currentMessages.length > 0 && (
267+
<ul id={chatId} className={styles.messageList}>
268+
{isLastSeenInPreviousDay &&
269+
!isMyMessageFirst &&
270+
newSeparatorEl}
271+
<li className={styles.dateTitle}>
272+
{isToday(date) ? "Today" : formatDate(date)}
273+
</li>
274+
{currentMessages.map((message, messageIndex) => {
275+
const nextMessage = currentMessages[messageIndex + 1];
276+
const isMyMessageNext =
277+
checkIsUserDiscussionMessage(nextMessage) &&
278+
nextMessage.ownerId === userId;
279+
const messageEl = isChatChannel ? (
280+
<DMChatMessage
281+
key={message.id}
282+
user={user}
283+
discussionMessage={message}
284+
chatType={type}
285+
scrollToRepliedMessage={scrollToRepliedMessageDMChat}
286+
highlighted={message.id === highlightedMessageId}
287+
hasPermissionToHide={hasPermissionToHide}
288+
users={users}
289+
feedItemId={feedItemId}
290+
commonMember={commonMember}
291+
governanceCircles={governanceCircles}
292+
onMessageDelete={onMessageDelete}
293+
directParent={directParent}
294+
onUserClick={onUserClick}
295+
onFeedItemClick={onFeedItemClick}
296+
onInternalLinkClick={onInternalLinkClick}
297+
chatChannelId={chatChannelId}
298+
/>
299+
) : (
300+
<ChatMessage
301+
key={message.id}
302+
user={user}
303+
discussionMessage={message}
304+
chatType={type}
305+
scrollToRepliedMessage={scrollToRepliedMessage}
306+
highlighted={message.id === highlightedMessageId}
307+
hasPermissionToHide={hasPermissionToHide}
308+
users={users}
309+
feedItemId={feedItemId}
310+
commonMember={commonMember}
311+
governanceCircles={governanceCircles}
312+
onMessageDelete={onMessageDelete}
313+
directParent={directParent}
314+
onUserClick={onUserClick}
315+
onFeedItemClick={onFeedItemClick}
316+
onInternalLinkClick={onInternalLinkClick}
317+
isMessageEditAllowed={isMessageEditAllowed}
318+
/>
319+
);
260320

261-
return (
262-
<Transition
263-
key={day}
264-
show={currentMessages.length > 0}
265-
transition={isTabletView ? ModalTransition.FadeIn : null}
266-
className={styles.messageListTransitionContainer}
267-
style={{ zIndex: dateListReverse.length - dayIndex }}
268-
>
269-
{currentMessages.length > 0 && (
270-
<ul id={chatId} className={styles.messageList}>
271-
{isLastSeenInPreviousDay && !isMyMessageFirst && newSeparatorEl}
272-
<li className={styles.dateTitle}>
273-
{isToday(date) ? "Today" : formatDate(date)}
274-
</li>
275-
{currentMessages.map((message, messageIndex) => {
276-
const nextMessage = currentMessages[messageIndex + 1];
277-
const isMyMessageNext =
278-
checkIsUserDiscussionMessage(nextMessage) &&
279-
nextMessage.ownerId === userId;
280-
const messageEl = isChatChannel ? (
281-
<DMChatMessage
282-
key={message.id}
283-
user={user}
284-
discussionMessage={message}
285-
chatType={type}
286-
scrollToRepliedMessage={scrollToRepliedMessageDMChat}
287-
highlighted={message.id === highlightedMessageId}
288-
hasPermissionToHide={hasPermissionToHide}
289-
users={users}
290-
feedItemId={feedItemId}
291-
commonMember={commonMember}
292-
governanceCircles={governanceCircles}
293-
onMessageDelete={onMessageDelete}
294-
directParent={directParent}
295-
onUserClick={onUserClick}
296-
onFeedItemClick={onFeedItemClick}
297-
onInternalLinkClick={onInternalLinkClick}
298-
chatChannelId={chatChannelId}
299-
/>
300-
) : (
301-
<ChatMessage
302-
key={message.id}
303-
user={user}
304-
discussionMessage={message}
305-
chatType={type}
306-
scrollToRepliedMessage={scrollToRepliedMessage}
307-
highlighted={message.id === highlightedMessageId}
308-
hasPermissionToHide={hasPermissionToHide}
309-
users={users}
310-
feedItemId={feedItemId}
311-
commonMember={commonMember}
312-
governanceCircles={governanceCircles}
313-
onMessageDelete={onMessageDelete}
314-
directParent={directParent}
315-
onUserClick={onUserClick}
316-
onFeedItemClick={onFeedItemClick}
317-
onInternalLinkClick={onInternalLinkClick}
318-
isMessageEditAllowed={isMessageEditAllowed}
319-
/>
320-
);
321+
if (
322+
message.id !== lastSeenItem?.id ||
323+
messageIndex === currentMessages.length - 1 ||
324+
isMyMessageNext
325+
) {
326+
return messageEl;
327+
}
321328

322-
if (
323-
message.id !== lastSeenItem?.id ||
324-
messageIndex === currentMessages.length - 1 ||
325-
isMyMessageNext
326-
) {
327-
return messageEl;
328-
}
329-
330-
return (
331-
<React.Fragment key={message.id}>
332-
{messageEl}
333-
{newSeparatorEl}
334-
</React.Fragment>
335-
);
336-
})}
337-
</ul>
338-
)}
339-
</Transition>
340-
);
341-
})}
329+
return (
330+
<React.Fragment key={message.id}>
331+
{messageEl}
332+
{newSeparatorEl}
333+
</React.Fragment>
334+
);
335+
})}
336+
</ul>
337+
)}
338+
</Transition>
339+
);
340+
},
341+
)}
342342
{isLoading && (
343343
<div className={styles.loaderContainer}>
344344
<Loader />
@@ -356,4 +356,4 @@ const ChatContent: ForwardRefRenderFunction<
356356
);
357357
};
358358

359-
export default memo(forwardRef(ChatContent));
359+
export default forwardRef(ChatContent);
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
export { default as ChatContent } from "./ChatContent";
22
export type { ChatContentRef } from "./ChatContent";
3+
export type { MessageInfoWithDateList } from "./ChatContent";

src/shared/components/Chat/ChatMessage/ChatMessage.tsx

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ const getStaticLinkByChatType = (chatType: ChatType): StaticLinkType => {
9494

9595
const FILE_NAME_LIMIT = 20;
9696

97-
export default function ChatMessage({
97+
const ChatMessage = ({
9898
discussionMessage,
9999
chatType,
100100
highlighted = false,
@@ -112,7 +112,7 @@ export default function ChatMessage({
112112
onFeedItemClick,
113113
onInternalLinkClick,
114114
isMessageEditAllowed,
115-
}: ChatMessageProps) {
115+
}: ChatMessageProps) => {
116116
const dispatch = useDispatch();
117117
const { notify } = useNotification();
118118
const updateMessageRef = useRef<{
@@ -268,7 +268,7 @@ export default function ChatMessage({
268268
setIsMessageEditLoading(true);
269269

270270
try {
271-
const updatedMessage = await ChatService.updateChatMessage({
271+
await ChatService.updateChatMessage({
272272
chatMessageId: discussionMessage.id,
273273
text: JSON.stringify(message),
274274
hasUncheckedItems: checkUncheckedItemsInTextEditorValue(message),
@@ -582,4 +582,8 @@ export default function ChatMessage({
582582
</li>
583583
</ChatMessageContext.Provider>
584584
);
585-
}
585+
};
586+
587+
const MemoizedChatMessage = React.memo(ChatMessage)
588+
589+
export default MemoizedChatMessage;

0 commit comments

Comments
 (0)