Compare commits

..

82 Commits

Author SHA1 Message Date
Alexandre POMMIER
dd3b985ce5 cahnge logout reqeust for nbr session fix key in social maps, 2023-06-28 18:54:54 +02:00
Alexandre POMMIER
cebe59f067 clean unused var 2023-06-28 18:10:09 +02:00
Elisee ADJIGUIDI
0d0d0e44ec Merge branch 'reborn' of github.com:kinou-p/ft_transcendence into reborn 2023-06-28 18:07:17 +02:00
Elisee ADJIGUIDI
302413350f unused 2023-06-28 18:06:58 +02:00
Alexandre POMMIER
6f98aa90e5 clean unused var 2023-06-28 18:03:32 +02:00
Alexandre POMMIER
c5371353f8 Merge remote-tracking branch 'origin/reborn' into apommier 2023-06-28 17:51:45 +02:00
Alexandre POMMIER
00a8c9567f delete all console log, hide join when pass 2023-06-28 17:49:23 +02:00
Elisee ADJIGUIDI
02ecea7d52 no dropIn in alert 2023-06-28 17:48:14 +02:00
Elisee ADJIGUIDI
e320c0fd66 Merge branch 'reborn' of github.com:kinou-p/ft_transcendence into reborn 2023-06-28 17:25:13 +02:00
Elisee ADJIGUIDI
b609c7a9d7 no comment 2023-06-28 17:23:01 +02:00
Alexandre POMMIER
49f3626948 Merge remote-tracking branch 'origin/reborn' into apommier 2023-06-28 17:05:32 +02:00
Alexandre POMMIER
86ceafae40 add > for gamesession and sessionnbr 2023-06-28 17:04:50 +02:00
Lara REALI
3eca00e7af Merge branch 'reborn' into phoenix 2023-06-28 16:37:14 +02:00
44183cd1b5 Merge branch 'tmp_apommier' into apommier 2023-06-28 14:22:29 +02:00
18706e168e fix error useEffect pong by putting it in field.tsx, add game session, when page closed nbr session work for me but maybe not at school 2023-06-28 14:19:23 +02:00
Alexandre POMMIER
790e9e5897 je sais plus 2023-06-26 12:02:50 +02:00
Lara REALI
dce2c895e1 remove comment 2023-06-26 11:48:53 +02:00
Alexandre POMMIER
ad10c23528 clean all 2023-06-26 11:38:22 +02:00
Lara REALI
c578ee926c Merge branch 'phoenix' into reborn 2023-06-26 11:13:08 +02:00
Lara REALI
fb6d96fb29 rm index.js change icon and title , delete report webvital 2023-06-26 10:50:47 +02:00
Alexandre POMMIER
0ceea91dc0 merge apommier dipper 2023-06-26 10:49:01 +02:00
Alexandre POMMIER
369ab63f8a clen a bit and add verifypassword who now add to channel if good pass 2023-06-26 10:47:15 +02:00
Elisee ADJIGUIDI
badd6a8379 merge 2023-06-26 10:45:08 +02:00
Elisee ADJIGUIDI
612d0084c0 password 2023-06-26 10:38:22 +02:00
Alexandre POMMIER
baa9b90e5d merge done 2023-06-26 08:00:30 +02:00
Alexandre POMMIER
a6dfe6940f big big merge 2023-06-26 07:55:12 +02:00
Alexandre POMMIER
0d80c118b4 Merge remote-tracking branch 'origin/phoenix' into reborn 2023-06-26 07:46:36 +02:00
Alexandre POMMIER
984b374500 fix alert in modal setting 2023-06-26 07:46:00 +02:00
Lara REALI
53106b33bc fix log color 2023-06-26 07:26:27 +02:00
Alexandre POMMIER
b59e987c7d clean chat api and pong from commentary 2023-06-26 07:06:16 +02:00
Lara REALI
49d73b92d3 log color to fix 2023-06-26 06:58:09 +02:00
Elisee ADJIGUIDI
cd4e414d16 resize name conv 2023-06-26 06:36:29 +02:00
Alexandre POMMIER
42cdd645c8 Merge remote-tracking branch 'origin/dipper' into reborn 2023-06-26 06:05:44 +02:00
Alexandre POMMIER
02ab84add4 mute work 2023-06-26 06:05:14 +02:00
Elisee ADJIGUIDI
94e6250e17 limit conv name 2023-06-26 06:00:38 +02:00
Elisee ADJIGUIDI
9f323ee15d from username to nickname 2023-06-26 05:49:26 +02:00
Elisee ADJIGUIDI
3d74296bb8 recentre alerte 2023-06-26 05:09:47 +02:00
Elisee ADJIGUIDI
ba5490cf90 Alert mute 2023-06-26 04:44:08 +02:00
Alexandre POMMIER
8ebeabb386 Merge remote-tracking branch 'origin/phoenix' into reborn 2023-06-26 04:18:16 +02:00
Lara REALI
84cc25a5a1 reload fix , friends , navbarSocial change margin friends 2023-06-26 04:17:07 +02:00
Alexandre POMMIER
abf09f24fd merge reborn 2023-06-26 04:16:48 +02:00
Alexandre POMMIER
cd6de16511 fix chan invite 2023-06-26 04:06:09 +02:00
Elisee ADJIGUIDI
13dfa6cd95 retrait compteur dans alert et recentre profile 2023-06-26 04:04:51 +02:00
Elisee ADJIGUIDI
9026a81680 merge 2023-06-26 03:02:04 +02:00
Lara REALI
26b3c82790 merge error 2023-06-26 02:54:48 +02:00
Elisee ADJIGUIDI
ba60337c71 unbanned unblocked 2023-06-26 02:40:29 +02:00
Lara REALI
87d342d89a merge apommier 2023-06-26 02:39:09 +02:00
Alexandre POMMIER
152d0541d4 add useeffect app for return 2023-06-26 02:27:43 +02:00
Lara REALI
322aecc182 quit + alert +addsesion 2023-06-26 02:22:47 +02:00
Elisee ADJIGUIDI
80ff5f6c9f new alert bad input qrcode resize button chat modif alert name already taken 2023-06-26 01:47:41 +02:00
Alexandre POMMIER
4151350162 fix login with other app, pong greater speed at start, fix in game status ?, rename home.js to loginbutton.tsx 2023-06-26 01:31:46 +02:00
Lara REALI
b61531d8d2 color for qr input + text in chat input + w = wall 2023-06-26 00:32:42 +02:00
Lara REALI
1e9946859c augment desactivate 2fa size + blur OK + Friend list css OK Invite button suppress comment spectate button 2023-06-25 21:51:21 +02:00
Lara REALI
007dbe1832 Merge branch 'ereali' into reborn 2023-06-25 00:39:05 +02:00
Alexandre POMMIER
9098c29287 fix invite double channel when add friend fix invite, history power up time limited wall 2023-06-25 00:30:30 +02:00
Lara REALI
cf0edf5bc0 Merge remote-tracking branch 'origin/apommier' into ereali 2023-06-24 20:18:46 +02:00
Alexandre POMMIER
2f777480a0 try locahost 2023-06-24 20:12:13 +02:00
Lara REALI
92f3f496de Friend request css + change navbar Social+ button border qr butonn desactivate qr 2023-06-24 20:02:14 +02:00
Alexandre POMMIER
c6fe3a5a99 fix invite and match history not done 2023-06-24 19:39:16 +02:00
Alexandre POMMIER
38052b5034 fix invit 2023-06-24 18:19:41 +02:00
Alexandre POMMIER
fc280662b9 merge 2023-06-24 16:17:16 +02:00
Lara REALI
b04683576d merge apommier 2023-06-24 15:52:24 +02:00
Lara REALI
c011ea2b04 merge 2023-06-24 15:50:10 +02:00
Alexandre POMMIER
e44320a88f Merge remote-tracking branch 'origin/ereali' into apommier 2023-06-24 15:39:27 +02:00
Alexandre POMMIER
cf7c648813 before merge 2023-06-24 15:38:16 +02:00
Elisee ADJIGUIDI
a84b932355 merge 2023-06-24 15:14:08 +02:00
Elisee ADJIGUIDI
44fb3cdecd responsive pages/game nickname already Taken/Nickname too short 2023-06-24 14:35:50 +02:00
Lara REALI
6fd9660bff message sans decalage 2023-06-24 01:04:47 +02:00
Lara REALI
bdeb414c09 border message + responsive on profile 2023-06-24 00:51:36 +02:00
Alexandre POMMIER
071f30764a canvas background page, fix message mute, win loss in profile 2023-06-24 00:51:32 +02:00
Elisee ADJIGUIDI
de59d21671 change 2023-06-24 00:37:20 +02:00
Elisee ADJIGUIDI
6ad04baf06 merge 2023-06-23 20:32:35 +02:00
Alexandre POMMIER
d5e3532bd0 merge all all 2023-06-23 20:30:14 +02:00
Alexandre POMMIER
6d1cd933e2 Merge remote-tracking branch 'origin/ereali' into apommier 2023-06-23 20:21:36 +02:00
Alexandre POMMIER
b50d789d1d merge all syd 2023-06-23 20:20:10 +02:00
Alexandre POMMIER
c07a169794 fix mute ? fix socket fix infinite request profile, modify port 2023-06-23 19:59:23 +02:00
Elisee ADJIGUIDI
72a4f42cdb change design 2023-06-23 19:59:07 +02:00
Lara REALI
4d98765009 margin on leaderboard pic + auto input qr 2023-06-23 19:58:45 +02:00
Lara REALI
b27cb189b3 Qrcode number without arrows 2023-06-23 18:45:59 +02:00
Elisee ADJIGUIDI
0d42eda749 change 2023-06-23 15:38:58 +02:00
Little Dipper
f9a26e8e0f longeur messages et logueur modal nouveau message 2023-06-18 23:04:49 +02:00
Little Dipper
263e3332a1 js to ts 2023-06-18 21:22:25 +02:00
91 changed files with 1399 additions and 3460 deletions

1
.env
View File

@ -14,6 +14,7 @@
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
View File

@ -1,4 +1,5 @@
#.env
.env
containers/react/.env
backend/node_modules/
containers/backend/dist/

2
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,2 @@
{
}

153
README.md
View File

@ -1,153 +0,0 @@
# 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

View File

@ -1 +1 @@
ALTER USER postgres WITH PASSWORD 'pass';
ALTER USER postgres WITH PASSWORD 'postgres';

View File

@ -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:8001;
proxy_pass http://react_app:8081;
}
location /api {
@ -21,7 +21,7 @@ server {
proxy_pass http://api:3000/api;
}
location /socket {
location /socket.io {
# Forward requests to socket server running on port 4001
if ($request_uri ~ ^/socket/4001) {
proxy_pass http://chat:4001;

View File

@ -1,22 +0,0 @@
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!');
});
});
});

View File

