stream-chat-react-native-core 9.11.3-beta.1 → 9.12.0-beta.1

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.
Files changed (114) hide show
  1. package/lib/commonjs/components/ChannelPreview/hooks/useChannelPreviewPollLabel.js +8 -5
  2. package/lib/commonjs/components/ChannelPreview/hooks/useChannelPreviewPollLabel.js.map +1 -1
  3. package/lib/commonjs/components/Poll/Poll.js +5 -2
  4. package/lib/commonjs/components/Poll/Poll.js.map +1 -1
  5. package/lib/commonjs/components/Poll/components/PollAnswersList.js +3 -1
  6. package/lib/commonjs/components/Poll/components/PollAnswersList.js.map +1 -1
  7. package/lib/commonjs/components/Poll/components/PollOption.js +8 -3
  8. package/lib/commonjs/components/Poll/components/PollOption.js.map +1 -1
  9. package/lib/commonjs/components/Poll/components/PollResults/PollOptionFullResults.js +5 -2
  10. package/lib/commonjs/components/Poll/components/PollResults/PollOptionFullResults.js.map +1 -1
  11. package/lib/commonjs/components/Poll/components/PollResults/PollResultItem.js +3 -1
  12. package/lib/commonjs/components/Poll/components/PollResults/PollResultItem.js.map +1 -1
  13. package/lib/commonjs/components/Poll/components/PollResults/PollResults.js +4 -1
  14. package/lib/commonjs/components/Poll/components/PollResults/PollResults.js.map +1 -1
  15. package/lib/commonjs/components/Poll/hooks/usePollState.js +3 -0
  16. package/lib/commonjs/components/Poll/hooks/usePollState.js.map +1 -1
  17. package/lib/commonjs/components/Poll/hooks/usePollTextTranslation.js +17 -0
  18. package/lib/commonjs/components/Poll/hooks/usePollTextTranslation.js.map +1 -0
  19. package/lib/commonjs/components/Poll/index.js +11 -0
  20. package/lib/commonjs/components/Poll/index.js.map +1 -1
  21. package/lib/commonjs/hooks/messagePreview/useMessagePreviewText.js +9 -4
  22. package/lib/commonjs/hooks/messagePreview/useMessagePreviewText.js.map +1 -1
  23. package/lib/commonjs/hooks/useTranslatedMessage.js +4 -3
  24. package/lib/commonjs/hooks/useTranslatedMessage.js.map +1 -1
  25. package/lib/commonjs/store/SqliteClient.js +1 -1
  26. package/lib/commonjs/store/mappers/mapPollToStorable.js +4 -0
  27. package/lib/commonjs/store/mappers/mapPollToStorable.js.map +1 -1
  28. package/lib/commonjs/store/mappers/mapStorableToPoll.js +5 -0
  29. package/lib/commonjs/store/mappers/mapStorableToPoll.js.map +1 -1
  30. package/lib/commonjs/store/schema.js +2 -0
  31. package/lib/commonjs/store/schema.js.map +1 -1
  32. package/lib/commonjs/utils/i18n/getTranslatedText.js +7 -0
  33. package/lib/commonjs/utils/i18n/getTranslatedText.js.map +1 -0
  34. package/lib/commonjs/version.json +1 -1
  35. package/lib/module/components/ChannelPreview/hooks/useChannelPreviewPollLabel.js +8 -5
  36. package/lib/module/components/ChannelPreview/hooks/useChannelPreviewPollLabel.js.map +1 -1
  37. package/lib/module/components/Poll/Poll.js +5 -2
  38. package/lib/module/components/Poll/Poll.js.map +1 -1
  39. package/lib/module/components/Poll/components/PollAnswersList.js +3 -1
  40. package/lib/module/components/Poll/components/PollAnswersList.js.map +1 -1
  41. package/lib/module/components/Poll/components/PollOption.js +8 -3
  42. package/lib/module/components/Poll/components/PollOption.js.map +1 -1
  43. package/lib/module/components/Poll/components/PollResults/PollOptionFullResults.js +5 -2
  44. package/lib/module/components/Poll/components/PollResults/PollOptionFullResults.js.map +1 -1
  45. package/lib/module/components/Poll/components/PollResults/PollResultItem.js +3 -1
  46. package/lib/module/components/Poll/components/PollResults/PollResultItem.js.map +1 -1
  47. package/lib/module/components/Poll/components/PollResults/PollResults.js +4 -1
  48. package/lib/module/components/Poll/components/PollResults/PollResults.js.map +1 -1
  49. package/lib/module/components/Poll/hooks/usePollState.js +3 -0
  50. package/lib/module/components/Poll/hooks/usePollState.js.map +1 -1
  51. package/lib/module/components/Poll/hooks/usePollTextTranslation.js +17 -0
  52. package/lib/module/components/Poll/hooks/usePollTextTranslation.js.map +1 -0
  53. package/lib/module/components/Poll/index.js +11 -0
  54. package/lib/module/components/Poll/index.js.map +1 -1
  55. package/lib/module/hooks/messagePreview/useMessagePreviewText.js +9 -4
  56. package/lib/module/hooks/messagePreview/useMessagePreviewText.js.map +1 -1
  57. package/lib/module/hooks/useTranslatedMessage.js +4 -3
  58. package/lib/module/hooks/useTranslatedMessage.js.map +1 -1
  59. package/lib/module/store/SqliteClient.js +1 -1
  60. package/lib/module/store/mappers/mapPollToStorable.js +4 -0
  61. package/lib/module/store/mappers/mapPollToStorable.js.map +1 -1
  62. package/lib/module/store/mappers/mapStorableToPoll.js +5 -0
  63. package/lib/module/store/mappers/mapStorableToPoll.js.map +1 -1
  64. package/lib/module/store/schema.js +2 -0
  65. package/lib/module/store/schema.js.map +1 -1
  66. package/lib/module/utils/i18n/getTranslatedText.js +7 -0
  67. package/lib/module/utils/i18n/getTranslatedText.js.map +1 -0
  68. package/lib/module/version.json +1 -1
  69. package/lib/typescript/components/ChannelPreview/hooks/useChannelPreviewPollLabel.d.ts.map +1 -1
  70. package/lib/typescript/components/Poll/Poll.d.ts.map +1 -1
  71. package/lib/typescript/components/Poll/components/PollAnswersList.d.ts.map +1 -1
  72. package/lib/typescript/components/Poll/components/PollOption.d.ts.map +1 -1
  73. package/lib/typescript/components/Poll/components/PollResults/PollOptionFullResults.d.ts.map +1 -1
  74. package/lib/typescript/components/Poll/components/PollResults/PollResultItem.d.ts.map +1 -1
  75. package/lib/typescript/components/Poll/components/PollResults/PollResults.d.ts.map +1 -1
  76. package/lib/typescript/components/Poll/hooks/usePollState.d.ts +2 -1
  77. package/lib/typescript/components/Poll/hooks/usePollState.d.ts.map +1 -1
  78. package/lib/typescript/components/Poll/hooks/usePollTextTranslation.d.ts +8 -0
  79. package/lib/typescript/components/Poll/hooks/usePollTextTranslation.d.ts.map +1 -0
  80. package/lib/typescript/components/Poll/index.d.ts +1 -0
  81. package/lib/typescript/components/Poll/index.d.ts.map +1 -1
  82. package/lib/typescript/hooks/messagePreview/useMessagePreviewText.d.ts.map +1 -1
  83. package/lib/typescript/hooks/useTranslatedMessage.d.ts.map +1 -1
  84. package/lib/typescript/store/mappers/mapPollToStorable.d.ts.map +1 -1
  85. package/lib/typescript/store/mappers/mapStorableToPoll.d.ts.map +1 -1
  86. package/lib/typescript/store/schema.d.ts +2 -0
  87. package/lib/typescript/store/schema.d.ts.map +1 -1
  88. package/lib/typescript/utils/i18n/getTranslatedText.d.ts +6 -0
  89. package/lib/typescript/utils/i18n/getTranslatedText.d.ts.map +1 -0
  90. package/package.json +1 -1
  91. package/src/components/ChannelPreview/hooks/__tests__/useChannelPreviewPollLabel.test.tsx +31 -6
  92. package/src/components/ChannelPreview/hooks/useChannelPreviewPollLabel.ts +8 -4
  93. package/src/components/Poll/Poll.tsx +4 -2
  94. package/src/components/Poll/__tests__/PollTranslation.test.tsx +152 -0
  95. package/src/components/Poll/components/PollAnswersList.tsx +5 -1
  96. package/src/components/Poll/components/PollOption.tsx +8 -4
  97. package/src/components/Poll/components/PollResults/PollOptionFullResults.tsx +5 -2
  98. package/src/components/Poll/components/PollResults/PollResultItem.tsx +3 -1
  99. package/src/components/Poll/components/PollResults/PollResults.tsx +4 -2
  100. package/src/components/Poll/hooks/usePollState.ts +5 -0
  101. package/src/components/Poll/hooks/usePollTextTranslation.ts +21 -0
  102. package/src/components/Poll/index.ts +1 -0
  103. package/src/hooks/__tests__/useTranslatedMessage.test.tsx +20 -0
  104. package/src/hooks/messagePreview/__tests__/useMessagePreviewText.test.tsx +37 -2
  105. package/src/hooks/messagePreview/useMessagePreviewText.tsx +5 -2
  106. package/src/hooks/useTranslatedMessage.ts +7 -7
  107. package/src/store/SqliteClient.ts +1 -1
  108. package/src/store/apis/__tests__/pollTranslations.test.ts +136 -0
  109. package/src/store/mappers/mapPollToStorable.ts +6 -0
  110. package/src/store/mappers/mapStorableToPoll.ts +4 -0
  111. package/src/store/schema.ts +4 -0
  112. package/src/utils/i18n/__tests__/getTranslatedText.test.ts +19 -0
  113. package/src/utils/i18n/getTranslatedText.ts +9 -0
  114. package/src/version.json +1 -1
