From 91d152c375cd753fa62d8fb6b5e68994f3b7004a Mon Sep 17 00:00:00 2001 From: Addy Date: Thu, 5 Oct 2023 11:20:13 -0400 Subject: [PATCH 01/17] Update server.js Added framework for add and delete server functionality. Still need to create DB connection --- server.js | 35 ++++++++++++++++++++++++++++++----- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/server.js b/server.js index 8a85ccdc..4341c10b 100644 --- a/server.js +++ b/server.js @@ -1,10 +1,35 @@ -import express from 'express' -import ViteExpress from 'vite-express' +import express from 'express'; +import ViteExpress from 'vite-express'; -const app = express() +const app = express(); +app.use(express.json()); -app.use( express.json() ) +// Sample data (to be replaced with database connection) +const data = []; +// Add function +app.post('/add', (req, res) => { + const item = req.body; -ViteExpress.listen( app, 3000 ) \ No newline at end of file + // TODO: Add database connection here to save the item + data.push(item); + + res.status(200).send({ message: 'Item added successfully!' }); +}); + +// Delete function +app.delete('/delete/:id', (req, res) => { + const { id } = req.params; + + // TODO: Add database connection here to delete the item by its ID + const index = data.findIndex(item => item.id === id); + if (index !== -1) { + data.splice(index, 1); + res.status(200).send({ message: 'Item deleted successfully!' }); + } else { + res.status(404).send({ message: 'Item not found!' }); + } +}); + +ViteExpress.listen(app, 3000); From 8b71950a0f06dd0d45b64174f6a8dbbfc3fae255 Mon Sep 17 00:00:00 2001 From: Addy Date: Thu, 5 Oct 2023 11:46:00 -0400 Subject: [PATCH 02/17] Update package.json --- package.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/package.json b/package.json index 80db9291..cc511598 100644 --- a/package.json +++ b/package.json @@ -25,5 +25,8 @@ "eslint-plugin-react-hooks": "^4.6.0", "eslint-plugin-react-refresh": "^0.4.3", "vite": "^4.4.5" + }, + "engines": { + "node": "16.x" } } From 38e565e1062f9d1931789b4911b1f8910617716a Mon Sep 17 00:00:00 2001 From: Addy Date: Fri, 6 Oct 2023 10:41:04 -0400 Subject: [PATCH 03/17] Update server.js Oauth beginning to integrate git oauth for users --- server.js | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/server.js b/server.js index 4341c10b..3435fa63 100644 --- a/server.js +++ b/server.js @@ -1,11 +1,34 @@ import express from 'express'; import ViteExpress from 'vite-express'; +import passport from 'passport'; +import GitHubStrategy from 'passport-github'; const app = express(); app.use(express.json()); -// Sample data (to be replaced with database connection) +passport.use(new GitHubStrategy({ + clientID: "ee68f2a2eb45c1602179", + clientSecret: "c94bc95b579f85d6fb3836ffd9f675491e4a5519", + callbackURL: "http://localhost:3000/auth/github/callback" +}, +function(accessToken, refreshToken, profile, done) { + //TODO Save user profile data into DB + return done(null, profile); +})); + +app.get('/auth/github', passport.authenticate('github')); + +app.get('/callback', + passport.authenticate('github', { failureRedirect: '/' }), + function(req, res) { + // Successful authentication + res.redirect('/'); + }); + + + +// replace with db connection const data = []; // Add function From 564a1d22d66801862e123c0c49698750845d9f7a Mon Sep 17 00:00:00 2001 From: Addy Date: Sun, 8 Oct 2023 11:39:27 -0400 Subject: [PATCH 04/17] Create LoginComponent.jsx --- src/LoginComponent.jsx | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 src/LoginComponent.jsx diff --git a/src/LoginComponent.jsx b/src/LoginComponent.jsx new file mode 100644 index 00000000..3b87db1b --- /dev/null +++ b/src/LoginComponent.jsx @@ -0,0 +1,19 @@ +import React from 'react'; + +function LoginComponent() { + const handleGitHubLogin = () => { + const clientID = 'ee68f2a2eb45c1602179'; + const redirectURI = 'http://localhost:3000/auth/github/callback'; // change when we move to DO + window.location.href = `https://github.com/login/oauth/authorize?client_id=${clientID}&redirect_uri=${redirectURI}`; + + }; + + return ( +
+

Login

