Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 82633fb869 |
1
.env
1
.env
@ -14,7 +14,6 @@
|
||||
NGINX_ENVSUBST_TEMPLATE_SUFFIX=".conf"
|
||||
|
||||
# BASE_URL=http://localhost
|
||||
# SOCKET_URL=localhost:8080
|
||||
BASE_URL=localhost:8080
|
||||
REACT_APP_BASE_URL=localhost:8080
|
||||
REDIRECT_URI=http://localhost:8080/api/auth/login
|
||||
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@ -1,5 +1,4 @@
|
||||
.env
|
||||
containers/react/.env
|
||||
#.env
|
||||
backend/node_modules/
|
||||
containers/backend/dist/
|
||||
|
||||
|
||||
153
README.md
Normal file
153
README.md
Normal file
@ -0,0 +1,153 @@
|
||||
# ft_transcendence
|
||||
|
||||
## Description
|
||||
ft_transcendence est le projet final du tronc commun de l'École 42. Il s'agit de créer une application web complète permettant de jouer au Pong en ligne avec des fonctionnalités modernes comme les tournois, le chat en temps réel, et l'authentification.
|
||||
|
||||
## Fonctionnalités principales
|
||||
- 🎮 **Jeu Pong** en temps réel multijoueur
|
||||
- 🏆 **Système de tournois** avec brackets
|
||||
- 💬 **Chat en temps réel** avec channels
|
||||
- 👤 **Profils utilisateurs** et amis
|
||||
- 🔐 **Authentification 2FA** (Google, 42)
|
||||
- 📊 **Statistiques** et historique des parties
|
||||
- 🎨 **Interface moderne** et responsive
|
||||
- 🔒 **Sécurité** web avancée
|
||||
|
||||
## Technologies utilisées
|
||||
|
||||
### Frontend
|
||||
- **Framework** : React/Vue.js/Angular ou Vanilla JS
|
||||
- **Styling** : CSS3, Bootstrap/Tailwind
|
||||
- **WebSockets** : Pour le temps réel
|
||||
|
||||
### Backend
|
||||
- **Framework** : Django/Flask/Node.js
|
||||
- **Base de données** : PostgreSQL
|
||||
- **API** : REST ou GraphQL
|
||||
- **Authentication** : OAuth2, JWT
|
||||
|
||||
### DevOps
|
||||
- **Containerisation** : Docker & Docker Compose
|
||||
- **Reverse Proxy** : Nginx
|
||||
- **SSL/TLS** : Certificats HTTPS
|
||||
- **Base de données** : PostgreSQL en conteneur
|
||||
|
||||
## Architecture
|
||||
```
|
||||
ft_transcendence/
|
||||
├── docker-compose.yml # Orchestration des services
|
||||
├── frontend/ # Application client
|
||||
│ ├── src/
|
||||
│ ├── public/
|
||||
│ └── Dockerfile
|
||||
├── backend/ # API serveur
|
||||
│ ├── api/
|
||||
│ ├── models/
|
||||
│ ├── services/
|
||||
│ └── Dockerfile
|
||||
├── database/ # Configuration PostgreSQL
|
||||
├── nginx/ # Configuration reverse proxy
|
||||
└── ssl/ # Certificats SSL
|
||||
```
|
||||
|
||||
## Modules bonus
|
||||
- **Module Web** : Framework moderne (React/Vue/Angular)
|
||||
- **Module User Management** : Authentification avancée
|
||||
- **Module Gaming** : Variantes de Pong ou autres jeux
|
||||
- **Module AI-Algo** : IA pour jouer contre
|
||||
- **Module Cybersecurity** : Sécurité renforcée
|
||||
- **Module DevOps** : Infrastructure monitoring
|
||||
- **Module Graphics** : Interface 3D avancée
|
||||
|
||||
## Installation et déploiement
|
||||
|
||||
### Prérequis
|
||||
- Docker et Docker Compose
|
||||
- Domaine avec certificat SSL
|
||||
- Clés API (42, Google) pour OAuth
|
||||
|
||||
### Lancement
|
||||
```bash
|
||||
git clone <repository-url>
|
||||
cd ft_transcendence
|
||||
docker-compose up --build
|
||||
```
|
||||
|
||||
### Configuration
|
||||
1. Configurer les variables d'environnement
|
||||
2. Générer les certificats SSL
|
||||
3. Configurer OAuth applications
|
||||
4. Initialiser la base de données
|
||||
|
||||
## Gameplay
|
||||
|
||||
### Pong multijoueur
|
||||
- Contrôles clavier fluides
|
||||
- Synchronisation en temps réel
|
||||
- Système de score et timer
|
||||
- Reconnexion automatique
|
||||
|
||||
### Tournois
|
||||
- Création de tournois public/privé
|
||||
- Système d'élimination
|
||||
- Classements et récompenses
|
||||
- Notifications en temps réel
|
||||
|
||||
## Sécurité implémentée
|
||||
- 🔒 **HTTPS** obligatoire
|
||||
- 🛡️ **Protection CSRF/XSS**
|
||||
- 🔑 **Authentification 2FA**
|
||||
- 💾 **Hashage sécurisé** des mots de passe
|
||||
- 🚫 **Protection injection SQL**
|
||||
- 🔐 **Validation** côté serveur
|
||||
- 🍪 **Gestion sécurisée** des sessions
|
||||
|
||||
## Fonctionnalités sociales
|
||||
- **Profils utilisateurs** personnalisables
|
||||
- **Système d'amis** avec invitations
|
||||
- **Chat global** et channels privés
|
||||
- **Statut en ligne** des utilisateurs
|
||||
- **Historique des parties**
|
||||
- **Achievements** et badges
|
||||
|
||||
## Performance et scalabilité
|
||||
- **WebSockets** pour le temps réel
|
||||
- **Cache Redis** pour les sessions
|
||||
- **Optimisation** des requêtes DB
|
||||
- **Load balancing** pour la montée en charge
|
||||
- **Monitoring** des performances
|
||||
|
||||
## Tests et qualité
|
||||
- **Tests unitaires** backend
|
||||
- **Tests d'intégration** API
|
||||
- **Tests end-to-end** Selenium
|
||||
- **Sécurité** avec OWASP ZAP
|
||||
- **Performance** avec JMeter
|
||||
|
||||
## Compétences développées
|
||||
- Architecture d'applications web modernes
|
||||
- Développement full-stack
|
||||
- Sécurité web avancée
|
||||
- DevOps et containerisation
|
||||
- Gestion de projet complexe
|
||||
- Programmation temps réel
|
||||
- UI/UX design
|
||||
|
||||
## Contraintes 42
|
||||
- **Single Page Application** obligatoire
|
||||
- **3 frameworks/langages** différents minimum
|
||||
- **Docker** pour tous les services
|
||||
- **Sécurité** de niveau production
|
||||
- **Code maintenable** et documenté
|
||||
|
||||
## Auteur
|
||||
Alexandre Pommier (apommier) - École 42
|
||||
|
||||
## Équipe (si applicable)
|
||||
- Développeur Frontend
|
||||
- Développeur Backend
|
||||
- DevOps Engineer
|
||||
- Security Specialist
|
||||
|
||||
## Licence
|
||||
Projet académique - École 42
|
||||
@ -1 +1 @@
|
||||
ALTER USER postgres WITH PASSWORD 'postgres';
|
||||
ALTER USER postgres WITH PASSWORD 'pass';
|
||||
@ -10,7 +10,7 @@ server {
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_pass http://react_app:8081;
|
||||
proxy_pass http://react_app:8001;
|
||||
}
|
||||
|
||||
location /api {
|
||||
@ -21,7 +21,7 @@ server {
|
||||
proxy_pass http://api:3000/api;
|
||||
}
|
||||
|
||||
location /socket.io {
|
||||
location /socket {
|
||||
# Forward requests to socket server running on port 4001
|
||||
if ($request_uri ~ ^/socket/4001) {
|
||||
proxy_pass http://chat:4001;
|
||||
|
||||
22
containers/api/src/app.controller.spec.ts
Normal file
22
containers/api/src/app.controller.spec.ts
Normal file
@ -0,0 +1,22 @@
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { AppController } from './app.controller';
|
||||
import { AppService } from './app.service';
|
||||
|
||||
describe('AppController', () => {
|
||||
let appController: AppController;
|
||||
|
||||
beforeEach(async () => {
|
||||
const app: TestingModule = await Test.createTestingModule({
|
||||
controllers: [AppController],
|
||||
providers: [AppService],
|
||||
}).compile();
|
||||
|
||||
appController = app.get<AppController>(AppController);
|
||||
});
|
||||
|
||||
describe('root', () => {
|
||||
it('should return "Hello World!"', () => {
|
||||
expect(appController.getHello()).toBe('Hello World!');
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -6,23 +6,39 @@
|
||||
/* By: apommier <apommier@student.42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2023/06/17 01:00:00 by apommier #+# #+# */
|
||||
/* Updated: 2023/06/26 08:00:13 by apommier ### ########.fr */
|
||||
/* Updated: 2023/06/21 01:19:01 by apommier ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
import { Controller, Request, Req, Get, Post, UseGuards, Redirect, Res, Body, UploadedFile, UseInterceptors} from '@nestjs/common';
|
||||
import { FileInterceptor } from '@nestjs/platform-express';
|
||||
|
||||
import { JwtAuthGuard } from './auth/jwt-auth.guard';
|
||||
import { AuthService } from './auth/auth.service';
|
||||
import { loginClass } from './auth/login42'
|
||||
import { ChatService } from './chat/chat.service';
|
||||
import { UsersService } from './users/users.service';
|
||||
|
||||
import { MatchLog } from './model/user.entity'
|
||||
import { generate } from 'rxjs';
|
||||
|
||||
// import { generateQRcode } from './users/2fa';
|
||||
import { generateOTP } from './users/2fa';
|
||||
import { VerifyOTP } from './users/2fa';
|
||||
import { ValidateOTP } from './users/2fa';
|
||||
import { privateDecrypt } from 'crypto';
|
||||
import { formatWithOptions } from 'util';
|
||||
|
||||
|
||||
//2fa
|
||||
|
||||
|
||||
// import { initStorage, getUser, setUser } from './storage';
|
||||
|
||||
// import { AuthGuard } from '@nestjs/passport';
|
||||
// import { Login42 } from './auth/login42'
|
||||
// import { loginClass } from './auth/test'
|
||||
|
||||
|
||||
@Controller('/api')
|
||||
export class AppController {
|
||||
@ -34,6 +50,7 @@ export class AppController {
|
||||
kFactor = 36;
|
||||
scaleFactor = 400;
|
||||
|
||||
|
||||
//========================================================================================================
|
||||
//========================================================================================================
|
||||
// User
|
||||
@ -43,52 +60,49 @@ export class AppController {
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Get('/profile')
|
||||
async getProfile(@Request() req) {
|
||||
// const myJSON = JSON.stringify(req.user);
|
||||
// console.log(`req user api= ${req.user}`)
|
||||
// console.log(`json user api= ${myJSON}`)
|
||||
// return req.user;
|
||||
return await this.userService.findOne(req.user.username);
|
||||
}
|
||||
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Post('/logout')
|
||||
async logout(@Request() req, @Body() data: any) {
|
||||
const user = await this.userService.findOne(req.user.username)
|
||||
// return await this.userService.refuseInvite(user, data.username);
|
||||
if (!user)
|
||||
return;
|
||||
if (user.sessionNumber === 1) {
|
||||
user.status = 0;
|
||||
}
|
||||
user.sessionNumber--;
|
||||
this.userService.save(user);
|
||||
}
|
||||
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Post('/user')
|
||||
async getUser( @Body() data: any) {
|
||||
console.log(`usernamewwww= ${data.username}`)
|
||||
return await this.userService.findOne(data.username);
|
||||
}
|
||||
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Get('/users')
|
||||
async getUsers( @Body() data: any) {
|
||||
console.log(`usernamewwww= ${data.username}`)
|
||||
return await this.userService.findAll();
|
||||
}
|
||||
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Get('/friends')
|
||||
async getFriends(@Request() req) {
|
||||
// return await this.userService.getFriends(req.user.username);
|
||||
return await this.userService.getFriends(req.user.username);
|
||||
}
|
||||
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Post('/friend')
|
||||
@Post('/friend')//need to do it 2 time when user accept one for each
|
||||
async newFriend(@Request() req, @Body() data: any) {
|
||||
// return await this.userService.getFriends(req.user.username);
|
||||
console.log(`user= ${req.user.username}`)
|
||||
const user = await this.userService.findOne(req.user.username)
|
||||
if (!user)
|
||||
return (0);
|
||||
if (user.friends.find(item => item === data.username)) {
|
||||
user.friendRequest = user.friendRequest.filter((item) => item !== data.username);
|
||||
this.userService.save(user);
|
||||
return (1);
|
||||
}
|
||||
//create personnal conv for user
|
||||
//await this.userService.addFriend(user, data.username);
|
||||
|
||||
|
||||
|
||||
// const amIhere = data.members.includes(req.user.username);
|
||||
// if (!amIhere)
|
||||
const conv = {
|
||||
id: null,
|
||||
name: req.user.username + ", " + data.username,
|
||||
@ -101,18 +115,20 @@ export class AppController {
|
||||
messages: null,
|
||||
group: false,
|
||||
private: false,
|
||||
|
||||
};
|
||||
conv.members.push(req.user.username);
|
||||
conv.members.push(data.username);
|
||||
await this.chatService.createConv(conv);
|
||||
|
||||
return await this.userService.addFriend(user, data.username);
|
||||
|
||||
}
|
||||
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Post('/block')
|
||||
async newBlocked(@Request() req, @Body() data: any) {
|
||||
// return await this.userService.getFriends(req.user.username);
|
||||
console.log(`user= ${req.user.username}`)
|
||||
if (data.username === req.user.username)
|
||||
return (0);
|
||||
const user = await this.userService.findOne(req.user.username)
|
||||
@ -122,6 +138,7 @@ export class AppController {
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Post('/invite')
|
||||
async newInvite(@Request() req, @Body() data: any) {
|
||||
console.log(`user= ${req.user.username}`)
|
||||
if (data.username === req.user.username)
|
||||
return (0);
|
||||
const user = await this.userService.findOne(data.username)
|
||||
@ -133,12 +150,17 @@ export class AppController {
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Get('/inviteRequest')
|
||||
async getInvite(@Request() req) {
|
||||
// return await this.userService.getFriends(req.user.username);
|
||||
console.log(`useawdawd\n\n\nr= ${req.user.username}`)
|
||||
// const user = await this.userService.findOne(req.user.username)
|
||||
return await this.userService.getInvite(req.user.username);
|
||||
}
|
||||
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Post('/refuseInvite')
|
||||
async refuseInvite(@Request() req, @Body() data: any) {
|
||||
// return await this.userService.getFriends(req.user.username);
|
||||
// console.log(`useawdawd\n\n\nr= ${req.user.username}`)
|
||||
const user = await this.userService.findOne(req.user.username)
|
||||
return await this.userService.refuseInvite(user, data.username);
|
||||
}
|
||||
@ -155,11 +177,12 @@ export class AppController {
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Post('/nickname')
|
||||
async setNickname(@Request() req, @Body() data: any) {
|
||||
const taken = await this.userService.findNickname(data.nickname)
|
||||
if (taken)
|
||||
return (0);
|
||||
// let user = req.user
|
||||
// user.nickname = data.nickname
|
||||
console.log(`user= ${req.user.username}`)
|
||||
let user = await this.userService.findOne(req.user.username)
|
||||
user.nickname = data.nickname;
|
||||
// return await this.userService.getFriends(req.user.username);
|
||||
return await this.userService.save(user);
|
||||
}
|
||||
|
||||
@ -178,17 +201,14 @@ export class AppController {
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Post('/getPicture')
|
||||
async getProfilPicture(@Body() data: any) {
|
||||
// console.log(`dataaaaa= ${data.username}`)
|
||||
return await this.userService.getPic(data.username)
|
||||
}
|
||||
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Post('/addSession')
|
||||
async addSession(@Request() req) {
|
||||
const user = await this.userService.findOne(req.user.username);
|
||||
user.sessionNumber += 1;
|
||||
if (user.status !== 2)
|
||||
user.status = 1;
|
||||
await this.userService.save(user);
|
||||
// return user.photo
|
||||
// const photoData = user.photo;
|
||||
// Buffer.from(user.photo, 'binary').buffer;
|
||||
// const arrayBuffer = ArrayBuffer.from(photoData, 'binary');
|
||||
// return await this.userService.save(user);
|
||||
}
|
||||
|
||||
//========================================================================================================
|
||||
@ -200,90 +220,131 @@ export class AppController {
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Post('/win')
|
||||
async addWin(@Request() req, @Body() data: any) {
|
||||
console.log("WIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIN: ", req.user.username)
|
||||
const user = await this.userService.findOne(req.user.username);
|
||||
console.log("User", user)
|
||||
// const user2 = await this.userService.findOne(data.opName);
|
||||
user.win++;
|
||||
const Esp = 1 / (1 + Math.pow(10, (data.opRank - user.rank) / this.scaleFactor))
|
||||
const newRank = user.rank + this.kFactor * (1 - Esp);
|
||||
|
||||
user.rank = newRank;
|
||||
console.log(`win new rank= ${newRank}`);
|
||||
console.log(`data win = ${data}`)
|
||||
|
||||
const newMatch = new MatchLog;
|
||||
newMatch.myScore = data.myScore;
|
||||
newMatch.opScore = data.opScore;
|
||||
newMatch.opponent = data.opName;
|
||||
newMatch.parent = user;
|
||||
console.log(`newMatch WIIIN = ${newMatch}`);
|
||||
await this.userService.saveChild(user, newMatch);
|
||||
}
|
||||
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Post('/loss')
|
||||
async addLoss(@Request() req, @Body() data: any) {
|
||||
console.log("LOOOOOOOOOOOOOOOSE: ", req.user.username)
|
||||
const user = await this.userService.findOne(req.user.username);
|
||||
console.log("User", user)
|
||||
user.loss++;
|
||||
user.status = 1;
|
||||
|
||||
const Esp = 1 / (1 + Math.pow(10, (data.opRank - user.rank) / this.scaleFactor))
|
||||
const newRank = user.rank + this.kFactor * (0 - Esp);
|
||||
|
||||
user.rank = newRank;
|
||||
console.log(`loss new rank= ${newRank}`);
|
||||
console.log(`data loss = ${data}`)
|
||||
|
||||
const newMatch = new MatchLog;
|
||||
newMatch.myScore = data.myScore;
|
||||
newMatch.opScore = data.opScore;
|
||||
newMatch.opponent = data.opName;
|
||||
newMatch.parent = user;
|
||||
console.log(`newMatch Loose= ${newMatch}`);
|
||||
await this.userService.saveChild(user, newMatch);
|
||||
}
|
||||
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Get('/rank')
|
||||
async getRank(@Request() req) {
|
||||
async getRank(@Request() req)
|
||||
{
|
||||
const user = await this.userService.findOne(req.user.username);
|
||||
return user.rank;
|
||||
}
|
||||
|
||||
// @UseGuards(JwtAuthGuard)
|
||||
@Get('/ranking')
|
||||
async getRanking() {
|
||||
async getRanking()
|
||||
{
|
||||
return await this.userService.getRanking();
|
||||
}
|
||||
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Post('/partyInvite')
|
||||
async partyInvite(@Request() req, @Body() data: any) {
|
||||
async partyInvite(@Request() req, @Body() data: any)
|
||||
{
|
||||
//find data.username and add invite to list
|
||||
console.log("data post priv invite=", data);
|
||||
const user = await this.userService.findOne(data.username);
|
||||
user.partyInvite = user.partyInvite || [];
|
||||
user.partyInvite.push({ username: req.user.username, gameId: data.gameId });
|
||||
console.log("usr === ", user)
|
||||
await this.userService.save(user);
|
||||
// user.partyInvite.push(data);
|
||||
console.log("invite === ", user.partyInvite)
|
||||
}
|
||||
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Get('/partyInvite')
|
||||
async getPartyInvite(@Request() req) {
|
||||
async getPartyInvite(@Request() req, @Body() data: any)
|
||||
{
|
||||
//find data.username and add invite to list
|
||||
const user = await this.userService.findOne(req.user.username);
|
||||
user.partyInvite = user.partyInvite || [];
|
||||
// this.userService.save(user);
|
||||
// user.partyInvite.push(data);
|
||||
// console.log("data invite === ", data.username)
|
||||
return user.partyInvite;
|
||||
}
|
||||
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Post('/deleteInvite')
|
||||
async deleteInvite(@Request() req, @Body() data: any) {
|
||||
async deleteInvite(@Request() req, @Body() data: any)
|
||||
{
|
||||
console.log("delete invite user= ", data.username)
|
||||
const user = await this.userService.findOne(req.user.username);
|
||||
|
||||
|
||||
// user.partyInvite = user.partyInvite.filter(item => Object.values(item)[1] !== req.user.username);
|
||||
console.log("user.partyInvite before", user.partyInvite)
|
||||
user.partyInvite = user.partyInvite.filter((item) => Object.values(item)[1] !== data.username);
|
||||
console.log("user.partyInvite after", user.partyInvite)
|
||||
this.userService.save(user);
|
||||
}
|
||||
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Post('/history')
|
||||
async getHistory(@Body() data: any) {
|
||||
async getHistory(@Body() data: any)
|
||||
{
|
||||
// const user = await this.userService.findOne(req.user.username);
|
||||
// return user.rank;
|
||||
return await this.userService.getHistory(data.username);
|
||||
|
||||
// if (user) {
|
||||
// const children = user.children;
|
||||
// console.log(user);
|
||||
// console.log(user.children); // or perform any operations with the children
|
||||
// return children;
|
||||
// // You can also access specific properties of each child
|
||||
// // children.forEach((child) => {
|
||||
// // console.log(child.id);
|
||||
// // console.log(child.opponent);
|
||||
// // // Access other child properties as needed
|
||||
// // });
|
||||
// }
|
||||
}
|
||||
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Post('/quit')
|
||||
async setOffline(@Request() req) {
|
||||
const user = await this.userService.findOne(req.user.username);
|
||||
if (!user)
|
||||
return;
|
||||
user.sessionNumber--;
|
||||
if (!user.sessionNumber)
|
||||
user.status = 0;
|
||||
await this.userService.save(user);
|
||||
}
|
||||
|
||||
//========================================================================================================
|
||||
//========================================================================================================
|
||||
@ -291,60 +352,107 @@ export class AppController {
|
||||
//========================================================================================================
|
||||
//========================================================================================================
|
||||
|
||||
// import { Prisma } from "@prisma/client";
|
||||
// import { Request, Response, NextFunction } from "express";
|
||||
// import { prisma } from "../server";
|
||||
|
||||
|
||||
|
||||
@Redirect('http://' + process.env.BASE_URL + '/token', 302)
|
||||
@Get('auth/login')
|
||||
async login2(@Req() request: Request) {
|
||||
const url = request.url;
|
||||
const user = await this.loginClass.Login42(url);
|
||||
console.log(`user in auth/login= ${user}`);
|
||||
console.log(`user in auth/login= ${user.username}`);
|
||||
const data = await this.authService.login(user);
|
||||
console.log(`all data in api = ${data}`)
|
||||
|
||||
const myJSON = JSON.stringify(data);
|
||||
console.log(`all data json version= ${myJSON}`)
|
||||
|
||||
console.log(`data in api = ${(await data).access_token}`)
|
||||
// console.log(`data i = ${(await data).access_token}`)
|
||||
const token = (await data).access_token;
|
||||
// console
|
||||
await this.userService.save(user);
|
||||
return { url: 'http://' + process.env.BASE_URL + `/token?data=${encodeURIComponent(JSON.stringify(token))}` };
|
||||
}
|
||||
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Get('/2fa')
|
||||
async get2fa(@Request() req) {
|
||||
async get2fa(@Request() req)
|
||||
{
|
||||
const user = await this.userService.findOne(req.user.username);
|
||||
return user.otp_enabled;
|
||||
}
|
||||
|
||||
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Post('/otp')
|
||||
async createOTP(@Request() req) {
|
||||
async createOTP(@Request() req)
|
||||
{
|
||||
const user = await this.userService.findOne(req.user.username);
|
||||
// const user2 = await this.userService.findOne(req.user.username);
|
||||
const res = await generateOTP(user);
|
||||
await this.userService.save(user);
|
||||
// console.log(user);
|
||||
return res;
|
||||
}
|
||||
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Post('/verifyOtp')
|
||||
async verifyOTP(@Request() req, @Body() data: any) {
|
||||
async verifyOTP(@Request() req, @Body() data: any)
|
||||
{
|
||||
const user = await this.userService.findOne(req.user.username);
|
||||
const res = await VerifyOTP(user, data.token)
|
||||
console.log('token in verify=', data.token)
|
||||
console.log('res in verify=', res)
|
||||
await this.userService.save(user);
|
||||
return res
|
||||
}
|
||||
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Post('/validateOtp')
|
||||
async validateOTP(@Request() req, @Body() data: any) {
|
||||
async validateOTP(@Request() req, @Body() data: any)
|
||||
{
|
||||
const user = await this.userService.findOne(req.user.username);
|
||||
const res = await ValidateOTP(user, data.token)
|
||||
// await this.userService.save(user);
|
||||
return res
|
||||
}
|
||||
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Post('/deleteOtp')
|
||||
async deleteOTP(@Request() req, @Body() data: any) {
|
||||
async deleteOTP(@Request() req, @Body() data: any)
|
||||
{
|
||||
const user = await this.userService.findOne(req.user.username);
|
||||
user.otp_verified = false;
|
||||
await this.userService.save(user);
|
||||
// const res = await ValidateOTP(user, data.token)
|
||||
// await this.userService.save(user);
|
||||
// return res
|
||||
}
|
||||
|
||||
// @UseGuards(JwtAuthGuard)
|
||||
// @Get('/QRcode')
|
||||
// async createQrCode(@Request() req)
|
||||
// {
|
||||
// return (await generateQRcode(req));
|
||||
// }
|
||||
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Post('/quit')
|
||||
async setOffline(@Request() req) {
|
||||
|
||||
const user = await this.userService.findOne(req.user.username);
|
||||
|
||||
user.status = 0;
|
||||
await this.userService.save(user);
|
||||
console.log("User quit");
|
||||
}
|
||||
|
||||
|
||||
//========================================================================================================
|
||||
//========================================================================================================
|
||||
// Chat
|
||||
@ -354,16 +462,26 @@ export class AppController {
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Post('/conv')
|
||||
async createConv(@Request() req, @Body() data: any) {
|
||||
///create conv and return it ? id?
|
||||
console.log(`data post /conv= ${data}`);
|
||||
console.log(`data post /conv= ${data.members}`);
|
||||
// console.log(`data post /conv= ${data.name}`);
|
||||
|
||||
// const param = data;
|
||||
const amIhere = data.members.includes(req.user.username);
|
||||
if (!amIhere)
|
||||
data.members.push(req.user.username)
|
||||
// let test = {id: 2, members: "cc"};
|
||||
data.admin = []
|
||||
data.admin.push(req.user.username)
|
||||
data.owner = req.user.username
|
||||
data.group = true;
|
||||
return await this.chatService.createConv(data);
|
||||
// res.json(messages);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Get('/conv')
|
||||
async getConv(@Request() req) {
|
||||
@ -386,11 +504,13 @@ export class AppController {
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Post('/message')
|
||||
async postMessage(@Request() req, @Body() data: any) {
|
||||
//if i can post post ?
|
||||
let message =
|
||||
{
|
||||
convid: data.convId,
|
||||
sender: data.sender,
|
||||
text: data.text,
|
||||
// createdAt: null,
|
||||
id: null,
|
||||
}
|
||||
console.log(data);
|
||||
@ -408,12 +528,24 @@ export class AppController {
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Post('/getMessage')
|
||||
async getMessage(@Body() data: any) {
|
||||
console.log(data);
|
||||
// console.log(req.query)
|
||||
console.log(`data get /conv= ${data.convId}`);
|
||||
// let test = {id: 2, members: "cc"};
|
||||
|
||||
|
||||
return await this.chatService.getMessages(data.convId);
|
||||
// return await this.chatService.getConv(req.user.username);
|
||||
|
||||
|
||||
// res.json(messages);
|
||||
}
|
||||
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Post('/name')
|
||||
async setName(@Body() data: any) {
|
||||
//find conv
|
||||
// data.convId
|
||||
return await this.chatService.setName(data.convId, data.name)
|
||||
}
|
||||
|
||||
@ -425,15 +557,12 @@ export class AppController {
|
||||
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Post('/verifyPassword')
|
||||
async verifyPassword(@Request() req, @Body() data: any) {
|
||||
return await this.chatService.verifyPassword(data.convId, data.password, req.user.username)
|
||||
async verifyPassword(@Body() data: any) {
|
||||
return await this.chatService.verifyPassword(data.convId, data.password)
|
||||
}
|
||||
// async verifyPassword(@Body() data: any) {
|
||||
// return await this.chatService.verifyPassword(data.convId, data.password)
|
||||
// }
|
||||
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Post('/inviteConv')
|
||||
@Post('/invite')
|
||||
async inviteUser(@Body() data: any) {
|
||||
return await this.chatService.inviteUser(data.convId, data.username)
|
||||
}
|
||||
@ -459,7 +588,7 @@ export class AppController {
|
||||
async muteUser(@Body() data: any) {
|
||||
if (!data.username)
|
||||
return ;
|
||||
return await this.chatService.muteUser(data.convId, data.username, data.time)
|
||||
return await this.chatService.muteUser(data.convId, data.username)
|
||||
}
|
||||
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@ -469,16 +598,11 @@ export class AppController {
|
||||
return await this.chatService.isAdmin(data.convId, req.user.username)
|
||||
}
|
||||
|
||||
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Post('/private')
|
||||
async setPrivate(@Body() data: any) {
|
||||
return await this.chatService.setPrivate(data.convId, true)
|
||||
}
|
||||
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Post('/public')
|
||||
async setPublic(@Body() data: any) {
|
||||
return await this.chatService.setPrivate(data.convId, false)
|
||||
return await this.chatService.setPrivate(data.convId)
|
||||
}
|
||||
|
||||
@UseGuards(JwtAuthGuard)
|
||||
|
||||
@ -2,8 +2,16 @@ import { Module } from '@nestjs/common';
|
||||
import { AppController } from './app.controller';
|
||||
import { AppService } from './app.service';
|
||||
import { AuthModule } from './auth/auth.module';
|
||||
|
||||
import { loginClass } from './auth/login42';
|
||||
// import { UsersService } from './users/users.service'; // in add
|
||||
|
||||
// import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
// import { getTypeOrmConfig } from './config/config.service';
|
||||
// import { User } from './model/item.entity';
|
||||
// import { UsersService } from './users/users.service';
|
||||
import { UsersModule } from './users/users.module';
|
||||
// import { ChatService } from './chat/chat.service';
|
||||
import { ChatModule } from './chat/chat.module';
|
||||
|
||||
@Module({
|
||||
@ -15,5 +23,7 @@ import { ChatModule } from './chat/chat.module';
|
||||
],
|
||||
controllers: [AppController],
|
||||
providers: [AppService, loginClass,],
|
||||
|
||||
// providers: [AppService, UsersService],//in add
|
||||
})
|
||||
export class AppModule {}
|
||||
|
||||
@ -1,8 +1,23 @@
|
||||
// import { Module } from '@nestjs/common';
|
||||
// import { AuthService } from './auth.service';
|
||||
// import { UsersModule } from '../users/users.module';
|
||||
// import { PassportModule } from '@nestjs/passport';
|
||||
// import { LocalStrategy } from './local.strategy';
|
||||
|
||||
// @Module({
|
||||
// imports: [UsersModule, PassportModule],
|
||||
// providers: [AuthService, LocalStrategy],
|
||||
// })
|
||||
// export class AuthModule {}
|
||||
|
||||
|
||||
import { Module } from '@nestjs/common';
|
||||
|
||||
import { AuthService } from './auth.service';
|
||||
import { UsersModule } from '../users/users.module';
|
||||
import { PassportModule } from '@nestjs/passport';
|
||||
import { LocalStrategy } from './local.strategy';
|
||||
|
||||
import { JwtModule } from '@nestjs/jwt';
|
||||
import { jwtConstants } from './constants';
|
||||
import { JwtStrategy } from './jwt.strategy';
|
||||
@ -13,6 +28,7 @@ import { JwtStrategy } from './jwt.strategy';
|
||||
PassportModule,
|
||||
JwtModule.register({
|
||||
secret: jwtConstants.secret,
|
||||
// signOptions: { expiresIn: '60000s' },
|
||||
}),
|
||||
],
|
||||
providers: [AuthService, LocalStrategy, JwtStrategy],
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
export const jwtConstants = {
|
||||
// secret: 'DO NOT USE THIS VALUE. INSTEAD, CREATE A COMPLEX SECRET AND KEEP IT SAFE OUTSIDE OF THE SOURCE CODE.',
|
||||
secret: process.env.JWT_SECRET,
|
||||
};
|
||||
@ -1,7 +1,12 @@
|
||||
// import React, { useEffect, useState } from 'react';
|
||||
import axios from 'axios';
|
||||
import { UsersService } from '../users/users.service';
|
||||
import { Injectable } from '@nestjs/common';
|
||||
|
||||
import { Repository } from 'typeorm';
|
||||
|
||||
import { MatchLog } from '../model/user.entity';
|
||||
|
||||
@Injectable()
|
||||
export class loginClass {
|
||||
constructor(private readonly usersService: UsersService) {};
|
||||
@ -11,16 +16,19 @@ export class loginClass {
|
||||
let token = null;
|
||||
let userId = null;
|
||||
let userName = null;
|
||||
// let = null;
|
||||
|
||||
|
||||
const params = new URLSearchParams(url.split('?')[1]);
|
||||
const code = params.get('code');
|
||||
|
||||
const data = {
|
||||
grant_type: 'authorization_code',
|
||||
client_id: process.env.CLIENT_UID,
|
||||
client_id: process.env.CLIENT_UID || 'u-s4t2ud-6d29dfa49ba7146577ffd8bf595ae8d9e5aaa3e0a9615df18777171ebf836a41',
|
||||
// client_secret: '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',
|
||||
client_secret: process.env.API_SECRET,
|
||||
code: code,
|
||||
redirect_uri: process.env.REDIRECT_URI,
|
||||
redirect_uri: process.env.REDIRECT_URI || 'http://' + process.env.REACT_APP_BASE_URL + '/api/auth/login',
|
||||
};
|
||||
|
||||
try {
|
||||
@ -34,14 +42,20 @@ export class loginClass {
|
||||
});
|
||||
userName = response2.data.login;
|
||||
userId = parseInt(response2.data.id, 10);
|
||||
// console.log(`all user data= ${response2.data}`)
|
||||
// const myJSON = JSON.stringify(response2.data);
|
||||
// console.log(`json version= ${myJSON}`)
|
||||
}
|
||||
catch(error)
|
||||
{
|
||||
console.log(error);
|
||||
return ;
|
||||
}
|
||||
console.log(`username before serach= ${userName}`)
|
||||
console.log(`ID before serach= ${userId}`)
|
||||
let user = await this.usersService.findOne(userName);
|
||||
if (!user) {
|
||||
console.log(`no user, creating one`);
|
||||
user = {
|
||||
id: null,
|
||||
partyInvite: null,
|
||||
@ -62,11 +76,15 @@ export class loginClass {
|
||||
friends: null,
|
||||
blocked: null,
|
||||
photo: null,
|
||||
sessionNumber: 0,
|
||||
};
|
||||
await this.usersService.create(user);
|
||||
}
|
||||
// console.log(`in login42 user= ${user}`)
|
||||
const myJSON = JSON.stringify(user);
|
||||
console.log(`in login42 user= ${myJSON}`)
|
||||
|
||||
console.log("end of login");
|
||||
return (user);
|
||||
// return (await this.usersService.findOne(userName));
|
||||
}
|
||||
}
|
||||
@ -1,3 +1,8 @@
|
||||
// import { Module } from '@nestjs/common';
|
||||
|
||||
// @Module({})
|
||||
// export class ChatModule {}
|
||||
|
||||
import { Module } from '@nestjs/common';
|
||||
import { ChatService} from './chat.service';
|
||||
|
||||
@ -12,6 +17,7 @@ import { Message } from '../model/chat.entity';
|
||||
TypeOrmModule.forRoot(getTypeOrmConfig()),
|
||||
TypeOrmModule.forFeature([Conv]),
|
||||
TypeOrmModule.forFeature([Message]),
|
||||
// TypeOrmModule.forFeature([UserRepository]),
|
||||
],
|
||||
providers:[ChatService],
|
||||
exports: [ChatService],
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
/* By: apommier <apommier@student.42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2023/06/17 01:00:25 by apommier #+# #+# */
|
||||
/* Updated: 2023/06/26 06:56:08 by apommier ### ########.fr */
|
||||
/* Updated: 2023/06/20 16:47:02 by apommier ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
@ -15,8 +15,13 @@ import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { Repository } from 'typeorm';
|
||||
import { Conv } from '../model/chat.entity';
|
||||
import { Message } from '../model/chat.entity';
|
||||
|
||||
import * as bcrypt from 'bcrypt';
|
||||
|
||||
import { ArrayContains } from "typeorm"
|
||||
import { query } from 'express';
|
||||
import { InitializeOnPreviewAllowlist } from '@nestjs/core';
|
||||
|
||||
|
||||
@Injectable()
|
||||
export class ChatService {
|
||||
@ -38,10 +43,13 @@ export class ChatService {
|
||||
|
||||
async getConv(username: string): Promise<Conv[]>{
|
||||
const convs = await this.chatRepository.query("SELECT * FROM \"conv\" WHERE $1 = ANY (ARRAY[members]);", [username])
|
||||
console.log(`convs= ${convs}`)
|
||||
return convs;
|
||||
}
|
||||
|
||||
async findConv(number: number){
|
||||
// username = "apommier"
|
||||
console.log(`fincConv; ${number}`)
|
||||
const conv = await this.chatRepository.findOneBy({id: number})
|
||||
return conv;
|
||||
}
|
||||
@ -74,68 +82,51 @@ export class ChatService {
|
||||
async banUser(convId: number, username: string) {
|
||||
const conv = await this.findConv(convId);
|
||||
|
||||
if (conv.owner === username)
|
||||
return (0);
|
||||
conv.banned = conv.banned || [];
|
||||
if (conv.banned.find(item => item === username)) {
|
||||
conv.banned = conv.banned.filter((item) => item !== username);
|
||||
this.save(conv);
|
||||
return (2);
|
||||
}
|
||||
if (conv.banned.find(item => item === username))
|
||||
return (1);
|
||||
conv.members = conv.members.filter((item) => item !== username);
|
||||
conv.banned.push(username);
|
||||
this.save(conv);
|
||||
return (1);
|
||||
}
|
||||
|
||||
async inviteUser(convId: number, username: string) {
|
||||
const conv = await this.findConv(convId);
|
||||
// const conv = await this.findConv(convId);
|
||||
// this.save(conv);
|
||||
|
||||
if (conv.members.find(item => item === username))
|
||||
return (1);
|
||||
conv.members.push(username);
|
||||
this.save(conv);
|
||||
//find user
|
||||
//add in chanInvite chanID
|
||||
//save user
|
||||
}
|
||||
|
||||
|
||||
|
||||
async setPassword(convId: number, password: string) {
|
||||
//verify is user is admin ?
|
||||
const conv = await this.findConv(convId);
|
||||
const saltRounds = 10;
|
||||
const hashedPassword = await bcrypt.hash(password, saltRounds);
|
||||
// return hashedPassword;
|
||||
conv.password = hashedPassword
|
||||
this.save(conv);
|
||||
}
|
||||
|
||||
// async verifyPassword(convId: number, password: string) {
|
||||
async verifyPassword(convId: number, password: string, username: string) {
|
||||
async verifyPassword(convId: number, password: string) {
|
||||
//verify is user is admin ?
|
||||
const conv = await this.findConv(convId);
|
||||
// return await bcrypt.compare(password, conv.password);
|
||||
const ret = await bcrypt.compare(password, conv.password);
|
||||
if (ret === true) {
|
||||
conv.members = conv.members || [];
|
||||
conv.members.push(username);
|
||||
this.save(conv);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
yy
|
||||
return await bcrypt.compare(password, conv.password);
|
||||
|
||||
async muteUser(convId: number, username: string, time: string) {
|
||||
// conv.password = password
|
||||
}
|
||||
|
||||
async muteUser(convId: number, username: string) {
|
||||
const conv = await this.findConv(convId);
|
||||
const intTime = parseInt(time) * 1000;
|
||||
if (conv.owner === username)
|
||||
return (0);
|
||||
|
||||
conv.muted = conv.muted || [];
|
||||
if (conv.muted.find(item => item === username))
|
||||
return (1);
|
||||
conv.muted.push(username);
|
||||
this.save(conv);
|
||||
|
||||
setTimeout(() => {
|
||||
conv.muted = conv.muted.filter((item) => item !== username)
|
||||
this.save(conv);
|
||||
}, intTime);
|
||||
}
|
||||
|
||||
async setAdmin(convId: number, username: string) {
|
||||
@ -158,10 +149,12 @@ yy
|
||||
return (0);
|
||||
}
|
||||
|
||||
async setPrivate(convId: number, bool: boolean) {
|
||||
async setPrivate(convId: number) {
|
||||
const conv = await this.findConv(convId);
|
||||
console.log("bool= ", bool);
|
||||
conv.private = bool;
|
||||
if (conv.private === true)
|
||||
conv.private = false;
|
||||
else
|
||||
conv.private = true;
|
||||
this.save(conv);
|
||||
}
|
||||
|
||||
@ -177,6 +170,7 @@ yy
|
||||
if (conv.members.find(item => item === username))
|
||||
return ;
|
||||
conv.members.push(username);
|
||||
// conv.name = name;
|
||||
this.save(conv);
|
||||
}
|
||||
|
||||
|
||||
@ -3,10 +3,10 @@
|
||||
/* ::: :::::::: */
|
||||
/* config.service.ts :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: sadjigui <sadjigui@student.42.fr> +#+ +:+ +#+ */
|
||||
/* By: apommier <apommier@student.42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2023/04/09 14:53:49 by apommier #+# #+# */
|
||||
/* Updated: 2023/06/24 15:09:20 by sadjigui ### ########.fr */
|
||||
/* Updated: 2023/06/22 20:42:32 by apommier ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
|
||||
@ -6,11 +6,20 @@ import * as dotenv from 'dotenv';
|
||||
dotenv.config();
|
||||
console.log(process.env);
|
||||
|
||||
// async function bootstrap() {
|
||||
// const app = await NestFactory.create(AppModule);
|
||||
// await app.listen(3000);
|
||||
// }
|
||||
// bootstrap();
|
||||
|
||||
|
||||
async function bootstrap() {
|
||||
const app = await NestFactory.create(AppModule, {
|
||||
cors: {
|
||||
origin: '*',
|
||||
methods: '*',
|
||||
// preflightContinue: false,
|
||||
// optionsSuccessStatus: 204,
|
||||
credentials: true,
|
||||
allowedHeaders: '*',
|
||||
},
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
/* By: apommier <apommier@student.42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2023/06/17 01:00:20 by apommier #+# #+# */
|
||||
/* Updated: 2023/06/26 06:55:03 by apommier ### ########.fr */
|
||||
/* Updated: 2023/06/23 15:18:19 by apommier ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
@ -29,6 +29,9 @@ import { Entity, Column, PrimaryGeneratedColumn, CreateDateColumn, BaseEntity }
|
||||
@Column({ nullable: true })
|
||||
private: boolean
|
||||
|
||||
// @Column()
|
||||
// members: string;// arry ??? one to many ???
|
||||
|
||||
@Column('text', { array: true, nullable: true })
|
||||
banned: string[];
|
||||
|
||||
@ -46,6 +49,18 @@ import { Entity, Column, PrimaryGeneratedColumn, CreateDateColumn, BaseEntity }
|
||||
|
||||
@Column({ nullable: true })
|
||||
messages: string;
|
||||
|
||||
// @CreateDateColumn()
|
||||
// createdAt: Date;
|
||||
|
||||
|
||||
|
||||
//ban user
|
||||
//user list
|
||||
//blocked user (in user model ?)
|
||||
//op list
|
||||
//a way to stock conv ?
|
||||
|
||||
}
|
||||
|
||||
@Entity()
|
||||
@ -62,6 +77,7 @@ import { Entity, Column, PrimaryGeneratedColumn, CreateDateColumn, BaseEntity }
|
||||
@Column()
|
||||
text: string;
|
||||
|
||||
|
||||
@CreateDateColumn({ nullable: true })
|
||||
createdAt?: Date;
|
||||
|
||||
|
||||
@ -20,6 +20,9 @@ export class User {
|
||||
@PrimaryGeneratedColumn()
|
||||
id: number;
|
||||
|
||||
// otp_enabled Boolean @default(false)
|
||||
// otp_verified Boolean @default(false)
|
||||
|
||||
@Column({ default: false })
|
||||
otp_enabled: boolean;
|
||||
|
||||
@ -47,9 +50,6 @@ export class User {
|
||||
@Column({ default: 0 })
|
||||
loss: number;
|
||||
|
||||
@Column({ default: 0 })
|
||||
sessionNumber: number;
|
||||
|
||||
@Column({ default: 0 })
|
||||
rank: number;
|
||||
|
||||
@ -59,12 +59,18 @@ export class User {
|
||||
@Column({ default: 0 })
|
||||
userId: number;
|
||||
|
||||
// @Column({ default: 0 })
|
||||
// doubleAuth: number;
|
||||
|
||||
@Column('text', { array: true, nullable: true })
|
||||
friendRequest: string[];
|
||||
|
||||
@Column({ type: 'jsonb', nullable: true })
|
||||
partyInvite: Record<string, string>[];
|
||||
|
||||
// @Column('text', { array: true, nullable: true })
|
||||
// friendRequest: string[];
|
||||
|
||||
@Column('text', { array: true, nullable: true })
|
||||
friends: string[];
|
||||
|
||||
@ -76,7 +82,7 @@ export class User {
|
||||
|
||||
}
|
||||
|
||||
@Entity({name: 'MatchLog' })
|
||||
@Entity()
|
||||
export class MatchLog {
|
||||
@PrimaryGeneratedColumn()
|
||||
id: number;
|
||||
|
||||
@ -1,7 +1,18 @@
|
||||
// import crypto from 'crypto';
|
||||
import base32Decode from 'base32-decode';
|
||||
|
||||
import crypto from "crypto";
|
||||
import * as OTPAuth from "otpauth";
|
||||
import { encode } from "hi-base32";
|
||||
|
||||
import * as qr from 'qrcode';
|
||||
|
||||
// [...] Register user
|
||||
|
||||
// [...] Login user
|
||||
|
||||
// [...] Generate OTP
|
||||
|
||||
const generateRandomBase32 = async () => {
|
||||
const {randomBytes} = await import('crypto');
|
||||
const buffer = randomBytes(15);
|
||||
@ -25,22 +36,35 @@ export const generateOTP = async (user) => {
|
||||
let otpauth_url = totp.toString();
|
||||
const qrCodeDataUrl = await qr.toDataURL(otpauth_url, { errorCorrectionLevel: 'H' });
|
||||
|
||||
const filePath = 'qrcode.png';
|
||||
const filePath = 'qrcode.png'; // Specify the file path where the QR code should be saved
|
||||
|
||||
qr.toFile(filePath, qrCodeDataUrl, (error) => {
|
||||
if (error) {
|
||||
console.error(error);
|
||||
// Handle the error appropriately
|
||||
return;
|
||||
}
|
||||
// QR code image has been generated and saved to the file
|
||||
// Or, you can create a buffer of the image data directly
|
||||
})
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
const res = {
|
||||
otpauth_url: otpauth_url,
|
||||
base32_secret: base32_secret
|
||||
}
|
||||
|
||||
console.log("res= ", res)
|
||||
|
||||
//update db with otp var
|
||||
user.otp_enabled = true;
|
||||
user.otp_base32 = base32_secret;
|
||||
return (res);
|
||||
return (res)
|
||||
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
}
|
||||
@ -60,11 +84,13 @@ export const generateOTP = async (user) => {
|
||||
let delta = totp.validate({ token });
|
||||
|
||||
if (delta === null) {
|
||||
console.log("error verify token")
|
||||
return (0)
|
||||
}
|
||||
else
|
||||
{
|
||||
user.otp_verified = true;
|
||||
console.log("token verified")
|
||||
return (1)
|
||||
}
|
||||
} catch (error) {
|
||||
@ -84,11 +110,194 @@ export const generateOTP = async (user) => {
|
||||
});
|
||||
let delta = totp.validate({ token });
|
||||
|
||||
if (delta === null)
|
||||
if (delta === null) {
|
||||
console.log("error validate token")
|
||||
return (0);
|
||||
}
|
||||
else
|
||||
{
|
||||
// user.otp_verified = true;
|
||||
console.log("token validated")
|
||||
return (1);
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
}
|
||||
};
|
||||
|
||||
// import { randomBytes} from 'crypto';
|
||||
// import { promisify } from 'util';
|
||||
|
||||
// export function generateHOTP(secret, counter) {
|
||||
// const decodedSecret = base32Decode(secret, 'RFC4648');
|
||||
|
||||
// const buffer = Buffer.alloc(8);
|
||||
// for (let i = 0; i < 8; i++)
|
||||
// {
|
||||
// buffer[7 - i] = counter & 0xff;
|
||||
// counter = counter >> 8;
|
||||
// }
|
||||
|
||||
// // Step 1: Generate an HMAC-SHA-1 value
|
||||
// const hmac = crypto.createHmac('sha1', Buffer.from(decodedSecret));
|
||||
// hmac.update(buffer);
|
||||
// const hmacResult = hmac.digest();
|
||||
|
||||
// // Step 2: Generate a 4-byte string (Dynamic Truncation)
|
||||
// const offset = hmacResult[hmacResult.length - 1] & 0xf;
|
||||
// const code =
|
||||
// ((hmacResult[offset] & 0x7f) << 24) |
|
||||
// ((hmacResult[offset + 1] & 0xff) << 16) |
|
||||
// ((hmacResult[offset + 2] & 0xff) << 8) |
|
||||
// (hmacResult[offset + 3] & 0xff);
|
||||
|
||||
// // Step 3: Compute an HOTP value
|
||||
// return `${code % 10 ** 6}`.padStart(6, '0');
|
||||
// }
|
||||
|
||||
// type QRcode = any;
|
||||
|
||||
// export function generateHOTP(secret, counter) {
|
||||
// const decodedSecret = base32Decode(secret, 'RFC4648');
|
||||
|
||||
// const buffer = Buffer.alloc(8);
|
||||
// for (let i = 0; i < 8; i++) {
|
||||
// buffer[7 - i] = counter & 0xff;
|
||||
// counter = counter >> 8;
|
||||
// }
|
||||
|
||||
// // Step 1: Generate an HMAC-SHA-1 value
|
||||
// const hmac = crypto.createHmac('sha1', Buffer.from(decodedSecret));
|
||||
// hmac.update(buffer);
|
||||
// const hmacResult = hmac.digest();
|
||||
|
||||
// // Step 2: Generate a 4-byte string (Dynamic Truncation)
|
||||
// const offset = hmacResult[hmacResult.length - 1] & 0xf;
|
||||
// const code =
|
||||
// ((hmacResult[offset] & 0x7f) << 24) |
|
||||
// ((hmacResult[offset + 1] & 0xff) << 16) |
|
||||
// ((hmacResult[offset + 2] & 0xff) << 8) |
|
||||
// (hmacResult[offset + 3] & 0xff);
|
||||
|
||||
// // Step 3: Compute an HOTP value
|
||||
// return code % 10 ** 6;
|
||||
// }
|
||||
|
||||
// export function generateTOTP(secret, window = 0)
|
||||
// {
|
||||
// const counter = Math.floor(Date.now() / 30000);
|
||||
// return generateHOTP(secret, counter + window);
|
||||
// }
|
||||
|
||||
// export function verifyTOTP(token, secret, window = 1)
|
||||
// {
|
||||
// for (let errorWindow = -window; errorWindow <= +window; errorWindow++)
|
||||
// {
|
||||
// const totp = generateTOTP(secret, errorWindow);
|
||||
// if (token === totp)
|
||||
// return true;
|
||||
// }
|
||||
// return false;
|
||||
// }
|
||||
|
||||
|
||||
|
||||
// import { initStorage, getUser, setUser } from './storage';
|
||||
// import util from 'util';
|
||||
// import qrcode from 'qrcode';
|
||||
// // import base32Encode from 'base32-encode';
|
||||
// import * as util from 'util';
|
||||
// import * as qrcode from 'qrcode';
|
||||
// import * as base32Encode from 'base32-encode';
|
||||
|
||||
// import * as util from 'util';
|
||||
// import * as qrcode from 'qrcode';
|
||||
// import * as crypto from 'crypto';
|
||||
// import { Response } from 'express';
|
||||
// import { Readable } from 'stream';
|
||||
// import * as base32Encode from 'base32-encode';
|
||||
// import { base32Encode } from 'base32-encode';
|
||||
// import base32Encode from 'base32-encode';
|
||||
// import { encode } from 'thirty-two';
|
||||
|
||||
// // ...
|
||||
|
||||
// import * as qrcode from 'qrcode';
|
||||
// import * as fs from 'fs';
|
||||
|
||||
|
||||
// import { nanoid } from "nanoid";
|
||||
// // import * as nanoid from 'nanoid'
|
||||
|
||||
// export async function generateQRcode(req)
|
||||
// {
|
||||
// // const base32Encode = (await import('base32-encode'));
|
||||
// // const nanoid = (await import('nanoid'));
|
||||
|
||||
// // const util = (await import('util'));
|
||||
// // const qrcode = (await import('qrcode'));
|
||||
|
||||
// const user = req.user;
|
||||
// let res;
|
||||
// // For security, we no longer show the QR code after is verified
|
||||
// // if (user.mfaEnabled) return res.status(404).end();
|
||||
|
||||
// // if (!user.mfaSecret) { //to do
|
||||
// const buffer = nanoid(14);
|
||||
// // generate unique secret for user
|
||||
// // this secret will be used to check the verification code sent by user
|
||||
// // const buffer = await util.promisify(crypto.randomBytes)(14);
|
||||
// // const buffer = crypto.lib.WordArray.random(32)
|
||||
// user.mfaSecret = encode(buffer).toString('utf8');
|
||||
// // user.mfaSecret = base32Encoded(buffer, 'RFC4648', { padding: false });
|
||||
|
||||
// // setUser(user); // to do !!
|
||||
|
||||
|
||||
// // }
|
||||
|
||||
// const issuer = 'Google';
|
||||
// const algorithm = 'SHA1';
|
||||
// const digits = '6';
|
||||
// const period = '30';
|
||||
// const otpType = 'totp';
|
||||
// const configUri = `otpauth://${otpType}/${issuer}:${user.username}?algorithm=${algorithm}&digits=${digits}&period=${period}&issuer=${issuer}&secret=${user.mfaSecret}`;
|
||||
|
||||
// // res.setHeader('Content-Type', 'image/png');
|
||||
// const QRCode = require('qrcode');
|
||||
// console.log(`before done`);
|
||||
// // QRCode.toFileStream(res, configUri);
|
||||
// // const filePath = 'qrcode.png'; // Specify the file path where the QR code should be saved
|
||||
|
||||
|
||||
// const qrCodeData = buffer; // Replace with your actual QR code data
|
||||
// const filePath = 'qrcode.png'; // Specify the file path where the QR code should be saved
|
||||
|
||||
// qrcode.toFile(filePath, qrCodeData, (error) => {
|
||||
// if (error) {
|
||||
// console.error(error);
|
||||
// // Handle the error appropriately
|
||||
// return;
|
||||
// }
|
||||
// // QR code image has been generated and saved to the file
|
||||
// // Or, you can create a buffer of the image data directly
|
||||
// })
|
||||
|
||||
// // qrcode.toFile(filePath, configUri, (error) => {
|
||||
// // if (error) {
|
||||
// // console.error(error);
|
||||
// // // Handle the error appropriately
|
||||
// // return;
|
||||
// // }
|
||||
// // const readableStream = fs.createReadStream(filePath);
|
||||
// // res.data = readableStream;
|
||||
// // Use the readable stream as needed
|
||||
// // });
|
||||
|
||||
|
||||
|
||||
// // qrcode.toFileStream(res, configUri);
|
||||
// console.log(`QRcode done`);
|
||||
// return res;
|
||||
// // return
|
||||
// }
|
||||
@ -11,6 +11,7 @@ import { MatchLog, User } from '../model/user.entity';
|
||||
TypeOrmModule.forRoot(getTypeOrmConfig()),
|
||||
TypeOrmModule.forFeature([User]),
|
||||
TypeOrmModule.forFeature([MatchLog]),
|
||||
// TypeOrmModule.forFeature([UserRepository]),
|
||||
],
|
||||
providers:[UsersService],
|
||||
exports: [UsersService],
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
/* By: apommier <apommier@student.42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2023/06/17 01:00:07 by apommier #+# #+# */
|
||||
/* Updated: 2023/06/26 07:52:08 by apommier ### ########.fr */
|
||||
/* Updated: 2023/06/21 01:31:44 by apommier ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
@ -41,15 +41,12 @@ export class UsersService {
|
||||
return await this.userRepository.findOneBy({username: username});
|
||||
}
|
||||
|
||||
async findNickname(username: string): Promise<User> {
|
||||
return await this.userRepository.findOneBy({nickname: username});
|
||||
}
|
||||
|
||||
async save(user: User): Promise<User> {
|
||||
return await this.userRepository.save(user);
|
||||
}
|
||||
|
||||
async saveChild(user: User, match: MatchLog): Promise<User> {
|
||||
// user.match = savedChild;
|
||||
user.children.push(match)
|
||||
await this.matchRepository.save(match);
|
||||
return await this.userRepository.save(user);
|
||||
@ -57,7 +54,9 @@ export class UsersService {
|
||||
|
||||
async getFriends(username: string) {
|
||||
const user = await this.findOne(username)
|
||||
let friendsTab = user.friends || [];
|
||||
let friendsTab = user.friends
|
||||
console.log(friendsTab)
|
||||
// friendsTab = ['apommier', 'syd']
|
||||
const friends = await this.userRepository.query("SELECT * FROM \"User\" WHERE username = ANY ($1);", [friendsTab]);
|
||||
console.log(friends)
|
||||
return (friends)
|
||||
@ -66,12 +65,12 @@ export class UsersService {
|
||||
async newInvite(user: User, username: string) {
|
||||
if (!(await this.findOne(username)))
|
||||
return (0);
|
||||
// user.friendRequest = user.friendRequest || [];
|
||||
// console.log("newInvite")
|
||||
// console.log(user.friendRequest)
|
||||
user.friendRequest = user.friendRequest || [];
|
||||
if (user.friendRequest.find(item => item === username))
|
||||
return (1);
|
||||
user.friends = user.friends || [];
|
||||
if (user.friends.find(item => item === username))
|
||||
return (1);
|
||||
user.friendRequest.push(username);
|
||||
this.save(user);
|
||||
return (1);
|
||||
@ -80,7 +79,10 @@ export class UsersService {
|
||||
async getInvite(username: string) {
|
||||
const user = await this.findOne(username)
|
||||
let friendsTab = user.friendRequest
|
||||
// console.log(friendsTab[0])
|
||||
// console.log(friendsTab[1])
|
||||
console.log(friendsTab)
|
||||
// friendsTab = ['apommier', 'syd']
|
||||
const friends = await this.userRepository.query("SELECT * FROM \"User\" WHERE username = ANY ($1);", [friendsTab]);
|
||||
console.log(friends)
|
||||
return (friends)
|
||||
@ -94,13 +96,18 @@ export class UsersService {
|
||||
async getHistory(username: string) {
|
||||
const user = await this.findOne(username);
|
||||
|
||||
return await this.userRepository.query("SELECT * FROM \"MatchLog\" WHERE \"parentId\" = ANY ($1);", [[user.id]]);
|
||||
if (user) {
|
||||
const children = user.children;
|
||||
console.log(user);
|
||||
console.log(user.children); // or perform any operations with the children
|
||||
return children;
|
||||
}
|
||||
}
|
||||
|
||||
async addFriend(user: User, username: string) {
|
||||
const user2 = await this.findOne(username)
|
||||
if (!user)
|
||||
if (!(await this.findOne(username)))
|
||||
return (0);
|
||||
// user.friendRequest = user.friendRequest || [];
|
||||
user.friends = user.friends || [];
|
||||
if (user.friends.find(item => item === username))
|
||||
{
|
||||
@ -110,9 +117,6 @@ export class UsersService {
|
||||
}
|
||||
user.friends.push(username);
|
||||
user.friendRequest = user.friendRequest.filter((item) => item !== username);
|
||||
user2.friends = user2.friends || [];
|
||||
user2.friends.push(user.username);
|
||||
this.save(user2);
|
||||
this.save(user);
|
||||
return (1);
|
||||
}
|
||||
@ -122,11 +126,7 @@ export class UsersService {
|
||||
return (0);
|
||||
user.blocked = user.blocked || [];
|
||||
if (user.blocked.find(item => item === username))
|
||||
{
|
||||
this.save(user);
|
||||
user.blocked = user.blocked.filter((item) => item !== username);
|
||||
return (2);
|
||||
}
|
||||
return (1);
|
||||
user.blocked.push(username);
|
||||
this.save(user);
|
||||
return (1);
|
||||
@ -137,11 +137,40 @@ export class UsersService {
|
||||
}
|
||||
|
||||
async getPic( username: string) {
|
||||
// const user = await this.findOne(username);
|
||||
let result = await this.userRepository.query("select encode(photo, 'base64') FROM public.\"User\" WHERE username = $1;", [username]);
|
||||
if (result.length > 0) {
|
||||
const encodedPhoto = result[0].encode;
|
||||
console.log(`pic!!! =`)
|
||||
return encodedPhoto;
|
||||
}
|
||||
console.log(`no pic`)
|
||||
return undefined
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// }
|
||||
// type orm here
|
||||
|
||||
// This should be a real class/interface representing a user entity
|
||||
// export type User = any;
|
||||
|
||||
// @Injectable()
|
||||
// export class UsersService {
|
||||
// private readonly users = [
|
||||
// {
|
||||
// userId: 1,
|
||||
// username: 'john',
|
||||
// password: 'changeme',
|
||||
// },
|
||||
// {
|
||||
// userId: 2,
|
||||
// username: 'maria',
|
||||
// password: 'guess',
|
||||
// },
|
||||
// ];
|
||||
|
||||
// async findOne(username: string): Promise<User | undefined> {
|
||||
// return this.users.find(user => user.username === username);
|
||||
// }
|
||||
@ -8,35 +8,58 @@ export class ChatGateway implements OnGatewayInit, OnGatewayConnection, OnGatewa
|
||||
@WebSocketServer()
|
||||
server: Server;
|
||||
|
||||
|
||||
private clients: Record<string, Socket> = {};
|
||||
// private clientsNames: Record<string, Socket[]> = {};
|
||||
private clientsNames: Map<string, string[]> = new Map();
|
||||
// private games: Map<string, Socket[]> = new Map();// Chat en cours, identifiées par un ID
|
||||
|
||||
|
||||
|
||||
afterInit(server: Server)
|
||||
{
|
||||
console.log('ChatGateway initialized');
|
||||
}
|
||||
|
||||
|
||||
handleConnection(client: Socket, ...args: any[])
|
||||
{
|
||||
console.log(`Client connected: ${client.id}`);
|
||||
// console.log(`Client connected: ${args[0].username}`);
|
||||
|
||||
// const clientId = args[0].username;
|
||||
const clientId = client.id;
|
||||
this.clients[clientId] = client;
|
||||
// client.emit('chat:clientId', clientId);
|
||||
console.log(`Total connected clients: ${Object.keys(this.clients).length}`);
|
||||
}
|
||||
|
||||
handleDisconnect(client: Socket)
|
||||
{
|
||||
console.log(`Client want to deco: ${client.id}`);
|
||||
|
||||
// const disconnectedClientId = Object.keys(this.clients).find(clientId => this.clients[clientId] === client);
|
||||
const disconnectedClientId = client.id
|
||||
if (disconnectedClientId)
|
||||
{
|
||||
this.clientsNames.forEach((clientArray, clientName) =>
|
||||
{
|
||||
// clientArray.
|
||||
console.log(`Clients with name ${clientName}:`);
|
||||
console.log(`array= ${clientArray}`)
|
||||
console.log(`lenght= ${clientArray.length}`)
|
||||
clientArray.forEach((targetClient, index) =>
|
||||
{
|
||||
console.log(`index= ${index}`)
|
||||
console.log(`lenght2= ${clientArray.length}`)
|
||||
if (targetClient === disconnectedClientId)
|
||||
{
|
||||
console.log("find it")
|
||||
console.log(`target= ${clientArray[index]}`)
|
||||
// delete this.clientsNames[clientName][index];
|
||||
if (clientArray.length === 1)
|
||||
{
|
||||
console.log("delete true")
|
||||
this.clientsNames.delete(clientName);
|
||||
return
|
||||
}
|
||||
@ -46,11 +69,16 @@ export class ChatGateway implements OnGatewayInit, OnGatewayConnection, OnGatewa
|
||||
this.clientsNames.delete(clientName);
|
||||
this.clientsNames.set(clientName, newArray);
|
||||
}
|
||||
//
|
||||
// this.clientsNames[clientName].delete(index);
|
||||
// else
|
||||
|
||||
return ;
|
||||
}
|
||||
});
|
||||
});
|
||||
delete this.clients[disconnectedClientId];
|
||||
// delete this.clientsNames;
|
||||
console.log(`Client disconnected: ${disconnectedClientId}`);
|
||||
console.log(`Total connected clients: ${Object.keys(this.clients).length}`);
|
||||
}
|
||||
@ -58,14 +86,22 @@ export class ChatGateway implements OnGatewayInit, OnGatewayConnection, OnGatewa
|
||||
|
||||
@SubscribeMessage('connection')
|
||||
connectClient(client: any, payload: any): void {
|
||||
console.log("connect client")
|
||||
console.log(`connect name: ${payload.username}`);
|
||||
if (this.clientsNames.has(payload.username)) {
|
||||
const clientArray = this.clientsNames.get(payload.username);
|
||||
clientArray.push(client.id);
|
||||
console.log("get it")
|
||||
const clientArray = this.clientsNames.get(payload.username); // Retrieve the array
|
||||
clientArray.push(client.id); // Add the new client to the array
|
||||
} else {
|
||||
this.clientsNames.set(payload.username, [client.id]);
|
||||
console.log("create")
|
||||
this.clientsNames.set(payload.username, [client.id]); // Create a new array with the new client as the value
|
||||
}
|
||||
}
|
||||
|
||||
// @SubscribeMessage('socket.io')
|
||||
// socketConnect(client: any, payload: any): void {
|
||||
// console.log("/socket.io")
|
||||
// }
|
||||
|
||||
@SubscribeMessage('ban')
|
||||
banUser(client: any, payload: any): void {
|
||||
@ -77,9 +113,20 @@ banUser(client: any, payload: any): void {
|
||||
const bannedClients = this.clientsNames.get(payload.username);
|
||||
bannedClients.forEach(client => {
|
||||
console.log("Banning client:", client);
|
||||
// Perform ban operation on each client, e.g., emit a 'ban' event
|
||||
console.log("clietn socket=", this.clients[client])
|
||||
this.clients[client].emit('ban', payload);
|
||||
});
|
||||
// console.log("/ban")
|
||||
// console.log("in ban username=", payload.username)
|
||||
// if (!this.clientsNames[payload.username])
|
||||
// {
|
||||
// console.log("no user ??")
|
||||
// return ;
|
||||
// }
|
||||
// this.clientsNames[payload.username].forEach()
|
||||
// console.log("client=", this.clientsNames)
|
||||
// this.clients[payload.username].emit('ban', payload)
|
||||
}
|
||||
|
||||
@SubscribeMessage('mute')
|
||||
@ -91,27 +138,50 @@ muteUser(client: any, payload: any): void {
|
||||
}
|
||||
const mutedClients = this.clientsNames.get(payload.username);
|
||||
mutedClients.forEach(client => {
|
||||
console.log("Banning client:", client);
|
||||
// Perform ban operation on each client, e.g., emit a 'ban' event
|
||||
console.log("clietn socket=", this.clients[client])
|
||||
this.clients[client].emit('mute', payload);
|
||||
});
|
||||
console.log("/mute")
|
||||
}
|
||||
|
||||
|
||||
@SubscribeMessage('sendMessage')
|
||||
handleMessage(client: Socket, payload: any): void {
|
||||
// console.log(`message received: ${payload}`);
|
||||
// console.log(`message sender: ${payload.sender}`);
|
||||
// console.log(`client id: ${client.id}`);
|
||||
// console.log(`conversation ID: ${payload.convId}`);
|
||||
// console.log(`members: ${payload.members}`);
|
||||
|
||||
this.clientsNames.forEach((clientArray, clientName) =>
|
||||
{
|
||||
// console.log(` 5Clients with name ${clientName}:`);
|
||||
if (payload.members.includes(clientName))
|
||||
{
|
||||
clientArray.forEach((targetClient, index) =>
|
||||
{
|
||||
// console.log(`client id: ${client.id}`);
|
||||
// console.log(`target: ${targetClient}`);
|
||||
// console.log(`target id: ${targetClient}`);
|
||||
if (targetClient && targetClient !== client.id)
|
||||
{
|
||||
// console.log("Sending to someone");
|
||||
// console.log(`index= ${index}`);
|
||||
// console.log(`target: ${targetClient}`); // Perform actions on each target client
|
||||
this.clients[targetClient].emit('message', payload)
|
||||
else
|
||||
|
||||
}
|
||||
else {
|
||||
console.log("not sending");
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -13,18 +13,25 @@ async function bootstrap() {
|
||||
cors: {
|
||||
origin: '*',
|
||||
methods: '*',
|
||||
// preflightContinue: false,
|
||||
// optionsSuccessStatus: 204,
|
||||
// credentials: true,
|
||||
allowedHeaders: '*',
|
||||
},
|
||||
});
|
||||
// const app = await NestFactory.create(AppModule);
|
||||
|
||||
const httpServer = app.getHttpServer();
|
||||
const io = new socketio.Server(httpServer);
|
||||
|
||||
io.on('connection', (socket) => {
|
||||
console.log('Client connected:', socket.id);
|
||||
|
||||
// Gestion des événements personnalisés ici
|
||||
socket.on('customEvent', (data) => {
|
||||
console.log('Custom event received:', data);
|
||||
|
||||
// Exemple de réponse à un événement personnalisé
|
||||
socket.emit('customEventResponse', { message: 'Event processed.' });
|
||||
});
|
||||
|
||||
|
||||
@ -1,5 +1,25 @@
|
||||
// import { NestFactory } from '@nestjs/core';
|
||||
// import { AppModule } from './app.module';
|
||||
// import * as cors from 'cors';
|
||||
|
||||
// async function bootstrap() {
|
||||
// const app = await NestFactory.create(AppModule);
|
||||
|
||||
// app.enableCors({
|
||||
// origin: 'http://localhost:8080',
|
||||
// methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
|
||||
// allowedHeaders: ['Content-Type', 'Authorization'],
|
||||
// credentials: true,
|
||||
// });
|
||||
|
||||
// await app.listen(3000);
|
||||
// }
|
||||
// bootstrap();
|
||||
|
||||
import { NestFactory } from '@nestjs/core';
|
||||
import { AppModule } from './app.module';
|
||||
import * as cors from 'cors';
|
||||
import { Server } from 'socket.io';
|
||||
import * as socketio from 'socket.io';
|
||||
import * as dotenv from 'dotenv';
|
||||
|
||||
@ -11,9 +31,13 @@ async function bootstrap() {
|
||||
cors: {
|
||||
origin: '*',
|
||||
methods: '*',
|
||||
// preflightContinue: false,
|
||||
// optionsSuccessStatus: 204,
|
||||
// credentials: true,
|
||||
allowedHeaders: '*',
|
||||
},
|
||||
});
|
||||
// const app = await NestFactory.create(AppModule);
|
||||
|
||||
const httpServer = app.getHttpServer();
|
||||
const io = new socketio.Server(httpServer);
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
/* By: apommier <apommier@student.42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2023/06/19 15:18:38 by apommier #+# #+# */
|
||||
/* Updated: 2023/06/26 07:04:47 by apommier ### ########.fr */
|
||||
/* Updated: 2023/06/23 15:19:12 by apommier ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
@ -28,6 +28,7 @@ export class PongGateway implements OnGatewayInit, OnGatewayConnection, OnGatewa
|
||||
private clients: Record<string, Socket> = {};
|
||||
|
||||
private waitingClients: Set<{ client: Socket, option: number }> = new Set();
|
||||
// private waitingClients: Set<Socket> = new Set(); // Utilisateurs cherchant un match
|
||||
private games: Map<string, Socket[]> = new Map(); // Parties en cours, identifiées par un ID
|
||||
|
||||
afterInit(server: Server)
|
||||
@ -38,31 +39,46 @@ export class PongGateway implements OnGatewayInit, OnGatewayConnection, OnGatewa
|
||||
handleConnection(client: Socket, ...args: any[])
|
||||
{
|
||||
console.log(`Client connected: ${client.id}`);
|
||||
|
||||
const clientId = client.id;
|
||||
this.clients[clientId] = client;
|
||||
// client.emit('pong:clientId', clientId);
|
||||
client.emit('pong:clientId', client.id);
|
||||
|
||||
console.log(`Total connected clients: ${Object.keys(this.clients).length}`);
|
||||
}
|
||||
|
||||
handleDisconnect(client: Socket)
|
||||
{
|
||||
console.log(`Normal disconnected: ${client.id}`);
|
||||
|
||||
this.waitingClients.forEach((item) => {
|
||||
if (item.client === client)
|
||||
this.waitingClients.delete(item);
|
||||
});
|
||||
|
||||
// Delete the socket from the 'games' map
|
||||
this.games.forEach((sockets, gameId) => {
|
||||
const index = sockets.indexOf(client);
|
||||
if (index !== -1)
|
||||
{
|
||||
if (index === 0)
|
||||
{
|
||||
console.log("emit boy1")
|
||||
sockets[1].emit("pong:win")
|
||||
// sockets[0].emit("/win")
|
||||
}
|
||||
else
|
||||
{
|
||||
console.log("emit boy2")
|
||||
sockets[0].emit("pong:win")
|
||||
// sockets[1].emit("/win")
|
||||
}
|
||||
this.games.delete(gameId);
|
||||
delete this.clients[client.id];
|
||||
}
|
||||
})
|
||||
|
||||
console.log(`Total connected clients: ${Object.keys(this.clients).length}`);
|
||||
}
|
||||
|
||||
@ -75,19 +91,29 @@ export class PongGateway implements OnGatewayInit, OnGatewayConnection, OnGatewa
|
||||
if (this.clients.hasOwnProperty(key) && this.clients[key] === client)
|
||||
delete this.clients[key];
|
||||
}
|
||||
// Delete the socket from the 'waitingClients' set
|
||||
this.waitingClients.forEach((item) => {
|
||||
if (item.client === client)
|
||||
this.waitingClients.delete(item);
|
||||
});
|
||||
|
||||
// Delete the socket from the 'games' map
|
||||
this.games.forEach((sockets, gameId) => {
|
||||
const index = sockets.indexOf(client);
|
||||
if (index !== -1)
|
||||
{
|
||||
if (index === 0)
|
||||
{
|
||||
console.log("emit boy1")
|
||||
sockets[1].emit("pong:win")
|
||||
// sockets[0].emit("/win")
|
||||
}
|
||||
else
|
||||
{
|
||||
console.log("emit boy2")
|
||||
sockets[0].emit("pong:win")
|
||||
// sockets[1].emit("/win")
|
||||
}
|
||||
this.games.delete(gameId);
|
||||
delete this.clients[client.id];
|
||||
}
|
||||
@ -103,18 +129,29 @@ export class PongGateway implements OnGatewayInit, OnGatewayConnection, OnGatewa
|
||||
|
||||
@SubscribeMessage('pong:matchmaking')
|
||||
addMatchmaking(client: Socket, payload: any): void {
|
||||
console.log("matchmaking");
|
||||
console.log(payload);
|
||||
console.log(`option= ${payload.option}`);
|
||||
// Add the client to the waitingClients set along with their chosen option
|
||||
this.waitingClients.add({ client, option: payload.option });
|
||||
console.log("Adding client to waiting list...");
|
||||
|
||||
// Filter the waitingClients set to find clients with the same option
|
||||
const matchingClients = Array.from(this.waitingClients).filter(
|
||||
(waitingClient) =>
|
||||
waitingClient.option === payload.option && waitingClient.client !== client
|
||||
);
|
||||
|
||||
|
||||
if (matchingClients.length > 0) {
|
||||
console.log("Creating new game...");
|
||||
const players = [matchingClients[0].client, client];
|
||||
const players = [matchingClients[0].client, client]; // Add the current client to the players array
|
||||
players.forEach((player) => {
|
||||
// this.waitingClients.delete(
|
||||
// this.waitingClients.find(
|
||||
// (waitingClient) => waitingClient.client === player
|
||||
// )
|
||||
// );
|
||||
const matchingClient = Array.from(this.waitingClients).find(
|
||||
(waitingClient) => waitingClient.client === player
|
||||
);
|
||||
@ -128,11 +165,12 @@ addMatchmaking(client: Socket, payload: any): void {
|
||||
player.join(gameId);
|
||||
console.log(`Player ${player.id} joined game ${gameId}`);
|
||||
});
|
||||
payload.gameId = gameId;
|
||||
players.forEach((player) => {
|
||||
player.emit('pong:gameId', payload);
|
||||
player.emit('pong:gameId', gameId);
|
||||
});
|
||||
}
|
||||
|
||||
// console.log(`from: ${client.id}`);
|
||||
}
|
||||
|
||||
|
||||
@ -144,27 +182,48 @@ addMatchmaking(client: Socket, payload: any): void {
|
||||
//========================================================================================================
|
||||
|
||||
|
||||
|
||||
// @SubscribeMessage('pong:invite')
|
||||
// createPrivateGame(client: Socket, payload: any): void {
|
||||
// //after invite accepted ?
|
||||
// //set the two user in a game ?
|
||||
|
||||
// }
|
||||
|
||||
|
||||
@SubscribeMessage('pong:joinParty')
|
||||
joinPrivateParty(client: Socket, payload: any): void {
|
||||
console.log(" join PrivateParty")
|
||||
|
||||
const game = this.games.get(payload.gameId);
|
||||
if (game)
|
||||
{
|
||||
game.push(client);
|
||||
const playersIds = game.map(socket => socket.id);
|
||||
this.clients[playersIds[0]].emit('pong:gameId', payload);
|
||||
this.clients[playersIds[1]].emit('pong:gameId', payload);
|
||||
this.clients[playersIds[0]].emit('pong:gameId', payload.gameId);
|
||||
this.clients[playersIds[1]].emit('pong:gameId', payload.gameId);
|
||||
}
|
||||
else
|
||||
{
|
||||
console.log("emit else")
|
||||
client.emit("pong:win")
|
||||
}
|
||||
// console.log("no game ???")
|
||||
|
||||
}
|
||||
|
||||
|
||||
@SubscribeMessage('pong:privateParty')
|
||||
addPrivateParty(client: Socket, payload: any): void {
|
||||
console.log("addPrivateParty")
|
||||
|
||||
const gameId = uuidv4();
|
||||
const players = [client];
|
||||
this.games.set(gameId, players);
|
||||
console.log("game created private")
|
||||
client.emit('pong:privateId', gameId);
|
||||
//create game
|
||||
//emit private gameId to canvas (don't launch canvas)
|
||||
|
||||
}
|
||||
|
||||
@ -185,6 +244,7 @@ addPrivateParty(client: Socket, payload: any): void {
|
||||
sendPower(client: Socket, payload: any): void
|
||||
{
|
||||
console.log(`from: ${client.id}`);
|
||||
console.log(payload);
|
||||
|
||||
const game = this.games.get(payload.gameId);
|
||||
const playersIds = game.map(socket => socket.id);
|
||||
@ -192,12 +252,14 @@ addPrivateParty(client: Socket, payload: any): void {
|
||||
this.clients[playersIds[1]].emit('pong:power', payload);
|
||||
else if (playersIds[1] === payload.id)
|
||||
this.clients[playersIds[0]].emit('pong:power', payload);
|
||||
console.log("END OF HANDLE");
|
||||
}
|
||||
|
||||
@SubscribeMessage('pong:message')
|
||||
handleMessage(client: Socket, payload: any): void
|
||||
{
|
||||
console.log(`from: ${client.id}`);
|
||||
console.log(payload);
|
||||
|
||||
const game = this.games.get(payload.gameId);
|
||||
const playersIds = game.map(socket => socket.id);
|
||||
@ -211,14 +273,20 @@ addPrivateParty(client: Socket, payload: any): void {
|
||||
if (payload.ballX < payload.width / 2)
|
||||
this.clients[playersIds[0]].emit('pong:info', payload);
|
||||
}
|
||||
console.log("END OF HANDLE");
|
||||
}
|
||||
|
||||
@SubscribeMessage('pong:forced')
|
||||
forcedMessage(client: Socket, payload: any): void
|
||||
{
|
||||
console.log(`from: ${client.id}`);
|
||||
console.log(payload);
|
||||
|
||||
const game = this.games.get(payload.gameId);
|
||||
const playersIds = game.map(socket => socket.id);
|
||||
|
||||
console.log(`id of 0= ${playersIds[0]}`);
|
||||
|
||||
if (playersIds[0] === payload.id)
|
||||
{
|
||||
this.clients[playersIds[1]].emit('pong:info', payload);
|
||||
@ -227,13 +295,20 @@ addPrivateParty(client: Socket, payload: any): void {
|
||||
{
|
||||
this.clients[playersIds[0]].emit('pong:info', payload);
|
||||
}
|
||||
console.log("END OF HANDLE");
|
||||
}
|
||||
|
||||
@SubscribeMessage('pong:paddle')
|
||||
handlePaddle(client: Socket, payload: any): void
|
||||
{
|
||||
console.log(`from: ${client.id}`);
|
||||
console.log(payload);
|
||||
|
||||
const game = this.games.get(payload.gameId);
|
||||
const playersIds = game.map(socket => socket.id);
|
||||
|
||||
console.log(`id of 0= ${playersIds[0]}`);
|
||||
|
||||
if (playersIds[0] === payload.id)
|
||||
{
|
||||
this.clients[playersIds[1]].emit('pong:paddle', payload);
|
||||
@ -242,6 +317,7 @@ addPrivateParty(client: Socket, payload: any): void {
|
||||
{
|
||||
this.clients[playersIds[0]].emit('pong:paddle', payload);
|
||||
}
|
||||
console.log("END OF HANDLE");
|
||||
}
|
||||
|
||||
@SubscribeMessage('pong:point')
|
||||
@ -261,32 +337,21 @@ addPrivateParty(client: Socket, payload: any): void {
|
||||
}
|
||||
}
|
||||
|
||||
@SubscribeMessage('pong:myPoint')
|
||||
handleMyPoint(client: Socket, payload: any): void
|
||||
{
|
||||
const game = this.games.get(payload.gameId);
|
||||
const playersIds = game.map(socket => socket.id);
|
||||
console.log(`id of 0 mypoint= ${playersIds[0]}`);
|
||||
|
||||
if (playersIds[0] === payload.id)
|
||||
this.clients[playersIds[1]].emit('pong:hisPoint', payload);
|
||||
else if (playersIds[1] === payload.id)
|
||||
this.clients[playersIds[0]].emit('pong:hisPoint', payload);
|
||||
}
|
||||
|
||||
@SubscribeMessage('pong:name')
|
||||
getName(client: Socket, payload: any): void
|
||||
{
|
||||
const game = this.games.get(payload.gameId);
|
||||
const playersIds = game.map(socket => socket.id);
|
||||
|
||||
console.log(`name of client= ${payload.name}`);
|
||||
|
||||
if (playersIds[0] === payload.id)
|
||||
{
|
||||
this.clients[playersIds[1]].emit('pong:name', payload);
|
||||
this.clients[playersIds[1]].emit('pong:name', payload.name);
|
||||
}
|
||||
if (playersIds[1] === payload.id)
|
||||
{
|
||||
this.clients[playersIds[0]].emit('pong:name', payload);
|
||||
this.clients[playersIds[0]].emit('pong:name', payload.name);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,11 +1,5 @@
|
||||
REACT_APP_BASE_URL=bess-f2r5s13:8080
|
||||
REACT_APP_SOCKET_URL=bess-f2r5s13
|
||||
REACT_APP_API_SECRET=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
|
||||
REACT_APP_CLIENT_UID=u-s4t2ud-2bd3c5d4f41e776f2e3d5d699d2a8421f6d0c0468ec882516d9ca89b0c211789
|
||||
|
||||
# REACT_APP_BASE_URL=92.143.191.152
|
||||
# REACT_APP_BASE_URL=192.168.1.19
|
||||
REACT_APP_INTRA_URL="https://api.intra.42.fr/oauth/authorize?client_id=u-s4t2ud-2bd3c5d4f41e776f2e3d5d699d2a8421f6d0c0468ec882516d9ca89b0c211789&redirect_uri=http%3A%2F%2Fbess-f2r5s13%3A8080%2Fapi%2Fauth%2Flogin&response_type=code"
|
||||
|
||||
REACT_APP_BASE_URL=localhost:8080
|
||||
REACT_APP_API_SECRET=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
|
||||
REACT_APP_CLIENT_UID=u-s4t2ud-6d29dfa49ba7146577ffd8bf595ae8d9e5aaa3e0a9615df18777171ebf836a41
|
||||
# REACT_APP_BASE_URL=92.143.191.152
|
||||
# REACT_APP_BASE_URL=192.168.1.19
|
||||
@ -16,7 +16,6 @@ export interface User {
|
||||
partyInvite: Record<string, string>[];
|
||||
friends: string[];
|
||||
blocked: string[];
|
||||
sessionNumber: number;
|
||||
}
|
||||
|
||||
export interface Conv {
|
||||
|
||||
@ -22,7 +22,7 @@
|
||||
"web-vitals": "^2.1.4"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "HOST=0.0.0.0 PORT=8081 react-scripts start",
|
||||
"start": "HOST=0.0.0.0 PORT=8001 react-scripts start",
|
||||
"start:dev": "npm run start --watch",
|
||||
"build": "react-scripts build",
|
||||
"test": "react-scripts test",
|
||||
|
||||
BIN
containers/react/public/favicon.ico
Normal file
BIN
containers/react/public/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.8 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 2.5 KiB |
@ -2,13 +2,14 @@
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="shortcut icon" type="image/jpeg" href="/favicon.jpeg"/>
|
||||
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta name="theme-color" content="#000000" />
|
||||
<meta
|
||||
name="description"
|
||||
content="Web site created using create-react-app"
|
||||
/>
|
||||
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
|
||||
<!--
|
||||
manifest.json provides metadata used when your web app is installed on a
|
||||
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
|
||||
@ -23,6 +24,7 @@
|
||||
work correctly both with client-side routing and a non-root public URL.
|
||||
Learn how to configure a non-root public URL by running `npm run build`.
|
||||
-->
|
||||
<title>React App</title>
|
||||
</head>
|
||||
<body>
|
||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||
|
||||
58
containers/react/src/DataBase/DataRank.js
Normal file
58
containers/react/src/DataBase/DataRank.js
Normal file
@ -0,0 +1,58 @@
|
||||
export const Rank = [
|
||||
{
|
||||
rank: '1',
|
||||
name: 'jean',
|
||||
},
|
||||
{
|
||||
rank: '2',
|
||||
name: 'marc',
|
||||
},
|
||||
{
|
||||
rank: '3',
|
||||
name: 'dujardain',
|
||||
},
|
||||
{
|
||||
rank: '4',
|
||||
name: 'mom',
|
||||
},
|
||||
{
|
||||
rank: '5',
|
||||
name: 'fary',
|
||||
},
|
||||
{
|
||||
rank: '6',
|
||||
name: 'aba',
|
||||
},
|
||||
{
|
||||
rank: '7',
|
||||
name: 'preach',
|
||||
},
|
||||
{
|
||||
rank: '1',
|
||||
name: 'jean',
|
||||
},
|
||||
{
|
||||
rank: '2',
|
||||
name: 'marc',
|
||||
},
|
||||
{
|
||||
rank: '3',
|
||||
name: 'dujardain',
|
||||
},
|
||||
{
|
||||
rank: '4',
|
||||
name: 'mom',
|
||||
},
|
||||
{
|
||||
rank: '5',
|
||||
name: 'fary',
|
||||
},
|
||||
{
|
||||
rank: '6',
|
||||
name: 'aba',
|
||||
},
|
||||
{
|
||||
rank: '7',
|
||||
name: 'preach',
|
||||
},
|
||||
]
|
||||
8
containers/react/src/DataBase/DataUserProfile.js
Normal file
8
containers/react/src/DataBase/DataUserProfile.js
Normal file
@ -0,0 +1,8 @@
|
||||
import DefaultPic from '../assets/profile.jpg';
|
||||
|
||||
export const UserProfile = {
|
||||
Pic: DefaultPic,
|
||||
UserName: 'Dipper Ratman',
|
||||
}
|
||||
|
||||
// export default UserProfile
|
||||
37
containers/react/src/DataBase/DummyDBWinLoss.js
Normal file
37
containers/react/src/DataBase/DummyDBWinLoss.js
Normal file
@ -0,0 +1,37 @@
|
||||
export const DBWinLoss = [
|
||||
{
|
||||
title: 'Victory',
|
||||
score: '10 - 6',
|
||||
opponent: 'chef bandit'
|
||||
},
|
||||
{
|
||||
title: 'Defeat',
|
||||
score: '9 - 10',
|
||||
opponent: 'ex tueur'
|
||||
},
|
||||
{
|
||||
title: 'Victory',
|
||||
score: '10 - 0',
|
||||
opponent: 'tueur'
|
||||
},
|
||||
{
|
||||
title: 'Victory',
|
||||
score: '10 - 9',
|
||||
opponent: 'boulanger'
|
||||
},
|
||||
{
|
||||
title: 'Defeat',
|
||||
score: '3 - 10',
|
||||
opponent: 'charcutier'
|
||||
},
|
||||
{
|
||||
title: 'Deafet',
|
||||
score: '9 - 10',
|
||||
opponent: 'preach'
|
||||
},
|
||||
{
|
||||
title: 'Victory',
|
||||
score: '10 - 9',
|
||||
opponent: 'aba'
|
||||
},
|
||||
]
|
||||
@ -23,9 +23,8 @@ interface AlertProps {
|
||||
}
|
||||
|
||||
function GreenAlert ({handleClose, text}: AlertProps){
|
||||
{ setTimeout(handleClose, 1500) }
|
||||
return (
|
||||
|
||||
return(
|
||||
<Backdrop onClick={handleClose}>
|
||||
<motion.div
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
@ -36,10 +35,9 @@ function GreenAlert({ handleClose, text }: AlertProps) {
|
||||
exit="exit"
|
||||
>
|
||||
<AiOutlineCheckCircle/>
|
||||
<div className="text_alert">
|
||||
<h5>{text}</h5>
|
||||
</div>
|
||||
<p>{text}</p>
|
||||
</motion.div>
|
||||
{setTimeout(handleClose, 1500)}
|
||||
</Backdrop>
|
||||
)
|
||||
}
|
||||
|
||||
@ -23,7 +23,6 @@ interface AlertProps {
|
||||
}
|
||||
|
||||
function RedAlert ({handleClose, text}: AlertProps) {
|
||||
{setTimeout(handleClose, 1500)}
|
||||
return(
|
||||
<Backdrop onClick={handleClose}>
|
||||
<motion.div
|
||||
@ -35,10 +34,9 @@ function RedAlert ({handleClose, text}: AlertProps) {
|
||||
exit="exit"
|
||||
>
|
||||
<BiErrorCircle/>
|
||||
<div className="text_alert">
|
||||
<h5>{text}</h5>
|
||||
</div>
|
||||
<p>{text}</p>
|
||||
</motion.div>
|
||||
{setTimeout(handleClose, 1500)}
|
||||
</Backdrop>
|
||||
)
|
||||
}
|
||||
|
||||
@ -25,7 +25,6 @@ interface AlertProps {
|
||||
}
|
||||
|
||||
function YellowAlert ({handleClose, text, icon}: AlertProps) {
|
||||
{ setTimeout(handleClose, 3000) }
|
||||
return(
|
||||
<Backdrop onClick={handleClose}>
|
||||
<motion.div
|
||||
@ -52,10 +51,9 @@ function YellowAlert({ handleClose, text, icon }: AlertProps) {
|
||||
<GiWingedSword/>
|
||||
):("")}
|
||||
|
||||
<div className="text_alert">
|
||||
<h5>{text}</h5>
|
||||
</div>
|
||||
</motion.div>
|
||||
{setTimeout(handleClose, 3000)}
|
||||
</Backdrop>
|
||||
)
|
||||
}
|
||||
|
||||
26
containers/react/src/components/AnimatedRoute.tsx
Normal file
26
containers/react/src/components/AnimatedRoute.tsx
Normal file
@ -0,0 +1,26 @@
|
||||
import React from "react";
|
||||
import {Routes, Route} from 'react-router-dom';
|
||||
import Home from "../pages/Home.jsx";
|
||||
import PlayButton from "./Game/PlayButton.tsx";
|
||||
import Field from "../pages/Field";
|
||||
import Login42 from "../pages/Login42.js";
|
||||
import Messages from "../pages/Messages.jsx";
|
||||
import { useLocation } from "react-router-dom";
|
||||
import {AnimatePresence} from "framer-motion";
|
||||
|
||||
function AnimatedRoute () {
|
||||
const location = useLocation();
|
||||
return (
|
||||
<AnimatePresence>
|
||||
<Routes location={location} key={location.pathname}>
|
||||
<Route path="/" element={<Home/>}/>
|
||||
<Route path="/game" element={<PlayButton />}/>
|
||||
<Route path="/pong/play" element={<Field />}/>
|
||||
<Route path="/login42" element={<Login42 />}/>
|
||||
<Route path="/messages" element={<Messages />}/>
|
||||
</Routes>
|
||||
</AnimatePresence>
|
||||
)
|
||||
}
|
||||
|
||||
export default AnimatedRoute
|
||||
@ -1,11 +1,12 @@
|
||||
import React, { useEffect } from "react";
|
||||
import React from "react";
|
||||
import {Routes, Route, Navigate} from 'react-router-dom';
|
||||
import HomeLogin from "../pages/LoginButton.tsx";
|
||||
import HomeLogin from "../pages/Home.js";
|
||||
|
||||
import Home from "../pages/Home.tsx";
|
||||
|
||||
import PlayButton from "./Game/PlayButton.tsx";
|
||||
import Field from "../pages/Field.tsx";
|
||||
import Login42 from "../pages/Login42.tsx";
|
||||
import Messages from "../pages/Messages.tsx";
|
||||
import QrCode from '../pages/QrCode.tsx'
|
||||
import { useLocation } from "react-router-dom";
|
||||
@ -18,46 +19,20 @@ import DoubleAuth from "../pages/2fa.tsx";
|
||||
import Game from "../pages/Game.tsx";
|
||||
import Social from "./Social/Social.tsx";
|
||||
import Logout from "./Profile/Logout.tsx";
|
||||
import api from "../script/axiosApi.tsx"
|
||||
|
||||
|
||||
function AnimatedRoute () {
|
||||
useEffect(() => {
|
||||
const handleBeforeUnload = async (event: { preventDefault: () => void; returnValue: string; }) => {
|
||||
console.log("git ")
|
||||
if (!localStorage.getItem('token'))
|
||||
return;
|
||||
try {
|
||||
await api.post("/quit");
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
}
|
||||
};
|
||||
|
||||
const handleLoad = async () => {
|
||||
if (!localStorage.getItem('token'))
|
||||
return;
|
||||
try {
|
||||
await api.post("/addSession");
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
}
|
||||
};
|
||||
|
||||
handleLoad();
|
||||
window.addEventListener('beforeunload', handleBeforeUnload);
|
||||
return () => {
|
||||
window.removeEventListener('beforeunload', handleBeforeUnload);
|
||||
};
|
||||
}, []);
|
||||
|
||||
// const location = useLocation();
|
||||
const location = useLocation();
|
||||
if (!localStorage.getItem('token')) {
|
||||
if (!localStorage.getItem('token'))
|
||||
{
|
||||
return (
|
||||
<AnimatePresence>
|
||||
<Routes location={location} key={location.pathname}>
|
||||
<Route path="/" element={<HomeLogin/>}/>
|
||||
<Route path="/token" element={<SuccessToken />}/>
|
||||
|
||||
{/* <Route path="/404" element={<HomeLogin/>} /> */}
|
||||
{/* <Route path="*" element={<Navigate to="/404" />} /> */}
|
||||
</Routes>
|
||||
</AnimatePresence>
|
||||
)
|
||||
@ -66,18 +41,26 @@ function AnimatedRoute() {
|
||||
return (
|
||||
<AnimatePresence>
|
||||
<Routes location={location} key={location.pathname}>
|
||||
|
||||
{/* <Route path="/login" element={<HomeLogin/>}/> */}
|
||||
<Route path="/" element={<Home/>}/>
|
||||
<Route path="/profile" element={<Home/>}/>
|
||||
<Route path="/profile/:username" element={<Home/>}/>
|
||||
<Route path="/qr" element={<QrCode/>}/>
|
||||
|
||||
<Route path="/2fa" element={<DoubleAuth/>}/>
|
||||
<Route path="/Social" element={<Social/>}/>
|
||||
|
||||
<Route path="/token" element={<SuccessToken />}/>
|
||||
<Route path="/game" element={<PlayButton />}/>
|
||||
<Route path="/pong" element={<Game />}/>
|
||||
<Route path="/pong/play" element={<Field />}/>
|
||||
{/* <Route path="/profile" element={<PlayButton />}/> */}
|
||||
|
||||
<Route path="/login42" element={<Login42 />}/>
|
||||
<Route path="/logout" element={<Logout />}/>
|
||||
<Route path="/messages" element={<Messages />}/>
|
||||
|
||||
<Route path="/404" element={<PageNotFound />} />
|
||||
<Route path="*" element={<Navigate to="/404" />} />
|
||||
</Routes>
|
||||
|
||||
@ -1,10 +1,16 @@
|
||||
import React from 'react';
|
||||
import '../../styles/field.css';
|
||||
// import { useHistory } from 'react-router-dom';
|
||||
import { useNavigate } from "react-router-dom";
|
||||
|
||||
function PlayButton() {
|
||||
|
||||
const history = useNavigate();
|
||||
|
||||
// const handleButtonClick = () => {
|
||||
// let path = `play`;
|
||||
// history(path);
|
||||
// };
|
||||
const handleButtonClick = () => {
|
||||
let path = `play?`;
|
||||
|
||||
@ -13,11 +19,17 @@ function PlayButton() {
|
||||
path += 'superpower=true&';
|
||||
}
|
||||
|
||||
const obstacleCheckbox = document.querySelector<HTMLInputElement>('input[value="obstacle"]');
|
||||
if (obstacleCheckbox && obstacleCheckbox.checked) {
|
||||
path += 'obstacle=true&';
|
||||
}
|
||||
|
||||
const speedCheckbox = document.querySelector<HTMLInputElement>('input[value="speed"]');
|
||||
if (speedCheckbox && speedCheckbox.checked) {
|
||||
path += 'speed=true&';
|
||||
}
|
||||
|
||||
// Remove the trailing '&' character
|
||||
path = path.slice(0, -1);
|
||||
console.log(path)
|
||||
history(path);
|
||||
@ -28,8 +40,9 @@ function PlayButton() {
|
||||
<button onClick={handleButtonClick} className="playButton">Play</button>
|
||||
{/* !buttonClicked && <button onClick={handleButtonClick}>Draw on Canvas</button> */}
|
||||
<div className='checkbox'>
|
||||
<p><input className="inside_checkbox" type="checkbox" value="superpower"/> Super Power <br/> ( w = wall power ) </p>
|
||||
<p><input className="inside_checkbox" type="checkbox" value="speed"/> Faster and Faster </p>
|
||||
<p><input type="checkbox" value="superpower"/> Super Power </p>
|
||||
<p><input type="checkbox" value="obstacle"/> Obstacle </p>
|
||||
<p><input type="checkbox" value="speed"/> Faster and Faster </p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
/* By: apommier <apommier@student.42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2023/06/09 08:49:24 by apommier #+# #+# */
|
||||
/* Updated: 2023/06/23 17:16:40 by apommier ### ########.fr */
|
||||
/* Updated: 2023/06/20 13:06:35 by apommier ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
@ -41,7 +41,7 @@ function Rank({user, index}: RankProps){
|
||||
};
|
||||
|
||||
fetchProfilePicture();
|
||||
}, [])
|
||||
})
|
||||
|
||||
// console.log(index);
|
||||
return (
|
||||
|
||||
@ -21,15 +21,18 @@ function Ranking(){
|
||||
// setFriends(tmpFriends.data);
|
||||
// return tmpUser;
|
||||
// console.log(`user= ${tmpUser.data.username}`);
|
||||
setIsLoading(false);
|
||||
setIsLoading(false)
|
||||
|
||||
}
|
||||
catch(err){
|
||||
console.log(err);
|
||||
}
|
||||
};
|
||||
getRanking();
|
||||
}, []);
|
||||
console.log(`ranking after= ${ranking}`);
|
||||
|
||||
}, [])
|
||||
|
||||
console.log(`ranking after= ${ranking}`)
|
||||
|
||||
return (
|
||||
<div>
|
||||
|
||||
@ -2,12 +2,14 @@ import React, { useState, useEffect, useRef } from "react";
|
||||
import io, { Socket } from 'socket.io-client';
|
||||
import '../../styles/Messages.css'
|
||||
import styled from "styled-components";
|
||||
import DefaultPic from '../../assets/profile.jpg'
|
||||
import api from '../../script/axiosApi.tsx';
|
||||
import { motion , AnimatePresence} from "framer-motion";
|
||||
import Modal from "./Modal.tsx";
|
||||
import GameModal from "./GameModal.tsx";
|
||||
|
||||
import Message from "./Message.tsx"
|
||||
// import Input from "./Input";
|
||||
|
||||
//react icons
|
||||
import { TbSend } from 'react-icons/tb';
|
||||
@ -15,15 +17,16 @@ import { ImBlocked } from 'react-icons/im';
|
||||
import { MdOutlineGroupAdd } from 'react-icons/md';
|
||||
import { GrAdd } from 'react-icons/gr';
|
||||
import { RiListSettingsLine } from 'react-icons/ri'
|
||||
import { HiChatBubbleLeft } from 'react-icons/hi2'
|
||||
|
||||
// import { Rank } from "../../DataBase/DataRank";
|
||||
import GreenAlert from "../Alert/GreenAlert.tsx";
|
||||
import RedAlert from "../Alert/RedAlert.tsx";
|
||||
import YellowAlert from "../Alert/YellowAlert";
|
||||
import ModalSetting from "./ModalSetting.tsx";
|
||||
import PartyInvite from "./PartyInvite.tsx";
|
||||
|
||||
// import {User, Conv, Message} from "../../../interfaces.tsx"
|
||||
import {User, Conv} from "../../../interfaces.tsx"
|
||||
import { IoLogoOctocat } from "react-icons/io5";
|
||||
|
||||
const TouchDiv = styled.div`
|
||||
margin-left: 10px;
|
||||
@ -54,6 +57,11 @@ const UserChat = styled.div `
|
||||
}
|
||||
`
|
||||
|
||||
// const SideSpan = styled.span`
|
||||
// font-size: 18px;
|
||||
// font-weight: 500;
|
||||
// `
|
||||
|
||||
const SideP = styled.p`
|
||||
font-size: 14px;
|
||||
color: lightgray;
|
||||
@ -82,11 +90,15 @@ function Chats(){
|
||||
const [user, setUser] = useState<User>();
|
||||
const [currentChat, setCurrentChat] = useState<Conv>(); // false is good?
|
||||
const [isAdmin, setIsAdmin] = useState<boolean>(false); // false is good?
|
||||
// const [currentChat, setCurrentChat] = useState(false); // false is good?
|
||||
const [messages, setMessage] = useState<MessageProps[]>([]);
|
||||
const [newMessages, setNewMessage] = useState("");
|
||||
const [incomingMessage, setIncomingMessage] = useState<MessageProps>();
|
||||
|
||||
// let socket: Socket;
|
||||
const socket = useRef<Socket | null>(null);
|
||||
// const socket = Socket<DefaultEventsMap, DefaultEventsMap> | null
|
||||
// socket = useRef( useRef<SocketIOClient.Socket | null>(null));
|
||||
|
||||
|
||||
useEffect(()=> {
|
||||
@ -100,38 +112,47 @@ function Chats(){
|
||||
|
||||
console.log(convs);
|
||||
|
||||
// console.log("invite data use effect= ", tmpInvite.data);
|
||||
setPartyInvite(tmpInvite.data);
|
||||
setUser(tmpUser.data);
|
||||
setConversation(convs.data);
|
||||
setUsers(tmpUsers.data);
|
||||
|
||||
socket.current = io('http://' + process.env.REACT_APP_SOCKET_URL + ':4001', { transports: ['polling'] });
|
||||
// console.log(`connection....`);
|
||||
socket.current = io('http://' + process.env.REACT_APP_BASE_URL + ':4001', { transports: ['polling'] });
|
||||
// console.log(`connection done`);
|
||||
socket.current.emit('connection', {username: tmpUser.data.username})
|
||||
socket.current.on('message', (data) => { //data should be a message ?)
|
||||
setIncomingMessage(data);
|
||||
});
|
||||
|
||||
socket.current.on('ban', (data) => {
|
||||
// setIncomingMessage(data);
|
||||
console.log("banned hehe");
|
||||
window.location.reload()
|
||||
});
|
||||
|
||||
// socket.current.on('mute', (data) => {
|
||||
// console.log("muted hehe");
|
||||
// //set mute var to true and do nothing
|
||||
// });
|
||||
socket.current.on('mute', (data) => {
|
||||
console.log("muted hehe");
|
||||
//set mute var to true and do nothing
|
||||
});
|
||||
|
||||
setIsLoading(false)
|
||||
|
||||
}
|
||||
catch(err){
|
||||
console.log("ERRORRRRR")
|
||||
console.log(err);
|
||||
}
|
||||
};
|
||||
getConv();
|
||||
|
||||
return () => {
|
||||
console.log("Cleanup");
|
||||
if (socket.current)
|
||||
socket.current.disconnect();
|
||||
// cleanup(); // Call the cleanup function to stop the ongoing process or perform necessary cleanup tasks
|
||||
// cleanup();
|
||||
};
|
||||
|
||||
}, [])
|
||||
@ -139,11 +160,14 @@ function Chats(){
|
||||
useEffect(()=> {
|
||||
|
||||
const updateChat = async ()=> {
|
||||
// if (currentChat)
|
||||
// console.log(currentChat.id)
|
||||
if (currentChat)
|
||||
{
|
||||
|
||||
try {
|
||||
const res = await api.post("/isAdmin", {convId: currentChat.id})
|
||||
console.log("isadmin= ", res.data)
|
||||
setIsAdmin(res.data);
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
@ -151,8 +175,14 @@ function Chats(){
|
||||
}
|
||||
// console.log(`result1 = ${currentChat.id !== incomingMessage.convId}`)
|
||||
if (currentChat && incomingMessage && currentChat.id === incomingMessage.convId)
|
||||
{
|
||||
console.log("incoming meaasge=",incomingMessage)
|
||||
// if (user && !user.blocked.find(incomingMessage.sender))
|
||||
// setMessage((prev) => [...prev, incomingMessage, key: incomingMessage.id]);
|
||||
// setMessage((prev) => [...prev, { ...incomingMessage, key: incomingMessage.id }]);
|
||||
setMessage((prev) => [...prev, incomingMessage]);
|
||||
}
|
||||
}
|
||||
updateChat();
|
||||
|
||||
}, [incomingMessage, currentChat])
|
||||
@ -166,6 +196,7 @@ function Chats(){
|
||||
|
||||
try {
|
||||
const res = await api.post('/getMessage', data);
|
||||
console.log("message of conv=", res.data)
|
||||
setMessage(res.data);
|
||||
} catch(err) {
|
||||
|
||||
@ -174,8 +205,11 @@ function Chats(){
|
||||
getMessage();
|
||||
}, [currentChat]);
|
||||
|
||||
const handleSubmit = async (e: { key?: any; preventDefault: any; })=>{
|
||||
const handleSubmit = async (e: { preventDefault: () => void; })=>{
|
||||
e.preventDefault();
|
||||
// console.log(`e= ${e.key}`)
|
||||
// console.log(`name= ${user.username}`)
|
||||
// let message;
|
||||
if (!user || !currentChat)
|
||||
return ;
|
||||
const message = {
|
||||
@ -187,8 +221,13 @@ function Chats(){
|
||||
};
|
||||
try{
|
||||
const allowed = await api.post('/allowed', {convId: currentChat.id});
|
||||
console.log("convid:", currentChat.id);
|
||||
if (!allowed.data)
|
||||
{
|
||||
console.log("muted or banned");
|
||||
return ;
|
||||
}
|
||||
console.log("not muted or banned");
|
||||
const res = await api.post('/message', message);
|
||||
const convMember = await api.post('/member', message);
|
||||
message.members = convMember.data.members;
|
||||
@ -203,15 +242,39 @@ function Chats(){
|
||||
}
|
||||
}
|
||||
|
||||
const handleKeyPress = async (e: { key?: any; preventDefault: () => void; })=> {
|
||||
const handleKeyPress = async (e: { key: string; })=> {
|
||||
// console.log(`e in press= ${e.key}`)
|
||||
if (e.key !== "Enter")
|
||||
return ;
|
||||
handleSubmit(e);
|
||||
// console.log(`name= ${user.username}`)
|
||||
if (!user || !currentChat)
|
||||
return ;
|
||||
const message = {
|
||||
sender: user.username,
|
||||
text: newMessages,
|
||||
convId: currentChat.id,
|
||||
members: null,
|
||||
id: null,
|
||||
};
|
||||
try{
|
||||
const res = await api.post('/message', message);
|
||||
const convMember = await api.post('/member', message);
|
||||
message.members = convMember.data.members;
|
||||
message.id = res.data.id
|
||||
setMessage([...messages, res.data]);
|
||||
setNewMessage("");
|
||||
if (socket.current)
|
||||
socket.current.emit('sendMessage', message);
|
||||
}
|
||||
catch(err){
|
||||
console.log(err)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
const [friend, setFriend] = useState("");
|
||||
// const [modalOpen, setModalOpen] = useState(false);
|
||||
const [addFriend, setAddFriend] = useState(false);
|
||||
const [block, setBlock] = useState(false);
|
||||
|
||||
@ -226,8 +289,6 @@ function Chats(){
|
||||
const [selectTags, setSelectTag] = useState([{ id: 1, selectedOption: ''}]);
|
||||
const [users, setUsers] = useState<User[]>([]);
|
||||
|
||||
const [unblock, setUnblock] = useState(false);
|
||||
const closeUnblock = () => setUnblock(false);
|
||||
|
||||
const openNewGameModal = () => {
|
||||
setNewGameModalOpen(true);
|
||||
@ -245,16 +306,26 @@ function Chats(){
|
||||
setNewConversationModalOpen(false);
|
||||
};
|
||||
|
||||
// const close = () => setModalOpen(false);
|
||||
// const open = () => setModalOpen(true);
|
||||
// const closeAddFriend = () => setAddFriend(false);
|
||||
// const closeBlock = () => setBlock(false);
|
||||
const closeSetting = () => setSetting(false);
|
||||
|
||||
|
||||
// const closeAddFriend = () => setAddFriend(false);
|
||||
// const closeBlock = () => setBlock(false);
|
||||
|
||||
|
||||
const handleFriend = (event: { target: { value: React.SetStateAction<string>; }; }) => {
|
||||
setFriend(event.target.value);
|
||||
};
|
||||
|
||||
const handleAddFriend = async () => {
|
||||
try{
|
||||
console.log("friend= ", friend);
|
||||
const res = await api.post("/invite", {username: friend})
|
||||
// if (res.data === 1)
|
||||
// console.log("res in friend= ", res)
|
||||
console.log("res in friend= ", res.data)
|
||||
if(res.data === 1)
|
||||
{
|
||||
@ -270,17 +341,14 @@ function Chats(){
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
const handleBlockFriend = async () => {
|
||||
try{
|
||||
const res = await api.post("/block", {username: friend})
|
||||
// if(1)
|
||||
if (res.data === 2)
|
||||
setUnblock(true);
|
||||
if (res.data === 1)
|
||||
{
|
||||
setBlock(true);
|
||||
setAddFriend(false);
|
||||
setAddFriend(false); // Reset addFriend state
|
||||
setShowAddFriendAlert(false);
|
||||
}
|
||||
else
|
||||
@ -303,7 +371,6 @@ function Chats(){
|
||||
|
||||
const handleOptionChange = (selectId: number, selectedOption: string) => {
|
||||
console.log("selected Option=", selectedOption)
|
||||
setFriend(selectedOption);
|
||||
setSelectTag((prevTags) =>
|
||||
prevTags.map((tag) =>
|
||||
tag.id === selectId ? { ...tag, selectedOption } : tag
|
||||
@ -322,14 +389,58 @@ function Chats(){
|
||||
<div className="chat">
|
||||
|
||||
<div className='navbar'>
|
||||
<IoLogoOctocat className="catchat"/>
|
||||
<img src={DefaultPic} alt="profile" className="pic"/>
|
||||
<span>
|
||||
{isLoading || !user ? (
|
||||
<h4>Loading...</h4>
|
||||
) : (
|
||||
<h2>Chat</h2>
|
||||
<h4>{user.nickname}</h4>
|
||||
)}
|
||||
</span>
|
||||
{/* <div className="end">
|
||||
<input className="lookForFriends" type="text" value={friend} onChange={handleFriend}/>
|
||||
<TouchDiv>
|
||||
<motion.div
|
||||
onClick={() => (addFriend ? setAddFriend(false) : setAddFriend(true))}>
|
||||
<MdOutlineGroupAdd/>
|
||||
</motion.div>
|
||||
<AnimatePresence
|
||||
initial={false}
|
||||
onExitComplete={() => null}
|
||||
>
|
||||
{addFriend && <GreenAlert handleClose={closeAddFriend} text={friend + " was successfuly added"}/>}
|
||||
</AnimatePresence>
|
||||
</TouchDiv>
|
||||
<TouchDiv>
|
||||
<motion.div
|
||||
onClick={() => (block ? setBlock(false) : setBlock(true))}
|
||||
>
|
||||
<ImBlocked/>
|
||||
<AnimatePresence
|
||||
initial={false}
|
||||
onExitComplete={() => null}
|
||||
>
|
||||
{block && <RedAlert handleClose={closeBlock} text={friend + " was successfuly blocked"}/>}
|
||||
</AnimatePresence>
|
||||
</motion.div>
|
||||
</TouchDiv>
|
||||
{currentChat ? (
|
||||
|
||||
<TouchDiv>
|
||||
<motion.div
|
||||
onClick={() => (setting ? setSetting(false) : setSetting(true))}
|
||||
>
|
||||
<RiListSettingsLine/>
|
||||
<AnimatePresence
|
||||
initial={false}
|
||||
onExitComplete={() => null}
|
||||
>
|
||||
{setting && <ModalSetting handleClose={closeSetting} convId={currentChat.id}/>}
|
||||
</AnimatePresence>
|
||||
</motion.div>
|
||||
</TouchDiv>
|
||||
):("")}
|
||||
</div> */}
|
||||
|
||||
<div className="end">
|
||||
{selectTags.map((selectTag) => (
|
||||
@ -340,11 +451,11 @@ function Chats(){
|
||||
onChange={(a) => handleOptionChange(selectTag.id, a.target.value)}
|
||||
>
|
||||
<option value="">{
|
||||
selectTag.selectedOption ? selectTag.selectedOption : "Select a user"
|
||||
selectTag.selectedOption ? selectTag.selectedOption : "Select an option"
|
||||
}</option>
|
||||
{users.filter((item) => !selectTags.some((tag) => tag.selectedOption === item.username)).map((item, index) => (
|
||||
<option key={index} value={item.username}>
|
||||
{item.nickname}
|
||||
{item.username}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
@ -352,7 +463,7 @@ function Chats(){
|
||||
))}
|
||||
<TouchDiv>
|
||||
<motion.div onClick={handleAddFriend}>
|
||||
<MdOutlineGroupAdd className="catchat"/>
|
||||
<MdOutlineGroupAdd />
|
||||
</motion.div>
|
||||
<AnimatePresence initial={false} onExitComplete={() => null}>
|
||||
{showAddFriendAlert && addFriend && (
|
||||
@ -365,7 +476,7 @@ function Chats(){
|
||||
</TouchDiv>
|
||||
<TouchDiv>
|
||||
<motion.div onClick={handleBlockFriend}>
|
||||
<ImBlocked className="block"/>
|
||||
<ImBlocked />
|
||||
</motion.div>
|
||||
<AnimatePresence initial={false} onExitComplete={() => null}>
|
||||
{showBlockAlert && block && (
|
||||
@ -374,9 +485,6 @@ function Chats(){
|
||||
{showBlockAlert && !block && (
|
||||
<RedAlert handleClose={closeBlock} text={friend + ' was not found'} />
|
||||
)}
|
||||
{unblock ? (
|
||||
<GreenAlert handleClose={closeUnblock} text={friend + ' was unblocked'} />
|
||||
):("")}
|
||||
</AnimatePresence>
|
||||
</TouchDiv>
|
||||
{currentChat && isAdmin ? (
|
||||
@ -384,7 +492,7 @@ function Chats(){
|
||||
<motion.div
|
||||
onClick={() => (setting ? setSetting(false) : setSetting(true))}
|
||||
>
|
||||
<RiListSettingsLine className="block"/>
|
||||
<RiListSettingsLine/>
|
||||
<AnimatePresence
|
||||
initial={false}
|
||||
onExitComplete={() => null}
|
||||
@ -419,6 +527,13 @@ function Chats(){
|
||||
)}
|
||||
</UserChat>
|
||||
|
||||
|
||||
{/* {partyInvite.map((c) => {
|
||||
return (
|
||||
|
||||
)})
|
||||
} */}
|
||||
|
||||
{partyInvite.map( i =>(
|
||||
<PartyInvite currentInvite={i}/>
|
||||
))}
|
||||
@ -428,9 +543,9 @@ function Chats(){
|
||||
<div key={index}
|
||||
onClick={() => setCurrentChat(c)}>
|
||||
<UserChat>
|
||||
<HiChatBubbleLeft className="catchat"/>
|
||||
<img className="pic-user" src={DefaultPic} alt="User" />
|
||||
<div className="infoSideBar">
|
||||
<h2>{c.name}</h2>
|
||||
<span>{c.name}</span>
|
||||
{/* <SideP>Desc?</SideP> */}
|
||||
</div>
|
||||
</UserChat>
|
||||
@ -448,6 +563,7 @@ function Chats(){
|
||||
<Message key={m.id} message= {m} own={m.sender === user.username}/>
|
||||
))}
|
||||
</div>
|
||||
{/* <Input/> */}
|
||||
<div className="input">
|
||||
<input
|
||||
onKeyDown={handleKeyPress}
|
||||
@ -469,6 +585,7 @@ function Chats(){
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
// </div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@ -79,6 +79,10 @@ const GameModal = ({ handleClose }: ModalGame) => {
|
||||
path += 'superpower=true&';
|
||||
}
|
||||
|
||||
const obstacleCheckbox = document.querySelector<HTMLInputElement>('input[value="obstacle"]');
|
||||
if (obstacleCheckbox && obstacleCheckbox.checked) {
|
||||
path += 'obstacle=true&';
|
||||
}
|
||||
|
||||
const speedCheckbox = document.querySelector<HTMLInputElement>('input[value="speed"]');
|
||||
if (speedCheckbox && speedCheckbox.checked) {
|
||||
@ -118,7 +122,7 @@ const GameModal = ({ handleClose }: ModalGame) => {
|
||||
<option value="">Select a user</option>
|
||||
{users.map((user: User) => (
|
||||
<option key={user.id} value={user.username}>
|
||||
{user.nickname}
|
||||
{user.username}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
@ -128,9 +132,10 @@ const GameModal = ({ handleClose }: ModalGame) => {
|
||||
{/* <button onClick={handleButtonClick}>Draw on Canvas</button> */}
|
||||
<div className='checkbox'>
|
||||
<p><input type="checkbox" value="superpower"/> Super Power </p>
|
||||
<p><input type="checkbox" value="obstacle"/> Obstacle </p>
|
||||
<p><input type="checkbox" value="speed"/> Faster and Faster </p>
|
||||
</div>
|
||||
<button className="playInvite" onClick={handleButtonClick} >Play</button>
|
||||
<button className="submit" onClick={handleButtonClick} >Play</button>
|
||||
{/* <button className="submit" onClick={handleClose}>Cancel</button> */}
|
||||
</div>
|
||||
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
/* By: apommier <apommier@student.42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2023/06/01 18:24:46 by apommier #+# #+# */
|
||||
/* Updated: 2023/06/25 23:24:46 by apommier ### ########.fr */
|
||||
/* Updated: 2023/06/20 19:05:10 by apommier ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
@ -23,9 +23,9 @@ import React from "react";
|
||||
const MeStyleP = styled.p`
|
||||
background-color: #5843e4;
|
||||
padding 10px 20px;
|
||||
border-radius 10px;
|
||||
border-radius 10px 0px 10px 10px;
|
||||
color: white;
|
||||
margin: 10px;
|
||||
margin-right: 20px;
|
||||
`
|
||||
|
||||
interface MessageMeProps {
|
||||
@ -42,16 +42,15 @@ function MessageMe({message, own}: MessageMeProps){
|
||||
const [user, setUser] = useState<User>();
|
||||
const scrollRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
// console.log("Message eher")
|
||||
|
||||
useEffect(() => {
|
||||
if (scrollRef.current)
|
||||
{
|
||||
scrollRef.current.scrollIntoView({ behavior: "smooth"});
|
||||
}})
|
||||
useEffect(() => {
|
||||
scrollRef.current.scrollIntoView({ behavior: "smooth",})
|
||||
}
|
||||
const fetchProfilePicture = async () => {
|
||||
try {
|
||||
console.log("useEffect message")
|
||||
// const user = await api.get("/profile");
|
||||
const tmpSender = await api.post("/user", {username: message.sender})
|
||||
const tmpConv = await api.post("/convId", {convId: message.convId})
|
||||
@ -69,7 +68,7 @@ function MessageMe({message, own}: MessageMeProps){
|
||||
}
|
||||
};
|
||||
fetchProfilePicture();
|
||||
}, []);
|
||||
}, [])
|
||||
|
||||
const handleButtonClick = () => {
|
||||
if (!sender)
|
||||
@ -82,37 +81,23 @@ function MessageMe({message, own}: MessageMeProps){
|
||||
window.location.reload();
|
||||
};
|
||||
|
||||
// const isAllowed = async () => {
|
||||
// const ret = await api.post("/allowed", {convId: message.convId});
|
||||
// return ret.data;
|
||||
// }
|
||||
|
||||
if (!user || !sender || !conv)
|
||||
return (<></>);
|
||||
// console.log("result includes=", conv.banned.includes(user.username))
|
||||
// console.log("result includes=", conv.blocked.includes(user.username))
|
||||
// const conv2: Conv = getConv();
|
||||
// if (!conv)
|
||||
// isAllowed().then((ret: number) => {
|
||||
// if (!ret)
|
||||
// {
|
||||
// console.log("return not allowed");
|
||||
// return ;
|
||||
// }
|
||||
// // Use the resolved currentConv here
|
||||
// });
|
||||
|
||||
if (user.blocked && user.blocked.includes(message.sender))
|
||||
return (<></>);
|
||||
else if (conv.banned && conv.banned.includes(user.username))
|
||||
return (<></>);
|
||||
else if (conv.muted && conv.muted.includes(user.username))
|
||||
{
|
||||
// console.log("muted00")
|
||||
// console.log("return")
|
||||
return (<></>);
|
||||
}
|
||||
// console.log("result includes=", conv.banned.includes(user.username))
|
||||
// console.log("result includes=", conv.blocked.includes(user.username))
|
||||
if (user.blocked && user.blocked.includes(message.sender))
|
||||
return (<></>);
|
||||
// else if (conv.banned && conv.banned.includes(user.username))
|
||||
// {
|
||||
// console.log("return2")
|
||||
// return (<></>);
|
||||
// }
|
||||
// console.log("noy return")
|
||||
// if (user.blocked.includes(message.sender))/
|
||||
console.log("no return message good");
|
||||
|
||||
return (
|
||||
<div className={own ? "meMessage" : "youMessage"} ref={scrollRef}>
|
||||
<div>
|
||||
|
||||
@ -7,7 +7,6 @@ import { GrAdd } from "react-icons/gr";
|
||||
import { Link } from "react-router-dom";
|
||||
import api from "../../script/axiosApi.tsx";
|
||||
import React from "react";
|
||||
import {User, Conv} from "../../../interfaces.tsx"
|
||||
|
||||
const dropIn = {
|
||||
hidden:{y:"-100vh",
|
||||
@ -22,19 +21,16 @@ const dropIn = {
|
||||
}},
|
||||
exit:{y: "100vh",
|
||||
opacity: 0,},
|
||||
|
||||
};
|
||||
|
||||
interface ModalProps {
|
||||
handleClose: Function,
|
||||
}
|
||||
|
||||
const Modal = ({handleClose}: ModalProps) => {
|
||||
const Modal = ({handleClose}) => {
|
||||
// const [multi, setMulti] = useState(false);
|
||||
const [selectTags, setSelectTag] = useState([{ id: 1, selectedOption: ''}]);
|
||||
const [selectedOptionArray, setSelectedOptionArray] = useState<string[]>([]);
|
||||
const [users, setUsers] = useState<User[]>([]);
|
||||
const [user, setUser] = useState<User>();
|
||||
const [convs, setConvs] = useState<Conv[]>([]);
|
||||
const [selectedOptionArray, setSelectedOptionArray] = useState([]);
|
||||
const [users, setUsers] = useState([]);
|
||||
const [user, setUser] = useState();
|
||||
const [convs, setConvs] = useState([]);
|
||||
|
||||
const [channel, setChannel] = useState('');
|
||||
|
||||
@ -57,46 +53,7 @@ const Modal = ({handleClose}: ModalProps) => {
|
||||
getConv();
|
||||
}, []);
|
||||
|
||||
const [askPass, setAskPass] = useState(false);
|
||||
const [PassWord, setPassWord] = useState('');
|
||||
useEffect(()=> {
|
||||
|
||||
const getConv = async ()=>{
|
||||
console.log("chan changed")
|
||||
console.log("chan = ", channel);
|
||||
try{
|
||||
|
||||
const tmpConv = await api.post("/convId", {convId: channel});
|
||||
if (tmpConv.data.password)
|
||||
setAskPass(true);
|
||||
}
|
||||
catch(err){
|
||||
console.log(err);
|
||||
}
|
||||
// if (channel.password)
|
||||
// console.log("password true")
|
||||
// else
|
||||
// console.log("password false")
|
||||
}
|
||||
getConv();
|
||||
}, [channel]);
|
||||
|
||||
const handlePassword = async (e: { key: string; }) => {
|
||||
if (e.key !== "Enter")
|
||||
return;
|
||||
try {
|
||||
const ret = await api.post("/verifyPassword", {convId: channel, password: PassWord})
|
||||
if (ret)
|
||||
console.log("ici ret password", ret);
|
||||
|
||||
// window.location.reload();
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
}
|
||||
handleClose();
|
||||
}
|
||||
|
||||
const handleOptionChange = (selectId: number, selectedOption: string) => {
|
||||
const handleOptionChange = (selectId, selectedOption) => {
|
||||
console.log("selected Option=", selectedOption)
|
||||
setSelectTag((prevTags) =>
|
||||
prevTags.map((tag) =>
|
||||
@ -114,8 +71,6 @@ const Modal = ({handleClose}: ModalProps) => {
|
||||
const joinChannel = async () => {
|
||||
try {
|
||||
console.log("channel= ", channel)
|
||||
console.log("ici test channel= ", channel)
|
||||
|
||||
await api.post("/join", {convId: channel})
|
||||
} catch(err) {
|
||||
console.log(err);
|
||||
@ -148,15 +103,12 @@ const Modal = ({handleClose}: ModalProps) => {
|
||||
<Backdrop onClick={handleClose}>
|
||||
<motion.div
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
className="modalSetting"
|
||||
className="modal"
|
||||
// variant={dropIn}
|
||||
initial="hidden"
|
||||
animate="visible"
|
||||
exit="exit"
|
||||
>
|
||||
{/* <p>New Conversation</p> */}
|
||||
<div className="settingFirstPart2">
|
||||
|
||||
{selectTags.map((selectTag) => (
|
||||
<div key={selectTag.id}>
|
||||
<select
|
||||
@ -164,11 +116,11 @@ const Modal = ({handleClose}: ModalProps) => {
|
||||
onChange={(a) => handleOptionChange(selectTag.id, a.target.value)}
|
||||
>
|
||||
<option value="">{
|
||||
selectTag.selectedOption ? selectTag.selectedOption : "Select a user"
|
||||
selectTag.selectedOption ? selectTag.selectedOption : "Select an option"
|
||||
}</option>
|
||||
{users.filter((item) => !selectTags.some((tag) => tag.selectedOption === item.nickname)).map((item, index) => (
|
||||
{users.filter((item) => !selectTags.some((tag) => tag.selectedOption === item.name)).map((item, index) => (
|
||||
<option key={index} value={item.username}>
|
||||
{item.nickname}
|
||||
{item.username}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
@ -179,11 +131,11 @@ const Modal = ({handleClose}: ModalProps) => {
|
||||
</div>
|
||||
<div className="div_submit">
|
||||
<Link to='#' className="submit" onClick={ saveSelectedOptions}>Submit</Link>
|
||||
</div>
|
||||
|
||||
<Link to="#" className="submit" onClick={handleClose}>Cancel</Link>
|
||||
</div>
|
||||
|
||||
|
||||
<div className="settingSecondPart">
|
||||
|
||||
{convs.length > 0 && (
|
||||
<select
|
||||
@ -191,25 +143,20 @@ const Modal = ({handleClose}: ModalProps) => {
|
||||
onChange={(event) => setChannel(event.target.value)}
|
||||
|
||||
>
|
||||
<option value="">Select a channel</option>
|
||||
<option value="">Select an option</option>
|
||||
{convs.map((conv) => (
|
||||
!(!conv.group || conv.private || (conv.banned && user && conv.banned.includes(user.username)) || (conv.members && user && conv.members.includes(user.username))) && (
|
||||
!(!conv.group || conv.private || (conv.banned && conv.banned.includes(user.username)) || (conv.members && conv.members.includes(user.username))) && (
|
||||
<option key={conv.id} value={conv.id}>
|
||||
{conv.name}
|
||||
</option>
|
||||
)
|
||||
// {conv.password ? (console.log("here is test")):("")}
|
||||
))}
|
||||
</select>
|
||||
)}
|
||||
{/* {console.log("here is channel == ",channel.password)} */}
|
||||
|
||||
<div>
|
||||
|
||||
{askPass ? (
|
||||
<input className="mdp" placeholder="password" type="password" onChange={(e) => setPassWord(e.target.value)} onKeyDown={handlePassword}/>
|
||||
{channel.private ? (
|
||||
<input className="mdp" placeholder="password" type="text" />
|
||||
):("")}
|
||||
</div>
|
||||
|
||||
|
||||
<div className="div_submit">
|
||||
<Link to='#' className="submit" onClick={ joinChannel }>Join</Link>
|
||||
@ -217,7 +164,6 @@ const Modal = ({handleClose}: ModalProps) => {
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
</motion.div>
|
||||
</Backdrop>
|
||||
)
|
||||
|
||||
@ -1,13 +1,31 @@
|
||||
import { AnimatePresence, motion } from "framer-motion";
|
||||
import { motion } from "framer-motion";
|
||||
import Backdrop from "../Sidebar/Backdrop.tsx";
|
||||
// import { Rank } from "../../DataBase/DataRank"
|
||||
import '../../styles/Messages.css'
|
||||
import { useState, useEffect } from "react";
|
||||
import { GrAdd } from "react-icons/gr";
|
||||
import { Link } from "react-router-dom";
|
||||
import api from "../../script/axiosApi.tsx";
|
||||
import React from "react";
|
||||
import {User} from "../../../interfaces.tsx"
|
||||
import { Socket } from "socket.io-client";
|
||||
import GreenAlert from "../Alert/GreenAlert.tsx";
|
||||
|
||||
|
||||
const dropIn = {
|
||||
hidden:{y:"-100vh",
|
||||
opacity: 0,},
|
||||
visible:{y: "0",
|
||||
opacity: 0,
|
||||
transotion:{
|
||||
duration:0.1,
|
||||
type:"spring",
|
||||
damping: 100,
|
||||
stiffness: 500,
|
||||
}},
|
||||
exit:{y: "100vh",
|
||||
opacity: 0,},
|
||||
|
||||
};
|
||||
|
||||
interface ModalSettingProps {
|
||||
handleClose: Function,
|
||||
@ -21,10 +39,8 @@ const ModalSetting = ({ handleClose, convId, socket }: ModalSettingProps) => {
|
||||
const [selectTags, setSelectTag] = useState([{ id: 1, selectedOption: ''}]);
|
||||
const [selectedUser, setSelectedUser] = useState("");
|
||||
const [newName, setNewName] = useState("");
|
||||
const [time, setTime] = useState("");
|
||||
const [newPassword, setNewPassword] = useState("");
|
||||
const [privateConv, setPrivateConv] = useState<Boolean>();
|
||||
const [loading, setLoading] = useState<Boolean>(true);
|
||||
const [privateConv, setPrivateConv] = useState(false);
|
||||
const dark = () => setPrivateConv(true);
|
||||
const light = () => setPrivateConv(false);
|
||||
const [mute, setMute] = useState(false);
|
||||
@ -37,13 +53,9 @@ const ModalSetting = ({ handleClose, convId, socket }: ModalSettingProps) => {
|
||||
console.log("convid =", convId)
|
||||
const getUsers = async ()=>{
|
||||
try {
|
||||
const currentConv = await api.post("/convId", { convId: convId });
|
||||
if (currentConv.data.private)
|
||||
setPrivateConv(true);
|
||||
const tmpUsers = await api.get("/users");
|
||||
console.log("users=", tmpUsers.data);
|
||||
setUsers(tmpUsers.data);
|
||||
setLoading(false);
|
||||
} catch(err){
|
||||
console.log(err)
|
||||
}
|
||||
@ -51,25 +63,9 @@ const ModalSetting = ({ handleClose, convId, socket }: ModalSettingProps) => {
|
||||
getUsers();
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
const handleVariableChange = () => {
|
||||
console.log('Variable changed:', privateConv);
|
||||
if (privateConv === undefined) {
|
||||
console.log("return")
|
||||
return;
|
||||
}
|
||||
try {
|
||||
if (privateConv)
|
||||
api.post("/private", { convId: convId })
|
||||
else
|
||||
api.post("/public", { convId: convId })
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
}
|
||||
};
|
||||
if (!loading)
|
||||
handleVariableChange();
|
||||
}, [privateConv]);
|
||||
// const [multi, setMulti] = useState(false);
|
||||
// const [selectedOptionArray, setSelectedOptionArray] = useState([]);
|
||||
|
||||
|
||||
const handleOptionChange = (selectId: number, selectedOption: string) => {
|
||||
console.log("tag= ", selectTags)
|
||||
@ -84,7 +80,29 @@ const ModalSetting = ({ handleClose, convId, socket }: ModalSettingProps) => {
|
||||
|
||||
const handleCheckPass = (e: { target: { checked: boolean | ((prevState: boolean) => boolean); }; }) => {
|
||||
setPassword(e.target.checked);
|
||||
console.log("password??", e.target.checked);
|
||||
console.log("password??", e.target.checked)
|
||||
}
|
||||
|
||||
const handleCheckPriv = (e: { target: { checked: any; }; }) => {
|
||||
// setPassword(e.target.checked);
|
||||
if (e.target.checked)
|
||||
{
|
||||
console.log("chack true", e.target.checked)
|
||||
try{
|
||||
api.post("/private", {convId: convId})
|
||||
} catch(err) {
|
||||
console.log(err);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
console.log("chack false", e.target.checked)
|
||||
try{
|
||||
api.post("/private", {convId: convId})
|
||||
} catch(err) {
|
||||
console.log(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const handleName = async (e: { key: string; })=>{
|
||||
@ -110,28 +128,22 @@ const ModalSetting = ({ handleClose, convId, socket }: ModalSettingProps) => {
|
||||
handleClose();
|
||||
}
|
||||
|
||||
const [unban, setUnban] = useState(false);
|
||||
const closeUnban = () => setUnban(false);
|
||||
|
||||
const handleBan = async () => {
|
||||
// console.log("ban option= ", selectedUser)
|
||||
try{
|
||||
// console.log("user select=", selectedUser.length)
|
||||
if (!selectedUser.length)
|
||||
return ;
|
||||
const res = await api.post("/ban", { convId: convId, username: selectedUser })
|
||||
console.log("res of ban", res.data)
|
||||
|
||||
if (res.data === 2) {
|
||||
console.log("hehe true");
|
||||
setUnban(true);
|
||||
}
|
||||
if (socket) {
|
||||
await api.post("/ban", {convId: convId, username: selectedUser})
|
||||
if (socket)
|
||||
{
|
||||
console.log("emit to ban server")
|
||||
socket.emit("ban", {username: selectedUser})
|
||||
}
|
||||
} catch(err) {
|
||||
console.log(err);
|
||||
}
|
||||
setTimeout(handleClose, 1500);
|
||||
handleClose();
|
||||
};
|
||||
|
||||
const handleAdmin = async () => {
|
||||
@ -145,18 +157,11 @@ const ModalSetting = ({ handleClose, convId, socket }: ModalSettingProps) => {
|
||||
handleClose();
|
||||
};
|
||||
|
||||
const [muteAlert, setMuteAlert] = useState(false);
|
||||
const closeMuteAlert = () => setMuteAlert(false);
|
||||
|
||||
const handleMute = async (e: { key: string; }) => {
|
||||
console.log(`e in press= ${e.key}`)
|
||||
if (e.key != "Enter")
|
||||
const handleMute = async () => {
|
||||
if (!selectedUser.length)
|
||||
return ;
|
||||
console.log("value mute = ", time);
|
||||
try{
|
||||
const ret = await api.post("/mute", { convId: convId, username: selectedUser, time: time })
|
||||
if (ret.data)
|
||||
setMuteAlert(true);
|
||||
await api.post("/mute", {convId: convId, username: selectedUser})
|
||||
} catch(err) {
|
||||
console.log(err);
|
||||
}
|
||||
@ -165,8 +170,7 @@ const ModalSetting = ({ handleClose, convId, socket }: ModalSettingProps) => {
|
||||
|
||||
const handleInvite = async () => {
|
||||
try{
|
||||
console.log("post invite bitch");
|
||||
await api.post("/inviteConv", { convId: convId, username: selectedUser });
|
||||
await api.post("/invite", {convId: convId, username: selectedUser})
|
||||
} catch(err) {
|
||||
console.log(err);
|
||||
}
|
||||
@ -182,14 +186,19 @@ const ModalSetting = ({ handleClose, convId, socket }: ModalSettingProps) => {
|
||||
animate="visible"
|
||||
exit="exit"
|
||||
>
|
||||
|
||||
{/* First selection */}
|
||||
<div className="settingFirstPart">
|
||||
<div>
|
||||
<div>
|
||||
<Link to="#" onClick={light} className={ privateConv ? "submit" : "darkSubmit"}>Public</Link>
|
||||
<Link to="#" onClick={dark} className={ privateConv ? "darkSubmit" : "submit"}>Private</Link>
|
||||
</div>
|
||||
<p className="checkbox">Password<input className="inside_ckeckbox" type="checkbox" value="password" checked={password} onChange={handleCheckPass} /> </p>
|
||||
{password ? (
|
||||
{/* <p className="checkbox">Private<input className="check"type="checkbox" value="private" onChange={handleCheckPriv}/></p> */}
|
||||
<p className="checkbox">Password<input type="checkbox" value="password" checked={password} onChange={handleCheckPass}/> </p>
|
||||
|
||||
|
||||
{password || privateConv ? (
|
||||
<input
|
||||
onChange={(e) => setNewPassword(e.target.value)}
|
||||
onKeyDown={handlePassword}
|
||||
@ -199,12 +208,12 @@ const ModalSetting = ({ handleClose, convId, socket }: ModalSettingProps) => {
|
||||
):
|
||||
("")}
|
||||
|
||||
|
||||
</div>
|
||||
<div className="forName">
|
||||
<input
|
||||
onChange={(e) => setNewName(e.target.value)}
|
||||
onKeyDown={handleName}
|
||||
maxLength={20}
|
||||
type="text"
|
||||
className="in"
|
||||
placeholder="New Name"
|
||||
@ -212,6 +221,8 @@ const ModalSetting = ({ handleClose, convId, socket }: ModalSettingProps) => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Second selection */}
|
||||
|
||||
<div className="settingSecondPart">
|
||||
|
||||
|
||||
@ -226,15 +237,16 @@ const ModalSetting = ({ handleClose, convId, socket }: ModalSettingProps) => {
|
||||
</option>
|
||||
{users.map((item, index) => (
|
||||
<option key={index} value={item.username}>
|
||||
{item.nickname}
|
||||
{item.username}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
))}
|
||||
|
||||
|
||||
<div>
|
||||
<Link to="#" onClick={handleInvite} className="submit">Invite</Link>
|
||||
<Link to="#" onClick={handleInvite} className="submit">Send</Link>
|
||||
<Link to="#" onClick={handleBan} className="submit">Ban</Link>
|
||||
<Link to="#" onClick={mute ? darkMute : lightMute} className={mute ? "darkSubmit": "submit"}>Mute</Link>
|
||||
<Link to="#" onClick={handleAdmin} className="submit">Admin</Link>
|
||||
@ -242,23 +254,8 @@ const ModalSetting = ({ handleClose, convId, socket }: ModalSettingProps) => {
|
||||
|
||||
</div>
|
||||
{mute ? (
|
||||
<input
|
||||
onKeyDown={handleMute}
|
||||
type="number"
|
||||
className="in_howLong"
|
||||
placeholder="Time"
|
||||
value={time}
|
||||
onChange={(e) => setTime(e.target.value)}
|
||||
/>
|
||||
<input type="text" className="in_howLong" placeholder="How long ?" />
|
||||
):("")}
|
||||
<AnimatePresence initial={false} onExitComplete={() => null}>
|
||||
{unban ? (
|
||||
<GreenAlert handleClose={closeUnban} text={selectedUser + ": was unbanned"} />
|
||||
) : ("")}
|
||||
{muteAlert ? (
|
||||
<GreenAlert handleClose={closeMuteAlert} text="Mute" />
|
||||
) : ("")}
|
||||
</AnimatePresence>
|
||||
|
||||
</motion.div>
|
||||
</Backdrop>
|
||||
|
||||
@ -1,13 +1,12 @@
|
||||
import { AnimatePresence, motion } from "framer-motion"
|
||||
import {motion} from "framer-motion"
|
||||
// import Backdrop from "../Sidebar/Backdrop"
|
||||
import {Link} from 'react-router-dom';
|
||||
// import { UserProfile } from "../../DataBase/DataUserProfile";
|
||||
import { UserProfile } from "../../DataBase/DataUserProfile";
|
||||
import {useState} from 'react';
|
||||
import "../../styles/Profile.css"
|
||||
|
||||
import api from '../../script/axiosApi.tsx';
|
||||
import React from "react";
|
||||
import RedAlert from "../Alert/RedAlert.tsx";
|
||||
|
||||
const dropIn = {
|
||||
hidden: {
|
||||
@ -27,54 +26,33 @@ const dropIn = {
|
||||
// )
|
||||
// }
|
||||
|
||||
const ModalEdit = () => {
|
||||
const ModalEdit = ( handleClose ) => {
|
||||
// let new_name = "";
|
||||
const [nickname, setNickname] = useState("");
|
||||
const [errTaken, setErrTaken] = useState(false);
|
||||
const closeTaken = () => setErrTaken(false);
|
||||
const [errTooShort, setErrTooShort] = useState(false);
|
||||
const closeTooShort = () => setErrTooShort(false);
|
||||
|
||||
const handler = (e: { target: { value: React.SetStateAction<string>; }; }) => {
|
||||
const handler = e =>
|
||||
{
|
||||
setNickname(e.target.value);
|
||||
console.log("testeeeee")
|
||||
const postNickname = async ()=>{
|
||||
// try{
|
||||
// await api.post("/nickname", {nickname: nickname})
|
||||
// // setUser(tmpUser.data);
|
||||
// // setIsLoading(false)
|
||||
// }
|
||||
// catch(err){
|
||||
// console.log(err);
|
||||
// }
|
||||
try{
|
||||
await api.post("/nickname", {nickname: nickname})
|
||||
// setUser(tmpUser.data);
|
||||
// setIsLoading(false)
|
||||
}
|
||||
catch(err){
|
||||
console.log(err);
|
||||
}
|
||||
};
|
||||
postNickname();
|
||||
}
|
||||
|
||||
const handlePostNickname = async () => {
|
||||
const handlePostNickname = async () =>
|
||||
{
|
||||
console.log("nickname=" ,nickname)
|
||||
try{
|
||||
// console.log("cest ici = ",ret);
|
||||
// if (!ret)
|
||||
// console.log("test ret =", ret.data);
|
||||
if (nickname.length > 3) {
|
||||
const ret = await api.post("/nickname", { nickname: nickname });
|
||||
if (ret.data) {
|
||||
console.log("ici error = ", ret.data);
|
||||
await api.post("/nickname", {nickname: nickname})
|
||||
window.location.reload();
|
||||
}
|
||||
else {
|
||||
console.log("nickname already set = ", ret.data);
|
||||
|
||||
setErrTaken(true);
|
||||
}
|
||||
}
|
||||
else if (nickname.length < 3)
|
||||
{
|
||||
setErrTooShort(true);
|
||||
}
|
||||
|
||||
|
||||
// setUser(tmpUser.data);
|
||||
// setIsLoading(false)
|
||||
}
|
||||
@ -94,28 +72,17 @@ const ModalEdit = () => {
|
||||
initial="hidden"
|
||||
animate="visible"
|
||||
exit="exit">
|
||||
<h1>Type your new name</h1>
|
||||
<input className="text" minLength={2} maxLength={10} type="text" value={nickname} onChange={handler} />
|
||||
<h2>Type your new name</h2>
|
||||
<input className="text" maxLength="10" type="text" value={nickname} onChange={handler} handleClose/>
|
||||
<div>
|
||||
<div className="button" onClick={handlePostNickname}>
|
||||
<div className="button" onClick={ () => handlePostNickname()}>
|
||||
change
|
||||
{/* <Link className="button" to={""}>change</Link> */}
|
||||
</div>
|
||||
<AnimatePresence initial={false} onExitComplete={() => null}>
|
||||
{
|
||||
errTaken ? (
|
||||
<RedAlert handleClose={closeTaken} text="Error: Nickname already taken" />
|
||||
) : ("")
|
||||
}
|
||||
{
|
||||
errTooShort ? (
|
||||
<RedAlert handleClose={closeTooShort} text="Error: Nickname it too short" />
|
||||
) : ("")
|
||||
}
|
||||
|
||||
</AnimatePresence>
|
||||
</div>
|
||||
</motion.div>
|
||||
|
||||
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@ -1,18 +1,9 @@
|
||||
import React from "react";
|
||||
import api from "../../script/axiosApi"
|
||||
|
||||
|
||||
|
||||
function Logout(){
|
||||
const logout = async () =>{
|
||||
|
||||
try {
|
||||
await api.post("/logout")
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
}
|
||||
}
|
||||
|
||||
logout();
|
||||
localStorage.clear();
|
||||
const path = 'http://' + process.env.REACT_APP_BASE_URL + '/';
|
||||
// history(path, { replace: true });
|
||||
|
||||
@ -62,20 +62,8 @@ function WinLoss() {
|
||||
const getUser = async ()=>{
|
||||
try{
|
||||
// const tmpUser = await api.get("/profile")
|
||||
console.log("username win loss=", username)
|
||||
let tmpUser;
|
||||
let tmpHistory;
|
||||
|
||||
if (username)
|
||||
{
|
||||
tmpUser = await api.post("/user", {username: username});
|
||||
tmpHistory = await api.post("/history", {username: username})
|
||||
}
|
||||
else
|
||||
{
|
||||
tmpUser = await api.get("/profile");
|
||||
tmpHistory = await api.post("/history", {username: tmpUser.data.username})
|
||||
}
|
||||
const tmpUser = await api.post("/user", {username: username})
|
||||
const tmpHistory = await api.post("/history", {username: username})
|
||||
setHistory(tmpHistory.data);
|
||||
setUser(tmpUser.data);
|
||||
setIsLoading(false)
|
||||
@ -106,7 +94,7 @@ function WinLoss() {
|
||||
// <span>Loading...</span>
|
||||
) : (
|
||||
<div className='scroll'>
|
||||
<h2 className='title'>Match history {user.win}/{user.loss}</h2>
|
||||
<h2 className='title'>Match history Win/Loss</h2>
|
||||
{history.map((c: Matchlog, index) => {
|
||||
return (
|
||||
<div key={index} className='elements'>
|
||||
|
||||
@ -26,7 +26,7 @@ export const SidebarData = [
|
||||
cName: 'nav-text'
|
||||
},
|
||||
{
|
||||
title: 'Friends',
|
||||
title: 'Friend',
|
||||
path: '/social',
|
||||
icon: <IoIcons.IoMdPeople />,
|
||||
cName: 'nav-text'
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
/* By: apommier <apommier@student.42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2023/06/09 08:18:58 by apommier #+# #+# */
|
||||
/* Updated: 2023/06/23 17:12:07 by apommier ### ########.fr */
|
||||
/* Updated: 2023/06/20 13:41:44 by apommier ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
@ -27,7 +27,6 @@ const UserChat = styled.div `
|
||||
gap: 5px;
|
||||
color: white;
|
||||
cursor: pointer;
|
||||
margin-top: 15px;
|
||||
|
||||
&:hover{
|
||||
background-color: #3e3c61;
|
||||
@ -60,14 +59,13 @@ export default function Friend({currentUser}: UserProps)
|
||||
console.error('Error fetching profile picture:', error);
|
||||
}
|
||||
};
|
||||
|
||||
fetchProfilePicture();
|
||||
}, []);
|
||||
})
|
||||
|
||||
function getStatus(friend: User)
|
||||
{
|
||||
let status = friend.status
|
||||
let session =friend.sessionNumber
|
||||
console.log(`session= ${session}`)
|
||||
console.log(`status= ${status}`)
|
||||
let statusColor;
|
||||
|
||||
@ -96,24 +94,24 @@ export default function Friend({currentUser}: UserProps)
|
||||
};
|
||||
|
||||
return (
|
||||
<UserChat className="centermargin">
|
||||
<UserChat>
|
||||
{profilePicture ? (
|
||||
<img className="pic-user" src={`data:image/jpeg;base64,${profilePicture}`} />
|
||||
) : (
|
||||
<img className="pic-user" src={DefaultPicture} alt="Default Profile Picture" />
|
||||
)}
|
||||
<div className="end">
|
||||
<div className="infoSideBar">
|
||||
<span onClick={() => handleButtonClick(currentUser)}>{currentUser.nickname}</span>
|
||||
<div className="end">
|
||||
<RxCircle className="friendRequest" color={getStatus(currentUser)} />
|
||||
</div>
|
||||
<RxCircle color={getStatus(currentUser)} />
|
||||
<button onClick={() => handleSpectate(currentUser)} >Invite</button>
|
||||
{getStatus(currentUser) !== 'blue' ? (
|
||||
<></>
|
||||
) : (
|
||||
<button onClick={() => handleSpectate(currentUser)} >Spectate</button>
|
||||
)}
|
||||
</div>
|
||||
</UserChat>
|
||||
)
|
||||
}
|
||||
// spectate visible
|
||||
// {getStatus(currentUser) !== 'blue' ? (
|
||||
// <></>
|
||||
// ) : (
|
||||
// <button className="friendRequest" onClick={() => handleSpectate(currentUser)} >Spectate</button>
|
||||
// )}
|
||||
|
||||
|
||||
|
||||
@ -15,7 +15,7 @@ const UserChat = styled.div `
|
||||
gap: 5px;
|
||||
color: white;
|
||||
cursor: pointer;
|
||||
margin-top: 10px;
|
||||
|
||||
&:hover{
|
||||
background-color: #3e3c61;
|
||||
}
|
||||
@ -94,21 +94,20 @@ export default function Friend({currentUser}: UserProps)
|
||||
}
|
||||
|
||||
return (
|
||||
<UserChat className="centermargin">
|
||||
<UserChat>
|
||||
{profilePicture ? (
|
||||
<img className="pic-user" src={`data:image/jpeg;base64,${profilePicture}`} />
|
||||
) : (
|
||||
<img className="pic-user" src={DefaultPicture} alt="Default Profile Picture" />
|
||||
)}
|
||||
{request ? (
|
||||
<div className="end">
|
||||
<div className="infoSideBar">
|
||||
<span onClick={() => handleButtonClick(currentUser)}>{currentUser.nickname}</span>
|
||||
<div className="end">
|
||||
<RxCheckCircled className="friendRequest" onClick={() => Accept(request)} color={'green'}/>
|
||||
<RxCircleBackslash className="friendRequest" onClick={() => Refuse(request)} color={'red'}/>
|
||||
</div>
|
||||
<RxCheckCircled onClick={() => Accept(request)} color={'green'}/>
|
||||
<RxCircleBackslash onClick={() => Refuse(request)} color={'red'}/>
|
||||
</div>
|
||||
) : ( "" )}
|
||||
</UserChat>
|
||||
)
|
||||
}
|
||||
|
||||
@ -7,7 +7,6 @@ import styled from "styled-components";
|
||||
import Friend from './Friend.tsx';
|
||||
import FriendRequest from './FriendRequest.tsx';
|
||||
|
||||
import {IoMdPeople} from 'react-icons/io'
|
||||
import { ImBlocked } from 'react-icons/im';
|
||||
import { MdOutlineGroupAdd } from 'react-icons/md';
|
||||
import {User} from "../../../interfaces.tsx"
|
||||
@ -87,17 +86,28 @@ function Social (){
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className='navbarSocial'>
|
||||
<div className='navbar'>
|
||||
{/* <img src={DefaultPic} alt="profile" className="pic"/> */}
|
||||
<IoMdPeople className="catchat"/>
|
||||
{profilePicture ? (
|
||||
<img className="pic" src={`data:image/jpeg;base64,${profilePicture}`} />
|
||||
) : (
|
||||
<img className="pic" src={DefaultPicture} alt="Default Profile Picture" />
|
||||
)}
|
||||
<span>
|
||||
{isLoading || !user ? (
|
||||
<h4>Loading...</h4>
|
||||
) : (
|
||||
<h2>Friends</h2>
|
||||
<h4>{user.nickname}</h4>
|
||||
)}
|
||||
</span>
|
||||
|
||||
<div className="end">
|
||||
<TouchDiv>
|
||||
<MdOutlineGroupAdd/>
|
||||
</TouchDiv>
|
||||
<TouchDiv>
|
||||
<ImBlocked/>
|
||||
</TouchDiv>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* map with fiend request */}
|
||||
@ -109,7 +119,6 @@ function Social (){
|
||||
{friends.map(c=> (
|
||||
<Friend currentUser={c}/>
|
||||
))}
|
||||
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
27
containers/react/src/index.js
Normal file
27
containers/react/src/index.js
Normal file
@ -0,0 +1,27 @@
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom/client';
|
||||
import { BrowserRouter } from 'react-router-dom';
|
||||
|
||||
import reportWebVitals from './reportWebVitals';
|
||||
import Header from './components/Header.tsx';
|
||||
import Head from './pages/Head.tsx';
|
||||
import App from './components/App.tsx';
|
||||
|
||||
import './styles/index.css';
|
||||
import './styles/App.css'
|
||||
|
||||
const root = ReactDOM.createRoot(document.getElementById('root'));
|
||||
root.render(
|
||||
<div className="App">
|
||||
<Head />
|
||||
<BrowserRouter>
|
||||
<Header />
|
||||
<App/>
|
||||
</BrowserRouter>
|
||||
</div>
|
||||
);
|
||||
|
||||
// If you want to start measuring performance in your app, pass a function
|
||||
// to log results (for example: reportWebVitals(console.log))
|
||||
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
|
||||
reportWebVitals();
|
||||
@ -1,22 +0,0 @@
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom/client';
|
||||
import { BrowserRouter } from 'react-router-dom';
|
||||
|
||||
import Header from './components/Header';
|
||||
import Head from './pages/Head';
|
||||
import App from './components/App';
|
||||
|
||||
import './styles/index.css';
|
||||
import './styles/App.css';
|
||||
|
||||
const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement);
|
||||
|
||||
root.render(
|
||||
<div className="App">
|
||||
<Head />
|
||||
<BrowserRouter>
|
||||
<Header />
|
||||
<App/>
|
||||
</BrowserRouter>
|
||||
</div>
|
||||
);
|
||||
@ -1,17 +1,112 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import React, { useCallback, useState, useEffect } from 'react';
|
||||
import api from '../script/axiosApi.tsx';
|
||||
|
||||
// function DoubleAuth() {
|
||||
|
||||
// // const enabled = await api.get("/2fa");
|
||||
|
||||
// // const response = await api.get("/2fa");
|
||||
// // const enabled = response.data;
|
||||
// // console.log(`enable= ${enabled.data}`)
|
||||
// // const enabled = 0;
|
||||
// let enabled;
|
||||
|
||||
// useEffect(() => {
|
||||
// async function get2fa()
|
||||
// {
|
||||
// const response = await api.get("/2fa");
|
||||
// const enabled = response.data;
|
||||
// console.log(`enable= ${enabled.data}`)
|
||||
// }
|
||||
// // const enabled = 0;
|
||||
// }, [])
|
||||
|
||||
|
||||
|
||||
// useEffect(() => {
|
||||
// async function get2fa()
|
||||
// {
|
||||
// api.get('/api/QRcode', { responseType: 'blob' })
|
||||
// .then(response => {
|
||||
// const reader = new FileReader();
|
||||
// reader.onloadend = () => {
|
||||
// setImageSrc(reader.result);
|
||||
// };
|
||||
// reader.readAsDataURL(response.data);
|
||||
// })
|
||||
// .catch(error => {
|
||||
// console.error(error);
|
||||
// });
|
||||
|
||||
// } }, []);
|
||||
|
||||
// // const [verificationCode, setVerificationCode] = useState('');
|
||||
// // const [invalidCode, setInvalidCode] = useState(false);
|
||||
|
||||
// const handleSubmit = () => {
|
||||
// // async (e) => {
|
||||
// // e.preventDefault();
|
||||
|
||||
// // const result = await verifyOtp(verificationCode);
|
||||
|
||||
// // if (result) return (window.location = '/');
|
||||
|
||||
// // setInvalidCode(true);
|
||||
// // },
|
||||
// // [verificationCode]
|
||||
// };
|
||||
|
||||
// let sourceCode
|
||||
|
||||
// if (!enabled)
|
||||
// {
|
||||
// api.get('/QRcode')
|
||||
// .then(response => {
|
||||
// sourceCode = response.data;
|
||||
// console.log(sourceCode);
|
||||
// })
|
||||
// .catch(error => {
|
||||
// console.error(error);
|
||||
// });
|
||||
// }
|
||||
|
||||
// return (
|
||||
// <div>
|
||||
// {!enabled && (
|
||||
// <div>
|
||||
// <p>Scan the QR code on your authenticator app</p>
|
||||
// <img src={sourceCode} />
|
||||
// </div>
|
||||
// )}
|
||||
|
||||
// <form onSubmit={handleSubmit}>
|
||||
// {/* <Input
|
||||
// id="verificationCode"
|
||||
// label="Verification code"
|
||||
// type="text"
|
||||
// value={verificationCode}
|
||||
// onChange={(e) => setVerificationCode(e.target.value)}
|
||||
// /> */}
|
||||
|
||||
// <button type="submit">Confirm</button>
|
||||
|
||||
// {/* {invalidCode && <p>Invalid verification code</p>} */}
|
||||
// </form>
|
||||
// </div>
|
||||
// );
|
||||
// }
|
||||
|
||||
|
||||
// import { toFileStream } from 'qrcode';
|
||||
|
||||
const DoubleAuth = () => {
|
||||
// const [imageSrc, setImageSrc] = useState('');
|
||||
const [imageSrc, setImageSrc] = useState<string | ArrayBuffer | null>('');
|
||||
const [imageSrc, setImageSrc] = useState('');
|
||||
|
||||
useEffect(() => {
|
||||
async function getCode(){
|
||||
await api.get('/QRcode', { responseType: 'blob' })
|
||||
.then(response => {
|
||||
const reader = new FileReader();
|
||||
if (!reader)
|
||||
return;
|
||||
reader.onloadend = () => {
|
||||
setImageSrc(reader.result);
|
||||
};
|
||||
@ -24,14 +119,27 @@ const DoubleAuth = () => {
|
||||
getCode();
|
||||
}, []);
|
||||
|
||||
// return (
|
||||
// <div>
|
||||
// {imageSrc && <img src={imageSrc} alt="QR Code" />}
|
||||
// </div>
|
||||
// );
|
||||
|
||||
// <img src={sourceCode} />
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div>
|
||||
<p>Scan the QR code on your authenticator app</p>
|
||||
{/* {imageSrc && <img src={imageSrc} alt="QR Code" />} */}
|
||||
{imageSrc && <img src={imageSrc.toString()} alt="QR Code" />}</div>
|
||||
{imageSrc && <img src={imageSrc} alt="QR Code" />}
|
||||
</div>
|
||||
{/* <form onSubmit={handleSubmit}>
|
||||
<button type="submit">Confirm</button>
|
||||
</form> */}
|
||||
</div>
|
||||
);
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
@ -1,9 +1,13 @@
|
||||
import { useEffect } from 'react';
|
||||
// import { useState, useRef } from 'react';
|
||||
import DrawCanvas from './canvas.tsx';
|
||||
import queryString from 'query-string';
|
||||
import '../styles/field.css';
|
||||
|
||||
import { useParams } from "react-router-dom";
|
||||
import React from 'react';
|
||||
|
||||
// import { withRouter } from 'react-router-dom';
|
||||
|
||||
interface GameProps {
|
||||
privateParty: boolean,
|
||||
@ -14,6 +18,7 @@ interface GameProps {
|
||||
function Field()
|
||||
{
|
||||
useEffect(() => {
|
||||
// const location = useLocation();
|
||||
const queryParams = queryString.parse(window.location.search);
|
||||
|
||||
console.log("launch canva hehe")
|
||||
@ -51,6 +56,7 @@ function Field()
|
||||
|
||||
return () => {
|
||||
console.log("Cleanup");
|
||||
// cleanup(); // Call the cleanup function to stop the ongoing process or perform necessary cleanup tasks
|
||||
if (cleanup)
|
||||
cleanup();
|
||||
};
|
||||
|
||||
@ -7,7 +7,9 @@ function Head()
|
||||
<meta charSet="utf-8"></meta>
|
||||
<link href="./css/header.css" rel="stylesheet"></link>
|
||||
<title>BEST PONG EVER</title>
|
||||
{/* <script src="./script/login.js"></script> */}
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com"></link>
|
||||
{/* <link rel="preconnect" href="https://fonts.gstatic.com" crossOrigin="true"></link> */}
|
||||
<link href="https://fonts.googleapis.com/css2?family=Rubik+Iso&display=swap" rel="stylesheet"></link>
|
||||
</div>
|
||||
);
|
||||
|
||||
50
containers/react/src/pages/Home.js
Normal file
50
containers/react/src/pages/Home.js
Normal file
@ -0,0 +1,50 @@
|
||||
import '../styles/old.css';
|
||||
import '../styles/field.css';
|
||||
|
||||
import { useLocation } from 'react-router-dom';
|
||||
import api from '../script/axiosApi.tsx';
|
||||
|
||||
function HomeLogin()
|
||||
{
|
||||
const login2 = () => {
|
||||
console.log('Hello from myFunction');
|
||||
api.get('/profile').then((response) => {
|
||||
const data = response;
|
||||
const myJSON = JSON.stringify(response.data);
|
||||
console.log(`data response= ${myJSON}`)
|
||||
});
|
||||
}
|
||||
|
||||
const location = useLocation();
|
||||
|
||||
const handleButtonClick = () => {
|
||||
const token = localStorage.getItem('token')
|
||||
console.log(`token type= ${typeof token}`);
|
||||
if (token !== null && typeof token === 'string')
|
||||
{
|
||||
console.log(`already token= ${localStorage.getItem('token')}`)
|
||||
return ;
|
||||
}
|
||||
// else
|
||||
// let path = "https://api.intra.42.fr/oauth/authorize?client_id=u-s4t2ud-6d29dfa49ba7146577ffd8bf595ae8d9e5aaa3e0a9615df18777171ebf836a41&redirect_uri=http%3A%2F%2F" + process.env.REACT_APP_BASE_URL + "%3A80%2Fapi%2Fauth%2Flogin&response_type=code";
|
||||
let path = "https://api.intra.42.fr/oauth/authorize?client_id=u-s4t2ud-6d29dfa49ba7146577ffd8bf595ae8d9e5aaa3e0a9615df18777171ebf836a41&redirect_uri=http%3A%2F%2F" + process.env.REACT_APP_BASE_URL + "%2Fapi%2Fauth%2Flogin&response_type=code"
|
||||
window.location.replace(path);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="notClicked">
|
||||
<button onClick={handleButtonClick} className="playButton" >LOGIN</button>
|
||||
{/* <div className ="loginForm">
|
||||
<button className="submit" onClick={login2}>test button</button>
|
||||
</div> */}
|
||||
{/* <div className ="loginForm">
|
||||
<button className="submit" onClick={() => api.post('/win')}>add win</button>
|
||||
</div>
|
||||
<div className ="loginForm">
|
||||
<button className="submit" onClick={() => api.post('/loss')}>add loss</button>
|
||||
</div> */}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default HomeLogin;
|
||||
@ -6,40 +6,65 @@
|
||||
/* By: apommier <apommier@student.42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2023/06/09 08:19:04 by apommier #+# #+# */
|
||||
/* Updated: 2023/06/26 07:06:35 by apommier ### ########.fr */
|
||||
/* Updated: 2023/06/23 15:58:14 by apommier ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
// import { React, useState } from "react";
|
||||
import '../styles/Profile.css'
|
||||
import RedAlert from "../components/Alert/RedAlert.tsx";
|
||||
// import '../styles/App.css'
|
||||
import DefaultPicture from "../assets/profile.jpg";
|
||||
import WinLoss from "../components/Profile/Win_Loss.tsx";
|
||||
import { motion, AnimatePresence } from 'framer-motion'
|
||||
// import { AiFillEdit } from 'react-icons/ai'
|
||||
// import { GrClose } from 'react-icons/gr'
|
||||
import { Link } from "react-router-dom";
|
||||
import ModalEdit from "../components/Profile/EditName.tsx";
|
||||
import {AiOutlineCloseCircle, AiOutlineHistory} from 'react-icons/ai'
|
||||
import {AiOutlineHistory} from 'react-icons/ai'
|
||||
import { MdQrCodeScanner, MdOutlinePhotoLibrary } from 'react-icons/md';
|
||||
import { GiWingedSword, GiCrownedSkull } from 'react-icons/gi';
|
||||
|
||||
// import { Link } from "react-router-dom";
|
||||
// import {UserProfile} from "../DataBase/DataUserProfile";
|
||||
// import axios from "axios";
|
||||
import api from '../script/axiosApi.tsx';
|
||||
import { CgEditMarkup } from 'react-icons/cg'
|
||||
import { IoCloseCircleOutline } from "react-icons/io5";
|
||||
import React, { useState, useEffect } from "react";
|
||||
|
||||
// import * as React from 'react';
|
||||
// import { useState, useEffect, useParams} from "react";
|
||||
import React, { useState, useEffect, useRef, ChangeEventHandler } from "react";
|
||||
import { useParams } from 'react-router-dom';
|
||||
import {User} from "../../interfaces.tsx"
|
||||
import {User, Conv} from "../../interfaces.tsx"
|
||||
import YellowAlert from '../components/Alert/YellowAlert.tsx';
|
||||
// axios.get("http://localhost/api")
|
||||
// .then((response) => {
|
||||
// response = response.json()
|
||||
// response.then((result) => {
|
||||
// console.log(result)
|
||||
// console.log("ceci est un test")
|
||||
// })
|
||||
// })
|
||||
|
||||
|
||||
function Profile () {
|
||||
const [user, setUser] = useState<User>();
|
||||
const [isLoading, setIsLoading] = useState<boolean>(true);
|
||||
const [modalOpen, setModalOpen] = useState<boolean>(false);
|
||||
const [mine, setMine] = useState<boolean>(false);
|
||||
const [error, setError] = useState<boolean>(false);
|
||||
const close = () => setModalOpen(false);
|
||||
const closeError = () => setError(false);
|
||||
const open = () => setModalOpen(true);
|
||||
|
||||
const { username } = useParams();
|
||||
|
||||
// const [selectedPhoto, setSelectedPhoto] = useState();
|
||||
// const [selectedPhoto, setSelectedPhoto] = useState(null);
|
||||
|
||||
const [profilePicture, setProfilePicture] = useState('');
|
||||
|
||||
const handleFileChange = async (event: { target: { files: any; }; }) => {
|
||||
// const files = event.target.files;
|
||||
// if (files && files.length > 0) {
|
||||
const photo = (event.target.files[0]);
|
||||
console.log("file selected")
|
||||
if (photo) {
|
||||
@ -51,18 +76,49 @@ function Profile () {
|
||||
console.log('File uploaded successfully');
|
||||
window.location.reload();
|
||||
} catch (error) {
|
||||
setError(true);
|
||||
console.error('Error uploading file:', error);
|
||||
}
|
||||
}
|
||||
// }
|
||||
};
|
||||
|
||||
// const handleUpload = async () => {
|
||||
// const formData = new FormData();
|
||||
// formData.append('photo', selectedPhoto);
|
||||
// try {
|
||||
// await api.post('/picture', formData);
|
||||
// console.log('File uploaded successfully');
|
||||
// window.location.reload();
|
||||
// } catch (error) {
|
||||
// console.error('Error uploading file:', error);
|
||||
// }
|
||||
// };
|
||||
|
||||
// const handleUpload = async (event: React.FormEvent) => {
|
||||
// event.preventDefault()
|
||||
// console.log("up photo")
|
||||
// if (selectedPhoto) {
|
||||
// console.log("selected photo")
|
||||
// const formData = new FormData();
|
||||
// formData.append('photo', selectedPhoto);
|
||||
// try {
|
||||
// await api.post('/picture', formData);
|
||||
// console.log('File uploaded successfully');
|
||||
// window.location.reload();
|
||||
// } catch (error) {
|
||||
// console.error('Error uploading file:', error);
|
||||
// }
|
||||
// } else {
|
||||
// console.log('No file selected');
|
||||
// }
|
||||
// };
|
||||
|
||||
useEffect(()=> {
|
||||
const getUser = async ()=>{
|
||||
console.log(`username= ${username}`)
|
||||
let pic;
|
||||
// const pic
|
||||
let pic
|
||||
try{
|
||||
console.log("before request")
|
||||
const me = await api.get("/profile")
|
||||
if (!username)
|
||||
{
|
||||
@ -70,6 +126,7 @@ function Profile () {
|
||||
setUser(me.data);
|
||||
console.log(`mine= true = ${mine}`)
|
||||
pic = await api.post("/getPicture", {username: me.data.username}) //good one?
|
||||
// username = me.data.username
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -78,7 +135,9 @@ function Profile () {
|
||||
pic = await api.post("/getPicture", {username: username}) //good one?
|
||||
|
||||
}
|
||||
// const pic = await api.get("/picture")//pic du user
|
||||
setProfilePicture(pic.data);
|
||||
// console.log(`user= ${tmpUser.data.username}`)
|
||||
setIsLoading(false)
|
||||
}
|
||||
catch(err){
|
||||
@ -90,6 +149,8 @@ function Profile () {
|
||||
|
||||
return (
|
||||
<div className="profile">
|
||||
{/* <img className="profile-pic" src={DefaultPicture} alt="Profile pic" />
|
||||
*/}
|
||||
{profilePicture ? (
|
||||
<img className="profile-pic" src={`data:image/jpeg;base64,${profilePicture}`} />
|
||||
) : (
|
||||
@ -99,9 +160,12 @@ function Profile () {
|
||||
{isLoading || !user ? (
|
||||
<h1>Loading...</h1>
|
||||
) : (
|
||||
<h1 className='user_name'>{user.nickname}</h1>
|
||||
<h1>{user.nickname}</h1>
|
||||
)}
|
||||
</span>
|
||||
|
||||
|
||||
|
||||
{mine ? (
|
||||
<div>
|
||||
<motion.div >
|
||||
@ -112,22 +176,25 @@ function Profile () {
|
||||
<>
|
||||
<label htmlFor="file-input" className="edit_name"><MdOutlinePhotoLibrary/></label>
|
||||
<input type="file" id="file-input" className="file-input" accept="image/*" onChange={handleFileChange} />
|
||||
<AnimatePresence initial={false} onExitComplete={() => null}>
|
||||
{error ? (
|
||||
<RedAlert handleClose={closeError} text={'Error : upload failed'} />
|
||||
): ("")}
|
||||
</AnimatePresence>
|
||||
</>
|
||||
)}
|
||||
</motion.div>
|
||||
|
||||
{/* <div className="file-upload-container"> */}
|
||||
{/* <button onClick={handleUpload} className="upload-button">Upload</button> */}
|
||||
{/* <button onClick={handleUpload} className="upload-button">Upload</button> */}
|
||||
{/* </div> */}
|
||||
</div>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
|
||||
|
||||
|
||||
<AnimatePresence
|
||||
initial={false}
|
||||
onExitComplete={() => null}>
|
||||
{modalOpen && <ModalEdit/>}
|
||||
{modalOpen && <ModalEdit modalOpen={modalOpen} handleclose={close}/>}
|
||||
</AnimatePresence>
|
||||
</div>
|
||||
)
|
||||
@ -135,7 +202,8 @@ function Profile () {
|
||||
|
||||
function Home () {
|
||||
const [move, setmove ] = useState(false);
|
||||
const [user, setUser] = useState<User>();
|
||||
const [user, setUser] = useState([]);
|
||||
|
||||
const [successQr, setSuccessQr] = useState(false);
|
||||
const [successSword, setSuccessSword] = useState(false);
|
||||
const [successCrown, setSuccessCrown] = useState(false);
|
||||
@ -143,29 +211,20 @@ function Home () {
|
||||
const closeSword = () => setSuccessSword(false);
|
||||
const closeCrown = () => setSuccessCrown(false);
|
||||
|
||||
const { username } = useParams();
|
||||
|
||||
useEffect(() => {
|
||||
const fetchSuccess = async () => {
|
||||
try {
|
||||
if (!username)
|
||||
{
|
||||
const tmpUser = await api.get("/profile");
|
||||
setUser(tmpUser.data);
|
||||
}
|
||||
else
|
||||
{
|
||||
const tmpUser = await api.post("/user", {username: username});
|
||||
setUser(tmpUser.data);
|
||||
}
|
||||
}
|
||||
catch (error)
|
||||
{
|
||||
console.log(error);
|
||||
}
|
||||
};
|
||||
fetchSuccess();
|
||||
}, []);
|
||||
})
|
||||
|
||||
return (
|
||||
<motion.div className="page"
|
||||
@ -173,19 +232,19 @@ function Home () {
|
||||
animate={{opacity: 1}}
|
||||
exit={{opacity: -1}}>
|
||||
<div>
|
||||
{user && user.otp_verified ? (
|
||||
{user.otp_verified ? (
|
||||
<MdQrCodeScanner className='success' onClick={() => setSuccessQr(true)}/>
|
||||
):("")}
|
||||
{user && user.win >= 2 ? (
|
||||
{user.win >= 2 ? (
|
||||
<GiWingedSword className="success" onClick={() => setSuccessSword(true)}/>
|
||||
):("")}
|
||||
{user && user.win >= 5 ? (
|
||||
|
||||
{user.win >= 5 ? (
|
||||
<GiCrownedSkull className="success" onClick={() => setSuccessCrown(true)}/>
|
||||
):("")}
|
||||
</div>
|
||||
<div className="home">
|
||||
<motion.div
|
||||
animate={{x: move ? '-50%' : '25%'}}
|
||||
<motion.div animate={{x: move ? -200: 120}}
|
||||
transition={{type: "tween", duration: 0.5}}>
|
||||
<Profile/>
|
||||
</motion.div>
|
||||
@ -195,8 +254,9 @@ function Home () {
|
||||
</div>
|
||||
<motion.div
|
||||
className="div_history"
|
||||
// className="history"
|
||||
onClick={ () => setmove(!move)}>
|
||||
<Link to="#" className="history"> {move ? (<AiOutlineCloseCircle/>):(<AiOutlineHistory/>)} Match History</Link>
|
||||
<Link to="#" className="history"><AiOutlineHistory/> Match History</Link>
|
||||
</motion.div>
|
||||
<AnimatePresence initial={false} onExitComplete={() => null}>
|
||||
{successQr ? (
|
||||
|
||||
47
containers/react/src/pages/Login42.tsx
Normal file
47
containers/react/src/pages/Login42.tsx
Normal file
@ -0,0 +1,47 @@
|
||||
// import GoogleLogin from 'react-google-login';
|
||||
import { useEffect } from 'react';
|
||||
import axios from 'axios';
|
||||
import React from 'react';
|
||||
// import setupLogin from '../script/login42';
|
||||
// import React, { useEffect } from 'react';
|
||||
|
||||
function Login42()
|
||||
{
|
||||
useEffect(() => {
|
||||
console.log("you said yes to connect with 42");
|
||||
const url = new URL(window.location.href);
|
||||
// console.log(`url is= ${url}`);
|
||||
const code = url.searchParams.get('code');
|
||||
console.log(`code is= ${code}`);
|
||||
|
||||
const data = {
|
||||
grant_type: 'authorization_code',
|
||||
// client_id: 'u-s4t2ud-6d29dfa49ba7146577ffd8bf595ae8d9e5aaa3e0a9615df18777171ebf836a41',
|
||||
// client_secret: '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',
|
||||
client_id: process.env.REACT_APP_CLIENT_UID,
|
||||
client_secret: process.env.REACT_APP_API_SECRET,
|
||||
code: code,
|
||||
redirect_uri: 'http://' + process.env.REACT_APP_BASE_URL + '/login42',
|
||||
};
|
||||
|
||||
|
||||
axios.post('https://api.intra.42.fr/oauth/token', data)
|
||||
.then(response => {
|
||||
// handle success response
|
||||
console.log(response);
|
||||
})
|
||||
.catch(error => {
|
||||
// handle error response
|
||||
console.error(error);
|
||||
});
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<p>"COUCOU LOGIN" </p>
|
||||
{/* <script src="../script/login42.js"></script> */}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default Login42;
|
||||
@ -1,23 +0,0 @@
|
||||
import '../styles/old.css';
|
||||
import '../styles/field.css';
|
||||
import React from 'react';
|
||||
|
||||
function HomeLogin()
|
||||
{
|
||||
const handleButtonClick = () => {
|
||||
const token = localStorage.getItem('token')
|
||||
console.log(`token type= ${typeof token}`);
|
||||
if (token !== null && typeof token === 'string')
|
||||
return ;
|
||||
let path = process.env.REACT_APP_INTRA_URL || "";
|
||||
window.location.replace(path);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="notClicked">
|
||||
<button onClick={handleButtonClick} className="playButton" >LOGIN</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default HomeLogin;
|
||||
@ -1,9 +1,29 @@
|
||||
import React from "react";
|
||||
// import Sidebar from '../components/Messages/Sidebar'
|
||||
import Chats from "../components/Messages/Chats.tsx"
|
||||
import '../styles/Messages.css'
|
||||
import { motion } from 'framer-motion'
|
||||
|
||||
// import {io} from 'socket.io-client'
|
||||
|
||||
function Messages() {
|
||||
// const socket = useRef(io("ws://localhost:8900"))
|
||||
|
||||
// useEffect(() => {
|
||||
// setSocket(io("ws://localhost:8900"))
|
||||
// }, [])
|
||||
// const socket = socketIO.connect('http://localhost:4000');
|
||||
|
||||
// axios.get('http://localhost/api/user/id')
|
||||
// .then(function());
|
||||
|
||||
// console.log(socket)
|
||||
// useEffect(() => {
|
||||
// socket.current.emit("addUser", user._id);
|
||||
// socket.current.on("getUsers", users=>{
|
||||
// console.log(users)
|
||||
// })
|
||||
// }, [user])
|
||||
return (
|
||||
<>
|
||||
<motion.div className="home"
|
||||
@ -11,6 +31,7 @@ function Messages() {
|
||||
animate={{opacity: 1}}
|
||||
exit={{opacity: 0}}>
|
||||
<div className="container">
|
||||
{/* <Sidebar/> */}
|
||||
<Chats/>
|
||||
</div>
|
||||
</motion.div>
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import React from 'react';
|
||||
import '../styles/field.css';
|
||||
// import { useHistory } from 'react-router-dom';
|
||||
import { useNavigate } from "react-router-dom";
|
||||
|
||||
function PlayButton() {
|
||||
@ -14,6 +15,8 @@ function PlayButton() {
|
||||
return (
|
||||
<div className="notClicked" id="canvas_container">
|
||||
<button onClick={handleButtonClick} className="playButton">Play</button>
|
||||
{/* !buttonClicked && <button onClick={handleButtonClick}>Draw on Canvas</button> */}
|
||||
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@ -6,14 +6,14 @@ import "../styles/App.css";
|
||||
import api from '../script/axiosApi.tsx';
|
||||
|
||||
import QRCodeStyling from "qr-code-styling";
|
||||
import { AnimatePresence, motion } from 'framer-motion'
|
||||
import RedAlert from "../components/Alert/RedAlert.tsx";
|
||||
import { motion } from 'framer-motion'
|
||||
|
||||
|
||||
|
||||
const qrCode = new QRCodeStyling({
|
||||
width: 300,
|
||||
height: 300,
|
||||
// image: "../assets/profile.jpg",
|
||||
dotsOptions: {
|
||||
color: "black",
|
||||
type: "rounded"
|
||||
@ -28,14 +28,16 @@ const qrCode = new QRCodeStyling({
|
||||
});
|
||||
|
||||
function QrCode () {
|
||||
// const url = "https://www.youtube.com";
|
||||
// const ref = useRef(null);
|
||||
const ref = useRef<HTMLDivElement>(null);
|
||||
const [user, setUser] = useState(false);
|
||||
const [url, setUrl] = useState("");
|
||||
const [secret, setSecret] = useState(false);
|
||||
const [code, setCode] = useState('');
|
||||
const [activated, setActivated] = useState(false);
|
||||
const [err, setErr] = useState(false);
|
||||
const closeErr = () => setErr(false);
|
||||
|
||||
// const history = useHistory();
|
||||
|
||||
useEffect(() => {
|
||||
if (ref.current)
|
||||
@ -78,10 +80,6 @@ function QrCode () {
|
||||
const res = await api.post("/verifyOtp", {token: code})
|
||||
console.log("res= ", res.data)
|
||||
console.log("res= ", res)
|
||||
if (!res.data)
|
||||
{
|
||||
setErr(true);
|
||||
}
|
||||
if (res.data === 1)
|
||||
{
|
||||
console.log("registered")
|
||||
@ -150,7 +148,7 @@ function QrCode () {
|
||||
<h1>Double Auth Validation</h1>
|
||||
<input
|
||||
onKeyDown={handleKeyPress}
|
||||
type="number"
|
||||
type="text"
|
||||
className="qr"
|
||||
placeholder="6 Digits Code"
|
||||
value={code}
|
||||
@ -158,13 +156,8 @@ function QrCode () {
|
||||
/>
|
||||
</>
|
||||
) : (
|
||||
<button className="desactivate" onClick={handleDesactivate}>Desactivate 2FA</button>
|
||||
<button onClick={handleDesactivate}>Desactivate 2FA</button>
|
||||
)}
|
||||
<AnimatePresence
|
||||
initial={false}
|
||||
onExitComplete={() => null}>
|
||||
{err ? (<RedAlert handleClose={closeErr} text="Error: Bad intput. Try again"/>):("")}
|
||||
</AnimatePresence>
|
||||
</>
|
||||
|
||||
{/* {!localStorage.getItem('token') && (
|
||||
|
||||
9
containers/react/src/pages/Social.tsx
Normal file
9
containers/react/src/pages/Social.tsx
Normal file
@ -0,0 +1,9 @@
|
||||
import React from "react";
|
||||
|
||||
function Social (){
|
||||
return (
|
||||
<div>je suis la partie social</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Social
|
||||
@ -1,6 +1,12 @@
|
||||
import { useEffect } from 'react';
|
||||
// import io from 'socket.io-client';
|
||||
|
||||
import api from '../script/axiosApi.tsx';
|
||||
|
||||
// import { useEffect, useRef } from 'react';
|
||||
import io from 'socket.io-client';
|
||||
// const socket = io('http://192.168.1.14:4000');
|
||||
// const socket = io('http://86.209.110.20:4000');
|
||||
// const socket = io('http://172.29.113.91:4000');
|
||||
|
||||
interface GameProps {
|
||||
privateParty: boolean,
|
||||
@ -10,21 +16,6 @@ interface GameProps {
|
||||
|
||||
function DrawCanvas(option: number, gameParam: GameProps) {
|
||||
|
||||
// useEffect(() => {
|
||||
// const handleBeforeUnload = async (event: { preventDefault: () => void; returnValue: string; }) => {
|
||||
// try {
|
||||
// await api.post("/status", {status: 1});
|
||||
// } catch (err) {
|
||||
// console.log(err);
|
||||
// }
|
||||
// };
|
||||
|
||||
// window.addEventListener('beforeunload', handleBeforeUnload);
|
||||
// return () => {
|
||||
// window.removeEventListener('beforeunload', handleBeforeUnload);
|
||||
// };
|
||||
// }, []);
|
||||
|
||||
console.log(`option= ${option}`);
|
||||
const superpowerModifier = option & 1; // Retrieves the superpower modifier
|
||||
const obstacleModifier = (option >> 1) & 1; // Retrieves the obstacle modifier
|
||||
@ -34,6 +25,11 @@ function DrawCanvas(option: number, gameParam: GameProps) {
|
||||
console.log(`obstacleModifier = ${obstacleModifier}`);
|
||||
console.log(`speedModifier = ${speedModifier}`);
|
||||
|
||||
|
||||
|
||||
// const socketRef = useRef(null);
|
||||
// socketRef.current = io('http://localhost:4000');
|
||||
|
||||
function launchGame()
|
||||
{
|
||||
if (!gameParam.privateParty)
|
||||
@ -53,8 +49,11 @@ function DrawCanvas(option: number, gameParam: GameProps) {
|
||||
}
|
||||
}
|
||||
|
||||
// const socket = socketRef.current
|
||||
console.log("start function");
|
||||
const canvas = document.getElementById('myCanvas') as HTMLCanvasElement | null;
|
||||
|
||||
// let canvas: HTMLElement | null;
|
||||
const canvas = document.getElementById('myCanvas') as HTMLCanvasElement | null;;
|
||||
if (!canvas)
|
||||
return ;
|
||||
|
||||
@ -62,7 +61,15 @@ function DrawCanvas(option: number, gameParam: GameProps) {
|
||||
if(!ctx)
|
||||
return ;
|
||||
|
||||
const socket = io('http://' + process.env.REACT_APP_SOCKET_URL + ':4000', { transports: ['polling'] });
|
||||
const socket = io('http://localhost:4000', { transports: ['polling'] });
|
||||
// useEffect(() => {
|
||||
// console.log("useeffect?????????????????")
|
||||
// return () => {
|
||||
// console.log("000000000000000000000000000000000")
|
||||
// socketRef.current.disconnect();
|
||||
// };
|
||||
// }, []);
|
||||
|
||||
|
||||
//========================================================================================================
|
||||
//========================================================================================================
|
||||
@ -80,6 +87,7 @@ function DrawCanvas(option: number, gameParam: GameProps) {
|
||||
let running = true;
|
||||
const scale = window.devicePixelRatio;
|
||||
canvas.width = canvas.offsetWidth;
|
||||
// canvas.height = canvas.width * 0.7
|
||||
canvas.height = canvas.offsetHeight;
|
||||
|
||||
//paddle var
|
||||
@ -116,8 +124,6 @@ function DrawCanvas(option: number, gameParam: GameProps) {
|
||||
const maxScore = 5;
|
||||
|
||||
let lastUpdateTime = performance.now();
|
||||
let lastPower = 0;
|
||||
|
||||
|
||||
const maxAngle = 50;
|
||||
let maxBounceAngle = (maxAngle * Math.PI) / 180;
|
||||
@ -131,13 +137,25 @@ function DrawCanvas(option: number, gameParam: GameProps) {
|
||||
socket.on('pong:win', async () => {
|
||||
myScore = maxScore;
|
||||
console.log("instant win opponent disconnect")
|
||||
// const data = {
|
||||
// myScore: myScore,
|
||||
// opScore: hisScore,
|
||||
// opName: opName,
|
||||
// opRank: opRank,
|
||||
// };
|
||||
|
||||
// await api.post('/win', data);
|
||||
console.log("after request1")
|
||||
await api.post('/status', {status: 1});
|
||||
console.log("after request2")
|
||||
//disconnect ?
|
||||
running = false;
|
||||
socket.emit('pong:disconnect', {id: myId});
|
||||
console.log("before reload")
|
||||
// window.location.replace("http://" + process.env.REACT_APP_BASE_URL + "/pong");
|
||||
// window.location.reload();
|
||||
return ;
|
||||
// console.log("send all ?? win");
|
||||
|
||||
});
|
||||
|
||||
@ -152,9 +170,7 @@ socket.on('pong:privateId', async (data) => {
|
||||
|
||||
socket.on('pong:gameId', async (data) => {
|
||||
console.log("gameId received");
|
||||
gameId = data.gameId;
|
||||
console.log("gameid = ", gameId);
|
||||
console.log("data gameid = ", data);
|
||||
gameId = data;
|
||||
|
||||
try {
|
||||
let response = await api.get('/profile');
|
||||
@ -174,24 +190,15 @@ socket.on('pong:gameId', async (data) => {
|
||||
|
||||
console.log("emit to name");
|
||||
socket.emit('pong:name', info);
|
||||
if (data.id === myId)
|
||||
{
|
||||
console.log("myId= true")
|
||||
vX = 0.0005;
|
||||
}
|
||||
else
|
||||
{
|
||||
console.log("myId= false")
|
||||
vX = -0.0005;
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
// Handle error here
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
socket.on('pong:name', (data) => {
|
||||
opName = data.name;
|
||||
opName = data;
|
||||
console.log(`opponent Name= ${opName}`)
|
||||
});
|
||||
|
||||
@ -215,6 +222,7 @@ socket.on('pong:info', (data) => {
|
||||
vY = data.vY;
|
||||
});
|
||||
|
||||
|
||||
socket.on('pong:paddle', (data) => {
|
||||
console.log("paddle info receive")
|
||||
oPaddleY = (data.paddleY / data.height) * canvas.height
|
||||
@ -227,25 +235,23 @@ socket.on('pong:power', (data) => {
|
||||
opPaddleHeight = canvas.height;
|
||||
|
||||
setTimeout(() => {
|
||||
// code à exécuter après 5 secondes
|
||||
opPaddleHeight = canvas.height * 0.25;
|
||||
oPaddleY = canvas.height / 2 - paddleHeight / 2;
|
||||
console.log('Cinq secondes se sont écoulées.');
|
||||
}, 5000);
|
||||
// oPaddleY = (data.paddleY / data.height) * canvas.height
|
||||
});
|
||||
|
||||
socket.on('pong:point', (data) => {
|
||||
// hisScore += 1;
|
||||
console.log("gain point");
|
||||
// if (vX != 0)
|
||||
// {
|
||||
// console.log("up point");
|
||||
myScore = data.point;
|
||||
vX = -0.0005;
|
||||
vY = 0;
|
||||
ballX = canvas.width / 2;
|
||||
ballY = canvas.height / 2;
|
||||
});
|
||||
|
||||
socket.on('pong:hisPoint', (data) => {
|
||||
console.log("myPointawdawdawdawd point");
|
||||
hisScore = data.point;
|
||||
vX = -0.0005;
|
||||
// }
|
||||
vX = 0;
|
||||
vY = 0;
|
||||
ballX = canvas.width / 2;
|
||||
ballY = canvas.height / 2;
|
||||
@ -317,25 +323,6 @@ socket.on('pong:hisPoint', (data) => {
|
||||
point: hisScore,
|
||||
}
|
||||
socket.emit('pong:point', info);
|
||||
vX = 0.0005;
|
||||
}
|
||||
|
||||
function send_my_point()
|
||||
{
|
||||
if (!gameId || !canvas)
|
||||
return ;
|
||||
const info = {
|
||||
id: myId,
|
||||
gameId: gameId,
|
||||
point: myScore,
|
||||
}
|
||||
socket.emit('pong:myPoint', info);
|
||||
myScore++;
|
||||
vX = 0.0005;
|
||||
vY = 0;
|
||||
ballX = canvas.width / 2;
|
||||
ballY = canvas.height / 2;
|
||||
send_forced_info();
|
||||
}
|
||||
|
||||
function send_paddle_info()
|
||||
@ -345,6 +332,7 @@ socket.on('pong:hisPoint', (data) => {
|
||||
const info = {
|
||||
id: myId,
|
||||
paddleY: paddleY,
|
||||
// width: canvas.width,
|
||||
height: canvas.height,
|
||||
gameId: gameId,
|
||||
};
|
||||
@ -397,6 +385,7 @@ socket.on('pong:hisPoint', (data) => {
|
||||
ctx.fillRect(canvas.width / 2 - ctx.lineWidth / 2, 0, canvas.width / 300, canvas.height);
|
||||
|
||||
ctx.beginPath();
|
||||
// ctx.lineWidth = 5;
|
||||
ctx.arc(canvas.width / 2, canvas.height / 2, circleRadius, 0, 2 * Math.PI);
|
||||
ctx.strokeStyle = 'white'; // couleur de dessin
|
||||
ctx.stroke(); // dessin du contour
|
||||
@ -422,6 +411,7 @@ socket.on('pong:hisPoint', (data) => {
|
||||
return ;
|
||||
ctx.beginPath();
|
||||
ctx.arc(ballX, ballY, ballRadius, 0, 2 * Math.PI);
|
||||
// ctx.lineWidth = 2;
|
||||
ctx.fillStyle = 'red ';
|
||||
ctx.fill();
|
||||
}
|
||||
@ -433,6 +423,11 @@ socket.on('pong:hisPoint', (data) => {
|
||||
//========================================================================================================
|
||||
//========================================================================================================
|
||||
|
||||
|
||||
// while (!gameId)
|
||||
// ;
|
||||
|
||||
// Define a function to stop the drawing process
|
||||
const stopDrawCanvas = async () => {
|
||||
running = false;
|
||||
|
||||
@ -442,38 +437,32 @@ socket.on('pong:hisPoint', (data) => {
|
||||
{
|
||||
console.log("stopDrawCanvas2")
|
||||
try{
|
||||
await api.post('/status', {status: 1});
|
||||
// const info = {
|
||||
// id: myId,
|
||||
// option: option,
|
||||
// };
|
||||
|
||||
await api.post("deleteInvite", {username: gameParam.username})
|
||||
}
|
||||
catch (err){
|
||||
console.log(err)
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const data = {
|
||||
myScore: myScore,
|
||||
opScore: 5,
|
||||
opName: opName,
|
||||
opRank: opRank,
|
||||
};
|
||||
await api.post('/loss', data);
|
||||
// await api.post('/status', {status: 1});
|
||||
}
|
||||
socket.emit('pong:disconnect', {id: myId});
|
||||
window.location.replace("http://" + process.env.REACT_APP_BASE_URL + "/pong");
|
||||
// window.location.reload();
|
||||
// Perform any necessary cleanup tasks
|
||||
// ...
|
||||
};
|
||||
|
||||
async function draw(timestamp: number)
|
||||
{
|
||||
console.log("turning, running= ", running);
|
||||
if (!running)
|
||||
{
|
||||
window.location.replace("http://" + process.env.REACT_APP_BASE_URL + "/pong")
|
||||
return ;
|
||||
}
|
||||
if (!gameId || !canvas )
|
||||
{
|
||||
// console.log("nogameid score= ", myScore);
|
||||
requestAnimationFrame(draw);
|
||||
return ;
|
||||
}
|
||||
@ -490,7 +479,9 @@ async function draw(timestamp: number)
|
||||
{
|
||||
await api.post('/win', data);
|
||||
await api.post('/status', {status: 1});
|
||||
//disconnect ?
|
||||
socket.emit('pong:disconnect', {id: myId});
|
||||
|
||||
console.log("send all ?? win");
|
||||
}
|
||||
else
|
||||
@ -498,9 +489,11 @@ async function draw(timestamp: number)
|
||||
await api.post('/loss', data);
|
||||
await api.post('/status', {status: 1});
|
||||
socket.emit('pong:disconnect', {id: myId});
|
||||
//disconnect ?
|
||||
console.log("send loose");
|
||||
}
|
||||
window.location.replace("http://" + process.env.REACT_APP_BASE_URL + "/pong");
|
||||
// window.location.reload();
|
||||
return ;
|
||||
}
|
||||
|
||||
@ -511,6 +504,7 @@ async function draw(timestamp: number)
|
||||
|
||||
if (!ctx)
|
||||
return ;
|
||||
// requestAnimationFrame(draw);
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||
drawPaddle();
|
||||
drawcenter();
|
||||
@ -574,11 +568,13 @@ async function draw(timestamp: number)
|
||||
}
|
||||
if (ballY - ballRadius - 2 <= 0 || ballY + ballRadius + 2 >= canvas.height) //touch up or down wall
|
||||
{
|
||||
// if ()
|
||||
vY = -vY;
|
||||
if (ballY > (canvas.height / 2))//down wall
|
||||
ballY = canvas.height - ballRadius - 2
|
||||
else
|
||||
ballY = ballRadius + 2
|
||||
// send_info();
|
||||
}
|
||||
}
|
||||
|
||||
@ -597,15 +593,31 @@ async function draw(timestamp: number)
|
||||
}
|
||||
ballX = canvas.width / 2;
|
||||
ballY = canvas.height / 2;
|
||||
vX = 0.0005;
|
||||
vX = 0;
|
||||
vY = 0;
|
||||
hisScore += 1;
|
||||
send_point();
|
||||
// send_forced_info();
|
||||
}
|
||||
if (ballX > (canvas.width * 1.2) && ballX - (vX * 2) > canvas.width)
|
||||
if (ballX > canvas.width)
|
||||
{
|
||||
console.log("ball out win point pls")
|
||||
send_my_point();
|
||||
// if (ballX > canvas.width * 2)
|
||||
// socket.emit
|
||||
// console.log("win point")
|
||||
// if (ballY <= paddleY + paddleHeight + ballRadius && ballY >= paddleY - ballRadius)
|
||||
// {
|
||||
// console.log('true hehe');
|
||||
// ballX = paddleX + paddleWidth + ballRadius;
|
||||
// updateVector();
|
||||
// return ;
|
||||
// }
|
||||
// ballX = canvas.width / 2;
|
||||
// ballY = canvas.height / 2;
|
||||
// vX = 0;
|
||||
// vY = 0;
|
||||
// hisScore += 1;
|
||||
// send_point();
|
||||
// // send_forced_info();
|
||||
}
|
||||
|
||||
}
|
||||
@ -634,14 +646,21 @@ async function draw(timestamp: number)
|
||||
|
||||
document.addEventListener("touchmove", event => {
|
||||
const touchY = event.touches[0].pageY;
|
||||
const newY = touchY > lastTouchY ? paddleY - (lastTouchY - touchY) : paddleY + (touchY - lastTouchY);
|
||||
|
||||
// if (!lastTouchY)
|
||||
// {
|
||||
// vX = -0.01;
|
||||
// lastTouchY = touchY;
|
||||
// return;
|
||||
// }
|
||||
const newY = touchY > lastTouchY ? paddleY - (lastTouchY - touchY) : paddleY + (touchY - lastTouchY);
|
||||
updatePaddlePosition(newY);
|
||||
lastTouchY = touchY;
|
||||
send_paddle_info();
|
||||
});
|
||||
|
||||
document.addEventListener("keydown", event => {
|
||||
// console.log(event.code);
|
||||
if (event.code === "ArrowUp")
|
||||
{
|
||||
if ((paddleY - paddleSpeed) > 0)
|
||||
@ -654,24 +673,50 @@ async function draw(timestamp: number)
|
||||
paddleY += paddleSpeed; // déplacer la raquette vers le bas
|
||||
send_paddle_info();
|
||||
}
|
||||
else if (event.code === "KeyW")
|
||||
else if (event.code === "Space")//space
|
||||
{
|
||||
console.log('vx change to -1');
|
||||
vX = -0.0001;
|
||||
|
||||
// ballSpeed = 0.0001;
|
||||
vY = 0;
|
||||
send_forced_info();
|
||||
// vX = 0.0001;
|
||||
}
|
||||
else if (event.code === "KeyE")
|
||||
{
|
||||
// console.log('vx change to -1');
|
||||
vX = 0;
|
||||
vY = 0;
|
||||
ballX = canvas.width / 2;
|
||||
ballY = canvas.height / 2;
|
||||
send_forced_info();
|
||||
}
|
||||
else if (event.code === "KeyQ" )
|
||||
{
|
||||
if (vX < 0.003 * canvas.width && vX > -0.003 * canvas.width)
|
||||
{
|
||||
if (vX > 0)
|
||||
vX += 0.0001;
|
||||
else
|
||||
vX -= 0.0001;
|
||||
}
|
||||
send_forced_info();
|
||||
// console.log(`vx = ${vX}`);
|
||||
}
|
||||
else if (event.code === "KeyR")
|
||||
{
|
||||
let date = new Date();
|
||||
console.log("last time =", date.getTime() - lastPower)
|
||||
if (date.getTime() - lastPower < 15000)//10000 + 5000
|
||||
return ;
|
||||
if (!superpowerModifier)
|
||||
return ;
|
||||
paddleY = 0;
|
||||
paddleHeight = canvas.height;
|
||||
use_power();
|
||||
setTimeout(() => {
|
||||
// code à exécuter après 5 secondes
|
||||
paddleHeight = canvas.height * 0.25;
|
||||
paddleY = canvas.height / 2 - paddleHeight / 2;
|
||||
console.log('Cinq secondes se sont écoulées.');
|
||||
}, 5000);
|
||||
date = new Date();
|
||||
lastPower = date.getTime();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
13
containers/react/src/reportWebVitals.js
Normal file
13
containers/react/src/reportWebVitals.js
Normal file
@ -0,0 +1,13 @@
|
||||
const reportWebVitals = onPerfEntry => {
|
||||
if (onPerfEntry && onPerfEntry instanceof Function) {
|
||||
import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
|
||||
getCLS(onPerfEntry);
|
||||
getFID(onPerfEntry);
|
||||
getFCP(onPerfEntry);
|
||||
getLCP(onPerfEntry);
|
||||
getTTFB(onPerfEntry);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export default reportWebVitals;
|
||||
@ -3,15 +3,12 @@ import { useState, useEffect } from 'react'
|
||||
import queryString from 'query-string';
|
||||
import api from "./axiosApi.tsx";
|
||||
import axios from 'axios';
|
||||
import React from 'react';
|
||||
|
||||
import {Matchlog, User} from "../../interfaces.tsx"
|
||||
|
||||
function SuccessToken() {
|
||||
const location = useLocation();
|
||||
const { data } = queryString.parse(location.search);
|
||||
const [code, setCode] = useState('');
|
||||
const [user, setUser] = useState<User>();
|
||||
const [user, setUser] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (!data) {
|
||||
@ -40,7 +37,7 @@ function SuccessToken() {
|
||||
getUser();
|
||||
}, [data]);
|
||||
|
||||
const handleKeyPress = async (e: { key: string; })=>{
|
||||
const handleKeyPress = async (e)=>{
|
||||
// console.log(`e in press= ${e.key}`)
|
||||
if (e.key !== "Enter")
|
||||
return ;
|
||||
@ -93,8 +90,7 @@ function SuccessToken() {
|
||||
// Render a loading indicator or return null while user is being fetched
|
||||
return <h1>Loading...</h1>;
|
||||
}
|
||||
if (!data)
|
||||
return (<></>);
|
||||
|
||||
const cleanData = data.slice(1, -1); // Declare cleanData here as well
|
||||
|
||||
if (!user.otp_verified) {
|
||||
|
||||
@ -5,41 +5,19 @@
|
||||
background-color: black;
|
||||
height: 100%;
|
||||
}
|
||||
input.qr::-webkit-outer-spin-button,
|
||||
input.qr::-webkit-inner-spin-button {
|
||||
-webkit-appearance: none;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
input.qr{
|
||||
width: auto;
|
||||
width: 20%;
|
||||
border-radius: 5px;
|
||||
background-color: rgb(0, 0, 0);
|
||||
margin : 1%;
|
||||
border-color:rgb(42, 41, 41);
|
||||
border-style: solid;
|
||||
border-width: 1px;
|
||||
color: #ccc;
|
||||
color:white;
|
||||
}
|
||||
|
||||
.desactivate {
|
||||
margin: 20%;
|
||||
color: ghostwhite;
|
||||
outline: 0;
|
||||
border-radius: 100px;
|
||||
padding: 2%;
|
||||
background-image: linear-gradient(90deg, #5843e4, #5a0760);
|
||||
border: 0;
|
||||
font-size: x-large;
|
||||
}
|
||||
.App-logo {
|
||||
height: 40vmin;
|
||||
pointer-events: none;
|
||||
}
|
||||
.centermargin
|
||||
{
|
||||
margin-left: 40px;
|
||||
margin-right: 40px;
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: no-preference) {
|
||||
.App-logo {
|
||||
@ -70,9 +48,3 @@ input.qr{
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
.friendRequest {
|
||||
margin-left: 4vh;
|
||||
stroke-width: 0.5;
|
||||
font-size: x-large;
|
||||
}
|
||||
|
||||
@ -3,7 +3,6 @@
|
||||
margin: 50px;
|
||||
}
|
||||
|
||||
|
||||
.rank_elements {
|
||||
border-width:1px;
|
||||
border-style:solid;
|
||||
@ -19,23 +18,11 @@
|
||||
/* background-color: #5843e4; */
|
||||
/* border-color: white; */
|
||||
overflow: scroll;
|
||||
height: 68vh;
|
||||
height: 70vh;
|
||||
}
|
||||
|
||||
.profilePic{
|
||||
margin-left: 10px;
|
||||
/* margin-top: 10px; */
|
||||
height: 30px;
|
||||
width: 30px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 755px){
|
||||
.game{
|
||||
display: grid;
|
||||
height: 20vh;
|
||||
}
|
||||
.scroll{
|
||||
height: 20vh;
|
||||
}
|
||||
}
|
||||
@ -127,5 +127,4 @@ span {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 1;
|
||||
}
|
||||
@ -1,6 +1,6 @@
|
||||
.home{
|
||||
background-color: rgb(0, 0, 0);
|
||||
height: 70vh;
|
||||
height: 90vh;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
@ -19,8 +19,7 @@ select{
|
||||
border: 0!important;
|
||||
margin: 5px;
|
||||
font-size: 18px;
|
||||
padding: 5px;
|
||||
border-radius: 1000px;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.modal{
|
||||
@ -55,7 +54,6 @@ select{
|
||||
height: 74vh;
|
||||
width: 30%;
|
||||
overflow: scroll;
|
||||
border-radius: 0px 0px 0px 10px;
|
||||
/* width: 2rem; */
|
||||
/* height: 4rem; */
|
||||
}
|
||||
@ -108,19 +106,6 @@ select{
|
||||
margin-top: 0px;
|
||||
}
|
||||
|
||||
.navbarSocial{
|
||||
/* width: clamp(50%, 500px, 20%); */
|
||||
/* height: min(50%, 100px); */
|
||||
display: flex;
|
||||
align-items: center;
|
||||
/* background-color: yellow; */
|
||||
margin: 10px;
|
||||
background-image: linear-gradient(90deg, #5843e4, #5a0760);
|
||||
color: white;
|
||||
padding: 3px;
|
||||
border-radius: 100px;
|
||||
}
|
||||
|
||||
.pic{
|
||||
height: 35px;
|
||||
width: 35px;
|
||||
@ -146,17 +131,16 @@ select{
|
||||
}
|
||||
|
||||
.messages{
|
||||
/* background-color: rgb(26, 26, 26); */
|
||||
background-color: rgb(26, 26, 26);
|
||||
/* height: calc(100% - 118px); */
|
||||
width: 70%;
|
||||
/* height: 300px; */
|
||||
border-radius: 0px 0px 10px 0px;
|
||||
overflow: scroll;
|
||||
}
|
||||
|
||||
.input{
|
||||
display: flex;
|
||||
height: 6vh;
|
||||
height: 50px;
|
||||
background-color: white;
|
||||
color:#060b26;
|
||||
border: none;
|
||||
@ -186,7 +170,6 @@ input{
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 50%;
|
||||
margin: 10px;
|
||||
}
|
||||
|
||||
.messageContent{
|
||||
@ -219,19 +202,8 @@ p {
|
||||
text-decoration: none;
|
||||
font-weight:lighter;
|
||||
margin: 1%;
|
||||
height: 25px;
|
||||
}
|
||||
|
||||
.playInvite{
|
||||
margin: 5%;
|
||||
color: ghostwhite;
|
||||
outline: 0;
|
||||
border-radius: 100px;
|
||||
padding: 3%;
|
||||
background-image: linear-gradient(90deg, #5843e4, #5a0760);
|
||||
width: 42%;
|
||||
font-size: x-large;
|
||||
}
|
||||
.darkSubmit{
|
||||
display: inline-block;
|
||||
color: white;
|
||||
@ -256,9 +228,9 @@ p {
|
||||
backdrop-filter: sepia(90%);
|
||||
background-color: rgba(0, 0, 0, 0.3);
|
||||
border-radius: 4px;
|
||||
width: 15rem;
|
||||
height: 2rem;
|
||||
margin-top: 1.3rem;
|
||||
width: 11rem;
|
||||
height: 1.5rem;
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
.greenAlert{
|
||||
@ -276,7 +248,7 @@ p {
|
||||
color: rgba(255, 255, 255, 1);
|
||||
}
|
||||
|
||||
/* .redAlert{
|
||||
.redAlert{
|
||||
width: clamp(50%, 500px, 90%);
|
||||
height: min(50%, 100px);
|
||||
|
||||
@ -285,11 +257,10 @@ p {
|
||||
border-radius: 12px;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
background-color: rgba(133, 6, 6, 0.7);
|
||||
font-size: 25px;
|
||||
color: rgba(255, 255, 255, 1);
|
||||
} */
|
||||
}
|
||||
|
||||
.redAlert{
|
||||
width: clamp(50%, 500px, 90%);
|
||||
@ -299,18 +270,12 @@ p {
|
||||
padding: 1rem;
|
||||
border-radius: 12px;
|
||||
flex-direction: row;
|
||||
text-align: center;
|
||||
/* align-items: center; */
|
||||
align-items: center;
|
||||
background-color: rgba(133, 6, 6, 0.7);
|
||||
font-size: 25px;
|
||||
color: rgba(255, 255, 255, 1);
|
||||
}
|
||||
|
||||
.text_alert{
|
||||
text-align: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.yellowAlert{
|
||||
width: clamp(50%, 500px, 90%);
|
||||
height: min(50%, 100px);
|
||||
@ -320,13 +285,17 @@ p {
|
||||
border-radius: 12px;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
background-color: rgba(212, 175, 55, 0.7);
|
||||
font-size: 25px;
|
||||
color: rgba(255, 255, 255, 1);
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.yellowAlert::p {
|
||||
overflow-wrap: break-word;
|
||||
max-width: 1000px;
|
||||
}
|
||||
|
||||
.modalSetting{
|
||||
width: clamp(50%, 700px, 90%);
|
||||
height: min(50%, 300px);
|
||||
@ -338,17 +307,11 @@ p {
|
||||
/* flex-direction: column; */
|
||||
/* align-items: center; */
|
||||
background-color: #3e3c61;
|
||||
overflow: scroll;
|
||||
}
|
||||
|
||||
.settingFirstPart{
|
||||
margin-top: 10%;
|
||||
margin-left: 20%;
|
||||
}
|
||||
|
||||
.settingFirstPart2{
|
||||
margin-top: 10%;
|
||||
margin-left: 30%;
|
||||
margin-left: 15%;
|
||||
}
|
||||
|
||||
.settingSecondPart{
|
||||
@ -361,7 +324,6 @@ p {
|
||||
.checkbox{
|
||||
display:flex;
|
||||
flex-direction:row;
|
||||
margin-left: 60px;
|
||||
}
|
||||
|
||||
input.in{
|
||||
@ -369,59 +331,23 @@ input.in{
|
||||
margin-left: 0px;
|
||||
background-color: black;
|
||||
color: white;
|
||||
border-radius: 4px;
|
||||
border-radius: 12px;
|
||||
width: 70%;
|
||||
height: 100%;
|
||||
font-weight:100;
|
||||
font-size: 20px;
|
||||
padding: 7px;
|
||||
}
|
||||
|
||||
input.in_howLong{
|
||||
margin-top: 13%;
|
||||
margin-top: 14.5%;
|
||||
margin-left: 0px;
|
||||
background-color: black;
|
||||
color: white;
|
||||
border-radius: 4px;
|
||||
width: 10%;
|
||||
height: 10%;
|
||||
font-weight:100;
|
||||
font-size: 20px;
|
||||
padding: 7px;
|
||||
border-radius: 12px;
|
||||
width: 15%;
|
||||
}
|
||||
|
||||
.mdp{
|
||||
background-color : black;
|
||||
border-radius: 8px;
|
||||
color: white;
|
||||
width: 60%;
|
||||
height: 30%;
|
||||
width: 20%;
|
||||
}
|
||||
|
||||
.case{
|
||||
height: auto;
|
||||
width: auto;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.catchat{
|
||||
font-size: 30px;
|
||||
margin-left: 12px;
|
||||
}
|
||||
|
||||
.block{
|
||||
font-size: 25px;
|
||||
margin-left: 12px;
|
||||
margin-top: 0.2rem;
|
||||
}
|
||||
|
||||
.inside_ckeckbox{
|
||||
height: 25px;
|
||||
margin-left: -50px;
|
||||
|
||||
}
|
||||
|
||||
h2{
|
||||
overflow-wrap: break-word;
|
||||
max-width: 200px;
|
||||
}
|
||||
|
||||
@ -62,7 +62,6 @@
|
||||
.page {
|
||||
text-align: center;
|
||||
overflow-y: scroll;
|
||||
/* height: 80vh; */
|
||||
/* height: 50vh; */
|
||||
/* width: 50vh; */
|
||||
/* background-color: black; */
|
||||
@ -81,9 +80,9 @@
|
||||
border-radius: 50%;
|
||||
border: thick;
|
||||
border-color: red;
|
||||
margin-left: 20px;
|
||||
/* border-image: linear-gradient(90deg, #5843e4, #5a0760); */
|
||||
|
||||
/* margin-top: 20px; */
|
||||
}
|
||||
|
||||
.home{
|
||||
@ -101,7 +100,7 @@
|
||||
color: white;
|
||||
background-color: #5843e4;
|
||||
border-radius: 20px;
|
||||
padding: 1.3% 30%;
|
||||
padding: 14px;
|
||||
font-size: 1.7rem;
|
||||
text-decoration: none;
|
||||
font-weight: bold;
|
||||
@ -154,13 +153,6 @@
|
||||
text-decoration: none;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.user_name{
|
||||
/* background-image: linear-gradient(90deg, #5843e4, #5a0760); */
|
||||
background: -webkit-linear-gradient(60deg, #5843e4, #5a0760);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
}
|
||||
/* canvas {
|
||||
margin-top: 20px;
|
||||
border: solid 0px #ccc;
|
||||
|
||||
@ -1,20 +1,20 @@
|
||||
.playButton {
|
||||
background-image: linear-gradient(90deg, #5843e4, #5a0760);
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
overflow: hidden;
|
||||
border-radius: 5vh;
|
||||
color: white;
|
||||
display: block;
|
||||
/* display: block; */
|
||||
margin: auto;
|
||||
margin-top: 30vh;
|
||||
padding: 2vh 5vw;
|
||||
padding: 2vh 4vw;
|
||||
height: 10vh;
|
||||
width: 20vw;
|
||||
font-size: 300%;
|
||||
font-size: 250%;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.inside_checkbox{
|
||||
height : 70%;
|
||||
width: 70%;
|
||||
}
|
||||
|
||||
.field {
|
||||
background-color: rgb(249, 249, 249);
|
||||
@ -69,18 +69,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
.responsive{
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
/* @media screen and (max-width: 350px){
|
||||
.responsive{
|
||||
display:list-item;
|
||||
flex-direction: column;
|
||||
}
|
||||
} */
|
||||
|
||||
#myCanvas {
|
||||
background-color: rgb(124, 47, 47);
|
||||
/* position: absolute; */
|
||||
|
||||
@ -3,7 +3,6 @@ version: "3.3"
|
||||
services:
|
||||
|
||||
nginx:
|
||||
restart: unless-stopped
|
||||
image: nginx:alpine
|
||||
container_name: nginx
|
||||
env_file: .env
|
||||
@ -15,11 +14,20 @@ services:
|
||||
- 8080:8080
|
||||
volumes:
|
||||
- ./conf/nginx.conf:/etc/nginx/conf.d/default.conf
|
||||
# volumes:
|
||||
# - "./conf:/etc/nginx/templates/"
|
||||
# ports:
|
||||
# - 80:80
|
||||
# volumes:
|
||||
# - ./conf/nginx.conf:/etc/nginx/conf.d/default.conf
|
||||
# command: sh -c "envsubst < /etc/nginx/conf.d/default.conf > /etc/nginx/conf.d/default.conf && nginx -g 'daemon off;'"
|
||||
# - ./containers/frontend:/var/www/html
|
||||
networks:
|
||||
- pongNetwork
|
||||
|
||||
|
||||
|
||||
react_app:
|
||||
restart: unless-stopped
|
||||
image: node:latest
|
||||
container_name: react_app
|
||||
working_dir: /app
|
||||
@ -36,7 +44,6 @@ services:
|
||||
|
||||
|
||||
api:
|
||||
restart: unless-stopped
|
||||
image: node:latest
|
||||
container_name: api
|
||||
working_dir: /app
|
||||
@ -52,9 +59,9 @@ services:
|
||||
entrypoint: ["sh", "-c" , "npm install && npm run start:dev"]
|
||||
|
||||
postgresql:
|
||||
restart: unless-stopped
|
||||
env_file: .env
|
||||
image: postgres:14.1-alpine
|
||||
restart: unless-stopped
|
||||
container_name: postgresql
|
||||
environment:
|
||||
- POSTGRES_USER=postgres
|
||||
@ -68,7 +75,6 @@ services:
|
||||
- pongNetwork
|
||||
|
||||
pong:
|
||||
restart: unless-stopped
|
||||
image: node:latest
|
||||
container_name: pong
|
||||
working_dir: /app
|
||||
@ -82,7 +88,6 @@ services:
|
||||
entrypoint: ["sh", "-c" , "npm install && npm run start:dev"]
|
||||
|
||||
chat:
|
||||
restart: unless-stopped
|
||||
image: node:latest
|
||||
container_name: chat
|
||||
working_dir: /app
|
||||
|
||||
Loading…
Reference in New Issue
Block a user