Compare commits
30 Commits
master
...
new_sadjig
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4974fecae6 | ||
|
|
2bc21b6950 | ||
|
|
c6fe3a5a99 | ||
|
|
38052b5034 | ||
|
|
b1fb8193a8 | ||
|
|
fc280662b9 | ||
|
|
6204cd2cfd | ||
|
|
20314382e6 | ||
|
|
b04683576d | ||
|
|
c011ea2b04 | ||
|
|
e44320a88f | ||
|
|
cf7c648813 | ||
|
|
41f8ad0d4d | ||
|
|
a84b932355 | ||
|
|
44fb3cdecd | ||
|
|
6fd9660bff | ||
|
|
bdeb414c09 | ||
|
|
071f30764a | ||
|
|
de59d21671 | ||
|
|
6ad04baf06 | ||
|
|
d5e3532bd0 | ||
|
|
6d1cd933e2 | ||
|
|
b50d789d1d | ||
|
|
c07a169794 | ||
|
|
72a4f42cdb | ||
|
|
4d98765009 | ||
|
|
b27cb189b3 | ||
|
|
0d42eda749 | ||
|
|
f9a26e8e0f | ||
|
|
263e3332a1 |
15
.env
15
.env
@ -12,14 +12,9 @@
|
||||
|
||||
#URL
|
||||
NGINX_ENVSUBST_TEMPLATE_SUFFIX=".conf"
|
||||
|
||||
# BASE_URL=http://localhost
|
||||
BASE_URL=localhost:8080
|
||||
REACT_APP_BASE_URL=localhost:8080
|
||||
REDIRECT_URI=http://localhost:8080/api/auth/login
|
||||
#postgres var
|
||||
# POSTGRES_HOST=127.0.0.1
|
||||
# DB_TYPE=postgres
|
||||
BASE_URL=bess-f2r2s14:8080
|
||||
REACT_APP_BASE_URL=bess-f2r2s14:8080
|
||||
REDIRECT_URI=http://bess-f2r2s14:8080/api/auth/login
|
||||
POSTGRES_HOST=postgresql
|
||||
POSTGRES_USER=postgres
|
||||
POSTGRES_PASSWORD=postgres
|
||||
@ -42,5 +37,5 @@ REACT_HOST=0.0.0.0
|
||||
#auth var
|
||||
JWT_SECRET=secrethere
|
||||
# REDIRECT_URI=http://localhost:80/api/auth/login
|
||||
API_SECRET=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
|
||||
CLIENT_UID=u-s4t2ud-6d29dfa49ba7146577ffd8bf595ae8d9e5aaa3e0a9615df18777171ebf836a41
|
||||
API_SECRET=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
|
||||
CLIENT_UID=u-s4t2ud-a58c0bac83e6a599129ff519650335526c634890b80bd360bce3a8007db4897e
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@ -1,4 +1,5 @@
|
||||
#.env
|
||||
.env
|
||||
containers/react/.env
|
||||
backend/node_modules/
|
||||
containers/backend/dist/
|
||||
|
||||
|
||||
153
README.md
153
README.md
@ -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
|
||||
@ -1 +1 @@
|
||||
ALTER USER postgres WITH PASSWORD 'pass';
|
||||
ALTER USER postgres WITH PASSWORD 'postgres';
|
||||
@ -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;
|
||||
|
||||
@ -3,10 +3,10 @@
|
||||
/* ::: :::::::: */
|
||||
/* app.controller.ts :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: apommier <apommier@student.42.fr> +#+ +:+ +#+ */
|
||||
/* By: sadjigui <sadjigui@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/24 20:37:12 by sadjigui ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
@ -180,6 +180,9 @@ export class AppController {
|
||||
// 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);
|
||||
@ -480,8 +483,6 @@ export class AppController {
|
||||
// res.json(messages);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Get('/conv')
|
||||
async getConv(@Request() req) {
|
||||
@ -588,7 +589,7 @@ export class AppController {
|
||||
async muteUser(@Body() data: any) {
|
||||
if (!data.username)
|
||||
return ;
|
||||
return await this.chatService.muteUser(data.convId, data.username)
|
||||
return await this.chatService.muteUser(data.convId, data.username, data.time)
|
||||
}
|
||||
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@ -598,11 +599,16 @@ export class AppController {
|
||||
return await this.chatService.isAdmin(data.convId, req.user.username)
|
||||
}
|
||||
|
||||
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Post('/private')
|
||||
async setPrivate(@Body() data: any) {
|
||||
return await this.chatService.setPrivate(data.convId)
|
||||
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)
|
||||
|
||||
@ -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/24 18:47:59 by apommier ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
@ -119,14 +119,22 @@ async verifyPassword(convId: number, password: string) {
|
||||
// conv.password = password
|
||||
}
|
||||
|
||||
async muteUser(convId: number, username: string) {
|
||||
async muteUser(convId: number, username: string, time: string) {
|
||||
const conv = await this.findConv(convId);
|
||||
|
||||
console.log("MUTE USER");
|
||||
|
||||
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);
|
||||
}, 5000);
|
||||
console.log("END MUTE USER");
|
||||
}
|
||||
|
||||
async setAdmin(convId: number, username: string) {
|
||||
@ -149,12 +157,14 @@ async isAdmin(convId: number, username: string) {
|
||||
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;
|
||||
console.log("bool= ", bool);
|
||||
conv.private = bool;
|
||||
// if (conv.private === true)
|
||||
// conv.private = false;
|
||||
// else
|
||||
// conv.private = true;
|
||||
this.save(conv);
|
||||
}
|
||||
|
||||
|
||||
@ -3,10 +3,10 @@
|
||||
/* ::: :::::::: */
|
||||
/* config.service.ts :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: apommier <apommier@student.42.fr> +#+ +:+ +#+ */
|
||||
/* By: sadjigui <sadjigui@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/24 15:09:20 by sadjigui ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
|
||||
@ -82,7 +82,7 @@ export class User {
|
||||
|
||||
}
|
||||
|
||||
@Entity()
|
||||
@Entity({name: 'MatchLog' })
|
||||
export class MatchLog {
|
||||
@PrimaryGeneratedColumn()
|
||||
id: number;
|
||||
|
||||
@ -3,10 +3,10 @@
|
||||
/* ::: :::::::: */
|
||||
/* users.service.ts :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: apommier <apommier@student.42.fr> +#+ +:+ +#+ */
|
||||
/* By: sadjigui <sadjigui@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/24 19:45:28 by sadjigui ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
@ -18,6 +18,7 @@ import { User } from '../model/user.entity';
|
||||
import { MatchLog } from '../model/user.entity';
|
||||
|
||||
|
||||
|
||||
@Injectable()
|
||||
export class UsersService {
|
||||
constructor(
|
||||
@ -37,10 +38,21 @@ export class UsersService {
|
||||
return await this.userRepository.find();
|
||||
}
|
||||
|
||||
// async findNickname(username: string): Promise<User> {
|
||||
// console.log("nick in find =", username)
|
||||
// const ret= await this.userRepository.findOneBy({nickname: username});
|
||||
// console.log("ret noick=", ret )
|
||||
// return ret;
|
||||
// }
|
||||
|
||||
async findOne(username: string): Promise<User> {
|
||||
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);
|
||||
}
|
||||
@ -71,6 +83,8 @@ export class UsersService {
|
||||
user.friendRequest = user.friendRequest || [];
|
||||
if (user.friendRequest.find(item => item === username))
|
||||
return (1);
|
||||
if (user.friends.find(item => item === username))
|
||||
return (1);
|
||||
user.friendRequest.push(username);
|
||||
this.save(user);
|
||||
return (1);
|
||||
@ -96,16 +110,24 @@ 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;
|
||||
if (user)
|
||||
{
|
||||
|
||||
// const ret = await this.matchRepository.query("SELECT * FROM \"MatchLog\" WHERE id = ($1);", [user.id]);
|
||||
const ret = await this.matchRepository.query("SELECT * FROM \"MatchLog\"");
|
||||
console.log("all match= ", ret);
|
||||
}
|
||||
// const children = user.children;
|
||||
// console.log(user);
|
||||
// console.log(user.children); // or perform any operations with the children
|
||||
// return children;
|
||||
|
||||
// }
|
||||
}
|
||||
|
||||
async addFriend(user: User, username: string) {
|
||||
if (!(await this.findOne(username)))
|
||||
const user2 = await this.findOne(username)
|
||||
if (!user)
|
||||
return (0);
|
||||
// user.friendRequest = user.friendRequest || [];
|
||||
user.friends = user.friends || [];
|
||||
@ -117,6 +139,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);
|
||||
}
|
||||
|
||||
@ -6,10 +6,12 @@
|
||||
/* 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/24 17:20:24 by apommier ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
//0.0001
|
||||
|
||||
import { SubscribeMessage, WebSocketGateway, OnGatewayInit, WebSocketServer, OnGatewayConnection, OnGatewayDisconnect } from '@nestjs/websockets';
|
||||
import { Server, Socket } from 'socket.io';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
@ -165,8 +167,9 @@ 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);
|
||||
});
|
||||
}
|
||||
|
||||
@ -200,8 +203,8 @@ joinPrivateParty(client: Socket, payload: any): void {
|
||||
{
|
||||
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
|
||||
{
|
||||
@ -337,6 +340,24 @@ addPrivateParty(client: Socket, payload: any): void {
|
||||
}
|
||||
}
|
||||
|
||||
@SubscribeMessage('pong:myPoint')
|
||||
handleMyPoint(client: Socket, payload: any): void
|
||||
{
|
||||
const game = this.games.get(payload.gameId);
|
||||
const playersIds = game.map(socket => socket.id);
|
||||
console.log(`id of 0 mypoint= ${playersIds[0]}`);
|
||||
|
||||
if (playersIds[0] === payload.id)
|
||||
{
|
||||
this.clients[playersIds[1]].emit('pong:hisPoint', payload);
|
||||
|
||||
}
|
||||
else if (playersIds[1] === payload.id)
|
||||
{
|
||||
this.clients[playersIds[0]].emit('pong:hisPoint', payload);
|
||||
}
|
||||
}
|
||||
|
||||
@SubscribeMessage('pong:name')
|
||||
getName(client: Socket, payload: any): void
|
||||
{
|
||||
@ -347,11 +368,11 @@ addPrivateParty(client: Socket, payload: any): void {
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
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=bess-f2r2s14:8080
|
||||
REACT_APP_SOCKET_URL=bess-f2r2s14:8080
|
||||
REACT_APP_API_SECRET=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
|
||||
REACT_APP_CLIENT_UID=u-s4t2ud-a58c0bac83e6a599129ff519650335526c634890b80bd360bce3a8007db4897e
|
||||
|
||||
# REACT_APP_BASE_URL=92.143.191.152
|
||||
# REACT_APP_BASE_URL=192.168.1.19
|
||||
@ -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",
|
||||
|
||||
@ -32,11 +32,11 @@ function RedAlert ({handleClose, text}: AlertProps) {
|
||||
initial="hidden"
|
||||
animate="visible"
|
||||
exit="exit"
|
||||
>
|
||||
>
|
||||
<BiErrorCircle/>
|
||||
<p>{text}</p>
|
||||
</motion.div>
|
||||
{setTimeout(handleClose, 1500)}
|
||||
{setTimeout(handleClose, 1500)}
|
||||
</Backdrop>
|
||||
)
|
||||
}
|
||||
|
||||
@ -40,9 +40,9 @@ function PlayButton() {
|
||||
<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 </p>
|
||||
<p><input className="inside_checkbox" type="checkbox" value="obstacle"/> Obstacle </p>
|
||||
<p><input className="inside_checkbox" type="checkbox" value="speed"/> Faster and Faster </p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
/* By: apommier <apommier@student.42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2023/06/09 08:49:24 by apommier #+# #+# */
|
||||
/* Updated: 2023/06/20 13:06:35 by apommier ### ########.fr */
|
||||
/* Updated: 2023/06/23 17:16:40 by apommier ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
@ -41,7 +41,7 @@ function Rank({user, index}: RankProps){
|
||||
};
|
||||
|
||||
fetchProfilePicture();
|
||||
})
|
||||
}, [])
|
||||
|
||||
// console.log(index);
|
||||
return (
|
||||
|
||||
@ -21,18 +21,15 @@ function Ranking(){
|
||||
// setFriends(tmpFriends.data);
|
||||
// return tmpUser;
|
||||
// console.log(`user= ${tmpUser.data.username}`);
|
||||
setIsLoading(false)
|
||||
|
||||
setIsLoading(false);
|
||||
}
|
||||
catch(err){
|
||||
console.log(err);
|
||||
}
|
||||
};
|
||||
getRanking();
|
||||
|
||||
}, [])
|
||||
|
||||
console.log(`ranking after= ${ranking}`)
|
||||
}, []);
|
||||
console.log(`ranking after= ${ranking}`);
|
||||
|
||||
return (
|
||||
<div>
|
||||
|
||||
@ -17,6 +17,7 @@ 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";
|
||||
@ -27,6 +28,7 @@ import PartyInvite from "./PartyInvite.tsx";
|
||||
|
||||
// import {User, Conv, Message} from "../../../interfaces.tsx"
|
||||
import {User, Conv} from "../../../interfaces.tsx"
|
||||
import { IoChatbox, IoLogoOctocat } from "react-icons/io5";
|
||||
|
||||
const TouchDiv = styled.div`
|
||||
margin-left: 10px;
|
||||
@ -119,7 +121,7 @@ function Chats(){
|
||||
setUsers(tmpUsers.data);
|
||||
|
||||
// console.log(`connection....`);
|
||||
socket.current = io('http://' + process.env.REACT_APP_BASE_URL + ':4001', { transports: ['polling'] });
|
||||
socket.current = io('http://' + process.env.REACT_APP_SOCKET_URL + ':4001', { transports: ['polling'] });
|
||||
// console.log(`connection done`);
|
||||
socket.current.emit('connection', {username: tmpUser.data.username})
|
||||
socket.current.on('message', (data) => { //data should be a message ?)
|
||||
@ -205,11 +207,12 @@ 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;
|
||||
console.log("in handle");
|
||||
if (!user || !currentChat)
|
||||
return ;
|
||||
const message = {
|
||||
@ -242,33 +245,11 @@ function Chats(){
|
||||
}
|
||||
}
|
||||
|
||||
const handleKeyPress = async (e: { key: string; })=> {
|
||||
const handleKeyPress = async (e: { key?: any; preventDefault: () => void; })=> {
|
||||
// console.log(`e in press= ${e.key}`)
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
@ -323,6 +304,7 @@ function Chats(){
|
||||
|
||||
const handleAddFriend = async () => {
|
||||
try{
|
||||
console.log("friend= ", friend);
|
||||
const res = await api.post("/invite", {username: friend})
|
||||
// if (res.data === 1)
|
||||
// console.log("res in friend= ", res)
|
||||
@ -371,6 +353,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,12 +372,13 @@ function Chats(){
|
||||
<div className="chat">
|
||||
|
||||
<div className='navbar'>
|
||||
<img src={DefaultPic} alt="profile" className="pic"/>
|
||||
{/* <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">
|
||||
@ -463,7 +447,7 @@ function Chats(){
|
||||
))}
|
||||
<TouchDiv>
|
||||
<motion.div onClick={handleAddFriend}>
|
||||
<MdOutlineGroupAdd />
|
||||
<MdOutlineGroupAdd className="catchat"/>
|
||||
</motion.div>
|
||||
<AnimatePresence initial={false} onExitComplete={() => null}>
|
||||
{showAddFriendAlert && addFriend && (
|
||||
@ -476,7 +460,7 @@ function Chats(){
|
||||
</TouchDiv>
|
||||
<TouchDiv>
|
||||
<motion.div onClick={handleBlockFriend}>
|
||||
<ImBlocked />
|
||||
<ImBlocked className="block"/>
|
||||
</motion.div>
|
||||
<AnimatePresence initial={false} onExitComplete={() => null}>
|
||||
{showBlockAlert && block && (
|
||||
@ -492,7 +476,7 @@ function Chats(){
|
||||
<motion.div
|
||||
onClick={() => (setting ? setSetting(false) : setSetting(true))}
|
||||
>
|
||||
<RiListSettingsLine/>
|
||||
<RiListSettingsLine className="inline"/>
|
||||
<AnimatePresence
|
||||
initial={false}
|
||||
onExitComplete={() => null}
|
||||
@ -543,7 +527,8 @@ function Chats(){
|
||||
<div key={index}
|
||||
onClick={() => setCurrentChat(c)}>
|
||||
<UserChat>
|
||||
<img className="pic-user" src={DefaultPic} alt="User" />
|
||||
{/* <img className="pic-user" src={DefaultPic} alt="User" /> */}
|
||||
{/* <HiChatBubbleLeft className="catchat"/> */}
|
||||
<div className="infoSideBar">
|
||||
<span>{c.name}</span>
|
||||
{/* <SideP>Desc?</SideP> */}
|
||||
@ -571,7 +556,7 @@ function Chats(){
|
||||
placeholder="What do you want to say"
|
||||
onChange={(e) => setNewMessage(e.target.value)}
|
||||
value={newMessages}
|
||||
/>
|
||||
/>
|
||||
<div className="send">
|
||||
<TbSend onClick={handleSubmit}></TbSend>
|
||||
</div>
|
||||
|
||||
@ -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/24 16:00:48 by apommier ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
@ -42,15 +42,16 @@ 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 {
|
||||
console.log("useEffect message")
|
||||
// const user = await api.get("/profile");
|
||||
const tmpSender = await api.post("/user", {username: message.sender})
|
||||
const tmpConv = await api.post("/convId", {convId: message.convId})
|
||||
@ -81,23 +82,37 @@ function MessageMe({message, own}: MessageMeProps){
|
||||
window.location.reload();
|
||||
};
|
||||
|
||||
// const isAllowed = async () => {
|
||||
// const ret = await api.post("/allowed", {convId: message.convId});
|
||||
// return ret.data;
|
||||
// }
|
||||
|
||||
if (!user || !sender || !conv)
|
||||
{
|
||||
// console.log("return")
|
||||
return (<></>);
|
||||
}
|
||||
// console.log("result includes=", conv.banned.includes(user.username))
|
||||
// console.log("result includes=", conv.blocked.includes(user.username))
|
||||
// const conv2: Conv = getConv();
|
||||
// if (!conv)
|
||||
// isAllowed().then((ret: number) => {
|
||||
// if (!ret)
|
||||
// {
|
||||
// console.log("return not allowed");
|
||||
// return ;
|
||||
// }
|
||||
// // Use the resolved currentConv here
|
||||
// });
|
||||
|
||||
if (user.blocked && user.blocked.includes(message.sender))
|
||||
return (<></>);
|
||||
// else if (conv.banned && conv.banned.includes(user.username))
|
||||
// {
|
||||
// console.log("return2")
|
||||
// return (<></>);
|
||||
// }
|
||||
// console.log("noy return")
|
||||
else if (conv.banned && conv.banned.includes(user.username))
|
||||
return (<></>);
|
||||
else if (conv.muted && conv.muted.includes(user.username))
|
||||
{
|
||||
// console.log("muted00")
|
||||
return (<></>);
|
||||
}
|
||||
// if (user.blocked.includes(message.sender))/
|
||||
|
||||
console.log("no return message good");
|
||||
return (
|
||||
<div className={own ? "meMessage" : "youMessage"} ref={scrollRef}>
|
||||
<div>
|
||||
|
||||
@ -7,6 +7,7 @@ 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",
|
||||
@ -21,16 +22,19 @@ const dropIn = {
|
||||
}},
|
||||
exit:{y: "100vh",
|
||||
opacity: 0,},
|
||||
|
||||
};
|
||||
|
||||
const Modal = ({handleClose}) => {
|
||||
interface ModalProps {
|
||||
handleClose: Function,
|
||||
}
|
||||
|
||||
const Modal = ({handleClose}: ModalProps) => {
|
||||
// const [multi, setMulti] = useState(false);
|
||||
const [selectTags, setSelectTag] = useState([{ id: 1, selectedOption: ''}]);
|
||||
const [selectedOptionArray, setSelectedOptionArray] = useState([]);
|
||||
const [users, setUsers] = useState([]);
|
||||
const [user, setUser] = useState();
|
||||
const [convs, setConvs] = useState([]);
|
||||
const [selectedOptionArray, setSelectedOptionArray] = useState<string[]>([]);
|
||||
const [users, setUsers] = useState<User[]>([]);
|
||||
const [user, setUser] = useState<User>();
|
||||
const [convs, setConvs] = useState<Conv[]>([]);
|
||||
|
||||
const [channel, setChannel] = useState('');
|
||||
|
||||
@ -53,7 +57,7 @@ const Modal = ({handleClose}) => {
|
||||
getConv();
|
||||
}, []);
|
||||
|
||||
const handleOptionChange = (selectId, selectedOption) => {
|
||||
const handleOptionChange = (selectId: number, selectedOption: string) => {
|
||||
console.log("selected Option=", selectedOption)
|
||||
setSelectTag((prevTags) =>
|
||||
prevTags.map((tag) =>
|
||||
@ -103,24 +107,27 @@ const Modal = ({handleClose}) => {
|
||||
<Backdrop onClick={handleClose}>
|
||||
<motion.div
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
className="modal"
|
||||
className="modalSetting"
|
||||
// variant={dropIn}
|
||||
initial="hidden"
|
||||
animate="visible"
|
||||
exit="exit"
|
||||
>
|
||||
{/* <p>New Conversation</p> */}
|
||||
<div className="settingFirstPart2">
|
||||
|
||||
{selectTags.map((selectTag) => (
|
||||
<div key={selectTag.id}>
|
||||
<div key={selectTag.id}>
|
||||
<select
|
||||
value={selectTag.selectedOption}
|
||||
onChange={(a) => handleOptionChange(selectTag.id, a.target.value)}
|
||||
>
|
||||
>
|
||||
<option value="">{
|
||||
selectTag.selectedOption ? selectTag.selectedOption : "Select an option"
|
||||
}</option>
|
||||
{users.filter((item) => !selectTags.some((tag) => tag.selectedOption === item.name)).map((item, index) => (
|
||||
<option key={index} value={item.username}>
|
||||
{item.username}
|
||||
selectTag.selectedOption ? selectTag.selectedOption : "Select an option"
|
||||
}</option>
|
||||
{users.filter((item) => !selectTags.some((tag) => tag.selectedOption === item.nickname)).map((item, index) => (
|
||||
<option key={index} value={item.username}>
|
||||
{item.nickname}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
@ -132,30 +139,32 @@ const Modal = ({handleClose}) => {
|
||||
<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={() => handleClose}>Cancel</Link>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div className="settingSecondPart">
|
||||
|
||||
{convs.length > 0 && (
|
||||
<select
|
||||
value={channel}
|
||||
onChange={(event) => setChannel(event.target.value)}
|
||||
<select
|
||||
value={channel}
|
||||
onChange={(event) => setChannel(event.target.value)}
|
||||
|
||||
>
|
||||
<option value="">Select an option</option>
|
||||
{convs.map((conv) => (
|
||||
!(!conv.group || conv.private || (conv.banned && conv.banned.includes(user.username)) || (conv.members && conv.members.includes(user.username))) && (
|
||||
<option key={conv.id} value={conv.id}>
|
||||
!(!conv.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>
|
||||
)
|
||||
))}
|
||||
))}
|
||||
</select>
|
||||
)}
|
||||
{channel.private ? (
|
||||
<input className="mdp" placeholder="password" type="text" />
|
||||
):("")}
|
||||
{/* {channel.private ? (
|
||||
<input className="mdp" placeholder="passdddddword" type="text" />
|
||||
):("")} */}
|
||||
|
||||
|
||||
<div className="div_submit">
|
||||
@ -164,6 +173,7 @@ const Modal = ({handleClose}) => {
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
</motion.div>
|
||||
</Backdrop>
|
||||
)
|
||||
|
||||
@ -39,8 +39,10 @@ const ModalSetting = ({handleClose, convId, socket }: ModalSettingProps) => {
|
||||
const [selectTags, setSelectTag] = useState([{ id: 1, selectedOption: ''}]);
|
||||
const [selectedUser, setSelectedUser] = useState("");
|
||||
const [newName, setNewName] = useState("");
|
||||
const [time, setTime] = useState("");
|
||||
const [newPassword, setNewPassword] = useState("");
|
||||
const [privateConv, setPrivateConv] = useState(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);
|
||||
@ -53,9 +55,15 @@ const ModalSetting = ({handleClose, convId, socket }: ModalSettingProps) => {
|
||||
console.log("convid =", convId)
|
||||
const getUsers = async ()=>{
|
||||
try {
|
||||
const currentConv = await api.post("/convId", {convId: convId});
|
||||
|
||||
// console.log("conv private =================== ", )
|
||||
if (currentConv.data.private)
|
||||
setPrivateConv(true);
|
||||
const tmpUsers = await api.get("/users");
|
||||
console.log("users=", tmpUsers.data);
|
||||
setUsers(tmpUsers.data);
|
||||
setLoading(false);
|
||||
} catch(err){
|
||||
console.log(err)
|
||||
}
|
||||
@ -63,6 +71,31 @@ const ModalSetting = ({handleClose, convId, socket }: ModalSettingProps) => {
|
||||
getUsers();
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
// Function to run when myVariable changes
|
||||
const handleVariableChange = () => {
|
||||
console.log('Variable changed:', privateConv);
|
||||
if (privateConv === undefined)
|
||||
{
|
||||
console.log("return")
|
||||
return ;
|
||||
}
|
||||
try {
|
||||
if (privateConv)
|
||||
api.post("/private", {convId: convId})
|
||||
else
|
||||
api.post("/public", {convId: convId})
|
||||
} catch (err){
|
||||
console.log(err);
|
||||
}
|
||||
};
|
||||
if (!loading)
|
||||
handleVariableChange();
|
||||
// return () => {
|
||||
// handleVariableChange();
|
||||
// };
|
||||
}, [privateConv]);
|
||||
|
||||
// const [multi, setMulti] = useState(false);
|
||||
// const [selectedOptionArray, setSelectedOptionArray] = useState([]);
|
||||
|
||||
@ -80,30 +113,30 @@ const ModalSetting = ({handleClose, convId, socket }: ModalSettingProps) => {
|
||||
|
||||
const handleCheckPass = (e: { target: { checked: boolean | ((prevState: boolean) => boolean); }; }) => {
|
||||
setPassword(e.target.checked);
|
||||
console.log("password??", e.target.checked)
|
||||
console.log("password??", e.target.checked);
|
||||
}
|
||||
|
||||
const handleCheckPriv = (e: { target: { checked: any; }; }) => {
|
||||
// setPassword(e.target.checked);
|
||||
if (e.target.checked)
|
||||
{
|
||||
console.log("chack true", e.target.checked)
|
||||
try{
|
||||
api.post("/private", {convId: convId})
|
||||
} catch(err) {
|
||||
console.log(err);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
console.log("chack false", e.target.checked)
|
||||
try{
|
||||
api.post("/private", {convId: convId})
|
||||
} catch(err) {
|
||||
console.log(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
// const 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; })=>{
|
||||
if (e.key !== "Enter")
|
||||
@ -157,11 +190,15 @@ const ModalSetting = ({handleClose, convId, socket }: ModalSettingProps) => {
|
||||
handleClose();
|
||||
};
|
||||
|
||||
const handleMute = async () => {
|
||||
if (!selectedUser.length)
|
||||
const handleMute = async (e: { key: string; }) => {
|
||||
console.log(`e in press= ${e.key}`)
|
||||
if (e.key != "Enter")
|
||||
return ;
|
||||
|
||||
// console.log("value mute = ", e.target.value);
|
||||
console.log("value mute = ", time);
|
||||
try{
|
||||
await api.post("/mute", {convId: convId, username: selectedUser})
|
||||
await api.post("/mute", {convId: convId, username: selectedUser, time: time})
|
||||
} catch(err) {
|
||||
console.log(err);
|
||||
}
|
||||
@ -177,6 +214,17 @@ const ModalSetting = ({handleClose, convId, socket }: ModalSettingProps) => {
|
||||
handleClose();
|
||||
};
|
||||
|
||||
const handleKeyPress = async (e: { key: string; })=> {
|
||||
if (e.key !== "Enter")
|
||||
return ;
|
||||
try{
|
||||
|
||||
}
|
||||
catch(err){
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Backdrop onClick={handleClose}>
|
||||
<motion.div
|
||||
@ -198,7 +246,7 @@ const ModalSetting = ({handleClose, convId, socket }: ModalSettingProps) => {
|
||||
<p className="checkbox">Password<input type="checkbox" value="password" checked={password} onChange={handleCheckPass}/> </p>
|
||||
|
||||
|
||||
{password || privateConv ? (
|
||||
{password ? (
|
||||
<input
|
||||
onChange={(e) => setNewPassword(e.target.value)}
|
||||
onKeyDown={handlePassword}
|
||||
@ -208,7 +256,6 @@ const ModalSetting = ({handleClose, convId, socket }: ModalSettingProps) => {
|
||||
):
|
||||
("")}
|
||||
|
||||
|
||||
</div>
|
||||
<div className="forName">
|
||||
<input
|
||||
@ -254,7 +301,14 @@ const ModalSetting = ({handleClose, convId, socket }: ModalSettingProps) => {
|
||||
|
||||
</div>
|
||||
{mute ? (
|
||||
<input type="text" className="in_howLong" placeholder="How long ?" />
|
||||
<input
|
||||
onKeyDown={handleMute}
|
||||
type="number"
|
||||
className="in_howLong"
|
||||
placeholder="How long ?"
|
||||
value={time}
|
||||
onChange={(e) => setTime(e.target.value)}
|
||||
/>
|
||||
):("")}
|
||||
|
||||
</motion.div>
|
||||
|
||||
@ -1,12 +1,13 @@
|
||||
import {motion} from "framer-motion"
|
||||
import { AnimatePresence, 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 { Link } from 'react-router-dom';
|
||||
// import { UserProfile } from "../../DataBase/DataUserProfile";
|
||||
import { useState } from 'react';
|
||||
import "../../styles/Profile.css"
|
||||
|
||||
import api from '../../script/axiosApi.tsx';
|
||||
import React from "react";
|
||||
import RedAlert from "../Alert/RedAlert.tsx";
|
||||
|
||||
const dropIn = {
|
||||
hidden: {
|
||||
@ -26,37 +27,55 @@ const dropIn = {
|
||||
// )
|
||||
// }
|
||||
|
||||
const ModalEdit = ( handleClose ) => {
|
||||
const ModalEdit = (handleClose) => {
|
||||
// let new_name = "";
|
||||
const [nickname, setNickname] = useState("");
|
||||
const [errTaken, setErrTaken] = useState(false);
|
||||
const closeTaken = () => setErrTaken(false);
|
||||
const [errTooShort, setErrTooShort] = useState(false);
|
||||
const closeTooShort = () => setErrTooShort(false);
|
||||
|
||||
const handler = e =>
|
||||
{
|
||||
const handler = e => {
|
||||
setNickname(e.target.value);
|
||||
console.log("testeeeee")
|
||||
const postNickname = async ()=>{
|
||||
try{
|
||||
await api.post("/nickname", {nickname: nickname})
|
||||
// setUser(tmpUser.data);
|
||||
// setIsLoading(false)
|
||||
}
|
||||
catch(err){
|
||||
console.log(err);
|
||||
}
|
||||
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})
|
||||
window.location.reload();
|
||||
const handlePostNickname = async () => {
|
||||
console.log("nickname=", nickname)
|
||||
try {
|
||||
const ret = await api.post("/nickname", { nickname: nickname });
|
||||
// console.log("cest ici = ",ret);
|
||||
// if (!ret)
|
||||
console.log("test ret =", ret.data);
|
||||
if (nickname.length < 3) {
|
||||
setErrTooShort(true);
|
||||
}
|
||||
else if (ret.data) {
|
||||
console.log("ici error = ", ret.data);
|
||||
window.location.reload();
|
||||
}
|
||||
else {
|
||||
console.log("nickname already set = ", ret.data);
|
||||
|
||||
setErrTaken(true);
|
||||
}
|
||||
|
||||
|
||||
// setUser(tmpUser.data);
|
||||
// setIsLoading(false)
|
||||
}
|
||||
catch(err){
|
||||
catch (err) {
|
||||
console.log(err);
|
||||
}
|
||||
}
|
||||
@ -66,23 +85,34 @@ const ModalEdit = ( handleClose ) => {
|
||||
// //do nothing
|
||||
// }
|
||||
return (
|
||||
<motion.div
|
||||
className="modal"
|
||||
variants={dropIn}
|
||||
initial="hidden"
|
||||
animate="visible"
|
||||
exit="exit">
|
||||
<h2>Type your new name</h2>
|
||||
<input className="text" maxLength="10" type="text" value={nickname} onChange={handler} handleClose/>
|
||||
<div>
|
||||
<div className="button" onClick={ () => handlePostNickname()}>
|
||||
change
|
||||
{/* <Link className="button" to={""}>change</Link> */}
|
||||
</div>
|
||||
<motion.div
|
||||
className="modal"
|
||||
variants={dropIn}
|
||||
initial="hidden"
|
||||
animate="visible"
|
||||
exit="exit">
|
||||
<h2>Type your new name</h2>
|
||||
<input className="text" minLength={2} maxLength={10} type="text" value={nickname} onChange={handler} />
|
||||
<div>
|
||||
<div className="button" onClick={handlePostNickname}>
|
||||
change
|
||||
{/* <Link className="button" to={""}>change</Link> */}
|
||||
</div>
|
||||
</motion.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>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@ -94,7 +94,7 @@ function WinLoss() {
|
||||
// <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'>
|
||||
|
||||
@ -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/23 17:12:07 by apommier ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
@ -59,9 +59,8 @@ export default function Friend({currentUser}: UserProps)
|
||||
console.error('Error fetching profile picture:', error);
|
||||
}
|
||||
};
|
||||
|
||||
fetchProfilePicture();
|
||||
})
|
||||
}, []);
|
||||
|
||||
function getStatus(friend: User)
|
||||
{
|
||||
|
||||
@ -3,10 +3,10 @@
|
||||
/* ::: :::::::: */
|
||||
/* Home.tsx :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: apommier <apommier@student.42.fr> +#+ +:+ +#+ */
|
||||
/* By: sadjigui <sadjigui@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/24 20:16:28 by sadjigui ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
@ -20,7 +20,7 @@ import { motion, AnimatePresence } from 'framer-motion'
|
||||
// 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';
|
||||
|
||||
@ -82,43 +82,13 @@ function Profile () {
|
||||
// }
|
||||
};
|
||||
|
||||
// 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{
|
||||
console.log("before request")
|
||||
const me = await api.get("/profile")
|
||||
if (!username)
|
||||
{
|
||||
@ -160,7 +130,7 @@ function Profile () {
|
||||
{isLoading || !user ? (
|
||||
<h1>Loading...</h1>
|
||||
) : (
|
||||
<h1>{user.nickname}</h1>
|
||||
<h1 className='user_name'>{user.nickname}</h1>
|
||||
)}
|
||||
</span>
|
||||
|
||||
@ -202,7 +172,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);
|
||||
@ -211,12 +181,23 @@ function Home () {
|
||||
const closeSword = () => setSuccessSword(false);
|
||||
const closeCrown = () => setSuccessCrown(false);
|
||||
|
||||
const { username } = useParams();
|
||||
|
||||
useEffect(() => {
|
||||
const fetchSuccess = async () => {
|
||||
try {
|
||||
const tmpUser = await api.get("/profile");
|
||||
setUser(tmpUser.data);
|
||||
if (!username)
|
||||
{
|
||||
const tmpUser = await api.get("/profile");
|
||||
setUser(tmpUser.data);
|
||||
}
|
||||
else
|
||||
{
|
||||
const tmpUser = await api.post("/user", {username: username});
|
||||
setUser(tmpUser.data);
|
||||
}
|
||||
// const tmpUser = await api.get("/profile");
|
||||
// setUser(tmpUser.data);
|
||||
}
|
||||
catch (error)
|
||||
{
|
||||
@ -224,7 +205,7 @@ function Home () {
|
||||
}
|
||||
};
|
||||
fetchSuccess();
|
||||
})
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<motion.div className="page"
|
||||
@ -232,20 +213,20 @@ 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}}
|
||||
transition={{type: "tween", duration: 0.5}}>
|
||||
transition={{type: "tween", duration: 0.5, position: "fixed",}}
|
||||
>
|
||||
<Profile/>
|
||||
</motion.div>
|
||||
<motion.div animate={{opacity: !move ? -1 : 1}}>
|
||||
@ -256,7 +237,7 @@ function Home () {
|
||||
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 ? (
|
||||
|
||||
@ -6,30 +6,30 @@ import "../styles/App.css";
|
||||
import api from '../script/axiosApi.tsx';
|
||||
|
||||
import QRCodeStyling from "qr-code-styling";
|
||||
import { motion } from 'framer-motion'
|
||||
|
||||
import { motion , AnimatePresence} 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"
|
||||
},
|
||||
backgroundOptions: {
|
||||
color: "#5843e4",
|
||||
},
|
||||
imageOptions: {
|
||||
crossOrigin: "anonymous",
|
||||
margin: 20
|
||||
}
|
||||
});
|
||||
width: 300,
|
||||
height: 300,
|
||||
// image: "../assets/profile.jpg",
|
||||
dotsOptions: {
|
||||
color: "black",
|
||||
type: "rounded"
|
||||
},
|
||||
backgroundOptions: {
|
||||
color: "#5843e4",
|
||||
},
|
||||
imageOptions: {
|
||||
crossOrigin: "anonymous",
|
||||
margin: 20
|
||||
}
|
||||
});
|
||||
|
||||
function QrCode () {
|
||||
// const url = "https://www.youtube.com";
|
||||
// const ref = useRef(null);
|
||||
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("");
|
||||
@ -39,17 +39,16 @@ function QrCode () {
|
||||
|
||||
// const history = useHistory();
|
||||
|
||||
useEffect(() => {
|
||||
useEffect(() => {
|
||||
if (ref.current)
|
||||
qrCode.append(ref.current);
|
||||
const getUser = async ()=>{
|
||||
try{
|
||||
qrCode.append(ref.current);
|
||||
const getUser = async () => {
|
||||
try {
|
||||
const tmpUser = await api.get("/profile");
|
||||
setUser(tmpUser.data);
|
||||
if (tmpUser.data.otp_verified)
|
||||
{
|
||||
if (tmpUser.data.otp_verified) {
|
||||
setActivated(true);
|
||||
return ;
|
||||
return;
|
||||
}
|
||||
const otpData = await api.post("/otp");
|
||||
setUrl(otpData.data.otpauth_url);
|
||||
@ -58,30 +57,33 @@ function QrCode () {
|
||||
// console.log("test")
|
||||
// console.table(convs);
|
||||
}
|
||||
catch(err){
|
||||
catch (err) {
|
||||
console.log(err);
|
||||
}
|
||||
};
|
||||
getUser();
|
||||
|
||||
}, []);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
qrCode.update({data: url});
|
||||
}, [url]);
|
||||
useEffect(() => {
|
||||
qrCode.update({ data: url });
|
||||
}, [url]);
|
||||
|
||||
|
||||
const handleKeyPress = async (e: { key: string; })=>{
|
||||
const [errCode, setErrCode] = useState(false);
|
||||
const closeErr = () => setErrCode(false);
|
||||
const handleKeyPress = async (e: { key: string; }) => {
|
||||
// console.log(`e in press= ${e.key}`)
|
||||
if (e.key !== "Enter")
|
||||
return ;
|
||||
try{
|
||||
return;
|
||||
try {
|
||||
console.log("code= ", code)
|
||||
const res = await api.post("/verifyOtp", {token: code})
|
||||
const res = await api.post("/verifyOtp", { token: code })
|
||||
if (!res.data) {
|
||||
setErrCode(true);
|
||||
}
|
||||
console.log("res= ", res.data)
|
||||
console.log("res= ", res)
|
||||
if (res.data === 1)
|
||||
{
|
||||
if (res.data === 1) {
|
||||
console.log("registered")
|
||||
// history.push('/login')
|
||||
|
||||
@ -90,15 +92,14 @@ function QrCode () {
|
||||
window.location.reload();
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
console.log("bad code")
|
||||
//alert ?? retry
|
||||
}
|
||||
// redirect('/test')
|
||||
}
|
||||
catch(err){
|
||||
console.log(err)
|
||||
catch (err) {
|
||||
console.log(err)
|
||||
}
|
||||
}
|
||||
|
||||
@ -108,59 +109,66 @@ function QrCode () {
|
||||
// const path = 'http://' + process.env.REACT_APP_BASE_URL + '/';
|
||||
// window.history.pushState({}, '', path);
|
||||
window.location.reload();
|
||||
} catch(err) {
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
return (
|
||||
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"/>
|
||||
// {}
|
||||
// <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 }}
|
||||
animate={{ opacity: 1 }}
|
||||
exit={{ opacity: -1 }}
|
||||
>
|
||||
{!activated && (
|
||||
<>
|
||||
<h1>Enter The Secret</h1>
|
||||
<h3>{secret}</h3>
|
||||
<h1>Or Scan The QRCode</h1>
|
||||
<div ref={ref} />
|
||||
{/* <div>{ref}</div> */}
|
||||
</>
|
||||
)}
|
||||
className="page"
|
||||
initial={{ opacity: -1 }}
|
||||
animate={{ opacity: 1 }}
|
||||
exit={{ opacity: -1 }}
|
||||
>
|
||||
{!activated && (
|
||||
<>
|
||||
<h1>Enter The Secret</h1>
|
||||
<h3>{secret}</h3>
|
||||
<h1>Or Scan The QRCode</h1>
|
||||
<div ref={ref} />
|
||||
{/* <div>{ref}</div> */}
|
||||
</>
|
||||
)}
|
||||
|
||||
<>
|
||||
{!activated && localStorage.getItem('token') ? (
|
||||
<>
|
||||
<h1>Double Auth Validation</h1>
|
||||
<input
|
||||
onKeyDown={handleKeyPress}
|
||||
type="text"
|
||||
className="qr"
|
||||
placeholder="6 Digits Code"
|
||||
value={code}
|
||||
onChange={(e) => setCode(e.target.value)}
|
||||
/>
|
||||
</>
|
||||
) : (
|
||||
<button onClick={handleDesactivate}>Desactivate 2FA</button>
|
||||
)}
|
||||
</>
|
||||
<>
|
||||
{!activated && localStorage.getItem('token') ? (
|
||||
<>
|
||||
<h1>Double Auth Validation</h1>
|
||||
<input
|
||||
onKeyDown={handleKeyPress}
|
||||
type="number"
|
||||
className="qr"
|
||||
placeholder="6 Digits Code"
|
||||
value={code}
|
||||
onChange={(e) => setCode(e.target.value)}
|
||||
/>
|
||||
</>
|
||||
) : (
|
||||
<button onClick={handleDesactivate}>Desactivate 2FA</button>
|
||||
)}
|
||||
<AnimatePresence initial={false} onExitComplete={() => null}>
|
||||
{
|
||||
errCode ? (
|
||||
<RedAlert handleClose={closeErr} text="Error: Incorrect Code" />
|
||||
) : ("")
|
||||
}
|
||||
</AnimatePresence>
|
||||
</>
|
||||
|
||||
{/* {!localStorage.getItem('token') && (
|
||||
{/* {!localStorage.getItem('token') && (
|
||||
<>
|
||||
<h1>Double Auth</h1>
|
||||
<input onKeyDown={handleKeyPress}
|
||||
@ -172,11 +180,11 @@ function QrCode () {
|
||||
</>
|
||||
) : (<button onClick={ handleDesactivate }>Desactivate 2FA</button>)}
|
||||
*/}
|
||||
{/* {!activated && (
|
||||
{/* {!activated && (
|
||||
<button onClick={() => setActivated(true)}>Activate</button>
|
||||
)} */}
|
||||
</motion.div>
|
||||
)
|
||||
</motion.div>
|
||||
)
|
||||
}
|
||||
|
||||
export default QrCode
|
||||
@ -61,7 +61,7 @@ function DrawCanvas(option: number, gameParam: GameProps) {
|
||||
if(!ctx)
|
||||
return ;
|
||||
|
||||
const socket = io('http://localhost:4000', { transports: ['polling'] });
|
||||
const socket = io('http://' + process.env.REACT_APP_SOCKET_URL + ':4000', { transports: ['polling'] });
|
||||
// useEffect(() => {
|
||||
// console.log("useeffect?????????????????")
|
||||
// return () => {
|
||||
@ -170,7 +170,9 @@ socket.on('pong:privateId', async (data) => {
|
||||
|
||||
socket.on('pong:gameId', async (data) => {
|
||||
console.log("gameId received");
|
||||
gameId = data;
|
||||
gameId = data.gameId;
|
||||
console.log("gameid = ", gameId);
|
||||
console.log("data gameid = ", data);
|
||||
|
||||
try {
|
||||
let response = await api.get('/profile');
|
||||
@ -190,6 +192,16 @@ socket.on('pong:gameId', async (data) => {
|
||||
|
||||
console.log("emit to name");
|
||||
socket.emit('pong:name', info);
|
||||
if (data.id === myId)
|
||||
{
|
||||
console.log("myId= true")
|
||||
vX = 0.0001;
|
||||
}
|
||||
else
|
||||
{
|
||||
console.log("myId= false")
|
||||
vX = -0.0001;
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
// Handle error here
|
||||
@ -198,7 +210,11 @@ socket.on('pong:gameId', async (data) => {
|
||||
});
|
||||
|
||||
socket.on('pong:name', (data) => {
|
||||
opName = data;
|
||||
opName = data.name;
|
||||
// if (data.myId === myId)
|
||||
// vX = 0.0001;
|
||||
// else
|
||||
// vX = -0.0001;
|
||||
console.log(`opponent Name= ${opName}`)
|
||||
});
|
||||
|
||||
@ -222,7 +238,6 @@ 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
|
||||
@ -251,12 +266,27 @@ socket.on('pong:point', (data) => {
|
||||
// console.log("up point");
|
||||
myScore = data.point;
|
||||
// }
|
||||
vX = 0;
|
||||
vX = -0.0001;
|
||||
vY = 0;
|
||||
ballX = canvas.width / 2;
|
||||
ballY = canvas.height / 2;
|
||||
});
|
||||
|
||||
socket.on('pong:hisPoint', (data) => {
|
||||
// hisScore += 1;
|
||||
console.log("myPointawdawdawdawd point");
|
||||
// if (vX != 0)
|
||||
// {
|
||||
// console.log("up point");
|
||||
hisScore = data.point;
|
||||
// }
|
||||
vX = -0.0001;
|
||||
vY = 0;
|
||||
ballX = canvas.width / 2;
|
||||
ballY = canvas.height / 2;
|
||||
// send_forced_info();
|
||||
});
|
||||
|
||||
//========================================================================================================
|
||||
//========================================================================================================
|
||||
// Socket EMIT
|
||||
@ -323,6 +353,26 @@ socket.on('pong:point', (data) => {
|
||||
point: hisScore,
|
||||
}
|
||||
socket.emit('pong:point', info);
|
||||
vX = 0.0001;
|
||||
}
|
||||
|
||||
function send_my_point()
|
||||
{
|
||||
if (!gameId || !canvas)
|
||||
return ;
|
||||
// console.log("send point");
|
||||
const info = {
|
||||
id: myId,
|
||||
gameId: gameId,
|
||||
point: myScore,
|
||||
}
|
||||
socket.emit('pong:myPoint', info);
|
||||
myScore++;
|
||||
vX = 0.0001;
|
||||
vY = 0;
|
||||
ballX = canvas.width / 2;
|
||||
ballY = canvas.height / 2;
|
||||
send_forced_info();
|
||||
}
|
||||
|
||||
function send_paddle_info()
|
||||
@ -459,7 +509,10 @@ 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);
|
||||
@ -593,16 +646,17 @@ async function draw(timestamp: number)
|
||||
}
|
||||
ballX = canvas.width / 2;
|
||||
ballY = canvas.height / 2;
|
||||
vX = 0;
|
||||
vX = 0.0001;
|
||||
vY = 0;
|
||||
hisScore += 1;
|
||||
send_point();
|
||||
// send_forced_info();
|
||||
}
|
||||
if (ballX > canvas.width)
|
||||
if (ballX > (canvas.width * 1.2) && ballX - vX > canvas.width)
|
||||
{
|
||||
console.log("ball out win point pls")
|
||||
send_my_point();
|
||||
// if (ballX > canvas.width * 2)
|
||||
// socket.emit
|
||||
// console.log("win point")
|
||||
// if (ballY <= paddleY + paddleHeight + ballRadius && ballY >= paddleY - ballRadius)
|
||||
// {
|
||||
@ -702,9 +756,8 @@ async function draw(timestamp: number)
|
||||
vX -= 0.0001;
|
||||
}
|
||||
send_forced_info();
|
||||
// console.log(`vx = ${vX}`);
|
||||
}
|
||||
else if (event.code === "KeyR")
|
||||
else if (event.code === "KeyW")
|
||||
{
|
||||
if (!superpowerModifier)
|
||||
return ;
|
||||
@ -717,6 +770,13 @@ async function draw(timestamp: number)
|
||||
paddleY = canvas.height / 2 - paddleHeight / 2;
|
||||
console.log('Cinq secondes se sont écoulées.');
|
||||
}, 5000);
|
||||
|
||||
// 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);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@ -3,12 +3,15 @@ import { useState, useEffect } from 'react'
|
||||
import queryString from 'query-string';
|
||||
import api from "./axiosApi.tsx";
|
||||
import axios from 'axios';
|
||||
import React from 'react';
|
||||
|
||||
import {Matchlog, User} from "../../interfaces.tsx"
|
||||
|
||||
function SuccessToken() {
|
||||
const location = useLocation();
|
||||
const { data } = queryString.parse(location.search);
|
||||
const [code, setCode] = useState('');
|
||||
const [user, setUser] = useState(false);
|
||||
const [user, setUser] = useState<User>();
|
||||
|
||||
useEffect(() => {
|
||||
if (!data) {
|
||||
@ -37,7 +40,7 @@ function SuccessToken() {
|
||||
getUser();
|
||||
}, [data]);
|
||||
|
||||
const handleKeyPress = async (e)=>{
|
||||
const handleKeyPress = async (e: { key: string; })=>{
|
||||
// console.log(`e in press= ${e.key}`)
|
||||
if (e.key !== "Enter")
|
||||
return ;
|
||||
@ -90,7 +93,8 @@ function SuccessToken() {
|
||||
// Render a loading indicator or return null while user is being fetched
|
||||
return <h1>Loading...</h1>;
|
||||
}
|
||||
|
||||
if (!data)
|
||||
return ;
|
||||
const cleanData = data.slice(1, -1); // Declare cleanData here as well
|
||||
|
||||
if (!user.otp_verified) {
|
||||
|
||||
@ -5,9 +5,13 @@
|
||||
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%;
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
margin: 50px;
|
||||
}
|
||||
|
||||
|
||||
.rank_elements {
|
||||
border-width:1px;
|
||||
border-style:solid;
|
||||
@ -18,11 +19,23 @@
|
||||
/* background-color: #5843e4; */
|
||||
/* border-color: white; */
|
||||
overflow: scroll;
|
||||
height: 70vh;
|
||||
height: 68vh;
|
||||
}
|
||||
|
||||
.profilePic{
|
||||
margin-left: 10px;
|
||||
/* margin-top: 10px; */
|
||||
height: 30px;
|
||||
width: 30px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 755px){
|
||||
.game{
|
||||
display: grid;
|
||||
height: 20vh;
|
||||
}
|
||||
.scroll{
|
||||
height: 20vh;
|
||||
}
|
||||
}
|
||||
@ -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,6 +55,7 @@ select{
|
||||
height: 74vh;
|
||||
width: 30%;
|
||||
overflow: scroll;
|
||||
border-radius: 0px 0px 0px 10px;
|
||||
/* width: 2rem; */
|
||||
/* height: 4rem; */
|
||||
}
|
||||
@ -131,16 +133,17 @@ select{
|
||||
}
|
||||
|
||||
.messages{
|
||||
background-color: rgb(26, 26, 26);
|
||||
/* background-color: rgb(26, 26, 26); */
|
||||
/* height: calc(100% - 118px); */
|
||||
width: 70%;
|
||||
/* height: 300px; */
|
||||
border-radius: 0px 0px 10px 0px;
|
||||
overflow: scroll;
|
||||
}
|
||||
|
||||
.input{
|
||||
display: flex;
|
||||
height: 50px;
|
||||
height: 6vh;
|
||||
background-color: white;
|
||||
color:#060b26;
|
||||
border: none;
|
||||
@ -202,6 +205,7 @@ p {
|
||||
text-decoration: none;
|
||||
font-weight:lighter;
|
||||
margin: 1%;
|
||||
height: 25px;
|
||||
}
|
||||
|
||||
.darkSubmit{
|
||||
@ -229,8 +233,8 @@ p {
|
||||
background-color: rgba(0, 0, 0, 0.3);
|
||||
border-radius: 4px;
|
||||
width: 11rem;
|
||||
height: 1.5rem;
|
||||
margin-top: 1rem;
|
||||
height: 2rem;
|
||||
margin-top: 1.3rem;
|
||||
}
|
||||
|
||||
.greenAlert{
|
||||
@ -307,11 +311,17 @@ p {
|
||||
/* 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{
|
||||
@ -324,6 +334,7 @@ p {
|
||||
.checkbox{
|
||||
display:flex;
|
||||
flex-direction:row;
|
||||
margin-left: 60px;
|
||||
}
|
||||
|
||||
input.in{
|
||||
@ -331,17 +342,25 @@ 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{
|
||||
@ -351,3 +370,25 @@ input.in_howLong{
|
||||
width: 20%;
|
||||
}
|
||||
|
||||
.case{
|
||||
height: auto;
|
||||
width: auto;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.catchat{
|
||||
font-size: 30px;
|
||||
margin-left: 12px;
|
||||
}
|
||||
|
||||
.block{
|
||||
font-size: 23px;
|
||||
margin-left: 12px;
|
||||
margin-top: 0.2rem;
|
||||
}
|
||||
|
||||
.inline{
|
||||
|
||||
font-size: 25px;
|
||||
margin-left: 12px;
|
||||
}
|
||||
|
||||
@ -62,6 +62,7 @@
|
||||
.page {
|
||||
text-align: center;
|
||||
overflow-y: scroll;
|
||||
/* height: 80vh; */
|
||||
/* height: 50vh; */
|
||||
/* width: 50vh; */
|
||||
/* background-color: black; */
|
||||
@ -80,9 +81,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 +97,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 +154,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;
|
||||
|
||||
@ -1,20 +1,20 @@
|
||||
.playButton {
|
||||
background-image: linear-gradient(90deg, #5843e4, #5a0760);
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
overflow: hidden;
|
||||
border-radius: 5vh;
|
||||
color: white;
|
||||
/* display: block; */
|
||||
display: block;
|
||||
margin: auto;
|
||||
margin-top: 30vh;
|
||||
padding: 2vh 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);
|
||||
@ -69,6 +69,18 @@
|
||||
}
|
||||
}
|
||||
|
||||
.responsive{
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
/* @media screen and (max-width: 350px){
|
||||
.responsive{
|
||||
display:list-item;
|
||||
flex-direction: column;
|
||||
}
|
||||
} */
|
||||
|
||||
#myCanvas {
|
||||
background-color: rgb(124, 47, 47);
|
||||
/* position: absolute; */
|
||||
|
||||
@ -14,19 +14,9 @@ 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:
|
||||
image: node:latest
|
||||
container_name: react_app
|
||||
|
||||
Loading…
Reference in New Issue
Block a user