stream-chat-react-native-core 9.5.1-beta.7 → 9.5.1-beta.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/commonjs/components/MessageList/MessageFlashList.js +7 -2
- package/lib/commonjs/components/MessageList/MessageFlashList.js.map +1 -1
- package/lib/commonjs/components/MessageList/MessageList.js +7 -2
- package/lib/commonjs/components/MessageList/MessageList.js.map +1 -1
- package/lib/commonjs/components/Notifications/index.js +11 -0
- package/lib/commonjs/components/Notifications/index.js.map +1 -1
- package/lib/commonjs/components/Notifications/notificationFilters.js +9 -0
- package/lib/commonjs/components/Notifications/notificationFilters.js.map +1 -0
- package/lib/commonjs/version.json +1 -1
- package/lib/module/components/MessageList/MessageFlashList.js +7 -2
- package/lib/module/components/MessageList/MessageFlashList.js.map +1 -1
- package/lib/module/components/MessageList/MessageList.js +7 -2
- package/lib/module/components/MessageList/MessageList.js.map +1 -1
- package/lib/module/components/Notifications/index.js +11 -0
- package/lib/module/components/Notifications/index.js.map +1 -1
- package/lib/module/components/Notifications/notificationFilters.js +9 -0
- package/lib/module/components/Notifications/notificationFilters.js.map +1 -0
- package/lib/module/version.json +1 -1
- package/lib/typescript/components/MessageList/MessageFlashList.d.ts +1 -1
- package/lib/typescript/components/MessageList/MessageFlashList.d.ts.map +1 -1
- package/lib/typescript/components/MessageList/MessageList.d.ts +1 -1
- package/lib/typescript/components/MessageList/MessageList.d.ts.map +1 -1
- package/lib/typescript/components/Notifications/index.d.ts +1 -0
- package/lib/typescript/components/Notifications/index.d.ts.map +1 -1
- package/lib/typescript/components/Notifications/notificationFilters.d.ts +10 -0
- package/lib/typescript/components/Notifications/notificationFilters.d.ts.map +1 -0
- package/package.json +1 -1
- package/src/components/MessageList/MessageFlashList.tsx +13 -3
- package/src/components/MessageList/MessageList.tsx +13 -3
- package/src/components/Notifications/__tests__/notificationFilters.test.ts +50 -0
- package/src/components/Notifications/index.ts +1 -0
- package/src/components/Notifications/notificationFilters.ts +26 -0
- package/src/version.json +1 -1
|
@@ -9,7 +9,7 @@ import { MessagesContextValue } from '../../contexts/messagesContext/MessagesCon
|
|
|
9
9
|
import { OwnCapabilitiesContextValue } from '../../contexts/ownCapabilitiesContext/OwnCapabilitiesContext';
|
|
10
10
|
import { PaginatedMessageListContextValue } from '../../contexts/paginatedMessageListContext/PaginatedMessageListContext';
|
|
11
11
|
import { ThreadContextValue } from '../../contexts/threadContext/ThreadContext';
|
|
12
|
-
type MessageListPropsWithContext = Pick<AttachmentPickerContextValue, 'closePicker' | 'attachmentPickerStore'> & Pick<OwnCapabilitiesContextValue, 'readEvents'> & Pick<ChannelContextValue, 'channel' | 'channelUnreadStateStore' | 'disabled' | 'hideStickyDateHeader' | 'loadChannelAroundMessage' | 'loading' | 'markRead' | 'reloadChannel' | 'scrollToFirstUnreadThreshold' | 'setChannelUnreadState' | 'setTargetedMessage' | 'targetedMessage' | 'threadList' | 'maximumMessageLimit'> & Pick<ChatContextValue, 'client'> & Pick<PaginatedMessageListContextValue, 'loadMore' | 'loadMoreRecent' | 'hasMore'> & Pick<MessagesContextValue, 'disableTypingIndicator' | 'FlatList' | 'myMessageTheme' | 'shouldShowUnreadUnderlay'> & Pick<MessageInputContextValue, 'messageInputFloating' | 'messageInputHeightStore'> & Pick<ThreadContextValue, 'loadMoreRecentThread' | 'loadMoreThread' | 'threadHasMore' | 'thread' | 'threadInstance'> & {
|
|
12
|
+
type MessageListPropsWithContext = Pick<AttachmentPickerContextValue, 'closePicker' | 'attachmentPickerStore'> & Pick<OwnCapabilitiesContextValue, 'readEvents'> & Pick<ChannelContextValue, 'channel' | 'channelUnreadStateStore' | 'disabled' | 'hideStickyDateHeader' | 'loadChannelAroundMessage' | 'loading' | 'markRead' | 'reloadChannel' | 'scrollToFirstUnreadThreshold' | 'setChannelUnreadState' | 'setTargetedMessage' | 'targetedMessage' | 'threadList' | 'maximumMessageLimit'> & Pick<ChatContextValue, 'client'> & Pick<PaginatedMessageListContextValue, 'loadMore' | 'loadMoreRecent' | 'hasMore'> & Pick<MessagesContextValue, 'disableTypingIndicator' | 'FlatList' | 'myMessageTheme' | 'shouldShowUnreadUnderlay'> & Pick<MessageInputContextValue, 'allowSendBeforeAttachmentsUpload' | 'messageInputFloating' | 'messageInputHeightStore'> & Pick<ThreadContextValue, 'loadMoreRecentThread' | 'loadMoreThread' | 'threadHasMore' | 'thread' | 'threadInstance'> & {
|
|
13
13
|
/**
|
|
14
14
|
* Besides existing (default) UX behavior of underlying FlatList of MessageList component, if you want
|
|
15
15
|
* to attach some additional props to underlying FlatList, you can add it to following prop.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MessageList.d.ts","sourceRoot":"","sources":["../../../../src/components/MessageList/MessageList.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA4D,MAAM,OAAO,CAAC;AACjF,OAAO,EAEL,aAAa,EACb,QAAQ,IAAI,YAAY,EAExB,eAAe,EAKhB,MAAM,cAAc,CAAC;AAgBtB,OAAO,EAEL,6BAA6B,EAC9B,MAAM,wCAAwC,CAAC;AAEhD,OAAO,EACL,4BAA4B,EAE7B,MAAM,gEAAgE,CAAC;AACxE,OAAO,EACL,mBAAmB,EAEpB,MAAM,8CAA8C,CAAC;AAEtD,OAAO,EAAE,gBAAgB,EAAkB,MAAM,wCAAwC,CAAC;AAI1F,OAAO,EACL,wBAAwB,EAEzB,MAAM,wDAAwD,CAAC;AAKhE,OAAO,EACL,oBAAoB,EAErB,MAAM,gDAAgD,CAAC;AACxD,OAAO,EACL,2BAA2B,EAE5B,MAAM,8DAA8D,CAAC;AACtE,OAAO,EACL,gCAAgC,EAEjC,MAAM,wEAAwE,CAAC;AAEhF,OAAO,EAAE,kBAAkB,EAAoB,MAAM,4CAA4C,CAAC;
|
|
1
|
+
{"version":3,"file":"MessageList.d.ts","sourceRoot":"","sources":["../../../../src/components/MessageList/MessageList.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA4D,MAAM,OAAO,CAAC;AACjF,OAAO,EAEL,aAAa,EACb,QAAQ,IAAI,YAAY,EAExB,eAAe,EAKhB,MAAM,cAAc,CAAC;AAgBtB,OAAO,EAEL,6BAA6B,EAC9B,MAAM,wCAAwC,CAAC;AAEhD,OAAO,EACL,4BAA4B,EAE7B,MAAM,gEAAgE,CAAC;AACxE,OAAO,EACL,mBAAmB,EAEpB,MAAM,8CAA8C,CAAC;AAEtD,OAAO,EAAE,gBAAgB,EAAkB,MAAM,wCAAwC,CAAC;AAI1F,OAAO,EACL,wBAAwB,EAEzB,MAAM,wDAAwD,CAAC;AAKhE,OAAO,EACL,oBAAoB,EAErB,MAAM,gDAAgD,CAAC;AACxD,OAAO,EACL,2BAA2B,EAE5B,MAAM,8DAA8D,CAAC;AACtE,OAAO,EACL,gCAAgC,EAEjC,MAAM,wEAAwE,CAAC;AAEhF,OAAO,EAAE,kBAAkB,EAAoB,MAAM,4CAA4C,CAAC;AA0IlG,KAAK,2BAA2B,GAAG,IAAI,CACrC,4BAA4B,EAC5B,aAAa,GAAG,uBAAuB,CACxC,GACC,IAAI,CAAC,2BAA2B,EAAE,YAAY,CAAC,GAC/C,IAAI,CACF,mBAAmB,EACjB,SAAS,GACT,yBAAyB,GACzB,UAAU,GACV,sBAAsB,GACtB,0BAA0B,GAC1B,SAAS,GACT,UAAU,GACV,eAAe,GACf,8BAA8B,GAC9B,uBAAuB,GACvB,oBAAoB,GACpB,iBAAiB,GACjB,YAAY,GACZ,qBAAqB,CACxB,GACD,IAAI,CAAC,gBAAgB,EAAE,QAAQ,CAAC,GAChC,IAAI,CAAC,gCAAgC,EAAE,UAAU,GAAG,gBAAgB,GAAG,SAAS,CAAC,GACjF,IAAI,CACF,oBAAoB,EACpB,wBAAwB,GAAG,UAAU,GAAG,gBAAgB,GAAG,0BAA0B,CACtF,GACD,IAAI,CACF,wBAAwB,EACxB,kCAAkC,GAAG,sBAAsB,GAAG,yBAAyB,CACxF,GACD,IAAI,CACF,kBAAkB,EAClB,sBAAsB,GAAG,gBAAgB,GAAG,eAAe,GAAG,QAAQ,GAAG,gBAAgB,CAC1F,GAAG;IACF;;;;;;;;;;;;;OAaG;IACH,uBAAuB,CAAC,EAAE,OAAO,CAAC,aAAa,CAAC,6BAA6B,CAAC,CAAC,CAAC;IAChF;;;;;;;OAOG;IACH,eAAe,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;IACtC;;;;;;;OAOG;IACH,eAAe,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;IACtC,gEAAgE;IAChE,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,4CAA4C;IAC5C,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,YAAY,CAAC,EAAE,eAAe,CAAC,UAAU,CAAC,CAAC;IAC3C;;;;OAIG;IACH,cAAc,CAAC,EAAE,CAAC,OAAO,EAAE,kBAAkB,CAAC,QAAQ,CAAC,KAAK,IAAI,CAAC;IACjE;;;;;;;;;;OAUG;IACH,cAAc,CAAC,EAAE,CAAC,GAAG,EAAE,YAAY,CAAC,6BAA6B,CAAC,GAAG,IAAI,KAAK,IAAI,CAAC;IACnF;;;;;;;OAOG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB,CAAC;AA4kCJ,MAAM,MAAM,gBAAgB,GAAG,OAAO,CAAC,2BAA2B,CAAC,CAAC;AAEpE,eAAO,MAAM,WAAW,GAAI,OAAO,gBAAgB,sBA2ElD,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/Notifications/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,oBAAoB,CAAC;AACnC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,SAAS,CAAC;AACxB,cAAc,sBAAsB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/Notifications/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,oBAAoB,CAAC;AACnC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,SAAS,CAAC;AACxB,cAAc,uBAAuB,CAAC;AACtC,cAAc,sBAAsB,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { NotificationListFilter } from './NotificationList';
|
|
2
|
+
/**
|
|
3
|
+
* Notification list filter that keeps every notification except the spurious
|
|
4
|
+
* "upload failed" one produced when a user removes an attachment mid-upload
|
|
5
|
+
* (a filter returns `true` to keep a notification). Genuine upload failures
|
|
6
|
+
* (network, server) are kept because their error is neither aborted nor
|
|
7
|
+
* cancelled.
|
|
8
|
+
*/
|
|
9
|
+
export declare const excludeCanceledUploadNotifications: NotificationListFilter;
|
|
10
|
+
//# sourceMappingURL=notificationFilters.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"notificationFilters.d.ts","sourceRoot":"","sources":["../../../../src/components/Notifications/notificationFilters.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAC;AAejE;;;;;;GAMG;AACH,eAAO,MAAM,kCAAkC,EAAE,sBACN,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "stream-chat-react-native-core",
|
|
3
3
|
"description": "The official React Native and Expo components for Stream Chat, a service for building chat applications",
|
|
4
|
-
"version": "9.5.1-beta.
|
|
4
|
+
"version": "9.5.1-beta.8",
|
|
5
5
|
"author": {
|
|
6
6
|
"company": "Stream.io Inc",
|
|
7
7
|
"name": "Stream.io Inc"
|
|
@@ -60,6 +60,7 @@ import { MessageInputHeightState } from '../../state-store/message-input-height-
|
|
|
60
60
|
import { primitives } from '../../theme';
|
|
61
61
|
import { transitions } from '../../utils/animations/transitions';
|
|
62
62
|
import { MessageWrapper } from '../Message/MessageItemView/MessageWrapper';
|
|
63
|
+
import { excludeCanceledUploadNotifications } from '../Notifications/notificationFilters';
|
|
63
64
|
import { PortalWhileClosingView } from '../UIComponents/PortalWhileClosingView';
|
|
64
65
|
|
|
65
66
|
type FlashListContextApi = { getRef?: () => FlashListRef<LocalMessage> | null } | undefined;
|
|
@@ -139,7 +140,10 @@ type MessageFlashListPropsWithContext = Pick<
|
|
|
139
140
|
| 'maximumMessageLimit'
|
|
140
141
|
> &
|
|
141
142
|
Pick<ChatContextValue, 'client'> &
|
|
142
|
-
Pick<
|
|
143
|
+
Pick<
|
|
144
|
+
MessageInputContextValue,
|
|
145
|
+
'allowSendBeforeAttachmentsUpload' | 'messageInputFloating' | 'messageInputHeightStore'
|
|
146
|
+
> &
|
|
143
147
|
Pick<PaginatedMessageListContextValue, 'loadMore' | 'loadMoreRecent'> &
|
|
144
148
|
Pick<
|
|
145
149
|
MessagesContextValue,
|
|
@@ -259,6 +263,7 @@ const MessageFlashListWithContext = (props: MessageFlashListPropsWithContext) =>
|
|
|
259
263
|
? InlineLoadingMoreRecentThreadIndicator
|
|
260
264
|
: InlineLoadingMoreRecentIndicator;
|
|
261
265
|
const {
|
|
266
|
+
allowSendBeforeAttachmentsUpload,
|
|
262
267
|
attachmentPickerStore,
|
|
263
268
|
additionalFlashListProps,
|
|
264
269
|
channel,
|
|
@@ -1153,7 +1158,10 @@ const MessageFlashListWithContext = (props: MessageFlashListPropsWithContext) =>
|
|
|
1153
1158
|
<AutoCompleteSuggestionList />
|
|
1154
1159
|
</PortalWhileClosingView>
|
|
1155
1160
|
</Animated.View>
|
|
1156
|
-
<NotificationList
|
|
1161
|
+
<NotificationList
|
|
1162
|
+
bottomOffset={messageInputFloating ? messageInputHeight + 16 : undefined}
|
|
1163
|
+
filter={allowSendBeforeAttachmentsUpload ? excludeCanceledUploadNotifications : undefined}
|
|
1164
|
+
/>
|
|
1157
1165
|
</View>
|
|
1158
1166
|
);
|
|
1159
1167
|
};
|
|
@@ -1238,11 +1246,13 @@ export const MessageFlashList = (props: MessageFlashListProps) => {
|
|
|
1238
1246
|
const { loadMore, loadMoreRecent } = usePaginatedMessageListContext();
|
|
1239
1247
|
const { loadMoreRecentThread, loadMoreThread, thread, threadInstance } = useThreadContext();
|
|
1240
1248
|
const { readEvents } = useOwnCapabilitiesContext();
|
|
1241
|
-
const { messageInputFloating, messageInputHeightStore } =
|
|
1249
|
+
const { allowSendBeforeAttachmentsUpload, messageInputFloating, messageInputHeightStore } =
|
|
1250
|
+
useMessageInputContext();
|
|
1242
1251
|
|
|
1243
1252
|
return (
|
|
1244
1253
|
<MessageFlashListWithContext
|
|
1245
1254
|
{...{
|
|
1255
|
+
allowSendBeforeAttachmentsUpload,
|
|
1246
1256
|
attachmentPickerStore,
|
|
1247
1257
|
channel,
|
|
1248
1258
|
channelUnreadStateStore,
|
|
@@ -74,6 +74,7 @@ import { primitives } from '../../theme';
|
|
|
74
74
|
import { transitions } from '../../utils/animations/transitions';
|
|
75
75
|
import { useIncomingMessageAnnouncements } from '../Accessibility/hooks/useIncomingMessageAnnouncements';
|
|
76
76
|
import { MessageWrapper } from '../Message/MessageItemView/MessageWrapper';
|
|
77
|
+
import { excludeCanceledUploadNotifications } from '../Notifications/notificationFilters';
|
|
77
78
|
import { PortalWhileClosingView } from '../UIComponents';
|
|
78
79
|
|
|
79
80
|
// This is just to make sure that the scrolling happens in a different task queue.
|
|
@@ -229,7 +230,10 @@ type MessageListPropsWithContext = Pick<
|
|
|
229
230
|
MessagesContextValue,
|
|
230
231
|
'disableTypingIndicator' | 'FlatList' | 'myMessageTheme' | 'shouldShowUnreadUnderlay'
|
|
231
232
|
> &
|
|
232
|
-
Pick<
|
|
233
|
+
Pick<
|
|
234
|
+
MessageInputContextValue,
|
|
235
|
+
'allowSendBeforeAttachmentsUpload' | 'messageInputFloating' | 'messageInputHeightStore'
|
|
236
|
+
> &
|
|
233
237
|
Pick<
|
|
234
238
|
ThreadContextValue,
|
|
235
239
|
'loadMoreRecentThread' | 'loadMoreThread' | 'threadHasMore' | 'thread' | 'threadInstance'
|
|
@@ -320,6 +324,7 @@ const MessageListWithContext = (props: MessageListPropsWithContext) => {
|
|
|
320
324
|
? InlineLoadingMoreRecentThreadIndicator
|
|
321
325
|
: InlineLoadingMoreRecentIndicator;
|
|
322
326
|
const {
|
|
327
|
+
allowSendBeforeAttachmentsUpload,
|
|
323
328
|
animateLayout = true,
|
|
324
329
|
attachmentPickerStore,
|
|
325
330
|
additionalFlatListProps,
|
|
@@ -1391,7 +1396,10 @@ const MessageListWithContext = (props: MessageListPropsWithContext) => {
|
|
|
1391
1396
|
<AutoCompleteSuggestionList />
|
|
1392
1397
|
</PortalWhileClosingView>
|
|
1393
1398
|
</Animated.View>
|
|
1394
|
-
<NotificationList
|
|
1399
|
+
<NotificationList
|
|
1400
|
+
bottomOffset={messageInputFloating ? messageInputHeight + 16 : undefined}
|
|
1401
|
+
filter={allowSendBeforeAttachmentsUpload ? excludeCanceledUploadNotifications : undefined}
|
|
1402
|
+
/>
|
|
1395
1403
|
</View>
|
|
1396
1404
|
);
|
|
1397
1405
|
};
|
|
@@ -1423,7 +1431,8 @@ export const MessageList = (props: MessageListProps) => {
|
|
|
1423
1431
|
const { readEvents } = useOwnCapabilitiesContext();
|
|
1424
1432
|
const { disableTypingIndicator, FlatList, myMessageTheme, shouldShowUnreadUnderlay } =
|
|
1425
1433
|
useMessagesContext();
|
|
1426
|
-
const { messageInputFloating, messageInputHeightStore } =
|
|
1434
|
+
const { allowSendBeforeAttachmentsUpload, messageInputFloating, messageInputHeightStore } =
|
|
1435
|
+
useMessageInputContext();
|
|
1427
1436
|
const { loadMore, loadMoreRecent, hasMore } = usePaginatedMessageListContext();
|
|
1428
1437
|
const { loadMoreRecentThread, loadMoreThread, threadHasMore, thread, threadInstance } =
|
|
1429
1438
|
useThreadContext();
|
|
@@ -1431,6 +1440,7 @@ export const MessageList = (props: MessageListProps) => {
|
|
|
1431
1440
|
return (
|
|
1432
1441
|
<MessageListWithContext
|
|
1433
1442
|
{...{
|
|
1443
|
+
allowSendBeforeAttachmentsUpload,
|
|
1434
1444
|
attachmentPickerStore,
|
|
1435
1445
|
channel,
|
|
1436
1446
|
channelUnreadStateStore,
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { Notification } from 'stream-chat';
|
|
2
|
+
|
|
3
|
+
import { excludeCanceledUploadNotifications } from '../notificationFilters';
|
|
4
|
+
|
|
5
|
+
const buildNotification = (overrides: Partial<Notification> = {}): Notification =>
|
|
6
|
+
({
|
|
7
|
+
createdAt: 0,
|
|
8
|
+
id: 'n1',
|
|
9
|
+
message: 'Error uploading attachment',
|
|
10
|
+
origin: { emitter: 'AttachmentManager' },
|
|
11
|
+
type: 'api:attachment:upload:failed',
|
|
12
|
+
...overrides,
|
|
13
|
+
}) as Notification;
|
|
14
|
+
|
|
15
|
+
const canceledError = (name: 'AbortError' | 'CanceledError') => {
|
|
16
|
+
const error = new Error('canceled');
|
|
17
|
+
error.name = name;
|
|
18
|
+
return error;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
// A filter returns `true` to KEEP a notification, `false` to hide it.
|
|
22
|
+
describe('excludeCanceledUploadNotifications', () => {
|
|
23
|
+
it.each(['AbortError', 'CanceledError'] as const)(
|
|
24
|
+
'hides an upload-failed notification aborted with %s',
|
|
25
|
+
(name) => {
|
|
26
|
+
const notification = buildNotification({ originalError: canceledError(name) });
|
|
27
|
+
|
|
28
|
+
expect(excludeCanceledUploadNotifications(notification)).toBe(false);
|
|
29
|
+
},
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
it('keeps a genuine upload failure', () => {
|
|
33
|
+
const notification = buildNotification({ originalError: new Error('Network Error') });
|
|
34
|
+
|
|
35
|
+
expect(excludeCanceledUploadNotifications(notification)).toBe(true);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it('keeps an upload-failed notification with no original error', () => {
|
|
39
|
+
expect(excludeCanceledUploadNotifications(buildNotification())).toBe(true);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it('keeps a cancellation error reported on a different notification type', () => {
|
|
43
|
+
const notification = buildNotification({
|
|
44
|
+
originalError: canceledError('CanceledError'),
|
|
45
|
+
type: 'api:message:send:failed',
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
expect(excludeCanceledUploadNotifications(notification)).toBe(true);
|
|
49
|
+
});
|
|
50
|
+
});
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { Notification } from 'stream-chat';
|
|
2
|
+
|
|
3
|
+
import type { NotificationListFilter } from './NotificationList';
|
|
4
|
+
|
|
5
|
+
const ATTACHMENT_UPLOAD_FAILED_TYPE = 'api:attachment:upload:failed';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* A cancelled upload surfaces as an `api:attachment:upload:failed` notification
|
|
9
|
+
* whose original error is an `AbortError` (fetch) or `CanceledError` (axios).
|
|
10
|
+
* This is what happens when the user removes an attachment before its upload
|
|
11
|
+
* has finished - the inflight request is aborted, not genuinely failed.
|
|
12
|
+
*/
|
|
13
|
+
const isCanceledAttachmentUpload = (notification: Notification) =>
|
|
14
|
+
notification.type === ATTACHMENT_UPLOAD_FAILED_TYPE &&
|
|
15
|
+
(notification.originalError?.name === 'CanceledError' ||
|
|
16
|
+
notification.originalError?.name === 'AbortError');
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Notification list filter that keeps every notification except the spurious
|
|
20
|
+
* "upload failed" one produced when a user removes an attachment mid-upload
|
|
21
|
+
* (a filter returns `true` to keep a notification). Genuine upload failures
|
|
22
|
+
* (network, server) are kept because their error is neither aborted nor
|
|
23
|
+
* cancelled.
|
|
24
|
+
*/
|
|
25
|
+
export const excludeCanceledUploadNotifications: NotificationListFilter = (notification) =>
|
|
26
|
+
!isCanceledAttachmentUpload(notification);
|
package/src/version.json
CHANGED