stream-chat-react-native-core 5.31.2-beta.3 → 5.32.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 (220) hide show
  1. package/lib/commonjs/components/Channel/Channel.js +21 -20
  2. package/lib/commonjs/components/Channel/Channel.js.map +1 -1
  3. package/lib/commonjs/components/Chat/hooks/handleEventToSyncDB.js.map +1 -1
  4. package/lib/commonjs/components/Message/Message.js +9 -19
  5. package/lib/commonjs/components/Message/Message.js.map +1 -1
  6. package/lib/commonjs/components/Message/MessageSimple/MessageFooter.js +1 -2
  7. package/lib/commonjs/components/Message/MessageSimple/MessageFooter.js.map +1 -1
  8. package/lib/commonjs/components/Message/MessageSimple/ReactionList.js +54 -37
  9. package/lib/commonjs/components/Message/MessageSimple/ReactionList.js.map +1 -1
  10. package/lib/commonjs/components/Message/hooks/useCreateMessageContext.js +6 -11
  11. package/lib/commonjs/components/Message/hooks/useCreateMessageContext.js.map +1 -1
  12. package/lib/commonjs/components/Message/hooks/useProcessReactions.js +90 -0
  13. package/lib/commonjs/components/Message/hooks/useProcessReactions.js.map +1 -0
  14. package/lib/commonjs/components/MessageOverlay/MessageOverlay.js +3 -12
  15. package/lib/commonjs/components/MessageOverlay/MessageOverlay.js.map +1 -1
  16. package/lib/commonjs/components/MessageOverlay/OverlayReactions.js +47 -143
  17. package/lib/commonjs/components/MessageOverlay/OverlayReactions.js.map +1 -1
  18. package/lib/commonjs/components/MessageOverlay/OverlayReactionsItem.js +166 -0
  19. package/lib/commonjs/components/MessageOverlay/OverlayReactionsItem.js.map +1 -0
  20. package/lib/commonjs/components/MessageOverlay/hooks/useFetchReactions.js +144 -0
  21. package/lib/commonjs/components/MessageOverlay/hooks/useFetchReactions.js.map +1 -0
  22. package/lib/commonjs/contexts/messageContext/MessageContext.js.map +1 -1
  23. package/lib/commonjs/contexts/themeContext/utils/theme.js +0 -1
  24. package/lib/commonjs/contexts/themeContext/utils/theme.js.map +1 -1
  25. package/lib/commonjs/i18n/es.json +13 -13
  26. package/lib/commonjs/i18n/fr.json +13 -13
  27. package/lib/commonjs/i18n/he.json +13 -13
  28. package/lib/commonjs/i18n/hi.json +13 -13
  29. package/lib/commonjs/i18n/it.json +13 -13
  30. package/lib/commonjs/i18n/ja.json +13 -13
  31. package/lib/commonjs/i18n/ko.json +13 -13
  32. package/lib/commonjs/i18n/nl.json +13 -13
  33. package/lib/commonjs/i18n/pt-BR.json +13 -13
  34. package/lib/commonjs/i18n/ru.json +13 -13
  35. package/lib/commonjs/i18n/tr.json +13 -13
  36. package/lib/commonjs/mock-builders/generator/message.js +2 -0
  37. package/lib/commonjs/mock-builders/generator/message.js.map +1 -1
  38. package/lib/commonjs/store/QuickSqliteClient.js +1 -1
  39. package/lib/commonjs/store/apis/getReactions.js +17 -0
  40. package/lib/commonjs/store/apis/getReactions.js.map +1 -0
  41. package/lib/commonjs/store/apis/getReactionsforFilterSort.js +30 -0
  42. package/lib/commonjs/store/apis/getReactionsforFilterSort.js.map +1 -0
  43. package/lib/commonjs/store/apis/insertReaction.js +8 -1
  44. package/lib/commonjs/store/apis/insertReaction.js.map +1 -1
  45. package/lib/commonjs/store/apis/queries/selectReactionsForMessages.js +1 -1
  46. package/lib/commonjs/store/apis/queries/selectReactionsForMessages.js.map +1 -1
  47. package/lib/commonjs/store/apis/updateReaction.js +6 -6
  48. package/lib/commonjs/store/apis/updateReaction.js.map +1 -1
  49. package/lib/commonjs/store/mappers/mapMessageToStorable.js +5 -3
  50. package/lib/commonjs/store/mappers/mapMessageToStorable.js.map +1 -1
  51. package/lib/commonjs/store/mappers/mapStorableToMessage.js +5 -3
  52. package/lib/commonjs/store/mappers/mapStorableToMessage.js.map +1 -1
  53. package/lib/commonjs/store/schema.js +2 -1
  54. package/lib/commonjs/store/schema.js.map +1 -1
  55. package/lib/commonjs/utils/addReactionToLocalState.js +25 -13
  56. package/lib/commonjs/utils/addReactionToLocalState.js.map +1 -1
  57. package/lib/commonjs/utils/removeReactionFromLocalState.js +11 -3
  58. package/lib/commonjs/utils/removeReactionFromLocalState.js.map +1 -1
  59. package/lib/commonjs/utils/removeReservedFields.js +1 -1
  60. package/lib/commonjs/utils/removeReservedFields.js.map +1 -1
  61. package/lib/commonjs/utils/utils.js +19 -5
  62. package/lib/commonjs/utils/utils.js.map +1 -1
  63. package/lib/commonjs/version.json +1 -1
  64. package/lib/module/components/Channel/Channel.js +21 -20
  65. package/lib/module/components/Channel/Channel.js.map +1 -1
  66. package/lib/module/components/Chat/hooks/handleEventToSyncDB.js.map +1 -1
  67. package/lib/module/components/Message/Message.js +9 -19
  68. package/lib/module/components/Message/Message.js.map +1 -1
  69. package/lib/module/components/Message/MessageSimple/MessageFooter.js +1 -2
  70. package/lib/module/components/Message/MessageSimple/MessageFooter.js.map +1 -1
  71. package/lib/module/components/Message/MessageSimple/ReactionList.js +54 -37
  72. package/lib/module/components/Message/MessageSimple/ReactionList.js.map +1 -1
  73. package/lib/module/components/Message/hooks/useCreateMessageContext.js +6 -11
  74. package/lib/module/components/Message/hooks/useCreateMessageContext.js.map +1 -1
  75. package/lib/module/components/Message/hooks/useProcessReactions.js +90 -0
  76. package/lib/module/components/Message/hooks/useProcessReactions.js.map +1 -0
  77. package/lib/module/components/MessageOverlay/MessageOverlay.js +3 -12
  78. package/lib/module/components/MessageOverlay/MessageOverlay.js.map +1 -1
  79. package/lib/module/components/MessageOverlay/OverlayReactions.js +47 -143
  80. package/lib/module/components/MessageOverlay/OverlayReactions.js.map +1 -1
  81. package/lib/module/components/MessageOverlay/OverlayReactionsItem.js +166 -0
  82. package/lib/module/components/MessageOverlay/OverlayReactionsItem.js.map +1 -0
  83. package/lib/module/components/MessageOverlay/hooks/useFetchReactions.js +144 -0
  84. package/lib/module/components/MessageOverlay/hooks/useFetchReactions.js.map +1 -0
  85. package/lib/module/contexts/messageContext/MessageContext.js.map +1 -1
  86. package/lib/module/contexts/themeContext/utils/theme.js +0 -1
  87. package/lib/module/contexts/themeContext/utils/theme.js.map +1 -1
  88. package/lib/module/i18n/es.json +13 -13
  89. package/lib/module/i18n/fr.json +13 -13
  90. package/lib/module/i18n/he.json +13 -13
  91. package/lib/module/i18n/hi.json +13 -13
  92. package/lib/module/i18n/it.json +13 -13
  93. package/lib/module/i18n/ja.json +13 -13
  94. package/lib/module/i18n/ko.json +13 -13
  95. package/lib/module/i18n/nl.json +13 -13
  96. package/lib/module/i18n/pt-BR.json +13 -13
  97. package/lib/module/i18n/ru.json +13 -13
  98. package/lib/module/i18n/tr.json +13 -13
  99. package/lib/module/mock-builders/generator/message.js +2 -0
  100. package/lib/module/mock-builders/generator/message.js.map +1 -1
  101. package/lib/module/store/QuickSqliteClient.js +1 -1
  102. package/lib/module/store/apis/getReactions.js +17 -0
  103. package/lib/module/store/apis/getReactions.js.map +1 -0
  104. package/lib/module/store/apis/getReactionsforFilterSort.js +30 -0
  105. package/lib/module/store/apis/getReactionsforFilterSort.js.map +1 -0
  106. package/lib/module/store/apis/insertReaction.js +8 -1
  107. package/lib/module/store/apis/insertReaction.js.map +1 -1
  108. package/lib/module/store/apis/queries/selectReactionsForMessages.js +1 -1
  109. package/lib/module/store/apis/queries/selectReactionsForMessages.js.map +1 -1
  110. package/lib/module/store/apis/updateReaction.js +6 -6
  111. package/lib/module/store/apis/updateReaction.js.map +1 -1
  112. package/lib/module/store/mappers/mapMessageToStorable.js +5 -3
  113. package/lib/module/store/mappers/mapMessageToStorable.js.map +1 -1
  114. package/lib/module/store/mappers/mapStorableToMessage.js +5 -3
  115. package/lib/module/store/mappers/mapStorableToMessage.js.map +1 -1
  116. package/lib/module/store/schema.js +2 -1
  117. package/lib/module/store/schema.js.map +1 -1
  118. package/lib/module/utils/addReactionToLocalState.js +25 -13
  119. package/lib/module/utils/addReactionToLocalState.js.map +1 -1
  120. package/lib/module/utils/removeReactionFromLocalState.js +11 -3
  121. package/lib/module/utils/removeReactionFromLocalState.js.map +1 -1
  122. package/lib/module/utils/removeReservedFields.js +1 -1
  123. package/lib/module/utils/removeReservedFields.js.map +1 -1
  124. package/lib/module/utils/utils.js +19 -5
  125. package/lib/module/utils/utils.js.map +1 -1
  126. package/lib/module/version.json +1 -1
  127. package/lib/typescript/components/Channel/Channel.d.ts.map +1 -1
  128. package/lib/typescript/components/Channel/hooks/useCreateInputMessageInputContext.d.ts +2 -2
  129. package/lib/typescript/components/Chat/hooks/handleEventToSyncDB.d.ts.map +1 -1
  130. package/lib/typescript/components/Message/Message.d.ts.map +1 -1
  131. package/lib/typescript/components/Message/MessageSimple/ReactionList.d.ts +11 -3
  132. package/lib/typescript/components/Message/MessageSimple/ReactionList.d.ts.map +1 -1
  133. package/lib/typescript/components/Message/hooks/useCreateMessageContext.d.ts.map +1 -1
  134. package/lib/typescript/components/Message/hooks/useMessageActionHandlers.d.ts +1 -1
  135. package/lib/typescript/components/Message/hooks/useMessageActions.d.ts +1 -1
  136. package/lib/typescript/components/Message/hooks/useProcessReactions.d.ts +38 -0
  137. package/lib/typescript/components/Message/hooks/useProcessReactions.d.ts.map +1 -0
  138. package/lib/typescript/components/MessageOverlay/MessageOverlay.d.ts.map +1 -1
  139. package/lib/typescript/components/MessageOverlay/OverlayReactions.d.ts +2 -1
  140. package/lib/typescript/components/MessageOverlay/OverlayReactions.d.ts.map +1 -1
  141. package/lib/typescript/components/MessageOverlay/OverlayReactionsItem.d.ts +11 -0
  142. package/lib/typescript/components/MessageOverlay/OverlayReactionsItem.d.ts.map +1 -0
  143. package/lib/typescript/components/MessageOverlay/hooks/useFetchReactions.d.ts +14 -0
  144. package/lib/typescript/components/MessageOverlay/hooks/useFetchReactions.d.ts.map +1 -0
  145. package/lib/typescript/contexts/messageContext/MessageContext.d.ts +3 -6
  146. package/lib/typescript/contexts/messageContext/MessageContext.d.ts.map +1 -1
  147. package/lib/typescript/contexts/messageInputContext/MessageInputContext.d.ts +1 -1
  148. package/lib/typescript/contexts/themeContext/utils/theme.d.ts +0 -1
  149. package/lib/typescript/contexts/themeContext/utils/theme.d.ts.map +1 -1
  150. package/lib/typescript/i18n/es.json +13 -13
  151. package/lib/typescript/i18n/fr.json +13 -13
  152. package/lib/typescript/i18n/he.json +13 -13
  153. package/lib/typescript/i18n/hi.json +13 -13
  154. package/lib/typescript/i18n/it.json +13 -13
  155. package/lib/typescript/i18n/ja.json +13 -13
  156. package/lib/typescript/i18n/ko.json +13 -13
  157. package/lib/typescript/i18n/nl.json +13 -13
  158. package/lib/typescript/i18n/pt-BR.json +13 -13
  159. package/lib/typescript/i18n/ru.json +13 -13
  160. package/lib/typescript/i18n/tr.json +13 -13
  161. package/lib/typescript/store/apis/getReactions.d.ts +7 -0
  162. package/lib/typescript/store/apis/getReactions.d.ts.map +1 -0
  163. package/lib/typescript/store/apis/getReactionsforFilterSort.d.ts +14 -0
  164. package/lib/typescript/store/apis/getReactionsforFilterSort.d.ts.map +1 -0
  165. package/lib/typescript/store/apis/insertReaction.d.ts +3 -2
  166. package/lib/typescript/store/apis/insertReaction.d.ts.map +1 -1
  167. package/lib/typescript/store/apis/queries/selectReactionsForMessages.d.ts +4 -0
  168. package/lib/typescript/store/apis/queries/selectReactionsForMessages.d.ts.map +1 -1
  169. package/lib/typescript/store/apis/updateReaction.d.ts.map +1 -1
  170. package/lib/typescript/store/mappers/mapMessageToStorable.d.ts.map +1 -1
  171. package/lib/typescript/store/mappers/mapStorableToMessage.d.ts.map +1 -1
  172. package/lib/typescript/store/schema.d.ts +2 -1
  173. package/lib/typescript/store/schema.d.ts.map +1 -1
  174. package/lib/typescript/utils/addReactionToLocalState.d.ts.map +1 -1
  175. package/lib/typescript/utils/removeReactionFromLocalState.d.ts.map +1 -1
  176. package/lib/typescript/utils/removeReservedFields.d.ts.map +1 -1
  177. package/lib/typescript/utils/utils.d.ts +9 -3
  178. package/lib/typescript/utils/utils.d.ts.map +1 -1
  179. package/package.json +1 -1
  180. package/src/components/Channel/Channel.tsx +24 -34
  181. package/src/components/Chat/hooks/handleEventToSyncDB.ts +1 -2
  182. package/src/components/Message/Message.tsx +8 -26
  183. package/src/components/Message/MessageSimple/MessageFooter.tsx +1 -1
  184. package/src/components/Message/MessageSimple/ReactionList.tsx +72 -47
  185. package/src/components/Message/MessageSimple/__tests__/MessageContent.test.js +1 -1
  186. package/src/components/Message/hooks/useCreateMessageContext.ts +5 -10
  187. package/src/components/Message/hooks/useProcessReactions.ts +116 -0
  188. package/src/components/MessageOverlay/MessageOverlay.tsx +4 -17
  189. package/src/components/MessageOverlay/OverlayReactions.tsx +75 -176
  190. package/src/components/MessageOverlay/OverlayReactionsItem.tsx +188 -0
  191. package/src/components/MessageOverlay/hooks/useFetchReactions.ts +85 -0
  192. package/src/components/Thread/__tests__/__snapshots__/Thread.test.js.snap +139 -0
  193. package/src/contexts/messageContext/MessageContext.tsx +2 -6
  194. package/src/contexts/themeContext/utils/theme.ts +0 -2
  195. package/src/i18n/es.json +13 -13
  196. package/src/i18n/fr.json +13 -13
  197. package/src/i18n/he.json +13 -13
  198. package/src/i18n/hi.json +13 -13
  199. package/src/i18n/it.json +13 -13
  200. package/src/i18n/ja.json +13 -13
  201. package/src/i18n/ko.json +13 -13
  202. package/src/i18n/nl.json +13 -13
  203. package/src/i18n/pt-BR.json +13 -13
  204. package/src/i18n/ru.json +13 -13
  205. package/src/i18n/tr.json +13 -13
  206. package/src/mock-builders/generator/message.js +2 -0
  207. package/src/store/QuickSqliteClient.ts +1 -1
  208. package/src/store/apis/getReactions.ts +21 -0
  209. package/src/store/apis/getReactionsforFilterSort.ts +43 -0
  210. package/src/store/apis/insertReaction.ts +15 -5
  211. package/src/store/apis/queries/selectReactionsForMessages.ts +5 -1
  212. package/src/store/apis/updateReaction.ts +6 -18
  213. package/src/store/mappers/mapMessageToStorable.ts +4 -2
  214. package/src/store/mappers/mapStorableToMessage.ts +12 -2
  215. package/src/store/schema.ts +4 -2
  216. package/src/utils/addReactionToLocalState.ts +33 -17
  217. package/src/utils/removeReactionFromLocalState.ts +22 -2
  218. package/src/utils/removeReservedFields.ts +2 -0
  219. package/src/utils/utils.ts +19 -7
  220. package/src/version.json +1 -1
