From 2f0e2a6fa6ee622a85b7dd1d4391d24b61e88c0d Mon Sep 17 00:00:00 2001 From: LuseBiswas Date: Thu, 5 Sep 2024 20:24:25 +0530 Subject: [PATCH 1/5] Moving Reconnect banner to its own component. --- client/src/components/BuddyMatcher.jsx | 20 +++-------------- client/src/components/ReconnectBanner.jsx | 27 +++++++++++++++++++++++ package-lock.json | 6 +++++ 3 files changed, 36 insertions(+), 17 deletions(-) create mode 100644 client/src/components/ReconnectBanner.jsx create mode 100644 package-lock.json diff --git a/client/src/components/BuddyMatcher.jsx b/client/src/components/BuddyMatcher.jsx index d32ea865..873db5b9 100644 --- a/client/src/components/BuddyMatcher.jsx +++ b/client/src/components/BuddyMatcher.jsx @@ -4,6 +4,7 @@ import { PiPlugsLight } from 'react-icons/pi'; import { connectWithId, socket } from 'src/lib/socketConnection'; import Anonymous from 'components/Anonymous'; +import ReconnectBanner from 'components/ReconnectBanner'; import { useAuth } from 'src/context/AuthContext'; import { useChat } from 'src/context/ChatContext'; import { useNavigate, Link } from 'react-router-dom'; @@ -258,23 +259,8 @@ const BuddyMatcher = () => { )} ) : disconnected ? ( -
- -

Sorry, it seems you're not connected

-
- - - Return Home - -
-
+ + //Changes made here with moviing reconnector to another component. ) : ( { + return ( +
+ +

Sorry, it seems you're not connected

+
+ + + Return Home + +
+
+ ); +}; + +export default ReconnectBanner; diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 00000000..eba05423 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,6 @@ +{ + "name": "Whisper", + "lockfileVersion": 3, + "requires": true, + "packages": {} +} From aa497151365f5942bc42dc477e299f7312a7a38d Mon Sep 17 00:00:00 2001 From: Ritesh Biswas Date: Fri, 6 Sep 2024 17:42:09 +0530 Subject: [PATCH 2/5] Update ReconnectBanner.jsx --- client/src/components/ReconnectBanner.jsx | 46 +++++++++++++---------- 1 file changed, 26 insertions(+), 20 deletions(-) diff --git a/client/src/components/ReconnectBanner.jsx b/client/src/components/ReconnectBanner.jsx index acceee11..530c8dae 100644 --- a/client/src/components/ReconnectBanner.jsx +++ b/client/src/components/ReconnectBanner.jsx @@ -1,27 +1,33 @@ import React from 'react'; +import PropTypes from 'prop-types'; // Import the PropTypes package import { PiPlugsLight } from 'react-icons/pi'; import { Link } from 'react-router-dom'; - const ReconnectBanner = ({ handleReconnect }) => { - return ( -
- -

Sorry, it seems you're not connected

-
- + - Try again - - - Return Home - -
-
- ); + Return Home + + + + ); +}; +// Define the expected prop types +ReconnectBanner.propTypes = { + handleReconnect: PropTypes.func.isRequired, }; - export default ReconnectBanner; From 8d840142297adb29104355c9414dd1545a2c11be Mon Sep 17 00:00:00 2001 From: Ritesh Biswas Date: Fri, 6 Sep 2024 17:42:54 +0530 Subject: [PATCH 3/5] Update BuddyMatcher.jsx --- client/src/components/BuddyMatcher.jsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/client/src/components/BuddyMatcher.jsx b/client/src/components/BuddyMatcher.jsx index 873db5b9..37e28d43 100644 --- a/client/src/components/BuddyMatcher.jsx +++ b/client/src/components/BuddyMatcher.jsx @@ -1,13 +1,13 @@ import { useState, useEffect, useRef, useCallback } from 'react'; import { ThreeDots } from 'react-loading-icons'; -import { PiPlugsLight } from 'react-icons/pi'; +//import { PiPlugsLight } from 'react-icons/pi'; import { connectWithId, socket } from 'src/lib/socketConnection'; import Anonymous from 'components/Anonymous'; import ReconnectBanner from 'components/ReconnectBanner'; import { useAuth } from 'src/context/AuthContext'; import { useChat } from 'src/context/ChatContext'; -import { useNavigate, Link } from 'react-router-dom'; +//import { useNavigate, Link } from 'react-router-dom'; import { useNotification } from 'src/lib/notification'; import { useApp } from 'src/context/AppContext'; import { createBrowserNotification } from 'src/lib/browserNotification'; @@ -24,6 +24,7 @@ import { NEW_EVENT_STOP_SEARCH, NEW_EVENT_STOP_SEARCH_SUCCESS, } from '../../../constants.json'; +import { useNavigate } from 'react-router-dom'; const stoppingSearchLoadingText =

