stream-chat-react-native-core 10.0.0-rc.3 → 10.0.0-rc.5
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/AttachmentPicker/components/AttachmentMediaPicker/AttachmentPickerItem.js +4 -1
- package/lib/commonjs/components/AttachmentPicker/components/AttachmentMediaPicker/AttachmentPickerItem.js.map +1 -1
- package/lib/commonjs/components/Channel/Channel.js +1 -0
- package/lib/commonjs/components/Channel/Channel.js.map +1 -1
- package/lib/commonjs/components/Channel/ChannelShell.js +8 -1
- package/lib/commonjs/components/Channel/ChannelShell.js.map +1 -1
- package/lib/commonjs/components/Channel/hooks/useChannelLifecycle.js +2 -2
- package/lib/commonjs/components/Channel/hooks/useChannelLifecycle.js.map +1 -1
- package/lib/commonjs/components/Channel/hooks/useJumpToLatestOnOpen.js +26 -0
- package/lib/commonjs/components/Channel/hooks/useJumpToLatestOnOpen.js.map +1 -0
- package/lib/commonjs/components/ChannelList/hooks/usePaginatedChannels.js +1 -1
- package/lib/commonjs/components/ChannelList/hooks/usePaginatedChannels.js.map +1 -1
- package/lib/commonjs/components/ChannelPreview/ChannelMessagePreviewDeliveryStatus.js +7 -0
- package/lib/commonjs/components/ChannelPreview/ChannelMessagePreviewDeliveryStatus.js.map +1 -1
- package/lib/commonjs/components/ChannelPreview/ChannelPreviewMessage.js +4 -5
- package/lib/commonjs/components/ChannelPreview/ChannelPreviewMessage.js.map +1 -1
- package/lib/commonjs/components/Message/Message.js.map +1 -1
- package/lib/commonjs/components/Message/MessageItemView/Headers/SentToChannelHeader.js +6 -32
- package/lib/commonjs/components/Message/MessageItemView/Headers/SentToChannelHeader.js.map +1 -1
- package/lib/commonjs/components/Message/MessageItemView/MessageContent.js +2 -2
- package/lib/commonjs/components/Message/MessageItemView/MessageContent.js.map +1 -1
- package/lib/commonjs/components/Message/MessageItemView/MessageStatus.js +29 -9
- package/lib/commonjs/components/Message/MessageItemView/MessageStatus.js.map +1 -1
- package/lib/commonjs/components/Message/hooks/useOpenThreadAtMessage.js +57 -0
- package/lib/commonjs/components/Message/hooks/useOpenThreadAtMessage.js.map +1 -0
- package/lib/commonjs/components/Message/utils/messageActions.js +1 -1
- package/lib/commonjs/components/Message/utils/messageActions.js.map +1 -1
- package/lib/commonjs/components/MessageInput/components/AttachmentPreview/AttachmentUploadPreviewList.js +12 -8
- package/lib/commonjs/components/MessageInput/components/AttachmentPreview/AttachmentUploadPreviewList.js.map +1 -1
- package/lib/commonjs/components/MessageInput/components/AttachmentPreview/AudioAttachmentUploadPreview.js +3 -2
- package/lib/commonjs/components/MessageInput/components/AttachmentPreview/AudioAttachmentUploadPreview.js.map +1 -1
- package/lib/commonjs/components/MessageInput/hooks/useAudioRecorder.js +2 -2
- package/lib/commonjs/components/MessageInput/hooks/useAudioRecorder.js.map +1 -1
- package/lib/commonjs/components/MessageList/InlineUnreadIndicator.js +2 -2
- package/lib/commonjs/components/MessageList/InlineUnreadIndicator.js.map +1 -1
- package/lib/commonjs/components/MessageList/MessageList.js +1 -4
- package/lib/commonjs/components/MessageList/MessageList.js.map +1 -1
- package/lib/commonjs/components/MessageList/hooks/useMessageListFocus.js +18 -2
- package/lib/commonjs/components/MessageList/hooks/useMessageListFocus.js.map +1 -1
- package/lib/commonjs/components/Thread/components/ThreadFooterComponent.js +1 -2
- package/lib/commonjs/components/Thread/components/ThreadFooterComponent.js.map +1 -1
- package/lib/commonjs/components/index.js +12 -0
- package/lib/commonjs/components/index.js.map +1 -1
- package/lib/commonjs/contexts/channelPinnedMessageListContext/ChannelPinnedMessageListContext.js +0 -15
- package/lib/commonjs/contexts/channelPinnedMessageListContext/ChannelPinnedMessageListContext.js.map +1 -1
- package/lib/commonjs/contexts/messageContext/MessageContext.js.map +1 -1
- package/lib/commonjs/contexts/messageListItemContext/MessageListItemContext.js.map +1 -1
- package/lib/commonjs/index.js +0 -12
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/types/types.js.map +1 -1
- package/lib/commonjs/version.json +1 -1
- package/lib/module/components/AttachmentPicker/components/AttachmentMediaPicker/AttachmentPickerItem.js +4 -1
- package/lib/module/components/AttachmentPicker/components/AttachmentMediaPicker/AttachmentPickerItem.js.map +1 -1
- package/lib/module/components/Channel/Channel.js +1 -0
- package/lib/module/components/Channel/Channel.js.map +1 -1
- package/lib/module/components/Channel/ChannelShell.js +8 -1
- package/lib/module/components/Channel/ChannelShell.js.map +1 -1
- package/lib/module/components/Channel/hooks/useChannelLifecycle.js +2 -2
- package/lib/module/components/Channel/hooks/useChannelLifecycle.js.map +1 -1
- package/lib/module/components/Channel/hooks/useJumpToLatestOnOpen.js +26 -0
- package/lib/module/components/Channel/hooks/useJumpToLatestOnOpen.js.map +1 -0
- package/lib/module/components/ChannelList/hooks/usePaginatedChannels.js +1 -1
- package/lib/module/components/ChannelList/hooks/usePaginatedChannels.js.map +1 -1
- package/lib/module/components/ChannelPreview/ChannelMessagePreviewDeliveryStatus.js +7 -0
- package/lib/module/components/ChannelPreview/ChannelMessagePreviewDeliveryStatus.js.map +1 -1
- package/lib/module/components/ChannelPreview/ChannelPreviewMessage.js +4 -5
- package/lib/module/components/ChannelPreview/ChannelPreviewMessage.js.map +1 -1
- package/lib/module/components/Message/Message.js.map +1 -1
- package/lib/module/components/Message/MessageItemView/Headers/SentToChannelHeader.js +6 -32
- package/lib/module/components/Message/MessageItemView/Headers/SentToChannelHeader.js.map +1 -1
- package/lib/module/components/Message/MessageItemView/MessageContent.js +2 -2
- package/lib/module/components/Message/MessageItemView/MessageContent.js.map +1 -1
- package/lib/module/components/Message/MessageItemView/MessageStatus.js +29 -9
- package/lib/module/components/Message/MessageItemView/MessageStatus.js.map +1 -1
- package/lib/module/components/Message/hooks/useOpenThreadAtMessage.js +57 -0
- package/lib/module/components/Message/hooks/useOpenThreadAtMessage.js.map +1 -0
- package/lib/module/components/Message/utils/messageActions.js +1 -1
- package/lib/module/components/Message/utils/messageActions.js.map +1 -1
- package/lib/module/components/MessageInput/components/AttachmentPreview/AttachmentUploadPreviewList.js +12 -8
- package/lib/module/components/MessageInput/components/AttachmentPreview/AttachmentUploadPreviewList.js.map +1 -1
- package/lib/module/components/MessageInput/components/AttachmentPreview/AudioAttachmentUploadPreview.js +3 -2
- package/lib/module/components/MessageInput/components/AttachmentPreview/AudioAttachmentUploadPreview.js.map +1 -1
- package/lib/module/components/MessageInput/hooks/useAudioRecorder.js +2 -2
- package/lib/module/components/MessageInput/hooks/useAudioRecorder.js.map +1 -1
- package/lib/module/components/MessageList/InlineUnreadIndicator.js +2 -2
- package/lib/module/components/MessageList/InlineUnreadIndicator.js.map +1 -1
- package/lib/module/components/MessageList/MessageList.js +1 -4
- package/lib/module/components/MessageList/MessageList.js.map +1 -1
- package/lib/module/components/MessageList/hooks/useMessageListFocus.js +18 -2
- package/lib/module/components/MessageList/hooks/useMessageListFocus.js.map +1 -1
- package/lib/module/components/Thread/components/ThreadFooterComponent.js +1 -2
- package/lib/module/components/Thread/components/ThreadFooterComponent.js.map +1 -1
- package/lib/module/components/index.js +12 -0
- package/lib/module/components/index.js.map +1 -1
- package/lib/module/contexts/channelPinnedMessageListContext/ChannelPinnedMessageListContext.js +0 -15
- package/lib/module/contexts/channelPinnedMessageListContext/ChannelPinnedMessageListContext.js.map +1 -1
- package/lib/module/contexts/messageContext/MessageContext.js.map +1 -1
- package/lib/module/contexts/messageListItemContext/MessageListItemContext.js.map +1 -1
- package/lib/module/index.js +0 -12
- package/lib/module/index.js.map +1 -1
- package/lib/module/types/types.js.map +1 -1
- package/lib/module/version.json +1 -1
- package/lib/typescript/ai-components/services/media-picker-service/index.d.ts +1 -1
- package/lib/typescript/components/Channel/Channel.d.ts.map +1 -1
- package/lib/typescript/components/Channel/ChannelShell.d.ts +2 -0
- package/lib/typescript/components/Channel/ChannelShell.d.ts.map +1 -1
- package/lib/typescript/components/Channel/hooks/useChannelLifecycle.d.ts.map +1 -1
- package/lib/typescript/components/Channel/hooks/useJumpToLatestOnOpen.d.ts +15 -0
- package/lib/typescript/components/Channel/hooks/useJumpToLatestOnOpen.d.ts.map +1 -0
- package/lib/typescript/components/ChannelPreview/ChannelMessagePreviewDeliveryStatus.d.ts.map +1 -1
- package/lib/typescript/components/ChannelPreview/ChannelPreviewMessage.d.ts.map +1 -1
- package/lib/typescript/components/Message/Message.d.ts +2 -1
- package/lib/typescript/components/Message/Message.d.ts.map +1 -1
- package/lib/typescript/components/Message/MessageItemView/Headers/SentToChannelHeader.d.ts.map +1 -1
- package/lib/typescript/components/Message/MessageItemView/MessageContent.d.ts.map +1 -1
- package/lib/typescript/components/Message/MessageItemView/MessageStatus.d.ts +6 -0
- package/lib/typescript/components/Message/MessageItemView/MessageStatus.d.ts.map +1 -1
- package/lib/typescript/components/Message/hooks/useOpenThreadAtMessage.d.ts +14 -0
- package/lib/typescript/components/Message/hooks/useOpenThreadAtMessage.d.ts.map +1 -0
- package/lib/typescript/components/MessageInput/components/AttachmentPreview/AttachmentUploadPreviewList.d.ts.map +1 -1
- package/lib/typescript/components/MessageInput/components/AttachmentPreview/AudioAttachmentUploadPreview.d.ts.map +1 -1
- package/lib/typescript/components/MessageList/MessageList.d.ts.map +1 -1
- package/lib/typescript/components/MessageList/hooks/useMessageListFocus.d.ts +5 -2
- package/lib/typescript/components/MessageList/hooks/useMessageListFocus.d.ts.map +1 -1
- package/lib/typescript/components/Thread/components/ThreadFooterComponent.d.ts.map +1 -1
- package/lib/typescript/components/index.d.ts +1 -0
- package/lib/typescript/components/index.d.ts.map +1 -1
- package/lib/typescript/contexts/channelPinnedMessageListContext/ChannelPinnedMessageListContext.d.ts.map +1 -1
- package/lib/typescript/contexts/messageContext/MessageContext.d.ts +2 -1
- package/lib/typescript/contexts/messageContext/MessageContext.d.ts.map +1 -1
- package/lib/typescript/contexts/messageListItemContext/MessageListItemContext.d.ts +10 -6
- package/lib/typescript/contexts/messageListItemContext/MessageListItemContext.d.ts.map +1 -1
- package/lib/typescript/i18n/keys.d.ts +2 -2
- package/lib/typescript/i18n/keys.d.ts.map +1 -1
- package/lib/typescript/index.d.ts +0 -1
- package/lib/typescript/index.d.ts.map +1 -1
- package/lib/typescript/types/types.d.ts +0 -4
- package/lib/typescript/types/types.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/components/AttachmentPicker/components/AttachmentMediaPicker/AttachmentPickerItem.tsx +1 -1
- package/src/components/AttachmentPicker/components/AttachmentMediaPicker/__tests__/AttachmentPickerItem.test.tsx +29 -1
- package/src/components/Channel/Channel.tsx +1 -0
- package/src/components/Channel/ChannelShell.tsx +12 -0
- package/src/components/Channel/__tests__/Channel.test.tsx +142 -7
- package/src/components/Channel/hooks/useChannelLifecycle.ts +8 -4
- package/src/components/Channel/hooks/useCreateOwnCapabilitiesContext.ts +1 -1
- package/src/components/Channel/hooks/useJumpToLatestOnOpen.ts +42 -0
- package/src/components/ChannelList/__tests__/ChannelList.test.tsx +28 -0
- package/src/components/ChannelList/hooks/usePaginatedChannels.ts +1 -1
- package/src/components/ChannelPreview/ChannelMessagePreviewDeliveryStatus.tsx +8 -0
- package/src/components/ChannelPreview/ChannelPreviewMessage.tsx +2 -7
- package/src/components/ChannelPreview/__tests__/ChannelPreviewView.test.tsx +41 -0
- package/src/components/Message/Message.tsx +5 -2
- package/src/components/Message/MessageItemView/Headers/SentToChannelHeader.tsx +4 -32
- package/src/components/Message/MessageItemView/MessageContent.tsx +3 -2
- package/src/components/Message/MessageItemView/MessageStatus.tsx +43 -4
- package/src/components/Message/MessageItemView/__tests__/MessageContent.test.tsx +68 -1
- package/src/components/Message/MessageItemView/__tests__/MessageStatus.test.tsx +57 -0
- package/src/components/Message/hooks/useOpenThreadAtMessage.ts +50 -0
- package/src/components/Message/utils/__tests__/messageActions.test.ts +57 -0
- package/src/components/Message/utils/messageActions.ts +1 -1
- package/src/components/MessageInput/__tests__/AttachmentUploadPreviewList.test.tsx +34 -6
- package/src/components/MessageInput/__tests__/AudioAttachmentUploadPreview.test.tsx +24 -3
- package/src/components/MessageInput/__tests__/SendMessageDisallowedIndicator.test.tsx +3 -6
- package/src/components/MessageInput/components/AttachmentPreview/AttachmentUploadPreviewList.tsx +19 -8
- package/src/components/MessageInput/components/AttachmentPreview/AudioAttachmentUploadPreview.tsx +2 -5
- package/src/components/MessageInput/hooks/useAudioRecorder.tsx +2 -2
- package/src/components/MessageList/InlineUnreadIndicator.tsx +2 -2
- package/src/components/MessageList/MessageList.tsx +1 -5
- package/src/components/MessageList/__tests__/InlineUnreadIndicator.test.tsx +2 -2
- package/src/components/MessageList/__tests__/MessageList.test.tsx +252 -6
- package/src/components/MessageList/hooks/useMessageListFocus.ts +22 -2
- package/src/components/Thread/__tests__/Thread.test.tsx +131 -1
- package/src/components/Thread/components/ThreadFooterComponent.tsx +0 -1
- package/src/components/index.ts +1 -0
- package/src/contexts/channelPinnedMessageListContext/ChannelPinnedMessageListContext.tsx +5 -14
- package/src/contexts/messageContext/MessageContext.tsx +2 -1
- package/src/contexts/messageListItemContext/MessageListItemContext.tsx +15 -6
- package/src/i18n/__tests__/catalog.fixture.json +2 -2
- package/src/i18n/keys.ts +2 -2
- package/src/index.ts +0 -1
- package/src/types/stream-chat-common-custom-data.d.ts +0 -3
- package/src/types/types.ts +0 -5
- package/src/version.json +1 -1
- package/lib/commonjs/utils/setupCommandUIMiddlewares.js +0 -34
- package/lib/commonjs/utils/setupCommandUIMiddlewares.js.map +0 -1
- package/lib/module/utils/setupCommandUIMiddlewares.js +0 -34
- package/lib/module/utils/setupCommandUIMiddlewares.js.map +0 -1
- package/lib/typescript/utils/setupCommandUIMiddlewares.d.ts +0 -3
- package/lib/typescript/utils/setupCommandUIMiddlewares.d.ts.map +0 -1
- package/src/utils/setupCommandUIMiddlewares.ts +0 -31
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React from 'react';
|
|
1
|
+
import React, { useEffect } from 'react';
|
|
2
2
|
|
|
3
3
|
import { FlatList, StyleSheet } from 'react-native';
|
|
4
4
|
|
|
@@ -8,6 +8,9 @@ import type { LocalMessage, StreamChat as StreamChatClient, UserResponse } from
|
|
|
8
8
|
import { msToNs, Thread } from 'stream-chat';
|
|
9
9
|
|
|
10
10
|
import { WithComponents } from '../../../contexts/componentsContext/ComponentsContext';
|
|
11
|
+
import { useMessageComposerAPIContext } from '../../../contexts/messageComposerContext/MessageComposerAPIContext';
|
|
12
|
+
import { useMessageComposer } from '../../../contexts/messageInputContext/hooks/useMessageComposer';
|
|
13
|
+
import { useMessageInputContext } from '../../../contexts/messageInputContext/MessageInputContext';
|
|
11
14
|
import { OverlayProvider } from '../../../contexts/overlayContext/OverlayProvider';
|
|
12
15
|
import { getOrCreateChannelApi } from '../../../mock-builders/api/getOrCreateChannel';
|
|
13
16
|
|
|
@@ -22,6 +25,7 @@ import { getTestClientWithUser } from '../../../mock-builders/mock';
|
|
|
22
25
|
import { primitives } from '../../../theme';
|
|
23
26
|
import { Channel } from '../../Channel/Channel';
|
|
24
27
|
import { Chat } from '../../Chat/Chat';
|
|
28
|
+
import { MessageComposer } from '../../MessageInput/MessageComposer';
|
|
25
29
|
|
|
26
30
|
import { Thread as ThreadComponent } from '../../Thread/Thread';
|
|
27
31
|
import { SCROLL_TO_BOTTOM_ACCESSIBILITY_ACTION_NAME } from '../hooks/useScrollToBottomAccessibilityAction';
|
|
@@ -1290,12 +1294,12 @@ describe('MessageList in a thread', () => {
|
|
|
1290
1294
|
generateMessage({ parent_id: parentMessage.id, text: `reply-${i}` }),
|
|
1291
1295
|
),
|
|
1292
1296
|
) as LocalMessage[];
|
|
1297
|
+
// Seeded as the thread seeds `latest_replies`: one complete page, which is the newest one.
|
|
1293
1298
|
act(() =>
|
|
1294
|
-
threadInstance.messagePaginator.
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
items: replies,
|
|
1299
|
+
threadInstance.messagePaginator.setItems({
|
|
1300
|
+
valueOrFactory: replies,
|
|
1301
|
+
isFirstPage: true,
|
|
1302
|
+
isLastPage: true,
|
|
1299
1303
|
}),
|
|
1300
1304
|
);
|
|
1301
1305
|
|
|
@@ -1412,4 +1416,246 @@ describe('MessageList in a thread', () => {
|
|
|
1412
1416
|
});
|
|
1413
1417
|
expect(queryAllByLabelText('Inline unread indicator')).toHaveLength(0);
|
|
1414
1418
|
});
|
|
1419
|
+
|
|
1420
|
+
// A thread opened without its replies shows only its parent message until the first page lands.
|
|
1421
|
+
// Autoscroll has to be on by then, or the list keeps the parent in view and the replies render out
|
|
1422
|
+
// of view below it.
|
|
1423
|
+
it('autoscrolls to the replies that arrive after the thread opened empty', async () => {
|
|
1424
|
+
const mockedChannel = generateChannelResponse();
|
|
1425
|
+
const chatClient = await getTestClientWithUser({ id: 'testID' } as UserResponse);
|
|
1426
|
+
useMockedApis(chatClient, [getOrCreateChannelApi(mockedChannel)]);
|
|
1427
|
+
const channel = chatClient.channel('messaging', mockedChannel.channel.id);
|
|
1428
|
+
await channel.watch();
|
|
1429
|
+
const parentMessage = channel.state.formatMessage(generateMessage({ text: 'parent' }));
|
|
1430
|
+
const threadInstance = new Thread({ channel, client: chatClient, parentMessage });
|
|
1431
|
+
// The replies arrive from the test below, not from a query.
|
|
1432
|
+
jest.spyOn(threadInstance, 'reload').mockResolvedValue(undefined);
|
|
1433
|
+
jest.spyOn(threadInstance.messagePaginator, 'toTail').mockResolvedValue(undefined);
|
|
1434
|
+
const { getByTestId, getByText } = render(
|
|
1435
|
+
<OverlayProvider>
|
|
1436
|
+
<Chat client={chatClient}>
|
|
1437
|
+
<ThreadComponent thread={threadInstance}>
|
|
1438
|
+
<MessageList />
|
|
1439
|
+
</ThreadComponent>
|
|
1440
|
+
</Chat>
|
|
1441
|
+
</OverlayProvider>,
|
|
1442
|
+
);
|
|
1443
|
+
const autoscrollThreshold = () =>
|
|
1444
|
+
getByTestId('message-flat-list').props.maintainVisibleContentPosition
|
|
1445
|
+
?.autoscrollToTopThreshold;
|
|
1446
|
+
await waitFor(() => expect(autoscrollThreshold()).toBeDefined());
|
|
1447
|
+
|
|
1448
|
+
const replies = Array.from({ length: 3 }, (_, i) =>
|
|
1449
|
+
channel.state.formatMessage(
|
|
1450
|
+
generateMessage({ parent_id: parentMessage.id, text: `reply-${i}` }),
|
|
1451
|
+
),
|
|
1452
|
+
) as LocalMessage[];
|
|
1453
|
+
act(() =>
|
|
1454
|
+
threadInstance.messagePaginator.setItems({
|
|
1455
|
+
valueOrFactory: replies,
|
|
1456
|
+
isFirstPage: true,
|
|
1457
|
+
isLastPage: true,
|
|
1458
|
+
}),
|
|
1459
|
+
);
|
|
1460
|
+
|
|
1461
|
+
await waitFor(() => expect(getByText('reply-2')).toBeTruthy());
|
|
1462
|
+
expect(autoscrollThreshold()).toBeDefined();
|
|
1463
|
+
});
|
|
1464
|
+
|
|
1465
|
+
it.each([
|
|
1466
|
+
['scrolls to', 'testID', 1],
|
|
1467
|
+
['does not scroll to', 'other-user', 0],
|
|
1468
|
+
])(
|
|
1469
|
+
'%s the latest reply when a new reply is the user’s own (%s)',
|
|
1470
|
+
async (_, userId, expectedScrolls) => {
|
|
1471
|
+
const { channel, chatClient, getByText, threadInstance } = await setup();
|
|
1472
|
+
const scrollToOffset = jest.spyOn(FlatList.prototype, 'scrollToOffset');
|
|
1473
|
+
|
|
1474
|
+
const reply = channel.state.formatMessage(
|
|
1475
|
+
generateMessage({
|
|
1476
|
+
cid: channel.cid,
|
|
1477
|
+
parent_id: threadInstance.id,
|
|
1478
|
+
text: 'new reply',
|
|
1479
|
+
timestamp: new Date(),
|
|
1480
|
+
user: generateUser({ id: userId }),
|
|
1481
|
+
}),
|
|
1482
|
+
) as LocalMessage;
|
|
1483
|
+
await act(async () => {
|
|
1484
|
+
threadInstance.messagePaginator.ingestItem(reply);
|
|
1485
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
1486
|
+
});
|
|
1487
|
+
|
|
1488
|
+
await waitFor(() => expect(getByText('new reply')).toBeTruthy());
|
|
1489
|
+
expect(chatClient.userId).toBe('testID');
|
|
1490
|
+
expect(scrollToOffset).toHaveBeenCalledTimes(expectedScrolls);
|
|
1491
|
+
if (expectedScrolls) {
|
|
1492
|
+
expect(scrollToOffset).toHaveBeenCalledWith({ animated: true, offset: 0 });
|
|
1493
|
+
}
|
|
1494
|
+
},
|
|
1495
|
+
);
|
|
1496
|
+
});
|
|
1497
|
+
|
|
1498
|
+
// Pressing a quote goes to the quoted message. A quoted reply that lives only in another thread is
|
|
1499
|
+
// not in this list, so its thread is opened at it instead.
|
|
1500
|
+
describe('MessageList quote press', () => {
|
|
1501
|
+
afterEach(() => {
|
|
1502
|
+
cleanup();
|
|
1503
|
+
jest.restoreAllMocks();
|
|
1504
|
+
});
|
|
1505
|
+
|
|
1506
|
+
const setup = async ({ quoteThreadOnlyReply }: { quoteThreadOnlyReply: boolean }) => {
|
|
1507
|
+
const user = generateUser();
|
|
1508
|
+
const base = new Date('2020-01-01T00:00:00.000Z').getTime();
|
|
1509
|
+
const parentMessage = generateMessage({ timestamp: new Date(base), user });
|
|
1510
|
+
const quotedMessage = generateMessage({
|
|
1511
|
+
parent_id: quoteThreadOnlyReply ? parentMessage.id : undefined,
|
|
1512
|
+
text: 'quoted text',
|
|
1513
|
+
timestamp: new Date(base + 1000),
|
|
1514
|
+
user,
|
|
1515
|
+
});
|
|
1516
|
+
const mockedChannel = generateChannelResponse({
|
|
1517
|
+
members: [generateMember({ user })],
|
|
1518
|
+
messages: [
|
|
1519
|
+
parentMessage,
|
|
1520
|
+
generateMessage({
|
|
1521
|
+
quoted_message: quotedMessage,
|
|
1522
|
+
quoted_message_id: quotedMessage.id,
|
|
1523
|
+
timestamp: new Date(base + 2000),
|
|
1524
|
+
user,
|
|
1525
|
+
}),
|
|
1526
|
+
],
|
|
1527
|
+
});
|
|
1528
|
+
const chatClient = await getTestClientWithUser({ id: 'testID' } as UserResponse);
|
|
1529
|
+
useMockedApis(chatClient, [getOrCreateChannelApi(mockedChannel)]);
|
|
1530
|
+
const channel = chatClient.channel('messaging', mockedChannel.channel.id);
|
|
1531
|
+
await channel.watch();
|
|
1532
|
+
const thread = chatClient.threads.ensure({
|
|
1533
|
+
channel,
|
|
1534
|
+
parentMessage: channel.state.formatMessage(parentMessage),
|
|
1535
|
+
});
|
|
1536
|
+
const jumpToMessage = jest
|
|
1537
|
+
.spyOn(channel.messagePaginator, 'jumpToMessage')
|
|
1538
|
+
.mockResolvedValue(true);
|
|
1539
|
+
const onAlsoSentToChannelHeaderPress = jest.fn();
|
|
1540
|
+
|
|
1541
|
+
const utils = render(
|
|
1542
|
+
<OverlayProvider>
|
|
1543
|
+
<Chat client={chatClient}>
|
|
1544
|
+
<Channel
|
|
1545
|
+
channel={channel}
|
|
1546
|
+
onAlsoSentToChannelHeaderPress={onAlsoSentToChannelHeaderPress}
|
|
1547
|
+
>
|
|
1548
|
+
<MessageList />
|
|
1549
|
+
</Channel>
|
|
1550
|
+
</Chat>
|
|
1551
|
+
</OverlayProvider>,
|
|
1552
|
+
);
|
|
1553
|
+
return { ...utils, jumpToMessage, onAlsoSentToChannelHeaderPress, quotedMessage, thread };
|
|
1554
|
+
};
|
|
1555
|
+
|
|
1556
|
+
it('opens the thread of a quoted reply that lives only in that thread', async () => {
|
|
1557
|
+
const { findByText, jumpToMessage, onAlsoSentToChannelHeaderPress, quotedMessage, thread } =
|
|
1558
|
+
await setup({ quoteThreadOnlyReply: true });
|
|
1559
|
+
|
|
1560
|
+
fireEvent.press(await findByText('quoted text'));
|
|
1561
|
+
|
|
1562
|
+
await waitFor(() =>
|
|
1563
|
+
expect(onAlsoSentToChannelHeaderPress).toHaveBeenCalledWith({
|
|
1564
|
+
targetedMessageId: quotedMessage.id,
|
|
1565
|
+
thread,
|
|
1566
|
+
}),
|
|
1567
|
+
);
|
|
1568
|
+
expect(jumpToMessage).not.toHaveBeenCalled();
|
|
1569
|
+
});
|
|
1570
|
+
|
|
1571
|
+
it('jumps to a quoted message that is in the channel', async () => {
|
|
1572
|
+
const { findByText, jumpToMessage, onAlsoSentToChannelHeaderPress, quotedMessage } =
|
|
1573
|
+
await setup({ quoteThreadOnlyReply: false });
|
|
1574
|
+
|
|
1575
|
+
fireEvent.press(await findByText('quoted text'));
|
|
1576
|
+
|
|
1577
|
+
await waitFor(() =>
|
|
1578
|
+
expect(jumpToMessage).toHaveBeenCalledWith(quotedMessage.id, expect.anything()),
|
|
1579
|
+
);
|
|
1580
|
+
expect(onAlsoSentToChannelHeaderPress).not.toHaveBeenCalled();
|
|
1581
|
+
});
|
|
1582
|
+
});
|
|
1583
|
+
|
|
1584
|
+
describe('MessageList optimistic edit', () => {
|
|
1585
|
+
afterEach(() => {
|
|
1586
|
+
cleanup();
|
|
1587
|
+
jest.restoreAllMocks();
|
|
1588
|
+
});
|
|
1589
|
+
|
|
1590
|
+
// A UI renders `i18n.<language>_text` in place of `text`, so an optimistic edit that kept the
|
|
1591
|
+
// translations of the old text showed the "Edited" label over the old message until the server
|
|
1592
|
+
// responded (or, offline, until the edit was replayed).
|
|
1593
|
+
it('shows an edit of an auto-translated message before the request resolves', async () => {
|
|
1594
|
+
const me = generateUser({ id: 'testID' });
|
|
1595
|
+
const mine = generateMessage({
|
|
1596
|
+
i18n: { en_text: 'before edit', es_text: 'antes de editar', language: 'en' },
|
|
1597
|
+
text: 'before edit',
|
|
1598
|
+
user: me,
|
|
1599
|
+
});
|
|
1600
|
+
const mockedChannel = generateChannelResponse({
|
|
1601
|
+
members: [generateMember({ user: me })],
|
|
1602
|
+
messages: [mine],
|
|
1603
|
+
});
|
|
1604
|
+
mine.cid = mockedChannel.channel.cid;
|
|
1605
|
+
|
|
1606
|
+
const chatClient = await getTestClientWithUser(me);
|
|
1607
|
+
useMockedApis(chatClient, [getOrCreateChannelApi(mockedChannel)]);
|
|
1608
|
+
const channel = chatClient.channel('messaging', mockedChannel.channel.id);
|
|
1609
|
+
await channel.watch();
|
|
1610
|
+
// Never settles, so whatever is on screen is the optimistic state.
|
|
1611
|
+
const updateMessage = jest
|
|
1612
|
+
.spyOn(chatClient, 'updateMessage')
|
|
1613
|
+
.mockImplementation(() => new Promise(() => undefined));
|
|
1614
|
+
|
|
1615
|
+
let startEditing: (message: LocalMessage) => void = () => undefined;
|
|
1616
|
+
let submit: () => Promise<void> = () => Promise.resolve();
|
|
1617
|
+
let composer: ReturnType<typeof useMessageComposer> | undefined;
|
|
1618
|
+
const EditDriver = () => {
|
|
1619
|
+
const { setEditingState } = useMessageComposerAPIContext();
|
|
1620
|
+
const { sendMessage } = useMessageInputContext();
|
|
1621
|
+
const messageComposer = useMessageComposer();
|
|
1622
|
+
useEffect(() => {
|
|
1623
|
+
startEditing = setEditingState;
|
|
1624
|
+
submit = sendMessage;
|
|
1625
|
+
composer = messageComposer;
|
|
1626
|
+
});
|
|
1627
|
+
return null;
|
|
1628
|
+
};
|
|
1629
|
+
|
|
1630
|
+
const { getByTestId } = render(
|
|
1631
|
+
<OverlayProvider>
|
|
1632
|
+
<Chat client={chatClient}>
|
|
1633
|
+
<Channel channel={channel}>
|
|
1634
|
+
<MessageList />
|
|
1635
|
+
<MessageComposer />
|
|
1636
|
+
<EditDriver />
|
|
1637
|
+
</Channel>
|
|
1638
|
+
</Chat>
|
|
1639
|
+
</OverlayProvider>,
|
|
1640
|
+
);
|
|
1641
|
+
await waitFor(() =>
|
|
1642
|
+
expect(
|
|
1643
|
+
within(getByTestId(`message-list-item-${mine.id}`)).getByText('before edit'),
|
|
1644
|
+
).toBeTruthy(),
|
|
1645
|
+
);
|
|
1646
|
+
|
|
1647
|
+
act(() => startEditing(channel.messagePaginator.getItem(mine.id) as LocalMessage));
|
|
1648
|
+
await waitFor(() => expect(composer?.editedMessage?.id).toBe(mine.id));
|
|
1649
|
+
act(() => composer?.textComposer.setText('after edit'));
|
|
1650
|
+
act(() => {
|
|
1651
|
+
void submit();
|
|
1652
|
+
});
|
|
1653
|
+
|
|
1654
|
+
await waitFor(() => expect(updateMessage).toHaveBeenCalled());
|
|
1655
|
+
await waitFor(() => {
|
|
1656
|
+
const row = within(getByTestId(`message-list-item-${mine.id}`));
|
|
1657
|
+
expect(row.getByText('after edit')).toBeTruthy();
|
|
1658
|
+
expect(row.queryByText('before edit')).toBeNull();
|
|
1659
|
+
});
|
|
1660
|
+
}, 15000);
|
|
1415
1661
|
});
|
|
@@ -2,7 +2,11 @@ import { useEffect } from 'react';
|
|
|
2
2
|
|
|
3
3
|
import type { MessagePaginator } from 'stream-chat';
|
|
4
4
|
|
|
5
|
+
import type { GoToMessage } from '../../../contexts/messageListItemContext/MessageListItemContext';
|
|
6
|
+
import { useMessagesContext } from '../../../contexts/messagesContext/MessagesContext';
|
|
7
|
+
import { useThreadContext } from '../../../contexts/threadContext/ThreadContext';
|
|
5
8
|
import { useStableCallback, useStateStore } from '../../../hooks';
|
|
9
|
+
import { useOpenThreadAtMessage } from '../../Message/hooks/useOpenThreadAtMessage';
|
|
6
10
|
|
|
7
11
|
/** How long, in milliseconds, a message the list jumped to stays highlighted. */
|
|
8
12
|
export const DEFAULT_HIGHLIGHT_DURATION = 3000;
|
|
@@ -23,7 +27,9 @@ const messageFocusSelector = (state: {
|
|
|
23
27
|
* still running when the user navigates away would scroll and highlight again on return.
|
|
24
28
|
*
|
|
25
29
|
* @param paginator The channel's or the open thread's paginator.
|
|
26
|
-
* @returns `focusedMessageId`, `focusToken` and `goToMessage`, which jumps to a message by ID.
|
|
30
|
+
* @returns `focusedMessageId`, `focusToken` and `goToMessage`, which jumps to a message by ID. A
|
|
31
|
+
* message passed along that is a reply living only in another thread is not in this list, so its
|
|
32
|
+
* thread is opened at it instead (through `onAlsoSentToChannelHeaderPress`, when set).
|
|
27
33
|
*/
|
|
28
34
|
export const useMessageListFocus = (paginator?: MessagePaginator) => {
|
|
29
35
|
const { focusedMessageId, focusToken } =
|
|
@@ -31,7 +37,21 @@ export const useMessageListFocus = (paginator?: MessagePaginator) => {
|
|
|
31
37
|
|
|
32
38
|
useEffect(() => () => paginator?.clearMessageFocusSignal(), [paginator]);
|
|
33
39
|
|
|
34
|
-
const
|
|
40
|
+
const { onAlsoSentToChannelHeaderPress } = useMessagesContext();
|
|
41
|
+
const { thread } = useThreadContext();
|
|
42
|
+
const openThreadAtMessage = useOpenThreadAtMessage();
|
|
43
|
+
|
|
44
|
+
const goToMessage: GoToMessage = useStableCallback(async (messageId, message) => {
|
|
45
|
+
const parentId = message?.parent_id;
|
|
46
|
+
if (
|
|
47
|
+
onAlsoSentToChannelHeaderPress &&
|
|
48
|
+
parentId &&
|
|
49
|
+
parentId !== thread?.id &&
|
|
50
|
+
!message.show_in_channel
|
|
51
|
+
) {
|
|
52
|
+
await openThreadAtMessage({ parentId, targetedMessageId: messageId });
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
35
55
|
await paginator?.jumpToMessage(messageId, {
|
|
36
56
|
focusReason: 'jump-to-message',
|
|
37
57
|
focusSignalTtlMs: DEFAULT_HIGHLIGHT_DURATION,
|
|
@@ -1,6 +1,14 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
act,
|
|
5
|
+
cleanup,
|
|
6
|
+
fireEvent,
|
|
7
|
+
render,
|
|
8
|
+
screen,
|
|
9
|
+
waitFor,
|
|
10
|
+
within,
|
|
11
|
+
} from '@testing-library/react-native';
|
|
4
12
|
import type {
|
|
5
13
|
Channel as ChannelType,
|
|
6
14
|
MessageResponse,
|
|
@@ -212,6 +220,43 @@ describe('Thread', () => {
|
|
|
212
220
|
// already has its data doesn't.
|
|
213
221
|
// An activation that is never released keeps the thread active for the session, so recovery
|
|
214
222
|
// keeps reloading it and it keeps being read automatically.
|
|
223
|
+
it.each([
|
|
224
|
+
['shows', true],
|
|
225
|
+
['does not show', false],
|
|
226
|
+
])(
|
|
227
|
+
'%s the delivery status of the parent message when it is the current user’s',
|
|
228
|
+
async (_, isOwn) => {
|
|
229
|
+
const parentMessage = generateMessage({
|
|
230
|
+
cid: channel.cid,
|
|
231
|
+
status: 'received',
|
|
232
|
+
text: 'Parent Message Text',
|
|
233
|
+
...(isOwn ? { user: generateUser({ id: chatClient.userId }) } : {}),
|
|
234
|
+
});
|
|
235
|
+
const threadInstance = new ThreadClass({ channel, client: chatClient, parentMessage });
|
|
236
|
+
// A thread with its replies loaded is not reloaded on open (see "metadata reload on open").
|
|
237
|
+
threadInstance.messagePaginator.setItems({
|
|
238
|
+
valueOrFactory: [
|
|
239
|
+
channel.state.formatMessage(
|
|
240
|
+
generateMessage({
|
|
241
|
+
cid: channel.cid,
|
|
242
|
+
parent_id: parentMessage.id,
|
|
243
|
+
}) as unknown as MessageResponse,
|
|
244
|
+
),
|
|
245
|
+
],
|
|
246
|
+
isFirstPage: true,
|
|
247
|
+
isLastPage: true,
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
renderComponent({ chatClient, thread: threadInstance });
|
|
251
|
+
|
|
252
|
+
const header = await screen.findByTestId('thread-footer-component');
|
|
253
|
+
expect(within(header).getByText('Parent Message Text')).toBeTruthy();
|
|
254
|
+
expect(within(header).queryByTestId('message-status-sent')).toBe(
|
|
255
|
+
isOwn ? within(header).getByTestId('message-status-sent') : null,
|
|
256
|
+
);
|
|
257
|
+
},
|
|
258
|
+
);
|
|
259
|
+
|
|
215
260
|
it('releases its activation of the thread on unmount', async () => {
|
|
216
261
|
const parentMessage = generateMessage({ cid: 'messaging:test-channel', text: 'Parent' });
|
|
217
262
|
const threadInstance = chatClient.threads.ensure({ channel, parentMessage });
|
|
@@ -586,4 +631,89 @@ describe('Thread lifecycle', () => {
|
|
|
586
631
|
expect(markRead.mock.calls.every(([options]) => options?.thread_id)).toBe(true);
|
|
587
632
|
});
|
|
588
633
|
});
|
|
634
|
+
|
|
635
|
+
describe('reopening a thread left on an older page', () => {
|
|
636
|
+
const OLDER_PAGE_START = new Date('2020-01-01T00:00:00.000Z').getTime();
|
|
637
|
+
|
|
638
|
+
// A thread whose newest replies are loaded, but whose list shows an older page, as it does
|
|
639
|
+
// after a jump to a quoted or searched reply.
|
|
640
|
+
const setUpThreadOnOlderPage = async () => {
|
|
641
|
+
const testChannel = await watchChannel();
|
|
642
|
+
const parentMessage = testChannel.state.formatMessage(generateMessage({ user }));
|
|
643
|
+
const threadInstance = new ThreadClass({
|
|
644
|
+
channel: testChannel,
|
|
645
|
+
client: chatClient,
|
|
646
|
+
parentMessage,
|
|
647
|
+
});
|
|
648
|
+
jest.spyOn(threadInstance, 'reload').mockResolvedValue(undefined);
|
|
649
|
+
jest.spyOn(threadInstance.messagePaginator, 'toTail').mockResolvedValue(undefined);
|
|
650
|
+
|
|
651
|
+
threadInstance.messagePaginator.setItems({
|
|
652
|
+
valueOrFactory: Array.from({ length: 10 }, (_, i) =>
|
|
653
|
+
generateMessage({ id: `newest-${i}`, parent_id: parentMessage.id }),
|
|
654
|
+
),
|
|
655
|
+
isFirstPage: true,
|
|
656
|
+
isLastPage: true,
|
|
657
|
+
});
|
|
658
|
+
threadInstance.messagePaginator.ingestPage({
|
|
659
|
+
page: Array.from({ length: 5 }, (_, i) =>
|
|
660
|
+
generateMessage({
|
|
661
|
+
id: `older-${i}`,
|
|
662
|
+
parent_id: parentMessage.id,
|
|
663
|
+
timestamp: OLDER_PAGE_START + i * 1000,
|
|
664
|
+
}),
|
|
665
|
+
),
|
|
666
|
+
policy: 'strict-overlap-only',
|
|
667
|
+
setActive: true,
|
|
668
|
+
});
|
|
669
|
+
expect(threadInstance.messagePaginator.isActiveIntervalAtHead).toBe(false);
|
|
670
|
+
|
|
671
|
+
return threadInstance;
|
|
672
|
+
};
|
|
673
|
+
|
|
674
|
+
it('shows the newest replies again', async () => {
|
|
675
|
+
const threadInstance = await setUpThreadOnOlderPage();
|
|
676
|
+
|
|
677
|
+
openThread(threadInstance);
|
|
678
|
+
|
|
679
|
+
await waitFor(() =>
|
|
680
|
+
expect(threadInstance.messagePaginator.isActiveIntervalAtHead).toBe(true),
|
|
681
|
+
);
|
|
682
|
+
expect(threadInstance.messagePaginator.items?.map((reply) => reply.id)).toContain('newest-9');
|
|
683
|
+
});
|
|
684
|
+
|
|
685
|
+
it('keeps a jump the integrator already made to a loaded reply', async () => {
|
|
686
|
+
const threadInstance = await setUpThreadOnOlderPage();
|
|
687
|
+
// A deep link from the screen: the target is loaded, so the jump lands at once.
|
|
688
|
+
await threadInstance.messagePaginator.jumpToMessage('older-2', {
|
|
689
|
+
focusReason: 'jump-to-message',
|
|
690
|
+
});
|
|
691
|
+
const jumpToTheLatestMessageSpy = jest.spyOn(
|
|
692
|
+
threadInstance.messagePaginator,
|
|
693
|
+
'jumpToTheLatestMessage',
|
|
694
|
+
);
|
|
695
|
+
|
|
696
|
+
openThread(threadInstance);
|
|
697
|
+
|
|
698
|
+
expect(jumpToTheLatestMessageSpy).not.toHaveBeenCalled();
|
|
699
|
+
expect(threadInstance.messagePaginator.isActiveIntervalAtHead).toBe(false);
|
|
700
|
+
expect(
|
|
701
|
+
threadInstance.messagePaginator.messageFocusSignal.getLatestValue().signal?.messageId,
|
|
702
|
+
).toBe('older-2');
|
|
703
|
+
});
|
|
704
|
+
|
|
705
|
+
it('leaves a jump that is still in flight alone', async () => {
|
|
706
|
+
const threadInstance = await setUpThreadOnOlderPage();
|
|
707
|
+
// A deep link to a reply that is not loaded: its query is in flight.
|
|
708
|
+
jest.spyOn(threadInstance.messagePaginator, 'isLoading', 'get').mockReturnValue(true);
|
|
709
|
+
const jumpToTheLatestMessageSpy = jest.spyOn(
|
|
710
|
+
threadInstance.messagePaginator,
|
|
711
|
+
'jumpToTheLatestMessage',
|
|
712
|
+
);
|
|
713
|
+
|
|
714
|
+
openThread(threadInstance);
|
|
715
|
+
|
|
716
|
+
expect(jumpToTheLatestMessageSpy).not.toHaveBeenCalled();
|
|
717
|
+
});
|
|
718
|
+
});
|
|
589
719
|
});
|
|
@@ -67,7 +67,6 @@ const ThreadFooterComponentWithContext = (props: ThreadFooterComponentPropsWithC
|
|
|
67
67
|
groupStyles={['single']}
|
|
68
68
|
message={parentMessage}
|
|
69
69
|
preventPress={parentMessagePreventPress}
|
|
70
|
-
showMessageStatus={false}
|
|
71
70
|
/>
|
|
72
71
|
<View style={styles.newThread}>
|
|
73
72
|
<Text style={styles.text}>
|
package/src/components/index.ts
CHANGED
|
@@ -34,6 +34,7 @@ export * from './Channel/hooks/useCreateChannelContext';
|
|
|
34
34
|
export * from './Channel/hooks/useCreateInputMessageInputContext';
|
|
35
35
|
export * from './Channel/hooks/useCreateMessagesContext';
|
|
36
36
|
export * from './Channel/hooks/useCreateThreadContext';
|
|
37
|
+
export * from './Channel/hooks/useJumpToLatestOnOpen';
|
|
37
38
|
|
|
38
39
|
export * from './ChannelList/ChannelList';
|
|
39
40
|
export * from './ChannelList/ChannelListFooterLoadingIndicator';
|
|
@@ -21,20 +21,11 @@ export const ChannelPinnedMessageListProvider = ({
|
|
|
21
21
|
}: PropsWithChildren<{ channel: Channel; searchSource?: MessageSearchSource }>) => {
|
|
22
22
|
const { client } = useChatContext();
|
|
23
23
|
const [defaultSearchSource] = useState(() => {
|
|
24
|
-
const source = new MessageSearchSource(
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
initialFilterConfig: {
|
|
30
|
-
$or: {
|
|
31
|
-
enabled: true,
|
|
32
|
-
generate: ({ searchQuery }) => (searchQuery ? { text: { $q: searchQuery } } : {}),
|
|
33
|
-
},
|
|
34
|
-
},
|
|
35
|
-
},
|
|
36
|
-
},
|
|
37
|
-
);
|
|
24
|
+
const source = new MessageSearchSource(client, {
|
|
25
|
+
pageSize: 25,
|
|
26
|
+
allowEmptySearchString: true,
|
|
27
|
+
resetOnNewSearchQuery: false,
|
|
28
|
+
});
|
|
38
29
|
source.messageSearchChannelFilters = { cid: channel.cid, members: undefined };
|
|
39
30
|
source.messageSearchFilters = { pinned: true, type: undefined };
|
|
40
31
|
source.activate();
|
|
@@ -19,6 +19,7 @@ import type { Rect } from '../../state-store/message-overlay-store';
|
|
|
19
19
|
import type { ViewRef } from '../../types/react-native-compat';
|
|
20
20
|
|
|
21
21
|
import type { MessageComposerAPIContextValue } from '../messageComposerContext/MessageComposerAPIContext';
|
|
22
|
+
import type { GoToMessage } from '../messageListItemContext/MessageListItemContext';
|
|
22
23
|
import { DEFAULT_BASE_CONTEXT_VALUE } from '../utils/defaultBaseContextValue';
|
|
23
24
|
|
|
24
25
|
export type Alignment = 'right' | 'left';
|
|
@@ -113,7 +114,7 @@ export type MessageContextValue = {
|
|
|
113
114
|
showMessageStatus: boolean;
|
|
114
115
|
/** The video attachments of the message. */
|
|
115
116
|
videos: Attachment[];
|
|
116
|
-
goToMessage?:
|
|
117
|
+
goToMessage?: GoToMessage;
|
|
117
118
|
/**
|
|
118
119
|
* Handles a reaction on the message.
|
|
119
120
|
*
|
|
@@ -1,18 +1,27 @@
|
|
|
1
1
|
import React, { createContext, PropsWithChildren, useContext } from 'react';
|
|
2
2
|
|
|
3
|
+
import type { LocalMessage } from 'stream-chat';
|
|
4
|
+
|
|
3
5
|
import { MessageListProps } from '../../components/MessageList/MessageList';
|
|
4
6
|
|
|
5
7
|
import { Theme } from '../themeContext/utils/theme';
|
|
6
8
|
import { DEFAULT_BASE_CONTEXT_VALUE } from '../utils/defaultBaseContextValue';
|
|
7
9
|
import { isTestEnvironment } from '../utils/isTestEnvironment';
|
|
8
10
|
|
|
11
|
+
/**
|
|
12
|
+
* Goes to a message, used when a quoted message is pressed.
|
|
13
|
+
*
|
|
14
|
+
* @param messageId The ID of the message to go to.
|
|
15
|
+
* @param message The message, when the caller has it (the pressed quote passes its quoted message).
|
|
16
|
+
*/
|
|
17
|
+
export type GoToMessage = (
|
|
18
|
+
messageId: string,
|
|
19
|
+
message?: NonNullable<LocalMessage['quoted_message']>,
|
|
20
|
+
) => void;
|
|
21
|
+
|
|
9
22
|
export type MessageListItemContextValue = {
|
|
10
|
-
/**
|
|
11
|
-
|
|
12
|
-
*
|
|
13
|
-
* @param messageId The ID of the message to go to.
|
|
14
|
-
*/
|
|
15
|
-
goToMessage: (messageId: string) => void;
|
|
23
|
+
/** Goes to a message, used when a quoted message is pressed. */
|
|
24
|
+
goToMessage: GoToMessage;
|
|
16
25
|
/** The theme of the list items, with `myMessageTheme` merged in. */
|
|
17
26
|
modifiedTheme: Theme;
|
|
18
27
|
/** Turns off grouping of consecutive messages by user. */
|
|
@@ -295,8 +295,8 @@
|
|
|
295
295
|
"messageInput.sendMessage.accessibilityLabel": "Send message",
|
|
296
296
|
"messageInput.sendMessageDisallowed.text": "You can't send messages in this channel",
|
|
297
297
|
"messageList.dismissUnread.accessibilityLabel": "Dismiss unread messages",
|
|
298
|
-
"messageList.newMessages.text_one": "{{count}}
|
|
299
|
-
"messageList.newMessages.text_other": "{{count}}
|
|
298
|
+
"messageList.newMessages.text_one": "{{count}} unread message",
|
|
299
|
+
"messageList.newMessages.text_other": "{{count}} unread messages",
|
|
300
300
|
"messageList.scrollToBottom.accessibilityLabel": "Scroll to bottom",
|
|
301
301
|
"messageList.scrollToBottom.withCount.accessibilityLabel_one": "Scroll to bottom, {{count}} new message",
|
|
302
302
|
"messageList.scrollToBottom.withCount.accessibilityLabel_other": "Scroll to bottom, {{count}} new messages",
|
package/src/i18n/keys.ts
CHANGED
|
@@ -306,8 +306,8 @@ export type TranslationCatalog = {
|
|
|
306
306
|
'messageInput.sendMessage.accessibilityLabel': 'Send message';
|
|
307
307
|
'messageInput.sendMessageDisallowed.text': "You can't send messages in this channel";
|
|
308
308
|
'messageList.dismissUnread.accessibilityLabel': 'Dismiss unread messages';
|
|
309
|
-
'messageList.newMessages.text_one': '{{count}}
|
|
310
|
-
'messageList.newMessages.text_other': '{{count}}
|
|
309
|
+
'messageList.newMessages.text_one': '{{count}} unread message';
|
|
310
|
+
'messageList.newMessages.text_other': '{{count}} unread messages';
|
|
311
311
|
'messageList.scrollToBottom.accessibilityLabel': 'Scroll to bottom';
|
|
312
312
|
'messageList.scrollToBottom.withCount.accessibilityLabel_one': 'Scroll to bottom, {{count}} new message';
|
|
313
313
|
'messageList.scrollToBottom.withCount.accessibilityLabel_other': 'Scroll to bottom, {{count}} new messages';
|
package/src/index.ts
CHANGED
|
@@ -23,7 +23,6 @@ export * from './types/types';
|
|
|
23
23
|
export * from './utils/attachmentUrls';
|
|
24
24
|
export * from './utils/i18n/Streami18n';
|
|
25
25
|
export * from './i18n';
|
|
26
|
-
export * from './utils/setupCommandUIMiddlewares';
|
|
27
26
|
export * from './utils/createGenerateVideoThumbnails';
|
|
28
27
|
export * from './utils/utils';
|
|
29
28
|
export * from './nativeMultipartUpload';
|
|
@@ -3,7 +3,6 @@ import 'stream-chat';
|
|
|
3
3
|
import {
|
|
4
4
|
DefaultAttachmentData,
|
|
5
5
|
DefaultChannelData,
|
|
6
|
-
DefaultCommandData,
|
|
7
6
|
DefaultEventData,
|
|
8
7
|
DefaultMemberData,
|
|
9
8
|
DefaultMessageData,
|
|
@@ -21,8 +20,6 @@ declare module 'stream-chat' {
|
|
|
21
20
|
|
|
22
21
|
interface CustomChannelData extends DefaultChannelData {}
|
|
23
22
|
|
|
24
|
-
interface CustomCommandData extends DefaultCommandData {}
|
|
25
|
-
|
|
26
23
|
interface CustomEventData extends DefaultEventData {}
|
|
27
24
|
|
|
28
25
|
interface CustomMemberData extends DefaultMemberData {}
|
package/src/types/types.ts
CHANGED
|
@@ -60,11 +60,6 @@ export interface DefaultChannelData {
|
|
|
60
60
|
name?: string;
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
-
export interface DefaultCommandData {
|
|
64
|
-
flag: unknown;
|
|
65
|
-
imgur: unknown;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
63
|
/* eslint-disable @typescript-eslint/no-empty-object-type */
|
|
69
64
|
|
|
70
65
|
export interface DefaultEventData {}
|
package/src/version.json
CHANGED