Skip to content

Commit 8493dfe

Browse files
committed
move notification logic to channel context
1 parent c5ca22d commit 8493dfe

File tree

3 files changed

+44
-44
lines changed

3 files changed

+44
-44
lines changed

src/components/Channel/Channel.tsx

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import React, {
55
useLayoutEffect,
66
useReducer,
77
useRef,
8+
useState,
89
} from 'react';
910
// @ts-expect-error
1011
import DefaultEmoji from 'emoji-mart/dist/components/emoji/nimble-emoji.js';
@@ -56,6 +57,7 @@ import { MessageSimple, MessageUIComponentProps } from '../Message';
5657

5758
import {
5859
ChannelContextValue,
60+
ChannelNotifications,
5961
ChannelProvider,
6062
MessageAttachments,
6163
MessageToSend,
@@ -245,6 +247,9 @@ const ChannelInner = <
245247
const { client, mutes, theme } = useChatContext<At, Ch, Co, Ev, Me, Re, Us>();
246248
const { t } = useTranslationContext();
247249

250+
const [notifications, setNotifications] = useState<ChannelNotifications>([]);
251+
const notificationTimeouts: Array<NodeJS.Timeout> = [];
252+
248253
const [state, dispatch] = useReducer<
249254
ChannelStateReducer<At, Ch, Co, Ev, Me, Re, Us>
250255
>(channelReducer, initialState);
@@ -383,6 +388,7 @@ const ChannelInner = <
383388
if (channel) channel.off(handleEvent);
384389
client.off('connection.changed', handleEvent);
385390
client.off('connection.recovered', handleEvent);
391+
notificationTimeouts.forEach(clearTimeout);
386392
};
387393
}, [channel, client, handleEvent, markRead]);
388394

@@ -399,6 +405,30 @@ const ChannelInner = <
399405

400406
/** MESSAGE */
401407

