This commit is contained in:
Alexandre POMMIER 2023-06-23 16:01:09 +02:00
commit cdd2836e7c
18 changed files with 249 additions and 78 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 149 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

View File

@ -3,6 +3,8 @@ import { motion } from 'framer-motion'
import { GrTrophy } from "react-icons/gr"; import { GrTrophy } from "react-icons/gr";
import '../../styles/Messages.css' import '../../styles/Messages.css'
import React from "react"; import React from "react";
import { MdQrCodeScanner } from "react-icons/md";
import { GiCrownedSkull, GiWingedSword } from "react-icons/gi";
const dropIn = { const dropIn = {
hidden: { hidden: {
@ -18,10 +20,11 @@ const dropIn = {
interface AlertProps { interface AlertProps {
handleClose: Function, handleClose: Function,
text: string text: string,
icon: number
} }
function YellowAlert ({handleClose, text}: AlertProps) { function YellowAlert ({handleClose, text, icon}: AlertProps) {
return( return(
<Backdrop onClick={handleClose}> <Backdrop onClick={handleClose}>
<motion.div <motion.div
@ -32,8 +35,23 @@ function YellowAlert ({handleClose, text}: AlertProps) {
animate="visible" animate="visible"
exit="exit" exit="exit"
> >
{icon === 0 ? (
<GrTrophy/> <GrTrophy/>
<p>{text}</p> ):("")}
{icon === 1 ? (
<MdQrCodeScanner/>
):("")}
{icon === 2 ? (
<GiCrownedSkull/>
):("")}
{icon === 3 ? (
<GiWingedSword/>
):("")}
<h5>{text}</h5>
</motion.div> </motion.div>
{setTimeout(handleClose, 3000)} {setTimeout(handleClose, 3000)}
</Backdrop> </Backdrop>

View File

@ -4,10 +4,14 @@ import {Link} from 'react-router-dom';
import DefaultPicture from '../assets/profile.jpg' import DefaultPicture from '../assets/profile.jpg'
import { motion, AnimatePresence } from 'framer-motion' import { motion, AnimatePresence } from 'framer-motion'
import Modal from './Sidebar/Modal.tsx'; import Modal from './Sidebar/Modal.tsx';
import YellowAlert from './Alert/YellowAlert.tsx';
import '../styles/Header.css'; import '../styles/Header.css';
import api from '../script/axiosApi.tsx'; import api from '../script/axiosApi.tsx';
import { MdQrCodeScanner } from 'react-icons/md';
import { GiWingedSword, GiCrownedSkull } from 'react-icons/gi';
function Header() { function Header() {
// const [sidebar, setSidebar] = useState(false); // const [sidebar, setSidebar] = useState(false);
// const showSidebar = () => setSidebar(!sidebar); // const showSidebar = () => setSidebar(!sidebar);
@ -15,6 +19,8 @@ function Header() {
const close = () => setModalOpen(false); const close = () => setModalOpen(false);
const open = () => setModalOpen(true); const open = () => setModalOpen(true);
const [success, setSuccess] = useState([]);
const [profilePicture, setProfilePicture] = useState(''); const [profilePicture, setProfilePicture] = useState('');
useEffect(() => { useEffect(() => {
@ -23,6 +29,8 @@ function Header() {
const user = await api.get("/profile"); const user = await api.get("/profile");
const pic = await api.post("/getPicture", {username: user.data.username}) const pic = await api.post("/getPicture", {username: user.data.username})
setProfilePicture(pic.data); setProfilePicture(pic.data);
// console.log("test ===", user.data)
setSuccess(user.data);
// console.log(`profile pic222= ${pic.data}`) // console.log(`profile pic222= ${pic.data}`)
} catch (error) { } catch (error) {
console.error('Error fetching profile picture:', error); console.error('Error fetching profile picture:', error);
@ -32,10 +40,6 @@ function Header() {
fetchProfilePicture(); fetchProfilePicture();
}, []); }, []);
// console.log(`profile pic= ${profilePicture}`)
// photo.toString('base64')
return ( return (
<div className='Header'> <div className='Header'>
<motion.div <motion.div
@ -45,6 +49,7 @@ function Header() {
</Link> </Link>
</motion.div> </motion.div>
<div className='end'> <div className='end'>
<Link to="/profile" className='menu-bars'> <Link to="/profile" className='menu-bars'>
<div> <div>

View File

@ -108,15 +108,19 @@ function Chats(){
const convs = await api.get("/conv") const convs = await api.get("/conv")
const tmpInvite = await api.get("/partyInvite") const tmpInvite = await api.get("/partyInvite")
const tmpUser = await api.get("/profile") const tmpUser = await api.get("/profile")
const tmpUsers = await api.get("/users");
console.log(convs); console.log(convs);
// console.log("invite data use effect= ", tmpInvite.data); // console.log("invite data use effect= ", tmpInvite.data);
setPartyInvite(tmpInvite.data); setPartyInvite(tmpInvite.data);
setUser(tmpUser.data); setUser(tmpUser.data);
setConversation(convs.data); setConversation(convs.data);
console.log(`connection....`); setUsers(tmpUsers.data);
socket.current = io('http://localhost:4001', { transports: ['polling'] });
console.log(`connection done`); // console.log(`connection....`);
socket.current = io('http://' + process.env.REACT_APP_BASE_URL + ':4001', { transports: ['polling'] });
// console.log(`connection done`);
socket.current.emit('connection', {username: tmpUser.data.username}) socket.current.emit('connection', {username: tmpUser.data.username})
socket.current.on('message', (data) => { //data should be a message ?) socket.current.on('message', (data) => { //data should be a message ?)
setIncomingMessage(data); setIncomingMessage(data);
@ -282,6 +286,10 @@ function Chats(){
const [newGameModalOpen, setNewGameModalOpen] = useState(false); const [newGameModalOpen, setNewGameModalOpen] = useState(false);
const [newConversationModalOpen, setNewConversationModalOpen] = useState(false); const [newConversationModalOpen, setNewConversationModalOpen] = useState(false);
const [selectTags, setSelectTag] = useState([{ id: 1, selectedOption: ''}]);
const [users, setUsers] = useState<User[]>([]);
const openNewGameModal = () => { const openNewGameModal = () => {
setNewGameModalOpen(true); setNewGameModalOpen(true);
}; };
@ -361,6 +369,15 @@ function Chats(){
setShowBlockAlert(false); setShowBlockAlert(false);
}; };
const handleOptionChange = (selectId: number, selectedOption: string) => {
console.log("selected Option=", selectedOption)
setSelectTag((prevTags) =>
prevTags.map((tag) =>
tag.id === selectId ? { ...tag, selectedOption } : tag
)
);
};
//======================================================================================================== //========================================================================================================
//======================================================================================================== //========================================================================================================
// HTML // HTML
@ -426,7 +443,24 @@ function Chats(){
</div> */} </div> */}
<div className="end"> <div className="end">
<input className="lookForFriends" type="text" value={friend} onChange={handleFriend} /> {selectTags.map((selectTag) => (
<div key={selectTag.id}>
<select
value={selectTag.selectedOption}
className="lookForFriends"
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.username)).map((item, index) => (
<option key={index} value={item.username}>
{item.username}
</option>
))}
</select>
</div>
))}
<TouchDiv> <TouchDiv>
<motion.div onClick={handleAddFriend}> <motion.div onClick={handleAddFriend}>
<MdOutlineGroupAdd /> <MdOutlineGroupAdd />

View File

@ -153,6 +153,10 @@ const Modal = ({handleClose}) => {
))} ))}
</select> </select>
)} )}
{channel.private ? (
<input className="mdp" placeholder="password" type="text" />
):("")}
<div className="div_submit"> <div className="div_submit">
<Link to='#' className="submit" onClick={ joinChannel }>Join</Link> <Link to='#' className="submit" onClick={ joinChannel }>Join</Link>

View File

@ -40,6 +40,13 @@ const ModalSetting = ({handleClose, convId, socket }: ModalSettingProps) => {
const [selectedUser, setSelectedUser] = useState(""); const [selectedUser, setSelectedUser] = useState("");
const [newName, setNewName] = useState(""); const [newName, setNewName] = useState("");
const [newPassword, setNewPassword] = useState(""); const [newPassword, setNewPassword] = useState("");
const [privateConv, setPrivateConv] = useState(false);
const dark = () => setPrivateConv(true);
const light = () => setPrivateConv(false);
const [mute, setMute] = useState(false);
const darkMute = () => setMute(false);
const lightMute = () => setMute(true);
useEffect(()=> { useEffect(()=> {
@ -183,15 +190,19 @@ const ModalSetting = ({handleClose, convId, socket }: ModalSettingProps) => {
{/* First selection */} {/* First selection */}
<div className="settingFirstPart"> <div className="settingFirstPart">
<div> <div>
<p className="checkbox">Private<input className="check"type="checkbox" value="private" onChange={handleCheckPriv}/></p> <div>
<Link to="#" onClick={light} className={ privateConv ? "submit" : "darkSubmit"}>Public</Link>
<Link to="#" onClick={dark} className={ privateConv ? "darkSubmit" : "submit"}>Private</Link>
</div>
{/* <p className="checkbox">Private<input className="check"type="checkbox" value="private" onChange={handleCheckPriv}/></p> */}
<p className="checkbox">Password<input type="checkbox" value="password" checked={password} onChange={handleCheckPass}/> </p> <p className="checkbox">Password<input type="checkbox" value="password" checked={password} onChange={handleCheckPass}/> </p>
{password ? ( {password || privateConv ? (
<input <input
onChange={(e) => setNewPassword(e.target.value)} onChange={(e) => setNewPassword(e.target.value)}
onKeyDown={handlePassword} onKeyDown={handlePassword}
type="text" type="password"
className="in" className="in"
placeholder="Password"/> placeholder="Password"/>
): ):
@ -237,11 +248,14 @@ const ModalSetting = ({handleClose, convId, socket }: ModalSettingProps) => {
<div> <div>
<Link to="#" onClick={handleInvite} className="submit">Send</Link> <Link to="#" onClick={handleInvite} className="submit">Send</Link>
<Link to="#" onClick={handleBan} className="submit">Ban</Link> <Link to="#" onClick={handleBan} className="submit">Ban</Link>
<Link to="#" onClick={handleMute} className="submit">Mute</Link> <Link to="#" onClick={mute ? darkMute : lightMute} className={mute ? "darkSubmit": "submit"}>Mute</Link>
<Link to="#" onClick={handleAdmin} className="submit">Admin</Link> <Link to="#" onClick={handleAdmin} className="submit">Admin</Link>
</div> </div>
</div> </div>
{mute ? (
<input type="text" className="in_howLong" placeholder="How long ?" />
):("")}
</motion.div> </motion.div>
</Backdrop> </Backdrop>

View File

@ -20,26 +20,6 @@ const dropIn = {
}, },
} }
// function showBar (){
// return (
// {SidebarData.map((item, index) => {
// return (
// <motion.div
// className="nav-menu"
// // whileHover={{scale: 1.1}}
// >
// <li key={index} className={item.cName}>
// <Link to={item.path}>
// {item.icon}
// <span>{item.title}</span>
// </Link>
// </li>
// </motion.div>
// )
// })}
// )
// }
interface CloseProps { interface CloseProps {
handleclose: Function; handleclose: Function;
} }

View File

@ -6,7 +6,7 @@
/* By: apommier <apommier@student.42.fr> +#+ +:+ +#+ */ /* By: apommier <apommier@student.42.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */ /* +#+#+#+#+#+ +#+ */
/* Created: 2023/06/09 08:19:04 by apommier #+# #+# */ /* Created: 2023/06/09 08:19:04 by apommier #+# #+# */
/* Updated: 2023/06/20 15:27:00 by apommier ### ########.fr */ /* Updated: 2023/06/23 15:58:14 by apommier ### ########.fr */
/* */ /* */
/* ************************************************************************** */ /* ************************************************************************** */
@ -21,6 +21,9 @@ import { motion, AnimatePresence } from 'framer-motion'
import { Link } from "react-router-dom"; import { Link } from "react-router-dom";
import ModalEdit from "../components/Profile/EditName.tsx"; import ModalEdit from "../components/Profile/EditName.tsx";
import {AiOutlineHistory} from 'react-icons/ai' import {AiOutlineHistory} from 'react-icons/ai'
import { MdQrCodeScanner, MdOutlinePhotoLibrary } from 'react-icons/md';
import { GiWingedSword, GiCrownedSkull } from 'react-icons/gi';
// import { Link } from "react-router-dom"; // import { Link } from "react-router-dom";
// import {UserProfile} from "../DataBase/DataUserProfile"; // import {UserProfile} from "../DataBase/DataUserProfile";
// import axios from "axios"; // import axios from "axios";
@ -33,6 +36,7 @@ import { IoCloseCircleOutline } from "react-icons/io5";
import React, { useState, useEffect, useRef, ChangeEventHandler } from "react"; import React, { useState, useEffect, useRef, ChangeEventHandler } from "react";
import { useParams } from 'react-router-dom'; import { useParams } from 'react-router-dom';
import {User, Conv} from "../../interfaces.tsx" import {User, Conv} from "../../interfaces.tsx"
import YellowAlert from '../components/Alert/YellowAlert.tsx';
// axios.get("http://localhost/api") // axios.get("http://localhost/api")
// .then((response) => { // .then((response) => {
// response = response.json() // response = response.json()
@ -58,24 +62,6 @@ function Profile () {
const [profilePicture, setProfilePicture] = useState(''); const [profilePicture, setProfilePicture] = useState('');
// const handleFileChange = (event: { target: { files: React.SetStateAction<null>[]; }; }) => {
// // 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 handleFileChange = (event: { target: { files: React.SetStateAction<null>[] | FileList; }; }) => {
// const files = event.target.files;
// if (event.target.files && event.target.files.length > 0) {
// setSelectedPhoto(event.target.files[0]);
// }
// };
const handleFileChange = async (event: { target: { files: any; }; }) => { const handleFileChange = async (event: { target: { files: any; }; }) => {
// const files = event.target.files; // const files = event.target.files;
// if (files && files.length > 0) { // if (files && files.length > 0) {
@ -182,18 +168,22 @@ function Profile () {
{mine ? ( {mine ? (
<div> <div>
<motion.div onClick={() => (modalOpen ? close() : open())}> <motion.div >
<Link to="#" className="edit_name"> <Link to="#" className="edit_name" onClick={() => (modalOpen ? close() : open())}>
{modalOpen === true ? <IoCloseCircleOutline/> : <CgEditMarkup/>} {modalOpen === true ? <IoCloseCircleOutline/> : <CgEditMarkup/>}
</Link> </Link>
{modalOpen === true ? ("") : (
<>
<label htmlFor="file-input" className="edit_name"><MdOutlinePhotoLibrary/></label>
<input type="file" id="file-input" className="file-input" accept="image/*" onChange={handleFileChange} />
</>
)}
</motion.div> </motion.div>
<div className="file-upload-container"> {/* <div className="file-upload-container"> */}
<label htmlFor="file-input" className="file-label">Choose File</label>
<input type="file" id="file-input" className="file-input" accept="image/*" onChange={handleFileChange} />
{/* <button onClick={handleUpload} className="upload-button">Upload</button> */} {/* <button onClick={handleUpload} className="upload-button">Upload</button> */}
{/* <button onClick={handleUpload} className="upload-button">Upload</button> */} {/* <button onClick={handleUpload} className="upload-button">Upload</button> */}
</div> {/* </div> */}
</div> </div>
) : ( ) : (
<></> <></>
@ -212,13 +202,49 @@ function Profile () {
function Home () { function Home () {
const [move, setmove ] = useState(false); const [move, setmove ] = useState(false);
const [user, setUser] = useState([]);
const [successQr, setSuccessQr] = useState(false);
const [successSword, setSuccessSword] = useState(false);
const [successCrown, setSuccessCrown] = useState(false);
const closeQr = () => setSuccessQr(false);
const closeSword = () => setSuccessSword(false);
const closeCrown = () => setSuccessCrown(false);
useEffect(() => {
const fetchSuccess = async () => {
try {
const tmpUser = await api.get("/profile");
setUser(tmpUser.data);
}
catch (error)
{
console.log(error);
}
};
fetchSuccess();
})
return ( return (
<motion.div className="page" <motion.div className="page"
initial={{opacity: -1}} initial={{opacity: -1}}
animate={{opacity: 1}} animate={{opacity: 1}}
exit={{opacity: -1}}> exit={{opacity: -1}}>
<div>
{user.otp_verified ? (
<MdQrCodeScanner className='success' onClick={() => setSuccessQr(true)}/>
):("")}
{user.win >= 2 ? (
<GiWingedSword className="success" onClick={() => setSuccessSword(true)}/>
):("")}
{user.win >= 5 ? (
<GiCrownedSkull className="success" onClick={() => setSuccessCrown(true)}/>
):("")}
</div>
<div className="home"> <div className="home">
<motion.div animate={{x: move ? -200: 170}} <motion.div animate={{x: move ? -200: 120}}
transition={{type: "tween", duration: 0.5}}> transition={{type: "tween", duration: 0.5}}>
<Profile/> <Profile/>
</motion.div> </motion.div>
@ -232,6 +258,19 @@ function Home () {
onClick={ () => setmove(!move)}> onClick={ () => setmove(!move)}>
<Link to="#" className="history"><AiOutlineHistory/> Match History</Link> <Link to="#" className="history"><AiOutlineHistory/> Match History</Link>
</motion.div> </motion.div>
<AnimatePresence initial={false} onExitComplete={() => null}>
{successQr ? (
<YellowAlert handleClose={closeQr} text={"Success: You have the 2fa success!"} icon={1} />
) : ("")}
{successCrown ? (
<YellowAlert handleClose={closeCrown} text={"Success: 5 victory ? You won king slayer success!"} icon={2}/>
) : ("")}
{successSword ? (
<YellowAlert handleClose={closeSword} text={"Success: 2 victory ? You won the noobi warrior success!"} icon={3}/>
) : ("")}
</AnimatePresence>
</motion.div> </motion.div>
) )
} }

View File

@ -9,7 +9,7 @@
input.qr{ input.qr{
width: 20%; width: 20%;
border-radius: 5px; border-radius: 5px;
background-color: rgb(66, 66, 66); background-color: rgb(0, 0, 0);
margin : 1%; margin : 1%;
color:white; color:white;
} }

View File

@ -89,6 +89,17 @@ span {
border-radius: 50%; border-radius: 50%;
} }
.success {
height: 2%;
width: 2%;
/* border: solid; */
margin-top: 1%;
margin: 3vh;
/* margin-bottom: -12vh; */
/* border-color: black; */
/* border-radius: 50%; */
}
.header-pic{ .header-pic{
text-align: end; text-align: end;
/* id: right; */ /* id: right; */

View File

@ -204,6 +204,18 @@ p {
margin: 1%; margin: 1%;
} }
.darkSubmit{
display: inline-block;
color: white;
background-color: #282155;
border-radius: 10px;
padding: 5px;
font-size: 1.2rem;
text-decoration: none;
font-weight:lighter;
margin: 1%;
}
.div_submit { .div_submit {
flex-direction: row; flex-direction: row;
align-items: center; align-items: center;
@ -276,6 +288,12 @@ p {
background-color: rgba(212, 175, 55, 0.7); background-color: rgba(212, 175, 55, 0.7);
font-size: 25px; font-size: 25px;
color: rgba(255, 255, 255, 1); color: rgba(255, 255, 255, 1);
flex-wrap: wrap;
}
.yellowAlert::p {
overflow-wrap: break-word;
max-width: 1000px;
} }
.modalSetting{ .modalSetting{
@ -298,7 +316,7 @@ p {
.settingSecondPart{ .settingSecondPart{
margin-top: 10%; margin-top: 10%;
margin-left: 10%; margin-left: 5%;
/* margin-left: 20%; */ /* margin-left: 20%; */
} }
@ -316,3 +334,20 @@ input.in{
border-radius: 12px; border-radius: 12px;
width: 70%; width: 70%;
} }
input.in_howLong{
margin-top: 14.5%;
margin-left: 0px;
background-color: black;
color: white;
border-radius: 12px;
width: 15%;
}
.mdp{
background-color : black;
border-radius: 8px;
color: white;
width: 20%;
}

View File

@ -61,12 +61,15 @@
.page { .page {
text-align: center; text-align: center;
overflow-y: scroll;
/* height: 50vh; */ /* height: 50vh; */
/* width: 50vh; */ /* width: 50vh; */
/* background-color: black; */ /* background-color: black; */
} }
.profile { .profile {
align-items: center;
text-align: center;
flex-direction: row; flex-direction: row;
color: white; color: white;
} }
@ -79,7 +82,7 @@
border-color: red; border-color: red;
/* border-image: linear-gradient(90deg, #5843e4, #5a0760); */ /* border-image: linear-gradient(90deg, #5843e4, #5a0760); */
margin-top: 20px; /* margin-top: 20px; */
} }
.home{ .home{
@ -106,7 +109,7 @@
.div_history { .div_history {
flex-direction: row; flex-direction: row;
align-items: center; align-items: center;
margin-top: -80px; /* margin-top: -80px; */
} }
.edit_name { .edit_name {

View File

@ -2,7 +2,7 @@
/* display: flex; */ /* display: flex; */
/* flex-direction: column; */ /* flex-direction: column; */
/* background-color: red; */ /* background-color: red; */
height: 70vh; height: 60vh;
/* padding: 15px; */ /* padding: 15px; */
/* overflow: scroll; */ /* overflow: scroll; */

View File

@ -1,16 +1,21 @@
.playButton { .playButton {
background-image: linear-gradient(90deg, #5843e4, #5a0760);; background-image: linear-gradient(90deg, #5843e4, #5a0760);
display: flex;
flex-wrap: wrap;
overflow: hidden;
border-radius: 5vh; border-radius: 5vh;
color: white; color: white;
display: block; /* display: block; */
margin: auto; margin: auto;
margin-top: 30vh; margin-top: 30vh;
padding: 2vh 5vw; padding: 2vh 4vw;
height: 10vh; height: 10vh;
width: 20vw; width: 20vw;
font-size: 300%; font-size: 250%;
text-align: center;
} }
.field { .field {
background-color: rgb(249, 249, 249); background-color: rgb(249, 249, 249);
/* border-radius: 5vh; */ /* border-radius: 5vh; */
@ -40,6 +45,29 @@
/* padding-top: 25; */ /* padding-top: 25; */
/* padding-top: 177.77% */ /* padding-top: 177.77% */
} }
@media screen and (max-width: 900px){
.playButton{
font-size: 200%;
}
}
@media screen and (max-width: 700px){
.playButton{
font-size: 150%;
}
}
@media screen and (max-width: 530px){
.playButton{
font-size: 100%;
}
}
@media screen and (max-width: 350px){
.playButton{
font-size: 50%;
}
}
#myCanvas { #myCanvas {
background-color: rgb(124, 47, 47); background-color: rgb(124, 47, 47);

View File

@ -11,7 +11,7 @@ services:
# command: sh -c "envsubst < /etc/nginx/conf.d/default.conf.template > /etc/nginx/conf.d/default.conf && nginx -g 'daemon off;'" # command: sh -c "envsubst < /etc/nginx/conf.d/default.conf.template > /etc/nginx/conf.d/default.conf && nginx -g 'daemon off;'"
ports: ports:
- 80:80 - 8080:8080
volumes: volumes:
- ./conf/nginx.conf:/etc/nginx/conf.d/default.conf - ./conf/nginx.conf:/etc/nginx/conf.d/default.conf
# volumes: # volumes:
@ -34,7 +34,7 @@ services:
# depends_on: # depends_on:
# - nginx # - nginx
ports: ports:
- 8080:8080 - 8001:8001
volumes: volumes:
- ./containers/react:/app - ./containers/react:/app
# - ./containers/react:/app # - ./containers/react:/app