diff --git a/client/src/index.tsx b/client/src/index.tsx index 152cedb294ecea94caf63aac2ec95921b7829499..614c3daca4bc2a62e8faecfe6510613c32025dca 100644 --- a/client/src/index.tsx +++ b/client/src/index.tsx @@ -10,9 +10,9 @@ if (root) createRoot(root).render( <HashRouter> <> - <Alert /> <Route exact path="/" component={UserLogin} /> <Route exact path="/user/:id" component={Main} /> + <Alert /> </> </HashRouter>, ); diff --git a/client/src/main.tsx b/client/src/main.tsx index 37941cab107e89ed625f0cb347b9bdbc23279bf3..3100e15e9b3488016c1e5f57bc55eb22faf41b82 100644 --- a/client/src/main.tsx +++ b/client/src/main.tsx @@ -49,6 +49,7 @@ export class Main extends Component<{ match: { params: { id: number } } }> { > <Card title="New chatRoom"> <Form.Input + placeholder="Title" type="text" width={'10vh'} value={this.new_chatRoom_input} @@ -182,7 +183,7 @@ export class Main extends Component<{ match: { params: { id: number } } }> { ? this.chatRooms ? this.chatRooms.find((room) => room.id == this.chatRoomId)?.name : this.chatRoomId - : '' + : 'Main' }`} > <div @@ -342,6 +343,8 @@ export class Main extends Component<{ match: { params: { id: number } } }> { }; this.subscription.onmessage = (message) => { + let instance = Alert.instance(); + if (instance) instance.alerts = []; if (message.action == 'user_data') { this.user = message.content; } @@ -356,6 +359,7 @@ export class Main extends Component<{ match: { params: { id: number } } }> { } if (message.action == 'chatrooms_recieve') { this.chatRooms = message.content; + this.render(); } if (message.action == 'receive_chatRoom_users') { @@ -366,6 +370,7 @@ export class Main extends Component<{ match: { params: { id: number } } }> { if (message.action == 'error') { console.error(message.content); + Alert.danger(message.content); } }; } diff --git a/client/src/message-http-services.tsx b/client/src/message-http-services.tsx new file mode 100644 index 0000000000000000000000000000000000000000..7e6dff67edc7cba0f63a9bff3af4eb5ad09634e3 --- /dev/null +++ b/client/src/message-http-services.tsx @@ -0,0 +1,20 @@ +import axios from 'axios'; + +axios.defaults.baseURL = 'http://10.22.221.97:3000/api/v1/whiteboard'; + +class LoginServices { + async user_login(username: string, password: string) { + try { + const response = await axios.post<{ data: { cookie: number } }>('/#/', { + username, + password, + }); + return response; + } catch (error: unknown) { + throw error; + } + } +} + +const loginServices = new LoginServices(); +export default loginServices; diff --git a/client/src/userLogin.tsx b/client/src/userLogin.tsx index b55639eb3ccb66be7b7d34fd19fbb0e750119442..999ad4a67f108ef6a4c439a61f9f4bb3d1d42626 100644 --- a/client/src/userLogin.tsx +++ b/client/src/userLogin.tsx @@ -1,11 +1,10 @@ import * as React from 'react'; -import { createRoot } from 'react-dom/client'; import { Alert, BlueCard, Button, Card, Column, Form, Row, AlertInput } from './widgets'; import { Component } from 'react-simplified'; import whiteboardService, { Subscription } from './whiteboard-service'; -import { HashRouter, Route } from 'react-router-dom'; import { createHashHistory } from 'history'; -import { User, ChatRoom, ChatRoomUserMap, Message } from '../../server/src/mesasage-services'; +import axios from 'axios'; +import loginServices from './message-http-services'; const history = createHashHistory(); // Use history.push(...) to programmatically change path, for instance after successfully saving a student @@ -20,6 +19,7 @@ export class UserLogin extends Component { return this.login_create_toggle ? ( <Card title="Log into user"> <Form.Input + placeholder="Username" type="text" value={this.username} onChange={(event) => { @@ -27,6 +27,7 @@ export class UserLogin extends Component { }} ></Form.Input> <Form.Input + placeholder="Password" type="password" value={this.password} onChange={(event) => { @@ -39,6 +40,7 @@ export class UserLogin extends Component { ) : ( <Card title="Create new user"> <Form.Input + placeholder="Username" type="text" value={this.username} onChange={(event) => { @@ -46,6 +48,7 @@ export class UserLogin extends Component { }} ></Form.Input> <Form.Input + placeholder="Password" type="password" value={this.password} onChange={(event) => { @@ -61,11 +64,20 @@ export class UserLogin extends Component { toggleLoginButton() { this.login_create_toggle = !this.login_create_toggle; } - loginButton() { - whiteboardService.send({ - action: 'user_login', - content: { username: this.username, password: this.password }, - }); + async loginButton() { + // whiteboardService.send({ + // action: 'user_login', + // content: { username: this.username, password: this.password }, + // }); + try { + const response = await loginServices.user_login(this.username, this.password); + console.log(response); + //@ts-ignore + history.push(`/user/${response.data.cookie}`); + if (this.subscription) whiteboardService.unsubscribe(this.subscription); + } catch (error) { + console.error(error); + } } createButton() { whiteboardService.send({ @@ -86,6 +98,8 @@ export class UserLogin extends Component { if (message.action == 'user_success') { history.push(`/user/${message.content}`); if (this.subscription) whiteboardService.unsubscribe(this.subscription); + let instance = Alert.instance(); + if (instance) instance.alerts = []; } if (message.action == 'user_login_failed') { Alert.danger(message.content); diff --git a/client/src/whiteboard-component.tsx b/client/src/whiteboard-component.tsx deleted file mode 100644 index 30058ca78cebd916eac798c5d139c297203fffa7..0000000000000000000000000000000000000000 --- a/client/src/whiteboard-component.tsx +++ /dev/null @@ -1,75 +0,0 @@ -// import * as React from 'react'; -// import { Component } from 'react-simplified'; -// import whiteboardService, { Subscription } from './whiteboard-service'; -// import { Alert } from './widgets'; - -// export class Whiteboard extends Component { -// canvas: HTMLCanvasElement | null = null; -// lastPos: { x: number; y: number } | null = null; -// subscription: Subscription | null = null; -// connected = false; - -// render() { -// return ( -// <> -// <canvas -// ref={(e) => (this.canvas = e) /* Store canvas element */} -// onMouseMove={(event) => { -// // Send lines to Whiteboard server -// const pos = { x: event.clientX, y: event.clientY }; -// if (this.lastPos && this.connected) { -// //@ts-ignore -// whiteboardService.send({ line: { from: this.lastPos, to: pos } }); -// } -// this.lastPos = pos; -// }} -// width={400} -// height={400} -// style={{ border: '2px solid black' }} -// /> -// <div>{this.connected ? 'Connected' : 'Not connected'}</div> -// </> -// ); -// } - -// mounted() { -// // Subscribe to whiteboardService to receive events from Whiteboard server in this component -// this.subscription = whiteboardService.subscribe(); - -// // Called when the subscription is ready -// this.subscription.onopen = () => { -// this.connected = true; -// }; - -// // Called on incoming message -// this.subscription.onmessage = (message) => { -// const context = this.canvas?.getContext('2d'); -// context?.beginPath(); -// //@ts-ignore - -// context?.moveTo(message.line.from.x, message.line.from.y); -// //@ts-ignore -// context?.lineTo(message.line.to.x, message.line.to.y); - -// context?.closePath(); -// context?.stroke(); -// }; - -// // Called if connection is closed -// this.subscription.onclose = (code, reason) => { -// this.connected = false; -// Alert.danger('Connection closed with code ' + code + ' and reason: ' + reason); -// }; - -// // Called on connection error -// this.subscription.onerror = (error) => { -// this.connected = false; -// Alert.danger('Connection error: ' + error.message); -// }; -// } - -// // Unsubscribe from whiteboardService when component is no longer in use -// beforeUnmount() { -// if (this.subscription) whiteboardService.unsubscribe(this.subscription); -// } -// } diff --git a/client/src/whiteboard-service.tsx b/client/src/whiteboard-service.tsx index 3c7b746f2f48313a7a5aff23d09868456d190b1c..3e82511ab7dc391405c519ba9fb42e54ba9c1905 100644 --- a/client/src/whiteboard-service.tsx +++ b/client/src/whiteboard-service.tsx @@ -24,7 +24,7 @@ class WhiteboardService { * * @private */ - connection = new WebSocket('ws://localhost:3000/api/v1/whiteboard'); + connection = new WebSocket('ws://10.22.221.97:3000/api/v1/whiteboard'); /** * Component subscriptions. * diff --git a/client/src/widgets.tsx b/client/src/widgets.tsx index 24595ea7706cde53d6fc513a3bc6a5b88d89751b..ff89ed5a2e372d1f6d6f96f92c5903db6ce2c31e 100644 --- a/client/src/widgets.tsx +++ b/client/src/widgets.tsx @@ -361,7 +361,7 @@ export class Alert extends Component { render() { return ( - <div> + <div style={{ position: 'absolute', zIndex: '1', width: '100%', bottom: '0px' }}> {this.alerts.map((alert, i) => ( <div key={alert.id} @@ -409,7 +409,7 @@ export class Alert extends Component { // To avoid 'Cannot update during an existing state transition' errors, run after current event through setTimeout setTimeout(() => { let instance = Alert.instance(); // Get rendered Alert component instance - if (instance) instance.alerts.push({ id: instance.nextId++, text: text, type: 'warning' }); + if (instance) instance.alerts = [{ id: instance.nextId++, text: text, type: 'warning' }]; }); } @@ -420,7 +420,7 @@ export class Alert extends Component { // To avoid 'Cannot update during an existing state transition' errors, run after current event through setTimeout setTimeout(() => { let instance = Alert.instance(); // Get rendered Alert component instance - if (instance) instance.alerts.push({ id: instance.nextId++, text: text, type: 'danger' }); + if (instance) instance.alerts = [{ id: instance.nextId++, text: text, type: 'danger' }]; }); } } diff --git a/server/src/message-server.ts b/server/src/message-server.ts index 3fa6886556e50d913be1d6b6b1a35227e5dd7ed2..44e30374b707c60544adf7f5ef7ec7229987c64e 100644 --- a/server/src/message-server.ts +++ b/server/src/message-server.ts @@ -7,9 +7,10 @@ import { chatRoomService, chatRoomUserService, } from './mesasage-services'; +import express from 'express'; function getRandomNumber() { - return Math.floor(Math.random() * 1000000000000) + 1; + return Math.floor(Math.random() * 1000000000000000) + 1; } let user_auth: any = []; @@ -17,6 +18,25 @@ let user_cookie: any = []; /** * Whiteboard server */ + +const router = express.Router(); + +router.post('/', async (request, response) => { + try { + const user = await userService.login(request.body.username, request.body.password); + if (!user) throw 'could not find user'; + // user_auth[user.id] = connection; + const cookie = getRandomNumber(); + user_cookie[user.id] = cookie; + // connection.send(JSON.stringify({ action: 'user_success', content: cookie })); + response.send({ cookie: cookie }); + } catch (error) { + response.status(400).send({ error: error }); + } +}); + +export { router }; + export default class WhiteboardServer { /** * Constructs a WebSocket server that will respond to the given path on webServer. @@ -153,6 +173,7 @@ export default class WhiteboardServer { if (data.action == 'chatroom_create') { try { + if (data.content.title == '') throw 'ChatRoom title cant be empty'; const chatroomId = await chatRoomService.create(data.content.title); await chatRoomUserService.create(data.content.userId, chatroomId); @@ -203,20 +224,22 @@ export default class WhiteboardServer { } if (data.action == 'add_user_to_chatroom') { - await chatRoomUserService.create(data.content.userId, data.content.chatRoomId); - let chatroom_user_map = await chatRoomUserService.get(data.content.userId); - if (chatroom_user_map) { - const userIds = chatroom_user_map.map((item) => Number(item.chatroom_id)); - let chatrooms = await chatRoomService.get(userIds); - let user_connection = user_auth[data.content.userId]; - - if (user_connection) { - user_connection.send( - JSON.stringify({ action: 'chatrooms_recieve', content: chatrooms }), - ); - } - } try { + await chatRoomUserService.create(data.content.userId, data.content.chatRoomId); + let chatroom_user_map = await chatRoomUserService.get(data.content.userId); + if (chatroom_user_map) { + const userIds = chatroom_user_map.map((item) => Number(item.chatroom_id)); + let chatrooms = await chatRoomService.get(userIds); + let user_connection = user_auth[data.content.userId]; + + if (user_connection) { + user_connection.send( + JSON.stringify({ action: 'chatrooms_recieve', content: chatrooms }), + ); + } + const users = await userService.getAllInChatRoom(data.content.chatRoomId); + connection.send(JSON.stringify({ action: 'receive_chatRoom_users', content: users })); + } } catch (error) { connection.send( JSON.stringify({ action: 'error', content: 'Unable to add user to chatroom' }), diff --git a/server/src/server.ts b/server/src/server.ts index 310fecf651580c0aace80a6a86f8474b1066c1af..72e47265137223ebe2111af6a7c67055df38660c 100644 --- a/server/src/server.ts +++ b/server/src/server.ts @@ -7,12 +7,14 @@ import express from 'express'; import path from 'path'; import http from 'http'; import WhiteboardServer from './message-server'; +import { router } from './message-server'; // Serve client files app.use(express.static(path.join(__dirname, '/../../client/public'))); const webServer = http.createServer(app); new WhiteboardServer(webServer, '/api/v1'); +app.use('/api/v1/whiteboard', router); const port = 3000; webServer.listen(port, () => {