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 {