diff --git a/README.md b/README.md
index 021859f161..1c923daf95 100644
--- a/README.md
+++ b/README.md
@@ -11,7 +11,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-439%20KB-blue)
+![JS Bundle Size](https://img.shields.io/badge/js_bundle_size-438.6728515625%20KB-blue)
diff --git a/examples/SampleApp/.bundle/config b/examples/SampleApp/.bundle/config
index d137d242ed..4c9a330d7b 100644
--- a/examples/SampleApp/.bundle/config
+++ b/examples/SampleApp/.bundle/config
@@ -1,2 +1,4 @@
-BUNDLE_PATH: "vendor/bundle"
-BUNDLE_FORCE_RUBY_PLATFORM: 1
\ No newline at end of file
+---
+BUNDLE_PATH: "/home/runner/work/stream-chat-react-native/stream-chat-react-native/examples/SampleApp/vendor/bundle"
+BUNDLE_FORCE_RUBY_PLATFORM: "1"
+BUNDLE_DEPLOYMENT: "true"
diff --git a/examples/SampleApp/Gemfile.lock b/examples/SampleApp/Gemfile.lock
index c399cce1de..ab10e3d6d2 100644
--- a/examples/SampleApp/Gemfile.lock
+++ b/examples/SampleApp/Gemfile.lock
@@ -163,7 +163,7 @@ GEM
google-apis-firebaseappdistribution_v1 (~> 0.3.0)
google-apis-firebaseappdistribution_v1alpha (~> 0.2.0)
fastlane-plugin-load_json (0.0.1)
- fastlane-plugin-stream_actions (0.3.65)
+ fastlane-plugin-stream_actions (0.3.67)
xctest_list (= 1.2.1)
ffi (1.17.0)
fourflusher (2.3.1)
@@ -320,7 +320,7 @@ DEPENDENCIES
fastlane
fastlane-plugin-firebase_app_distribution
fastlane-plugin-load_json
- fastlane-plugin-stream_actions (= 0.3.65)
+ fastlane-plugin-stream_actions (= 0.3.67)
rubocop-performance
rubocop-require_tools
diff --git a/examples/SampleApp/fastlane/Fastfile b/examples/SampleApp/fastlane/Fastfile
index 6e2b2169f6..b1d7416d0a 100644
--- a/examples/SampleApp/fastlane/Fastfile
+++ b/examples/SampleApp/fastlane/Fastfile
@@ -133,6 +133,7 @@ lane :update_img_shields_sdk_sizes do |options|
update_sdk_size_in_readme(
readme_path: '../../README.md',
open_pr: options[:open_pr] || false,
+ pr_title: 'chore: update sdk size',
sizes: options[:sizes] || frameworks_sizes,
size_ext: sdk_size_ext
)
diff --git a/examples/SampleApp/fastlane/Pluginfile b/examples/SampleApp/fastlane/Pluginfile
index 96f8283318..f2703d5b51 100644
--- a/examples/SampleApp/fastlane/Pluginfile
+++ b/examples/SampleApp/fastlane/Pluginfile
@@ -4,4 +4,4 @@
gem 'fastlane-plugin-firebase_app_distribution'
gem 'fastlane-plugin-load_json'
-gem 'fastlane-plugin-stream_actions', '0.3.65'
+gem 'fastlane-plugin-stream_actions', '0.3.67'
diff --git a/package/src/components/Chat/hooks/__tests__/useAppSettings.test.tsx b/package/src/components/Chat/hooks/__tests__/useAppSettings.test.tsx
index 3f96bdab75..c83111b9f0 100644
--- a/package/src/components/Chat/hooks/__tests__/useAppSettings.test.tsx
+++ b/package/src/components/Chat/hooks/__tests__/useAppSettings.test.tsx
@@ -18,7 +18,6 @@ describe('useAppSettings', () => {
auto_translation_enabled: true,
}),
),
- userID: 'some-user-id',
} as unknown as StreamChat,
isOnline,
false,
diff --git a/package/src/components/Chat/hooks/useAppSettings.ts b/package/src/components/Chat/hooks/useAppSettings.ts
index d17a3b61f0..b3e77552db 100644
--- a/package/src/components/Chat/hooks/useAppSettings.ts
+++ b/package/src/components/Chat/hooks/useAppSettings.ts
@@ -18,12 +18,32 @@ export const useAppSettings = <
const isMounted = useIsMountedRef();
useEffect(() => {
- async function enforeAppSettings() {
- if (!client.userID) return;
+ /**
+ * Fetches app settings from the backend when offline support is disabled.
+ */
+ const enforceAppSettingsWithoutOfflineSupport = async () => {
+ try {
+ const appSettings = await client.getAppSettings();
+ if (isMounted.current) {
+ setAppSettings(appSettings);
+ }
+ } catch (error: unknown) {
+ if (error instanceof Error) {
+ console.error(`An error occurred while getting app settings: ${error}`);
+ }
+ }
+ };
- if (enableOfflineSupport && !initialisedDatabase) return;
+ /**
+ * Fetches app settings from the local database when offline support is enabled if internet is off else fetches from the backend.
+ * Note: We need to set the app settings from the local database when offline as the client will not have the app settings in memory. For this we store it for the `client.userID`.
+ *
+ * TODO: Remove client.userID usage for offline support case.
+ */
+ const enforceAppSettingsWithOfflineSupport = async () => {
+ if (!client.userID) return;
- if (!isOnline && enableOfflineSupport) {
+ if (!isOnline) {
const appSettings = dbApi.getAppSettings({ currentUserId: client.userID });
setAppSettings(appSettings);
return;
@@ -33,17 +53,24 @@ export const useAppSettings = <
const appSettings = await client.getAppSettings();
if (isMounted.current) {
setAppSettings(appSettings);
- enableOfflineSupport &&
- dbApi.upsertAppSettings({
- appSettings,
- currentUserId: client.userID as string,
- });
+ dbApi.upsertAppSettings({
+ appSettings,
+ currentUserId: client.userID as string,
+ });
}
} catch (error: unknown) {
if (error instanceof Error) {
console.error(`An error occurred while getting app settings: ${error}`);
}
}
+ };
+
+ async function enforeAppSettings() {
+ if (enableOfflineSupport) {
+ await enforceAppSettingsWithOfflineSupport();
+ } else {
+ await enforceAppSettingsWithoutOfflineSupport();
+ }
}
enforeAppSettings();
diff --git a/package/src/components/Message/MessageSimple/utils/generateMarkdownText.ts b/package/src/components/Message/MessageSimple/utils/generateMarkdownText.ts
index 91fb1010fd..2851be1376 100644
--- a/package/src/components/Message/MessageSimple/utils/generateMarkdownText.ts
+++ b/package/src/components/Message/MessageSimple/utils/generateMarkdownText.ts
@@ -2,10 +2,7 @@ import truncate from 'lodash/truncate';
import { parseLinksFromText } from './parseLinks';
-// If you need to use any of the special characters literally (actually searching for a "*", for instance), you must escape it by putting a backslash in front of it.
-function escapeRegExp(text: string) {
- return text.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&');
-}
+import { escapeRegExp } from '../../../../utils/utils';
export const generateMarkdownText = (text?: string) => {
if (!text) return null;
diff --git a/package/src/components/Message/MessageSimple/utils/renderText.tsx b/package/src/components/Message/MessageSimple/utils/renderText.tsx
index f096bb9adf..5096ea0390 100644
--- a/package/src/components/Message/MessageSimple/utils/renderText.tsx
+++ b/package/src/components/Message/MessageSimple/utils/renderText.tsx
@@ -23,6 +23,7 @@ import { generateMarkdownText } from './generateMarkdownText';
import type { MessageContextValue } from '../../../../contexts/messageContext/MessageContext';
import type { Colors, MarkdownStyle } from '../../../../contexts/themeContext/utils/theme';
import type { DefaultStreamChatGenerics } from '../../../../types/types';
+import { escapeRegExp } from '../../../../utils/utils';
import type { MessageType } from '../../../MessageList/hooks/useMessageList';
const defaultMarkdownStyles: MarkdownStyle = {
@@ -211,10 +212,6 @@ export const renderText = <
);
};
- function escapeRegExp(text: string) {
- return text.replace(/[-[\]{}()*+?.,/\\^$|#]/g, '\\$&');
- }
-
// take the @ mentions and turn them into markdown?
// translate links
const { mentioned_users } = message;
diff --git a/package/src/contexts/messageInputContext/MessageInputContext.tsx b/package/src/contexts/messageInputContext/MessageInputContext.tsx
index 412e0c7564..d27de877fe 100644
--- a/package/src/contexts/messageInputContext/MessageInputContext.tsx
+++ b/package/src/contexts/messageInputContext/MessageInputContext.tsx
@@ -87,6 +87,15 @@ import { DEFAULT_BASE_CONTEXT_VALUE } from '../utils/defaultBaseContextValue';
import { getDisplayName } from '../utils/getDisplayName';
import { isTestEnvironment } from '../utils/isTestEnvironment';
+/**
+ * Function to escape special characters except . in a string and replace with '_'
+ * @param text
+ * @returns string
+ */
+function escapeRegExp(text: string) {
+ return text.replace(/[[\]{}()*+?,\\^$|#\s]/g, '_');
+}
+
export type EmojiSearchIndex = {
search: (query: string) => PromiseLike> | Array | null;
};
@@ -1149,6 +1158,9 @@ export const MessageInputProvider = <
const uploadFile = async ({ newFile }: { newFile: FileUpload }) => {
const { file, id } = newFile;
+ // The file name can have special characters, so we escape it.
+ const filename = escapeRegExp(file.name);
+
setFileUploads(getUploadSetStateAction(id, FileState.UPLOADING));
let response: Partial = {};
@@ -1157,17 +1169,17 @@ export const MessageInputProvider = <
response = await value.doDocUploadRequest(file, channel);
} else if (channel && file.uri) {
uploadAbortControllerRef.current.set(
- file.name,
+ filename,
client.createAbortControllerForNextRequest(),
);
// Compress images selected through file picker when uploading them
if (file.mimeType?.includes('image')) {
const compressedUri = await compressedImageURI(file, value.compressImageQuality);
- response = await channel.sendFile(compressedUri, file.name, file.mimeType);
+ response = await channel.sendFile(compressedUri, filename, file.mimeType);
} else {
- response = await channel.sendFile(file.uri, file.name, file.mimeType);
+ response = await channel.sendFile(file.uri, filename, file.mimeType);
}
- uploadAbortControllerRef.current.delete(file.name);
+ uploadAbortControllerRef.current.delete(filename);
}
const extraData: Partial = {
@@ -1181,7 +1193,7 @@ export const MessageInputProvider = <
(error.name === 'AbortError' || error.name === 'CanceledError')
) {
// nothing to do
- uploadAbortControllerRef.current.delete(file.name);
+ uploadAbortControllerRef.current.delete(filename);
return;
}
handleFileOrImageUploadError(error, false, id);
@@ -1198,7 +1210,8 @@ export const MessageInputProvider = <
let response = {} as SendFileAPIResponse;
const uri = file.uri || '';
- const filename = file.name ?? getFileNameFromPath(uri);
+ // The file name can have special characters, so we escape it.
+ const filename = escapeRegExp(file.name ?? getFileNameFromPath(uri));
try {
const compressedUri = await compressedImageURI(file, value.compressImageQuality);
diff --git a/package/src/utils/utils.ts b/package/src/utils/utils.ts
index 5240790493..c7b0165480 100644
--- a/package/src/utils/utils.ts
+++ b/package/src/utils/utils.ts
@@ -677,3 +677,12 @@ export const getDurationLabelFromDuration = (duration: number) => {
return durationLabel;
};
+
+/**
+ * Utility to escape special characters in a string.
+ * @param text
+ * @returns string
+ */
+export function escapeRegExp(text: string) {
+ return text.replace(/[-[\]{}()*+?.,/\\^$|#]/g, '\\$&');
+}