diff --git a/client/src/components/Chat.js b/client/src/components/Chat.js new file mode 100644 index 0000000..091154a --- /dev/null +++ b/client/src/components/Chat.js @@ -0,0 +1,75 @@ +// src/components/Chat.js +import React, { useState, useRef, useCallback, useEffect } from 'react'; +import PropTypes from 'prop-types'; +import toast from 'react-hot-toast'; +import Button from './Button'; +import ChatHandler from '../services/chatHandler'; +import ChatInput from './ChatInput'; + + +const Chat = ({ meeting_id, username, socket }) => { + const [chatHistory, setChatHistory] = useState([]); + const chatHandler = useRef(null); + + const initializeChat = () => { + if (!username) { + toast.error('Please enter a username before joining a meeting.'); + return; + } + + const errorHandler = (error) => { + console.error(error); + toast.error(error.message); + } + + // Assuming ChatHandler is a utility to handle the chat logic + chatHandler.current = new ChatHandler(meeting_id, username, socket, setChatHistory, errorHandler); + chatHandler.current.initialize(); + }; + + useEffect(() => { + initializeChat(); + }, [meeting_id, username, socket]); + + const handleSendMessage = useCallback((message) => { + if (!message.trim()) { + toast.error('Please enter a message before sending.'); + return; + } + chatHandler.current.sendMessage(message); + setChatHistory(prevHistory => [...prevHistory, { sender: username, text: message }]); + }, [username]); + + const getProfilePicture = (name) => { + return `https://ui-avatars.com/api/?name=${encodeURIComponent(name)}&background=random`; + }; + + return ( +
+

Chat

+
+ {chatHistory.map((msg, index) => ( +
+ {`${msg.sender}'s +
+ {msg.sender}: {msg.text} +
+
+ ))} +
+ +
+ ); +}; + +Chat.propTypes = { + meeting_id: PropTypes.string.isRequired, + username: PropTypes.string.isRequired, + socket: PropTypes.object.isRequired, +}; + +export default Chat; diff --git a/client/src/components/ChatInput.js b/client/src/components/ChatInput.js index f5dc353..6c9beb3 100644 --- a/client/src/components/ChatInput.js +++ b/client/src/components/ChatInput.js @@ -2,35 +2,33 @@ import React, { useRef } from 'react'; import Button from '../components/Button'; import PropTypes from 'prop-types'; -const ChatInput = ({ onSend }) => { +const ChatInputSection = ({ onSend }) => { const inputRef = useRef(); const handleSendMessage = (e) => { - e.preventDefault(); + e.preventDefault(); // Prevent the form from causing a page reload const message = inputRef.current.value.trim(); if (message) { onSend(message); inputRef.current.value = ''; // Clear the input after sending - } else { - console.error('Message cannot be empty'); } }; return ( -
+
- -
+ + ); }; -ChatInput.propTypes = { +ChatInputSection.propTypes = { onSend: PropTypes.func.isRequired, }; -export default ChatInput; +export default ChatInputSection; diff --git a/client/src/pages/MeetingPage.js b/client/src/pages/MeetingPage.js index 55f16d3..f1bc1e8 100644 --- a/client/src/pages/MeetingPage.js +++ b/client/src/pages/MeetingPage.js @@ -1,9 +1,8 @@ import React, { useState, useEffect, useRef, useCallback } from 'react'; import { useParams, useLocation, useNavigate } from 'react-router-dom'; import io from 'socket.io-client'; -import ChatHandler from '../services/chatHandler'; import RTCHandler from '../services/rtcHandler'; -import ChatInput from '../components/ChatInput'; +import Chat from '../components/Chat'; import Button from '../components/Button'; import toast, { Toaster } from 'react-hot-toast'; @@ -22,9 +21,6 @@ const MeetingPage = () => { const [isMuted, setIsMuted] = useState(false); const [isVideoOff, setIsVideoOff] = useState(false); - const chatHandler = useRef(null); - const [chatHistory, setChatHistory] = useState([]); - const initializeMeeting = () => { if (!username) { toast.error('Please enter a username before joining a meeting.'); @@ -47,10 +43,8 @@ const MeetingPage = () => { console.error(error); navigate('/'); toast.error(error.message); - } + }; - chatHandler.current = new ChatHandler(meeting_id, username, socketRef.current, setChatHistory, errorHandler); - chatHandler.current.initialize(); rtcHandler.current = new RTCHandler(meeting_id, username, socketRef.current, setPeers, errorHandler); rtcHandler.current.initialize(); }; @@ -61,16 +55,14 @@ const MeetingPage = () => { return () => { rtcHandler.current.cleanup(); socketRef.current.disconnect(); - } + }; }, []); const toggleMute = () => { setIsMuted(prevState => { const newMutedState = !prevState; - // Mute or unmute the audio track in the local stream if (rtcHandler.current && rtcHandler.current.localStream) { rtcHandler.current.localStream.getAudioTracks().forEach(track => { - console.log(track); track.enabled = !newMutedState; }); } @@ -81,10 +73,8 @@ const MeetingPage = () => { const toggleVideo = () => { setIsVideoOff(prevState => { const newVideoState = !prevState; - // Turn on or off the video track in the local stream if (rtcHandler.current && rtcHandler.current.localStream) { rtcHandler.current.localStream.getVideoTracks().forEach(track => { - console.log(track); track.enabled = !newVideoState; }); } @@ -92,24 +82,6 @@ const MeetingPage = () => { }); }; - const handleSendMessage = useCallback((message) => { - if (!message.trim()) { - toast.error('Please enter a message before sending.'); - return; - } - chatHandler.current.sendMessage(message); - setChatHistory(prevHistory => [...prevHistory, { sender: username, text: message }]); - }, [username]); - - - const getProfilePicture = (name) => { - return `https://ui-avatars.com/api/?name=${encodeURIComponent(name)}&background=random`; - }; - - if (!username || !rtcHandler.current) { - return null; - } - const VideoElement = React.memo(({ stream, muted, peerName }) => { const videoRef = useRef(); @@ -121,29 +93,15 @@ const MeetingPage = () => { return (
-
); }); - const ChatMessages = React.memo(({ chatHistory }) => ( -
- {chatHistory.map((msg, index) => ( -
- {`${msg.sender}'s -
- {msg.sender}: {msg.text} -
-
- ))} -
- )); - + if (!username || !rtcHandler.current) { + return null; + } return (
@@ -154,23 +112,21 @@ const MeetingPage = () => {
- + {rtcHandler.current.localStream && ( + + )} {Object.entries(peers).map(([peerUsername, peer]) => ( peerUsername !== username && ( - ) ))}
-
-

Chat

- - -
+