+ +
+ ); +} + +export default LoginComponent; From d51f7c7fe2acfb9d1dcc694b1501dd4eff363701 Mon Sep 17 00:00:00 2001 From: Addy Date: Sun, 8 Oct 2023 11:40:22 -0400 Subject: [PATCH 05/17] Update App.jsx --- src/App.jsx | 29 +++++++---------------------- 1 file changed, 7 insertions(+), 22 deletions(-) diff --git a/src/App.jsx b/src/App.jsx index b8b8473a..e9a9d89b 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -2,34 +2,19 @@ import { useState } from 'react' import reactLogo from './assets/react.svg' import viteLogo from '/vite.svg' import './App.css' +import LoginComponent from './LoginComponent'; + function App() { const [count, setCount] = useState(0) - return ( +return ( <> - -

Vite + React

-
- -

- Edit src/App.jsx and save to test HMR -

-
-

- Click on the Vite and React logos to learn more -

+ + {/* ... other components ... */} - ) + ); } export default App + From a4b6a008632ddcd47bc657b7711a10ae1fdd9800 Mon Sep 17 00:00:00 2001 From: Addy Date: Sun, 8 Oct 2023 11:41:23 -0400 Subject: [PATCH 06/17] Update server.js --- server.js | 82 ++++++++++++++++++++++--------------------------------- 1 file changed, 33 insertions(+), 49 deletions(-) diff --git a/server.js b/server.js index 3435fa63..7380d7ea 100644 --- a/server.js +++ b/server.js @@ -1,58 +1,42 @@ -import express from 'express'; -import ViteExpress from 'vite-express'; -import passport from 'passport'; -import GitHubStrategy from 'passport-github'; - -const app = express(); - -app.use(express.json()); - -passport.use(new GitHubStrategy({ - clientID: "ee68f2a2eb45c1602179", - clientSecret: "c94bc95b579f85d6fb3836ffd9f675491e4a5519", - callbackURL: "http://localhost:3000/auth/github/callback" -}, -function(accessToken, refreshToken, profile, done) { - //TODO Save user profile data into DB - return done(null, profile); -})); - -app.get('/auth/github', passport.authenticate('github')); - -app.get('/callback', - passport.authenticate('github', { failureRedirect: '/' }), - function(req, res) { - // Successful authentication - res.redirect('/'); +import express from 'express' +import ViteExpress from 'vite-express' +import axios from 'axios' +const clientSecret = process.env.GITHUB_CLIENT_SECRET; + + +const app = express() +app.get('/auth/github/callback', async (req, res) => { + const code = req.query.code; + + + const response = await axios.post('https://github.com/login/oauth/access_token', { + client_id: 'ee68f2a2eb45c1602179', + client_secret: clientSecret, + code: code + }, { + headers: { + 'Accept': 'application/json' + } }); + const accessToken = response.data.access_token; + // Fetch user data from GitHub + const userResponse = await axios.get('https://api.github.com/user', { + headers: { + 'Authorization': `token ${accessToken}` + } + }); -// replace with db connection -const data = []; - -// Add function -app.post('/add', (req, res) => { - const item = req.body; + const userData = userResponse.data; - // TODO: Add database connection here to save the item - data.push(item); + //TODO store the user data in your database and create a session or JWT for the user - res.status(200).send({ message: 'Item added successfully!' }); + res.redirect('/'); // Redirect user back to app }); -// Delete function -app.delete('/delete/:id', (req, res) => { - const { id } = req.params; - - // TODO: Add database connection here to delete the item by its ID - const index = data.findIndex(item => item.id === id); - if (index !== -1) { - data.splice(index, 1); - res.status(200).send({ message: 'Item deleted successfully!' }); - } else { - res.status(404).send({ message: 'Item not found!' }); - } -}); -ViteExpress.listen(app, 3000); +app.use( express.json() ) + + +ViteExpress.listen( app, 3000 ) From adb5bcc781a3eeb62175d55b543e8d06c9d28498 Mon Sep 17 00:00:00 2001 From: Addy Date: Sun, 8 Oct 2023 11:46:05 -0400 Subject: [PATCH 07/17] Update .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index a547bf36..19862e32 100644 --- a/.gitignore +++ b/.gitignore @@ -16,6 +16,7 @@ dist-ssr .vscode/* !.vscode/extensions.json .idea +.env .DS_Store *.suo *.ntvs* From 6264939401632dc37b68992e7d0da051979cde96 Mon Sep 17 00:00:00 2001 From: Addy Date: Sun, 8 Oct 2023 11:47:11 -0400 Subject: [PATCH 08/17] Create .env --- .env | 1 + 1 file changed, 1 insertion(+) create mode 100644 .env diff --git a/.env b/.env new file mode 100644 index 00000000..fd58a5fe --- /dev/null +++ b/.env @@ -0,0 +1 @@ +GITHUB_CLIENT_SECRET=00e79e25b8ab17abf8f6794d6d622802de442857 From 6922d72e7f1a1521567dfbcd856a906a59d99ac8 Mon Sep 17 00:00:00 2001 From: Addy Date: Sun, 8 Oct 2023 12:55:17 -0400 Subject: [PATCH 09/17] Update server.js --- server.js | 36 ++++++++++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/server.js b/server.js index 7380d7ea..66406ab7 100644 --- a/server.js +++ b/server.js @@ -3,12 +3,18 @@ import ViteExpress from 'vite-express' import axios from 'axios' const clientSecret = process.env.GITHUB_CLIENT_SECRET; +const app = express(); + +// In-memory storage for user data +const users = []; -const app = express() app.get('/auth/github/callback', async (req, res) => { + console.log('Received GitHub callback request.'); + const code = req.query.code; - + console.log('Exchanging GitHub code for access token...'); + // Exchange code for access token const response = await axios.post('https://github.com/login/oauth/access_token', { client_id: 'ee68f2a2eb45c1602179', client_secret: clientSecret, @@ -20,7 +26,9 @@ app.get('/auth/github/callback', async (req, res) => { }); const accessToken = response.data.access_token; + console.log('Received access token from GitHub.'); + console.log('Fetching user data from GitHub...'); // Fetch user data from GitHub const userResponse = await axios.get('https://api.github.com/user', { headers: { @@ -28,15 +36,27 @@ app.get('/auth/github/callback', async (req, res) => { } }); - const userData = userResponse.data; + const githubUserData = userResponse.data; + console.log('Received user data from GitHub:', githubUserData); + + // Store user data in local storage + const user = { + user_id: users.length + 1, // Simple incrementing ID for now + github_oauth_id: githubUserData.id, + username: githubUserData.login, + display_name: githubUserData.name || githubUserData.login, + joined_date: new Date().toISOString() + }; + users.push(user); - //TODO store the user data in your database and create a session or JWT for the user + console.log('Stored user in local storage:', user); res.redirect('/'); // Redirect user back to app + console.log('Redirected user back to app.'); }); +app.use(express.json()); -app.use( express.json() ) - - -ViteExpress.listen( app, 3000 ) +ViteExpress.listen(app, 3000, () => { + console.log('Server is running on http://localhost:3000'); +}); From 455a5af7834f51af4d4546abaf64337065286007 Mon Sep 17 00:00:00 2001 From: Addy Date: Sun, 8 Oct 2023 14:38:43 -0400 Subject: [PATCH 10/17] Update server.js --- server.js | 1 - 1 file changed, 1 deletion(-) diff --git a/server.js b/server.js index 66406ab7..f735769c 100644 --- a/server.js +++ b/server.js @@ -41,7 +41,6 @@ app.get('/auth/github/callback', async (req, res) => { // Store user data in local storage const user = { - user_id: users.length + 1, // Simple incrementing ID for now github_oauth_id: githubUserData.id, username: githubUserData.login, display_name: githubUserData.name || githubUserData.login, From 1930ee230fdb9643ae857bd0cd71f93e6fbf9506 Mon Sep 17 00:00:00 2001 From: Addy Date: Sun, 8 Oct 2023 14:53:44 -0400 Subject: [PATCH 11/17] Update server.js --- server.js | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 68 insertions(+), 1 deletion(-) diff --git a/server.js b/server.js index f735769c..6798cbb9 100644 --- a/server.js +++ b/server.js @@ -39,7 +39,25 @@ app.get('/auth/github/callback', async (req, res) => { const githubUserData = userResponse.data; console.log('Received user data from GitHub:', githubUserData); - // Store user data in local storage + /* +Will stay in callback +const user = { + github_oauth_id: githubUserData.id, + username: githubUserData.login, + display_name: githubUserData.name || githubUserData.login, + joined_date: new Date().toISOString() + }; + + try { + const savedUser = await addUserToDatabase(user); + console.log('User saved to database:', savedUser); + } catch (err) { + console.error('Error saving user to database:', err); + } + + */ + + // Store user data in local storage- will be deleted const user = { github_oauth_id: githubUserData.id, username: githubUserData.login, @@ -49,6 +67,55 @@ app.get('/auth/github/callback', async (req, res) => { users.push(user); console.log('Stored user in local storage:', user); + //end of deleted portion + + /* + Digital Ocean replacement-connection template for postgresql +const { Pool } = require('pg'); + +const pool = new Pool({ + user: 'your_db_username', + host: 'your_db_host', + database: 'your_db_name', + password: 'your_db_password', + port: your_db_port +}); + + + */ + + /* + Adding new user data to db after oauth +async function addUserToDatabase(user) { + try { + const query = ` + INSERT INTO users(github_oauth_id, username, display_name, joined_date) + VALUES($1, $2, $3, $4) + RETURNING *; + `; + + const values = [user.github_oauth_id, user.username, user.display_name, user.joined_date]; + + const result = await pool.query(query, values); + return result.rows[0]; // Returns the inserted user + } catch (err) { + console.error('Error inserting user into database:', err); + throw err; + } +} + + */ + + /* +SQL CODE for creating table: +CREATE TABLE users ( + github_oauth_id BIGINT UNIQUE NOT NULL PRIMARY KEY, + username VARCHAR(255) NOT NULL, + display_name VARCHAR(255), + joined_date TIMESTAMP NOT NULL +); + + */ res.redirect('/'); // Redirect user back to app console.log('Redirected user back to app.'); From 56802a1bd6e0f841e038c68262978d2e0a400c73 Mon Sep 17 00:00:00 2001 From: Colinm1215 Date: Sun, 8 Oct 2023 17:10:46 -0400 Subject: [PATCH 12/17] chatroom (not working) --- http_server.js | 64 +++++++++++++++++ package-lock.json | 177 ++++++++++++++++++++++++++++++++++++++++++++-- package.json | 4 +- src/App.jsx | 36 ++++------ src/Chat.jsx | 93 ++++++++++++++++++++++++ 5 files changed, 346 insertions(+), 28 deletions(-) create mode 100644 http_server.js create mode 100644 src/Chat.jsx diff --git a/http_server.js b/http_server.js new file mode 100644 index 00000000..02b4c5ea --- /dev/null +++ b/http_server.js @@ -0,0 +1,64 @@ +import express from 'express' +import ViteExpress from 'vite-express' +import { createServer } from 'http' +import { Server } from 'socket.io' + +let messagesLog = []; + +const app = express(); +const httpServer = createServer(app); +const io = new Server(httpServer, { + cors: { + origin: "http://localhost:3000", + methods: ["GET", "POST"] + } + }); + + +app.use(express.static('dist')); + + +io.on('connection', (socket) => { + console.log('a user connected'); + + // Handle joining a chatroom + socket.on('join-room', (room) => { + socket.join(room); + }); + + // Handle sending a message + socket.on('send-message', ({ room, message }) => { + const timestamp = new Date().toISOString(); + console.log(`${timestamp} : ${room}: ${message}`); + + // Store the message details + messagesLog.push({ + message, + room, + timestamp + }); + const roomMessages = messagesLog.filter(msg => msg.room === room); + + socket.on('request-historical-messages', (room) => { + console.log("request-historical-messages"); + socket.emit('historical-messages', roomMessages); + }); + + io.to(room).emit('receive-message', roomMessages); + }); + + + socket.on('leave-room', (room) => { + socket.leave(room); + }); + + socket.on('disconnect', () => { + console.log('user disconnected'); + }); +}); + +httpServer.listen(3001, () => { + console.log('http server started'); +}); + +ViteExpress.listen( app, 3000 ) \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 2231d9b9..f1dc3b73 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,6 +11,8 @@ "express": "^4.18.2", "react": "^18.2.0", "react-dom": "^18.2.0", + "socket.io": "^4.7.2", + "socket.io-client": "^4.7.2", "vite-express": "^0.10.0" }, "devDependencies": { @@ -912,6 +914,11 @@ "node": ">= 8" } }, + "node_modules/@socket.io/component-emitter": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz", + "integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg==" + }, "node_modules/@types/babel__core": { "version": "7.20.2", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.2.tgz", @@ -953,6 +960,24 @@ "@babel/types": "^7.20.7" } }, + "node_modules/@types/cookie": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz", + "integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==" + }, + "node_modules/@types/cors": { + "version": "2.8.14", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.14.tgz", + "integrity": "sha512-RXHUvNWYICtbP6s18PnOCaqToK8y14DnLd75c6HfyKf228dxy7pHNOQkxPtvXKp/hINFMDjbYzsj63nnpPMSRQ==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/node": { + "version": "20.8.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.8.2.tgz", + "integrity": "sha512-Vvycsc9FQdwhxE3y3DzeIxuEJbWGDsnrxvMADzTDF/lcdR9/K+AQIeAghTQsHtotg/q0j3WEOYS/jQgSdWue3w==" + }, "node_modules/@types/prop-types": { "version": "15.7.8", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.8.tgz", @@ -1214,6 +1239,14 @@ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true }, + "node_modules/base64id": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", + "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==", + "engines": { + "node": "^4.5.0 || >= 5.9" + } + }, "node_modules/body-parser": { "version": "1.20.1", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", @@ -1414,6 +1447,18 @@ "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" }, + "node_modules/cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + } + }, "node_modules/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -1438,7 +1483,6 @@ "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, "dependencies": { "ms": "2.1.2" }, @@ -1536,6 +1580,54 @@ "node": ">= 0.8" } }, + "node_modules/engine.io": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.5.2.tgz", + "integrity": "sha512-IXsMcGpw/xRfjra46sVZVHiSWo/nJ/3g1337q9KNXtS6YRzbW5yIzTCb9DjhrBe7r3GZQR0I4+nq+4ODk5g/cA==", + "dependencies": { + "@types/cookie": "^0.4.1", + "@types/cors": "^2.8.12", + "@types/node": ">=10.0.0", + "accepts": "~1.3.4", + "base64id": "2.0.0", + "cookie": "~0.4.1", + "cors": "~2.8.5", + "debug": "~4.3.1", + "engine.io-parser": "~5.2.1", + "ws": "~8.11.0" + }, + "engines": { + "node": ">=10.2.0" + } + }, + "node_modules/engine.io-client": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.5.2.tgz", + "integrity": "sha512-CQZqbrpEYnrpGqC07a9dJDz4gePZUgTPMU3NKJPSeQOyw27Tst4Pl3FemKoFGAlHzgZmKjoRmiJvbWfhCXUlIg==", + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.1", + "engine.io-parser": "~5.2.1", + "ws": "~8.11.0", + "xmlhttprequest-ssl": "~2.0.0" + } + }, + "node_modules/engine.io-parser": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.1.tgz", + "integrity": "sha512-9JktcM3u18nU9N2Lz3bWeBgxVgOKpw7yhRaoxQA3FUDZzzw+9WlA6p4G4u0RixNkg14fH7EfEc/RhpurtiROTQ==", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/engine.io/node_modules/cookie": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", + "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/es-abstract": { "version": "1.22.2", "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.2.tgz", @@ -3074,8 +3166,7 @@ "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "node_modules/nanoid": { "version": "3.3.6", @@ -3119,7 +3210,6 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -3821,6 +3911,57 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/socket.io": { + "version": "4.7.2", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.7.2.tgz", + "integrity": "sha512-bvKVS29/I5fl2FGLNHuXlQaUH/BlzX1IN6S+NKLNZpBsPZIDH+90eQmCs2Railn4YUiww4SzUedJ6+uzwFnKLw==", + "dependencies": { + "accepts": "~1.3.4", + "base64id": "~2.0.0", + "cors": "~2.8.5", + "debug": "~4.3.2", + "engine.io": "~6.5.2", + "socket.io-adapter": "~2.5.2", + "socket.io-parser": "~4.2.4" + }, + "engines": { + "node": ">=10.2.0" + } + }, + "node_modules/socket.io-adapter": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.2.tgz", + "integrity": "sha512-87C3LO/NOMc+eMcpcxUBebGjkpMDkNBS9tf7KJqcDsmL936EChtVva71Dw2q4tQcuVC+hAUy4an2NO/sYXmwRA==", + "dependencies": { + "ws": "~8.11.0" + } + }, + "node_modules/socket.io-client": { + "version": "4.7.2", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.7.2.tgz", + "integrity": "sha512-vtA0uD4ibrYD793SOIAwlo8cj6haOeMHrGvwPxJsxH7CeIksqJ+3Zc06RvWTIFgiSqx4A3sOnTXpfAEE2Zyz6w==", + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.2", + "engine.io-client": "~6.5.2", + "socket.io-parser": "~4.2.4" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/socket.io-parser": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz", + "integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==", + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/source-map-js": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", @@ -4313,6 +4454,34 @@ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "dev": true }, + "node_modules/ws": { + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz", + "integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xmlhttprequest-ssl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.0.0.tgz", + "integrity": "sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A==", + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/yallist": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", diff --git a/package.json b/package.json index 80db9291..b9225ba5 100644 --- a/package.json +++ b/package.json @@ -8,12 +8,14 @@ "build": "vite build", "lint": "eslint . --ext js,jsx --report-unused-disable-directives --max-warnings 0", "preview": "vite preview", - "start": "node server.js" + "start": "node http_server.js" }, "dependencies": { "express": "^4.18.2", "react": "^18.2.0", "react-dom": "^18.2.0", + "socket.io": "^4.7.2", + "socket.io-client": "^4.7.2", "vite-express": "^0.10.0" }, "devDependencies": { diff --git a/src/App.jsx b/src/App.jsx index b8b8473a..64b7e49b 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -1,35 +1,25 @@ -import { useState } from 'react' -import reactLogo from './assets/react.svg' -import viteLogo from '/vite.svg' +import { useState } from 'react'; +import Chat from './Chat'; import './App.css' function App() { - const [count, setCount] = useState(0) + const [count, setCount] = useState(0); + const [selectedRoom, setSelectedRoom] = useState(null); return ( <> - -

Vite + React

- -

- Edit src/App.jsx and save to test HMR -

+

Select a chatroom:

+ + {selectedRoom && }
-

- Click on the Vite and React logos to learn more -

) } -export default App +export default App; diff --git a/src/Chat.jsx b/src/Chat.jsx new file mode 100644 index 00000000..8e86cefa --- /dev/null +++ b/src/Chat.jsx @@ -0,0 +1,93 @@ +import { useEffect, useState, useRef } from 'react'; +import io from 'socket.io-client'; + +function Chat({ room }) { + const [messages, setMessages] = useState([]); + const [input, setInput] = useState(''); + const socketRef = useRef(null); + const [prevRoom, setPrevRoom] = useState(null); + const [connected, setConnected] = useState(false); + + useEffect(() => { + console.log("useEffect"); + setMessages([]); + if (room) { + setPrevRoom(room); + } + if (!connected) { + socketRef.current = io.connect('http://localhost:3001'); + setConnected(true); + } + + if (prevRoom != null) { + socketRef.current.emit('leave-room', prevRoom); + } + socketRef.current.emit('join-room', room); + + socketRef.current.emit('request-historical-messages', room); + socketRef.current.on('historical-messages', (historicalMessages) => { + console.log("historical-message"); + console.log(messages); + console.log(historicalMessages); + setMessages(historicalMessages); + }); + + socketRef.current.on('receive-message', (message) => { + console.log("Received message:", message); + setMessages((prev) => [...prev, message]); + }); + + + return () => { + socketRef.current.off('historical-messages'); + socketRef.current.off('receive-message'); + }; + + + }, [room]); + + + useEffect(() => { + return () => { + socketRef.current.disconnect(); + setConnected(false); + }; + }, []); + + const sendMessage = () => { + console.log(room + ' : ' + input); + socketRef.current.emit('send-message', { room, message: input }); + + // Use setMessages to update the state + const newMessage = { + message: input, + room, + timestamp: new Date().toISOString() + }; + setMessages((prev) => [...prev, newMessage]); + + setInput(''); + console.log('Sent Message : ' + newMessage); + }; + + return ( +
+

{room}

+
+ {messages.map((messageObj, index) => ( +
+

{messageObj.room} ({messageObj.timestamp}): {messageObj.message}

+
+ ))} +
+ setInput(e.target.value)} + type="text" + /> + +
+ ); +} + +export default Chat; From fb5715bc97565122ba051aeaa83a2c7d8a6bc523 Mon Sep 17 00:00:00 2001 From: Colinm1215 Date: Sun, 8 Oct 2023 17:56:20 -0400 Subject: [PATCH 13/17] chatroom structure (WORKING) --- http_server.js | 86 ++++++++++++++++++++++++++------------------------ src/Chat.jsx | 40 +++++++++++++++-------- 2 files changed, 71 insertions(+), 55 deletions(-) diff --git a/http_server.js b/http_server.js index 02b4c5ea..34e52379 100644 --- a/http_server.js +++ b/http_server.js @@ -4,61 +4,65 @@ import { createServer } from 'http' import { Server } from 'socket.io' let messagesLog = []; - + const app = express(); const httpServer = createServer(app); const io = new Server(httpServer, { - cors: { - origin: "http://localhost:3000", - methods: ["GET", "POST"] - } - }); - + cors: { + origin: "http://localhost:3000", + methods: ["GET", "POST"] + } +}); + app.use(express.static('dist')); io.on('connection', (socket) => { - console.log('a user connected'); - - // Handle joining a chatroom - socket.on('join-room', (room) => { - socket.join(room); - }); - - // Handle sending a message - socket.on('send-message', ({ room, message }) => { - const timestamp = new Date().toISOString(); - console.log(`${timestamp} : ${room}: ${message}`); - - // Store the message details - messagesLog.push({ - message, - room, - timestamp - }); - const roomMessages = messagesLog.filter(msg => msg.room === room); - - socket.on('request-historical-messages', (room) => { - console.log("request-historical-messages"); - socket.emit('historical-messages', roomMessages); - }); - - io.to(room).emit('receive-message', roomMessages); + console.log('a user connected'); + + // Handle joining a chatroom + socket.on('join-room', (room) => { + socket.join(room); }); - - socket.on('leave-room', (room) => { - socket.leave(room); - }); + // Handle sending a message + socket.on('send-message', ({ room, message }) => { + const timestamp = new Date().toISOString(); + console.log(`${room} (${timestamp}): ${message}`); + + // Store the message details + const newMessage = { + message, + room, + timestamp + }; + messagesLog.push(newMessage); + + // Emit the new message to everyone in the room + io.to(room).emit('receive-message', newMessage); + }); - socket.on('disconnect', () => { - console.log('user disconnected'); - }); + // Handle the request for historical messages + socket.on('request-historical-messages', (room) => { + console.log("request-historical-messages"); + const roomMessages = messagesLog.filter(msg => msg.room === room); + socket.emit('historical-messages', roomMessages); + }); + + + + socket.on('leave-room', (room) => { + socket.leave(room); + }); + + socket.on('disconnect', () => { + console.log('user disconnected'); + }); }); httpServer.listen(3001, () => { console.log('http server started'); }); -ViteExpress.listen( app, 3000 ) \ No newline at end of file +ViteExpress.listen(app, 3000) \ No newline at end of file diff --git a/src/Chat.jsx b/src/Chat.jsx index 8e86cefa..83284196 100644 --- a/src/Chat.jsx +++ b/src/Chat.jsx @@ -7,6 +7,14 @@ function Chat({ room }) { const socketRef = useRef(null); const [prevRoom, setPrevRoom] = useState(null); const [connected, setConnected] = useState(false); + const activeRoomRef = useRef(room); + + useEffect(() => { + + // ... (rest of the code remains the same) + + }, [room]); + useEffect(() => { console.log("useEffect"); @@ -14,6 +22,8 @@ function Chat({ room }) { if (room) { setPrevRoom(room); } + activeRoomRef.current = room; // Update ref to current room + if (!connected) { socketRef.current = io.connect('http://localhost:3001'); setConnected(true); @@ -22,21 +32,23 @@ function Chat({ room }) { if (prevRoom != null) { socketRef.current.emit('leave-room', prevRoom); } - socketRef.current.emit('join-room', room); + socketRef.current.emit('join-room', room); socketRef.current.emit('request-historical-messages', room); + socketRef.current.on('historical-messages', (historicalMessages) => { - console.log("historical-message"); - console.log(messages); - console.log(historicalMessages); - setMessages(historicalMessages); + // Check if the room associated with the messages matches the currently active room + if (historicalMessages.length > 0 && historicalMessages[0].room === activeRoomRef.current) { + console.log("historical-message"); + setMessages(historicalMessages); + } }); socketRef.current.on('receive-message', (message) => { console.log("Received message:", message); setMessages((prev) => [...prev, message]); - }); - + }); + return () => { socketRef.current.off('historical-messages'); @@ -57,15 +69,13 @@ function Chat({ room }) { const sendMessage = () => { console.log(room + ' : ' + input); socketRef.current.emit('send-message', { room, message: input }); - + // Use setMessages to update the state const newMessage = { message: input, room, timestamp: new Date().toISOString() - }; - setMessages((prev) => [...prev, newMessage]); - + }; setInput(''); console.log('Sent Message : ' + newMessage); }; @@ -75,9 +85,11 @@ function Chat({ room }) {

{room}

{messages.map((messageObj, index) => ( -
-

{messageObj.room} ({messageObj.timestamp}): {messageObj.message}

-
+ messageObj.message ? ( +
+

{messageObj.room} ({messageObj.timestamp}): {messageObj.message}

+
+ ) : null ))}
Date: Sun, 8 Oct 2023 18:12:26 -0400 Subject: [PATCH 14/17] Update http_server.js --- http_server.js | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/http_server.js b/http_server.js index 34e52379..b31f2551 100644 --- a/http_server.js +++ b/http_server.js @@ -14,7 +14,6 @@ const io = new Server(httpServer, { } }); - app.use(express.static('dist')); @@ -32,10 +31,24 @@ io.on('connection', (socket) => { console.log(`${room} (${timestamp}): ${message}`); // Store the message details + /* + Messages + message_id: Primary Key, Auto-incremented + building_id: Foreign Key referencing Buildings + user_id: Foreign Key referencing Users + message_content: Text content of the message + timestamp: Date and time when the message was sent + is_edited: Boolean, indicating if the message was edited + */ + const messageID = (messagesLog.length === 0) ? 0 : messagesLog[messagesLog.length - 1] + 1; + const is_edited = false; const newMessage = { - message, + messageID, room, - timestamp + userid, + message, + timestamp, + is_edited }; messagesLog.push(newMessage); From 12e5d1754152da847a67102f9761fccccfe314cf Mon Sep 17 00:00:00 2001 From: Colinm1215 Date: Sun, 8 Oct 2023 18:13:49 -0400 Subject: [PATCH 15/17] Revert "Merge branch 'chatroom' into dbfunctions" This reverts commit 2f8a3e5fb30d441f1d8b8ca3cf997c185e686557, reversing changes made to 1930ee230fdb9643ae857bd0cd71f93e6fbf9506. --- http_server.js | 68 ------------------ package-lock.json | 177 ++-------------------------------------------- package.json | 4 +- src/App.jsx | 22 ++---- src/Chat.jsx | 105 --------------------------- 5 files changed, 12 insertions(+), 364 deletions(-) delete mode 100644 http_server.js delete mode 100644 src/Chat.jsx diff --git a/http_server.js b/http_server.js deleted file mode 100644 index 34e52379..00000000 --- a/http_server.js +++ /dev/null @@ -1,68 +0,0 @@ -import express from 'express' -import ViteExpress from 'vite-express' -import { createServer } from 'http' -import { Server } from 'socket.io' - -let messagesLog = []; - -const app = express(); -const httpServer = createServer(app); -const io = new Server(httpServer, { - cors: { - origin: "http://localhost:3000", - methods: ["GET", "POST"] - } -}); - - -app.use(express.static('dist')); - - -io.on('connection', (socket) => { - console.log('a user connected'); - - // Handle joining a chatroom - socket.on('join-room', (room) => { - socket.join(room); - }); - - // Handle sending a message - socket.on('send-message', ({ room, message }) => { - const timestamp = new Date().toISOString(); - console.log(`${room} (${timestamp}): ${message}`); - - // Store the message details - const newMessage = { - message, - room, - timestamp - }; - messagesLog.push(newMessage); - - // Emit the new message to everyone in the room - io.to(room).emit('receive-message', newMessage); - }); - - // Handle the request for historical messages - socket.on('request-historical-messages', (room) => { - console.log("request-historical-messages"); - const roomMessages = messagesLog.filter(msg => msg.room === room); - socket.emit('historical-messages', roomMessages); - }); - - - - socket.on('leave-room', (room) => { - socket.leave(room); - }); - - socket.on('disconnect', () => { - console.log('user disconnected'); - }); -}); - -httpServer.listen(3001, () => { - console.log('http server started'); -}); - -ViteExpress.listen(app, 3000) \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index f1dc3b73..2231d9b9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,8 +11,6 @@ "express": "^4.18.2", "react": "^18.2.0", "react-dom": "^18.2.0", - "socket.io": "^4.7.2", - "socket.io-client": "^4.7.2", "vite-express": "^0.10.0" }, "devDependencies": { @@ -914,11 +912,6 @@ "node": ">= 8" } }, - "node_modules/@socket.io/component-emitter": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz", - "integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg==" - }, "node_modules/@types/babel__core": { "version": "7.20.2", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.2.tgz", @@ -960,24 +953,6 @@ "@babel/types": "^7.20.7" } }, - "node_modules/@types/cookie": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz", - "integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==" - }, - "node_modules/@types/cors": { - "version": "2.8.14", - "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.14.tgz", - "integrity": "sha512-RXHUvNWYICtbP6s18PnOCaqToK8y14DnLd75c6HfyKf228dxy7pHNOQkxPtvXKp/hINFMDjbYzsj63nnpPMSRQ==", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/node": { - "version": "20.8.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.8.2.tgz", - "integrity": "sha512-Vvycsc9FQdwhxE3y3DzeIxuEJbWGDsnrxvMADzTDF/lcdR9/K+AQIeAghTQsHtotg/q0j3WEOYS/jQgSdWue3w==" - }, "node_modules/@types/prop-types": { "version": "15.7.8", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.8.tgz", @@ -1239,14 +1214,6 @@ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true }, - "node_modules/base64id": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", - "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==", - "engines": { - "node": "^4.5.0 || >= 5.9" - } - }, "node_modules/body-parser": { "version": "1.20.1", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", @@ -1447,18 +1414,6 @@ "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" }, - "node_modules/cors": { - "version": "2.8.5", - "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", - "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", - "dependencies": { - "object-assign": "^4", - "vary": "^1" - }, - "engines": { - "node": ">= 0.10" - } - }, "node_modules/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -1483,6 +1438,7 @@ "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, "dependencies": { "ms": "2.1.2" }, @@ -1580,54 +1536,6 @@ "node": ">= 0.8" } }, - "node_modules/engine.io": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.5.2.tgz", - "integrity": "sha512-IXsMcGpw/xRfjra46sVZVHiSWo/nJ/3g1337q9KNXtS6YRzbW5yIzTCb9DjhrBe7r3GZQR0I4+nq+4ODk5g/cA==", - "dependencies": { - "@types/cookie": "^0.4.1", - "@types/cors": "^2.8.12", - "@types/node": ">=10.0.0", - "accepts": "~1.3.4", - "base64id": "2.0.0", - "cookie": "~0.4.1", - "cors": "~2.8.5", - "debug": "~4.3.1", - "engine.io-parser": "~5.2.1", - "ws": "~8.11.0" - }, - "engines": { - "node": ">=10.2.0" - } - }, - "node_modules/engine.io-client": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.5.2.tgz", - "integrity": "sha512-CQZqbrpEYnrpGqC07a9dJDz4gePZUgTPMU3NKJPSeQOyw27Tst4Pl3FemKoFGAlHzgZmKjoRmiJvbWfhCXUlIg==", - "dependencies": { - "@socket.io/component-emitter": "~3.1.0", - "debug": "~4.3.1", - "engine.io-parser": "~5.2.1", - "ws": "~8.11.0", - "xmlhttprequest-ssl": "~2.0.0" - } - }, - "node_modules/engine.io-parser": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.1.tgz", - "integrity": "sha512-9JktcM3u18nU9N2Lz3bWeBgxVgOKpw7yhRaoxQA3FUDZzzw+9WlA6p4G4u0RixNkg14fH7EfEc/RhpurtiROTQ==", - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/engine.io/node_modules/cookie": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", - "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", - "engines": { - "node": ">= 0.6" - } - }, "node_modules/es-abstract": { "version": "1.22.2", "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.2.tgz", @@ -3166,7 +3074,8 @@ "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true }, "node_modules/nanoid": { "version": "3.3.6", @@ -3210,6 +3119,7 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, "engines": { "node": ">=0.10.0" } @@ -3911,57 +3821,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/socket.io": { - "version": "4.7.2", - "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.7.2.tgz", - "integrity": "sha512-bvKVS29/I5fl2FGLNHuXlQaUH/BlzX1IN6S+NKLNZpBsPZIDH+90eQmCs2Railn4YUiww4SzUedJ6+uzwFnKLw==", - "dependencies": { - "accepts": "~1.3.4", - "base64id": "~2.0.0", - "cors": "~2.8.5", - "debug": "~4.3.2", - "engine.io": "~6.5.2", - "socket.io-adapter": "~2.5.2", - "socket.io-parser": "~4.2.4" - }, - "engines": { - "node": ">=10.2.0" - } - }, - "node_modules/socket.io-adapter": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.2.tgz", - "integrity": "sha512-87C3LO/NOMc+eMcpcxUBebGjkpMDkNBS9tf7KJqcDsmL936EChtVva71Dw2q4tQcuVC+hAUy4an2NO/sYXmwRA==", - "dependencies": { - "ws": "~8.11.0" - } - }, - "node_modules/socket.io-client": { - "version": "4.7.2", - "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.7.2.tgz", - "integrity": "sha512-vtA0uD4ibrYD793SOIAwlo8cj6haOeMHrGvwPxJsxH7CeIksqJ+3Zc06RvWTIFgiSqx4A3sOnTXpfAEE2Zyz6w==", - "dependencies": { - "@socket.io/component-emitter": "~3.1.0", - "debug": "~4.3.2", - "engine.io-client": "~6.5.2", - "socket.io-parser": "~4.2.4" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/socket.io-parser": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz", - "integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==", - "dependencies": { - "@socket.io/component-emitter": "~3.1.0", - "debug": "~4.3.1" - }, - "engines": { - "node": ">=10.0.0" - } - }, "node_modules/source-map-js": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", @@ -4454,34 +4313,6 @@ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "dev": true }, - "node_modules/ws": { - "version": "8.11.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz", - "integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==", - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "node_modules/xmlhttprequest-ssl": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.0.0.tgz", - "integrity": "sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A==", - "engines": { - "node": ">=0.4.0" - } - }, "node_modules/yallist": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", diff --git a/package.json b/package.json index 3c979294..cc511598 100644 --- a/package.json +++ b/package.json @@ -8,14 +8,12 @@ "build": "vite build", "lint": "eslint . --ext js,jsx --report-unused-disable-directives --max-warnings 0", "preview": "vite preview", - "start": "node http_server.js" + "start": "node server.js" }, "dependencies": { "express": "^4.18.2", "react": "^18.2.0", "react-dom": "^18.2.0", - "socket.io": "^4.7.2", - "socket.io-client": "^4.7.2", "vite-express": "^0.10.0" }, "devDependencies": { diff --git a/src/App.jsx b/src/App.jsx index 2d3a4ee9..e9a9d89b 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -1,28 +1,20 @@ -import { useState } from 'react'; -import Chat from './Chat'; +import { useState } from 'react' +import reactLogo from './assets/react.svg' +import viteLogo from '/vite.svg' import './App.css' import LoginComponent from './LoginComponent'; function App() { - const [count, setCount] = useState(0); - const [selectedRoom, setSelectedRoom] = useState(null); + const [count, setCount] = useState(0) return ( <> -
-

Select a chatroom:

- - {selectedRoom && } -
+ {/* ... other components ... */} ); } -export default App; +export default App + diff --git a/src/Chat.jsx b/src/Chat.jsx deleted file mode 100644 index 83284196..00000000 --- a/src/Chat.jsx +++ /dev/null @@ -1,105 +0,0 @@ -import { useEffect, useState, useRef } from 'react'; -import io from 'socket.io-client'; - -function Chat({ room }) { - const [messages, setMessages] = useState([]); - const [input, setInput] = useState(''); - const socketRef = useRef(null); - const [prevRoom, setPrevRoom] = useState(null); - const [connected, setConnected] = useState(false); - const activeRoomRef = useRef(room); - - useEffect(() => { - - // ... (rest of the code remains the same) - - }, [room]); - - - useEffect(() => { - console.log("useEffect"); - setMessages([]); - if (room) { - setPrevRoom(room); - } - activeRoomRef.current = room; // Update ref to current room - - if (!connected) { - socketRef.current = io.connect('http://localhost:3001'); - setConnected(true); - } - - if (prevRoom != null) { - socketRef.current.emit('leave-room', prevRoom); - } - - socketRef.current.emit('join-room', room); - socketRef.current.emit('request-historical-messages', room); - - socketRef.current.on('historical-messages', (historicalMessages) => { - // Check if the room associated with the messages matches the currently active room - if (historicalMessages.length > 0 && historicalMessages[0].room === activeRoomRef.current) { - console.log("historical-message"); - setMessages(historicalMessages); - } - }); - - socketRef.current.on('receive-message', (message) => { - console.log("Received message:", message); - setMessages((prev) => [...prev, message]); - }); - - - return () => { - socketRef.current.off('historical-messages'); - socketRef.current.off('receive-message'); - }; - - - }, [room]); - - - useEffect(() => { - return () => { - socketRef.current.disconnect(); - setConnected(false); - }; - }, []); - - const sendMessage = () => { - console.log(room + ' : ' + input); - socketRef.current.emit('send-message', { room, message: input }); - - // Use setMessages to update the state - const newMessage = { - message: input, - room, - timestamp: new Date().toISOString() - }; - setInput(''); - console.log('Sent Message : ' + newMessage); - }; - - return ( -
-

{room}

-
- {messages.map((messageObj, index) => ( - messageObj.message ? ( -
-

{messageObj.room} ({messageObj.timestamp}): {messageObj.message}

-
- ) : null - ))} -
- setInput(e.target.value)} - type="text" - /> - -
- ); -} - -export default Chat; From 9d099cd8b42b447d6ec2472d823dfb56c988f866 Mon Sep 17 00:00:00 2001 From: Colinm1215 Date: Sun, 8 Oct 2023 18:18:37 -0400 Subject: [PATCH 16/17] merge db into chat --- package-lock.json | 177 ++++++++++++++++++++++++++++++++++++++++++++-- package.json | 4 +- src/App.jsx | 22 ++++-- src/Chat.jsx | 105 +++++++++++++++++++++++++++ 4 files changed, 296 insertions(+), 12 deletions(-) create mode 100644 src/Chat.jsx diff --git a/package-lock.json b/package-lock.json index 2231d9b9..f1dc3b73 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,6 +11,8 @@ "express": "^4.18.2", "react": "^18.2.0", "react-dom": "^18.2.0", + "socket.io": "^4.7.2", + "socket.io-client": "^4.7.2", "vite-express": "^0.10.0" }, "devDependencies": { @@ -912,6 +914,11 @@ "node": ">= 8" } }, + "node_modules/@socket.io/component-emitter": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz", + "integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg==" + }, "node_modules/@types/babel__core": { "version": "7.20.2", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.2.tgz", @@ -953,6 +960,24 @@ "@babel/types": "^7.20.7" } }, + "node_modules/@types/cookie": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz", + "integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==" + }, + "node_modules/@types/cors": { + "version": "2.8.14", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.14.tgz", + "integrity": "sha512-RXHUvNWYICtbP6s18PnOCaqToK8y14DnLd75c6HfyKf228dxy7pHNOQkxPtvXKp/hINFMDjbYzsj63nnpPMSRQ==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/node": { + "version": "20.8.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.8.2.tgz", + "integrity": "sha512-Vvycsc9FQdwhxE3y3DzeIxuEJbWGDsnrxvMADzTDF/lcdR9/K+AQIeAghTQsHtotg/q0j3WEOYS/jQgSdWue3w==" + }, "node_modules/@types/prop-types": { "version": "15.7.8", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.8.tgz", @@ -1214,6 +1239,14 @@ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true }, + "node_modules/base64id": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", + "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==", + "engines": { + "node": "^4.5.0 || >= 5.9" + } + }, "node_modules/body-parser": { "version": "1.20.1", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", @@ -1414,6 +1447,18 @@ "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" }, + "node_modules/cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + } + }, "node_modules/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -1438,7 +1483,6 @@ "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, "dependencies": { "ms": "2.1.2" }, @@ -1536,6 +1580,54 @@ "node": ">= 0.8" } }, + "node_modules/engine.io": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.5.2.tgz", + "integrity": "sha512-IXsMcGpw/xRfjra46sVZVHiSWo/nJ/3g1337q9KNXtS6YRzbW5yIzTCb9DjhrBe7r3GZQR0I4+nq+4ODk5g/cA==", + "dependencies": { + "@types/cookie": "^0.4.1", + "@types/cors": "^2.8.12", + "@types/node": ">=10.0.0", + "accepts": "~1.3.4", + "base64id": "2.0.0", + "cookie": "~0.4.1", + "cors": "~2.8.5", + "debug": "~4.3.1", + "engine.io-parser": "~5.2.1", + "ws": "~8.11.0" + }, + "engines": { + "node": ">=10.2.0" + } + }, + "node_modules/engine.io-client": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.5.2.tgz", + "integrity": "sha512-CQZqbrpEYnrpGqC07a9dJDz4gePZUgTPMU3NKJPSeQOyw27Tst4Pl3FemKoFGAlHzgZmKjoRmiJvbWfhCXUlIg==", + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.1", + "engine.io-parser": "~5.2.1", + "ws": "~8.11.0", + "xmlhttprequest-ssl": "~2.0.0" + } + }, + "node_modules/engine.io-parser": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.1.tgz", + "integrity": "sha512-9JktcM3u18nU9N2Lz3bWeBgxVgOKpw7yhRaoxQA3FUDZzzw+9WlA6p4G4u0RixNkg14fH7EfEc/RhpurtiROTQ==", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/engine.io/node_modules/cookie": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", + "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/es-abstract": { "version": "1.22.2", "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.2.tgz", @@ -3074,8 +3166,7 @@ "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "node_modules/nanoid": { "version": "3.3.6", @@ -3119,7 +3210,6 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -3821,6 +3911,57 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/socket.io": { + "version": "4.7.2", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.7.2.tgz", + "integrity": "sha512-bvKVS29/I5fl2FGLNHuXlQaUH/BlzX1IN6S+NKLNZpBsPZIDH+90eQmCs2Railn4YUiww4SzUedJ6+uzwFnKLw==", + "dependencies": { + "accepts": "~1.3.4", + "base64id": "~2.0.0", + "cors": "~2.8.5", + "debug": "~4.3.2", + "engine.io": "~6.5.2", + "socket.io-adapter": "~2.5.2", + "socket.io-parser": "~4.2.4" + }, + "engines": { + "node": ">=10.2.0" + } + }, + "node_modules/socket.io-adapter": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.2.tgz", + "integrity": "sha512-87C3LO/NOMc+eMcpcxUBebGjkpMDkNBS9tf7KJqcDsmL936EChtVva71Dw2q4tQcuVC+hAUy4an2NO/sYXmwRA==", + "dependencies": { + "ws": "~8.11.0" + } + }, + "node_modules/socket.io-client": { + "version": "4.7.2", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.7.2.tgz", + "integrity": "sha512-vtA0uD4ibrYD793SOIAwlo8cj6haOeMHrGvwPxJsxH7CeIksqJ+3Zc06RvWTIFgiSqx4A3sOnTXpfAEE2Zyz6w==", + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.2", + "engine.io-client": "~6.5.2", + "socket.io-parser": "~4.2.4" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/socket.io-parser": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz", + "integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==", + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/source-map-js": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", @@ -4313,6 +4454,34 @@ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "dev": true }, + "node_modules/ws": { + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz", + "integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xmlhttprequest-ssl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.0.0.tgz", + "integrity": "sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A==", + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/yallist": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", diff --git a/package.json b/package.json index cc511598..3c979294 100644 --- a/package.json +++ b/package.json @@ -8,12 +8,14 @@ "build": "vite build", "lint": "eslint . --ext js,jsx --report-unused-disable-directives --max-warnings 0", "preview": "vite preview", - "start": "node server.js" + "start": "node http_server.js" }, "dependencies": { "express": "^4.18.2", "react": "^18.2.0", "react-dom": "^18.2.0", + "socket.io": "^4.7.2", + "socket.io-client": "^4.7.2", "vite-express": "^0.10.0" }, "devDependencies": { diff --git a/src/App.jsx b/src/App.jsx index e9a9d89b..2d3a4ee9 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -1,20 +1,28 @@ -import { useState } from 'react' -import reactLogo from './assets/react.svg' -import viteLogo from '/vite.svg' +import { useState } from 'react'; +import Chat from './Chat'; import './App.css' import LoginComponent from './LoginComponent'; function App() { - const [count, setCount] = useState(0) + const [count, setCount] = useState(0); + const [selectedRoom, setSelectedRoom] = useState(null); return ( <> - {/* ... other components ... */} +
+

Select a chatroom:

+ + {selectedRoom && } +
); } -export default App - +export default App; diff --git a/src/Chat.jsx b/src/Chat.jsx new file mode 100644 index 00000000..83284196 --- /dev/null +++ b/src/Chat.jsx @@ -0,0 +1,105 @@ +import { useEffect, useState, useRef } from 'react'; +import io from 'socket.io-client'; + +function Chat({ room }) { + const [messages, setMessages] = useState([]); + const [input, setInput] = useState(''); + const socketRef = useRef(null); + const [prevRoom, setPrevRoom] = useState(null); + const [connected, setConnected] = useState(false); + const activeRoomRef = useRef(room); + + useEffect(() => { + + // ... (rest of the code remains the same) + + }, [room]); + + + useEffect(() => { + console.log("useEffect"); + setMessages([]); + if (room) { + setPrevRoom(room); + } + activeRoomRef.current = room; // Update ref to current room + + if (!connected) { + socketRef.current = io.connect('http://localhost:3001'); + setConnected(true); + } + + if (prevRoom != null) { + socketRef.current.emit('leave-room', prevRoom); + } + + socketRef.current.emit('join-room', room); + socketRef.current.emit('request-historical-messages', room); + + socketRef.current.on('historical-messages', (historicalMessages) => { + // Check if the room associated with the messages matches the currently active room + if (historicalMessages.length > 0 && historicalMessages[0].room === activeRoomRef.current) { + console.log("historical-message"); + setMessages(historicalMessages); + } + }); + + socketRef.current.on('receive-message', (message) => { + console.log("Received message:", message); + setMessages((prev) => [...prev, message]); + }); + + + return () => { + socketRef.current.off('historical-messages'); + socketRef.current.off('receive-message'); + }; + + + }, [room]); + + + useEffect(() => { + return () => { + socketRef.current.disconnect(); + setConnected(false); + }; + }, []); + + const sendMessage = () => { + console.log(room + ' : ' + input); + socketRef.current.emit('send-message', { room, message: input }); + + // Use setMessages to update the state + const newMessage = { + message: input, + room, + timestamp: new Date().toISOString() + }; + setInput(''); + console.log('Sent Message : ' + newMessage); + }; + + return ( +
+

{room}

+
+ {messages.map((messageObj, index) => ( + messageObj.message ? ( +
+

{messageObj.room} ({messageObj.timestamp}): {messageObj.message}

+
+ ) : null + ))} +
+ setInput(e.target.value)} + type="text" + /> + +
+ ); +} + +export default Chat; From fe593e0be4464d64137f1f360e9d87e0c6bdda71 Mon Sep 17 00:00:00 2001 From: Colinm1215 Date: Mon, 9 Oct 2023 23:26:44 -0400 Subject: [PATCH 17/17] chatroom - login integration --- http_server.js | 162 ++++++++++++++++++++++++++++++++++++++++- package-lock.json | 141 +++++++++++++++++++++++++++++++++++ package.json | 7 +- src/App.jsx | 34 ++++----- src/Chat.jsx | 126 ++++++++++++++++++++++---------- src/LoginComponent.jsx | 3 +- src/Room.jsx | 22 ++++++ 7 files changed, 427 insertions(+), 68 deletions(-) create mode 100644 src/Room.jsx diff --git a/http_server.js b/http_server.js index b31f2551..9df34f1e 100644 --- a/http_server.js +++ b/http_server.js @@ -2,8 +2,14 @@ import express from 'express' import ViteExpress from 'vite-express' import { createServer } from 'http' import { Server } from 'socket.io' +import axios from 'axios' +import dotenv from 'dotenv'; +dotenv.config(); +const clientSecret = process.env.GITHUB_CLIENT_SECRET; +const socketToUserData = new Map(); let messagesLog = []; +const users = []; const app = express(); const httpServer = createServer(app); @@ -16,9 +22,17 @@ const io = new Server(httpServer, { app.use(express.static('dist')); - io.on('connection', (socket) => { - console.log('a user connected'); + + socket.on('set-user', (userid, callback) => { + console.log("User ID received:", userid); + if (userid != null) { + socketToUserData.set(socket.id, userid); + callback('User ID received successfully.'); + } else { + callback('error'); + } + }); // Handle joining a chatroom socket.on('join-room', (room) => { @@ -27,6 +41,11 @@ io.on('connection', (socket) => { // Handle sending a message socket.on('send-message', ({ room, message }) => { + const user = socketToUserData.get(socket.id); + if (!user) { + console.error('User not found for socket:', socket.id); + return; + } const timestamp = new Date().toISOString(); console.log(`${room} (${timestamp}): ${message}`); @@ -45,7 +64,7 @@ io.on('connection', (socket) => { const newMessage = { messageID, room, - userid, + user, message, timestamp, is_edited @@ -71,6 +90,7 @@ io.on('connection', (socket) => { socket.on('disconnect', () => { console.log('user disconnected'); + socketToUserData.delete(socket.id); }); }); @@ -78,4 +98,138 @@ httpServer.listen(3001, () => { console.log('http server started'); }); -ViteExpress.listen(app, 3000) \ No newline at end of file +app.get('/auth/github/callback', async (req, res) => { + console.log('Received GitHub callback request.'); + + const code = req.query.code; + + console.log('Exchanging GitHub code for access token...'); + // Exchange code for access token + const response = await axios.post('https://github.com/login/oauth/access_token', { + client_id: 'ee68f2a2eb45c1602179', + client_secret: clientSecret, + code: code + }, { + headers: { + 'Accept': 'application/json' + } + }); + + const accessToken = response.data.access_token; + console.log('Received access token from GitHub.'); + + console.log('Fetching user data from GitHub...'); + // Fetch user data from GitHub + const userResponse = await axios.get('https://api.github.com/user', { + headers: { + 'Authorization': `token ${accessToken}` + } + }); + + const githubUserData = userResponse.data; + console.log('Received user data from GitHub:', githubUserData); + + /* +Will stay in callback +const user = { + github_oauth_id: githubUserData.id, + username: githubUserData.login, + display_name: githubUserData.name || githubUserData.login, + joined_date: new Date().toISOString() + }; + + try { + const savedUser = await addUserToDatabase(user); + console.log('User saved to database:', savedUser); + } catch (err) { + console.error('Error saving user to database:', err); + } + + */ + + // Store user data in local storage- will be deleted + const user = { + github_oauth_id: githubUserData.id, + username: githubUserData.login, + display_name: githubUserData.name || githubUserData.login, + joined_date: new Date().toISOString() + }; + users.push(user); + console.log('Stored user in local storage:', user); + + //end of deleted portion + + /* + Digital Ocean replacement-connection template for postgresql +const { Pool } = require('pg'); + +const pool = new Pool({ + user: 'your_db_username', + host: 'your_db_host', + database: 'your_db_name', + password: 'your_db_password', + port: your_db_port +}); + + + */ + + /* + Adding new user data to db after oauth +async function addUserToDatabase(user) { + try { + const query = ` + INSERT INTO users(github_oauth_id, username, display_name, joined_date) + VALUES($1, $2, $3, $4) + RETURNING *; + `; + + const values = [user.github_oauth_id, user.username, user.display_name, user.joined_date]; + + const result = await pool.query(query, values); + return result.rows[0]; // Returns the inserted user + } catch (err) { + console.error('Error inserting user into database:', err); + throw err; + } +} + + */ + + /* +SQL CODE for creating table: +CREATE TABLE users ( + github_oauth_id BIGINT UNIQUE NOT NULL PRIMARY KEY, + username VARCHAR(255) NOT NULL, + display_name VARCHAR(255), + joined_date TIMESTAMP NOT NULL +); + + */ + // Return the user data in the HTTP response + res.cookie('userData', JSON.stringify(user)); + res.redirect('/main'); // Redirect user back to app + console.log('Redirected user back to app.'); +}); + +app.get('/get-username', (req, res) => { + const { userid } = req.query; + console.log("Finding username of user with id " + userid); + + // Find the user in the users array + const user = users.find(u => u.github_oauth_id === parseInt(userid)); + console.log("username " + user.username); + + if (user) { + res.json({ username: user.username }); + } else { + res.status(404).json({ error: "User not found" }); + } +}); + + +app.use(express.json()); + +ViteExpress.listen(app, 3000, () => { + console.log('Server is running on http://localhost:3000'); +}); \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index f1dc3b73..aef8da6c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,9 +8,14 @@ "name": "cs4241_final", "version": "0.0.0", "dependencies": { + "axios": "^1.5.1", + "dotenv": "^16.3.1", "express": "^4.18.2", + "js-cookie": "^3.0.5", + "js-cookies": "^1.0.4", "react": "^18.2.0", "react-dom": "^18.2.0", + "react-router-dom": "^6.16.0", "socket.io": "^4.7.2", "socket.io-client": "^4.7.2", "vite-express": "^0.10.0" @@ -24,6 +29,9 @@ "eslint-plugin-react-hooks": "^4.6.0", "eslint-plugin-react-refresh": "^0.4.3", "vite": "^4.4.5" + }, + "engines": { + "node": "16.x" } }, "node_modules/@aashutoshrathi/word-wrap": { @@ -914,6 +922,14 @@ "node": ">= 8" } }, + "node_modules/@remix-run/router": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.9.0.tgz", + "integrity": "sha512-bV63itrKBC0zdT27qYm6SDZHlkXwFL1xMBuhkn+X7l0+IIhNaH5wuuvZKp6eKhCD4KFhujhfhCT1YxXW6esUIA==", + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/@socket.io/component-emitter": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz", @@ -1221,6 +1237,11 @@ "has-symbols": "^1.0.3" } }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, "node_modules/available-typed-arrays": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", @@ -1233,6 +1254,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/axios": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.5.1.tgz", + "integrity": "sha512-Q28iYCWzNHjAm+yEAot5QaAMxhMghWLFVf7rRdwhUI+c2jix2DUXjAHXVi+s1ibs3mjPO/cCgbA++3BjD0vP/A==", + "dependencies": { + "follow-redirects": "^1.15.0", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -1403,6 +1434,17 @@ "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", "dev": true }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -1532,6 +1574,14 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/depd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", @@ -1561,6 +1611,17 @@ "node": ">=6.0.0" } }, + "node_modules/dotenv": { + "version": "16.3.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.3.1.tgz", + "integrity": "sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/motdotla/dotenv?sponsor=1" + } + }, "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -2271,6 +2332,25 @@ "integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==", "dev": true }, + "node_modules/follow-redirects": { + "version": "1.15.3", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.3.tgz", + "integrity": "sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, "node_modules/for-each": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", @@ -2280,6 +2360,19 @@ "is-callable": "^1.1.3" } }, + "node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -2963,6 +3056,19 @@ "set-function-name": "^2.0.1" } }, + "node_modules/js-cookie": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-3.0.5.tgz", + "integrity": "sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==", + "engines": { + "node": ">=14" + } + }, + "node_modules/js-cookies": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/js-cookies/-/js-cookies-1.0.4.tgz", + "integrity": "sha512-cO1SHDH7zJsi8FihHmDtcWx90mWmrfGOrcLKPeaEX6tLyuTK2wnzgdmNa34Q6rNAd6VhQUgjDt5Eyl90VI/Fpg==" + }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -3500,6 +3606,11 @@ "node": ">= 0.10" } }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, "node_modules/punycode": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", @@ -3603,6 +3714,36 @@ "node": ">=0.10.0" } }, + "node_modules/react-router": { + "version": "6.16.0", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.16.0.tgz", + "integrity": "sha512-VT4Mmc4jj5YyjpOi5jOf0I+TYzGpvzERy4ckNSvSh2RArv8LLoCxlsZ2D+tc7zgjxcY34oTz2hZaeX5RVprKqA==", + "dependencies": { + "@remix-run/router": "1.9.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": ">=16.8" + } + }, + "node_modules/react-router-dom": { + "version": "6.16.0", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.16.0.tgz", + "integrity": "sha512-aTfBLv3mk/gaKLxgRDUPbPw+s4Y/O+ma3rEN1u8EgEpLpPe6gNjIsWt9rxushMHHMb7mSwxRGdGlGdvmFsyPIg==", + "dependencies": { + "@remix-run/router": "1.9.0", + "react-router": "6.16.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": ">=16.8", + "react-dom": ">=16.8" + } + }, "node_modules/reflect.getprototypeof": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.4.tgz", diff --git a/package.json b/package.json index 3c979294..6ac3a989 100644 --- a/package.json +++ b/package.json @@ -11,9 +11,14 @@ "start": "node http_server.js" }, "dependencies": { + "axios": "^1.5.1", + "dotenv": "^16.3.1", "express": "^4.18.2", + "js-cookie": "^3.0.5", + "js-cookies": "^1.0.4", "react": "^18.2.0", "react-dom": "^18.2.0", + "react-router-dom": "^6.16.0", "socket.io": "^4.7.2", "socket.io-client": "^4.7.2", "vite-express": "^0.10.0" @@ -28,7 +33,7 @@ "eslint-plugin-react-refresh": "^0.4.3", "vite": "^4.4.5" }, - "engines": { + "engines": { "node": "16.x" } } diff --git a/src/App.jsx b/src/App.jsx index 2d3a4ee9..a098e177 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -1,28 +1,20 @@ -import { useState } from 'react'; -import Chat from './Chat'; -import './App.css' +import './App.css'; import LoginComponent from './LoginComponent'; - +import { BrowserRouter as Router, Route, Routes } from "react-router-dom"; +import Room from './Room'; function App() { - const [count, setCount] = useState(0); - const [selectedRoom, setSelectedRoom] = useState(null); -return ( - <> - -
-

Select a chatroom:

- - {selectedRoom && } -
- - ); + return ( + <> + + + } /> + } /> + + + + ); } export default App; diff --git a/src/Chat.jsx b/src/Chat.jsx index 83284196..d201fe76 100644 --- a/src/Chat.jsx +++ b/src/Chat.jsx @@ -1,5 +1,6 @@ import { useEffect, useState, useRef } from 'react'; import io from 'socket.io-client'; +import Cookies from 'js-cookie'; function Chat({ room }) { const [messages, setMessages] = useState([]); @@ -8,63 +9,87 @@ function Chat({ room }) { const [prevRoom, setPrevRoom] = useState(null); const [connected, setConnected] = useState(false); const activeRoomRef = useRef(room); + const [usernames, setUsernames] = useState({}); + const [userData, setUserData] = useState({}); + const [status, setStatus] = useState("pending"); useEffect(() => { - // ... (rest of the code remains the same) + return () => { + socketRef.current.disconnect(); + setConnected(false); + }; + }, []); - }, [room]); + useEffect(() => { + const uniqueUserIds = [...new Set(messages.map(msg => msg.user))]; + + uniqueUserIds.forEach(async user => { + if (!usernames[user]) { + const response = await fetch(`/get-username?userid=${user}`); + const data = await response.json(); + console.log(data.username); + setUsernames(prev => ({ ...prev, [user]: data.username })); + } + }); + }, [messages]); useEffect(() => { - console.log("useEffect"); - setMessages([]); - if (room) { - setPrevRoom(room); - } - activeRoomRef.current = room; // Update ref to current room + const userDataFromCookie = Cookies.get('userData'); - if (!connected) { - socketRef.current = io.connect('http://localhost:3001'); - setConnected(true); - } + if (userDataFromCookie) { + const userData = JSON.parse(userDataFromCookie); + setUserData(userData); // store this in a state variable or context - if (prevRoom != null) { - socketRef.current.emit('leave-room', prevRoom); - } - - socketRef.current.emit('join-room', room); - socketRef.current.emit('request-historical-messages', room); + setMessages([]); + if (room) { + setPrevRoom(room); + } + activeRoomRef.current = room; // Update ref to current room - socketRef.current.on('historical-messages', (historicalMessages) => { - // Check if the room associated with the messages matches the currently active room - if (historicalMessages.length > 0 && historicalMessages[0].room === activeRoomRef.current) { - console.log("historical-message"); - setMessages(historicalMessages); + if (!connected) { + socketRef.current = io.connect('http://localhost:3001'); + setConnected(true); } - }); - socketRef.current.on('receive-message', (message) => { - console.log("Received message:", message); - setMessages((prev) => [...prev, message]); - }); + console.log(userData); + socketRef.current.emit('set-user', userData.github_oauth_id, (acknowledgmentMessage) => { + if (acknowledgmentMessage === 'User ID received successfully.') { + setStatus("acknowledged"); + } else { + setStatus("error"); + } + }); + + if (prevRoom != null) { + socketRef.current.emit('leave-room', prevRoom); + } + socketRef.current.emit('join-room', room); + socketRef.current.emit('request-historical-messages', room); - return () => { - socketRef.current.off('historical-messages'); - socketRef.current.off('receive-message'); - }; + socketRef.current.on('historical-messages', (historicalMessages) => { + // Check if the room associated with the messages matches the currently active room + if (historicalMessages.length > 0 && historicalMessages[0].room === activeRoomRef.current) { + console.log("historical-message"); + setMessages(historicalMessages); + } + }); + socketRef.current.on('receive-message', (message) => { + console.log("Received message:", message); + setMessages((prev) => [...prev, message]); + }); - }, [room]); + return () => { + socketRef.current.off('historical-messages'); + socketRef.current.off('receive-message'); + }; + } - useEffect(() => { - return () => { - socketRef.current.disconnect(); - setConnected(false); - }; - }, []); + }, [room]); const sendMessage = () => { console.log(room + ' : ' + input); @@ -80,6 +105,27 @@ function Chat({ room }) { console.log('Sent Message : ' + newMessage); }; + function humanReadableTimestamp(timestamp) { + const date = new Date(timestamp); + + // Create an array of month names for display + const monthNames = [ + "January", "February", "March", "April", "May", "June", + "July", "August", "September", "October", "November", "December" + ]; + + // Extract the date details + const day = date.getDate(); + const monthIndex = date.getMonth(); + const year = date.getFullYear(); + const hours = date.getHours(); + const minutes = date.getMinutes(); + + // Return the formatted string + return `${monthNames[monthIndex]} ${day}, ${year} ${hours}:${minutes < 10 ? '0' : ''}${minutes}`; + } + + return (

{room}

@@ -87,7 +133,7 @@ function Chat({ room }) { {messages.map((messageObj, index) => ( messageObj.message ? (
-

{messageObj.room} ({messageObj.timestamp}): {messageObj.message}

+

{usernames[messageObj.user] || 'Fetching...'} ({humanReadableTimestamp(messageObj.timestamp)}): {messageObj.message}

) : null ))} diff --git a/src/LoginComponent.jsx b/src/LoginComponent.jsx index 3b87db1b..63c81401 100644 --- a/src/LoginComponent.jsx +++ b/src/LoginComponent.jsx @@ -1,11 +1,10 @@ import React from 'react'; function LoginComponent() { - const handleGitHubLogin = () => { + const handleGitHubLogin = async () => { const clientID = 'ee68f2a2eb45c1602179'; const redirectURI = 'http://localhost:3000/auth/github/callback'; // change when we move to DO window.location.href = `https://github.com/login/oauth/authorize?client_id=${clientID}&redirect_uri=${redirectURI}`; - }; return ( diff --git a/src/Room.jsx b/src/Room.jsx new file mode 100644 index 00000000..04760b05 --- /dev/null +++ b/src/Room.jsx @@ -0,0 +1,22 @@ +import React, { useState } from 'react'; +import Chat from './Chat'; + + +function Room() { + const [selectedRoom, setSelectedRoom] = useState(null); + + return ( +
+

Select a chatroom:

+ + {selectedRoom && } +
+ ); +} + +export default Room;