@@ -0,0 +1,136 @@
1
+ import type { ChannelAPIResponse, PollResponse } 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: '2026-10-27T10:00:00.000Z',
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: '2026-10-27T10:00:00.000Z',
36
+ vote_count: 0,
37
+ vote_counts_by_option: {},
38
+ } as unknown as PollResponse;
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 ChannelAPIResponse[],
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], currentUserId: '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 PollResponse });
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 PollResponse,
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 ChannelAPIResponse[],
109
+ isLatestMessagesSet: true,
110
+ });
111
+
112
+ const [channel] = await getChannels({
113
+ channelIds: [untranslatedCid],
114
+ currentUserId: '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: PollResponse): 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: PollResponse): 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: PollResponse): TableRow<'poll'> => {
36
38
  created_by: JSON.stringify(created_by), // decouple the users from the actual 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: PollResponse): TableRow<'poll'> => {
43
48
  latest_votes_by_option: JSON.stringify(latest_votes_by_option),
44
49
  max_votes_allowed,
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,
@@ -11,6 +11,7 @@ export const mapStorableToPoll = (pollRow: TableRow<'poll'>): PollResponse => {
11
11
  created_by,
12
12
  created_by_id,
13
13
  description,
14
+ description_i18n,
14
15
  enforce_unique_vote,
15
16
  id,
16
17
  is_closed,
@@ -18,6 +19,7 @@ export const mapStorableToPoll = (pollRow: TableRow<'poll'>): PollResponse => {
18
19
  latest_votes_by_option,
19
20
  max_votes_allowed,
20
21
  name,
22
+ name_i18n,
21
23
  options,
22
24
  own_votes,
23
25
  updated_at,
@@ -34,6 +36,7 @@ export const mapStorableToPoll = (pollRow: TableRow<'poll'>): PollResponse => {
34
36
  created_by: JSON.parse(created_by),
35
37
  created_by_id,
36
38
  description,
39
+ description_i18n: description_i18n ? (JSON.parse(description_i18n) ?? undefined) : undefined,
37
40
  enforce_unique_vote,
38
41
  id,
39
42
  is_closed,
@@ -41,6 +44,7 @@ export const mapStorableToPoll = (pollRow: TableRow<'poll'>): PollResponse => {
41
44
  latest_votes_by_option: JSON.parse(latest_votes_by_option),
42
45
  max_votes_allowed,
43
46
  name,
47
+ name_i18n: name_i18n ? (JSON.parse(name_i18n) ?? undefined) : undefined,
44
48
  options: JSON.parse(options),
45
49
  own_votes: own_votes ? JSON.parse(own_votes) : [],
46
50
  updated_at,
@@ -224,6 +224,7 @@ export const tables: Tables = {
224
224
  created_by: 'TEXT',
225
225
  created_by_id: 'TEXT',
226
226
  description: 'TEXT',
227
+ description_i18n: 'TEXT',
227
228
  enforce_unique_vote: 'BOOLEAN DEFAULT FALSE',
228
229
  id: 'TEXT NOT NULL',
229
230
  is_closed: 'BOOLEAN DEFAULT FALSE',
@@ -231,6 +232,7 @@ export const tables: Tables = {
231
232
  latest_votes_by_option: 'TEXT',
232
233
  max_votes_allowed: 'INTEGER DEFAULT 1',
233
234
  name: 'TEXT',
235
+ name_i18n: 'TEXT',
234
236
  options: 'TEXT',
235
237
  own_votes: 'TEXT',
236
238
  updated_at: 'TEXT',
@@ -459,7 +461,9 @@ export type Schema = {
459
461
  allow_answers?: boolean;
460
462
  allow_user_suggested_options?: boolean;
461
463
  description?: string;
464
+ description_i18n?: string;
462
465
  is_closed?: boolean;
466
+ name_i18n?: string;
463
467
  own_votes?: string;
464
468
  voting_visibility?: string;
465
469
  };
@@ -0,0 +1,19 @@
1
+ import type { TranslatedField } from 'stream-chat';
2
+
3
+ import { getTranslatedText } from '../getTranslatedText';
4
+
5
+ describe('getTranslatedText', () => {
6
+ const i18n = { de_text: 'Wie geht es?', language: 'en' } as TranslatedField;
7
+
8
+ it('returns the translation into the given language', () => {
9
+ expect(getTranslatedText(i18n, 'de')).toBe('Wie geht es?');
10
+ });
11
+
12
+ it('returns undefined when there is no translation into the given language', () => {
13
+ expect(getTranslatedText(i18n, 'fr')).toBeUndefined();
14
+ });
15
+
16
+ it('returns undefined when the text has no translations', () => {
17
+ expect(getTranslatedText(undefined, 'de')).toBeUndefined();
18
+ });
19
+ });
@@ -0,0 +1,9 @@
1
+ import type { TranslatedField, TranslationLanguages } from 'stream-chat';
2
+
3
+ /**
4
+ * Returns the translation of a text into `language`, or undefined if there is none.
5
+ */
6
+ export const getTranslatedText = (
7
+ i18n: TranslatedField | undefined,
8
+ language: TranslationLanguages,
9
+ ): string | undefined => i18n?.[`${language}_text` as `${TranslationLanguages}_text`];
package/src/version.json CHANGED
@@ -1,3 +1,3 @@
1
1
  {
2
- "version": "9.11.3-beta.1"
2
+ "version": "9.12.0-beta.1"
3
3
  }