Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
bc35420
remove chat button for now
apsinghdev Aug 20, 2024
8400ff0
remove unnecessary code
apsinghdev Aug 22, 2024
adf14dd
install uuid
apsinghdev Sep 2, 2024
4fe444d
feat: generate the collaboraion link
apsinghdev Sep 2, 2024
2648d9f
feat: add message feature and collaboration flag
apsinghdev Sep 3, 2024
36c8a44
feat: add collaboration flag to initiate collaboraion specific functions
apsinghdev Sep 3, 2024
66759c9
feat: add logic to stop the collaboration and disconnect the socket
apsinghdev Sep 3, 2024
f411c1d
feat: add rooms feature
apsinghdev Sep 3, 2024
b2c793d
feat: add custom state management mechanism using a class
apsinghdev Sep 3, 2024
b21192d
feat: add logic to make socket connection only when there is a roomID…
apsinghdev Sep 3, 2024
25954e4
refactor: store roomID in a variable
apsinghdev Sep 3, 2024
f6291eb
fix: store the socket in socket variable and change the collaboration…
apsinghdev Sep 3, 2024
52294fc
fix: fixed state management of socket using context API
apsinghdev Sep 4, 2024
b8532a1
refactor: correct the spelling of hasCollaborationStarted
apsinghdev Sep 4, 2024
450d99e
fix: fix the non-consistent behaviour of the text editor
apsinghdev Sep 4, 2024
2f5eef7
chore: remove testing console log
apsinghdev Sep 4, 2024
60e5d34
feat: connect the collaboration logic with Start-collaboration button
apsinghdev Sep 4, 2024
97c2db0
chore: store the url in a variable
apsinghdev Sep 4, 2024
a6e5820
feat: limit the socket calls in case ofserver-not-found
apsinghdev Sep 4, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 21 additions & 7 deletions api/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,26 +27,40 @@ app.get('/test', (res) => {
})

io.on('connection', (socket) => {
console.log('user connected socket')

socket.on('joinRoom', ({room_id}) => {
socket.join(room_id);
console.log(`User ${socket.id} joined room ${room_id}`);
})

socket.on('draw', (data)=>{
socket.broadcast.emit('draw', data);
const room = data.room_id;
socket.to(room).emit('draw', data);
})

socket.on('clear', () => {
io.emit('clear');
socket.on('clear', (data) => {
const room = data.room_id;
socket.to(room).emit('clear');
})

socket.on('open-text-editor', data => {
socket.broadcast.emit("open-text-editor", data);
const room = data.room_id;
socket.to(room).emit("open-text-editor", data);
})

socket.on('close-text-editor', data => {
socket.broadcast.emit("close-text-editor", data);
const room = data.room_id;
socket.to(room).emit("close-text-editor", data);
})

socket.on("text-updated", (data) => {
socket.broadcast.emit("text-updated", data);
const room = data.room_id;
socket.to(room).emit("text-updated", data);
});

socket.on("disconnect", () => {
console.log(`${socket.id} disconnected`);
})
})

server.listen(PORT, ()=>{
Expand Down
1 change: 0 additions & 1 deletion client/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,5 @@
<body>
<div id="root"></div>
<script type="module" src="/src/main.jsx"></script>
<script src="./src/socket.js"></script>
</body>
</html>
14 changes: 14 additions & 0 deletions client/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"react-icons": "^5.2.0",
"recoil": "^0.7.7",
"socket.io-client": "^4.7.4",
"uuid": "^10.0.0",
"y-socket.io": "^1.1.3",
"yjs": "^13.6.15"
},
Expand Down
140 changes: 112 additions & 28 deletions client/src/App.jsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,29 @@
/* eslint-disable react-hooks/exhaustive-deps */
import { useEffect, useRef, useState } from "react";
import { io } from "socket.io-client";
import "./App.css";
import socket from "./socket";

import InfoMsg from "./components/InfoMsg";
import Sidebar from "./components/Sidebar";
import Canvas from "./components/Canvas";
import Menu from "./components/Menu";
import EraserCursor from "./components/EraserCursor";
import TextEditor from "./components/TextEditor";
import { useRecoilValue, useRecoilState } from "recoil";
import { useRecoilValue, useRecoilState, useSetRecoilState } from "recoil";
import {
eraserState,
cursorPosition,
canvasColors,
canvasState,
showMenuState,
showTextEditor,
collaborationStarted,
showMsg,
roomIdAtom,
messageTxtAtom
} from "./atoms";
import { useSocket } from "./Context";

socket.connect();
const PORT = "http://localhost:8000";

function App() {
const [showMenu, setShowMenu] = useRecoilState(showMenuState);
Expand All @@ -32,7 +37,13 @@ function App() {
const canvasColor = useRecoilValue(canvasColors);
const [currentCanvas, setCanvas] = useRecoilState(canvasState);
const textEditor = useRecoilValue(showTextEditor);

const setTextEditor = useSetRecoilState(showTextEditor);
const hasCollaborationStarted = useRecoilValue(collaborationStarted);
const setCollaborationFlag = useSetRecoilState(collaborationStarted);
const [showMessage, setShowMsg] = useRecoilState(showMsg);
const [roomId, setRoomId] = useRecoilState(roomIdAtom);
const { socket, setSocket } = useSocket();
const [ messageText, setMessageText ] = useRecoilState(messageTxtAtom);

function toggleMenu() {
setShowMenu(!showMenu);
Expand Down Expand Up @@ -76,7 +87,9 @@ function App() {
const endX = e.clientX - canvas.getBoundingClientRect().left;
const endY = e.clientY - canvas.getBoundingClientRect().top;
drawLine(startX, startY, endX, endY, penColor);
socket.emit("draw", { startX, startY, endX, endY, penColor, lineWidth });
if (hasCollaborationStarted && socket) {
socket.emit("draw", { startX, startY, endX, endY, penColor, lineWidth, room_id: roomId });
}
setStartX(endX);
setStartY(endY);
}
Expand Down Expand Up @@ -104,29 +117,31 @@ function App() {
canvas.removeEventListener("mousedown", handleMousedown);
canvas.removeEventListener("mouseup", handleMouseup);
};
}, [penColor, eraserMode, position, ctx, isDrawing, startX, startY]);
}, [socket, penColor, eraserMode, position, ctx, isDrawing, startX, startY]);

useEffect(() => {
socket.on("draw", (data) => {
drawLine(
data.startX,
data.startY,
data.endX,
data.endY,
data.penColor,
data.lineWidth
);
});

socket.on("clear", () => {
clearRect();
});

return () => {
socket.off("draw");
socket.off("clear");
};
}, [socket, ctx]);
if (hasCollaborationStarted && socket) {
socket.on("draw", (data) => {
drawLine(
data.startX,
data.startY,
data.endX,
data.endY,
data.penColor,
data.lineWidth
);
});

socket.on("clear", () => {
clearRect();
});

return () => {
socket.off("draw");
socket.off("clear");
};
}
}, [socket, ctx, hasCollaborationStarted]);

