diff --git a/.github/workflows/sample-distribution.yml b/.github/workflows/sample-distribution.yml
index 1073f11080..4bc3199398 100644
--- a/.github/workflows/sample-distribution.yml
+++ b/.github/workflows/sample-distribution.yml
@@ -14,7 +14,7 @@ on:
jobs:
build_and_deploy_ios_testflight_qa:
name: Build SampleApp iOS and Deploy-${{ github.ref == 'refs/heads/develop' }}
- runs-on: [macos-14]
+ runs-on: [macos-15]
steps:
- name: Connect Bot
uses: webfactory/ssh-agent@v0.7.0
diff --git a/README.md b/README.md
index 79d52128c6..97c1642e23 100644
--- a/README.md
+++ b/README.md
@@ -10,7 +10,7 @@
[](https://www.npmjs.com/package/stream-chat-react-native)
[](https://github.com/GetStream/stream-chat-react-native/actions)
[](https://getstream.io/chat/docs/sdk/reactnative)
-
+
diff --git a/examples/ExpoMessaging/yarn.lock b/examples/ExpoMessaging/yarn.lock
index 422188b1e7..a939119a0b 100644
--- a/examples/ExpoMessaging/yarn.lock
+++ b/examples/ExpoMessaging/yarn.lock
@@ -7358,10 +7358,10 @@ stream-buffers@2.2.x, stream-buffers@~2.2.0:
version "0.0.0"
uid ""
-stream-chat-react-native-core@6.6.6:
- version "6.6.6"
- resolved "https://registry.yarnpkg.com/stream-chat-react-native-core/-/stream-chat-react-native-core-6.6.6.tgz#d701beb9652f0a5851286f752d8c4fdadb3e0603"
- integrity sha512-sfBtWz4K4OzhFDMRaPF2xMj7aP9FQU4dMN1XCsmRT07hyYn6iEviECxNttYvoRLB1zNdeja5cL63IDY3UZSpAQ==
+stream-chat-react-native-core@6.6.7:
+ version "6.6.7"
+ resolved "https://registry.yarnpkg.com/stream-chat-react-native-core/-/stream-chat-react-native-core-6.6.7.tgz#d887234af18890c3396f1b8b5f169d9b28a793ab"
+ integrity sha512-Xc/S92nUBSwfVPZqNjt/zNs/DJcRV1aRa/+yCSBCqjCwo0EuiWEP9yKy3xGxBkehNe4vaIDvkeREduA4dRUGpA==
dependencies:
"@gorhom/bottom-sheet" "^5.1.1"
dayjs "1.10.5"
@@ -7374,28 +7374,13 @@ stream-chat-react-native-core@6.6.6:
path "0.12.7"
react-native-markdown-package "1.8.2"
react-native-url-polyfill "^1.3.0"
- stream-chat "^8.57.5"
+ stream-chat "^8.57.6"
use-sync-external-store "^1.4.0"
"stream-chat-react-native-core@link:../../package":
version "0.0.0"
uid ""
-stream-chat@^8.57.5:
- version "8.57.5"
- resolved "https://registry.yarnpkg.com/stream-chat/-/stream-chat-8.57.5.tgz#1b49b7504371e19a539465e2ae5dc86aa3269637"
- integrity sha512-ndcbH/zGzUIAhZLGn1owVV8MeNvVfWITIlhAhfmnsV7RLoo/eiGFEuP4aNoG1YRos/g9xJQ7TEmKpz8xYqo13w==
- dependencies:
- "@babel/runtime" "^7.16.3"
- "@types/jsonwebtoken" "~9.0.0"
- "@types/ws" "^7.4.0"
- axios "^1.6.0"
- base64-js "^1.5.1"
- form-data "^4.0.0"
- isomorphic-ws "^4.0.1"
- jsonwebtoken "~9.0.0"
- ws "^7.5.10"
-
stream-chat@^8.57.6:
version "8.57.6"
resolved "https://registry.yarnpkg.com/stream-chat/-/stream-chat-8.57.6.tgz#dd3a4a0a024ee44bfa6ae7ca15648e6c9f2e498f"
diff --git a/examples/SampleApp/ios/Podfile.lock b/examples/SampleApp/ios/Podfile.lock
index 047b8ed1e5..296862d232 100644
--- a/examples/SampleApp/ios/Podfile.lock
+++ b/examples/SampleApp/ios/Podfile.lock
@@ -2213,7 +2213,7 @@ PODS:
- libwebp (~> 1.0)
- SDWebImage/Core (~> 5.10)
- SocketRocket (0.7.1)
- - stream-chat-react-native (6.6.6):
+ - stream-chat-react-native (6.6.7):
- DoubleConversion
- glog
- hermes-engine
@@ -2554,92 +2554,92 @@ SPEC CHECKSUMS:
hermes-engine: b417d2b2aee3b89b58e63e23a51e02be91dc876d
libwebp: 02b23773aedb6ff1fd38cec7a77b81414c6842a8
nanopb: fad817b59e0457d11a5dfbde799381cd727c1275
- op-sqlite: c33561ea312a2ae38aae032fd3a42635dc6b57e8
+ op-sqlite: 2e34a191af7e843608357671c94a6e2befd4b986
PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47
PromisesSwift: 9d77319bbe72ebf6d872900551f7eeba9bce2851
- RCT-Folly: 36fe2295e44b10d831836cc0d1daec5f8abcf809
+ RCT-Folly: e78785aa9ba2ed998ea4151e314036f6c49e6d82
RCTDeprecation: b2eecf2d60216df56bc5e6be5f063826d3c1ee35
RCTRequired: 78522de7dc73b81f3ed7890d145fa341f5bb32ea
RCTTypeSafety: c135dd2bf50402d87fd12884cbad5d5e64850edd
React: b229c49ed5898dab46d60f61ed5a0bfa2ee2fadb
React-callinvoker: 2ac508e92c8bd9cf834cc7d7787d94352e4af58f
React-Codegen: 4b8b4817cea7a54b83851d4c1f91f79aa73de30a
- React-Core: 13cdd1558d0b3f6d9d5a22e14d89150280e79f02
- React-CoreModules: b07a6744f48305405e67c845ebf481b6551b712a
- React-cxxreact: 1055a86c66ac35b4e80bd5fb766aed5f494dfff4
+ React-Core: 325b4f6d9162ae8b9a6ff42fe78e260eb124180d
+ React-CoreModules: 558041e5258f70cd1092f82778d07b8b2ff01897
+ React-cxxreact: 8fff17cbe76e6a8f9991b59552e1235429f9c74b
React-debug: c76e92776a86622209279fe6d24a0147584444ed
- React-defaultsnativemodule: c2e3ac39909241374c3322eb2be33f4c15fe6be4
- React-domnativemodule: 240b3c95b5300cc6537594e73ebc6e8e77585b74
- React-Fabric: 3b403ca25f74d54454b31d1d2627050e0777d42c
- React-FabricComponents: 154740cfcd57943709a9d0343769d17173c0ac9c
- React-FabricImage: 0863e39cea98f3ca2f8c3d92984660795cec84ae
+ React-defaultsnativemodule: 111fb1efc95c2bd0ee18e38e9f7b57d678e6f932
+ React-domnativemodule: d5154a815306fd6050ee9346a1490d2fb17eb0e5
+ React-Fabric: 51ac32f0a6790b1d3b14d90c6870e5ce5bb3854a
+ React-FabricComponents: 1094d6a3c2566b3c56951331c44d7d3960570ac8
+ React-FabricImage: 6b210ad3c72704a9ad60dde66c397ce6257333f4
React-featureflags: efb93a998907e4ad5b88f6ed77cc140914d5c36d
- React-featureflagsnativemodule: 51116d72aafea30860f315702d17eb76bbb725a3
- React-graphics: 91d9920451f633d64d31948da3ba0377b6eda8de
- React-hermes: 71186f872c932e4574d5feb3ed754dda63a0b3bd
- React-idlecallbacksnativemodule: 19bf1fa4b2b66fe1898ac1d185129cdcc3221c7c
- React-ImageManager: 7dc7bfca8e9ecb9a7436b8a89a143a193ef5adcf
- React-jserrorhandler: d8640792495ac2d78e73acbcc77a8439d1eedfef
- React-jsi: 0775a66820496769ad83e629f0f5cce621a57fc7
- React-jsiexecutor: 2cf5ba481386803f3c88b85c63fa102cba5d769e
- React-jsinspector: d1d9f215c7431b286acc12e83cdf0d90c265f0ed
- React-jsinspectortracing: c4c1cceb9a9c266ce849c82332e35cc57ee9dae9
- React-jsitracing: 267618eec9c362658a4587c5ddcfb41b2e00c403
- React-logger: 795cd5055782db394f187f9db0477d4b25b44291
- React-Mapbuffer: 0df2a235bd0182f5cbed6c5f095e66deca12e335
- React-microtasksnativemodule: b31e56a980634f383221bfefd5111d04c14c110b
- react-native-blob-util: 875bbeee07e4ada135e4edf9fc7b22acf8d9721d
- react-native-cameraroll: 36dc62b41c7943a79ac2f7cf4d3da10d4138513f
- react-native-document-picker: 19be73c0423e4bc886cef74ec282eff750698013
- react-native-netinfo: f0a9899081c185db1de5bb2fdc1c88c202a059ac
- react-native-safe-area-context: 0b43456abcaaa3c8323bbfafe9c5f0f9511219d2
- react-native-video: a225b4d4d3286f3253dc7b00a62e7c8e59d04d51
- React-NativeModulesApple: b74b4e3004104429461593fe460ad790cc4928c2
- React-perflogger: ab51b7592532a0ea45bf6eed7e6cae14a368b678
- React-performancetimeline: 37192fd1019c3b3b597a877dff12f3af68305c34
+ React-featureflagsnativemodule: a74b09429c2e7a57412d78cc159ab86ae4f15db9
+ React-graphics: 17ef0ee3ef4a4c1774cc82f1f477ecef4d67c73f
+ React-hermes: a9a0c8377627b5506ef9a7b6f60a805c306e3f51
+ React-idlecallbacksnativemodule: 0711ec5eb53c7f790641fa00e5f6ec0355d3159b
+ React-ImageManager: 23b4701408390428724f0e0ebb2cbed7b37c2b24
+ React-jserrorhandler: e21b438ef8b99ea8bf070ff35f00bc0215b5f769
+ React-jsi: f3f51595cc4c089037b536368f016d4742bf9cf7
+ React-jsiexecutor: cca6c232db461e2fd213a11e9364cfa6fdaa20eb
+ React-jsinspector: 8a3c2637b84ebec478f46a43432a522d7489410f
+ React-jsinspectortracing: ee0215d2db753cc10f45fc9aa86557718d0b16fb
+ React-jsitracing: 258be1fd259141f6aa43012c20c70ebc02e32087
+ React-logger: 018826bfd51b9f18e87f67db1590bc510ad20664
+ React-Mapbuffer: 9fbb496e7d6f7c34d5e617365ee778bf96d14eae
+ React-microtasksnativemodule: 36adde22631838680d1be62776e8ccb83186c06a
+ react-native-blob-util: d03eaad9fd1bbe90bd0eedb5bad3333215976086
+ react-native-cameraroll: 45c76b20e80da6fbf48ba17490990305810a2a7f
+ react-native-document-picker: 78c262a7f9f77df2380378aa4b3413b8646ce91b
+ react-native-netinfo: cec9c4e86083cb5b6aba0e0711f563e2fbbff187
+ react-native-safe-area-context: 02e0f487c16ccf1acc8a666bed2318ceeb5dc14c
+ react-native-video: 16b5c395d05f8af23e16bfe3dc0794a5514c882f
+ React-NativeModulesApple: ec44c21ae0bbb5f9a2df72db00294e33a00e07f0
+ React-perflogger: 9e8d3c0dc0194eb932162812a168aa5dc662f418
+ React-performancetimeline: 350424518f433dd43f063dc5f2cf3195c1a5b60f
React-RCTActionSheet: 592674cf61142497e0e820688f5a696e41bf16dd
- React-RCTAnimation: 8fbb8dba757b49c78f4db403133ab6399a4ce952
- React-RCTAppDelegate: 7f88baa8cb4e5d6c38bb4d84339925c70c9ac864
- React-RCTBlob: f89b162d0fe6b570a18e755eb16cbe356d3c6d17
- React-RCTFabric: f2151588dc1dc884b34b8660d72ef5237aa4b10e
- React-RCTFBReactNativeSpec: 8c29630c2f379c729300e4c1e540f3d1b78d1936
- React-RCTImage: ccac9969940f170503857733f9a5f63578e106e1
- React-RCTLinking: d82427bbf18415a3732105383dff119131cadd90
- React-RCTNetwork: 12ad4d0fbde939e00251ca5ca890da2e6825cc3c
- React-RCTSettings: e7865bf9f455abf427da349c855f8644b5c39afa
- React-RCTText: 2cdfd88745059ec3202a0842ea75a956c7d6f27d
- React-RCTVibration: a3a1458e6230dfd64b3768ebc0a4aac430d9d508
+ React-RCTAnimation: e6d669872f9b3b4ab9527aab283b7c49283236b7
+ React-RCTAppDelegate: de2343fe08be4c945d57e0ecce44afcc7dd8fc03
+ React-RCTBlob: 3e2dce94c56218becc4b32b627fc2293149f798d
+ React-RCTFabric: adad07a08efb186bc1046041207527927524170d
+ React-RCTFBReactNativeSpec: d10ca5e0ccbfeac8c047361fedf8e4ac653887b6
+ React-RCTImage: dc04b176c022d12a8f55ae7a7279b1e091066ae0
+ React-RCTLinking: 88f5e37fe4f26fbc80791aa2a5f01baf9b9a3fd5
+ React-RCTNetwork: f213693565efbd698b8e9c18d700a514b49c0c8e
+ React-RCTSettings: a2d32a90c45a3575568cad850abc45924999b8a5
+ React-RCTText: 54cdcd1cbf6f6a91dc6317f5d2c2b7fc3f6bf7a0
+ React-RCTVibration: 11dae0e7f577b5807bb7d31e2e881eb46f854fd4
React-rendererconsistency: aa476d937c91886dd8b2ddde3191c775585ae47a
- React-rendererdebug: 5a2219e0ceb78f4ffe9ee2d80fa260bb5bac50b2
+ React-rendererdebug: df10d858ac7709b9c8349d952474b0746092c690
React-rncore: 517c6c3647d45de81a7920b6959adf14fed2a5a5
- React-RuntimeApple: 40809bf5975c265b990dec2725f2cfb61f1afc75
- React-RuntimeCore: 375c2645e924fdca875918f07ed987653c517edc
+ React-RuntimeApple: 6922a0861c3fc4c7d544fc7d1d5cb38c779d1264
+ React-RuntimeCore: 41a95876d16630ce00946eaaee7ffd5222242b44
React-runtimeexecutor: a188df372373baf5066e6e229177836488799f80
- React-RuntimeHermes: 2de8d61ec25d950ae4aebcab1a895e0bb8b18c95
- React-runtimescheduler: e8b49a60eca68a3513c259879a352ed010fed255
+ React-RuntimeHermes: f2ca409c03c36bb3dcbf61bdfa2636501f9faebd
+ React-runtimescheduler: 7ae10fa81428c2479e0a5534943dacb8e34c9d52
React-timing: e56b95cb12c6fb9146be7ba3d671cf6b5d17b2e0
- React-utils: 8ad62100a8780798a380b769e968c4764bad1f4b
- ReactAppDependencyProvider: f2e81d80afd71a8058589e19d8a134243fa53f17
- ReactCodegen: 299e99fc57c93edc7c5396ef1a39a3a4d494f25d
- ReactCommon: c8fdbc582b98a07daf201cd95c1da75dd029f3ee
- RNAudioRecorderPlayer: 224c7de87722938aedce04000d09baa633148f5b
- RNCAsyncStorage: dac011cac81189c2b3b8654f3db97d2b6362d165
- RNFastImage: 5c9c9fed9c076e521b3f509fe79e790418a544e8
- RNFBApp: 60366dd9d6bb01327607e1561a32508592d76db9
- RNFBMessaging: 9465c2e3adb5e02cae8d40048306a30aea7f55cf
- RNGestureHandler: 0a16f3f13829c01268ae55610a40b57b713c8161
- RNNotifee: 4a6ee5c7deaf00e005050052d73ee6315dff7ec9
- RNReactNativeHapticFeedback: a49e613d48d721c99cad9689a490554104c22154
- RNReanimated: c9f295fb1679867288d238bfaf3ea39225c95e1b
- RNScreens: 77f93ec55b749c49549b447527ebf78e990125f3
- RNShare: 12d13ebc179faf22534c605d17b2c2fa40191850
- RNSVG: 05776cf3f0d52d3f8e7ebee34b2189da7b8638ff
+ React-utils: 6eabecc0e7d7bcf21b6b33357bc1fe8ae13c7c4c
+ ReactAppDependencyProvider: a1fb08dfdc7ebc387b2e54cfc9decd283ed821d8
+ ReactCodegen: 0f8899ac1bad260bf3b362ee848ef67a70b5a306
+ ReactCommon: a30b578194de911fbe1698efb8247bfe4cb6abff
+ RNAudioRecorderPlayer: 11df0c7b614e9767ef24d896465c3a758c592de7
+ RNCAsyncStorage: 849b77e6ab3eb838361a902b492993056924faab
+ RNFastImage: 462a183c4b0b6b26fdfd639e1ed6ba37536c3b87
+ RNFBApp: b5626640e0f4b4fe5be4f44375df703c0d62ee4b
+ RNFBMessaging: 8e38f5ca846497f8a9c91d33f311c00ca52d119c
+ RNGestureHandler: f7b3a72c099e1e29b5b81688678bc9108d44057c
+ RNNotifee: 5e3b271e8ea7456a36eec994085543c9adca9168
+ RNReactNativeHapticFeedback: eb5395b503c7a8f10de5e6722ef8afd3c61bc4f5
+ RNReanimated: fe5c52894886953248a81a10b2a9b6eeb5398d61
+ RNScreens: fc78b9b5a1274426d7a59b7d07c272bba13604fa
+ RNShare: dcef43a8864fcc114fd582edba7832a906fd318d
+ RNSVG: 71e35e78add645b84b52b0c6f203f91028e1ab5e
SDWebImage: a7f831e1a65eb5e285e3fb046a23fcfbf08e696d
SDWebImageWebPCoder: 908b83b6adda48effe7667cd2b7f78c897e5111d
SocketRocket: d4aabe649be1e368d1318fdf28a022d714d65748
- stream-chat-react-native: 3495d75137b4ded6b0cdf42395e89a484063c78f
+ stream-chat-react-native: 46be17d00c7de9c1c032e217257cd494b2f7f277
Yoga: be02ca501b03c79d7027a6bbbd0a8db985034f11
PODFILE CHECKSUM: 4f662370295f8f9cee909f1a4c59a614999a209d
-COCOAPODS: 1.14.3
+COCOAPODS: 1.16.2
diff --git a/examples/SampleApp/yarn.lock b/examples/SampleApp/yarn.lock
index ce929aba6a..64a98b1c59 100644
--- a/examples/SampleApp/yarn.lock
+++ b/examples/SampleApp/yarn.lock
@@ -7530,10 +7530,10 @@ statuses@~1.5.0:
resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c"
integrity sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==
-stream-chat-react-native-core@6.6.6:
- version "6.6.6"
- resolved "https://registry.yarnpkg.com/stream-chat-react-native-core/-/stream-chat-react-native-core-6.6.6.tgz#d701beb9652f0a5851286f752d8c4fdadb3e0603"
- integrity sha512-sfBtWz4K4OzhFDMRaPF2xMj7aP9FQU4dMN1XCsmRT07hyYn6iEviECxNttYvoRLB1zNdeja5cL63IDY3UZSpAQ==
+stream-chat-react-native-core@6.6.7:
+ version "6.6.7"
+ resolved "https://registry.yarnpkg.com/stream-chat-react-native-core/-/stream-chat-react-native-core-6.6.7.tgz#d887234af18890c3396f1b8b5f169d9b28a793ab"
+ integrity sha512-Xc/S92nUBSwfVPZqNjt/zNs/DJcRV1aRa/+yCSBCqjCwo0EuiWEP9yKy3xGxBkehNe4vaIDvkeREduA4dRUGpA==
dependencies:
"@gorhom/bottom-sheet" "^5.1.1"
dayjs "1.10.5"
@@ -7546,7 +7546,7 @@ stream-chat-react-native-core@6.6.6:
path "0.12.7"
react-native-markdown-package "1.8.2"
react-native-url-polyfill "^1.3.0"
- stream-chat "^8.57.5"
+ stream-chat "^8.57.6"
use-sync-external-store "^1.4.0"
"stream-chat-react-native-core@link:../../package":
@@ -7557,21 +7557,6 @@ stream-chat-react-native-core@6.6.6:
version "0.0.0"
uid ""
-stream-chat@^8.57.5:
- version "8.57.5"
- resolved "https://registry.yarnpkg.com/stream-chat/-/stream-chat-8.57.5.tgz#1b49b7504371e19a539465e2ae5dc86aa3269637"
- integrity sha512-ndcbH/zGzUIAhZLGn1owVV8MeNvVfWITIlhAhfmnsV7RLoo/eiGFEuP4aNoG1YRos/g9xJQ7TEmKpz8xYqo13w==
- dependencies:
- "@babel/runtime" "^7.16.3"
- "@types/jsonwebtoken" "~9.0.0"
- "@types/ws" "^7.4.0"
- axios "^1.6.0"
- base64-js "^1.5.1"
- form-data "^4.0.0"
- isomorphic-ws "^4.0.1"
- jsonwebtoken "~9.0.0"
- ws "^7.5.10"
-
stream-chat@^8.57.6:
version "8.57.6"
resolved "https://registry.yarnpkg.com/stream-chat/-/stream-chat-8.57.6.tgz#dd3a4a0a024ee44bfa6ae7ca15648e6c9f2e498f"
diff --git a/examples/TypeScriptMessaging/ios/Podfile.lock b/examples/TypeScriptMessaging/ios/Podfile.lock
index d529a65c0e..341c7a63e5 100644
--- a/examples/TypeScriptMessaging/ios/Podfile.lock
+++ b/examples/TypeScriptMessaging/ios/Podfile.lock
@@ -2039,7 +2039,7 @@ PODS:
- ReactCommon/turbomodule/core
- Yoga
- SocketRocket (0.7.1)
- - stream-chat-react-native (6.6.6):
+ - stream-chat-react-native (6.6.7):
- DoubleConversion
- glog
- hermes-engine
@@ -2322,91 +2322,91 @@ EXTERNAL SOURCES:
:path: "../node_modules/react-native/ReactCommon/yoga"
SPEC CHECKSUMS:
- boost: 7e761d76ca2ce687f7cc98e698152abd03a18f90
- DoubleConversion: cb417026b2400c8f53ae97020b2be961b59470cb
+ boost: 1dca942403ed9342f98334bf4c3621f011aa7946
+ DoubleConversion: f16ae600a246532c4020132d54af21d0ddb2a385
fast_float: 06eeec4fe712a76acc9376682e4808b05ce978b6
FBLazyVector: 6fe148afcef2e3213e484758e3459609d40d57f5
fmt: a40bb5bd0294ea969aaaba240a927bd33d878cdd
- glog: eb93e2f488219332457c3c4eafd2738ddc7e80b8
+ glog: 08b301085f15bcbb6ff8632a8ebaf239aae04e6a
hermes-engine: b417d2b2aee3b89b58e63e23a51e02be91dc876d
- op-sqlite: c33561ea312a2ae38aae032fd3a42635dc6b57e8
- RCT-Folly: 36fe2295e44b10d831836cc0d1daec5f8abcf809
+ op-sqlite: 2e34a191af7e843608357671c94a6e2befd4b986
+ RCT-Folly: e78785aa9ba2ed998ea4151e314036f6c49e6d82
RCTDeprecation: b2eecf2d60216df56bc5e6be5f063826d3c1ee35
RCTRequired: 78522de7dc73b81f3ed7890d145fa341f5bb32ea
RCTTypeSafety: c135dd2bf50402d87fd12884cbad5d5e64850edd
React: b229c49ed5898dab46d60f61ed5a0bfa2ee2fadb
React-callinvoker: 2ac508e92c8bd9cf834cc7d7787d94352e4af58f
React-Codegen: 4b8b4817cea7a54b83851d4c1f91f79aa73de30a
- React-Core: 13cdd1558d0b3f6d9d5a22e14d89150280e79f02
- React-CoreModules: b07a6744f48305405e67c845ebf481b6551b712a
- React-cxxreact: 1055a86c66ac35b4e80bd5fb766aed5f494dfff4
+ React-Core: 325b4f6d9162ae8b9a6ff42fe78e260eb124180d
+ React-CoreModules: 558041e5258f70cd1092f82778d07b8b2ff01897
+ React-cxxreact: 8fff17cbe76e6a8f9991b59552e1235429f9c74b
React-debug: 0a5fcdbacc6becba0521e910c1bcfdb20f32a3f6
- React-defaultsnativemodule: 4bb28fc97fee5be63a9ebf8f7a435cfe8ba69459
- React-domnativemodule: b36a11c2597243d7563985028c51ece988d8ae33
- React-Fabric: afc561718f25b2cd800b709d934101afe376a12c
- React-FabricComponents: f4e0a4e18a27bf6d39cbf2a0b42f37a92fa4e37f
- React-FabricImage: 37d8e8b672eda68a19d71143eb65148084efb325
+ React-defaultsnativemodule: 618dc50a0fad41b489997c3eb7aba3a74479fd14
+ React-domnativemodule: 7ba599afb6c2a7ec3eb6450153e2efe0b8747e9a
+ React-Fabric: 252112089d2c63308f4cbfade4010b6606db67d1
+ React-FabricComponents: 3c0f75321680d14d124438ab279c64ec2a3d13c4
+ React-FabricImage: 728b8061cdec2857ca885fd605ee03ad43ffca98
React-featureflags: 19682e02ef5861d96b992af16a19109c3dfc1200
- React-featureflagsnativemodule: d7cddf6d907b4e5ab84f9e744b7e88461656e48c
- React-graphics: b0f78580cdaf5800d25437e3d41cc6c3d83b7aea
- React-hermes: 71186f872c932e4574d5feb3ed754dda63a0b3bd
- React-idlecallbacksnativemodule: dd2af19cdd3bc55149d17a2409ed72b694dfbe9c
- React-ImageManager: a77dde8d5aa6a2b6962c702bf3a47695ef0aa32b
- React-jserrorhandler: 9c14e89f12d5904257a79aaf84a70cd2e5ac07ba
- React-jsi: 0775a66820496769ad83e629f0f5cce621a57fc7
- React-jsiexecutor: 2cf5ba481386803f3c88b85c63fa102cba5d769e
- React-jsinspector: 8052d532bb7a98b6e021755674659802fb140cc5
- React-jsinspectortracing: bdd8fd0adcb4813663562e7874c5842449df6d8a
- React-jsitracing: 2bab3bf55de3d04baf205def375fa6643c47c794
- React-logger: 795cd5055782db394f187f9db0477d4b25b44291
- React-Mapbuffer: 0502faf46cab8fb89cfc7bf3e6c6109b6ef9b5de
- React-microtasksnativemodule: 663bc64e3a96c5fc91081923ae7481adc1359a78
- react-native-blob-util: fa67658b21ee53bf62a54741a74c441c0e3f2c90
- react-native-document-picker: 5cb1c6615796389f4f1b7fe2e4f103e38e4d6398
- react-native-image-picker: 0452fc9efc21101946746663bf34e0db5741f00c
- react-native-netinfo: f0a9899081c185db1de5bb2fdc1c88c202a059ac
- react-native-safe-area-context: 9c33120e9eac7741a5364cc2d9f74665049b76b3
- react-native-video: c95c10cdac8541f74bd92194dd6a8137ebe6a19d
- React-NativeModulesApple: 16fbd5b040ff6c492dacc361d49e63cba7a6a7a1
- React-perflogger: ab51b7592532a0ea45bf6eed7e6cae14a368b678
- React-performancetimeline: bc2e48198ec814d578ac8401f65d78a574358203
+ React-featureflagsnativemodule: 23528c7e7d50782b7ef0804168ba40bbaf1e86ab
+ React-graphics: fefe48f71bfe6f48fd037f59e8277b12e91b6be1
+ React-hermes: a9a0c8377627b5506ef9a7b6f60a805c306e3f51
+ React-idlecallbacksnativemodule: 7e2b6a3b70e042f89cd91dbd73c479bb39a72a7e
+ React-ImageManager: e3300996ac2e2914bf821f71e2f2c92ae6e62ae2
+ React-jserrorhandler: fa75876c662e5d7e79d6efc763fc9f4c88e26986
+ React-jsi: f3f51595cc4c089037b536368f016d4742bf9cf7
+ React-jsiexecutor: cca6c232db461e2fd213a11e9364cfa6fdaa20eb
+ React-jsinspector: 2bd4c9fddf189d6ec2abf4948461060502582bef
+ React-jsinspectortracing: a417d8a0ad481edaa415734b4dac81e3e5ee7dc6
+ React-jsitracing: 1ff7172c5b0522cbf6c98d82bdbb160e49b5804e
+ React-logger: 018826bfd51b9f18e87f67db1590bc510ad20664
+ React-Mapbuffer: 3c11cee7737609275c7b66bd0b1de475f094cedf
+ React-microtasksnativemodule: 843f352b32aacbe13a9c750190d34df44c3e6c2c
+ react-native-blob-util: f82bbc6f071231ae76e1c03b77290de1781df313
+ react-native-document-picker: 8663632f183816c420ea0c462711d1abc19ac936
+ react-native-image-picker: df2b20cdfa981f7288f4019774d9baa26a4772c1
+ react-native-netinfo: cec9c4e86083cb5b6aba0e0711f563e2fbbff187
+ react-native-safe-area-context: 7e513d737b0b5c1d10bbe0e5fcc9f925a7be144c
+ react-native-video: b0fc63469ac8cab3bae8e0e7368ba940e425f8a4
+ React-NativeModulesApple: 88433b6946778bea9c153e27b671de15411bf225
+ React-perflogger: 9e8d3c0dc0194eb932162812a168aa5dc662f418
+ React-performancetimeline: 5a2d6efef52bdcefac079c7baa30934978acd023
React-RCTActionSheet: 592674cf61142497e0e820688f5a696e41bf16dd
- React-RCTAnimation: 8fbb8dba757b49c78f4db403133ab6399a4ce952
- React-RCTAppDelegate: 7f88baa8cb4e5d6c38bb4d84339925c70c9ac864
- React-RCTBlob: f89b162d0fe6b570a18e755eb16cbe356d3c6d17
- React-RCTFabric: 8ad6d875abe6e87312cef90e4b15ef7f6bed72e6
- React-RCTFBReactNativeSpec: 8c29630c2f379c729300e4c1e540f3d1b78d1936
- React-RCTImage: ccac9969940f170503857733f9a5f63578e106e1
- React-RCTLinking: d82427bbf18415a3732105383dff119131cadd90
- React-RCTNetwork: 12ad4d0fbde939e00251ca5ca890da2e6825cc3c
- React-RCTSettings: e7865bf9f455abf427da349c855f8644b5c39afa
- React-RCTText: 2cdfd88745059ec3202a0842ea75a956c7d6f27d
- React-RCTVibration: a3a1458e6230dfd64b3768ebc0a4aac430d9d508
+ React-RCTAnimation: e6d669872f9b3b4ab9527aab283b7c49283236b7
+ React-RCTAppDelegate: de2343fe08be4c945d57e0ecce44afcc7dd8fc03
+ React-RCTBlob: 3e2dce94c56218becc4b32b627fc2293149f798d
+ React-RCTFabric: cac2c033381d79a5956e08550b0220cb2d78ea93
+ React-RCTFBReactNativeSpec: d10ca5e0ccbfeac8c047361fedf8e4ac653887b6
+ React-RCTImage: dc04b176c022d12a8f55ae7a7279b1e091066ae0
+ React-RCTLinking: 88f5e37fe4f26fbc80791aa2a5f01baf9b9a3fd5
+ React-RCTNetwork: f213693565efbd698b8e9c18d700a514b49c0c8e
+ React-RCTSettings: a2d32a90c45a3575568cad850abc45924999b8a5
+ React-RCTText: 54cdcd1cbf6f6a91dc6317f5d2c2b7fc3f6bf7a0
+ React-RCTVibration: 11dae0e7f577b5807bb7d31e2e881eb46f854fd4
React-rendererconsistency: 64e897e00d2568fd8dfe31e2496f80e85c0aaad1
- React-rendererdebug: a3f6d3ae7d2fa0035885026756281c07ee32479e
+ React-rendererdebug: 41ce452460c44bba715d9e41d5493a96de277764
React-rncore: 58748c2aa445f56b99e5118dad0aedb51c40ce9f
- React-RuntimeApple: f0fda7bacabd32daa099cfda8f07466c30acd149
- React-RuntimeCore: 683ee0b6a76d4b4bf6fbf83a541895b4887cc636
+ React-RuntimeApple: 7785ed0d8ae54da65a88736bb63ca97608a6d933
+ React-RuntimeCore: 6029ea70bc77f98cfd43ebe69217f14e93ba1f12
React-runtimeexecutor: a188df372373baf5066e6e229177836488799f80
- React-RuntimeHermes: 907c8e9bec13ea6466b94828c088c24590d4d0b6
- React-runtimescheduler: a2e2a39125dd6426b5d8b773f689d660cd7c5f60
+ React-RuntimeHermes: a264609c28b796edfffc8ae4cb8fad1773ab948b
+ React-runtimescheduler: 23ec3a1e0fb1ec752d1a9c1fb15258c30bfc7222
React-timing: bb220a53a795ed57976a4855c521f3de2f298fe5
- React-utils: 300d8bbb6555dcffaca71e7a0663201b5c7edbbc
- ReactAppDependencyProvider: f2e81d80afd71a8058589e19d8a134243fa53f17
- ReactCodegen: a63a0ab6ae824aef2e8c744981edd718b16eb9f2
- ReactCommon: 3d39389f8e2a2157d5c999f8fba57bd1c8f226f0
- RNAudioRecorderPlayer: 224c7de87722938aedce04000d09baa633148f5b
- RNCClipboard: 7659a79c651d0e889bbd533dcc8bc8ff1e98ed70
- RNGestureHandler: 9b05fab9a0b48fe48c968de7dbb9ca38a2b4f7ab
- RNReactNativeHapticFeedback: 5fdbbaedabc1698dc3bb2a72105fadf63136a451
- RNReanimated: ff71ce0443c71c8a77501ace7b9738ede83cfa55
- RNScreens: 991214b4e69016c1ae32830d9cea31c9c9422367
- RNShare: 6b1ee93f4fce1346c7c299c3107af20af05120b4
- RNSVG: 8588ee1ca9b2e6fd2c99466e35b3db0e9f81bb40
+ React-utils: 3b054aaebe658fc710a8d239d0e4b9fd3e0b78f9
+ ReactAppDependencyProvider: a1fb08dfdc7ebc387b2e54cfc9decd283ed821d8
+ ReactCodegen: 008c319179d681a6a00966edfc67fda68f9fbb2e
+ ReactCommon: 0c097b53f03d6bf166edbcd0915da32f3015dd90
+ RNAudioRecorderPlayer: 11df0c7b614e9767ef24d896465c3a758c592de7
+ RNCClipboard: f13dd3ceae005858e137ae9e70f3c414e174ff81
+ RNGestureHandler: 8b1080a6db0be82dbca18550d6212b885bfab6b2
+ RNReactNativeHapticFeedback: 66c6b0cf19f5d9dae8be36b2336e1fe2a2e42566
+ RNReanimated: 6383cd0d805e48768b97bd65bcb1d06f0e69ab8e
+ RNScreens: 0d4cb9afe052607ad0aa71f645a88bb7c7f2e64c
+ RNShare: 56b5431c60e1e9ee167191f4f327471af1c2941a
+ RNSVG: 8126581b369adf6a0004b6a6cab1a55e3002d5b0
SocketRocket: d4aabe649be1e368d1318fdf28a022d714d65748
- stream-chat-react-native: 13410c6834ae177a11f198ed51576dae78842e22
+ stream-chat-react-native: f2cbd02c0a9838bb512b223d511267d2df5312bc
Yoga: afd04ff05ebe0121a00c468a8a3c8080221cb14c
PODFILE CHECKSUM: 6b7a4b74915b42bfe4ffddaf67cbf5e7a2bfeab3
-COCOAPODS: 1.14.3
+COCOAPODS: 1.16.2
diff --git a/examples/TypeScriptMessaging/yarn.lock b/examples/TypeScriptMessaging/yarn.lock
index 81b1407854..5a6df6ff33 100644
--- a/examples/TypeScriptMessaging/yarn.lock
+++ b/examples/TypeScriptMessaging/yarn.lock
@@ -6921,10 +6921,10 @@ statuses@~1.5.0:
resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c"
integrity sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==
-stream-chat-react-native-core@6.6.6:
- version "6.6.6"
- resolved "https://registry.yarnpkg.com/stream-chat-react-native-core/-/stream-chat-react-native-core-6.6.6.tgz#d701beb9652f0a5851286f752d8c4fdadb3e0603"
- integrity sha512-sfBtWz4K4OzhFDMRaPF2xMj7aP9FQU4dMN1XCsmRT07hyYn6iEviECxNttYvoRLB1zNdeja5cL63IDY3UZSpAQ==
+stream-chat-react-native-core@6.6.7:
+ version "6.6.7"
+ resolved "https://registry.yarnpkg.com/stream-chat-react-native-core/-/stream-chat-react-native-core-6.6.7.tgz#d887234af18890c3396f1b8b5f169d9b28a793ab"
+ integrity sha512-Xc/S92nUBSwfVPZqNjt/zNs/DJcRV1aRa/+yCSBCqjCwo0EuiWEP9yKy3xGxBkehNe4vaIDvkeREduA4dRUGpA==
dependencies:
"@gorhom/bottom-sheet" "^5.1.1"
dayjs "1.10.5"
@@ -6937,7 +6937,7 @@ stream-chat-react-native-core@6.6.6:
path "0.12.7"
react-native-markdown-package "1.8.2"
react-native-url-polyfill "^1.3.0"
- stream-chat "^8.57.5"
+ stream-chat "^8.57.6"
use-sync-external-store "^1.4.0"
"stream-chat-react-native-core@link:../../package":
@@ -6948,21 +6948,6 @@ stream-chat-react-native-core@6.6.6:
version "0.0.0"
uid ""
-stream-chat@^8.57.5:
- version "8.57.5"
- resolved "https://registry.yarnpkg.com/stream-chat/-/stream-chat-8.57.5.tgz#1b49b7504371e19a539465e2ae5dc86aa3269637"
- integrity sha512-ndcbH/zGzUIAhZLGn1owVV8MeNvVfWITIlhAhfmnsV7RLoo/eiGFEuP4aNoG1YRos/g9xJQ7TEmKpz8xYqo13w==
- dependencies:
- "@babel/runtime" "^7.16.3"
- "@types/jsonwebtoken" "~9.0.0"
- "@types/ws" "^7.4.0"
- axios "^1.6.0"
- base64-js "^1.5.1"
- form-data "^4.0.0"
- isomorphic-ws "^4.0.1"
- jsonwebtoken "~9.0.0"
- ws "^7.5.10"
-
stream-chat@^8.57.6:
version "8.57.6"
resolved "https://registry.yarnpkg.com/stream-chat/-/stream-chat-8.57.6.tgz#dd3a4a0a024ee44bfa6ae7ca15648e6c9f2e498f"
diff --git a/package/expo-package/yarn.lock b/package/expo-package/yarn.lock
index fae918baa2..b022f27bba 100644
--- a/package/expo-package/yarn.lock
+++ b/package/expo-package/yarn.lock
@@ -4733,10 +4733,10 @@ stream-buffers@2.2.x, stream-buffers@~2.2.0:
resolved "https://registry.yarnpkg.com/stream-buffers/-/stream-buffers-2.2.0.tgz#91d5f5130d1cef96dcfa7f726945188741d09ee4"
integrity sha512-uyQK/mx5QjHun80FLJTfaWE7JtwfRMKBLkMne6udYOmvH0CawotVa7TfgYHzAnpphn4+TweIx1QKMnRIbipmUg==
-stream-chat-react-native-core@6.6.6:
- version "6.6.6"
- resolved "https://registry.yarnpkg.com/stream-chat-react-native-core/-/stream-chat-react-native-core-6.6.6.tgz#d701beb9652f0a5851286f752d8c4fdadb3e0603"
- integrity sha512-sfBtWz4K4OzhFDMRaPF2xMj7aP9FQU4dMN1XCsmRT07hyYn6iEviECxNttYvoRLB1zNdeja5cL63IDY3UZSpAQ==
+stream-chat-react-native-core@6.6.7:
+ version "6.6.7"
+ resolved "https://registry.yarnpkg.com/stream-chat-react-native-core/-/stream-chat-react-native-core-6.6.7.tgz#d887234af18890c3396f1b8b5f169d9b28a793ab"
+ integrity sha512-Xc/S92nUBSwfVPZqNjt/zNs/DJcRV1aRa/+yCSBCqjCwo0EuiWEP9yKy3xGxBkehNe4vaIDvkeREduA4dRUGpA==
dependencies:
"@gorhom/bottom-sheet" "^5.1.1"
dayjs "1.10.5"
@@ -4749,13 +4749,13 @@ stream-chat-react-native-core@6.6.6:
path "0.12.7"
react-native-markdown-package "1.8.2"
react-native-url-polyfill "^1.3.0"
- stream-chat "^8.57.5"
+ stream-chat "^8.57.6"
use-sync-external-store "^1.4.0"
-stream-chat@^8.57.5:
- version "8.57.5"
- resolved "https://registry.yarnpkg.com/stream-chat/-/stream-chat-8.57.5.tgz#1b49b7504371e19a539465e2ae5dc86aa3269637"
- integrity sha512-ndcbH/zGzUIAhZLGn1owVV8MeNvVfWITIlhAhfmnsV7RLoo/eiGFEuP4aNoG1YRos/g9xJQ7TEmKpz8xYqo13w==
+stream-chat@^8.57.6:
+ version "8.57.6"
+ resolved "https://registry.yarnpkg.com/stream-chat/-/stream-chat-8.57.6.tgz#dd3a4a0a024ee44bfa6ae7ca15648e6c9f2e498f"
+ integrity sha512-+zkC5DtxvdkEBAv7dCzzO4WWosjaM15EjsH3q4xD1nX/yf2qT6BMhPJguM+CUWxwlFh32X0KR+ARtD0ChPqtnA==
dependencies:
"@babel/runtime" "^7.16.3"
"@types/jsonwebtoken" "~9.0.0"
diff --git a/package/native-package/src/optionalDependencies/pickImage.ts b/package/native-package/src/optionalDependencies/pickImage.ts
index 5ab35fcd76..770319b285 100644
--- a/package/native-package/src/optionalDependencies/pickImage.ts
+++ b/package/native-package/src/optionalDependencies/pickImage.ts
@@ -11,6 +11,7 @@ export const pickImage = ImagePicker
? async () => {
try {
const result = await ImagePicker.launchImageLibrary({
+ assetRepresentationMode: 'current',
mediaType: 'mixed',
});
const canceled = result.didCancel;
diff --git a/package/native-package/yarn.lock b/package/native-package/yarn.lock
index 723b03e359..8e7cbd228d 100644
--- a/package/native-package/yarn.lock
+++ b/package/native-package/yarn.lock
@@ -3409,10 +3409,10 @@ statuses@~1.5.0:
resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c"
integrity sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==
-stream-chat-react-native-core@6.6.6:
- version "6.6.6"
- resolved "https://registry.yarnpkg.com/stream-chat-react-native-core/-/stream-chat-react-native-core-6.6.6.tgz#d701beb9652f0a5851286f752d8c4fdadb3e0603"
- integrity sha512-sfBtWz4K4OzhFDMRaPF2xMj7aP9FQU4dMN1XCsmRT07hyYn6iEviECxNttYvoRLB1zNdeja5cL63IDY3UZSpAQ==
+stream-chat-react-native-core@6.6.7:
+ version "6.6.7"
+ resolved "https://registry.yarnpkg.com/stream-chat-react-native-core/-/stream-chat-react-native-core-6.6.7.tgz#d887234af18890c3396f1b8b5f169d9b28a793ab"
+ integrity sha512-Xc/S92nUBSwfVPZqNjt/zNs/DJcRV1aRa/+yCSBCqjCwo0EuiWEP9yKy3xGxBkehNe4vaIDvkeREduA4dRUGpA==
dependencies:
"@gorhom/bottom-sheet" "^5.1.1"
dayjs "1.10.5"
@@ -3425,13 +3425,13 @@ stream-chat-react-native-core@6.6.6:
path "0.12.7"
react-native-markdown-package "1.8.2"
react-native-url-polyfill "^1.3.0"
- stream-chat "^8.57.5"
+ stream-chat "^8.57.6"
use-sync-external-store "^1.4.0"
-stream-chat@^8.57.5:
- version "8.57.5"
- resolved "https://registry.yarnpkg.com/stream-chat/-/stream-chat-8.57.5.tgz#1b49b7504371e19a539465e2ae5dc86aa3269637"
- integrity sha512-ndcbH/zGzUIAhZLGn1owVV8MeNvVfWITIlhAhfmnsV7RLoo/eiGFEuP4aNoG1YRos/g9xJQ7TEmKpz8xYqo13w==
+stream-chat@^8.57.6:
+ version "8.57.6"
+ resolved "https://registry.yarnpkg.com/stream-chat/-/stream-chat-8.57.6.tgz#dd3a4a0a024ee44bfa6ae7ca15648e6c9f2e498f"
+ integrity sha512-+zkC5DtxvdkEBAv7dCzzO4WWosjaM15EjsH3q4xD1nX/yf2qT6BMhPJguM+CUWxwlFh32X0KR+ARtD0ChPqtnA==
dependencies:
"@babel/runtime" "^7.16.3"
"@types/jsonwebtoken" "~9.0.0"
diff --git a/package/src/components/Avatar/Avatar.tsx b/package/src/components/Avatar/Avatar.tsx
index c97a34622b..96906c61a8 100644
--- a/package/src/components/Avatar/Avatar.tsx
+++ b/package/src/components/Avatar/Avatar.tsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import React, { useCallback, useMemo } from 'react';
import {
Image,
ImageProps,
@@ -83,6 +83,34 @@ export const Avatar = (props: AvatarProps) => {
const { isLoadingImageError, setLoadingImageError } = useLoadingImage();
+ const onError = useCallback(() => {
+ setLoadingImageError(true);
+ }, [setLoadingImageError]);
+
+ const uri = useMemo(() => {
+ let imageUrl;
+ if (
+ !imageProp ||
+ imageProp.includes(randomImageBaseUrl) ||
+ imageProp.includes(randomSvgBaseUrl)
+ ) {
+ if (imageProp?.includes(streamCDN)) {
+ imageUrl = imageProp;
+ } else {
+ imageUrl = `${randomImageBaseUrl}${name ? `?name=${getInitials(name)}&size=${size}` : ''}`;
+ }
+ } else {
+ imageUrl = getResizedImageUrl({
+ height: size,
+ resizableCDNHosts,
+ url: imageProp,
+ width: size,
+ });
+ }
+
+ return imageUrl;
+ }, [imageProp, name, size, resizableCDNHosts]);
+
return (
{
/>
) : (
setLoadingImageError(true)}
+ accessibilityLabel={testID ?? 'Avatar Image'}
+ onError={onError}
source={{
- uri:
- !imageProp ||
- imageProp.includes(randomImageBaseUrl) ||
- imageProp.includes(randomSvgBaseUrl)
- ? imageProp?.includes(streamCDN)
- ? imageProp
- : `${randomImageBaseUrl}${
- name ? `?name=${getInitials(name)}&size=${size}` : ''
- }`
- : getResizedImageUrl({
- height: size,
- resizableCDNHosts,
- url: imageProp,
- width: size,
- }),
+ uri,
}}
style={[
image,
@@ -139,7 +153,7 @@ export const Avatar = (props: AvatarProps) => {
: {},
imageStyle,
]}
- testID={testID || 'avatar-image'}
+ testID={testID ?? 'avatar-image'}
/>
)}
diff --git a/package/src/components/Channel/Channel.tsx b/package/src/components/Channel/Channel.tsx
index 26abaf0893..c52f422f58 100644
--- a/package/src/components/Channel/Channel.tsx
+++ b/package/src/components/Channel/Channel.tsx
@@ -228,7 +228,7 @@ export const reactionData: ReactionData[] = [
* If count of unread messages is less than 4, then no need to scroll to first unread message,
* since first unread message will be in visible frame anyways.
*/
-const scrollToFirstUnreadThreshold = 4;
+const scrollToFirstUnreadThreshold = 0;
const defaultThrottleInterval = 500;
const defaultDebounceInterval = 500;
diff --git a/package/src/components/ChannelList/ChannelList.tsx b/package/src/components/ChannelList/ChannelList.tsx
index 833aebe111..9b52e80a02 100644
--- a/package/src/components/ChannelList/ChannelList.tsx
+++ b/package/src/components/ChannelList/ChannelList.tsx
@@ -10,7 +10,6 @@ import { ChannelListHeaderNetworkDownIndicator } from './ChannelListHeaderNetwor
import { ChannelListLoadingIndicator } from './ChannelListLoadingIndicator';
import { ChannelListMessenger, ChannelListMessengerProps } from './ChannelListMessenger';
import { useChannelUpdated } from './hooks/listeners/useChannelUpdated';
-import { useUserPresence } from './hooks/listeners/useUserPresence';
import { useCreateChannelsContext } from './hooks/useCreateChannelsContext';
import { usePaginatedChannels } from './hooks/usePaginatedChannels';
import { Skeleton as SkeletonDefault } from './Skeleton';
@@ -367,11 +366,6 @@ export const ChannelList = <
setChannels: channelManager.setChannels,
});
- useUserPresence({
- setChannels: channelManager.setChannels,
- setForceUpdate,
- });
-
const channelIdsStr = channels?.reduce((acc, channel) => `${acc}${channel.cid}`, '');
useEffect(() => {
diff --git a/package/src/components/ChannelList/__tests__/ChannelList.test.js b/package/src/components/ChannelList/__tests__/ChannelList.test.js
index 520f4aaa8e..06dbbd958c 100644
--- a/package/src/components/ChannelList/__tests__/ChannelList.test.js
+++ b/package/src/components/ChannelList/__tests__/ChannelList.test.js
@@ -25,8 +25,6 @@ import dispatchMessageNewEvent from '../../../mock-builders/event/messageNew';
import dispatchNotificationAddedToChannelEvent from '../../../mock-builders/event/notificationAddedToChannel';
import dispatchNotificationMessageNewEvent from '../../../mock-builders/event/notificationMessageNew';
import dispatchNotificationRemovedFromChannel from '../../../mock-builders/event/notificationRemovedFromChannel';
-import dispatchUserPresenceEvent from '../../../mock-builders/event/userPresence';
-import dispatchUserUpdatedEvent from '../../../mock-builders/event/userUpdated';
import { generateChannel, generateChannelResponse } from '../../../mock-builders/generator/channel';
import { generateMessage } from '../../../mock-builders/generator/message';
import { generateUser } from '../../../mock-builders/generator/user';
@@ -691,65 +689,5 @@ describe('ChannelList', () => {
});
});
});
-
- describe('user.updated', () => {
- it('should call handleEvent in the custom hook if the user updates', async () => {
- useMockedApis(chatClient, [queryChannelsApi([testChannel1])]);
- const updateSpy = jest.spyOn(chatClient, 'on');
- const offlineUser = generateUser();
-
- render(
-
-
- ,
- );
-
- await waitFor(() => {
- expect(screen.getByTestId('channel-list')).toBeTruthy();
- });
-
- act(() =>
- dispatchUserUpdatedEvent(
- chatClient,
- { ...offlineUser, name: 'dan' },
- testChannel1.channel,
- ),
- );
-
- await waitFor(() => {
- expect(updateSpy).toHaveBeenCalledWith('user.updated', expect.any(Function));
- });
- });
- });
-
- describe('user.presence.changed', () => {
- it('should call handleEvent in the custom hook if user presence changes', async () => {
- useMockedApis(chatClient, [queryChannelsApi([testChannel1])]);
- const updateSpy = jest.spyOn(chatClient, 'on');
- const offlineUser = generateUser();
-
- render(
-
-
- ,
- );
-
- await waitFor(() => {
- expect(screen.getByTestId('channel-list')).toBeTruthy();
- });
-
- act(() =>
- dispatchUserPresenceEvent(
- chatClient,
- { ...offlineUser, online: true },
- testChannel1.channel,
- ),
- );
-
- await waitFor(() => {
- expect(updateSpy).toHaveBeenCalledWith('user.presence.changed', expect.any(Function));
- });
- });
- });
});
});
diff --git a/package/src/components/ChannelList/hooks/listeners/useUserPresence.ts b/package/src/components/ChannelList/hooks/listeners/useUserPresence.ts
index 4bf878b7b7..d44c6bf022 100644
--- a/package/src/components/ChannelList/hooks/listeners/useUserPresence.ts
+++ b/package/src/components/ChannelList/hooks/listeners/useUserPresence.ts
@@ -12,6 +12,10 @@ type Parameters>;
};
+/**
+ * Hook to update the channel members when the user presence changes
+ * @deprecated this hook will be removed in favour of the useChannelPreviewDisplayPresence to improve performance
+ */
export const useUserPresence = <
StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics,
>({
diff --git a/package/src/components/ChannelList/hooks/useChannelMembershipState.ts b/package/src/components/ChannelList/hooks/useChannelMembershipState.ts
index 6e285862be..b95b646a02 100644
--- a/package/src/components/ChannelList/hooks/useChannelMembershipState.ts
+++ b/package/src/components/ChannelList/hooks/useChannelMembershipState.ts
@@ -1,6 +1,6 @@
import { Channel, ChannelMemberResponse, EventTypes } from 'stream-chat';
-import { useSelectedChannelState } from './useSelectedChannelState';
+import { useSelectedChannelState } from '../../../hooks/useSelectedChannelState';
import { DefaultStreamChatGenerics } from '../../../types/types';
diff --git a/package/src/components/ChannelList/hooks/usePaginatedChannels.ts b/package/src/components/ChannelList/hooks/usePaginatedChannels.ts
index 4211e7b046..30213cace5 100644
--- a/package/src/components/ChannelList/hooks/usePaginatedChannels.ts
+++ b/package/src/components/ChannelList/hooks/usePaginatedChannels.ts
@@ -66,7 +66,7 @@ export const usePaginatedChannels = <
}: Parameters) => {
const [error, setError] = useState(undefined);
const [staticChannelsActive, setStaticChannelsActive] = useState(false);
- const activeQueryType = useRef('queryLocalDB');
+ const [activeQueryType, setActiveQueryType] = useState('queryLocalDB');
const activeChannels = useActiveChannelsRefContext();
const isMountedRef = useIsMountedRef();
const { client } = useChatContext();
@@ -114,7 +114,7 @@ export const usePaginatedChannels = <
setError(undefined);
activeRequestId.current++;
const currentRequestId = activeRequestId.current;
- activeQueryType.current = queryType;
+ setActiveQueryType(queryType);
const newOptions = {
limit: options?.limit ?? MAX_QUERY_CHANNELS_LIMIT,
@@ -152,7 +152,7 @@ export const usePaginatedChannels = <
// querying.current check is needed in order to make sure the next query call doesnt flick an error
// state and then succeed (reconnect case)
if (retryCount === MAX_NUMBER_OF_RETRIES && !isQueryingRef.current) {
- activeQueryType.current = null;
+ setActiveQueryType(null);
console.warn(err);
setError(
@@ -166,7 +166,7 @@ export const usePaginatedChannels = <
return queryChannels(queryType, retryCount + 1);
}
- activeQueryType.current = null;
+ setActiveQueryType(null);
};
const refreshList = async () => {
@@ -229,7 +229,7 @@ export const usePaginatedChannels = <
return false;
}
- activeQueryType.current = null;
+ setActiveQueryType(null);
return true;
};
@@ -279,7 +279,7 @@ export const usePaginatedChannels = <
error,
hasNextPage,
loadingChannels:
- activeQueryType.current === 'queryLocalDB'
+ activeQueryType === 'queryLocalDB'
? true
: // Although channels.length === 0 should come as a given when we have !channelListInitialized,
// due to the way offline storage works currently we have to do this additional
@@ -290,7 +290,7 @@ export const usePaginatedChannels = <
pagination?.isLoading || (!channelListInitialized && channels.length === 0),
loadingNextPage: pagination?.isLoadingNext,
loadNextPage: channelManager.loadNext,
- refreshing: activeQueryType.current === 'refresh',
+ refreshing: activeQueryType === 'refresh',
refreshList,
reloadList,
staticChannelsActive,
diff --git a/package/src/components/ChannelPreview/hooks/__tests__/useChannelPreviewDisplayPresence.test.tsx b/package/src/components/ChannelPreview/hooks/__tests__/useChannelPreviewDisplayPresence.test.tsx
new file mode 100644
index 0000000000..f09e1b09a6
--- /dev/null
+++ b/package/src/components/ChannelPreview/hooks/__tests__/useChannelPreviewDisplayPresence.test.tsx
@@ -0,0 +1,108 @@
+import { renderHook } from '@testing-library/react-native';
+import type { Channel, StreamChat, UserResponse } from 'stream-chat';
+
+import type { ChatContextValue } from '../../../../contexts/chatContext/ChatContext';
+import * as ChatContext from '../../../../contexts/chatContext/ChatContext';
+import { getTestClientWithUser } from '../../../../mock-builders/mock';
+import { DefaultStreamChatGenerics } from '../../../../types/types';
+import { useChannelPreviewDisplayPresence } from '../useChannelPreviewDisplayPresence';
+
+describe('useChannelPreviewDisplayPresence', () => {
+ // Mock user data
+ const currentUserId = 'current-user';
+ const otherUserId = 'other-user';
+ let chatClient: StreamChat;
+
+ let mockChannel: Channel;
+
+ beforeEach(async () => {
+ jest.clearAllMocks();
+ chatClient = await getTestClientWithUser({
+ id: currentUserId,
+ userID: currentUserId,
+ });
+
+ // Create mock channel
+ mockChannel = {
+ state: {
+ members: {
+ [currentUserId]: {
+ user: { id: currentUserId, online: true } as UserResponse,
+ },
+ [otherUserId]: {
+ user: { id: otherUserId, online: false } as UserResponse,
+ },
+ },
+ },
+ } as unknown as Channel;
+
+ // Mock the useChatContext hook
+ jest
+ .spyOn(ChatContext, 'useChatContext')
+ .mockImplementation(() => ({ client: chatClient }) as unknown as ChatContextValue);
+ });
+
+ afterEach(() => {
+ jest.clearAllMocks();
+ });
+
+ it('should return false for channels with more than 2 members', () => {
+ // Create a channel with 3 members
+ const thirdUserId = 'third-user';
+ const channelWithThreeMembers = {
+ state: {
+ members: {
+ [currentUserId]: {
+ user: { id: currentUserId } as UserResponse,
+ },
+ [otherUserId]: {
+ user: { id: otherUserId } as UserResponse,
+ },
+ [thirdUserId]: {
+ user: { id: thirdUserId } as UserResponse,
+ },
+ },
+ },
+ } as unknown as Channel;
+
+ const { result } = renderHook(() => useChannelPreviewDisplayPresence(channelWithThreeMembers));
+ expect(result.current).toBe(false);
+ });
+
+ it('should return false when the other user is offline', () => {
+ const { result } = renderHook(() => useChannelPreviewDisplayPresence(mockChannel));
+ expect(result.current).toBe(false);
+ });
+
+ it('should return true when the other user is online', () => {
+ // Update the other user to be online
+ const onlineUser = {
+ ...mockChannel.state.members[otherUserId].user,
+ online: true,
+ } as UserResponse;
+
+ mockChannel.state.members[otherUserId].user = onlineUser;
+
+ const { result } = renderHook(() => useChannelPreviewDisplayPresence(mockChannel));
+ expect(result.current).toBe(true);
+ });
+
+ it('should handle null user gracefully', () => {
+ // Create a channel with a member that has no user
+ const channelWithNullUser = {
+ state: {
+ members: {
+ [currentUserId]: {
+ user: { id: currentUserId } as UserResponse,
+ },
+ 'null-user': {
+ user: null,
+ },
+ },
+ },
+ } as unknown as Channel;
+
+ const { result } = renderHook(() => useChannelPreviewDisplayPresence(channelWithNullUser));
+ expect(result.current).toBe(false);
+ });
+});
diff --git a/package/src/components/ChannelPreview/hooks/useChannelPreviewDisplayAvatar.ts b/package/src/components/ChannelPreview/hooks/useChannelPreviewDisplayAvatar.ts
index 54f6856784..5ce86a726b 100644
--- a/package/src/components/ChannelPreview/hooks/useChannelPreviewDisplayAvatar.ts
+++ b/package/src/components/ChannelPreview/hooks/useChannelPreviewDisplayAvatar.ts
@@ -1,4 +1,4 @@
-import { useEffect, useState } from 'react';
+import { useMemo } from 'react';
import type { Channel, StreamChat } from 'stream-chat';
@@ -61,19 +61,10 @@ export const useChannelPreviewDisplayAvatar = <
) => {
const { client } = useChatContext();
- const channelData = channel?.data;
- const image = channelData?.image;
- const name = channelData?.name;
- const id = client?.user?.id;
-
- const [displayAvatar, setDisplayAvatar] = useState(
- getChannelPreviewDisplayAvatar(channel, client),
+ const displayAvatar = useMemo(
+ () => getChannelPreviewDisplayAvatar(channel, client),
+ [channel, client],
);
- useEffect(() => {
- setDisplayAvatar(getChannelPreviewDisplayAvatar(channel, client));
- // eslint-disable-next-line react-hooks/exhaustive-deps
- }, [id, image, name]);
-
return displayAvatar;
};
diff --git a/package/src/components/ChannelPreview/hooks/useChannelPreviewDisplayName.ts b/package/src/components/ChannelPreview/hooks/useChannelPreviewDisplayName.ts
index 9a1d5e04c5..93ef4cf267 100644
--- a/package/src/components/ChannelPreview/hooks/useChannelPreviewDisplayName.ts
+++ b/package/src/components/ChannelPreview/hooks/useChannelPreviewDisplayName.ts
@@ -1,4 +1,4 @@
-import { useEffect, useState } from 'react';
+import { useMemo } from 'react';
import type { Channel, ChannelMemberResponse } from 'stream-chat';
@@ -26,7 +26,9 @@ export const getChannelPreviewDisplayName = <
members?: Channel['state']['members'];
}): string => {
if (channelName) {
- return channelName;
+ return channelName.length > characterLimit
+ ? `${channelName.slice(0, characterLimit - ELLIPSIS.length)}${ELLIPSIS}`
+ : channelName;
}
const channelMembers = Object.values(members || {});
@@ -83,33 +85,25 @@ export const useChannelPreviewDisplayName = <
const { client } = useChatContext();
const { vw } = useViewport();
- const DEFAULT_MAX_CHARACTER_LENGTH = (vw(100) - 16) / 6;
+ const DEFAULT_MAX_CHARACTER_LENGTH = Math.floor((vw(100) - 16) / 6);
const currentUserId = client?.userID;
const members = channel?.state?.members;
- const numOfMembers = Object.keys(members || {}).length;
const channelName = channel?.data?.name;
const characterLimit = characterLength || DEFAULT_MAX_CHARACTER_LENGTH;
- const [displayName, setDisplayName] = useState(
- getChannelPreviewDisplayName({
- channelName,
- characterLimit,
- currentUserId,
- members,
- }),
- );
+ const numOfMembers = Object.keys(members || {}).length;
- useEffect(() => {
- setDisplayName(
+ const displayName = useMemo(
+ () =>
getChannelPreviewDisplayName({
channelName,
characterLimit,
currentUserId,
members,
}),
- );
// eslint-disable-next-line react-hooks/exhaustive-deps
- }, [channelName, currentUserId, characterLimit, numOfMembers]);
+ [channelName, characterLimit, currentUserId, members, numOfMembers],
+ );
return displayName;
};
diff --git a/package/src/components/ChannelPreview/hooks/useChannelPreviewDisplayPresence.ts b/package/src/components/ChannelPreview/hooks/useChannelPreviewDisplayPresence.ts
index f76a82f191..2356d6eac6 100644
--- a/package/src/components/ChannelPreview/hooks/useChannelPreviewDisplayPresence.ts
+++ b/package/src/components/ChannelPreview/hooks/useChannelPreviewDisplayPresence.ts
@@ -1,54 +1,41 @@
-import { useEffect, useState } from 'react';
-
-import type { Channel, StreamChat } from 'stream-chat';
+import type { Channel, EventTypes, StreamChat } from 'stream-chat';
import { useChatContext } from '../../../contexts/chatContext/ChatContext';
+import { useSyncClientEventsToChannel } from '../../../hooks/useSyncClientEvents';
import type { DefaultStreamChatGenerics } from '../../../types/types';
-const getChannelPreviewDisplayPresence = <
- StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics,
->(
+/**
+ * Selector to get the display avatar presence for channel preview
+ * @param channel
+ * @param client
+ * @returns boolean
+ *
+ * NOTE: If you want to listen to the value changes where you call the hook, the selector should return primitive values instead of object.
+ */
+const selector = (
channel: Channel,
client: StreamChat,
) => {
- const currentUserId = client.userID;
+ const members = channel.state.members;
+ const membersCount = Object.keys(members).length;
+ const otherMember = Object.values(members).find((member) => member.user?.id !== client.userID);
- if (currentUserId) {
- const members = Object.values(channel.state.members);
- const otherMembers = members.filter((member) => member.user?.id !== currentUserId);
-
- if (otherMembers.length === 1) {
- return !!otherMembers[0].user?.online;
- }
- }
- return false;
+ if (membersCount !== 2) return false;
+ return otherMember?.user?.online ?? false;
};
+const keys: EventTypes[] = ['user.presence.changed', 'user.updated'];
+
/**
* Hook to set the display avatar presence for channel preview
* @param {*} channel
*
* @returns {boolean} e.g., true
*/
-export const useChannelPreviewDisplayPresence = <
- StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics,
->(
- channel: Channel,
-) => {
+export function useChannelPreviewDisplayPresence<
+ StreamChatGenerics extends DefaultStreamChatGenerics,
+>(channel: Channel) {
const { client } = useChatContext();
-
- const currentUserId = client.userID;
- const members = Object.values(channel.state.members).filter(
- (member) => !!member.user?.id && !!currentUserId && member.user?.id !== currentUserId,
- );
- const channelMemberOnline = members.some((member) => member.user?.online);
-
- const [displayPresence, setDisplayPresence] = useState(false);
-
- useEffect(() => {
- setDisplayPresence(getChannelPreviewDisplayPresence(channel, client));
- }, [channel, channelMemberOnline, client]);
-
- return displayPresence;
-};
+ return useSyncClientEventsToChannel({ channel, client, selector, stateChangeEventKeys: keys });
+}
diff --git a/package/src/components/ChannelPreview/hooks/useIsChannelMuted.ts b/package/src/components/ChannelPreview/hooks/useIsChannelMuted.ts
index 02d83f79d7..04ddbf6644 100644
--- a/package/src/components/ChannelPreview/hooks/useIsChannelMuted.ts
+++ b/package/src/components/ChannelPreview/hooks/useIsChannelMuted.ts
@@ -6,6 +6,12 @@ import { useChatContext } from '../../../contexts/chatContext/ChatContext';
import type { DefaultStreamChatGenerics } from '../../../types/types';
+const defaultMuteStatus = {
+ createdAt: null,
+ expiresAt: null,
+ muted: false,
+};
+
export const useIsChannelMuted = <
StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics,
>(
@@ -24,5 +30,5 @@ export const useIsChannelMuted = <
return () => client.off('notification.channel_mutes_updated', handleEvent);
}, [channel, client, muted]);
- return muted || { createdAt: null, expiresAt: null, muted: false };
+ return muted ?? defaultMuteStatus;
};
diff --git a/package/src/components/ChannelPreview/hooks/useLatestMessagePreview.ts b/package/src/components/ChannelPreview/hooks/useLatestMessagePreview.ts
index 5886fccab1..ac2efc7329 100644
--- a/package/src/components/ChannelPreview/hooks/useLatestMessagePreview.ts
+++ b/package/src/components/ChannelPreview/hooks/useLatestMessagePreview.ts
@@ -1,4 +1,4 @@
-import { useEffect, useState } from 'react';
+import { useMemo } from 'react';
import { TFunction } from 'i18next';
import type {
@@ -285,63 +285,44 @@ export const useLatestMessagePreview = <
? stringifyMessage(translatedLastMessage)
: '';
- const [readEvents, setReadEvents] = useState(true);
- const [latestMessagePreview, setLatestMessagePreview] = useState<
- LatestMessagePreview
- >({
- created_at: '',
- messageObject: undefined,
- previews: [
- {
- bold: false,
- text: '',
- },
- ],
- status: MessageReadStatus.NOT_SENT_BY_CURRENT_USER,
- });
+ const readEvents = useMemo(() => {
+ if (!channelConfigExists) {
+ return true;
+ }
+ const read_events = !channel.disconnected && !!channel?.id && channel.getConfig()?.read_events;
+ if (typeof read_events !== 'boolean') {
+ return true;
+ }
+ return read_events;
+ }, [channelConfigExists, channel]);
const readStatus = getLatestMessageReadStatus(channel, client, translatedLastMessage, readEvents);
- useEffect(() => {
- if (channelConfigExists) {
- const read_events =
- !channel.disconnected && !!channel?.id && channel.getConfig()?.read_events;
- if (typeof read_events === 'boolean') {
- setReadEvents(read_events);
- }
- }
- // eslint-disable-next-line react-hooks/exhaustive-deps
- }, [channelConfigExists]);
-
const pollId = lastMessage?.poll_id ?? '';
const poll = client.polls.fromState(pollId);
const pollState: LatestMessagePreviewSelectorReturnType =
useStateStore(poll?.state, selector) ?? {};
const { createdBy, latestVotesByOption, name } = pollState;
- useEffect(
- () =>
- setLatestMessagePreview(
- getLatestMessagePreview({
- channel,
- client,
- lastMessage: translatedLastMessage,
- pollState,
- readEvents,
- t,
- }),
- ),
- // eslint-disable-next-line react-hooks/exhaustive-deps
- [
- channelLastMessageString,
- forceUpdate,
+ const latestMessagePreview = useMemo(() => {
+ return getLatestMessagePreview({
+ channel,
+ client,
+ lastMessage: translatedLastMessage,
+ pollState,
readEvents,
- readStatus,
- latestVotesByOption,
- createdBy,
- name,
- ],
- );
+ t,
+ });
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [
+ channelLastMessageString,
+ forceUpdate,
+ readEvents,
+ readStatus,
+ latestVotesByOption,
+ createdBy,
+ name,
+ ]);
return latestMessagePreview;
};
diff --git a/package/src/components/Message/MessageSimple/MessageContent.tsx b/package/src/components/Message/MessageSimple/MessageContent.tsx
index 718e8bb91a..954edc973b 100644
--- a/package/src/components/Message/MessageSimple/MessageContent.tsx
+++ b/package/src/components/Message/MessageSimple/MessageContent.tsx
@@ -88,6 +88,7 @@ export type MessageContentPropsWithContext<
MessagesContextValue,
| 'additionalPressableProps'
| 'Attachment'
+ | 'enableMessageGroupingByUser'
| 'FileAttachmentGroup'
| 'Gallery'
| 'isAttachmentEqual'
@@ -102,10 +103,18 @@ export type MessageContentPropsWithContext<
* Background color for the message content
*/
backgroundColor?: ColorValue;
+ /**
+ * If the message is the very last message in the message list
+ */
+ isVeryLastMessage?: boolean;
/**
* If the message has no border radius
*/
noBorder?: boolean;
+ /**
+ * If the message is grouped in a single or bottom container
+ */
+ messageGroupedSingleOrBottom?: boolean;
};
/**
@@ -121,13 +130,16 @@ const MessageContentWithContext = <
alignment,
Attachment,
backgroundColor,
+ enableMessageGroupingByUser,
FileAttachmentGroup,
Gallery,
groupStyles,
isMessageAIGenerated,
isMyMessage,
+ isVeryLastMessage,
message,
messageContentOrder,
+ messageGroupedSingleOrBottom = false,
MessageError,
noBorder,
onLongPress,
@@ -159,6 +171,9 @@ const MessageContentWithContext = <
...container
},
containerInner,
+ lastMessageContainer,
+ messageGroupedSingleOrBottomContainer,
+ messageGroupedTopContainer,
replyBorder,
replyContainer,
wrapper,
@@ -283,6 +298,11 @@ const MessageContentWithContext = <
},
noBorder ? { borderWidth: 0 } : {},
containerInner,
+ messageGroupedSingleOrBottom
+ ? isVeryLastMessage && enableMessageGroupingByUser
+ ? lastMessageContainer
+ : messageGroupedSingleOrBottomContainer
+ : messageGroupedTopContainer,
]}
testID='message-content-wrapper'
>
@@ -520,6 +540,7 @@ export const MessageContent = <
const {
additionalPressableProps,
Attachment,
+ enableMessageGroupingByUser,
FileAttachmentGroup,
Gallery,
isAttachmentEqual,
@@ -536,6 +557,7 @@ export const MessageContent = <
additionalPressableProps,
alignment,
Attachment,
+ enableMessageGroupingByUser,
FileAttachmentGroup,
Gallery,
goToMessage,
diff --git a/package/src/components/Message/MessageSimple/MessageSimple.tsx b/package/src/components/Message/MessageSimple/MessageSimple.tsx
index 0c883c77fe..35aeedcd92 100644
--- a/package/src/components/Message/MessageSimple/MessageSimple.tsx
+++ b/package/src/components/Message/MessageSimple/MessageSimple.tsx
@@ -278,6 +278,8 @@ const MessageSimpleWithContext = <
@@ -293,6 +295,8 @@ const MessageSimpleWithContext = <
ReactionListTop,
backgroundColor,
contentWrapper,
+ isVeryLastMessage,
+ messageGroupedSingleOrBottom,
noBorder,
],
);
diff --git a/package/src/components/Thread/__tests__/__snapshots__/Thread.test.js.snap b/package/src/components/Thread/__tests__/__snapshots__/Thread.test.js.snap
index 3cb5780a2e..b05aa25bed 100644
--- a/package/src/components/Thread/__tests__/__snapshots__/Thread.test.js.snap
+++ b/package/src/components/Thread/__tests__/__snapshots__/Thread.test.js.snap
@@ -602,6 +602,7 @@ exports[`Thread should match thread snapshot 1`] = `
},
{},
{},
+ {},
]
}
testID="message-content-wrapper"
@@ -1112,6 +1113,7 @@ exports[`Thread should match thread snapshot 1`] = `
},
{},
{},
+ {},
]
}
testID="message-content-wrapper"
@@ -1660,6 +1662,7 @@ exports[`Thread should match thread snapshot 1`] = `
},
{},
{},
+ {},
]
}
testID="message-content-wrapper"
@@ -2163,6 +2166,7 @@ exports[`Thread should match thread snapshot 1`] = `
},
{},
{},
+ {},
]
}
testID="message-content-wrapper"
diff --git a/package/src/contexts/themeContext/utils/theme.ts b/package/src/contexts/themeContext/utils/theme.ts
index 9139531cdf..3357bdbba8 100644
--- a/package/src/contexts/themeContext/utils/theme.ts
+++ b/package/src/contexts/themeContext/utils/theme.ts
@@ -539,11 +539,14 @@ export type Theme = {
errorIcon: IconProps;
errorIconContainer: ViewStyle;
eyeIcon: IconProps;
+ lastMessageContainer: ViewStyle;
/**
* Available options for styling text:
* https://github.com/andangrd/react-native-markdown-package/blob/main/styles.js
*/
markdown: MarkdownStyle;
+ messageGroupedSingleOrBottomContainer: ViewStyle;
+ messageGroupedTopContainer: ViewStyle;
messageUser: TextStyle;
metaContainer: ViewStyle;
metaText: TextStyle;
@@ -1325,7 +1328,10 @@ export const defaultTheme: Theme = {
height: 16,
width: 16,
},
+ lastMessageContainer: {},
markdown: {},
+ messageGroupedSingleOrBottomContainer: {},
+ messageGroupedTopContainer: {},
messageUser: {
fontSize: 12,
fontWeight: '700',
diff --git a/package/src/components/ChannelList/hooks/useSelectedChannelState.ts b/package/src/hooks/useSelectedChannelState.ts
similarity index 96%
rename from package/src/components/ChannelList/hooks/useSelectedChannelState.ts
rename to package/src/hooks/useSelectedChannelState.ts
index d4cbfa3aee..2c7b5c2e03 100644
--- a/package/src/components/ChannelList/hooks/useSelectedChannelState.ts
+++ b/package/src/hooks/useSelectedChannelState.ts
@@ -3,7 +3,7 @@ import { useCallback } from 'react';
import type { Channel, EventTypes } from 'stream-chat';
import { useSyncExternalStore } from 'use-sync-external-store/shim';
-import { DefaultStreamChatGenerics } from '../../../types/types';
+import { DefaultStreamChatGenerics } from '../types/types';
const noop = () => {};
diff --git a/package/src/hooks/useSyncClientEvents.ts b/package/src/hooks/useSyncClientEvents.ts
new file mode 100644
index 0000000000..82d66207c3
--- /dev/null
+++ b/package/src/hooks/useSyncClientEvents.ts
@@ -0,0 +1,69 @@
+import { useCallback } from 'react';
+
+import type { Channel, EventTypes, StreamChat } from 'stream-chat';
+import { useSyncExternalStore } from 'use-sync-external-store/shim';
+
+import { DefaultStreamChatGenerics } from '../types/types';
+
+const noop = () => {};
+
+export function useSyncClientEventsToChannel<
+ StreamChatGenerics extends DefaultStreamChatGenerics,
+ O,
+>(_: {
+ channel: Channel;
+ client: StreamChat;
+ selector: (channel: Channel, client: StreamChat) => O;
+ stateChangeEventKeys?: EventTypes[];
+}): O;
+export function useSyncClientEventsToChannel<
+ StreamChatGenerics extends DefaultStreamChatGenerics,
+ O,
+>(_: {
+ selector: (channel: Channel, client: StreamChat) => O;
+ channel?: Channel | undefined;
+ client?: StreamChat | undefined;
+ stateChangeEventKeys?: EventTypes[];
+}): O | undefined;
+export function useSyncClientEventsToChannel<
+ StreamChatGenerics extends DefaultStreamChatGenerics,
+ O,
+>({
+ channel,
+ client,
+ selector,
+ stateChangeEventKeys = ['all'],
+}: {
+ selector: (channel: Channel, client: StreamChat) => O;
+ channel?: Channel | undefined;
+ client?: StreamChat;
+ stateChangeEventKeys?: EventTypes[];
+}): O | undefined {
+ const subscribe = useCallback(
+ (onStoreChange: (value: O) => void) => {
+ if (!client || !channel) {
+ return noop;
+ }
+
+ const subscriptions = stateChangeEventKeys.map((et) =>
+ client.on(et, () => {
+ onStoreChange(selector(channel, client));
+ }),
+ );
+
+ return () => subscriptions.forEach((subscription) => subscription.unsubscribe());
+ },
+ [channel, client, selector, stateChangeEventKeys],
+ );
+
+ const getSnapshot = useCallback(() => {
+ if (!client || !channel) {
+ return undefined;
+ }
+
+ const originalSnapshot = selector(channel, client);
+ return originalSnapshot;
+ }, [channel, client, selector]);
+
+ return useSyncExternalStore(subscribe, getSnapshot);
+}
diff --git a/package/src/hooks/useTranslatedMessage.ts b/package/src/hooks/useTranslatedMessage.ts
index f8b2c814e6..98df5520e7 100644
--- a/package/src/hooks/useTranslatedMessage.ts
+++ b/package/src/hooks/useTranslatedMessage.ts
@@ -10,9 +10,7 @@ export const useTranslatedMessage = <
>(
message?: MessageResponse | FormatMessageResponse,
) => {
- const { userLanguage: translationContextUserLanguage } = useTranslationContext();
-
- const userLanguage = translationContextUserLanguage;
+ const { userLanguage } = useTranslationContext();
const translationKey: TranslationKey = `${userLanguage}_text`;
diff --git a/package/src/store/apis/queries/selectMessagesForChannels.ts b/package/src/store/apis/queries/selectMessagesForChannels.ts
index 2239401bd2..c020ec2376 100644
--- a/package/src/store/apis/queries/selectMessagesForChannels.ts
+++ b/package/src/store/apis/queries/selectMessagesForChannels.ts
@@ -30,7 +30,7 @@ export const selectMessagesForChannels = async (
*,
ROW_NUMBER() OVER (
PARTITION BY cid
- ORDER BY cast(strftime('%s', createdAt) AS INTEGER) ASC
+ ORDER BY cast(strftime('%s', createdAt) AS INTEGER) DESC
) RowNum
FROM messages
WHERE cid in (${questionMarks})
@@ -38,7 +38,8 @@ export const selectMessagesForChannels = async (
LEFT JOIN
users b
ON b.id = a.userId
- WHERE RowNum < 200`,
+ WHERE RowNum < 200
+ ORDER BY cast(strftime('%s', a.createdAt) AS INTEGER) ASC`,
cids,
);