diff --git a/api-server/test.js b/api-server/test.js
deleted file mode 100644
index ec5b490..0000000
--- a/api-server/test.js
+++ /dev/null
@@ -1,20 +0,0 @@
-import { io } from 'socket.io-client';
-
-const socket = io('http://127.0.0.1:5000');
-
-// Join a room with a specific meeting ID
-socket.emit('join', { 'username': 'teet', meeting_id: 'e45f73db-9973-4acd-9467-c48f56b26804' });
-
-// Emit the SDP offer immediately
-socket.emit('offer', { meeting_id: 'e45f73db-9973-4acd-9467-c48f56b26804', sdp: '...' });
-
-// Simulate receiving the offer and sending back an SDP answer after 1 second
-socket.emit('answer', { meeting_id: 'e45f73db-9973-4acd-9467-c48f56b26804', sdp: 'v=0\r\no=- 25678 753849 IN IP4 192.0.2.2\r\ns=-\r\nc=IN IP4 192.0.2.2\r\nt=0 0\r\na=recvonly\r\nm=video 49170 RTP/AVP 98\r\na=rtpmap:98 H264/90000\r\n' });
-
-// Simulate sending ICE candidates after 2 seconds
-socket.emit('ice_candidate', { meeting_id: 'e45f73db-9973-4acd-9467-c48f56b2', candidate: 'candidate:842163049 1 udp 1677729535 192.0.2.1 3478 typ srflx raddr 192.0.2.1 rport 3478' });
-
-// Listen for events
-socket.on('offer', (data) => console.log('Received offer:', data));
-socket.on('answer', (data) => console.log('Received answer:', data));
-socket.on('ice_candidate', (data) => console.log('Received ICE candidate:', data));
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}: {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
new file mode 100644
index 0000000..6c9beb3
--- /dev/null
+++ b/client/src/components/ChatInput.js
@@ -0,0 +1,34 @@
+import React, { useRef } from 'react';
+import Button from '../components/Button';
+import PropTypes from 'prop-types';
+
+const ChatInputSection = ({ onSend }) => {
+ const inputRef = useRef();
+
+ const handleSendMessage = (e) => {
+ 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
+ }
+ };
+
+ return (
+
+ );
+};
+
+ChatInputSection.propTypes = {
+ onSend: PropTypes.func.isRequired,
+};
+
+export default ChatInputSection;
diff --git a/client/src/pages/MeetingPage.js b/client/src/pages/MeetingPage.js
index d5af21c..f1bc1e8 100644
--- a/client/src/pages/MeetingPage.js
+++ b/client/src/pages/MeetingPage.js
@@ -1,8 +1,8 @@
-import React, { useState, useEffect, useRef } from 'react';
+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 Chat from '../components/Chat';
import Button from '../components/Button';
import toast, { Toaster } from 'react-hot-toast';
@@ -21,11 +21,7 @@ const MeetingPage = () => {
const [isMuted, setIsMuted] = useState(false);
const [isVideoOff, setIsVideoOff] = useState(false);
- const chatHandler = useRef(null);
- const [chatHistory, setChatHistory] = useState([]);
- const [message, setMessage] = useState('');
-
- useEffect(() => {
+ const initializeMeeting = () => {
if (!username) {
toast.error('Please enter a username before joining a meeting.');
navigate('/');
@@ -47,25 +43,26 @@ 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();
+ };
+
+ useEffect(() => {
+ initializeMeeting();
+
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;
});
}
@@ -76,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;
});
}
@@ -87,24 +82,6 @@ const MeetingPage = () => {
});
};
- const sendMessage = (e) => {
- e.preventDefault();
- if (!message.trim()) {
- toast.error('Please enter a message before sending.');
- return;
- }
- chatHandler.current.sendMessage(message);
- setMessage('');
- };
-
- 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();
@@ -116,12 +93,16 @@ const MeetingPage = () => {
return (
);
});
+ if (!username || !rtcHandler.current) {
+ return null;
+ }
+
return (
@@ -131,45 +112,21 @@ const MeetingPage = () => {
-
+ {rtcHandler.current.localStream && (
+
+ )}
{Object.entries(peers).map(([peerUsername, peer]) => (
peerUsername !== username && (
-
)
))}
-
-
Chat
-
- {chatHistory.map((msg, index) => (
-
-
-
- {msg.sender}: {msg.text}
-
-
- ))}
-
-
-
+