function clearRect() {
if (ctx) {
Expand All @@ -136,7 +151,10 @@ function App() {

function clearOnClick() {
clearRect();
socket.emit("clear");
if (hasCollaborationStarted && socket) {
const data = {room_id: roomId};
socket.emit("clear", data);
}
}

function addStroke(e) {
Expand All @@ -158,6 +176,71 @@ function App() {
}
}

const closeMsg = () => {
setMessageText(null);
setShowMsg(false);
}

useEffect(() => {
const urlParams = new URLSearchParams(window.location.search);
const roomID = urlParams.get("roomID");
const RETRIES = 5;
const DELAY_DURATION = 2000;
let attempts = 0;

const closeConnection = (socket) => {
if (attempts >= RETRIES) {
socket.disconnect();
setCollaborationFlag(false);
console.log("Max socket calls exceeded. Please try connecting again.")
}
}

if (roomID) {
const collaborationLink = window.location.href;
setRoomId(roomID);
setCollaborationFlag(true);
const newSocket = io(PORT);

try {
newSocket.on("connect", () => {
console.log("connected");
try {
newSocket.emit("joinRoom", { room_id: roomID });
console.log(`joined room ${roomID}`);
setSocket(newSocket);
setMessageText(`Collaboration Link : ${collaborationLink}`);
setShowMsg(true);
} catch (error) {
console.log("Can't join the room", error);
}
});

newSocket.on("connect_error", (error) => {
attempts++;
console.log("Failed to connect to the socket server. Retrying...")
setTimeout(() => closeConnection(newSocket), DELAY_DURATION);
})

} catch (error) {
console.log("Can't connect", error);
}
}
}, []);

// Hook to listen the events emitted by the server
useEffect(() => {
if (hasCollaborationStarted && socket) {
socket.on("open-text-editor", () => {
setTextEditor(true);
});

return () => {
socket.off("open-text-editor");
};
}
}, [showTextEditor, socket, hasCollaborationStarted]);

return (
<div id="container">
<Sidebar
Expand All @@ -172,6 +255,7 @@ function App() {
{eraserMode && <EraserCursor></EraserCursor>}
{showMenu && <Menu></Menu>}
{textEditor && <TextEditor></TextEditor>}
{showMessage && <InfoMsg message={messageText} clickHandler={closeMsg}></InfoMsg>}
</div>
);
}
Expand Down
20 changes: 20 additions & 0 deletions client/src/Context.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import React, { createContext, useContext, useState } from 'react';

// Create a Context for the socket
const SocketContext = createContext(null);

// Create a custom hook to use the SocketContext
export const useSocket = () => {
return useContext(SocketContext);
};

// Create a provider component
export const SocketProvider = ({ children }) => {
const [socket, setSocket] = useState(null);

return (
<SocketContext.Provider value={{ socket, setSocket }}>
{children}
</SocketContext.Provider>
);
};
22 changes: 21 additions & 1 deletion client/src/atoms.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,24 @@ export const showTextEditor = atom({
export const textEditorInput = atom({
key: "textEditorInput",
default: ''
})
})

export const collaborationStarted = atom({
key: "collaboraionstarted",
default: false
})

export const showMsg = atom({
key: "showMsg",
default: false
})

export const roomIdAtom = atom({
key: "roomIdAtom",
default: null
})

export const messageTxtAtom = atom({
key: "msgTxtAtom",
default: null
});
10 changes: 10 additions & 0 deletions client/src/components/InfoMsg.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
const InfoMsg = (props) => {
return (
<div className="fixed top-4 left-1/2 transform -translate-x-1/2 inline-block max-w-lg max-h-40 overflow-auto p-3 m-2 max-w-full break-words rounded-xl bg-gradient-to-r from-slate-900 to-slate-700 absolute rounded-lg shadow-xl content-center animate-slide-in" >
<h6 className="font-sans text-emerald-300 cursor-pointer justify-center flex absolute top-0 right-2 mb-1" onClick={props.clickHandler}>×</h6>
<h6 className="font-sans text-white justify-center flex">{props.message}</h6>
</div>
)
}

export default InfoMsg;
Loading
Loading