@ -6,51 +6,34 @@
/* By: apommier <apommier@student.42.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2023/06/17 01:00:00 by apommier #+# #+# */
/* Updated: 2023/06/21 01:19:01 by apommier ### ########.fr */
/* Updated: 2023/06/28 18:49:39 by apommier ### ########.fr */
/* */
/* ************************************************************************** */
import { Controller, Request, Req, Get, Post, UseGuards, Redirect, Res, Body, UploadedFile, UseInterceptors} from '@nestjs/common';
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 {
constructor(private authService: AuthService,
private loginClass: loginClass,
private chatService: ChatService,
private userService: UsersService, ) {}
private userService: UsersService,) { }
kFactor = 36;
scaleFactor = 400;
//========================================================================================================
//========================================================================================================
// User
@ -60,49 +43,51 @@ 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)
if(!user)
return ;
if (user.sessionNumber > 0)
user.sessionNumber--;
if (!user.sessionNumber)
user.status = 0;
this.userService.save(user);
}
@UseGuards(JwtAuthGuard)
@Post('/user')
async getUser( @Body() data: any) {
console.log(`usernamewwww= ${data.username}`)
async getUser(@Body() data: any) {
return await this.userService.findOne(data.username);
}
@UseGuards(JwtAuthGuard)
@Get('/users')
async getUsers( @Body() data: any) {
console.log(`usernamewwww= ${data.username}`)
async getUsers(@Body() data: any) {
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')//need to do it 2 time when user accept one for each
@Post('/friend')
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);
//create personnal conv for user
//await this.userService.addFriend(user, data.username);
// const amIhere = data.members.includes(req.user.username);
// if (!amIhere)
if (user.friends.find(item => item === data.username)) {
user.friendRequest = user.friendRequest.filter((item) => item !== data.username);
this.userService.save(user);
return (1);
}
const conv = {
id: null,
name: req.user.username + ", " + data.username,
@ -115,20 +100,18 @@ 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)
@ -138,7 +121,6 @@ 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)
@ -150,17 +132,12 @@ 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);
}
@ -177,12 +154,11 @@ export class AppController {
@UseGuards(JwtAuthGuard)
@Post('/nickname')
async setNickname(@Request() req, @Body() data: any) {
// let user = req.user
// user.nickname = data.nickname
console.log(`user= ${req.user.username}`)
const taken = await this.userService.findNickname(data.nickname)
if (taken)
return (0);
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);
}
@ -201,79 +177,84 @@ export class AppController {
@UseGuards(JwtAuthGuard)
@Post('/getPicture')
async getProfilPicture(@Body() data: any) {
// console.log(`dataaaaa= ${data.username}`)
return await this.userService.getPic(data.username)
// 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);
}
//========================================================================================================
//========================================================================================================
// Pong
//========================================================================================================
//========================================================================================================
@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);
}
//========================================================================================================
//========================================================================================================
// Pong
//========================================================================================================
//========================================================================================================
@UseGuards(JwtAuthGuard)
@Post('/addGame')
async addGame(@Request() req, @Body() data: any) {
const user = await this.userService.findOne(req.user.username);
user.gameSession += 1;
await this.userService.save(user);
}
@UseGuards(JwtAuthGuard)
@Post('/rmGame')
async removeGame(@Request() req, @Body() data: any) {
const user = await this.userService.findOne(req.user.username);
if (user.gameSession > 0)
user.gameSession -= 1;
if (user.gameSession === 0)
user.status = 1;
await this.userService.save(user);
}
@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()
{
@ -284,27 +265,18 @@ export class AppController {
@Post('/partyInvite')
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, @Body() data: any)
async getPartyInvite(@Request() req)
{
//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;
}
@ -312,14 +284,8 @@ export class AppController {
@Post('/deleteInvite')
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);
}
@ -327,24 +293,21 @@ export class AppController {
@Post('/history')
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 ;
if (user.sessionNumber > 0)
user.sessionNumber--;
if (!user.sessionNumber)
user.status = 0;
await this.userService.save(user);
}
//========================================================================================================
//========================================================================================================
@ -352,29 +315,15 @@ 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))}` };
}
@ -387,16 +336,13 @@ export class AppController {
return user.otp_enabled;
}
@UseGuards(JwtAuthGuard)
@Post('/otp')
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;
}
@ -406,8 +352,6 @@ export class AppController {
{
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
}
@ -418,7 +362,6 @@ export class AppController {
{
const user = await this.userService.findOne(req.user.username);
const res = await ValidateOTP(user, data.token)
// await this.userService.save(user);
return res
}
@ -429,30 +372,8 @@ export class AppController {
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
@ -462,26 +383,16 @@ 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) {
@ -504,48 +415,31 @@ 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);
return await this.chatService.createMessage(message, req.user.username);
}
@UseGuards(JwtAuthGuard)
@Post('/member')
async getMember(@Body() data: any) {
console.log(data);
console.log(`get member= ${data.convId}`);
return await this.chatService.findConv(data.convId);
}
@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)
}
@ -557,12 +451,12 @@ export class AppController {
@UseGuards(JwtAuthGuard)
@Post('/verifyPassword')
async verifyPassword(@Body() data: any) {
return await this.chatService.verifyPassword(data.convId, data.password)
async verifyPassword(@Request() req, @Body() data: any) {
return await this.chatService.verifyPassword(data.convId, data.password, req.user.username)
}
@UseGuards(JwtAuthGuard)
@Post('/invite')
@Post('/inviteConv')
async inviteUser(@Body() data: any) {
return await this.chatService.inviteUser(data.convId, data.username)
}
@ -571,7 +465,7 @@ export class AppController {
@Post('/ban')
async banUser(@Body() data: any) {
if (!data.username)
return ;
return;
return await this.chatService.banUser(data.convId, data.username)
}
@ -579,7 +473,7 @@ export class AppController {
@Post('/admin')
async setAdmin(@Body() data: any) {
if (!data.username)
return ;
return;
return await this.chatService.setAdmin(data.convId, data.username)
}
@ -587,22 +481,26 @@ export class AppController {
@Post('/mute')
async muteUser(@Body() data: any) {
if (!data.username)
return ;
return await this.chatService.muteUser(data.convId, data.username)
return;
return await this.chatService.muteUser(data.convId, data.username, data.time)
}
@UseGuards(JwtAuthGuard)
@Post('/isAdmin')
async isAdmin(@Request() req, @Body() data: any) {
console.log("isdamin= ", req.user.username, " id=", data.convId)
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)
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)
}
@UseGuards(JwtAuthGuard)

View File

@ -2,16 +2,8 @@ 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({
@ -23,7 +15,5 @@ import { ChatModule } from './chat/chat.module';
],
controllers: [AppController],
providers: [AppService, loginClass,],
// providers: [AppService, UsersService],//in add
})
export class AppModule {}

View File

@ -1,23 +1,8 @@
// 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';
@ -28,7 +13,6 @@ import { JwtStrategy } from './jwt.strategy';
PassportModule,
JwtModule.register({
secret: jwtConstants.secret,
// signOptions: { expiresIn: '60000s' },
}),
],
providers: [AuthService, LocalStrategy, JwtStrategy],

View File

@ -21,12 +21,7 @@ export class AuthService {
}
async login(user: User) {
// const myJSON = JSON.stringify(user);
// console.log(`in login all user= ${myJSON}`)
console.log(`in login user= ${user.username}`)
const payload = { username: user.username, sub: user.userId };
console.log(`in login payload name= ${payload.username}`)
console.log(`in login payload sub= ${payload.sub}`)
return {
access_token: this.jwtService.sign(payload),
};

View File

@ -1,4 +1,3 @@
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,
};

View File

@ -14,8 +14,6 @@ export class JwtStrategy extends PassportStrategy(Strategy) {
}
async validate(payload: any) {
console.log("in validate function")
console.log(`userid= ${payload.sub} nickname= ${payload.username}`)
return { userId: payload.sub, username: payload.username };
}
}

View File

@ -1,12 +1,7 @@
// 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) {};
@ -16,19 +11,16 @@ 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 || 'u-s4t2ud-6d29dfa49ba7146577ffd8bf595ae8d9e5aaa3e0a9615df18777171ebf836a41',
// client_secret: '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',
client_id: process.env.CLIENT_UID,
client_secret: process.env.API_SECRET,
code: code,
redirect_uri: process.env.REDIRECT_URI || 'http://' + process.env.REACT_APP_BASE_URL + '/api/auth/login',
redirect_uri: process.env.REDIRECT_URI,
};
try {
@ -42,20 +34,14 @@ 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,
@ -69,22 +55,18 @@ export class loginClass {
otp_base32: null,
children: null,
status: 1,
// doubleAuth: 0,
otp_enabled: false,
otp_verified: false,
friendRequest: null,
friends: null,
blocked: null,
photo: null,
sessionNumber: 0,
gameSession: 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));
}
}

View File

@ -1,8 +1,3 @@
// import { Module } from '@nestjs/common';
// @Module({})
// export class ChatModule {}
import { Module } from '@nestjs/common';
import { ChatService} from './chat.service';
@ -17,7 +12,6 @@ import { Message } from '../model/chat.entity';
TypeOrmModule.forRoot(getTypeOrmConfig()),
TypeOrmModule.forFeature([Conv]),
TypeOrmModule.forFeature([Message]),
// TypeOrmModule.forFeature([UserRepository]),
],
providers:[ChatService],
exports: [ChatService],

View File

@ -6,7 +6,7 @@
/* By: apommier <apommier@student.42.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2023/06/17 01:00:25 by apommier #+# #+# */
/* Updated: 2023/06/20 16:47:02 by apommier ### ########.fr */
/* Updated: 2023/06/28 18:20:07 by apommier ### ########.fr */
/* */
/* ************************************************************************** */
@ -15,13 +15,8 @@ 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 {
@ -43,13 +38,10 @@ async findAll(): Promise<Conv[]> {
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;
}
@ -82,51 +74,69 @@ async findConv(number: number){
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))
return (1);
{
conv.banned = conv.banned.filter((item) => item !== username);
this.save(conv);
return (2);
}
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);
// this.save(conv);
const conv = await this.findConv(convId);
//find user
//add in chanInvite chanID
//save user
if (conv.members.find(item => item === username))
return (1);
if (conv.banned.find(item => item === username))
return (0);
conv.members.push(username);
this.save(conv);
}
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) {
//verify is user is admin ?
async verifyPassword(convId: number, password: string, username: string) {
const conv = await this.findConv(convId);
return await bcrypt.compare(password, conv.password);
// conv.password = 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;
}
async muteUser(convId: number, username: string) {
async muteUser(convId: number, username: string, time: 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) {
@ -145,16 +155,12 @@ async isAdmin(convId: number, username: string) {
conv.admin = conv.admin || [];
if (conv.admin.find(item => item === username))
return (1);
console.log("nope");
return (0);
}
async setPrivate(convId: number) {
async setPrivate(convId: number, bool: boolean) {
const conv = await this.findConv(convId);
if (conv.private === true)
conv.private = false;
else
conv.private = true;
conv.private = bool;
this.save(conv);
}
@ -170,7 +176,6 @@ async joinChannel(convId: number, username: string) {
if (conv.members.find(item => item === username))
return ;
conv.members.push(username);
// conv.name = name;
this.save(conv);
}

View File

@ -6,7 +6,7 @@
/* By: apommier <apommier@student.42.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2023/04/09 14:53:49 by apommier #+# #+# */
/* Updated: 2023/06/22 20:42:32 by apommier ### ########.fr */
/* Updated: 2023/06/28 17:41:26 by apommier ### ########.fr */
/* */
/* ************************************************************************** */
@ -20,8 +20,6 @@ export const getTypeOrmConfig = (): TypeOrmModuleOptions => ({
password: process.env.POSTGRES_PASSWORD || 'postgres',
database: process.env.POSTGRES_DATABASE || 'postgres',
entities: ["dist/**/*.entity.js"],
// entities: [join(__dirname, '**', '*.entity.{ts,js}')]
// entities: ['**/*.entity{.ts,.js}'], //basic
migrationsTableName: 'migration',
migrations: ['src/migration/*.ts'],
ssl: process.env.MODE !== 'DEV',

View File

@ -4,22 +4,12 @@ import * as session from 'express-session';
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: '*',
},

View File

@ -6,7 +6,7 @@
/* By: apommier <apommier@student.42.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2023/06/17 01:00:20 by apommier #+# #+# */
/* Updated: 2023/06/23 15:18:19 by apommier ### ########.fr */
/* Updated: 2023/06/26 06:55:03 by apommier ### ########.fr */
/* */
/* ************************************************************************** */
@ -29,9 +29,6 @@ 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[];
@ -49,18 +46,6 @@ 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()
@ -77,7 +62,6 @@ import { Entity, Column, PrimaryGeneratedColumn, CreateDateColumn, BaseEntity }
@Column()
text: string;
@CreateDateColumn({ nullable: true })
createdAt?: Date;

View File

@ -1,28 +1,12 @@
// item.entity.ts
// import { BaseEntity } from './base.entity';
// @Column({ type: 'varchar', length: 300 , nullable: true})
// name: string;
// @Column({ type: 'varchar', length: 300 , nullable: true})
// description: string;
import { Entity, Column, PrimaryGeneratedColumn } from 'typeorm';
import { ManyToOne, OneToMany } from 'typeorm';
@Entity({ name: 'User' })
export class User {
@PrimaryGeneratedColumn()
id: number;
// otp_enabled Boolean @default(false)
// otp_verified Boolean @default(false)
@Column({ default: false })
otp_enabled: boolean;
@ -50,27 +34,27 @@ export class User {
@Column({ default: 0 })
loss: number;
@Column({ default: 0 })
sessionNumber: number;
@Column({ default: 0 })
gameSession: number;
@Column({ default: 0 })
rank: number;
@Column({ default: 0 }) //0 = offline | 1 = connected | 2 = in game
@Column({ default: 0 })
status: number;
@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[];
@ -82,7 +66,7 @@ export class User {
}
@Entity()
@Entity({name: 'MatchLog' })
export class MatchLog {
@PrimaryGeneratedColumn()
id: number;

View File

@ -1,18 +1,7 @@
// 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);
@ -36,35 +25,22 @@ export const generateOTP = async (user) => {
let otpauth_url = totp.toString();
const qrCodeDataUrl = await qr.toDataURL(otpauth_url, { errorCorrectionLevel: 'H' });
const filePath = 'qrcode.png'; // Specify the file path where the QR code should be saved
const filePath = 'qrcode.png';
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)
}
@ -84,13 +60,11 @@ 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) {
@ -110,194 +84,11 @@ export const generateOTP = async (user) => {
});
let delta = totp.validate({ token });
if (delta === null) {
console.log("error validate token")
if (delta === null)
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
// }

View File

@ -11,7 +11,6 @@ import { MatchLog, User } from '../model/user.entity';
TypeOrmModule.forRoot(getTypeOrmConfig()),
TypeOrmModule.forFeature([User]),
TypeOrmModule.forFeature([MatchLog]),
// TypeOrmModule.forFeature([UserRepository]),
],
providers:[UsersService],
exports: [UsersService],

View File

@ -6,7 +6,7 @@
/* By: apommier <apommier@student.42.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2023/06/17 01:00:07 by apommier #+# #+# */
/* Updated: 2023/06/21 01:31:44 by apommier ### ########.fr */
/* Updated: 2023/06/28 17:43:46 by apommier ### ########.fr */
/* */
/* ************************************************************************** */
@ -41,12 +41,15 @@ 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);
@ -54,23 +57,20 @@ export class UsersService {
async getFriends(username: string) {
const user = await this.findOne(username)
let friendsTab = user.friends
console.log(friendsTab)
// friendsTab = ['apommier', 'syd']
let friendsTab = user.friends || [];
const friends = await this.userRepository.query("SELECT * FROM \"User\" WHERE username = ANY ($1);", [friendsTab]);
console.log(friends)
return (friends)
}
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);
@ -79,12 +79,7 @@ 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)
}
@ -96,18 +91,13 @@ export class UsersService {
async getHistory(username: string) {
const user = await this.findOne(username);
if (user) {
const children = user.children;
console.log(user);
console.log(user.children); // or perform any operations with the children
return children;
}
return await this.userRepository.query("SELECT * FROM \"MatchLog\" WHERE \"parentId\" = ANY ($1);", [[user.id]]);
}
async addFriend(user: User, username: string) {
if (!(await this.findOne(username)))
const user2 = await this.findOne(username)
if (!user)
return (0);
// user.friendRequest = user.friendRequest || [];
user.friends = user.friends || [];
if (user.friends.find(item => item === username))
{
@ -117,6 +107,9 @@ 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);
}
@ -126,7 +119,11 @@ export class UsersService {
return (0);
user.blocked = user.blocked || [];
if (user.blocked.find(item => item === username))
return (1);
{
this.save(user);
user.blocked = user.blocked.filter((item) => item !== username);
return (2);
}
user.blocked.push(username);
this.save(user);
return (1);
@ -137,40 +134,11 @@ 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);
// }

View File

@ -8,58 +8,35 @@ 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
}
@ -69,16 +46,11 @@ 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}`);
}
@ -86,22 +58,14 @@ 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)) {
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
const clientArray = this.clientsNames.get(payload.username);
clientArray.push(client.id);
} else {
console.log("create")
this.clientsNames.set(payload.username, [client.id]); // Create a new array with the new client as the value
this.clientsNames.set(payload.username, [client.id]);
}
}
// @SubscribeMessage('socket.io')
// socketConnect(client: any, payload: any): void {
// console.log("/socket.io")
// }
@SubscribeMessage('ban')
banUser(client: any, payload: any): void {
@ -112,21 +76,8 @@ 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')
@ -138,51 +89,26 @@ 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 {
console.log("not sending");
}
});
}
});
}
}
}

View File

