add profile picture everywhere for all user

This commit is contained in:
kinou-p 2023-06-09 10:10:07 +02:00
parent ec776b150e
commit 2248b4e89e
19 changed files with 568 additions and 155 deletions

View File

@ -15,6 +15,7 @@
"@nestjs/passport": "^9.0.3", "@nestjs/passport": "^9.0.3",
"@nestjs/platform-express": "^9.0.0", "@nestjs/platform-express": "^9.0.0",
"@nestjs/typeorm": "^9.0.1", "@nestjs/typeorm": "^9.0.1",
"@types/multer": "^1.4.7",
"axios": "^1.4.0", "axios": "^1.4.0",
"base32-decode": "^1.0.0", "base32-decode": "^1.0.0",
"base32-encode": "^2.0.0", "base32-encode": "^2.0.0",
@ -2132,7 +2133,6 @@
"version": "1.19.2", "version": "1.19.2",
"resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz", "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz",
"integrity": "sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==", "integrity": "sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==",
"dev": true,
"dependencies": { "dependencies": {
"@types/connect": "*", "@types/connect": "*",
"@types/node": "*" "@types/node": "*"
@ -2141,14 +2141,12 @@
"node_modules/@types/body-parser/node_modules/@types/node": { "node_modules/@types/body-parser/node_modules/@types/node": {
"version": "18.16.3", "version": "18.16.3",
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.16.3.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.16.3.tgz",
"integrity": "sha512-OPs5WnnT1xkCBiuQrZA4+YAV4HEJejmHneyraIaxsbev5yCEr6KMwINNFP9wQeFIw8FWcoTqF3vQsa5CDaI+8Q==", "integrity": "sha512-OPs5WnnT1xkCBiuQrZA4+YAV4HEJejmHneyraIaxsbev5yCEr6KMwINNFP9wQeFIw8FWcoTqF3vQsa5CDaI+8Q=="
"dev": true
}, },
"node_modules/@types/connect": { "node_modules/@types/connect": {
"version": "3.4.35", "version": "3.4.35",
"resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz",
"integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==", "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==",
"dev": true,
"dependencies": { "dependencies": {
"@types/node": "*" "@types/node": "*"
} }
@ -2156,8 +2154,7 @@
"node_modules/@types/connect/node_modules/@types/node": { "node_modules/@types/connect/node_modules/@types/node": {
"version": "18.16.3", "version": "18.16.3",
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.16.3.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.16.3.tgz",
"integrity": "sha512-OPs5WnnT1xkCBiuQrZA4+YAV4HEJejmHneyraIaxsbev5yCEr6KMwINNFP9wQeFIw8FWcoTqF3vQsa5CDaI+8Q==", "integrity": "sha512-OPs5WnnT1xkCBiuQrZA4+YAV4HEJejmHneyraIaxsbev5yCEr6KMwINNFP9wQeFIw8FWcoTqF3vQsa5CDaI+8Q=="
"dev": true
}, },
"node_modules/@types/cookiejar": { "node_modules/@types/cookiejar": {
"version": "2.1.2", "version": "2.1.2",
@ -2192,7 +2189,6 @@
"version": "4.17.17", "version": "4.17.17",
"resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.17.tgz", "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.17.tgz",
"integrity": "sha512-Q4FmmuLGBG58btUnfS1c1r/NQdlp3DMfGDGig8WhfpA2YRUtEkxAjkZb0yvplJGYdF1fsQ81iMDcH24sSCNC/Q==", "integrity": "sha512-Q4FmmuLGBG58btUnfS1c1r/NQdlp3DMfGDGig8WhfpA2YRUtEkxAjkZb0yvplJGYdF1fsQ81iMDcH24sSCNC/Q==",
"dev": true,
"dependencies": { "dependencies": {
"@types/body-parser": "*", "@types/body-parser": "*",
"@types/express-serve-static-core": "^4.17.33", "@types/express-serve-static-core": "^4.17.33",
@ -2204,7 +2200,6 @@
"version": "4.17.34", "version": "4.17.34",
"resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.34.tgz", "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.34.tgz",
"integrity": "sha512-fvr49XlCGoUj2Pp730AItckfjat4WNb0lb3kfrLWffd+RLeoGAMsq7UOy04PAPtoL01uKwcp6u8nhzpgpDYr3w==", "integrity": "sha512-fvr49XlCGoUj2Pp730AItckfjat4WNb0lb3kfrLWffd+RLeoGAMsq7UOy04PAPtoL01uKwcp6u8nhzpgpDYr3w==",
"dev": true,
"dependencies": { "dependencies": {
"@types/node": "*", "@types/node": "*",
"@types/qs": "*", "@types/qs": "*",
@ -2215,8 +2210,7 @@
"node_modules/@types/express-serve-static-core/node_modules/@types/node": { "node_modules/@types/express-serve-static-core/node_modules/@types/node": {
"version": "18.16.3", "version": "18.16.3",
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.16.3.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.16.3.tgz",
"integrity": "sha512-OPs5WnnT1xkCBiuQrZA4+YAV4HEJejmHneyraIaxsbev5yCEr6KMwINNFP9wQeFIw8FWcoTqF3vQsa5CDaI+8Q==", "integrity": "sha512-OPs5WnnT1xkCBiuQrZA4+YAV4HEJejmHneyraIaxsbev5yCEr6KMwINNFP9wQeFIw8FWcoTqF3vQsa5CDaI+8Q=="
"dev": true
}, },
"node_modules/@types/graceful-fs": { "node_modules/@types/graceful-fs": {
"version": "4.1.6", "version": "4.1.6",
@ -2283,8 +2277,15 @@
"node_modules/@types/mime": { "node_modules/@types/mime": {
"version": "1.3.2", "version": "1.3.2",
"resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz",
"integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==", "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw=="
"dev": true },
"node_modules/@types/multer": {
"version": "1.4.7",
"resolved": "https://registry.npmjs.org/@types/multer/-/multer-1.4.7.tgz",
"integrity": "sha512-/SNsDidUFCvqqcWDwxv2feww/yqhNeTRL5CVoL3jU4Goc4kKEL10T7Eye65ZqPNi4HRx8sAEX59pV1aEH7drNA==",
"dependencies": {
"@types/express": "*"
}
}, },
"node_modules/@types/node": { "node_modules/@types/node": {
"version": "18.15.11", "version": "18.15.11",
@ -2306,14 +2307,12 @@
"node_modules/@types/qs": { "node_modules/@types/qs": {
"version": "6.9.7", "version": "6.9.7",
"resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz",
"integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==", "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw=="
"dev": true
}, },
"node_modules/@types/range-parser": { "node_modules/@types/range-parser": {
"version": "1.2.4", "version": "1.2.4",
"resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz", "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz",
"integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==", "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw=="
"dev": true
}, },
"node_modules/@types/semver": { "node_modules/@types/semver": {
"version": "7.3.13", "version": "7.3.13",
@ -2325,7 +2324,6 @@
"version": "0.17.1", "version": "0.17.1",
"resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.1.tgz", "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.1.tgz",
"integrity": "sha512-Cwo8LE/0rnvX7kIIa3QHCkcuF21c05Ayb0ZfxPiv0W8VRiZiNW/WuRupHKpqqGVGf7SUA44QSOUKaEd9lIrd/Q==", "integrity": "sha512-Cwo8LE/0rnvX7kIIa3QHCkcuF21c05Ayb0ZfxPiv0W8VRiZiNW/WuRupHKpqqGVGf7SUA44QSOUKaEd9lIrd/Q==",
"dev": true,
"dependencies": { "dependencies": {
"@types/mime": "^1", "@types/mime": "^1",
"@types/node": "*" "@types/node": "*"
@ -2334,14 +2332,12 @@
"node_modules/@types/send/node_modules/@types/node": { "node_modules/@types/send/node_modules/@types/node": {
"version": "18.16.3", "version": "18.16.3",
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.16.3.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.16.3.tgz",
"integrity": "sha512-OPs5WnnT1xkCBiuQrZA4+YAV4HEJejmHneyraIaxsbev5yCEr6KMwINNFP9wQeFIw8FWcoTqF3vQsa5CDaI+8Q==", "integrity": "sha512-OPs5WnnT1xkCBiuQrZA4+YAV4HEJejmHneyraIaxsbev5yCEr6KMwINNFP9wQeFIw8FWcoTqF3vQsa5CDaI+8Q=="
"dev": true
}, },
"node_modules/@types/serve-static": { "node_modules/@types/serve-static": {
"version": "1.15.1", "version": "1.15.1",
"resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.1.tgz", "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.1.tgz",
"integrity": "sha512-NUo5XNiAdULrJENtJXZZ3fHtfMolzZwczzBbnAeBbqBwG+LaG6YaJtuwzwGSQZ2wsCrxjEhNNjAkKigy3n8teQ==", "integrity": "sha512-NUo5XNiAdULrJENtJXZZ3fHtfMolzZwczzBbnAeBbqBwG+LaG6YaJtuwzwGSQZ2wsCrxjEhNNjAkKigy3n8teQ==",
"dev": true,
"dependencies": { "dependencies": {
"@types/mime": "*", "@types/mime": "*",
"@types/node": "*" "@types/node": "*"
@ -2350,8 +2346,7 @@
"node_modules/@types/serve-static/node_modules/@types/node": { "node_modules/@types/serve-static/node_modules/@types/node": {
"version": "18.16.3", "version": "18.16.3",
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.16.3.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.16.3.tgz",
"integrity": "sha512-OPs5WnnT1xkCBiuQrZA4+YAV4HEJejmHneyraIaxsbev5yCEr6KMwINNFP9wQeFIw8FWcoTqF3vQsa5CDaI+8Q==", "integrity": "sha512-OPs5WnnT1xkCBiuQrZA4+YAV4HEJejmHneyraIaxsbev5yCEr6KMwINNFP9wQeFIw8FWcoTqF3vQsa5CDaI+8Q=="
"dev": true
}, },
"node_modules/@types/stack-utils": { "node_modules/@types/stack-utils": {
"version": "2.0.1", "version": "2.0.1",

View File

@ -26,6 +26,7 @@
"@nestjs/passport": "^9.0.3", "@nestjs/passport": "^9.0.3",
"@nestjs/platform-express": "^9.0.0", "@nestjs/platform-express": "^9.0.0",
"@nestjs/typeorm": "^9.0.1", "@nestjs/typeorm": "^9.0.1",
"@types/multer": "^1.4.7",
"axios": "^1.4.0", "axios": "^1.4.0",
"base32-decode": "^1.0.0", "base32-decode": "^1.0.0",
"base32-encode": "^2.0.0", "base32-encode": "^2.0.0",

View File

@ -1,4 +1,5 @@
import { Controller, Request, Req, Get, Post, UseGuards, Redirect, Res, Body } 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 { JwtAuthGuard } from './auth/jwt-auth.guard';
import { AuthService } from './auth/auth.service'; import { AuthService } from './auth/auth.service';
@ -51,10 +52,29 @@ export class AppController {
return await this.userService.findOne(data.username); return await this.userService.findOne(data.username);
} }
@UseGuards(JwtAuthGuard)
@Get('/friends') @Get('/friends')
async getFriends(@Request() req) { async getFriends(@Request() req) {
// return await this.userService.getFriends(req.user.username); // return await this.userService.getFriends(req.user.username);
return await this.userService.getFriends("apommier"); return await this.userService.getFriends(req.user.username);
}
@UseGuards(JwtAuthGuard)
@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)
return await this.userService.addFriend(user, data.username);
}
@UseGuards(JwtAuthGuard)
@Post('/status')
async setStatus(@Request() req, @Body() data: any) {
const user = await this.userService.findOne(req.user.username);
user.status = data.status;
await this.userService.save(user);
} }
@UseGuards(JwtAuthGuard) @UseGuards(JwtAuthGuard)
@ -62,12 +82,38 @@ export class AppController {
async setNickname(@Request() req, @Body() data: any) { async setNickname(@Request() req, @Body() data: any) {
// let user = req.user // let user = req.user
// user.nickname = data.nickname // user.nickname = data.nickname
console.log(`user= ${req.user.username}`)
let user = await this.userService.findOne(req.user.username) let user = await this.userService.findOne(req.user.username)
user.nickname = data.nickname; user.nickname = data.nickname;
// return await this.userService.getFriends(req.user.username); // return await this.userService.getFriends(req.user.username);
return await this.userService.save(user); return await this.userService.save(user);
} }
@UseGuards(JwtAuthGuard)
@Post('/picture')
@UseInterceptors(FileInterceptor('photo'))
async setProfilPicture(@Request() req, @UploadedFile() file: Express.Multer.File) {
let user = await this.userService.findOne(req.user.username)
if (!file)
user.photo = null;
else
user.photo = file.buffer;
return await this.userService.save(user);
}
@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 // Pong
@ -125,6 +171,13 @@ export class AppController {
return user.rank; return user.rank;
} }
// @UseGuards(JwtAuthGuard)
@Get('/ranking')
async getRanking()
{
return await this.userService.getRanking();
}
@UseGuards(JwtAuthGuard) @UseGuards(JwtAuthGuard)
@Post('/history') @Post('/history')
async getHistory(@Body() data: any) async getHistory(@Body() data: any)

View File

@ -69,6 +69,7 @@ export class loginClass {
doubleAuth: 0, doubleAuth: 0,
friendRequest: null, friendRequest: null,
friends: null, friends: null,
photo: null,
}; };
await this.usersService.create(user); await this.usersService.create(user);
} }

View File

@ -26,6 +26,9 @@ export class User {
@Column({ nullable: true }) @Column({ nullable: true })
username: string; username: string;
@Column({ type: 'bytea', nullable: true })
photo: Buffer;
@Column({ nullable: true }) @Column({ nullable: true })
password: string; password: string;

View File

@ -65,6 +65,32 @@ export class UsersService {
// }); // });
} }
} }
async addFriend(user: User, username: string) {
user.friends = user.friends || [];
user.friends.push(username);
this.save(user);
}
async getRanking() {
return await this.userRepository.query("SELECT * FROM \"User\" ORDER BY rank DESC;");
}
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]);
// console.log(`result= ${result}`)
// console.log(`result= ${result.text}`)
// console.log(`encode= ${result.encode}`)
// console.log(`encode= ${result.string}`)
if (result.length > 0) {
const encodedPhoto = result[0].encode;
console.log(`pic!!! =`)
return encodedPhoto;
}
console.log(`no pic`)
return undefined
}
} }

View File

@ -17,6 +17,7 @@ import SuccessToken from '../script/tokenSuccess'
import DoubleAuth from "../pages/2fa.js"; import DoubleAuth from "../pages/2fa.js";
import Game from "../pages/Game.jsx"; import Game from "../pages/Game.jsx";
import Social from "../components/Social/Social.jsx"; import Social from "../components/Social/Social.jsx";
import Logout from "../components/Profile/Logout.jsx";
function AnimatedRoute () { function AnimatedRoute () {
const location = useLocation(); const location = useLocation();
@ -38,6 +39,7 @@ function AnimatedRoute () {
{/* <Route path="/profile" element={<PlayButton />}/> */} {/* <Route path="/profile" element={<PlayButton />}/> */}
<Route exact path="/login42" element={<Login42 />}/> <Route exact path="/login42" element={<Login42 />}/>
<Route exact path="/logout" element={<Logout />}/>
<Route exact path="/messages" element={<Messages />}/> <Route exact path="/messages" element={<Messages />}/>
</Routes> </Routes>
</AnimatePresence> </AnimatePresence>

View File

@ -0,0 +1,57 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* Rank.jsx :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: apommier <apommier@student.42.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2023/06/09 08:49:24 by apommier #+# #+# */
/* Updated: 2023/06/09 08:55:22 by apommier ### ########.fr */
/* */
/* ************************************************************************** */
// import React from "react"
import React, { useState, useEffect, useRef } from "react";
// import {Rank} from '../../DataBase/DataRank.js'
import DefaultPicture from '../../assets/profile.jpg'
import api from '../../script/axiosApi';
function Rank({user, index}){
const [profilePicture, setProfilePicture] = useState('');
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);
}
};
fetchProfilePicture();
})
return (
<div className='rank_elements'>
<div>
<p>{index + 1}</p>
<h4>{user.rank}: {user.nickname}
{profilePicture ? (
<img className="profilePic" src={`data:image/jpeg;base64,${profilePicture}`} />
) : (
<img className="profilePic" src={DefaultPicture} alt="Default Profile Picture" />
)}
{/* <img className="profilePic" src={defaultpic}/> */}
</h4>
</div>
<h4 className='content'>{user.opponent}</h4>
</div>
)
}
export default Rank

View File

@ -1,25 +1,59 @@
import React from "react" // import React from "react"
import {Rank} from '../../DataBase/DataRank.js' import React, { useState, useEffect, useRef } from "react";
import Rank from './Rank.jsx'
import defaultpic from '../../assets/profile.jpg' import defaultpic from '../../assets/profile.jpg'
import api from '../../script/axiosApi';
function Ranking(){ function Ranking(){
const [isLoading, setIsLoading] = useState(true);
const [ranking, setRanking] = useState([]);
useEffect(()=> {
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)
}
catch(err){
console.log(err);
}
};
getRanking();
}, [])
console.log(`ranking after= ${ranking}`)
return ( return (
<div> <div>
<h1 className='title'>Ranking</h1> {isLoading ? (
<></>
) : (
// <h1 className='title'>Ranking</h1>
<div className='scroll'> <div className='scroll'>
{Rank.map((item, index) => { {ranking.map((user, index) => (
return ( <Rank user={user} index={index}/>
<div className='rank_elements'> // return (
<li key={index}> // <div className='rank_elements'>
<div> // <div>
<h4>{item.rank}: {item.name} <img className="profilePic" src={defaultpic}/></h4> // <p>{index + 1}</p>
</div> // <h4>{user.rank}: {user.nickname} <img className="profilePic" src={defaultpic}/></h4>
{/* <h4 className='content'>{item.openent}</h4> */} // </div>
</li> // <h4 className='content'>{user.opponent}</h4>
</div> // </div>
) // )
})} ))}
</div> </div>
)}
</div> </div>
) )
} }

View File

@ -1,4 +1,4 @@
import React, {useState} from 'react'; import React, {useState, useEffect} from 'react';
import {AiOutlineMenuUnfold} from 'react-icons/ai'; import {AiOutlineMenuUnfold} from 'react-icons/ai';
// import * as AiIcons from 'react-icons/ai'; // import * as AiIcons from 'react-icons/ai';
import {Link} from 'react-router-dom'; import {Link} from 'react-router-dom';
@ -10,7 +10,7 @@ import Modal from './Sidebar/Modal';
// import AnimatePresence from // import AnimatePresence from
import '../styles/Header.css'; import '../styles/Header.css';
import api from '../script/axiosApi';
function Header() { function Header() {
// const [sidebar, setSidebar] = useState(false); // const [sidebar, setSidebar] = useState(false);
@ -19,54 +19,29 @@ function Header() {
const close = () => setModalOpen(false); const close = () => setModalOpen(false);
const open = () => setModalOpen(true); const open = () => setModalOpen(true);
const [profilePicture, setProfilePicture] = useState('');
useEffect(() => {
const fetchProfilePicture = async () => {
try {
const user = await api.get("/profile");
const pic = await api.post("/getPicture", {username: user.data.username})
setProfilePicture(pic.data);
// console.log(`profile pic222= ${pic.data}`)
} catch (error) {
console.error('Error fetching profile picture:', error);
}
};
fetchProfilePicture();
}, []);
// console.log(`profile pic= ${profilePicture}`)
// photo.toString('base64')
return ( return (
<div className='Header'> <div className='Header'>
{/* <div className='Header'>
<Link to="#" className='menu-bars'>
<motion.div>
onClick={() => (modalOpen ? close() : open())}>
<AiOutlineMenuUnfold/>
</motion.div>
</Link>
<div className='end'>
<Link to="/" className='menu-bars'>
<img className='Header-pic' src={DefaultPicture} alt='profile'/>
</Link>
</div> */}
{/* <Link to="#" className='menu-bars'>
<AiOutlineMenuUnfold onClick={showSidebar}/>
</Link>
<div className='end'>
<Link to="/" className='menu-bars'>
<img className='Header-pic' src={DefaultPicture} alt='profile'/>
</Link>
</div> */}
{/* </div> */}
{/* <nav className={sidebar ? 'nav-menu active' : 'nav-menu'}>
<ul className='nav-menu-items' onClick={showSidebar}>
<li className='Header-toggle'>
<Link to="#" className='menu-bars'>
<AiIcons.AiOutlineClose />
</Link>
</li>
{SidebarData.map((item, index) => {
return (
<motion.div
whileHover={{scale: 1.1}}>
<li key={index} className={item.cName}>
<Link to={item.path}>
{item.icon}
<span>{item.title}</span>
</Link>
</li>
</motion.div>
)
})}
</ul>
</nav> */}
<motion.div <motion.div
onClick={() => (modalOpen ? close() : open())}> onClick={() => (modalOpen ? close() : open())}>
<Link to="#" className='menu-bars'> <Link to="#" className='menu-bars'>
@ -75,7 +50,17 @@ function Header() {
</motion.div> </motion.div>
<div className='end'> <div className='end'>
<Link to="/profile" className='menu-bars'> <Link to="/profile" className='menu-bars'>
<img className='Header-pic' src={DefaultPicture} alt='profile'/> <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" />
)}
</div>
</Link> </Link>
</div> </div>
<AnimatePresence <AnimatePresence

View File

@ -241,7 +241,7 @@ function Chats(){
</div> </div>
{/* <div className="chat"> */}
<div className='navbar'> <div className='navbar'>
<img src={DefaultPic} alt="profile" className="pic"/> <img src={DefaultPic} alt="profile" className="pic"/>
<span> <span>
@ -260,7 +260,6 @@ function Chats(){
</TouchDiv> </TouchDiv>
</div> </div>
</div> </div>
{/* </div> */}
{conversations.map(c=> ( {conversations.map(c=> (
<div onClick={() => setCurrentChat(c)}> <div onClick={() => setCurrentChat(c)}>
<UserChat> <UserChat>
@ -278,7 +277,7 @@ function Chats(){
<> <>
<div className="messages"> <div className="messages">
{messages.map(m=>( {messages.map(m=>(
<Message message = {m} own={m.sender === user.username}/> <Message message = {m} own={m.sender === user.username} user={m}/>
))} ))}
{/* <Input/> */} {/* <Input/> */}
<div className="input"> <div className="input">
@ -293,8 +292,12 @@ function Chats(){
<TbSend onClick={handleSubmit}></TbSend> <TbSend onClick={handleSubmit}></TbSend>
</div> </div>
</div> </div>
</div></>) : (<span className="noConv">Open a conversation</span>)}
</div> </div>
</>
) : (
<span className="noConv">Open a conversation</span>)}
</div>
// </div>
); );

View File

@ -6,15 +6,16 @@
/* By: apommier <apommier@student.42.fr> +#+ +:+ +#+ */ /* By: apommier <apommier@student.42.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */ /* +#+#+#+#+#+ +#+ */
/* Created: 2023/06/01 18:24:46 by apommier #+# #+# */ /* Created: 2023/06/01 18:24:46 by apommier #+# #+# */
/* Updated: 2023/06/01 18:33:43 by apommier ### ########.fr */ /* Updated: 2023/06/09 09:00:06 by apommier ### ########.fr */
/* */ /* */
/* ************************************************************************** */ /* ************************************************************************** */
import React from "react" import { useEffect, useState, useRef } from "react";
import api from '../../script/axiosApi';
import styled from "styled-components" import styled from "styled-components"
import DefaultPic from '../../assets/profile.jpg' import DefaultPicture from '../../assets/profile.jpg'
import { useRef } from "react"; // import { useRef } from "react";
import { useEffect } from "react"; // import { useEffect } from "react";
import '../../styles/Messages.css' import '../../styles/Messages.css'
const MeStyleP = styled.p` const MeStyleP = styled.p`
@ -26,16 +27,38 @@ const MeStyleP = styled.p`
` `
function MessageMe({message, own}){ function MessageMe({message, own}){
const [profilePicture, setProfilePicture] = useState('');
const scrollRef = useRef(); const scrollRef = useRef();
useEffect(() => { useEffect(() => {
scrollRef.current?.scrollIntoView({ behavior: "smooth"}) scrollRef.current?.scrollIntoView({ behavior: "smooth"})
}, []) const fetchProfilePicture = async () => {
try {
// const user = 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}`)
setProfilePicture(pic.data);
} catch (error) {
console.error('Error fetching profile picture:', error);
}
};
fetchProfilePicture();
}, [])
return ( return (
<div className={own ? "meMessage" : "youMessage"} ref={scrollRef}> <div className={own ? "meMessage" : "youMessage"} ref={scrollRef}>
<div> <div>
<img className="messageInfo" src={DefaultPic} alt="profile" /> {/* <img className="messageInfo" src={DefaultPic} alt="profile" />
*/}
{profilePicture ? (
<img className="messageInfo" src={`data:image/jpeg;base64,${profilePicture}`} />
) : (
<img className="messageInfo" src={DefaultPicture} alt="Default Profile Picture" />
)}
</div> </div>
{/* <div className="usernameMesage">{message.senderNickname}</div> */}
<div className="usernameMesage">{message.sender}</div> <div className="usernameMesage">{message.sender}</div>
<div className="messageContent"> <div className="messageContent">
<MeStyleP>{message.text}</MeStyleP> <MeStyleP>{message.text}</MeStyleP>

View File

@ -63,6 +63,7 @@ const ModalEdit = ( handleClose ) => {
</div> </div>
</motion.div> </motion.div>
) )
} }

View File

@ -0,0 +1,15 @@
function Logout(){
localStorage.clear();
const path = `http://localhost/`;
// history(path, { replace: true });
// window.location.replace(path);
// window.history.pushState({}, '', path);
window.history.pushState({}, null, path);
window.location.reload(false);
}
export default Logout;

View File

@ -39,7 +39,7 @@ export const SidebarData = [
}, },
{ {
title: 'Log out', title: 'Log out',
path: '/team', path: '/logout',
icon: <BiLogOutCircle />, icon: <BiLogOutCircle />,
cName: 'nav-text' cName: 'nav-text'
}, },

View File

@ -0,0 +1,110 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* Friend.jsx :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: apommier <apommier@student.42.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2023/06/09 08:18:58 by apommier #+# #+# */
/* Updated: 2023/06/09 08:35:21 by apommier ### ########.fr */
/* */
/* ************************************************************************** */
import { useEffect, useState } from "react";
import api from '../../script/axiosApi';
import DefaultPicture from '../../assets/profile.jpg'
import styled from "styled-components";
import { RxCircle } from "react-icons/rx";
import { CgFontSpacing } from "react-icons/cg";
const UserChat = styled.div `
padding: 5px;
display: flex;
align-items: center;
gap: 5px;
color: white;
cursor: pointer;
&:hover{
background-color: #3e3c61;
}
`
const SideP = styled.p`
font-size: 14px;
color: lightgray;
margin-left: 15px;
`
export default function Friend({currentUser})
{
const [profilePicture, setProfilePicture] = useState('');
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)
{
let status = friend.status
console.log(`status= ${status}`)
let statusColor;
if (status === 0)
statusColor = 'grey';
else if (status === 1)
statusColor = 'green';
else if (status === 2)
statusColor = 'blue';
return statusColor;
}
const handleSpectate = (user) => {
//socket connection and add to party with one with username
console.log(`spectate hehe`)
console.log(`user= ${user}`)
};
const handleButtonClick = (user) => {
let path = `http://localhost/profile/${user.username}`;
// history(path, { replace: true });
// window.location.replace(path);
window.history.pushState({}, null, path);
window.location.reload(false);
};
return (
<UserChat>
{profilePicture ? (
<img className="pic-user" src={`data:image/jpeg;base64,${profilePicture}`} />
) : (
<img className="pic-user" src={DefaultPicture} alt="Default Profile Picture" />
)}
<div className="infoSideBar">
<span onClick={() => handleButtonClick(currentUser)}>{currentUser.nickname}</span>
<RxCircle icon={RxCircle} color={getStatus(currentUser)} />
<button onClick={() => handleSpectate(currentUser)} >Invite</button>
{getStatus(currentUser) !== 'blue' ? (
<></>
) : (
<button onClick={() => handleSpectate(currentUser)} >Spectate</button>
)}
</div>
</UserChat>
)
}

View File

@ -1,32 +1,21 @@
import DefaultPic from '../../assets/profile.jpg' import DefaultPicture from '../../assets/profile.jpg'
import api from '../../script/axiosApi'; import api from '../../script/axiosApi';
import React, { useState, useEffect, useRef } from "react"; import React, { useState, useEffect, useRef } from "react";
import styled from "styled-components"; import styled from "styled-components";
import Friend from './Friend.jsx';
import { ImBlocked } from 'react-icons/im'; import { ImBlocked } from 'react-icons/im';
import { MdOutlineGroupAdd } from 'react-icons/md'; import { MdOutlineGroupAdd } from 'react-icons/md';
// import React from "react"; // import React from "react";
import { useNavigate } from "react-router-dom"; import { useNavigate } from "react-router-dom";
const UserChat = styled.div `
padding: 5px;
display: flex;
align-items: center;
gap: 5px;
color: white;
cursor: pointer;
&:hover{
background-color: #3e3c61;
}
`
const SideP = styled.p`
font-size: 14px;
color: lightgray;
margin-left: 15px;
`
const TouchDiv = styled.div` const TouchDiv = styled.div`
margin-left: 10px; margin-left: 10px;
margin-right: 4px; margin-right: 4px;
@ -45,6 +34,7 @@ function Social (){
const [friends, setFriends] = useState([]); const [friends, setFriends] = useState([]);
const [isLoading, setIsLoading] = useState(true); const [isLoading, setIsLoading] = useState(true);
const [user, setUser] = useState(null); const [user, setUser] = useState(null);
const [profilePicture, setProfilePicture] = useState('');
useEffect(()=> { useEffect(()=> {
@ -52,6 +42,8 @@ function Social (){
try{ try{
const tmpFriends = await api.get("/friends") const tmpFriends = await api.get("/friends")
const tmpUser = await api.get("/profile") const tmpUser = await api.get("/profile")
const pic = await api.post("/getPicture", {username: tmpUser.data.username})
setProfilePicture(pic.data);
setUser(tmpUser.data); setUser(tmpUser.data);
setFriends(tmpFriends.data); setFriends(tmpFriends.data);
// return tmpUser; // return tmpUser;
@ -67,18 +59,35 @@ function Social (){
}, []) }, [])
const handleButtonClick = (user) => {
let path = `http://localhost/profile/${user.username}`;
// history(path, { replace: true });
// window.location.replace(path);
window.history.pushState({}, null, path); // const { status } = this.props;
window.location.reload(false); // 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 ( return (
<div> <div>
<div className='navbar'> <div className='navbar'>
<img src={DefaultPic} alt="profile" className="pic"/> {/* <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" />
)}
<span> <span>
{isLoading ? ( {isLoading ? (
<h4>Loading...</h4> <h4>Loading...</h4>
@ -97,15 +106,27 @@ function Social (){
</div> </div>
{friends.map(c=> ( {friends.map(c=> (
<div onClick={() => handleButtonClick(c)}> <Friend currentUser={c}/>
<UserChat> // <UserChat>
<img className="pic-user" src={DefaultPic} alt="User" /> // {profilePicture ? (
<div className="infoSideBar"> // <img className="pic-user" src={`data:image/jpeg;base64,${profilePicture}`} />
<span>{c.nickname}</span> // ) : (
<SideP>Desc?</SideP> // <img className="pic-user" src={DefaultPicture} alt="Default Profile Picture" />
</div> // )}
</UserChat> // <div className="infoSideBar">
</div> // <span onClick={() => handleButtonClick(c)}>{c.nickname}</span>
// <RxCircle icon={RxCircle} color={getStatus(c)} />
// <button onClick={() => handleSpectate(c)} >Invite</button>
// {getStatus(c) !== 'blue' ? (
// <></>
// ) : (
// <button onClick={() => handleSpectate(c)} >Spectate</button>
// )}
// </div>
// </UserChat>
// </div>
))} ))}
</div> </div>
) )

View File

@ -1,3 +1,15 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* Home.jsx :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: apommier <apommier@student.42.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2023/06/09 08:19:04 by apommier #+# #+# */
/* Updated: 2023/06/09 08:19:05 by apommier ### ########.fr */
/* */
/* ************************************************************************** */
// import { React, useState } from "react"; // import { React, useState } from "react";
import '../styles/Profile.css' import '../styles/Profile.css'
// import '../styles/App.css' // import '../styles/App.css'
@ -34,18 +46,63 @@ function Profile () {
const [user, setUser] = useState(null); const [user, setUser] = useState(null);
const [isLoading, setIsLoading] = useState(true); const [isLoading, setIsLoading] = useState(true);
const [modalOpen, setModalOpen] = useState(false); const [modalOpen, setModalOpen] = useState(false);
const [mine, setMine] = useState(false);
const close = () => setModalOpen(false); const close = () => setModalOpen(false);
const open = () => setModalOpen(true); const open = () => setModalOpen(true);
const { username } = useParams(); const { username } = useParams();
const [selectedPhoto, setSelectedPhoto] = useState(null);
const [profilePicture, setProfilePicture] = useState('');
const handleFileChange = (event) => {
// const file = event.target.files[0];
setSelectedPhoto(event.target.files[0]);
// try{
// api.post("/picture", {picture: URL.createObjectURL(file)})
// }
// catch(err){
// console.log(err);
// }
};
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(false);
} catch (error) {
console.error('Error uploading file:', error);
}
};
useEffect(()=> { useEffect(()=> {
const getUser = async ()=>{ const getUser = async ()=>{
console.log(`username= ${username}`) console.log(`username= ${username}`)
// const pic
let pic
try{ 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
{
const tmpUser = await api.post("/user", {username: username}) const tmpUser = await api.post("/user", {username: username})
setUser(tmpUser.data); setUser(tmpUser.data);
console.log(`user= ${tmpUser.data.username}`) 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) setIsLoading(false)
} }
catch(err){ catch(err){
@ -57,7 +114,13 @@ function Profile () {
return ( return (
<div className="profile"> <div className="profile">
<img className="profile-pic" src={DefaultPicture} alt="Profile pic" /> {/* <img className="profile-pic" src={DefaultPicture} alt="Profile pic" />
*/}
{profilePicture ? (
<img className="profile-pic" src={`data:image/jpeg;base64,${profilePicture}`} />
) : (
<img className="profile-pic" src={DefaultPicture} alt="Default Profile Picture" />
)}
<span> <span>
{isLoading ? ( {isLoading ? (
<h1>Loading...</h1> <h1>Loading...</h1>
@ -65,11 +128,28 @@ function Profile () {
<h1>{user.nickname}</h1> <h1>{user.nickname}</h1>
)} )}
</span> </span>
{mine ? (
<div>
<motion.div onClick={() => (modalOpen ? close() : open())}> <motion.div onClick={() => (modalOpen ? close() : open())}>
<Link to="#" className="edit_name"> <Link to="#" className="edit_name">
{modalOpen === true ? <IoCloseCircleOutline/> : <CgEditMarkup/>} {modalOpen === true ? <IoCloseCircleOutline/> : <CgEditMarkup/>}
</Link> </Link>
</motion.div> </motion.div>
<div>
<input type="file" accept="image/*" onChange={handleFileChange} />
<button onClick={handleUpload}>Upload</button>
</div>
</div>
) : (
<></>
)}
<AnimatePresence <AnimatePresence
initial={false} initial={false}
onExitComplete={() => null}> onExitComplete={() => null}>

View File

@ -120,6 +120,7 @@ export function drawCanvas() {
let response = await api.get('/profile'); let response = await api.get('/profile');
const myName = response.data.username; const myName = response.data.username;
response = await api.get('/rank'); response = await api.get('/rank');
await api.post('/status', {status: 2});
opRank = response.data opRank = response.data
console.log(`rank= ${opRank}`); console.log(`rank= ${opRank}`);
console.log(`myname= ${myName}`); console.log(`myname= ${myName}`);
@ -316,11 +317,13 @@ function draw(timestamp)
if (myScore === maxScore) if (myScore === maxScore)
{ {
api.post('/win', data); api.post('/win', data);
api.post('/status', {status: 1});
console.log("send win"); console.log("send win");
} }
else else
{ {
api.post('/loss', data); api.post('/loss', data);
api.post('/status', {status: 1});
console.log("send loose"); console.log("send loose");
} }
window.location.replace("http://localhost/pong"); window.location.replace("http://localhost/pong");