@@ -1,11 +1,12 @@
1
1
  import React from 'react';
2
- import { StyleSheet, TouchableOpacity, useWindowDimensions, View } from 'react-native';
2
+ import { StyleSheet, Text, TouchableOpacity, useWindowDimensions, View } from 'react-native';
3
3
 
4
4
  import Svg, { Circle } from 'react-native-svg';
5
5
 
6
+ import { ReactionGroupResponse, ReactionResponse } from 'stream-chat';
7
+
6
8
  import {
7
9
  MessageContextValue,
8
- Reactions,
9
10
  useMessageContext,
10
11
  } from '../../../contexts/messageContext/MessageContext';
11
12
  import {
@@ -19,26 +20,10 @@ import { Unknown } from '../../../icons/Unknown';
19
20
  import type { IconProps } from '../../../icons/utils/base';
20
21
  import type { DefaultStreamChatGenerics } from '../../../types/types';
21
22
  import type { ReactionData } from '../../../utils/utils';
22
-
23
- const styles = StyleSheet.create({
24
- container: {
25
- left: 0,
26
- position: 'absolute',
27
- top: 0,
28
- },
29
- reactionBubble: {
30
- alignItems: 'center',
31
- flexDirection: 'row',
32
- justifyContent: 'space-evenly',
33
- position: 'absolute',
34
- },
35
- reactionBubbleBackground: {
36
- position: 'absolute',
37
- },
38
- });
23
+ import { ReactionSummary } from '../hooks/useProcessReactions';
39
24
 
40
25
  export type MessageReactions = {
41
- reactions: Reactions;
26
+ reactions: ReactionSummary[];
42
27
  supportedReactions?: ReactionData[];
43
28
  };
44
29
 
@@ -76,7 +61,13 @@ export type ReactionListPropsWithContext<
76
61
  messageContentWidth: number;
77
62
  supportedReactions: ReactionData[];
78
63
  fill?: string;
64
+ /** An array of the reaction objects to display in the list */
65
+ latest_reactions?: ReactionResponse<StreamChatGenerics>[];
66
+ /** An array of the own reaction objects to distinguish own reactions visually */
67
+ own_reactions?: ReactionResponse<StreamChatGenerics>[] | null;
79
68
  radius?: number; // not recommended to change this
69
+ /** An object containing summary for each reaction type on a message */
70
+ reaction_groups?: Record<string, ReactionGroupResponse> | null;
80
71
  reactionSize?: number;
81
72
  stroke?: string;
82
73
  strokeSize?: number; // not recommended to change this
@@ -110,6 +101,7 @@ const ReactionListWithContext = <
110
101
  theme: {
111
102
  colors: {
112
103
  accent_blue,
104
+ black,
113
105
  grey,
114
106
  grey_gainsboro,
115
107
  grey_whisper,
@@ -125,7 +117,6 @@ const ReactionListWithContext = <
125
117
  middleIcon,
126
118
  radius: themeRadius,
127
119
  reactionBubble,
128
- reactionBubbleBackground,
129
120
  reactionSize: themeReactionSize,
130
121
  strokeSize: themeStrokeSize,
131
122
  },
@@ -200,21 +191,6 @@ const ReactionListWithContext = <
200
191
  <Circle cx={x1} cy={y1} fill={alignmentLeft ? fill : white} r={radius} />
201
192
  <Circle cx={x2} cy={y2} fill={alignmentLeft ? fill : white} r={radius * 2} />
202
193
  </Svg>
203
- <View
204
- style={[
205
- styles.reactionBubbleBackground,
206
- {
207
- backgroundColor: alignmentLeft ? fill : white,
208
- borderColor: fill,
209
- borderRadius: reactionSize,
210
- borderWidth: strokeSize,
211
- height: reactionSize,
212
- left,
213
- width: reactionSize * reactions.length,
214
- },
215
- reactionBubbleBackground,
216
- ]}
217
- />
218
194
  <View pointerEvents='none' style={[StyleSheet.absoluteFill]}>
219
195
  <Svg>
220
196
  <Circle cx={x2} cy={y2} fill={alignmentLeft ? fill : white} r={radius * 2} />
@@ -252,24 +228,36 @@ const ReactionListWithContext = <
252
228
  styles.reactionBubble,
253
229
  {
254
230
  backgroundColor: alignmentLeft ? fill : white,
255
- borderRadius: reactionSize - strokeSize * 2,
231
+ borderColor: fill,
232
+ borderRadius: reactionSize,
233
+ borderWidth: strokeSize,
256
234
  height: reactionSize - strokeSize * 2,
257
235
  left: left + strokeSize,
258
236
  top: strokeSize,
259
- width: reactionSize * reactions.length - strokeSize * 2,
260
237
  },
261
238
  reactionBubble,
262
239
  ]}
