diff --git a/likeminds-chat-reactnative-integration/ChatSX/components/LMChatAIButton/index.tsx b/likeminds-chat-reactnative-integration/ChatSX/components/LMChatAIButton/index.tsx index e824fbd8..03480f8c 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; @@ -83,12 +84,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/Messages/index.tsx b/likeminds-chat-reactnative-integration/ChatSX/components/Messages/index.tsx index 22469f85..4202723a 100644 --- a/likeminds-chat-reactnative-integration/ChatSX/components/Messages/index.tsx +++ b/likeminds-chat-reactnative-integration/ChatSX/components/Messages/index.tsx @@ -79,13 +79,15 @@ 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 = () => { @@ -94,7 +96,7 @@ const MessagesComponent = ({ if (item?.attachments?.length > 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/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 74d5e54a..bdc3e0d0 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, @@ -23,6 +24,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, @@ -57,6 +59,7 @@ import { LMSeverity } from "@likeminds.community/chat-rn" import { CommonActions, StackActions, + useFocusEffect, useIsFocused, useNavigation, useRoute, @@ -119,6 +122,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 NetInfo from "@react-native-community/netinfo" interface UploadResource { selectedImages: Attachment[] | any[]; @@ -191,6 +195,7 @@ export interface ChatroomContextValues { refInput: any; shimmerVisibleForChatbot: boolean; messageSentByUserId: string; + isSocketConnected: boolean, // Functions setIsEditable: Dispatch>; @@ -258,6 +263,7 @@ export interface ChatroomContextValues { setRetryUploadInProgress: Dispatch>, retryUploadInProgress: boolean ) => void; + setIsSocketConnected: Dispatch> } const ChatroomContext = createContext( @@ -287,6 +293,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 @@ -294,6 +301,7 @@ export const ChatroomContextProvider = ({ children }: ChatroomContextProps) => { deepLinking: any; // Adjust the type accordingly isNavigationToSearchedConversation: any; searchedConversation: any; + isSocketConnected: any }; const refInput = useRef(); @@ -304,7 +312,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); @@ -332,6 +341,12 @@ export const ChatroomContextProvider = ({ children }: ChatroomContextProps) => { const isFocused = useIsFocused(); + const isSocketConnected = useRef(false); + const isSocketConnecting = useRef(false); + + const [socketError, setSocketError] = useState(false); + const [isInternet, setIsInternet] = useState(false); + const dispatch = useAppDispatch(); const { chatroomDetails, @@ -343,7 +358,7 @@ export const ChatroomContextProvider = ({ children }: ChatroomContextProps) => { chatroomCreator, currentChatroomTopic, temporaryStateMessage, - messageId + messageId, }: any = useAppSelector((state) => state.chatroom); const { user, community, memberRights } = useAppSelector( (state) => state.homefeed @@ -355,6 +370,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; @@ -536,7 +557,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 ); } @@ -715,6 +737,119 @@ export const ChatroomContextProvider = ({ children }: ChatroomContextProps) => { }); }, [chatroomID]); + const ChatCallback = { + onSocketConnectionOpen: async () => { + 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; + if (conversationID) { + await firebaseConversationSyncAPI( + INITIAL_SYNC_PAGE, + data?.conversation, + conversationID, + data?.widgets + ); + fetchChatroomDetails(); + } + }, + onSocketConnectionClosed: () => { + isSocketConnected.current = false; + isSocketConnecting.current = false; + console.log("WebSocket connection closed."); + }, + onError: (errorMessage: string) => { + isSocketConnecting.current = false; + setSocketError(true); + + console.error("WebSocket error:", errorMessage); + }, + }; + + + + useEffect(() => { + const routeName = route.name; + if (routeName == ScreenName.FileUpload) { + return; + } + + if (!isSocketConnected.current && isFocused && !isSocketConnecting.current) { + // Subscribe to a chatroom + isSocketConnecting.current = true + myClient.subscribeChatroom( + { chatroomId: chatroomID }, + ChatCallback + ); + } + + if (isSocketConnected && !isFocused) { + myClient.unSubscribeChatroom(); + } + + }, [chatroomID, isSocketConnected, isFocused, isInternet, socketError]); + + useEffect(() => { + if (route.name == ScreenName.FileUpload) { + return; + } + + return () => { + myClient.unSubscribeChatroom(); + } + }, []) + + 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 + ); + } + if (state == "background" || state == "inactive") { + myClient.unSubscribeChatroom(); + } + }) + + return unsubscribe.remove + + }, [isSocketConnected, isSocketConnecting]) + + + + + useEffect(() => { + if (route.name == ScreenName.FileUpload) { + return; + } + const unsubscribe = NetInfo.addEventListener(state => { + if (state.isInternetReachable === true) { + setIsInternet(true); + } else if (!state.isInternetReachable) { + setIsInternet(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(() => { if (isFound) { @@ -1003,10 +1138,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(); } @@ -1037,59 +1173,56 @@ export const ChatroomContextProvider = ({ children }: ChatroomContextProps) => { ) } } - }, [chatroomID, chatroomDBDetails, selectedMessages]) + }, [chatroomID, chatroomDBDetails, selectedMessages]); // sync conversation call with conversation_id from firebase listener const firebaseConversationSyncAPI = async ( page: number, - minTimeStamp: number, - maxTimeStamp: number, - conversationId?: string + data: any, + conversationId?: string, + widgets?: any ) => { 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, + widgets + ) - 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) .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, @@ -1107,45 +1240,12 @@ export const ChatroomContextProvider = ({ children }: ChatroomContextProps) => { LMSeverity.ERROR ) } - }; - - //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()) { - try { - 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(); - } - } catch (error) { - Client?.myClient?.handleException( - error, - error?.stack, - LMSeverity.ERROR - ) - } - } - }); - }, [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]); @@ -2235,7 +2335,7 @@ export const ChatroomContextProvider = ({ children }: ChatroomContextProps) => { 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; try { @@ -2329,7 +2429,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, @@ -2353,16 +2454,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, @@ -2567,6 +2668,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( @@ -2813,7 +2920,9 @@ export const ChatroomContextProvider = ({ children }: ChatroomContextProps) => { REQUEST_DM_LIMIT, `You can only send ${userDMLimit?.numberInDuration } DM requests per ${userDMLimit?.duration - }.\n\nTry again in ${formatTime(res?.newRequestDmTimestamp as number)}`, + }.\n\nTry again in ${formatTime( + res?.newRequestDmTimestamp as number + )}`, [ { text: CANCEL_BUTTON, @@ -2886,6 +2995,7 @@ export const ChatroomContextProvider = ({ children }: ChatroomContextProps) => { messageSentByUserId, uploadResourceRetry, onRetryButtonClicked, + // isSocketConnected, setIsEditable, setIsReact, @@ -2928,7 +3038,8 @@ export const ChatroomContextProvider = ({ children }: ChatroomContextProps) => { onReplyPrivatelyClick, backAction, setShimmerVisibleForChatbot, - setMessageSentByUserId + setMessageSentByUserId, + // setIsSocketConnected }; return ( diff --git a/likeminds-chat-reactnative-integration/ChatSX/context/InputBoxContext.tsx b/likeminds-chat-reactnative-integration/ChatSX/context/InputBoxContext.tsx index b40d55d2..1bf8d1ff 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"; @@ -347,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 @@ -818,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) { @@ -864,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], @@ -991,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( @@ -1015,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({ @@ -1166,6 +1171,23 @@ export const InputBoxContextProvider = ({ } } + 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; + } + // this method is trigerred whenever user presses the send button const onSend = async ( conversation: string, @@ -1531,6 +1553,7 @@ export const InputBoxContextProvider = ({ chatroomID?.toString(), ChatroomChatRequestState.ACCEPTED ); + localDBSyncCall() } else { if (isReply) { if (attachmentsCount > 0) { @@ -1673,6 +1696,7 @@ export const InputBoxContextProvider = ({ response?.conversation, response?.widgets ); + await localDBSyncCall(); } else { dispatch({ type: SET_FAILED_MESSAGE_ID, @@ -1804,12 +1828,13 @@ export const InputBoxContextProvider = ({ id: response?.conversation?.id, }, }); + await myClient?.replaceSavedConversation( + response?.conversation, + response?.widgets + ); + await localDBSyncCall() } - await myClient?.replaceSavedConversation( - response?.conversation, - response?.widgets - ); if (response === undefined) { dispatch({ 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, diff --git a/likeminds-chat-reactnative-integration/ChatSX/lmChatProvider/index.tsx b/likeminds-chat-reactnative-integration/ChatSX/lmChatProvider/index.tsx index 61b09484..b57d297a 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 @@ -51,12 +51,10 @@ export const LMChatBotProvider = ({ // setting lmChatInterface in CallBack class CallBack.setLMChatInterface(lmChatInterface); - }, [myClient, lmChatInterface]) + }, [myClient, lmChatInterface]); - return ( - {children} - ) -} + return {children}; +}; export const LMChatProvider = ({ myClient, @@ -110,9 +108,9 @@ export const LMChatProvider = ({ token().then((res) => { if (!!res) { - pushAPI(res, accessToken) + pushAPI(res, accessToken); } - }) + }); await dispatch(getMemberState()); } @@ -126,12 +124,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) { @@ -139,9 +139,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/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, 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 {