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
|
@@ -16,6 +16,7 @@ import { useComponentsContext } from '../../../../contexts/componentsContext/Com
|
|
|
16
16
|
import { primitives } from '../../../../theme';
|
|
17
17
|
import { usePollOptionVotesPagination } from '../../hooks/usePollOptionVotesPagination';
|
|
18
18
|
import { usePollState } from '../../hooks/usePollState';
|
|
19
|
+
import { usePollTextTranslation } from '../../hooks/usePollTextTranslation';
|
|
19
20
|
|
|
20
21
|
export type PollOptionFullResultsProps = PollContextValue & {
|
|
21
22
|
option: PollOptionResponseData;
|
|
@@ -33,6 +34,8 @@ export const PollOptionFullResultsContent = ({
|
|
|
33
34
|
const { t } = useTranslationContext();
|
|
34
35
|
const { hasNextPage, loadMore, votes } = usePollOptionVotesPagination({ option });
|
|
35
36
|
const { voteCountsByOption } = usePollState();
|
|
37
|
+
const translate = usePollTextTranslation();
|
|
38
|
+
const optionText = translate(option.text, option.text_i18n);
|
|
36
39
|
|
|
37
40
|
const {
|
|
38
41
|
theme: {
|
|
@@ -46,7 +49,7 @@ export const PollOptionFullResultsContent = ({
|
|
|
46
49
|
const PollOptionFullResultsHeader = useCallback(
|
|
47
50
|
() => (
|
|
48
51
|
<View style={[styles.headerContainer, headerContainer]}>
|
|
49
|
-
<Text style={[styles.headerTitle, headerTitle]}>{
|
|
52
|
+
<Text style={[styles.headerTitle, headerTitle]}>{optionText}</Text>
|
|
50
53
|
<Text style={[styles.headerText, headerText]}>
|
|
51
54
|
{t('poll.votes.text', {
|
|
52
55
|
count: voteCountsByOption[option.id] ?? 0,
|
|
@@ -61,7 +64,7 @@ export const PollOptionFullResultsContent = ({
|
|
|
61
64
|
headerText,
|
|
62
65
|
headerTitle,
|
|
63
66
|
option.id,
|
|
64
|
-
|
|
67
|
+
optionText,
|
|
65
68
|
styles.headerContainer,
|
|
66
69
|
styles.headerText,
|
|
67
70
|
styles.headerTitle,
|
|
@@ -20,6 +20,7 @@ import {
|
|
|
20
20
|
|
|
21
21
|
import { primitives } from '../../../../theme';
|
|
22
22
|
import { usePollState } from '../../hooks/usePollState';
|
|
23
|
+
import { usePollTextTranslation } from '../../hooks/usePollTextTranslation';
|
|
23
24
|
import { GenericPollButton } from '../Button';
|
|
24
25
|
import { PollModal } from '../PollModal';
|
|
25
26
|
import { PollModalHeader } from '../PollModalHeader';
|
|
@@ -97,6 +98,7 @@ const PollResultsVoteItem = (vote: PollVoteClass) => (
|
|
|
97
98
|
export const PollResultsItem = ({ option, index }: PollResultItemProps) => {
|
|
98
99
|
const { t } = useTranslationContext();
|
|
99
100
|
const { latestVotesByOption, voteCountsByOption } = usePollState();
|
|
101
|
+
const translate = usePollTextTranslation();
|
|
100
102
|
|
|
101
103
|
const {
|
|
102
104
|
theme: {
|
|
@@ -116,7 +118,7 @@ export const PollResultsItem = ({ option, index }: PollResultItemProps) => {
|
|
|
116
118
|
{t('poll.results.optionNumber.text', 'Option {{count}}', { count: index + 1 })}
|
|
117
119
|
</Text>
|
|
118
120
|
<View style={[styles.headerContainer, headerContainer]}>
|
|
119
|
-
<Text style={[styles.title, title]}>{option.text}</Text>
|
|
121
|
+
<Text style={[styles.title, title]}>{translate(option.text, option.text_i18n)}</Text>
|
|
120
122
|
<Text style={[styles.voteCount, voteCount]}>
|
|
121
123
|
{t('poll.votes.text', {
|
|
122
124
|
count: voteCountsByOption[option.id] ?? 0,
|
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
import { useComponentsContext } from '../../../../contexts/componentsContext/ComponentsContext';
|
|
15
15
|
import { primitives } from '../../../../theme';
|
|
16
16
|
import { usePollState } from '../../hooks/usePollState';
|
|
17
|
+
import { usePollTextTranslation } from '../../hooks/usePollTextTranslation';
|
|
17
18
|
|
|
18
19
|
export type PollResultsProps = PollContextValue & {
|
|
19
20
|
additionalScrollViewProps?: Partial<ScrollViewProps>;
|
|
@@ -22,7 +23,8 @@ export type PollResultsProps = PollContextValue & {
|
|
|
22
23
|
export const PollResultsContent = ({
|
|
23
24
|
additionalScrollViewProps,
|
|
24
25
|
}: Pick<PollResultsProps, 'additionalScrollViewProps'>) => {
|
|
25
|
-
const { name, options, voteCountsByOption } = usePollState();
|
|
26
|
+
const { name, nameI18n, options, voteCountsByOption } = usePollState();
|
|
27
|
+
const translate = usePollTextTranslation();
|
|
26
28
|
|
|
27
29
|
const sortedOptions = useMemo(
|
|
28
30
|
() =>
|
|
@@ -51,7 +53,7 @@ export const PollResultsContent = ({
|
|
|
51
53
|
>
|
|
52
54
|
<View style={[styles.container, container]}>
|
|
53
55
|
<Text style={[styles.titleMeta, titleMeta]}>{t('poll.question.label', 'Question')}</Text>
|
|
54
|
-
<Text style={[styles.title, title]}>{name}</Text>
|
|
56
|
+
<Text style={[styles.title, title]}>{translate(name, nameI18n)}</Text>
|
|
55
57
|
</View>
|
|
56
58
|
<View style={styles.resultsContainer}>
|
|
57
59
|
{sortedOptions.map((option, index) => (
|
|
@@ -26,6 +26,7 @@ export type UsePollStateSelectorReturnType = {
|
|
|
26
26
|
maxVotedOptionIds: string[];
|
|
27
27
|
maxVotesAllowed: number;
|
|
28
28
|
name: string;
|
|
29
|
+
nameI18n: Record<string, string> | undefined;
|
|
29
30
|
options: PollOptionResponseData[];
|
|
30
31
|
ownAnswer: PollVoteResponseData | undefined;
|
|
31
32
|
ownVotesByOptionId: Record<string, PollVoteResponseData>;
|
|
@@ -51,6 +52,7 @@ const selector = (nextValue: PollState): UsePollStateSelectorReturnType => ({
|
|
|
51
52
|
maxVotedOptionIds: nextValue.maxVotedOptionIds,
|
|
52
53
|
maxVotesAllowed: nextValue.max_votes_allowed ?? 0,
|
|
53
54
|
name: nextValue.name,
|
|
55
|
+
nameI18n: nextValue.name_i18n,
|
|
54
56
|
options: nextValue.options,
|
|
55
57
|
ownAnswer: nextValue.ownAnswer,
|
|
56
58
|
ownVotesByOptionId: nextValue.ownVotesByOptionId,
|
|
@@ -72,6 +74,7 @@ export const usePollState = (): UsePollStateReturnType => {
|
|
|
72
74
|
maxVotedOptionIds,
|
|
73
75
|
maxVotesAllowed,
|
|
74
76
|
name,
|
|
77
|
+
nameI18n,
|
|
75
78
|
options,
|
|
76
79
|
ownAnswer,
|
|
77
80
|
ownVotesByOptionId,
|
|
@@ -106,6 +109,7 @@ export const usePollState = (): UsePollStateReturnType => {
|
|
|
106
109
|
maxVotedOptionIds,
|
|
107
110
|
maxVotesAllowed,
|
|
108
111
|
name,
|
|
112
|
+
nameI18n,
|
|
109
113
|
options,
|
|
110
114
|
ownAnswer,
|
|
111
115
|
ownVotesByOptionId,
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { useCallback } from 'react';
|
|
2
|
+
|
|
3
|
+
import { useTranslationContext } from '../../../contexts/translationContext/TranslationContext';
|
|
4
|
+
import { getTranslatedText } from '../../../utils/i18n/getTranslatedText';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Returns `translate(original, i18n)`, which resolves a poll text (question, option or answer)
|
|
8
|
+
* into the current user's language. Falls back to `original` when there is no translation for it,
|
|
9
|
+
* the same way auto-translated message text does.
|
|
10
|
+
*/
|
|
11
|
+
export const usePollTextTranslation = () => {
|
|
12
|
+
const { userLanguage } = useTranslationContext();
|
|
13
|
+
|
|
14
|
+
return useCallback(
|
|
15
|
+
(original: string, i18n: Record<string, string> | undefined): string =>
|
|
16
|
+
getTranslatedText(i18n, userLanguage) ?? original,
|
|
17
|
+
[userLanguage],
|
|
18
|
+
);
|
|
19
|
+
};
|
|
@@ -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 });
|
|
@@ -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}>
|
|
@@ -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. */
|
|
@@ -59,6 +59,26 @@ describe('useTranslatedMessage', () => {
|
|
|
59
59
|
});
|
|
60
60
|
});
|
|
61
61
|
|
|
62
|
+
it("doesn't translate a deleted message", async () => {
|
|
63
|
+
const message = {
|
|
64
|
+
i18n: {
|
|
65
|
+
no_text: 'Hallo verden!',
|
|
66
|
+
},
|
|
67
|
+
text: 'Hello world!',
|
|
68
|
+
type: 'deleted',
|
|
69
|
+
} as unknown as MessageResponse;
|
|
70
|
+
|
|
71
|
+
render(
|
|
72
|
+
<TranslationProvider value={{ userLanguage: 'no' } as TranslationContextValue}>
|
|
73
|
+
<TestComponent message={message} />
|
|
74
|
+
</TranslationProvider>,
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
await waitFor(() => {
|
|
78
|
+
expect(screen.getByText('Hello world!')).toBeTruthy();
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
|
|
62
82
|
it("returns the original text if the message doesn't contain any translations", async () => {
|
|
63
83
|
const message = {
|
|
64
84
|
text: 'Hello world!',
|
|
@@ -2,7 +2,7 @@ import React, { PropsWithChildren } from 'react';
|
|
|
2
2
|
|
|
3
3
|
import { renderHook } from '@testing-library/react-native';
|
|
4
4
|
|
|
5
|
-
import type { Attachment } from 'stream-chat';
|
|
5
|
+
import type { Attachment, PollResponseData, StreamChat } from 'stream-chat';
|
|
6
6
|
|
|
7
7
|
import { Chat } from '../../../components/Chat/Chat';
|
|
8
8
|
import { initiateClientWithChannels } from '../../../mock-builders/api/initiateClientWithChannels';
|
|
@@ -15,8 +15,12 @@ import { generateMessage } from '../../../mock-builders/generator/message';
|
|
|
15
15
|
import { useMessagePreviewText } from '../useMessagePreviewText';
|
|
16
16
|
|
|
17
17
|
describe('useMessagePreviewText', () => {
|
|
18
|
-
const render = async (
|
|
18
|
+
const render = async (
|
|
19
|
+
message: ReturnType<typeof generateMessage>,
|
|
20
|
+
prepareClient?: (client: StreamChat) => void,
|
|
21
|
+
) => {
|
|
19
22
|
const { client } = await initiateClientWithChannels();
|
|
23
|
+
prepareClient?.(client);
|
|
20
24
|
const wrapper = ({ children }: PropsWithChildren) => <Chat client={client}>{children}</Chat>;
|
|
21
25
|
const { result } = renderHook(() => useMessagePreviewText({ message }), { wrapper });
|
|
22
26
|
return result;
|
|
@@ -54,4 +58,35 @@ describe('useMessagePreviewText', () => {
|
|
|
54
58
|
);
|
|
55
59
|
expect(result.current).toBe('hello');
|
|
56
60
|
});
|
|
61
|
+
|
|
62
|
+
describe('poll messages', () => {
|
|
63
|
+
const poll = {
|
|
64
|
+
id: 'poll-id',
|
|
65
|
+
latest_answers: [],
|
|
66
|
+
latest_votes_by_option: {},
|
|
67
|
+
name: 'Favourite colour?',
|
|
68
|
+
name_i18n: { es_text: '¿Color favorito?', language: 'en' },
|
|
69
|
+
options: [],
|
|
70
|
+
vote_count: 0,
|
|
71
|
+
vote_counts_by_option: {},
|
|
72
|
+
} as unknown as PollResponseData;
|
|
73
|
+
|
|
74
|
+
const renderPollMessage = (language: string) => {
|
|
75
|
+
const message = generateMessage({ poll, poll_id: poll.id, text: '' });
|
|
76
|
+
return render(message, (client) => {
|
|
77
|
+
(client.user as { language?: string }).language = language;
|
|
78
|
+
client.polls.hydratePollCache([message]);
|
|
79
|
+
});
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
it("shows the poll question in the user's language", async () => {
|
|
83
|
+
const result = await renderPollMessage('es');
|
|
84
|
+
expect(result.current).toBe('¿Color favorito?');
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it('shows the original poll question when it has no translation', async () => {
|
|
88
|
+
const result = await renderPollMessage('de');
|
|
89
|
+
expect(result.current).toBe('Favourite colour?');
|
|
90
|
+
});
|
|
91
|
+
});
|
|
57
92
|
});
|
|
@@ -14,9 +14,11 @@ import { useGroupedAttachments } from './useGroupedAttachments';
|
|
|
14
14
|
import { useChatContext } from '../../contexts/chatContext/ChatContext';
|
|
15
15
|
import { useTranslationContext } from '../../contexts/translationContext/TranslationContext';
|
|
16
16
|
import { useStateStore } from '../../hooks/useStateStore';
|
|
17
|
+
import { getTranslatedText } from '../../utils/i18n/getTranslatedText';
|
|
17
18
|
|
|
18
19
|
const selector = (nextValue: PollState) => ({
|
|
19
20
|
name: nextValue.name,
|
|
21
|
+
name_i18n: nextValue.name_i18n,
|
|
20
22
|
});
|
|
21
23
|
|
|
22
24
|
export const useMessagePreviewText = ({
|
|
@@ -24,10 +26,11 @@ export const useMessagePreviewText = ({
|
|
|
24
26
|
}: {
|
|
25
27
|
message?: LocalMessage | MessageResponse | DraftMessage | null;
|
|
26
28
|
}) => {
|
|
27
|
-
const { t } = useTranslationContext();
|
|
29
|
+
const { t, userLanguage } = useTranslationContext();
|
|
28
30
|
const { client } = useChatContext();
|
|
29
31
|
const poll = client.polls.fromState(message?.poll_id ?? '');
|
|
30
|
-
const { name
|
|
32
|
+
const { name, name_i18n } = useStateStore(poll?.state, selector) ?? {};
|
|
33
|
+
const pollName = getTranslatedText(name_i18n, userLanguage) ?? name;
|
|
31
34
|
const { giphys, audios, images, videos, files, voiceRecordings } = useGroupedAttachments(
|
|
32
35
|
message?.attachments,
|
|
33
36
|
);
|
|
@@ -1,13 +1,7 @@
|
|
|
1
1
|
import type { LocalMessage, MessageResponse } from 'stream-chat';
|
|
2
2
|
|
|
3
3
|
import { useTranslationContext } from '../contexts/translationContext/TranslationContext';
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* The key under which auto-translated text lives in `message.i18n`. The UI language can be any
|
|
7
|
-
* registered string, while `message.i18n` only carries the languages the auto-translation endpoint
|
|
8
|
-
* supports: the `in` check below makes an unsupported language fall through to the original text.
|
|
9
|
-
*/
|
|
10
|
-
type TranslationKey = `${string}_text`;
|
|
4
|
+
import { getTranslatedText } from '../utils/i18n/getTranslatedText';
|
|
11
5
|
|
|
12
6
|
/**
|
|
13
7
|
* Returns a copy of `message` with its text swapped for the auto-translation into `userLanguage`,
|
|
@@ -21,16 +15,17 @@ export const getTranslatedMessage = (
|
|
|
21
15
|
message: LocalMessage | MessageResponse | undefined,
|
|
22
16
|
userLanguage: string,
|
|
23
17
|
) => {
|
|
24
|
-
const translationKey: TranslationKey = `${userLanguage}_text`;
|
|
25
|
-
|
|
26
18
|
if (!message) {
|
|
27
19
|
return undefined;
|
|
28
20
|
}
|
|
29
21
|
|
|
30
|
-
|
|
22
|
+
const translatedText =
|
|
23
|
+
message.type !== 'deleted' ? getTranslatedText(message.i18n, userLanguage) : undefined;
|
|
24
|
+
|
|
25
|
+
if (translatedText !== undefined) {
|
|
31
26
|
return {
|
|
32
27
|
...message,
|
|
33
|
-
text:
|
|
28
|
+
text: translatedText,
|
|
34
29
|
};
|
|
35
30
|
}
|
|
36
31
|
|
|
@@ -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';
|
|
@@ -44,7 +44,7 @@ export class SqliteClientError extends Error {
|
|
|
44
44
|
|
|
45
45
|
/** Wraps all direct use of `@op-engineering/op-sqlite`. */
|
|
46
46
|
export class SqliteClient {
|
|
47
|
-
static dbVersion =
|
|
47
|
+
static dbVersion = 19;
|
|
48
48
|
|
|
49
49
|
static dbName = DB_NAME;
|
|
50
50
|
static dbLocation = DB_LOCATION;
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import type { ChannelStateResponseFields, PollResponseData } from 'stream-chat';
|
|
2
|
+
|
|
3
|
+
import { generateChannelResponse } from '../../../mock-builders/generator/channel';
|
|
4
|
+
import { generateMessage } from '../../../mock-builders/generator/message';
|
|
5
|
+
import { BetterSqlite } from '../../../test-utils/BetterSqlite';
|
|
6
|
+
import { SqliteClient } from '../../SqliteClient';
|
|
7
|
+
import { getChannels } from '../getChannels';
|
|
8
|
+
import { upsertChannels } from '../upsertChannels';
|
|
9
|
+
import { upsertPoll } from '../upsertPoll';
|
|
10
|
+
|
|
11
|
+
const POLL_ID = 'poll-id';
|
|
12
|
+
|
|
13
|
+
const translatedPoll = {
|
|
14
|
+
answers_count: 0,
|
|
15
|
+
created_at: new Date('2026-10-27T10:00:00.000Z').getTime(),
|
|
16
|
+
created_by: { id: 'other-user' },
|
|
17
|
+
created_by_id: 'other-user',
|
|
18
|
+
description: 'For the team dinner',
|
|
19
|
+
description_i18n: { es_text: 'Para la cena del equipo', language: 'en' },
|
|
20
|
+
enforce_unique_vote: true,
|
|
21
|
+
id: POLL_ID,
|
|
22
|
+
latest_answers: [],
|
|
23
|
+
latest_votes_by_option: {},
|
|
24
|
+
max_votes_allowed: 1,
|
|
25
|
+
name: 'Favourite colour?',
|
|
26
|
+
name_i18n: { es_text: '¿Color favorito?', language: 'en' },
|
|
27
|
+
options: [
|
|
28
|
+
{
|
|
29
|
+
id: 'option-red',
|
|
30
|
+
poll_id: POLL_ID,
|
|
31
|
+
text: 'Red',
|
|
32
|
+
text_i18n: { es_text: 'Rojo', language: 'en' },
|
|
33
|
+
},
|
|
34
|
+
],
|
|
35
|
+
updated_at: new Date('2026-10-27T10:00:00.000Z').getTime(),
|
|
36
|
+
vote_count: 0,
|
|
37
|
+
vote_counts_by_option: {},
|
|
38
|
+
} as unknown as PollResponseData;
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* The backend translates poll texts. The offline DB has to keep those translations, so a cold start
|
|
42
|
+
* offline shows the poll in the user's language, the same way message translations are kept.
|
|
43
|
+
*/
|
|
44
|
+
describe('poll translations in the offline DB', () => {
|
|
45
|
+
let cid: string;
|
|
46
|
+
|
|
47
|
+
beforeEach(async () => {
|
|
48
|
+
await SqliteClient.initializeDatabase();
|
|
49
|
+
await BetterSqlite.openDB();
|
|
50
|
+
|
|
51
|
+
const channelResponse = generateChannelResponse({ members: [], messages: [] });
|
|
52
|
+
cid = channelResponse.channel.cid as string;
|
|
53
|
+
channelResponse.messages = [
|
|
54
|
+
generateMessage({ cid, poll: translatedPoll, poll_id: POLL_ID, text: '' }),
|
|
55
|
+
] as unknown as typeof channelResponse.messages;
|
|
56
|
+
await upsertChannels({
|
|
57
|
+
channels: [channelResponse] as unknown as ChannelStateResponseFields[],
|
|
58
|
+
isLatestMessagesSet: true,
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
afterEach(() => {
|
|
63
|
+
BetterSqlite.dropAllTables();
|
|
64
|
+
BetterSqlite.closeDB();
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
const getStoredPoll = async () => {
|
|
68
|
+
const [channel] = await getChannels({ channelIds: [cid], userId: 'some-user' });
|
|
69
|
+
return channel.messages[0].poll;
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
it("keeps the question's, description's and options' translations", async () => {
|
|
73
|
+
const poll = await getStoredPoll();
|
|
74
|
+
|
|
75
|
+
expect(poll?.name_i18n).toEqual(translatedPoll.name_i18n);
|
|
76
|
+
expect(poll?.description_i18n).toEqual(translatedPoll.description_i18n);
|
|
77
|
+
expect(poll?.options[0].text_i18n).toEqual(translatedPoll.options[0].text_i18n);
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it('replaces the translations when the poll is stored again', async () => {
|
|
81
|
+
const name_i18n = { de_text: 'Lieblingsfarbe?', language: 'en' };
|
|
82
|
+
await upsertPoll({ poll: { ...translatedPoll, name_i18n } as PollResponseData });
|
|
83
|
+
|
|
84
|
+
expect((await getStoredPoll())?.name_i18n).toEqual(name_i18n);
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it('stores a poll without translations unchanged', async () => {
|
|
88
|
+
const {
|
|
89
|
+
description_i18n: _description_i18n,
|
|
90
|
+
name_i18n: _name_i18n,
|
|
91
|
+
...untranslatedPoll
|
|
92
|
+
} = translatedPoll;
|
|
93
|
+
const untranslatedChannel = generateChannelResponse({ members: [], messages: [] });
|
|
94
|
+
const untranslatedCid = untranslatedChannel.channel.cid as string;
|
|
95
|
+
untranslatedChannel.messages = [
|
|
96
|
+
generateMessage({
|
|
97
|
+
cid: untranslatedCid,
|
|
98
|
+
poll: {
|
|
99
|
+
...untranslatedPoll,
|
|
100
|
+
id: 'untranslated-poll-id',
|
|
101
|
+
options: [{ id: 'option-red', poll_id: 'untranslated-poll-id', text: 'Red' }],
|
|
102
|
+
} as unknown as PollResponseData,
|
|
103
|
+
poll_id: 'untranslated-poll-id',
|
|
104
|
+
text: '',
|
|
105
|
+
}),
|
|
106
|
+
] as unknown as typeof untranslatedChannel.messages;
|
|
107
|
+
await upsertChannels({
|
|
108
|
+
channels: [untranslatedChannel] as unknown as ChannelStateResponseFields[],
|
|
109
|
+
isLatestMessagesSet: true,
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
const [channel] = await getChannels({
|
|
113
|
+
channelIds: [untranslatedCid],
|
|
114
|
+
userId: 'some-user',
|
|
115
|
+
});
|
|
116
|
+
const poll = channel.messages[0].poll;
|
|
117
|
+
|
|
118
|
+
expect(poll?.name).toBe('Favourite colour?');
|
|
119
|
+
expect(poll?.description).toBe('For the team dinner');
|
|
120
|
+
expect(poll?.options).toEqual([
|
|
121
|
+
{ id: 'option-red', poll_id: 'untranslated-poll-id', text: 'Red' },
|
|
122
|
+
]);
|
|
123
|
+
expect(poll?.name_i18n).toBeUndefined();
|
|
124
|
+
expect(poll?.description_i18n).toBeUndefined();
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
it('clears translations that the poll no longer has', async () => {
|
|
128
|
+
await upsertPoll({
|
|
129
|
+
poll: { ...translatedPoll, description_i18n: undefined, name_i18n: undefined },
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
const poll = await getStoredPoll();
|
|
133
|
+
expect(poll?.name_i18n).toBeUndefined();
|
|
134
|
+
expect(poll?.description_i18n).toBeUndefined();
|
|
135
|
+
});
|
|
136
|
+
});
|
|
@@ -13,6 +13,7 @@ export const mapPollToStorable = (poll: PollResponseData): TableRow<'poll'> => {
|
|
|
13
13
|
created_by,
|
|
14
14
|
created_by_id,
|
|
15
15
|
description,
|
|
16
|
+
description_i18n,
|
|
16
17
|
enforce_unique_vote,
|
|
17
18
|
id,
|
|
18
19
|
is_closed,
|
|
@@ -20,6 +21,7 @@ export const mapPollToStorable = (poll: PollResponseData): TableRow<'poll'> => {
|
|
|
20
21
|
latest_votes_by_option,
|
|
21
22
|
max_votes_allowed,
|
|
22
23
|
name,
|
|
24
|
+
name_i18n,
|
|
23
25
|
options,
|
|
24
26
|
own_votes,
|
|
25
27
|
updated_at,
|
|
@@ -36,6 +38,9 @@ export const mapPollToStorable = (poll: PollResponseData): TableRow<'poll'> => {
|
|
|
36
38
|
created_by: JSON.stringify(created_by), // stored as JSON to decouple the user from the poll
|
|
37
39
|
created_by_id,
|
|
38
40
|
description,
|
|
41
|
+
// Always written (as `null` when absent): an upsert skips undefined columns, which would keep
|
|
42
|
+
// translations the server has since dropped, e.g. after the question was edited.
|
|
43
|
+
description_i18n: JSON.stringify(description_i18n ?? null),
|
|
39
44
|
enforce_unique_vote,
|
|
40
45
|
id,
|
|
41
46
|
is_closed,
|
|
@@ -43,6 +48,7 @@ export const mapPollToStorable = (poll: PollResponseData): TableRow<'poll'> => {
|
|
|
43
48
|
latest_votes_by_option: JSON.stringify(latest_votes_by_option),
|
|
44
49
|
max_votes_allowed: max_votes_allowed ?? 1,
|
|
45
50
|
name,
|
|
51
|
+
name_i18n: JSON.stringify(name_i18n ?? null),
|
|
46
52
|
options: JSON.stringify(options),
|
|
47
53
|
own_votes: JSON.stringify(own_votes),
|
|
48
54
|
updated_at: mapTimestampToStorable(updated_at),
|