263
240
  >
264
- {reactions.map((reaction) => (
265
- <Icon
241
+ {reactions.map((reaction, index) => (
242
+ <View
266
243
  key={reaction.type}
267
- pathFill={reaction.own ? iconFillColor || accent_blue : grey}
268
- size={reactionSize / 2}
269
- style={middleIcon}
270
- supportedReactions={supportedReactions}
271
- type={reaction.type}
272
- />
244
+ style={[
245
+ styles.reactionContainer,
246
+ {
247
+ marginRight: index < reactions.length - 1 ? 5 : 0,
248
+ },
249
+ ]}
250
+ >
251
+ <Icon
252
+ key={reaction.type}
253
+ pathFill={reaction.own ? iconFillColor || accent_blue : grey}
254
+ size={reactionSize / 2}
255
+ style={middleIcon}
256
+ supportedReactions={supportedReactions}
257
+ type={reaction.type}
258
+ />
259
+ <Text style={[styles.reactionCount, { color: black }]}>{reaction.count}</Text>
260
+ </View>
273
261
  ))}
274
262
  </TouchableOpacity>
275
263
  </View>
@@ -285,11 +273,13 @@ const areEqual = <StreamChatGenerics extends DefaultStreamChatGenerics = Default
285
273
  const {
286
274
  message: prevMessage,
287
275
  messageContentWidth: prevMessageContentWidth,
276
+ reactions: prevReactions,
288
277
  targetedMessage: prevTargetedMessage,
289
278
  } = prevProps;
290
279
  const {
291
280
  message: nextMessage,
292
281
  messageContentWidth: nextMessageContentWidth,
282
+ reactions: nextReactions,
293
283
  targetedMessage: nextTargetedMessage,
294
284
  } = nextProps;
295
285
 
@@ -313,6 +303,16 @@ const areEqual = <StreamChatGenerics extends DefaultStreamChatGenerics = Default
313
303
  : prevMessage.latest_reactions === nextMessage.latest_reactions;
314
304
  if (!latestReactionsEqual) return false;
315
305
 
306
+ const reactionsEqual =
307
+ Array.isArray(prevReactions) && Array.isArray(nextReactions)
308
+ ? prevReactions.length === nextReactions.length &&
309
+ prevReactions.every(
310
+ ({ type }, index) => type === nextMessage.latest_reactions?.[index].type,
311
+ )
312
+ : prevReactions === nextReactions;
313
+
314
+ if (!reactionsEqual) return false;
315
+
316
316
  return true;
317
317
  };
318
318
 
@@ -323,7 +323,7 @@ const MemoizedReactionList = React.memo(
323
323
 
324
324
  export type ReactionListProps<
325
325
  StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics,
326
- > = Partial<Omit<ReactionListPropsWithContext<StreamChatGenerics>, 'messageContentWidth'>> &
326
+ > = Partial<ReactionListPropsWithContext<StreamChatGenerics>> &
327
327
  Pick<ReactionListPropsWithContext<StreamChatGenerics>, 'messageContentWidth'>;
328
328
 
329
329
  /**
@@ -364,3 +364,28 @@ export const ReactionList = <
364
364
  />
365
365
  );
366
366
  };
367
+
368
+ const styles = StyleSheet.create({
369
+ container: {
370
+ left: 0,
371
+ position: 'absolute',
372
+ top: 0,
373
+ },
374
+ reactionBubble: {
375
+ alignItems: 'center',
376
+ flexDirection: 'row',
377
+ justifyContent: 'space-evenly',
378
+ paddingHorizontal: 5,
379
+ position: 'absolute',
380
+ },
381
+ reactionContainer: {
382
+ alignItems: 'center',
383
+ flexDirection: 'row',
384
+ justifyContent: 'center',
385
+ },
386
+ reactionCount: {
387
+ fontSize: 12,
388
+ fontWeight: 'bold',
389
+ marginLeft: 2,
390
+ },
391
+ });
@@ -212,7 +212,7 @@ describe('MessageContent', () => {
212
212
  const user = generateUser();
213
213
  const reaction = generateReaction();
214
214
  const message = generateMessage({
215
- latest_reactions: [reaction],
215
+ reaction_groups: { [reaction.type]: reaction },
216
216
  user,
217
217
  });
218
218
 
@@ -2,7 +2,7 @@ import { useMemo } from 'react';
2
2
 
3
3
  import type { MessageContextValue } from '../../../contexts/messageContext/MessageContext';
4
4
  import type { DefaultStreamChatGenerics } from '../../../types/types';
5
- import { isMessageWithStylesReadByAndDateSeparator } from '../../MessageList/hooks/useMessageList';
5
+ import { stringifyMessage } from '../../../utils/utils';
6
6
 
7
7
  export const useCreateMessageContext = <
8
8
  StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics,
@@ -48,14 +48,9 @@ export const useCreateMessageContext = <
48
48
  videos,
49
49
  }: MessageContextValue<StreamChatGenerics>) => {
50
50
  const groupStylesLength = groupStyles.length;
51
- const reactionsValue = reactions.map(({ own, type }) => `${own}${type}`).join();
52
- const latestReactions = message.latest_reactions ? message.latest_reactions : undefined;
53
- const readBy = isMessageWithStylesReadByAndDateSeparator(message) && message.readBy;
54
- const messageValue = `${
55
- latestReactions ? latestReactions.map(({ type, user }) => `${type}${user?.id}`).join() : ''
56
- }${message.updated_at}${message.deleted_at}${readBy}${message.status}${message.type}${
57
- message.text
58
- }${message.reply_count}`;
51
+ const reactionsValue = reactions.map(({ count, own, type }) => `${own}${type}${count}`).join();
52
+ const stringifiedMessage = stringifyMessage(message);
53
+
59
54
  const membersValue = JSON.stringify(members);
60
55
  const myMessageThemeString = useMemo(() => JSON.stringify(myMessageTheme), [myMessageTheme]);
61
56
 
@@ -115,7 +110,7 @@ export const useCreateMessageContext = <
115
110
  lastGroupMessage,
116
111
  lastReceivedId,
117
112
  membersValue,
118
- messageValue,
113
+ stringifiedMessage,
119
114
  myMessageThemeString,
120
115
  reactionsValue,
121
116
  showAvatar,
@@ -0,0 +1,116 @@
1
+ import { ComponentType, useMemo } from 'react';
2
+
3
+ import { ReactionResponse } from 'stream-chat';
4
+
5
+ import {
6
+ MessagesContextValue,
7
+ useMessagesContext,
8
+ } from '../../../contexts/messagesContext/MessagesContext';
9
+ import { DefaultStreamChatGenerics } from '../../../types/types';
10
+ import { ReactionData } from '../../../utils/utils';
11
+ import { ReactionListProps } from '../MessageSimple/ReactionList';
12
+
13
+ export type ReactionSummary = {
14
+ own: boolean;
15
+ type: string;
16
+ count?: number;
17
+ firstReactionAt?: Date | null;
18
+ Icon?: ComponentType | null;
19
+ lastReactionAt?: Date | null;
20
+ latestReactedUserNames?: string[];
21
+ unlistedReactedUserCount?: number;
22
+ };
23
+
24
+ export type ReactionsComparator = (a: ReactionSummary, b: ReactionSummary) => number;
25
+
26
+ type UseProcessReactionsParams<
27
+ StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics,
28
+ > = Pick<
29
+ ReactionListProps<StreamChatGenerics>,
30
+ 'own_reactions' | 'reaction_groups' | 'latest_reactions'
31
+ > &
32
+ Partial<Pick<MessagesContextValue<StreamChatGenerics>, 'supportedReactions'>> & {
33
+ sortReactions?: ReactionsComparator;
34
+ };
35
+
36
+ export const defaultReactionsSort: ReactionsComparator = (a, b) => {
37
+ if (a.firstReactionAt && b.firstReactionAt) {
38
+ return +a.firstReactionAt - +b.firstReactionAt;
39
+ }
40
+
41
+ return a.type.localeCompare(b.type, 'en');
42
+ };
43
+
44
+ const isOwnReaction = <
45
+ StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics,
46
+ >(
47
+ reactionType: string,
48
+ ownReactions?: ReactionResponse<StreamChatGenerics>[] | null,
49
+ ) => (ownReactions ? ownReactions.some((reaction) => reaction.type === reactionType) : false);
50
+
51
+ const isSupportedReaction = (reactionType: string, supportedReactions: ReactionData[]) =>
52
+ supportedReactions
53
+ ? supportedReactions.some((reactionOption) => reactionOption.type === reactionType)
54
+ : false;
55
+
56
+ const getEmojiByReactionType = (reactionType: string, supportedReactions: ReactionData[]) =>
57
+ supportedReactions.find(({ type }) => type === reactionType)?.Icon ?? null;
58
+
59
+ const getLatestReactedUserNames = (reactionType: string, latestReactions?: ReactionResponse[]) =>
60
+ latestReactions
61
+ ? latestReactions.flatMap((reaction) => {
62
+ if (reactionType && reactionType === reaction.type) {
63
+ const username = reaction.user?.name || reaction.user?.id;
64
+ return username ? [username] : [];
65
+ }
66
+ return [];
67
+ })
68
+ : [];
69
+
70
+ /**
71
+ * Custom hook to process reactions data from message and return a list of reactions with additional info.
72
+ */
73
+ export const useProcessReactions = <
74
+ StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics,
75
+ >(
76
+ props: UseProcessReactionsParams<StreamChatGenerics>,
77
+ ) => {
78
+ const { supportedReactions: contextSupportedReactions } = useMessagesContext();
79
+
80
+ const {
81
+ latest_reactions,
82
+ own_reactions,
83
+ reaction_groups,
84
+ sortReactions = defaultReactionsSort,
85
+ supportedReactions = contextSupportedReactions,
86
+ } = props;
87
+
88
+ return useMemo(() => {
89
+ if (!reaction_groups)
90
+ return { existingReactions: [], hasReactions: false, totalReactionCount: 0 };
91
+ const unsortedReactions = Object.entries(reaction_groups).flatMap(
92
+ ([reactionType, { count, first_reaction_at, last_reaction_at }]) => {
93
+ if (count === 0 || !isSupportedReaction(reactionType, supportedReactions)) return [];
94
+
95
+ const latestReactedUserNames = getLatestReactedUserNames(reactionType, latest_reactions);
96
+
97
+ return {
98
+ count,
99
+ firstReactionAt: first_reaction_at ? new Date(first_reaction_at) : null,
100
+ Icon: getEmojiByReactionType(reactionType, supportedReactions),
101
+ lastReactionAt: last_reaction_at ? new Date(last_reaction_at) : null,
102
+ latestReactedUserNames,
103
+ own: isOwnReaction<StreamChatGenerics>(reactionType, own_reactions),
104
+ type: reactionType,
105
+ unlistedReactedUserCount: count - latestReactedUserNames.length,
106
+ };
107
+ },
108
+ );
109
+
110
+ return {
111
+ existingReactions: unsortedReactions.sort(sortReactions),
112
+ hasReactions: unsortedReactions.length > 0,
113
+ totalReactionCount: unsortedReactions.reduce((total, { count }) => total + count, 0),
114
+ };
115
+ }, [reaction_groups, own_reactions?.length, latest_reactions?.length, sortReactions]);
116
+ };
@@ -44,10 +44,7 @@ import { mergeThemes, ThemeProvider, useTheme } from '../../contexts/themeContex
44
44
  import { useViewport } from '../../hooks/useViewport';
45
45
  import type { DefaultStreamChatGenerics } from '../../types/types';
46
46
  import { MessageTextContainer } from '../Message/MessageSimple/MessageTextContainer';
47
- import {
48
- OverlayReactions as DefaultOverlayReactions,
49
- Reaction,
50
- } from '../MessageOverlay/OverlayReactions';
47
+ import { OverlayReactions as DefaultOverlayReactions } from '../MessageOverlay/OverlayReactions';
51
48
  import type { ReplyProps } from '../Reply/Reply';
52
49
 
53
50
  const styles = StyleSheet.create({
@@ -464,26 +461,16 @@ const MessageOverlayWithContext = <
464
461
  message={message}
465
462
  />
466
463
  )}
467
- {!!messageReactionTitle &&
468
- message.latest_reactions &&
469
- message.latest_reactions.length > 0 ? (
464
+ {!!messageReactionTitle && (
470
465
  <OverlayReactions
471
466
  alignment={alignment}
467
+ messageId={message.id}
472
468
  OverlayReactionsAvatar={OverlayReactionsAvatar}
473
- reactions={
474
- message.latest_reactions.map((reaction) => ({
475
- alignment: clientId && clientId === reaction.user?.id ? 'right' : 'left',
476
- id: reaction?.user?.id || '',
477
- image: reaction?.user?.image,
478
- name: reaction?.user?.name || reaction.user_id || '',
479
- type: reaction.type,
480
- })) as Reaction[]
481
- }
482
469
  showScreen={showScreen}
483
470
  supportedReactions={messagesContext?.supportedReactions}
484
471
  title={messageReactionTitle}
485
472
  />
486
- ) : null}
473
+ )}
487
474
  </View>
488
475
  )}
489
476
  </Animated.View>