Stopping the search

; const BuddyMatcher = () => { @@ -267,5 +268,4 @@ const BuddyMatcher = () => { /> ); }; - export default BuddyMatcher; From b0901c82fee7ebcf0c852e7fb95ddd9d9286c4ed Mon Sep 17 00:00:00 2001 From: LuseBiswas Date: Fri, 6 Sep 2024 20:33:31 +0530 Subject: [PATCH 4/5] Updating all the things according to the instructions --- client/src/App.jsx | 74 +++-- client/src/components/Anonymous.jsx | 2 +- client/src/components/BuddyMatcher.jsx | 65 ++-- client/src/components/Chat.jsx | 39 +-- client/src/components/Chat/DropDownOption.jsx | 9 +- client/src/components/Chat/MessageInput.jsx | 104 +++---- client/src/components/Chat/MessageSeen.jsx | 10 +- client/src/components/Loading.jsx | 16 +- client/src/components/NavBar.jsx | 2 +- client/src/components/ReconnectBanner.jsx | 10 +- client/src/hooks/useObserver.js | 56 ++-- client/src/index.jsx | 8 +- client/src/lib/socketConnection.js | 4 +- client/src/pages/Home.jsx | 99 ++++--- client/src/pages/Login.jsx | 277 +++++++++--------- client/src/pages/Settings.jsx | 2 +- 16 files changed, 380 insertions(+), 397 deletions(-) diff --git a/client/src/App.jsx b/client/src/App.jsx index 6b9d0f43..483484ce 100644 --- a/client/src/App.jsx +++ b/client/src/App.jsx @@ -16,52 +16,50 @@ import { useAuth } from 'context/AuthContext'; import useIsTabActive from './hooks/useIsTabActive'; function App() { - ReactGA.initialize(import.meta.env.VITE_GOOGLE_ANALYTICS); + ReactGA.initialize(import.meta.env.VITE_GOOGLE_ANALYTICS); - const { isLoggedIn } = useAuth(); - const { updateOnlineStatus, app } = useApp(); + const { isLoggedIn } = useAuth(); + const { updateOnlineStatus, app } = useApp(); - const { settings } = app; - const [onlineStatus, setOnlineStatus] = useState(null); + const { settings } = app; + const [onlineStatus, setOnlineStatus] = useState(null); - const isTabActive = useIsTabActive(); + const isTabActive = useIsTabActive(); - useEffect(() => { - if (!isLoggedIn) { - return; - } + useEffect(() => { + if (!isLoggedIn) { + return; + } - if (isTabActive) { - setOnlineStatus('online'); - } else { - setOnlineStatus(new Date()); - } - }, [isTabActive]); + if (isTabActive) { + setOnlineStatus('online'); + } else { + setOnlineStatus(new Date()); + } + }, [isTabActive]); - useEffect(() => { - updateOnlineStatus(onlineStatus); - }, [onlineStatus]); + useEffect(() => { + updateOnlineStatus(onlineStatus); + }, [onlineStatus]); - return ( + return ( +
+ {isLoggedIn && } + + }> + } /> + {/* TODO: Sepreate searching and foundUser into different routes */} + } /> + } /> + } /> + } /> + -
- {isLoggedIn && } - - }> - } /> - {/* TODO: Sepreate searching and foundUser into different routes */} - } /> - } /> - } /> - } /> - - - : } /> - } /> - -
- - ); + : } /> + } /> +
+
+ ); } export default App; diff --git a/client/src/components/Anonymous.jsx b/client/src/components/Anonymous.jsx index e6b6645e..899b3a1a 100644 --- a/client/src/components/Anonymous.jsx +++ b/client/src/components/Anonymous.jsx @@ -14,7 +14,7 @@ import { Dropdown, IconButton, Tooltip, Whisper } from 'rsuite'; import { Icon } from '@rsuite/icons'; // Icons -import { BiArrowBack} from 'react-icons/bi'; +import { BiArrowBack } from 'react-icons/bi'; // Store import { socket } from 'src/lib/socketConnection'; diff --git a/client/src/components/BuddyMatcher.jsx b/client/src/components/BuddyMatcher.jsx index 37e28d43..cb027974 100644 --- a/client/src/components/BuddyMatcher.jsx +++ b/client/src/components/BuddyMatcher.jsx @@ -1,13 +1,10 @@ import { useState, useEffect, useRef, useCallback } from 'react'; import { ThreeDots } from 'react-loading-icons'; -//import { PiPlugsLight } from 'react-icons/pi'; import { connectWithId, socket } from 'src/lib/socketConnection'; - import Anonymous from 'components/Anonymous'; import ReconnectBanner from 'components/ReconnectBanner'; import { useAuth } from 'src/context/AuthContext'; import { useChat } from 'src/context/ChatContext'; -//import { useNavigate, Link } from 'react-router-dom'; import { useNotification } from 'src/lib/notification'; import { useApp } from 'src/context/AppContext'; import { createBrowserNotification } from 'src/lib/browserNotification'; @@ -40,7 +37,7 @@ const BuddyMatcher = () => { const userID = authState.loginId; const defaultLoadingText =

