Skip to content

Commit f9a0081

Browse files
authored
fix: Update quoted message preview on message update (#1503)
1 parent 5f3b60b commit f9a0081

File tree

5 files changed

+377
-191
lines changed

5 files changed

+377
-191
lines changed

src/components/Channel/Channel.tsx

Lines changed: 2 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ import type { Data as EmojiMartData } from 'emoji-mart';
6565
import type { MessageInputProps } from '../MessageInput/MessageInput';
6666

6767
import type { CustomTrigger, DefaultStreamChatGenerics, GiphyVersions } from '../../types/types';
68+
import { makeAddNotifications } from './utils';
6869

6970
export type ChannelProps<
7071
StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics,
@@ -428,25 +429,7 @@ const ChannelInner = <
428429
/** MESSAGE */
429430

430431
// Adds a temporary notification to message list, will be removed after 5 seconds
431-
const addNotification = (text: string, type: 'success' | 'error') => {
432-
if (typeof text !== 'string' || (type !== 'success' && type !== 'error')) {
433-
return;
434-
}
435-
436-
const id = uuidv4();
437-
438-
setNotifications((prevNotifications) => [...prevNotifications, { id, text, type }]);
439-
440-
const timeout = setTimeout(
441-
() =>
442-
setNotifications((prevNotifications) =>
443-
prevNotifications.filter((notification) => notification.id !== id),
444-
),
445-
5000,
446-
);
447-
448-
notificationTimeouts.push(timeout);
449-
};
432+
const addNotification = makeAddNotifications(setNotifications, notificationTimeouts);
450433

451434
const loadMoreFinished = debounce(
452435
(hasMore: boolean, messages: ChannelState<StreamChatGenerics>['messages']) => {

src/components/Channel/utils.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import type { Dispatch, SetStateAction } from 'react';
2+
import type { ChannelNotifications } from '../../context/ChannelStateContext';
3+
import { v4 as uuidv4 } from 'uuid';
4+
5+
export const makeAddNotifications = (
6+
setNotifications: Dispatch<SetStateAction<ChannelNotifications>>,
7+
notificationTimeouts: NodeJS.Timeout[],
8+
) => (text: string, type: 'success' | 'error') => {
9+
if (typeof text !== 'string' || (type !== 'success' && type !== 'error')) {
10+
return;
11+
}
12+
13+
const id = uuidv4();
14+
15+
setNotifications((prevNotifications) => [...prevNotifications, { id, text, type }]);
16+
17+
const timeout = setTimeout(
18+
() =>
19+
setNotifications((prevNotifications) =>
20+
prevNotifications.filter((notification) => notification.id !== id),
21+
),
22+
5000,
23+
);
24+
25+
notificationTimeouts.push(timeout);
26+
};

src/components/MessageInput/MessageInputFlat.tsx

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
import React from 'react';
1+
import React, { useEffect } from 'react';
22
import { FileUploadButton, ImageDropzone } from 'react-file-utils';
3+
import type { Event } from 'stream-chat';
34

45
import { EmojiPicker } from './EmojiPicker';
56
import { CooldownTimer as DefaultCooldownTimer } from './hooks/useCooldownTimer';
@@ -14,6 +15,8 @@ import { UploadsPreview } from './UploadsPreview';
1415
import { ChatAutoComplete } from '../ChatAutoComplete/ChatAutoComplete';
1516
import { Tooltip } from '../Tooltip/Tooltip';
1617

18+
import { useChatContext } from '../../context/ChatContext';
19+
import { useChannelActionContext } from '../../context/ChannelActionContext';
1720
import { useChannelStateContext } from '../../context/ChannelStateContext';
1821
import { useTranslationContext } from '../../context/TranslationContext';
1922
import { useMessageInputContext } from '../../context/MessageInputContext';
@@ -29,8 +32,9 @@ export const MessageInputFlat = <
2932
multipleUploads,
3033
quotedMessage,
3134
} = useChannelStateContext<StreamChatGenerics>('MessageInputFlat');
35+
const { setQuotedMessage } = useChannelActionContext('MessageInputFlat');
3236
const { t } = useTranslationContext('MessageInputFlat');
33-
37+
const { channel } = useChatContext<StreamChatGenerics>('MessageInputFlat');
3438
const {
3539
closeEmojiPicker,
3640
cooldownRemaining,
@@ -52,6 +56,24 @@ export const MessageInputFlat = <
5256
SendButton = DefaultSendButton,
5357
} = useComponentContext<StreamChatGenerics>('MessageInputFlat');
5458

59+
useEffect(() => {
60+
const handleQuotedMessageUpdate = (e: Event<StreamChatGenerics>) => {
61+
if (e.message?.id !== quotedMessage?.id) return;
62+
if (e.type === 'message.deleted') {
63+
setQuotedMessage(undefined);
64+
return;
65+
}
66+
setQuotedMessage(e.message);
67+
};
68+
channel?.on('message.deleted', handleQuotedMessageUpdate);
69+
channel?.on('message.updated', handleQuotedMessageUpdate);
70+
71+
return () => {
72+
channel?.off('message.deleted', handleQuotedMessageUpdate);
73+
channel?.off('message.updated', handleQuotedMessageUpdate);
74+
};
75+
}, [channel, quotedMessage]);
76+
5577
return (
5678
<div
5779
className={`str-chat__input-flat ${

src/components/MessageInput/MessageInputSmall.tsx

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
import React from 'react';
1+
import React, { useEffect } from 'react';
22
import { FileUploadButton, ImageDropzone } from 'react-file-utils';
3+
import type { Event } from 'stream-chat';
34

45
import { EmojiPicker } from './EmojiPicker';
56
import { CooldownTimer as DefaultCooldownTimer } from './hooks/useCooldownTimer';
@@ -13,6 +14,8 @@ import { UploadsPreview } from './UploadsPreview';
1314
import { ChatAutoComplete } from '../ChatAutoComplete/ChatAutoComplete';
1415
import { Tooltip } from '../Tooltip/Tooltip';
1516

17+
import { useChatContext } from '../../context/ChatContext';
18+
import { useChannelActionContext } from '../../context/ChannelActionContext';
1619
import { useChannelStateContext } from '../../context/ChannelStateContext';
1720
import { useTranslationContext } from '../../context/TranslationContext';
1821
import { useMessageInputContext } from '../../context/MessageInputContext';
@@ -31,7 +34,9 @@ export const MessageInputSmall = <
3134
multipleUploads,
3235
quotedMessage,
3336
} = useChannelStateContext<StreamChatGenerics>('MessageInputSmall');
37+
const { setQuotedMessage } = useChannelActionContext('MessageInputSmall');
3438
const { t } = useTranslationContext('MessageInputSmall');
39+
const { channel } = useChatContext<StreamChatGenerics>('MessageInputSmall');
3540

3641
const {
3742
closeEmojiPicker,
@@ -54,6 +59,23 @@ export const MessageInputSmall = <
5459
QuotedMessagePreview = DefaultQuotedMessagePreview,
5560
} = useComponentContext<StreamChatGenerics>('MessageInputSmall');
5661

62+
useEffect(() => {
63+
const handleQuotedMessageUpdate = (e: Event<StreamChatGenerics>) => {
64+
if (!(quotedMessage && e.message?.id === quotedMessage.id)) return;
65+
if (e.type === 'message.deleted') {
66+
setQuotedMessage(undefined);
67+
return;
68+
}
69+
setQuotedMessage(e.message);
70+
};
71+
channel?.on('message.deleted', handleQuotedMessageUpdate);
72+
channel?.on('message.updated', handleQuotedMessageUpdate);
73+
74+
return () => {
75+
channel?.off('message.deleted', handleQuotedMessageUpdate);
76+
channel?.off('message.updated', handleQuotedMessageUpdate);
77+
};
78+
}, [channel, quotedMessage]);
5779
return (
5880
<div className='str-chat__small-message-input__wrapper'>
5981
<ImageDropzone

0 commit comments

Comments
 (0)