diff --git a/backend/code/accountPickerCli.ts b/backend/code/accountPickerCli.ts deleted file mode 100644 index ad90f7f..0000000 --- a/backend/code/accountPickerCli.ts +++ /dev/null @@ -1,74 +0,0 @@ -import * as figlet from 'figlet'; -import * as fs from 'fs'; -import * as readline from 'node:readline'; -(async () => { - const header = figlet.textSync('Account Picker', { - font: 'Roman', - horizontalLayout: 'default', - verticalLayout: 'default', - }); - - console.log(header); - - const users = fs - .readFileSync('./users.txt', 'utf8') - .trim() - .split('\n') - .map((user) => { - const [email, password] = user.split(':'); - return { email, password }; - }); - - // list users to choose from - const userChoices = users.map((user, index) => { - return { - name: `${user.email} (${user.password})`, - value: index, - }; - }); - - // list uset userChoices - // - for (const userChoice of userChoices) { - console.log(`${userChoice.value}: ${userChoice.name}`); - } - - const rl = readline.createInterface({ - input: process.stdin, - output: process.stdout, - }); - - const question = (query: string) => - new Promise((resolve) => - rl.question(query, (ans) => { - resolve(ans); - }), - ); - - const userIndex = await question('User index: '); - const user = users[parseInt(userIndex as string, 10)]; - console.log(`You chose: ${user.email} (${user.password})`); - rl.close(); - - const codeTemplate = ` -var myHeaders = new Headers(); -myHeaders.append("Content-Type", "application/json"); - -var raw = JSON.stringify({ - "email": "${user.email}", - "password": "${user.password}" -}); - -var requestOptions = { - method: 'POST', - headers: myHeaders, - body: raw, - redirect: 'follow' -}; - -fetch("http://localhost:3001/auth/login", requestOptions) - .then(response => response.text()) - .then(result => console.log(result)) - .catch(error => console.log('error', error));`; - console.log(codeTemplate); -})(); diff --git a/backend/code/package.json b/backend/code/package.json index c396818..a3c214d 100644 --- a/backend/code/package.json +++ b/backend/code/package.json @@ -10,12 +10,12 @@ "private": true, "license": "UNLICENSED", "scripts": { - "build": "nest build", + "build": "npm run db:generate && nest build", "format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"", "start": "nest start", "start:dev": "npm run db:generate && nest start --watch", "start:debug": "nest start --debug --watch", - "start:prod": "node dist/src/main", + "start:prod": "node dist/main", "db:generate": "prisma generate", "lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix", "test": "jest", diff --git a/backend/code/prisma/Dockerfile b/backend/code/prisma/Dockerfile new file mode 100644 index 0000000..f7d7150 --- /dev/null +++ b/backend/code/prisma/Dockerfile @@ -0,0 +1,13 @@ +FROM node:18 + +# Create app directory +WORKDIR /app + +# Install prisma for the migration +RUN npm install -g prisma --unsafe-perm + +# Copy schema and migration folder +ADD ./ ./prisma/ + +# Run migration +CMD ["prisma", "migrate", "deploy"] \ No newline at end of file diff --git a/backend/code/prisma/dbml/schema.dbml b/backend/code/prisma/dbml/schema.dbml index 6b7f374..0ffaa10 100644 --- a/backend/code/prisma/dbml/schema.dbml +++ b/backend/code/prisma/dbml/schema.dbml @@ -53,10 +53,14 @@ Table blocked_friends { createdAt DateTime [default: `now()`, not null] id String [pk] Blcoked_by users [not null] - blocked_by_id String [unique, not null] + blocked_by_id String [not null] Blocked users [not null] - blocked_id String [unique, not null] + blocked_id String [not null] dmRoomId String + + indexes { + (blocked_by_id, blocked_id) [unique] + } } Table matches { diff --git a/backend/code/prisma/migrations/20231116010258_fix_block_relation/migration.sql b/backend/code/prisma/migrations/20231116010258_fix_block_relation/migration.sql new file mode 100644 index 0000000..48f9673 --- /dev/null +++ b/backend/code/prisma/migrations/20231116010258_fix_block_relation/migration.sql @@ -0,0 +1,14 @@ +/* + Warnings: + + - A unique constraint covering the columns `[blocked_by_id,blocked_id]` on the table `blocked_friends` will be added. If there are existing duplicate values, this will fail. + +*/ +-- DropIndex +DROP INDEX "blocked_friends_blocked_by_id_key"; + +-- DropIndex +DROP INDEX "blocked_friends_blocked_id_key"; + +-- CreateIndex +CREATE UNIQUE INDEX "blocked_friends_blocked_by_id_blocked_id_key" ON "blocked_friends"("blocked_by_id", "blocked_id"); diff --git a/backend/code/prisma/schema.prisma b/backend/code/prisma/schema.prisma index 9290dfb..f3e605a 100644 --- a/backend/code/prisma/schema.prisma +++ b/backend/code/prisma/schema.prisma @@ -71,11 +71,12 @@ model BlockedUsers { id String @id Blcoked_by User @relation("blocked_by", fields: [blocked_by_id], references: [userId], onDelete: Cascade) - blocked_by_id String @unique + blocked_by_id String Blocked User @relation("blocked", fields: [blocked_id], references: [userId], onDelete: Cascade) - blocked_id String @unique + blocked_id String dmRoomId String? + @@unique([blocked_by_id, blocked_id], name: "unique_block") @@map("blocked_friends") } diff --git a/backend/code/seeder.ts b/backend/code/seeder.ts deleted file mode 100644 index a1148dd..0000000 --- a/backend/code/seeder.ts +++ /dev/null @@ -1,162 +0,0 @@ -import { PrismaClient, User } from '@prisma/client'; -import { faker } from '@faker-js/faker'; -import * as bcrypt from 'bcrypt'; -import * as fs from 'fs'; - -class dataSeeder extends PrismaClient { - constructor() { - super({ - datasources: { - db: { - url: process.env.DATABASE_URL, - }, - }, - }); - } - - async seed() { - await this.$connect(); - const users = faker.helpers.multiple(this.createRandomUser, { count: 10 }); - const registeredUsers = await this.registerUser(users); - await this.makeFriendship(registeredUsers); - await this.makeMatch(registeredUsers); - await this.createRoom(registeredUsers); - await this.$disconnect(); - } - - private async registerUser(users: any): Promise { - if (fs.existsSync('users.txt')) { - console.log('users.txt exists'); - fs.unlinkSync('users.txt'); - } - const new_users: User[] = []; - for await (const user of users) { - fs.appendFile('users.txt', `${user.email}:${user.password}\n`, (err) => { - if (err) throw err; - }); - - const hash = await bcrypt.hash(user.password, 10); - - const new_user = await this.user.create({ - data: { - email: user.email, - password: hash, - Username: user.username, - firstName: user.firstName, - lastName: user.lastName, - avatar: user.avatar, - discreption: user.bio, - profileFinished: true, - }, - }); - new_users.push(new_user); - } - return new_users; - } - - private async makeFriendship(users: User[]) { - for await (const user of users) { - const randomUser = users[Math.floor(Math.random() * users.length)]; - if (randomUser.userId !== user.userId) { - const friendshipid = [user.userId, randomUser.userId].sort().join('-'); - await this.friend.upsert({ - where: { - id: friendshipid, - }, - create: { - id: friendshipid, - from: { - connect: { - userId: user.userId, - }, - }, - to: { - connect: { - userId: randomUser.userId, - }, - }, - accepted: true, - }, - update: {}, - }); - } - } - } - - private async makeMatch(users: User[]) { - for await (const user of users) { - const randomUser = users[Math.floor(Math.random() * users.length)]; - if (randomUser.userId !== user.userId) { - await this.match.create({ - data: { - participant1Id: user.userId, - participant2Id: randomUser.userId, - winner_id: Math.random() > 0.5 ? user.userId : randomUser.userId, - score1: Math.floor(Math.random() * 10), - score2: Math.floor(Math.random() * 10), - }, - }); - } - } - } - - private createRandomUser() { - return { - username: faker.internet.userName(), - email: faker.internet.email(), - avatar: 'v1698656518/nest-blog/clocnzgx80006q73seyj9hzx5.png', - password: faker.internet.password(), - firstName: faker.person.firstName(), - lastName: faker.person.lastName(), - bio: faker.person.bio(), - }; - } - - private async createRoom(users: User[]) { - const owner = users[Math.floor(Math.random() * users.length)]; - const roomData = { - name: faker.lorem.word(), - ownerId: owner.userId, - }; - - // add random users to the room - const filtredUsers = users.filter((user) => user.userId !== owner.userId); - const randomUsers = filtredUsers.slice( - 0, - Math.floor(Math.random() * filtredUsers.length), - ); - - const room = await this.room.create({ - data: { - name: roomData.name, - ownerId: roomData.ownerId, - type: 'public', - }, - }); - - for await (const user of randomUsers) { - await this.roomMember.create({ - data: { - userId: user.userId, - roomId: room.id, - is_admin: Math.random() > 0.8 ? true : false, - }, - }); - } - await this.roomMember.create({ - data: { - userId: owner.userId, - roomId: room.id, - is_admin: true, - }, - }); - - console.log("roomid: ", room.id) - console.log("ownerid: ", owner.userId) - console.log("randomUsers: ", randomUsers) - } -} - -(async () => { - await new dataSeeder().seed(); -})(); diff --git a/backend/code/src/app.controller.ts b/backend/code/src/app.controller.ts index d27d2e6..f7f97d5 100644 --- a/backend/code/src/app.controller.ts +++ b/backend/code/src/app.controller.ts @@ -1,274 +1,8 @@ -import { Controller, Get } from '@nestjs/common'; +import { Controller } from '@nestjs/common'; import { ApiExcludeController } from '@nestjs/swagger'; @ApiExcludeController(true) @Controller() export class AppController { constructor() {} - @Get('/login') - logIn() { - // send the login page - return ` - - - - - - - - - login frm here - - -`; - } - - // @Post('test') - // test() { - // this.prisma.friend.upsert({}) - // } - - @Get() - // @UseGuards(AuthenticatedGuard) - home() { - return ` - - - - - - - - Socket.io Example - - - - -

Socket.io Example

- -
- - - -
    - - -
    - - - - - -
    - - - - - - -
    - - - - - -
    - - -
    - - - -
    -
    - - -`; - } } diff --git a/backend/code/src/auth/stratgies/ft.strategy.ts b/backend/code/src/auth/stratgies/ft.strategy.ts index 2aeb8ca..a128046 100644 --- a/backend/code/src/auth/stratgies/ft.strategy.ts +++ b/backend/code/src/auth/stratgies/ft.strategy.ts @@ -48,7 +48,7 @@ export class FtStrategy extends PassportStrategy(Strategy, '42') { user.userId, tokens.refresh_token, ); - console.log(tokens); + res.cookie('X-Access-Token', tokens.access_token, { httpOnly: true }); res.cookie('X-Refresh-Token', tokens.refresh_token, { httpOnly: true, diff --git a/backend/code/src/auth/utils/jwt_utils/jwt_utils.ts b/backend/code/src/auth/utils/jwt_utils/jwt_utils.ts index 596d6b6..2ac1115 100644 --- a/backend/code/src/auth/utils/jwt_utils/jwt_utils.ts +++ b/backend/code/src/auth/utils/jwt_utils/jwt_utils.ts @@ -17,7 +17,7 @@ export class JwtUtils { { username, sub: userId }, { secret: JwtConsts.at_secret, - expiresIn: '15m', + expiresIn: '2h', }, ), this.jwtService.signAsync( diff --git a/backend/code/src/friends/friends.service.ts b/backend/code/src/friends/friends.service.ts index 3b7b38e..2868801 100644 --- a/backend/code/src/friends/friends.service.ts +++ b/backend/code/src/friends/friends.service.ts @@ -38,7 +38,6 @@ export class FriendsService { }, update: {}, }); - // this.evenEmitter.emit('addFriendNotif', notifData); TODO: emit an event with the correct data this.evenEmitter.emit('sendNotification', { receiverId: friendId, actorId: userId, diff --git a/backend/code/src/game/game.controller.ts b/backend/code/src/game/game.controller.ts index 657ebf8..1935229 100644 --- a/backend/code/src/game/game.controller.ts +++ b/backend/code/src/game/game.controller.ts @@ -1,4 +1,4 @@ -import { Controller, Get, Post, Query, UseGuards, Param } from '@nestjs/common'; +import { Controller, Get, Query, UseGuards, Param } from '@nestjs/common'; import { GameService } from './game.service'; import { AtGuard } from 'src/auth/guards/at.guard'; import { GetCurrentUser } from 'src/auth/decorator/get_current_user.decorator'; @@ -10,11 +10,6 @@ import { ApiTags } from '@nestjs/swagger'; export class GameController { constructor(private readonly gameService: GameService) {} - @Post('start') - startGame() { - // return this.gameService.startGame(); - } - @Get('history') @UseGuards(AtGuard) getHistory( diff --git a/backend/code/src/game/game.service.ts b/backend/code/src/game/game.service.ts index 9b50781..62e2346 100644 --- a/backend/code/src/game/game.service.ts +++ b/backend/code/src/game/game.service.ts @@ -38,7 +38,6 @@ export class GameService { this.classicwaitingPlayers.push({ socket: client, userData: userData }); else if (gameMode === 'extra') this.extraWaitingPlayers.push({ socket: client, userData: userData }); - console.log('client subscribed to the queue'); } else if (data.mode === 'unregister') { const client = data.client; const gameMode = data.gameMode; @@ -57,25 +56,13 @@ export class GameService { //NOTE: add game modes here private launchGame() { setInterval(() => { - // console.log('waitingPlayers', this.classicwaitingPlayers.length); - console.log('waitingPlayers classic', this.classicwaitingPlayers.length); - console.log('waitingPlayers extra', this.extraWaitingPlayers.length); - if (this.classicwaitingPlayers.length >= 2) { - console.log('Game launched!'); const two_players = this.classicwaitingPlayers.splice(0, 2); this.eventEmitter.emit('game.launched', two_players, 'classic'); - console.log(two_players); - // const user = await this.getUser(two_players[0].data.user.sub) - // console.log(user) } if (this.extraWaitingPlayers.length >= 2) { - console.log('Game launched!'); const two_players = this.extraWaitingPlayers.splice(0, 2); this.eventEmitter.emit('game.launched', two_players, 'extra'); - console.log(two_players); - // const user = await this.getUser(two_players[0].data.user.sub) - // console.log(user) } }, 5027); } diff --git a/backend/code/src/game/game.ts b/backend/code/src/game/game.ts index 5d64a2c..12e8637 100644 --- a/backend/code/src/game/game.ts +++ b/backend/code/src/game/game.ts @@ -43,8 +43,6 @@ export class Game { const scale2 = player2.h / this.h; const newPos = this.p1PaddleY * scale2; - // let scale_y = player2.h / this.h; - // let center = this.paddleHeight * scale_y; if (p2PaddleY - player2.h / 6 / 6 < 0) { p2PaddleY = 0; @@ -72,9 +70,6 @@ export class Game { const scale2 = player1.h / this.h; const newPos = this.p2PaddleY * scale2; - // let scale_y = player1.h / this.h; - - // let center = this.paddleHeight * scale_y; if (p1PaddleY - player1.h / 6 / 6 < 0) { p1PaddleY = 0; @@ -114,13 +109,7 @@ export class Game { private async loop() { if (this.closeGame) return; - console.log('loop'); - // if ( - // this.x + this.dx + this.ballSize / 2 >= this.w || - // this.x + this.dx - this.ballSize / 2 <= 0 - // ) - // this.dx *= -1; if ( this.y + this.dy + this.ballSize / 2 >= this.h || this.y + this.dy - this.ballSize / 2 <= 0 @@ -151,7 +140,6 @@ export class Game { this.y > this.p2PaddleY + this.paddleHeight) && this.x + this.ballSize / 2 >= this.w ) { - console.log(`${this.p1PaddleY} ${this.x} ${this.y} ${this.ballSize}`); this.p1Score += 1; this.init(); this.checkForWinner(); @@ -162,33 +150,15 @@ export class Game { this.y > this.p1PaddleY + this.paddleHeight) && this.x - this.ballSize / 2 <= 0 ) { - console.log(`${this.p1PaddleY} ${this.x} ${this.y} ${this.ballSize}`); this.p2Score += 1; this.init(); this.checkForWinner(); await new Promise((resolve) => setTimeout(resolve, 1000)); } - console.log(this.x); - console.log(this.y); - - // const forwardx = this.x + this.dx; - // const forwardy = this.y + this.dy - // if (forwardx > this.) { - // } this.x += this.dx; this.y += this.dy; - // if ( - // parseFloat((this.p1Res.w / this.p1Res.h).toFixed(1)) !== 1.8 && - // parseFloat((this.p2Res.w / this.p2Res.h).toFixed(1)) !== 1.9 - // ) { - // this.p1socket.emit('screen Error'); - - // this.emitGameEnd('p1Leave'); - // this.p1socket.emit('lose', 'trying cheat'); - // this.p2socket.emit('win', 'you win other player try to cheat'); - // } else { this.p1socket.emit( 'ball', this.screenAdapter(this.p1Res, this.x, this.y, this.ballSize), @@ -203,18 +173,7 @@ export class Game { true, ), ); - // } - - // if ( - // parseFloat((this.p2Res.w / this.p2Res.h).toFixed(1)) !== 1.8 && - // parseFloat((this.p2Res.w / this.p2Res.h).toFixed(1)) !== 1.9 - // ) { - // this.p1socket.emit('screen Error'); - - // this.emitGameEnd('p2Leave'); - // this.p1socket.emit('win', 'you win other player try to cheat'); - // this.p2socket.emit('lose', 'trying cheat'); - // } else { + this.p2socket.emit( 'ball', this.screenAdapter(this.p2Res, this.x, this.y, this.ballSize), @@ -229,7 +188,6 @@ export class Game { true, ), ); - // } await this.sleep(this.frames); @@ -247,10 +205,8 @@ export class Game { } } async start(ngameid: string) { - console.log('game started', ngameid); this.gameid = ngameid; await this.sleepCounter(); - // await this.setplayerScokets(this.p1socket, this.p2socket ,) this.loop(); } @@ -264,10 +220,7 @@ export class Game { this.p2socket = p2socket; this.p1Data = p1Data; this.p2Data = p2Data; - console.log(p1Data); - console.log(p2Data); this.server.emit('players', [p1Data, p2Data]); - console.log('newfunc'); if (this.mode === 'extra') { let l = 1; @@ -323,53 +276,50 @@ export class Game { this.p2socket.on('screen', (data) => { this.p2Res = data; }); - this.p1socket.on('disconnect', () => { - this.emitGameEnd('p1Leave'); - this.p2socket.emit('win', 'you win other player leave the game'); - this.p1socket.emit('lose', 'you win other player leave the game'); - }); - this.p2socket.on('disconnect', () => { - this.emitGameEnd('p2Leave'); - this.p1socket.emit('win', 'you win other player leave the game'); - this.p2socket.emit('lose', 'you lost other player leave the game'); - }); - this.p1socket.on('leave', () => { - this.emitGameEnd('p1Leave'); - this.p2socket.emit('win', 'you win other player leave the game'); - this.p1socket.emit('lose', 'you win other player leave the game'); - }); - this.p2socket.on('leave', () => { - this.emitGameEnd('p2Leave'); - this.p1socket.emit('win', 'you win other player leave the game'); - this.p2socket.emit('lose', 'you lost other player leave the game'); - }); + this.p1socket.once('disconnect', this.handleP1Disconnect); + this.p2socket.once('disconnect', this.handleP2Disconnect); + this.p1socket.once('leave', this.handleP1Disconnect); + this.p2socket.once('leave', this.handleP2Disconnect); } private checkForWinner() { if (this.p1Score >= 5) { - this.p1socket.emit('win', 'you win'); - this.p2socket.emit('lose', 'you lose'); + this.p1socket.emit('win', 'you won'); + this.p2socket.emit('lose', 'you lost'); this.emitGameEnd('end'); } if (this.p2Score >= 5) { - this.p2socket.emit('win', 'you win'); - this.p1socket.emit('lose', 'you lose'); + this.p2socket.emit('win', 'you won'); + this.p1socket.emit('lose', 'you lost'); this.emitGameEnd('end'); } } + private handleP1Disconnect = () => { + this.p2socket.emit('win', 'you won, the other player left the game'); + this.p1socket.emit('lose', 'you lost'); + this.emitGameEnd('p1Leave'); + }; + + private handleP2Disconnect = () => { + this.p1socket.emit('win', 'you won, the other player left the game'); + this.p2socket.emit('lose', 'you lost'); + this.emitGameEnd('p2Leave'); + }; + private removeListeners(socket: Socket) { - socket.removeAllListeners('disconnect'); - socket.removeAllListeners('leave'); socket.removeAllListeners('screen'); socket.removeAllListeners('mouse'); socket.removeAllListeners('up'); socket.removeAllListeners('down'); } private emitGameEnd(message: string) { - console.log`asdaqwe Game end`; this.closeGame = true; this.removeListeners(this.p1socket); + this.p1socket.off('leave', this.handleP1Disconnect); + this.p1socket.off('disconnect', this.handleP1Disconnect); this.removeListeners(this.p2socket); + this.p2socket.off('leave', this.handleP2Disconnect); + this.p2socket.off('disconnect', this.handleP2Disconnect); if (message === 'p1Leave') { this.eventEmitter.emit('game.end', { diff --git a/backend/code/src/gateways/gateways.gateway.ts b/backend/code/src/gateways/gateways.gateway.ts index 74d92af..7be7aa1 100644 --- a/backend/code/src/gateways/gateways.gateway.ts +++ b/backend/code/src/gateways/gateways.gateway.ts @@ -26,7 +26,7 @@ interface GameInvite { @WebSocketGateway(3004, { cors: { - origin: ['http://localhost:3001'], + origin: process.env.WS_CORS_ORIGIN?.split(',') || ['http://localhost:3001'], }, transports: ['websocket'], }) @@ -75,12 +75,39 @@ export class Gateways implements OnGatewayConnection, OnGatewayDisconnect { const userId = client.data.user.sub; this.server.emit('friendOffline', userId); + this.eventEmitter.emit('game.start', { + client, + gameMode: 'cassic', + mode: 'unregister', + }); + this.eventEmitter.emit('game.start', { + client, + gameMode: 'extra', + mode: 'unregister', + }); } @OnEvent('sendMessages') - sendMessage(message: MessageFormatDto) { + async sendMessage( + message: MessageFormatDto, + blockedRoomMembersIds?: string[], + ) { const chanellname: string = `Room:${message.roomId}`; - this.server.to(chanellname).emit('message', message); + if (!blockedRoomMembersIds) { + this.server.to(chanellname).emit('message', message); + } else { + const sockets = await this.server.in(chanellname).fetchSockets(); + for await (const socket of sockets) { + if (!blockedRoomMembersIds.includes(socket.data.user.sub)) { + socket.emit('message', message); + } else { + socket.emit('message', { + ...message, + content: '[REDACTED]', + }); + } + } + } } private async createNotification(notif: Partial) { @@ -113,7 +140,10 @@ export class Gateways implements OnGatewayConnection, OnGatewayDisconnect { } @OnEvent('sendNotification') - async sendNotification(notif: Partial) { + async sendNotification( + notif: Partial, + blockedRoomMembersIds?: string[], + ) { // create the notification on the database switch (notif.type) { case $Enums.NotifType.acceptFriend: @@ -165,6 +195,10 @@ export class Gateways implements OnGatewayConnection, OnGatewayDisconnect { .in(`Room:${message.roomId}`) .fetchSockets(); for await (const member of roomMembers) { + if (blockedRoomMembersIds?.includes(member.userId)) { + continue; + } + let found = false; for await (const clientSocket of clientsSockets) { if (clientSocket.data.user.sub === member.userId) { @@ -193,7 +227,6 @@ export class Gateways implements OnGatewayConnection, OnGatewayDisconnect { @SubscribeMessage('status') async handleStatusEvent(@MessageBody() data: any) { - console.log('status event', data); const userId = data.userId; const status = this.server.sockets.adapter.rooms.get(`User:${userId}`)?.size ? 'online' @@ -230,10 +263,6 @@ export class Gateways implements OnGatewayConnection, OnGatewayDisconnect { }); } - // @SubscribeMessage('getPlayers') - // getPlayers() { - // this.server.emit("players",[this.p1Data ,this.p2Data]) - // } private async checkIfCanInvite(userId: string) { const opententSockets = await this.server .in(`User:${userId}`) @@ -291,10 +320,6 @@ export class Gateways implements OnGatewayConnection, OnGatewayDisconnect { const game_invite = Array.from(this.game_invites).find( (invite) => invite.gameId === data.gameId, ); - //TODO: check if user is already in queue - // check if already has an active invite from anyone - // check if he is already on game || save if user is in game by saving it in the data of socket - // check if user is offline if (!game_invite) { client.emit('game.declined', { gameId: data.gameId, @@ -340,13 +365,11 @@ export class Gateways implements OnGatewayConnection, OnGatewayDisconnect { this.game_invites.delete(game_invite); if (game_invite.inviter === client.data.user.sub) { - console.log('declined by inviter'); this.server.to(`User:${game_invite.opponentId}`).emit('game.declined', { decliner: client.data.user.sub, gameId: data.gameId, }); } else { - console.log('decliner is the opponent'); this.server.to(`User:${game_invite.inviter}`).emit('game.declined', { decliner: client.data.user.sub, gameId: data.gameId, @@ -357,7 +380,7 @@ export class Gateways implements OnGatewayConnection, OnGatewayDisconnect { @OnEvent('game.launched') async handleGameLaunchedEvent(clients: any, mode: string) { const game_channel = crypto.randomBytes(16).toString('hex'); - // console.log(game_channel); + clients.forEach((client: any) => { client.socket.join(game_channel); client.socket.data.user.inGame = true; @@ -379,11 +402,9 @@ export class Gateways implements OnGatewayConnection, OnGatewayDisconnect { @OnEvent('game.end') async handleGameEndEvent(data: any) { this.games_map.delete(data.gameid); - console.log('game ended'); - console.log(data); + const sockets = await this.server.in(data.gameid).fetchSockets(); this.server.to(data.gameid).emit('game.end', data); - console.log(data); for await (const socket of sockets) { socket.data.user.inGame = false; diff --git a/backend/code/src/main.ts b/backend/code/src/main.ts index 9175e0a..b7726c6 100644 --- a/backend/code/src/main.ts +++ b/backend/code/src/main.ts @@ -14,8 +14,7 @@ import { GatewayAdapter } from './gateways/gateway-adapter'; async function bootstrap() { const app = await NestFactory.create(AppModule); const corsOptions = { - origin: [ - 'http://localhost:9000', + origin: process.env.CORS_ORIGIN?.split(',') || [ 'http://localhost:8000', 'http://localhost:3000', 'http://142.93.161.63', diff --git a/backend/code/src/messages/dto/message-format.dto.ts b/backend/code/src/messages/dto/message-format.dto.ts index da9266a..0acee39 100644 --- a/backend/code/src/messages/dto/message-format.dto.ts +++ b/backend/code/src/messages/dto/message-format.dto.ts @@ -9,7 +9,7 @@ export class MessageFormatDto { author: Partial; room?: { type: $Enums.RoomType }; }, - clientMessageId?: string + clientMessageId?: string, ) { this.id = messageData.id; this.content = messageData.content; diff --git a/backend/code/src/messages/messages.service.ts b/backend/code/src/messages/messages.service.ts index dd3a549..806e2f4 100644 --- a/backend/code/src/messages/messages.service.ts +++ b/backend/code/src/messages/messages.service.ts @@ -12,9 +12,10 @@ export class MessagesService { ) {} async sendMessages(userId: string, channelId: string, messageDto: any) { - console.log(messageDto); if (messageDto.content.length > 1000) { throw new HttpException('Message is too long', HttpStatus.BAD_REQUEST); + } else if (messageDto.content === '[REDACTED]') { + throw new HttpException('Message is not allowed', HttpStatus.BAD_REQUEST); } const room = await this.prisma.room.findUnique({ @@ -40,8 +41,8 @@ export class MessagesService { }); if (blocked) { throw new HttpException( - 'You are blocked from this dm', - HttpStatus.UNAUTHORIZED, + 'You are blocked from sending messages to this user', + HttpStatus.FORBIDDEN, ); } } @@ -50,22 +51,27 @@ export class MessagesService { if (!roomMember) { throw new HttpException( - 'User is not in channel', - HttpStatus.UNAUTHORIZED, + 'You are not in this channel', + HttpStatus.FORBIDDEN, ); } if (roomMember.is_banned) { throw new HttpException( - 'you are banned from this channel', - HttpStatus.UNAUTHORIZED, + 'You are banned from this channel', + HttpStatus.FORBIDDEN, ); } if (roomMember.is_mueted) { const now = new Date(); if (now < roomMember.mute_expires) { - throw new HttpException('User is muted', HttpStatus.UNAUTHORIZED); + throw new HttpException( + `You are muted for ${Math.round( + (roomMember.mute_expires.valueOf() - now.valueOf()) / 1000, + )} seconds`, + HttpStatus.FORBIDDEN, + ); } await this.prisma.roomMember.update({ where: { @@ -99,14 +105,45 @@ export class MessagesService { }, }); - const responseMessage: MessageFormatDto = new MessageFormatDto(messageData, messageDto.clientMessageId); - this.eventEmitter.emit('sendNotification', { - actorId: userId, - type: $Enums.NotifType.message, - entityId: messageData.id, - entity_type: 'message', + const roomMembersIds = await this.prisma.roomMember.findMany({ + where: { roomId: channelId, NOT: { userId } }, + select: { userId: true }, }); - this.eventEmitter.emit('sendMessages', responseMessage); + const blockedUsersIds = await this.prisma.blockedUsers.findMany({ + where: { OR: [{ blocked_by_id: userId }, { blocked_id: userId }] }, + select: { blocked_by_id: true, blocked_id: true }, + }); + + const blockedRoomMembersIds = roomMembersIds + .filter((member) => { + return blockedUsersIds.some((blocked) => { + return ( + blocked.blocked_by_id === member.userId || + blocked.blocked_id === member.userId + ); + }); + }) + .map((member) => member.userId); + + const responseMessage: MessageFormatDto = new MessageFormatDto( + messageData, + messageDto.clientMessageId, + ); + this.eventEmitter.emit( + 'sendNotification', + { + actorId: userId, + type: $Enums.NotifType.message, + entityId: messageData.id, + entity_type: 'message', + }, + blockedRoomMembersIds.length ? blockedRoomMembersIds : undefined, + ); + this.eventEmitter.emit( + 'sendMessages', + responseMessage, + blockedRoomMembersIds.length ? blockedRoomMembersIds : undefined, + ); return responseMessage; } @@ -125,8 +162,8 @@ export class MessagesService { if (!roomMember) { throw new HttpException( - 'User is not in channel', - HttpStatus.UNAUTHORIZED, + 'You are not in this channel', + HttpStatus.FORBIDDEN, ); } const messages = await this.prisma.message.findMany({ @@ -156,7 +193,7 @@ export class MessagesService { take: limit, }); - // get rppm type of room + // get room type of room const room = await this.prisma.room.findUnique({ where: { id: channelId, @@ -175,7 +212,7 @@ export class MessagesService { if (blocked) { messages.forEach((message) => { if (message.authorId !== userId) { - message.content = '[REDUCTED]'; + message.content = '[REDACTED]'; } }); } @@ -200,7 +237,7 @@ export class MessagesService { ); messages.forEach((message) => { if (blockedUsersIds.includes(message.authorId)) { - message.content = '[REDUCTED]'; + message.content = '[REDACTED]'; } }); } diff --git a/backend/code/src/profile/dto/update-profile.dto.ts b/backend/code/src/profile/dto/update-profile.dto.ts index fe6276c..b6dabaf 100644 --- a/backend/code/src/profile/dto/update-profile.dto.ts +++ b/backend/code/src/profile/dto/update-profile.dto.ts @@ -6,7 +6,7 @@ import { IsNotEmpty, IsOptional, IsString, - MinLength, + Length, } from 'class-validator'; export class UpdateProfileDto { @@ -28,20 +28,21 @@ export class UpdateProfileDto { @IsOptional() @IsString() @IsNotEmpty() - @MinLength(4) + @Length(4, 50) firstName?: string; @ApiProperty({ required: false }) @IsOptional() @IsString() @IsNotEmpty() - @MinLength(4) + @Length(4, 50) lastName?: string; @ApiProperty({ required: false }) @IsOptional() @IsString() @IsNotEmpty() + @Length(4, 50) discreption?: string; @ApiProperty({ required: true }) @@ -53,5 +54,6 @@ export class UpdateProfileDto { @IsOptional() @IsString() @IsNotEmpty() + @Length(4, 50) Username: string; } diff --git a/backend/code/src/rooms/dto/create-room.dto.ts b/backend/code/src/rooms/dto/create-room.dto.ts index 906524f..13b94c5 100644 --- a/backend/code/src/rooms/dto/create-room.dto.ts +++ b/backend/code/src/rooms/dto/create-room.dto.ts @@ -10,10 +10,10 @@ import { } from 'class-validator'; export class CreateRoomDto { - // @IgnoreName('type', { message: 'room name is not required on type dm' }) @ApiProperty({ description: 'name of the room required if type is not dm' }) @IsString() @IsNotEmpty() + @Length(4, 20) @ValidateIf((o) => o.type !== 'dm') name: string; diff --git a/backend/code/src/rooms/rooms.service.ts b/backend/code/src/rooms/rooms.service.ts index 9b68ff1..bda0473 100644 --- a/backend/code/src/rooms/rooms.service.ts +++ b/backend/code/src/rooms/rooms.service.ts @@ -1,8 +1,8 @@ import { + BadRequestException, HttpException, HttpStatus, Injectable, - UnauthorizedException, } from '@nestjs/common'; import { CreateRoomDto } from './dto/create-room.dto'; import { PrismaService } from 'src/prisma/prisma.service'; @@ -150,7 +150,7 @@ export class RoomsService { room.password, ); if (!isPasswordCorrect) { - throw new UnauthorizedException('wrong password'); + throw new BadRequestException('wrong password'); } } await this.prisma.roomMember.create({ @@ -185,7 +185,7 @@ export class RoomsService { }, }); if (ownerId === userId && !newOwner) - throw new UnauthorizedException( + throw new BadRequestException( 'You cannot leave this room because you are the only admin in it', ); @@ -213,7 +213,7 @@ export class RoomsService { }); if (!room) throw new HttpException('room not found', HttpStatus.NOT_FOUND); if (room.ownerId !== userId) { - throw new UnauthorizedException('you are not the owner of this room'); + throw new BadRequestException('You are not the owner of this room'); } await this.prisma.room.delete({ where: { id: roomData.roomId } }); return { message: 'deleted room successfully' }; @@ -236,7 +236,7 @@ export class RoomsService { if (!room) throw new HttpException('room not found', HttpStatus.NOT_FOUND); if (room.ownerId !== userId) { - throw new UnauthorizedException('you are not the owner of this room'); + throw new BadRequestException('You are not the owner of this room'); } if (roomData.type == 'protected' && !roomData.password) { @@ -284,9 +284,9 @@ export class RoomsService { select: { id: true }, }); if (room.ownerId !== userId) - throw new UnauthorizedException('You are not the owner of this room'); + throw new BadRequestException('You are not the owner of this room'); if (!member) - throw new UnauthorizedException('user is not a member of this room'); + throw new BadRequestException('user is not a member of this room'); await this.prisma.room.update({ where: { id: roomData.roomId }, data: { owner: { connect: { userId: roomData.memberId } } }, @@ -314,11 +314,11 @@ export class RoomsService { }); if (!room) throw new HttpException('room not found', HttpStatus.NOT_FOUND); if (room.ownerId !== userId) - throw new UnauthorizedException('You are not the owner of this room'); + throw new BadRequestException('You are not the owner of this room'); if (!user) - throw new UnauthorizedException('user is not a member of this room'); + throw new BadRequestException('User is not a member of this room'); if (user.is_admin || room.ownerId === roomData.memberId) - throw new UnauthorizedException( + throw new BadRequestException( 'new admin is already an admin of this room', ); return await this.prisma.roomMember.update({ @@ -352,13 +352,11 @@ export class RoomsService { if (!member) throw new HttpException('member not found', HttpStatus.NOT_FOUND); if (!user.is_admin || user.is_banned) - throw new UnauthorizedException('You are not admin of this room'); + throw new BadRequestException('You are not admin of this room'); if (member.userId === room.ownerId) - throw new UnauthorizedException( - 'You can not kick the owner of this room', - ); + throw new BadRequestException('You can not kick the owner of this room'); if (member.userId === userId) - throw new UnauthorizedException('You can not kick yourself'); + throw new BadRequestException('You can not kick yourself'); return await this.prisma.roomMember.delete({ where: { unique_user_room: { @@ -409,13 +407,13 @@ export class RoomsService { if (!member) throw new HttpException('member not found', HttpStatus.NOT_FOUND); if (!user.is_admin || user.is_banned) - throw new UnauthorizedException('You are not admin of this room'); + throw new BadRequestException('You are not admin of this room'); if (member.is_mueted) - throw new UnauthorizedException('member is already muted'); + throw new BadRequestException('Member is already muted'); if (member.room.ownerId === roomData.memberId) - throw new UnauthorizedException('You cannot mute the owner'); + throw new BadRequestException('You cannot mute the owner'); if (member.userId === userId) - throw new UnauthorizedException('You can not mute yourself'); + throw new BadRequestException('You can not mute yourself'); const afterFiveMin = new Date(Date.now() + 5 * 60 * 1000); await this.prisma.roomMember.update({ where: { @@ -455,7 +453,7 @@ export class RoomsService { where: { unique_user_room: { userId: userId, roomId: roomId } }, }); if (!user) - throw new UnauthorizedException('You are not a member of this room'); + throw new BadRequestException('You are not a member of this room'); const members = await this.prisma.roomMember.findMany({ skip: offset, take: limit, @@ -507,11 +505,11 @@ export class RoomsService { }); if (!user || !user.is_admin || user.is_banned) - throw new UnauthorizedException('You are not the admin of this Room'); + throw new BadRequestException('You are not the admin of this Room'); if (userId == memberData.memberId) - throw new UnauthorizedException('You cannot ban yourself'); + throw new BadRequestException('You cannot ban yourself'); if (ownerId == memberData.memberId) - throw new UnauthorizedException('You cannot ban the Owner of this Room'); + throw new BadRequestException('You cannot ban the Owner of this Room'); await this.prisma.roomMember.update({ where: { unique_user_room: { @@ -546,7 +544,7 @@ export class RoomsService { if (!member.is_banned) throw new HttpException('member is not banned', HttpStatus.BAD_REQUEST); if (!user.is_admin) - throw new UnauthorizedException('You are not admin of this room'); + throw new BadRequestException('You are not admin of this room'); await this.prisma.roomMember.update({ where: { unique_user_room: { @@ -589,8 +587,8 @@ export class RoomsService { if (count._count.userId >= 20) throw new HttpException('Room is full', HttpStatus.BAD_REQUEST); if (!user || !user.is_admin || user.is_banned) - throw new UnauthorizedException('You are not the admin of this Room'); - if (member) throw new UnauthorizedException('User already Exist'); + throw new BadRequestException('You are not the admin of this Room'); + if (member) throw new BadRequestException('User already Exist'); await this.prisma.roomMember.create({ data: { user: { @@ -618,7 +616,10 @@ export class RoomsService { members: { some: { userId: userId } }, NOT: { type: 'dm' }, }), - ...(!joined && { OR: [{ type: 'public' }, { type: 'protected' }] }), + ...(!joined && { + NOT: { members: { some: { userId } } }, + OR: [{ type: 'public' }, { type: 'protected' }], + }), }, select: { id: true, @@ -665,11 +666,13 @@ export class RoomsService { authorId: true, }, }); - const blocked = await this.prisma.blockedUsers.findFirst({ - where: { - id: [userId, last_message.authorId].sort().join('-'), - }, - }); + const blocked = last_message + ? await this.prisma.blockedUsers.findFirst({ + where: { + id: [userId, last_message.authorId].sort().join('-'), + }, + }) + : null; const is_owner = room.ownerId === userId; return { @@ -786,7 +789,7 @@ export class RoomsService { if (!room) throw new HttpException('room not found', HttpStatus.NOT_FOUND); const member = room.members.find((member) => member.user.userId === userId); if (!member) - throw new UnauthorizedException('you are not a member of this room'); + throw new BadRequestException('You are not a member of this room'); const secondMember = room.members.find( (member) => member.user.userId !== userId, ); diff --git a/backend/code/src/users/dto/update-user.dto.ts b/backend/code/src/users/dto/update-user.dto.ts index e8eaa17..f04ceaf 100644 --- a/backend/code/src/users/dto/update-user.dto.ts +++ b/backend/code/src/users/dto/update-user.dto.ts @@ -56,4 +56,6 @@ export class UpdateUserDto { discreption?: string; tfaToken?: string; + + Username?: string; } diff --git a/backend/code/src/users/users.service.ts b/backend/code/src/users/users.service.ts index 9b389db..f1b71d5 100644 --- a/backend/code/src/users/users.service.ts +++ b/backend/code/src/users/users.service.ts @@ -154,14 +154,11 @@ export class UsersService { } if (dataDto.action === TwoFactorAction.ENABLE && !user.tfaEnabled) { - console.log(dataDto); // generate a top with the same secret - console.log(authenticator.generate(dataDto.secret)); const isValid = authenticator.verify({ token: dataDto.otp, secret: dataDto.secret, }); - console.log(authenticator.keyuri('test', 'test', dataDto.secret)); if (!isValid) { throw new HttpException('Invalid OTP', 400); diff --git a/backend/code/test/app.e2e-spec.ts b/backend/code/test/app.e2e-spec.ts index f4a316f..fc3acfe 100644 --- a/backend/code/test/app.e2e-spec.ts +++ b/backend/code/test/app.e2e-spec.ts @@ -23,20 +23,4 @@ describe('AppController (e2e)', () => { }); }); - - - - - - - - - - - - - - - - //kslsl diff --git a/docker-compose.yaml b/docker-compose.yaml index a24d0ac..3e59164 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -10,15 +10,7 @@ services : networks: - pongnet init: true - database: - image: postgres - restart: always - environment: - POSTGRES_PASSWORD: test - volumes: - - database:/var/lib/postgresql/data - networks: - - pongnet + backend: build: context: ./backend @@ -28,11 +20,11 @@ services : - pongnet depends_on: - database - restart: always ports: - 3001:3001 - 3004:3004 init : true + restart: always nginx : build: @@ -49,10 +41,33 @@ services : - 8000:80 init: true restart: always + + database: + image: postgres + restart: always + env_file: + - ./.env + volumes: + - database:/var/lib/postgresql/data + networks: + - pongnet + + migration: + build: + context: ./backend/code/prisma + dockerfile: Dockerfile + image: prisma_migration:local + env_file: + - ./.env + networks: + - pongnet + depends_on: + - database volumes: front: database: + networks: pongnet: diff --git a/frontend/code/package-lock.json b/frontend/code/package-lock.json index 9471470..72affdb 100644 --- a/frontend/code/package-lock.json +++ b/frontend/code/package-lock.json @@ -9,15 +9,10 @@ "version": "0.1.0", "dependencies": { "@react-spring/web": "^9.7.3", - "@testing-library/jest-dom": "^5.17.0", - "@testing-library/react": "^13.4.0", - "@testing-library/user-event": "^13.5.0", - "@types/jest": "^27.5.2", "@types/node": "^16.18.38", "@types/react": "^18.2.15", "@types/react-dom": "^18.2.7", "axios": "^1.6.0", - "framer-motion": "^10.16.4", "preline": "^1.9.0", "react": "^18.2.0", "react-dom": "^18.2.0", @@ -29,7 +24,6 @@ "react-konva": "^18.2.10", "react-qr-code": "^2.0.12", "react-scripts": "^5.0.1", - "react-virtuoso": "^4.6.2", "socket.io-client": "^4.7.2", "tailwind-merge": "^2.0.0", "typescript": "^4.9.5", @@ -50,11 +44,6 @@ "node": ">=0.10.0" } }, - "node_modules/@adobe/css-tools": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.3.1.tgz", - "integrity": "sha512-/62yikz7NLScCGAAST5SHdnjaDJQBDq0M2muyRTpf2VQhw6StBg2ALiu73zSJQ4fMVLA+0uBhBHAle7Wg+2kSg==" - }, "node_modules/@alloc/quick-lru": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", @@ -3456,108 +3445,6 @@ "url": "https://github.com/sponsors/gregberge" } }, - "node_modules/@testing-library/dom": { - "version": "9.3.1", - "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-9.3.1.tgz", - "integrity": "sha512-0DGPd9AR3+iDTjGoMpxIkAsUihHZ3Ai6CneU6bRRrffXMgzCdlNk43jTrD2/5LT6CBb3MWTP8v510JzYtahD2w==", - "peer": true, - "dependencies": { - "@babel/code-frame": "^7.10.4", - "@babel/runtime": "^7.12.5", - "@types/aria-query": "^5.0.1", - "aria-query": "5.1.3", - "chalk": "^4.1.0", - "dom-accessibility-api": "^0.5.9", - "lz-string": "^1.5.0", - "pretty-format": "^27.0.2" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/@testing-library/jest-dom": { - "version": "5.17.0", - "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-5.17.0.tgz", - "integrity": "sha512-ynmNeT7asXyH3aSVv4vvX4Rb+0qjOhdNHnO/3vuZNqPmhDpV/+rCSGwQ7bLcmU2cJ4dvoheIO85LQj0IbJHEtg==", - "dependencies": { - "@adobe/css-tools": "^4.0.1", - "@babel/runtime": "^7.9.2", - "@types/testing-library__jest-dom": "^5.9.1", - "aria-query": "^5.0.0", - "chalk": "^3.0.0", - "css.escape": "^1.5.1", - "dom-accessibility-api": "^0.5.6", - "lodash": "^4.17.15", - "redent": "^3.0.0" - }, - "engines": { - "node": ">=8", - "npm": ">=6", - "yarn": ">=1" - } - }, - "node_modules/@testing-library/jest-dom/node_modules/chalk": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@testing-library/react": { - "version": "13.4.0", - "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-13.4.0.tgz", - "integrity": "sha512-sXOGON+WNTh3MLE9rve97ftaZukN3oNf2KjDy7YTx6hcTO2uuLHuCGynMDhFwGw/jYf4OJ2Qk0i4i79qMNNkyw==", - "dependencies": { - "@babel/runtime": "^7.12.5", - "@testing-library/dom": "^8.5.0", - "@types/react-dom": "^18.0.0" - }, - "engines": { - "node": ">=12" - }, - "peerDependencies": { - "react": "^18.0.0", - "react-dom": "^18.0.0" - } - }, - "node_modules/@testing-library/react/node_modules/@testing-library/dom": { - "version": "8.20.1", - "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-8.20.1.tgz", - "integrity": "sha512-/DiOQ5xBxgdYRC8LNk7U+RWat0S3qRLeIw3ZIkMQ9kkVlRmwD/Eg8k8CqIpD6GW7u20JIUOfMKbxtiLutpjQ4g==", - "dependencies": { - "@babel/code-frame": "^7.10.4", - "@babel/runtime": "^7.12.5", - "@types/aria-query": "^5.0.1", - "aria-query": "5.1.3", - "chalk": "^4.1.0", - "dom-accessibility-api": "^0.5.9", - "lz-string": "^1.5.0", - "pretty-format": "^27.0.2" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@testing-library/user-event": { - "version": "13.5.0", - "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-13.5.0.tgz", - "integrity": "sha512-5Kwtbo3Y/NowpkbRuSepbyMFkZmHgD+vPzYB/RJ4oxt5Gj/avFFBYjhw27cqSVPVw/3a67NK1PbiIr9k4Gwmdg==", - "dependencies": { - "@babel/runtime": "^7.12.5" - }, - "engines": { - "node": ">=10", - "npm": ">=6" - }, - "peerDependencies": { - "@testing-library/dom": ">=7.21.4" - } - }, "node_modules/@tootallnate/once": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", @@ -3574,11 +3461,6 @@ "node": ">=10.13.0" } }, - "node_modules/@types/aria-query": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.1.tgz", - "integrity": "sha512-XTIieEY+gvJ39ChLcB4If5zHtPxt3Syj5rgZR+e1ctpmK8NjPf0zFqsz4JpLJT0xla9GFDKjy8Cpu331nrmE1Q==" - }, "node_modules/@types/babel__core": { "version": "7.20.1", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.1.tgz", @@ -3742,15 +3624,6 @@ "@types/istanbul-lib-report": "*" } }, - "node_modules/@types/jest": { - "version": "27.5.2", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-27.5.2.tgz", - "integrity": "sha512-mpT8LJJ4CMeeahobofYWIjFo0xonRS/HfxnVEPMPFSQdGUt1uHCnoPT7Zhb+sjDU2wz0oKV0OLUR0WzrHNgfeA==", - "dependencies": { - "jest-matcher-utils": "^27.0.0", - "pretty-format": "^27.0.0" - } - }, "node_modules/@types/json-schema": { "version": "7.0.12", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.12.tgz", @@ -3890,14 +3763,6 @@ "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==" }, - "node_modules/@types/testing-library__jest-dom": { - "version": "5.14.9", - "resolved": "https://registry.npmjs.org/@types/testing-library__jest-dom/-/testing-library__jest-dom-5.14.9.tgz", - "integrity": "sha512-FSYhIjFlfOpGSRyVoMBMuS3ws5ehFQODymf3vlI7U1K8c7PHwWwFY7VREfmsuzHSOnoKs/9/Y983ayOs7eRzqw==", - "dependencies": { - "@types/jest": "*" - } - }, "node_modules/@types/trusted-types": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.3.tgz", @@ -5979,11 +5844,6 @@ "url": "https://github.com/sponsors/fb55" } }, - "node_modules/css.escape": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz", - "integrity": "sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==" - }, "node_modules/cssdb": { "version": "7.7.2", "resolved": "https://registry.npmjs.org/cssdb/-/cssdb-7.7.2.tgz", @@ -6415,11 +6275,6 @@ "node": ">=6.0.0" } }, - "node_modules/dom-accessibility-api": { - "version": "0.5.16", - "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", - "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==" - }, "node_modules/dom-converter": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz", @@ -7937,44 +7792,6 @@ "url": "https://github.com/sponsors/rawify" } }, - "node_modules/framer-motion": { - "version": "10.16.4", - "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-10.16.4.tgz", - "integrity": "sha512-p9V9nGomS3m6/CALXqv6nFGMuFOxbWsmaOrdmhyQimMIlLl3LC7h7l86wge/Js/8cRu5ktutS/zlzgR7eBOtFA==", - "dependencies": { - "tslib": "^2.4.0" - }, - "optionalDependencies": { - "@emotion/is-prop-valid": "^0.8.2" - }, - "peerDependencies": { - "react": "^18.0.0", - "react-dom": "^18.0.0" - }, - "peerDependenciesMeta": { - "react": { - "optional": true - }, - "react-dom": { - "optional": true - } - } - }, - "node_modules/framer-motion/node_modules/@emotion/is-prop-valid": { - "version": "0.8.8", - "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-0.8.8.tgz", - "integrity": "sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA==", - "optional": true, - "dependencies": { - "@emotion/memoize": "0.7.4" - } - }, - "node_modules/framer-motion/node_modules/@emotion/memoize": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.4.tgz", - "integrity": "sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==", - "optional": true - }, "node_modules/fresh": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", @@ -8704,14 +8521,6 @@ "node": ">=0.8.19" } }, - "node_modules/indent-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", - "engines": { - "node": ">=8" - } - }, "node_modules/inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -10543,14 +10352,6 @@ "yallist": "^3.0.2" } }, - "node_modules/lz-string": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz", - "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", - "bin": { - "lz-string": "bin/bin.js" - } - }, "node_modules/magic-string": { "version": "0.25.9", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz", @@ -10689,14 +10490,6 @@ "node": ">=6" } }, - "node_modules/min-indent": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", - "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", - "engines": { - "node": ">=4" - } - }, "node_modules/mini-css-extract-plugin": { "version": "2.7.6", "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.7.6.tgz", @@ -13241,18 +13034,6 @@ } } }, - "node_modules/react-virtuoso": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/react-virtuoso/-/react-virtuoso-4.6.2.tgz", - "integrity": "sha512-vvlqvzPif+MvBrJ09+hJJrVY0xJK9yran+A+/1iwY78k0YCVKsyoNPqoLxOxzYPggspNBNXqUXEcvckN29OxyQ==", - "engines": { - "node": ">=10" - }, - "peerDependencies": { - "react": ">=16 || >=17 || >= 18", - "react-dom": ">=16 || >=17 || >= 18" - } - }, "node_modules/read-cache": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", @@ -13296,18 +13077,6 @@ "node": ">=6.0.0" } }, - "node_modules/redent": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", - "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", - "dependencies": { - "indent-string": "^4.0.0", - "strip-indent": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/reflect.getprototypeof": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.4.tgz", @@ -14460,17 +14229,6 @@ "node": ">=6" } }, - "node_modules/strip-indent": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", - "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", - "dependencies": { - "min-indent": "^1.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", diff --git a/frontend/code/package.json b/frontend/code/package.json index 2ff1164..6c6f8e0 100644 --- a/frontend/code/package.json +++ b/frontend/code/package.json @@ -4,15 +4,10 @@ "private": true, "dependencies": { "@react-spring/web": "^9.7.3", - "@testing-library/jest-dom": "^5.17.0", - "@testing-library/react": "^13.4.0", - "@testing-library/user-event": "^13.5.0", - "@types/jest": "^27.5.2", "@types/node": "^16.18.38", "@types/react": "^18.2.15", "@types/react-dom": "^18.2.7", "axios": "^1.6.0", - "framer-motion": "^10.16.4", "preline": "^1.9.0", "react": "^18.2.0", "react-dom": "^18.2.0", @@ -24,7 +19,6 @@ "react-konva": "^18.2.10", "react-qr-code": "^2.0.12", "react-scripts": "^5.0.1", - "react-virtuoso": "^4.6.2", "socket.io-client": "^4.7.2", "tailwind-merge": "^2.0.0", "typescript": "^4.9.5", @@ -34,14 +28,15 @@ "scripts": { "start": "FORK_TS_CHECKER=false react-scripts start", "build": "FORK_TS_CHECKER=false react-scripts build", - "test": "react-scripts test", "eject": "react-scripts eject" }, "eslintConfig": { "extends": [ - "react-app", - "react-app/jest" - ] + "react-app" + ], + "rules": { + "jsx-a11y/anchor-is-valid": "off" + } }, "browserslist": { "production": [ diff --git a/frontend/code/src/Api/base.tsx b/frontend/code/src/Api/base.tsx index 4003abd..5203412 100644 --- a/frontend/code/src/Api/base.tsx +++ b/frontend/code/src/Api/base.tsx @@ -1,10 +1,4 @@ import axios from "axios"; -// import { useNavigate } from 'react-router-dom'; -// import { useUserStore } from "../Stores/stores"; -// const useNavigateCustom = () => { -// const navigate = useNavigate(); -// return navigate; -// }; const apiWithoutManager = axios.create({ baseURL: `${process.env.REACT_APP_API_ENDPOINT}`, @@ -17,8 +11,8 @@ const apiWithoutManager = axios.create({ }); const ConcurrencyManager = (axios: any, MAX_CONCURRENT = 10) => { - if (MAX_CONCURRENT < 1){ - //eslint-disable-next-line + if (MAX_CONCURRENT < 1) { + //eslint-disable-next-line throw "Concurrency Manager Error: minimun concurrent requests is 1"; } let instance = { @@ -44,7 +38,7 @@ const ConcurrencyManager = (axios: any, MAX_CONCURRENT = 10) => { }, // Use as interceptor. Queue outgoing requests requestHandler: (req: any) => { - return new Promise(resolve => { + return new Promise((resolve) => { instance.push({ request: req, resolver: resolve }); }); }, @@ -57,31 +51,34 @@ const ConcurrencyManager = (axios: any, MAX_CONCURRENT = 10) => { responseErrorHandler: async (error: any) => { if (error?.response?.status === 401) { try { - const refreshError = await apiWithoutManager.get("auth/refresh").then(() => null).catch((err: any) => err); - if (refreshError && window.location.pathname !== '/') { + const refreshError = await apiWithoutManager + .get("auth/refresh") + .then(() => null) + .catch((err: any) => err); + if (refreshError && window.location.pathname !== "/") { instance.queue = []; instance.running = []; - window.location.href = '/'; + window.location.href = "/"; return; } const res = await apiWithoutManager.request(error.config); return instance.responseHandler(res); - } catch (refreshError) { } + } catch (refreshError) {} } return Promise.reject(instance.responseHandler(error)); }, interceptors: { request: null, - response: null + response: null, }, detach: () => { axios.interceptors.request.eject(instance.interceptors.request); axios.interceptors.response.eject(instance.interceptors.response); - } + }, }; // queue concurrent requests instance.interceptors.request = axios.interceptors.request.use( - instance.requestHandler + instance.requestHandler, ); instance.interceptors.response = axios.interceptors.response.use( instance.responseHandler, @@ -103,18 +100,4 @@ const api = axios.create({ // init your manager. ConcurrencyManager(api, 1); -// const errorHandler = async (error: any) => { -// if (error?.response?.status === 401) { -// try { -// await api.get("auth/refresh"); -// return api.request(error.config); -// } catch (refreshError) {} -// } -// return Promise.reject(error); -// }; -// api.interceptors.response.use( -// (response) => response, -// (error) => errorHandler(error) -// ); - export default api; diff --git a/frontend/code/src/Components/Chat/Components/Conversation.tsx b/frontend/code/src/Components/Chat/Components/Conversation.tsx index 0c3aaab..84c22cd 100644 --- a/frontend/code/src/Components/Chat/Components/Conversation.tsx +++ b/frontend/code/src/Components/Chat/Components/Conversation.tsx @@ -46,7 +46,13 @@ export const CurrentUserMessage = forwardRef((props, ref) => { const currentUserId = useUserStore((state) => state.id); return props.senderId === currentUserId ? ( -
    +
    {props.message}
    - {props.isPending ? 'Sending...' : (props.isFailed ? "Failed" : "Delivered")} + {props.isPending + ? "Sending..." + : props.isFailed + ? "Failed" + : "Delivered"}
    ) : (
    - {props.avatar?.medium - ? - :
    } + {props.avatar?.medium ? ( + + ) : ( +
    + )}
    @@ -126,12 +138,12 @@ export const ConversationHeader: React.FC = ({ useEffect(() => { SetOnline(false); - socketStore.socket.on("friendOffline", handleOffline); - socketStore.socket.on("friendOnline", handleOnline); + socketStore.socket?.on("friendOffline", handleOffline); + socketStore.socket?.on("friendOnline", handleOnline); return () => { - socketStore.socket.off("friendOffline", handleOffline); - socketStore.socket.off("friendOnline", handleOnline); + socketStore.socket?.off("friendOffline", handleOffline); + socketStore.socket?.off("friendOnline", handleOnline); }; // eslint-disable-next-line }, [ChatState.selectedChatID]); @@ -146,8 +158,9 @@ export const ConversationHeader: React.FC = ({
    -
    @@ -169,8 +186,9 @@ export const ConversationHeader: React.FC = ({

    {selectedChatType === ChatType.Chat ? (

    {isOnline ? "online" : "offline"}

    @@ -193,13 +211,12 @@ export const ConversationHeader: React.FC = ({ className="p-2 shadow menu dropdown-content z-[1] bg-base-100 rounded-box w-52 absolute right-full" >
  • { + onClick={() => { ChatState.setIsLoading(true); - await blockUserCall(currentUser?.secondUserId).then((res) => { + blockUserCall(currentUser?.secondUserId).then((res) => { ChatState.setIsLoading(false); if (res?.status === 200 || res?.status === 201) { toast.success("User Blocked"); - // ChatState.selectNewChatID("1"); } else { toast.error("Could Not Block User"); } @@ -225,7 +242,7 @@ export const ConversationHeader: React.FC = ({ } user.setGameWaitingId(data.gameId); inviteWaitingModalRef.current?.showModal(); - } + }, ); }} > @@ -259,37 +276,31 @@ export const ConversationHeader: React.FC = ({ > {(currentRoom?.isAdmin === true || currentRoom?.isOwner === true) && ( -
  • - - Edit Room Settings - -
  • - - { - LayoutState.setShowAddUsersModal( - !LayoutState.showAddUsersModal - ); - }} - href="#my_modal_6" - className="" - > -
  • - Add Users -
  • -
    -
    - )} + + )}
  • { @@ -304,21 +315,17 @@ export const ConversationHeader: React.FC = ({ : "hide Room Info"}
  • - {/* {currentRoom?.isOwner === false && ( */}
  • { + onClick={() => { ChatState.setIsLoading(true); - await leaveRoomCall(currentRoom?.id as string).then( - (res) => { - ChatState.setIsLoading(false); - if (res?.status === 200 || res?.status === 201) { - toast.success("Room Left Successfully"); - // ChatState.changeChatType(ChatType.Chat); - ChatState.deleteRoom(currentRoom?.id as string); - } + leaveRoomCall(currentRoom?.id as string).then((res) => { + ChatState.setIsLoading(false); + if (res?.status === 200 || res?.status === 201) { + toast.success("Room Left Successfully"); + ChatState.deleteRoom(currentRoom?.id as string); } - ); + }); }} > leave The Room @@ -352,7 +359,6 @@ export const Conversation: React.FC = ({ onRemoveUserPreview, }) => { const chatState = useChatStore(); - const currentUserId = useUserStore((state) => state.id); const messageContainerRef = useRef(null); const socketStore = useSocketStore(); @@ -365,8 +371,6 @@ export const Conversation: React.FC = ({ } }; - const [inputValue, setInputValue] = useState(""); - const [FailToSendMessage, setFail] = useState(false); const [IsLoading, setLoading] = useState(true); const currentUser = useUserStore((state) => state); @@ -395,11 +399,6 @@ export const Conversation: React.FC = ({ } }; - const handleInputChange = (e: { target: { value: React.SetStateAction } }) => { - setFail(false); - setInputValue(e.target.value); - }; - const [ref, inView] = useInView({ threshold: 0.5 }); useEffect(() => { @@ -411,21 +410,20 @@ export const Conversation: React.FC = ({ useEffect(() => { if (!socketStore.socket) return; - socketStore.socket.emit("joinRoom", { + socketStore.socket?.emit("joinRoom", { memberId: currentUser.id, roomId: chatState.selectedChatID, }); - socketStore.socket.emit("PingOnline", { + socketStore.socket?.emit("PingOnline", { friendId: chatState.currentDmUser.secondUserId, }); - // const handle - socketStore.socket.on("roomDeparture", handleLeave); - socketStore.socket.on("message", handleMessage); + socketStore.socket?.on("roomDeparture", handleLeave); + socketStore.socket?.on("message", handleMessage); return () => { - socketStore.socket.off("message", handleMessage); - socketStore.socket.emit("roomDeparture", { + socketStore.socket?.off("message", handleMessage); + socketStore.socket?.emit("roomDeparture", { roomId: chatState.selectedChatID, memberId: currentUser.id, type: "out", @@ -448,13 +446,15 @@ export const Conversation: React.FC = ({ if (!res.data || !res.data.length) { setShowLoadMore(false); } else { - const messages: Message[] = res.data.map((message: APIMessageResponse) => ({ - id: message.id, - avatar: message.avatar, - senderId: message.authorId, - message: message.content, - time: message.time, - })); + const messages: Message[] = res.data.map( + (message: APIMessageResponse) => ({ + id: message.id, + avatar: message.avatar, + senderId: message.authorId, + message: message.content, + time: message.time, + }), + ); chatState.fillCurrentMessages([...currentMessages, ...messages]); } } @@ -464,51 +464,15 @@ export const Conversation: React.FC = ({ // eslint-disable-next-line }, [chatState.selectedChatID, inView]); - const sendMessage = async () => { - if (inputValue.length === 0) return; - setInputValue(""); - const clientMessageId = btoa(Math.random().toString(36)).substring(0, 16); - - const newMessage: Message = { - avatar: { thumbnail: '', medium: '', large: '' }, - senderId: currentUserId, - message: inputValue, - time: new Date().toISOString(), - isPending: true, - clientMessageId, - }; - chatState.fillCurrentMessages([newMessage, ...chatState.currentMessages]); - - scrollToBottom(); - - sendMessageCall(chatState.selectedChatID, inputValue, clientMessageId).then((res) => { - if (res?.status !== 200 && res?.status !== 201) { - setFail(true); - chatState.selectedChatType === ChatType.Room - ? toast.error("you are not authorized to send messages in this room") - : toast.error("you are blocked from sending messages to this user"); - chatState.setMessageAsFailed(res?.data.id); - // Remove failed message - chatState.removeMessageFromCurrentMessages((e) => e.clientMessageId !== clientMessageId); - } - }); - }; - - const handleKeyPress = async (e: KeyboardEvent) => { - if (e.key === "Enter") { - await sendMessage().then(() => scrollToBottom()); - } - }; - return (
    - {(chatState.currentMessages && chatState.currentMessages.length > 0) ? ( + {chatState.currentMessages && chatState.currentMessages.length > 0 ? ( chatState.currentMessages.map((message) => ( = ({ ) : ( )} - {showLoadMore && chatState.currentMessages && chatState.currentMessages.length &&
    - {IsLoading ? 'Loading...' : 'Load more'} -
    } - {IsLoading && (!chatState.currentMessages || !chatState.currentMessages.length) && ( -
    - -
    - )} + {showLoadMore && + chatState.currentMessages && + chatState.currentMessages.length && ( +
    + {IsLoading ? "Loading..." : "Load more"} +
    + )} + {IsLoading && + (!chatState.currentMessages || !chatState.currentMessages.length) && ( +
    + +
    + )}
    -
    -
    -
    -
    - - - -
    -
    -
    + +
    + ); +}; + +interface ConversationInputProps { + scrollToBottom: () => void; +} + +const ConversationInput = (props: ConversationInputProps) => { + const [inputValue, setInputValue] = useState(""); + const [FailToSendMessage, setFail] = useState(false); + + const chatState = useChatStore(); + const currentUserId = useUserStore((state) => state.id); + + const sendMessage = () => { + if (inputValue.length === 0) return; + setInputValue(""); + const clientMessageId = btoa(Math.random().toString(36)).substring(0, 16); + + const newMessage: Message = { + avatar: { thumbnail: "", medium: "", large: "" }, + senderId: currentUserId, + message: inputValue, + time: new Date().toISOString(), + isPending: true, + clientMessageId, + }; + chatState.fillCurrentMessages([newMessage, ...chatState.currentMessages]); + + props.scrollToBottom(); + + sendMessageCall(chatState.selectedChatID, inputValue, clientMessageId).then( + (res) => { + if (res?.status !== 200 && res?.status !== 201) { + setFail(true); + if (res?.data.message) { + toast.error(res.data.message); + } else { + toast.error("You cannot send a message at the moment"); + } + chatState.setMessageAsFailed(res?.data.id); + // Remove failed message + chatState.removeMessageFromCurrentMessages( + (e) => e.clientMessageId !== clientMessageId, + ); + } + }, + ); + }; + + const handleKeyPress = (e: KeyboardEvent) => { + if (e.key === "Enter") { + sendMessage(); + } + }; + + const handleInputChange = (e: { + target: { value: React.SetStateAction }; + }) => { + setFail(false); + setInputValue(e.target.value); + }; + + return ( +
    +
    + + +
    ); diff --git a/frontend/code/src/Components/Chat/Components/RecentChat.tsx b/frontend/code/src/Components/Chat/Components/RecentChat.tsx index 9292a22..705c3a0 100644 --- a/frontend/code/src/Components/Chat/Components/RecentChat.tsx +++ b/frontend/code/src/Components/Chat/Components/RecentChat.tsx @@ -12,7 +12,7 @@ import { check, } from "./tools/Assets"; -import { NullPlaceHolder, RoomChatPlaceHolder } from "./RoomChatHelpers"; +import { NullPlaceHolder } from "./RoomChatHelpers"; import { useModalStore } from "../Controllers/LayoutControllers"; import { createNewRoomCall, @@ -28,7 +28,6 @@ import { useInView } from "react-intersection-observer"; export const RecentConversations = () => { const [isLoading, setLoading] = useState(false); - const selectedChatType = useChatStore((state) => state.selectedChatType); const ChatRoomsState = useChatStore((state) => state); const [ref, inView] = useInView(); @@ -42,49 +41,53 @@ export const RecentConversations = () => { offset === 0 && setLoading(true); - fetchDmsCall(offset, 7).then((res) => { - if (res?.status !== 200 && res?.status !== 201) { - } else { - const rooms: DmRoom[] = []; - res.data.forEach( - (room: { - secondMemberId: string; - id: string; - last_message?: { - content?: string; - createdAt?: string; - }; - name: string; + fetchDmsCall(offset, 7) + .then((res) => { + if (res?.status !== 200 && res?.status !== 201) { + } else { + const rooms: DmRoom[] = []; + res.data.forEach( + (room: { + secondMemberId: string; + id: string; + last_message?: { + content?: string; + createdAt?: string; + }; + name: string; - avatar: { - thumbnail: string; - medium: string; - large: string; - }; - bio: string; - }) => { - // to check if not exist - rooms.push({ - secondUserId: room.secondMemberId, - id: room.id, - name: room.name, - avatar: room.avatar, - last_message: { - content: room.last_message?.content, - createdAt: room.last_message?.createdAt, - }, - bio: room.bio, - }); - } - ); + avatar: { + thumbnail: string; + medium: string; + large: string; + }; + bio: string; + }) => { + // to check if not exist + rooms.push({ + secondUserId: room.secondMemberId, + id: room.id, + name: room.name, + avatar: room.avatar, + last_message: { + content: room.last_message?.content, + createdAt: room.last_message?.createdAt, + }, + bio: room.bio, + }); + }, + ); - if (res.data.length > 0) { - ChatRoomsState.fillRecentDms([...ChatRoomsState.recentDms, ...rooms]); - } else { - setEndOfFetching(true); + if (res.data.length > 0) { + ChatRoomsState.fillRecentDms([ + ...ChatRoomsState.recentDms, + ...rooms, + ]); + } else { + setEndOfFetching(true); + } } - } - }) + }) .finally(() => setLoading(false)); }; @@ -93,7 +96,7 @@ export const RecentConversations = () => { // eslint-disable-next-line }, [inView]); - return selectedChatType === ChatType.Chat ? ( + return (
    {ChatRoomsState.recentDms.length > 0 ? ( @@ -112,20 +115,36 @@ export const RecentConversations = () => { userImage={friend.avatar.medium} /> ))} - {!EndOfFetching &&
    - - Loading... - -
    } - {EndOfFetching &&
    - - No more dm... { - setEndOfFetching(false); // Reset - ChatRoomsState.fillRecentDms([]); // Reset - setTimeout(() => fetchDms(true), 100); - }}>Refresh! - -
    } + {!EndOfFetching && ( +
    + + Loading... + +
    + )} + {EndOfFetching && ( +
    + + No more dm...{" "} + { + setEndOfFetching(false); // Reset + ChatRoomsState.fillRecentDms([]); // Reset + setTimeout(() => fetchDms(true), 100); + }} + > + Refresh! + + +
    + )}
    ) : ( <> @@ -139,13 +158,6 @@ export const RecentConversations = () => { )}
    - ) : ( -
    - -
    - -
    -
    ); }; @@ -181,8 +193,9 @@ export const ChatPlaceHolder = ({ }, }); }} - className={`message-container flex px-4 py-5 hover:bg-[#272932] items-center ${selectedChatID === id ? "bg-[#272932]" : "bg-[#1A1C26]" - }`} + className={`message-container flex px-4 py-5 hover:bg-[#272932] items-center ${ + selectedChatID === id ? "bg-[#272932]" : "bg-[#1A1C26]" + }`} >
    { const navigate = useNavigate(); const [Users, setUsers] = useState([]); - const setModalState = useModalStore((state) => state.setShowExploreModal); + const modalState = useModalStore(); const handleListOfOnline = (ids: string[]) => { ids.forEach((id) => { @@ -263,7 +276,7 @@ export const OnlineNowUsers = () => { // to inject it with the real images later avatar: friend.avatar, } as RoomMember); - } + }, ); setUsers(friends); @@ -271,7 +284,7 @@ export const OnlineNowUsers = () => { } }); }; - socketStore.socket.on("onlineFriends", handleListOfOnline); + socketStore.socket?.on("onlineFriends", handleListOfOnline); fetchFriends(); // eslint-disable-next-line }, [chatState.onlineFriendsIds.length]); @@ -284,25 +297,27 @@ export const OnlineNowUsers = () => { Messages

    -
    - {/* Avatar Tailwind CSS Component */}
    diff --git a/frontend/code/src/Components/Error/Assets/Font.tsx b/frontend/code/src/Components/Error/Assets/Font.tsx index 9c5322c..dfba0b7 100644 --- a/frontend/code/src/Components/Error/Assets/Font.tsx +++ b/frontend/code/src/Components/Error/Assets/Font.tsx @@ -1,13 +1,38 @@ - - export const Font = () => { - return ( - - - - - - - - ) -} \ No newline at end of file + return ( + + + + + + + ); +}; diff --git a/frontend/code/src/Components/Error/index.tsx b/frontend/code/src/Components/Error/index.tsx index d9dd299..7f10f30 100644 --- a/frontend/code/src/Components/Error/index.tsx +++ b/frontend/code/src/Components/Error/index.tsx @@ -1,12 +1,13 @@ -import { Font } from './Assets/Font' +import { Font } from "./Assets/Font"; -export const Error = () => -{ - return ( -
    - -
    -

    Page Not Found

    -
    - ) -} \ No newline at end of file +export const Error = () => { + return ( +
    + +
    +

    + Page Not Found +

    +
    + ); +}; diff --git a/frontend/code/src/Components/FirstLogin/UploadAvatar.tsx b/frontend/code/src/Components/FirstLogin/UploadAvatar.tsx index 1a558ec..7aa5813 100644 --- a/frontend/code/src/Components/FirstLogin/UploadAvatar.tsx +++ b/frontend/code/src/Components/FirstLogin/UploadAvatar.tsx @@ -10,6 +10,7 @@ type Inputs = { lastName: string; discreption: string; email: string; + Username: string; }; const ERROR_MESSAGES = [ "Field is required", @@ -20,10 +21,18 @@ const payload_objects = [ "firstName", "lastName", "email", + "Username", "phone", "discreption", ]; -const data_names = ["First name", "Last name", "Email", "Phone", "Bio"]; +const data_names = [ + "First name", + "Last name", + "Email", + "Username", + "Phone", + "Bio", +]; export const UploadAvatar = () => { const userStore = useUserStore(); const navigate = useNavigate(); @@ -40,7 +49,7 @@ export const UploadAvatar = () => { } catch (e) {} }; const handleError = (errors: any) => { - //eslint-disable-next-line + // eslint-disable-next-line payload_objects.map((item: any, index: number) => { if (errors[`${item}`]?.type === "required") toast.error(`${data_names[index]} ${ERROR_MESSAGES[0]} `); @@ -48,6 +57,8 @@ export const UploadAvatar = () => { toast.error(`${data_names[index]} ${ERROR_MESSAGES[1]} 4`); if (errors[`${item}`]?.type === "maxLength") toast.error(`${data_names[index]} ${ERROR_MESSAGES[2]} 50 `); + if (errors[`${item}`]?.type === "pattern") + toast.error(`${errors[`${item}`]?.message}`); }); }; @@ -91,6 +102,17 @@ export const UploadAvatar = () => { defaultValue={userStore.bio} className="input input-bordered input-primary w-full" /> + { success: "New Avatar Saved", error: "Error On Uploading image", }, - { position: "top-center", className: "h-20", duration: 2000 } + { position: "top-center", className: "h-20", duration: 2000 }, ); }} ref={inputRef} diff --git a/frontend/code/src/Components/Game/States/GameState.ts b/frontend/code/src/Components/Game/States/GameState.ts index a5c9f11..e9c0805 100644 --- a/frontend/code/src/Components/Game/States/GameState.ts +++ b/frontend/code/src/Components/Game/States/GameState.ts @@ -1,59 +1,58 @@ -import { create } from 'zustand' +import { create } from "zustand"; type GameStateType = { - width:number; - height:number; - mobile:boolean; - ball:{ - x:number, - y:number, - size:number, - p1Score:number, - p2Score:number, + width: number; + height: number; + mobile: boolean; + ball: { + x: number; + y: number; + size: number; + p1Score: number; + p2Score: number; }; - lPaddle:number; - rPaddle:number; - ballOwner:number; - p1:any; - p2:any; - side:boolean; - end:boolean; -} + lPaddle: number; + rPaddle: number; + ballOwner: number; + p1: any; + p2: any; + side: boolean; + end: boolean; +}; type GameActions = { - setHeight : (h: GameStateType['height']) => void; - setWidth : (w : GameStateType['width']) => void; - setLPaddle : (lp : GameStateType['lPaddle']) => void; - setRPaddle : (rp : GameStateType['rPaddle']) => void; - setBall : (pos : GameStateType['ball']) => void; - setMobile : (isMobile : GameStateType['mobile']) => void; - setP1 : (p1 : GameStateType['p1']) => void; - setP2 : (p2 : GameStateType['p2']) => void; - setSide : (side : GameStateType['side']) => void; - setEnd : (end : GameStateType['end']) => void; -} + setHeight: (h: GameStateType["height"]) => void; + setWidth: (w: GameStateType["width"]) => void; + setLPaddle: (lp: GameStateType["lPaddle"]) => void; + setRPaddle: (rp: GameStateType["rPaddle"]) => void; + setBall: (pos: GameStateType["ball"]) => void; + setMobile: (isMobile: GameStateType["mobile"]) => void; + setP1: (p1: GameStateType["p1"]) => void; + setP2: (p2: GameStateType["p2"]) => void; + setSide: (side: GameStateType["side"]) => void; + setEnd: (end: GameStateType["end"]) => void; +}; -export const useGameState = create((set)=> ({ - width : 0, - height : 0, - mobile : false, - ball : {x: 0,y:0,size:0,p1Score:0,p2Score:0}, - lPaddle : 0, - rPaddle : 0, - ballOwner:-1, - p1:null, - p2:null, - side:false, - end:true, - setHeight : (h) => set(() => ({height : h})), - setWidth : (w) => set(() => ({width : w})), - setLPaddle : (lp) => set(() => ({lPaddle : lp})), - setRPaddle : (rp) => set(() => ({rPaddle : rp})), - setMobile : (isMobile ) => set(() => ({mobile:isMobile})), - setBall : (pos) => set(() => ({ball:pos})), - setP1 : (p1) => set(() => ({p1:p1})), - setP2 : (p2) => set(() => ({p2:p2})), - setSide : (side) => set(() => ({side:side})), - setEnd : (end) => set(() => ({end:end})), - -})) \ No newline at end of file +export const useGameState = create((set) => ({ + width: 0, + height: 0, + mobile: false, + ball: { x: 0, y: 0, size: 0, p1Score: 0, p2Score: 0 }, + lPaddle: 0, + rPaddle: 0, + ballOwner: -1, + p1: null, + p2: null, + side: false, + end: true, + setHeight: (h) => set(() => ({ height: h })), + setWidth: (w) => set(() => ({ width: w })), + setLPaddle: (lp) => set(() => ({ lPaddle: lp })), + setRPaddle: (rp) => set(() => ({ rPaddle: rp })), + setMobile: (isMobile) => set(() => ({ mobile: isMobile })), + setBall: (pos) => set(() => ({ ball: pos })), + setP1: (p1) => set(() => ({ p1: p1 })), + setP2: (p2) => set(() => ({ p2: p2 })), + setSide: (side) => set(() => ({ side: side })), + setEnd: (end) => set(() => ({ end: end })), +})); diff --git a/frontend/code/src/Components/Game/index.tsx b/frontend/code/src/Components/Game/index.tsx index e57ca62..4b5ab1f 100644 --- a/frontend/code/src/Components/Game/index.tsx +++ b/frontend/code/src/Components/Game/index.tsx @@ -1,196 +1,262 @@ -import { useCallback, useEffect, useState } from "react" -import { Rect, Stage , Layer , Circle, Line} from "react-konva" -import { BsFillArrowRightCircleFill, BsFillArrowLeftCircleFill} from "react-icons/bs"; +import { useCallback, useEffect, useState } from "react"; +import { Rect, Stage, Layer, Circle, Line } from "react-konva"; +import { + BsFillArrowRightCircleFill, + BsFillArrowLeftCircleFill, +} from "react-icons/bs"; import { useGameState } from "./States/GameState"; import { useSocketStore } from "../Chat/Services/SocketsServices"; import { useNavigate } from "react-router-dom"; - - - - const DURATION = 20; type Cords = { - x:number; - y:number; - ballsize:number; - p1Score:number; - p2Score:number; -} + x: number; + y: number; + ballsize: number; + p1Score: number; + p2Score: number; +}; -const throttle = (function() { - let timeout:any = undefined; - return function throttle(callback:any) { +const throttle = (function () { + let timeout: any = undefined; + return function throttle(callback: any) { if (timeout === undefined) { callback(); timeout = setTimeout(() => { timeout = undefined; }, DURATION); } - } + }; })(); - -function throttlify(callback : any) { - return function throttlified(event :any) { +function throttlify(callback: any) { + return function throttlified(event: any) { throttle(() => { callback(event); }); - } + }; } export const Game = () => { - const gameState = useGameState(); - const socketStore = useSocketStore(); - const [level , setLevel] = useState(1); - const [t , setT ] = useState(0); - const navigate = useNavigate() + const gameState = useGameState(); + const socketStore = useSocketStore(); + const [level, setLevel] = useState(1); + const [t, setT] = useState(0); + const navigate = useNavigate(); - const leave = useCallback(() => { - socketStore.socket.emit("leave") - gameState.setEnd(true); - // eslint-disable-next-line - },[]) - - const handleMove = throttlify((e :any) => { - socketStore.socket.emit("mouse",e.evt.layerY); - }) - const ArrowUp = () => { - socketStore.socket.emit("up"); - socketStore.socket.off("up"); - } - const ArrowDown = () => { - socketStore.socket.emit("down") - socketStore.socket.off("down"); - } - useEffect(() => { - socketStore.socket.on("level", (l:number) => {setLevel(l)}) - socketStore.socket.on("t", (t:number) => {setT(t)}) - socketStore.socket.on("game.end", () =>{ - gameState.setEnd(true) - }) - document.addEventListener('keydown', (event) =>{ - if (event.key === "ArrowUp") - socketStore.socket.emit("up"); - if (event.key === "ArrowDown") - socketStore.socket.emit("down") - }) - socketStore.socket.on("ball", (cord:Cords) => { - gameState.setBall({x:cord.x,y:cord.y,size:cord.ballsize,p1Score:cord.p1Score,p2Score:cord.p2Score}) - }) - socketStore.socket.on("paddle", (paddles:any) => { - gameState.setLPaddle(paddles.p1PaddleY); - gameState.setRPaddle(paddles.p2PaddleY); - if (gameState?.side !== paddles.side) - gameState.setSide(paddles.side); - }) - socketStore.socket.on("screen Error", () =>{ - console.log("you lose") - navigate("/home") - }) - socketStore.socket.on("players", (players:any) => { - gameState.setP1(players[0]); - gameState.setP2(players[1]); - }) - return () => { - socketStore.socket.off("ball"); - socketStore.socket.off("mouse"); - socketStore.socket.off("down"); - socketStore.socket.off("up"); - socketStore.socket.off("leave") - socketStore.socket.off("level") - socketStore.socket.off("t") - socketStore.socket.off("game.end") + const leave = useCallback(() => { + socketStore.socket?.emit("leave"); + gameState.setEnd(true); + // eslint-disable-next-line + }, []); - window.removeEventListener("keydown",()=>{}); + const handleMove = throttlify((e: any) => { + socketStore.socket?.emit("mouse", e.evt.layerY); + }); + const ArrowUp = () => { + socketStore.socket?.emit("up"); + socketStore.socket?.off("up"); + }; + const ArrowDown = () => { + socketStore.socket?.emit("down"); + socketStore.socket?.off("down"); + }; + useEffect(() => { + socketStore.socket?.on("level", (l: number) => { + setLevel(l); + }); + socketStore.socket?.on("t", (t: number) => { + setT(t); + }); + socketStore.socket?.on("game.end", () => { + gameState.setEnd(true); + }); + document.addEventListener("keydown", (event) => { + if (event.key === "ArrowUp") socketStore.socket?.emit("up"); + if (event.key === "ArrowDown") socketStore.socket?.emit("down"); + }); + socketStore.socket?.on("ball", (cord: Cords) => { + gameState.setBall({ + x: cord.x, + y: cord.y, + size: cord.ballsize, + p1Score: cord.p1Score, + p2Score: cord.p2Score, + }); + }); + socketStore.socket?.on("paddle", (paddles: any) => { + gameState.setLPaddle(paddles.p1PaddleY); + gameState.setRPaddle(paddles.p2PaddleY); + if (gameState?.side !== paddles.side) gameState.setSide(paddles.side); + }); + socketStore.socket?.on("screen Error", () => { + navigate("/home"); + }); + socketStore.socket?.on("players", (players: any) => { + gameState.setP1(players[0]); + gameState.setP2(players[1]); + }); + return () => { + socketStore.socket?.off("ball"); + socketStore.socket?.off("mouse"); + socketStore.socket?.off("down"); + socketStore.socket?.off("up"); + socketStore.socket?.off("leave"); + socketStore.socket?.off("level"); + socketStore.socket?.off("t"); + socketStore.socket?.off("game.end"); - } - // eslint-disable-next-line - },[]) - /* eslint-disable */ - useEffect(() => { - if (!gameState.p1) - navigate("/home") - const divh = document.getElementById('Game')?.offsetHeight - const divw = document.getElementById('Game')?.offsetWidth - socketStore.socket.emit("screen",{h:divh,w:divw}) + window.removeEventListener("keydown", () => {}); + }; + // eslint-disable-next-line + }, []); + /* eslint-disable */ + useEffect(() => { + if (!gameState.p1) navigate("/home"); + const divh = document.getElementById("Game")?.offsetHeight; + const divw = document.getElementById("Game")?.offsetWidth; + socketStore.socket?.emit("screen", { h: divh, w: divw }); + gameState.setEnd(false); + if (divw) { + divw <= 742 ? gameState.setMobile(true) : gameState.setMobile(false); + } + window.addEventListener("resize", () => { gameState.setEnd(false); - if (divw) {divw <= 742 ? gameState.setMobile(true) : gameState.setMobile(false)} - window.addEventListener('resize', () => { - gameState.setEnd(false); - const divh = document.getElementById('Game')?.offsetHeight - const divw = document.getElementById('Game')?.offsetWidth - const aspectRatio = 16 / 9; - const newWidth = divw ?? 0 ; - const newHeight = newWidth / aspectRatio; - socketStore.socket.emit("screen",{h:newHeight,w:newWidth}) - if (divh) gameState.setHeight(newHeight); - if (divw) {gameState.setWidth(divw);divw <= 742 ? gameState.setMobile(true) : gameState.setMobile(false);} - }); - - return () => { - socketStore.socket.off("screen"); - window.removeEventListener("resize",()=>{}); + const divh = document.getElementById("Game")?.offsetHeight; + const divw = document.getElementById("Game")?.offsetWidth; + const aspectRatio = 16 / 9; + const newWidth = divw ?? 0; + const newHeight = newWidth / aspectRatio; + socketStore.socket?.emit("screen", { h: newHeight, w: newWidth }); + if (divh) gameState.setHeight(newHeight); + if (divw) { + gameState.setWidth(divw); + divw <= 742 ? gameState.setMobile(true) : gameState.setMobile(false); + } + }); - } + return () => { + socketStore.socket?.off("screen"); + window.removeEventListener("resize", () => {}); + }; - // disable eslit next line - },[]) + // disable eslit next line + }, []); - useEffect(() => { - const divh = document.getElementById('Game')?.offsetHeight - const divw = document.getElementById('Game')?.offsetWidth - console.log(divh) - console.log(divw) - const aspectRatio = 16 / 9; - const newWidth = divw ?? 0 ; - const newHeight = newWidth / aspectRatio; - if (divh) gameState.setHeight(newHeight); - if (divw) gameState.setWidth(divw); - - },[gameState.width , gameState.height]) + useEffect(() => { + const divh = document.getElementById("Game")?.offsetHeight; + const divw = document.getElementById("Game")?.offsetWidth; - return ( -
    -
    -
    - - {gameState.ball.p1Score} -
    -
    - {gameState?.ball.p2Score} - - -
    - + const aspectRatio = 16 / 9; + const newWidth = divw ?? 0; + const newHeight = newWidth / aspectRatio; + if (divh) gameState.setHeight(newHeight); + if (divw) gameState.setWidth(divw); + }, [gameState.width, gameState.height]); + return ( +
    +
    +
    + + + {gameState.ball.p1Score} +
    -
    -
    {t > 0 ? (`next level start after ${t}`) : (`level ${level}`)}
    - -
    -
    - - - - - - - - - - - +
    + + {gameState?.ball.p2Score} + + +
    + +
    +
    +
    + {t > 0 ? `next level start after ${t}` : `level ${level}`}
    - {gameState.mobile && ( +
    +
    + + + + + + + + + +
    + {gameState.mobile && (
    - - + +
    - ) - - } + )}
    - - ) -} + ); +}; diff --git a/frontend/code/src/Components/Home/LeaderBoard.tsx b/frontend/code/src/Components/Home/LeaderBoard.tsx index 089ede0..ecec368 100644 --- a/frontend/code/src/Components/Home/LeaderBoard.tsx +++ b/frontend/code/src/Components/Home/LeaderBoard.tsx @@ -3,7 +3,7 @@ import InfiniteScroll from "react-infinite-scroll-component"; import { Link } from "react-router-dom"; import toast from "react-hot-toast"; -import { Chart } from './assets/Chart'; +import { Chart } from "./assets/Chart"; import { Trophy } from "./assets/Trophy"; import { Daimond } from "./assets/Daimond"; import { Logo } from "../Layout/Assets/Logo"; @@ -13,141 +13,143 @@ import { NullPlaceHolder } from "../Chat/Components/RoomChatHelpers"; import api from "../../Api/base"; export const LeaderBoard = () => { - const [users, setUsers] = useState([]); - const [loading, setLoading] = useState(true); + const [users, setUsers] = useState([]); + const [loading, setLoading] = useState(true); - const page = useRef(0); - const hasMoreItems = useRef(true); - const [fetching, setFetching] = useState(false); - const [nextPageUrl, setNextPageUrl] = useState("/leaderboard?offset=0&limit=20"); + const page = useRef(0); + const hasMoreItems = useRef(true); + const [fetching, setFetching] = useState(false); + const [nextPageUrl, setNextPageUrl] = useState( + "/leaderboard?offset=0&limit=20", + ); - const fetchItems = useCallback(async () => { - if (!nextPageUrl) return; - if (fetching) return; + const fetchItems = useCallback(async () => { + if (!nextPageUrl) return; + if (fetching) return; - setFetching(true); + setFetching(true); - try { - const newdata = await api.get(nextPageUrl); - // End of pagination - if (!newdata.data || newdata.data.length < 20) { - newdata.data && setUsers([...users, ...newdata.data]); - setNextPageUrl(null); - // Update hasMoreItems state - hasMoreItems.current = false; - return; - } - // Prepare next page - setUsers([...users, ...newdata.data]); - setNextPageUrl(`/leaderboard?offset=${page.current}&limit=20`); - page.current += 20; - // Update hasMoreItems state - hasMoreItems.current = true; - } catch (e) { - toast.error("Can't get leadeboard"); - } finally { - setLoading(false); - setFetching(false); - } - }, [users, fetching, nextPageUrl]); + try { + const newdata = await api.get(nextPageUrl); + // End of pagination + if (!newdata.data || newdata.data.length < 20) { + newdata.data && setUsers([...users, ...newdata.data]); + setNextPageUrl(null); + // Update hasMoreItems state + hasMoreItems.current = false; + return; + } + // Prepare next page + setUsers([...users, ...newdata.data]); + setNextPageUrl(`/leaderboard?offset=${page.current}&limit=20`); + page.current += 20; + // Update hasMoreItems state + hasMoreItems.current = true; + } catch (e) { + toast.error("Can't get leadeboard"); + } finally { + setLoading(false); + setFetching(false); + } + }, [users, fetching, nextPageUrl]); - useEffect(() => { - fetchItems(); - page.current += 20; - //eslint-disable-next-line - }, []); + useEffect(() => { + fetchItems(); + page.current += 20; + // eslint-disable-next-line + }, []); - return ( -
    -
    - Leader Board -
    + return ( +
    +
    + Leader Board +
    - {(users.length > 0) || loading ? ( -
    - - -
    - } - endMessage={ -
    - No more results! -
    - } - hasMore={hasMoreItems.current} - scrollableTarget="scrollTarget" - style={{ overflow: "auto", height: "100%" }} + {users.length > 0 || loading ? ( +
    + + +
    + } + endMessage={ +
    + No more results! +
    + } + hasMore={hasMoreItems.current} + scrollableTarget="scrollTarget" + style={{ overflow: "auto", height: "100%" }} + > + + + + + + + + + + {!loading && + users.map((x: any, index: number) => ( + -
    +
    + Place +
    +
    +
    + User +
    +
    +
    + Score +
    +
    - - - - - - - - - {!loading && - users.map((x: any, index: number) => ( - - - - - - ))} - -
    -
    - Place -
    -
    -
    - User -
    -
    -
    - Score -
    -
    -
    - {index + 1} -
    -
    -
    - -
    - {x?.Username} -
    - - {x?.Username} - -
    -
    - -
    -
    -
    - {x?.wins} -
    -
    - -
    - ) : ( -
    - -
    - )} + +
    + {index + 1} +
    + + +
    + +
    + {x?.Username} +
    + + {x?.Username} + +
    +
    + +
    + + +
    + {x?.wins} +
    + + + ))} + + + +
    + ) : ( +
    +
    - ) -} + )} +
    + ); +}; diff --git a/frontend/code/src/Components/Home/assets/Chart.tsx b/frontend/code/src/Components/Home/assets/Chart.tsx index 404dcd2..e9a5cd2 100644 --- a/frontend/code/src/Components/Home/assets/Chart.tsx +++ b/frontend/code/src/Components/Home/assets/Chart.tsx @@ -1,9 +1,16 @@ export const Chart = () => { - return ( - - - - - - ) -} + return ( + + + + ); +}; diff --git a/frontend/code/src/Components/Home/assets/Daimond.tsx b/frontend/code/src/Components/Home/assets/Daimond.tsx index f3c9d09..f802dc7 100644 --- a/frontend/code/src/Components/Home/assets/Daimond.tsx +++ b/frontend/code/src/Components/Home/assets/Daimond.tsx @@ -1,11 +1,22 @@ -import type { HTMLAttributes } from "react" +import type { HTMLAttributes } from "react"; type DiamondProps = HTMLAttributes; export const Daimond = (props: DiamondProps) => { - return ( - - - - ) -} + return ( + + + + ); +}; diff --git a/frontend/code/src/Components/Home/assets/Trophy.tsx b/frontend/code/src/Components/Home/assets/Trophy.tsx index 7d9e5ba..3237080 100644 --- a/frontend/code/src/Components/Home/assets/Trophy.tsx +++ b/frontend/code/src/Components/Home/assets/Trophy.tsx @@ -1,11 +1,21 @@ -import type { HTMLAttributes } from "react" +import type { HTMLAttributes } from "react"; type TrophyProps = HTMLAttributes; export const Trophy = (props: TrophyProps) => { - return ( - - - - ) -} + return ( + + + + ); +}; diff --git a/frontend/code/src/Components/Home/index.tsx b/frontend/code/src/Components/Home/index.tsx index 7c8c943..2f4f5a7 100644 --- a/frontend/code/src/Components/Home/index.tsx +++ b/frontend/code/src/Components/Home/index.tsx @@ -19,8 +19,13 @@ export const Home = (): JSX.Element => { READY TO PLAY A GAME?
    - - PLAY NOW + + + PLAY NOW +
    diff --git a/frontend/code/src/Components/Layout/Assets/Alert.tsx b/frontend/code/src/Components/Layout/Assets/Alert.tsx index fcdf0ae..ca45e1b 100644 --- a/frontend/code/src/Components/Layout/Assets/Alert.tsx +++ b/frontend/code/src/Components/Layout/Assets/Alert.tsx @@ -32,54 +32,53 @@ export const Alert = () => { }, [user?.notifications]); useEffect(() => { - socketStore.socket.on("notification", (notification: any) => { + socketStore.socket?.on("notification", (notification: any) => { if ( notification.actorId === user.id || notification.entity_type === "message" ) { - console.log(notification); if (notification.entity.authorId !== user.id) { toast.custom( - (t) => ( - // eslint-disable-next-line - (t.duration = 450), + (t) => ( -
    -
    -
    - avatar -
    -

    - message Received -

    -

    - {notification.entity.content} -

    + // eslint-disable-next-line + (t.duration = 450), + ( +
    +
    +
    + avatar +
    +

    + message Received +

    +

    + {notification.entity.content} +

    +
    -
    -
    - avatar +
    + avatar +
    -
    - ) - ) + ) + ), ); } - // } return; } @@ -87,9 +86,9 @@ export const Alert = () => { }); return () => { - socketStore.socket.off("notification"); + socketStore.socket?.off("notification"); }; - //eslint-disable-next-line + // eslint-disable-next-line }, [socketStore]); useEffect(() => { @@ -194,8 +193,7 @@ export const Alert = () => { ))}
    {notificationDone ? "No more notifications" : "Loading..."} diff --git a/frontend/code/src/Components/Layout/Assets/Dash.tsx b/frontend/code/src/Components/Layout/Assets/Dash.tsx index 1f4f091..0524839 100644 --- a/frontend/code/src/Components/Layout/Assets/Dash.tsx +++ b/frontend/code/src/Components/Layout/Assets/Dash.tsx @@ -12,7 +12,7 @@ export const Dash = ({ selected, className, ...props }: DashProps) => { className={classNames( "h-10 w-10 hover:bg-secondary p-1 rounded-xl flex justify-center items-center hover:cursor-pointer", selected && "bg-secondary", - className + className, )} {...props} > diff --git a/frontend/code/src/Components/Layout/Assets/Game.tsx b/frontend/code/src/Components/Layout/Assets/Game.tsx index 47c1d05..c10a497 100644 --- a/frontend/code/src/Components/Layout/Assets/Game.tsx +++ b/frontend/code/src/Components/Layout/Assets/Game.tsx @@ -12,7 +12,7 @@ export const Game = ({ selected, className, ...props }: GameProps) => { className={classNames( "h-10 w-10 hover:bg-secondary rounded-xl flex justify-center items-center hover:cursor-pointer", selected && "bg-secondary", - className + className, )} {...props} > diff --git a/frontend/code/src/Components/Layout/Assets/Invitationacceptance.tsx b/frontend/code/src/Components/Layout/Assets/Invitationacceptance.tsx index 85b8273..4a8ce3b 100644 --- a/frontend/code/src/Components/Layout/Assets/Invitationacceptance.tsx +++ b/frontend/code/src/Components/Layout/Assets/Invitationacceptance.tsx @@ -13,25 +13,25 @@ export const InvitationWaiting = forwardRef( useEffect(() => { if (!userStore.gameId) return () => { - socketStore.socket.off("game.declined"); - socketStore.socket.off("game.accepted"); + socketStore.socket?.off("game.declined"); + socketStore.socket?.off("game.accepted"); }; - socketStore.socket.on("game.declined", () => { + socketStore.socket?.on("game.declined", () => { toast.error("Game declined"); userStore.setGameWaitingId(""); (ref as RefObject).current?.close(); }); - socketStore.socket.on("game.accepted", () => { + socketStore.socket?.on("game.accepted", () => { toast.success("Game accepted"); userStore.setGameWaitingId(""); (ref as RefObject).current?.close(); }); return () => { - socketStore.socket.off("game.declined"); - socketStore.socket.off("game.accepted"); + socketStore.socket?.off("game.declined"); + socketStore.socket?.off("game.accepted"); }; - //eslint-disable-next-line + // eslint-disable-next-line }, [userStore.gameId, socketStore.socket, ref]); return ( diff --git a/frontend/code/src/Components/Layout/Assets/Invitationmodale.tsx b/frontend/code/src/Components/Layout/Assets/Invitationmodale.tsx index 6da0dbf..f4ac303 100644 --- a/frontend/code/src/Components/Layout/Assets/Invitationmodale.tsx +++ b/frontend/code/src/Components/Layout/Assets/Invitationmodale.tsx @@ -26,18 +26,18 @@ export const InvitationGame = forwardRef((_, ref) => { useEffect(() => { if (!userStore.inviterId) return () => { - socketStore.socket.off("game.declined"); + socketStore.socket?.off("game.declined"); }; - socketStore.socket.on("game.declined", () => { + socketStore.socket?.on("game.declined", () => { toast.error("Game declined"); userStore.updateGameInvitationId(""); (ref as RefObject).current?.close(); }); return () => { - socketStore.socket.off("game.declined"); + socketStore.socket?.off("game.declined"); }; - //eslint-disable-next-line + // eslint-disable-next-line }, [userStore.inviterId, socketStore, ref]); return ( diff --git a/frontend/code/src/Components/Layout/Assets/Message.tsx b/frontend/code/src/Components/Layout/Assets/Message.tsx index 1fecb84..3341d03 100644 --- a/frontend/code/src/Components/Layout/Assets/Message.tsx +++ b/frontend/code/src/Components/Layout/Assets/Message.tsx @@ -12,7 +12,7 @@ export const Message = ({ selected, className, ...props }: MessageProps) => { className={classNames( "h-10 w-10 hover:bg-secondary rounded-xl flex justify-center items-center hover:cursor-pointer", selected && "bg-secondary", - className + className, )} {...props} > diff --git a/frontend/code/src/Components/Layout/Assets/Modal.tsx b/frontend/code/src/Components/Layout/Assets/Modal.tsx index e38cdb9..e476a7e 100644 --- a/frontend/code/src/Components/Layout/Assets/Modal.tsx +++ b/frontend/code/src/Components/Layout/Assets/Modal.tsx @@ -1,98 +1,98 @@ -import { useSocketStore } from "../../Chat/Services/SocketsServices" +import { useSocketStore } from "../../Chat/Services/SocketsServices"; import { useEffect, useState } from "react"; import { useNavigate } from "react-router-dom"; import { useGameState } from "../../Game/States/GameState"; export const Modal = () => { - const gameState = useGameState(); - const [opacity , setOpacity] = useState(""); - const [resOpacity , setResOpacity] = useState(""); - const [result , setResutl] = useState(undefined); - const [status , setStatus] = useState(undefined); - const [timer , setTimer] = useState(undefined); - const [gameid , setGameId] = useState(undefined); - const socketStore = useSocketStore(); - const navigate = useNavigate(); - useEffect(() => { - if (socketStore.socket !== null){ - socketStore.socket.on("game.launched" , (GameId:any) => { - setGameId(GameId.slice(5)) - }) - socketStore.socket.on("timer",(msg:any) => { - msg !== 0 && setOpacity("opacity-100") - msg === 0 && setOpacity("opacity-0") - setTimer(msg / 1000) - if (timer === 5){ - navigate(`/Game/${gameid}`) - } - }) - socketStore.socket.on("players", (players:any) => { - gameState.setP1(players[0]); - gameState.setP2(players[1]); - console.log(players) - console.log("sda") - }) - socketStore.socket.on("win" , (msg:string) => { - setResutl(msg) - setStatus("win"); - setResOpacity("opacity-100"); - let count = 2; - setTimer(count); - const inter = setInterval(() => { - setTimer(count); - --count; - if (count === -1){ - setResOpacity("opacity-0") - clearInterval(inter); - navigate("/home") - } - },1000) - - }) - socketStore.socket.on("lose" , (msg:string) => { - setResutl(msg) - setStatus("lose"); - setResOpacity("opacity-100"); - let count = 2; - setTimer(count); - const inter = setInterval(() => { - setTimer(count); - --count; - if (count === -1){ - setResOpacity("opacity-0") - clearInterval(inter); - navigate("/home") - } - },1000) - - }) + const gameState = useGameState(); + const [opacity, setOpacity] = useState(""); + const [resOpacity, setResOpacity] = useState(""); + const [result, setResutl] = useState(undefined); + const [status, setStatus] = useState(undefined); + const [timer, setTimer] = useState(undefined); + const [gameid, setGameId] = useState(undefined); + const socketStore = useSocketStore(); + const navigate = useNavigate(); + useEffect(() => { + if (socketStore.socket !== null) { + socketStore.socket?.on("game.launched", (GameId: any) => { + setGameId(GameId.slice(5)); + }); + socketStore.socket?.on("timer", (msg: any) => { + msg !== 0 && setOpacity("opacity-100"); + msg === 0 && setOpacity("opacity-0"); + setTimer(msg / 1000); + if (timer === 5) { + navigate(`/Game/${gameid}`); + } + }); + socketStore.socket?.on("players", (players: any) => { + gameState.setP1(players[0]); + gameState.setP2(players[1]); + }); + socketStore.socket?.on("win", (msg: string) => { + setResutl(msg); + setStatus("win"); + setResOpacity("opacity-100"); + let count = 2; + setTimer(count); + const inter = setInterval(() => { + setTimer(count); + --count; + if (count === -1) { + setResOpacity("opacity-0"); + clearInterval(inter); + navigate("/home"); + } + }, 1000); + }); + socketStore.socket?.on("lose", (msg: string) => { + setResutl(msg); + setStatus("lose"); + setResOpacity("opacity-100"); + let count = 2; + setTimer(count); + const inter = setInterval(() => { + setTimer(count); + --count; + if (count === -1) { + setResOpacity("opacity-0"); + clearInterval(inter); + navigate("/home"); + } + }, 1000); + }); } return () => { - socketStore.socket.off("lose") - socketStore.socket.off("win") - socketStore.socket.off("timer") - socketStore.socket.off("game.launched") - socketStore.socket.off("players") - } -// eslint-disable-next-line -},[timer]) - - return ( - - <> -
    -
    -

    Game Starting ....

    -

    Game Start In {timer}

    -
    -
    -
    -
    -

    You {status}

    -

    {result}

    -

    this window will be dismiss in {timer}

    + socketStore.socket?.off("lose"); + socketStore.socket?.off("win"); + socketStore.socket?.off("timer"); + socketStore.socket?.off("game.launched"); + socketStore.socket?.off("players"); + }; + // eslint-disable-next-line + }, [timer]); -
    -
    - - ) -} \ No newline at end of file + return ( + <> +
    +
    +

    Game Starting ....

    +

    + Game Start In {timer} +

    +
    +
    +
    +
    +

    You {status}

    +

    + {result}{" "} +

    +

    + this window will be dismiss in {timer}{" "} +

    +
    +
    + + ); +}; diff --git a/frontend/code/src/Components/Layout/Assets/Out.tsx b/frontend/code/src/Components/Layout/Assets/Out.tsx index ca221ea..3448807 100644 --- a/frontend/code/src/Components/Layout/Assets/Out.tsx +++ b/frontend/code/src/Components/Layout/Assets/Out.tsx @@ -2,31 +2,43 @@ import { classNames } from "../../../Utils/helpers"; import { useUserStore } from "../../../Stores/stores"; import { Link } from "react-router-dom"; - type OutProps = React.HTMLAttributes & { - selected?: boolean; - }; -export const Out = ({ selected, className, ...props} : OutProps) => { + selected?: boolean; +}; +export const Out = ({ selected, className, ...props }: OutProps) => { const user = useUserStore(); - return ( - <> - { process.env?.REACT_APP_LOGOUT && + return ( + <> + {process.env?.REACT_APP_LOGOUT && ( user.logout()} to={process.env.REACT_APP_LOGOUT}> -
    - - - +
    + + + -
    +
    - } - - - ) -} + )} + + ); +}; diff --git a/frontend/code/src/Components/Layout/Assets/Profile.tsx b/frontend/code/src/Components/Layout/Assets/Profile.tsx index 8528270..2ad189e 100644 --- a/frontend/code/src/Components/Layout/Assets/Profile.tsx +++ b/frontend/code/src/Components/Layout/Assets/Profile.tsx @@ -1,5 +1,5 @@ -import {Link} from 'react-router-dom' -import { useUserStore } from '../../../Stores/stores' +import { Link } from "react-router-dom"; +import { useUserStore } from "../../../Stores/stores"; import { classNames } from "../../../Utils/helpers"; type ProfileProps = React.HTMLAttributes & { @@ -7,22 +7,34 @@ type ProfileProps = React.HTMLAttributes & { }; export const Profile = ({ selected, className, ...props }: ProfileProps) => { - const userStore = useUserStore(); - return ( - + const userStore = useUserStore(); + return (
    -
    - - - +
    + + +
    diff --git a/frontend/code/src/Components/Layout/Assets/Search.tsx b/frontend/code/src/Components/Layout/Assets/Search.tsx index 2482b2b..84b51dc 100644 --- a/frontend/code/src/Components/Layout/Assets/Search.tsx +++ b/frontend/code/src/Components/Layout/Assets/Search.tsx @@ -1,74 +1,87 @@ -import {useState , ChangeEvent , useEffect} from 'react' -import {BiSearch} from 'react-icons/bi' -import { Link } from 'react-router-dom' -import api from '../../../Api/base' -import toast from 'react-hot-toast' +import { useState, ChangeEvent, useEffect } from "react"; +import { BiSearch } from "react-icons/bi"; +import { Link } from "react-router-dom"; +import api from "../../../Api/base"; +import toast from "react-hot-toast"; function useDebounce(value: T, delay?: number): T { - const [debouncedValue, setDebouncedValue] = useState(value) - - useEffect(() => { - const timer = setTimeout(() => setDebouncedValue(value), delay || 500) - - return () => { - clearTimeout(timer) - } - }, [value, delay]) - - return debouncedValue + const [debouncedValue, setDebouncedValue] = useState(value); + + useEffect(() => { + const timer = setTimeout(() => setDebouncedValue(value), delay || 500); + + return () => { + clearTimeout(timer); + }; + }, [value, delay]); + + return debouncedValue; } export const Search = () => { const [searchText, setSearchText] = useState(""); const DebounceValue = useDebounce(searchText); const [hidden, setHidden] = useState("hidden"); - const onSearchTextChange = (e: ChangeEvent) => setSearchText(e.target.value); - const [result , setResult] = useState([]); - useEffect(() => - { - const search = async() => { - try { - const res = await api.get("/users/search",{params:{q:DebounceValue}}) - setResult(res.data) - console.log(res.data) - res.data.length ? setHidden("") : setHidden("hidden") - } catch (error) { - toast.error("can't find anyone") - } - } - DebounceValue && search() - },[DebounceValue]) - const clear = () => { - setHidden("hidden");setSearchText("");setResult([]); - } - return ( - -
    - - - -
    -
      -
      - { result.map((item : any , index : number) => { + const onSearchTextChange = (e: ChangeEvent) => + setSearchText(e.target.value); + const [result, setResult] = useState([]); + useEffect(() => { + const search = async () => { + try { + const res = await api.get("/users/search", { + params: { q: DebounceValue }, + }); + setResult(res.data); + res.data.length ? setHidden("") : setHidden("hidden"); + } catch (error) { + toast.error("can't find anyone"); + } + }; + DebounceValue && search(); + }, [DebounceValue]); + const clear = () => { + setHidden("hidden"); + setSearchText(""); + setResult([]); + }; + return ( +
      + + +
      + +
      +
        +
        + {result.map((item: any, index: number) => { return ( - -
      • -
        -
        -
        - -
        -
        - {item.name.first} {item.name.last} -
        -
      • - - ) - }) - } - + +
      • +
        +
        +
        + +
        +
        + + {item.name.first} {item.name.last} + +
        +
      • + + ); + })}
        -
      -
      - ) -} \ No newline at end of file +
    +
    + ); +}; diff --git a/frontend/code/src/Components/Layout/Assets/Settings.tsx b/frontend/code/src/Components/Layout/Assets/Settings.tsx index 27f414d..2283c35 100644 --- a/frontend/code/src/Components/Layout/Assets/Settings.tsx +++ b/frontend/code/src/Components/Layout/Assets/Settings.tsx @@ -11,7 +11,7 @@ export const Settings = ({ selected, className, ...props }: SettingsProps) => { className={classNames( "h-10 w-10 hover:bg-secondary rounded-xl flex justify-center text-center items-center hover:cursor-pointer", selected && "bg-secondary", - className + className, )} {...props} > diff --git a/frontend/code/src/Components/Layout/index.tsx b/frontend/code/src/Components/Layout/index.tsx index a4eeb79..eef3cc6 100644 --- a/frontend/code/src/Components/Layout/index.tsx +++ b/frontend/code/src/Components/Layout/index.tsx @@ -8,7 +8,13 @@ import { Message } from "./Assets/Message"; import { Profile } from "./Assets/Profile"; import { Settings } from "./Assets/Settings"; import { Out } from "./Assets/Out"; -import { FC, PropsWithChildren, useEffect, useLayoutEffect, useRef } from "react"; +import { + FC, + PropsWithChildren, + useEffect, + useLayoutEffect, + useRef, +} from "react"; import { Outlet } from "react-router"; import { matchRoutes, useLocation } from "react-router-dom"; import { useUserStore } from "../../Stores/stores"; @@ -24,6 +30,7 @@ import { Modal } from "./Assets/Modal"; import { InvitationGame } from "./Assets/Invitationmodale"; import { useGameState } from "../Game/States/GameState"; +import { useModalStore } from "../Chat/Controllers/LayoutControllers"; const routes = [ { path: "Profile/:id" }, { path: "Dm/:id" }, @@ -41,9 +48,6 @@ const useCurrentPath = () => { return route.path; }; -function onConnect() { - console.log("hello"); -} export const Layout: FC = (): JSX.Element => { const gameStore = useGameState(); const user = useUserStore(); @@ -51,20 +55,30 @@ export const Layout: FC = (): JSX.Element => { const socketStore = useSocketStore(); const invitationGameRef = useRef(null); const path: string = useCurrentPath(); + + const modalState = useModalStore(); + useEffect(() => { - console.log(gameStore) - console.log(`path is saads ${path}`) - if (gameStore.end === false && path !== "Game/:id") - { - socketStore.socket.emit("leave"); - gameStore.setEnd(true) + if (gameStore.end === false && path !== "Game/:id") { + socketStore.socket?.emit("leave"); + gameStore.setEnd(true); } return () => { - socketStore.socket.off("leave"); - } - // eslint-disable-next-line - },[path]) + socketStore.socket?.off("leave"); + }; + // eslint-disable-next-line + }, [path]); useLayoutEffect(() => { + // Prevent ESC key + const preventEsc = (e: KeyboardEvent) => { + if (e.key === "Escape") { + e.preventDefault(); + e.stopPropagation(); + return false; + } + }; + document.addEventListener("keydown", preventEsc, false); + const log = async () => { try { await user.login(); @@ -80,113 +94,19 @@ export const Layout: FC = (): JSX.Element => { }; socketStore.socket = socketStore.setSocket(); - socketStore.socket.on("connect", onConnect); - - // socketStore.socket.on("message", (msg: any) => { - // toast.custom( - // (t) => - // ( - // // eslint-disable-next-line - // (t.duration = 450), - // ( - //
    - //
    - //
    - // avatar - //
    - //

    - // message Received - //

    - //

    - // {msg.content} - //

    - //
    - //
    - - //
    - // avatar - //
    - //
    - //
    - // ) - // ), - // ); - // }); - // socketStore.socket.on("notification", (msg: any) => { - // console.log("chat id", chatState.currentDmUser.id); - // console.log("chat id", chatState.selectedChatID); - - // console.log("room id", msg.roomId); - // if (msg.authorId !== user.id) { - // toast.custom( - // (t) => ( - // // eslint-disable-next-line - // (t.duration = 450), - // ( - //
    - //
    - //
    - // avatar - //
    - //

    - // message Received - //

    - //

    - // {msg.content} - //

    - //
    - //
    - - //
    - // avatar - //
    - //
    - //
    - // ) - // ) - // ); - // } - // }); log(); - socketStore.socket.on("invitedToGame", (data: any) => { - console.log("invitedToGame", data); + socketStore.socket?.on("invitedToGame", (data: any) => { user.setGameInvitation(data); invitationGameRef.current?.showModal(); }); return () => { - socketStore.socket.off("connect"); - socketStore.socket.off("invitedToGame"); + document.removeEventListener("keydown", preventEsc, false); + socketStore.socket?.off("invitedToGame"); }; - //eslint-disable-next-line + // eslint-disable-next-line }, []); - - return ( <> {user.profileComplet === false && user.isLogged ? ( @@ -194,14 +114,16 @@ export const Layout: FC = (): JSX.Element => { ) : (
    - - + {modalState.showBlockedListModal && } + {modalState.showFriendsListModal && }
    diff --git a/frontend/code/src/Components/Login/Assets/Button.tsx b/frontend/code/src/Components/Login/Assets/Button.tsx index cf940de..d464ae1 100644 --- a/frontend/code/src/Components/Login/Assets/Button.tsx +++ b/frontend/code/src/Components/Login/Assets/Button.tsx @@ -1,20 +1,40 @@ -export const Button = () =>{ - return ( - - - - - - - - - - +export const Button = () => { + return ( + + + + + + + + + + - + - - - - ) -} \ No newline at end of file + + + ); +}; diff --git a/frontend/code/src/Components/Login/index.tsx b/frontend/code/src/Components/Login/index.tsx index 4df614e..ed4f714 100644 --- a/frontend/code/src/Components/Login/index.tsx +++ b/frontend/code/src/Components/Login/index.tsx @@ -1,57 +1,46 @@ -import { Link } from "react-router-dom"; -import pingpong from '../images/pingpong.svg' -import {Button} from './Assets/Button' +import { Link } from "react-router-dom"; +import pingpong from "../images/pingpong.svg"; +import { Button } from "./Assets/Button"; import { useUserStore } from "../../Stores/stores"; import { useNavigate } from "react-router-dom"; import { useLayoutEffect } from "react"; -// import { PageLoading } from '../Loading'; -// const FallBackLoading = () => { -// return ( -//
    -// -//
    -// ) -// } -export const Login = () => -{ - const userStore = useUserStore(); - const navigate = useNavigate(); - useLayoutEffect(() => { - const check = async() => { - try { - const loggedin = await userStore.login(); - if (loggedin) - navigate("/home") - } catch (error:any) { - if (error.response && error.response.status === 401) { - // This is a 401 error; you can choose to handle it silently - console.log("hit") - } else { - // Handle other errors - // console.error(error); - } + +export const Login = () => { + const userStore = useUserStore(); + const navigate = useNavigate(); + useLayoutEffect(() => { + const check = async () => { + try { + const loggedin = await userStore.login(); + if (loggedin) navigate("/home"); + } catch (error: any) { + if (error.response && error.response.status === 401) { + // This is a 401 error; you can choose to handle it silently + } else { + // Handle other errors } - } - check() + } + }; + check(); // eslint-disable-next-line - },[]) - return ( - <> -
    -
    -
    -
    - Logo -
    - { - process.env.REACT_APP_AUTH_PATH && - -
    -
    - - - ); -} + }, []); + return ( + <> +
    +
    +
    +
    + Logo +
    + {process.env.REACT_APP_AUTH_PATH && ( + +
    +
    + + ); +}; diff --git a/frontend/code/src/Components/Play/assets/Watch.tsx b/frontend/code/src/Components/Play/assets/Watch.tsx deleted file mode 100644 index 0b9d626..0000000 --- a/frontend/code/src/Components/Play/assets/Watch.tsx +++ /dev/null @@ -1,21 +0,0 @@ -export const Watch = () => { - return ( - - - - - - - - - - - - - - - - - - ) -} \ No newline at end of file diff --git a/frontend/code/src/Components/Play/assets/queuemodal.tsx b/frontend/code/src/Components/Play/assets/queuemodal.tsx index e42ca67..61f17de 100644 --- a/frontend/code/src/Components/Play/assets/queuemodal.tsx +++ b/frontend/code/src/Components/Play/assets/queuemodal.tsx @@ -17,7 +17,7 @@ export const QueueWaitModal = forwardRef(