Looking for a random buddy

; - const [loadingText, setLoadingText] = useState(defaultLoadingText); + const [loadingText, setLoadingText] = useState(defaultLoadingText); let timeout = null; function disconnect() { @@ -58,25 +55,25 @@ const BuddyMatcher = () => { socket.volatile.emit(NEW_EVENT_JOIN, { loginId: authState.loginId, email: authState.email, - }) - }, []) + }); + }, []); const emitStopSearch = useCallback(() => { socket.emit(NEW_EVENT_STOP_SEARCH, { loginId: authState.loginId, email: authState.email, }); - }, []) + }, []); const startNewSearch = () => { startSearch(); setLoadingText(defaultLoadingText); - emitJoin() + emitJoin(); }; const handleStopSearch = () => { - emitStopSearch() + emitStopSearch(); setIsStoppingSearch(true); }; @@ -87,9 +84,9 @@ const BuddyMatcher = () => { startSearch(); setLoadingText(defaultLoadingText); - connectWithId(app.currentChatId) + connectWithId(app.currentChatId); } - + const onUserJoined = useCallback(({ roomId, userIds }) => { playNotification('buddyPaired'); createBrowserNotification( @@ -98,20 +95,20 @@ const BuddyMatcher = () => { ); createChat(roomId, userIds); endSearch(roomId); - }, []) + }, []); const onRestoreChat = useCallback(({ chats, currentChatId }) => { Object.values(chats).forEach((chat) => { createChat(chat.id, chat.userIds, chat.messages, chat.createdAt); }); endSearch(currentChatId); - }, []) + }, []); - const onStopSearch = useCallback( () => { + const onStopSearch = useCallback(() => { setIsStoppingSearch(false); endSearch(); navigate('/'); - }, []) + }, []); const onConnect = useCallback(() => { // Here server will be informed that user is searching for @@ -121,7 +118,7 @@ const BuddyMatcher = () => { email: authState.email, }); setDisconnected(false); - }, []) + }, []); const onClose = useCallback((chatId) => { endSearch(); @@ -135,11 +132,11 @@ const BuddyMatcher = () => { createBrowserNotification('Chat Closed', 'Your buddy left the chat'); startNewSearch(); - }, []) + }, []); const onInactive = useCallback(() => { closeAllChats(); - }, []) + }, []); const onDisconnect = useCallback((reason) => { if (isExplicitDisconnection(reason)) { @@ -147,28 +144,26 @@ const BuddyMatcher = () => { } disconnect(); - }, []) + }, []); const onReconnectAttempt = useCallback((attempts) => { reconnectAttempts.current = attempts; - }, []) + }, []); const onReconnectError = useCallback(() => { if (reconnectAttempts.current >= 3) { disconnect(); } - }, []) + }, []); const emitCreateRoom = useCallback(() => { socket.emit(NEW_EVENT_CREATE_ROOM, `${userID}-in-search`); - }, []) + }, []); const emitAddingUser = useCallback(() => { socket.emit(NEW_EVENT_ADDING, { userID }); - }, []) - + }, []); - useEffect(() => { setLoadingText(isStoppingSearch ? stoppingSearchLoadingText : defaultLoadingText); }, [isStoppingSearch]); @@ -209,15 +204,15 @@ const BuddyMatcher = () => { } if (!socket.connected) { - connectWithId(app.currentChatId) + connectWithId(app.currentChatId); } - - emitCreateRoom() - socket.connected && emitAddingUser() + + emitCreateRoom(); + socket.connected && emitAddingUser(); // This is necessary else chat won't be restored after re-connections socket.on('connect', onConnect); - socket.on(NEW_EVENT_CLOSE, onClose); + socket.on(NEW_EVENT_CLOSE, onClose); // From here will get the info from server that user has joined the room socket.on(NEW_EVENT_JOINED, onUserJoined); socket.on(NEW_EVENT_CHAT_RESTORE, onRestoreChat); @@ -230,7 +225,7 @@ const BuddyMatcher = () => { return () => { socket .off('connect', onConnect) - .off(NEW_EVENT_JOINED, onUserJoined) + .off(NEW_EVENT_JOINED, onUserJoined) .off(NEW_EVENT_CHAT_RESTORE, onRestoreChat) .off(NEW_EVENT_CLOSE, onClose) .off(NEW_EVENT_INACTIVE, onInactive) @@ -260,12 +255,10 @@ const BuddyMatcher = () => { )} ) : disconnected ? ( - - //Changes made here with moviing reconnector to another component. + ) : ( - + //Changes made here with moviing reconnector to another component. + ); }; export default BuddyMatcher; diff --git a/client/src/components/Chat.jsx b/client/src/components/Chat.jsx index 89b92ad6..52731c94 100644 --- a/client/src/components/Chat.jsx +++ b/client/src/components/Chat.jsx @@ -270,16 +270,19 @@ const Chat = () => { return decryptedMessages.find((object) => object.id === replyTo); } - const onNewMessageHandler = useCallback(async (message) => { - try { - const decryptedMessage = await decryptMessage(message.message, cryptoKeyRef.current); - addMessage(message); - playNotification('newMessage'); - createBrowserNotification('You received a new message on Whisper', decryptedMessage); - } catch (error) { - console.error(`Could not decrypt message: ${error.message}`, error); - } - }, [cryptoKey]); + const onNewMessageHandler = useCallback( + async (message) => { + try { + const decryptedMessage = await decryptMessage(message.message, cryptoKeyRef.current); + addMessage(message); + playNotification('newMessage'); + createBrowserNotification('You received a new message on Whisper', decryptedMessage); + } catch (error) { + console.error(`Could not decrypt message: ${error.message}`, error); + } + }, + [cryptoKey] + ); const onDeleteMessageHandler = useCallback(({ id, chatId }) => { removeMessage(id, chatId); @@ -297,15 +300,13 @@ const Chat = () => { receiveMessage(messageId, chatId); }, []); - const onPublicStringHandler = useCallback(({ pemPublicKeyString, pemPrivateKeyString }) => { - const pemPublicKeyArrayBuffer = pemToArrayBuffer(pemPublicKeyString); - const pemPrivateKeyArrayBuffer = pemToArrayBuffer(pemPrivateKeyString); - - // Import PEM-formatted public key as CryptoKey - importKey(pemPublicKeyArrayBuffer, pemPrivateKeyArrayBuffer); - }, []); - + const onPublicStringHandler = useCallback(({ pemPublicKeyString, pemPrivateKeyString }) => { + const pemPublicKeyArrayBuffer = pemToArrayBuffer(pemPublicKeyString); + const pemPrivateKeyArrayBuffer = pemToArrayBuffer(pemPrivateKeyString); + // Import PEM-formatted public key as CryptoKey + importKey(pemPublicKeyArrayBuffer, pemPrivateKeyArrayBuffer); + }, []); // Clear chat when escape is pressed useEffect(() => { @@ -612,4 +613,4 @@ const Chat = () => { ); }; -export default Chat; \ No newline at end of file +export default Chat; diff --git a/client/src/components/Chat/DropDownOption.jsx b/client/src/components/Chat/DropDownOption.jsx index 496f43d9..f99eb75f 100644 --- a/client/src/components/Chat/DropDownOption.jsx +++ b/client/src/components/Chat/DropDownOption.jsx @@ -12,7 +12,7 @@ import useCryptoKeys from 'src/hooks/useCryptoKeys'; const DropDownOptions = ({ id, isSender, inputRef, cancelEdit, setEditing, setReplyId }) => { const { app } = useApp(); - const { importedPrivateKey, cryptoKey } = useCryptoKeys(app.currentChatId) + const { importedPrivateKey, cryptoKey } = useCryptoKeys(app.currentChatId); const { messages: state, updateMessage, removeMessage } = useChat(); const { getMessage, messageExists, handleCopyToClipBoard } = chatHelper(state, app); const { deleteMessage } = useChatUtils(socket); @@ -85,8 +85,9 @@ const DropDownOptions = ({ id, isSender, inputRef, cancelEdit, setEditing, setRe > handleEdit(id)}>Edit - - handleCopyToClipBoard(id, importedPrivateKey)}>Copy + handleCopyToClipBoard(id, importedPrivateKey)}> + Copy + setReplyId(id)}>Reply handleDelete(id)}>Delete @@ -101,7 +102,7 @@ const DropDownOptions = ({ id, isSender, inputRef, cancelEdit, setEditing, setRe renderToggle={renderIconButtonReceiver} NoCaret > - handleCopyToClipBoard(id, cryptoKey)}>Copy + handleCopyToClipBoard(id, cryptoKey)}>Copy setReplyId(id)}>Reply ); diff --git a/client/src/components/Chat/MessageInput.jsx b/client/src/components/Chat/MessageInput.jsx index 248565a2..4119db0f 100644 --- a/client/src/components/Chat/MessageInput.jsx +++ b/client/src/components/Chat/MessageInput.jsx @@ -59,61 +59,61 @@ const MessageInput = ({ return (
- {currentReplyMessage && ( -
-
- - {typeof currentReplyMessage.message !== 'string' ? ( -
{currentReplyMessage.message}
- ) : ( -
scrollToMessage(currentReplyMessageId)} - > - {currentReplyMessage.senderId.toString() === senderId.toString() - ? 'Replying Yourself' - : 'Replying to Buddy'} -
- )} -
- cancelReply(null)} - className="fill-white scale-150 cursor-pointer" - /> -
- )} -
-
-