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 @@ [![NPM](https://img.shields.io/npm/v/stream-chat-react-native.svg)](https://www.npmjs.com/package/stream-chat-react-native) [![Build Status](https://github.com/GetStream/stream-chat-react-native/actions/workflows/release.yml/badge.svg)](https://github.com/GetStream/stream-chat-react-native/actions) [![Component Reference](https://img.shields.io/badge/docs-component%20reference-blue.svg)](https://getstream.io/chat/docs/sdk/reactnative) -![JS Bundle Size](https://img.shields.io/badge/js_bundle_size-468%20KB-blue) +![JS Bundle Size](https://img.shields.io/badge/js_bundle_size-466%20KB-blue) 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, );