From 10e08f3d86fb66ce7ef1fddc998812375eb26051 Mon Sep 17 00:00:00 2001 From: Jai Chaudhary Date: Fri, 14 Feb 2025 23:31:37 +0530 Subject: [PATCH 1/8] added core changes to enable websocket in chatroom --- .../components/LMChatAIButton/index.tsx | 3 + .../ChatSX/components/ParseDeepLink/index.ts | 3 + .../ChatSX/context/ChatroomContext.tsx | 197 ++++++++++-------- .../ChatSX/lmChatProvider/index.tsx | 24 +-- .../ChatSX/setupChat.ts | 7 +- 5 files changed, 136 insertions(+), 98 deletions(-) diff --git a/likeminds-chat-reactnative-integration/ChatSX/components/LMChatAIButton/index.tsx b/likeminds-chat-reactnative-integration/ChatSX/components/LMChatAIButton/index.tsx index b22f7422..8510dfe7 100644 --- a/likeminds-chat-reactnative-integration/ChatSX/components/LMChatAIButton/index.tsx +++ b/likeminds-chat-reactnative-integration/ChatSX/components/LMChatAIButton/index.tsx @@ -10,6 +10,7 @@ import { useNavigation } from "@react-navigation/native"; import { StyleSheet } from "react-native"; import { CHATBOT_INITIATE_SCREEN, CHATROOM } from "../../constants/Screens"; import Layout from "../../constants/Layout"; +import { getUniqueId } from "react-native-device-info"; interface LMChatAIButtonProps { text?: string; @@ -79,12 +80,14 @@ export default function LMChatAIButton({ callValidateApi(accessToken, refreshToken); return; } + const deviceID = await getUniqueId(); const payload: InitUserWithUuid = { userName: userName, apiKey: apiKey ? apiKey : "", uuid: uuid ? uuid : "", isGuest: false, imageUrl: imageUrl ? imageUrl : "", + deviceId: deviceID, }; const initiateResponse: any = await dispatch(initAPI(payload)); if (initiateResponse !== undefined && initiateResponse !== null) { diff --git a/likeminds-chat-reactnative-integration/ChatSX/components/ParseDeepLink/index.ts b/likeminds-chat-reactnative-integration/ChatSX/components/ParseDeepLink/index.ts index 874cb357..bdafcb83 100644 --- a/likeminds-chat-reactnative-integration/ChatSX/components/ParseDeepLink/index.ts +++ b/likeminds-chat-reactnative-integration/ChatSX/components/ParseDeepLink/index.ts @@ -5,6 +5,7 @@ import { isValidURI } from "../../shareUtils"; import { DeepLinkRequest, DeepLinkResponse } from "./models"; import { CHATROOM } from "../../constants/Screens"; import { Client } from "../../client"; +import { getUniqueId } from "react-native-device-info"; // this function is to parse deep link url export async function parseDeepLink( @@ -34,11 +35,13 @@ export async function parseDeepLink( const internalRoute = `route://collabcard?collabcard_id=${chatroomId}`; const user: any = await Client.myClient.getUserFromLocalStorage(); // initiate API call + const deviceID = await getUniqueId(); const initiateUserRequest = { userName: request?.userName, uuid: request?.uuid, isGuest: false, apiKey: user?.apiKey, + deviceId: deviceID, }; const initiateUserResponse = await Client.myClient?.initiateUser( initiateUserRequest diff --git a/likeminds-chat-reactnative-integration/ChatSX/context/ChatroomContext.tsx b/likeminds-chat-reactnative-integration/ChatSX/context/ChatroomContext.tsx index aab6c285..0bd38c17 100644 --- a/likeminds-chat-reactnative-integration/ChatSX/context/ChatroomContext.tsx +++ b/likeminds-chat-reactnative-integration/ChatSX/context/ChatroomContext.tsx @@ -75,7 +75,10 @@ import { } from "@likeminds.community/chat-rn"; import { Credentials } from "../credentials"; import { initAPI } from "../store/actions/homefeed"; -import { createTemporaryStateMessage, splitFileName } from "../utils/chatroomUtils"; +import { + createTemporaryStateMessage, + splitFileName, +} from "../utils/chatroomUtils"; import { LMChatAnalytics } from "../analytics/LMChatAnalytics"; import { getChatroomType, getConversationType } from "../utils/analyticsUtils"; import { @@ -110,7 +113,7 @@ import AudioPlayer from "../optionalDependecies/AudioPlayer"; import { Attachment } from "@likeminds.community/chat-rn/dist/shared/responseModels/Attachment"; import { SdkTheme } from "../setupChat"; import { Themes } from "../enums/Themes"; -import { ScreenName } from "../enums/ScreenNameEnums" +import { ScreenName } from "../enums/ScreenNameEnums"; interface UploadResource { selectedImages: any; @@ -279,7 +282,8 @@ export const ChatroomContextProvider = ({ children }: ChatroomContextProps) => { const [replyChatID, setReplyChatID] = useState(); const [modalVisible, setModalVisible] = useState(false); - const [shimmerVisibleForChatbot, setShimmerVisibleForChatbot] = useState(false); + const [shimmerVisibleForChatbot, setShimmerVisibleForChatbot] = + useState(false); const [messageSentByUserId, setMessageSentByUserId] = useState(""); const [isToast, setIsToast] = useState(false); @@ -318,7 +322,7 @@ export const ChatroomContextProvider = ({ children }: ChatroomContextProps) => { chatroomCreator, currentChatroomTopic, temporaryStateMessage, - messageId + messageId, }: any = useAppSelector((state) => state.chatroom); const { user, community, memberRights } = useAppSelector( (state) => state.homefeed @@ -635,6 +639,50 @@ export const ChatroomContextProvider = ({ children }: ChatroomContextProps) => { }); }, [chatroomID]); + const ChatCallback = { + onSocketConnectionOpen: () => { + console.log("WebSocket connection opened."); + }, + onMessageReceived: async (data) => { + console.log("New message received:", data.conversation); + const conversationID = data?.conversation?.id; + if (conversationID) { + const maxTimeStamp = Math.floor(Date.now() * 1000); + await firebaseConversationSyncAPI( + INITIAL_SYNC_PAGE, + 0, + maxTimeStamp, + conversationID + ); + fetchChatroomDetails(); + } + }, + onSocketConnectionClosed: () => { + console.log("WebSocket connection closed."); + }, + onError: (errorMessage: string) => { + console.error("WebSocket error:", errorMessage); + }, + }; + + useEffect(() => { + const routeName = route.name; + if (routeName == ScreenName.FileUpload) { + return; + } + // Subscribe to a chatroom + myClient.subscribeChatroom( + { chatroomId: chatroomID }, + ChatCallback + ); + + return () => { + if (routeName == ScreenName.Chatroom) { + myClient.unSubscribeChatroom(); + } + } + }, []); + // This useEffect is used to highlight the chatroom topic conversation for 1 sec on scrolling to it useEffect(() => { if (isFound) { @@ -846,10 +894,11 @@ export const ChatroomContextProvider = ({ children }: ChatroomContextProps) => { }, [chatroomDBDetails, chatroomID]); useEffect(() => { - if ((chatroomType == ChatroomType.OPENCHATROOM || - chatroomType == ChatroomType.ANNOUNCEMENTROOM) && + if ( + (chatroomType == ChatroomType.OPENCHATROOM || + chatroomType == ChatroomType.ANNOUNCEMENTROOM) && selectedMessages?.length == 1 && - (SdkTheme.sdkTheme == Themes.COMMUNITY_HYBRID) + SdkTheme.sdkTheme == Themes.COMMUNITY_HYBRID ) { callAPI(); } @@ -869,7 +918,7 @@ export const ChatroomContextProvider = ({ children }: ChatroomContextProps) => { setShowDM(response?.showDm); } } - }, [chatroomID, chatroomDBDetails, selectedMessages]) + }, [chatroomID, chatroomDBDetails, selectedMessages]); // sync conversation call with conversation_id from firebase listener const firebaseConversationSyncAPI = async ( @@ -885,13 +934,13 @@ export const ChatroomContextProvider = ({ children }: ChatroomContextProps) => { conversationId ); const DB_RESPONSE = val?.data; - if ((DB_RESPONSE?.chatroomMeta[chatroomID])?.chatRequestState == 1) { + if (DB_RESPONSE?.chatroomMeta[chatroomID]?.chatRequestState == 1) { await myClient?.updateChatRequestState( chatroomID?.toString(), ChatroomChatRequestState.ACCEPTED ); } - let flagForShimmer = shimmerVisibleForChatbot + let flagForShimmer = shimmerVisibleForChatbot; if (DB_RESPONSE?.conversationsData?.length !== 0) { await myClient?.saveConversationData( DB_RESPONSE, @@ -907,8 +956,8 @@ export const ChatroomContextProvider = ({ children }: ChatroomContextProps) => { if (messageId != conversationId) { dispatch({ - type: HIDE_SHIMMER - }) + type: HIDE_SHIMMER, + }); setShimmerVisibleForChatbot(false); } } @@ -920,45 +969,26 @@ export const ChatroomContextProvider = ({ children }: ChatroomContextProps) => { let conversationsFromRealm = await myClient?.getConversations(payload); // if uploadingFilesMessages is not empty then add those messages to the conversation list if (Object.keys(uploadingFilesMessages)?.length > 0) { - conversationsFromRealm = [...Object.values(uploadingFilesMessages), ...conversationsFromRealm] + conversationsFromRealm = [ + ...Object.values(uploadingFilesMessages), + ...conversationsFromRealm, + ]; } dispatch({ type: GET_CONVERSATIONS_SUCCESS, - body: { conversations: conversationsFromRealm, shimmer: flagForShimmer }, + body: { + conversations: conversationsFromRealm, + shimmer: flagForShimmer, + }, }); } return; }; - //useffect includes firebase realtime listener - useEffect(() => { - // if FileUpload Screen is opened then don't call API's - if (route.name == ScreenName.FileUpload) { - return; - } - const query = ref(db, `/collabcards/${chatroomID}`); - return onValue(query, async (snapshot: DataSnapshot) => { - if (snapshot.exists()) { - const firebaseData = snapshot.val(); - const conversationID = firebaseData?.collabcard?.answer_id; - if (conversationID) { - const maxTimeStamp = Math.floor(Date.now() * 1000); - await firebaseConversationSyncAPI( - INITIAL_SYNC_PAGE, - 0, - maxTimeStamp, - conversationID - ); - fetchChatroomDetails(); - } - } - }); - }, [chatroomID, messageSentByUserId, messageId]); - // this useffect updates routes, previousRoute variables when we come to chatroom. useEffect(() => { if (isFocused) { - routes = (navigation.getState())?.routes; + routes = navigation.getState()?.routes; previousRoute = routes[routes?.length - 2]; } }, [isFocused, chatroomID]); @@ -1405,14 +1435,14 @@ export const ChatroomContextProvider = ({ children }: ChatroomContextProps) => { const resultArr = selectedMessages[0]?.reactions.map((element: any) => element?.member?.id == user?.id ? { - member: { - id: user?.id, - name: user?.name, - imageUrl: "", - }, - reaction: val, - updatedAt: Date.now(), - } + member: { + id: user?.id, + name: user?.name, + imageUrl: "", + }, + reaction: val, + updatedAt: Date.now(), + } : element ); changedMsg = { @@ -1425,14 +1455,14 @@ export const ChatroomContextProvider = ({ children }: ChatroomContextProps) => { const resultArr = selectedMessages[0]?.reactions.map((element: any) => element?.member?.id == user?.id ? { - member: { - id: user?.id, - name: user?.name, - imageUrl: "", - }, - reaction: val, - updatedAt: Date.now(), - } + member: { + id: user?.id, + name: user?.name, + imageUrl: "", + }, + reaction: val, + updatedAt: Date.now(), + } : element ); changedMsg = { @@ -1694,9 +1724,7 @@ export const ChatroomContextProvider = ({ children }: ChatroomContextProps) => { ChatroomChatRequestState.REJECTED ); - await paginatedConversationSyncAPI(INITIAL_SYNC_PAGE, - 0, - Date.now() * 1000) + await paginatedConversationSyncAPI(INITIAL_SYNC_PAGE, 0, Date.now() * 1000); await fetchChatroomDetails(); return response; @@ -1722,9 +1750,7 @@ export const ChatroomContextProvider = ({ children }: ChatroomContextProps) => { chatroomID?.toString(), ChatroomChatRequestState.ACCEPTED ); - await paginatedConversationSyncAPI(INITIAL_SYNC_PAGE, - 0, - Date.now() * 1000) + await paginatedConversationSyncAPI(INITIAL_SYNC_PAGE, 0, Date.now() * 1000); await fetchChatroomDetails(); return response; }; @@ -1748,9 +1774,7 @@ export const ChatroomContextProvider = ({ children }: ChatroomContextProps) => { chatroomID?.toString(), ChatroomChatRequestState.REJECTED ); - await paginatedConversationSyncAPI(INITIAL_SYNC_PAGE, - 0, - Date.now() * 1000) + await paginatedConversationSyncAPI(INITIAL_SYNC_PAGE, 0, Date.now() * 1000); await fetchChatroomDetails(); return response; }; @@ -1846,16 +1870,16 @@ export const ChatroomContextProvider = ({ children }: ChatroomContextProps) => { attachmentType === IMAGE_TEXT ? item.fileName : attachmentType === VIDEO_TEXT - ? item.fileName - : attachmentType === VOICE_NOTE_TEXT - ? item.name - : docAttachmentType === PDF_TEXT - ? item.name - : null; + ? item.fileName + : attachmentType === VOICE_NOTE_TEXT + ? item.name + : docAttachmentType === PDF_TEXT + ? item.name + : null; const fileInfo = splitFileName(name); const path = `files/collabcard/${chatroomID}/conversation/${user?.uuid}/${fileInfo?.name}-${conversationID}.${fileInfo.extension}`; - const thumbnailUrlPath = `files/collabcard/${chatroomID}/conversation/${user?.uuid}/${thumbnailURL}` + const thumbnailUrlPath = `files/collabcard/${chatroomID}/conversation/${user?.uuid}/${thumbnailURL}`; let uriFinal: any; @@ -1922,15 +1946,15 @@ export const ChatroomContextProvider = ({ children }: ChatroomContextProps) => { meta: fileType === VIDEO_TEXT ? { - size: selectedFilesToUpload[i]?.fileSize, - duration: selectedFilesToUpload[i]?.duration, - } + size: selectedFilesToUpload[i]?.fileSize, + duration: selectedFilesToUpload[i]?.duration, + } : fileType === VOICE_NOTE_TEXT - ? { + ? { size: null, duration: item?.duration, } - : { + : { size: docAttachmentType === PDF_TEXT ? selectedFilesToUpload[i]?.size @@ -1940,8 +1964,8 @@ export const ChatroomContextProvider = ({ children }: ChatroomContextProps) => { docAttachmentType === PDF_TEXT ? selectedFilesToUpload[i]?.name : voiceNoteAttachmentType === VOICE_NOTE_TEXT - ? item?.name - : selectedFilesToUpload[i]?.fileName, + ? item?.name + : selectedFilesToUpload[i]?.fileName, type: fileType, url: awsResponse, thumbnailUrl: @@ -1949,7 +1973,8 @@ export const ChatroomContextProvider = ({ children }: ChatroomContextProps) => { awsFolderPath: path, localFilePath: item.uri, thumbnailAWSFolderPath: thumbnailUrlPath, - thumbnailLocalFilePath: fileType === VIDEO_TEXT ? thumbnailURL : null, + thumbnailLocalFilePath: + fileType === VIDEO_TEXT ? thumbnailURL : null, fileUrl: awsResponse, createdAt: conversationID, updatedAt: conversationID, @@ -2119,9 +2144,13 @@ export const ChatroomContextProvider = ({ children }: ChatroomContextProps) => { if (userDMLimit) { Alert.alert( REQUEST_DM_LIMIT, - `You can only send ${userDMLimit?.numberInDuration - } DM requests per ${userDMLimit?.duration - }.\n\nTry again in ${formatTime(res?.newRequestDmTimestamp as number)}`, + `You can only send ${ + userDMLimit?.numberInDuration + } DM requests per ${ + userDMLimit?.duration + }.\n\nTry again in ${formatTime( + res?.newRequestDmTimestamp as number + )}`, [ { text: CANCEL_BUTTON, @@ -2234,7 +2263,7 @@ export const ChatroomContextProvider = ({ children }: ChatroomContextProps) => { onReplyPrivatelyClick, backAction, setShimmerVisibleForChatbot, - setMessageSentByUserId + setMessageSentByUserId, }; return ( diff --git a/likeminds-chat-reactnative-integration/ChatSX/lmChatProvider/index.tsx b/likeminds-chat-reactnative-integration/ChatSX/lmChatProvider/index.tsx index f4af6228..afd73647 100644 --- a/likeminds-chat-reactnative-integration/ChatSX/lmChatProvider/index.tsx +++ b/likeminds-chat-reactnative-integration/ChatSX/lmChatProvider/index.tsx @@ -18,14 +18,14 @@ import { initAPI, validateUser, } from "../store/actions/homefeed"; -import { pushAPI, token } from "../notifications/index" +import { pushAPI, token } from "../notifications/index"; +import { getUniqueId } from "react-native-device-info"; export const LMChatBotProvider = ({ myClient, children, - lmChatInterface + lmChatInterface, }: LMChatBotProviderProps) => { - const dispatch = useAppDispatch(); // to initialise track player @@ -77,12 +77,10 @@ export const LMChatBotProvider = ({ // setting lmChatInterface in CallBack class CallBack.setLMChatInterface(lmChatInterface); - }, [myClient, lmChatInterface]) + }, [myClient, lmChatInterface]); - return ( - {children} - ) -} + return {children}; +}; export const LMChatProvider = ({ myClient, @@ -163,9 +161,9 @@ export const LMChatProvider = ({ token().then((res) => { if (!!res) { - pushAPI(res, accessToken) + pushAPI(res, accessToken); } - }) + }); await dispatch(getMemberState()); } @@ -179,12 +177,14 @@ export const LMChatProvider = ({ callValidateApi(accessToken, refreshToken); return; } + const deviceID = await getUniqueId(); const payload: InitUserWithUuid = { userName: userName, apiKey: apiKey ? apiKey : "", uuid: userUniqueId ? userUniqueId : "", isGuest: false, imageUrl: imageUrl ? imageUrl : "", + deviceId: deviceID, }; const initiateResponse: any = await dispatch(initAPI(payload)); if (initiateResponse !== undefined && initiateResponse !== null) { @@ -192,9 +192,9 @@ export const LMChatProvider = ({ await dispatch(getMemberState()); token().then((res) => { if (!!res) { - pushAPI(res, accessToken) + pushAPI(res, accessToken); } - }) + }); setIsInitiated(true); } } diff --git a/likeminds-chat-reactnative-integration/ChatSX/setupChat.ts b/likeminds-chat-reactnative-integration/ChatSX/setupChat.ts index ea5710b8..024ad967 100644 --- a/likeminds-chat-reactnative-integration/ChatSX/setupChat.ts +++ b/likeminds-chat-reactnative-integration/ChatSX/setupChat.ts @@ -5,6 +5,7 @@ import { } from "@likeminds.community/chat-rn"; import { Client } from "./client"; import { Themes } from "../ChatSX/enums/Themes"; +import { getUniqueId } from "react-native-device-info"; // create a class by LMChatCoreCallbacks and take two functions in its contructors, assign these two functions to the class's functions export class LMCoreCallbacks { @@ -45,11 +46,13 @@ export class LMSDKCallbacksImplementations extends LMSDKCallbacks { await Client.myClient.getUserFromLocalStorage(); // replace with actual method to get user const user = stringifiedUser ? JSON.parse(stringifiedUser) : null; if (user?.apiKey) { + const deviceID = await getUniqueId(); const payload: InitUserWithUuid = { apiKey: user.apiKey, uuid: user.userUniqueID, userName: user.userName, isGuest: false, + deviceId: deviceID, }; const response: any = await Client.myClient.initiateUser(payload); await Client.myClient.setTokens( @@ -82,10 +85,10 @@ export class LMSDKCallbacksImplementations extends LMSDKCallbacks { } export class SdkTheme { - private static _theme: Themes + private static _theme: Themes; static setSdkTheme(theme: Themes): void { - this._theme = theme + this._theme = theme; } static get sdkTheme(): Themes { From a9fa294f1ab1967540ba7336acfb4d495fb23dc7 Mon Sep 17 00:00:00 2001 From: Usman salim Date: Sat, 29 Mar 2025 22:19:41 +0530 Subject: [PATCH 2/8] added changes for socket --- .../ChatSX/context/ChatroomContext.tsx | 116 +++++++++--------- .../ChatSX/context/InputBoxContext.tsx | 48 +++++++- 2 files changed, 101 insertions(+), 63 deletions(-) diff --git a/likeminds-chat-reactnative-integration/ChatSX/context/ChatroomContext.tsx b/likeminds-chat-reactnative-integration/ChatSX/context/ChatroomContext.tsx index 8d77f271..d3468cac 100644 --- a/likeminds-chat-reactnative-integration/ChatSX/context/ChatroomContext.tsx +++ b/likeminds-chat-reactnative-integration/ChatSX/context/ChatroomContext.tsx @@ -23,6 +23,7 @@ import { CLEAR_SELECTED_FILES_TO_UPLOAD, CLEAR_SELECTED_MESSAGES, CLEAR_SELECTED_VOICE_NOTE_FILES_TO_UPLOAD, + FIREBASE_CONVERSATIONS_SUCCESS, GET_CHATROOM_ACTIONS_SUCCESS, GET_CHATROOM_DB_SUCCESS, GET_CONVERSATIONS_SUCCESS, @@ -119,6 +120,7 @@ import { SdkTheme } from "../setupChat"; import { Themes } from "../enums/Themes"; import { ScreenName } from "../enums/ScreenNameEnums" import { Conversation } from "@likeminds.community/chat-rn/dist/shared/responseModels/Conversation"; +import DeviceInfo from "react-native-device-info"; interface UploadResource { selectedImages: Attachment[] | any[]; @@ -721,15 +723,12 @@ export const ChatroomContextProvider = ({ children }: ChatroomContextProps) => { console.log("WebSocket connection opened."); }, onMessageReceived: async (data) => { - console.log("New message received:", data.conversation); const conversationID = data?.conversation?.id; if (conversationID) { - const maxTimeStamp = Math.floor(Date.now() * 1000); await firebaseConversationSyncAPI( INITIAL_SYNC_PAGE, - 0, - maxTimeStamp, - conversationID + data?.conversation, + conversationID, ); fetchChatroomDetails(); } @@ -758,7 +757,7 @@ export const ChatroomContextProvider = ({ children }: ChatroomContextProps) => { myClient.unSubscribeChatroom(); } } - }, []); + }, [chatroomID]); // This useEffect is used to highlight the chatroom topic conversation for 1 sec on scrolling to it useEffect(() => { @@ -1088,46 +1087,42 @@ export const ChatroomContextProvider = ({ children }: ChatroomContextProps) => { // sync conversation call with conversation_id from firebase listener const firebaseConversationSyncAPI = async ( page: number, - minTimeStamp: number, - maxTimeStamp: number, - conversationId?: string + data: Conversation, + conversationId?: string, + flag: boolean = true ) => { try { - const val = await syncConversationAPI( - page, - maxTimeStamp, - minTimeStamp, - conversationId - ); - const DB_RESPONSE = val?.data; - if ((DB_RESPONSE?.chatroomMeta[chatroomID])?.chatRequestState == 1) { - await myClient?.updateChatRequestState( - chatroomID?.toString(), - ChatroomChatRequestState.ACCEPTED - ); - } - let flagForShimmer = shimmerVisibleForChatbot - if (DB_RESPONSE?.conversationsData?.length !== 0) { - await myClient?.saveConversationData( - DB_RESPONSE, - DB_RESPONSE?.chatroomMeta, - DB_RESPONSE?.conversationsData, - community?.id - ); + await myClient?.saveConversationData( + { + chatroomMeta: {}, + chatroomReactionsMeta: {}, + communityMeta: {}, + convAttachmentsMeta: {}, + conversationMeta: {}, + conversationsData: {}, + convPollsMeta: {}, + convReactionsMeta: {}, + widgets: {}, + userMeta: {} + }, + {}, + [data], + community?.id + ) - if (messageSentByUserId != conversationId) { - setShimmerVisibleForChatbot(() => false); - flagForShimmer = false; - } + let flagForShimmer = shimmerVisibleForChatbot + if (messageSentByUserId != conversationId) { + setShimmerVisibleForChatbot(() => false); + flagForShimmer = false; + } - if (messageId != conversationId) { - dispatch({ - type: HIDE_SHIMMER - }) - setShimmerVisibleForChatbot(false); - } + if (messageId != conversationId) { + dispatch({ + type: HIDE_SHIMMER + }) + setShimmerVisibleForChatbot(false); } - if (page === 1) { + if (page == 1) { const payload = GetConversationsRequestBuilder.builder() .setChatroomId(chatroomID?.toString()) .setLimit(PAGE_SIZE) @@ -1153,6 +1148,7 @@ export const ChatroomContextProvider = ({ children }: ChatroomContextProps) => { LMSeverity.ERROR ) } + } // this useffect updates routes, previousRoute variables when we come to chatroom. useEffect(() => { @@ -2238,12 +2234,12 @@ export const ChatroomContextProvider = ({ children }: ChatroomContextProps) => { attachmentType === IMAGE_TEXT ? item.fileName : attachmentType === VIDEO_TEXT - ? item.fileName - : attachmentType === VOICE_NOTE_TEXT - ? item.name - : docAttachmentType === PDF_TEXT - ? item.name - : null; + ? item.fileName + : attachmentType === VOICE_NOTE_TEXT + ? item.name + : docAttachmentType === PDF_TEXT + ? item.name + : null; const fileInfo = splitFileName(name); const path = `files/collabcard/${chatroomID}/conversation/${user?.uuid}/${fileInfo?.name}-${conversationID}.${fileInfo.extension}`; @@ -2314,15 +2310,15 @@ export const ChatroomContextProvider = ({ children }: ChatroomContextProps) => { meta: fileType === VIDEO_TEXT ? { - size: selectedFilesToUpload[i]?.fileSize, - duration: selectedFilesToUpload[i]?.duration, - } + size: selectedFilesToUpload[i]?.fileSize, + duration: selectedFilesToUpload[i]?.duration, + } : fileType === VOICE_NOTE_TEXT - ? { + ? { size: null, duration: item?.duration, } - : { + : { size: docAttachmentType === PDF_TEXT ? selectedFilesToUpload[i]?.size @@ -2332,8 +2328,8 @@ export const ChatroomContextProvider = ({ children }: ChatroomContextProps) => { docAttachmentType === PDF_TEXT ? selectedFilesToUpload[i]?.name : voiceNoteAttachmentType === VOICE_NOTE_TEXT - ? item?.name - : selectedFilesToUpload[i]?.fileName, + ? item?.name + : selectedFilesToUpload[i]?.fileName, type: fileType, url: awsResponse, thumbnailUrl: @@ -2580,6 +2576,12 @@ export const ChatroomContextProvider = ({ children }: ChatroomContextProps) => { .setWidgets(response?.widgets) .build() ) + await paginatedConversationSyncAPI( + INITIAL_SYNC_PAGE, + 0, + Math.floor(Date.now() * 1000), + response?.conversation?.id + ) } } catch (error) { Client?.myClient?.handleException( @@ -2824,10 +2826,8 @@ export const ChatroomContextProvider = ({ children }: ChatroomContextProps) => { if (userDMLimit) { Alert.alert( REQUEST_DM_LIMIT, - `You can only send ${ - userDMLimit?.numberInDuration - } DM requests per ${ - userDMLimit?.duration + `You can only send ${userDMLimit?.numberInDuration + } DM requests per ${userDMLimit?.duration }.\n\nTry again in ${formatTime( res?.newRequestDmTimestamp as number )}`, diff --git a/likeminds-chat-reactnative-integration/ChatSX/context/InputBoxContext.tsx b/likeminds-chat-reactnative-integration/ChatSX/context/InputBoxContext.tsx index b40d55d2..d3e7a6fe 100644 --- a/likeminds-chat-reactnative-integration/ChatSX/context/InputBoxContext.tsx +++ b/likeminds-chat-reactnative-integration/ChatSX/context/InputBoxContext.tsx @@ -57,6 +57,7 @@ import { EDIT_CONVERSATION, EMPTY_BLOCK_DELETION, FILE_SENT, + GET_CONVERSATIONS_SUCCESS, LONG_PRESSED, MESSAGE_SENT, SELECTED_FILE_TO_VIEW, @@ -121,7 +122,7 @@ import { PanGestureHandlerEventPayload, } from "react-native-gesture-handler"; import { DefaultStyle } from "react-native-reanimated/lib/typescript/hook/commonTypes"; -import { SyncConversationRequest, UpdateConversationDataRequest } from "@likeminds.community/chat-rn"; +import { GetConversationsRequestBuilder, SyncConversationRequest, UpdateConversationDataRequest } from "@likeminds.community/chat-rn"; import AudioPlayer from "../optionalDependecies/AudioPlayer"; import { useNavigation } from "@react-navigation/native"; import { isOtherUserAIChatbot } from "../utils/chatroomUtils"; @@ -1166,6 +1167,31 @@ export const InputBoxContextProvider = ({ } } + async function syncAPI( + page: number, + maxTimeStamp: number, + minTimeStamp: number, + conversationId?: string + ) { + + if (page == 1) { + const payload = GetConversationsRequestBuilder.builder() + .setChatroomId(chatroomID?.toString()) + .setLimit(200) + .build(); + let conversationsFromRealm = await myClient?.getConversations(payload); + // if uploadingFilesMessages is not empty then add those messages to the conversation list + if (Object.keys(uploadingFilesMessages)?.length > 0) { + conversationsFromRealm = [...Object.values(uploadingFilesMessages), ...conversationsFromRealm] + } + dispatch({ + type: GET_CONVERSATIONS_SUCCESS, + body: { conversations: conversationsFromRealm, shimmer: false }, + }); + } + return; + } + // this method is trigerred whenever user presses the send button const onSend = async ( conversation: string, @@ -1673,6 +1699,12 @@ export const InputBoxContextProvider = ({ response?.conversation, response?.widgets ); + await syncAPI( + page, + Math.floor(Date.now() * 1000), + 0, + response?.conversation?.id + ); } else { dispatch({ type: SET_FAILED_MESSAGE_ID, @@ -1804,12 +1836,18 @@ export const InputBoxContextProvider = ({ id: response?.conversation?.id, }, }); + await myClient?.replaceSavedConversation( + response?.conversation, + response?.widgets + ); + await syncAPI( + page, + Math.floor(Date.now() * 1000), + 0, + response?.conversation?.id + ); } - await myClient?.replaceSavedConversation( - response?.conversation, - response?.widgets - ); if (response === undefined) { dispatch({ From 64948f59ba8e3e51fad9a4381d4446a0e4454984 Mon Sep 17 00:00:00 2001 From: Usman salim Date: Mon, 21 Apr 2025 01:26:37 +0530 Subject: [PATCH 3/8] added condition to avoid retry with new messages --- .../ChatSX/components/Messages/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/likeminds-chat-reactnative-integration/ChatSX/components/Messages/index.tsx b/likeminds-chat-reactnative-integration/ChatSX/components/Messages/index.tsx index 22469f85..f15e7e7c 100644 --- a/likeminds-chat-reactnative-integration/ChatSX/components/Messages/index.tsx +++ b/likeminds-chat-reactnative-integration/ChatSX/components/Messages/index.tsx @@ -92,7 +92,7 @@ const MessagesComponent = ({ const currentTimeStampEpoch = Math.floor(Date.now()); if (item?.id?.includes && item?.id?.includes("-")) { if (item?.attachments?.length > 0) { - const localTimestamp = Math.floor(Math.abs(parseInt(item?.attachmentUploadedEpoch))); + const localTimestamp = Math.floor(Math.abs(parseInt(item?.attachmentUploadedEpoch > 0 ? item?.attachmentUploadedEpoch : item?.localSavedEpoch ?? item?.localCreatedEpoch ?? 0 ))); if ( (uploadFailed) || (currentTimeStampEpoch - localTimestamp > 30000 && ((item?.inProgress == undefined || item?.inProgress == null)) )) { setShowRetry(true); From eab3c84fdee3ce74d3af0203640bc0ce65f7c4b4 Mon Sep 17 00:00:00 2001 From: Usman salim Date: Mon, 21 Apr 2025 01:27:27 +0530 Subject: [PATCH 4/8] fixed notification --- .../ChatSX/notifications/index.ts | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/likeminds-chat-reactnative-integration/ChatSX/notifications/index.ts b/likeminds-chat-reactnative-integration/ChatSX/notifications/index.ts index 807bf7f2..e37fecdb 100644 --- a/likeminds-chat-reactnative-integration/ChatSX/notifications/index.ts +++ b/likeminds-chat-reactnative-integration/ChatSX/notifications/index.ts @@ -134,7 +134,15 @@ function formatTimestampTo24Hour(timestamp: number): string { return `${hours}:${minutes}`; } -export default async function getNotification(remoteMessage: any) { +export default async function getNotification(remoteMessage: any, navigationRef?: any) { + if (navigationRef && navigationRef?.current?.isReady()) { + // condition to avoid notifications if the same chatroom is opened + const currentRoute = navigationRef?.current?.getCurrentRoute(); + const formattedMessage = JSON.parse(remoteMessage?.data?.unread_follow_notification); + if (currentRoute?.params?.chatroomID == formattedMessage?.chatroom_id?.toString()) { + return; + } + } if (Client?.myClient == undefined || Client?.myClient == null) { initMyClient([]); } @@ -350,7 +358,6 @@ export default async function getNotification(remoteMessage: any) { } } - notifee.cancelAllNotifications() // Create summary notifee.displayNotification({ title: navigationRoute, From 8b3a914b1ebe6db55ce0329f586c775fda26a8ed Mon Sep 17 00:00:00 2001 From: Usman salim Date: Mon, 21 Apr 2025 01:31:06 +0530 Subject: [PATCH 5/8] added eventlistner for socket --- .../ChatSX/context/ChatroomContext.tsx | 117 +++++++++++++----- .../ChatSX/context/InputBoxContext.tsx | 63 ++++------ 2 files changed, 112 insertions(+), 68 deletions(-) diff --git a/likeminds-chat-reactnative-integration/ChatSX/context/ChatroomContext.tsx b/likeminds-chat-reactnative-integration/ChatSX/context/ChatroomContext.tsx index d3468cac..6eb724f9 100644 --- a/likeminds-chat-reactnative-integration/ChatSX/context/ChatroomContext.tsx +++ b/likeminds-chat-reactnative-integration/ChatSX/context/ChatroomContext.tsx @@ -120,7 +120,7 @@ import { SdkTheme } from "../setupChat"; import { Themes } from "../enums/Themes"; import { ScreenName } from "../enums/ScreenNameEnums" import { Conversation } from "@likeminds.community/chat-rn/dist/shared/responseModels/Conversation"; -import DeviceInfo from "react-native-device-info"; +import NetInfo from "@react-native-community/netinfo" interface UploadResource { selectedImages: Attachment[] | any[]; @@ -193,6 +193,7 @@ export interface ChatroomContextValues { refInput: any; shimmerVisibleForChatbot: boolean; messageSentByUserId: string; + isSocketConnected: boolean, // Functions setIsEditable: Dispatch>; @@ -260,6 +261,7 @@ export interface ChatroomContextValues { setRetryUploadInProgress: Dispatch>, retryUploadInProgress: boolean ) => void; + setIsSocketConnected: Dispatch> } const ChatroomContext = createContext( @@ -289,6 +291,7 @@ export const ChatroomContextProvider = ({ children }: ChatroomContextProps) => { deepLinking, isNavigationToSearchedConversation, searchedConversation, + isSocketConnected: socketConnectedStatus } = route.params as { chatroomID: any; // Adjust the type accordingly previousChatroomID: any; // Adjust the type accordingly @@ -296,6 +299,7 @@ export const ChatroomContextProvider = ({ children }: ChatroomContextProps) => { deepLinking: any; // Adjust the type accordingly isNavigationToSearchedConversation: any; searchedConversation: any; + isSocketConnected: any }; const refInput = useRef(); @@ -334,6 +338,9 @@ export const ChatroomContextProvider = ({ children }: ChatroomContextProps) => { const reactionArr = ["❤️", "😂", "😮", "😢", "😠", "👍"]; const isFocused = useIsFocused(); + const [isSocketConnected, setIsSocketConnected] = useState(false); + const [socketError, setSocketError] = useState(false); + const [isInternet, setIsInternet] = useState(false); const dispatch = useAppDispatch(); const { @@ -358,6 +365,12 @@ export const ChatroomContextProvider = ({ children }: ChatroomContextProps) => { (state) => state.upload ); + const uploadingFilesMessagesRef = useRef(uploadingFilesMessages); + + useEffect(() => { + uploadingFilesMessagesRef.current = uploadingFilesMessages; + }, [uploadingFilesMessages]); + const INITIAL_SYNC_PAGE = 1; const PAGE_SIZE = 200; @@ -539,7 +552,8 @@ export const ChatroomContextProvider = ({ children }: ChatroomContextProps) => { DB_RESPONSE, DB_RESPONSE?.chatroomMeta, DB_RESPONSE?.conversationsData, - user?.sdkClientInfo?.community?.toString() + user?.sdkClientInfo?.community?.toString(), + DB_RESPONSE?.widgets ); } @@ -719,8 +733,12 @@ export const ChatroomContextProvider = ({ children }: ChatroomContextProps) => { }, [chatroomID]); const ChatCallback = { - onSocketConnectionOpen: () => { - console.log("WebSocket connection opened."); + onSocketConnectionOpen: async () => { + setIsSocketConnected(true); + setSocketError(false); + // call sync API on socket connection to sync chatroom incase socket was disconnected for some time + const chatroomDetails = await fetchChatroomDetails(); + await fetchData(chatroomDetails, false); }, onMessageReceived: async (data) => { const conversationID = data?.conversation?.id; @@ -729,35 +747,71 @@ export const ChatroomContextProvider = ({ children }: ChatroomContextProps) => { INITIAL_SYNC_PAGE, data?.conversation, conversationID, + data?.widgets ); fetchChatroomDetails(); } }, onSocketConnectionClosed: () => { - console.log("WebSocket connection closed."); + setIsSocketConnected(false); }, onError: (errorMessage: string) => { - console.error("WebSocket error:", errorMessage); + setIsSocketConnected(false); + setSocketError(true); + }, }; - + useEffect(() => { const routeName = route.name; if (routeName == ScreenName.FileUpload) { return; } - // Subscribe to a chatroom - myClient.subscribeChatroom( - { chatroomId: chatroomID }, - ChatCallback - ); + + if (!isSocketConnected && isFocused) { + // Subscribe to a chatroom + myClient.subscribeChatroom( + { chatroomId: chatroomID }, + ChatCallback + ); + } + + if (isSocketConnected && !isFocused) { + myClient.unSubscribeChatroom(); + } + + }, [chatroomID, isSocketConnected, isFocused, isInternet]); + + useEffect(() => { + if (route.name == ScreenName.FileUpload) { + return; + } return () => { - if (routeName == ScreenName.Chatroom) { - myClient.unSubscribeChatroom(); - } + myClient.unSubscribeChatroom(); } - }, [chatroomID]); + }, []) + + + useEffect(() => { + if (route.name == ScreenName.FileUpload) { + return; + } + const unsubscribe = NetInfo.addEventListener(state => { + if (state.isInternetReachable === true) { + setIsInternet(true); + } else if (state.isInternetReachable === false) { + setIsInternet(false); + setIsSocketConnected(false); + } + }); + + return () => { + unsubscribe(); // Clean up the listener on unmount + }; + + }, []) + // This useEffect is used to highlight the chatroom topic conversation for 1 sec on scrolling to it useEffect(() => { @@ -1087,9 +1141,9 @@ export const ChatroomContextProvider = ({ children }: ChatroomContextProps) => { // sync conversation call with conversation_id from firebase listener const firebaseConversationSyncAPI = async ( page: number, - data: Conversation, + data: any, conversationId?: string, - flag: boolean = true + widgets?: any, ) => { try { await myClient?.saveConversationData( @@ -1107,7 +1161,8 @@ export const ChatroomContextProvider = ({ children }: ChatroomContextProps) => { }, {}, [data], - community?.id + community?.id, + widgets ) let flagForShimmer = shimmerVisibleForChatbot @@ -1129,8 +1184,8 @@ export const ChatroomContextProvider = ({ children }: ChatroomContextProps) => { .build(); let conversationsFromRealm = await myClient?.getConversations(payload); // if uploadingFilesMessages is not empty then add those messages to the conversation list - if (Object.keys(uploadingFilesMessages)?.length > 0) { - conversationsFromRealm = [...Object.values(uploadingFilesMessages), ...conversationsFromRealm] + if (Object.keys(uploadingFilesMessagesRef.current)?.length > 0) { + conversationsFromRealm = [...Object.values(uploadingFilesMessagesRef.current), ...conversationsFromRealm] } dispatch({ type: GET_CONVERSATIONS_SUCCESS, @@ -2362,16 +2417,16 @@ export const ChatroomContextProvider = ({ children }: ChatroomContextProps) => { ID: conversationID, }, }); - const id = conversationID; - const message = { - ...uploadingFilesMessages[conversationID?.toString()], - isInProgress: FAILED, - }; + // const id = conversationID; + // const message = { + // ...uploadingFilesMessages[conversationID?.toString()], + // isInProgress: FAILED, + // }; - await myClient?.saveAttachmentUploadConversation( - id?.toString(), - JSON.stringify(message) - ); + // await myClient?.saveAttachmentUploadConversation( + // id?.toString(), + // JSON.stringify(message) + // ); Client?.myClient?.handleException( error, @@ -2903,6 +2958,7 @@ export const ChatroomContextProvider = ({ children }: ChatroomContextProps) => { messageSentByUserId, uploadResourceRetry, onRetryButtonClicked, + isSocketConnected, setIsEditable, setIsReact, @@ -2946,6 +3002,7 @@ export const ChatroomContextProvider = ({ children }: ChatroomContextProps) => { backAction, setShimmerVisibleForChatbot, setMessageSentByUserId, + setIsSocketConnected }; return ( diff --git a/likeminds-chat-reactnative-integration/ChatSX/context/InputBoxContext.tsx b/likeminds-chat-reactnative-integration/ChatSX/context/InputBoxContext.tsx index d3e7a6fe..1bf8d1ff 100644 --- a/likeminds-chat-reactnative-integration/ChatSX/context/InputBoxContext.tsx +++ b/likeminds-chat-reactnative-integration/ChatSX/context/InputBoxContext.tsx @@ -348,7 +348,7 @@ export const InputBoxContextProvider = ({ const [url, setUrl] = useState(""); const [closedPreview, setClosedPreview] = useState(false); - const { memberRights, setMessageSentByUserId, setShimmerVisibleForChatbot } = + const { memberRights, setMessageSentByUserId, setShimmerVisibleForChatbot, isSocketConnected } = useChatroomContext(); const MAX_FILE_SIZE = 104857600; // 100MB in bytes @@ -819,7 +819,8 @@ export const InputBoxContextProvider = ({ chatroomID: chatroomID, previousMessage: message, // to keep message on uploadScreen InputBox limit, - communityId: community?.id?.toString() + communityId: community?.id?.toString(), + isSocketConnected }); await launchImageLibrary(options, async (response: ImagePickerResponse) => { if (response?.didCancel) { @@ -865,7 +866,8 @@ export const InputBoxContextProvider = ({ navigation.navigate(FILE_UPLOAD, { chatroomID: chatroomID, previousMessage: message, // to keep message on uploadScreen InputBox - communityId: community?.id?.toString() + communityId: community?.id?.toString(), + isSocketConnected }); const response = await DocumentPicker.pick({ type: [DocumentPicker.types.pdf], @@ -992,7 +994,8 @@ export const InputBoxContextProvider = ({ navigation.navigate(FILE_UPLOAD, { chatroomID: chatroomID, previousMessage: message, // to keep message on uploadScreen InputBox - communityId: community?.id?.toString() + communityId: community?.id?.toString(), + isSocketConnected }); } catch (error) { Client?.myClient?.handleException( @@ -1016,7 +1019,8 @@ export const InputBoxContextProvider = ({ navigation.navigate(FILE_UPLOAD, { chatroomID: chatroomID, previousMessage: message, // to keep message on uploadScreen InputBox - communityId: community?.id?.toString() + communityId: community?.id?.toString(), + isSocketConnected }); await createThumbnail({ @@ -1167,28 +1171,20 @@ export const InputBoxContextProvider = ({ } } - async function syncAPI( - page: number, - maxTimeStamp: number, - minTimeStamp: number, - conversationId?: string - ) { - - if (page == 1) { - const payload = GetConversationsRequestBuilder.builder() - .setChatroomId(chatroomID?.toString()) - .setLimit(200) - .build(); - let conversationsFromRealm = await myClient?.getConversations(payload); - // if uploadingFilesMessages is not empty then add those messages to the conversation list - if (Object.keys(uploadingFilesMessages)?.length > 0) { - conversationsFromRealm = [...Object.values(uploadingFilesMessages), ...conversationsFromRealm] - } - dispatch({ - type: GET_CONVERSATIONS_SUCCESS, - body: { conversations: conversationsFromRealm, shimmer: false }, - }); + async function localDBSyncCall() { + const payload = GetConversationsRequestBuilder.builder() + .setChatroomId(chatroomID?.toString()) + .setLimit(200) + .build(); + let conversationsFromRealm = await myClient?.getConversations(payload); + // if uploadingFilesMessages is not empty then add those messages to the conversation list + if (Object.keys(uploadingFilesMessages)?.length > 0) { + conversationsFromRealm = [...Object.values(uploadingFilesMessages), ...conversationsFromRealm] } + dispatch({ + type: GET_CONVERSATIONS_SUCCESS, + body: { conversations: conversationsFromRealm, shimmer: false }, + }); return; } @@ -1557,6 +1553,7 @@ export const InputBoxContextProvider = ({ chatroomID?.toString(), ChatroomChatRequestState.ACCEPTED ); + localDBSyncCall() } else { if (isReply) { if (attachmentsCount > 0) { @@ -1699,12 +1696,7 @@ export const InputBoxContextProvider = ({ response?.conversation, response?.widgets ); - await syncAPI( - page, - Math.floor(Date.now() * 1000), - 0, - response?.conversation?.id - ); + await localDBSyncCall(); } else { dispatch({ type: SET_FAILED_MESSAGE_ID, @@ -1840,12 +1832,7 @@ export const InputBoxContextProvider = ({ response?.conversation, response?.widgets ); - await syncAPI( - page, - Math.floor(Date.now() * 1000), - 0, - response?.conversation?.id - ); + await localDBSyncCall() } From 626ac2b00717b14dbba108941874a618db58d405 Mon Sep 17 00:00:00 2001 From: Usman salim Date: Mon, 21 Apr 2025 06:05:49 +0530 Subject: [PATCH 6/8] added event listeners --- .../ChatSX/context/ChatroomContext.tsx | 56 +++++++++++++++---- 1 file changed, 45 insertions(+), 11 deletions(-) diff --git a/likeminds-chat-reactnative-integration/ChatSX/context/ChatroomContext.tsx b/likeminds-chat-reactnative-integration/ChatSX/context/ChatroomContext.tsx index 6eb724f9..a44b4c82 100644 --- a/likeminds-chat-reactnative-integration/ChatSX/context/ChatroomContext.tsx +++ b/likeminds-chat-reactnative-integration/ChatSX/context/ChatroomContext.tsx @@ -3,6 +3,7 @@ import React, { Dispatch, ReactNode, SetStateAction, + useCallback, useContext, useEffect, useLayoutEffect, @@ -58,6 +59,7 @@ import { LMSeverity } from "@likeminds.community/chat-rn" import { CommonActions, StackActions, + useFocusEffect, useIsFocused, useNavigation, useRoute, @@ -338,7 +340,10 @@ export const ChatroomContextProvider = ({ children }: ChatroomContextProps) => { const reactionArr = ["❤️", "😂", "😮", "😢", "😠", "👍"]; const isFocused = useIsFocused(); - const [isSocketConnected, setIsSocketConnected] = useState(false); + + const isSocketConnected = useRef(false); + const isSocketConnecting = useRef(false); + const [socketError, setSocketError] = useState(false); const [isInternet, setIsInternet] = useState(false); @@ -734,11 +739,14 @@ export const ChatroomContextProvider = ({ children }: ChatroomContextProps) => { const ChatCallback = { onSocketConnectionOpen: async () => { - setIsSocketConnected(true); + isSocketConnected.current = true; + isSocketConnecting.current = false; setSocketError(false); + // call sync API on socket connection to sync chatroom incase socket was disconnected for some time const chatroomDetails = await fetchChatroomDetails(); await fetchData(chatroomDetails, false); + console.log("WebSocket connection opened."); }, onMessageReceived: async (data) => { const conversationID = data?.conversation?.id; @@ -753,14 +761,19 @@ export const ChatroomContextProvider = ({ children }: ChatroomContextProps) => { } }, onSocketConnectionClosed: () => { - setIsSocketConnected(false); + isSocketConnected.current = false; + isSocketConnecting.current = false; + console.log("WebSocket connection closed."); }, onError: (errorMessage: string) => { - setIsSocketConnected(false); + isSocketConnecting.current = false; setSocketError(true); + console.error("WebSocket error:", errorMessage); }, }; + + useEffect(() => { const routeName = route.name; @@ -768,8 +781,9 @@ export const ChatroomContextProvider = ({ children }: ChatroomContextProps) => { return; } - if (!isSocketConnected && isFocused) { + if (!isSocketConnected.current && isFocused && !isSocketConnecting.current) { // Subscribe to a chatroom + isSocketConnecting.current = true myClient.subscribeChatroom( { chatroomId: chatroomID }, ChatCallback @@ -780,7 +794,7 @@ export const ChatroomContextProvider = ({ children }: ChatroomContextProps) => { myClient.unSubscribeChatroom(); } - }, [chatroomID, isSocketConnected, isFocused, isInternet]); + }, [chatroomID, isSocketConnected, isFocused, isInternet, socketError]); useEffect(() => { if (route.name == ScreenName.FileUpload) { @@ -792,6 +806,27 @@ export const ChatroomContextProvider = ({ children }: ChatroomContextProps) => { } }, []) + useEffect(() => { + if (route.name == ScreenName.FileUpload) { + return; + } + + const unsubscribe = AppState.addEventListener("change", (state) => { + if (state == "active" && !isSocketConnected.current && !isSocketConnecting.current) { + isSocketConnecting.current = true; + myClient.subscribeChatroom( + { chatroomId: chatroomID }, + ChatCallback + ); + } + }) + + return unsubscribe.remove + + }, [isSocketConnected, isSocketConnecting]) + + + useEffect(() => { if (route.name == ScreenName.FileUpload) { @@ -800,9 +835,8 @@ export const ChatroomContextProvider = ({ children }: ChatroomContextProps) => { const unsubscribe = NetInfo.addEventListener(state => { if (state.isInternetReachable === true) { setIsInternet(true); - } else if (state.isInternetReachable === false) { + } else if (!state.isInternetReachable) { setIsInternet(false); - setIsSocketConnected(false); } }); @@ -1143,7 +1177,7 @@ export const ChatroomContextProvider = ({ children }: ChatroomContextProps) => { page: number, data: any, conversationId?: string, - widgets?: any, + widgets?: any ) => { try { await myClient?.saveConversationData( @@ -2958,7 +2992,7 @@ export const ChatroomContextProvider = ({ children }: ChatroomContextProps) => { messageSentByUserId, uploadResourceRetry, onRetryButtonClicked, - isSocketConnected, + // isSocketConnected, setIsEditable, setIsReact, @@ -3002,7 +3036,7 @@ export const ChatroomContextProvider = ({ children }: ChatroomContextProps) => { backAction, setShimmerVisibleForChatbot, setMessageSentByUserId, - setIsSocketConnected + // setIsSocketConnected }; return ( From 92800430a90a412e4ea8e6fc73dcf47dce9ef2da Mon Sep 17 00:00:00 2001 From: Usman salim Date: Mon, 21 Apr 2025 20:17:10 +0530 Subject: [PATCH 7/8] added logic to close socket when app is in background --- .../ChatSX/context/ChatroomContext.tsx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/likeminds-chat-reactnative-integration/ChatSX/context/ChatroomContext.tsx b/likeminds-chat-reactnative-integration/ChatSX/context/ChatroomContext.tsx index a44b4c82..bdc3e0d0 100644 --- a/likeminds-chat-reactnative-integration/ChatSX/context/ChatroomContext.tsx +++ b/likeminds-chat-reactnative-integration/ChatSX/context/ChatroomContext.tsx @@ -819,6 +819,9 @@ export const ChatroomContextProvider = ({ children }: ChatroomContextProps) => { ChatCallback ); } + if (state == "background" || state == "inactive") { + myClient.unSubscribeChatroom(); + } }) return unsubscribe.remove From 4242565add4b3712dcee903277da207e22ae334f Mon Sep 17 00:00:00 2001 From: Usman salim Date: Mon, 21 Apr 2025 21:09:15 +0530 Subject: [PATCH 8/8] updated logic for retry --- .../ChatSX/components/Messages/index.tsx | 10 ++++++---- .../ChatSX/context/MessageContext.tsx | 4 +++- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/likeminds-chat-reactnative-integration/ChatSX/components/Messages/index.tsx b/likeminds-chat-reactnative-integration/ChatSX/components/Messages/index.tsx index f15e7e7c..4202723a 100644 --- a/likeminds-chat-reactnative-integration/ChatSX/components/Messages/index.tsx +++ b/likeminds-chat-reactnative-integration/ChatSX/components/Messages/index.tsx @@ -79,22 +79,24 @@ const MessagesComponent = ({ setShowRetry, setRetryUploadInProgress, retryUploadInProgress, - failedMessageId + failedMessageId, + messageUploadInProgressId } = useMessageContext(); const styles = STYLES?.$CHAT_BUBBLE_STYLE; useEffect(() => { let interval; + let isCurrentlyBeingUploaded = item?.id == messageUploadInProgressId; let uploadFailed = item?.id == failedMessageId; const checkMessageStatus = () => { const currentTimeStampEpoch = Math.floor(Date.now()); if (item?.id?.includes && item?.id?.includes("-")) { if (item?.attachments?.length > 0) { - const localTimestamp = Math.floor(Math.abs(parseInt(item?.attachmentUploadedEpoch > 0 ? item?.attachmentUploadedEpoch : item?.localSavedEpoch ?? item?.localCreatedEpoch ?? 0 ))); + const localTimestamp = Math.floor(Math.abs(parseInt(item?.attachmentUploadedEpoch))); - if ( (uploadFailed) || (currentTimeStampEpoch - localTimestamp > 30000 && ((item?.inProgress == undefined || item?.inProgress == null)) )) { + if ( (uploadFailed) || ( (!isCurrentlyBeingUploaded) && (currentTimeStampEpoch - localTimestamp > 30000 && ((item?.inProgress == undefined || item?.inProgress == null))) )) { setShowRetry(true); // Stop checking once the condition is met @@ -127,7 +129,7 @@ const MessagesComponent = ({ // Cleanup interval when component unmounts return () => clearInterval(interval); - }, [item, failedMessageId]) + }, [item, failedMessageId, messageUploadInProgressId]) const { customReactionList }: CustomReactionList = diff --git a/likeminds-chat-reactnative-integration/ChatSX/context/MessageContext.tsx b/likeminds-chat-reactnative-integration/ChatSX/context/MessageContext.tsx index fdbec4cd..e6fc20a0 100644 --- a/likeminds-chat-reactnative-integration/ChatSX/context/MessageContext.tsx +++ b/likeminds-chat-reactnative-integration/ChatSX/context/MessageContext.tsx @@ -42,6 +42,7 @@ export interface MessageContextValues { showRetry: boolean; retryUploadInProgress: boolean; failedMessageId: string; + messageUploadInProgressId; handleLongPress: (event: GestureResponderEvent) => void; setRetryUploadInProgress: Dispatch>; @@ -73,7 +74,7 @@ export const MessageContextProvider = ({ }: MessageContextProps) => { const { user } = useAppSelector((state) => state.homefeed); - const { stateArr, chatroomDBDetails, failedMessageId }: any = useAppSelector( + const { stateArr, chatroomDBDetails, failedMessageId, messageUploadInProgressId }: any = useAppSelector( (state) => state.chatroom ); @@ -198,6 +199,7 @@ export const MessageContextProvider = ({ showRetry, retryUploadInProgress, failedMessageId, + messageUploadInProgressId, setShowRetry, handleLongPress,