@ -6,32 +6,24 @@ import * as socketio from 'socket.io';
import * as dotenv from 'dotenv';
dotenv.config();
console.log(process.env);
async function bootstrap() {
const app = await NestFactory.create(AppModule, {
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.' });
});

View File

@ -1,43 +1,18 @@
// 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';
dotenv.config();
console.log(process.env);
async function bootstrap() {
const app = await NestFactory.create(AppModule, {
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);

View File

@ -6,7 +6,7 @@
/* By: apommier <apommier@student.42.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2023/06/19 15:18:38 by apommier #+# #+# */
/* Updated: 2023/06/23 15:19:12 by apommier ### ########.fr */
/* Updated: 2023/06/28 17:46:12 by apommier ### ########.fr */
/* */
/* ************************************************************************** */
@ -28,7 +28,6 @@ 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)
@ -39,81 +38,56 @@ 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}`);
}
@SubscribeMessage('pong:disconnect')
disconnectClient(client: Socket, payload: any): void {
console.log("disconnect forced client= ", client.id)
console.log("Forced disconnect client= ", client.id)
for (const key in this.clients) {
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];
}
@ -129,29 +103,18 @@ 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]; // Add the current client to the players array
const players = [matchingClients[0].client, client];
players.forEach((player) => {
// this.waitingClients.delete(
// this.waitingClients.find(
// (waitingClient) => waitingClient.client === player
// )
// );
const matchingClient = Array.from(this.waitingClients).find(
(waitingClient) => waitingClient.client === player
);
@ -165,12 +128,11 @@ 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', gameId);
player.emit('pong:gameId', payload);
});
}
// console.log(`from: ${client.id}`);
}
@ -182,48 +144,27 @@ 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.gameId);
this.clients[playersIds[1]].emit('pong:gameId', payload.gameId);
this.clients[playersIds[0]].emit('pong:gameId', payload);
this.clients[playersIds[1]].emit('pong:gameId', payload);
}
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)
}
@ -243,24 +184,17 @@ addPrivateParty(client: Socket, payload: any): void {
@SubscribeMessage('pong:power')
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);
if (playersIds[0] === payload.id)
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);
if (playersIds[0] === payload.id)
@ -273,20 +207,14 @@ 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);
@ -295,20 +223,13 @@ 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);
@ -317,7 +238,6 @@ addPrivateParty(client: Socket, payload: any): void {
{
this.clients[playersIds[0]].emit('pong:paddle', payload);
}
console.log("END OF HANDLE");
}
@SubscribeMessage('pong:point')
@ -325,7 +245,6 @@ addPrivateParty(client: Socket, payload: any): void {
{
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)
{
@ -337,21 +256,31 @@ 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);
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.name);
this.clients[playersIds[1]].emit('pong:name', payload);
}
if (playersIds[1] === payload.id)
{
this.clients[playersIds[0]].emit('pong:name', payload.name);
this.clients[playersIds[0]].emit('pong:name', payload);
}
}

View File

@ -1,5 +1,6 @@
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
REACT_APP_BASE_URL=paul-f5Ar4s4:8080
REACT_APP_SOCKET_URL=paul-f5Ar4s4
REACT_APP_API_SECRET=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
REACT_APP_CLIENT_UID=u-s4t2ud-2bd3c5d4f41e776f2e3d5d699d2a8421f6d0c0468ec882516d9ca89b0c211789
REACT_APP_INTRA_URL="https://api.intra.42.fr/oauth/authorize?client_id=u-s4t2ud-2bd3c5d4f41e776f2e3d5d699d2a8421f6d0c0468ec882516d9ca89b0c211789&redirect_uri=http%3A%2F%2Fpaul-f5Ar4s4%3A8080%2Fapi%2Fauth%2Flogin&response_type=code"

View File

@ -16,6 +16,8 @@ export interface User {
partyInvite: Record<string, string>[];
friends: string[];
blocked: string[];
sessionNumber: number;
gameSession : number;
}
export interface Conv {

View File

@ -22,7 +22,7 @@
"web-vitals": "^2.1.4"
},
"scripts": {
"start": "HOST=0.0.0.0 PORT=8001 react-scripts start",
"start": "HOST=0.0.0.0 PORT=8081 react-scripts start",
"start:dev": "npm run start --watch",
"build": "react-scripts build",
"test": "react-scripts test",

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

@ -2,14 +2,10 @@
<html lang="en">
<head>
<meta charset="utf-8" />
<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" />
<link rel="shortcut icon" type="image/jpeg" href="/favicon.jpeg"/>
<!--
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/
@ -24,10 +20,8 @@
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>
<body >
<div id="root" style=" height: 100%;"></div>
<!--
This HTML file is a template.

View File

@ -1,58 +0,0 @@
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',
},
]

View File

@ -1,8 +0,0 @@
import DefaultPic from '../assets/profile.jpg';
export const UserProfile = {
Pic: DefaultPic,
UserName: 'Dipper Ratman',
}
// export default UserProfile

View File

@ -1,37 +0,0 @@
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'
},
]

View File

@ -4,40 +4,28 @@ import { AiOutlineCheckCircle } from "react-icons/ai";
import '../../styles/Messages.css'
import React from "react";
const dropIn = {
hidden: {
y: "-100vh",
},
visible: {
y: "0",
},
exit: {
y: "-100vh",
},
};
interface AlertProps {
handleClose: Function,
text: string
}
}
function GreenAlert ({handleClose, text}: AlertProps){
function GreenAlert({ handleClose, text }: AlertProps) {
{ setTimeout(handleClose, 1500) }
return (
return(
<Backdrop onClick={handleClose}>
<motion.div
onClick={(e) => e.stopPropagation()}
className="greenAlert"
// variant={dropIn}
initial="hidden"
animate="visible"
exit="exit"
>
<AiOutlineCheckCircle/>
<p>{text}</p>
<AiOutlineCheckCircle />
<div className="text_alert">
<h5>{text}</h5>
</div>
</motion.div>
{setTimeout(handleClose, 1500)}
</Backdrop>
)
}

View File

@ -4,39 +4,27 @@ import { BiErrorCircle } from "react-icons/bi";
import '../../styles/Messages.css'
import React from "react";
const dropIn = {
hidden: {
y: "-100vh",
},
visible: {
y: "0",
},
exit: {
y: "-100vh",
},
};
interface AlertProps {
handleClose: Function,
text: string
}
function RedAlert ({handleClose, text}: AlertProps) {
{setTimeout(handleClose, 1500)}
return(
<Backdrop onClick={handleClose}>
<motion.div
onClick={(e) => e.stopPropagation()}
className="redAlert"
// variant={dropIn}
initial="hidden"
animate="visible"
exit="exit"
>
<BiErrorCircle/>
<p>{text}</p>
<div className="text_alert">
<h5>{text}</h5>
</div>
</motion.div>
{setTimeout(handleClose, 1500)}
</Backdrop>
)
}

View File

@ -6,54 +6,43 @@ import React from "react";
import { MdQrCodeScanner } from "react-icons/md";
import { GiCrownedSkull, GiWingedSword } from "react-icons/gi";
const dropIn = {
hidden: {
y: "-100vh",
},
visible: {
y: "0",
},
exit: {
y: "-100vh",
},
};
interface AlertProps {
handleClose: Function,
text: string,
icon: number
}
}
function YellowAlert ({handleClose, text, icon}: AlertProps) {
return(
function YellowAlert({ handleClose, text, icon }: AlertProps) {
{ setTimeout(handleClose, 3000) }
return (
<Backdrop onClick={handleClose}>
<motion.div
onClick={(e) => e.stopPropagation()}
className="yellowAlert"
// variant={dropIn}
initial="hidden"
animate="visible"
exit="exit"
>
{icon === 0 ? (
<GrTrophy/>
):("")}
<GrTrophy />
) : ("")}
{icon === 1 ? (
<MdQrCodeScanner/>
):("")}
<MdQrCodeScanner />
) : ("")}
{icon === 2 ? (
<GiCrownedSkull/>
):("")}
<GiCrownedSkull />
) : ("")}
{icon === 3 ? (
<GiWingedSword/>
):("")}
<GiWingedSword />
) : ("")}
<div className="text_alert">
<h5>{text}</h5>
</div>
</motion.div>
{setTimeout(handleClose, 3000)}
</Backdrop>
)
}

View File

@ -1,26 +0,0 @@
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

View File

@ -1,16 +1,15 @@
import React from "react";
import {Routes, Route, Navigate} from 'react-router-dom';
import HomeLogin from "../pages/Home.js";
import React, { useEffect } from "react";
import { Routes, Route, Navigate } from 'react-router-dom';
import HomeLogin from "../pages/LoginButton.tsx";
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";
import {AnimatePresence} from "framer-motion";
import { AnimatePresence } from "framer-motion";
import SuccessToken from '../script/tokenSuccess.tsx'
@ -19,20 +18,38 @@ 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 () {
// const location = useLocation();
const location = useLocation();
function AnimatedRoute() {
useEffect(() => {
const handleLoad = async () => {
if (!localStorage.getItem('token'))
{
return;
try {
await api.post("/addSession");
} catch (err) {
console.log(err);
}
};
handleLoad();
window.addEventListener("beforeunload", async (event) => {
if (!localStorage.getItem('token'))
return;
await api.post("/quit");
});
return () => {};
}, []);
const location = useLocation();
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" />} /> */}
<Route path="/" element={<HomeLogin />} />
<Route path="/token" element={<SuccessToken />} />
</Routes>
</AnimatePresence>
)
@ -41,26 +58,18 @@ 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="/" 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="/logout" element={<Logout />} />
<Route path="/messages" element={<Messages />} />
<Route path="/404" element={<PageNotFound />} />
<Route path="*" element={<Navigate to="/404" />} />
</Routes>

View File

@ -1,12 +0,0 @@
import React from 'react';
// import './Header.scss';
function Footer() {
return (
<footer className="footer">
<p>&copy; 2023 Paris France</p>
</footer>
);
}
export default Footer;

View File

@ -1,16 +1,10 @@
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?`;
@ -19,30 +13,22 @@ 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);
};
return (
<div className="notClicked" id="canvas_container">
<button onClick={handleButtonClick} className="playButton">Play</button>
{/* !buttonClicked && <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>
<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>
</div>
</div>
);

View File

@ -3,20 +3,17 @@
/* ::: :::::::: */
/* Rank.tsx :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: apommier <apommier@student.42.fr> +#+ +:+ +#+ */
/* By: sadjigui <sadjigui@student.42.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2023/06/09 08:49:24 by apommier #+# #+# */
/* Updated: 2023/06/20 13:06:35 by apommier ### ########.fr */
/* Updated: 2023/06/28 17:55:55 by sadjigui ### ########.fr */
/* */
/* ************************************************************************** */
// import React from "react"
import React, { useState, useEffect, useRef } from "react";
// import {Rank} from '../../DataBase/DataRank.js'
import React, { useState, useEffect } from "react";
import DefaultPicture from '../../assets/profile.jpg'
import api from '../../script/axiosApi.tsx';
import {Matchlog, User} from "../../../interfaces.tsx"
// import { Match } from "@testing-library/react";
import {User} from "../../../interfaces.tsx"
interface RankProps {
user: User
@ -30,10 +27,7 @@ function Rank({user, index}: RankProps){
useEffect(() => {
const fetchProfilePicture = async () => {
try {
// const user = await api.get("/profile");
const pic = await api.post("/getPicture", {username: user.username})
// console.log(`user naem profile pic222= ${currentUser.username}`)
// console.log(` profile pic222= ${pic.data}`)
setProfilePicture(pic.data);
} catch (error) {
console.error('Error fetching profile picture:', error);
@ -41,13 +35,11 @@ function Rank({user, index}: RankProps){
};
fetchProfilePicture();
})
}, [])
// console.log(index);
return (
<div className='rank_elements'>
<div >
{/* <p>{(index + 1).toString()}</p> */}
<p>{(index + 1)}</p>
<h4>{user.rank}: {user.nickname}
{profilePicture ? (
@ -55,10 +47,8 @@ function Rank({user, index}: RankProps){
) : (
<img className="profilePic" src={DefaultPicture} alt="Default Profile Picture" />
)}
{/* <img className="profilePic" src={defaultpic}/> */}
</h4>
</div>
{/* <h4 className='content'>{user.opponent}</h4> */}
</div>
)
}

View File

@ -1,7 +1,5 @@
// import React from "react"
import React, { useState, useEffect, useRef } from "react";
import React, { useState, useEffect } from "react";
import Rank from './Rank.tsx'
import defaultpic from '../../assets/profile.jpg'
import api from '../../script/axiosApi.tsx';
import {User} from "../../../interfaces.tsx"
@ -14,32 +12,22 @@ function Ranking(){
const getRanking = async ()=>{
try{
// const tmpFriends = await api.get("/friends")
const Ranking = await api.get("/ranking")
setRanking(Ranking.data);
console.log(`ranking= ${Ranking.data}`)
// 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}`)
}, []);
return (
<div>
{isLoading ? (
<></>
) : (
// <h1 className='title'>Ranking</h1>
<div className='scroll'>
{ranking.map((user, index) => (
<Rank user={user} index={index} key={user.username}/>

View File

@ -4,23 +4,13 @@ import {Link} from 'react-router-dom';
import DefaultPicture from '../assets/profile.jpg'
import { motion, AnimatePresence } from 'framer-motion'
import Modal from './Sidebar/Modal.tsx';
import YellowAlert from './Alert/YellowAlert.tsx';
import '../styles/Header.css';
import api from '../script/axiosApi.tsx';
import { MdQrCodeScanner } from 'react-icons/md';
import { GiWingedSword, GiCrownedSkull } from 'react-icons/gi';
function Header() {
// const [sidebar, setSidebar] = useState(false);
// const showSidebar = () => setSidebar(!sidebar);
const [modalOpen, setModalOpen] = useState(false);
const close = () => setModalOpen(false);
const open = () => setModalOpen(true);
const [success, setSuccess] = useState([]);
const [profilePicture, setProfilePicture] = useState('');
useEffect(() => {
@ -29,9 +19,6 @@ function Header() {
const user = await api.get("/profile");
const pic = await api.post("/getPicture", {username: user.data.username})
setProfilePicture(pic.data);
// console.log("test ===", user.data)
setSuccess(user.data);
// console.log(`profile pic222= ${pic.data}`)
} catch (error) {
console.error('Error fetching profile picture:', error);
}
@ -54,9 +41,7 @@ function Header() {
<div>
{profilePicture ? (
// <img className='Header-pic' src={profilePicture} alt="Profile Picture" />
<img className='Header-pic' src={`data:image/jpeg;base64,${profilePicture}`} />
// <img className='Header-pic' src={`data:image/jpeg;base64,${profilePicture.data}`} alt="Profile Picture" />
) : (
<img className='Header-pic' src={DefaultPicture} alt="Default Profile Picture" />
)}

View File

@ -2,14 +2,12 @@ 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';
@ -17,16 +15,15 @@ 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;
@ -57,17 +54,6 @@ const UserChat = styled.div `
}
`
// const SideSpan = styled.span`
// font-size: 18px;
// font-weight: 500;
// `
const SideP = styled.p`
font-size: 14px;
color: lightgray;
margin-left: 15px;
`
//========================================================================================================
//========================================================================================================
// Logical part
@ -88,17 +74,13 @@ function Chats(){
const [conversations, setConversation] = useState([]);
const [partyInvite, setPartyInvite] = useState([]);
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 [currentChat, setCurrentChat] = useState<Conv>();
const [isAdmin, setIsAdmin] = useState<boolean>(false);
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(()=> {
@ -110,49 +92,32 @@ function Chats(){
const tmpUser = await api.get("/profile")
const tmpUsers = await api.get("/users");
console.log(convs);
// console.log("invite data use effect= ", tmpInvite.data);
setPartyInvite(tmpInvite.data);
setUser(tmpUser.data);
setConversation(convs.data);
setUsers(tmpUsers.data);
// console.log(`connection....`);
socket.current = io('http://' + process.env.REACT_APP_BASE_URL + ':4001', { transports: ['polling'] });
// console.log(`connection done`);
socket.current = io('http://' + process.env.REACT_APP_SOCKET_URL + ':4001', { transports: ['polling'] });
socket.current.emit('connection', {username: tmpUser.data.username})
socket.current.on('message', (data) => { //data should be a message ?)
socket.current.on('message', (data) => {
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
});
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();
};
}, [])
@ -160,29 +125,19 @@ 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);
}
}
// 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])
@ -196,7 +151,6 @@ function Chats(){
try {
const res = await api.post('/getMessage', data);
console.log("message of conv=", res.data)
setMessage(res.data);
} catch(err) {
@ -205,11 +159,8 @@ function Chats(){
getMessage();
}, [currentChat]);
const handleSubmit = async (e: { preventDefault: () => void; })=>{
const handleSubmit = async (e: { key?: any; preventDefault: any; })=>{
e.preventDefault();
// console.log(`e= ${e.key}`)
// console.log(`name= ${user.username}`)
// let message;
if (!user || !currentChat)
return ;
const message = {
@ -221,13 +172,8 @@ 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;
@ -242,39 +188,15 @@ function Chats(){
}
}
const handleKeyPress = async (e: { key: string; })=> {
// console.log(`e in press= ${e.key}`)
const handleKeyPress = async (e: { key?: any; preventDefault: () => void; })=> {
if (e.key !== "Enter")
return ;
// 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)
}
handleSubmit(e);
}
const [friend, setFriend] = useState("");
// const [modalOpen, setModalOpen] = useState(false);
const [addFriend, setAddFriend] = useState(false);
const [block, setBlock] = useState(false);
@ -289,6 +211,8 @@ 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);
@ -306,27 +230,11 @@ 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{
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)
{
setAddFriend(true);
@ -341,14 +249,17 @@ 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); // Reset addFriend state
setAddFriend(false);
setShowAddFriendAlert(false);
}
else
@ -370,7 +281,7 @@ 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
@ -389,58 +300,14 @@ function Chats(){
<div className="chat">
<div className='navbar'>
<img src={DefaultPic} alt="profile" className="pic"/>
<IoLogoOctocat className="catchat"/>
<span>
{isLoading || !user ? (
<h4>Loading...</h4>
) : (
<h4>{user.nickname}</h4>
<h2>Chat</h2>
)}
</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) => (
@ -451,11 +318,11 @@ function Chats(){
onChange={(a) => handleOptionChange(selectTag.id, a.target.value)}
>
<option value="">{
selectTag.selectedOption ? selectTag.selectedOption : "Select an option"
selectTag.selectedOption ? selectTag.selectedOption : "Select a user"
}</option>
{users.filter((item) => !selectTags.some((tag) => tag.selectedOption === item.username)).map((item, index) => (
<option key={index} value={item.username}>
{item.username}
{item.nickname}
</option>
))}
</select>
@ -463,7 +330,7 @@ function Chats(){
))}
<TouchDiv>
<motion.div onClick={handleAddFriend}>
<MdOutlineGroupAdd />
<MdOutlineGroupAdd className="catchat"/>
</motion.div>
<AnimatePresence initial={false} onExitComplete={() => null}>
{showAddFriendAlert && addFriend && (
@ -476,7 +343,7 @@ function Chats(){
</TouchDiv>
<TouchDiv>
<motion.div onClick={handleBlockFriend}>
<ImBlocked />
<ImBlocked className="block"/>
</motion.div>
<AnimatePresence initial={false} onExitComplete={() => null}>
{showBlockAlert && block && (
@ -485,6 +352,9 @@ function Chats(){
{showBlockAlert && !block && (
<RedAlert handleClose={closeBlock} text={friend + ' was not found'} />
)}
{unblock ? (
<GreenAlert handleClose={closeUnblock} text={friend + ' was unblocked'} />
):("")}
</AnimatePresence>
</TouchDiv>
{currentChat && isAdmin ? (
@ -492,7 +362,7 @@ function Chats(){
<motion.div
onClick={() => (setting ? setSetting(false) : setSetting(true))}
>
<RiListSettingsLine/>
<RiListSettingsLine className="block"/>
<AnimatePresence
initial={false}
onExitComplete={() => null}
@ -527,13 +397,6 @@ function Chats(){
)}
</UserChat>
{/* {partyInvite.map((c) => {
return (
)})
} */}
{partyInvite.map( i =>(
<PartyInvite currentInvite={i}/>
))}
@ -543,10 +406,9 @@ function Chats(){
<div key={index}
onClick={() => setCurrentChat(c)}>
<UserChat>
<img className="pic-user" src={DefaultPic} alt="User" />
<HiChatBubbleLeft className="catchat"/>
<div className="infoSideBar">
<span>{c.name}</span>
{/* <SideP>Desc?</SideP> */}
<h2>{c.name}</h2>
</div>
</UserChat>
</div>
@ -563,7 +425,6 @@ function Chats(){
<Message key={m.id} message= {m} own={m.sender === user.username}/>
))}
</div>
{/* <Input/> */}
<div className="input">
<input
onKeyDown={handleKeyPress}
@ -585,7 +446,6 @@ function Chats(){
)}
</div>
</div>
// </div>
);
}

View File

@ -5,46 +5,20 @@ import { useState, useEffect } from "react";
import api from "../../script/axiosApi.tsx";
import React from "react";
import {User} from "../../../interfaces.tsx"
// import { useNavigate } from "react-router-dom";
const dropIn = {
hidden: { y: "-100vh", opacity: 0 },
visible: {
y: "0",
opacity: 1,
transition: {
duration: 0.3,
type: "spring",
damping: 100,
stiffness: 500,
},
},
exit: { y: "100vh", opacity: 0 },
};
interface ModalGame {
handleClose: Function,
// convId: string
}
const GameModal = ({ handleClose }: ModalGame) => {
const [users, setUsers] = useState([]);
// const [user, setUser] = useState();
const [selectedUser, setSelectedUser] = useState('');
// const [convs, setConvs] = useState([]);
const [channel, setChannel] = useState('');
// const history = useNavigate();
useEffect(() => {
const fetchData = async () => {
try {
const tmpUsers = await api.get("/users");
// const tmpUser = await api.get("/profile");
// const tmpConvs = await api.get("/convs");
setUsers(tmpUsers.data);
// setUser(tmpUser.data);
// setConvs(tmpConvs.data);
} catch (err) {
console.log(err);
}
@ -56,21 +30,8 @@ const GameModal = ({ handleClose }: ModalGame) => {
setSelectedUser(event.target.value);
};
// const joinChannel = async () => {
// try {
// await api.post("/join", { convId: channel });
// } catch (err) {
// console.log(err);
// }
// };
// const handleCheckButtonClick = () => {
// // Perform your check action here
// console.log("Checking user:", selectedUser);
// };
const handleButtonClick = async () => {
// let path = `play?`;
let path = `http://` + process.env.REACT_APP_BASE_URL + `/pong/play?`;
@ -79,10 +40,6 @@ 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) {
@ -90,21 +47,11 @@ const GameModal = ({ handleClose }: ModalGame) => {
}
if (selectedUser.length > 0)
path += 'username=' + selectedUser;//important here
path += 'username=' + selectedUser;
// Remove the trailing '&' character
// path = path.slice(0, -1);
// console.log(path)
// await api.post("/partyInvite", {username: selectedUser, gameId})
// console.log("path= ", path)
// history(path, { replace: true });
// window.location.replace(path);
window.history.pushState({}, '', path);
window.location.reload();
// history(path);
};
return (
@ -112,7 +59,6 @@ const GameModal = ({ handleClose }: ModalGame) => {
<motion.div
onClick={(e) => e.stopPropagation()}
className="modal"
// variant={dropIn}
initial="hidden"
animate="visible"
exit="exit"
@ -122,28 +68,19 @@ const GameModal = ({ handleClose }: ModalGame) => {
<option value="">Select a user</option>
{users.map((user: User) => (
<option key={user.id} value={user.username}>
{user.username}
{user.nickname}
</option>
))}
</select>
</div>
<div className="notClicked" id="canvas_container">
{/* <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="submit" onClick={handleButtonClick} >Play</button>
{/* <button className="submit" onClick={handleClose}>Cancel</button> */}
<button className="playInvite" onClick={handleButtonClick} >Play</button>
</div>
{/* <div className="div_submit">
<button className="submit" onClick={handleCheckButtonClick}>
Invite to play
</button>
</div> */}
</motion.div>
</Backdrop>
);

View File

@ -6,7 +6,7 @@
/* By: apommier <apommier@student.42.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2023/06/01 18:24:46 by apommier #+# #+# */
/* Updated: 2023/06/20 19:05:10 by apommier ### ########.fr */
/* Updated: 2023/06/25 23:24:46 by apommier ### ########.fr */
/* */
/* ************************************************************************** */
@ -14,8 +14,6 @@ import { useEffect, useState, useRef } from "react";
import api from '../../script/axiosApi.tsx';
import styled from "styled-components"
import DefaultPicture from '../../assets/profile.jpg'
// import { useRef } from "react";
// import { useEffect } from "react";
import '../../styles/Messages.css'
import {User, Conv, Message} from "../../../interfaces.tsx"
import React from "react";
@ -23,9 +21,9 @@ import React from "react";
const MeStyleP = styled.p`
background-color: #5843e4;
padding 10px 20px;
border-radius 10px 0px 10px 10px;
border-radius 10px;
color: white;
margin-right: 20px;
margin: 10px;
`
interface MessageMeProps {
@ -42,23 +40,19 @@ 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",})
}
scrollRef.current.scrollIntoView({ behavior: "smooth"});
}})
useEffect(() => {
const fetchProfilePicture = async () => {
try {
// const user = await api.get("/profile");
const tmpSender = await api.post("/user", {username: message.sender})
const tmpConv = await api.post("/convId", {convId: message.convId})
// const tmpSender = await api.post("/user", {username: message.sender})
const tmpUser = await api.get("/profile")
const pic = await api.post("/getPicture", {username: message.sender})
// console.log(`user naem profile pic222= ${currentUser.username}`)
// console.log(` profile pic222= ${pic.data}`)
setConv(tmpConv.data);
setUser(tmpUser.data);
setSender(tmpSender.data);
@ -68,36 +62,28 @@ function MessageMe({message, own}: MessageMeProps){
}
};
fetchProfilePicture();
}, [])
}, []);
const handleButtonClick = () => {
if (!sender)
return ;
let path = `http://` + process.env.REACT_APP_BASE_URL + `/profile/${sender.username}`;
// console.log("path= ", path)
// history(path, { replace: true });
// window.location.replace(path);
window.history.pushState({}, '', path);
window.location.reload();
};
if (!user || !sender || !conv)
{
// 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))/
else if (conv.banned && conv.banned.includes(user.username))
return (<></>);
else if (conv.muted && conv.muted.includes(user.username))
{
return (<></>);
}
return (
<div className={own ? "meMessage" : "youMessage"} ref={scrollRef}>
<div>
@ -107,7 +93,6 @@ function MessageMe({message, own}: MessageMeProps){
<img className="messageInfo" onClick={() => handleButtonClick()} src={DefaultPicture} alt="Default Profile Picture" />
)}
</div>
{/* <div className="usernameMesage">{message.senderNickname}</div> */}
{sender ? (
<div className="usernameMesage">{sender.nickname}</div>
): ""}

View File

@ -14,7 +14,6 @@ const MeStyleP = styled.p`
`
function MessageMe(){
// const scrollRef = useRef();
const scrollRef = useRef<HTMLDivElement>(null);
useEffect(() => {

View File

@ -1,60 +1,74 @@
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, Conv} from "../../../interfaces.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 ModalProps {
handleClose: Function,
}
};
const Modal = ({handleClose}) => {
// const [multi, setMulti] = useState(false);
const Modal = ({handleClose}: ModalProps) => {
const [selectTags, setSelectTag] = useState([{ id: 1, selectedOption: ''}]);
const [selectedOptionArray, setSelectedOptionArray] = useState([]);
const [users, setUsers] = useState([]);
const [user, setUser] = useState();
const [convs, setConvs] = useState([]);
const [users, setUsers] = useState<User[]>([]);
const [user, setUser] = useState<User>();
const [convs, setConvs] = useState<Conv[]>([]);
const [channel, setChannel] = useState('');
useEffect(()=> {
useEffect(()=> {
const getConv = async ()=>{
try {
const tmpUsers = await api.get("/users");
const tmpUser = await api.get("/profile");
const tmpConvs = await api.get("/convs");
console.log("users=", tmpUsers.data);
console.log("convs=", tmpConvs.data);
setUsers(tmpUsers.data);
setUser(tmpUser.data);
setConvs(tmpConvs.data);
} catch(err){
} catch(err) {
console.log(err)
}
}
getConv();
}, []);
const handleOptionChange = (selectId, selectedOption) => {
console.log("selected Option=", selectedOption)
const [askPass, setAskPass] = useState(false);
const [PassWord, setPassWord] = useState('');
useEffect(()=> {
const getConv = async ()=>{
try{
const tmpConv = await api.post("/convId", {convId: channel});
if (tmpConv.data.password)
setAskPass(true);
}
catch(err){
console.log(err);
}
}
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.data)
window.location.reload();
} catch (err) {
console.log(err);
}
handleClose();
}
const handleOptionChange = (selectId: number, selectedOption: string) => {
setSelectTag((prevTags) =>
prevTags.map((tag) =>
tag.id === selectId ? { ...tag, selectedOption } : tag
@ -65,50 +79,43 @@ const Modal = ({handleClose}) => {
const addNewSelectedTag = () => {
const newSelectedId = Math.max (...selectTags.map((tag) => tag.id)) + 1;
setSelectTag([...selectTags, { id: newSelectedId, selectedOption: ''}]);
console.log(selectTags)
};
const joinChannel = async () => {
try {
console.log("channel= ", channel)
await api.post("/join", {convId: channel})
window.location.reload();
} catch(err) {
console.log(err);
}
};
const saveSelectedOptions = async () => {
// const selectedOptions = selectTags.map((tag) => tag.selectedOption);
const selectedOptions = selectTags.map((tag) => tag.selectedOption).filter((option) => option !== '');
console.log("selected= ", selectedOptions);
//do db stuff here
const data = {
members: selectedOptions,
}
try{
// test
await api.post("/conv", data);
handleClose();
window.location.reload();
} catch(err) {
console.log(err);
}
setSelectedOptionArray(selectedOptions);
}
// let new_name;
return (
<Backdrop onClick={handleClose}>
<motion.div
onClick={(e) => e.stopPropagation()}
className="modal"
// variant={dropIn}
className="modalSetting"
initial="hidden"
animate="visible"
exit="exit"
>
<div className="settingFirstPart2">
{selectTags.map((selectTag) => (
<div key={selectTag.id}>
<select
@ -116,11 +123,11 @@ const Modal = ({handleClose}) => {
onChange={(a) => handleOptionChange(selectTag.id, a.target.value)}
>
<option value="">{
selectTag.selectedOption ? selectTag.selectedOption : "Select an option"
selectTag.selectedOption ? selectTag.selectedOption : "Select a user"
}</option>
{users.filter((item) => !selectTags.some((tag) => tag.selectedOption === item.name)).map((item, index) => (
{users.filter((item) => !selectTags.some((tag) => tag.selectedOption === item.nickname)).map((item, index) => (
<option key={index} value={item.username}>
{item.username}
{item.nickname}
</option>
))}
</select>
@ -130,12 +137,12 @@ const Modal = ({handleClose}) => {
<GrAdd onClick={addNewSelectedTag}/>
</div>
<div className="div_submit">
<Link to='#' className="submit" onClick={ saveSelectedOptions}>Submit</Link>
<Link to="#" className="submit" onClick={handleClose}>Cancel</Link>
<Link to='#' className="submit" onClick={saveSelectedOptions}>Submit</Link>
</div>
</div>
<div className="settingSecondPart">
{convs.length > 0 && (
<select
@ -143,9 +150,9 @@ const Modal = ({handleClose}) => {
onChange={(event) => setChannel(event.target.value)}
>
<option value="">Select an option</option>
<option value="">Select a channel</option>
{convs.map((conv) => (
!(!conv.group || conv.private || (conv.banned && conv.banned.includes(user.username)) || (conv.members && conv.members.includes(user.username))) && (
!(!conv.group || conv.private || (conv.banned && user && conv.banned.includes(user.username)) || (conv.members && user && conv.members.includes(user.username))) && (
<option key={conv.id} value={conv.id}>
{conv.name}
</option>
@ -153,17 +160,20 @@ const Modal = ({handleClose}) => {
))}
</select>
)}
{channel.private ? (
<input className="mdp" placeholder="password" type="text" />
):("")}
<div>
{askPass ? (
<input className="mdp" placeholder="password" type="password" onChange={(e) => setPassWord(e.target.value)} onKeyDown={handlePassword}/>
):(
<div className="div_submit">
<Link to='#' className="submit" onClick={ joinChannel }>Join</Link>
</div>
)}
</div>
</div>
</motion.div>
</Backdrop>
)

View File

@ -1,31 +1,13 @@
import { motion } from "framer-motion";
import { AnimatePresence, 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 { User } from "../../../interfaces.tsx"
import { Socket } from "socket.io-client";
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,},
};
import GreenAlert from "../Alert/GreenAlert.tsx";
interface ModalSettingProps {
handleClose: Function,
@ -33,14 +15,16 @@ interface ModalSettingProps {
socket: Socket | null,
}
const ModalSetting = ({handleClose, convId, socket }: ModalSettingProps) => {
const ModalSetting = ({ handleClose, convId, socket }: ModalSettingProps) => {
const [password, setPassword] = useState(false);
const [users, setUsers] = useState<User[]>([]);
const [selectTags, setSelectTag] = useState([{ id: 1, selectedOption: ''}]);
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(false);
const [privateConv, setPrivateConv] = useState<Boolean>();
const [loading, setLoading] = useState<Boolean>(true);
const dark = () => setPrivateConv(true);
const light = () => setPrivateConv(false);
const [mute, setMute] = useState(false);
@ -48,28 +32,42 @@ const ModalSetting = ({handleClose, convId, socket }: ModalSettingProps) => {
const lightMute = () => setMute(true);
useEffect(()=> {
useEffect(() => {
console.log("convid =", convId)
const getUsers = async ()=>{
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);
} catch(err){
setLoading(false);
} catch (err) {
console.log(err)
}
}
getUsers();
}, []);
// const [multi, setMulti] = useState(false);
// const [selectedOptionArray, setSelectedOptionArray] = useState([]);
useEffect(() => {
const handleVariableChange = () => {
if (privateConv === undefined) {
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 handleOptionChange = (selectId: number, selectedOption: string) => {
console.log("tag= ", selectTags)
console.log("option= ", selectedOption)
setSelectTag((prevTags) =>
prevTags.map((tag) =>
tag.id === selectId ? { ...tag, selectedOption } : tag
@ -80,98 +78,83 @@ 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)
}
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; })=>{
const handleName = async (e: { key: string; }) => {
if (e.key !== "Enter")
return ;
try{
api.post("/name", {convId: convId, name: newName})
return;
try {
api.post("/name", { convId: convId, name: newName })
window.location.reload()
} catch(err) {
} catch (err) {
console.log(err);
}
handleClose();
}
const handlePassword = async (e: { key: string; })=>{
const handlePassword = async (e: { key: string; }) => {
if (e.key !== "Enter")
return ;
try{
await api.post("/password", {convId: convId, password: newPassword})
} catch(err) {
return;
try {
await api.post("/password", { convId: convId, password: newPassword })
} catch (err) {
console.log(err);
}
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)
try {
if (!selectedUser.length)
return ;
await api.post("/ban", {convId: convId, username: selectedUser})
if (socket)
{
console.log("emit to ban server")
socket.emit("ban", {username: selectedUser})
return;
const res = await api.post("/ban", { convId: convId, username: selectedUser })
if (res.data === 2) {
setUnban(true);
}
} catch(err) {
if (socket) {
socket.emit("ban", { username: selectedUser })
}
} catch (err) {
console.log(err);
}
handleClose();
setTimeout(handleClose, 1500);
};
const handleAdmin = async () => {
if (!selectedUser.length)
return ;
try{
await api.post("/admin", {convId: convId, username: selectedUser})
} catch(err) {
return;
try {
await api.post("/admin", { convId: convId, username: selectedUser })
} catch (err) {
console.log(err);
}
handleClose();
};
const handleMute = async () => {
if (!selectedUser.length)
return ;
try{
await api.post("/mute", {convId: convId, username: selectedUser})
} catch(err) {
const [muteAlert, setMuteAlert] = useState(false);
const closeMuteAlert = () => setMuteAlert(false);
const handleMute = async (e: { key: string; }) => {
if (e.key !== "Enter")
return;
try {
const ret = await api.post("/mute", { convId: convId, username: selectedUser, time: time })
if (ret.data)
setMuteAlert(true);
} catch (err) {
console.log(err);
}
handleClose();
};
const handleInvite = async () => {
try{
await api.post("/invite", {convId: convId, username: selectedUser})
} catch(err) {
try {
await api.post("/inviteConv", { convId: convId, username: selectedUser });
} catch (err) {
console.log(err);
}
handleClose();
@ -186,34 +169,29 @@ 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>
<Link to="#" onClick={light} className={privateConv ? "submit" : "darkSubmit"}>Public</Link>
<Link to="#" onClick={dark} className={privateConv ? "darkSubmit" : "submit"}>Private</Link>
</div>
{/* <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 ? (
<p className="checkbox">Password<input className="inside_ckeckbox" type="checkbox" value="password" checked={password} onChange={handleCheckPass} /> </p>
{password ? (
<input
onChange={(e) => setNewPassword(e.target.value)}
onKeyDown={handlePassword}
type="password"
className="in"
placeholder="Password"/>
):
placeholder="Password" />
) :
("")}
</div>
<div className="forName">
<input
onChange={(e) => setNewName(e.target.value)}
onKeyDown={handleName}
maxLength={20}
type="text"
className="in"
placeholder="New Name"
@ -221,8 +199,6 @@ const ModalSetting = ({handleClose, convId, socket }: ModalSettingProps) => {
</div>
</div>
{/* Second selection */}
<div className="settingSecondPart">
@ -237,25 +213,39 @@ const ModalSetting = ({handleClose, convId, socket }: ModalSettingProps) => {
</option>
{users.map((item, index) => (
<option key={index} value={item.username}>
{item.username}
{item.nickname}
</option>
))}
</select>
</div>
))}
<div>
<Link to="#" onClick={handleInvite} className="submit">Send</Link>
<Link to="#" onClick={handleInvite} className="submit">Invite</Link>
<Link to="#" onClick={handleBan} className="submit">Ban</Link>
<Link to="#" onClick={mute ? darkMute : lightMute} className={mute ? "darkSubmit": "submit"}>Mute</Link>
<Link to="#" onClick={mute ? darkMute : lightMute} className={mute ? "darkSubmit" : "submit"}>Mute</Link>
<Link to="#" onClick={handleAdmin} className="submit">Admin</Link>
</div>
</div>
{mute ? (
<input type="text" className="in_howLong" placeholder="How long ?" />
):("")}
<input
onKeyDown={handleMute}
type="number"
className="in_howLong"
placeholder="Time"
value={time}
onChange={(e) => setTime(e.target.value)}
/>
) : ("")}
<AnimatePresence initial={false} onExitComplete={() => null}>
{unban ? (
<GreenAlert handleClose={closeUnban} text={selectedUser + ": was unbanned"} />
) : ("")}
{muteAlert ? (
<GreenAlert handleClose={closeMuteAlert} text="Mute" />
) : ("")}
</AnimatePresence>
</motion.div>
</Backdrop>

View File

@ -6,7 +6,7 @@
/* By: apommier <apommier@student.42.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2023/06/19 16:44:29 by apommier #+# #+# */
/* Updated: 2023/06/20 23:53:01 by apommier ### ########.fr */
/* Updated: 2023/06/28 18:08:11 by apommier ### ########.fr */
/* */
/* ************************************************************************** */
@ -33,12 +33,6 @@ const UserChat = styled.div `
}
`
const SideP = styled.p`
font-size: 14px;
color: lightgray;
margin-left: 15px;
`
interface InviteProps {
username: string,
gameId: string
@ -53,19 +47,13 @@ export default function PartyInvite({currentInvite}: UserProps)
const [profilePicture, setProfilePicture] = useState('');
const [request, setRequest] = useState<User>(); //user who invite
const [clickEvent, setClickEvent] = useState(false);
// const [user, setUser] = useState(null);
useEffect(() => {
const fetchProfilePicture = async () => {
try {
// const user = await api.get("/profile");\
// const tmpUser = await api.get("/profile")
const pic = await api.post("/getPicture", {username: currentInvite.username})
const tmpRequest = await api.post("/user", {username: currentInvite.username})
// setUser(tmpUser.data);
setRequest(tmpRequest.data);
// console.log(`user naem profile pic222= ${currentInvite.username}`)
// console.log(` profile pic222= ${pic.data}`)
setProfilePicture(pic.data);
} catch (error) {
console.error('Error fetching profile picture:', error);
@ -77,45 +65,33 @@ export default function PartyInvite({currentInvite}: UserProps)
const handleButtonClick = (user: InviteProps) => {
let path = `http://` + process.env.REACT_APP_BASE_URL + `/profile/${user.username}`;
// history(path, { replace: true });
// window.location.replace(path);
window.history.pushState({}, '', path);
window.location.reload();
};
const Accept = async (request: User) => {
try{
//call canvas ??
// await api.post("/friend", {username: request.username})
await api.post("/deleteInvite", {username: request.username})
let path = `http://` + process.env.REACT_APP_BASE_URL + `/pong/play?`
path += 'username=' + request.username;
path += '&gameId=' + currentInvite.gameId;
// setClickEvent(true);
window.history.pushState({}, '', path);
window.location.reload();
} catch(err) {
console.log(err);
}
console.log("accept")
console.log(`request = ${request}`)
}
const Refuse = async (request: User) => {
try{
await api.post("/deleteInvite", {username: request.username})
// await api.post("/refuseInvite", {username: request.username})
setClickEvent(true);
} catch(err) {
console.log(err);
}
console.log("refuse")
console.log(`request = ${request}`)
}
// Vérifier si le contenu doit être caché
if (clickEvent) {
console.log("retrun true")
return null; // Rendre null pour ne pas afficher le contenu
}

View File

@ -1,12 +1,10 @@
import {motion} from "framer-motion"
// import Backdrop from "../Sidebar/Backdrop"
import {Link} from 'react-router-dom';
import { UserProfile } from "../../DataBase/DataUserProfile";
import {useState} from 'react';
import { AnimatePresence, motion } from "framer-motion"
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: {
@ -20,51 +18,36 @@ const dropIn = {
},
}
// const changeName = ({handleclose, name}) => {
// return (
// UserProfile.UserName = name
// )
// }
const ModalEdit = ( handleClose ) => {
// let new_name = "";
const ModalEdit = () => {
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 =>
{
const handler = (e: { target: { value: React.SetStateAction<string>; }; }) => {
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);
}
};
postNickname();
}
const handlePostNickname = async () =>
{
console.log("nickname=" ,nickname)
try{
await api.post("/nickname", {nickname: nickname})
const handlePostNickname = async () => {
try {
if (nickname.length > 3) {
const ret = await api.post("/nickname", { nickname: nickname });
if (ret.data) {
window.location.reload();
// setUser(tmpUser.data);
// setIsLoading(false)
}
catch(err){
else {
setErrTaken(true);
}
}
else if (nickname.length < 3)
setErrTooShort(true);
}
catch (err) {
console.log(err);
}
}
// function handleClose(){
// //do nothing
// }
return (
<motion.div
className="modal"
@ -72,17 +55,27 @@ const ModalEdit = ( handleClose ) => {
initial="hidden"
animate="visible"
exit="exit">
<h2>Type your new name</h2>
<input className="text" maxLength="10" type="text" value={nickname} onChange={handler} handleClose/>
<h1>Type your new name</h1>
<input className="text" minLength={2} maxLength={10} type="text" value={nickname} onChange={handler} />
<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>
)
}

View File

@ -1,17 +1,21 @@
import React from "react";
import api from "../../script/axiosApi"
function Logout(){
const logout = async () =>{
try {
await api.post("/logout");
localStorage.clear();
const path = 'http://' + process.env.REACT_APP_BASE_URL + '/';
// history(path, { replace: true });
// window.location.replace(path);
// window.history.pushState({}, '', path);
window.history.pushState({}, '', path);
window.location.reload();
return (<></>)
} catch (err) {
console.log(err);
}
}
logout();
}
export default Logout;

View File

@ -1,69 +1,32 @@
// import PropTypes from "prop-types"
// import styled from 'styled-components';
// import '../DataBase/DummyDBWinLoss.js'
// import '../DataBase/DataProfileUser.js'
// import { DBWinLoss } from '../../DataBase/DummyDBWinLoss.js';
import '../../styles/Win_Loss.css'
import { User, Matchlog } from "../../../interfaces.tsx"
// import { UserProfile } from '../../DataBase/DataUserProfile';
// import color from '../../utils/style/color.js';
// const CardWrapper = styled.div`
// display: flex;
// flex-direction: column;
// padding: 15px;
// background-color: black;
// border-radius: 30px;
// width: 350px;
// transition: 200ms;
// margin-top: 50px;
// &:hover {
// cursor: pointer;
// box-shadow: 2px 2px 10px #b6b6b6;
// }
// `
// const CardLabel1 = styled.h1`
// color: #5843e4;
// // font-size: 22px;
// font-weight: bold;
// margin-bottom: 25px;
// `
// const CardLabel2 = styled.span`
// color: #5843e4;
// font-size: 22px;
// font-weight: bold;
// display: flex;
// flex-direction: column;
// `
// const CardImage = styled.img`
// heigh: 80px;
// width: 80px;
// border-radius: 50%;
// `
import React, { useState, useEffect, useRef } from "react";
import React, { useState, useEffect} from "react";
import { useParams } from 'react-router-dom';
import api from '../../script/axiosApi.tsx';
function WinLoss() {
const [user, setUser] = useState<User>();
const [history, setHistory] = useState([]);
const [isLoading, setIsLoading] = useState(true);
const { username } = useParams();
useEffect(()=> {
const getUser = async ()=>{
try{
// const tmpUser = await api.get("/profile")
const tmpUser = await api.post("/user", {username: username})
const tmpHistory = await api.post("/history", {username: 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})
}
setHistory(tmpHistory.data);
setUser(tmpUser.data);
setIsLoading(false)
@ -75,65 +38,28 @@ function WinLoss() {
getUser();
}, [])
// console.log(`user= ${user.children}`)
return (
// <div>
// {isLoading ? (
// <h1>Loading...</h1>
// ) : (
// <h1>{user.username}</h1>
// )}
// </div>
<div className='tab'>
{isLoading || !history || !user ? (
<h1>Loading...</h1>
// <span>Loading...</span>
) : (
<div className='scroll'>
<h2 className='title'>Match history Win/Loss</h2>
<h2 className='title'>Match history {user.win}/{user.loss}</h2>
{history.map((c: Matchlog, index) => {
return (
<div key={index} className='elements'>
<li key={index}>
{/* <h4 className='content'>{c.id}</h4> */}
<div className='content2nd'>
<h4 className='me'>{user.username}</h4> <h4 className='score'>{c.myScore} - {c.opScore} </h4> <h4 className="opponent">{c.opponent}</h4>
</div>
{/* <h4 className='content'>{c.openent}</h4> */}
</li>
</div>
)
})}
</div>
// <div>
// <h1>User: {user.name}</h1>
// <div>
// <h2>Children:</h2>
// {history.map((child) => (
// <div key={child.id}>
// <p>Child ID: {child.id}</p>
// <p>Child Name: {child.name}</p>
// {/* Render other child properties as needed */}
// </div>
// ))}
// </div>
// </div>
)}
</div>
)
}
// Card.propTypes = {
// label: PropTypes.string,
// title: PropTypes.string.isRequired,
// picture: PropTypes.string,
// }
export default WinLoss

View File

@ -1,4 +1,4 @@
import React, { MouseEventHandler, ReactNode, HTMLAttributes } from "react";
import React, { ReactNode } from "react";
import { motion } from "framer-motion"
import "../../styles/Header.css"

View File

@ -26,7 +26,7 @@ export const SidebarData = [
cName: 'nav-text'
},
{
title: 'Friend',
title: 'Friends',
path: '/social',
icon: <IoIcons.IoMdPeople />,
cName: 'nav-text'

View File

@ -6,7 +6,7 @@
/* By: apommier <apommier@student.42.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2023/06/09 08:18:58 by apommier #+# #+# */
/* Updated: 2023/06/20 13:41:44 by apommier ### ########.fr */
/* Updated: 2023/06/28 17:59:49 by apommier ### ########.fr */
/* */
/* ************************************************************************** */
@ -16,7 +16,6 @@ import DefaultPicture from '../../assets/profile.jpg'
import styled from "styled-components";
import { RxCircle } from "react-icons/rx";
import { CgFontSpacing } from "react-icons/cg";
import React from "react";
import {User} from "../../../interfaces.tsx"
@ -27,22 +26,17 @@ const UserChat = styled.div `
gap: 5px;
color: white;
cursor: pointer;
margin-top: 15px;
&:hover{
background-color: #3e3c61;
}
`
const SideP = styled.p`
font-size: 14px;
color: lightgray;
margin-left: 15px;
`
interface UserProps {
currentUser: User
}
// export default function Friend({currentUser})
export default function Friend({currentUser}: UserProps)
{
const [profilePicture, setProfilePicture] = useState('');
@ -50,23 +44,18 @@ export default function Friend({currentUser}: UserProps)
useEffect(() => {
const fetchProfilePicture = async () => {
try {
// const user = await api.get("/profile");
const pic = await api.post("/getPicture", {username: currentUser.username})
// console.log(`user naem profile pic222= ${currentUser.username}`)
// console.log(` profile pic222= ${pic.data}`)
setProfilePicture(pic.data);
} catch (error) {
console.error('Error fetching profile picture:', error);
}
};
fetchProfilePicture();
})
}, []);
function getStatus(friend: User)
{
let status = friend.status
console.log(`status= ${status}`)
let statusColor;
if (status === 0)
@ -78,40 +67,25 @@ export default function Friend({currentUser}: UserProps)
return statusColor;
}
const handleSpectate = (user: User) => {
//socket connection and add to party with one with username
console.log(`spectate hehe`)
console.log(`user= ${user}`)
};
const handleButtonClick = (user: User) => {
let path = `http://` + process.env.REACT_APP_BASE_URL + `/profile/${user.username}`;
console.log("path= ", path)
// history(path, { replace: true });
// window.location.replace(path);
window.history.pushState({}, '', path);
window.location.reload();
};
return (
<UserChat>
<UserChat className="centermargin">
{profilePicture ? (
<img className="pic-user" src={`data:image/jpeg;base64,${profilePicture}`} />
) : (
<img className="pic-user" src={DefaultPicture} alt="Default Profile Picture" />
)}
<div className="infoSideBar">
<div className="end">
<span onClick={() => handleButtonClick(currentUser)}>{currentUser.nickname}</span>
<RxCircle color={getStatus(currentUser)} />
<button onClick={() => handleSpectate(currentUser)} >Invite</button>
{getStatus(currentUser) !== 'blue' ? (
<></>
) : (
<button onClick={() => handleSpectate(currentUser)} >Spectate</button>
)}
<div className="end">
<RxCircle className="friendRequest" color={getStatus(currentUser)} />
</div>
</div>
</UserChat>
)
}

View File

@ -15,18 +15,12 @@ const UserChat = styled.div `
gap: 5px;
color: white;
cursor: pointer;
margin-top: 10px;
&:hover{
background-color: #3e3c61;
}
`
const SideP = styled.p`
font-size: 14px;
color: lightgray;
margin-left: 15px;
`
interface UserProps {
currentUser: User
}
@ -34,21 +28,15 @@ interface UserProps {
export default function Friend({currentUser}: UserProps)
{
const [profilePicture, setProfilePicture] = useState('');
const [request, setRequest] = useState<User>(); //user who invite
const [request, setRequest] = useState<User>();
const [clickEvent, setClickEvent] = useState(false);
// const [user, setUser] = useState(null);
useEffect(() => {
const fetchProfilePicture = async () => {
try {
// const user = await api.get("/profile");\
// const tmpUser = await api.get("/profile")
const pic = await api.post("/getPicture", {username: currentUser.username})
const tmpRequest = await api.post("/user", {username: currentUser.username})
// setUser(tmpUser.data);
setRequest(tmpRequest.data);
// console.log(`user naem profile pic222= ${currentUser.username}`)
// console.log(` profile pic222= ${pic.data}`)
setProfilePicture(pic.data);
} catch (error) {
console.error('Error fetching profile picture:', error);
@ -60,8 +48,6 @@ export default function Friend({currentUser}: UserProps)
const handleButtonClick = (user: User) => {
let path = `http://` + process.env.REACT_APP_BASE_URL + `/profile/${user.username}`;
// history(path, { replace: true });
// window.location.replace(path);
window.history.pushState({}, '', path);
window.location.reload();
};
@ -73,8 +59,7 @@ export default function Friend({currentUser}: UserProps)
} catch(err) {
console.log(err);
}
console.log("accept")
console.log(`request = ${request}`)
window.location.reload();
}
const Refuse = async (request: User) => {
@ -84,30 +69,29 @@ export default function Friend({currentUser}: UserProps)
} catch(err) {
console.log(err);
}
console.log("refuse")
console.log(`request = ${request}`)
window.location.reload();
}
// Vérifier si le contenu doit être caché
if (clickEvent) {
return null; // Rendre null pour ne pas afficher le contenu
return (<></>);
}
return (
<UserChat>
<UserChat className="centermargin">
{profilePicture ? (
<img className="pic-user" src={`data:image/jpeg;base64,${profilePicture}`} />
) : (
<img className="pic-user" src={DefaultPicture} alt="Default Profile Picture" />
)}
{request ? (
<div className="infoSideBar">
<div className="end">
<span onClick={() => handleButtonClick(currentUser)}>{currentUser.nickname}</span>
<RxCheckCircled onClick={() => Accept(request)} color={'green'}/>
<RxCircleBackslash onClick={() => Refuse(request)} color={'red'}/>
<div className="end">
<RxCheckCircled className="friendRequest" onClick={() => Accept(request)} color={'green'}/>
<RxCircleBackslash className="friendRequest" onClick={() => Refuse(request)} color={'red'}/>
</div>
</div>
) : ( "" )}
</UserChat>
)
}

View File

@ -1,43 +1,16 @@
import DefaultPicture from '../../assets/profile.jpg'
import api from '../../script/axiosApi.tsx';
import React, { useState, useEffect, useRef } from "react";
import styled from "styled-components";
import React, { useState, useEffect} from "react";
import Friend from './Friend.tsx';
import FriendRequest from './FriendRequest.tsx';
import { ImBlocked } from 'react-icons/im';
import { MdOutlineGroupAdd } from 'react-icons/md';
import {IoMdPeople} from 'react-icons/io'
import {User} from "../../../interfaces.tsx"
// import React from "react";
import { useNavigate } from "react-router-dom";
const TouchDiv = styled.div`
margin-left: 10px;
margin-right: 4px;
margin-bottom: 21px;
margin-top: 21px;
cursor: pointer;
justify-content: space-around;
&:hover {
color: #F4F3EF;
}
`
function Social (){
const [friends, setFriends] = useState([]);
const [invite, setInvite] = useState([]);
const [isLoading, setIsLoading] = useState<boolean>(true);
const [user, setUser] = useState<User>();
const [profilePicture, setProfilePicture] = useState('');
useEffect(()=> {
const getFriend = async ()=>{
@ -45,14 +18,10 @@ function Social (){
const tmpFriends = await api.get("/friends")
const tmpUser = await api.get("/profile")
const tmpInv = await api.get("/inviteRequest")
const pic = await api.post("/getPicture", {username: tmpUser.data.username})
setInvite(tmpInv.data);
setProfilePicture(pic.data);
setUser(tmpUser.data);
setFriends(tmpFriends.data);
// return tmpUser;
console.log(`user= ${tmpUser.data.username}`);
setIsLoading(false)
}
@ -64,61 +33,28 @@ function Social (){
}, [])
// const { status } = this.props;
// let statusColor = '';
// // let statusIcon = RxCircle;
// let status = 0
// if (status === 0) {
// // statusIcon = faCircle;
// statusColor = 'green';
// } else if (status === 1) {
// // statusIcon = faCircle;
// statusColor = 'red';
// } else if (status === 2) {
// // statusIcon = faCircle;
// statusColor = 'blue';
// }
return (
<div>
<div className='navbar'>
{/* <img src={DefaultPic} alt="profile" className="pic"/> */}
{profilePicture ? (
<img className="pic" src={`data:image/jpeg;base64,${profilePicture}`} />
) : (
<img className="pic" src={DefaultPicture} alt="Default Profile Picture" />
)}
<div className='navbarSocial'>
<IoMdPeople className="catchat"/>
<span>
{isLoading || !user ? (
<h4>Loading...</h4>
) : (
<h4>{user.nickname}</h4>
<h2>Friends</h2>
)}
</span>
<div className="end">
<TouchDiv>
<MdOutlineGroupAdd/>
</TouchDiv>
<TouchDiv>
<ImBlocked/>
</TouchDiv>
</div>
</div>
{/* map with fiend request */}
{invite.map(c=> (
<FriendRequest currentUser={c}/>
{invite.map((c: User)=> (
<FriendRequest currentUser={c} key={c.username}/>
))}
{friends.map(c=> (
<Friend currentUser={c}/>
{friends.map((c: User)=> (
<Friend currentUser={c} key={c.username}/>
))}
</div>
)
}

View File

@ -1,27 +0,0 @@
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();

View File

@ -0,0 +1,22 @@
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>
);

View File

@ -1,112 +1,17 @@
import React, { useCallback, useState, useEffect } from 'react';
import React, { 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>('');
useEffect(() => {
async function getCode(){
await api.get('/QRcode', { responseType: 'blob' })
.then(response => {
const reader = new FileReader();
if (!reader)
return ;
reader.onloadend = () => {
setImageSrc(reader.result);
};
@ -119,23 +24,12 @@ 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>
{/* <form onSubmit={handleSubmit}>
<button type="submit">Confirm</button>
</form> */}
</div>
);

View File

@ -1,13 +1,9 @@
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';
import api from '../script/axiosApi.tsx';
interface GameProps {
privateParty: boolean,
@ -17,11 +13,37 @@ interface GameProps {
function Field()
{
useEffect(() => {
const addGameSession = async () => {
try {
await api.post("/addGame");
} catch (err) {
console.log(err);
}
};
addGameSession();
const handleBeforeUnload = async () => {
try {
await api.post("/rmGame");
} catch (err) {
console.log(err);
}
};
window.addEventListener('beforeunload', handleBeforeUnload);
return () => {
window.removeEventListener('beforeunload', handleBeforeUnload);
};
}, []);
useEffect(() => {
// const location = useLocation();
const queryParams = queryString.parse(window.location.search);
console.log("launch canva hehe")
let Modifiers = 0;
let info: GameProps;
@ -43,20 +65,16 @@ function Field()
}
if (queryParams.username)
{
console.log("user= ", queryParams.username)
info = {
privateParty: true,
username: queryParams.username as string,
gameId: queryParams.gameId as unknown as number
}
console.log("info of param vefore canvas=", info)
}
const cleanup = DrawCanvas(Modifiers, info);
return () => {
console.log("Cleanup");
// cleanup(); // Call the cleanup function to stop the ongoing process or perform necessary cleanup tasks
if (cleanup)
cleanup();
};

View File

@ -7,9 +7,7 @@ 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>
);

View File

@ -1,50 +0,0 @@
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;

View File

@ -6,127 +6,64 @@
/* By: apommier <apommier@student.42.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2023/06/09 08:19:04 by apommier #+# #+# */
/* Updated: 2023/06/23 15:58:14 by apommier ### ########.fr */
/* Updated: 2023/06/28 17:47:35 by apommier ### ########.fr */
/* */
/* ************************************************************************** */
// import { React, useState } from "react";
import '../styles/Profile.css'
// import '../styles/App.css'
import RedAlert from "../components/Alert/RedAlert.tsx";
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 {AiOutlineHistory} from 'react-icons/ai'
import {AiOutlineCloseCircle, 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 * as React from 'react';
// import { useState, useEffect, useParams} from "react";
import React, { useState, useEffect, useRef, ChangeEventHandler } from "react";
import React, { useState, useEffect } from "react";
import { useParams } from 'react-router-dom';
import {User, Conv} from "../../interfaces.tsx"
import {User} 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) {
console.log("selected photo")
const formData = new FormData();
formData.append('photo', photo);
try {
await api.post('/picture', formData);
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}`)
// const pic
let pic
let pic;
try{
const me = await api.get("/profile")
if (!username)
{
setMine(true);
setUser(me.data);
console.log(`mine= true = ${mine}`)
pic = await api.post("/getPicture", {username: me.data.username}) //good one?
// username = me.data.username
}
else
{
@ -135,9 +72,7 @@ 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){
@ -149,8 +84,6 @@ 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}`} />
) : (
@ -160,12 +93,9 @@ function Profile () {
{isLoading || !user ? (
<h1>Loading...</h1>
) : (
<h1>{user.nickname}</h1>
<h1 className='user_name'>{user.nickname}</h1>
)}
</span>
{mine ? (
<div>
<motion.div >
@ -176,25 +106,22 @@ 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={modalOpen} handleclose={close}/>}
{modalOpen && <ModalEdit/>}
</AnimatePresence>
</div>
)
@ -202,8 +129,7 @@ function Profile () {
function Home () {
const [move, setmove ] = useState(false);
const [user, setUser] = useState([]);
const [user, setUser] = useState<User>();
const [successQr, setSuccessQr] = useState(false);
const [successSword, setSuccessSword] = useState(false);
const [successCrown, setSuccessCrown] = useState(false);
@ -211,20 +137,29 @@ 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"
@ -232,19 +167,19 @@ function Home () {
animate={{opacity: 1}}
exit={{opacity: -1}}>
<div>
{user.otp_verified ? (
{user && user.otp_verified ? (
<MdQrCodeScanner className='success' onClick={() => setSuccessQr(true)}/>
):("")}
{user.win >= 2 ? (
{user && user.win >= 2 ? (
<GiWingedSword className="success" onClick={() => setSuccessSword(true)}/>
):("")}
{user.win >= 5 ? (
{user && user.win >= 5 ? (
<GiCrownedSkull className="success" onClick={() => setSuccessCrown(true)}/>
):("")}
</div>
<div className="home">
<motion.div animate={{x: move ? -200: 120}}
<motion.div
animate={{x: move ? '-50%' : '25%'}}
transition={{type: "tween", duration: 0.5}}>
<Profile/>
</motion.div>
@ -254,9 +189,8 @@ function Home () {
</div>
<motion.div
className="div_history"
// className="history"
onClick={ () => setmove(!move)}>
<Link to="#" className="history"><AiOutlineHistory/> Match History</Link>
<Link to="#" className="history"> {move ? (<AiOutlineCloseCircle/>):(<AiOutlineHistory/>)} Match History</Link>
</motion.div>
<AnimatePresence initial={false} onExitComplete={() => null}>
{successQr ? (

View File

@ -1,47 +0,0 @@
// 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;

View File

@ -0,0 +1,22 @@
import '../styles/old.css';
import '../styles/field.css';
import React from 'react';
function HomeLogin()
{
const handleButtonClick = () => {
const token = localStorage.getItem('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;

View File

@ -1,29 +1,9 @@
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"
@ -31,7 +11,6 @@ function Messages() {
animate={{opacity: 1}}
exit={{opacity: 0}}>
<div className="container">
{/* <Sidebar/> */}
<Chats/>
</div>
</motion.div>

View File

@ -1,6 +1,5 @@
import React from 'react';
import '../styles/field.css';
// import { useHistory } from 'react-router-dom';
import { useNavigate } from "react-router-dom";
function PlayButton() {
@ -15,8 +14,6 @@ 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>
);
}

View File

@ -6,14 +6,14 @@ import "../styles/App.css";
import api from '../script/axiosApi.tsx';
import QRCodeStyling from "qr-code-styling";
import { motion } from 'framer-motion'
import { AnimatePresence, motion } from 'framer-motion'
import RedAlert from "../components/Alert/RedAlert.tsx";
const qrCode = new QRCodeStyling({
width: 300,
height: 300,
// image: "../assets/profile.jpg",
dotsOptions: {
color: "black",
type: "rounded"
@ -28,16 +28,13 @@ 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 history = useHistory();
const [err, setErr] = useState(false);
const closeErr = () => setErr(false);
useEffect(() => {
if (ref.current)
@ -45,7 +42,6 @@ function QrCode () {
const getUser = async ()=>{
try{
const tmpUser = await api.get("/profile");
setUser(tmpUser.data);
if (tmpUser.data.otp_verified)
{
setActivated(true);
@ -54,9 +50,6 @@ function QrCode () {
const otpData = await api.post("/otp");
setUrl(otpData.data.otpauth_url);
setSecret(otpData.data.base32_secret);
// const tmpUser = await api.get("/profile")
// console.log("test")
// console.table(convs);
}
catch(err){
console.log(err);
@ -72,30 +65,22 @@ function QrCode () {
const handleKeyPress = async (e: { key: string; })=>{
// console.log(`e in press= ${e.key}`)
if (e.key !== "Enter")
return ;
try{
console.log("code= ", code)
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")
// history.push('/login')
const path = 'http://' + process.env.REACT_APP_BASE_URL + '/';
window.history.pushState({}, '', path);
window.location.reload();
}
else
{
console.log("bad code")
//alert ?? retry
}
// redirect('/test')
console.log("Bad code")
}
catch(err){
console.log(err)
@ -105,8 +90,6 @@ function QrCode () {
const handleDesactivate = async () => {
try {
await api.post("/deleteOtp")
// const path = 'http://' + process.env.REACT_APP_BASE_URL + '/';
// window.history.pushState({}, '', path);
window.location.reload();
} catch(err) {
console.log(err);
@ -114,18 +97,6 @@ function QrCode () {
};
return (
// <motion.div className="page"
// initial={{opacity: -1}}
// animate={{opacity: 1}}
// exit={{opacity: -1}}>
// <h1>QRcode</h1>
// <h3>{secret}</h3>
// <div ref={ref} />
// <input type="text" className="qr" placeholder="Type The Code"/>
// {}
// </motion.div>
<motion.div
className="page"
initial={{ opacity: -1 }}
@ -138,7 +109,6 @@ function QrCode () {
<h3>{secret}</h3>
<h1>Or Scan The QRCode</h1>
<div ref={ref} />
{/* <div>{ref}</div> */}
</>
)}
@ -148,7 +118,7 @@ function QrCode () {
<h1>Double Auth Validation</h1>
<input
onKeyDown={handleKeyPress}
type="text"
type="number"
className="qr"
placeholder="6 Digits Code"
value={code}
@ -156,25 +126,14 @@ function QrCode () {
/>
</>
) : (
<button onClick={handleDesactivate}>Desactivate 2FA</button>
<button className="desactivate" onClick={handleDesactivate}>Desactivate 2FA</button>
)}
<AnimatePresence
initial={false}
onExitComplete={() => null}>
{err ? (<RedAlert handleClose={closeErr} text="Error: Bad intput. Try again"/>):("")}
</AnimatePresence>
</>
{/* {!localStorage.getItem('token') && (
<>
<h1>Double Auth</h1>
<input onKeyDown={handleKeyPress}
type="text"
className="qr"
placeholder="6 Digits Code"
onChange={(e) => setCode(e.target.value)}
/>
</>
) : (<button onClick={ handleDesactivate }>Desactivate 2FA</button>)}
*/}
{/* {!activated && (
<button onClick={() => setActivated(true)}>Activate</button>
)} */}
</motion.div>
)
}

View File

@ -1,9 +0,0 @@
import React from "react";
function Social (){
return (
<div>je suis la partie social</div>
)
}
export default Social

View File

@ -1,12 +1,6 @@
// import io from 'socket.io-client';
// import { useEffect } from 'react';
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,
@ -16,44 +10,20 @@ interface GameProps {
function DrawCanvas(option: number, gameParam: GameProps) {
console.log(`option= ${option}`);
const superpowerModifier = option & 1; // Retrieves the superpower modifier
const obstacleModifier = (option >> 1) & 1; // Retrieves the obstacle modifier
const speedModifier = (option >> 2) & 1; // Retrieves the speed modifier
console.log(`superpowerModifier = ${superpowerModifier}`);
console.log(`obstacleModifier = ${obstacleModifier}`);
console.log(`speedModifier = ${speedModifier}`);
// const socketRef = useRef(null);
// socketRef.current = io('http://localhost:4000');
function launchGame()
{
if (!gameParam.privateParty)
{
console.log("laucnh matchmaking")
matchmaking();
}
else if (!gameParam.gameId)
{
console.log("laucnh private")
privateParty();
}
else
{
console.log("join private")
joinPrivateParty();
}
}
// const socket = socketRef.current
console.log("start function");
// let canvas: HTMLElement | null;
const canvas = document.getElementById('myCanvas') as HTMLCanvasElement | null;;
const canvas = document.getElementById('myCanvas') as HTMLCanvasElement | null;
if (!canvas)
return ;
@ -61,15 +31,7 @@ function DrawCanvas(option: number, gameParam: GameProps) {
if(!ctx)
return ;
const socket = io('http://localhost:4000', { transports: ['polling'] });
// useEffect(() => {
// console.log("useeffect?????????????????")
// return () => {
// console.log("000000000000000000000000000000000")
// socketRef.current.disconnect();
// };
// }, []);
const socket = io('http://' + process.env.REACT_APP_SOCKET_URL + ':4000', { transports: ['polling'] });
//========================================================================================================
//========================================================================================================
@ -85,9 +47,7 @@ function DrawCanvas(option: number, gameParam: GameProps) {
//general canvas
let running = true;
const scale = window.devicePixelRatio;
canvas.width = canvas.offsetWidth;
// canvas.height = canvas.width * 0.7
canvas.height = canvas.offsetHeight;
//paddle var
@ -124,6 +84,8 @@ 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;
@ -136,31 +98,14 @@ 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 ?
await api.post('/rmGame');
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");
});
socket.on('pong:privateId', async (data) => {
console.log("private id = ", data)
try{
await api.post("/partyInvite", {username: gameParam.username, gameId: data});
} catch(err) {
@ -169,17 +114,13 @@ socket.on('pong:privateId', async (data) => {
});
socket.on('pong:gameId', async (data) => {
console.log("gameId received");
gameId = data;
gameId = data.gameId;
try {
let response = await api.get('/profile');
const myName = response.data.username;
response = await api.get('/rank');
await api.post('/status', {status: 2});
opRank = response.data
console.log(`rank= ${opRank}`);
console.log(`myname= ${myName}`);
const info = {
id: myId,
@ -188,18 +129,19 @@ socket.on('pong:gameId', async (data) => {
rank: opRank,
};
console.log("emit to name");
socket.emit('pong:name', info);
if (data.id === myId)
vX = 0.0005;
else
vX = -0.0005;
} catch (error) {
console.log(error);
// Handle error here
return;
}
});
socket.on('pong:name', (data) => {
opName = data;
console.log(`opponent Name= ${opName}`)
opName = data.name;
});
socket.on('connect', () => {
@ -207,9 +149,7 @@ socket.on('connect', () => {
});
socket.on('pong:clientId', (data) => {
console.log("receive id")
myId = data;
console.log(`id is= ${myId}`)
launchGame();
});
@ -222,36 +162,32 @@ 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
});
socket.on('pong:power', (data) => {
console.log("paddle info receive")
oPaddleY = 0;
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;
vX = -0.0005;
vY = 0;
ballX = canvas.width / 2;
ballY = canvas.height / 2;
});
socket.on('pong:hisPoint', (data) => {
hisScore = data.point;
vX = -0.0005;
vY = 0;
ballX = canvas.width / 2;
ballY = canvas.height / 2;
@ -265,7 +201,6 @@ socket.on('pong:point', (data) => {
function matchmaking()
{
console.log(`id ion matcj= ${myId}`)
const info = {
id: myId,
option: option,
@ -275,7 +210,6 @@ socket.on('pong:point', (data) => {
function privateParty()
{
console.log(`id private party= ${myId}`)
const info = {
id: myId,
option: option,
@ -285,7 +219,6 @@ socket.on('pong:point', (data) => {
function joinPrivateParty()
{
console.log(`id private party= ${myId}`)
const info = {
id: myId,
gameId: gameParam.gameId,
@ -316,13 +249,31 @@ socket.on('pong:point', (data) => {
{
if (!gameId || !canvas)
return ;
console.log("send point");
const info = {
id: myId,
gameId: gameId,
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()
@ -332,7 +283,6 @@ socket.on('pong:point', (data) => {
const info = {
id: myId,
paddleY: paddleY,
// width: canvas.width,
height: canvas.height,
gameId: gameId,
};
@ -378,14 +328,12 @@ socket.on('pong:point', (data) => {
function drawcenter()
{
// ctx.restore();
if (!ctx || !canvas)
return ;
ctx.fillStyle = 'white';
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
@ -411,7 +359,6 @@ socket.on('pong:point', (data) => {
return ;
ctx.beginPath();
ctx.arc(ballX, ballY, ballRadius, 0, 2 * Math.PI);
// ctx.lineWidth = 2;
ctx.fillStyle = 'red ';
ctx.fill();
}
@ -423,52 +370,48 @@ socket.on('pong:point', (data) => {
//========================================================================================================
//========================================================================================================
// while (!gameId)
// ;
// Define a function to stop the drawing process
const stopDrawCanvas = async () => {
running = false;
console.log("stopDrawCanvas 1")
if (gameParam.privateParty && !gameId) //delete invite
{
console.log("stopDrawCanvas2")
try{
// const info = {
// id: myId,
// option: option,
// };
await api.post("deleteInvite", {username: gameParam.username})
await api.post('/rmGame');
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);
}
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 ;
}
if (myScore === maxScore || hisScore === maxScore)
{
console.log("maxScore!!!!")
const data = {
myScore: myScore,
opScore: hisScore,
@ -478,22 +421,16 @@ async function draw(timestamp: number)
if (myScore === maxScore)
{
await api.post('/win', data);
await api.post('/status', {status: 1});
//disconnect ?
await api.post('/rmGame');
socket.emit('pong:disconnect', {id: myId});
console.log("send all ?? win");
}
else
{
await api.post('/loss', data);
await api.post('/status', {status: 1});
await api.post('/rmGame');
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 ;
}
@ -504,7 +441,6 @@ async function draw(timestamp: number)
if (!ctx)
return ;
// requestAnimationFrame(draw);
ctx.clearRect(0, 0, canvas.width, canvas.height);
drawPaddle();
drawcenter();
@ -557,10 +493,7 @@ async function draw(timestamp: number)
if (ballY <= paddleY + paddleHeight + ballRadius && ballY >= paddleY - ballRadius)//touch paddle
{
if (ballX + ballRadius > paddleX && ballX - ballRadius < paddleX + paddleWidth)
{
console.log("hehe here")
ballX = paddleX + paddleWidth + ballRadius;
}
updateVector();
}
send_info();
@ -568,13 +501,11 @@ 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();
}
}
@ -586,40 +517,19 @@ async function draw(timestamp: number)
{
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;
vX = 0.0005;
vY = 0;
hisScore += 1;
send_point();
// send_forced_info();
}
if (ballX > canvas.width)
{
// 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();
}
if (ballX > (canvas.width * 1.2) && ballX - (vX * 2) > canvas.width)
send_my_point();
}
@ -646,21 +556,14 @@ async function draw(timestamp: number)
document.addEventListener("touchmove", event => {
const touchY = event.touches[0].pageY;
// 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)
@ -673,55 +576,26 @@ async function draw(timestamp: number)
paddleY += paddleSpeed; // déplacer la raquette vers le bas
send_paddle_info();
}
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")
else if (event.code === "KeyW")
{
let date = new Date();
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();
}
});
requestAnimationFrame(draw);
console.log("retuuuuuuuuuuurn")
return (stopDrawCanvas);
}

View File

@ -0,0 +1,24 @@
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import Header from '../components/Header.tsx';
import Head from './Head.tsx';
import App from '../components/App.tsx';
import { BrowserRouter } from 'react-router-dom';
import './styles/index.css';
import './styles/App.css'
ReactDOM.render(
<html >
<Head />
<BrowserRouter>
<Header />
<App />
</BrowserRouter>
</html>,
document.getElementById('root') as HTMLElement
);

View File

@ -1,13 +0,0 @@
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;

View File

@ -1,30 +1,9 @@
import axios from 'axios';
function getToken() {
const token = localStorage.getItem('token');
if (typeof token === 'string') {
console.log("is a string !!!")
}
return token;
}
console.log(`getToken = ${getToken()}`)
console.log(`Bearer ${localStorage.getItem("token")}`)
// const test = "192.168.1.19"
// const url = 'http://' + process.env.REACT_APP_BASE_URL + '/api'
// const url = 'http://' + test + '/api'
// console.log("url= ", url)
// console.log("test= ", test)
// console.log("env= ", process.env.REACT_APP_BASE_URL)
let api = axios.create({
// baseURL: 'http://localhost/api',
baseURL: 'http://' + process.env.REACT_APP_BASE_URL + '/api',
headers: {
// Authorization: `Bearer ${getToken()}`,
Authorization : `Bearer ${localStorage.getItem("token")}`
},
withCredentials: true,

View File

@ -1,13 +0,0 @@
// export const login()
// {
// alert("Le bouton a été cliqué !");
// var formulaire = document.getElementById("loginForm");
// formulaire.submit();
// }
export const login = () => {
console.log('Hello from myFunction');
// alert("Le bouton a été cliqué !");
var formulaire = document.getElementById("loginForm");
formulaire.submit();
}

View File

@ -1,7 +0,0 @@
// function setupLogin()
// {
// // alert("Le bouton a été cliqué !");
// console.log('Hello from login42');
// }
// export default setupLogin;

View File

@ -1,19 +1,20 @@
import { useLocation } from 'react-router-dom';
import { useState, useEffect } from 'react'
import queryString from 'query-string';
import api from "./axiosApi.tsx";
import axios from 'axios';
import React from 'react';
import {User} from "../../interfaces.tsx"
function SuccessToken() {
const location = useLocation();
const { data } = queryString.parse(location.search);
const [code, setCode] = useState('');
const [user, setUser] = useState(false);
const [user, setUser] = useState<User>();
useEffect(() => {
if (!data) {
console.log("No data");
return;
return ;
}
const cleanData = data.slice(1, -1); // Declare cleanData here
@ -37,15 +38,10 @@ function SuccessToken() {
getUser();
}, [data]);
const handleKeyPress = async (e)=>{
// console.log(`e in press= ${e.key}`)
const handleKeyPress = async (e: { key: string; })=>{
if (e.key !== "Enter")
return ;
try{
console.log("code= ", code)
// const res = await api.post("/verifyOtp", {token: code})
const res = await axios({
method: 'POST',
url: 'http://' + process.env.REACT_APP_BASE_URL + '/api/verifyOtp',
@ -56,28 +52,13 @@ function SuccessToken() {
data: { token: code }
});
console.log("res= ", res.data)
console.log("res= ", res)
if (res.data === 1)
{
console.log("registered")
// history.push('/login')
localStorage.setItem('token', `${cleanData}`);
console.log(`prout token2= ${localStorage.getItem('token')}`);
window.location.replace("http://" + process.env.REACT_APP_BASE_URL + "/pong");
// const path = 'http://' + process.env.REACT_APP_BASE_URL + '/';
// window.history.pushState({}, '', path);
// window.location.reload();
}
else
{
console.log("bad code")
//alert ?? retry
}
// redirect('/test')
console.log("Bad code")
}
catch(err){
console.log(err)
@ -87,16 +68,14 @@ function SuccessToken() {
if (!user) {
// 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) {
console.log("false");
localStorage.setItem('token', `${cleanData}`);
console.log(`prout token2= ${localStorage.getItem('token')}`);
window.location.replace("http://" + process.env.REACT_APP_BASE_URL + "/pong");
return null; // or return a message or component indicating not verified
}
@ -117,131 +96,3 @@ function SuccessToken() {
}
export default SuccessToken;
// function SuccessToken() {
// const location = useLocation();
// const { data } = queryString.parse(location.search);
// if ( !data)
// {
// console.log("no data")
// return ;
// }
// const cleanData = data.slice(1, -1);
// const [code, setCode] = useState('');
// const [user, setUser] = useState(false);
// useEffect(()=> {
// const getUser = async ()=>{
// try {
// // const tmpUser = await api.get("/profile");
// const tmpUser = await axios({
// method: 'GET',
// url: 'http://' + process.env.REACT_APP_BASE_URL + '/api/profile',
// headers: {
// Authorization: `Bearer ${cleanData}`,
// },
// withCredentials: true,
// });
// setUser(tmpUser.data);
// // setUser(tmpUser.data);
// // if (tmpUser.data.otp_verified)
// // {
// // console.log("true");
// // return (
// // <>
// // <h1>Double Auth</h1>
// // <input
// // onKeyDown={handleKeyPress}
// // type="text"
// // className="qr"
// // placeholder="6 Digits Code"
// // value={code}
// // onChange={(e) => setCode(e.target.value)}
// // />
// // </>
// // )
// // }
// // else
// // {
// // console.log("false");
// // localStorage.setItem('token', `${cleanData}`);
// // console.log(`prout token2= ${localStorage.getItem('token')}`)
// // window.location.replace("http://" + process.env.REACT_APP_BASE_URL + "/pong");
// // }
// } catch(err) {
// console.log(err)
// }
// }
// getUser();
// }, []);
// const handleKeyPress = async (e)=>{
// // console.log(`e in press= ${e.key}`)
// if (e.key !== "Enter")
// return ;
// try{
// console.log("code= ", code)
// const res = await api.post("/verifyOtp", {token: code})
// console.log("res= ", res.data)
// console.log("res= ", res)
// if (res.data === 1)
// {
// console.log("registered")
// // history.push('/login')
// const path = 'http://' + process.env.REACT_APP_BASE_URL + '/';
// window.history.pushState({}, '', path);
// window.location.reload();
// }
// else
// {
// console.log("bad code")
// //alert ?? retry
// }
// // redirect('/test')
// }
// catch(err){
// console.log(err)
// }
// }
// console.log("start while...")
// while(user === false)
// ;
// console.log("end while")
// if (!user.otp_verified)
// {
// console.log("false");
// localStorage.setItem('token', `${cleanData}`);
// console.log(`prout token2= ${localStorage.getItem('token')}`)
// window.location.replace("http://" + process.env.REACT_APP_BASE_URL + "/pong");
// return ;
// }
// return (
// <>
// <h1>Double Auth</h1>
// <input
// onKeyDown={handleKeyPress}
// type="text"
// className="qr"
// placeholder="6 Digits Code"
// value={code}
// onChange={(e) => setCode(e.target.value)}
// />
// </>
// )
// }
// export default SuccessToken;

View File

@ -5,19 +5,41 @@
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: 20%;
width: auto;
border-radius: 5px;
background-color: rgb(0, 0, 0);
margin : 1%;
color:white;
border-color:rgb(42, 41, 41);
border-style: solid;
border-width: 1px;
color: #ccc;
}
.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 {
@ -48,3 +70,9 @@ input.qr{
transform: rotate(360deg);
}
}
.friendRequest {
margin-left: 4vh;
stroke-width: 0.5;
font-size: x-large;
}

View File

@ -3,10 +3,10 @@
margin: 50px;
}
.rank_elements {
border-width:1px;
border-style:solid;
/* background-color: #5843e4; */
border-color: grey;
/* overflow: scroll; */
padding: 5px 100px;
@ -14,15 +14,23 @@
}
.scroll {
/* border:3px; */
/* background-color: #5843e4; */
/* border-color: white; */
overflow: scroll;
height: 70vh;
height: 68vh;
}
.profilePic{
margin-left: 10px;
height: 30px;
width: 30px;
border-radius: 50%;
}
@media screen and (max-width: 755px){
.game{
display: grid;
height: 20vh;
}
.scroll{
height: 20vh;
}
}

View File

@ -1,10 +1,7 @@
.Header {
background-image: linear-gradient(90deg, #5843e4, #5a0760);
/* background-color: blue; */
height: 80px;
display: flex;
/* justify-content: start; */
align-items: center;
}
@ -25,10 +22,6 @@
top: 0;
left: 0;
transition: 350ms;
/* margin-top: 10px; */
/* left: -100%; */
/* transition: 850ms; */
}
.nav-menu.active {
@ -38,10 +31,8 @@
.nav-text {
display: flex;
/* justify-content: start; */
align-items: center;
padding: 8px 0px 8px 16px;
list-style: none;
height: 60px;
}
@ -54,9 +45,7 @@
height: 100%;
display: flex;
align-items: center;
/* padding: 0 16px; */
padding: 8px 8px 8px 8px;
border-radius: 20px;
}
@ -73,7 +62,6 @@
width: 100%;
height: 80px;
display: flex;
/* justify-content: start; */
align-items: center;
}
@ -92,17 +80,12 @@ span {
.success {
height: 2%;
width: 2%;
/* border: solid; */
margin-top: 1%;
margin: 3vh;
/* margin-bottom: -12vh; */
/* border-color: black; */
/* border-radius: 50%; */
}
.header-pic{
text-align: end;
/* id: right; */
}
.footer {
@ -122,9 +105,9 @@ span {
left: 0;
height: 100%;
width: 100%;
/* background: #000000e1; */
backdrop-filter: blur(1.5rem);
display: flex;
align-items: center;
justify-content: center;
z-index: 1;
}

View File

@ -1,6 +1,6 @@
.home{
background-color: rgb(0, 0, 0);
height: 90vh;
height: 70vh;
display: flex;
align-items: center;
justify-content: center;
@ -19,7 +19,8 @@ select{
border: 0!important;
margin: 5px;
font-size: 18px;
border-radius: 6px;
padding: 5px;
border-radius: 1000px;
}
.modal{
@ -54,18 +55,14 @@ select{
height: 74vh;
width: 30%;
overflow: scroll;
/* width: 2rem; */
/* height: 4rem; */
border-radius: 0px 0px 0px 10px;
}
.messages_box{
background-color: rgb(0, 0, 0);
/* height: 90vh; */
display: flex;
align-items: center;
justify-content: center;
/* position:relative; */
}
.container{
@ -94,11 +91,8 @@ select{
}
.navbar{
/* width: clamp(50%, 500px, 20%); */
/* height: min(50%, 100px); */
display: flex;
align-items: center;
/* background-color: yellow; */
background-image: linear-gradient(90deg, #5843e4, #5a0760);
color: white;
padding: 3px;
@ -106,6 +100,16 @@ select{
margin-top: 0px;
}
.navbarSocial{
display: flex;
align-items: center;
margin: 10px;
background-image: linear-gradient(90deg, #5843e4, #5a0760);
color: white;
padding: 3px;
border-radius: 100px;
}
.pic{
height: 35px;
width: 35px;
@ -127,20 +131,17 @@ select{
width: 50px;
border-radius: 50%;
object-fit: cover;
/* margin-right: 10px; */
}
.messages{
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: 50px;
height: 6vh;
background-color: white;
color:#060b26;
border: none;
@ -170,6 +171,7 @@ input{
width: 40px;
height: 40px;
border-radius: 50%;
margin: 10px;
}
.messageContent{
@ -202,8 +204,19 @@ 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;
@ -219,8 +232,6 @@ p {
.div_submit {
flex-direction: row;
align-items: center;
/* margin-left: 4px;
margin-right: 4px; */
}
.lookForFriends{
@ -228,9 +239,9 @@ p {
backdrop-filter: sepia(90%);
background-color: rgba(0, 0, 0, 0.3);
border-radius: 4px;
width: 11rem;
height: 1.5rem;
margin-top: 1rem;
width: 15rem;
height: 2rem;
margin-top: 1.3rem;
}
.greenAlert{
@ -240,7 +251,6 @@ p {
margin: auto;
padding: 1rem;
border-radius: 12px;
/* display: flex; */
flex-direction: row;
align-items: center;
background-color: rgba(0, 86, 27, 0.7);
@ -256,24 +266,15 @@ p {
padding: 1rem;
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%);
height: min(50%, 100px);
margin: auto;
padding: 1rem;
border-radius: 12px;
flex-direction: row;
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{
@ -285,17 +286,13 @@ 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);
@ -304,26 +301,29 @@ p {
padding: 2rem;
border-radius: 12px;
display: flex;
/* flex-direction: column; */
/* align-items: center; */
background-color: #3e3c61;
overflow: scroll;
}
.settingFirstPart{
margin-top: 10%;
margin-left: 15%;
margin-left: 20%;
}
.settingFirstPart2{
margin-top: 10%;
margin-left: 30%;
}
.settingSecondPart{
margin-top: 10%;
margin-left: 5%;
/* margin-left: 20%; */
}
.checkbox{
display:flex;
flex-direction:row;
margin-left: 60px;
}
input.in{
@ -331,23 +331,59 @@ input.in{
margin-left: 0px;
background-color: black;
color: white;
border-radius: 12px;
border-radius: 4px;
width: 70%;
height: 100%;
font-weight:100;
font-size: 20px;
padding: 7px;
}
input.in_howLong{
margin-top: 14.5%;
margin-top: 13%;
margin-left: 0px;
background-color: black;
color: white;
border-radius: 12px;
width: 15%;
border-radius: 4px;
width: 10%;
height: 10%;
font-weight:100;
font-size: 20px;
padding: 7px;
}
.mdp{
background-color : black;
border-radius: 8px;
color: white;
width: 20%;
width: 60%;
height: 30%;
}
.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;
}

View File

@ -1,10 +1,6 @@
/* Container style */
.file-upload-container {
.file-upload-container {
margin-left: 2rem;
font-size: 1.7rem;
/* background: #5843e4; */
/* color:#f5f5f5; */
margin: 0 16px;
text-decoration: none;
padding: 10px 16px;
@ -15,11 +11,8 @@
gap: 10px;
}
/* File input style */
.file-input {
/* background: #5843e4; */
/* color:#f5f5f5; */
display: none; /* Hide the default file input */
.file-input {
display: none;
}
.file-label {
@ -62,6 +55,7 @@
.page {
text-align: center;
overflow-y: scroll;
/* height: 80vh; */
/* height: 50vh; */
/* width: 50vh; */
/* background-color: black; */
@ -80,9 +74,9 @@
border-radius: 50%;
border: thick;
border-color: red;
margin-left: 20px;
/* border-image: linear-gradient(90deg, #5843e4, #5a0760); */
/* margin-top: 20px; */
}
.home{
@ -96,11 +90,11 @@
}
.history{
display: inline-block;
display:inline-block;
color: white;
background-color: #5843e4;
border-radius: 20px;
padding: 14px;
padding: 1.3% 30%;
font-size: 1.7rem;
text-decoration: none;
font-weight: bold;
@ -153,6 +147,13 @@
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;

View File

@ -1,17 +1,8 @@
.tab{
/* display: flex; */
/* flex-direction: column; */
/* background-color: red; */
height: 60vh;
/* padding: 15px; */
/* overflow: scroll; */
}
.scroll {
/* border:3px; */
/* background-color: #5843e4; */
/* border-color: white; */
overflow: scroll;
}
@ -20,26 +11,20 @@
}
.elements {
/* display: flex; */
border-width:1px;
border-style:solid;
/* background-color: #5843e4; */
border-color: grey;
/* overflow: scroll; */
}
.title {
color: #5843e4;
/* font-size: 22px; */
font-weight: bold;
margin-bottom: 25px;
}
.content {
color: white;
/* font-size: 22px; */
font-weight: bold;
/* display: flex; */
flex-direction: column;
margin-bottom: 5px;
}
@ -48,11 +33,8 @@
display:inline;
flex-direction: row;
color: white;
/* font-size: 22px; */
font-weight: bold;
flex-direction: row;
/* text-align: justify; */
/* margin-bottom: 5px; */
}
.me {

View File

@ -157,13 +157,3 @@
font-size: 13px;
font-style: italic;
}
/* Messages.css */
/* import '../../styles/Messages.css' */
/* General styles */
/* Messages.css */
/* import '../../styles/Messages.css' */
/* General styles

View File

@ -1,49 +1,39 @@
.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 4vw;
padding: 2vh 5vw;
height: 10vh;
width: 20vw;
font-size: 250%;
text-align: center;
font-size: 300%;
}
.inside_checkbox{
height : 70%;
width: 70%;
}
.field {
background-color: rgb(249, 249, 249);
/* border-radius: 5vh; */
/* color: rgb(100, 42, 42); */
display: block;
margin: auto;
margin-top: 5vh;
/* padding: 2vh 5vw; */
height: 80%;
width: 80%;
/* font-size: 300%; */
}
.clicked{
/* justify-content: center; */
/* display: flex;
justify-content: center; */
background-color: rgb(0, 0, 0);
width: 70vw;
/* height: 70vh; */
margin:auto;
margin-right: 15vw;
margin-left: 15vw;
margin-top: 10vh;
position: relative;
padding-top: 35%;
/* padding-top: 25; */
/* padding-top: 177.77% */
}
@media screen and (max-width: 900px){
.playButton{
@ -69,29 +59,14 @@
}
}
.responsive{
display: flex;
flex-direction: column;
}
#myCanvas {
background-color: rgb(124, 47, 47);
/* position: absolute; */
/* top: 0; */
/* left: 0; */
/* cursor: none; */
width: 100%;
height: 100%;
margin: 0;
}
/* @media screen and (max-width: 768px) { */
/* #canvas_container { */
/* width: 50%; */
/* transform: rotate(90deg);
transform-origin: top right;
position: relative;
/* margin-right: 100vw; */
/* height: 100vw; */
/* width: 100vh; */
/* } */
/* #myCanvas {
height: 100%;
width: 100%;
} */
/* } */

View File

@ -5,7 +5,6 @@ body {
sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
/* height: 100%; */
}
code {

View File

@ -1,5 +1,4 @@
body {
/* display: flex; */
margin: 0%;
width: 100vw;
height: 100vh;
@ -20,7 +19,6 @@ footer {
width: 7vw;
max-height: 7vh;
max-width: 7vh;
/* max-width: ; */
border-radius: 50%;
border: 5px solid rgb(255, 255, 255);
}
@ -66,7 +64,6 @@ input{
}
.username {
/* justify-content: center; */
margin-right: 1vw;
display: flex;
align-items: center;
@ -90,7 +87,6 @@ input{
.menu {
margin-left: 2vw;
color: aqua;
/* font-size: 4vh; */
font-size: 2vw;
text-decoration: none;
}
@ -111,9 +107,7 @@ input{
display:flex;
max-width: 33%;
height: 100%;
/* font-size: 50px; */
color:blueviolet;
/* font-size: 10vw; */
font-size: min(10vw, 10vh);
justify-content: center;
}

View File

@ -3,6 +3,7 @@ version: "3.3"
services:
nginx:
restart: unless-stopped
image: nginx:alpine
container_name: nginx
env_file: .env
@ -14,20 +15,11 @@ 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
@ -44,6 +36,7 @@ services:
api:
restart: unless-stopped
image: node:latest
container_name: api
working_dir: /app
@ -59,9 +52,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
@ -70,11 +63,12 @@ services:
- 5432:5432
volumes:
- db:/var/lib/postgresql/data
- ./conf/init.sql:/docker-entrypoint-initdb.d/create_tables.sql
# - ./conf/init.sql:/docker-entrypoint-initdb.d/create_tables.sql
networks:
- pongNetwork
pong:
restart: unless-stopped
image: node:latest
container_name: pong
working_dir: /app
@ -88,6 +82,7 @@ services:
entrypoint: ["sh", "-c" , "npm install && npm run start:dev"]
chat:
restart: unless-stopped
image: node:latest
container_name: chat
working_dir: /app