408+
// Adds a temporary notification to message list, will be removed after 5 seconds
409+
const addNotification = (text: string, type: 'success' | 'error') => {
410+
if (typeof text !== 'string' || (type !== 'success' && type !== 'error')) {
411+
return;
412+
}
413+
414+
const id = uuidv4();
415+
416+
setNotifications((prevNotifications) => [
417+
...prevNotifications,
418+
{ id, text, type },
419+
]);
420+
421+
const timeout = setTimeout(
422+
() =>
423+
setNotifications((prevNotifications) =>
424+
prevNotifications.filter((notification) => notification.id !== id),
425+
),
426+
5000,
427+
);
428+
429+
notificationTimeouts.push(timeout);
430+
};
431+
402432
const loadMoreFinished = useCallback(
403433
debounce(
404434
(
@@ -718,6 +748,7 @@ const ChannelInner = <
718748
const channelContextValue: ChannelContextValue<At, Ch, Co, Ev, Me, Re, Us> = {
719749
...state,
720750
acceptedFiles,
751+
addNotification,
721752
Attachment,
722753
channel,
723754
client, // from chatContext, for legacy reasons
@@ -731,6 +762,7 @@ const ChannelInner = <
731762
Message,
732763
multipleUploads,
733764
mutes,
765+
notifications,
734766
onMentionsClick: onMentionsHoverOrClick,
735767
onMentionsHover: onMentionsHoverOrClick,
736768
openThread,

src/components/MessageList/MessageList.tsx

Lines changed: 4 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import React, { PureComponent, RefObject } from 'react';
2-
import { v4 as uuidv4 } from 'uuid';
32

43
import { Center } from './Center';
54
import { ConnectionStatus } from './ConnectionStatus';
@@ -71,11 +70,6 @@ class MessageListWithContext<
7170
MessageListWithContextProps<At, Ch, Co, Ev, Me, Re, Us>,
7271
{
7372
newMessagesNotification: boolean;
74-
notifications: Array<{
75-
id: string;
76-
text: string;
77-
type: 'success' | 'error';
78-
}>;
7973
messageListRect?: DOMRect;
8074
}
8175
> {
@@ -87,7 +81,6 @@ class MessageListWithContext<
8781

8882
bottomRef: RefObject<HTMLDivElement>;
8983
messageList: RefObject<HTMLDivElement>;
90-
notificationTimeouts: Array<NodeJS.Timeout>;
9184
closeToTop: boolean | undefined;
9285
scrollOffset: number | undefined;
9386

@@ -96,12 +89,10 @@ class MessageListWithContext<
9689

9790
this.state = {
9891
newMessagesNotification: false,
99-
notifications: [],
10092
};
10193

10294
this.bottomRef = React.createRef();
10395
this.messageList = React.createRef();
104-
this.notificationTimeouts = [];
10596
}
10697

10798
componentDidMount() {
@@ -114,10 +105,6 @@ class MessageListWithContext<
114105
});
115106
}
116107

117-
componentWillUnmount() {
118-
this.notificationTimeouts.forEach(clearTimeout);
119-
}
120-
121108
getSnapshotBeforeUpdate(
122109
prevProps: MessageListWithContextProps<At, Ch, Co, Ev, Me, Re, Us>,
123110
) {
@@ -270,35 +257,6 @@ class MessageListWithContext<
270257
}
271258
};
272259

273-
/**
274-
* Adds a temporary notification to message list.
275-
* Notification will be removed after 5 seconds.
276-
*
277-
* @param notificationText Text of notification to be added
278-
* @param type Type of notification. success | error
279-
*/
280-
addNotification = (notificationText: string, type: 'success' | 'error') => {
281-
if (typeof notificationText !== 'string') return;
282-
if (type !== 'success' && type !== 'error') return;
283-
284-
const id = uuidv4();
285-
286-
this.setState(({ notifications }) => ({
287-
notifications: [...notifications, { id, text: notificationText, type }],
288-
}));
289-
290-
// remove the notification after 5000 ms
291-
const ct = setTimeout(
292-
() =>
293-
this.setState(({ notifications }) => ({
294-
notifications: notifications.filter((n) => n.id !== id),
295-
})),
296-
5000,
297-
);
298-
299-
this.notificationTimeouts.push(ct);
300-
};
301-
302260
onMessageLoadCaptured = () => {
303261
// A load event (emitted by e.g. an <img>) was captured on a message.
304262
// In some cases, the loaded asset is larger than the placeholder, which means we have to scroll down.
@@ -319,6 +277,7 @@ class MessageListWithContext<
319277

320278
render() {
321279
const {
280+
addNotification,
322281
Attachment = DefaultAttachment,
323282
Avatar = DefaultAvatar,
324283
DateSeparator = DefaultDateSeparator,
@@ -329,6 +288,7 @@ class MessageListWithContext<
329288
messageActions = Object.keys(MESSAGE_ACTIONS),
330289
messages = [],
331290
MessageSystem = EventComponent,
291+
notifications,
332292
noGroupByUser = false,
333293
pinPermissions = defaultPinPermissions,
334294
t,
@@ -370,7 +330,7 @@ class MessageListWithContext<
370330
internalMessageProps={{
371331
additionalMessageInputProps: this.props
372332
.additionalMessageInputProps,
373-
addNotification: this.addNotification,
333+
addNotification,
374334
Attachment,
375335
Avatar,
376336
channel: this.props.channel,
@@ -411,7 +371,7 @@ class MessageListWithContext<
411371
/>
412372
</div>
413373
<div className='str-chat__list-notifications'>
414-
{this.state.notifications.map((notification) => (
374+
{notifications.map((notification) => (
415375
<CustomNotification
416376
active={true}
417377
key={notification.id}

src/context/ChannelContext.tsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,12 @@ import type {
3333
UnknownType,
3434
} from '../../types/types';
3535

36+
export type ChannelNotifications = Array<{
37+
id: string;
38+
text: string;
39+
type: 'success' | 'error';
40+
}>;
41+
3642
export type CommonEmoji = {
3743
custom: boolean;
3844
emoticons: [];
@@ -144,8 +150,10 @@ export type ChannelContextValue<
144150
Re extends DefaultReactionType = DefaultReactionType,
145151
Us extends DefaultUserType<Us> = DefaultUserType
146152
> = ChannelState<At, Ch, Co, Ev, Me, Re, Us> & {
153+
addNotification: (text: string, type: 'success' | 'error') => void;
147154
channel: Channel<At, Ch, Co, Ev, Me, Re, Us>;
148155
client: StreamChat<At, Ch, Co, Ev, Me, Re, Us>;
156+
notifications: ChannelNotifications;
149157
acceptedFiles?: string[];
150158
Attachment?: React.ComponentType<AttachmentProps<At>>;
151159
closeThread?: (event: React.SyntheticEvent) => void;

0 commit comments

Comments
 (0)