stream-chat-react-native-core 10.0.0-rc.4 → 10.0.0
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/hooks/useChannelLifecycle.js +2 -2
- package/lib/commonjs/components/Channel/hooks/useChannelLifecycle.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/ChannelPreview/hooks/useChannelPreviewPollLabel.js +8 -5
- package/lib/commonjs/components/ChannelPreview/hooks/useChannelPreviewPollLabel.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/Poll/Poll.js +5 -2
- package/lib/commonjs/components/Poll/Poll.js.map +1 -1
- package/lib/commonjs/components/Poll/components/PollAnswersList.js +4 -2
- package/lib/commonjs/components/Poll/components/PollAnswersList.js.map +1 -1
- package/lib/commonjs/components/Poll/components/PollOption.js +8 -3
- package/lib/commonjs/components/Poll/components/PollOption.js.map +1 -1
- package/lib/commonjs/components/Poll/components/PollResults/PollOptionFullResults.js +5 -2
- package/lib/commonjs/components/Poll/components/PollResults/PollOptionFullResults.js.map +1 -1
- package/lib/commonjs/components/Poll/components/PollResults/PollResultItem.js +3 -1
- package/lib/commonjs/components/Poll/components/PollResults/PollResultItem.js.map +1 -1
- package/lib/commonjs/components/Poll/components/PollResults/PollResults.js +4 -1
- package/lib/commonjs/components/Poll/components/PollResults/PollResults.js.map +1 -1
- package/lib/commonjs/components/Poll/hooks/usePollState.js +3 -0
- package/lib/commonjs/components/Poll/hooks/usePollState.js.map +1 -1
- package/lib/commonjs/components/Poll/hooks/usePollTextTranslation.js +17 -0
- package/lib/commonjs/components/Poll/hooks/usePollTextTranslation.js.map +1 -0
- package/lib/commonjs/components/Poll/index.js +11 -0
- package/lib/commonjs/components/Poll/index.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/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/hooks/messagePreview/useMessagePreviewText.js +9 -4
- package/lib/commonjs/hooks/messagePreview/useMessagePreviewText.js.map +1 -1
- package/lib/commonjs/hooks/useTranslatedMessage.js +4 -3
- package/lib/commonjs/hooks/useTranslatedMessage.js.map +1 -1
- package/lib/commonjs/index.js +0 -12
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/store/SqliteClient.js +1 -1
- package/lib/commonjs/store/mappers/mapPollToStorable.js +4 -0
- package/lib/commonjs/store/mappers/mapPollToStorable.js.map +1 -1
- package/lib/commonjs/store/mappers/mapStorableToPoll.js +5 -1
- package/lib/commonjs/store/mappers/mapStorableToPoll.js.map +1 -1
- package/lib/commonjs/store/schema.js +2 -0
- package/lib/commonjs/store/schema.js.map +1 -1
- package/lib/commonjs/types/types.js.map +1 -1
- package/lib/commonjs/utils/i18n/getTranslatedText.js +7 -0
- package/lib/commonjs/utils/i18n/getTranslatedText.js.map +1 -0
- package/lib/commonjs/utils/utils.js +35 -1
- package/lib/commonjs/utils/utils.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/hooks/useChannelLifecycle.js +2 -2
- package/lib/module/components/Channel/hooks/useChannelLifecycle.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/ChannelPreview/hooks/useChannelPreviewPollLabel.js +8 -5
- package/lib/module/components/ChannelPreview/hooks/useChannelPreviewPollLabel.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/Poll/Poll.js +5 -2
- package/lib/module/components/Poll/Poll.js.map +1 -1
- package/lib/module/components/Poll/components/PollAnswersList.js +4 -2
- package/lib/module/components/Poll/components/PollAnswersList.js.map +1 -1
- package/lib/module/components/Poll/components/PollOption.js +8 -3
- package/lib/module/components/Poll/components/PollOption.js.map +1 -1
- package/lib/module/components/Poll/components/PollResults/PollOptionFullResults.js +5 -2
- package/lib/module/components/Poll/components/PollResults/PollOptionFullResults.js.map +1 -1
- package/lib/module/components/Poll/components/PollResults/PollResultItem.js +3 -1
- package/lib/module/components/Poll/components/PollResults/PollResultItem.js.map +1 -1
- package/lib/module/components/Poll/components/PollResults/PollResults.js +4 -1
- package/lib/module/components/Poll/components/PollResults/PollResults.js.map +1 -1
- package/lib/module/components/Poll/hooks/usePollState.js +3 -0
- package/lib/module/components/Poll/hooks/usePollState.js.map +1 -1
- package/lib/module/components/Poll/hooks/usePollTextTranslation.js +17 -0
- package/lib/module/components/Poll/hooks/usePollTextTranslation.js.map +1 -0
- package/lib/module/components/Poll/index.js +11 -0
- package/lib/module/components/Poll/index.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/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/hooks/messagePreview/useMessagePreviewText.js +9 -4
- package/lib/module/hooks/messagePreview/useMessagePreviewText.js.map +1 -1
- package/lib/module/hooks/useTranslatedMessage.js +4 -3
- package/lib/module/hooks/useTranslatedMessage.js.map +1 -1
- package/lib/module/index.js +0 -12
- package/lib/module/index.js.map +1 -1
- package/lib/module/store/SqliteClient.js +1 -1
- package/lib/module/store/mappers/mapPollToStorable.js +4 -0
- package/lib/module/store/mappers/mapPollToStorable.js.map +1 -1
- package/lib/module/store/mappers/mapStorableToPoll.js +5 -1
- package/lib/module/store/mappers/mapStorableToPoll.js.map +1 -1
- package/lib/module/store/schema.js +2 -0
- package/lib/module/store/schema.js.map +1 -1
- package/lib/module/types/types.js.map +1 -1
- package/lib/module/utils/i18n/getTranslatedText.js +7 -0
- package/lib/module/utils/i18n/getTranslatedText.js.map +1 -0
- package/lib/module/utils/utils.js +35 -1
- package/lib/module/utils/utils.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/hooks/useChannelLifecycle.d.ts.map +1 -1
- 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/ChannelPreview/hooks/useChannelPreviewPollLabel.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/Poll/Poll.d.ts.map +1 -1
- package/lib/typescript/components/Poll/components/PollAnswersList.d.ts.map +1 -1
- package/lib/typescript/components/Poll/components/PollOption.d.ts.map +1 -1
- package/lib/typescript/components/Poll/components/PollResults/PollOptionFullResults.d.ts.map +1 -1
- package/lib/typescript/components/Poll/components/PollResults/PollResultItem.d.ts.map +1 -1
- package/lib/typescript/components/Poll/components/PollResults/PollResults.d.ts.map +1 -1
- package/lib/typescript/components/Poll/hooks/usePollState.d.ts +1 -0
- package/lib/typescript/components/Poll/hooks/usePollState.d.ts.map +1 -1
- package/lib/typescript/components/Poll/hooks/usePollTextTranslation.d.ts +7 -0
- package/lib/typescript/components/Poll/hooks/usePollTextTranslation.d.ts.map +1 -0
- package/lib/typescript/components/Poll/index.d.ts +1 -0
- package/lib/typescript/components/Poll/index.d.ts.map +1 -1
- package/lib/typescript/components/Thread/components/ThreadFooterComponent.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/hooks/messagePreview/useMessagePreviewText.d.ts.map +1 -1
- package/lib/typescript/hooks/useTranslatedMessage.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/store/mappers/mapPollToStorable.d.ts.map +1 -1
- package/lib/typescript/store/mappers/mapStorableToPoll.d.ts.map +1 -1
- package/lib/typescript/store/schema.d.ts +2 -0
- package/lib/typescript/store/schema.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/lib/typescript/utils/i18n/getTranslatedText.d.ts +8 -0
- package/lib/typescript/utils/i18n/getTranslatedText.d.ts.map +1 -0
- package/lib/typescript/utils/utils.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/__tests__/Channel.test.tsx +40 -7
- package/src/components/Channel/hooks/useChannelLifecycle.ts +8 -4
- package/src/components/Channel/hooks/useCreateOwnCapabilitiesContext.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/ChannelPreview/hooks/__tests__/useChannelPreviewPollLabel.test.tsx +28 -3
- package/src/components/ChannelPreview/hooks/useChannelPreviewPollLabel.ts +8 -4
- 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 +163 -0
- package/src/components/MessageList/hooks/useMessageListFocus.ts +22 -2
- package/src/components/Poll/Poll.tsx +4 -2
- package/src/components/Poll/__tests__/PollTranslation.test.tsx +152 -0
- package/src/components/Poll/components/PollAnswersList.tsx +5 -1
- package/src/components/Poll/components/PollOption.tsx +8 -4
- package/src/components/Poll/components/PollResults/PollOptionFullResults.tsx +5 -2
- package/src/components/Poll/components/PollResults/PollResultItem.tsx +3 -1
- package/src/components/Poll/components/PollResults/PollResults.tsx +4 -2
- package/src/components/Poll/hooks/usePollState.ts +4 -0
- package/src/components/Poll/hooks/usePollTextTranslation.ts +19 -0
- package/src/components/Poll/index.ts +1 -0
- package/src/components/Thread/__tests__/Thread.test.tsx +46 -1
- package/src/components/Thread/components/ThreadFooterComponent.tsx +0 -1
- 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/hooks/__tests__/useTranslatedMessage.test.tsx +20 -0
- package/src/hooks/messagePreview/__tests__/useMessagePreviewText.test.tsx +37 -2
- package/src/hooks/messagePreview/useMessagePreviewText.tsx +5 -2
- package/src/hooks/useTranslatedMessage.ts +6 -11
- package/src/i18n/__tests__/catalog.fixture.json +2 -2
- package/src/i18n/keys.ts +2 -2
- package/src/index.ts +0 -1
- package/src/store/SqliteClient.ts +1 -1
- package/src/store/apis/__tests__/pollTranslations.test.ts +136 -0
- package/src/store/mappers/mapPollToStorable.ts +6 -0
- package/src/store/mappers/mapStorableToPoll.ts +4 -0
- package/src/store/schema.ts +4 -0
- package/src/types/stream-chat-common-custom-data.d.ts +0 -3
- package/src/types/types.ts +0 -5
- package/src/utils/__tests__/utils.test.ts +42 -1
- package/src/utils/i18n/__tests__/getTranslatedText.test.ts +17 -0
- package/src/utils/i18n/getTranslatedText.ts +10 -0
- package/src/utils/utils.ts +57 -1
- package/src/version.json +1 -1
- package/lib/commonjs/utils/setupCommandUIMiddlewares.js +0 -37
- package/lib/commonjs/utils/setupCommandUIMiddlewares.js.map +0 -1
- package/lib/module/utils/setupCommandUIMiddlewares.js +0 -37
- 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/__tests__/setupCommandUIMiddlewares.test.ts +0 -49
- package/src/utils/setupCommandUIMiddlewares.ts +0 -34
package/src/components/MessageInput/components/AttachmentPreview/AttachmentUploadPreviewList.tsx
CHANGED
|
@@ -21,6 +21,7 @@ import {
|
|
|
21
21
|
isVideoAttachment,
|
|
22
22
|
LocalAttachment,
|
|
23
23
|
LocalAudioAttachment,
|
|
24
|
+
LocalUploadAttachment,
|
|
24
25
|
LocalVoiceRecordingAttachment,
|
|
25
26
|
} from 'stream-chat';
|
|
26
27
|
|
|
@@ -292,6 +293,16 @@ const UnMemoizedAttachmentUploadPreviewList = () => {
|
|
|
292
293
|
[attachmentManager, dataRef, prepareForRemoval],
|
|
293
294
|
);
|
|
294
295
|
|
|
296
|
+
// `uploadFile` does not check whether uploads are enabled, so a retry does not start one while
|
|
297
|
+
// they are off.
|
|
298
|
+
const handleRetry = useCallback(
|
|
299
|
+
(attachment: LocalUploadAttachment) => {
|
|
300
|
+
if (!attachmentManager.isUploadEnabled) return;
|
|
301
|
+
return attachmentManager.uploadFile(attachment);
|
|
302
|
+
},
|
|
303
|
+
[attachmentManager],
|
|
304
|
+
);
|
|
305
|
+
|
|
295
306
|
useLayoutEffect(() => {
|
|
296
307
|
const previousData = previousDataRef.current;
|
|
297
308
|
const nextIds = new Set(data.map((attachment) => attachment.localMetadata.id));
|
|
@@ -346,7 +357,7 @@ const UnMemoizedAttachmentUploadPreviewList = () => {
|
|
|
346
357
|
return (
|
|
347
358
|
<ImageAttachmentUploadPreview
|
|
348
359
|
attachment={attachment}
|
|
349
|
-
handleRetry={
|
|
360
|
+
handleRetry={handleRetry}
|
|
350
361
|
removeAttachments={removeAttachments}
|
|
351
362
|
/>
|
|
352
363
|
);
|
|
@@ -354,7 +365,7 @@ const UnMemoizedAttachmentUploadPreviewList = () => {
|
|
|
354
365
|
return (
|
|
355
366
|
<AudioAttachmentUploadPreview
|
|
356
367
|
attachment={attachment}
|
|
357
|
-
handleRetry={
|
|
368
|
+
handleRetry={handleRetry}
|
|
358
369
|
removeAttachments={removeAttachments}
|
|
359
370
|
/>
|
|
360
371
|
);
|
|
@@ -363,7 +374,7 @@ const UnMemoizedAttachmentUploadPreviewList = () => {
|
|
|
363
374
|
return (
|
|
364
375
|
<AudioAttachmentUploadPreview
|
|
365
376
|
attachment={attachment}
|
|
366
|
-
handleRetry={
|
|
377
|
+
handleRetry={handleRetry}
|
|
367
378
|
removeAttachments={removeAttachments}
|
|
368
379
|
/>
|
|
369
380
|
);
|
|
@@ -371,7 +382,7 @@ const UnMemoizedAttachmentUploadPreviewList = () => {
|
|
|
371
382
|
return (
|
|
372
383
|
<FileAttachmentUploadPreview
|
|
373
384
|
attachment={attachment}
|
|
374
|
-
handleRetry={
|
|
385
|
+
handleRetry={handleRetry}
|
|
375
386
|
removeAttachments={removeAttachments}
|
|
376
387
|
/>
|
|
377
388
|
);
|
|
@@ -380,7 +391,7 @@ const UnMemoizedAttachmentUploadPreviewList = () => {
|
|
|
380
391
|
return (
|
|
381
392
|
<VideoAttachmentUploadPreview
|
|
382
393
|
attachment={attachment}
|
|
383
|
-
handleRetry={
|
|
394
|
+
handleRetry={handleRetry}
|
|
384
395
|
removeAttachments={removeAttachments}
|
|
385
396
|
/>
|
|
386
397
|
);
|
|
@@ -388,7 +399,7 @@ const UnMemoizedAttachmentUploadPreviewList = () => {
|
|
|
388
399
|
return (
|
|
389
400
|
<FileAttachmentUploadPreview
|
|
390
401
|
attachment={attachment}
|
|
391
|
-
handleRetry={
|
|
402
|
+
handleRetry={handleRetry}
|
|
392
403
|
removeAttachments={removeAttachments}
|
|
393
404
|
/>
|
|
394
405
|
);
|
|
@@ -399,7 +410,7 @@ const UnMemoizedAttachmentUploadPreviewList = () => {
|
|
|
399
410
|
FileAttachmentUploadPreview,
|
|
400
411
|
ImageAttachmentUploadPreview,
|
|
401
412
|
VideoAttachmentUploadPreview,
|
|
402
|
-
|
|
413
|
+
handleRetry,
|
|
403
414
|
removeAttachments,
|
|
404
415
|
soundPackageAvailable,
|
|
405
416
|
],
|
|
@@ -496,7 +507,7 @@ const UnMemoizedAttachmentUploadPreviewList = () => {
|
|
|
496
507
|
<AttachmentPreviewCell key={attachment.localMetadata.id}>
|
|
497
508
|
<AudioAttachmentUploadPreview
|
|
498
509
|
attachment={attachment}
|
|
499
|
-
handleRetry={
|
|
510
|
+
handleRetry={handleRetry}
|
|
500
511
|
removeAttachments={removeAttachments}
|
|
501
512
|
/>
|
|
502
513
|
</AttachmentPreviewCell>
|
package/src/components/MessageInput/components/AttachmentPreview/AudioAttachmentUploadPreview.tsx
CHANGED
|
@@ -43,11 +43,8 @@ export const AudioAttachmentUploadPreview = ({
|
|
|
43
43
|
const messageComposer = useMessageComposer();
|
|
44
44
|
const isDraft = messageComposer.draftId;
|
|
45
45
|
const isEditing = messageComposer.editedMessage;
|
|
46
|
-
const
|
|
47
|
-
|
|
48
|
-
? attachment.asset_url
|
|
49
|
-
: (attachment.localMetadata.file as FileReference).uri) ??
|
|
50
|
-
(attachment.localMetadata.file as FileReference).uri;
|
|
46
|
+
const fileUri = (attachment.localMetadata.file as FileReference | undefined)?.uri;
|
|
47
|
+
const assetUrl = (isDraft || isEditing ? attachment.asset_url : fileUri) ?? fileUri;
|
|
51
48
|
|
|
52
49
|
const finalAttachment = useMemo(
|
|
53
50
|
() => ({
|
|
@@ -97,8 +97,8 @@ export const useAudioRecorder = ({
|
|
|
97
97
|
if (sendOnComplete) {
|
|
98
98
|
attachmentManager.upsertAttachments([audioFile]);
|
|
99
99
|
sendMessage();
|
|
100
|
-
} else {
|
|
101
|
-
await attachmentManager.
|
|
100
|
+
} else if (attachmentManager.isUploadEnabled) {
|
|
101
|
+
await attachmentManager.uploadFile(audioFile);
|
|
102
102
|
}
|
|
103
103
|
} catch (error) {
|
|
104
104
|
console.log('Error uploading voice recording: ', error);
|
|
@@ -20,8 +20,8 @@ export const InlineUnreadIndicator = (props: InlineUnreadIndicatorProps) => {
|
|
|
20
20
|
{unreadCount
|
|
21
21
|
? t('messageList.newMessages.text', {
|
|
22
22
|
count: unreadCount,
|
|
23
|
-
defaultValue_one: '{{count}}
|
|
24
|
-
defaultValue_other: '{{count}}
|
|
23
|
+
defaultValue_one: '{{count}} unread message',
|
|
24
|
+
defaultValue_other: '{{count}} unread messages',
|
|
25
25
|
})
|
|
26
26
|
: t('messageList.unreadMessages.label', 'Unread Messages')}
|
|
27
27
|
</Text>
|
|
@@ -432,12 +432,8 @@ const MessageListWithContext = (props: MessageListPropsWithContext) => {
|
|
|
432
432
|
}, [disabled]);
|
|
433
433
|
|
|
434
434
|
useEffect(() => {
|
|
435
|
-
if (thread) {
|
|
436
|
-
setAutoscrollToRecent(true);
|
|
437
|
-
return;
|
|
438
|
-
}
|
|
439
|
-
|
|
440
435
|
if (!processedMessageList.length || !paginator) {
|
|
436
|
+
if (thread) setAutoscrollToRecent(true);
|
|
441
437
|
return;
|
|
442
438
|
}
|
|
443
439
|
|
|
@@ -9,8 +9,8 @@ import { InlineUnreadIndicator } from '../InlineUnreadIndicator';
|
|
|
9
9
|
|
|
10
10
|
describe('InlineUnreadIndicator', () => {
|
|
11
11
|
it.each([
|
|
12
|
-
[1, '1
|
|
13
|
-
[3, '3
|
|
12
|
+
[1, '1 unread message'],
|
|
13
|
+
[3, '3 unread messages'],
|
|
14
14
|
])('labels %i unread messages as "%s"', async (unreadCount, label) => {
|
|
15
15
|
const translators = await new Streami18n().init();
|
|
16
16
|
render(
|
|
@@ -1416,6 +1416,169 @@ describe('MessageList in a thread', () => {
|
|
|
1416
1416
|
});
|
|
1417
1417
|
expect(queryAllByLabelText('Inline unread indicator')).toHaveLength(0);
|
|
1418
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
|
+
});
|
|
1419
1582
|
});
|
|
1420
1583
|
|
|
1421
1584
|
describe('MessageList optimistic edit', () => {
|
|
@@ -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,
|
|
@@ -8,6 +8,7 @@ import { PollUIStateProvider } from './contexts/PollUIStateContext';
|
|
|
8
8
|
|
|
9
9
|
import { useIsPollCreatedByCurrentUser } from './hook/useIsPollCreatedByCurrentUser';
|
|
10
10
|
import { usePollState } from './hooks/usePollState';
|
|
11
|
+
import { usePollTextTranslation } from './hooks/usePollTextTranslation';
|
|
11
12
|
|
|
12
13
|
import {
|
|
13
14
|
PollContextProvider,
|
|
@@ -27,7 +28,8 @@ export type PollContentProps = Record<string, never>;
|
|
|
27
28
|
export const PollHeader = () => {
|
|
28
29
|
const styles = useStyles();
|
|
29
30
|
const { t } = useTranslationContext();
|
|
30
|
-
const { enforceUniqueVote, isClosed, maxVotesAllowed, name } = usePollState();
|
|
31
|
+
const { enforceUniqueVote, isClosed, maxVotesAllowed, name, nameI18n } = usePollState();
|
|
32
|
+
const translate = usePollTextTranslation();
|
|
31
33
|
|
|
32
34
|
const subtitle = useMemo(() => {
|
|
33
35
|
if (isClosed) {
|
|
@@ -56,7 +58,7 @@ export const PollHeader = () => {
|
|
|
56
58
|
|
|
57
59
|
return (
|
|
58
60
|
<View accessible accessibilityRole='text' style={styles.headerContainer}>
|
|
59
|
-
<Text style={[styles.headerTitle, header.title]}>{name}</Text>
|
|
61
|
+
<Text style={[styles.headerTitle, header.title]}>{translate(name, nameI18n)}</Text>
|
|
60
62
|
<Text style={[styles.headerSubtitle, header.subtitle]}>{subtitle}</Text>
|
|
61
63
|
</View>
|
|
62
64
|
);
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
import { act, render, screen } from '@testing-library/react-native';
|
|
4
|
+
import dayjs from 'dayjs';
|
|
5
|
+
import { Poll, PollResponseData, PollVoteResponseData, StreamChat } from 'stream-chat';
|
|
6
|
+
|
|
7
|
+
import {
|
|
8
|
+
ChatProvider,
|
|
9
|
+
OwnCapabilitiesProvider,
|
|
10
|
+
PollContextProvider,
|
|
11
|
+
ThemeProvider,
|
|
12
|
+
TranslationProvider,
|
|
13
|
+
} from '../../../contexts';
|
|
14
|
+
import { generateMessage } from '../../../mock-builders/generator/message';
|
|
15
|
+
import { PollAnswerListItem } from '../components/PollAnswersList';
|
|
16
|
+
import { PollAllOptionsContent, PollOption } from '../components/PollOption';
|
|
17
|
+
import { PollResultsContent } from '../components/PollResults/PollResults';
|
|
18
|
+
import { PollHeader } from '../Poll';
|
|
19
|
+
|
|
20
|
+
const POLL_ID = 'poll-id';
|
|
21
|
+
|
|
22
|
+
const pollResponse = {
|
|
23
|
+
created_by: { id: 'other-user' },
|
|
24
|
+
enforce_unique_vote: true,
|
|
25
|
+
id: POLL_ID,
|
|
26
|
+
latest_answers: [],
|
|
27
|
+
latest_votes_by_option: {},
|
|
28
|
+
name: 'Favourite colour?',
|
|
29
|
+
name_i18n: { es_text: '¿Color favorito?', language: 'en' },
|
|
30
|
+
options: [
|
|
31
|
+
{ id: 'option-red', text: 'Red', text_i18n: { es_text: 'Rojo', language: 'en' } },
|
|
32
|
+
{ id: 'option-blue', text: 'Blue' },
|
|
33
|
+
],
|
|
34
|
+
vote_count: 0,
|
|
35
|
+
vote_counts_by_option: {},
|
|
36
|
+
} as unknown as PollResponseData;
|
|
37
|
+
|
|
38
|
+
const answer = {
|
|
39
|
+
answer_text: 'Green, actually',
|
|
40
|
+
answer_text_i18n: { es_text: 'Verde, en realidad', language: 'en' },
|
|
41
|
+
created_at: new Date('2026-10-27T10:00:00.000Z').getTime(),
|
|
42
|
+
id: 'answer-id',
|
|
43
|
+
is_answer: true,
|
|
44
|
+
poll_id: POLL_ID,
|
|
45
|
+
updated_at: new Date('2026-10-27T10:00:00.000Z').getTime(),
|
|
46
|
+
user: { id: 'other-user', name: 'Other' },
|
|
47
|
+
} as unknown as PollVoteResponseData;
|
|
48
|
+
|
|
49
|
+
const setup = (userLanguage: string) => {
|
|
50
|
+
const client = { user: { id: 'own-user' }, userID: 'own-user' } as unknown as StreamChat;
|
|
51
|
+
const poll = new Poll({ client, poll: pollResponse });
|
|
52
|
+
const [red, blue] = poll.data.options;
|
|
53
|
+
|
|
54
|
+
render(
|
|
55
|
+
<ThemeProvider>
|
|
56
|
+
<ChatProvider value={{ client } as never}>
|
|
57
|
+
<TranslationProvider
|
|
58
|
+
value={{ t: (key: string) => key, tDateTimeParser: dayjs, userLanguage } as never}
|
|
59
|
+
>
|
|
60
|
+
<OwnCapabilitiesProvider value={{ castPollVote: true } as never}>
|
|
61
|
+
<PollContextProvider value={{ message: generateMessage(), poll }}>
|
|
62
|
+
<PollHeader />
|
|
63
|
+
<PollOption option={red} />
|
|
64
|
+
<PollOption option={blue} />
|
|
65
|
+
<PollAnswerListItem answer={answer} />
|
|
66
|
+
</PollContextProvider>
|
|
67
|
+
</OwnCapabilitiesProvider>
|
|
68
|
+
</TranslationProvider>
|
|
69
|
+
</ChatProvider>
|
|
70
|
+
</ThemeProvider>,
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
return { poll };
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
const renderDialogs = (userLanguage: string) => {
|
|
77
|
+
const client = { user: { id: 'own-user' }, userID: 'own-user' } as unknown as StreamChat;
|
|
78
|
+
const poll = new Poll({ client, poll: pollResponse });
|
|
79
|
+
|
|
80
|
+
return render(
|
|
81
|
+
<ThemeProvider>
|
|
82
|
+
<ChatProvider value={{ client } as never}>
|
|
83
|
+
<TranslationProvider value={{ t: (key: string) => key, userLanguage } as never}>
|
|
84
|
+
<OwnCapabilitiesProvider value={{} as never}>
|
|
85
|
+
<PollContextProvider value={{ message: generateMessage(), poll }}>
|
|
86
|
+
<PollResultsContent />
|
|
87
|
+
<PollAllOptionsContent />
|
|
88
|
+
</PollContextProvider>
|
|
89
|
+
</OwnCapabilitiesProvider>
|
|
90
|
+
</TranslationProvider>
|
|
91
|
+
</ChatProvider>
|
|
92
|
+
</ThemeProvider>,
|
|
93
|
+
);
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
describe('Poll translations', () => {
|
|
97
|
+
it("renders the question, options and answers in the user's language", () => {
|
|
98
|
+
setup('es');
|
|
99
|
+
|
|
100
|
+
expect(screen.getByText('¿Color favorito?')).toBeTruthy();
|
|
101
|
+
expect(screen.getByText('Rojo')).toBeTruthy();
|
|
102
|
+
expect(screen.getByLabelText('Rojo')).toBeTruthy();
|
|
103
|
+
expect(screen.getByText('Verde, en realidad')).toBeTruthy();
|
|
104
|
+
expect(screen.queryByText('Favourite colour?')).toBeNull();
|
|
105
|
+
expect(screen.queryByText('Red')).toBeNull();
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
it('falls back to the original text when a text has no translation', () => {
|
|
109
|
+
setup('es');
|
|
110
|
+
|
|
111
|
+
expect(screen.getByText('Blue')).toBeTruthy();
|
|
112
|
+
expect(screen.getByLabelText('Blue')).toBeTruthy();
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
it("renders the original texts when nothing is translated into the user's language", () => {
|
|
116
|
+
setup('de');
|
|
117
|
+
|
|
118
|
+
expect(screen.getByText('Favourite colour?')).toBeTruthy();
|
|
119
|
+
expect(screen.getByText('Red')).toBeTruthy();
|
|
120
|
+
expect(screen.getByText('Blue')).toBeTruthy();
|
|
121
|
+
expect(screen.getByText('Green, actually')).toBeTruthy();
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
it('shows a translation that arrives later through poll.updated', () => {
|
|
125
|
+
const { poll } = setup('de');
|
|
126
|
+
expect(screen.getByText('Favourite colour?')).toBeTruthy();
|
|
127
|
+
|
|
128
|
+
act(() => {
|
|
129
|
+
poll.handlePollUpdated({
|
|
130
|
+
created_at: '2026-10-27T11:00:00.000Z',
|
|
131
|
+
poll: {
|
|
132
|
+
...pollResponse,
|
|
133
|
+
name_i18n: { de_text: 'Lieblingsfarbe?', language: 'en' },
|
|
134
|
+
},
|
|
135
|
+
type: 'poll.updated',
|
|
136
|
+
} as never);
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
expect(screen.getByText('Lieblingsfarbe?')).toBeTruthy();
|
|
140
|
+
expect(screen.queryByText('Favourite colour?')).toBeNull();
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
it('translates the question and options in the results and all-options dialogs', () => {
|
|
144
|
+
renderDialogs('es');
|
|
145
|
+
|
|
146
|
+
// Each dialog shows the question once and every option once.
|
|
147
|
+
expect(screen.getAllByText('¿Color favorito?')).toHaveLength(2);
|
|
148
|
+
expect(screen.getAllByText('Rojo')).toHaveLength(2);
|
|
149
|
+
expect(screen.getAllByText('Blue')).toHaveLength(2);
|
|
150
|
+
expect(screen.queryByText('Favourite colour?')).toBeNull();
|
|
151
|
+
});
|
|
152
|
+
});
|
|
@@ -21,6 +21,7 @@ import { Button } from '../../ui';
|
|
|
21
21
|
import { UserAvatar } from '../../ui/Avatar/UserAvatar';
|
|
22
22
|
import { usePollAnswersPagination } from '../hooks/usePollAnswersPagination';
|
|
23
23
|
import { usePollState } from '../hooks/usePollState';
|
|
24
|
+
import { usePollTextTranslation } from '../hooks/usePollTextTranslation';
|
|
24
25
|
|
|
25
26
|
export const AnswerListAddCommentButton = (props: PollButtonProps) => {
|
|
26
27
|
const { t } = useTranslationContext();
|
|
@@ -75,6 +76,7 @@ export const PollAnswerListItem = ({ answer }: { answer: PollVoteResponseData })
|
|
|
75
76
|
const { client } = useChatContext();
|
|
76
77
|
const { t, tDateTimeParser } = useTranslationContext();
|
|
77
78
|
const { votingVisibility } = usePollState();
|
|
79
|
+
const translate = usePollTextTranslation();
|
|
78
80
|
|
|
79
81
|
const {
|
|
80
82
|
theme: {
|
|
@@ -108,7 +110,9 @@ export const PollAnswerListItem = ({ answer }: { answer: PollVoteResponseData })
|
|
|
108
110
|
return (
|
|
109
111
|
<View style={[styles.listItemWrapper, itemStyle.wrapper]}>
|
|
110
112
|
<View style={[styles.listItemContainer, itemStyle.container]}>
|
|
111
|
-
<Text style={[styles.listItemAnswerText, itemStyle.answerText]}>
|
|
113
|
+
<Text style={[styles.listItemAnswerText, itemStyle.answerText]}>
|
|
114
|
+
{translate(answer.answer_text ?? '', answer.answer_text_i18n)}
|
|
115
|
+
</Text>
|
|
112
116
|
<View style={[styles.listItemInfoContainer, itemStyle.infoContainer]}>
|
|
113
117
|
<View style={[styles.listItemUserInfoContainer, itemStyle.userInfoContainer]}>
|
|
114
118
|
{!isAnonymous && answer.user?.image ? (
|
|
@@ -27,6 +27,7 @@ import { ProgressBar } from '../../ProgressControl/ProgressBar';
|
|
|
27
27
|
import { UserAvatarStack } from '../../ui/Avatar/AvatarStack';
|
|
28
28
|
import { useIsPollCreatedByCurrentUser } from '../hook/useIsPollCreatedByCurrentUser';
|
|
29
29
|
import { usePollState } from '../hooks/usePollState';
|
|
30
|
+
import { usePollTextTranslation } from '../hooks/usePollTextTranslation';
|
|
30
31
|
import { usePollVoteToggle } from '../hooks/usePollVoteToggle';
|
|
31
32
|
|
|
32
33
|
const pollVoteAccessibilityStates = {
|
|
@@ -48,7 +49,8 @@ export const PollAllOptionsContent = ({
|
|
|
48
49
|
additionalScrollViewProps,
|
|
49
50
|
}: Pick<PollAllOptionsContentProps, 'additionalScrollViewProps'>) => {
|
|
50
51
|
const { t } = useTranslationContext();
|
|
51
|
-
const { name, options } = usePollState();
|
|
52
|
+
const { name, nameI18n, options } = usePollState();
|
|
53
|
+
const translate = usePollTextTranslation();
|
|
52
54
|
|
|
53
55
|
const {
|
|
54
56
|
theme: {
|
|
@@ -67,7 +69,7 @@ export const PollAllOptionsContent = ({
|
|
|
67
69
|
>
|
|
68
70
|
<View style={[styles.allOptionsTitleContainer, titleContainer]}>
|
|
69
71
|
<Text style={styles.allOptionsTitleMeta}>{t('poll.question.label', 'Question')}</Text>
|
|
70
|
-
<Text style={[styles.allOptionsTitleText, titleText]}>{name}</Text>
|
|
72
|
+
<Text style={[styles.allOptionsTitleText, titleText]}>{translate(name, nameI18n)}</Text>
|
|
71
73
|
</View>
|
|
72
74
|
<View style={[styles.allOptionsListContainer, listContainer]}>
|
|
73
75
|
{options?.map((option: PollOptionClass) => (
|
|
@@ -96,6 +98,7 @@ export const PollAllOptions = ({
|
|
|
96
98
|
export const PollOption = ({ option, showProgressBar = true, forceIncoming }: PollOptionProps) => {
|
|
97
99
|
const { latestVotesByOption, voteCountsByOption, voteCount } = usePollState();
|
|
98
100
|
const { t } = useTranslationContext();
|
|
101
|
+
const translate = usePollTextTranslation();
|
|
99
102
|
const isPollCreatedByClient = useIsPollCreatedByCurrentUser();
|
|
100
103
|
// `forceIncoming` marks the full-options surface, a neutral card rather than a bubble, so it wins
|
|
101
104
|
// over poll ownership.
|
|
@@ -133,7 +136,7 @@ export const PollOption = ({ option, showProgressBar = true, forceIncoming }: Po
|
|
|
133
136
|
<View style={[styles.info, info]}>
|
|
134
137
|
<View style={[styles.header, header]}>
|
|
135
138
|
<Text ellipsizeMode='tail' numberOfLines={2} style={[styles.text, text]}>
|
|
136
|
-
{option.text}
|
|
139
|
+
{translate(option.text, option.text_i18n)}
|
|
137
140
|
</Text>
|
|
138
141
|
<View style={[styles.votesContainer, votesContainer]}>
|
|
139
142
|
{relevantVotes.length > 0 ? (
|
|
@@ -196,6 +199,7 @@ export const VoteButton = ({ forceIncoming, onPress, option }: PollVoteButtonPro
|
|
|
196
199
|
} = useTheme();
|
|
197
200
|
|
|
198
201
|
const toggleVote = usePollVoteToggle();
|
|
202
|
+
const translate = usePollTextTranslation();
|
|
199
203
|
|
|
200
204
|
const onPressHandler = useCallback(() => {
|
|
201
205
|
if (onPress) {
|
|
@@ -213,7 +217,7 @@ export const VoteButton = ({ forceIncoming, onPress, option }: PollVoteButtonPro
|
|
|
213
217
|
|
|
214
218
|
return ownCapabilities.castPollVote && !isClosed ? (
|
|
215
219
|
<Pressable
|
|
216
|
-
accessibilityLabel={option.text}
|
|
220
|
+
accessibilityLabel={translate(option.text, option.text_i18n)}
|
|
217
221
|
accessibilityRole={poll.data?.enforce_unique_vote ? 'radio' : 'checkbox'}
|
|
218
222
|
accessibilityState={accessibilityState}
|
|
219
223
|
onPress={onPressHandler}
|